@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.
- package/dist/bin.js +712 -39
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-ICAIQ57V.js → chunk-6JBGU74P.js} +5 -3
- package/dist/chunk-6JBGU74P.js.map +1 -0
- package/dist/{chunk-U4GQ2JTD.js → chunk-D35RGPAG.js} +412 -35
- package/dist/chunk-D35RGPAG.js.map +1 -0
- package/dist/{chunk-XNWDI6UT.js → chunk-F7ITZPDJ.js} +5 -5
- package/dist/{chunk-IOJE35DZ.js → chunk-NWQ4CJOQ.js} +3 -3
- package/dist/{chunk-V7YLRR4C.js → chunk-Q7GOHVOK.js} +3 -3
- package/dist/{chunk-2DJH4F4P.js → chunk-RVRTRESS.js} +3 -3
- package/dist/{chunk-2H2JAA3U.js → chunk-SSLQXHNX.js} +3 -3
- package/dist/{core-DKHB7FYV.js → core-SKRPJQZG.js} +4 -4
- package/dist/{generate-KL24VZVD.js → generate-7AF7WRVK.js} +5 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.js +15 -7
- package/dist/index.js.map +1 -1
- package/dist/{init-NION5S3M.js → init-WKGDPYI4.js} +5 -5
- package/dist/mcp-bin.js +8 -220
- package/dist/mcp-bin.js.map +1 -1
- package/dist/scan-K6JNMCGM.js +12 -0
- package/dist/{service-RWUMZ3EW.js → service-F3E4JJM7.js} +5 -5
- package/dist/static-viewer-4LQZ5AGA.js +12 -0
- package/dist/{test-ECPEXFDN.js → test-CJDNJTPZ.js} +4 -4
- package/dist/{tokens-ITADYVPF.js → tokens-JAJABYXP.js} +6 -6
- package/dist/viewer-R3Q6WAMJ.js +1822 -0
- package/dist/viewer-R3Q6WAMJ.js.map +1 -0
- package/package.json +5 -4
- package/src/bin.ts +8 -0
- package/src/build.ts +104 -13
- package/src/cli-commands.ts +18 -0
- package/src/commands/__tests__/a11y-scoring.test.ts +278 -0
- package/src/commands/a11y-report.ts +625 -0
- package/src/commands/a11y.ts +168 -14
- package/src/commands/build.ts +16 -0
- package/src/core/auto-props.ts +464 -0
- package/src/core/schema.ts +2 -0
- package/src/core/types.ts +3 -1
- package/src/index.ts +4 -0
- package/src/mcp/server.ts +13 -220
- package/src/theme/__tests__/component-contrast.test.ts +338 -0
- package/src/theme/__tests__/contrast-validation.test.ts +326 -0
- package/src/theme/contrast.test.ts +331 -0
- package/src/theme/contrast.ts +246 -0
- package/src/theme/generator.ts +213 -1
- package/src/theme/index.ts +16 -0
- package/src/theme/types.ts +51 -0
- package/src/viewer/__tests__/a11y-fixes.test.ts +358 -0
- package/src/viewer/__tests__/viewer-integration.test.ts +2 -7
- package/src/viewer/components/AccessibilityPanel.tsx +493 -433
- package/src/viewer/components/ActionCapture.tsx +1 -1
- package/src/viewer/components/ActionsPanel.tsx +142 -183
- package/src/viewer/components/App.tsx +159 -164
- package/src/viewer/components/BottomPanel.tsx +40 -80
- package/src/viewer/components/CodePanel.tsx +9 -87
- package/src/viewer/components/CommandPalette.tsx +117 -74
- package/src/viewer/components/ComponentGraph.tsx +143 -126
- package/src/viewer/components/ComponentHeader.tsx +46 -43
- package/src/viewer/components/ContractPanel.tsx +124 -117
- package/src/viewer/components/ErrorBoundary.tsx +47 -35
- package/src/viewer/components/FigmaEmbed.tsx +18 -13
- package/src/viewer/components/FragmentEditor.tsx +126 -63
- package/src/viewer/components/HealthDashboard.tsx +146 -171
- package/src/viewer/components/HmrStatusIndicator.tsx +31 -41
- package/src/viewer/components/Icons.tsx +99 -98
- package/src/viewer/components/InteractionsPanel.tsx +317 -264
- package/src/viewer/components/IsolatedPreviewFrame.tsx +52 -27
- package/src/viewer/components/IsolatedRender.tsx +12 -6
- package/src/viewer/components/KeyboardShortcutsHelp.tsx +34 -70
- package/src/viewer/components/LandingPage.tsx +285 -305
- package/src/viewer/components/Layout.tsx +7 -9
- package/src/viewer/components/LeftSidebar.tsx +78 -108
- package/src/viewer/components/MultiViewportPreview.tsx +254 -63
- package/src/viewer/components/PreviewArea.tsx +113 -44
- package/src/viewer/components/PreviewFrameHost.tsx +6 -5
- package/src/viewer/components/PreviewPane.tsx +2 -3
- package/src/viewer/components/PreviewToolbar.tsx +61 -104
- package/src/viewer/components/PropsEditor.tsx +154 -74
- package/src/viewer/components/PropsTable.tsx +95 -82
- package/src/viewer/components/RelationsSection.tsx +71 -40
- package/src/viewer/components/ResizablePanel.tsx +158 -55
- package/src/viewer/components/RightSidebar.tsx +46 -56
- package/src/viewer/components/ScreenshotButton.tsx +12 -12
- package/src/viewer/components/SkeletonLoader.tsx +99 -83
- package/src/viewer/components/StoryRenderer.tsx +4 -11
- package/src/viewer/components/Toast.tsx +3 -67
- package/src/viewer/components/TokenStylePanel.tsx +136 -118
- package/src/viewer/components/UsageSection.tsx +26 -26
- package/src/viewer/components/VariantMatrix.tsx +140 -47
- package/src/viewer/components/VariantTabs.tsx +24 -68
- package/src/viewer/components/ViewportSelector.tsx +106 -110
- package/src/viewer/constants/ui.ts +19 -18
- package/src/viewer/entry.tsx +8 -3
- package/src/viewer/index.ts +3 -6
- package/src/viewer/preview-frame.html +21 -5
- package/src/viewer/server.ts +7 -16
- package/src/viewer/styles/globals.css +4 -4
- package/src/viewer/utils/a11y-fixes.ts +53 -30
- package/dist/chunk-ICAIQ57V.js.map +0 -1
- package/dist/chunk-U4GQ2JTD.js.map +0 -1
- package/dist/scan-ESEXV7LF.js +0 -12
- package/dist/static-viewer-O37MJ5B6.js +0 -12
- package/dist/viewer-YDGFDTK5.js +0 -11104
- package/dist/viewer-YDGFDTK5.js.map +0 -1
- package/src/viewer/postcss.config.js +0 -6
- package/src/viewer/tailwind.config.js +0 -37
- /package/dist/{chunk-XNWDI6UT.js.map → chunk-F7ITZPDJ.js.map} +0 -0
- /package/dist/{chunk-IOJE35DZ.js.map → chunk-NWQ4CJOQ.js.map} +0 -0
- /package/dist/{chunk-V7YLRR4C.js.map → chunk-Q7GOHVOK.js.map} +0 -0
- /package/dist/{chunk-2DJH4F4P.js.map → chunk-RVRTRESS.js.map} +0 -0
- /package/dist/{chunk-2H2JAA3U.js.map → chunk-SSLQXHNX.js.map} +0 -0
- /package/dist/{core-DKHB7FYV.js.map → core-SKRPJQZG.js.map} +0 -0
- /package/dist/{generate-KL24VZVD.js.map → generate-7AF7WRVK.js.map} +0 -0
- /package/dist/{init-NION5S3M.js.map → init-WKGDPYI4.js.map} +0 -0
- /package/dist/{scan-ESEXV7LF.js.map → scan-K6JNMCGM.js.map} +0 -0
- /package/dist/{service-RWUMZ3EW.js.map → service-F3E4JJM7.js.map} +0 -0
- /package/dist/{static-viewer-O37MJ5B6.js.map → static-viewer-4LQZ5AGA.js.map} +0 -0
- /package/dist/{test-ECPEXFDN.js.map → test-CJDNJTPZ.js.map} +0 -0
- /package/dist/{tokens-ITADYVPF.js.map → tokens-JAJABYXP.js.map} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useState
|
|
2
|
-
import
|
|
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 || '?'}
|
|
39
|
+
? `${customSize.width || '?'}\u00D7${customSize.height || 'auto'}`
|
|
52
40
|
: currentPreset?.label || 'Responsive';
|
|
53
41
|
|
|
54
42
|
return (
|
|
55
|
-
<
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
>
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
{
|
|
96
|
-
|
|
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
|
-
<
|
|
77
|
+
<Text size="2xs" color="tertiary">
|
|
78
|
+
{preset.width}px
|
|
79
|
+
</Text>
|
|
99
80
|
)}
|
|
100
|
-
</
|
|
101
|
-
|
|
81
|
+
</Stack>
|
|
82
|
+
</Menu.Item>
|
|
83
|
+
))}
|
|
102
84
|
|
|
103
|
-
|
|
85
|
+
<Menu.Separator />
|
|
104
86
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
<
|
|
118
|
-
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
|
|
66
|
-
|
|
66
|
+
bgColor: 'rgba(59, 130, 246, 0.1)',
|
|
67
|
+
textColor: '#3b82f6',
|
|
67
68
|
},
|
|
68
69
|
parent: {
|
|
69
70
|
label: 'Parent',
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
bgColor: 'rgba(147, 51, 234, 0.1)',
|
|
72
|
+
textColor: '#a855f7',
|
|
72
73
|
},
|
|
73
74
|
child: {
|
|
74
75
|
label: 'Child',
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
bgColor: 'rgba(16, 185, 129, 0.1)',
|
|
77
|
+
textColor: '#10b981',
|
|
77
78
|
},
|
|
78
79
|
sibling: {
|
|
79
80
|
label: 'Sibling',
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
bgColor: 'rgba(245, 158, 11, 0.1)',
|
|
82
|
+
textColor: '#f59e0b',
|
|
82
83
|
},
|
|
83
84
|
related: {
|
|
84
85
|
label: 'Related',
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
bgColor: 'var(--bg-tertiary)',
|
|
87
|
+
textColor: 'var(--text-secondary)',
|
|
87
88
|
},
|
|
88
89
|
composition: {
|
|
89
90
|
label: 'Uses',
|
|
90
|
-
|
|
91
|
-
|
|
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: '
|
|
171
|
-
bg: '
|
|
171
|
+
color: '#10b981',
|
|
172
|
+
bg: '#10b981',
|
|
172
173
|
},
|
|
173
174
|
reconnecting: {
|
|
174
175
|
label: 'Reconnecting...',
|
|
175
|
-
color: '
|
|
176
|
-
bg: '
|
|
176
|
+
color: '#f59e0b',
|
|
177
|
+
bg: '#f59e0b',
|
|
177
178
|
},
|
|
178
179
|
disconnected: {
|
|
179
180
|
label: 'Disconnected',
|
|
180
|
-
color: '
|
|
181
|
-
bg: '
|
|
181
|
+
color: '#ef4444',
|
|
182
|
+
bg: '#ef4444',
|
|
182
183
|
},
|
|
183
184
|
} as const;
|
|
184
185
|
|
package/src/viewer/entry.tsx
CHANGED
|
@@ -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
|
-
<
|
|
248
|
-
<
|
|
249
|
-
|
|
250
|
+
<ToastProvider position="bottom-right" duration={3000}>
|
|
251
|
+
<AppErrorBoundary>
|
|
252
|
+
<App segments={currentSegments} />
|
|
253
|
+
</AppErrorBoundary>
|
|
254
|
+
</ToastProvider>
|
|
250
255
|
</ThemeProvider>
|
|
251
256
|
);
|
|
252
257
|
};
|
package/src/viewer/index.ts
CHANGED
|
@@ -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
|
-
//
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
<
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
<
|
|
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
|
-
</
|
|
122
|
+
</main>
|
|
107
123
|
<script type="module" src="/src/preview-frame-entry.tsx"></script>
|
|
108
124
|
</body>
|
|
109
125
|
</html>
|
package/src/viewer/server.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
228
|
-
|
|
229
|
-
//
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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
|
|
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
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
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
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
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
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
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
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
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":[]}
|