The style pipeline & recipes
How token ids inside a style spec become var() strings, and how the data-only recipe layer expresses variants without a runtime.
FDS keeps CSS compilers token-agnostic: authors write bare token ids as values, and a resolution pass rewrites them into var() strings before any CSS is generated. The compiler never learns what a token is.
import { resolveStyleTokens, hasToken } from 'flexa-design-system';
resolveStyleTokens(
{
'.btn': {
background: 'color.primary',
padding: 'space.3 space.6', // multi-value works too
'border-radius': 'c.button.radius',
},
},
hasToken,
);
// → { '.btn': { background: 'var(--fx-color-primary)', … } }Values that aren't token ids (#fff, 1.5rem, url(img.png)) pass through untouched. The gate for typos is separate:
import { findUnknownStyleTokens } from 'flexa-design-system';
findUnknownStyleTokens({ '.x': { color: 'color.primry' } });
// → ['.x.color: color.primry'] — reserved namespace, unknown token → rejectThis is the machine gate that makes the system safe for generated styles: an AI (or a marketplace vendor) can only reference tokens that exist. Off-system ids are rejected at validate time, not discovered in production.
Recipes: variants as data
A recipe is a data-only variant model (think CVA/vanilla-extract, minus the runtime): a base style fragment, per-option variants, optional compound fragments for option combinations, and default selections. A pure function merges the fragments for a node's chosen props into one style spec, which then flows through the same token resolution above.
{
"base": { ".btn": { "border-radius": "c.button.radius" } },
"variants": {
"tone": {
"primary": { ".btn": { "background": "color.primary" } },
"danger": { ".btn": { "background": "color.danger" } }
},
"kind": {
"solid": {},
"outline": { ".btn": { "background": "transparent" } }
}
},
"compound": [{
"when": { "kind": "outline", "tone": "danger" },
"style": { ".btn": { "color": "color.danger" } }
}],
"default": { "tone": "primary", "kind": "solid" }
}The layering model
In Flexa Builder the final CSS for a node is a deterministic cascade of specs, each resolved through the same pipeline: manifest style < recipe < global component styles < per-node overrides. Every layer speaks tokens, so a theme swap restyles all four at once.