@dfosco/storyboard 0.5.0-alpha.0
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/commandpalette.config.json +152 -0
- package/dist/storyboard-ui.css +1 -0
- package/dist/storyboard-ui.js +21328 -0
- package/dist/storyboard-ui.js.map +1 -0
- package/dist/tailwind.css +2 -0
- package/dist/tiny-canvas.css +1 -0
- package/dist/tiny-canvas.js +389 -0
- package/package.json +121 -0
- package/paste.config.json +67 -0
- package/scaffold/AGENTS.md +432 -0
- package/scaffold/agents/prompt-agent.agent.md +181 -0
- package/scaffold/agents/terminal-agent.agent.md +351 -0
- package/scaffold/codex/config.toml +246 -0
- package/scaffold/deploy.yml +103 -0
- package/scaffold/githooks/pre-push +114 -0
- package/scaffold/gitignore +64 -0
- package/scaffold/manifest.json +56 -0
- package/scaffold/preview.yml +181 -0
- package/scaffold/scripts/link.sh +26 -0
- package/scaffold/scripts/unlink.sh +10 -0
- package/scaffold/skills/agent-browser/SKILL.md +260 -0
- package/scaffold/skills/canvas/SKILL.md +364 -0
- package/scaffold/skills/create/SKILL.md +501 -0
- package/scaffold/skills/ship/SKILL.md +237 -0
- package/scaffold/skills/storyboard/SKILL.md +360 -0
- package/scaffold/skills/update-storyboard/SKILL.md +16 -0
- package/scaffold/skills/update-storyboard/update-storyboard-packages.sh +26 -0
- package/scaffold/skills/vitest/GENERATION.md +5 -0
- package/scaffold/skills/vitest/SKILL.md +52 -0
- package/scaffold/skills/vitest/references/advanced-environments.md +264 -0
- package/scaffold/skills/vitest/references/advanced-projects.md +300 -0
- package/scaffold/skills/vitest/references/advanced-type-testing.md +237 -0
- package/scaffold/skills/vitest/references/advanced-vi.md +249 -0
- package/scaffold/skills/vitest/references/core-cli.md +166 -0
- package/scaffold/skills/vitest/references/core-config.md +174 -0
- package/scaffold/skills/vitest/references/core-describe.md +193 -0
- package/scaffold/skills/vitest/references/core-expect.md +219 -0
- package/scaffold/skills/vitest/references/core-hooks.md +244 -0
- package/scaffold/skills/vitest/references/core-test-api.md +233 -0
- package/scaffold/skills/vitest/references/features-concurrency.md +250 -0
- package/scaffold/skills/vitest/references/features-context.md +238 -0
- package/scaffold/skills/vitest/references/features-coverage.md +207 -0
- package/scaffold/skills/vitest/references/features-filtering.md +211 -0
- package/scaffold/skills/vitest/references/features-mocking.md +265 -0
- package/scaffold/skills/vitest/references/features-snapshots.md +207 -0
- package/scaffold/skills/worktree/SKILL.md +93 -0
- package/scaffold/storyboard.config.json +44 -0
- package/src/canvas/Canvas.jsx +78 -0
- package/src/canvas/Draggable.jsx +235 -0
- package/src/canvas/index.d.ts +41 -0
- package/src/canvas/index.js +6 -0
- package/src/canvas/style.css +118 -0
- package/src/canvas/useResetCanvas.js +17 -0
- package/src/canvas/utils.js +136 -0
- package/src/core/assets/fonts/IoskeleyMono-Bold.woff2 +0 -0
- package/src/core/assets/fonts/IoskeleyMono-Italic.woff2 +0 -0
- package/src/core/assets/fonts/IoskeleyMono-Medium.woff2 +0 -0
- package/src/core/assets/fonts/IoskeleyMono-Regular.woff2 +0 -0
- package/src/core/assets/fonts/IoskeleyMono-SemiBold.woff2 +0 -0
- package/src/core/autosync/server.js +714 -0
- package/src/core/autosync/server.test.js +158 -0
- package/src/core/canvas/__tests__/agent-integration.test.js +596 -0
- package/src/core/canvas/__tests__/helpers/browser.js +95 -0
- package/src/core/canvas/__tests__/helpers/canvas-api.js +129 -0
- package/src/core/canvas/__tests__/helpers/perf.js +118 -0
- package/src/core/canvas/__tests__/helpers/setup.js +176 -0
- package/src/core/canvas/__tests__/helpers/tmux.js +130 -0
- package/src/core/canvas/__tests__/helpers/transcript.js +132 -0
- package/src/core/canvas/__tests__/terminal-integration.test.js +177 -0
- package/src/core/canvas/collision.js +292 -0
- package/src/core/canvas/collision.test.js +371 -0
- package/src/core/canvas/compact.js +83 -0
- package/src/core/canvas/deriveCanvasId.test.js +40 -0
- package/src/core/canvas/githubEmbeds.js +527 -0
- package/src/core/canvas/githubEmbeds.test.js +302 -0
- package/src/core/canvas/hot-pool.js +766 -0
- package/src/core/canvas/identity.js +107 -0
- package/src/core/canvas/identity.test.js +100 -0
- package/src/core/canvas/materializer.js +259 -0
- package/src/core/canvas/materializer.test.js +356 -0
- package/src/core/canvas/selectedWidgets.js +270 -0
- package/src/core/canvas/selectedWidgets.test.js +321 -0
- package/src/core/canvas/server.js +3134 -0
- package/src/core/canvas/server.test.js +379 -0
- package/src/core/canvas/terminal-config.js +330 -0
- package/src/core/canvas/terminal-registry.js +465 -0
- package/src/core/canvas/terminal-server.js +1436 -0
- package/src/core/canvas/writeGuard.js +53 -0
- package/src/core/cli/agent.js +85 -0
- package/src/core/cli/branch.js +386 -0
- package/src/core/cli/canvasAdd.js +241 -0
- package/src/core/cli/canvasBatch.js +98 -0
- package/src/core/cli/canvasBounds.js +160 -0
- package/src/core/cli/canvasRead.js +236 -0
- package/src/core/cli/canvasUpdate.js +179 -0
- package/src/core/cli/code.js +67 -0
- package/src/core/cli/compact.js +62 -0
- package/src/core/cli/create.js +674 -0
- package/src/core/cli/dev-helpers.js +53 -0
- package/src/core/cli/dev-helpers.test.js +53 -0
- package/src/core/cli/dev.js +430 -0
- package/src/core/cli/exit.js +38 -0
- package/src/core/cli/flags.js +174 -0
- package/src/core/cli/flags.test.js +155 -0
- package/src/core/cli/index.js +233 -0
- package/src/core/cli/intro.js +37 -0
- package/src/core/cli/proxy.js +319 -0
- package/src/core/cli/proxy.test.js +63 -0
- package/src/core/cli/schemas.js +223 -0
- package/src/core/cli/server.js +192 -0
- package/src/core/cli/serverUrl.js +61 -0
- package/src/core/cli/sessions.js +459 -0
- package/src/core/cli/setup.js +404 -0
- package/src/core/cli/terminal-commands.js +287 -0
- package/src/core/cli/terminal-messaging.js +231 -0
- package/src/core/cli/terminal-welcome.js +515 -0
- package/src/core/cli/updateVersion.js +124 -0
- package/src/core/comments/api.js +284 -0
- package/src/core/comments/api.test.js +282 -0
- package/src/core/comments/auth.js +151 -0
- package/src/core/comments/auth.test.js +167 -0
- package/src/core/comments/commentCache.js +109 -0
- package/src/core/comments/commentCache.test.js +48 -0
- package/src/core/comments/commentDrafts.js +68 -0
- package/src/core/comments/commentMode.js +63 -0
- package/src/core/comments/commentMode.test.js +90 -0
- package/src/core/comments/config.js +47 -0
- package/src/core/comments/config.test.js +77 -0
- package/src/core/comments/graphql.js +65 -0
- package/src/core/comments/graphql.test.js +95 -0
- package/src/core/comments/index.js +42 -0
- package/src/core/comments/metadata.js +52 -0
- package/src/core/comments/metadata.test.js +110 -0
- package/src/core/comments/queries.js +245 -0
- package/src/core/comments/ui/AuthModal.jsx +114 -0
- package/src/core/comments/ui/CommentOverlay.js +52 -0
- package/src/core/comments/ui/CommentWindow.jsx +329 -0
- package/src/core/comments/ui/CommentsDrawer.jsx +102 -0
- package/src/core/comments/ui/Composer.jsx +64 -0
- package/src/core/comments/ui/authModal.js +66 -0
- package/src/core/comments/ui/authModal.test.js +76 -0
- package/src/core/comments/ui/comment-cursor-dark.svg +1 -0
- package/src/core/comments/ui/comment-cursor.svg +1 -0
- package/src/core/comments/ui/comment-layout.css +142 -0
- package/src/core/comments/ui/commentWindow.js +121 -0
- package/src/core/comments/ui/comments.css +242 -0
- package/src/core/comments/ui/commentsDrawer.js +84 -0
- package/src/core/comments/ui/composer.js +136 -0
- package/src/core/comments/ui/index.js +14 -0
- package/src/core/comments/ui/mount.js +687 -0
- package/src/core/comments/ui/mount.test.js +336 -0
- package/src/core/data/dotPath.js +53 -0
- package/src/core/data/dotPath.test.js +114 -0
- package/src/core/data/loader.js +409 -0
- package/src/core/data/loader.test.js +599 -0
- package/src/core/data/viewfinder.js +363 -0
- package/src/core/data/viewfinder.test.js +456 -0
- package/src/core/devtools/devtools-consumer.js +28 -0
- package/src/core/devtools/devtools.js +144 -0
- package/src/core/devtools/devtools.test.js +75 -0
- package/src/core/devtools/sceneDebug.js +112 -0
- package/src/core/devtools/sceneDebug.test.js +141 -0
- package/src/core/index.js +124 -0
- package/src/core/inspector/fiberWalker.js +239 -0
- package/src/core/inspector/highlighter.js +275 -0
- package/src/core/inspector/mouseMode.js +259 -0
- package/src/core/lib/components/ui/alert/alert-action.jsx +11 -0
- package/src/core/lib/components/ui/alert/alert-description.jsx +11 -0
- package/src/core/lib/components/ui/alert/alert-title.jsx +11 -0
- package/src/core/lib/components/ui/alert/alert.jsx +25 -0
- package/src/core/lib/components/ui/alert/index.js +17 -0
- package/src/core/lib/components/ui/avatar/avatar-badge.jsx +22 -0
- package/src/core/lib/components/ui/avatar/avatar-fallback.jsx +18 -0
- package/src/core/lib/components/ui/avatar/avatar-group-count.jsx +19 -0
- package/src/core/lib/components/ui/avatar/avatar-group.jsx +19 -0
- package/src/core/lib/components/ui/avatar/avatar-image.jsx +15 -0
- package/src/core/lib/components/ui/avatar/avatar.jsx +19 -0
- package/src/core/lib/components/ui/avatar/index.js +22 -0
- package/src/core/lib/components/ui/badge/badge.jsx +31 -0
- package/src/core/lib/components/ui/badge/index.js +2 -0
- package/src/core/lib/components/ui/button/button.jsx +100 -0
- package/src/core/lib/components/ui/button/index.js +12 -0
- package/src/core/lib/components/ui/card/card-action.jsx +11 -0
- package/src/core/lib/components/ui/card/card-content.jsx +11 -0
- package/src/core/lib/components/ui/card/card-description.jsx +11 -0
- package/src/core/lib/components/ui/card/card-footer.jsx +11 -0
- package/src/core/lib/components/ui/card/card-header.jsx +19 -0
- package/src/core/lib/components/ui/card/card-title.jsx +11 -0
- package/src/core/lib/components/ui/card/card.jsx +17 -0
- package/src/core/lib/components/ui/card/index.js +25 -0
- package/src/core/lib/components/ui/checkbox/checkbox.jsx +29 -0
- package/src/core/lib/components/ui/checkbox/index.js +6 -0
- package/src/core/lib/components/ui/collapsible/collapsible-content.jsx +7 -0
- package/src/core/lib/components/ui/collapsible/collapsible-trigger.jsx +7 -0
- package/src/core/lib/components/ui/collapsible/collapsible.jsx +7 -0
- package/src/core/lib/components/ui/collapsible/index.js +13 -0
- package/src/core/lib/components/ui/dialog/dialog-close.jsx +7 -0
- package/src/core/lib/components/ui/dialog/dialog-content.jsx +34 -0
- package/src/core/lib/components/ui/dialog/dialog-description.jsx +15 -0
- package/src/core/lib/components/ui/dialog/dialog-footer.jsx +23 -0
- package/src/core/lib/components/ui/dialog/dialog-header.jsx +11 -0
- package/src/core/lib/components/ui/dialog/dialog-overlay.jsx +15 -0
- package/src/core/lib/components/ui/dialog/dialog-portal.jsx +4 -0
- package/src/core/lib/components/ui/dialog/dialog-title.jsx +15 -0
- package/src/core/lib/components/ui/dialog/dialog-trigger.jsx +7 -0
- package/src/core/lib/components/ui/dialog/dialog.jsx +4 -0
- package/src/core/lib/components/ui/dialog/index.js +34 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.jsx +8 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.jsx +30 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-content.jsx +22 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.jsx +16 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-group.jsx +7 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-item.jsx +20 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-label.jsx +17 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-portal.jsx +4 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.jsx +7 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.jsx +29 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-separator.jsx +15 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.jsx +16 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.jsx +15 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.jsx +23 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub.jsx +4 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-trigger.jsx +7 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu.jsx +4 -0
- package/src/core/lib/components/ui/dropdown-menu/index.js +54 -0
- package/src/core/lib/components/ui/input/index.js +7 -0
- package/src/core/lib/components/ui/input/input.jsx +19 -0
- package/src/core/lib/components/ui/label/index.js +7 -0
- package/src/core/lib/components/ui/label/label.jsx +19 -0
- package/src/core/lib/components/ui/panel/index.js +24 -0
- package/src/core/lib/components/ui/panel/panel-body.jsx +11 -0
- package/src/core/lib/components/ui/panel/panel-close.jsx +16 -0
- package/src/core/lib/components/ui/panel/panel-content.jsx +29 -0
- package/src/core/lib/components/ui/panel/panel-footer.jsx +11 -0
- package/src/core/lib/components/ui/panel/panel-header.jsx +11 -0
- package/src/core/lib/components/ui/panel/panel-title.jsx +12 -0
- package/src/core/lib/components/ui/panel/panel.jsx +4 -0
- package/src/core/lib/components/ui/popover/index.js +28 -0
- package/src/core/lib/components/ui/popover/popover-close.jsx +7 -0
- package/src/core/lib/components/ui/popover/popover-content.jsx +22 -0
- package/src/core/lib/components/ui/popover/popover-description.jsx +11 -0
- package/src/core/lib/components/ui/popover/popover-header.jsx +11 -0
- package/src/core/lib/components/ui/popover/popover-portal.jsx +4 -0
- package/src/core/lib/components/ui/popover/popover-title.jsx +11 -0
- package/src/core/lib/components/ui/popover/popover-trigger.jsx +8 -0
- package/src/core/lib/components/ui/popover/popover.jsx +4 -0
- package/src/core/lib/components/ui/searchable-list.jsx +160 -0
- package/src/core/lib/components/ui/select/index.js +37 -0
- package/src/core/lib/components/ui/select/select-content.jsx +30 -0
- package/src/core/lib/components/ui/select/select-group-heading.jsx +17 -0
- package/src/core/lib/components/ui/select/select-group.jsx +15 -0
- package/src/core/lib/components/ui/select/select-item.jsx +26 -0
- package/src/core/lib/components/ui/select/select-label.jsx +11 -0
- package/src/core/lib/components/ui/select/select-portal.jsx +4 -0
- package/src/core/lib/components/ui/select/select-scroll-down-button.jsx +18 -0
- package/src/core/lib/components/ui/select/select-scroll-up-button.jsx +18 -0
- package/src/core/lib/components/ui/select/select-separator.jsx +15 -0
- package/src/core/lib/components/ui/select/select-trigger.jsx +25 -0
- package/src/core/lib/components/ui/select/select.jsx +4 -0
- package/src/core/lib/components/ui/separator/index.js +7 -0
- package/src/core/lib/components/ui/separator/separator.jsx +22 -0
- package/src/core/lib/components/ui/sheet/index.js +34 -0
- package/src/core/lib/components/ui/sheet/sheet-close.jsx +7 -0
- package/src/core/lib/components/ui/sheet/sheet-content.jsx +35 -0
- package/src/core/lib/components/ui/sheet/sheet-description.jsx +15 -0
- package/src/core/lib/components/ui/sheet/sheet-footer.jsx +11 -0
- package/src/core/lib/components/ui/sheet/sheet-header.jsx +11 -0
- package/src/core/lib/components/ui/sheet/sheet-overlay.jsx +15 -0
- package/src/core/lib/components/ui/sheet/sheet-portal.jsx +4 -0
- package/src/core/lib/components/ui/sheet/sheet-title.jsx +15 -0
- package/src/core/lib/components/ui/sheet/sheet-trigger.jsx +7 -0
- package/src/core/lib/components/ui/sheet/sheet.jsx +4 -0
- package/src/core/lib/components/ui/textarea/index.js +7 -0
- package/src/core/lib/components/ui/textarea/textarea.jsx +18 -0
- package/src/core/lib/components/ui/toggle/index.js +8 -0
- package/src/core/lib/components/ui/toggle/toggle.jsx +36 -0
- package/src/core/lib/components/ui/toggle-group/index.js +10 -0
- package/src/core/lib/components/ui/toggle-group/toggle-group-item.jsx +29 -0
- package/src/core/lib/components/ui/toggle-group/toggle-group.jsx +43 -0
- package/src/core/lib/components/ui/tooltip/index.js +3 -0
- package/src/core/lib/components/ui/tooltip/tooltip-content.jsx +21 -0
- package/src/core/lib/components/ui/tooltip/tooltip-trigger.jsx +23 -0
- package/src/core/lib/components/ui/tooltip/tooltip.jsx +11 -0
- package/src/core/lib/components/ui/trigger-button/index.js +6 -0
- package/src/core/lib/components/ui/trigger-button/trigger-button.css +38 -0
- package/src/core/lib/components/ui/trigger-button/trigger-button.jsx +63 -0
- package/src/core/lib/utils/index.js +6 -0
- package/src/core/logger/devLogger.js +238 -0
- package/src/core/logger/devLogger.test.js +193 -0
- package/src/core/modes/modes.css +98 -0
- package/src/core/modes/modes.js +492 -0
- package/src/core/modes/modes.test.js +562 -0
- package/src/core/mountStoryboardCore.js +478 -0
- package/src/core/rename-watcher/config.json +23 -0
- package/src/core/rename-watcher/watcher.js +531 -0
- package/src/core/scaffold.js +100 -0
- package/src/core/server/index.js +391 -0
- package/src/core/session/bodyClasses.js +128 -0
- package/src/core/session/bodyClasses.test.js +192 -0
- package/src/core/session/hashSubscribe.js +19 -0
- package/src/core/session/hashSubscribe.test.js +62 -0
- package/src/core/session/hideMode.js +424 -0
- package/src/core/session/hideMode.test.js +268 -0
- package/src/core/session/interceptHideParams.js +35 -0
- package/src/core/session/interceptHideParams.test.js +90 -0
- package/src/core/session/localStorage.js +134 -0
- package/src/core/session/localStorage.test.js +148 -0
- package/src/core/session/session.js +76 -0
- package/src/core/session/session.test.js +91 -0
- package/src/core/stores/canvasConfig.js +134 -0
- package/src/core/stores/canvasConfig.test.js +120 -0
- package/src/core/stores/commandActions.js +284 -0
- package/src/core/stores/commandPaletteConfig.js +31 -0
- package/src/core/stores/configSchema.js +232 -0
- package/src/core/stores/configSchema.test.js +72 -0
- package/src/core/stores/configStore.js +161 -0
- package/src/core/stores/customerModeConfig.js +30 -0
- package/src/core/stores/featureFlags.js +127 -0
- package/src/core/stores/paletteProviders.js +360 -0
- package/src/core/stores/paletteProviders.test.js +186 -0
- package/src/core/stores/plugins.js +40 -0
- package/src/core/stores/plugins.test.js +68 -0
- package/src/core/stores/recentArtifacts.js +68 -0
- package/src/core/stores/recentArtifacts.test.js +71 -0
- package/src/core/stores/sidePanelStore.ts +143 -0
- package/src/core/stores/themeStore.ts +291 -0
- package/src/core/stores/toolRegistry.js +227 -0
- package/src/core/stores/toolStateStore.js +183 -0
- package/src/core/stores/toolStateStore.test.js +220 -0
- package/src/core/stores/toolbarConfigStore.js +165 -0
- package/src/core/stores/uiConfig.js +64 -0
- package/src/core/stores/uiConfig.test.js +63 -0
- package/src/core/styles/tailwind.css +204 -0
- package/src/core/tools/handlers/autosync.js +12 -0
- package/src/core/tools/handlers/canvasAddWidget.js +11 -0
- package/src/core/tools/handlers/canvasAgents.js +20 -0
- package/src/core/tools/handlers/canvasToolbar.js +56 -0
- package/src/core/tools/handlers/commandPalette.js +9 -0
- package/src/core/tools/handlers/comments.js +16 -0
- package/src/core/tools/handlers/create.js +39 -0
- package/src/core/tools/handlers/devtools.js +122 -0
- package/src/core/tools/handlers/devtools.test.js +87 -0
- package/src/core/tools/handlers/featureFlags.js +21 -0
- package/src/core/tools/handlers/flows.js +68 -0
- package/src/core/tools/handlers/hideChrome.js +9 -0
- package/src/core/tools/handlers/hideToolbars.js +25 -0
- package/src/core/tools/handlers/inspector.js +19 -0
- package/src/core/tools/handlers/paletteTheme.js +35 -0
- package/src/core/tools/handlers/theme.js +9 -0
- package/src/core/tools/registry.js +26 -0
- package/src/core/tools/surfaces/canvasToolbar.js +10 -0
- package/src/core/tools/surfaces/commandList.js +10 -0
- package/src/core/tools/surfaces/mainToolbar.js +11 -0
- package/src/core/tools/surfaces/registry.js +19 -0
- package/src/core/ui/ActionMenuButton.jsx +114 -0
- package/src/core/ui/AutosyncMenuButton.css +67 -0
- package/src/core/ui/AutosyncMenuButton.jsx +242 -0
- package/src/core/ui/BranchSelect.jsx +29 -0
- package/src/core/ui/BranchSelect.module.css +30 -0
- package/src/core/ui/CanvasAgentsMenu.jsx +89 -0
- package/src/core/ui/CanvasCreateMenu.jsx +611 -0
- package/src/core/ui/CanvasSnap.css +27 -0
- package/src/core/ui/CanvasSnap.jsx +51 -0
- package/src/core/ui/CanvasUndoRedo.css +36 -0
- package/src/core/ui/CanvasUndoRedo.jsx +62 -0
- package/src/core/ui/CanvasZoomControl.css +53 -0
- package/src/core/ui/CanvasZoomControl.jsx +49 -0
- package/src/core/ui/CanvasZoomToFit.css +18 -0
- package/src/core/ui/CanvasZoomToFit.jsx +26 -0
- package/src/core/ui/CommandMenu.css +8 -0
- package/src/core/ui/CommandMenu.jsx +287 -0
- package/src/core/ui/CommandPalette.jsx +35 -0
- package/src/core/ui/CommandPaletteTrigger.jsx +25 -0
- package/src/core/ui/CommentsMenuButton.jsx +40 -0
- package/src/core/ui/CoreUIBar.css +47 -0
- package/src/core/ui/CoreUIBar.jsx +905 -0
- package/src/core/ui/CreateMenuButton.jsx +117 -0
- package/src/core/ui/HideChromeTrigger.jsx +48 -0
- package/src/core/ui/Icon.jsx +279 -0
- package/src/core/ui/InspectorPanel.css +109 -0
- package/src/core/ui/InspectorPanel.jsx +632 -0
- package/src/core/ui/PwaInstallBanner.css +42 -0
- package/src/core/ui/PwaInstallBanner.jsx +124 -0
- package/src/core/ui/SidePanel.jsx +261 -0
- package/src/core/ui/ThemeMenuButton.jsx +139 -0
- package/src/core/ui/core-ui-colors.css +129 -0
- package/src/core/ui/design-modes.ts +7 -0
- package/src/core/ui/sidepanel.css +301 -0
- package/src/core/ui/viewfinder.ts +7 -0
- package/src/core/ui-entry.js +30 -0
- package/src/core/utils/fuzzySearch.js +117 -0
- package/src/core/utils/fuzzySearch.test.js +119 -0
- package/src/core/utils/mobileViewport.js +57 -0
- package/src/core/utils/mobileViewport.test.js +68 -0
- package/src/core/utils/prodMode.js +38 -0
- package/src/core/utils/smoothCorners.js +20 -0
- package/src/core/vite/docs-handler.js +155 -0
- package/src/core/vite/server-plugin.js +797 -0
- package/src/core/workshop/features/createCanvas/CreateCanvasForm.jsx +260 -0
- package/src/core/workshop/features/createCanvas/index.js +14 -0
- package/src/core/workshop/features/createFlow/CreateFlowForm.jsx +334 -0
- package/src/core/workshop/features/createFlow/index.js +19 -0
- package/src/core/workshop/features/createFlow/server.js +663 -0
- package/src/core/workshop/features/createPage/CreatePageForm.jsx +304 -0
- package/src/core/workshop/features/createPage/index.js +11 -0
- package/src/core/workshop/features/createPrototype/CreatePrototypeForm.jsx +289 -0
- package/src/core/workshop/features/createPrototype/index.js +19 -0
- package/src/core/workshop/features/createPrototype/server.js +433 -0
- package/src/core/workshop/features/createStory/CreateStoryForm.jsx +208 -0
- package/src/core/workshop/features/createStory/index.js +14 -0
- package/src/core/workshop/features/registry-server.js +22 -0
- package/src/core/workshop/features/registry.js +28 -0
- package/src/core/workshop/features/templateIndex.js +155 -0
- package/src/core/workshop/ui/WorkshopPanel.jsx +98 -0
- package/src/core/workshop/ui/mount.ts +6 -0
- package/src/core/worktree/port.js +268 -0
- package/src/core/worktree/port.test.js +222 -0
- package/src/core/worktree/serverRegistry.js +120 -0
- package/src/internals/AuthModal/AuthModal.jsx +132 -0
- package/src/internals/AuthModal/AuthModal.module.css +221 -0
- package/src/internals/BranchBar/BranchBar.jsx +87 -0
- package/src/internals/BranchBar/BranchBar.module.css +247 -0
- package/src/internals/BranchBar/useBranches.js +93 -0
- package/src/internals/BranchBar/useBranches.test.js +68 -0
- package/src/internals/CommandPalette/CommandPalette.jsx +1361 -0
- package/src/internals/CommandPalette/CreateDialog.jsx +219 -0
- package/src/internals/CommandPalette/command-palette.css +180 -0
- package/src/internals/FlowError.module.css +30 -0
- package/src/internals/Icon.jsx +279 -0
- package/src/internals/StoryboardContext.js +3 -0
- package/src/internals/Viewfinder.jsx +1479 -0
- package/src/internals/Viewfinder.module.css +1540 -0
- package/src/internals/Workspace.jsx +7 -0
- package/src/internals/__mocks__/virtual-storyboard-data-index.js +4 -0
- package/src/internals/canvas/CanvasControls.jsx +112 -0
- package/src/internals/canvas/CanvasControls.module.css +135 -0
- package/src/internals/canvas/CanvasPage.bridge.test.jsx +387 -0
- package/src/internals/canvas/CanvasPage.dragdrop.test.jsx +350 -0
- package/src/internals/canvas/CanvasPage.jsx +3092 -0
- package/src/internals/canvas/CanvasPage.module.css +187 -0
- package/src/internals/canvas/CanvasPage.multiselect.test.jsx +358 -0
- package/src/internals/canvas/CanvasToolbar.jsx +73 -0
- package/src/internals/canvas/CanvasToolbar.module.css +92 -0
- package/src/internals/canvas/ComponentErrorBoundary.jsx +50 -0
- package/src/internals/canvas/ConnectorLayer.jsx +208 -0
- package/src/internals/canvas/ConnectorLayer.module.css +129 -0
- package/src/internals/canvas/MarqueeOverlay.jsx +20 -0
- package/src/internals/canvas/PageSelector.jsx +587 -0
- package/src/internals/canvas/PageSelector.module.css +261 -0
- package/src/internals/canvas/PageSelector.test.jsx +113 -0
- package/src/internals/canvas/WebGLContextPool.jsx +292 -0
- package/src/internals/canvas/WebGLContextPool.test.jsx +165 -0
- package/src/internals/canvas/canvasApi.js +164 -0
- package/src/internals/canvas/canvasReloadGuard.js +37 -0
- package/src/internals/canvas/canvasReloadGuard.test.js +27 -0
- package/src/internals/canvas/canvasTheme.js +118 -0
- package/src/internals/canvas/componentIsolate.jsx +165 -0
- package/src/internals/canvas/componentSetIsolate.jsx +257 -0
- package/src/internals/canvas/computeCanvasBounds.test.js +121 -0
- package/src/internals/canvas/connectorGeometry.js +132 -0
- package/src/internals/canvas/hotPoolDevLogs.js +25 -0
- package/src/internals/canvas/textSelection.js +10 -0
- package/src/internals/canvas/textSelection.test.js +26 -0
- package/src/internals/canvas/useCanvas.js +126 -0
- package/src/internals/canvas/useCanvas.test.js +26 -0
- package/src/internals/canvas/useMarqueeSelect.js +213 -0
- package/src/internals/canvas/useMarqueeSelect.test.js +78 -0
- package/src/internals/canvas/useUndoRedo.js +86 -0
- package/src/internals/canvas/useUndoRedo.test.js +231 -0
- package/src/internals/canvas/widgets/CodePenEmbed.jsx +293 -0
- package/src/internals/canvas/widgets/CodePenEmbed.module.css +161 -0
- package/src/internals/canvas/widgets/ComponentSetWidget.jsx +2 -0
- package/src/internals/canvas/widgets/ComponentSetWidget.module.css +89 -0
- package/src/internals/canvas/widgets/ComponentWidget.jsx +14 -0
- package/src/internals/canvas/widgets/ComponentWidget.module.css +0 -0
- package/src/internals/canvas/widgets/CropOverlay.jsx +179 -0
- package/src/internals/canvas/widgets/CropOverlay.module.css +154 -0
- package/src/internals/canvas/widgets/ExpandedPane.jsx +474 -0
- package/src/internals/canvas/widgets/ExpandedPane.module.css +179 -0
- package/src/internals/canvas/widgets/ExpandedPane.test.jsx +240 -0
- package/src/internals/canvas/widgets/ExpandedPaneTopBar.jsx +111 -0
- package/src/internals/canvas/widgets/ExpandedPaneTopBar.module.css +59 -0
- package/src/internals/canvas/widgets/ExpandedPaneTopBar.test.jsx +45 -0
- package/src/internals/canvas/widgets/FigmaEmbed.jsx +296 -0
- package/src/internals/canvas/widgets/FigmaEmbed.module.css +222 -0
- package/src/internals/canvas/widgets/FrozenTerminalOverlay.jsx +151 -0
- package/src/internals/canvas/widgets/FrozenTerminalOverlay.module.css +83 -0
- package/src/internals/canvas/widgets/ImageWidget.jsx +287 -0
- package/src/internals/canvas/widgets/ImageWidget.module.css +81 -0
- package/src/internals/canvas/widgets/LinkPreview.jsx +439 -0
- package/src/internals/canvas/widgets/LinkPreview.module.css +585 -0
- package/src/internals/canvas/widgets/LinkPreview.test.jsx +193 -0
- package/src/internals/canvas/widgets/MarkdownBlock.jsx +354 -0
- package/src/internals/canvas/widgets/MarkdownBlock.module.css +377 -0
- package/src/internals/canvas/widgets/MarkdownBlock.test.jsx +92 -0
- package/src/internals/canvas/widgets/PromptWidget.jsx +428 -0
- package/src/internals/canvas/widgets/PromptWidget.module.css +273 -0
- package/src/internals/canvas/widgets/PrototypeEmbed.jsx +463 -0
- package/src/internals/canvas/widgets/PrototypeEmbed.module.css +579 -0
- package/src/internals/canvas/widgets/PrototypeEmbed.test.jsx +10 -0
- package/src/internals/canvas/widgets/ResizeHandle.jsx +67 -0
- package/src/internals/canvas/widgets/ResizeHandle.module.css +29 -0
- package/src/internals/canvas/widgets/StickyNote.jsx +92 -0
- package/src/internals/canvas/widgets/StickyNote.module.css +70 -0
- package/src/internals/canvas/widgets/StickyNote.test.jsx +116 -0
- package/src/internals/canvas/widgets/StorySetWidget.jsx +208 -0
- package/src/internals/canvas/widgets/StorySetWidget.module.css +89 -0
- package/src/internals/canvas/widgets/StoryWidget.jsx +334 -0
- package/src/internals/canvas/widgets/StoryWidget.module.css +211 -0
- package/src/internals/canvas/widgets/TerminalReadWidget.jsx +146 -0
- package/src/internals/canvas/widgets/TerminalReadWidget.module.css +94 -0
- package/src/internals/canvas/widgets/TerminalWidget.jsx +704 -0
- package/src/internals/canvas/widgets/TerminalWidget.module.css +444 -0
- package/src/internals/canvas/widgets/TilesWidget.jsx +300 -0
- package/src/internals/canvas/widgets/TilesWidget.module.css +133 -0
- package/src/internals/canvas/widgets/WidgetChrome.jsx +580 -0
- package/src/internals/canvas/widgets/WidgetChrome.module.css +421 -0
- package/src/internals/canvas/widgets/WidgetWrapper.jsx +15 -0
- package/src/internals/canvas/widgets/WidgetWrapper.module.css +25 -0
- package/src/internals/canvas/widgets/codepenUrl.js +75 -0
- package/src/internals/canvas/widgets/codepenUrl.test.js +76 -0
- package/src/internals/canvas/widgets/embedInteraction.test.jsx +173 -0
- package/src/internals/canvas/widgets/embedOverlay.module.css +35 -0
- package/src/internals/canvas/widgets/embedTheme.js +148 -0
- package/src/internals/canvas/widgets/expandUtils.js +559 -0
- package/src/internals/canvas/widgets/expandUtils.test.js +155 -0
- package/src/internals/canvas/widgets/figmaUrl.js +118 -0
- package/src/internals/canvas/widgets/figmaUrl.test.js +139 -0
- package/src/internals/canvas/widgets/githubUrl.js +82 -0
- package/src/internals/canvas/widgets/githubUrl.test.js +74 -0
- package/src/internals/canvas/widgets/iframeDevLogs.js +49 -0
- package/src/internals/canvas/widgets/iframeDevLogs.test.jsx +81 -0
- package/src/internals/canvas/widgets/index.js +42 -0
- package/src/internals/canvas/widgets/pasteRules.js +295 -0
- package/src/internals/canvas/widgets/pasteRules.test.js +474 -0
- package/src/internals/canvas/widgets/snapshotDisplay.test.jsx +211 -0
- package/src/internals/canvas/widgets/tilePool.js +23 -0
- package/src/internals/canvas/widgets/tiles/diagonal-bl.png +0 -0
- package/src/internals/canvas/widgets/tiles/diagonal-br.png +0 -0
- package/src/internals/canvas/widgets/tiles/diagonal-tl.png +0 -0
- package/src/internals/canvas/widgets/tiles/leaf.png +0 -0
- package/src/internals/canvas/widgets/tiles/quarter-tl.png +0 -0
- package/src/internals/canvas/widgets/tiles/quarter-tr.png +0 -0
- package/src/internals/canvas/widgets/tiles/solid-a.png +0 -0
- package/src/internals/canvas/widgets/tiles/solid-b.png +0 -0
- package/src/internals/canvas/widgets/widgetConfig.js +291 -0
- package/src/internals/canvas/widgets/widgetConfig.test.js +68 -0
- package/src/internals/canvas/widgets/widgetIcons.jsx +190 -0
- package/src/internals/canvas/widgets/widgetProps.js +133 -0
- package/src/internals/context/FormContext.js +13 -0
- package/src/internals/context/FormContext.test.js +48 -0
- package/src/internals/context.jsx +481 -0
- package/src/internals/context.test.jsx +296 -0
- package/src/internals/hashPreserver.js +73 -0
- package/src/internals/hashPreserver.test.js +107 -0
- package/src/internals/hooks/useConfig.js +14 -0
- package/src/internals/hooks/useFeatureFlag.js +14 -0
- package/src/internals/hooks/useFlows.js +50 -0
- package/src/internals/hooks/useFlows.test.js +134 -0
- package/src/internals/hooks/useHideMode.js +31 -0
- package/src/internals/hooks/useHideMode.test.js +43 -0
- package/src/internals/hooks/useLocalStorage.js +57 -0
- package/src/internals/hooks/useLocalStorage.test.js +75 -0
- package/src/internals/hooks/useMode.js +43 -0
- package/src/internals/hooks/useObject.js +101 -0
- package/src/internals/hooks/useObject.test.js +74 -0
- package/src/internals/hooks/useOverride.js +84 -0
- package/src/internals/hooks/useOverride.test.js +71 -0
- package/src/internals/hooks/usePrototypeReloadGuard.js +64 -0
- package/src/internals/hooks/useRecord.js +158 -0
- package/src/internals/hooks/useRecord.test.js +221 -0
- package/src/internals/hooks/useScene.js +38 -0
- package/src/internals/hooks/useScene.test.js +66 -0
- package/src/internals/hooks/useSceneData.js +108 -0
- package/src/internals/hooks/useSceneData.test.js +136 -0
- package/src/internals/hooks/useSession.js +4 -0
- package/src/internals/hooks/useSession.test.js +8 -0
- package/src/internals/hooks/useThemeState.js +61 -0
- package/src/internals/hooks/useThemeState.test.js +66 -0
- package/src/internals/hooks/useUndoRedo.js +28 -0
- package/src/internals/hooks/useUndoRedo.test.js +64 -0
- package/src/internals/index.js +58 -0
- package/src/internals/story/ComponentSetPage.jsx +198 -0
- package/src/internals/story/ComponentSetPage.module.css +129 -0
- package/src/internals/story/StoryPage.jsx +147 -0
- package/src/internals/story/StoryPage.module.css +18 -0
- package/src/internals/test-utils.js +45 -0
- package/src/internals/vite/data-plugin.js +1508 -0
- package/src/internals/vite/data-plugin.test.js +1223 -0
- package/src/test-utils.js +44 -0
- package/toolbar.config.json +271 -0
- package/widgets.config.json +1537 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas Widget Props API
|
|
3
|
+
*
|
|
4
|
+
* Every canvas widget receives its data through a structured `props` object
|
|
5
|
+
* stored in .canvas.json. This module defines the prop schema system that
|
|
6
|
+
* widgets use to declare, read, and update their editable properties.
|
|
7
|
+
*
|
|
8
|
+
* ## Prop Categories
|
|
9
|
+
*
|
|
10
|
+
* Widget props are grouped into three categories:
|
|
11
|
+
*
|
|
12
|
+
* ### `content` — User-editable content
|
|
13
|
+
* Text, markdown, URLs — the stuff users type or paste.
|
|
14
|
+
* Updated frequently (every keystroke when editing).
|
|
15
|
+
* Examples: sticky note text, markdown content, embed URL.
|
|
16
|
+
*
|
|
17
|
+
* ### `settings` — Widget configuration
|
|
18
|
+
* One-off choices that affect appearance or behavior.
|
|
19
|
+
* Updated infrequently (user picks from a menu).
|
|
20
|
+
* Examples: sticky note color, markdown width, embed layout.
|
|
21
|
+
*
|
|
22
|
+
* ### `size` — Dimensions
|
|
23
|
+
* Width and height of the widget.
|
|
24
|
+
* Updated via resize handles or explicit input.
|
|
25
|
+
* Examples: markdown block width, prototype embed width/height.
|
|
26
|
+
*
|
|
27
|
+
* ## Storage Format (.canvas.json)
|
|
28
|
+
*
|
|
29
|
+
* Props are stored flat in the widget's `props` object:
|
|
30
|
+
*
|
|
31
|
+
* ```json
|
|
32
|
+
* {
|
|
33
|
+
* "id": "sticky-1",
|
|
34
|
+
* "type": "sticky-note",
|
|
35
|
+
* "position": { "x": 100, "y": 200 },
|
|
36
|
+
* "props": {
|
|
37
|
+
* "text": "Hello world",
|
|
38
|
+
* "color": "yellow"
|
|
39
|
+
* }
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* ## Widget Contract
|
|
44
|
+
*
|
|
45
|
+
* Every widget component receives:
|
|
46
|
+
* - `id` — stable widget identifier
|
|
47
|
+
* - `props` — the flat props object (may be null/undefined)
|
|
48
|
+
* - `onUpdate` — callback to persist prop changes: onUpdate({ key: value })
|
|
49
|
+
* - `onRemove` — callback to delete the widget
|
|
50
|
+
*
|
|
51
|
+
* `onUpdate` accepts a partial object that is shallow-merged into `props`.
|
|
52
|
+
* Multiple keys can be updated in one call:
|
|
53
|
+
* onUpdate({ text: 'new text', color: 'blue' })
|
|
54
|
+
*
|
|
55
|
+
* ## Declaring Widget Props (Schema)
|
|
56
|
+
*
|
|
57
|
+
* Widget prop schemas are defined in widgets.config.json (packages/core)
|
|
58
|
+
* and loaded via widgetConfig.js. This module re-exports the generated
|
|
59
|
+
* schemas and provides utility functions for reading props with defaults.
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @typedef {'text' | 'select' | 'number' | 'url' | 'boolean'} PropType
|
|
64
|
+
*
|
|
65
|
+
* @typedef {Object} PropDef
|
|
66
|
+
* @property {PropType} type — input type for editing
|
|
67
|
+
* @property {string} label — human-readable label
|
|
68
|
+
* @property {string} category — 'content' | 'settings' | 'size'
|
|
69
|
+
* @property {*} defaultValue — fallback when prop is missing
|
|
70
|
+
* @property {Array} [options] — choices for 'select' type
|
|
71
|
+
* @property {number} [min] — minimum for 'number' type
|
|
72
|
+
* @property {number} [max] — maximum for 'number' type
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
import { schemas as configSchemas } from './widgetConfig.js'
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Read a prop value with fallback to schema default.
|
|
79
|
+
* @param {object} props — widget props object (may be null)
|
|
80
|
+
* @param {string} key — prop name
|
|
81
|
+
* @param {object} schema — widget schema
|
|
82
|
+
* @returns {*}
|
|
83
|
+
*/
|
|
84
|
+
export function readProp(props, key, schema) {
|
|
85
|
+
const value = props?.[key]
|
|
86
|
+
if (value !== undefined && value !== null) return value
|
|
87
|
+
return schema[key]?.defaultValue ?? null
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Read all props with defaults applied from schema.
|
|
92
|
+
* @param {object} props — widget props object (may be null)
|
|
93
|
+
* @param {object} schema — widget schema
|
|
94
|
+
* @returns {object}
|
|
95
|
+
*/
|
|
96
|
+
export function readAllProps(props, schema) {
|
|
97
|
+
const result = {}
|
|
98
|
+
for (const key of Object.keys(schema)) {
|
|
99
|
+
result[key] = readProp(props, key, schema)
|
|
100
|
+
}
|
|
101
|
+
return result
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get default props for a widget type from its schema.
|
|
106
|
+
* Used when creating new widgets.
|
|
107
|
+
* @param {object} schema — widget schema
|
|
108
|
+
* @returns {object}
|
|
109
|
+
*/
|
|
110
|
+
export function getDefaults(schema) {
|
|
111
|
+
const result = {}
|
|
112
|
+
for (const [key, def] of Object.entries(schema)) {
|
|
113
|
+
if (def.defaultValue !== undefined) {
|
|
114
|
+
result[key] = def.defaultValue
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return result
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ── Config-driven schemas ───────────────────────────────────────────
|
|
121
|
+
|
|
122
|
+
/** Schema registry — maps widget type strings to their schemas. */
|
|
123
|
+
export const schemas = configSchemas
|
|
124
|
+
|
|
125
|
+
// Named exports for backward compatibility with widget imports
|
|
126
|
+
export const stickyNoteSchema = schemas['sticky-note']
|
|
127
|
+
export const markdownSchema = schemas['markdown']
|
|
128
|
+
export const prototypeEmbedSchema = schemas['prototype']
|
|
129
|
+
export const linkPreviewSchema = schemas['link-preview']
|
|
130
|
+
export const imageSchema = schemas['image']
|
|
131
|
+
export const figmaEmbedSchema = schemas['figma-embed']
|
|
132
|
+
export const terminalSchema = schemas['terminal']
|
|
133
|
+
export const promptSchema = schemas['prompt']
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createContext } from 'react'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Provides the form context from <StoryboardForm> to child inputs.
|
|
5
|
+
*
|
|
6
|
+
* Value shape:
|
|
7
|
+
* {
|
|
8
|
+
* prefix: string, // data path prefix (e.g. "checkout")
|
|
9
|
+
* getDraft: (name) => any, // read local draft value for a field
|
|
10
|
+
* setDraft: (name, value) => void, // write local draft value
|
|
11
|
+
* }
|
|
12
|
+
*/
|
|
13
|
+
export const FormContext = createContext(null)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createElement } from 'react'
|
|
2
|
+
import { render, screen } from '@testing-library/react'
|
|
3
|
+
import { FormContext } from './FormContext.js'
|
|
4
|
+
|
|
5
|
+
describe('FormContext', () => {
|
|
6
|
+
it('is a React context object', () => {
|
|
7
|
+
expect(FormContext).toBeDefined()
|
|
8
|
+
expect(FormContext.Provider).toBeDefined()
|
|
9
|
+
expect(FormContext.Consumer).toBeDefined()
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('has a default value of null', () => {
|
|
13
|
+
function Reader() {
|
|
14
|
+
return createElement(FormContext.Consumer, null, (value) =>
|
|
15
|
+
createElement('span', { 'data-testid': 'val' }, String(value)),
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
render(createElement(Reader))
|
|
19
|
+
expect(screen.getByTestId('val')).toHaveTextContent('null')
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('can provide and consume a value with prefix, getDraft, setDraft', () => {
|
|
23
|
+
const getDraft = vi.fn((name) => `draft-${name}`)
|
|
24
|
+
const setDraft = vi.fn()
|
|
25
|
+
const contextValue = { prefix: 'checkout', getDraft, setDraft }
|
|
26
|
+
|
|
27
|
+
function Reader() {
|
|
28
|
+
return createElement(FormContext.Consumer, null, (value) =>
|
|
29
|
+
createElement(
|
|
30
|
+
'span',
|
|
31
|
+
{ 'data-testid': 'val' },
|
|
32
|
+
`${value.prefix}:${value.getDraft('email')}`,
|
|
33
|
+
),
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
render(
|
|
38
|
+
createElement(
|
|
39
|
+
FormContext.Provider,
|
|
40
|
+
{ value: contextValue },
|
|
41
|
+
createElement(Reader),
|
|
42
|
+
),
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
expect(screen.getByTestId('val')).toHaveTextContent('checkout:draft-email')
|
|
46
|
+
expect(getDraft).toHaveBeenCalledWith('email')
|
|
47
|
+
})
|
|
48
|
+
})
|
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
import { useState, useEffect, useMemo, useRef, Suspense, lazy } from 'react'
|
|
2
|
+
import { useParams, useLocation } from 'react-router-dom'
|
|
3
|
+
// Named import seeds the core data index via init() AND provides canvas/story route data
|
|
4
|
+
import { canvases, stories } from 'virtual:storyboard-data-index'
|
|
5
|
+
import { loadFlow, flowExists, findRecord, deepMerge, setFlowClass, installBodyClassSync, resolveFlowName, resolveRecordName, isModesEnabled, getPrototypeMetadata } from '../core/index.js'
|
|
6
|
+
import { StoryboardContext } from './StoryboardContext.js'
|
|
7
|
+
import usePrototypeReloadGuard from './hooks/usePrototypeReloadGuard.js'
|
|
8
|
+
import styles from './FlowError.module.css'
|
|
9
|
+
|
|
10
|
+
export { StoryboardContext }
|
|
11
|
+
|
|
12
|
+
const CanvasPageLazy = lazy(() => import('./canvas/CanvasPage.jsx'))
|
|
13
|
+
const StoryPageLazy = lazy(() => import('./story/StoryPage.jsx'))
|
|
14
|
+
const CommandPaletteLazy = lazy(() => import('./CommandPalette/CommandPalette.jsx'))
|
|
15
|
+
|
|
16
|
+
// Build a map from canvas route paths → canvas names at module load time
|
|
17
|
+
const canvasRouteMap = new Map()
|
|
18
|
+
// Build a map from group name → array of { name, route, title } for page selector
|
|
19
|
+
const canvasGroupMap = new Map()
|
|
20
|
+
for (const [name, data] of Object.entries(canvases || {})) {
|
|
21
|
+
const route = (data?._route || `/canvas/${name}`).replace(/\/+$/, '')
|
|
22
|
+
canvasRouteMap.set(route, name)
|
|
23
|
+
const group = data?._group
|
|
24
|
+
if (group) {
|
|
25
|
+
if (!canvasGroupMap.has(group)) canvasGroupMap.set(group, [])
|
|
26
|
+
canvasGroupMap.get(group).push({
|
|
27
|
+
name,
|
|
28
|
+
route,
|
|
29
|
+
title: data?.title || name.split('/').pop(),
|
|
30
|
+
_canvasMeta: data?._canvasMeta || null,
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Sort each group's pages by pageOrder from .meta.json (if available)
|
|
35
|
+
for (const [, pages] of canvasGroupMap) {
|
|
36
|
+
const pageOrder = pages[0]?._canvasMeta?.pageOrder
|
|
37
|
+
if (Array.isArray(pageOrder)) {
|
|
38
|
+
const orderMap = new Map()
|
|
39
|
+
pageOrder.forEach((entry, idx) => {
|
|
40
|
+
if (typeof entry === 'string' && !entry.startsWith('sep-')) orderMap.set(entry, idx)
|
|
41
|
+
})
|
|
42
|
+
pages.sort((a, b) => {
|
|
43
|
+
const ai = orderMap.has(a.name) ? orderMap.get(a.name) : Infinity
|
|
44
|
+
const bi = orderMap.has(b.name) ? orderMap.get(b.name) : Infinity
|
|
45
|
+
return ai - bi
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function matchCanvasRoute(pathname) {
|
|
51
|
+
const normalized = stripBasePath(pathname)
|
|
52
|
+
return canvasRouteMap.get(normalized) || null
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Live-lookup a story route against the current `stories` object.
|
|
57
|
+
*
|
|
58
|
+
* Unlike the canvas route map (built once at module scope), this iterates
|
|
59
|
+
* the `stories` object on every call so it always reflects HMR mutations
|
|
60
|
+
* (the virtual-module HMR handler mutates `stories` in place).
|
|
61
|
+
*
|
|
62
|
+
* Also strips encoded query strings (%3F / %3f) that can leak into the
|
|
63
|
+
* pathname when an iframe src is percent-encoded incorrectly.
|
|
64
|
+
*/
|
|
65
|
+
function matchStoryRoute(pathname) {
|
|
66
|
+
let normalized = stripBasePath(pathname)
|
|
67
|
+
// Strip encoded query strings that leaked into the path (%3F / %3f = ?)
|
|
68
|
+
const encodedIdx = normalized.search(/%3f/i)
|
|
69
|
+
if (encodedIdx !== -1) normalized = normalized.substring(0, encodedIdx)
|
|
70
|
+
const literalIdx = normalized.indexOf('?')
|
|
71
|
+
if (literalIdx !== -1) normalized = normalized.substring(0, literalIdx)
|
|
72
|
+
|
|
73
|
+
for (const [name, data] of Object.entries(stories || {})) {
|
|
74
|
+
if (data?._route && data._route.replace(/\/+$/, '') === normalized) {
|
|
75
|
+
return name
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return null
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Strip the app's sub-path prefix (e.g. /storyboard) from the pathname.
|
|
83
|
+
* React Router's basename strips the branch prefix but not the app name prefix
|
|
84
|
+
* when the app runs under a nested base path.
|
|
85
|
+
*/
|
|
86
|
+
function stripBasePath(pathname) {
|
|
87
|
+
let p = pathname.replace(/\/+$/, '') || '/'
|
|
88
|
+
// BASE_URL includes branch prefix + app path (e.g. /branch--name/storyboard/)
|
|
89
|
+
// React Router strips the branch prefix but may leave the app sub-path
|
|
90
|
+
const base = (import.meta.env?.BASE_URL || '/').replace(/\/+$/, '')
|
|
91
|
+
if (base && base !== '/') {
|
|
92
|
+
// Extract just the last segment(s) after the branch prefix
|
|
93
|
+
const withoutBranch = base.replace(/^\/branch--[^/]+/, '')
|
|
94
|
+
const subPath = withoutBranch.replace(/\/+$/, '')
|
|
95
|
+
if (subPath && p.startsWith(subPath)) {
|
|
96
|
+
p = p.slice(subPath.length) || '/'
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return p
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function isCanvasPath(pathname) {
|
|
103
|
+
const normalized = stripBasePath(pathname)
|
|
104
|
+
return normalized === '/canvas' || normalized.startsWith('/canvas/')
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function isStoryPath(pathname) {
|
|
108
|
+
const normalized = stripBasePath(pathname)
|
|
109
|
+
return normalized === '/components' || normalized.startsWith('/components/')
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Derives the top-level prototype name from a pathname.
|
|
114
|
+
* "/Dashboard" → "Dashboard", "/Dashboard/sub" → "Dashboard"
|
|
115
|
+
* "/posts/123" → "posts", "/" → null
|
|
116
|
+
*/
|
|
117
|
+
function getPrototypeName(pathname) {
|
|
118
|
+
const path = pathname.replace(/\/+$/, '') || '/'
|
|
119
|
+
if (path === '/') return null
|
|
120
|
+
const segments = path.split('/').filter(Boolean)
|
|
121
|
+
return segments[0] || null
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Derives a flow name from a pathname.
|
|
126
|
+
* "/Overview" → "Overview", "/" → "index", "/nested/Page" → "Page"
|
|
127
|
+
*/
|
|
128
|
+
function getPageFlowName(pathname) {
|
|
129
|
+
const path = pathname.replace(/\/+$/, '') || '/'
|
|
130
|
+
if (path === '/') return 'index'
|
|
131
|
+
const last = path.split('/').pop()
|
|
132
|
+
return last || 'index'
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Provides loaded flow data to the component tree.
|
|
137
|
+
* Reads the flow name from the ?flow= URL param (with ?scene= as alias),
|
|
138
|
+
* a matching flow file for the current page, or defaults to "default".
|
|
139
|
+
*
|
|
140
|
+
* Derives the prototype scope from the route and uses it to resolve
|
|
141
|
+
* scoped flow and record names (e.g. "Dashboard/default" for /Dashboard).
|
|
142
|
+
*
|
|
143
|
+
* Optionally merges record data when `recordName` and `recordParam` are provided.
|
|
144
|
+
* The matched record entry is injected under the "record" key in flow data.
|
|
145
|
+
*/
|
|
146
|
+
export default function StoryboardProvider({ flowName, sceneName, recordName, recordParam, children }) {
|
|
147
|
+
const basePath = import.meta.env?.BASE_URL || '/'
|
|
148
|
+
|
|
149
|
+
// Suppress HMR full-reloads when prototype-auto-reload flag is off
|
|
150
|
+
usePrototypeReloadGuard()
|
|
151
|
+
|
|
152
|
+
return (
|
|
153
|
+
<>
|
|
154
|
+
<StoryboardProviderInner
|
|
155
|
+
flowName={flowName}
|
|
156
|
+
sceneName={sceneName}
|
|
157
|
+
recordName={recordName}
|
|
158
|
+
recordParam={recordParam}
|
|
159
|
+
>
|
|
160
|
+
{children}
|
|
161
|
+
</StoryboardProviderInner>
|
|
162
|
+
<Suspense fallback={null}>
|
|
163
|
+
<CommandPaletteLazy basePath={basePath} />
|
|
164
|
+
</Suspense>
|
|
165
|
+
</>
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function StoryboardProviderInner({ flowName, sceneName, recordName, recordParam, children }) {
|
|
170
|
+
const location = useLocation()
|
|
171
|
+
const params = useParams()
|
|
172
|
+
|
|
173
|
+
// Re-evaluate story route detection when the data index changes via HMR.
|
|
174
|
+
// The virtual-module HMR handler mutates `stories` in place and dispatches
|
|
175
|
+
// this event; bumping the key forces useMemo deps to re-fire.
|
|
176
|
+
const [storyIndexKey, setStoryIndexKey] = useState(0)
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
const handler = () => setStoryIndexKey((k) => k + 1)
|
|
179
|
+
document.addEventListener('storyboard:story-index-changed', handler)
|
|
180
|
+
return () => document.removeEventListener('storyboard:story-index-changed', handler)
|
|
181
|
+
}, [])
|
|
182
|
+
|
|
183
|
+
// Story route detection — matches current URL against registered story routes
|
|
184
|
+
// storyIndexKey forces re-evaluation when HMR mutates the stories object in place
|
|
185
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
186
|
+
const storyName = useMemo(() => matchStoryRoute(location.pathname), [location.pathname, storyIndexKey])
|
|
187
|
+
const isMissingStoryRoute = useMemo(
|
|
188
|
+
() => isStoryPath(location.pathname) && !storyName,
|
|
189
|
+
[location.pathname, storyName],
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
// Canvas route detection — matches current URL against registered canvas routes
|
|
193
|
+
const canvasId = useMemo(() => matchCanvasRoute(location.pathname), [location.pathname])
|
|
194
|
+
const isMissingCanvasRoute = useMemo(
|
|
195
|
+
() => isCanvasPath(location.pathname) && !canvasId && !storyName,
|
|
196
|
+
[location.pathname, canvasId, storyName],
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
const searchParams = new URLSearchParams(location.search)
|
|
200
|
+
const sceneParam = searchParams.get('flow') || searchParams.get('scene')
|
|
201
|
+
const prototypeName = getPrototypeName(location.pathname)
|
|
202
|
+
const pageFlow = getPageFlowName(location.pathname)
|
|
203
|
+
|
|
204
|
+
// Resolve flow name with prototype scoping (skip for canvas/story pages)
|
|
205
|
+
const activeFlowName = useMemo(() => {
|
|
206
|
+
if (canvasId || isMissingCanvasRoute || storyName || isMissingStoryRoute) return null
|
|
207
|
+
const requested = sceneParam || flowName || sceneName
|
|
208
|
+
if (requested) {
|
|
209
|
+
// Allow fully-scoped flow names from URLs/widgets without re-prefixing
|
|
210
|
+
// (e.g. "Proto/flow" should not become "Proto/Proto/flow").
|
|
211
|
+
if (requested.includes('/')) return requested
|
|
212
|
+
return resolveFlowName(prototypeName, requested)
|
|
213
|
+
}
|
|
214
|
+
// 1. Page-specific flow (e.g., Example/Forms)
|
|
215
|
+
const scopedPageFlow = resolveFlowName(prototypeName, pageFlow)
|
|
216
|
+
if (flowExists(scopedPageFlow)) return scopedPageFlow
|
|
217
|
+
// 2. Prototype flow — named after the prototype folder (e.g., Example/example)
|
|
218
|
+
if (prototypeName) {
|
|
219
|
+
const protoFlow = resolveFlowName(prototypeName, prototypeName)
|
|
220
|
+
if (flowExists(protoFlow)) return protoFlow
|
|
221
|
+
}
|
|
222
|
+
// 3. Prototype-scoped default (e.g. Example/default)
|
|
223
|
+
if (prototypeName) {
|
|
224
|
+
const scopedDefault = resolveFlowName(prototypeName, 'default')
|
|
225
|
+
if (flowExists(scopedDefault)) return scopedDefault
|
|
226
|
+
}
|
|
227
|
+
// 4. Global default — or null if no flow exists at all
|
|
228
|
+
if (flowExists('default')) return 'default'
|
|
229
|
+
return null
|
|
230
|
+
}, [canvasId, isMissingCanvasRoute, storyName, isMissingStoryRoute, sceneParam, flowName, sceneName, prototypeName, pageFlow])
|
|
231
|
+
|
|
232
|
+
// Auto-install body class sync (sb-key--value classes on <body>)
|
|
233
|
+
useEffect(() => installBodyClassSync(), [])
|
|
234
|
+
|
|
235
|
+
// Update document.title to reflect the current artifact
|
|
236
|
+
useEffect(() => {
|
|
237
|
+
const base = import.meta.env?.BASE_URL || '/'
|
|
238
|
+
const branchMatch = base.match(/\/branch--([^/]+)/)
|
|
239
|
+
const branchSuffix = branchMatch ? ` (${branchMatch[1]})` : ''
|
|
240
|
+
|
|
241
|
+
let title
|
|
242
|
+
if (canvasId) {
|
|
243
|
+
const canvasData = canvases?.[canvasId]
|
|
244
|
+
const meta = canvasData?._canvasMeta
|
|
245
|
+
const pageTitle = canvasData?.title || canvasId.split('/').pop()
|
|
246
|
+
title = (meta?.title || pageTitle) + ' · Storyboard'
|
|
247
|
+
} else if (prototypeName) {
|
|
248
|
+
title = prototypeName + ' · Storyboard'
|
|
249
|
+
} else {
|
|
250
|
+
title = 'Storyboard'
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
document.title = title + branchSuffix
|
|
254
|
+
}, [canvasId, prototypeName])
|
|
255
|
+
|
|
256
|
+
// Mount design modes UI when enabled in storyboard.config.json
|
|
257
|
+
useEffect(() => {
|
|
258
|
+
if (!isModesEnabled()) return
|
|
259
|
+
|
|
260
|
+
let cleanup
|
|
261
|
+
import('@dfosco/storyboard/ui-runtime')
|
|
262
|
+
.then(({ mountDesignModes }) => {
|
|
263
|
+
cleanup = mountDesignModes()
|
|
264
|
+
})
|
|
265
|
+
.catch(() => {
|
|
266
|
+
// UI not available — degrade gracefully
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
return () => cleanup?.()
|
|
270
|
+
}, [])
|
|
271
|
+
|
|
272
|
+
// Skip flow loading for canvas/story pages and flow-less pages
|
|
273
|
+
const { data, error, flowTokens } = useMemo(() => {
|
|
274
|
+
if (canvasId || isMissingCanvasRoute || storyName || isMissingStoryRoute) return { data: null, error: null, flowTokens: null }
|
|
275
|
+
if (!activeFlowName) return { data: {}, error: null, flowTokens: null }
|
|
276
|
+
try {
|
|
277
|
+
let flowData = loadFlow(activeFlowName)
|
|
278
|
+
|
|
279
|
+
// Extract tokens before passing data to consumers (reserved metadata key)
|
|
280
|
+
const extractedTokens = flowData?.tokens || null
|
|
281
|
+
if (flowData?.tokens) {
|
|
282
|
+
flowData = { ...flowData }
|
|
283
|
+
delete flowData.tokens
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Merge record data if configured (with scoped resolution)
|
|
287
|
+
if (recordName && recordParam && params[recordParam]) {
|
|
288
|
+
const resolvedRecord = resolveRecordName(prototypeName, recordName)
|
|
289
|
+
const entry = findRecord(resolvedRecord, params[recordParam])
|
|
290
|
+
if (entry) {
|
|
291
|
+
flowData = deepMerge(flowData, { record: entry })
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
setFlowClass(activeFlowName)
|
|
296
|
+
return { data: flowData, error: null, flowTokens: extractedTokens }
|
|
297
|
+
} catch (err) {
|
|
298
|
+
return { data: null, error: err.message, flowTokens: null }
|
|
299
|
+
}
|
|
300
|
+
}, [canvasId, isMissingCanvasRoute, storyName, isMissingStoryRoute, activeFlowName, recordName, recordParam, params, prototypeName])
|
|
301
|
+
|
|
302
|
+
// Resolve prototype-level tokens from .prototype.json metadata
|
|
303
|
+
const protoTokens = useMemo(() => {
|
|
304
|
+
if (!prototypeName) return null
|
|
305
|
+
const meta = getPrototypeMetadata(prototypeName)
|
|
306
|
+
return meta?.tokens || null
|
|
307
|
+
}, [prototypeName])
|
|
308
|
+
|
|
309
|
+
// Merge prototype + flow tokens (flow wins). Stable reference when tokens don't change.
|
|
310
|
+
const mergedTokens = useMemo(() => {
|
|
311
|
+
if (!protoTokens && !flowTokens) return null
|
|
312
|
+
return { ...(protoTokens || {}), ...(flowTokens || {}) }
|
|
313
|
+
}, [protoTokens, flowTokens])
|
|
314
|
+
|
|
315
|
+
// Track which URL params were set by tokens (vs. user-explicit params)
|
|
316
|
+
const managedParamsRef = useRef({})
|
|
317
|
+
|
|
318
|
+
// Apply merged tokens to URL search params via replaceState.
|
|
319
|
+
// Only sets params not already present (user-explicit wins on first load).
|
|
320
|
+
// Cleans up stale managed params when flow/prototype tokens change.
|
|
321
|
+
useEffect(() => {
|
|
322
|
+
const url = new URL(window.location.href)
|
|
323
|
+
const managed = managedParamsRef.current
|
|
324
|
+
const nextManaged = {}
|
|
325
|
+
let changed = false
|
|
326
|
+
|
|
327
|
+
// Remove stale managed params no longer in merged tokens
|
|
328
|
+
for (const key of Object.keys(managed)) {
|
|
329
|
+
if (!mergedTokens || !(key in mergedTokens)) {
|
|
330
|
+
url.searchParams.delete(key)
|
|
331
|
+
changed = true
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Apply current tokens
|
|
336
|
+
if (mergedTokens) {
|
|
337
|
+
const reserved = new Set(['flow', 'scene'])
|
|
338
|
+
for (const [key, value] of Object.entries(mergedTokens)) {
|
|
339
|
+
if (value == null || typeof value === 'object' || reserved.has(key)) continue
|
|
340
|
+
const strValue = String(value)
|
|
341
|
+
if (!url.searchParams.has(key) || (key in managed && managed[key] !== strValue)) {
|
|
342
|
+
url.searchParams.set(key, strValue)
|
|
343
|
+
nextManaged[key] = strValue
|
|
344
|
+
changed = true
|
|
345
|
+
} else if (key in managed) {
|
|
346
|
+
nextManaged[key] = strValue
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
managedParamsRef.current = nextManaged
|
|
352
|
+
|
|
353
|
+
if (changed) {
|
|
354
|
+
window.history.replaceState(window.history.state, '', url.toString())
|
|
355
|
+
}
|
|
356
|
+
}, [mergedTokens])
|
|
357
|
+
|
|
358
|
+
// Canvas pages get their own rendering path — no flow data needed
|
|
359
|
+
if (canvasId) {
|
|
360
|
+
const canvasData = canvases?.[canvasId]
|
|
361
|
+
const group = canvasData?._group
|
|
362
|
+
// Include the current canvas as a sibling even if it's the only page in its group,
|
|
363
|
+
// so the PageSelector can render and allow adding new pages.
|
|
364
|
+
const siblingPages = group
|
|
365
|
+
? canvasGroupMap.get(group) || []
|
|
366
|
+
: [{ name: canvasId, route: canvasData?._route || `/canvas/${canvasId}`, title: canvasData?.title || canvasId.split('/').pop() }]
|
|
367
|
+
const canvasMeta = canvasData?._canvasMeta || null
|
|
368
|
+
const canvasValue = {
|
|
369
|
+
data: null,
|
|
370
|
+
error: null,
|
|
371
|
+
loading: false,
|
|
372
|
+
flowName: null,
|
|
373
|
+
sceneName: null,
|
|
374
|
+
prototypeName: null,
|
|
375
|
+
}
|
|
376
|
+
return (
|
|
377
|
+
<StoryboardContext.Provider value={canvasValue}>
|
|
378
|
+
<Suspense fallback={null}>
|
|
379
|
+
<CanvasPageLazy canvasId={canvasId} siblingPages={siblingPages} canvasMeta={canvasMeta} />
|
|
380
|
+
</Suspense>
|
|
381
|
+
</StoryboardContext.Provider>
|
|
382
|
+
)
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Story pages get their own rendering path — no flow data needed
|
|
386
|
+
if (storyName) {
|
|
387
|
+
const storyValue = {
|
|
388
|
+
data: null,
|
|
389
|
+
error: null,
|
|
390
|
+
loading: false,
|
|
391
|
+
flowName: null,
|
|
392
|
+
sceneName: null,
|
|
393
|
+
prototypeName: null,
|
|
394
|
+
}
|
|
395
|
+
return (
|
|
396
|
+
<StoryboardContext.Provider value={storyValue}>
|
|
397
|
+
<Suspense fallback={null}>
|
|
398
|
+
<StoryPageLazy name={storyName} />
|
|
399
|
+
</Suspense>
|
|
400
|
+
</StoryboardContext.Provider>
|
|
401
|
+
)
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (isMissingCanvasRoute) {
|
|
405
|
+
const currentUrl = `${location.pathname}${location.search}`
|
|
406
|
+
const truncatedUrl = currentUrl.length > 60
|
|
407
|
+
? currentUrl.slice(0, 60) + '…'
|
|
408
|
+
: currentUrl
|
|
409
|
+
|
|
410
|
+
return (
|
|
411
|
+
<main className={styles.container}>
|
|
412
|
+
<div className={styles.banner}>
|
|
413
|
+
<strong>Canvas not found</strong>
|
|
414
|
+
No canvas matches this route.
|
|
415
|
+
</div>
|
|
416
|
+
<p className={styles.meta}>
|
|
417
|
+
Tried to open{' '}
|
|
418
|
+
<a href={currentUrl} title={currentUrl}>{truncatedUrl}</a>
|
|
419
|
+
</p>
|
|
420
|
+
<a className={styles.homeLink} href="/">← Go to index page</a>
|
|
421
|
+
</main>
|
|
422
|
+
)
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (isMissingStoryRoute) {
|
|
426
|
+
const currentUrl = `${location.pathname}${location.search}`
|
|
427
|
+
const truncatedUrl = currentUrl.length > 60
|
|
428
|
+
? currentUrl.slice(0, 60) + '…'
|
|
429
|
+
: currentUrl
|
|
430
|
+
|
|
431
|
+
return (
|
|
432
|
+
<main className={styles.container}>
|
|
433
|
+
<div className={styles.banner}>
|
|
434
|
+
<strong>Story not found</strong>
|
|
435
|
+
No story matches this route.
|
|
436
|
+
</div>
|
|
437
|
+
<p className={styles.meta}>
|
|
438
|
+
Tried to open{' '}
|
|
439
|
+
<a href={currentUrl} title={currentUrl}>{truncatedUrl}</a>
|
|
440
|
+
</p>
|
|
441
|
+
<a className={styles.homeLink} href="/">← Go to index page</a>
|
|
442
|
+
</main>
|
|
443
|
+
)
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const value = {
|
|
447
|
+
data,
|
|
448
|
+
error,
|
|
449
|
+
loading: false,
|
|
450
|
+
flowName: activeFlowName,
|
|
451
|
+
sceneName: activeFlowName, // backward compat
|
|
452
|
+
prototypeName,
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (error) {
|
|
456
|
+
const currentUrl = `${location.pathname}${location.search}`
|
|
457
|
+
const truncatedUrl = currentUrl.length > 60
|
|
458
|
+
? currentUrl.slice(0, 60) + '…'
|
|
459
|
+
: currentUrl
|
|
460
|
+
|
|
461
|
+
return (
|
|
462
|
+
<div className={styles.container}>
|
|
463
|
+
<div className={styles.banner}>
|
|
464
|
+
<strong>Error loading flow</strong>
|
|
465
|
+
{error}
|
|
466
|
+
</div>
|
|
467
|
+
<p className={styles.meta}>
|
|
468
|
+
Tried to load{' '}
|
|
469
|
+
<a href={currentUrl} title={currentUrl}>{truncatedUrl}</a>
|
|
470
|
+
</p>
|
|
471
|
+
<a className={styles.homeLink} href="/">← Go to homepage</a>
|
|
472
|
+
</div>
|
|
473
|
+
)
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
return (
|
|
477
|
+
<StoryboardContext.Provider value={value}>
|
|
478
|
+
{children}
|
|
479
|
+
</StoryboardContext.Provider>
|
|
480
|
+
)
|
|
481
|
+
}
|