/** * Token Reference — auto-generated from docs/token-name-mapping.json * * This file imports the JSON directly. It is always current — no manual * editing required. To update the tables, run: * * pnpm figma:export * * then rebuild Storybook. The JSON is regenerated by * scripts/export-figma-tokens.ts as part of that command. */ import type { Meta, StoryObj } from '@storybook/react-vite'; import type { CSSProperties } from 'react'; import tokenMap from '../../../docs/token-name-mapping.json'; // ── Types inferred from the JSON shape ─────────────────────────────────────── interface SemanticEntry { figmaPath: string; pandaToken: string; cssProperty: string; exampleUsage: string; note?: string; } interface SpacingShapeEntry { figmaPath: string; pandaToken: string; pandaCategory: string; cssProperty: string; exampleUsage: string; } interface EffectStyleEntry { figmaEffectStyle: string; pandaToken: string; pandaCategory: string; cssProperty: string; description: string; exampleUsage: string; } interface PandaOnlyEntry { pandaToken: string; cssProperty: string; notes?: string; exampleUsage: string; } interface ShadowAliasEntry { pandaToken: string; cssProperty: string; resolvesTo: string; description?: string; exampleUsage: string; } interface TextStyleEntry { figmaTextStyle: string; figmaDescription: string; ddsTokenPath: string; pandaTextStyle: string; fontFamily: string; fontStyle: string; fontWeight: number; fontSize: number; lineHeightPx: number; letterSpacing: number; isDefaultWeight: boolean; exampleUsage: string; } // ── Shared style helpers ───────────────────────────────────────────────────── const T: Record = { page: { fontFamily: 'Inter, -apple-system, BlinkMacSystemFont, sans-serif', fontSize: '14px', color: '#1a1a1a', maxWidth: '1100px', }, section: { marginBottom: '56px', }, h2: { fontSize: '20px', fontWeight: '600', margin: '0 0 4px', color: '#111', }, meta: { fontSize: '12px', color: '#888', margin: '0 0 20px', fontFamily: 'monospace', }, table: { width: '100%', borderCollapse: 'collapse' as const, fontSize: '13px', }, th: { textAlign: 'left' as const, padding: '8px 12px', background: '#f4f4f4', borderBottom: '2px solid #e0e0e0', fontWeight: '600', fontSize: '12px', color: '#444', whiteSpace: 'nowrap' as const, }, td: { padding: '8px 12px', borderBottom: '1px solid #f0f0f0', verticalAlign: 'middle' as const, }, mono: { fontFamily: 'monospace', fontSize: '12px', background: '#f5f5f5', padding: '2px 5px', borderRadius: '3px', color: '#333', whiteSpace: 'nowrap' as const, display: 'inline-block' as const, }, pill: { display: 'inline-block' as const, fontSize: '10px', fontWeight: '600', padding: '1px 6px', borderRadius: '10px', background: '#e8f0e0', color: '#3a5a18', marginLeft: '6px', verticalAlign: 'middle' as const, }, warning: { display: 'inline-block' as const, fontSize: '10px', fontWeight: '600', padding: '1px 6px', borderRadius: '10px', background: '#fff3cd', color: '#856404', marginLeft: '6px', verticalAlign: 'middle' as const, }, }; function rowBg(i: number): CSSProperties { return { background: i % 2 === 0 ? '#fff' : '#fafafa' }; } // ── Color swatch using CSS custom property directly ────────────────────────── // We use the cssProperty value from the JSON (e.g. --colors-surface-container) // to render a live swatch via inline style. This bypasses Panda's static // extraction requirement and works with any token at runtime. function Swatch({ cssVar, size = 32 }: { cssVar: string; size?: number }) { return (
{/* Light swatch */}
{/* Dark swatch — forced via data-theme attribute */}
); } function SpacingSwatch({ cssVar, category, }: { cssVar: string; category: string; }) { if (category !== 'spacing') { // For radii — show a box with the corner radius applied return (
); } // For spacing — show a bar whose width is the spacing value return (
); } function ShadowSwatch({ cssVar }: { cssVar: string }) { return (
); } function TypeSwatch({ fontFamily, fontWeight, fontSize, }: { fontFamily: string; fontWeight: number; fontSize: number; }) { // Clamp display size so table rows don't get too tall const displaySize = Math.min(fontSize, 22); return ( Aa ); } // ── Storybook meta ──────────────────────────────────────────────────────────── const meta = { title: 'Foundations/Token Reference', parameters: { layout: 'padded' }, } satisfies Meta; export default meta; type Story = StoryObj; // ── Story 1: Semantic Colors ───────────────────────────────────────────────── export const SemanticColors: Story = { name: '1 · Semantic Colors', render: () => { const entries = tokenMap.semantic as SemanticEntry[]; const pandaOnly = (tokenMap.semanticPandaOnly ?? []) as PandaOnlyEntry[]; // Mismatches flagged in token-name-mapping.md const mismatches = new Set([ 'surfaceVariant', 'inverseSurface', 'inverseOnSurface', 'inversePrimary', ]); return (

Semantic Colors

{entries.length} entries · source: Figma "Semantic" collection · auto-generated from docs/token-name-mapping.json v {tokenMap.version}

{entries.map((e, i) => ( ))}
Swatch (L / D) Figma Variable Path Panda CSS Token CSS Custom Property Code Usage
{e.figmaPath} {e.pandaToken} {mismatches.has(e.pandaToken) && ( ⚠ flat )} {e.cssProperty} {e.exampleUsage}
{pandaOnly.length > 0 && ( <>

Panda-only tokens (no Figma variable)

{pandaOnly.map((e, i) => ( ))}
Swatch (L / D) Panda CSS Token CSS Custom Property Code Usage Notes
{e.pandaToken} {e.cssProperty} {e.exampleUsage} {e.notes ?? '—'}
)}
⚠ Mismatch tokens — five tokens do NOT follow dot-notation despite slash-path Figma naming:{' '} surfaceVariant, inverseSurface,{' '} inverseOnSurface, inversePrimary,{' '} inverseSecondary, inverseTertiary. Use the Panda CSS token column exactly — never derive it from the Figma path by replacing / with ..
); }, }; // ── Story 2: Spacing & Shape ───────────────────────────────────────────────── export const SpacingAndShape: Story = { name: '2 · Spacing & Shape', render: () => { const entries = tokenMap.spacingAndShape as SpacingShapeEntry[]; const categories = ['spacing', 'radii', 'borderWidths', 'durations']; return (
{categories.map((cat) => { const rows = entries.filter((e) => e.pandaCategory === cat); if (rows.length === 0) return null; const catLabel: Record = { spacing: 'Spacing', radii: 'Border Radii (M3 base tokens)', borderWidths: 'Border Widths', durations: 'Motion Durations', }; return (

{catLabel[cat] ?? cat}

{rows.length} entries · Figma "Spacing & Shape" collection · v{tokenMap.version}

{cat === 'spacing' || cat === 'radii' ? ( ) : null} {rows.map((e, i) => ( {cat === 'spacing' || cat === 'radii' ? ( ) : null} ))}
VisualFigma Variable Path Panda CSS Token CSS Custom Property Code Usage
{e.figmaPath} {e.pandaToken} {cat === 'radii' && ( base )} {e.cssProperty} {e.exampleUsage}
{cat === 'radii' && (
Use DDS canonical radii in component code — not these M3 base tokens. l1 = 2px (checkboxes, breadcrumbs) · l2 = 6px (buttons, inputs, badges) · l3 = 8px (cards, dialogs, popovers) ·{' '} full = 9999px (avatars, pills, switches)
)}
); })}
); }, }; // ── Story 3: Elevation & Shadows ───────────────────────────────────────────── export const ElevationAndShadows: Story = { name: '3 · Elevation & Shadows', render: () => { const baseLevels = tokenMap.effectStyles as EffectStyleEntry[]; const aliases = (tokenMap.shadowSemanticAliases ?? []) as ShadowAliasEntry[]; return (

