Skip to content

feat(theme): accept a [light, dark] tuple for defineTheme color.accent (#2279) - #4592

Open
jiunshinn wants to merge 1 commit into
facebook:mainfrom
jiunshinn:feat/2279-tuple-accent
Open

feat(theme): accept a [light, dark] tuple for defineTheme color.accent (#2279)#4592
jiunshinn wants to merge 1 commit into
facebook:mainfrom
jiunshinn:feat/2279-tuple-accent

Conversation

@jiunshinn

Copy link
Copy Markdown
Contributor

Fixes #2279

Issue item 1 (make accent optional for neutral-only configs) already landed in #3916. This PR resolves the remaining items 2, 3 and 4.

Item 2: accent accepts a [light, dark] tuple

ColorScaleConfig.accent is now string | [light: string, dark: string], matching the TokenValue shape the rest of the token system uses:

defineTheme({
  name: 'my-theme',
  color: { accent: ['#0064E0', '#48CAE4'] },
});

Item 3: per-scheme palette derivation

With a tuple, expandColorScale builds two sets of tonal palettes: the light half of every generated light-dark() pair derives from the light seed's palettes (primary, neutral, neutral-variant), and the dark half from the dark seed's. So --color-accent, --color-on-accent and the hue-tinted neutrals each follow their scheme's own seed, instead of the tokens['--color-accent'] workaround that skips scale generation entirely.

A plain string accent normalizes to a same-seed pair whose dark palettes alias the light ones, so single-seed configs produce byte-identical output to the previous implementation. A test pins this equivalence (expandColorScale({accent: X}) deep-equals expandColorScale({accent: [X, X]})), and another pins that each tuple half resolves identically to the matching single-accent expansion per mode.

Item 4: precedence between color and tokens for accent-derived values

Documented in the DefineThemeInput.color JSDoc and the CLI theme docs (astryx docs theme, including the dense and zh variants), and pinned by tests:

  • Explicit tokens entries win over color-generated values, token by token.
  • --color-accent-muted, --color-text-accent and --color-icon-accent are generated as var(--color-accent) references, so a tokens['--color-accent'] override re-points them at runtime.
  • --color-on-accent does NOT follow: it is baked from the color.accent seed (a contrast computation CSS cannot express). Overriding the accent via tokens without also overriding --color-on-accent leaves the two out of sync; the docs now say to prefer a tuple color.accent, which item 3 makes possible.

The tests fix the current behavior rather than change it. If maintainers would rather have tokens['--color-accent'] re-derive --color-on-accent, that is a behavior change I kept out of scope here (see open questions).

Scope note (Color Studio)

Per ernestt's comment on the issue, @rubyycheung is exploring an expansion of the color scale config (grey tone and saturation controls) via Color Studio. This PR is intentionally scoped narrowly to tuple accents + per-scheme derivation + precedence documentation so it does not preempt that work: the per-scheme seed split composes with additional palette controls (they would apply to both seeds the way neutralStyle/contrast already do).

Related open PR: #4354 (WCAG contrast assertions for generated token pairs) also touches expandColorScale.ts/.test.ts. The changes are orthogonal (this PR does not alter any single-seed output), but whichever lands second will need a small rebase. If #4354's assertions land first, tuple configs give them two seeds to check per pair, which the per-scheme split here already models.

Open questions

  1. With a tuple, the neutral palettes also split per scheme (dark neutrals take the dark seed's hue tint). I read issue item 3's "derive light palette from the light accent and dark palette from the dark accent" as covering the full derived palette, and it degenerates to the old behavior for a single seed. If the intent was accent tokens only (neutrals from the light seed), that is a small change to the NL/ND wiring.
  2. Should tokens['--color-accent'] re-derive --color-on-accent when a color config is present? Left as documented divergence to avoid changing existing themes.

Testing

  • pnpm exec vitest run packages/core/src/theme (555 passed, includes new tuple + precedence tests)
  • pnpm exec vitest run packages/cli (2171 passed, doc structure)
  • pnpm -F @astryxdesign/core typecheck, pnpm -F @astryxdesign/core lint (0 errors)
  • pnpm -F "@astryxdesign/theme-*" build (all 7 theme packages build clean)
  • node scripts/check-changesets.mjs passes; changeset is [feat] patch per pre-1.0 policy

@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
astryx Ready Ready Preview Aug 1, 2026 12:44pm

Request Review

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Jul 31, 2026
@github-actions github-actions Bot added community Authored by a community contributor (not on the eng/design team) needs:code-review High-risk change (new package/component/API) — needs human code review before merge labels Jul 31, 2026
@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

🧪 Sandbox Preview

View Sandbox for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

No new or modified components detected.

Bundle Size Summary

Package Size (ESM) Size (CJS) Gzipped
@astryxdesign/core N/A 4.9KB 1.3KB

Accessibility Audit

Status: No accessibility violations detected.


Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

github-actions Bot added a commit that referenced this pull request Jul 31, 2026
@jiunshinn
jiunshinn marked this pull request as ready for review July 31, 2026 11:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot. community Authored by a community contributor (not on the eng/design team) needs:code-review High-risk change (new package/component/API) — needs human code review before merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

defineTheme color config: accent required for neutral-only, lacks light/dark support

1 participant