@dfosco/storyboard-react 4.0.0-beta.4 → 4.0.0-beta.41

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 (63) hide show
  1. package/package.json +9 -4
  2. package/src/Icon.jsx +179 -0
  3. package/src/Viewfinder.jsx +1030 -57
  4. package/src/Viewfinder.module.css +1524 -155
  5. package/src/canvas/CanvasControls.jsx +51 -2
  6. package/src/canvas/CanvasControls.module.css +31 -0
  7. package/src/canvas/CanvasPage.bridge.test.jsx +95 -10
  8. package/src/canvas/CanvasPage.dragdrop.test.jsx +346 -0
  9. package/src/canvas/CanvasPage.jsx +843 -301
  10. package/src/canvas/CanvasPage.module.css +73 -50
  11. package/src/canvas/CanvasPage.multiselect.test.jsx +13 -11
  12. package/src/canvas/CanvasToolbar.jsx +2 -2
  13. package/src/canvas/ComponentErrorBoundary.jsx +50 -0
  14. package/src/canvas/PageSelector.jsx +198 -0
  15. package/src/canvas/PageSelector.module.css +158 -0
  16. package/src/canvas/PageSelector.test.jsx +104 -0
  17. package/src/canvas/canvasApi.js +22 -8
  18. package/src/canvas/canvasReloadGuard.js +37 -0
  19. package/src/canvas/canvasReloadGuard.test.js +27 -0
  20. package/src/canvas/componentIsolate.jsx +135 -0
  21. package/src/canvas/useCanvas.js +15 -10
  22. package/src/canvas/widgets/CodePenEmbed.jsx +292 -0
  23. package/src/canvas/widgets/CodePenEmbed.module.css +161 -0
  24. package/src/canvas/widgets/ComponentWidget.jsx +82 -9
  25. package/src/canvas/widgets/ComponentWidget.module.css +14 -6
  26. package/src/canvas/widgets/FigmaEmbed.jsx +110 -24
  27. package/src/canvas/widgets/FigmaEmbed.module.css +21 -7
  28. package/src/canvas/widgets/LinkPreview.jsx +297 -11
  29. package/src/canvas/widgets/LinkPreview.module.css +386 -18
  30. package/src/canvas/widgets/LinkPreview.test.jsx +193 -0
  31. package/src/canvas/widgets/MarkdownBlock.jsx +95 -21
  32. package/src/canvas/widgets/MarkdownBlock.module.css +133 -2
  33. package/src/canvas/widgets/MarkdownBlock.test.jsx +39 -0
  34. package/src/canvas/widgets/PrototypeEmbed.jsx +95 -144
  35. package/src/canvas/widgets/PrototypeEmbed.module.css +74 -4
  36. package/src/canvas/widgets/StickyNote.module.css +5 -0
  37. package/src/canvas/widgets/StickyNote.test.jsx +9 -9
  38. package/src/canvas/widgets/StoryWidget.jsx +276 -0
  39. package/src/canvas/widgets/StoryWidget.module.css +211 -0
  40. package/src/canvas/widgets/WidgetChrome.jsx +76 -20
  41. package/src/canvas/widgets/WidgetChrome.module.css +4 -7
  42. package/src/canvas/widgets/WidgetWrapper.module.css +2 -0
  43. package/src/canvas/widgets/codepenUrl.js +75 -0
  44. package/src/canvas/widgets/codepenUrl.test.js +76 -0
  45. package/src/canvas/widgets/embedInteraction.test.jsx +235 -0
  46. package/src/canvas/widgets/embedOverlay.module.css +35 -0
  47. package/src/canvas/widgets/embedTheme.js +56 -0
  48. package/src/canvas/widgets/githubUrl.js +82 -0
  49. package/src/canvas/widgets/githubUrl.test.js +74 -0
  50. package/src/canvas/widgets/iframeDevLogs.js +49 -0
  51. package/src/canvas/widgets/iframeDevLogs.test.jsx +81 -0
  52. package/src/canvas/widgets/index.js +4 -0
  53. package/src/canvas/widgets/pasteRules.js +295 -0
  54. package/src/canvas/widgets/pasteRules.test.js +474 -0
  55. package/src/canvas/widgets/snapshotDisplay.test.jsx +259 -0
  56. package/src/canvas/widgets/widgetConfig.js +16 -5
  57. package/src/canvas/widgets/widgetConfig.test.js +34 -12
  58. package/src/context.jsx +141 -16
  59. package/src/hooks/useSceneData.js +4 -2
  60. package/src/story/StoryPage.jsx +117 -0
  61. package/src/story/StoryPage.module.css +18 -0
  62. package/src/vite/data-plugin.js +375 -57
  63. package/src/vite/data-plugin.test.js +405 -5