Base Elevation Levels (M3)

{baseLevels.length} levels · Figma effect styles · v {tokenMap.version}

{baseLevels.map((e, i) => ( ))}
Visual Figma Effect Style Panda Base Token CSS Custom Property Description Code Usage
{e.figmaEffectStyle} {e.pandaToken} base {e.cssProperty} {e.description} {e.exampleUsage}
Do not use base level tokens in component code. Use the semantic aliases below (xs/sm/md/lg/xl).
{aliases.length > 0 && (

Semantic Shadow Aliases

{aliases.length} aliases · src/preset/shadows.ts · use these in components and recipes

{aliases.map((e, i) => ( ))}
Visual Panda Token CSS Custom Property Resolves To Description Code Usage
{e.pandaToken} {e.cssProperty} {e.resolvesTo} {e.description ?? '—'} {e.exampleUsage}
)}
); }, }; // ── Story 4: Typography ─────────────────────────────────────────────────────── export const Typography: Story = { name: '4 · Typography', render: () => { const entries = tokenMap.textStyles as TextStyleEntry[]; // Group by pandaTextStyle (scale step) const groups = entries.reduce>( (acc, e) => { if (!acc[e.pandaTextStyle]) acc[e.pandaTextStyle] = []; acc[e.pandaTextStyle].push(e); return acc; }, {}, ); const categoryOrder = [ 'displayLarge', 'displayMedium', 'displaySmall', 'headlineLarge', 'headlineMedium', 'headlineSmall', 'titleLarge', 'titleMedium', 'titleSmall', 'bodyLarge', 'bodyMedium', 'bodySmall', 'labelLarge', 'labelMedium', 'labelSmall', ]; const categoryLabel: Record = { displayLarge: 'Display', headlineLarge: 'Headline', titleLarge: 'Title', bodyLarge: 'Body', labelLarge: 'Label', }; let rowIndex = 0; return (

