@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,492 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design Modes — mode registry, switching, and cross-plugin event bus.
|
|
3
|
+
*
|
|
4
|
+
* Framework-agnostic (zero npm dependencies).
|
|
5
|
+
* State is stored in the ?mode= URL search param so it's shareable and bookmarkable.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Internal state
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
const _modes = new Map()
|
|
13
|
+
const _listeners = new Set()
|
|
14
|
+
const _eventListeners = new Map()
|
|
15
|
+
|
|
16
|
+
const DEFAULT_MODE = 'prototype'
|
|
17
|
+
|
|
18
|
+
let _modesEnabled = false
|
|
19
|
+
let _lockedMode = null
|
|
20
|
+
|
|
21
|
+
// Tool registry — seeded from modes.config.json, state managed at runtime
|
|
22
|
+
const _tools = new Map() // id → { id, label, group, modes[] }
|
|
23
|
+
const _toolState = new Map() // id → { enabled, active, busy, hidden, badge }
|
|
24
|
+
const _toolActions = new Map() // id → action function
|
|
25
|
+
const _toolListeners = new Set() // subscribers to tool state/action changes
|
|
26
|
+
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Registry
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Register a mode plugin.
|
|
33
|
+
*
|
|
34
|
+
* @param {string} name Unique mode identifier (e.g. 'prototype', 'present')
|
|
35
|
+
* @param {object} config Mode configuration
|
|
36
|
+
* @param {string} config.label Human-readable label for UI
|
|
37
|
+
* @param {string} [config.icon] Icon name (Octicon, Feather, or custom)
|
|
38
|
+
* @param {string|string[]} [config.className] Extra class(es) applied to <html> when active
|
|
39
|
+
* @param {Function} [config.onActivate] Called when mode becomes active
|
|
40
|
+
* @param {Function} [config.onDeactivate] Called when leaving this mode
|
|
41
|
+
* @param {Array} [config.tools] Tool definitions for the tools toolbar
|
|
42
|
+
* @param {Array} [config.devTools] Tool definitions for the dev toolbar
|
|
43
|
+
*/
|
|
44
|
+
export function registerMode(name, config = {}) {
|
|
45
|
+
if (_modes.has(name)) {
|
|
46
|
+
console.warn(`[storyboard] Mode "${name}" is already registered — overwriting.`)
|
|
47
|
+
}
|
|
48
|
+
_modes.set(name, { name, label: config.label ?? name, ...config })
|
|
49
|
+
_notify()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Remove a previously registered mode.
|
|
54
|
+
*/
|
|
55
|
+
export function unregisterMode(name) {
|
|
56
|
+
if (name === DEFAULT_MODE) {
|
|
57
|
+
console.warn(`[storyboard] Cannot unregister the default mode "${DEFAULT_MODE}".`)
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
const mode = _modes.get(name)
|
|
61
|
+
if (!mode) return
|
|
62
|
+
// If this mode is currently active, deactivate first
|
|
63
|
+
if (getCurrentMode() === name) {
|
|
64
|
+
deactivateMode()
|
|
65
|
+
}
|
|
66
|
+
_modes.delete(name)
|
|
67
|
+
_notify()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get all registered modes in insertion order.
|
|
72
|
+
*
|
|
73
|
+
* @returns {Array<{ name: string, label: string, icon?: string }>}
|
|
74
|
+
*/
|
|
75
|
+
export function getRegisteredModes() {
|
|
76
|
+
return Array.from(_modes.values())
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// Switching
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Read the active mode from the ?mode= URL search param.
|
|
85
|
+
* Falls back to DEFAULT_MODE when the param is absent or unrecognised.
|
|
86
|
+
*/
|
|
87
|
+
export function getCurrentMode() {
|
|
88
|
+
if (_lockedMode && _modes.has(_lockedMode)) return _lockedMode
|
|
89
|
+
if (typeof window === 'undefined') return DEFAULT_MODE
|
|
90
|
+
const url = new URL(window.location.href)
|
|
91
|
+
const param = url.searchParams.get('mode')
|
|
92
|
+
if (param && _modes.has(param)) return param
|
|
93
|
+
return DEFAULT_MODE
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Switch to a registered mode.
|
|
98
|
+
* Calls onDeactivate on the previous mode and onActivate on the new one.
|
|
99
|
+
*
|
|
100
|
+
* @param {string} name Mode to activate
|
|
101
|
+
* @param {object} [options] Passed through to onActivate
|
|
102
|
+
*/
|
|
103
|
+
export function activateMode(name, options) {
|
|
104
|
+
if (_lockedMode) {
|
|
105
|
+
console.warn(`[storyboard] Modes are locked to "${_lockedMode}" — ignoring switch to "${name}".`)
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
if (!_modes.has(name)) {
|
|
109
|
+
console.warn(`[storyboard] Mode "${name}" is not registered.`)
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const prev = getCurrentMode()
|
|
114
|
+
if (prev === name) return
|
|
115
|
+
|
|
116
|
+
// Deactivate previous
|
|
117
|
+
const prevMode = _modes.get(prev)
|
|
118
|
+
_removeModeClasses(prevMode)
|
|
119
|
+
if (prevMode?.onDeactivate) prevMode.onDeactivate()
|
|
120
|
+
emit('mode:deactivate', prev)
|
|
121
|
+
|
|
122
|
+
// Update URL param
|
|
123
|
+
const url = new URL(window.location.href)
|
|
124
|
+
if (name === DEFAULT_MODE) {
|
|
125
|
+
url.searchParams.delete('mode')
|
|
126
|
+
} else {
|
|
127
|
+
url.searchParams.set('mode', name)
|
|
128
|
+
}
|
|
129
|
+
window.history.replaceState(null, '', url.toString())
|
|
130
|
+
|
|
131
|
+
// Activate new
|
|
132
|
+
const newMode = _modes.get(name)
|
|
133
|
+
_applyModeClasses(newMode)
|
|
134
|
+
if (newMode?.onActivate) newMode.onActivate(options)
|
|
135
|
+
emit('mode:activate', name, options)
|
|
136
|
+
emit('mode:change', prev, name)
|
|
137
|
+
|
|
138
|
+
_notify()
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Return to the default mode.
|
|
143
|
+
*/
|
|
144
|
+
export function deactivateMode() {
|
|
145
|
+
activateMode(DEFAULT_MODE)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
// Reactivity (for useSyncExternalStore)
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Subscribe to mode changes. Compatible with React's useSyncExternalStore.
|
|
154
|
+
*
|
|
155
|
+
* @param {Function} callback Called whenever the mode or registry changes
|
|
156
|
+
* @returns {Function} Unsubscribe function
|
|
157
|
+
*/
|
|
158
|
+
export function subscribeToMode(callback) {
|
|
159
|
+
_listeners.add(callback)
|
|
160
|
+
// Also listen to popstate so browser back/forward syncs mode
|
|
161
|
+
const onPopState = () => {
|
|
162
|
+
_notify()
|
|
163
|
+
}
|
|
164
|
+
window.addEventListener('popstate', onPopState)
|
|
165
|
+
return () => {
|
|
166
|
+
_listeners.delete(callback)
|
|
167
|
+
window.removeEventListener('popstate', onPopState)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Snapshot for useSyncExternalStore.
|
|
173
|
+
* Returns a serialised string that changes when mode or registry changes.
|
|
174
|
+
*/
|
|
175
|
+
export function getModeSnapshot() {
|
|
176
|
+
const mode = getCurrentMode()
|
|
177
|
+
const names = Array.from(_modes.keys()).join(',')
|
|
178
|
+
return `${mode}|${names}`
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
// Event bus (cross-plugin communication)
|
|
183
|
+
// ---------------------------------------------------------------------------
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Listen for an event.
|
|
187
|
+
*
|
|
188
|
+
* @param {string} event Event name (e.g. 'mode:change', 'room:create')
|
|
189
|
+
* @param {Function} callback
|
|
190
|
+
*/
|
|
191
|
+
export function on(event, callback) {
|
|
192
|
+
if (!_eventListeners.has(event)) {
|
|
193
|
+
_eventListeners.set(event, new Set())
|
|
194
|
+
}
|
|
195
|
+
_eventListeners.get(event).add(callback)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Remove an event listener.
|
|
200
|
+
*/
|
|
201
|
+
export function off(event, callback) {
|
|
202
|
+
const listeners = _eventListeners.get(event)
|
|
203
|
+
if (listeners) listeners.delete(callback)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Emit an event to all registered listeners.
|
|
208
|
+
*
|
|
209
|
+
* @param {string} event Event name
|
|
210
|
+
* @param {...*} args Arguments forwarded to listeners
|
|
211
|
+
*/
|
|
212
|
+
export function emit(event, ...args) {
|
|
213
|
+
const listeners = _eventListeners.get(event)
|
|
214
|
+
if (!listeners) return
|
|
215
|
+
for (const cb of listeners) {
|
|
216
|
+
try {
|
|
217
|
+
cb(...args)
|
|
218
|
+
} catch (err) {
|
|
219
|
+
console.error(`[storyboard] Error in "${event}" listener:`, err)
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// ---------------------------------------------------------------------------
|
|
225
|
+
// Internal helpers
|
|
226
|
+
// ---------------------------------------------------------------------------
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Collect all classes for a mode: the automatic `storyboard-mode-{name}`
|
|
230
|
+
* plus any custom `className` string(s) from the mode config.
|
|
231
|
+
*/
|
|
232
|
+
function _getModeClasses(mode) {
|
|
233
|
+
if (!mode) return []
|
|
234
|
+
const classes = [`storyboard-mode-${mode.name}`]
|
|
235
|
+
if (mode.className) {
|
|
236
|
+
const extra = Array.isArray(mode.className) ? mode.className : mode.className.split(/\s+/)
|
|
237
|
+
classes.push(...extra.filter(Boolean))
|
|
238
|
+
}
|
|
239
|
+
return classes
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function _applyModeClasses(mode) {
|
|
243
|
+
if (typeof document === 'undefined') return
|
|
244
|
+
const classes = _getModeClasses(mode)
|
|
245
|
+
if (classes.length) document.documentElement.classList.add(...classes)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function _removeModeClasses(mode) {
|
|
249
|
+
if (typeof document === 'undefined') return
|
|
250
|
+
const classes = _getModeClasses(mode)
|
|
251
|
+
if (classes.length) document.documentElement.classList.remove(...classes)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Apply classes for the current mode on first load.
|
|
256
|
+
* Called automatically so the initial mode is reflected in the DOM.
|
|
257
|
+
*/
|
|
258
|
+
export function syncModeClasses() {
|
|
259
|
+
const name = getCurrentMode()
|
|
260
|
+
const mode = _modes.get(name)
|
|
261
|
+
if (mode) _applyModeClasses(mode)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function _notify() {
|
|
265
|
+
for (const cb of _listeners) {
|
|
266
|
+
try {
|
|
267
|
+
cb()
|
|
268
|
+
} catch (err) {
|
|
269
|
+
console.error('[storyboard] Error in mode subscriber:', err)
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// ---------------------------------------------------------------------------
|
|
275
|
+
// Configuration
|
|
276
|
+
// ---------------------------------------------------------------------------
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Initialize modes configuration.
|
|
280
|
+
* Called by the Vite data plugin's generated virtual module.
|
|
281
|
+
* @param {{ enabled?: boolean, locked?: string }} [config]
|
|
282
|
+
*/
|
|
283
|
+
export function initModesConfig(config = {}) {
|
|
284
|
+
_modesEnabled = config.enabled !== false
|
|
285
|
+
_lockedMode = typeof config.locked === 'string' ? config.locked : null
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Check whether modes UI is enabled.
|
|
290
|
+
* When false, the app stays in prototype mode with no mode switcher.
|
|
291
|
+
* @returns {boolean}
|
|
292
|
+
*/
|
|
293
|
+
export function isModesEnabled() {
|
|
294
|
+
return _modesEnabled
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Get the locked mode name, or null if modes are not locked.
|
|
299
|
+
* When locked, the mode switcher is hidden and activateMode() is a no-op.
|
|
300
|
+
* @returns {string|null}
|
|
301
|
+
*/
|
|
302
|
+
export function getLockedMode() {
|
|
303
|
+
return _lockedMode
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Check whether the mode switcher UI should be visible.
|
|
308
|
+
* Returns false when modes are disabled or locked to a specific mode.
|
|
309
|
+
* @returns {boolean}
|
|
310
|
+
*/
|
|
311
|
+
export function isModeSwitcherVisible() {
|
|
312
|
+
return _modesEnabled && !_lockedMode
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// ---------------------------------------------------------------------------
|
|
316
|
+
// Tool registry
|
|
317
|
+
// ---------------------------------------------------------------------------
|
|
318
|
+
|
|
319
|
+
const DEFAULT_TOOL_STATE = Object.freeze({
|
|
320
|
+
enabled: true,
|
|
321
|
+
active: false,
|
|
322
|
+
busy: false,
|
|
323
|
+
hidden: false,
|
|
324
|
+
badge: null,
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Seed the tool registry from modes.config.json.
|
|
329
|
+
* Called by the Vite data plugin's generated virtual module.
|
|
330
|
+
*
|
|
331
|
+
* @param {Record<string, Array<{ id: string, label: string, group: string }>>} config
|
|
332
|
+
* Keys are mode names or '*' (all modes). Values are tool declarations.
|
|
333
|
+
*/
|
|
334
|
+
export function initTools(config = {}) {
|
|
335
|
+
for (const [modeKey, tools] of Object.entries(config)) {
|
|
336
|
+
if (!Array.isArray(tools)) continue
|
|
337
|
+
for (const tool of tools) {
|
|
338
|
+
if (!tool.id) continue
|
|
339
|
+
const existing = _tools.get(tool.id)
|
|
340
|
+
if (existing) {
|
|
341
|
+
// Merge mode assignments (tool declared in multiple mode keys)
|
|
342
|
+
if (!existing.modes.includes(modeKey)) {
|
|
343
|
+
existing.modes.push(modeKey)
|
|
344
|
+
}
|
|
345
|
+
} else {
|
|
346
|
+
_tools.set(tool.id, {
|
|
347
|
+
id: tool.id,
|
|
348
|
+
label: tool.label ?? tool.id,
|
|
349
|
+
group: tool.group ?? 'tools',
|
|
350
|
+
icon: tool.icon ?? null,
|
|
351
|
+
order: tool.order ?? 100,
|
|
352
|
+
modes: [modeKey],
|
|
353
|
+
})
|
|
354
|
+
_toolState.set(tool.id, { ...DEFAULT_TOOL_STATE })
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
_notifyTools()
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Wire up a click handler for a declared tool.
|
|
363
|
+
* Plugins call this to provide the action callback.
|
|
364
|
+
*
|
|
365
|
+
* @param {string} id Tool id (must exist in registry)
|
|
366
|
+
* @param {Function} action Click handler
|
|
367
|
+
*/
|
|
368
|
+
export function setToolAction(id, action) {
|
|
369
|
+
if (!_tools.has(id)) {
|
|
370
|
+
console.warn(`[storyboard] Tool "${id}" is not declared in modes.config.json.`)
|
|
371
|
+
return
|
|
372
|
+
}
|
|
373
|
+
_toolActions.set(id, action)
|
|
374
|
+
_notifyTools()
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Update the runtime state of a tool.
|
|
379
|
+
* Merges the update into existing state — only the provided keys change.
|
|
380
|
+
*
|
|
381
|
+
* @param {string} id Tool id (must exist in registry)
|
|
382
|
+
* @param {object} state Partial state update
|
|
383
|
+
* @param {boolean} [state.enabled] Whether the tool can be interacted with
|
|
384
|
+
* @param {boolean} [state.active] Whether the tool is currently "on" (highlighted)
|
|
385
|
+
* @param {boolean} [state.busy] Whether the tool is in use / unavailable
|
|
386
|
+
* @param {boolean} [state.hidden] Whether the tool should be hidden entirely
|
|
387
|
+
* @param {string|number|null} [state.badge] Notification badge
|
|
388
|
+
*/
|
|
389
|
+
export function setToolState(id, state = {}) {
|
|
390
|
+
if (!_tools.has(id)) {
|
|
391
|
+
console.warn(`[storyboard] Tool "${id}" is not declared in modes.config.json.`)
|
|
392
|
+
return
|
|
393
|
+
}
|
|
394
|
+
const current = _toolState.get(id) ?? { ...DEFAULT_TOOL_STATE }
|
|
395
|
+
_toolState.set(id, { ...current, ...state })
|
|
396
|
+
_notifyTools()
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Get the current runtime state of a tool.
|
|
401
|
+
*
|
|
402
|
+
* @param {string} id Tool id
|
|
403
|
+
* @returns {{ enabled: boolean, active: boolean, busy: boolean, hidden: boolean, badge: string|number|null } | null}
|
|
404
|
+
*/
|
|
405
|
+
export function getToolState(id) {
|
|
406
|
+
return _toolState.get(id) ?? null
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Get all tools for a given mode, merged with '*' wildcard tools.
|
|
411
|
+
* Returns tool declarations with their current state and action.
|
|
412
|
+
* Sorted by group (tools first, dev second), then by order.
|
|
413
|
+
*
|
|
414
|
+
* @param {string} modeName
|
|
415
|
+
* @returns {Array<{ id, label, group, icon, order, modes, state, action }>}
|
|
416
|
+
*/
|
|
417
|
+
export function getToolsForMode(modeName) {
|
|
418
|
+
const result = []
|
|
419
|
+
for (const [id, tool] of _tools) {
|
|
420
|
+
if (!tool.modes.includes(modeName) && !tool.modes.includes('*')) continue
|
|
421
|
+
const state = _toolState.get(id) ?? { ...DEFAULT_TOOL_STATE }
|
|
422
|
+
if (state.hidden) continue
|
|
423
|
+
result.push({
|
|
424
|
+
...tool,
|
|
425
|
+
state,
|
|
426
|
+
action: _toolActions.get(id) ?? null,
|
|
427
|
+
})
|
|
428
|
+
}
|
|
429
|
+
// Sort: 'tools' group before 'dev', then by order
|
|
430
|
+
const groupOrder = { tools: 0, dev: 1 }
|
|
431
|
+
result.sort((a, b) => {
|
|
432
|
+
const ga = groupOrder[a.group] ?? 0
|
|
433
|
+
const gb = groupOrder[b.group] ?? 0
|
|
434
|
+
if (ga !== gb) return ga - gb
|
|
435
|
+
return (a.order ?? 100) - (b.order ?? 100)
|
|
436
|
+
})
|
|
437
|
+
return result
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Subscribe to tool state/action changes.
|
|
442
|
+
* Compatible with React's useSyncExternalStore.
|
|
443
|
+
*
|
|
444
|
+
* @param {Function} callback Called on any tool change
|
|
445
|
+
* @returns {Function} Unsubscribe function
|
|
446
|
+
*/
|
|
447
|
+
export function subscribeToTools(callback) {
|
|
448
|
+
_toolListeners.add(callback)
|
|
449
|
+
return () => _toolListeners.delete(callback)
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Snapshot for useSyncExternalStore.
|
|
454
|
+
* Returns a serialised string that changes when tool state/actions change.
|
|
455
|
+
*/
|
|
456
|
+
export function getToolsSnapshot() {
|
|
457
|
+
const entries = []
|
|
458
|
+
for (const [id, state] of _toolState) {
|
|
459
|
+
const hasAction = _toolActions.has(id) ? '1' : '0'
|
|
460
|
+
entries.push(`${id}:${state.enabled}:${state.active}:${state.busy}:${state.hidden}:${state.badge}:${hasAction}`)
|
|
461
|
+
}
|
|
462
|
+
return entries.join('|')
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function _notifyTools() {
|
|
466
|
+
for (const cb of _toolListeners) {
|
|
467
|
+
try {
|
|
468
|
+
cb()
|
|
469
|
+
} catch (err) {
|
|
470
|
+
console.error('[storyboard] Error in tool subscriber:', err)
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// ---------------------------------------------------------------------------
|
|
476
|
+
// Test helpers
|
|
477
|
+
// ---------------------------------------------------------------------------
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Reset all internal state. Only for use in tests.
|
|
481
|
+
*/
|
|
482
|
+
export function _resetModes() {
|
|
483
|
+
_modes.clear()
|
|
484
|
+
_listeners.clear()
|
|
485
|
+
_eventListeners.clear()
|
|
486
|
+
_tools.clear()
|
|
487
|
+
_toolState.clear()
|
|
488
|
+
_toolActions.clear()
|
|
489
|
+
_toolListeners.clear()
|
|
490
|
+
_modesEnabled = false
|
|
491
|
+
_lockedMode = null
|
|
492
|
+
}
|