one-design-system
v0.1.4
Published
One Design System — token-driven, theme-aware React component library
Readme
One Design System
A production-ready, token-driven React + TypeScript component library. Tokens are the single source of truth. Themes are applied via CSS variable overrides — zero component-level logic.
Architecture Overview
JSON Tokens → Transform Script → CSS Variables → Components
↓ ↓ ↓ ↓
W3C spec TypeScript types :root / [data-theme] CSS ModulesToken layers
| Layer | File | Purpose |
| -------------------- | ----------------------------------- | ---------------------------------------------------------- |
| Primitive | tokens/primitive.tokens.json | Raw values — colours, spacing, radii, shadows |
| Semantic (light) | tokens/semantic.light.tokens.json | Contextual meaning — color-brand-primary, elevation-md |
| Semantic (dark) | tokens/semantic.dark.tokens.json | Dark theme overrides only — references same primitives |
| Generated CSS | styles/tokens.css | Output of transform script — consumed by browser |
Where TypeScript enforces safety
SemanticToken— union type of every valid token key; used bytoken()utility so invalid token names are caught at compile time- Inferred JSON types —
typeof primitiveTokensJsongives exact literal types for all token values - Strict component props —
ButtonVariant,AlertVariant, etc. are string literal unions derived from the token system tokenVar<T>— generic utility returnsvar(--ds-${T})typed asTokenVar<T>for use in inline styles
Getting Started
1. Install
npm install2. Build tokens
npm run tokens:buildThis runs scripts/transform-tokens.ts which:
- Flattens primitive tokens into a lookup map
- Resolves all
{reference}values in semantic tokens - Outputs
styles/tokens.cssandstyles/themes/dark.css - Generates
tokens/types/token-vars.generated.tswith typed constants
3. Validate tokens
npm run tokens:validateUses Zod to validate all token JSON files against the W3C spec shape.
4. Storybook
npm run storybookStorybook runs on http://localhost:6006. Use the Theme toolbar toggle to switch between light and dark.
5. Tests
npm run test # run all tests
npm run test:coverage # with coverage report
npm run test:watch # watch mode6. Typecheck
npm run typecheckProject Structure
one-design-system/
├── tokens/
│ ├── primitive.tokens.json # Raw values (W3C spec)
│ ├── semantic.light.tokens.json # Semantic tokens — light theme
│ ├── semantic.dark.tokens.json # Semantic overrides — dark theme
│ └── types/
│ ├── tokens.types.ts # TypeScript type system
│ └── token-vars.generated.ts # AUTO-GENERATED — do not edit
│
├── scripts/
│ ├── transform-tokens.ts # JSON → CSS variables transform
│ └── validate-tokens.ts # Zod schema validation
│
├── styles/
│ ├── tokens.css # Generated CSS variables (light + primitives)
│ ├── themes/
│ │ └── dark.css # Generated dark theme overrides
│ └── global.css # Reset + base styles
│
├── components/
│ ├── index.ts # Barrel export
│ ├── Button/
│ ├── Input/
│ ├── Select/
│ ├── Typography/
│ ├── Card/
│ ├── Alert/
│ ├── Stack/
│ └── Icon/
│
├── hooks/
│ └── useTheme.tsx # ThemeProvider + useTheme()
│
├── utils/
│ └── token.utils.ts # token(), tokenStyle(), cx()
│
├── tests/
│ ├── setup.ts # Vitest + jest-dom setup
│ ├── Button.test.tsx
│ ├── Input.test.tsx
│ └── token.utils.test.ts
│
├── storybook/
│ └── stories/
│ └── TokenReference.stories.tsx
│
├── .storybook/
│ ├── main.ts
│ └── preview.tsx
│
├── vite.config.ts
├── vitest.config.ts
├── tsconfig.json
└── package.jsonConsuming Tokens in Components
In CSS Modules (preferred)
/* MyComponent.module.css */
.button {
background-color: var(--ds-color-brand-primary);
padding: var(--ds-spacing-component-md);
border-radius: var(--ds-borderRadius-button);
transition: background-color var(--ds-transition-fast);
}In TypeScript (type-safe inline styles)
import { token } from '../utils/token.utils';
// Type-safe — invalid token names are a compile error
const style = {
color: token('color-text-default'),
background: token('color-surface-raised'),
};Using the tokenStyle() helper
import { tokenStyle } from '../utils/token.utils';
const style = tokenStyle({
backgroundColor: 'color-brand-primaryMuted',
borderColor: 'color-brand-primaryBorder',
});Theming
Themes work by applying a data-theme attribute to <html>. No component code changes.
// Wrap your app
import { ThemeProvider } from './hooks/useTheme';
<ThemeProvider>
<App />
</ThemeProvider>;
// Inside any component
import { useTheme } from './hooks/useTheme';
function ThemeToggle() {
const { theme, toggleTheme } = useTheme();
return <button onClick={toggleTheme}>{theme}</button>;
}The ThemeProvider:
- Reads
localStorageon mount (persists preference) - Falls back to
prefers-color-schememedia query - Applies
data-theme="light"ordata-theme="dark"to<html>
Adding a New Token
- Add the value to
tokens/primitive.tokens.json - Add a semantic reference to
tokens/semantic.light.tokens.json(and override insemantic.dark.tokens.jsonif it needs a dark value) - Add the key to the relevant union type in
tokens/types/tokens.types.ts - Run
npm run tokens:buildto regenerate CSS and typed constants
Adding a New Component
Use the generator script to scaffold all required files automatically:
npm run generate:component -- MyComponentThis creates the following files in one step:
components/MyComponent/MyComponent.tsx— component withvariantprop andcx()classnamescomponents/MyComponent/MyComponent.module.css— CSS Module using only design tokenscomponents/MyComponent/MyComponent.stories.tsx— Storybook stories withDefaultandOutlinedvariants
It also appends the barrel export to components/index.ts automatically.
The component name must be PascalCase (e.g. MyComponent, not my-component). Edit the generated files to implement your component's full API.
Token Naming Convention
[category]-[subcategory]-[variant]-[state]
Examples:
color-brand-primary
color-brand-primaryHover
color-status-errorText
spacing-component-md
elevation-lg
transition-fast
borderRadius-buttonCSS variable prefix: --ds- (design system)
Scripts Reference
| Script | Description |
| ------------------------- | ---------------------------- |
| npm run dev | Vite dev server |
| npm run build | Production build |
| npm run tokens:validate | Validate token JSON with Zod |
| npm run tokens:build | Transform tokens → CSS + TS |
| npm run storybook | Storybook dev server |
| npm run build-storybook | Build Storybook static site |
| npm run test | Run all tests |
| npm run test:coverage | Tests with coverage report |
| npm run typecheck | TypeScript type checking |
| npm run generate:component | Scaffold a new component with all files|
| npm run lint | ESLint |
| npm run format | Prettier |
