@dfosco/storyboard-react-primer 3.8.0 → 3.8.2

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": "@dfosco/storyboard-react-primer",
3
- "version": "3.8.0",
3
+ "version": "3.8.2",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -12,7 +12,7 @@
12
12
  "src"
13
13
  ],
14
14
  "dependencies": {
15
- "@dfosco/storyboard-react": "3.8.0"
15
+ "@dfosco/storyboard-react": "3.8.2"
16
16
  },
17
17
  "peerDependencies": {
18
18
  "@primer/react": ">=37",
@@ -0,0 +1,73 @@
1
+ /**
2
+ * ThemeSync — invisible React component that bridges the storyboard-core
3
+ * toolbar theme switcher with Primer's ThemeProvider context.
4
+ *
5
+ * Listens for `storyboard:theme:changed` custom events dispatched by the
6
+ * core theme store and calls setColorMode/setDayScheme/setNightScheme on
7
+ * Primer's useTheme() hook accordingly.
8
+ *
9
+ * On mount it reads localStorage to initialize Primer to the correct
10
+ * scheme before the Svelte CoreUIBar has loaded.
11
+ *
12
+ * When prototype sync is disabled (via "Apply theme to" settings), the
13
+ * prototype is forced to light mode regardless of the selected theme.
14
+ */
15
+
16
+ import { useEffect } from 'react'
17
+ import { useTheme } from '@primer/react'
18
+
19
+ const THEME_STORAGE_KEY = 'sb-color-scheme'
20
+ const THEME_SYNC_STORAGE_KEY = 'sb-theme-sync'
21
+
22
+ const DEFAULT_SYNC = {
23
+ prototype: true,
24
+ toolbar: false,
25
+ codeBoxes: true,
26
+ }
27
+
28
+ function readSyncTargets() {
29
+ try {
30
+ const raw = localStorage.getItem(THEME_SYNC_STORAGE_KEY)
31
+ if (!raw) return DEFAULT_SYNC
32
+ return { ...DEFAULT_SYNC, ...JSON.parse(raw) }
33
+ } catch {
34
+ return DEFAULT_SYNC
35
+ }
36
+ }
37
+
38
+ function applyToPrimer(setColorMode, setDayScheme, setNightScheme, themeValue) {
39
+ if (themeValue === 'system' || !themeValue) {
40
+ setColorMode('auto')
41
+ setDayScheme('light')
42
+ setNightScheme('dark')
43
+ } else {
44
+ setColorMode('day')
45
+ setDayScheme(themeValue)
46
+ setNightScheme(themeValue)
47
+ }
48
+ }
49
+
50
+ export default function ThemeSync() {
51
+ const { setColorMode, setDayScheme, setNightScheme } = useTheme()
52
+
53
+ // Restore saved theme on mount
54
+ useEffect(() => {
55
+ const saved = localStorage.getItem(THEME_STORAGE_KEY)
56
+ const syncTargets = readSyncTargets()
57
+ const prototypeTheme = syncTargets.prototype ? saved : 'light'
58
+ applyToPrimer(setColorMode, setDayScheme, setNightScheme, prototypeTheme)
59
+ }, []) // eslint-disable-line react-hooks/exhaustive-deps
60
+
61
+ // Listen for theme changes from the Svelte CoreUIBar
62
+ useEffect(() => {
63
+ function handleThemeChanged(e) {
64
+ const { prototypeTheme } = e.detail || {}
65
+ if (typeof prototypeTheme !== 'string') return
66
+ applyToPrimer(setColorMode, setDayScheme, setNightScheme, prototypeTheme)
67
+ }
68
+ document.addEventListener('storyboard:theme:changed', handleThemeChanged)
69
+ return () => document.removeEventListener('storyboard:theme:changed', handleThemeChanged)
70
+ }, [setColorMode, setDayScheme, setNightScheme])
71
+
72
+ return null
73
+ }
package/src/index.js CHANGED
@@ -12,5 +12,8 @@ export { default as Checkbox } from './Checkbox.jsx'
12
12
  export { default as Textarea } from './Textarea.jsx'
13
13
  export { default as StoryboardForm } from './StoryboardForm.jsx'
14
14
 
15
+ // Theme bridge (Primer ThemeProvider ↔ storyboard-core theme store)
16
+ export { default as ThemeSync } from './ThemeSync.jsx'
17
+
15
18
  // Scene data demo
16
19
  export { default as SceneDataDemo } from './SceneDataDemo.jsx'