Skip to content

refactor: move off deprecated foregroundColor, cornerRadius and overlay(_:alignment:) - #43

Merged
romchornyi merged 5 commits into
masterfrom
refactor/deprecated-swiftui-idioms
Nov 1, 2026
Merged

romchornyi merged 5 commits into
masterfrom
refactor/deprecated-swiftui-idioms

Conversation

@romchornyi

@romchornyi romchornyi commented Oct 31, 2026 •

Copy link
Copy Markdown
Collaborator

Issue being fixed or feature implemented

Part of #28. Sources/ still uses three SwiftUI APIs that the SDK marks deprecated: 100000.0 (deprecated in a future version, so no warning yet): foregroundColor(_:), cornerRadius(_:) and overlay(_:alignment:) with a view. This PR moves every use off them, except in five files that other open PRs are changing right now (see "Follow-up" below).

What was done?

One commit per idiom, plus one for the docs:

  • .foregroundColor(x) → .foregroundStyle(x) (78 call sites in 26 files). foregroundStyle takes a generic ShapeStyle, so implicit members are spelled out where their meaning would change:

    • .secondary → Color.secondary. A bare .secondary would become the hierarchical style.
    • .dash.x → Color.dash.x, because .dash does not resolve on ShapeStyle.
    • .clear → Color.clear.

    No call passes an optional color, and nothing concatenates Text. DashButtonStyle.foregroundColor(isEnabled:) is an internal method, not the modifier, and is unchanged.

  • .cornerRadius(r) → .clipShape(.rect(cornerRadius: r)) (ThumbView, FrameReader preview). The SDK's inlinable body of cornerRadius is clipShape(RoundedRectangle(cornerRadius: r), style: FillStyle(antialiased: true)). .rect(cornerRadius:) is the same RoundedRectangle with the same default corner style, and FillStyle() is antialiased, so the expression is the same. No explicit style: is passed, on purpose.

  • .overlay(view[, alignment: a]) → .overlay(alignment: a) { view } (11 sites in DashButton, AddressFieldView, NavigationBarCircleIcon, SimpleSelect, ConverterCard, ConverterArrowBadge, plus the SheetFeature and FrameReader previews). The value form is deprecated even without alignment:, because that parameter just defaults to .center. Both forms build the same _OverlayModifier. ShapeStyle overlays are a separate overload that is not deprecated; none are touched.

  • Docs: the README.md, docs/foundation.md and docs/navigation-and-containers.md examples use .foregroundStyle(Color.dash.primaryText).

No visual change: every replacement builds the same view (pixel check below).

Follow-up (not in this PR)

These files are left untouched because open PRs are editing them. They get the same sweep after those PRs merge:

File PR Remaining
BottomSheet/BottomSheet.swift #24 12× .foregroundColor(.dash.…) / .foregroundColor(.clear), 1× .cornerRadius(5)
Switch/SwitchView.swift #27 1× .cornerRadius(Constants.switchTrackRadius)
Geometry/ScrollViewWithOnScrollChanged.swift #32 preview: .cornerRadius(10), .overlay(Text("Row \(index)"))
Geometry/LocationReader.swift #32 (deletes it) 2× .cornerRadius(10), 1× .overlay(Text(…))
SearchBar.swift #31 none of the three idioms

A conventions.sh rule against these idioms would go in with that follow-up, so it lands with no exclusion list.

Also found, outside #28's three APIs:

  • background(_:alignment:) with a view value is deprecated the same way, and is used in about 10 places.
  • DashButton's strokeGray branch applies .background / .clipShape before .frame(maxWidth:), while its stroke overlay comes after the frame. So a disabled full-width strokeGray button would draw its gray fill narrower than its outline. This is from reading the code and predates this PR; it would be a visual change, so it is not fixed here.

