feat(assets): import Menu icon set and normalize catalog names - #7
Conversation
Adds 82 imagesets covering the Menu icon set from the Hybrid design system, with light and dark artwork in a single imageset via luminosity appearances. Dark artwork is only included where it actually differs from light — 52 of the exported dark files were byte-identical to their light counterparts and were dropped rather than shipped as redundant duplicates. Layer names were normalized to a menu-<slug> template: separators unified, image-menu-/menu- prefixes de-duplicated, and "floopy disk" corrected to menu-floppy-disk. Two Face ID components that collapsed to the same slug are kept apart as menu-face-id (square brackets) and menu-face-id-rounded. Note: menu-send.disabled and menu-receive.disabled are removed here. The only remaining reference is a #if DEBUG preview in MenuItem.swift, which will render a blank icon until the disabled variants are re-exported.
Prefixes every icon in the group with system-message- and replaces the ad-hoc warning_triangle spelling, so names match the folder they live in. Adds the shield, timer, unmixed-funds and username-change icons. The top-level stopwatch imageset is folded into the group as system-message-timer-small.
Replaces dot separators with dashes so the names follow the same kebab-case convention as the rest of the catalog: transaction-all.trans becomes transaction-all-trans, transaction-coinbase.received becomes transaction-coinbase-received, transaction-uphold.received becomes transaction-uphold-received.
Moves the per-component icon folders under a shared Components/ parent and renames RadioButton to CheckBox, which is what the icons in it actually are. Checkbox assets pick up a checkbox- prefix to match.
The Menu (disabled) frame in Figma only diverges from the light set for these two icons; everything else in that frame is identical to its enabled counterpart. Named with a -disabled suffix to match the kebab-case convention the rest of the catalog now uses.
|
Important Review skippedToo many files! This PR contains 125 files, which is 25 over the limit of 100. To get a review, narrow the scope: Upgrade to a paid plan to raise the limit. This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (421)
📒 Files selected for processing (126)
You can disable this status message by setting the |
Two settings, both needed because icon imports are large:
- path_filters drops **/*.xcassets/** so generated imageset Contents.json
does not count toward the review file limit and skip the review of the
source changes.
- auto_review.base_branches allows feat/* bases, since the code half of a
stacked import targets the asset branch rather than the default branch.
Lives on the asset branch because CodeRabbit reads its config from the base
branch of a pull request, not from the head.
Implements the switch from the iOS design system (node 1841:259) as a standalone SwiftUI view: a 64x28 track with a 39x24 pill thumb inset by 2, sliding 21pt between states with a 0.2s ease-in-out. Covers all four states. Disabled is read from the isEnabled environment value rather than a parameter, so .disabled(true) on any ancestor works: on + enabled blue on + disabled blueAlpha50 off + enabled gray300Alpha50 off + disabled black1000Alpha20 The off and on colors map exactly to the switch/track-fill-off and switch/track-fill-on design variables. The design system has no track-fill-on-disabled variable, so blueAlpha50 is a stand-in and needs confirming with the designer.
Introduces DashIcon, a namespace of String-backed enums mirroring the asset catalog folder structure — 137 icons across 12 groups. The raw value is the imageset name, so a wrong name becomes a compile error instead of a blank image at runtime. DashIconAsset gives each case .source (a DashIconSource, for components that take one) and .image (a plain Image, styled by the caller). Group prefixes are dropped from case names since the enum already namespaces them: menu-account-error reads as DashIcon.Menu.accountError. Generated from the catalog rather than hand-written, and CaseIterable so a gallery preview can enumerate a group.
Replaces all 20 raw asset-name strings in the library with DashIcon cases.
Three of them were already broken by the catalog normalization and were
failing silently:
- SystemMessageView's default icon still pointed at "warning_triangle",
renamed to system-message-warning-triangle. This is a default parameter
value in shipping code, not a preview, so every SystemMessageView built
without an explicit icon rendered a blank one.
- MenuItem's preview used "menu-receive.disabled"; the imageset is now
menu-receive-disabled.
- TransactionView passed "transaction-mining" with no bundle, so it
resolved against the host app's bundle rather than the library's.
Call sites that only needed an Image collapse from
Image(dash: .custom(name, bundle: .dashUIKit)) to DashIcon.Group.case.image.
Converts every unambiguous .font(Font.dash.X) to .dashFont(.X), so the
documented design line height is applied alongside the font rather than
leaving each Text at the system's natural leading. Also maps two preview
labels off Apple's .subheadline onto .dashFont(.subhead).
Deliberately left on .font:
- The previews in LineHeight+DashUI and DashTextStyle exist precisely to
contrast bare .font against .dashFont — converting them would erase what
they demonstrate.
- SearchBar's Font.dash.footnote.weight(.semibold): the nearest token,
footnoteMedium, is .medium, so converting would change the weight.
- DashButtonSize.fontSize returns .system(size: 16/14/13/12); 14pt has no
token, so a partial conversion would leave the sizes inconsistent.
- DashAmount, NumericKeyboardView and SwapAmountView size text dynamically
or take a Font parameter. Converting those means reshaping the API to pass
DashTextStyle, which is a separate change.
The design system has no track-fill-on-disabled variable, so the disabled on state was a stand-in. Aligns it with the disabled off state, which means a disabled switch reads the same either way and only the thumb position tells them apart.
SwitchView announced itself as a button with no value, and the tap gesture was not exposed as an accessibility action, so VoiceOver users could not tell the state or change it. Adds a localized On/Off value and an explicit accessibility action. The trait becomes .isToggle where available; that API is iOS 17 and this component must stay usable on iOS 14, so the older path keeps .isButton. No accessibility label is set. SwitchView takes no title, so it has no context to describe itself with — a generic label would also shadow the one the host sets, the same way SwiftUI's own Toggle requires the caller to supply it.
feat: add DashIcon enums, SwitchView and dashFont line heights
Split out of #6 so the Swift changes can be reviewed separately — see #6 for why.
The code half is stacked on top of this branch.
Issue being fixed or feature implemented
The Menu icon set from the design system was missing from the library, and the names
already in the catalog carried whatever spelling the Figma layer happened to use
(
floopy disk,credit.card,image-menu-face_id,UserSearch), with folders mixingconventions.
What was done?
Menu icon set imported
82 imagesets from the Hybrid design system, light and dark artwork in a single imageset
via
luminosityappearances.Dark artwork is only included where it actually differs. 52 of the exported dark files
were byte-identical to their light counterparts — Figma renders most of these components
the same in both frames — so they were dropped rather than shipped as duplicates. That is
156 files not added.
Also adds
menu-send-disabled/menu-receive-disabled. These are the only two icons inFigma's
Menu (disabled)frame that genuinely diverge from the enabled set; the rest ofthat frame is identical to the light one.
Names normalized across the catalog
Layer names were normalized to a
menu-<slug>template: separators unified,image-menu-/menu-prefixes de-duplicated, andfloopy diskcorrected tomenu-floppy-disk. Two Face ID components that collapsed onto the same slug are keptapart as
menu-face-id(square brackets) andmenu-face-id-rounded.The same pass covered the rest of the catalog:
System messagesystem-message-; top-levelstopwatchfolded in assystem-message-timer-smallTransactionstransaction-all.trans→transaction-all-transRadioButton→Components/CheckboxComponents/parentSearchBar→Components/SearchBarHow Has This Been Tested?
swift buildpasses at every commit.This PR is assets only — no Swift source changes, so nothing here can fail to compile.
Three call sites in the library referenced assets renamed by this PR and were already
broken before it; they are fixed in the stacked code PR, which is why the two should
land together.
Breaking Changes
None for the package's public API — no public symbol exposed an asset name. Any consumer
referencing these assets by raw string would break, but the library is not yet consumed
by
dashwallet-ios.Checklist: