@fragments-sdk/cli 0.5.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/dist/bin.js +712 -39
  2. package/dist/bin.js.map +1 -1
  3. package/dist/{chunk-ICAIQ57V.js → chunk-6JBGU74P.js} +5 -3
  4. package/dist/chunk-6JBGU74P.js.map +1 -0
  5. package/dist/{chunk-U4GQ2JTD.js → chunk-D35RGPAG.js} +412 -35
  6. package/dist/chunk-D35RGPAG.js.map +1 -0
  7. package/dist/{chunk-XNWDI6UT.js → chunk-F7ITZPDJ.js} +5 -5
  8. package/dist/{chunk-IOJE35DZ.js → chunk-NWQ4CJOQ.js} +3 -3
  9. package/dist/{chunk-V7YLRR4C.js → chunk-Q7GOHVOK.js} +3 -3
  10. package/dist/{chunk-2DJH4F4P.js → chunk-RVRTRESS.js} +3 -3
  11. package/dist/{chunk-2H2JAA3U.js → chunk-SSLQXHNX.js} +3 -3
  12. package/dist/{core-DKHB7FYV.js → core-SKRPJQZG.js} +4 -4
  13. package/dist/{generate-KL24VZVD.js → generate-7AF7WRVK.js} +5 -5
  14. package/dist/index.d.ts +1 -0
  15. package/dist/index.js +15 -7
  16. package/dist/index.js.map +1 -1
  17. package/dist/{init-NION5S3M.js → init-WKGDPYI4.js} +5 -5
  18. package/dist/mcp-bin.js +8 -220
  19. package/dist/mcp-bin.js.map +1 -1
  20. package/dist/scan-K6JNMCGM.js +12 -0
  21. package/dist/{service-RWUMZ3EW.js → service-F3E4JJM7.js} +5 -5
  22. package/dist/static-viewer-4LQZ5AGA.js +12 -0
  23. package/dist/{test-ECPEXFDN.js → test-CJDNJTPZ.js} +4 -4
  24. package/dist/{tokens-ITADYVPF.js → tokens-JAJABYXP.js} +6 -6
  25. package/dist/viewer-R3Q6WAMJ.js +1822 -0
  26. package/dist/viewer-R3Q6WAMJ.js.map +1 -0
  27. package/package.json +5 -4
  28. package/src/bin.ts +8 -0
  29. package/src/build.ts +104 -13
  30. package/src/cli-commands.ts +18 -0
  31. package/src/commands/__tests__/a11y-scoring.test.ts +278 -0
  32. package/src/commands/a11y-report.ts +625 -0
  33. package/src/commands/a11y.ts +168 -14
  34. package/src/commands/build.ts +16 -0
  35. package/src/core/auto-props.ts +464 -0
  36. package/src/core/schema.ts +2 -0
  37. package/src/core/types.ts +3 -1
  38. package/src/index.ts +4 -0
  39. package/src/mcp/server.ts +13 -220
  40. package/src/theme/__tests__/component-contrast.test.ts +338 -0
  41. package/src/theme/__tests__/contrast-validation.test.ts +326 -0
  42. package/src/theme/contrast.test.ts +331 -0
  43. package/src/theme/contrast.ts +246 -0
  44. package/src/theme/generator.ts +213 -1
  45. package/src/theme/index.ts +16 -0
  46. package/src/theme/types.ts +51 -0
  47. package/src/viewer/__tests__/a11y-fixes.test.ts +358 -0
  48. package/src/viewer/__tests__/viewer-integration.test.ts +2 -7
  49. package/src/viewer/components/AccessibilityPanel.tsx +493 -433
  50. package/src/viewer/components/ActionCapture.tsx +1 -1
  51. package/src/viewer/components/ActionsPanel.tsx +142 -183
  52. package/src/viewer/components/App.tsx +159 -164
  53. package/src/viewer/components/BottomPanel.tsx +40 -80
  54. package/src/viewer/components/CodePanel.tsx +9 -87
  55. package/src/viewer/components/CommandPalette.tsx +117 -74
  56. package/src/viewer/components/ComponentGraph.tsx +143 -126
  57. package/src/viewer/components/ComponentHeader.tsx +46 -43
  58. package/src/viewer/components/ContractPanel.tsx +124 -117
  59. package/src/viewer/components/ErrorBoundary.tsx +47 -35
  60. package/src/viewer/components/FigmaEmbed.tsx +18 -13
  61. package/src/viewer/components/FragmentEditor.tsx +126 -63
  62. package/src/viewer/components/HealthDashboard.tsx +146 -171
  63. package/src/viewer/components/HmrStatusIndicator.tsx +31 -41
  64. package/src/viewer/components/Icons.tsx +99 -98
  65. package/src/viewer/components/InteractionsPanel.tsx +317 -264
  66. package/src/viewer/components/IsolatedPreviewFrame.tsx +52 -27
  67. package/src/viewer/components/IsolatedRender.tsx +12 -6
  68. package/src/viewer/components/KeyboardShortcutsHelp.tsx +34 -70
  69. package/src/viewer/components/LandingPage.tsx +285 -305
  70. package/src/viewer/components/Layout.tsx +7 -9
  71. package/src/viewer/components/LeftSidebar.tsx +78 -108
  72. package/src/viewer/components/MultiViewportPreview.tsx +254 -63
  73. package/src/viewer/components/PreviewArea.tsx +113 -44
  74. package/src/viewer/components/PreviewFrameHost.tsx +6 -5
  75. package/src/viewer/components/PreviewPane.tsx +2 -3
  76. package/src/viewer/components/PreviewToolbar.tsx +61 -104
  77. package/src/viewer/components/PropsEditor.tsx +154 -74
  78. package/src/viewer/components/PropsTable.tsx +95 -82
  79. package/src/viewer/components/RelationsSection.tsx +71 -40
  80. package/src/viewer/components/ResizablePanel.tsx +158 -55
  81. package/src/viewer/components/RightSidebar.tsx +46 -56
  82. package/src/viewer/components/ScreenshotButton.tsx +12 -12
  83. package/src/viewer/components/SkeletonLoader.tsx +99 -83
  84. package/src/viewer/components/StoryRenderer.tsx +4 -11
  85. package/src/viewer/components/Toast.tsx +3 -67
  86. package/src/viewer/components/TokenStylePanel.tsx +136 -118
  87. package/src/viewer/components/UsageSection.tsx +26 -26
  88. package/src/viewer/components/VariantMatrix.tsx +140 -47
  89. package/src/viewer/components/VariantTabs.tsx +24 -68
  90. package/src/viewer/components/ViewportSelector.tsx +106 -110
  91. package/src/viewer/constants/ui.ts +19 -18
  92. package/src/viewer/entry.tsx +8 -3
  93. package/src/viewer/index.ts +3 -6
  94. package/src/viewer/preview-frame.html +21 -5
  95. package/src/viewer/server.ts +7 -16
  96. package/src/viewer/styles/globals.css +4 -4
  97. package/src/viewer/utils/a11y-fixes.ts +53 -30
  98. package/dist/chunk-ICAIQ57V.js.map +0 -1
  99. package/dist/chunk-U4GQ2JTD.js.map +0 -1
  100. package/dist/scan-ESEXV7LF.js +0 -12
  101. package/dist/static-viewer-O37MJ5B6.js +0 -12
  102. package/dist/viewer-YDGFDTK5.js +0 -11104
  103. package/dist/viewer-YDGFDTK5.js.map +0 -1
  104. package/src/viewer/postcss.config.js +0 -6
  105. package/src/viewer/tailwind.config.js +0 -37
  106. /package/dist/{chunk-XNWDI6UT.js.map → chunk-F7ITZPDJ.js.map} +0 -0
  107. /package/dist/{chunk-IOJE35DZ.js.map → chunk-NWQ4CJOQ.js.map} +0 -0
  108. /package/dist/{chunk-V7YLRR4C.js.map → chunk-Q7GOHVOK.js.map} +0 -0
  109. /package/dist/{chunk-2DJH4F4P.js.map → chunk-RVRTRESS.js.map} +0 -0
  110. /package/dist/{chunk-2H2JAA3U.js.map → chunk-SSLQXHNX.js.map} +0 -0
  111. /package/dist/{core-DKHB7FYV.js.map → core-SKRPJQZG.js.map} +0 -0
  112. /package/dist/{generate-KL24VZVD.js.map → generate-7AF7WRVK.js.map} +0 -0
  113. /package/dist/{init-NION5S3M.js.map → init-WKGDPYI4.js.map} +0 -0
  114. /package/dist/{scan-ESEXV7LF.js.map → scan-K6JNMCGM.js.map} +0 -0
  115. /package/dist/{service-RWUMZ3EW.js.map → service-F3E4JJM7.js.map} +0 -0
  116. /package/dist/{static-viewer-O37MJ5B6.js.map → static-viewer-4LQZ5AGA.js.map} +0 -0
  117. /package/dist/{test-ECPEXFDN.js.map → test-CJDNJTPZ.js.map} +0 -0
  118. /package/dist/{tokens-ITADYVPF.js.map → tokens-JAJABYXP.js.map} +0 -0
@@ -1,5 +1,5 @@
1
- import { useState, useEffect } from 'react';
2
- import clsx from 'clsx';
1
+ import { useState } from 'react';
2
+ import { Button, Menu, Stack, Input, Text, Box } from '@fragments/ui';
3
3
  import { VIEWPORT_PRESETS, type ViewportPreset } from '../constants/ui.js';
4
4
  import { ViewportIcon, ChevronDownIcon } from './Icons.js';
5
5
 
@@ -32,128 +32,124 @@ export function ViewportSelector({
32
32
  onViewportChange,
33
33
  onCustomSizeChange,
34
34
  }: ViewportSelectorProps) {
35
- const [isOpen, setIsOpen] = useState(false);
36
35
  const [showCustom, setShowCustom] = useState(false);
37
36
 
38
- // Close dropdown when clicking outside
39
- useEffect(() => {
40
- const handleClick = () => {
41
- setIsOpen(false);
42
- };
43
- if (isOpen) {
44
- document.addEventListener('click', handleClick);
45
- return () => document.removeEventListener('click', handleClick);
46
- }
47
- }, [isOpen]);
48
-
49
37
  const currentPreset = VIEWPORT_PRESETS_UI.find(p => p.value === viewport);
50
38
  const displayLabel = viewport === 'custom'
51
- ? `${customSize.width || '?'}×${customSize.height || 'auto'}`
39
+ ? `${customSize.width || '?'}\u00D7${customSize.height || 'auto'}`
52
40
  : currentPreset?.label || 'Responsive';
53
41
 
54
42
  return (
55
- <div className="relative">
56
- <button
57
- onClick={(e) => {
58
- e.stopPropagation();
59
- setIsOpen(!isOpen);
60
- }}
61
- className={clsx(
62
- 'flex items-center gap-1.5 px-2 py-1 text-xs font-medium rounded',
63
- 'text-secondary hover:text-primary',
64
- 'hover:bg-[--bg-hover] transition-colors',
65
- 'focus:outline-none focus-visible:ring-2 focus-visible:ring-[--color-accent]'
66
- )}
67
- title="Viewport size"
68
- >
69
- <ViewportIcon className="w-3.5 h-3.5" />
70
- <span>{displayLabel}</span>
71
- <ChevronDownIcon className="w-3 h-3" />
72
- </button>
73
-
74
- {isOpen && (
75
- <div
76
- className="absolute top-full right-0 mt-1 py-1 min-w-[160px] bg-[--bg-elevated] border border-[--border] rounded-lg shadow-lg z-50"
77
- onClick={(e) => e.stopPropagation()}
78
- >
79
- {VIEWPORT_PRESETS_UI.map((preset) => (
80
- <button
81
- key={preset.value}
82
- onClick={() => {
83
- onViewportChange(preset.value);
84
- setShowCustom(false);
85
- setIsOpen(false);
86
- }}
87
- className={clsx(
88
- 'w-full px-3 py-1.5 text-xs text-left flex items-center justify-between',
89
- 'hover:bg-[--bg-hover] transition-colors',
90
- preset.value === viewport ? 'text-[--color-accent] font-medium' : 'text-secondary'
91
- )}
92
- >
93
- <span className="flex items-center gap-2">
43
+ <Menu>
44
+ <Menu.Trigger asChild>
45
+ <Button variant="ghost" size="sm" title="Viewport size">
46
+ <Stack direction="row" gap="xs" align="center">
47
+ <span style={{ display: 'inline-flex', width: '14px', height: '14px' }}>
48
+ <ViewportIcon />
49
+ </span>
50
+ <span>{displayLabel}</span>
51
+ <span style={{ display: 'inline-flex', width: '12px', height: '12px' }}>
52
+ <ChevronDownIcon />
53
+ </span>
54
+ </Stack>
55
+ </Button>
56
+ </Menu.Trigger>
57
+ <Menu.Content side="bottom" align="end">
58
+ {VIEWPORT_PRESETS_UI.map((preset) => (
59
+ <Menu.Item
60
+ key={preset.value}
61
+ onSelect={() => {
62
+ onViewportChange(preset.value);
63
+ setShowCustom(false);
64
+ }}
65
+ >
66
+ <Stack direction="row" gap="sm" align="center" justify="between" style={{ width: '100%' }}>
67
+ <Stack direction="row" gap="sm" align="center">
94
68
  <span>{preset.icon}</span>
95
- {preset.label}
96
- </span>
69
+ <span style={{
70
+ fontWeight: preset.value === viewport ? 600 : 400,
71
+ color: preset.value === viewport ? 'var(--color-accent)' : undefined,
72
+ }}>
73
+ {preset.label}
74
+ </span>
75
+ </Stack>
97
76
  {preset.width && (
98
- <span className="text-[10px] text-tertiary">{preset.width}px</span>
77
+ <Text size="2xs" color="tertiary">
78
+ {preset.width}px
79
+ </Text>
99
80
  )}
100
- </button>
101
- ))}
81
+ </Stack>
82
+ </Menu.Item>
83
+ ))}
102
84
 
103
- <div className="border-t border-[--border-subtle] my-1" />
85
+ <Menu.Separator />
104
86
 
105
- <button
106
- onClick={() => {
107
- setShowCustom(!showCustom);
108
- }}
109
- className={clsx(
110
- 'w-full px-3 py-1.5 text-xs text-left flex items-center gap-2',
111
- 'hover:bg-[--bg-hover] transition-colors',
112
- viewport === 'custom' ? 'text-[--color-accent] font-medium' : 'text-secondary'
113
- )}
114
- >
115
- <span>⚙</span>
87
+ <Menu.Item onSelect={() => setShowCustom(!showCustom)}>
88
+ <Stack direction="row" gap="sm" align="center" style={{
89
+ width: '100%',
90
+ fontWeight: viewport === 'custom' ? 600 : 400,
91
+ color: viewport === 'custom' ? 'var(--color-accent)' : undefined,
92
+ }}>
93
+ <span>{'\u2699'}</span>
116
94
  Custom size
117
- <ChevronDownIcon className={clsx('w-3 h-3 ml-auto transition-transform', showCustom && 'rotate-180')} />
118
- </button>
95
+ <span style={{
96
+ display: 'inline-flex',
97
+ width: '12px',
98
+ height: '12px',
99
+ marginLeft: 'auto',
100
+ transition: 'transform 150ms ease',
101
+ transform: showCustom ? 'rotate(180deg)' : 'none',
102
+ }}>
103
+ <ChevronDownIcon />
104
+ </span>
105
+ </Stack>
106
+ </Menu.Item>
119
107
 
120
- {showCustom && (
121
- <div className="px-3 py-2 space-y-2">
122
- <div className="flex items-center gap-2">
123
- <label className="text-[10px] text-tertiary w-8">W:</label>
124
- <input
125
- type="number"
126
- value={customSize.width || ''}
127
- onChange={(e) => {
128
- const width = e.target.value ? parseInt(e.target.value, 10) : null;
129
- onCustomSizeChange({ ...customSize, width });
130
- onViewportChange('custom');
131
- }}
132
- placeholder="auto"
133
- className="w-16 px-2 py-1 text-[11px] font-mono bg-[--bg-primary] border border-[--border] rounded text-primary"
134
- />
135
- <span className="text-[10px] text-tertiary">px</span>
136
- </div>
137
- <div className="flex items-center gap-2">
138
- <label className="text-[10px] text-tertiary w-8">H:</label>
139
- <input
140
- type="number"
141
- value={customSize.height || ''}
142
- onChange={(e) => {
143
- const height = e.target.value ? parseInt(e.target.value, 10) : null;
144
- onCustomSizeChange({ ...customSize, height });
145
- onViewportChange('custom');
146
- }}
147
- placeholder="auto"
148
- className="w-16 px-2 py-1 text-[11px] font-mono bg-[--bg-primary] border border-[--border] rounded text-primary"
149
- />
150
- <span className="text-[10px] text-tertiary">px</span>
151
- </div>
152
- </div>
153
- )}
154
- </div>
155
- )}
156
- </div>
108
+ {showCustom && (
109
+ <div
110
+ onClick={(e) => e.stopPropagation()}
111
+ onKeyDown={(e) => e.stopPropagation()}
112
+ >
113
+ <Box padding="sm">
114
+ <Stack gap="sm">
115
+ <Stack direction="row" gap="sm" align="center">
116
+ <Text size="2xs" color="tertiary" style={{ width: '20px' }}>W:</Text>
117
+ <Input
118
+ type="number"
119
+ size="sm"
120
+ value={customSize.width != null ? String(customSize.width) : ''}
121
+ onChange={(value) => {
122
+ const width = value ? parseInt(value, 10) : null;
123
+ onCustomSizeChange({ ...customSize, width });
124
+ onViewportChange('custom');
125
+ }}
126
+ placeholder="auto"
127
+ style={{ width: '64px' }}
128
+ />
129
+ <Text size="2xs" color="tertiary">px</Text>
130
+ </Stack>
131
+ <Stack direction="row" gap="sm" align="center">
132
+ <Text size="2xs" color="tertiary" style={{ width: '20px' }}>H:</Text>
133
+ <Input
134
+ type="number"
135
+ size="sm"
136
+ value={customSize.height != null ? String(customSize.height) : ''}
137
+ onChange={(value) => {
138
+ const height = value ? parseInt(value, 10) : null;
139
+ onCustomSizeChange({ ...customSize, height });
140
+ onViewportChange('custom');
141
+ }}
142
+ placeholder="auto"
143
+ style={{ width: '64px' }}
144
+ />
145
+ <Text size="2xs" color="tertiary">px</Text>
146
+ </Stack>
147
+ </Stack>
148
+ </Box>
149
+ </div>
150
+ )}
151
+ </Menu.Content>
152
+ </Menu>
157
153
  );
158
154
  }
