@fragments-sdk/cli 0.6.0 → 0.7.1

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 (178) hide show
  1. package/dist/bin.js +529 -285
  2. package/dist/bin.js.map +1 -1
  3. package/dist/{chunk-F7ITZPDJ.js → chunk-32VIEOQY.js} +18 -18
  4. package/dist/chunk-32VIEOQY.js.map +1 -0
  5. package/dist/{chunk-SSLQXHNX.js → chunk-5ITIP3ES.js} +27 -27
  6. package/dist/chunk-5ITIP3ES.js.map +1 -0
  7. package/dist/{chunk-RVRTRESS.js → chunk-DQHWLAUV.js} +29 -29
  8. package/dist/chunk-DQHWLAUV.js.map +1 -0
  9. package/dist/{chunk-Q7GOHVOK.js → chunk-GCZMFLDI.js} +67 -32
  10. package/dist/chunk-GCZMFLDI.js.map +1 -0
  11. package/dist/{chunk-6JBGU74P.js → chunk-GHYYFAQN.js} +23 -23
  12. package/dist/chunk-GHYYFAQN.js.map +1 -0
  13. package/dist/{chunk-NWQ4CJOQ.js → chunk-GKX2HPZ6.js} +40 -40
  14. package/dist/chunk-GKX2HPZ6.js.map +1 -0
  15. package/dist/{chunk-D35RGPAG.js → chunk-U6VTHBNI.js} +499 -83
  16. package/dist/chunk-U6VTHBNI.js.map +1 -0
  17. package/dist/{core-SKRPJQZG.js → core-SFHPYR5H.js} +24 -26
  18. package/dist/{generate-7AF7WRVK.js → generate-54GJAWUY.js} +5 -5
  19. package/dist/generate-54GJAWUY.js.map +1 -0
  20. package/dist/index.d.ts +23 -27
  21. package/dist/index.js +10 -10
  22. package/dist/{init-WKGDPYI4.js → init-EIM5WNMP.js} +5 -5
  23. package/dist/{init-WKGDPYI4.js.map → init-EIM5WNMP.js.map} +1 -1
  24. package/dist/mcp-bin.js +73 -73
  25. package/dist/mcp-bin.js.map +1 -1
  26. package/dist/scan-KQBKUS64.js +12 -0
  27. package/dist/{service-F3E4JJM7.js → service-ED2LNCTU.js} +6 -6
  28. package/dist/{static-viewer-4LQZ5AGA.js → static-viewer-Q4F4QP5M.js} +4 -4
  29. package/dist/{test-CJDNJTPZ.js → test-6VN2DA3S.js} +19 -19
  30. package/dist/test-6VN2DA3S.js.map +1 -0
  31. package/dist/{tokens-JAJABYXP.js → tokens-P2B7ZAM3.js} +5 -5
  32. package/dist/{viewer-R3Q6WAMJ.js → viewer-GM7IQPPB.js} +199 -199
  33. package/dist/viewer-GM7IQPPB.js.map +1 -0
  34. package/package.json +2 -2
  35. package/src/ai.ts +5 -5
  36. package/src/analyze.ts +11 -11
  37. package/src/bin.ts +24 -1
  38. package/src/build.ts +64 -21
  39. package/src/commands/a11y.ts +6 -6
  40. package/src/commands/add.ts +11 -11
  41. package/src/commands/audit.ts +4 -4
  42. package/src/commands/baseline.ts +3 -3
  43. package/src/commands/build.ts +8 -8
  44. package/src/commands/compare.ts +20 -20
  45. package/src/commands/context.ts +16 -16
  46. package/src/commands/enhance.ts +36 -36
  47. package/src/commands/generate.ts +1 -1
  48. package/src/commands/graph.ts +274 -0
  49. package/src/commands/init.ts +1 -1
  50. package/src/commands/link/figma.ts +82 -82
  51. package/src/commands/link/index.ts +3 -3
  52. package/src/commands/link/storybook.ts +9 -9
  53. package/src/commands/list.ts +2 -2
  54. package/src/commands/reset.ts +15 -15
  55. package/src/commands/scan.ts +27 -27
  56. package/src/commands/storygen.ts +24 -24
  57. package/src/commands/validate.ts +2 -2
  58. package/src/commands/verify.ts +8 -8
  59. package/src/core/auto-props.ts +4 -4
  60. package/src/core/composition.test.ts +36 -36
  61. package/src/core/composition.ts +83 -20
  62. package/src/core/config.ts +6 -6
  63. package/src/core/{defineSegment.ts → defineFragment.ts} +16 -22
  64. package/src/core/discovery.ts +6 -6
  65. package/src/core/figma.ts +2 -2
  66. package/src/core/graph-extractor.test.ts +542 -0
  67. package/src/core/graph-extractor.ts +601 -0
  68. package/src/core/importAnalyzer.ts +6 -1
  69. package/src/core/index.ts +22 -23
  70. package/src/core/loader.ts +22 -22
  71. package/src/core/node.ts +5 -5
  72. package/src/core/parser.ts +31 -31
  73. package/src/core/previewLoader.ts +1 -1
  74. package/src/core/schema.ts +16 -16
  75. package/src/core/storyAdapter.test.ts +87 -87
  76. package/src/core/storyAdapter.ts +16 -16
  77. package/src/core/types.ts +21 -26
  78. package/src/diff.ts +22 -22
  79. package/src/index.ts +2 -2
  80. package/src/mcp/server.ts +80 -80
  81. package/src/migrate/__tests__/utils/utils.test.ts +3 -3
  82. package/src/migrate/bin.ts +4 -4
  83. package/src/migrate/converter.ts +16 -16
  84. package/src/migrate/index.ts +3 -3
  85. package/src/migrate/migrate.ts +3 -3
  86. package/src/migrate/parser.ts +8 -8
  87. package/src/migrate/report.ts +2 -2
  88. package/src/migrate/types.ts +4 -4
  89. package/src/screenshot.ts +22 -22
  90. package/src/service/__tests__/props-extractor.test.ts +15 -15
  91. package/src/service/analytics.ts +39 -39
  92. package/src/service/enhance/codebase-scanner.ts +1 -1
  93. package/src/service/enhance/index.ts +1 -1
  94. package/src/service/enhance/props-extractor.ts +2 -2
  95. package/src/service/enhance/types.ts +2 -2
  96. package/src/service/index.ts +2 -2
  97. package/src/service/metrics-store.ts +1 -1
  98. package/src/service/patch-generator.ts +1 -1
  99. package/src/setup.ts +52 -52
  100. package/src/shared/dev-server-client.ts +7 -7
  101. package/src/shared/fragment-loader.ts +59 -0
  102. package/src/shared/index.ts +1 -1
  103. package/src/shared/types.ts +4 -4
  104. package/src/static-viewer.ts +35 -35
  105. package/src/test/discovery.ts +6 -6
  106. package/src/test/index.ts +5 -5
  107. package/src/test/reporters/console.ts +1 -1
  108. package/src/test/reporters/junit.ts +1 -1
  109. package/src/test/runner.ts +7 -7
  110. package/src/test/types.ts +3 -3
  111. package/src/test/watch.ts +9 -9
  112. package/src/validators.ts +26 -26
  113. package/src/viewer/__tests__/render-utils.test.ts +28 -28
  114. package/src/viewer/__tests__/viewer-integration.test.ts +4 -4
  115. package/src/viewer/cli/health.ts +26 -26
  116. package/src/viewer/components/App.tsx +201 -103
  117. package/src/viewer/components/BottomPanel.tsx +17 -17
  118. package/src/viewer/components/CodePanel.tsx +3 -3
  119. package/src/viewer/components/CommandPalette.tsx +11 -11
  120. package/src/viewer/components/ComponentGraph.tsx +28 -28
  121. package/src/viewer/components/ComponentHeader.tsx +2 -2
  122. package/src/viewer/components/ContractPanel.tsx +6 -6
  123. package/src/viewer/components/FigmaEmbed.tsx +9 -9
  124. package/src/viewer/components/HealthDashboard.tsx +17 -17
  125. package/src/viewer/components/Icons.tsx +53 -1
  126. package/src/viewer/components/InteractionsPanel.tsx +2 -2
  127. package/src/viewer/components/IsolatedPreviewFrame.tsx +6 -6
  128. package/src/viewer/components/IsolatedRender.tsx +10 -10
  129. package/src/viewer/components/Layout.tsx +7 -3
  130. package/src/viewer/components/LeftSidebar.tsx +92 -114
  131. package/src/viewer/components/MultiViewportPreview.tsx +14 -14
  132. package/src/viewer/components/PreviewArea.tsx +11 -11
  133. package/src/viewer/components/PreviewFrameHost.tsx +77 -48
  134. package/src/viewer/components/PreviewToolbar.tsx +57 -10
  135. package/src/viewer/components/RightSidebar.tsx +9 -9
  136. package/src/viewer/components/Sidebar.tsx +17 -17
  137. package/src/viewer/components/StoryRenderer.tsx +2 -2
  138. package/src/viewer/components/TokenStylePanel.tsx +1 -1
  139. package/src/viewer/components/UsageSection.tsx +2 -2
  140. package/src/viewer/components/VariantMatrix.tsx +11 -11
  141. package/src/viewer/components/VariantRenderer.tsx +3 -3
  142. package/src/viewer/components/VariantTabs.tsx +2 -2
  143. package/src/viewer/components/ViewportSelector.tsx +56 -45
  144. package/src/viewer/components/_future/CreatePage.tsx +6 -6
  145. package/src/viewer/composition-renderer.ts +11 -11
  146. package/src/viewer/constants/ui.ts +4 -4
  147. package/src/viewer/entry.tsx +40 -40
  148. package/src/viewer/hooks/useFigmaIntegration.ts +1 -1
  149. package/src/viewer/hooks/usePreviewBridge.ts +5 -5
  150. package/src/viewer/hooks/useUrlState.ts +6 -6
  151. package/src/viewer/index.ts +2 -2
  152. package/src/viewer/intelligence/healthReport.ts +17 -17
  153. package/src/viewer/intelligence/styleDrift.ts +1 -1
  154. package/src/viewer/intelligence/usageScanner.ts +1 -1
  155. package/src/viewer/preview-frame.html +22 -13
  156. package/src/viewer/render-template.html +1 -1
  157. package/src/viewer/render-utils.ts +21 -21
  158. package/src/viewer/server.ts +18 -18
  159. package/src/viewer/styles/globals.css +42 -81
  160. package/src/viewer/utils/detectRelationships.ts +22 -22
  161. package/src/viewer/vite-plugin.ts +213 -213
  162. package/dist/chunk-6JBGU74P.js.map +0 -1
  163. package/dist/chunk-D35RGPAG.js.map +0 -1
  164. package/dist/chunk-F7ITZPDJ.js.map +0 -1
  165. package/dist/chunk-NWQ4CJOQ.js.map +0 -1
  166. package/dist/chunk-Q7GOHVOK.js.map +0 -1
  167. package/dist/chunk-RVRTRESS.js.map +0 -1
  168. package/dist/chunk-SSLQXHNX.js.map +0 -1
  169. package/dist/generate-7AF7WRVK.js.map +0 -1
  170. package/dist/scan-K6JNMCGM.js +0 -12
  171. package/dist/test-CJDNJTPZ.js.map +0 -1
  172. package/dist/viewer-R3Q6WAMJ.js.map +0 -1
  173. package/src/shared/segment-loader.ts +0 -59
  174. /package/dist/{core-SKRPJQZG.js.map → core-SFHPYR5H.js.map} +0 -0
  175. /package/dist/{scan-K6JNMCGM.js.map → scan-KQBKUS64.js.map} +0 -0
  176. /package/dist/{service-F3E4JJM7.js.map → service-ED2LNCTU.js.map} +0 -0
  177. /package/dist/{static-viewer-4LQZ5AGA.js.map → static-viewer-Q4F4QP5M.js.map} +0 -0
  178. /package/dist/{tokens-JAJABYXP.js.map → tokens-P2B7ZAM3.js.map} +0 -0
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * This component runs inside the preview iframe and:
5
5
  * 1. Listens for render requests from the parent window