How Has This Been Tested?

  • swift build (macOS) and the iOS Release device build (generic/platform=iOS) are clean, with no warnings. The unit tests pass in CI ("Unit tests (iOS Simulator)"); the local simulator run did not finish because the machine was overloaded.
  • conventions.sh passes (161 imagesets, 162 colorsets).
  • api-check.sh on a squash of this branch onto master: "No breaking changes detected in DashUIKit".
  • Pixels. A test harness walks the PreviewRegistry / PreviewProvider conformance records, so it renders every #Preview and PreviewProvider in the package as written. That is 108 previews, plus TopIntroView, which has no preview. Each was rendered in light and dark, at 3×, on the iOS 27 simulator, once on master (402db65) and once on this branch, and the PNGs were compared.
Renders (light + dark) Byte-identical Different
170 of the components this PR touches (85 previews / renders) 168 2: Toast, inside the ProgressView spinner only (47×47 px)
50 of untouched components 49 1: LoadingIllustration (animated)
220 total 217 3

The three differences are animation phase, not this change. Two renders of master differ in the same 47×47 px box of the Toast spinner, and LoadingIllustration.swift is not touched.

Before / After

  • No visual change (refactor, tests, docs). Say why in "What was done?".

Each replacement builds the same view: the same _OverlayModifier, the same RoundedRectangle clip, and the same color as the foreground style. 217 of 220 before/after renders are byte-identical, and the other 3 differ only in spinner/animation phase, which also differs between two runs of master (see the table above).

Breaking Changes

None. Public API is unchanged (api-check.sh).

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have made corresponding changes to the documentation

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Refactor

    • Updated text styling and shape clipping across interface components and previews. Existing colors, layouts, and display behavior remain unchanged.
    • Standardized overlay presentation in several components without changing their appearance or positioning.
  • Documentation

    • Updated the styling examples in the quick start guide and documentation to match the interface examples.

romchornyi and others added 4 commits October 31, 2026 15:34
foregroundColor(_:) is deprecated in a future SDK. Implicit members are
spelled out where foregroundStyle's generic ShapeStyle parameter would
change their meaning: .secondary becomes Color.secondary (not the
hierarchical style) and .dash.x becomes Color.dash.x.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Radius

cornerRadius(_:) is deprecated in a future SDK. Its inlinable body is
clipShape(RoundedRectangle(cornerRadius:), style: FillStyle(antialiased:
true)); .rect(cornerRadius:) is the same RoundedRectangle with the same
default corner style, so the corner does not change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
overlay(_:alignment:) is deprecated in a future SDK, also when called
without alignment: (it defaults to .center). overlay(alignment:content:)
builds the same _OverlayModifier. ShapeStyle overlays are a different,
non-deprecated overload; none are touched here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between ee9f47d and 7c89ac9.

Files selected for processing: 32
  • README.md
  • Sources/DashUIKit/Button/DashButton.swift
  • Sources/DashUIKit/Components/AddressFieldView.swift
  • Sources/DashUIKit/Components/BottomSheet/SheetFeature.swift
  • Sources/DashUIKit/Components/CoinSelector.swift
  • Sources/DashUIKit/Components/ConverterCard/ConverterArrowBadge.swift
  • Sources/DashUIKit/Components/ConverterCard/ConverterCard.swift
  • Sources/DashUIKit/Components/Criteria.swift
  • Sources/DashUIKit/Components/EnterAmount/DashBalanceView.swift
  • Sources/DashUIKit/Components/EnterAmount/DashPickerView.swift
  • Sources/DashUIKit/Components/EnterAmount/DualSwapAmountView.swift
  • Sources/DashUIKit/Components/EnterAmount/EnterAmountView.swift
  • Sources/DashUIKit/Components/EnterAmount/SwapAmountView.swift
  • Sources/DashUIKit/Components/Geometry/FrameReader.swift
  • Sources/DashUIKit/Components/MenuItem.swift
  • Sources/DashUIKit/Components/NavigationBar.swift
  • Sources/DashUIKit/Components/NavigationBarCircleIcon.swift
  • Sources/DashUIKit/Components/NumericKeyboardView.swift
  • Sources/DashUIKit/Components/RadioButtonRow.swift
  • Sources/DashUIKit/Components/ReceiveEstimateView.swift
  • Sources/DashUIKit/Components/SimpleSelect.swift
  • Sources/DashUIKit/Components/Switch/Components/ThumbView.swift
  • Sources/DashUIKit/Components/SystemMessageView.swift
  • Sources/DashUIKit/Components/Toast.swift
  • Sources/DashUIKit/Components/TopIntro/TopIntroView.swift
  • Sources/DashUIKit/Components/Transaction/TransactionView.swift
  • Sources/DashUIKit/Foundation/DashTextStyle.swift
  • Sources/DashUIKit/Foundation/LineHeight+DashUI.swift
  • Sources/DashUIKit/Table List/List1View.swift
  • Sources/DashUIKit/Table List/List8View.swift
  • docs/foundation.md
  • docs/navigation-and-containers.md

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

