@fragments-sdk/cli 0.7.13 → 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.13",
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",
@@ -26,14 +26,12 @@ import { useAllFigmaUrls } from "./FigmaEmbed.js";
26
26
  import { ActionCapture } from "./ActionCapture.js";
27
27
 
28
28
  // Fragments UI
29
- 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";
30
30
  import { DeviceMobile, GridFour, Rows } from "@phosphor-icons/react";
31
31
 
32
32
  // Icons
33
33
  import { EmptyIcon, FigmaIcon, CompareIcon } from "./Icons.js";
34
34
 
35
- // Logo
36
- import { fragmentsLogo } from "../assets/fragments-logo.js";
37
35
 
38
36
  function GitHubIcon() {
39
37
  return (
@@ -605,7 +603,7 @@ function ViewerHeader({ showHealth, searchQuery, onSearchChange, searchInputRef
605
603
  <Header.Trigger />
606
604
  <Header.Brand>
607
605
  <Stack direction="row" gap="sm" align="center">
608
- <img src={fragmentsLogo} alt="" width={20} height={20} style={{ display: 'block' }} />
606
+ <FragmentsLogo size={20} />
609
607
  <Text weight="medium" size="sm">{BRAND.name}</Text>
610
608
  <Text size="xs" color="tertiary">{showHealth ? 'health dashboard' : 'preview'}</Text>
611
609
  </Stack>
@@ -761,7 +759,7 @@ function TopToolbar({
761
759
  <Header.Trigger />
762
760
  <Header.Brand>
763
761
  <Stack direction="row" align="center" gap="sm">
764
- <img src={fragmentsLogo} alt="" width={20} height={20} style={{ display: 'block' }} />
762
+ <FragmentsLogo size={20} />
765
763
  <Text weight="medium" size="sm">{fragment.fragment.meta.name}</Text>
766
764
  <Text size="xs" color="tertiary">{fragment.fragment.meta.category}</Text>
767
765
  </Stack>
@@ -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
  }