Skip to content

chore(ds): finish the button axis rename + drift fixes (secondary/ghost, attention, input size, press gate) (TASK-22817) - #3302

Merged
kushagrasarathe merged 11 commits into
devfrom
chore/ds-drift-fixes
Sep 22, 2026
Merged

kushagrasarathe merged 11 commits into
devfrom
chore/ds-drift-fixes

Conversation

@kushagrasarathe

@kushagrasarathe kushagrasarathe commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Eight drift fixes in the design system: names that no longer match the board, three variants the board never had, a prop the board does not draw, two types nobody could import, a comment that named the wrong colour, and a contract test that could not fail a merge.

Everything except H is a rename, a deletion or a comment. H has one deliberate visual change, named below.

Stacks on #3301

Branched off fix/nav-circle-one-color-press, not dev, because #3301 touches the same button call sites. Merge #3301 first. After it lands, this PR shows only its own 7 commits.

A — the button variants are named after the board rows

The board (17802:61527) calls the three live rows primary, secondary and ghost. The code called two of them stroke and transparent.

  • ButtonVariant: stroke → secondary, transparent → ghost
  • CSS: .btn-stroke → .btn-secondary (the ghost row is styled inline, so there is no .btn-transparent to rename)
  • 111 files, ~250 lines: product call sites, /dev pages, jest tests, the press-physics spec and the prose that named the old words
  • the legacy tail (transparent-light, transparent-dark, primary-soft) kept its names here, then H removes it outright
  • the frozen audit fixture under dev/ds/audit/ is untouched by design

B — the non-blocking limits state is 'attention'

LimitsWarningCard renders a Callout with priority="attention", but the props that chose it said warning.

  • LimitsWarningType: 'warning' → 'attention'
  • titleKind: 'warning' → 'attention'
  • the message key those build renames with them: limits.warningCard.warningTitle → .attentionTitle, in the 3 locales that carry it (es-AR has no title keys and falls back)

Same copy, same colour, same branch.

Analytics scope. type reaches PostHog: LimitsWarningCard captures it on limits_check_link_navigation, so that property's value becomes attention from this PR on. Nothing reads it — no saved insight or dashboard in project 138913 references the event at all (system.insights, checked; Chip found the same). The break is a value split in raw events only, so any later query on that property has to accept both words across the rename date.

C — BaseInput's height axis is size

sm/md are heights (40/48px). Calling the prop variant made it read like a look, so callers forced the height by className instead.

  • prop and local type renamed (BaseInputVariant → BaseInputSize)
  • 13 call sites: 1 product (ProfileEditField) and 12 on /dev pages
  • the native size attribute is omitted from the props — nothing passed it
  • SearchInput moves to size="sm" and drops its h-10. It already overrode the horizontal padding with px-10, so the class list it renders is byte-identical.
  • CopyField keeps its className="h-10". sm is h-10 px-3, md is h-12 px-4 — the size does not differ in height alone, and switching CopyField would narrow its padding from 16px to 12px. That is a visual change, so it waits for a ruling.

D — disableBackBtn is gone

No product screen ever passed it. Its only caller was the /dev/ds page documenting it, so the doc page was the whole demand. A disabled back button is also not a state the navigation board draws; flows that wanted it use hideBackBtn.

Removed: the prop, its destructure, the disabled={...} it fed, and the two doc-page rows plus the live demo usage.

E — the shadow-size unions are exported

Both were private, so a caller building a props object had to retype the union. Card's was also called ShadowSize while holding a different set of members than Button's, so it becomes CardShadowSize. Type-only: no union changes, no call-site changes.

F — AVATAR_LINK_BG is the brand pink

The comment said "peanut pink". The same file defines a peanut_pink palette entry whose background is #FFD5F6. #FF90E8 is action-primary. One line.

G — the press-physics contract can now fail a merge

e2e/flows/button-press-physics.spec.ts ran only inside ds-shots, which is deliberately not in ci-success.needs. A change that broke the press state could merge green. The contract has broken twice, and a class-name unit test cannot catch it: the bug is which state wins in the cascade, readable only off computed style in a real browser.

New press-contract job: checkout with submodules, install, cached Playwright chromium, pnpm build, then that one spec. No screenshot or diff machinery. Added to ci-success.needs. ds-shots keeps its advisory role unchanged.

