@maholan/tokens
v0.2.1
Published
Design tokens for the MHL Untitled UI Platform. This package implements a comprehensive 4-tier token architecture that bridges Figma design files with production code.
Readme
@maholan/tokens
Design tokens for the MHL Untitled UI Platform. This package implements a comprehensive 4-tier token architecture that bridges Figma design files with production code.
Architecture
The token system follows a hierarchical 4-tier architecture:
┌─────────────────────────────────────────────────┐
│ TIER 1 — Primitives │
│ Raw values from Figma Foundation.json │
│ Examples: brand-600, gray-light-300, scale-8 │
└──────────────────────┬──────────────────────────┘
│ composed into
┌──────────────────────▼──────────────────────────┐
│ TIER 2 — Theme Variants │
│ Selectable at install-time via CLI │
│ Dimensions: brand, gray, radius │
└──────────────────────┬──────────────────────────┘
│ mapped to
┌──────────────────────▼──────────────────────────┐
│ TIER 3 — Semantic Tokens │
│ What components consume (mode-aware: L/D) │
│ Examples: bg-primary, text-secondary, border-* │
└──────────────────────┬──────────────────────────┘
│ specialized into
┌──────────────────────▼──────────────────────────┐
│ TIER 4 — Component Tokens │
│ Scoped to specific components │
│ Examples: button-bg-primary, input-border │
└─────────────────────────────────────────────────┘Installation
Interactive CLI Installation (Recommended)
The recommended way to use MHL tokens is through the interactive CLI:
# Initialize your project with theme selection
npx @maholan/cli initThe CLI will guide you through:
- Brand color selection - Choose from 10 color palettes
- Gray base selection - Pick your preferred neutral gray
- Radius style selection - Define corner rounding preferences
- Path configuration - Set component and utility paths
- Preview & confirm - Review before installation
See the CLI flow example for a full walkthrough.
Package Installation
For direct package usage (without CLI):
npm install @maholan/tokens
yarn add @maholan/tokens
pnpm add @maholan/tokensImporting the Token CSS
After installing the package, import the CSS variables into your global CSS
file. Tailwind v4 resolves CSS imports using the "style" export condition,
which is correctly declared in the package exports:
/* globals.css */
@import "tailwindcss";
/* Option A — full path (matches what cli init injects) */
@import "@maholan/tokens/mhl-tokens.css";
/* Option B — shorter alias */
@import "@maholan/tokens/css";This imports the complete @theme { … } block and dark-mode overrides generated
from Foundation.json. All Tailwind classes like bg-brand-600,
text-gray-700, shadow-xs resolve to these CSS custom properties.
CLI Experience
The CLI provides an interactive, guided experience similar to shadcn/ui:
npx @maholan/cli init
# Interactive prompts:
? Which brand color would you like to use?
› purple (default)
? Which gray base would you like to use?
› neutral (default)
? Which radius style would you like to use?
› base (default)
# Preview theme before installation
Your selected theme:
Brand Color: purple
Gray Base: neutral
Radius Style: base
? Ready to install? (Y/n)Try the demo:
pnpm --filter @maholan/tokens example:cliUsage
Accessing Primitives
import { brandColors, grayLightColors, scale } from "@maholan/tokens";
// Direct primitive access
const brandPrimary = brandColors[600]; // { hex: '#7f56d9', hsl: '259 56% 59%' }
const spacing = scale[8]; // '8px'Using Theme Variants
import { brandThemes, grayThemes, radiusThemes } from "@maholan/tokens";
// Get theme by name
const purpleBrand = brandThemes.purple;
const neutralGray = grayThemes.neutral;
const baseRadius = radiusThemes.base;
// Access specific values
const brandAccent = purpleBrand[600].hsl; // '259 56% 59%'
const textColor = neutralGray[900].hsl; // '23 6% 9%'
const buttonRadius = baseRadius.field.md; // '8px'Building Semantic Tokens
import { buildSemanticColors, brandThemes, grayThemes } from "@maholan/tokens";
// Select themes
const brand = brandThemes.teal;
const gray = grayThemes.steel;
// Build semantic tokens
const semanticColors = buildSemanticColors(brand, gray);
// Use in light mode
const lightBg = semanticColors.light["bg-primary"]; // Uses white
const lightText = semanticColors.light["text-primary"]; // Uses steel-900
// Use in dark mode
const darkBg = semanticColors.dark["bg-primary"]; // Uses gray-dark-950
const darkText = semanticColors.dark["text-primary"]; // Uses gray-dark-50Utility Functions
import { hexToHsl, pxToRem, formatCssVar } from "@maholan/tokens";
// Convert hex to HSL
const hsl = hexToHsl("#7f56d9"); // '259 56% 59%'
// Convert px to rem
const rem = pxToRem(16); // '1rem'
// Format CSS variable name
const cssVar = formatCssVar("brand-600"); // '--brand-600'Theme Dimensions
Brand Colors
10 brand color options:
purple(default) - MHL defaultblue- Professional, corporatecerulean- Fresh, modernteal- Calm, balancedindigo- Deep, sophisticatedfuchsia- Bold, vibrantpink- Playful, energeticmagenta- Creative, artisticorange- Warm, friendlyrose- Elegant, refined
Gray Bases
6 gray base options:
neutral(default) - Warm gray for light modesteel- Cool gray (always used for dark mode surfaces)slate- Blue-tinted grayzinc- True neutralstone- Warm brown-graygray- Balanced gray
Radius Styles
5 radius style options:
base(default) - Balanced 8px roundingsharp- No rounding (brutalist)square- Subtle 4px roundinground- Generous 16px roundingcircular- Pill-shaped fields
Light/Dark Mode
Semantic tokens automatically handle light/dark mode:
import { buildSemanticColors, brandThemes, grayThemes } from "@maholan/tokens";
const colors = buildSemanticColors(brandThemes.purple, grayThemes.neutral);
// Light mode uses selected gray variant
colors.light["bg-primary"]; // white
colors.light["text-primary"]; // neutral-900
// Dark mode ALWAYS uses gray-dark (steel) for surfaces
colors.dark["bg-primary"]; // gray-dark-950
colors.dark["text-primary"]; // gray-dark-50Important: Dark mode surfaces always use the cool gray-dark (steel)
palette regardless of the selected gray variant, ensuring consistent contrast
across all brand color choices.
Type Safety
All tokens are fully typed:
import type {
ColorValue,
ColorScale,
BrandThemeName,
GrayThemeName,
RadiusThemeName,
SpacingToken,
} from "@maholan/tokens";
// ColorValue has both hex and HSL
const color: ColorValue = {
hex: "#7f56d9",
hsl: "259 56% 59%",
};
// Theme names are strictly typed
const brand: BrandThemeName = "purple"; // ✅
const brand2: BrandThemeName = "green"; // ❌ Type errorComponent Integration
Components never reference primitives directly. They use semantic tokens:
// ✅ Correct - uses semantic token
className = "bg-brand-solid text-white";
// ❌ Wrong - hard-coded primitive
className = "bg-[#7f56d9] text-white";Figma Sync
This package is generated from Figma design files:
- Foundation.json → Tier 1 Primitives
- Master.json → Tier 3 Semantic Tokens
To regenerate tokens from updated Figma files, see the Token Architecture documentation.
Package Structure
@maholan/tokens
├── src/
│ ├── primitives/ # Tier 1: Raw values
│ │ ├── colors.ts
│ │ ├── secondary-colors.ts
│ │ ├── scale.ts
│ │ └── typography.ts
│ │
│ ├── themes/ # Tier 2: Theme variants
│ │ ├── brand/
│ │ ├── gray/
│ │ └── radius/
│ │
│ ├── semantic/ # Tier 3: Semantic tokens
│ │ └── colors.ts
│ │
│ ├── types.ts # All type definitions
│ ├── utils.ts # Helper functions
│ └── index.ts # Main export
│
├── assets/ # Figma JSON exports
│ ├── Foundation.json
│ └── Master.json
│
└── ARCHITECTURE.md # Full architecture documentationRelated Packages
@maholan/theme- ThemeProvider and global CSS@maholan/ui- Component library (consumes these tokens)@maholan/cli- CLI tool for theme installation
Registry System (CLI Integration)
The token package includes a comprehensive registry system that enables the CLI to:
- Resolve theme configurations to actual CSS values
- Track which tokens each component needs
- Inject only necessary tokens (deduplicated)
- Support incremental component additions
CLI Workflow
import {
resolveTheme,
formatCssVars,
getComponentTokens,
resolveComponentTokens,
} from "@maholan/tokens";
// 1. CLI Init: Generate initial CSS
const theme = { brand: "purple", gray: "neutral", radius: "base" };
const css = resolveTheme(theme);
const cssText = formatCssVars(css);
// Write cssText to globals.css
// 2. CLI Add: Inject component tokens
const buttonTokens = resolveComponentTokens("button"); // ['brand-600', 'gray-50', ...]
const newCss = resolveTokens(theme, buttonTokens);
// Append only new tokens to globals.css
// 3. CLI Theme: Update theme
const newTheme = { brand: "teal", gray: "steel", radius: "round" };
const updatedCss = resolveTheme(newTheme);
// Rewrite CSS with new theme valuesRun Registry Example
pnpm --filter @maholan/tokens example:registryLicense
MIT
Documentation
For complete architecture documentation, see ARCHITECTURE.md.
