Repository navigation
fix(theme): make theme token references resolve (borders, prose colours, focus ring) - #205
Merged
Merged
Conversation
… use
The theme builder used flat dotted keys ('border.default'). Panda emits
those as `--colors-border\.default`, but every reference to them
(`{colors.border.default}`, `token(colors.border.subtle)`) resolves to
`var(--colors-border-default)`, which was never defined. The references
silently computed to nothing:
- the `default`, `subtle`, `emphasis`, `sponsor` and admin border tokens
rendered as no border
- every prose colour on MDX pages (body, headings, links, quotes, rules)
fell back to the inherited colour
- the `bg.*`, `button.*` and `link.*` aliases were empty
- `token(colors.border.subtle)` dividers in the header and modals vanished
Nest the keys so Panda defines the hyphenated names. The two places that
hard-coded the escaped name (body background, hero fade) move to the
hyphenated one.
`colorPalette="brand.primary"` stops type-checking, because a nested
`brand` group no longer yields a `brand.primary` palette. The prop was
always a no-op: it only set `--colors-color-palette`, while the button
recipe reads `colorPalette.solid.bg` and friends, which brand never had,
so those buttons inherited the gray palette from `html`. Removing it
keeps them exactly as they rendered.
New test fails on any colour, border or shadow var the generated CSS
references but never defines, and on any dot-escaped token name.
`0 0 0 3px {colors.interactive.focus}33` meant a hex alpha suffix, but
the reference becomes `var(...)`, and `var(...)33` is a var followed by
a stray number. The whole declaration was invalid, so inputs styled with
`boxShadow: 'focus-ring'` showed no ring. Express the 20% alpha (0x33)
with color-mix instead.
Regenerated with `pnpm vr --update-snapshots=all`, since several of the changes sit under the 2% tolerance and a plain update would skip them. - home: Important Dates rows gain their 2px emphasis top border (+12px) - content page, blog post: prose colours apply, so link-wrapped headings, links, list markers and the blockquote rule take `text.highlight` - sponsors, agenda: sponsor tiles gain their 6px `border.sponsor` gap - talk detail: the dialog's title divider now renders Blog index is unchanged.
JakeGinnivan
added a commit
to dddwa/ddd-core
that referenced
this pull request
Oct 19, 2026
Upstreamed from dddwa/dddperth#205. The theme builder used flat dotted keys ('border.default'). Panda emits those as `--colors-border\.default`, but every reference to them (`{colors.border.default}`, `token(colors.border.subtle)`) resolves to `var(--colors-border-default)`, which was never defined. Those references silently computed to nothing: the border tokens rendered as no border, prose colours fell back to the inherited colour, the `bg.*`/`button.*`/`link.*` aliases were empty, and `token()` dividers vanished. - Nest the keys so Panda defines the hyphenated names; move the two hard-coded escaped references (body background, hero fade) over. - `focus-ring` was `{colors.interactive.focus}33`, which becomes `var(...)33`: an invalid box-shadow, so no ring showed. Use color-mix for the 20% alpha in both stub themes. - Drop `colorPalette="brand.primary|secondary"` from the voting, agenda, my agenda and feedback buttons. It no longer type-checks once `brand` is nested, and it was always a no-op: the button recipe reads `colorPalette.solid.*`, which brand never had, so the buttons inherited gray and still do. - New test fails on any referenced-but-undefined colour, border or shadow var, and on any dot-escaped token name. Stub baselines regenerated with `pnpm vr --update-snapshots=all`: home gains the Important Dates top border, prose links and anchor headings take `text.highlight`, sponsor tiles get their `border.sponsor` frame, and the talk dialog's title divider renders.
JakeGinnivan
added a commit
to dddwa/ddd-core
that referenced
this pull request
Oct 19, 2026
Upstreamed from dddwa/dddperth#205. The theme builder used flat dotted keys ('border.default'). Panda emits those as `--colors-border\.default`, but every reference to them (`{colors.border.default}`, `token(colors.border.subtle)`) resolves to `var(--colors-border-default)`, which was never defined. Those references silently computed to nothing: the border tokens rendered as no border, prose colours fell back to the inherited colour, the `bg.*`/`button.*`/`link.*` aliases were empty, and `token()` dividers vanished. - Nest the keys so Panda defines the hyphenated names; move the two hard-coded escaped references (body background, hero fade) over. - `focus-ring` was `{colors.interactive.focus}33`, which becomes `var(...)33`: an invalid box-shadow, so no ring showed. Use color-mix for the 20% alpha in both stub themes. - Drop `colorPalette="brand.primary|secondary"` from the voting, agenda, my agenda and feedback buttons. It no longer type-checks once `brand` is nested, and it was always a no-op: the button recipe reads `colorPalette.solid.*`, which brand never had, so the buttons inherited gray and still do. - New test fails on any referenced-but-undefined colour, border or shadow var, and on any dot-escaped token name. Stub baselines regenerated with `pnpm vr --update-snapshots=all`: home gains the Important Dates top border, prose links and anchor headings take `text.highlight`, sponsor tiles get their `border.sponsor` frame, and the talk dialog's title divider renders.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was broken
The theme builder used flat dotted keys (
'border.default'). Panda emits those as--colors-border\.default, but every reference to them ({colors.border.default},token(colors.border.subtle)) resolves tovar(--colors-border-default), which was never defined. Those references silently computed to nothing:border="default" | "subtle" | "emphasis", the 6pxsponsorborder and the admin borders rendered as no borderbg.*,button.*andlink.*aliases were emptytoken(colors.border.subtle)dividers in the header and modals vanishedUtility props like
bg="surface.card"kept working, because the class and the definition used the same escaped name. That's why it went unnoticed.Separately,
focus-ringwas0 0 0 3px {colors.interactive.focus}33. Once the reference becomesvar(...), the33is a stray number rather than a hex alpha, so the wholebox-shadowwas invalid and inputs using it showed no ring.The fix
theme-builder.ts(a smallnest()helper) so Panda defines the hyphenated names that references use. The two places that hard-coded the escaped name (body background, hero fade) now use the hyphenated one.color-mix(... 20%, transparent)in all four themes (fork + stub).colorPalette="brand.primary|secondary"from 8 buttons. It stops type-checking oncebrandis nested, and it was always a no-op: it only set--colors-color-palette, while the button recipe readscolorPalette.solid.*, which brand never had. Those buttons inherited gray fromhtmlbefore and still do.app/theme/token-references.test.tsfails on any colour/border/shadow var the generated CSS references but never defines, and on any dot-escaped token name. Verified it fails without the fix.Visible changes
Baselines were regenerated with
pnpm vr --update-snapshots=all, because several changes sit under the 2% tolerance. I reviewed before/after crops of each route:text.highlight(5.6:1 dark, 5.4:1 light, calculated rather than measured with axe)border.sponsorgapThe admin and portal pages also get their card borders back. Those pages aren't in the visual suite.
Worth a look: MDX headings are anchor links, so they now take the link colour instead of white. If we'd rather they stay white, it's a one-line prose override.
Testing
tscclean, 814 unit tests pass,pnpm vr81/81 on the new baselinesCore change, so this needs a
/core-pushafter merge.🤖 Generated with Claude Code