Prettier reflowed the needs: array when the entry pushed it past the print width — that is why the diff there is larger than one line.

H — ButtonVariant is primary | secondary | ghost

kush 2026-09-22: the union is the board. The three legacy variants had no board row and kept a fourth, fifth and sixth way to ask for a button the board already answers. All 10 call sites are migrated and the type, the buttonVariants record and the two CSS classes are gone.

primary-soft → secondary (4 sites, no visual change at rest.) primary-soft was bg-white with no shadow, so every call site paired it with shadowSize="4". --color-background-default is #ffffff and .btn-secondary already ships the same 4px shadow, so the swap is pixel-identical and the redundant shadowSize goes with it.

  • Profile — "Log out"
  • Success.link.send.view — "Cancel link"
  • AddMoneyBankDetails — the "Share details" ShareButton
  • CopyToClipboard — "Copy code" (button mode)

The disabled state changes: 4px → 1px. primary-soft carried no shadow of its own, so the whole shadow on these four came from shadowSize="4" → .btn-shadow-primary-4, which has no disabled: scope (globals.css). A disabled primary-soft therefore still painted the full 4px offset, only dimmed by .btn's disabled:opacity-40. .btn-secondary scopes its own disabled:shadow-[0.0625rem…], so the four now drop to the 1px residual instead. That is the board's disabled state, so it is a gain, not a regression — but the delta is 4px to 1px, not flat to 1px. ShareButton's own hard-coded shadowSize="4" stays — ProfileHeader passes it variant="ghost", which has no shadow of its own and would lose one if it were dropped.

transparent-dark → ghost (3 sites, no visual change.) SetupWrapper ("Skip") and the two BadgesRow scroll arrows. No className changes.

The fourth transparent-dark was not a button at all. The UnsupportedBrowserModal paste hint was an ActionModal cta with no onClick — a button that did nothing, styled down to h-2 to stop looking like one. It is now a <p className="text-body-xs text-foreground-secondary"> in the modal footer. Footer, not content: "Then paste it in your preferred browser." has to read after the copy cta, and content renders above the ctas. Net spacing below the button moves 20px → 24px. The test's ActionModal mock gained footer and lost its now-dead onClick ? button : p branch.

transparent-light → ghost (QRScanner, 2 sites) — the one visual change. The scanner overlay circles now use NAV_CIRCLE_BUTTON_CLASSES with border-white text-white fill-white, so they match every other icon-only nav button in the app. At rest: white ring, white glyph on the camera feed — same as today. On press: pink fill with a black glyph, which is the ruled ghost icon-only state and is what changes. The hard-coded fill="white" on the inner <Icon> goes, so the glyph now inherits from the button and can invert.

On a desktop pointer the circles also take the pink fill on hover, not only on press. NAV_CIRCLE_BUTTON_CLASSES paints hover and press with the same action-primary — one colour for both states is the 2026-09-21 ruling, so this is the ruled behaviour and not a second change. Touch has no hover, so the scanner's own users see press only.

Deleted: .btn-transparent-light and .btn-transparent-dark from globals.css; the three variants from ButtonVariant, buttonVariants and the Button docblock; the three from the /dev/ds/primitives/button playground and variants list. That list's usage counts were stale, so it now names each row's job instead of a number nobody regenerates. The frozen audit fixture under dev/ds/audit/ is untouched.

Separate commit — the dead UserHeader is deleted. It was the fifth primary-soft call site and had zero callers; the home header was rebuilt during the consolidation. All 12 imports of @/components/UserHeader pull VerifiedUserLabel, which stays in place with its import path unchanged.

Not done — each waits on a ruling

  • unifying the size vocabulary across primitives (Button uses small|medium|large, BaseInput uses sm|md)
  • Avatar defaults
  • font schemes
  • folding Field and FieldColumn into one primitive

Gates

prettier --check . · typecheck · TZ=UTC npm test (717 suites, 9133 tests) · npm run build · full pnpm test:e2e:regression against the production build (112 passed) — all green locally, re-run after H. The press-physics spec is unaffected and passes.

ds-shots should now report two classes of difference, both intended:

  1. the QR scanner overlay circles (H), if the shot captures a pressed state
  2. disabled-state shots of the four migrated primary-soft buttons, whose shadow drops from 4px to the 1px residual

Anything else is a regression.


