[FIR-316] Make component tokens overridable from an ancestor - #55
Conversation
ff-panel, ff-banner, ff-toast, ff-input, ff-select, ff-dialog and ff-button each re-declared their own default custom properties on the selector that also consumed them, which always beats a value inherited from an ancestor. Consume every token through var(token, default) instead, keeping semantic variant blocks (color axis, per-type accents) that intentionally provide the final value for that variant.
ff-radio, ff-chip, ff-checkbox, ff-progress, ff-icon-button and ff-bottom-sheet each re-declared their own default custom properties on the selector that also consumed them, which always beats a value inherited from an ancestor. Consume every token through var(token, default) instead, keeping the semantic variant block in ff-progress that intentionally provides the final fill color per type.
…okens ff-loader, ff-card, ff-tooltip, ff-skeleton, ff-link, ff-empty-state, ff-avatar and ff-divider each re-declared their own default custom properties on the selector that also consumed them, which always beats a value inherited from an ancestor. Consume every token through var(token, default) instead, so a wrapping container can retint or resize any of these primitives.
…ancestor Add an architectural spec that scans every component.scss file and fails if a rule both declares and consumes the same --ff-* custom property, which is exactly the pattern that shadows an ancestor's override. Pair it with a behavioural spec that mounts ff-select inside a host declaring --ff-select-min-width and checks the DOM wiring the cascade rides on, documenting why jsdom's lack of CSS custom property support rules out a getComputedStyle-based assertion here.
Explain why the design system never declares a default for its own component tokens (a specified value always beats an inherited one) and show the ff-select min-width override already used by ff-list as the worked example for retinting/resizing a component from a wrapping container.
|
✅ Verdict: APPROVED (reviewer: mgarcia). Base component tokens are now overridable from an ancestor — proven in a real browser, not just structurally — with zero visual regression across 31 catalog routes captured before and after in the same dev config. The spec that scans every stylesheet for the declare-and-consume anti-pattern is a good guardrail against the pattern creeping back. On acceptance criterion 1: 64 declarations remain inside variant modifier blocks, so the criterion is not met literally. Accepted as the correct scope — a variant picks the final value for that variant rather than offering a tunable default, converting it would be a CSS cycle, and variants resolve from the global palette, which is what the parity gate actually needs. The limit is measured and documented in the README rather than left implicit. If FIR-294 shows per-variant context overrides are genuinely needed, that becomes a follow-up with real requirements behind it. CI green on the final head. Merging to develop. |
What
Design-system components no longer declare their base custom-property tokens on their own selector; they consume them with a fallback:
105 of 169 declarations converted across 21 files; 4 files already complied. No default value changed anywhere — every fallback is the literal that used to be declared.
Why
A custom property specified on an element always beats an inherited one, so declaring a component's tokens on its own block made them impossible to tune from a wrapping container. Found in FIR-293:
.ff-data-table__page-size { --ff-select-min-width: 0 }had no effect because.ff-selectre-declared180pxon itself, and the select overflowed its box by 84px onto the pagination controls. Jira: FIR-316This lands before FIR-294 (visual parity gate) on purpose: porting the Flydocs theme will need per-component tuning, not just palette swaps.
Known limit (deliberate, documented)
Variant modifiers keep their declarations (
.ff-panel--warning { --ff-panel-accent: … }). A variant picks the final value for that variant rather than offering a tunable default, and converting it would be a CSS cycle (--x: var(--x, …)). Measured in a browser:--ff-panel-accenton a warning panel is not overridable from an ancestor. Variants are retinted through the palette they resolve from. The README states this explicitly.How to verify
pnpm nx run-many -t build lint test -p design-system design-system-contract playground— design-system 608 ✓ · contract 13 ✓ · playground 2 ✓ · lint 0 errors.#fff→rgb(12,34,56), button radius8px→2px, select min-width180px→420px, all viagetComputedStyle.