@fragments-sdk/cli 0.5.2 → 0.7.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 (124) hide show
  1. package/dist/bin.js +996 -79
  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-7OPWMLOE.js +1625 -0
  6. package/dist/chunk-7OPWMLOE.js.map +1 -0
  7. package/dist/{chunk-2H2JAA3U.js → chunk-CVXKXVOY.js} +3 -3
  8. package/dist/{chunk-2H2JAA3U.js.map → chunk-CVXKXVOY.js.map} +1 -1
  9. package/dist/{chunk-IOJE35DZ.js → chunk-NWQ4CJOQ.js} +3 -3
  10. package/dist/{chunk-2DJH4F4P.js → chunk-RVRTRESS.js} +3 -3
  11. package/dist/{chunk-V7YLRR4C.js → chunk-TJ34N7C7.js} +41 -4
  12. package/dist/{chunk-V7YLRR4C.js.map → chunk-TJ34N7C7.js.map} +1 -1
  13. package/dist/{chunk-XNWDI6UT.js → chunk-XHUDJNN3.js} +5 -5
  14. package/dist/{core-DKHB7FYV.js → core-W2HYIQW6.js} +4 -4
  15. package/dist/{generate-KL24VZVD.js → generate-LMTISDIJ.js} +5 -5
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.js +15 -7
  18. package/dist/index.js.map +1 -1
  19. package/dist/{init-NION5S3M.js → init-7CHRKQ7P.js} +5 -5
  20. package/dist/mcp-bin.js +8 -220
  21. package/dist/mcp-bin.js.map +1 -1
  22. package/dist/scan-WY23TJCP.js +12 -0
  23. package/dist/{service-RWUMZ3EW.js → service-T2L7VLTE.js} +5 -5
  24. package/dist/static-viewer-GBR7YNF3.js +12 -0
  25. package/dist/{test-ECPEXFDN.js → test-OJRXNDO2.js} +4 -4
  26. package/dist/{tokens-ITADYVPF.js → tokens-3BWDESVM.js} +6 -6
  27. package/dist/viewer-SUFOISZM.js +1822 -0
  28. package/dist/viewer-SUFOISZM.js.map +1 -0
  29. package/package.json +6 -5
  30. package/src/bin.ts +31 -0
  31. package/src/build.ts +147 -13
  32. package/src/cli-commands.ts +18 -0
  33. package/src/commands/__tests__/a11y-scoring.test.ts +278 -0
  34. package/src/commands/a11y-report.ts +625 -0
  35. package/src/commands/a11y.ts +168 -14
  36. package/src/commands/build.ts +16 -0
  37. package/src/commands/graph.ts +274 -0
  38. package/src/core/auto-props.ts +464 -0
  39. package/src/core/composition.ts +64 -1
  40. package/src/core/graph-extractor.test.ts +542 -0
  41. package/src/core/graph-extractor.ts +601 -0
  42. package/src/core/importAnalyzer.ts +5 -0
  43. package/src/core/schema.ts +2 -0
  44. package/src/core/types.ts +3 -1
  45. package/src/index.ts +4 -0
  46. package/src/mcp/server.ts +13 -220
  47. package/src/theme/__tests__/component-contrast.test.ts +338 -0
  48. package/src/theme/__tests__/contrast-validation.test.ts +326 -0
  49. package/src/theme/contrast.test.ts +331 -0
  50. package/src/theme/contrast.ts +246 -0
  51. package/src/theme/generator.ts +213 -1
  52. package/src/theme/index.ts +16 -0
  53. package/src/theme/types.ts +51 -0
  54. package/src/viewer/__tests__/a11y-fixes.test.ts +358 -0
  55. package/src/viewer/__tests__/viewer-integration.test.ts +2 -7
  56. package/src/viewer/components/AccessibilityPanel.tsx +493 -433
  57. package/src/viewer/components/ActionCapture.tsx +1 -1
  58. package/src/viewer/components/ActionsPanel.tsx +142 -183
  59. package/src/viewer/components/App.tsx +276 -183
  60. package/src/viewer/components/BottomPanel.tsx +40 -80
  61. package/src/viewer/components/CodePanel.tsx +9 -87
  62. package/src/viewer/components/CommandPalette.tsx +117 -74
  63. package/src/viewer/components/ComponentGraph.tsx +143 -126
  64. package/src/viewer/components/ComponentHeader.tsx +46 -43
  65. package/src/viewer/components/ContractPanel.tsx +124 -117
  66. package/src/viewer/components/ErrorBoundary.tsx +47 -35
  67. package/src/viewer/components/FigmaEmbed.tsx +18 -13
  68. package/src/viewer/components/FragmentEditor.tsx +126 -63
  69. package/src/viewer/components/HealthDashboard.tsx +146 -171
  70. package/src/viewer/components/HmrStatusIndicator.tsx +31 -41
  71. package/src/viewer/components/Icons.tsx +151 -98
  72. package/src/viewer/components/InteractionsPanel.tsx +317 -264
  73. package/src/viewer/components/IsolatedPreviewFrame.tsx +52 -27
  74. package/src/viewer/components/IsolatedRender.tsx +12 -6
  75. package/src/viewer/components/KeyboardShortcutsHelp.tsx +34 -70
  76. package/src/viewer/components/LandingPage.tsx +285 -305
  77. package/src/viewer/components/Layout.tsx +12 -10
  78. package/src/viewer/components/LeftSidebar.tsx +103 -155
  79. package/src/viewer/components/MultiViewportPreview.tsx +254 -63
  80. package/src/viewer/components/PreviewArea.tsx +113 -44
  81. package/src/viewer/components/PreviewFrameHost.tsx +36 -6
  82. package/src/viewer/components/PreviewPane.tsx +2 -3
  83. package/src/viewer/components/PreviewToolbar.tsx +109 -105
  84. package/src/viewer/components/PropsEditor.tsx +154 -74
  85. package/src/viewer/components/PropsTable.tsx +95 -82
  86. package/src/viewer/components/RelationsSection.tsx +71 -40
  87. package/src/viewer/components/ResizablePanel.tsx +158 -55
  88. package/src/viewer/components/RightSidebar.tsx +46 -56
  89. package/src/viewer/components/ScreenshotButton.tsx +12 -12
  90. package/src/viewer/components/SkeletonLoader.tsx +99 -83
  91. package/src/viewer/components/StoryRenderer.tsx +4 -11
  92. package/src/viewer/components/Toast.tsx +3 -67
  93. package/src/viewer/components/TokenStylePanel.tsx +136 -118
  94. package/src/viewer/components/UsageSection.tsx +26 -26
  95. package/src/viewer/components/VariantMatrix.tsx +140 -47
  96. package/src/viewer/components/VariantTabs.tsx +24 -68
  97. package/src/viewer/components/ViewportSelector.tsx +121 -114
  98. package/src/viewer/constants/ui.ts +23 -22
  99. package/src/viewer/entry.tsx +8 -3
  100. package/src/viewer/index.ts +3 -6
  101. package/src/viewer/preview-frame.html +43 -18
  102. package/src/viewer/server.ts +7 -16
  103. package/src/viewer/styles/globals.css +46 -85
  104. package/src/viewer/utils/a11y-fixes.ts +53 -30
  105. package/dist/chunk-ICAIQ57V.js.map +0 -1
  106. package/dist/chunk-U4GQ2JTD.js +0 -832
  107. package/dist/chunk-U4GQ2JTD.js.map +0 -1
  108. package/dist/scan-ESEXV7LF.js +0 -12
  109. package/dist/static-viewer-O37MJ5B6.js +0 -12
  110. package/dist/viewer-YDGFDTK5.js +0 -11104
  111. package/dist/viewer-YDGFDTK5.js.map +0 -1
  112. package/src/viewer/postcss.config.js +0 -6
  113. package/src/viewer/tailwind.config.js +0 -37
  114. /package/dist/{chunk-IOJE35DZ.js.map → chunk-NWQ4CJOQ.js.map} +0 -0
  115. /package/dist/{chunk-2DJH4F4P.js.map → chunk-RVRTRESS.js.map} +0 -0
  116. /package/dist/{chunk-XNWDI6UT.js.map → chunk-XHUDJNN3.js.map} +0 -0
  117. /package/dist/{core-DKHB7FYV.js.map → core-W2HYIQW6.js.map} +0 -0
  118. /package/dist/{generate-KL24VZVD.js.map → generate-LMTISDIJ.js.map} +0 -0
  119. /package/dist/{init-NION5S3M.js.map → init-7CHRKQ7P.js.map} +0 -0
  120. /package/dist/{scan-ESEXV7LF.js.map → scan-WY23TJCP.js.map} +0 -0
  121. /package/dist/{service-RWUMZ3EW.js.map → service-T2L7VLTE.js.map} +0 -0
  122. /package/dist/{static-viewer-O37MJ5B6.js.map → static-viewer-GBR7YNF3.js.map} +0 -0
  123. /package/dist/{test-ECPEXFDN.js.map → test-OJRXNDO2.js.map} +0 -0
  124. /package/dist/{tokens-ITADYVPF.js.map → tokens-3BWDESVM.js.map} +0 -0