The pull request replaces foregroundColor with foregroundStyle across DashUIKit views and examples. It also updates selected overlays to trailing-closure syntax and selected rounded corners to clipShape. Existing colors and stated layout values remain unchanged.

Changes: SwiftUI modifier migration

Layer / File(s) Summary
Package-wide modifier updates
Sources/DashUIKit/Button/*, Sources/DashUIKit/Components/*, Sources/DashUIKit/Foundation/*, Sources/DashUIKit/Table List/*, README.md, docs/*
Views, previews, and examples use foregroundStyle in place of foregroundColor. Selected overlays use trailing-closure syntax, and selected rounded corners use clipShape. Existing color values, conditions, and layout values remain unchanged.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Refactor

Possibly related issues

  • DashUIKit issue 28 requests the same modifier replacements across Sources/. This pull request performs those replacements across the package; the issue’s notes about Text concatenation and continuous corner style are not covered in the supplied change details.

Possibly related PRs

  • dashpay/DashUIKit#15: This pull request uses newer SwiftUI modifier forms after the package floor update and does not add older-platform branches.
  • dashpay/DashUIKit#31: This pull request continues the foregroundStyle migration in DashUIKit views.

Suggested reviewers: jeanpierreroma, romchornyi-pitcrew

Merge Risk: Minimal · up to 7c89a

The modifier migration has no identified merge-blocking issue and appears ready to merge subject to normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title accurately and clearly summarizes the main changes: replacing deprecated SwiftUI uses of foregroundColor, cornerRadius, and overlay(_:alignment:).
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 4 functions across 29 files. (3 skipped: 3 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@romchornyi-pitcrew

romchornyi-pitcrew commented Oct 31, 2026 •

Copy link
Copy Markdown

✅ Review posted for commit 3b02962 · triage: normal · approve · took 4 min

@romchornyi-pitcrew romchornyi-pitcrew left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ no blockers · no majors · 7 non-blocking recommendations — reviewed at 3b02962688

Level Verdict
1 · Idea ✅ valid Part of #28: moves Sources/ off three SwiftUI APIs the SDK marks for deprecation, before they start warning
2 · Architecture ✅ right layer A mechanical sweep inside the library. The public API is unchanged (api-check.sh)
3 · Completeness ✅ gaps tracked At this head, no .foregroundColor( / .cornerRadius( / view-value .overlay( is left in Sources/ outside the five files the description defers to the open PRs that edit them (#24, #27, #31, #32), and #28 tracks those. The two foregroundColor matches left are DashButtonStyle.foregroundColor(isEnabled:), the internal method
4 · Code ✅ clean Each swap builds the same view: the same _OverlayModifier, the same RoundedRectangle clip, and implicit members spelled out (Color.secondary, Color.dash.x, Color.clear) so none turns into a hierarchical style. 217 of 220 renders are byte-identical, and the 3 others are animation phase
7 non-blocking recommendations
  1. A CI guard for the three idioms now — the SDK does not warn yet, so any PR merged after this one can bring .foregroundColor(.dash.x) back with CI green. A conventions.sh rule with a temporary exclusion list for the four deferred files would stop the drift today, instead of after the follow-up.
  2. Possible colour animation in SwapAmountView —
    .foregroundStyle(iconForegroundColor)
    and
    .foregroundStyle(fontPrimary ? Color.dash.tertiaryText : Color.dash.primaryText)
    — the row colours moved from the foregroundColor environment to foregroundStyle, which may interpolate when it changes inside an animated transaction. The swap's onChange assumes "font/color snaps to target". The still-frame pixel check cannot see this. Worth one look with isPrimaryLarge toggled inside withAnimation. (not verified)
  3. strokeGray fill narrower than its outline —
    .foregroundStyle(style.foregroundColor(isEnabled: isEnabled))
    .background(style.backgroundColor(isEnabled: isEnabled))
    .clipShape(RoundedRectangle(cornerRadius: size.radius, style: .continuous))
    .frame(maxWidth: fillsWidth ? .infinity : nil)
    .overlay {
    RoundedRectangle(cornerRadius: size.radius)
    .inset(by: 0.5)
    .stroke(Color.dash.buttonStrokeGrayStroke, lineWidth: 1)
    }
    — .background / .clipShape come before .frame(maxWidth:), while the stroke overlay comes after it. A disabled full-width strokeGray shows a narrow gray pill inside a wide outline. This predates the PR, and the description already notes it. It needs its own issue, since the fix is a visual change. (order verified at this head)
  4. Corner styles do not match —
    RoundedRectangle(cornerRadius: size.radius)
    and
    RoundedRectangle(cornerRadius: Layout.cornerRadius)
    — the stroke overlays use the default .circular RoundedRectangle, while the fill is clipped with .continuous (and AddressFieldView's focus ring is .continuous too). At larger radii the stroke and the fill meet unevenly at the corners. This also predates the PR. (not verified visually)
  5. The same hunk keeps view-value .background(_:alignment:) — — the description already notes that this form is deprecated the same way. Since this PR rewrites that chain anyway, .background(…, in: RoundedRectangle(…)) here would avoid another sweep of the same lines.
  6. Plain styles have no tap shape —
    content
    .padding(.horizontal, size.hPadding)
    .padding(.vertical, size.vPadding)
    .foregroundStyle(style.foregroundColor(isEnabled: isEnabled))
    .frame(maxWidth: fillsWidth ? .infinity : nil)
    .background(style.backgroundColor(isEnabled: isEnabled))
    .clipShape(RoundedRectangle(cornerRadius: size.radius, style: .continuous))
    — styles with a .clear background have no contentShape under .buttonStyle(.plain), so the padding and the full-width area cannot be tapped. SimpleSelect already notes this trap. Not from this PR. (not verified at runtime)
  7. ThumbView as a capsule —
    .foregroundStyle(Color.clear)
    .frame(width: 39, height: 24)
    .background(Constants.switchThumbFill)
    .clipShape(.rect(cornerRadius: Constants.switchThumbRadius))
    .shadow(color: Color.dash.switchThumbShadow.opacity(0.06), radius: 1, x: 0, y: 1)
    .shadow(color: Color.dash.switchThumbShadow.opacity(0.1), radius: 1.5, x: 0, y: 1)
    — a clear Rectangle plus background plus a 1000pt radius clip is a capsule in four steps. Capsule().fill(…) gives the same pixels. A preview-only nit in the same file set: Color.secondary in DashButton's previews (lines 285, 303) is a system colour where the rest of the diff uses Color.dash.secondaryText.
Review details

Tier: normal (a mechanical refactor across 32 files). Levels 1–3 inline. For completeness, the head was grepped for the three idioms and for implicit-member traps. Level 4 used the general lane (/code-review high), which traced the swaps for equivalence. The verifier read the DashButton branch order and SimpleSelect's background at this head. Items 3, 4 and 6 predate the PR and are listed because they sit in the touched hunks. CI was green at this head.

🤖 Reviewed with Claude Code

@romchornyi

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@romchornyi
romchornyi merged commit 2642d97 into master Nov 1, 2026
12 checks passed
@romchornyi
romchornyi deleted the refactor/deprecated-swiftui-idioms branch November 1, 2026 16:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants