@cdx-ui/styles
v0.0.1-beta.20
Published
Design tokens and theme infrastructure for the Candescent Design System. Tokens flow from Figma Variables through a Style Dictionary pipeline into CSS custom properties, Tailwind v4 theme variables, and runtime theming artifacts — supporting three presets
Readme
@cdx-ui/styles
Design tokens and theme infrastructure for the Candescent Design System. Tokens flow from Figma Variables through a Style Dictionary pipeline into CSS custom properties, Tailwind v4 theme variables, and runtime theming artifacts — supporting three presets (Poise, Prestige, Pulse), light/dark modes, cross-platform fonts, and FI white-label overrides.
Installation
pnpm add @cdx-ui/stylesUsage
CSS imports (Tailwind v4 + Uniwind)
Import theme.css and utilities.css in your global stylesheet, after Tailwind and Uniwind:
@import 'tailwindcss';
@import 'uniwind';
@import '@cdx-ui/styles/theme.css';
@import '@cdx-ui/styles/utilities.css';theme.css declares all token variables — primitives in @theme static, mode-dependent semantics in @variant light/dark, and platform fonts in @variant ios/android/web. utilities.css provides composite typography utilities (heading-xl through body-xs).
Components then use standard Tailwind utilities backed by theme variables:
<View className="bg-surface-background p-4 rounded-lg">
<Text className="text-content-primary heading-md">Welcome</Text>
<Text className="text-content-secondary body-md">Get started below.</Text>
</View>CSS imports (non-Tailwind)
For consumers that do not use Tailwind, vanilla.css provides all variables as plain :root declarations with @media (prefers-color-scheme: dark) and class-based typography:
@import '@cdx-ui/styles/vanilla.css';Preset JSON
All three preset theme objects are importable as JSON for runtime theming:
import poise from '@cdx-ui/styles/presets/poise.json';
import prestige from '@cdx-ui/styles/presets/prestige.json';
import pulse from '@cdx-ui/styles/presets/pulse.json';TypeScript types
The package exports DTCG-compatible type definitions for theme objects, overrides, and related structures:
import type {
ThemeObject,
ThemeOverride,
ThemeMetadata,
ThemeOverrideMetadata,
TokenGroup,
TokenValue,
Mode,
Platform,
} from '@cdx-ui/styles';ThemeMetadata— metadata stored under$extensions.com.candescent.theme(name, preset, schema version).ThemeOverrideMetadata— metadata for FI overrides under$extensions.com.candescent.themeOverride(base preset, FI id/name, schema version).
Token pipeline
The pipeline has two stages — fetch and build — both run from package scripts.
Fetching tokens from Figma
Tokens are pulled from Figma Variables via the REST API (GET /v1/files/:file_key/variables/local). This requires an Enterprise plan and a personal access token with file_variables:read scope.
FIGMA_VARIABLES_TOKEN=your_token pnpm tokens:fetchThe script reads figma.config.json for the file key, preset list, and default FI mode, then assembles one DTCG-compatible theme object JSON per preset:
tokens/presets/
poise.json # Default build preset
prestige.json
pulse.jsonEach file is assembled from four Figma collections: Primitives (shared), FI Primitives (Candescent mode — brand/accent/base colors), Semantics ({Preset}) (Light + Dark modes), and Platform (Web/iOS/Android fonts). Alias references are preserved as DTCG "{path.to.token}" syntax.
Figma MCP alternative
If the Figma MCP server is configured in Cursor, you can inspect variables interactively. Select a frame/layer and ask the agent for variable names and values. This is useful for ad-hoc inspection but does not replace the fetch script for full pipeline runs.
Building tokens
Style Dictionary v4 reads the default preset JSON and produces all output artifacts:
pnpm tokens:buildCSS outputs (written to css/):
| File | Contents |
| --------------- | --------------------------------------------------------------------------------------------------- |
| theme.css | @theme static (primitives + semantic defaults), @variant light/dark, @variant ios/android/web |
| utilities.css | @utility blocks for composite typography (headings, body, labels) |
| vanilla.css | Non-Tailwind fallback — :root variables + @media (prefers-color-scheme: dark) + classes |
Generated artifacts (from the same build pass):
| Artifact | Ships to | Purpose | | ------------------- | ----------------- | ------------------------------------------------------------------ | | Runtime map | Package (JSON) | Theme object path → CSS custom property name for sparse flattening | | Preset patches | Package (JSON) | Sparse diff from build default → each non-default preset | | Validation manifest | API deploy bundle | Allow-listed paths and types for server-side override validation |
Validating font tokens
Font registration names in useCdxFonts must exactly match the --font-* values emitted into theme.css — a mismatch causes silent fallback to platform default fonts with no error. The validation script catches this drift as a build/CI failure:
pnpm fonts:validateIt parses every --font-* declaration from css/theme.css (across @theme static, @variant light/dark, and @variant ios/android/web), reads the font map keys from src/useCdxFonts.ts source, and verifies a matching key exists for every non-system value. System fonts (SF Pro, SF Mono, Roboto, Roboto Mono) are read from figma.config.json and excluded — they are platform built-ins resolved natively by React Native. var() aliases are skipped because they resolve to other variables that are themselves validated.
On success the script prints Font validation: N CSS values checked, N matched, 0 mismatches. and exits 0. On failure it lists each mismatch with its variable name, value, and CSS section, then exits non-zero. The script is wired into .github/workflows/ci.yml as a pre-build step so font-token drift fast-fails before the heavier build/lint/test stages.
Theme architecture
Presets
Three presets ship with the package — Poise (default), Prestige, and Pulse — each a complete theme object with all primitives, semantic tokens (light + dark), platform fonts, and typography composites. Poise is compiled into CSS at build time. Apps using a different preset apply a build-generated sparse patch via Uniwind.updateCSSVariables.
Modes and platforms
Light/dark mode switching is handled by Uniwind @variant light/dark blocks in theme.css. Platform-specific fonts (SF Pro on iOS, Roboto on Android, Inter on web) use @variant ios/android/web blocks. Both are activated automatically by Uniwind at runtime.
FI overrides
Financial institution white-labelling uses sparse JSON overrides — only the token paths that differ from the base preset. Overrides are validated server-side against a generated validation manifest and applied at runtime via the runtime map + Uniwind.updateCSSVariables. See Theme Definition for the full override flow.
Package structure
styles/
├── css/
│ ├── theme.css # Auto-generated — all token variable declarations
│ ├── utilities.css # Auto-generated — composite typography @utility blocks
│ └── vanilla.css # Auto-generated — non-Tailwind fallback
├── scripts/
│ ├── figma-fetch-variables.mjs # Figma Variables REST API fetch
│ ├── build-tokens.mjs # Style Dictionary build + artifact generation
│ └── validate-font-tokens.mjs # CI check: --font-* values match useCdxFonts keys
├── src/
│ ├── index.ts # TypeScript type exports (ThemeObject, ThemeOverride, etc.)
│ └── useCdxFonts.ts # Font loader hook (expo-font) — loads all preset display fonts
├── tokens/
│ └── presets/
│ ├── poise.json # Poise theme object (build default)
│ ├── prestige.json # Prestige theme object
│ └── pulse.json # Pulse theme object
├── figma.config.json # File key, preset list, default preset/FI mode
├── sd.config.ts # Style Dictionary v4 configuration
├── package.json
├── tsconfig.json
└── tsconfig.build.jsoncss/ files are auto-generated — do not edit directly.
Building
pnpm --filter @cdx-ui/styles buildTypeScript sources are compiled by react-native-builder-bob to lib/ with CommonJS, ESM, and declaration targets.
Further reading
- Token Architecture — full pipeline documentation (Figma analysis, theme definition, output architecture, Style Dictionary config, expected CSS output, runtime theming guide)
