@fragments-sdk/cli 0.7.12 → 0.7.13

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fragments-sdk/cli",
3
- "version": "0.7.12",
3
+ "version": "0.7.13",
4
4
  "license": "FSL-1.1-MIT",
5
5
  "description": "CLI, MCP server, and dev tools for Fragments design system",
6
6
  "author": "Conan McNicholl",
@@ -15,7 +15,6 @@ import { useToast } from "./Toast.js";
15
15
 
16
16
  // Toolbar
17
17
  import { PreviewToolbar } from "./PreviewToolbar.js";
18
- import { getBackgroundStyle } from "../constants/ui.js";
19
18
 
20
19
  // Preview & Rendering
21
20
  import { PreviewArea } from "./PreviewArea.js";
@@ -65,16 +64,14 @@ export function App({ fragments }: AppProps) {
65
64
  // UI state (modals, panels, view modes)
66
65
  const { state: uiState, actions: uiActions } = useAppState();
67
66
 
68
- // View settings (zoom, background, viewport, theme)
67
+ // View settings (zoom, viewport, theme)
69
68
  const viewSettings = useViewSettings({
70
69
  initialState: {
71
70
  zoom: urlState.zoom as any,
72
- background: urlState.background as any,
73
71
  viewport: urlState.viewport as any,
74
72
  customSize: { width: urlState.customWidth, height: urlState.customHeight },
75
73
  },
76
74
  onZoomChange: (zoom) => setUrlViewSettings({ zoom }),
77
- onBackgroundChange: (bg) => setUrlViewSettings({ background: bg }),
78
75
  onViewportChange: (vp, size) => setUrlViewSettings({
79
76
  viewport: vp,
80
77
  customWidth: size?.width,
@@ -386,6 +383,7 @@ export function App({ fragments }: AppProps) {
386
383
  activeFragment && !uiState.showHealthDashboard ? (
387
384
  <TopToolbar
388
385
  fragment={activeFragment}
386
+ viewSettings={viewSettings}
389
387
  uiState={uiState}
390
388
  uiActions={uiActions}
391
389
  figmaUrl={figmaUrl}
@@ -450,19 +448,6 @@ export function App({ fragments }: AppProps) {
450
448
  <div id="preview-layout" style={{ display: 'flex', height: '100%', flexDirection: panelDock === "bottom" ? 'column' : 'row' }}>
451
449
  {/* Main Content Area */}
452
450
  <div style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0, minHeight: 0 }}>
453
- <PreviewControlsBar
454
- zoom={viewSettings.zoom}
455
- background={viewSettings.background}
456
- onZoomChange={viewSettings.setZoom}
457
- onBackgroundChange={viewSettings.setBackground}
458
- showMatrixView={uiState.showMatrixView}
459
- showMultiViewport={uiState.showMultiViewport}
460
- panelOpen={uiState.panelOpen}
461
- onToggleMatrix={() => uiActions.setMatrixView(!uiState.showMatrixView)}
462
- onToggleMultiViewport={() => uiActions.setMultiViewport(!uiState.showMultiViewport)}
463
- onTogglePanel={uiActions.togglePanel}
464
- />
465
-
466
451
  {/* Preview Area */}
467
452
  <div
468
453
  id="preview-canvas"
@@ -470,7 +455,6 @@ export function App({ fragments }: AppProps) {
470
455
  flex: 1,
471
456
  overflow: 'auto',
472
457
  position: 'relative',
473
- ...(uiState.showMatrixView ? {} : getBackgroundStyle(viewSettings.background)),
474
458
  }}
475
459
  >
476
460
  {variantCount === 0 ? (
@@ -482,7 +466,6 @@ export function App({ fragments }: AppProps) {
482
466
  variants={variants}
483
467
  focusedVariantIndex={safeVariantIndex}
484
468
  zoom={viewSettings.zoom}
485
- background={viewSettings.background}
486
469
  viewport={viewSettings.viewport}
487
470
  customSize={viewSettings.customSize}
488
471
  previewTheme={resolvedTheme}
@@ -500,7 +483,6 @@ export function App({ fragments }: AppProps) {
500
483
  variant={activeVariant}
501
484
  variants={variants}
502
485
  zoom={viewSettings.zoom}
503
- background={viewSettings.background}
504
486
  viewport={viewSettings.viewport}
505
487
  customSize={viewSettings.customSize}
506
488
  previewTheme={resolvedTheme}
@@ -566,6 +548,7 @@ export function App({ fragments }: AppProps) {
566
548
  // Top Toolbar Component
567
549
  interface TopToolbarProps {
568
550
  fragment: { path: string; fragment: FragmentDefinition };
551
+ viewSettings: ReturnType<typeof useViewSettings>;
569
552
  uiState: ReturnType<typeof useAppState>['state'];
570
553
  uiActions: ReturnType<typeof useAppState>['actions'];
571
554
  figmaUrl?: string;
@@ -764,6 +747,7 @@ function PreviewAside({
764
747
 
765
748
  function TopToolbar({
766
749
  fragment,
750
+ viewSettings,
767
751
  uiState,
768
752
  uiActions,
769
753
  figmaUrl,
@@ -785,6 +769,48 @@ function TopToolbar({
785
769
  <HeaderSearch value={searchQuery} onChange={onSearchChange} inputRef={searchInputRef} />
786
770
  <Header.Spacer />
787
771
  <Header.Actions>
772
+ <PreviewToolbar
773
+ zoom={viewSettings.zoom}
774
+ onZoomChange={viewSettings.setZoom}
775
+ />
776
+ <Separator orientation="vertical" style={{ height: '16px' }} />
777
+ <Tooltip content={uiState.showMatrixView ? "Disable matrix view" : "Enable matrix view"}>
778
+ <Button
779
+ variant="ghost"
780
+ size="sm"
781
+ aria-pressed={uiState.showMatrixView}
782
+ aria-label="Toggle matrix view"
783
+ onClick={() => uiActions.setMatrixView(!uiState.showMatrixView)}
784
+ style={uiState.showMatrixView ? { color: 'var(--color-accent)', backgroundColor: 'var(--bg-hover)' } : {}}
785
+ >
786
+ <GridFour size={16} />
787
+ </Button>
788
+ </Tooltip>
789
+ <Tooltip content={uiState.showMultiViewport ? "Disable responsive view" : "Enable responsive view"}>
790
+ <Button
791
+ variant="ghost"
792
+ size="sm"
793
+ aria-pressed={uiState.showMultiViewport}
794
+ aria-label="Toggle responsive view"
795
+ onClick={() => uiActions.setMultiViewport(!uiState.showMultiViewport)}
796
+ style={uiState.showMultiViewport ? { color: 'var(--color-accent)', backgroundColor: 'var(--bg-hover)' } : {}}
797
+ >
798
+ <DeviceMobile size={16} />
799
+ </Button>
800
+ </Tooltip>
801
+ <Tooltip content={uiState.panelOpen ? "Hide addons panel" : "Show addons panel"}>
802
+ <Button
803
+ variant="ghost"
804
+ size="sm"
805
+ aria-pressed={uiState.panelOpen}
806
+ aria-label="Toggle addons panel"
807
+ onClick={uiActions.togglePanel}
808
+ style={uiState.panelOpen ? { color: 'var(--color-accent)', backgroundColor: 'var(--bg-hover)' } : {}}
809
+ >
810
+ <Rows size={16} />
811
+ </Button>
812
+ </Tooltip>
813
+ <Separator orientation="vertical" style={{ height: '16px' }} />
788
814
  {figmaUrl && (
789
815
  <>
790
816
  <Tooltip content={uiState.showComparison ? "Hide Figma comparison" : "Compare with Figma design"}>
@@ -851,93 +877,12 @@ function getVariantSectionId(componentName: string, variantName: string): string
851
877
  return `preview-${normalizeAnchorSegment(componentName)}-${normalizeAnchorSegment(variantName)}`;
852
878
  }
853
879
 
854
- interface PreviewControlsBarProps {
855
- zoom: ReturnType<typeof useViewSettings>["zoom"];
856
- background: ReturnType<typeof useViewSettings>["background"];
857
- onZoomChange: ReturnType<typeof useViewSettings>["setZoom"];
858
- onBackgroundChange: ReturnType<typeof useViewSettings>["setBackground"];
859
- showMatrixView: boolean;
860
- showMultiViewport: boolean;
861
- panelOpen: boolean;
862
- onToggleMatrix: () => void;
863
- onToggleMultiViewport: () => void;
864
- onTogglePanel: () => void;
865
- }
866
-
867
- function PreviewControlsBar({
868
- zoom,
869
- background,
870
- onZoomChange,
871
- onBackgroundChange,
872
- showMatrixView,
873
- showMultiViewport,
874
- panelOpen,
875
- onToggleMatrix,
876
- onToggleMultiViewport,
877
- onTogglePanel,
878
- }: PreviewControlsBarProps) {
879
- const toggleButtonStyle = (active: boolean): CSSProperties => (
880
- active ? { color: 'var(--color-accent)', backgroundColor: 'var(--bg-hover)' } : {}
881
- );
882
-
883
- return (
884
- <div style={{ padding: '8px 16px', borderBottom: '1px solid var(--border)', backgroundColor: 'var(--bg-primary)', flexShrink: 0 }}>
885
- <Stack direction="row" gap="sm" align="center" justify="end">
886
- <PreviewToolbar
887
- zoom={zoom}
888
- background={background}
889
- onZoomChange={onZoomChange}
890
- onBackgroundChange={onBackgroundChange}
891
- />
892
- <Separator orientation="vertical" style={{ height: '16px' }} />
893
- <Tooltip content={showMatrixView ? "Disable matrix view" : "Enable matrix view"}>
894
- <Button
895
- variant="ghost"
896
- size="sm"
897
- aria-pressed={showMatrixView}
898
- aria-label="Toggle matrix view"
899
- onClick={onToggleMatrix}
900
- style={toggleButtonStyle(showMatrixView)}
901
- >
902
- <GridFour size={16} />
903
- </Button>
904
- </Tooltip>
905
- <Tooltip content={showMultiViewport ? "Disable responsive view" : "Enable responsive view"}>
906
- <Button
907
- variant="ghost"
908
- size="sm"
909
- aria-pressed={showMultiViewport}
910
- aria-label="Toggle responsive view"
911
- onClick={onToggleMultiViewport}
912
- style={toggleButtonStyle(showMultiViewport)}
913
- >
914
- <DeviceMobile size={16} />
915
- </Button>
916
- </Tooltip>
917
- <Tooltip content={panelOpen ? "Hide addons panel" : "Show addons panel"}>
918
- <Button
919
- variant="ghost"
920
- size="sm"
921
- aria-pressed={panelOpen}
922
- aria-label="Toggle addons panel"
923
- onClick={onTogglePanel}
924
- style={toggleButtonStyle(panelOpen)}
925
- >
926
- <Rows size={16} />
927
- </Button>
928
- </Tooltip>
929
- </Stack>
930
- </div>
931
- );
932
- }
933
-
934
880
  interface AllVariantsPreviewProps {
935
881
  componentName: string;
936
882
  fragmentPath: string;
937
883
  variants: FragmentVariant[];
938
884
  focusedVariantIndex: number;
939
885
  zoom: ReturnType<typeof useViewSettings>["zoom"];
940
- background: ReturnType<typeof useViewSettings>["background"];
941
886
  viewport: ReturnType<typeof useViewSettings>["viewport"];
942
887
  customSize: ReturnType<typeof useViewSettings>["customSize"];
943
888
  previewTheme: ReturnType<typeof useTheme>["resolvedTheme"];
@@ -955,7 +900,6 @@ function AllVariantsPreview({
955
900
  variants,
956
901
  focusedVariantIndex,
957
902
  zoom,
958
- background,
959
903
  viewport,
960
904
  customSize,
961
905
  previewTheme,
@@ -994,7 +938,6 @@ function AllVariantsPreview({
994
938
  variant={variant}
995
939
  variants={variants}
996
940
  zoom={zoom}
997
- background={background}
998
941
  viewport={viewport}
999
942
  customSize={customSize}
1000
943
  previewTheme={previewTheme}
@@ -1,7 +1,7 @@
1
1
  import { useMemo, useEffect, useState } from "react";
2
2
  import type { FragmentDefinition } from "../../core/index.js";
3
3
  import { VariantRenderer } from "./VariantRenderer.js";
4
- import { getBackgroundStyle, type BackgroundOption, type ZoomLevel } from "../constants/ui.js";
4
+ import { type ZoomLevel } from "../constants/ui.js";
5
5
 
6
6
  interface IsolatedRenderProps {
7
7
  fragments: Array<{ path: string; fragment: FragmentDefinition }>;
@@ -10,7 +10,7 @@ interface IsolatedRenderProps {
10
10
  /**
11
11
  * Isolated render component for screenshot capture and standalone viewing.
12
12
  * Renders a single variant with minimal UI for visual testing.
13
- * URL params: ?isolated=true&component=Name&variant=VariantName&zoom=100&bg=white&theme=light
13
+ * URL params: ?isolated=true&component=Name&variant=VariantName&zoom=100&theme=light
14
14
  */
15
15
  export function IsolatedRender({ fragments }: IsolatedRenderProps) {
16
16
  const [ready, setReady] = useState(false);
@@ -19,15 +19,11 @@ export function IsolatedRender({ fragments }: IsolatedRenderProps) {
19
19
  const params = useMemo(() => {
20
20
  const searchParams = new URLSearchParams(window.location.search);
21
21
  const zoomParam = parseInt(searchParams.get("zoom") || "100", 10);
22
- const bgParam = searchParams.get("bg") || "white";
23
22
  return {
24
23
  component: searchParams.get("component"),
25
24
  variant: searchParams.get("variant"),
26
25
  theme: searchParams.get("theme") || "light",
27
26
  zoom: [50, 75, 100, 150, 200].includes(zoomParam) ? zoomParam as ZoomLevel : 100 as ZoomLevel,
28
- background: ["white", "black", "checkerboard", "transparent"].includes(bgParam)
29
- ? bgParam as BackgroundOption
30
- : "white" as BackgroundOption,
31
27
  };
32
28
  }, []);
33
29
 
@@ -101,7 +97,7 @@ export function IsolatedRender({ fragments }: IsolatedRenderProps) {
101
97
  display: 'flex',
102
98
  alignItems: 'center',
103
99
  justifyContent: 'center',
104
- ...getBackgroundStyle(params.background),
100
+ backgroundColor: 'var(--bg-primary)',
105
101
  }}
106
102
  >
107
103
  <div
@@ -10,7 +10,6 @@ import { useState, type ReactNode } from "react";
10
10
  import { ErrorBoundary } from "./ErrorBoundary.js";
11
11
  import { IsolatedPreviewFrame } from "./IsolatedPreviewFrame.js";
12
12
  import { ChevronDownIcon } from "./Icons.js";
13
- import { getBackgroundStyle, type BackgroundOption } from "../constants/ui.js";
14
13
 
15
14
  interface ViewportConfig {
16
15
  name: string;
@@ -50,8 +49,6 @@ interface MultiViewportPreviewProps {
50
49
  renderContent: () => ReactNode;
51
50
  /** Preview theme */
52
51
  previewTheme: "light" | "dark";
53
- /** Background option for preview */
54
- background: BackgroundOption;
55
52
  /** Base zoom level (used for scaling if needed) */
56
53
  zoom: number;
57
54
  /** Whether to use iframe isolation */
@@ -64,7 +61,6 @@ export function MultiViewportPreview({
64
61
  variantName,
65
62
  renderContent,
66
63
  previewTheme,
67
- background,
68
64
  zoom,
69
65
  useIframeIsolation = true,
70
66
  }: MultiViewportPreviewProps) {
@@ -207,7 +203,6 @@ export function MultiViewportPreview({
207
203
  variantName={variantName}
208
204
  renderContent={renderContent}
209
205
  previewTheme={previewTheme}
210
- background={background}
211
206
  useIframeIsolation={useIframeIsolation}
212
207
  />
213
208
  ))}
@@ -224,7 +219,6 @@ interface ViewportPanelProps {
224
219
  variantName: string;
225
220
  renderContent: () => ReactNode;
226
221
  previewTheme: "light" | "dark";
227
- background: BackgroundOption;
228
222
  useIframeIsolation: boolean;
229
223
  }
230
224
 
@@ -235,7 +229,6 @@ function ViewportPanel({
235
229
  variantName,
236
230
  renderContent,
237
231
  previewTheme,
238
- background,
239
232
  useIframeIsolation,
240
233
  }: ViewportPanelProps) {
241
234
  if (viewport.type === "desktop") {
@@ -245,7 +238,6 @@ function ViewportPanel({
245
238
  height={viewport.height}
246
239
  label={viewport.name}
247
240
  previewTheme={previewTheme}
248
- background={background}
249
241
  componentName={componentName}
250
242
  fragmentPath={fragmentPath}
251
243
  variantName={variantName}
@@ -262,7 +254,6 @@ function ViewportPanel({
262
254
  height={viewport.height}
263
255
  label={viewport.name}
264
256
  previewTheme={previewTheme}
265
- background={background}
266
257
  componentName={componentName}
267
258
  fragmentPath={fragmentPath}
268
259
  variantName={variantName}
@@ -278,7 +269,6 @@ interface DeviceMockupProps {
278
269
  height: number;
279
270
  label: string;
280
271
  previewTheme: "light" | "dark";
281
- background: BackgroundOption;
282
272
  componentName: string;
283
273
  fragmentPath: string;
284
274
  variantName: string;
@@ -292,7 +282,6 @@ function DeviceMockup({
292
282
  height,
293
283
  label,
294
284
  previewTheme,
295
- background,
296
285
  componentName,
297
286
  fragmentPath,
298
287
  variantName,
@@ -302,7 +291,6 @@ function DeviceMockup({
302
291
  const isMobile = type === "mobile";
303
292
  const frameWidth = width + 24; // Add bezel width
304
293
  const screenHeight = height;
305
- const backgroundStyle = getBackgroundStyle(background);
306
294
 
307
295
  return (
308
296
  <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
@@ -479,7 +467,6 @@ interface DesktopMockupProps {
479
467
  height: number;
480
468
  label: string;
481
469
  previewTheme: "light" | "dark";
482
- background: BackgroundOption;
483
470
  componentName: string;
484
471
  fragmentPath: string;
485
472
  variantName: string;
@@ -492,15 +479,12 @@ function DesktopMockup({
492
479
  height,
493
480
  label,
494
481
  previewTheme,
495
- background,
496
482
  componentName,
497
483
  fragmentPath,
498
484
  variantName,
499
485
  renderContent,
500
486
  useIframeIsolation,
501
487
  }: DesktopMockupProps) {
502
- const backgroundStyle = getBackgroundStyle(background);
503
-
504
488
  return (
505
489
  <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
506
490
  {/* Label */}
@@ -568,7 +552,6 @@ function DesktopMockup({
568
552
  overflow: 'hidden',
569
553
  width: `${width}px`,
570
554
  height: `${height}px`,
571
- ...backgroundStyle,
572
555
  }}
573
556
  data-theme={previewTheme}
574
557
  >
@@ -13,7 +13,7 @@ import { FigmaEmbed } from './FigmaEmbed.js';
13
13
  import { VariantMatrix } from './VariantMatrix.js';
14
14
  import { MultiViewportPreview } from './MultiViewportPreview.js';
15
15
  import { IsolatedPreviewFrame } from './IsolatedPreviewFrame.js';
16
- import { getBackgroundStyle, getViewportWidth, type ZoomLevel, type BackgroundOption, type ViewportPreset, type ViewportSize } from '../constants/ui.js';
16
+ import { getViewportWidth, type ZoomLevel, type ViewportPreset, type ViewportSize } from '../constants/ui.js';
17
17
  import type { PreviewTheme } from '../hooks/useViewSettings.js';
18
18
 
19
19
  interface PreviewAreaProps {
@@ -25,7 +25,6 @@ interface PreviewAreaProps {
25
25
 
26
26
  // View settings
27
27
  zoom: ZoomLevel;
28
- background: BackgroundOption;
29
28
  viewport: ViewportPreset;
30
29
  customSize: ViewportSize;
31
30
  previewTheme: PreviewTheme;
@@ -151,11 +150,10 @@ const DeviceMockup = memo(function DeviceMockup({ type, width, children }: Devic
151
150
  interface PreviewContentProps {
152
151
  zoom: ZoomLevel;
153
152
  previewTheme: PreviewTheme;
154
- background: BackgroundOption;
155
153
  children: ReactNode;
156
154
  }
157
155
 
158
- const PreviewContent = memo(function PreviewContent({ zoom, previewTheme, background, children }: PreviewContentProps) {
156
+ const PreviewContent = memo(function PreviewContent({ zoom, previewTheme, children }: PreviewContentProps) {
159
157
  return (
160
158
  <div
161
159
  data-preview-container="true"
@@ -164,7 +162,6 @@ const PreviewContent = memo(function PreviewContent({ zoom, previewTheme, backgr
164
162
  width: '100%',
165
163
  height: '100%',
166
164
  overflow: 'auto',
167
- backgroundColor: background === 'transparent' ? 'transparent' : undefined,
168
165
  }}
169
166
  >
170
167
  <div
@@ -188,7 +185,6 @@ export function PreviewArea({
188
185
  variant,
189
186
  variants,
190
187
  zoom,
191
- background,
192
188
  viewport,
193
189
  customSize,
194
190
  previewTheme,
@@ -212,7 +208,6 @@ export function PreviewArea({
212
208
  fragmentPath={fragmentPath}
213
209
  zoom={zoom}
214
210
  previewTheme={previewTheme}
215
- background={background}
216
211
  useIframeIsolation={useIframeIsolation}
217
212
  onSelectVariant={(index) => {
218
213
  onSelectVariant(index);
@@ -230,7 +225,6 @@ export function PreviewArea({
230
225
  variantName={variant.name}
231
226
  renderContent={renderContent}
232
227
  previewTheme={previewTheme}
233
- background={background}
234
228
  zoom={zoom}
235
229
  useIframeIsolation={useIframeIsolation}
236
230
  />
@@ -240,7 +234,6 @@ export function PreviewArea({
240
234
  const viewportWidth = getViewportWidth(viewport, customSize);
241
235
  const viewportHeight = viewport === 'custom' ? customSize.height : null;
242
236
  const isDevice = viewport === 'tablet' || viewport === 'mobile';
243
- const backgroundStyle = getBackgroundStyle(background);
244
237
 
245
238
  // Device mockup view (tablet/mobile)
246
239
  if (isDevice && viewportWidth && variant) {
@@ -252,7 +245,7 @@ export function PreviewArea({
252
245
  <div style={{ display: 'flex', gap: '16px', flex: 1 }}>
253
246
  <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
254
247
  <div style={{ fontSize: '12px', fontWeight: 500, color: 'var(--text-tertiary)', marginBottom: '8px', textAlign: 'center' }}>Rendered</div>
255
- <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', ...backgroundStyle }}>
248
+ <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
256
249
  <DeviceMockup type={viewport as 'tablet' | 'mobile'} width={viewportWidth}>
257
250
  {useIframeIsolation ? (
258
251
  <IsolatedPreviewFrame
@@ -264,7 +257,7 @@ export function PreviewArea({
264
257
  previewKey={previewKey}
265
258
  />
266
259
  ) : (
267
- <PreviewContent zoom={zoom} previewTheme={previewTheme} background={background}>
260
+ <PreviewContent zoom={zoom} previewTheme={previewTheme}>
268
261
  <ErrorBoundary key={previewKey} componentName={componentName} onRetry={onRetry}>
269
262
  {renderContent()}
270
263
  </ErrorBoundary>
@@ -285,7 +278,6 @@ export function PreviewArea({
285
278
  borderRadius: '8px',
286
279
  border: '1px solid var(--border)',
287
280
  overflow: 'hidden',
288
- ...backgroundStyle,
289
281
  }}
290
282
  />
291
283
  </div>
@@ -307,7 +299,7 @@ export function PreviewArea({
307
299
  previewKey={previewKey}
308
300
  />
309
301
  ) : (
310
- <PreviewContent zoom={zoom} previewTheme={previewTheme} background={background}>
302
+ <PreviewContent zoom={zoom} previewTheme={previewTheme}>
311
303
  <ErrorBoundary key={previewKey} componentName={componentName} onRetry={onRetry}>
312
304
  {renderContent()}
313
305
  </ErrorBoundary>
@@ -331,7 +323,6 @@ export function PreviewArea({
331
323
  borderRadius: '8px',
332
324
  border: '1px solid var(--border)',
333
325
  overflow: 'auto',
334
- ...backgroundStyle,
335
326
  }}
336
327
  >
337
328
  {useIframeIsolation ? (
@@ -383,7 +374,6 @@ export function PreviewArea({
383
374
  borderRadius: '8px',
384
375
  border: '1px solid var(--border)',
385
376
  overflow: 'hidden',
386
- ...backgroundStyle,
387
377
  }}
388
378
  />
389
379
  </div>
@@ -1,85 +1,19 @@
1
1
  import { useEffect, useCallback } from 'react';
2
- import { Button, Menu, Stack, Separator } from '@fragments-sdk/ui';
3
- import {
4
- ZOOM_LEVELS,
5
- type ZoomLevel,
6
- type BackgroundOption,
7
- } from '../constants/ui.js';
2
+ import { Button, Menu, Stack } from '@fragments-sdk/ui';
3
+ import { ZOOM_LEVELS, type ZoomLevel } from '../constants/ui.js';
8
4
  import { ZoomIcon, ChevronDownIcon } from './Icons.js';
9
5
 
10
6
  // Re-export types for consumers
11
- export type { ZoomLevel, BackgroundOption };
12
- export { getBackgroundStyle } from '../constants/ui.js';
13
-
14
- // Background options with display metadata
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
- ];
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
- }
7
+ export type { ZoomLevel };
70
8
 
71
9
  interface PreviewToolbarProps {
72
10
  zoom: ZoomLevel;
73
- background: BackgroundOption;
74
11
  onZoomChange: (zoom: ZoomLevel) => void;
75
- onBackgroundChange: (bg: BackgroundOption) => void;
76
12
  }
77
13
 
78
14
  export function PreviewToolbar({
79
15
  zoom,
80
- background,
81
16
  onZoomChange,
82
- onBackgroundChange,
83
17
  }: PreviewToolbarProps) {
84
18
  // Keyboard shortcuts for zoom
85
19
  const handleKeyDown = useCallback((e: KeyboardEvent) => {
@@ -114,7 +48,6 @@ export function PreviewToolbar({
114
48
 
115
49
  return (
116
50
  <Stack direction="row" gap="sm" align="center">
117
- {/* Zoom dropdown */}
118
51
  <Menu>
119
52
  <Menu.Trigger asChild>
120
53
  <Button variant="ghost" size="sm" title="Zoom level (+/-/0)">
@@ -142,39 +75,6 @@ export function PreviewToolbar({
142
75
  </Menu.RadioGroup>
143
76
  </Menu.Content>
144
77
  </Menu>
145
-
146
- {/* Divider */}
147
- <Separator orientation="vertical" />
148
-
149
- {/* Background selector */}
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
- >
167
- {BACKGROUND_OPTIONS_UI.map((option) => (
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>
174
- ))}
175
- </Menu.RadioGroup>
176
- </Menu.Content>
177
- </Menu>
178
78
  </Stack>
179
79
  );
180
80
  }
@@ -17,7 +17,6 @@ import { ErrorBoundary } from "./ErrorBoundary.js";
17
17
  import { StoryRenderer, LoaderIndicator } from "./StoryRenderer.js";
18
18
  import { IsolatedPreviewFrame } from "./IsolatedPreviewFrame.js";
19
19
  import { ChevronDownIcon } from "./Icons.js";
20
- import { getBackgroundStyle, type BackgroundOption } from "../constants/ui.js";
21
20
 
22
21
  interface VariantMatrixProps {
23
22
  /** All variants to display */
@@ -30,8 +29,6 @@ interface VariantMatrixProps {
30
29
  zoom: number;
31
30
  /** Preview theme */
32
31
  previewTheme: "light" | "dark";
33
- /** Background option */
34
- background: BackgroundOption;
35
32
  /** Whether to use iframe isolation */
36
33
  useIframeIsolation?: boolean;
37
34
  /** Callback when a variant is clicked to focus on it */
@@ -63,7 +60,6 @@ export function VariantMatrix({
63
60
  fragmentPath,
64
61
  zoom,
65
62
  previewTheme,
66
- background,
67
63
  useIframeIsolation = true,
68
64
  onSelectVariant,
69
65
  }: VariantMatrixProps) {
@@ -208,7 +204,6 @@ export function VariantMatrix({
208
204
  scale={effectiveScale}
209
205
  minHeight={gridConfig.minHeight}
210
206
  previewTheme={previewTheme}
211
- background={background}
212
207
  useIframeIsolation={useIframeIsolation}
213
208
  isHovered={hoveredIndex === index}
214
209
  onHover={() => setHoveredIndex(index)}
@@ -240,7 +235,6 @@ export function VariantMatrix({
240
235
  scale={effectiveScale}
241
236
  minHeight={gridConfig.minHeight}
242
237
  previewTheme={previewTheme}
243
- background={background}
244
238
  useIframeIsolation={useIframeIsolation}
245
239
  isHovered={hoveredIndex === index}
246
240
  onHover={() => setHoveredIndex(index)}
@@ -263,7 +257,6 @@ interface VariantCardProps {
263
257
  scale: number;
264
258
  minHeight: string;
265
259
  previewTheme: "light" | "dark";
266
- background: BackgroundOption;
267
260
  useIframeIsolation: boolean;
268
261
  isHovered: boolean;
269
262
  onHover: () => void;
@@ -279,15 +272,12 @@ function VariantCard({
279
272
  scale,
280
273
  minHeight,
281
274
  previewTheme,
282
- background,
283
275
  useIframeIsolation,
284
276
  isHovered,
285
277
  onHover,
286
278
  onLeave,
287
279
  onClick,
288
280
  }: VariantCardProps) {
289
- const backgroundStyle = getBackgroundStyle(background);
290
-
291
281
  return (
292
282
  <div
293
283
  style={{
@@ -373,7 +363,6 @@ function VariantCard({
373
363
  display: 'flex',
374
364
  alignItems: 'center',
375
365
  justifyContent: 'center',
376
- ...backgroundStyle,
377
366
  }}
378
367
  >
379
368
  {useIframeIsolation ? (
@@ -102,12 +102,6 @@ export function getRelationshipConfig(relationship: string) {
102
102
  return RELATIONSHIP_CONFIG[relationship as RelationshipType] || RELATIONSHIP_CONFIG.related;
103
103
  }
104
104
 
105
- /**
106
- * Preview background options.
107
- */
108
- export const BACKGROUND_OPTIONS = ['white', 'black', 'checkerboard', 'transparent'] as const;
109
- export type BackgroundOption = (typeof BACKGROUND_OPTIONS)[number];
110
-
111
105
  /**
112
106
  * Zoom level options.
113
107
  */
@@ -140,34 +134,6 @@ export function getViewportWidth(viewport: ViewportPreset, customSize: ViewportS
140
134
  return VIEWPORT_PRESETS[viewport]?.width ?? null;
141
135
  }
142
136
 
143
- /**
144
- * Get CSS background style for preview pane.
145
- */
146
- export function getBackgroundStyle(bg: BackgroundOption): React.CSSProperties {
147
- switch (bg) {
148
- case 'white':
149
- return { backgroundColor: '#ffffff' };
150
- case 'black':
151
- return { backgroundColor: '#000000' };
152
- case 'transparent':
153
- return { backgroundColor: 'transparent' };
154
- case 'checkerboard':
155
- return {
156
- backgroundColor: '#ffffff',
157
- backgroundImage: `
158
- linear-gradient(45deg, #e5e5e5 25%, transparent 25%),
159
- linear-gradient(-45deg, #e5e5e5 25%, transparent 25%),
160
- linear-gradient(45deg, transparent 75%, #e5e5e5 75%),
161
- linear-gradient(-45deg, transparent 75%, #e5e5e5 75%)
162
- `,
163
- backgroundSize: '16px 16px',
164
- backgroundPosition: '0 0, 0 8px, 8px -8px, -8px 0px',
165
- };
166
- default:
167
- return { backgroundColor: '#ffffff' };
168
- }
169
- }
170
-
171
137
  /**
172
138
  * Storage keys for localStorage persistence.
173
139
  */
@@ -5,9 +5,9 @@
5
5
  * - Component path
6
6
  * - Variant index/name
7
7
  * - Edited props
8
- * - View settings (zoom, background, viewport)
8
+ * - View settings (zoom, viewport)
9
9
  *
10
- * URL format: #/ComponentName/VariantName?props=base64&zoom=100&bg=white
10
+ * URL format: #/ComponentName/VariantName?props=base64&zoom=100
11
11
  */
12
12
 
13
13
  import { useState, useEffect, useCallback, useMemo } from "react";
@@ -21,7 +21,6 @@ export interface UrlState {
21
21
  props: Record<string, unknown>;
22
22
  /** View settings */
23
23
  zoom: number;
24
- background: string;
25
24
  viewport: string;
26
25
  customWidth: number | null;
27
26
  customHeight: number | null;
@@ -32,7 +31,6 @@ const DEFAULT_STATE: UrlState = {
32
31
  variant: null,
33
32
  props: {},
34
33
  zoom: 100,
35
- background: "transparent",
36
34
  viewport: "responsive",
37
35
  customWidth: null,
38
36
  customHeight: null,
@@ -99,11 +97,6 @@ function parseUrl(): UrlState {
99
97
  }
100
98
  }
101
99
 
102
- const bg = params.get("bg");
103
- if (bg && ["white", "black", "checkerboard", "transparent"].includes(bg)) {
104
- state.background = bg;
105
- }
106
-
107
100
  const viewport = params.get("viewport");
108
101
  if (viewport && ["responsive", "desktop", "tablet", "mobile", "custom"].includes(viewport)) {
109
102
  state.viewport = viewport;
@@ -155,10 +148,6 @@ function buildUrl(state: Partial<UrlState>): string {
155
148
  params.set("zoom", String(state.zoom));
156
149
  }
157
150
 
158
- if (state.background && state.background !== "transparent") {
159
- params.set("bg", state.background);
160
- }
161
-
162
151
  if (state.viewport && state.viewport !== "responsive") {
163
152
  params.set("viewport", state.viewport);
164
153
  }
@@ -249,7 +238,6 @@ export function useUrlState() {
249
238
  const setViewSettings = useCallback(
250
239
  (settings: {
251
240
  zoom?: number;
252
- background?: string;
253
241
  viewport?: string;
254
242
  customWidth?: number | null;
255
243
  customHeight?: number | null;
@@ -1,17 +1,16 @@
1
1
  /**
2
2
  * View settings state management.
3
- * Handles zoom, background, viewport, and theme settings with URL sync.
3
+ * Handles zoom, viewport, and theme settings with URL sync.
4
4
  */
5
5
 
6
6
  import { useReducer, useCallback, useMemo } from 'react';
7
- import type { ZoomLevel, BackgroundOption, ViewportPreset, ViewportSize } from '../constants/ui.js';
7
+ import type { ZoomLevel, ViewportPreset, ViewportSize } from '../constants/ui.js';
8
8
 
9
9
  // Preview theme type (for canvas theming)
10
10
  export type PreviewTheme = 'light' | 'dark';
11
11
 
12
12
  interface ViewSettings {
13
13
  zoom: ZoomLevel;
14
- background: BackgroundOption;
15
14
  viewport: ViewportPreset;
16
15
  customSize: ViewportSize;
17
16
  previewTheme: PreviewTheme;
@@ -19,7 +18,6 @@ interface ViewSettings {
19
18
 
20
19
  type ViewSettingsAction =
21
20
  | { type: 'SET_ZOOM'; payload: ZoomLevel }
22
- | { type: 'SET_BACKGROUND'; payload: BackgroundOption }
23
21
  | { type: 'SET_VIEWPORT'; payload: ViewportPreset }
24
22
  | { type: 'SET_CUSTOM_SIZE'; payload: ViewportSize }
25
23
  | { type: 'SET_PREVIEW_THEME'; payload: PreviewTheme }
@@ -28,7 +26,6 @@ type ViewSettingsAction =
28
26
 
29
27
  interface ViewSettingsInit {
30
28
  zoom?: ZoomLevel;
31
- background?: BackgroundOption;
32
29
  viewport?: ViewportPreset;
33
30
  customSize?: ViewportSize;
34
31
  previewTheme?: PreviewTheme;
@@ -37,7 +34,6 @@ interface ViewSettingsInit {
37
34
  function createInitialState(init?: ViewSettingsInit): ViewSettings {
38
35
  return {
39
36
  zoom: init?.zoom ?? 100,
40
- background: init?.background ?? 'transparent',
41
37
  viewport: init?.viewport ?? 'responsive',
42
38
  customSize: init?.customSize ?? { width: null, height: null },
43
39
  previewTheme: init?.previewTheme ?? 'light',
@@ -48,8 +44,6 @@ function viewSettingsReducer(state: ViewSettings, action: ViewSettingsAction): V
48
44
  switch (action.type) {
49
45
  case 'SET_ZOOM':
50
46
  return { ...state, zoom: action.payload };
51
- case 'SET_BACKGROUND':
52
- return { ...state, background: action.payload };
53
47
  case 'SET_VIEWPORT':
54
48
  return { ...state, viewport: action.payload };
55
49
  case 'SET_CUSTOM_SIZE':
@@ -68,12 +62,11 @@ function viewSettingsReducer(state: ViewSettings, action: ViewSettingsAction): V
68
62
  interface UseViewSettingsOptions {
69
63
  initialState?: ViewSettingsInit;
70
64
  onZoomChange?: (zoom: ZoomLevel) => void;
71
- onBackgroundChange?: (bg: BackgroundOption) => void;
72
65
  onViewportChange?: (viewport: ViewportPreset, customSize?: ViewportSize) => void;
73
66
  }
74
67
 
75
68
  export function useViewSettings(options: UseViewSettingsOptions = {}) {
76
- const { initialState: init, onZoomChange, onBackgroundChange, onViewportChange } = options;
69
+ const { initialState: init, onZoomChange, onViewportChange } = options;
77
70
 
78
71
  const [state, dispatch] = useReducer(
79
72
  viewSettingsReducer,
@@ -86,11 +79,6 @@ export function useViewSettings(options: UseViewSettingsOptions = {}) {
86
79
  onZoomChange?.(zoom);
87
80
  }, [onZoomChange]);
88
81
 
89
- const setBackground = useCallback((bg: BackgroundOption) => {
90
- dispatch({ type: 'SET_BACKGROUND', payload: bg });
91
- onBackgroundChange?.(bg);
92
- }, [onBackgroundChange]);
93
-
94
82
  const setViewport = useCallback((viewport: ViewportPreset) => {
95
83
  dispatch({ type: 'SET_VIEWPORT', payload: viewport });
96
84
  onViewportChange?.(viewport);
@@ -111,12 +99,11 @@ export function useViewSettings(options: UseViewSettingsOptions = {}) {
111
99
 
112
100
  const actions = useMemo(() => ({
113
101
  setZoom,
114
- setBackground,
115
102
  setViewport,
116
103
  setCustomSize,
117
104
  setPreviewTheme,
118
105
  toggleTheme,
119
- }), [setZoom, setBackground, setViewport, setCustomSize, setPreviewTheme, toggleTheme]);
106
+ }), [setZoom, setViewport, setCustomSize, setPreviewTheme, toggleTheme]);
120
107
 
121
108
  return { ...state, ...actions };
122
109
  }