@fragments-sdk/cli 0.7.12 → 0.7.14

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.14",
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";
@@ -27,14 +26,12 @@ import { useAllFigmaUrls } from "./FigmaEmbed.js";
27
26
  import { ActionCapture } from "./ActionCapture.js";
28
27
 
29
28
  // Fragments UI
30
- import { Header, Stack, Text, Separator, Tooltip, Button, EmptyState, Box, Alert, Input, ThemeToggle } from "@fragments-sdk/ui";
29
+ import { Header, Stack, Text, Separator, Tooltip, Button, EmptyState, Box, Alert, Input, ThemeToggle, FragmentsLogo } from "@fragments-sdk/ui";
31
30
  import { DeviceMobile, GridFour, Rows } from "@phosphor-icons/react";
32
31
 
33
32
  // Icons
34
33
  import { EmptyIcon, FigmaIcon, CompareIcon } from "./Icons.js";
35
34
 
36
- // Logo
37
- import { fragmentsLogo } from "../assets/fragments-logo.js";
38
35
 
39
36
  function GitHubIcon() {
40
37
  return (
@@ -65,16 +62,14 @@ export function App({ fragments }: AppProps) {
65
62
  // UI state (modals, panels, view modes)
66
63
  const { state: uiState, actions: uiActions } = useAppState();
67
64
 
68
- // View settings (zoom, background, viewport, theme)
65
+ // View settings (zoom, viewport, theme)
69
66
  const viewSettings = useViewSettings({
70
67
  initialState: {
71
68
  zoom: urlState.zoom as any,
72
- background: urlState.background as any,
73
69
  viewport: urlState.viewport as any,
74
70
  customSize: { width: urlState.customWidth, height: urlState.customHeight },
75
71
  },
76
72
  onZoomChange: (zoom) => setUrlViewSettings({ zoom }),
77
- onBackgroundChange: (bg) => setUrlViewSettings({ background: bg }),
78
73
  onViewportChange: (vp, size) => setUrlViewSettings({
79
74
  viewport: vp,
80
75
  customWidth: size?.width,
@@ -386,6 +381,7 @@ export function App({ fragments }: AppProps) {
386
381
  activeFragment && !uiState.showHealthDashboard ? (
387
382
  <TopToolbar
388
383
  fragment={activeFragment}
384
+ viewSettings={viewSettings}
389
385
  uiState={uiState}
390
386
  uiActions={uiActions}
391
387
  figmaUrl={figmaUrl}
@@ -450,19 +446,6 @@ export function App({ fragments }: AppProps) {
450
446
  <div id="preview-layout" style={{ display: 'flex', height: '100%', flexDirection: panelDock === "bottom" ? 'column' : 'row' }}>
451
447
  {/* Main Content Area */}
452
448
  <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
449
  {/* Preview Area */}
467
450
  <div
468
451
  id="preview-canvas"
@@ -470,7 +453,6 @@ export function App({ fragments }: AppProps) {
470
453
  flex: 1,
471
454
  overflow: 'auto',
472
455
  position: 'relative',
473
- ...(uiState.showMatrixView ? {} : getBackgroundStyle(viewSettings.background)),
474
456
  }}
475
457
  >
476
458
  {variantCount === 0 ? (
@@ -482,7 +464,6 @@ export function App({ fragments }: AppProps) {
482
464
  variants={variants}
483
465
  focusedVariantIndex={safeVariantIndex}
484
466
  zoom={viewSettings.zoom}
485
- background={viewSettings.background}
486
467
  viewport={viewSettings.viewport}
487
468
  customSize={viewSettings.customSize}
488
469
  previewTheme={resolvedTheme}
@@ -500,7 +481,6 @@ export function App({ fragments }: AppProps) {
500
481
  variant={activeVariant}
501
482
  variants={variants}
502
483
  zoom={viewSettings.zoom}
503
- background={viewSettings.background}
504
484
  viewport={viewSettings.viewport}
505
485
  customSize={viewSettings.customSize}
506
486
  previewTheme={resolvedTheme}
@@ -566,6 +546,7 @@ export function App({ fragments }: AppProps) {
566
546
  // Top Toolbar Component
567
547
  interface TopToolbarProps {
568
548
  fragment: { path: string; fragment: FragmentDefinition };
549
+ viewSettings: ReturnType<typeof useViewSettings>;
569
550
  uiState: ReturnType<typeof useAppState>['state'];
570
551
  uiActions: ReturnType<typeof useAppState>['actions'];
571
552
  figmaUrl?: string;
@@ -622,7 +603,7 @@ function ViewerHeader({ showHealth, searchQuery, onSearchChange, searchInputRef
622
603
  <Header.Trigger />
623
604
  <Header.Brand>
624
605
  <Stack direction="row" gap="sm" align="center">
625
- <img src={fragmentsLogo} alt="" width={20} height={20} style={{ display: 'block' }} />
606
+ <FragmentsLogo size={20} />
626
607
  <Text weight="medium" size="sm">{BRAND.name}</Text>
627
608
  <Text size="xs" color="tertiary">{showHealth ? 'health dashboard' : 'preview'}</Text>
628
609
  </Stack>
@@ -764,6 +745,7 @@ function PreviewAside({
764
745
 
765
746
  function TopToolbar({
766
747
  fragment,
748
+ viewSettings,
767
749
  uiState,
768
750
  uiActions,
769
751
  figmaUrl,
@@ -777,7 +759,7 @@ function TopToolbar({
777
759
  <Header.Trigger />
778
760
  <Header.Brand>
779
761
  <Stack direction="row" align="center" gap="sm">
780
- <img src={fragmentsLogo} alt="" width={20} height={20} style={{ display: 'block' }} />
762
+ <FragmentsLogo size={20} />
781
763
  <Text weight="medium" size="sm">{fragment.fragment.meta.name}</Text>
782
764
  <Text size="xs" color="tertiary">{fragment.fragment.meta.category}</Text>
783
765
  </Stack>
@@ -785,6 +767,48 @@ function TopToolbar({
785
767
  <HeaderSearch value={searchQuery} onChange={onSearchChange} inputRef={searchInputRef} />
786
768
  <Header.Spacer />
787
769
  <Header.Actions>
770
+ <PreviewToolbar
771
+ zoom={viewSettings.zoom}
772
+ onZoomChange={viewSettings.setZoom}
773
+ />
774
+ <Separator orientation="vertical" style={{ height: '16px' }} />
775
+ <Tooltip content={uiState.showMatrixView ? "Disable matrix view" : "Enable matrix view"}>
776
+ <Button
777
+ variant="ghost"
778
+ size="sm"
779
+ aria-pressed={uiState.showMatrixView}
780
+ aria-label="Toggle matrix view"
781
+ onClick={() => uiActions.setMatrixView(!uiState.showMatrixView)}
782
+ style={uiState.showMatrixView ? { color: 'var(--color-accent)', backgroundColor: 'var(--bg-hover)' } : {}}
783
+ >
784
+ <GridFour size={16} />
785
+ </Button>
786
+ </Tooltip>
787
+ <Tooltip content={uiState.showMultiViewport ? "Disable responsive view" : "Enable responsive view"}>
788
+ <Button
789
+ variant="ghost"
790
+ size="sm"
791
+ aria-pressed={uiState.showMultiViewport}
792
+ aria-label="Toggle responsive view"
793
+ onClick={() => uiActions.setMultiViewport(!uiState.showMultiViewport)}
794
+ style={uiState.showMultiViewport ? { color: 'var(--color-accent)', backgroundColor: 'var(--bg-hover)' } : {}}
795
+ >
796
+ <DeviceMobile size={16} />
797
+ </Button>
798
+ </Tooltip>
799
+ <Tooltip content={uiState.panelOpen ? "Hide addons panel" : "Show addons panel"}>
800
+ <Button
801
+ variant="ghost"
802
+ size="sm"
803
+ aria-pressed={uiState.panelOpen}
804
+ aria-label="Toggle addons panel"
805
+ onClick={uiActions.togglePanel}
806
+ style={uiState.panelOpen ? { color: 'var(--color-accent)', backgroundColor: 'var(--bg-hover)' } : {}}
807
+ >
808
+ <Rows size={16} />
809
+ </Button>
810
+ </Tooltip>
811
+ <Separator orientation="vertical" style={{ height: '16px' }} />
788
812
  {figmaUrl && (
789
813
  <>
790
814
  <Tooltip content={uiState.showComparison ? "Hide Figma comparison" : "Compare with Figma design"}>
@@ -851,93 +875,12 @@ function getVariantSectionId(componentName: string, variantName: string): string
851
875
  return `preview-${normalizeAnchorSegment(componentName)}-${normalizeAnchorSegment(variantName)}`;
852
876
  }
853
877
 
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
878
  interface AllVariantsPreviewProps {
935
879
  componentName: string;
936
880
  fragmentPath: string;
937
881
  variants: FragmentVariant[];
938
882
  focusedVariantIndex: number;
939
883
  zoom: ReturnType<typeof useViewSettings>["zoom"];
940
- background: ReturnType<typeof useViewSettings>["background"];
941
884
  viewport: ReturnType<typeof useViewSettings>["viewport"];
942
885
  customSize: ReturnType<typeof useViewSettings>["customSize"];
943
886
  previewTheme: ReturnType<typeof useTheme>["resolvedTheme"];
@@ -955,7 +898,6 @@ function AllVariantsPreview({
955
898
  variants,
956
899
  focusedVariantIndex,
957
900
  zoom,
958
- background,
959
901
  viewport,
960
902
  customSize,
961
903
  previewTheme,
@@ -994,7 +936,6 @@ function AllVariantsPreview({
994
936
  variant={variant}
995
937
  variants={variants}
996
938
  zoom={zoom}
997
- background={background}
998
939
  viewport={viewport}
999
940
  customSize={customSize}
1000
941
  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
  }
@@ -1,96 +1,42 @@
1
- import { createContext, useContext, useEffect, useState, useCallback, type ReactNode } from 'react';
1
+ import type { ReactNode } from 'react';
2
+ import {
3
+ ThemeProvider as FragmentsThemeProvider,
4
+ useTheme as useFragmentsTheme,
5
+ } from '@fragments-sdk/ui';
2
6
  import { BRAND } from '../../core/index.js';
3
7
 
4
8
  type Theme = 'light' | 'dark' | 'system';
5
9
 
6
- interface ThemeContextValue {
10
+ interface ViewerThemeContextValue {
7
11
  theme: Theme;
8
12
  resolvedTheme: 'light' | 'dark';
9
13
  setTheme: (theme: Theme) => void;
10
14
  }
11
15
 
12
- const ThemeContext = createContext<ThemeContextValue | null>(null);
13
-
14
16
  const STORAGE_KEY = `${BRAND.storagePrefix}theme`;
15
17
 
16
- function getSystemTheme(): 'light' | 'dark' {
17
- if (typeof window === 'undefined') return 'light';
18
- return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
19
- }
20
-
21
- function getStoredTheme(): Theme {
22
- if (typeof window === 'undefined') return 'system';
23
- const stored = localStorage.getItem(STORAGE_KEY);
24
- if (stored === 'light' || stored === 'dark' || stored === 'system') {
25
- return stored;
26
- }
27
- return 'system';
28
- }
29
-
18
+ /**
19
+ * Viewer theme adapter that reuses the shared UI ThemeProvider while preserving
20
+ * existing viewer storage keys and API shape.
21
+ */
30
22
  export function ThemeProvider({ children }: { children: ReactNode }) {
31
- const [theme, setThemeState] = useState<Theme>(getStoredTheme);
32
- const [resolvedTheme, setResolvedTheme] = useState<'light' | 'dark'>(() => {
33
- const stored = getStoredTheme();
34
- return stored === 'system' ? getSystemTheme() : stored;
35
- });
36
-
37
- const setTheme = useCallback((newTheme: Theme) => {
38
- setThemeState(newTheme);
39
- localStorage.setItem(STORAGE_KEY, newTheme);
40
-
41
- // Immediately update resolved theme to avoid timing issues
42
- const resolved = newTheme === 'system' ? getSystemTheme() : newTheme;
43
- setResolvedTheme(resolved);
44
-
45
- // Immediately apply to document
46
- if (resolved === 'dark') {
47
- document.documentElement.classList.add('dark');
48
- } else {
49
- document.documentElement.classList.remove('dark');
50
- }
51
- }, []);
52
-
53
- // Update resolved theme and apply to document
54
- useEffect(() => {
55
- const resolved = theme === 'system' ? getSystemTheme() : theme;
56
- setResolvedTheme(resolved);
57
-
58
- if (resolved === 'dark') {
59
- document.documentElement.classList.add('dark');
60
- } else {
61
- document.documentElement.classList.remove('dark');
62
- }
63
- }, [theme]);
64
-
65
- // Listen for system theme changes
66
- useEffect(() => {
67
- if (theme !== 'system') return;
68
-
69
- const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
70
- const handler = (e: MediaQueryListEvent) => {
71
- setResolvedTheme(e.matches ? 'dark' : 'light');
72
- if (e.matches) {
73
- document.documentElement.classList.add('dark');
74
- } else {
75
- document.documentElement.classList.remove('dark');
76
- }
77
- };
78
-
79
- mediaQuery.addEventListener('change', handler);
80
- return () => mediaQuery.removeEventListener('change', handler);
81
- }, [theme]);
82
-
83
23
  return (
84
- <ThemeContext.Provider value={{ theme, resolvedTheme, setTheme }}>
24
+ <FragmentsThemeProvider
25
+ defaultMode="system"
26
+ storageKey={STORAGE_KEY}
27
+ attribute="class"
28
+ >
85
29
  {children}
86
- </ThemeContext.Provider>
30
+ </FragmentsThemeProvider>
87
31
  );
88
32
  }
89
33
 
90
- export function useTheme() {
91
- const context = useContext(ThemeContext);
92
- if (!context) {
93
- throw new Error('useTheme must be used within a ThemeProvider');
94
- }
95
- return context;
34
+ export function useTheme(): ViewerThemeContextValue {
35
+ const { mode, setMode, resolvedMode } = useFragmentsTheme();
36
+
37
+ return {
38
+ theme: mode,
39
+ resolvedTheme: resolvedMode,
40
+ setTheme: setMode,
41
+ };
96
42
  }
@@ -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
  }