Extends TASK-22817. The id is in the title only — the branch was already pushed and open, and renaming a branch closes its PR, so the second mention the linker wants is not available here. Follow-up fixes are in #3317.

🤖 Generated with Claude Code

The board (17802:61527) calls the three live rows primary, secondary and
ghost. The code called two of them 'stroke' and 'transparent', so every
review of a button had to translate between the two vocabularies, and the
press-physics spec named a test after a word the board does not use.

Renames the union members, the class (.btn-stroke -> .btn-secondary) and
every call site. The legacy tail (transparent-light|dark, primary-soft)
keeps its names: it has no board row and waits on a page rebuild.

No visual change — the class bodies and the variant strings are untouched.
The card renders a Callout with priority="attention" — the board's name for
the state — but the props that choose it were called 'warning'. Reading the
file meant mapping one word onto the other, and a new caller had no way to
guess which name the board uses.

Renames the LimitsWarningType member and the titleKind value, plus the
message key they build (warningCard.warningTitle -> .attentionTitle) in the
three locales that carry it. Same copy, same colour, same branch.
sm/md are heights (40/48px), which is what every other primitive in the DS
calls size. Calling it 'variant' made it read like a look, so call sites
reached for className instead and forced the height by hand.

Renames the prop and the local type, and moves SearchInput onto size="sm":
it already overrode the horizontal padding with px-10, so the class list it
renders is byte-identical. CopyField keeps its className h-10 — sm also
narrows the padding to px-3, which would move its text 4px.

The native `size` attribute is omitted from the props; nothing passed it.
No product screen has ever passed it. Its only caller was the /dev/ds page
that documents it, so the doc page was the whole demand — and a documented
prop reads as one somebody should use.

A disabled back button is also not a state the navigation board draws: the
flows that wanted it use hideBackBtn.
Both were private, so a caller building a props object for a Button or a
Card had to retype the union or reach for `as const` and hope. Card's was
also called ShadowSize while holding a different set of members than
Button's — two names for two things is the rule, so Card's becomes
CardShadowSize.

Type-only change; the unions and every call site are untouched.
The comment said "peanut pink", and the file above it defines a
peanut_pink palette entry whose background is #FFD5F6. Anyone matching the
two would pick the wrong hex. #FF90E8 is action-primary.
The spec ran only inside ds-shots, which is deliberately not in
ci-success.needs, so a change that broke the press state could merge green.
The contract has broken twice and a class-name unit test cannot catch it:
the bug is which state wins in the cascade, readable only off computed
style in a real browser.

Adds one lean job that builds and runs that single spec, and puts it in
ci-success.needs. ds-shots keeps its advisory role.
@vercel

vercel Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
peanut-wallet Ready Ready Preview Sep 22, 2026 8:02am UTC

Request Review

@coderabbitai

coderabbitai Bot commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository: peanutprotocol/peanut-ui/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 3e7bad1b-c94a-4c42-8633-6d281be69ff7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Code-analysis diff

Painscore total: 8694.58 → 8705.18 (+10.6)
Findings: -2 net (+60 new, -62 resolved)

