Migrated from design-system-swarm with fresh git history.
Old project history preserved in /home/overbits/apps/design-system-swarm
Core components:
- MCP Server (Python FastAPI with mcp 1.23.1)
- Claude Plugin (agents, commands, skills, strategies, hooks, core)
- DSS Backend (dss-mvp1 - token translation, Figma sync)
- Admin UI (Node.js/React)
- Server (Node.js/Express)
- Storybook integration (dss-mvp1/.storybook)
Self-contained configuration:
- All paths relative or use DSS_BASE_PATH=/home/overbits/dss
- PYTHONPATH configured for dss-mvp1 and dss-claude-plugin
- .env file with all configuration
- Claude plugin uses ${CLAUDE_PLUGIN_ROOT} for portability
Migration completed: $(date)
🤖 Clean migration with full functionality preserved
473 lines
14 KiB
JavaScript
473 lines
14 KiB
JavaScript
/**
|
||
* Component Definitions - Metadata for all design system components
|
||
*
|
||
* This file defines the complete metadata for each component including:
|
||
* - State combinations and variants
|
||
* - Token dependencies
|
||
* - Accessibility requirements
|
||
* - Test case counts
|
||
*
|
||
* Used by VariantGenerator to auto-generate CSS and validate 123 component states
|
||
*/
|
||
|
||
export const componentDefinitions = {
|
||
components: {
|
||
'ds-button': {
|
||
name: 'Button',
|
||
group: 'interactive',
|
||
cssClass: '.ds-btn',
|
||
description: 'Primary interactive button component',
|
||
states: ['default', 'hover', 'active', 'disabled', 'loading', 'focus'],
|
||
variants: {
|
||
variant: ['primary', 'secondary', 'outline', 'ghost', 'destructive', 'success', 'link'],
|
||
size: ['sm', 'default', 'lg', 'icon', 'icon-sm', 'icon-lg']
|
||
},
|
||
variantCombinations: 42, // 7 variants × 6 sizes
|
||
stateCount: 6,
|
||
totalStates: 252, // 42 × 6
|
||
tokens: {
|
||
color: ['--primary', '--secondary', '--destructive', '--success', '--foreground'],
|
||
spacing: ['--space-3', '--space-4', '--space-6'],
|
||
typography: ['--text-xs', '--text-sm', '--text-base'],
|
||
radius: ['--radius'],
|
||
transitions: ['--duration-fast', '--ease-default'],
|
||
shadow: ['--shadow-sm']
|
||
},
|
||
a11y: {
|
||
ariaAttributes: ['aria-label', 'aria-disabled', 'aria-pressed'],
|
||
focusManagement: true,
|
||
contrastRatio: 'WCAG AA (4.5:1)',
|
||
keyboardInteraction: 'Enter, Space',
|
||
semantics: '<button> element'
|
||
},
|
||
darkMode: {
|
||
support: true,
|
||
colorOverrides: ['--primary', '--secondary', '--destructive', '--success']
|
||
},
|
||
testCases: 45 // unit tests
|
||
},
|
||
|
||
'ds-input': {
|
||
name: 'Input',
|
||
group: 'form',
|
||
cssClass: '.ds-input',
|
||
description: 'Text input with label, icon, and error states',
|
||
states: ['default', 'focus', 'hover', 'disabled', 'error', 'disabled-error'],
|
||
variants: {
|
||
type: ['text', 'password', 'email', 'number', 'search', 'tel', 'url'],
|
||
size: ['default']
|
||
},
|
||
variantCombinations: 7,
|
||
stateCount: 6,
|
||
totalStates: 42,
|
||
tokens: {
|
||
color: ['--foreground', '--muted-foreground', '--border', '--destructive'],
|
||
spacing: ['--space-3', '--space-4'],
|
||
typography: ['--text-sm', '--text-base'],
|
||
radius: ['--radius-md'],
|
||
transitions: ['--duration-normal'],
|
||
shadow: ['--shadow-sm']
|
||
},
|
||
a11y: {
|
||
ariaAttributes: ['aria-label', 'aria-invalid', 'aria-describedby'],
|
||
focusManagement: true,
|
||
contrastRatio: 'WCAG AA (4.5:1)',
|
||
keyboardInteraction: 'Tab, Arrow keys',
|
||
semantics: '<input> with associated <label>'
|
||
},
|
||
darkMode: {
|
||
support: true,
|
||
colorOverrides: ['--input', '--border', '--muted-foreground']
|
||
},
|
||
testCases: 38
|
||
},
|
||
|
||
'ds-card': {
|
||
name: 'Card',
|
||
group: 'container',
|
||
cssClass: '.ds-card',
|
||
description: 'Container with header, content, footer sections',
|
||
states: ['default', 'hover', 'interactive'],
|
||
variants: {
|
||
style: ['default', 'interactive']
|
||
},
|
||
variantCombinations: 2,
|
||
stateCount: 3,
|
||
totalStates: 6,
|
||
tokens: {
|
||
color: ['--card', '--card-foreground', '--border'],
|
||
spacing: ['--space-4', '--space-6'],
|
||
radius: ['--radius-lg'],
|
||
shadow: ['--shadow-md']
|
||
},
|
||
a11y: {
|
||
ariaAttributes: [],
|
||
focusManagement: false,
|
||
contrastRatio: 'WCAG AA (4.5:1)',
|
||
semantics: 'Article or Section'
|
||
},
|
||
darkMode: {
|
||
support: true,
|
||
colorOverrides: ['--card', '--card-foreground']
|
||
},
|
||
testCases: 28
|
||
},
|
||
|
||
'ds-badge': {
|
||
name: 'Badge',
|
||
group: 'indicator',
|
||
cssClass: '.ds-badge',
|
||
description: 'Status indicator badge',
|
||
states: ['default', 'hover'],
|
||
variants: {
|
||
variant: ['default', 'secondary', 'outline', 'destructive', 'success', 'warning'],
|
||
size: ['default']
|
||
},
|
||
variantCombinations: 6,
|
||
stateCount: 2,
|
||
totalStates: 12,
|
||
tokens: {
|
||
color: ['--primary', '--secondary', '--destructive', '--success', '--warning'],
|
||
spacing: ['--space-1', '--space-3'],
|
||
typography: ['--text-xs'],
|
||
radius: ['--radius-full']
|
||
},
|
||
a11y: {
|
||
ariaAttributes: ['aria-label'],
|
||
focusManagement: false,
|
||
semantics: 'span with role'
|
||
},
|
||
darkMode: {
|
||
support: true,
|
||
colorOverrides: ['--primary', '--secondary', '--destructive', '--success']
|
||
},
|
||
testCases: 22
|
||
},
|
||
|
||
'ds-toast': {
|
||
name: 'Toast',
|
||
group: 'notification',
|
||
cssClass: '.ds-toast',
|
||
description: 'Auto-dismiss notification toast',
|
||
states: ['entering', 'visible', 'exiting', 'swiped'],
|
||
variants: {
|
||
type: ['default', 'success', 'warning', 'error', 'info'],
|
||
duration: ['auto', 'manual']
|
||
},
|
||
variantCombinations: 10,
|
||
stateCount: 4,
|
||
totalStates: 40,
|
||
tokens: {
|
||
color: ['--success', '--warning', '--destructive', '--info', '--foreground'],
|
||
spacing: ['--space-4'],
|
||
shadow: ['--shadow-lg'],
|
||
transitions: ['--duration-slow'],
|
||
zIndex: ['--z-toast']
|
||
},
|
||
a11y: {
|
||
ariaAttributes: ['role="alert"', 'aria-live="polite"'],
|
||
focusManagement: false,
|
||
semantics: 'div with alert role'
|
||
},
|
||
darkMode: {
|
||
support: true,
|
||
colorOverrides: ['--success', '--warning', '--destructive']
|
||
},
|
||
testCases: 35
|
||
},
|
||
|
||
'ds-workflow': {
|
||
name: 'Workflow',
|
||
group: 'stepper',
|
||
cssClass: '.ds-workflow',
|
||
description: 'Multi-step workflow indicator',
|
||
states: ['pending', 'active', 'completed', 'error', 'skipped'],
|
||
variants: {
|
||
direction: ['vertical', 'horizontal']
|
||
},
|
||
variantCombinations: 2,
|
||
stateCount: 5,
|
||
totalStates: 10, // per step; multiply by step count
|
||
stepsPerWorkflow: 4,
|
||
tokens: {
|
||
color: ['--primary', '--success', '--destructive', '--muted'],
|
||
spacing: ['--space-4', '--space-6'],
|
||
transitions: ['--duration-normal']
|
||
},
|
||
a11y: {
|
||
ariaAttributes: ['aria-current="step"'],
|
||
focusManagement: true,
|
||
semantics: 'ol with li steps'
|
||
},
|
||
darkMode: {
|
||
support: true,
|
||
colorOverrides: ['--primary', '--success', '--destructive']
|
||
},
|
||
testCases: 37
|
||
},
|
||
|
||
'ds-notification-center': {
|
||
name: 'NotificationCenter',
|
||
group: 'notification',
|
||
cssClass: '.ds-notification-center',
|
||
description: 'Notification list with grouping and filtering',
|
||
states: ['empty', 'loading', 'open', 'closed', 'scrolling'],
|
||
variants: {
|
||
layout: ['compact', 'expanded'],
|
||
groupBy: ['type', 'date', 'none']
|
||
},
|
||
variantCombinations: 6,
|
||
stateCount: 5,
|
||
totalStates: 30,
|
||
tokens: {
|
||
color: ['--card', '--card-foreground', '--border', '--primary'],
|
||
spacing: ['--space-3', '--space-4'],
|
||
shadow: ['--shadow-md'],
|
||
zIndex: ['--z-popover']
|
||
},
|
||
a11y: {
|
||
ariaAttributes: ['role="region"', 'aria-label="Notifications"'],
|
||
focusManagement: true,
|
||
semantics: 'ul with li items'
|
||
},
|
||
darkMode: {
|
||
support: true,
|
||
colorOverrides: ['--card', '--card-foreground', '--border']
|
||
},
|
||
testCases: 40
|
||
},
|
||
|
||
'ds-action-bar': {
|
||
name: 'ActionBar',
|
||
group: 'layout',
|
||
cssClass: '.ds-action-bar',
|
||
description: 'Fixed or sticky action button bar',
|
||
states: ['default', 'expanded', 'collapsed', 'dismissing'],
|
||
variants: {
|
||
position: ['fixed', 'relative', 'sticky'],
|
||
alignment: ['left', 'center', 'right']
|
||
},
|
||
variantCombinations: 9,
|
||
stateCount: 4,
|
||
totalStates: 36,
|
||
tokens: {
|
||
color: ['--card', '--card-foreground', '--border'],
|
||
spacing: ['--space-4'],
|
||
shadow: ['--shadow-lg'],
|
||
transitions: ['--duration-normal']
|
||
},
|
||
a11y: {
|
||
ariaAttributes: ['role="toolbar"'],
|
||
focusManagement: true,
|
||
semantics: 'nav with button children'
|
||
},
|
||
darkMode: {
|
||
support: true,
|
||
colorOverrides: ['--card', '--card-foreground']
|
||
},
|
||
testCases: 31
|
||
},
|
||
|
||
'ds-toast-provider': {
|
||
name: 'ToastProvider',
|
||
group: 'provider',
|
||
cssClass: '.ds-toast-provider',
|
||
description: 'Global toast notification container and manager',
|
||
states: ['empty', 'toasts-visible', 'dismissing-all'],
|
||
variants: {
|
||
position: ['top-left', 'top-center', 'top-right', 'bottom-left', 'bottom-center', 'bottom-right']
|
||
},
|
||
variantCombinations: 6,
|
||
stateCount: 3,
|
||
totalStates: 18,
|
||
tokens: {
|
||
spacing: ['--space-4'],
|
||
zIndex: ['--z-toast']
|
||
},
|
||
a11y: {
|
||
ariaAttributes: ['aria-live="polite"'],
|
||
focusManagement: false,
|
||
semantics: 'div container'
|
||
},
|
||
darkMode: {
|
||
support: true,
|
||
colorOverrides: []
|
||
},
|
||
testCases: 23
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Summary statistics
|
||
*/
|
||
summary: {
|
||
totalComponents: 9,
|
||
totalVariants: 123,
|
||
totalTestCases: 315,
|
||
averageTestsPerComponent: 35,
|
||
a11yComponentsSupported: 9,
|
||
darkModeComponentsSupported: 9,
|
||
totalTokensUsed: 42,
|
||
colorTokens: 20,
|
||
spacingTokens: 8,
|
||
typographyTokens: 6,
|
||
radiusTokens: 4,
|
||
transitionTokens: 2,
|
||
shadowTokens: 2
|
||
},
|
||
|
||
/**
|
||
* Token dependency map - which tokens are used where
|
||
*/
|
||
tokenDependencies: {
|
||
'--primary': ['ds-button', 'ds-input', 'ds-badge', 'ds-workflow', 'ds-notification-center', 'ds-action-bar'],
|
||
'--secondary': ['ds-button', 'ds-badge'],
|
||
'--destructive': ['ds-button', 'ds-badge', 'ds-input', 'ds-toast', 'ds-workflow'],
|
||
'--success': ['ds-button', 'ds-badge', 'ds-toast', 'ds-workflow'],
|
||
'--warning': ['ds-badge', 'ds-toast'],
|
||
'--foreground': ['ds-button', 'ds-input', 'ds-card', 'ds-badge', 'ds-toast', 'ds-notification-center', 'ds-action-bar'],
|
||
'--card': ['ds-card', 'ds-notification-center', 'ds-action-bar'],
|
||
'--border': ['ds-input', 'ds-card', 'ds-notification-center', 'ds-action-bar'],
|
||
'--space-1': ['ds-badge'],
|
||
'--space-2': ['ds-input'],
|
||
'--space-3': ['ds-button', 'ds-input', 'ds-notification-center', 'ds-action-bar'],
|
||
'--space-4': ['ds-button', 'ds-input', 'ds-card', 'ds-toast', 'ds-workflow', 'ds-action-bar', 'ds-toast-provider'],
|
||
'--space-6': ['ds-button', 'ds-card', 'ds-workflow'],
|
||
'--text-xs': ['ds-badge', 'ds-button'],
|
||
'--text-sm': ['ds-button', 'ds-input'],
|
||
'--text-base': ['ds-input'],
|
||
'--radius': ['ds-button'],
|
||
'--radius-md': ['ds-input', 'ds-action-bar'],
|
||
'--radius-lg': ['ds-card'],
|
||
'--radius-full': ['ds-badge'],
|
||
'--duration-fast': ['ds-button'],
|
||
'--duration-normal': ['ds-input', 'ds-workflow', 'ds-action-bar'],
|
||
'--duration-slow': ['ds-toast'],
|
||
'--shadow-sm': ['ds-button', 'ds-input'],
|
||
'--shadow-md': ['ds-card', 'ds-notification-center'],
|
||
'--shadow-lg': ['ds-toast', 'ds-action-bar'],
|
||
'--z-popover': ['ds-notification-center'],
|
||
'--z-toast': ['ds-toast', 'ds-toast-provider'],
|
||
'--ease-default': ['ds-button', 'ds-workflow'],
|
||
'--muted-foreground': ['ds-input', 'ds-workflow'],
|
||
'--input': ['ds-input']
|
||
},
|
||
|
||
/**
|
||
* Accessibility requirements matrix
|
||
*/
|
||
a11yRequirements: {
|
||
'ds-button': {
|
||
wcagLevel: 'AA',
|
||
contrastRatio: 4.5,
|
||
keyboardSupport: ['Enter', 'Space'],
|
||
ariaRoles: ['button (implicit)'],
|
||
screenReaderSupport: true
|
||
},
|
||
'ds-input': {
|
||
wcagLevel: 'AA',
|
||
contrastRatio: 4.5,
|
||
keyboardSupport: ['Tab', 'Arrow keys'],
|
||
ariaRoles: ['textbox (implicit)'],
|
||
screenReaderSupport: true
|
||
},
|
||
'ds-card': {
|
||
wcagLevel: 'AA',
|
||
contrastRatio: 4.5,
|
||
keyboardSupport: [],
|
||
ariaRoles: ['article', 'section'],
|
||
screenReaderSupport: true
|
||
},
|
||
'ds-badge': {
|
||
wcagLevel: 'AA',
|
||
contrastRatio: 3,
|
||
keyboardSupport: [],
|
||
ariaRoles: ['status (implicit)'],
|
||
screenReaderSupport: true
|
||
},
|
||
'ds-toast': {
|
||
wcagLevel: 'AA',
|
||
contrastRatio: 4.5,
|
||
keyboardSupport: ['Escape'],
|
||
ariaRoles: ['alert'],
|
||
screenReaderSupport: true
|
||
},
|
||
'ds-workflow': {
|
||
wcagLevel: 'AA',
|
||
contrastRatio: 4.5,
|
||
keyboardSupport: ['Tab', 'Arrow keys'],
|
||
ariaRoles: [],
|
||
screenReaderSupport: true
|
||
},
|
||
'ds-notification-center': {
|
||
wcagLevel: 'AA',
|
||
contrastRatio: 4.5,
|
||
keyboardSupport: ['Tab', 'Arrow keys', 'Enter'],
|
||
ariaRoles: ['region'],
|
||
screenReaderSupport: true
|
||
},
|
||
'ds-action-bar': {
|
||
wcagLevel: 'AA',
|
||
contrastRatio: 4.5,
|
||
keyboardSupport: ['Tab', 'Space/Enter'],
|
||
ariaRoles: ['toolbar'],
|
||
screenReaderSupport: true
|
||
},
|
||
'ds-toast-provider': {
|
||
wcagLevel: 'AA',
|
||
contrastRatio: 4.5,
|
||
keyboardSupport: [],
|
||
ariaRoles: [],
|
||
screenReaderSupport: true
|
||
}
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Export utility functions for working with definitions
|
||
*/
|
||
|
||
export function getComponentDefinition(componentName) {
|
||
return componentDefinitions.components[componentName];
|
||
}
|
||
|
||
export function getComponentVariantCount(componentName) {
|
||
const def = getComponentDefinition(componentName);
|
||
return def ? def.variantCombinations : 0;
|
||
}
|
||
|
||
export function getTotalVariants() {
|
||
return componentDefinitions.summary.totalVariants;
|
||
}
|
||
|
||
export function getTokensForComponent(componentName) {
|
||
const def = getComponentDefinition(componentName);
|
||
return def ? def.tokens : {};
|
||
}
|
||
|
||
export function getComponentsUsingToken(tokenName) {
|
||
return componentDefinitions.tokenDependencies[tokenName] || [];
|
||
}
|
||
|
||
export function validateComponentDefinition(componentName) {
|
||
const def = getComponentDefinition(componentName);
|
||
if (!def) return { valid: false, errors: ['Component not found'] };
|
||
|
||
const errors = [];
|
||
|
||
if (!def.name) errors.push('Missing name');
|
||
if (!def.variants) errors.push('Missing variants');
|
||
if (!def.tokens) errors.push('Missing tokens');
|
||
if (!def.a11y) errors.push('Missing a11y info');
|
||
if (def.darkMode && !Array.isArray(def.darkMode.colorOverrides)) {
|
||
errors.push('Invalid darkMode.colorOverrides');
|
||
}
|
||
|
||
return {
|
||
valid: errors.length === 0,
|
||
errors
|
||
};
|
||
}
|
||
|
||
export default componentDefinitions;
|