@wandelbots/design-tokens
v1.2.3
Published
Wandelbots Nova design tokens (DTCG sources + generated CSS / JS / MUI / Tailwind outputs).
Keywords
Readme
@wandelbots/design-tokens
Single source of truth for Wandelbots Nova design tokens. Generates CSS custom properties, typed JS exports, a MUI theme factory, and a Tailwind preset from DTCG-format token sources.
Token architecture
Token files are generated from data/variables.json (raw Figma export) by scripts/transform-variables.ts. Each Figma variable collection becomes its own <collection>.tokens.json file in DTCG format. The collection names, hierarchy, and aliasing structure are defined in Figma — this repo does not impose a layering convention.
Do not hand-edit files in tokens/. To change token values or structure, update them in Figma and re-export.
All token files use the DTCG format with $value, $type, and $description.
Filtering unused tokens
Tokens with $description: "no use" are excluded from all build outputs (CSS variables, JS exports, Tailwind preset). They remain in the DTCG source files for documentation/completeness but are not shipped to consumers. This keeps the public API surface intentional — only tokens actively used in the design system are exported.
To mark a token as unused, set its description to "no use" in Figma. To re-include it later, change the description to something meaningful.
Build outputs
| Output | Import path | Usage |
| --------------------- | ------------------------------------------ | ---------------------------------- |
| CSS custom properties | @wandelbots/design-tokens/css | @import in global CSS |
| JS/TS constants | @wandelbots/design-tokens | Direct value access in JS/TS |
| MUI theme factory | @wandelbots/design-tokens/mui | createNovaMuiTheme() for MUI 7 |
| Tailwind preset | @wandelbots/design-tokens/tailwind | Add to presets in Tailwind config |
Quick start
# Build all outputs (transform + compile)
pnpm build
# Transform only (raw Figma → DTCG)
pnpm build:tokens
# Compile only (DTCG → dist/)
pnpm build:styles
# Run tests
pnpm testUsage examples
CSS
@import "@wandelbots/design-tokens/css";
.card {
background: var(--wb-color-bg-glass);
border: 1px solid var(--wb-color-border-glass);
border-radius: var(--wb-card-radius);
}MUI
The package ships a hand-authored MUI 7 theme. @mui/material is an optional peer dependency — install it only if you actually use the MUI integration.
import { createNovaMuiTheme } from "@wandelbots/design-tokens/mui"
import { ThemeProvider } from "@mui/material/styles"
const theme = createNovaMuiTheme()
function App() {
return <ThemeProvider theme={theme}>...</ThemeProvider>
}Importing this entry once at the app root also activates the type augmentation, so theme.palette.tertiary.main, theme.paletteExt.primary.hover, and theme.palette.backgroundPaperElevation[8] are all typed.
Package-specific theme extensions (e.g. jogging-panel colors, DataGrid styling slots) belong in the consuming package, not in @wandelbots/design-tokens. Consumers add their own declare module "@mui/material/styles" augmentation — see the architecture rules in AGENTS.md for what stays here vs what lives in wandelbots-js-react-components / formfactors-ui.
Overriding and extending
createNovaMuiTheme is variadic and uses MUI's canonical createTheme(base, ...overrides) for deep-merging. Pass any number of ThemeOptions — each layer is deep-merged on top of the previous one.
// Single override layer
const theme = createNovaMuiTheme({
palette: { primary: { main: "#ff00ff" } },
components: {
MuiDialog: {
styleOverrides: { paper: { borderRadius: 16 } },
},
},
})
// theme.palette.primary.main → "#ff00ff"
// theme.paletteExt.primary.hover → preserved from base
// theme.components.MuiButton.* → preserved (deep-merge, not replace)// Multiple override layers (later wins)
const theme = createNovaMuiTheme(appOverrides, featureOverrides)Building blocks
If you need fine-grained control (e.g. compose a custom theme that uses Nova's palette but your own component overrides), the building blocks are exported alongside the factory:
import {
darkBaseOptions,
commonComponents,
} from "@wandelbots/design-tokens/mui"
import { createTheme } from "@mui/material/styles"
const theme = createTheme(
darkBaseOptions(),
{ components: commonComponents() },
// your overrides (palette tweaks, custom components, etc.)
)darkBaseOptions() returns the canonical Nova ThemeOptions — palette (including backgroundPaperElevation and tertiary), paletteExt, shape.borderRadius, and typography — but no component overrides. commonComponents() returns the shared component overrides; palette-dependent values use MUI's function-form callbacks (({ theme }) => ({...})) so consumer palette overrides propagate automatically.
How propagation actually works.
commonComponents()doesn't call its callbacks — it returns function references. MUI invokes them at component render time, passing the final merged theme from<ThemeProvider>. So the order in which you build the theme doesn't matter: an override likecreateNovaMuiTheme({ palette: { text: { secondary: "#abcdef" } } })reachesMuiTab'scolorvalue even thoughcommonComponents()was already in the layer stack when the override was added. The one exception isMuiCssBaseline.styleOverrides, which is intentionally a static object so consumer global selectors deep-merge instead of replacing Nova's scrollbar rules — it uses a literal divider color rather than reading fromtheme.palette.divider.
Light mode
Light mode is not yet supported — createNovaMuiTheme({ palette: { mode: "light" } }) throws. Light tokens will land when the upstream Figma sync provides them.
What the base theme includes
- Full dark palette (primary, secondary, tertiary, error, warning, success, background, action, common, divider).
paletteExt.primary.{hover,selected,focus,focusVisible,outlineBorder}andpaletteExt.secondary.tonal.palette.backgroundPaperElevation[0..16].- Typography:
'Inter', 'Roboto', 'Helvetica', 'Arial', system-ui, sans-serif,fontWeightRegular: 500. shape.borderRadius: from theRadiusSmtoken.- Component overrides:
MuiCssBaseline(scrollbars),MuiButton,MuiTab,MuiTabs,MuiToggleButtonGroup,MuiToggleButton,MuiSelect(filled variant),MuiDrawer,MuiFab.
Package-specific overrides (e.g. DataGrid, JoggingPanel, MuiAutocomplete, MuiTooltip) are not included — add them as overrides in your consuming package.
Migration from local theme
Replace your local createDarkTheme / createNovaMuiTheme files with the upstream factory and pass any package-specific bits as overrides:
- import { createNovaMuiTheme } from "./themes"
+ import { createNovaMuiTheme } from "@wandelbots/design-tokens/mui"
- const theme = createNovaMuiTheme(opts)
+ const theme = createNovaMuiTheme(opts, {
+ components: {
+ // your DataGrid / JoggingPanel / Autocomplete / Tooltip overrides
+ },
+ })Tailwind
// tailwind.config.js
import novaPreset from "@wandelbots/design-tokens/tailwind"
export default {
presets: [novaPreset],
}Figma sync
Token values come from Figma via the WB Tokens Export plugin (see figma-variables-export/ at the repo root).
- Open the Figma file → run the plugin → click Export Tokens
- The plugin pushes
data/variables.jsonto a PR on GitHub - CI (
.github/workflows/tokens-sync.yml) auto-transforms and validates the PR
To transform locally after updating data/variables.json:
pnpm build:tokens # raw → tokens/*.tokens.json
pnpm build:styles # tokens → dist/CSS variable naming
All CSS custom properties use the --wb- prefix:
--wb-color-bg-default— background color--wb-color-primary-default— primary action color--wb-space-4— 16px spacing unit--wb-radius-lg— 10px border radius