🆕 New findings (60)

  • high hotspot — src/components/Profile/index.tsx — 63 commits, +431/-339 lines since 6 months ago
  • high hotspot — src/components/Home/ActivationCTAs.tsx — 62 commits, +961/-421 lines since 6 months ago
  • high hotspot — src/components/Profile/views/UnlockPayments.view.tsx — 60 commits, +1714/-953 lines since 6 months ago
  • high hotspot — src/components/Global/QRScanner/index.tsx — 55 commits, +1079/-621 lines since 6 months ago
  • high hotspot — src/app/(setup)/setup/page.tsx — 49 commits, +689/-346 lines since 6 months ago
  • high hotspot — src/app/shhhhh/ShhhhhLandingPage.tsx — 49 commits, +1346/-1139 lines since 6 months ago
  • high complexity — src/components/0_Bruddle/Button.tsx — CC 49, MI 51.95, SLOC 82
  • high hotspot — src/components/AddWithdraw/DynamicBankAccountForm.tsx — 48 commits, +1196/-955 lines since 6 months ago
  • high complexity — src/components/Global/QRScanner/index.tsx — CC 47, MI 64.29, SLOC 182
  • high complexity — src/features/limits/components/LimitsWarningCard.tsx — CC 42, MI 59.55, SLOC 135
  • high complexity — src/components/Setup/components/SetupWrapper.tsx — CC 40, MI 61.91, SLOC 78
  • high method-complexity — src/components/0_Bruddle/Button.tsx:113 — CC 38 SLOC 46
  • medium react-long-component — src/app/(mobile-ui)/dev/ds/primitives/button/page.tsx:15 — ButtonPage is 362 lines — split it
  • medium high-mdd — src/app/(setup)/setup/page.tsx:59 — SetupPageContent: MDD 105.4 (uses across many lines from declarations)
  • medium high-mdd — src/components/Profile/index.tsx:32 — Profile: MDD 94.3 (uses across many lines from declarations)
  • medium high-mdd — src/components/Send/link/views/Success.link.send.view.tsx:26 — LinkSendSuccessView: MDD 64.5 (uses across many lines from declarations)
  • medium high-mdd — src/components/0_Bruddle/Button.tsx:113 — : MDD 54.1 (uses across many lines from declarations)
  • medium high-mdd — src/app/dev/devices/page.tsx:44 — Harness: MDD 39.9 (uses across many lines from declarations)
  • medium high-mdd — src/components/Badges/BadgesRow.tsx:38 — BadgesRow: MDD 35.8 (uses across many lines from declarations)
  • medium high-mdd — src/components/Global/QRScanner/index.tsx:176 — ScanRegionOverlay: MDD 31.3 (uses across many lines from declarations)

…and 40 more.

✅ Resolved (62)

  • src/components/Home/ActivationCTAs.tsx — 61 commits, +960/-420 lines since 6 months ago
  • src/components/Profile/index.tsx — 61 commits, +429/-336 lines since 6 months ago
  • src/components/Profile/views/UnlockPayments.view.tsx — 59 commits, +1713/-952 lines since 6 months ago
  • src/components/Global/QRScanner/index.tsx — 54 commits, +1070/-614 lines since 6 months ago
  • src/components/0_Bruddle/Button.tsx — CC 49, MI 51.59, SLOC 85
  • src/components/AddMoney/components/MantecaAddMoney.tsx — 48 commits, +375/-158 lines since 6 months ago
  • src/components/Global/TokenSelector/TokenSelector.tsx — 48 commits, +892/-774 lines since 6 months ago
  • src/hooks/useHomeCarouselCTAs.tsx — 48 commits, +534/-374 lines since 6 months ago
  • src/components/Global/QRScanner/index.tsx — CC 47, MI 64.3, SLOC 182
  • src/features/limits/components/LimitsWarningCard.tsx — CC 42, MI 59.56, SLOC 135
  • src/components/Setup/components/SetupWrapper.tsx — CC 40, MI 61.92, SLOC 78
  • src/components/0_Bruddle/Button.tsx:123 — CC 38 SLOC 46
  • src/app/(mobile-ui)/dev/ds/primitives/button/page.tsx:15 — ButtonPage is 383 lines — split it
  • src/app/(setup)/setup/page.tsx:59 — SetupPageContent: MDD 105.2 (uses across many lines from declarations)
  • src/components/Profile/index.tsx:32 — Profile: MDD 94.5 (uses across many lines from declarations)
  • src/components/Send/link/views/Success.link.send.view.tsx:26 — LinkSendSuccessView: MDD 64.9 (uses across many lines from declarations)
  • src/components/0_Bruddle/Button.tsx:123 — : MDD 54.1 (uses across many lines from declarations)
  • src/app/dev/devices/page.tsx:44 — Harness: MDD 38.9 (uses across many lines from declarations)
  • src/components/Badges/BadgesRow.tsx:38 — BadgesRow: MDD 36.6 (uses across many lines from declarations)
  • src/app/(mobile-ui)/dev/ds/_components/DocSidebar.tsx:12 — DocSidebar: MDD 33.5 (uses across many lines from declarations)

…and 42 more.

@github-actions

github-actions Bot commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

🧪 UI test report — ✅ all green

Suites

  • ✅ unit: 9168 ran, 0 failed, 0 skipped, 2.3m

📊 Coverage (unit)