159
155
 
@@ -58,37 +58,38 @@ export function getStatusConfig(status: string | undefined) {
58
58
 
59
59
  /**
60
60
  * Relationship type styling for related components.
61
+ * Uses inline-style-compatible color values (not Tailwind classes).
61
62
  */
62
63
  export const RELATIONSHIP_CONFIG = {
63
64
  alternative: {
64
65
  label: 'Alternative',
65
- bg: 'bg-blue-500/10',
66
- text: 'text-blue-500',
66
+ bgColor: 'rgba(59, 130, 246, 0.1)',
67
+ textColor: '#3b82f6',
67
68
  },
68
69
  parent: {
69
70
  label: 'Parent',
70
- bg: 'bg-purple-500/10',
71
- text: 'text-purple-500',
71
+ bgColor: 'rgba(147, 51, 234, 0.1)',
72
+ textColor: '#a855f7',
72
73
  },
73
74
  child: {
74
75
  label: 'Child',
75
- bg: 'bg-emerald-500/10',
76
- text: 'text-emerald-500',
76
+ bgColor: 'rgba(16, 185, 129, 0.1)',
77
+ textColor: '#10b981',
77
78
  },
78
79
  sibling: {
79
80
  label: 'Sibling',
80
- bg: 'bg-amber-500/10',
81
- text: 'text-amber-500',
81
+ bgColor: 'rgba(245, 158, 11, 0.1)',
82
+ textColor: '#f59e0b',
82
83
  },
83
84
  related: {
84
85
  label: 'Related',
85
- bg: 'bg-[--bg-tertiary]',
86
- text: 'text-secondary',
86
+ bgColor: 'var(--bg-tertiary)',
87
+ textColor: 'var(--text-secondary)',
87
88
  },
88
89
  composition: {
89
90
  label: 'Uses',
90
- bg: 'bg-cyan-500/10',
91
- text: 'text-cyan-500',
91
+ bgColor: 'rgba(6, 182, 212, 0.1)',
92
+ textColor: '#06b6d4',
92
93
  },
93
94
  } as const;
94
95
 
@@ -167,18 +168,18 @@ export const STORAGE_KEYS = {
167
168
  export const HMR_STATUS = {
168
169
  connected: {
169
170
  label: 'Connected',
170
- color: 'text-emerald-500',
171
- bg: 'bg-emerald-500',
171
+ color: '#10b981',
172
+ bg: '#10b981',
172
173
  },
173
174
  reconnecting: {
174
175
  label: 'Reconnecting...',
175
- color: 'text-amber-500',
176
- bg: 'bg-amber-500',
176
+ color: '#f59e0b',
177
+ bg: '#f59e0b',
177
178
  },
178
179
  disconnected: {
179
180
  label: 'Disconnected',
180
- color: 'text-red-500',
181
- bg: 'bg-red-500',
181
+ color: '#ef4444',
182
+ bg: '#ef4444',
182
183
  },
183
184
  } as const;
184
185
 
@@ -2,10 +2,13 @@ import { createRoot, type Root } from "react-dom/client";
2
2
  import { Component, type ReactNode, type ErrorInfo } from "react";
3
3
  import { App } from "./components/App.js";
4
4
  import { ThemeProvider } from "./components/ThemeProvider.js";
5
+ import { ToastProvider } from "./components/Toast.js";
5
6
  import { AppSkeleton } from "./components/SkeletonLoader.js";
6
7
  // Viewer shell styles - independent from UI library
7
8
  // UI library styles are only loaded in the isolated preview area
8
9
  import "./styles/globals.css";
10
+ // Fragments UI globals - adds --fui-* CSS variables for dogfooding UI components
11
+ import "@fragments/ui";
9
12
 
10
13
  // App-level error boundary that catches any unhandled errors
11
14
  class AppErrorBoundary extends Component<{ children: ReactNode }, { hasError: boolean; error: Error | null; errorInfo: ErrorInfo | null }> {
@@ -244,9 +247,11 @@ if (rootElement) {
244
247
 
245
248
  appRoot?.render(
246
249
  <ThemeProvider>
247
- <AppErrorBoundary>
248
- <App segments={currentSegments} />
249
- </AppErrorBoundary>
250
+ <ToastProvider position="bottom-right" duration={3000}>
251
+ <AppErrorBoundary>
252
+ <App segments={currentSegments} />
253
+ </AppErrorBoundary>
254
+ </ToastProvider>
250
255
  </ThemeProvider>
251
256
  );
252
257
  };
@@ -6,9 +6,6 @@ export type { DevServerOptions } from "./server.js";
6
6
  export { segmentsPlugin } from "./vite-plugin.js";
7
7
  export type { SegmentsPluginOptions } from "./vite-plugin.js";
8
8
 
9
- // Components
10
- export { App } from "./components/App.js";
11
- export { Layout } from "./components/Layout.js";
12
- export { LeftSidebar } from "./components/LeftSidebar.js";
13
- export { RightSidebar } from "./components/RightSidebar.js";
14
- export { ThemeProvider, useTheme } from "./components/ThemeProvider.js";
9
+ // Note: Viewer components (App, Layout, etc.) are NOT exported here.
10
+ // They use @fragments/ui which is a Vite-only alias and can't be resolved by Node.js.
11
+ // Vite serves these components directly from source during development.
@@ -73,6 +73,19 @@
73
73
  font-family: 'JetBrains Mono', ui-monospace, monospace;
74
74
  }
75
75
 
76
+ /* Visually hidden but accessible to screen readers */
77
+ .sr-only {
78
+ position: absolute;
79
+ width: 1px;
80
+ height: 1px;
81
+ padding: 0;
82
+ margin: -1px;
83
+ overflow: hidden;
84
+ clip: rect(0, 0, 0, 0);
85
+ white-space: nowrap;
86
+ border-width: 0;
87
+ }
88
+
76
89
  /* Loading indicator */
77
90
  .preview-loading {
78
91
  display: flex;
@@ -98,12 +111,15 @@
98
111
  </style>
99
112
  </head>
100
113
  <body>
101
- <div id="preview-root">
102
- <div class="preview-loading">
103
- <div class="spinner"></div>
104
- <span>Loading preview...</span>
114
+ <main>
115
+ <h1 class="sr-only">Component Preview</h1>
116
+ <div id="preview-root">
117
+ <div class="preview-loading">
118
+ <div class="spinner"></div>
119
+ <span>Loading preview...</span>
120
+ </div>
105
121
  </div>
106
- </div>
122
+ </main>
107
123
  <script type="module" src="/src/preview-frame-entry.tsx"></script>
108
124
  </body>
109
125
  </html>
@@ -18,8 +18,6 @@ import {
18
18
  type InlineConfig,
19
19
  } from "vite";
20
20
  import react from "@vitejs/plugin-react";
21
- import tailwindcss from "tailwindcss";
22
- import autoprefixer from "autoprefixer";
23
21
  import { resolve, dirname, join } from "node:path";
24
22
  import { existsSync, realpathSync } from "node:fs";
25
23
  import { fileURLToPath } from "node:url";
@@ -30,8 +28,8 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
30
28
  // At runtime, __dirname is dist/. Viewer assets live in src/viewer/.
31
29
  const cliPackageRoot = resolve(__dirname, "..");
32
30
  const viewerRoot = resolve(cliPackageRoot, "src/viewer");
33
- const viewerTailwindConfig = resolve(viewerRoot, "tailwind.config.js");
34
31
  const packagesRoot = resolve(cliPackageRoot, "..");
32
+ const uiLibRoot = resolve(packagesRoot, "../libs/ui/src");
35
33
 
36
34
  export interface DevServerOptions {
37
35
  /** Port to run the server on */
@@ -124,8 +122,8 @@ export async function createDevServer(
124
122
  port,
125
123
  open: open ? "/fragments/" : false,
126
124
  fs: {
127
- // Allow serving files from viewer package, project, and node_modules root
128
- allow: [viewerRoot, projectRoot, configDir, dirname(nodeModulesPath), ...installedPkgRoots],
125
+ // Allow serving files from viewer package, project, UI library, and node_modules root
126
+ allow: [viewerRoot, uiLibRoot, projectRoot, configDir, dirname(nodeModulesPath), ...installedPkgRoots],
129
127
  },
130
128
  },
131
129
 
@@ -141,17 +139,8 @@ export async function createDevServer(
141
139
  }),
142
140
  ],
143
141
 
144
- // CSS configuration for viewer's Tailwind
145
- css: {
146
- postcss: {
147
- plugins: [
148
- tailwindcss({
149
- config: viewerTailwindConfig,
150
- }),
151
- autoprefixer(),
152
- ],
153
- },
154
- },
142
+ // CSS configuration
143
+ css: {},
155
144
 
156
145
  optimizeDeps: {
157
146
  // Include common dependencies for faster startup
@@ -165,6 +154,8 @@ export async function createDevServer(
165
154
  alias: {
166
155
  // Allow importing from viewer package
167
156
  "@fragments/viewer": viewerRoot,
157
+ // Resolve @fragments/ui to the UI library source for dogfooding
158
+ "@fragments/ui": resolve(uiLibRoot, "index.ts"),
168
159
  // Resolve @fragments/core to the consolidated core source
169
160
  "@fragments/core": resolve(cliPackageRoot, "src/core/index.ts"),
170
161
  // Ensure ALL react imports resolve to project's node_modules
@@ -1,7 +1,3 @@
1
- @tailwind base;
2
- @tailwind components;
3
- @tailwind utilities;
4
-
5
1
  /* ============================================
6
2
  * Fragments Viewer Theme System
7
3
  * ============================================
@@ -330,6 +326,10 @@ td {
330
326
  * Animations
331
327
  * ============================================ */
332
328
 
329
+ @keyframes spin {
330
+ to { transform: rotate(360deg); }
331
+ }
332
+
333
333
  @keyframes fadeIn {
334
334
  from { opacity: 0; }
335
335
  to { opacity: 1; }
@@ -10,6 +10,7 @@
10
10
 
11
11
  import type { ImpactValue } from 'axe-core';
12
12
  import type { StaticFixSuggestion, ElementFix, SerializedNode } from '../types/a11y.js';
13
+ import { parseColor, suggestFix, rgbToHex } from '../../theme/contrast.js';
13
14
 
14
15
  /**
15
16
  * WCAG criteria references
@@ -217,24 +218,36 @@ function generateContrastFix(node: SerializedNode): ElementFix | null {
217
218
  const data = parseContrastData(node);
218
219
  if (!data?.fgColor || !data?.bgColor) return null;
219
220
 
220
- const { fgColor, bgColor, contrastRatio, requiredRatio } = data;
221
+ const { fgColor, bgColor, contrastRatio: ratio, requiredRatio } = data;
221
222
 
222
223
  // Safely convert to number and format
223
- const currentRatioNum = typeof contrastRatio === 'number' ? contrastRatio : parseFloat(String(contrastRatio || ''));
224
+ const currentRatioNum = typeof ratio === 'number' ? ratio : parseFloat(String(ratio || ''));
224
225
  const requiredRatioNum = typeof requiredRatio === 'number' ? requiredRatio : parseFloat(String(requiredRatio || ''));
225
226
 
226
227
  const currentRatio = !isNaN(currentRatioNum) ? currentRatioNum.toFixed(2) : 'unknown';
227
- const required = !isNaN(requiredRatioNum) ? requiredRatioNum.toFixed(1) : '4.5';
228
-
229
- // Suggest darkening text if it's light, or lightening if it's dark
230
- const suggestion = `Adjust colors to meet ${required}:1 contrast ratio (currently ${currentRatio}:1)`;
231
-
232
- return {
233
- originalHtml: node.html,
234
- fixedHtml: node.html, // Can't auto-generate fixed HTML without color calculation
235
- explanation: `Text color ${fgColor} on background ${bgColor} has insufficient contrast. ${suggestion}`,
236
- autoFixable: false,
237
- };
228
+ const required = !isNaN(requiredRatioNum) ? requiredRatioNum : 4.5;
229
+
230
+ // Use real color math to suggest a corrected foreground color
231
+ try {
232
+ const fgRgb = parseColor(fgColor);
233
+ const bgRgb = parseColor(bgColor);
234
+ const correctedHex = suggestFix(fgRgb, bgRgb, required);
235
+
236
+ return {
237
+ originalHtml: node.html,
238
+ fixedHtml: node.html,
239
+ explanation: `Text color ${fgColor} on background ${bgColor} has insufficient contrast (${currentRatio}:1, need ${required}:1). Suggested foreground: ${correctedHex}`,
240
+ autoFixable: true,
241
+ };
242
+ } catch {
243
+ // Fall back to non-auto-fixable if color parsing fails
244
+ return {
245
+ originalHtml: node.html,
246
+ fixedHtml: node.html,
247
+ explanation: `Text color ${fgColor} on background ${bgColor} has insufficient contrast (${currentRatio}:1, need ${required}:1). Adjust the foreground color to meet the required ratio.`,
248
+ autoFixable: false,
249
+ };
250
+ }
238
251
  }
239
252
 
240
253
  /**
@@ -413,9 +426,11 @@ export function getImpactDescription(impact: ImpactValue | null): string {
413
426
  }
414
427
 
415
428
  /**
416
- * Get impact color class for styling
429
+ * Get impact styling for inline styles and Badge variant mapping
417
430
  */
418
431
  export function getImpactColorClass(impact: ImpactValue | null): {
432
+ variant: 'error' | 'warning' | 'info' | 'default';
433
+ color: string;
419
434
  bg: string;
420
435
  text: string;
421
436
  border: string;
@@ -424,32 +439,40 @@ export function getImpactColorClass(impact: ImpactValue | null): {
424
439
  switch (impact) {
425
440
  case 'critical':
426
441
  return {
427
- bg: 'bg-red-100 dark:bg-red-950/50',
428
- text: 'text-red-700 dark:text-red-300',
429
- border: 'border-red-300 dark:border-red-700',
430
- borderLeft: 'border-l-red-500',
442
+ variant: 'error',
443
+ color: 'var(--color-danger)',
444
+ bg: 'var(--color-danger-bg)',
445
+ text: 'var(--color-danger)',
446
+ border: 'var(--color-danger)',
447
+ borderLeft: 'var(--color-danger)',
431
448
  };
432
449
  case 'serious':
433
450
  return {
434
- bg: 'bg-orange-100 dark:bg-orange-950/50',
435
- text: 'text-orange-700 dark:text-orange-300',
436
- border: 'border-orange-300 dark:border-orange-700',
437
- borderLeft: 'border-l-orange-500',
451
+ variant: 'error',
452
+ color: 'var(--color-danger)',
453
+ bg: 'var(--color-danger-bg)',
454
+ text: 'var(--color-danger)',
455
+ border: 'var(--color-danger)',
456
+ borderLeft: 'var(--color-danger)',
438
457
  };
439
458
  case 'moderate':
440
459
  return {
441
- bg: 'bg-amber-100 dark:bg-amber-950/50',
442
- text: 'text-amber-700 dark:text-amber-300',
443
- border: 'border-amber-300 dark:border-amber-700',
444
- borderLeft: 'border-l-amber-500',
460
+ variant: 'warning',
461
+ color: 'var(--color-warning)',
462
+ bg: 'var(--color-warning-bg)',
463
+ text: 'var(--color-warning)',
464
+ border: 'var(--color-warning)',
465
+ borderLeft: 'var(--color-warning)',
445
466
  };
446
467
  case 'minor':
447
468
  default:
448
469
  return {
449
- bg: 'bg-yellow-100 dark:bg-yellow-950/50',
450
- text: 'text-yellow-700 dark:text-yellow-300',
451
- border: 'border-yellow-300 dark:border-yellow-700',
452
- borderLeft: 'border-l-yellow-500',
470
+ variant: 'info',
471
+ color: 'var(--color-info)',
472
+ bg: 'var(--color-info-bg)',
473
+ text: 'var(--color-info)',
474
+ border: 'var(--color-info)',
475
+ borderLeft: 'var(--color-info)',
453
476
  };
454
477
  }
455
478
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/constants.ts","../src/core/schema.ts"],"sourcesContent":["/**\n * Brand constants for easy rebranding if domain availability requires it.\n * All naming throughout the codebase should reference these constants.\n */\nexport const BRAND = {\n /** Display name (e.g., \"Fragments\") */\n name: \"Fragments\",\n\n /** Lowercase name for file paths and CLI (e.g., \"fragments\") */\n nameLower: \"fragments\",\n\n /** File extension for fragment definition files (e.g., \".fragment.tsx\") */\n fileExtension: \".fragment.tsx\",\n\n /** Legacy file extension for segments (still supported for migration) */\n legacyFileExtension: \".segment.tsx\",\n\n /** JSON file extension for compiled output */\n jsonExtension: \".fragment.json\",\n\n /** Default output file name (e.g., \"fragments.json\") */\n outFile: \"fragments.json\",\n\n /** Config file name (e.g., \"fragments.config.ts\") */\n configFile: \"fragments.config.ts\",\n\n /** Legacy config file name (still supported for migration) */\n legacyConfigFile: \"segments.config.ts\",\n\n /** CLI command name (e.g., \"fragments\") */\n cliCommand: \"fragments\",\n\n /** Package scope (e.g., \"@fragments\") */\n packageScope: \"@fragments\",\n\n /** Directory for storing fragments, registry, and cache */\n dataDir: \".fragments\",\n\n /** Components subdirectory within .fragments/ */\n componentsDir: \"components\",\n\n /** Registry file name */\n registryFile: \"registry.json\",\n\n /** Context file name (AI-ready markdown) */\n contextFile: \"context.md\",\n\n /** Screenshots subdirectory */\n screenshotsDir: \"screenshots\",\n\n /** Cache subdirectory (gitignored) */\n cacheDir: \"cache\",\n\n /** Diff output subdirectory (gitignored) */\n diffDir: \"diff\",\n\n /** Manifest filename */\n manifestFile: \"manifest.json\",\n\n /** Prefix for localStorage keys (e.g., \"fragments-\") */\n storagePrefix: \"fragments-\",\n\n /** Static viewer HTML file name */\n viewerHtmlFile: \"fragments-viewer.html\",\n\n /** MCP tool name prefix (e.g., \"fragments_\") */\n mcpToolPrefix: \"fragments_\",\n\n /** File extension for block definition files */\n blockFileExtension: \".block.ts\",\n\n /** @deprecated Use blockFileExtension instead */\n recipeFileExtension: \".recipe.ts\",\n\n /** Vite plugin namespace */\n vitePluginNamespace: \"fragments-core-shim\",\n} as const;\n\nexport type Brand = typeof BRAND;\n\n/**\n * Default configuration values for the service.\n * These can be overridden in fragments.config.ts\n */\nexport const DEFAULTS = {\n /** Default viewport dimensions */\n viewport: {\n width: 1280,\n height: 800,\n },\n\n /** Default diff threshold (percentage) */\n diffThreshold: 5,\n\n /** Browser pool size */\n poolSize: 3,\n\n /** Idle timeout before browser shutdown (ms) - 5 minutes */\n idleTimeoutMs: 5 * 60 * 1000,\n\n /** Delay after render before capture (ms) */\n captureDelayMs: 100,\n\n /** Font loading timeout (ms) */\n fontTimeoutMs: 3000,\n\n /** Default theme */\n theme: \"light\" as const,\n\n /** Dev server port */\n port: 6006,\n} as const;\n\nexport type Defaults = typeof DEFAULTS;\n","import { z } from 'zod';\n\n/**\n * Zod schemas for runtime validation of segment definitions\n */\n\n// Figma property mapping schemas\nconst figmaStringMappingSchema = z.object({\n __type: z.literal('figma-string'),\n figmaProperty: z.string().min(1),\n});\n\nconst figmaBooleanMappingSchema = z.object({\n __type: z.literal('figma-boolean'),\n figmaProperty: z.string().min(1),\n valueMapping: z.object({ true: z.unknown(), false: z.unknown() }).optional(),\n});\n\nconst figmaEnumMappingSchema = z.object({\n __type: z.literal('figma-enum'),\n figmaProperty: z.string().min(1),\n valueMapping: z.record(z.unknown()),\n});\n\nconst figmaInstanceMappingSchema = z.object({\n __type: z.literal('figma-instance'),\n figmaProperty: z.string().min(1),\n});\n\nconst figmaChildrenMappingSchema = z.object({\n __type: z.literal('figma-children'),\n layers: z.array(z.string().min(1)),\n});\n\nconst figmaTextContentMappingSchema = z.object({\n __type: z.literal('figma-text-content'),\n layer: z.string().min(1),\n});\n\nexport const figmaPropMappingSchema = z.discriminatedUnion('__type', [\n figmaStringMappingSchema,\n figmaBooleanMappingSchema,\n figmaEnumMappingSchema,\n figmaInstanceMappingSchema,\n figmaChildrenMappingSchema,\n figmaTextContentMappingSchema,\n]);\n\nexport const segmentMetaSchema = z.object({\n name: z.string().min(1),\n description: z.string().min(1),\n category: z.string().min(1),\n tags: z.array(z.string()).optional(),\n status: z.enum(['stable', 'beta', 'deprecated', 'experimental']).optional(),\n since: z.string().optional(),\n figma: z.string().url().optional(),\n figmaProps: z.record(figmaPropMappingSchema).optional(),\n});\n\nexport const segmentUsageSchema = z.object({\n when: z.array(z.string()).min(1),\n whenNot: z.array(z.string()).min(1),\n guidelines: z.array(z.string()).optional(),\n accessibility: z.array(z.string()).optional(),\n});\n\nexport const propTypeSchema: z.ZodType<string> = z.enum([\n 'string',\n 'number',\n 'boolean',\n 'enum',\n 'function',\n 'node',\n 'element',\n 'object',\n 'array',\n 'union',\n 'custom',\n]);\n\nexport const propDefinitionSchema = z.object({\n type: propTypeSchema,\n values: z.array(z.string()).readonly().optional(),\n default: z.unknown().optional(),\n description: z.string().optional(),\n required: z.boolean().optional(),\n constraints: z.array(z.string()).optional(),\n typeDetails: z.record(z.unknown()).optional(),\n});\n\nexport const relationshipTypeSchema = z.enum([\n 'alternative',\n 'sibling',\n 'parent',\n 'child',\n 'composition',\n]);\n\nexport const componentRelationSchema = z.object({\n component: z.string().min(1),\n relationship: relationshipTypeSchema,\n note: z.string().min(1),\n});\n\nexport const segmentVariantSchema = z.object({\n name: z.string().min(1),\n description: z.string().min(1),\n render: z.function().returns(z.unknown()),\n code: z.string().optional(),\n figma: z.string().url().optional(),\n});\n\n/**\n * Schema for banned patterns in codebase\n */\nexport const segmentBanSchema = z.object({\n pattern: z.string().min(1),\n message: z.string().min(1),\n});\n\n/**\n * Schema for agent-optimized contract metadata\n */\nexport const segmentContractSchema = z.object({\n propsSummary: z.array(z.string()).optional(),\n a11yRules: z.array(z.string()).optional(),\n bans: z.array(segmentBanSchema).optional(),\n scenarioTags: z.array(z.string()).optional(),\n});\n\n/**\n * Schema for provenance tracking of generated segments\n */\nexport const segmentGeneratedSchema = z.object({\n source: z.enum(['storybook', 'manual', 'ai']),\n sourceFile: z.string().optional(),\n confidence: z.number().min(0).max(1).optional(),\n timestamp: z.string().datetime().optional(),\n});\n\n/**\n * Schema for AI-specific metadata for playground context generation\n */\nexport const aiMetadataSchema = z.object({\n compositionPattern: z.enum(['compound', 'simple', 'controlled']).optional(),\n subComponents: z.array(z.string()).optional(),\n requiredChildren: z.array(z.string()).optional(),\n commonPatterns: z.array(z.string()).optional(),\n});\n\n/**\n * Schema for block definitions\n */\nexport const blockDefinitionSchema = z.object({\n name: z.string().min(1),\n description: z.string().min(1),\n category: z.string().min(1),\n components: z.array(z.string().min(1)).min(1),\n code: z.string().min(1),\n tags: z.array(z.string()).optional(),\n});\n\nexport const segmentDefinitionSchema = z.object({\n component: z.any(), // Allow any component type (function, class, forwardRef, etc.)\n meta: segmentMetaSchema,\n usage: segmentUsageSchema,\n props: z.record(propDefinitionSchema),\n relations: z.array(componentRelationSchema).optional(),\n variants: z.array(segmentVariantSchema), // Allow empty variants array\n contract: segmentContractSchema.optional(),\n ai: aiMetadataSchema.optional(),\n _generated: segmentGeneratedSchema.optional(),\n});\n\n/**\n * Config schema - validates required fields, passes through optional config objects.\n * Type definitions are in types.ts - schema just ensures basic structure.\n */\nexport const segmentsConfigSchema = z.object({\n include: z.array(z.string()).min(1),\n exclude: z.array(z.string()).optional(),\n components: z.array(z.string()).optional(),\n outFile: z.string().optional(),\n framework: z.enum(['react', 'vue', 'svelte']).optional(),\n figmaFile: z.string().url().optional(),\n figmaToken: z.string().optional(),\n screenshots: z.object({}).passthrough().optional(),\n service: z.object({}).passthrough().optional(),\n registry: z.object({}).passthrough().optional(),\n tokens: z.object({\n include: z.array(z.string()).min(1),\n }).passthrough().optional(),\n});\n\n/**\n * @deprecated Use blockDefinitionSchema instead\n */\nexport const recipeDefinitionSchema = blockDefinitionSchema;\n"],"mappings":"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","names":[]}