6
- * 2. Loads and renders the requested segment variant
6
+ * 2. Loads and renders the requested fragment variant
7
7
  * 3. Applies theme styling
8
8
  * 4. Reports render status back to parent
9
9
  */
@@ -11,8 +11,8 @@
11
11
  import { useState, useEffect, useRef, type ReactNode } from 'react';
12
12
  import { useFrameBridge } from '../hooks/usePreviewBridge.js';
13
13
 
14
- // Types for segment data
15
- interface SegmentVariant {
14
+ // Types for fragment data
15
+ interface FragmentVariant {
16
16
  name: string;
17
17
  render: (options?: { loadedData?: Record<string, unknown> }) => ReactNode;
18
18
  loaders?: Array<() => Promise<Record<string, unknown>>>;
@@ -20,66 +20,84 @@ interface SegmentVariant {
20
20
  hasPlayFunction?: boolean;
21
21
  }
22
22
 
23
- interface SegmentDefinition {
23
+ interface FragmentDefinition {
24
24
  meta: {
25
25
  name: string;
26
26
  description?: string;
27
+ category?: string;
27
28
  };
28
- variants?: SegmentVariant[];
29
+ variants?: FragmentVariant[];
29
30
  }
30
31
 
31
- interface SegmentItem {
32
+ interface FragmentItem {
32
33
  path: string;
33
- segment: SegmentDefinition;
34
+ fragment: FragmentDefinition;
34
35
  }
35
36
 
36
- // Cached segments
37
- let cachedSegments: SegmentItem[] | null = null;
38
- let segmentsPromise: Promise<SegmentItem[]> | null = null;
37
+ // Cached fragments
38
+ let cachedFragments: FragmentItem[] | null = null;
39
+ let fragmentsPromise: Promise<FragmentItem[]> | null = null;
39
40
 
40
41
  /**
41
- * Load segments from the virtual module
42
+ * Load fragments from the virtual module
42
43
  */
43
- async function loadSegments(): Promise<SegmentItem[]> {
44
- if (cachedSegments) {
45
- return cachedSegments;
44
+ async function loadFragments(): Promise<FragmentItem[]> {
45
+ if (cachedFragments) {
46
+ return cachedFragments;
46
47
  }
47
48
 
48
- if (segmentsPromise) {
49
- return segmentsPromise;
49
+ if (fragmentsPromise) {
50
+ return fragmentsPromise;
50
51
  }
51
52
 
52
- segmentsPromise = (async () => {
53
+ fragmentsPromise = (async () => {
53
54
  try {
54
55
  // @ts-expect-error Virtual module
55
56
  const module = await import('virtual:fragments');
56
- if (module.segmentsPromise) {
57
- cachedSegments = await module.segmentsPromise;
57
+ if (module.fragmentsPromise) {
58
+ cachedFragments = await module.fragmentsPromise;
58
59
  } else {
59
- cachedSegments = module.segments || [];
60
+ cachedFragments = module.fragments || [];
60
61
  }
61
- return cachedSegments!;
62
+ return cachedFragments!;
62
63
  } catch (error) {
63
- console.error('[PreviewFrameHost] Failed to load segments:', error);
64
+ console.error('[PreviewFrameHost] Failed to load fragments:', error);
64
65
  throw error;
65
66
  }
66
67
  })();
67
68
 
68
- return segmentsPromise;
69
+ return fragmentsPromise;
69
70
  }
70
71
 
71
72
  /**
72
- * Find a segment by its path
73
+ * Find a fragment by its path
73
74
  */
74
- function findSegmentByPath(segments: SegmentItem[], path: string): SegmentItem | undefined {
75
- return segments.find(s => s.path === path);
75
+ function findFragmentByPath(fragments: FragmentItem[], path: string): FragmentItem | undefined {
76
+ return fragments.find(s => s.path === path);
76
77
  }
77
78
 
78
79
  /**
79
- * Find a variant by name within a segment
80
+ * Find a variant by name within a fragment
80
81
  */
81
- function findVariant(segment: SegmentDefinition, variantName: string): SegmentVariant | undefined {
82
- return segment.variants?.find(v => v.name === variantName);
82
+ function findVariant(fragment: FragmentDefinition, variantName: string): FragmentVariant | undefined {
83
+ return fragment.variants?.find(v => v.name === variantName);
84
+ }
85
+
86
+ type PreviewMode = 'centered' | 'full-bleed';
87
+
88
+ function resolvePreviewMode(fragment: FragmentDefinition): PreviewMode {
89
+ const name = fragment.meta.name.toLowerCase();
90
+ const category = (fragment.meta.category || '').toLowerCase();
91
+
92
+ if (category === 'layout' || category === 'navigation') {
93
+ return 'full-bleed';
94
+ }
95
+
96
+ if (name.includes('appshell') || name.includes('sidebar') || name.includes('header') || name.includes('layout')) {
97
+ return 'full-bleed';
98
+ }
99
+
100
+ return 'centered';
83
101
  }
84
102
 
85
103
  /**
@@ -118,11 +136,13 @@ function LoadingIndicator() {
118
136
  function VariantRenderer({
119
137
  variant,
120
138
  props,
139
+ mode,
121
140
  onRendered,
122
141
  onError,
123
142
  }: {
124
- variant: SegmentVariant;
143
+ variant: FragmentVariant;
125
144
  props?: Record<string, unknown>;
145
+ mode: PreviewMode;
126
146
  onRendered: (width: number, height: number) => void;
127
147
  onError: (message: string, stack?: string) => void;
128
148
  }) {
@@ -208,7 +228,9 @@ function VariantRenderer({
208
228
  <div
209
229
  ref={containerRef}
210
230
  style={{
211
- display: 'inline-block',
231
+ display: mode === 'full-bleed' ? 'block' : 'inline-block',
232
+ width: mode === 'full-bleed' ? '100%' : undefined,
233
+ minHeight: mode === 'full-bleed' ? '100vh' : undefined,
212
234
  transition: 'opacity 150ms',
213
235
  opacity: content ? 1 : 0,
214
236
  }}
@@ -223,10 +245,11 @@ function VariantRenderer({
223
245
  */
224
246
  export function PreviewFrameHost() {
225
247
  const { renderRequest, theme, notifyReady, notifyRendered, notifyError } = useFrameBridge();
226
- const [segments, setSegments] = useState<SegmentItem[] | null>(null);
248
+ const [fragments, setFragments] = useState<FragmentItem[] | null>(null);
227
249
  const [loadError, setLoadError] = useState<string | null>(null);
228
- const [currentVariant, setCurrentVariant] = useState<SegmentVariant | null>(null);
250
+ const [currentVariant, setCurrentVariant] = useState<FragmentVariant | null>(null);
229
251
  const [currentProps, setCurrentProps] = useState<Record<string, unknown> | undefined>(undefined);
252
+ const [previewMode, setPreviewMode] = useState<PreviewMode>('centered');
230
253
 
231
254
  // Apply theme to document
232
255
  useEffect(() => {
@@ -237,15 +260,19 @@ export function PreviewFrameHost() {
237
260
  }
238
261
  }, [theme]);
239
262
 
240
- // Load segments on mount
241
263
  useEffect(() => {
242
- loadSegments()
264
+ document.body.setAttribute('data-preview-mode', previewMode);
265
+ }, [previewMode]);
266
+
267
+ // Load fragments on mount
268
+ useEffect(() => {
269
+ loadFragments()
243
270
  .then(segs => {
244
- setSegments(segs);
271
+ setFragments(segs);
245
272
  notifyReady();
246
273
  })
247
274
  .catch(err => {
248
- const message = err instanceof Error ? err.message : 'Failed to load segments';
275
+ const message = err instanceof Error ? err.message : 'Failed to load fragments';
249
276
  setLoadError(message);
250
277
  notifyError(message);
251
278
  });
@@ -253,32 +280,33 @@ export function PreviewFrameHost() {
253
280
 
254
281
  // Handle render requests
255
282
  useEffect(() => {
256
- if (!renderRequest || !segments) return;
283
+ if (!renderRequest || !fragments) return;
257
284
 
258
- const { segmentPath, variantName, props } = renderRequest;
285
+ const { fragmentPath, variantName, props } = renderRequest;
259
286
 
260
- // Find segment
261
- const segmentItem = findSegmentByPath(segments, segmentPath);
262
- if (!segmentItem) {
263
- notifyError(`Segment not found: ${segmentPath}`);
287
+ // Find fragment
288
+ const fragmentItem = findFragmentByPath(fragments, fragmentPath);
289
+ if (!fragmentItem) {
290
+ notifyError(`Fragment not found: ${fragmentPath}`);
264
291
  setCurrentVariant(null);
265
292
  return;
266
293
  }
267
294
 
268
295
  // Find variant
269
- const variant = findVariant(segmentItem.segment, variantName);
296
+ const variant = findVariant(fragmentItem.fragment, variantName);
270
297
  if (!variant) {
271
- notifyError(`Variant not found: ${variantName} in ${segmentPath}`);
298
+ notifyError(`Variant not found: ${variantName} in ${fragmentPath}`);
272
299
  setCurrentVariant(null);
273
300
  return;
274
301
  }
275
302
 
303
+ setPreviewMode(resolvePreviewMode(fragmentItem.fragment));
276
304
  setCurrentVariant(variant);
277
305
  setCurrentProps(props);
278
- }, [renderRequest, segments, notifyError]);
306
+ }, [renderRequest, fragments, notifyError]);
279
307
 
280
308
  // Show loading state
281
- if (!segments && !loadError) {
309
+ if (!fragments && !loadError) {
282
310
  return <LoadingIndicator />;
283
311
  }
284
312
 
@@ -299,9 +327,10 @@ export function PreviewFrameHost() {
299
327
  // Render the variant
300
328
  return (
301
329
  <VariantRenderer
302
- key={`${renderRequest?.segmentPath}-${renderRequest?.variantName}`}
330
+ key={`${renderRequest?.fragmentPath}-${renderRequest?.variantName}`}
303
331
  variant={currentVariant}
304
332
  props={currentProps}
333
+ mode={previewMode}
305
334
  onRendered={notifyRendered}
306
335
  onError={notifyError}
307
336
  />
@@ -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: '\u25FB' },
17
- { value: 'black', label: 'Black', icon: '\u25FC' },
18
- { value: 'checkerboard', label: 'Checkerboard', icon: '\u25A6' },
19
- { value: 'transparent', label: 'Transparent', icon: '\u25C7' },
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;
@@ -102,10 +151,8 @@ export function PreviewToolbar({
102
151
  <Menu.Trigger asChild>
103
152
  <Button variant="ghost" size="sm" title="Background color">
104
153
  <Stack direction="row" gap="xs" align="center">
105
- <span style={{ fontSize: '14px' }}>
106
- {BACKGROUND_OPTIONS_UI.find(o => o.value === background)?.icon}
107
- </span>
108
- <span style={{ textTransform: 'capitalize' }}>{background}</span>
154
+ <BackgroundSwatch background={background} />
155
+ <span>{BACKGROUND_OPTIONS_UI.find(o => o.value === background)?.label}</span>
109
156
  <span style={{ display: 'inline-flex', width: '12px', height: '12px' }}>
110
157
  <ChevronDownIcon />
111
158
  </span>
@@ -120,7 +167,7 @@ export function PreviewToolbar({
120
167
  {BACKGROUND_OPTIONS_UI.map((option) => (
121
168
  <Menu.RadioItem key={option.value} value={option.value}>
122
169
  <Stack direction="row" gap="sm" align="center">
123
- <span style={{ fontSize: '14px' }}>{option.icon}</span>
170
+ <BackgroundSwatch background={option.value} />
124
171
  {option.label}
125
172
  </Stack>
126
173
  </Menu.RadioItem>
@@ -1,9 +1,9 @@
1
- import type { SegmentDefinition } from '../../core/index.js';
1
+ import type { FragmentDefinition } from '../../core/index.js';
2
2
  import { useScrollSpy } from '../hooks/useScrollSpy.js';
3
3
  import { Sidebar } from '@fragments/ui';
4
4
 
5
5
  interface RightSidebarProps {
6
- segment: SegmentDefinition;
6
+ fragment: FragmentDefinition;
7
7
  }
8
8
 
9
9
  interface TocItem {
@@ -12,19 +12,19 @@ interface TocItem {
12
12
  children?: TocItem[];
13
13
  }
14
14
 
15
- export function RightSidebar({ segment }: RightSidebarProps) {
16
- // Build table of contents from segment
15
+ export function RightSidebar({ fragment }: RightSidebarProps) {
16
+ // Build table of contents from fragment
17
17
  const tocItems: TocItem[] = [];
18
18
 
19
19
  // Overview section
20
20
  tocItems.push({ id: 'overview', label: 'Overview' });
21
21
 
22
22
  // Variants section with nested items
23
- if (segment.variants && segment.variants.length > 0) {
23
+ if (fragment.variants && fragment.variants.length > 0) {
24
24
  tocItems.push({
25
25
  id: 'variants',
26
26
  label: 'Variants',
27
- children: segment.variants.map((variant, index) => ({
27
+ children: fragment.variants.map((variant, index) => ({
28
28
  id: `variant-${index}`,
29
29
  label: variant.name,
30
30
  })),
@@ -32,17 +32,17 @@ export function RightSidebar({ segment }: RightSidebarProps) {
32
32
  }
33
33
 
34
34
  // Usage section
35
- if (segment.usage) {
35
+ if (fragment.usage) {
36
36
  tocItems.push({ id: 'usage', label: 'Usage' });
37
37
  }
38
38
 
39
39
  // Props section
40
- if (segment.props && Object.keys(segment.props).length > 0) {
40
+ if (fragment.props && Object.keys(fragment.props).length > 0) {
41
41
  tocItems.push({ id: 'props', label: 'Props' });
42
42
  }
43
43
 
44
44
  // Relations section
45
- if (segment.relations && segment.relations.length > 0) {
45
+ if (fragment.relations && fragment.relations.length > 0) {
46
46
  tocItems.push({ id: 'relations', label: 'Relations' });
47
47
  }
48
48
 
@@ -1,21 +1,21 @@
1
1
  import React, { useState, useMemo } from 'react';
2
- import type { SegmentDefinition } from '../../core/index.js';
2
+ import type { FragmentDefinition } from '../../core/index.js';
3
3
 
4
4
  interface SidebarProps {
5
- segments: Array<{ path: string; segment: SegmentDefinition }>;
6
- activeSegment: string | null;
5
+ fragments: Array<{ path: string; fragment: FragmentDefinition }>;
6
+ activeFragment: string | null;
7
7
  onSelect: (path: string) => void;
8
8
  }
9
9
 
10
- export function Sidebar({ segments, activeSegment, onSelect }: SidebarProps): React.ReactElement {
10
+ export function Sidebar({ fragments, activeFragment, onSelect }: SidebarProps): React.ReactElement {
11
11
  const [search, setSearch] = useState('');
12
12
 
13
- // Group segments by category
13
+ // Group fragments by category
14
14
  const grouped = useMemo(() => {
15
- const groups: Record<string, typeof segments> = {};
15
+ const groups: Record<string, typeof fragments> = {};
16
16
 
17
- for (const item of segments) {
18
- const category = item.segment.meta.category || 'uncategorized';
17
+ for (const item of fragments) {
18
+ const category = item.fragment.meta.category || 'uncategorized';
19
19
  if (!groups[category]) {
20
20
  groups[category] = [];
21
21
  }
@@ -24,12 +24,12 @@ export function Sidebar({ segments, activeSegment, onSelect }: SidebarProps): Re
24
24
 
25
25
  // Filter by search
26
26
  if (search) {
27
- const filtered: Record<string, typeof segments> = {};
27
+ const filtered: Record<string, typeof fragments> = {};
28
28
  for (const [category, items] of Object.entries(groups)) {
29
29
  const matchingItems = items.filter(
30
30
  (item) =>
31
- item.segment.meta.name.toLowerCase().includes(search.toLowerCase()) ||
32
- item.segment.meta.description.toLowerCase().includes(search.toLowerCase())
31
+ item.fragment.meta.name.toLowerCase().includes(search.toLowerCase()) ||
32
+ item.fragment.meta.description.toLowerCase().includes(search.toLowerCase())
33
33
  );
34
34
  if (matchingItems.length > 0) {
35
35
  filtered[category] = matchingItems;
@@ -39,7 +39,7 @@ export function Sidebar({ segments, activeSegment, onSelect }: SidebarProps): Re
39
39
  }
40
40
 
41
41
  return groups;
42
- }, [segments, search]);
42
+ }, [fragments, search]);
43
43
 
44
44
  return (
45
45
  <div
@@ -68,7 +68,7 @@ export function Sidebar({ segments, activeSegment, onSelect }: SidebarProps): Re
68
68
  color: '#111827',
69
69
  }}
70
70
  >
71
- Segments
71
+ Fragments
72
72
  </h1>
73
73
  <p
74
74
  style={{
@@ -77,7 +77,7 @@ export function Sidebar({ segments, activeSegment, onSelect }: SidebarProps): Re
77
77
  color: '#6b7280',
78
78
  }}
79
79
  >
80
- {segments.length} component{segments.length !== 1 ? 's' : ''}
80
+ {fragments.length} component{fragments.length !== 1 ? 's' : ''}
81
81
  </p>
82
82
  </div>
83
83
 
@@ -132,7 +132,7 @@ export function Sidebar({ segments, activeSegment, onSelect }: SidebarProps): Re
132
132
  padding: '8px 12px',
133
133
  border: 'none',
134
134
  borderRadius: '6px',
135
- background: activeSegment === item.path ? '#e5e7eb' : 'transparent',
135
+ background: activeFragment === item.path ? '#e5e7eb' : 'transparent',
136
136
  textAlign: 'left',
137
137
  cursor: 'pointer',
138
138
  transition: 'background 0.15s',
@@ -145,7 +145,7 @@ export function Sidebar({ segments, activeSegment, onSelect }: SidebarProps): Re
145
145
  color: '#111827',
146
146
  }}
147
147
  >
148
- {item.segment.meta.name}
148
+ {item.fragment.meta.name}
149
149
  </div>
150
150
  <div
151
151
  style={{
@@ -157,7 +157,7 @@ export function Sidebar({ segments, activeSegment, onSelect }: SidebarProps): Re
157
157
  whiteSpace: 'nowrap',
158
158
  }}
159
159
  >
160
- {item.segment.meta.description}
160
+ {item.fragment.meta.description}
161
161
  </div>
162
162
  </button>
163
163
  ))}
@@ -1,9 +1,9 @@
1
1
  import { useState, useEffect, useMemo, type ReactNode } from "react";
2
- import type { SegmentVariant } from "../../core/index.js";
2
+ import type { FragmentVariant } from "../../core/index.js";
3
3
 
4
4
  interface StoryRendererProps {
5
5
  /** The variant to render */
6
- variant: SegmentVariant;
6
+ variant: FragmentVariant;
7
7
  /** Children render function - receives rendered content */
8
8
  children: (content: ReactNode | null, isLoading: boolean, error: Error | null) => ReactNode;
9
9
  }
@@ -164,7 +164,7 @@ export function TokenStylePanel({
164
164
  setTokenError(null);
165
165
 
166
166
  try {
167
- const response = await fetch("/segments/tokens");
167
+ const response = await fetch("/fragments/tokens");
168
168
 
169
169
  if (!response.ok) {
170
170
  const data = await response.json();
@@ -1,8 +1,8 @@
1
- import type { SegmentUsage } from '../../core/index.js';
1
+ import type { FragmentUsage } from '../../core/index.js';
2
2
  import { CheckIcon, XIcon, AccessibilityIcon } from './Icons.js';
3
3
 
4
4
  interface UsageSectionProps {
5
- usage: SegmentUsage;
5
+ usage: FragmentUsage;
6
6
  }
7
7
 
8
8
  export function UsageSection({ usage }: UsageSectionProps) {
@@ -12,7 +12,7 @@
12
12
 
13
13
  import { useState, useMemo, useRef, useCallback } from "react";
14
14
  import { useVirtualizer } from "@tanstack/react-virtual";
15
- import type { SegmentVariant } from "../../core/index.js";
15
+ import type { FragmentVariant } from "../../core/index.js";
16
16
  import { ErrorBoundary } from "./ErrorBoundary.js";
17
17
  import { StoryRenderer, LoaderIndicator } from "./StoryRenderer.js";
18
18
  import { IsolatedPreviewFrame } from "./IsolatedPreviewFrame.js";
@@ -21,11 +21,11 @@ import { getBackgroundStyle, type BackgroundOption } from "./PreviewToolbar.js";
21
21
 
22
22
  interface VariantMatrixProps {
23
23
  /** All variants to display */
24
- variants: SegmentVariant[];
24
+ variants: FragmentVariant[];
25
25
  /** Component name for error display */
26
26
  componentName: string;
27
- /** Segment path for iframe rendering */
28
- segmentPath: string;
27
+ /** Fragment path for iframe rendering */
28
+ fragmentPath: string;
29
29
  /** Current zoom level */
30
30
  zoom: number;
31
31
  /** Preview theme */
@@ -60,7 +60,7 @@ const VIRTUALIZATION_THRESHOLD = 12;
60
60
  export function VariantMatrix({
61
61
  variants,
62
62
  componentName,
63
- segmentPath,
63
+ fragmentPath,
64
64
  zoom,
65
65
  previewTheme,
66
66
  background,
@@ -204,7 +204,7 @@ export function VariantMatrix({
204
204
  variant={variant}
205
205
  index={index}
206
206
  componentName={componentName}
207
- segmentPath={segmentPath}
207
+ fragmentPath={fragmentPath}
208
208
  scale={effectiveScale}
209
209
  minHeight={gridConfig.minHeight}
210
210
  previewTheme={previewTheme}
@@ -236,7 +236,7 @@ export function VariantMatrix({
236
236
  variant={variant}
237
237
  index={index}
238
238
  componentName={componentName}
239
- segmentPath={segmentPath}
239
+ fragmentPath={fragmentPath}
240
240
  scale={effectiveScale}
241
241
  minHeight={gridConfig.minHeight}
242
242
  previewTheme={previewTheme}
@@ -256,10 +256,10 @@ export function VariantMatrix({
256
256
  }
257
257
 
258
258
  interface VariantCardProps {
259
- variant: SegmentVariant;
259
+ variant: FragmentVariant;
260
260
  index: number;
261
261
  componentName: string;
262
- segmentPath: string;
262
+ fragmentPath: string;
263
263
  scale: number;
264
264
  minHeight: string;
265
265
  previewTheme: "light" | "dark";
@@ -275,7 +275,7 @@ function VariantCard({
275
275
  variant,
276
276
  index,
277
277
  componentName,
278
- segmentPath,
278
+ fragmentPath,
279
279
  scale,
280
280
  minHeight,
281
281
  previewTheme,
@@ -378,7 +378,7 @@ function VariantCard({
378
378
  >
379
379
  {useIframeIsolation ? (
380
380
  <IsolatedPreviewFrame
381
- segmentPath={segmentPath}
381
+ fragmentPath={fragmentPath}
382
382
  variantName={variant.name}
383
383
  theme={previewTheme}
384
384
  width="100%"
@@ -1,11 +1,11 @@
1
1
  // @ts-nocheck
2
2
  import React, { type ReactNode, Suspense } from 'react';
3
- import type { SegmentVariant } from '../../core/index.js';
3
+ import type { FragmentVariant } from '../../core/index.js';
4
4
  import { ErrorBoundary } from './ErrorBoundary.js';
5
5
 
6
6
  interface VariantRendererProps {
7
7
  /** The variant to render */
8
- variant: SegmentVariant;
8
+ variant: FragmentVariant;
9
9
 
10
10
  /** Optional loading fallback for async components */
11
11
  loadingFallback?: ReactNode;
@@ -54,7 +54,7 @@ export function VariantRenderer({
54
54
 
55
55
  interface VariantGridProps {
56
56
  /** Variants to render */
57
- variants: SegmentVariant[];
57
+ variants: FragmentVariant[];
58
58
 
59
59
  /** Number of columns in the grid */
60
60
  columns?: number;
@@ -1,9 +1,9 @@
1
1
  import { Tabs } from '@fragments/ui';
2
- import type { SegmentVariant } from '../../core/index.js';
2
+ import type { FragmentVariant } from '../../core/index.js';
3
3
  import { PlayIcon } from './Icons.js';
4
4
 
5
5
  interface VariantTabsProps {
6
- variants: SegmentVariant[];
6
+ variants: FragmentVariant[];
7
7
  activeIndex: number;
8
8
  onSelect: (index: number) => void;
9
9
  }