Skip to content

Introduce primitive color palette; alias duplicated theme tokens#129

Open
theanmolsharma wants to merge 2 commits into
masterfrom
theme-color-palette-primitives
Open

Introduce primitive color palette; alias duplicated theme tokens#129
theanmolsharma wants to merge 2 commits into
masterfrom
theme-color-palette-primitives

Conversation

@theanmolsharma

@theanmolsharma theanmolsharma commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Why

Followup to the token-duplication discussion in #124 (thread).

That thread surfaced a real tension:

  • @notTanveer was right that the same raw hex was being typed into many tokens (#E6E4E4 ×4, #E6E2FA ×6, #754CE8 ×11, …), so a palette change means editing the same value in N places.
  • @chaitika was right that the tokens themselves must stay distinct — several that share a value in light mode intentionally diverge in dark mode, so collapsing them onto one token would break theming.

Reusing an existing semantic token (the proposed fix) would have coupled unrelated components; keeping duplicate literals leaves the maintenance debt. The correct fix is the layer we didn't have yet: primitives + semantic aliases.

What

1. Primitive palette (commit 1). Adds a module-level palette of raw color values, each declared exactly once. Every semantic token in both ShroudDefaultTheme and ShroudDarkTheme now references a palette entry instead of repeating a literal:

const palette = { gray200: '#E6E4E4', violet100: '#E6E2FA', /* … */ };

// light                          // dark
divider: palette.gray200,         // (inherits light)
transactionCardBorder: palette.gray200,   transactionCardBorder: palette.gray850,
  • Single source of truth for each raw value (Tanveer's concern).
  • Semantic tokens stay distinct and independently themeable per light/dark (Chaitika's concern) — e.g. divider and transactionCardBorder share gray200 in light, yet the card border still diverges to gray850 in dark.
  • Palette names describe hue + lightness (gray200, violet600), deliberately not tied to any component — as suggested in the thread.
  • Only duplicated values are palettized; genuinely unique one-offs (e.g. incomingIconBackground: '#E7E6F5') stay inline.

2. Remove dead tokens (commit 2). Drops 16 color tokens with zero consumers anywhere in the app, plus the now-orphaned blue300 primitive:

borderWidth, borderTopColor, buttonBlueBackgroundColor, outgoingBackgroundColor, failedColor, hdbackgroundColor, lnborderColor, lnbackgroundColor, modalButton, feeActive, cta2, outputValue, msSuccessBG, msSuccessCheck, newBlue, secondary

Verified dead: no colors.<token> access, no destructuring of individual tokens, no dynamic colors[...] access. React Navigation reserved keys (primary/background/…) are retained.

Guarantees

No rendered color changes. Every remaining token resolves byte-identically to its value on master (verified programmatically across both themes).

  • tsc — no new errors. The removal pass is itself a safety net: had any of the 16 tokens been consumed, tsc would now fail with "Property does not exist on type Theme". It passes. (Also dropped as const on the palette so token types stay string, preserving the Theme type and the light/dark divergence.)
  • eslint components/themes.ts — clean.

Not in scope

Single-use literals were left inline, and token renaming (making semantic names less component-specific) is a separate change, as noted in the thread.

🤖 Generated with Claude Code

theanmolsharma and others added 2 commits July 15, 2026 17:07
Introduces a `palette` of raw color values, each declared exactly once,
which the semantic tokens in both ShroudDefaultTheme and ShroudDarkTheme
now reference. Purely structural — every token resolves to the exact same
color as before (verified across all 128 light + 68 dark tokens); no
rendered color changes.

Addresses the duplication raised in the #124 review: a shared value like
#E6E4E4 (previously typed into 4 tokens) or #E6E2FA (6 tokens) now lives
in one place, so a palette change happens once. Semantic tokens stay
distinct and independently themeable per light/dark — e.g. divider and
transactionCardBorder both alias palette.gray200 in light, yet
transactionCardBorder still diverges to palette.gray850 in dark. Genuinely
unique one-off values are left inline.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drops 16 color tokens with zero consumers anywhere in the app, from both
ShroudDefaultTheme and ShroudDarkTheme, plus the now-orphaned `blue300`
palette primitive (it was referenced only by two of the removed tokens):

  borderWidth, borderTopColor, buttonBlueBackgroundColor,
  outgoingBackgroundColor, failedColor, hdbackgroundColor, lnborderColor,
  lnbackgroundColor, modalButton, feeActive, cta2, outputValue,
  msSuccessBG, msSuccessCheck, newBlue, secondary

Verified dead: no `colors.<token>` access, no destructuring of individual
tokens from `colors`, and no dynamic `colors[...]` access anywhere. React
Navigation reserved keys (primary/background/…) are retained. `tsc` passes,
confirming no consumer referenced any removed token; the values of all
remaining tokens are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@notTanveer

Copy link
Copy Markdown
Contributor

i dont like this approach. if a color ends up diverging between dark and light mode, we should fix the token itself instead of introducing a separate color palette. otherwise we're just working around the issue and adding more tokens to maintain.

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