@@ -0,0 +1,117 @@
1
+ /**
2
+ * StoryPage — renders a .story.jsx module at its own route.
3
+ *
4
+ * Renders only the bare component(s) with no layout chrome.
5
+ * When ?export=ExportName is present, renders that single export.
6
+ * Without ?export, renders all named exports stacked.
7
+ */
8
+ import { useState, useEffect, useMemo } from 'react'
9
+ import { useLocation } from 'react-router-dom'
10
+ import { getStoryData } from '@dfosco/storyboard-core'
11
+ import { ThemeProvider, BaseStyles } from '@primer/react'
12
+ import styles from './StoryPage.module.css'
13
+
14
+ function StoryErrorFallback({ name, error }) {
15
+ return (
16
+ <div className={styles.error}>
17
+ <strong>{name}</strong>
18
+ <span>{String(error?.message || error)}</span>
19
+ </div>
20
+ )
21
+ }
22
+
23
+ export default function StoryPage({ name }) {
24
+ const location = useLocation()
25
+ const searchParams = new URLSearchParams(location.search)
26
+ const exportFilter = searchParams.get('export')
27
+ const isEmbed = searchParams.has('_sb_embed')
28
+
29
+ const story = useMemo(() => getStoryData(name), [name])
30
+ const [exports, setExports] = useState(null)
31
+ const [error, setError] = useState(null)
32
+
33
+ useEffect(() => {
34
+ if (!story?._storyImport) {
35
+ Promise.resolve().then(() => setError(`Story "${name}" not found or missing import`))
36
+ return
37
+ }
38
+
39
+ let cancelled = false
40
+ story._storyImport()
41
+ .then((mod) => {
42
+ if (cancelled) return
43
+ const namedExports = {}
44
+ for (const [key, value] of Object.entries(mod)) {
45
+ if (key !== 'default' && typeof value === 'function') {
46
+ namedExports[key] = value
47
+ }
48
+ }
49
+ setExports(namedExports)
50
+ setError(null)
51
+ })
52
+ .catch((err) => {
53
+ if (cancelled) return
54
+ setError(`Failed to load story "${name}": ${err.message || err}`)
55
+ })
56
+
57
+ return () => { cancelled = true }
58
+ }, [name, story])
59
+
60
+ // Signal snapshot-ready after story renders in embed mode.
61
+ useEffect(() => {
62
+ if (!isEmbed || !exports || window.parent === window) return
63
+ document.fonts.ready.then(() => {
64
+ requestAnimationFrame(() => requestAnimationFrame(() => {
65
+ window.__sbSnapshotReady?.()
66
+ }))
67
+ })
68
+ }, [isEmbed, exports])
69
+
70
+ if (error) {
71
+ return (
72
+ <StoryErrorFallback name={name} error={error} />
73
+ )
74
+ }
75
+
76
+ if (!exports) {
77
+ if (isEmbed) return null
78
+ return (
79
+ <div className={styles.loading}>Loading story…</div>
80
+ )
81
+ }
82
+
83
+ // Single export mode
84
+ if (exportFilter) {
85
+ const Component = exports[exportFilter]
86
+ if (!Component) {
87
+ return (
88
+ <StoryErrorFallback
89
+ name={`${name}/${exportFilter}`}
90
+ error={`Export "${exportFilter}" not found in story "${name}"`}
91
+ />
92
+ )
93
+ }
94
+
95
+ return (
96
+ <ThemeProvider colorMode="day">
97
+ <BaseStyles>
98
+ <Component />
99
+ </BaseStyles>
100
+ </ThemeProvider>
101
+ )
102
+ }
103
+
104
+ // All exports — render each component bare
105
+ const exportNames = Object.keys(exports)
106
+
107
+ return (
108
+ <ThemeProvider colorMode="day">
109
+ <BaseStyles>
110
+ {exportNames.map((exportName) => {
111
+ const Component = exports[exportName]
112
+ return <Component key={exportName} />
113
+ })}
114
+ </BaseStyles>
115
+ </ThemeProvider>
116
+ )
117
+ }
@@ -0,0 +1,18 @@
1
+ .loading {
2
+ display: flex;
3
+ align-items: center;
4
+ justify-content: center;
5
+ padding: 3rem;
6
+ color: var(--fgColor-muted, #656d76);
7
+ font-size: 0.875rem;
8
+ }
9
+
10
+ .error {
11
+ display: flex;
12
+ flex-direction: column;
13
+ gap: 4px;
14
+ padding: 1rem;
15
+ color: var(--fgColor-danger, #cf222e);
16
+ font-size: 0.875rem;
17
+ line-height: 1.5;
18
+ }