metric %
statements 81.2%
branches 70.0%
functions 76.1%
lines 82.3%
⏱ 10 slowest test cases
time test
🐢 9.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › Network failure keeps loading while retries remain, then shows the generic error
4.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › MANTECA_USER_NOT_PROVISIONED fails fast with copy that names the real cause
4.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › MANTECA_MERCHANT_RECENT_REFUND fails fast with copy that names the real cause
4.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › MANTECA_SOURCE_OVER_MONTHLY_CAP fails fast with copy that names the real cause
4.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › User KYC not approved fails fast with copy that names the real cause
4.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › MANTECA_MERCHANT_VOLUME_NEAR_CAP fails fast with copy that names the real cause
4.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › a refused idempotency key tells the user to scan again, not to contact support
4.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › routes the KYC rejection on its wire code, and does not retry it
3.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › Going offline blames the connection, and reconnecting clears it for the recovered scan
3.0s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › Scan that recovers on the retry lands on the payment screen, not an error
📍 Inline annotations are in the **Unit test report** check above. Coverage artifact: `coverage-unit`. Generated by `.github/workflows/tests.yml`.

@chip-peanut-bot chip-peanut-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Chip review — no blocking findings — this is not an approval

Seven design-system drift fixes, all rename/delete/comment plus one new required CI gate. The mechanical sweep is complete and typechecked (nothing outside the intentionally frozen audit fixture still uses the old names), the SearchInput/CopyField padding calls were verified against twMerge conflict rules, the i18n key rename touches exactly the three locales that carry it, and no PostHog consumer reads the one capture value that changes. Two major findings: the mono design rulebook still records the opposite naming resolution for the button variants, and the new required press-contract job drops the apt-stall retry its own template documents.

Findings

  • MAJOR · src/components/0_Bruddle/Button.tsx:94 · DS rulebook still records stroke/transparent as the code names
    The rename reverses a recorded resolution without updating the record. mono design/design.md's open-questions row for button variant names (TASK-22817) says "stroke=secondary and transparent=ghost keep their names", and its recipes still instruct variant="stroke" / variant="transparent" (design.md:144, 224, 489; components.md:17). The open mono PR #220 from this author corrects only the press colour, not the naming row. After this merges, the rulebook that agents build screens from contradicts the code union: misuse fails typecheck loudly, but every recipe line keeps teaching the old vocabulary — re-creating the two-vocabulary translation cost this PR exists to remove — and the reversal of a recorded ruling goes unrecorded (design.md law 6: never silently decide). Fix: extend mono #220 or open a mono PR updating the variant-names row, the recipes, and components.md.

  • MAJOR · .github/workflows/tests.yml:794 · press-contract's install-deps step drops the documented apt-stall retry
    ds-shots documents three consecutive 6-minute npx playwright install-deps stalls on the runner's Azure mirrors (2026-08-19, PR #2755) and hardened its step with 3 attempts, a mirror fallback after the first failure, and a 9-minute cap (tests.yml ~509-533). press-contract copies the step without any of that. ds-shots is advisory, but press-contract is in ci-success.needs, so the same transient stall now fails a required check and blocks merges until a manual re-run — the exact failure mode the hardening exists for, moved onto a gate. Fix: copy ds-shots's retry block into this step.