@@ -1,5 +1,5 @@
1
- import { useState, useEffect, useCallback } from 'react';
2
- import clsx from 'clsx';
1
+ import { useEffect, useCallback } from 'react';
2
+ import { Button, Menu, Stack, Separator } from '@fragments/ui';
3
3
  import {
4
4
  ZOOM_LEVELS,
5
5
  type ZoomLevel,
@@ -12,13 +12,62 @@ export type { ZoomLevel, BackgroundOption };
12
12
  export { getBackgroundStyle } from '../constants/ui.js';
13
13
 
14
14
  // Background options with display metadata
15
- const BACKGROUND_OPTIONS_UI: { value: BackgroundOption; label: string; icon: string }[] = [
16
- { value: 'white', label: 'White', icon: '◻' },
17
- { value: 'black', label: 'Black', icon: '◼' },
18
- { value: 'checkerboard', label: 'Checkerboard', icon: '▦' },
19
- { value: 'transparent', label: 'Transparent', icon: '◇' },
15
+ const BACKGROUND_OPTIONS_UI: { value: BackgroundOption; label: string }[] = [
16
+ { value: 'white', label: 'White' },
17
+ { value: 'black', label: 'Black' },
18
+ { value: 'checkerboard', label: 'Checkerboard' },
19
+ { value: 'transparent', label: 'Transparent' },
20
20
  ];
21
21
 
22
+ function BackgroundSwatch({ background }: { background: BackgroundOption }) {
23
+ const baseStyle = {
24
+ width: '14px',
25
+ height: '14px',
26
+ borderRadius: '4px',
27
+ border: '1px solid var(--border)',
28
+ flexShrink: 0,
29
+ };
30
+
31
+ if (background === 'white') {
32
+ return <span aria-hidden="true" style={{ ...baseStyle, backgroundColor: '#ffffff' }} />;
33
+ }
34
+
35
+ if (background === 'black') {
36
+ return <span aria-hidden="true" style={{ ...baseStyle, backgroundColor: '#171717', borderColor: '#2a2a2a' }} />;
37
+ }
38
+
39
+ if (background === 'checkerboard') {
40
+ return (
41
+ <span
42
+ aria-hidden="true"
43
+ style={{
44
+ ...baseStyle,
45
+ backgroundColor: '#ffffff',
46
+ backgroundImage: `
47
+ linear-gradient(45deg, #d4d4d8 25%, transparent 25%),
48
+ linear-gradient(-45deg, #d4d4d8 25%, transparent 25%),
49
+ linear-gradient(45deg, transparent 75%, #d4d4d8 75%),
50
+ linear-gradient(-45deg, transparent 75%, #d4d4d8 75%)
51
+ `,
52
+ backgroundSize: '8px 8px',
53
+ backgroundPosition: '0 0, 0 4px, 4px -4px, -4px 0',
54
+ }}
55
+ />
56
+ );
57
+ }
58
+
59
+ return (
60
+ <span
61
+ aria-hidden="true"
62
+ style={{
63
+ ...baseStyle,
64
+ backgroundColor: 'transparent',
65
+ backgroundImage: 'linear-gradient(135deg, transparent 42%, var(--text-tertiary) 43%, var(--text-tertiary) 57%, transparent 58%)',
66
+ }}
67
+ />
68
+ );
69
+ }
70
+
22
71
  interface PreviewToolbarProps {
23
72
  zoom: ZoomLevel;
24
73
  background: BackgroundOption;
@@ -32,9 +81,6 @@ export function PreviewToolbar({
32
81
  onZoomChange,
33
82
  onBackgroundChange,
34
83
  }: PreviewToolbarProps) {
35
- const [zoomOpen, setZoomOpen] = useState(false);
36
- const [bgOpen, setBgOpen] = useState(false);
37
-
38
84
  // Keyboard shortcuts for zoom
39
85
  const handleKeyDown = useCallback((e: KeyboardEvent) => {
40
86
  // Don't handle if in input/textarea
@@ -66,111 +112,69 @@ export function PreviewToolbar({
66
112
  return () => document.removeEventListener('keydown', handleKeyDown);
67
113
  }, [handleKeyDown]);
68
114
 
69
- // Close dropdowns when clicking outside
70
- useEffect(() => {
71
- const handleClick = () => {
72
- setZoomOpen(false);
73
- setBgOpen(false);
74
- };
75
- if (zoomOpen || bgOpen) {
76
- document.addEventListener('click', handleClick);
77
- return () => document.removeEventListener('click', handleClick);
78
- }
79
- }, [zoomOpen, bgOpen]);
80
-
81
115
  return (
82
- <div className="flex items-center gap-2">
116
+ <Stack direction="row" gap="sm" align="center">
83
117
  {/* Zoom dropdown */}
84
- <div className="relative">
85
- <button
86
- onClick={(e) => {
87
- e.stopPropagation();
88
- setZoomOpen(!zoomOpen);
89
- setBgOpen(false);
90
- }}
91
- className={clsx(
92
- 'flex items-center gap-1.5 px-2 py-1 text-xs font-medium rounded',
93
- 'text-secondary hover:text-primary',
94
- 'hover:bg-[--bg-hover] transition-colors',
95
- 'focus:outline-none focus-visible:ring-2 focus-visible:ring-[--color-accent]'
96
- )}
97
- title="Zoom level (+/-/0)"
98
- >
99
- <ZoomIcon className="w-3.5 h-3.5" />
100
- <span>{zoom}%</span>
101
- <ChevronDownIcon className="w-3 h-3" />
102
- </button>
103
- {zoomOpen && (
104
- <div className="absolute top-full left-0 mt-1 py-1 min-w-[80px] bg-[--bg-elevated] border border-[--border] rounded-lg shadow-lg z-50">
118
+ <Menu>
119
+ <Menu.Trigger asChild>
120
+ <Button variant="ghost" size="sm" title="Zoom level (+/-/0)">
121
+ <Stack direction="row" gap="xs" align="center">
122
+ <span style={{ display: 'inline-flex', width: '14px', height: '14px' }}>
123
+ <ZoomIcon />
124
+ </span>
125
+ <span>{zoom}%</span>
126
+ <span style={{ display: 'inline-flex', width: '12px', height: '12px' }}>
127
+ <ChevronDownIcon />
128
+ </span>
129
+ </Stack>
130
+ </Button>
131
+ </Menu.Trigger>
132
+ <Menu.Content side="bottom" align="start">
133
+ <Menu.RadioGroup
134
+ value={String(zoom)}
135
+ onValueChange={(value: string) => onZoomChange(Number(value) as ZoomLevel)}
136
+ >
105
137
  {ZOOM_LEVELS.map((level) => (
106
- <button
107
- key={level}
108
- onClick={(e) => {
109
- e.stopPropagation();
110
- onZoomChange(level);
111
- setZoomOpen(false);
112
- }}
113
- className={clsx(
114
- 'w-full px-3 py-1.5 text-xs text-left',
115
- 'hover:bg-[--bg-hover] transition-colors',
116
- level === zoom ? 'text-[--color-accent] font-medium' : 'text-secondary'
117
- )}
118
- >
138
+ <Menu.RadioItem key={level} value={String(level)}>
119
139
  {level}%
120
- </button>
140
+ </Menu.RadioItem>
121
141
  ))}
122
- </div>
123
- )}
124
- </div>
142
+ </Menu.RadioGroup>
143
+ </Menu.Content>
144
+ </Menu>
125
145
 
126
146
  {/* Divider */}
127
- <div className="w-px h-4 bg-[--border]" />
147
+ <Separator orientation="vertical" />
128
148
 
129
149
  {/* Background selector */}
130
- <div className="relative">
131
- <button
132
- onClick={(e) => {
133
- e.stopPropagation();
134
- setBgOpen(!bgOpen);
135
- setZoomOpen(false);
136
- }}
137
- className={clsx(
138
- 'flex items-center gap-1.5 px-2 py-1 text-xs font-medium rounded',
139
- 'text-secondary hover:text-primary',
140
- 'hover:bg-[--bg-hover] transition-colors',
141
- 'focus:outline-none focus-visible:ring-2 focus-visible:ring-[--color-accent]'
142
- )}
143
- title="Background color"
144
- >
145
- <span className="text-sm">
146
- {BACKGROUND_OPTIONS_UI.find(o => o.value === background)?.icon}
147
- </span>
148
- <span className="capitalize">{background}</span>
149
- <ChevronDownIcon className="w-3 h-3" />
150
- </button>
151
- {bgOpen && (
152
- <div className="absolute top-full left-0 mt-1 py-1 min-w-[120px] bg-[--bg-elevated] border border-[--border] rounded-lg shadow-lg z-50">
150
+ <Menu>
151
+ <Menu.Trigger asChild>
152
+ <Button variant="ghost" size="sm" title="Background color">
153
+ <Stack direction="row" gap="xs" align="center">
154
+ <BackgroundSwatch background={background} />
155
+ <span>{BACKGROUND_OPTIONS_UI.find(o => o.value === background)?.label}</span>
156
+ <span style={{ display: 'inline-flex', width: '12px', height: '12px' }}>
157
+ <ChevronDownIcon />
158
+ </span>
159
+ </Stack>
160
+ </Button>
161
+ </Menu.Trigger>
162
+ <Menu.Content side="bottom" align="start">
163
+ <Menu.RadioGroup
164
+ value={background}
165
+ onValueChange={(value: string) => onBackgroundChange(value as BackgroundOption)}
166
+ >
153
167
  {BACKGROUND_OPTIONS_UI.map((option) => (
154
- <button
155
- key={option.value}
156
- onClick={(e) => {
157
- e.stopPropagation();
158
- onBackgroundChange(option.value);
159
- setBgOpen(false);
160
- }}
161
- className={clsx(
162
- 'w-full px-3 py-1.5 text-xs text-left flex items-center gap-2',
163
- 'hover:bg-[--bg-hover] transition-colors',
164
- option.value === background ? 'text-[--color-accent] font-medium' : 'text-secondary'
165
- )}
166
- >
167
- <span className="text-sm">{option.icon}</span>
168
- {option.label}
169
- </button>
168
+ <Menu.RadioItem key={option.value} value={option.value}>
169
+ <Stack direction="row" gap="sm" align="center">
170
+ <BackgroundSwatch background={option.value} />
171
+ {option.label}
172
+ </Stack>
173
+ </Menu.RadioItem>
170
174
  ))}
171
- </div>
172
- )}
173
- </div>
174
- </div>
175
+ </Menu.RadioGroup>
176
+ </Menu.Content>
177
+ </Menu>
178
+ </Stack>
175
179
  );
176
180
  }