Typography — All Weight Variants

{entries.length} entries ({categoryOrder.length} scale steps × weight variants) · auto-generated from docs/token-name-mapping.json v {tokenMap.version}

{categoryOrder.flatMap((step) => { const rows = groups[step] ?? []; return rows.map((e) => { const i = rowIndex++; const isDefault = e.isDefaultWeight; return ( ); }); })}
Preview Figma Text Style DDS Token Path Panda textStyle Font / Weight Size / LH Code Usage
{e.figmaTextStyle} {/* Section label at first row of each category */} {categoryLabel[step] && rows.indexOf(e) === 0 && ( ── {categoryLabel[step]} )} {e.ddsTokenPath} {e.pandaTextStyle} {isDefault && ( default )} {e.fontFamily.split(',')[0].replace(/"/g, '')} {e.fontStyle} ({e.fontWeight}) {e.fontSize}px / {e.lineHeightPx}px {e.letterSpacing !== 0 && ( {' '} ls:{e.letterSpacing} )} {e.exampleUsage} {!isDefault && ( + fontWeight="{e.fontStyle.toLowerCase()}" )}
How to read this table: The Panda textStyle{' '} sets geometry (size, line-height, letter-spacing, font-family). The default weight variant is applied automatically. To use a non-default weight, add fontWeight separately.
Example:{' '} <Text textStyle="headlineSmall" fontWeight="semibold">
The DDS Token Path is what the Figma text style description field encodes ( dds:typography.scale.headlineSmall.weights.semiBold) — the most direct resolution path from MCP output.
); }, }; // ── Story 5: Full Reference (all sections on one page) ─────────────────────── export const FullReference: Story = { name: '5 · Full Reference', render: () => (
Token Reference — v{tokenMap.version}
Generated:{' '} {tokenMap.generatedAt ? new Date(tokenMap.generatedAt).toLocaleString() : 'unknown'}
Sources:{' '} {(tokenMap.generatedFrom as string[]).map((f, i) => ( {f} {i < tokenMap.generatedFrom.length - 1 ? ' · ' : ''} ))}
To update: run pnpm figma:export then rebuild Storybook.
{/* Render all four sections inline */} {SemanticColors.render && SemanticColors.render({} as never, {} as never)} {SpacingAndShape.render && SpacingAndShape.render({} as never, {} as never)} {ElevationAndShadows.render && ElevationAndShadows.render({} as never, {} as never)} {Typography.render && Typography.render({} as never, {} as never)}
), };