Checked clean

  • Worktree HEAD verified at 9fd74aa; full 126-file diff vs base f9372c0 reviewed, including the two stacked #3301 nav commits it carries
  • Rename completeness: no variant="stroke"/"transparent" and no BaseInput variant prop survives outside the intentionally frozen dev/ds/audit fixture; no raw .btn-stroke class remains in product or e2e code
  • SearchInput size="sm" swap verified: twMerge yields the same final class list (h-10 + px-10) as the old h-10 override, matching the byte-identical claim; CopyField's h-10 correctly left alone to keep 16px padding
  • i18n: warningTitle -> attentionTitle in exactly the three locales carrying limits.warningCard; es-AR never had the key (same fallback as before); the unrelated crypto-deposit warningTitle untouched
  • PostHog production checked: no insight or dashboard filters on limits_check_link_navigation or its type property, so the 'warning'->'attention' capture value change breaks no consumer
  • CI at this head: press-contract green, plus unit, typecheck, eslint, ds-lint, screen-tests, format, native-export, human-authors, bot-approval; ci-success green; ds-shots still in flight (advisory, PR expects zero diffs)
  • e2e rewrite matches the 2026-09-21 one-colour nav-circle ruling (documented in open mono #220); SetupWrapper circles + NAV_CIRCLE_BUTTON_CLASSES twMerge precedence verified and the /setup/finish white-chip regression covered by the new test
  • AVATAR_LINK_BG comment verified against the token table: #FF90E8 is action-primary; the peanut_pink palette entry's lightShade is #FFD5F6
  • LimitsWarningCard: no caller still passes type="warning"; getLimitsWarningCardProps is the only type producer and now emits 'attention'

Security review by moonshotai/kimi-k3: 0 finding(s), marked with the model name. It reads the diff only and answers only security, privacy and money, so treat its findings as advice.

Third opinion by claude-opus: 0 finding(s), marked with the model name. It answers only product truth, missing tests and the cross-repo contract, so treat its findings as advice.

The usual first reviewer was out of plan, so this review was done by openrouter/z-ai/glm-5.3.

Exact head: 9fd74aaf7c8e · Context: repo, mono, notion, production · Took 13m

Comment thread src/components/0_Bruddle/Button.tsx
Comment thread .github/workflows/tests.yml
@github-actions

github-actions Bot commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

🖼 Visual diff — 3 screens moved

5 of 146 shots changed · 141 identical · baseline 3e2ce1e → head d44fb85

worst % screen widths
48.91% early-user 320
43.12% avatar-picker 320, 430
1.48% guest-invite 320, 430

job summary · before/after/diff images — artifact

Fixture screenshots, no backend. Advisory — this check never blocks a merge. Posted from the default branch by ds-shots-comment.yml; the report it renders is untrusted data.

@github-actions

github-actions Bot commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

English · Español · Español (Argentina) · Português (Brasil)

Open screen library dashboard

After merge: 3e2ce1e → b194ae8. Capture complete in all locales.

UserHeader had zero call sites — the home header was rebuilt during the
consolidation and nothing renders it any more. All 12 imports of the module
pull VerifiedUserLabel instead, which stays and keeps its import path.

It was also the fifth primary-soft call site, so removing it is one less
thing to migrate in the variant collapse.
kush 2026-09-22: the union is the board — primary/secondary/ghost. The three
legacy variants had no board row and kept a fourth, fifth and sixth way to
ask for a button that the board already answers.

primary-soft -> secondary (4 sites). primary-soft was bg-white with no
shadow, so every call site paired it with shadowSize="4";
--color-background-default is #ffffff and .btn-secondary already ships the
same 4px shadow, so the swap is pixel-identical at rest and the redundant
shadowSize goes. The sites gain secondary's 1px residual shadow when
disabled, which is the board's disabled state.

transparent-dark -> ghost (3 sites). The fourth was not a button at all: the
UnsupportedBrowserModal paste hint was an ActionModal cta with no onClick —
a button that did nothing. It is now a footer note, which is also where
"Then paste it in your preferred browser." has to read, after the copy cta.

transparent-light -> ghost (QRScanner, 2 sites). The only visual change. The
scanner overlay circles now use NAV_CIRCLE_BUTTON_CLASSES with white border,
text and fill, so they match every other icon-only nav button: white ring and
white glyph at rest, pink fill with a black glyph on press. The hard-coded
fill="white" on the inner Icon goes with it.

Also drops .btn-transparent-light and .btn-transparent-dark from globals.css
and the three variants from the /dev/ds button page, whose usage counts were
stale anyway — the variants list now names each row's job instead.
…te must not fail on a transient mirror stall (chip review)
dev's new RequestCreatedView is the one semantic conflict: it was written
against the old variant vocabulary while this branch renamed it. stroke ->
secondary and transparent -> ghost, the same pure rename 526d911 applied to
every other call site. No visual change — the class bodies are untouched.

That single type error is what failed typecheck, native-export, press-contract,
ds-shots, Deploy-Preview and ci-success: all five build steps type check, so all
five inherited it from the one file.
@kushagrasarathe
kushagrasarathe merged commit b194ae8 into dev Sep 22, 2026
32 of 34 checks passed
kushagrasarathe added a commit that referenced this pull request Sep 22, 2026
dev landed the ButtonVariant collapse (#3302) while this branch was open, so
the two sides met on the same two marketing files.

Conflict: src/components/Jobs/Careers.tsx. dev's only edit to the Ready?
section was the variant rename stroke -> secondary (526d911); this branch
had rebuilt the whole section into the marketing CTA card (mascot behind the
Card, centered, inline buttons). Union rule: keep this branch's composition,
take dev's variant name on top of it. Nothing of either side is dropped.

press/page.tsx auto-merged for the same reason — dev renamed the download
pill's variant, this branch added its w-auto/whitespace-nowrap classes on the
same element, and git kept both.

Swept the branch for the other legacy variant names dev retired
(stroke -> secondary, transparent -> ghost, transparent-light|dark -> ghost,
primary-soft -> secondary). The only live site left was the careers CTA
button, which this branch added after dev's migration ran — it is renamed
here. The remaining hits are the /dev/ds audit datasets, which quote
historical class names as data and are allowlisted out of ds-lint.

ds-lint baseline: two debt metrics move up, both recorded with reasons.
offScaleSpacing 85 -> 87 is this branch's own arrears — the Ready? rebuild
added pt-24/md:pt-28 without a baseline bump, so the ratchet was already red
before this merge. That padding is the mascot's overhang reservation, the
geometry-tied-to-what-it-overlaps category the counter already exempts for
inset offsets. hoverNoActiveFiles 20 -> 21 arrives with dev
(UnsupportedBrowserModal/useCopyLinkActions.ts, added in the variant
collapse); 21 is still under dev's own baseline of 22.

Gates: prettier clean, tsc clean, 719/719 jest suites pass, ds-lint ratchet
ok. Checked /careers and /en/content at 375px — the CTA still reads as the
white outlined button it did under 'stroke', and the tab track keeps its
weld, its 1px gutter and its single scroll axis.
@kushagrasarathe kushagrasarathe changed the title chore(ds): finish the button axis rename + drift fixes (secondary/ghost, attention, input size, press gate) chore(ds): finish the button axis rename + drift fixes (secondary/ghost, attention, input size, press gate) (TASK-22817) Sep 22, 2026
@notion-workspace

Copy link
Copy Markdown

@kushagrasarathe
kushagrasarathe deleted the chore/ds-drift-fixes branch September 22, 2026 11:23
kushagrasarathe added a commit that referenced this pull request Sep 22, 2026
dev collapsed ButtonVariant to primary | secondary | ghost (#3302): stroke
became secondary, transparent became ghost, and transparent-light,
transparent-dark and primary-soft were deleted with their call sites
migrated. BaseInput's height axis became `size`. This branch recreates real
call sites on every primitive and pattern page, so the merge is not a text
merge: each recreation had to be read against the file it cites.

Three conflicts:

- DocSidebar.tsx — ours. The old sidebar is gone; the file is now a 15-line
  shim over DocNavList, and the mobile drawer it used to hold lives in
  DocNavDrawer, mounted from the layout. dev's side only renamed variants
  inside the body this branch deleted, so nothing was left to port.
- primitives/button/page.tsx — both. Takes dev's three board rows and their
  roles, keeps this branch's usage count beside each one, and re-counts them
  against the merged tree: primary 199 (97 explicit plus 102 that pass no
  variant), secondary 52, ghost 24, over 275 Button call sites with /dev and
  tests excluded. The header said 120+; it says 275. The rows for the three
  deleted variants are gone.
- scripts/ds-lint-baseline.json — dev's, unchanged. No number was
  hand-merged and no metric ends above dev's value.

Recreations reconciled against the file each cites:
PaymentSuccessView, Landing, BridgeTosStep, LockCardModal and the drawer,
modal, toast and divider trigger buttons all read secondary now;
Profile's nav circle and the DS nav drawer read ghost; ProfileEditField and
the nav search read size="sm". The clip-gate comment and the layout comment
name .btn-secondary, which is what globals.css calls it.

One spacing change: the progress-bar recreation paired its label and bar with
a 6px gap copied from the real file. That is one off-scale site the app
already counts once, and a second copy pushed offScaleSpacing past dev's 87.
The showcase uses the on-scale step instead — the quoted code never showed
the wrapper, so nothing it claims changed.

The audit pages are left alone. They are a dated snapshot of the codebase and
dev did not touch them either; rewriting a record of what was true in
September would not make it truer.

Gates: tsc clean, 117 dev/ds tests pass, ds-lint ratchet ok, prettier clean.

This branch was successfully deployed

1 active deployment
Preview — d44fb856 Deployed Sep 22, 2026 by vercel[bot]
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.

1 participant