@dfosco/storyboard-core 4.2.0-beta.2 → 4.2.0-beta.21
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 +109 -24
- package/dist/storyboard-ui.css +1 -1
- package/dist/storyboard-ui.js +17379 -28568
- package/dist/storyboard-ui.js.map +1 -1
- package/dist/tailwind.css +1 -1
- package/package.json +5 -2
- 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/manifest.json +5 -0
- package/scaffold/skills/canvas/SKILL.md +5 -4
- package/scaffold/skills/ship/SKILL.md +1 -1
- package/scaffold/storyboard.config.json +14 -1
- package/scaffold/toolbar.config.json +1 -1
- package/src/ActionMenuButton.jsx +100 -0
- package/src/AutosyncMenuButton.css +67 -0
- package/src/AutosyncMenuButton.jsx +241 -0
- package/src/BranchSelect.jsx +29 -0
- package/src/BranchSelect.module.css +30 -0
- package/src/CanvasAgentsMenu.jsx +87 -0
- package/src/CanvasCreateMenu.jsx +609 -0
- package/src/CanvasSnap.css +27 -0
- package/src/CanvasSnap.jsx +51 -0
- package/src/CanvasUndoRedo.css +36 -0
- package/src/CanvasUndoRedo.jsx +62 -0
- package/src/CanvasZoomControl.css +53 -0
- package/src/CanvasZoomControl.jsx +49 -0
- package/src/CanvasZoomToFit.css +18 -0
- package/src/CanvasZoomToFit.jsx +26 -0
- package/src/CommandMenu.css +8 -0
- package/src/CommandMenu.jsx +286 -0
- package/src/CommandPalette.jsx +35 -0
- package/src/CommandPaletteTrigger.jsx +25 -0
- package/src/CommentsMenuButton.jsx +38 -0
- package/src/CoreUIBar.css +47 -0
- package/src/CoreUIBar.jsx +855 -0
- package/src/CreateMenuButton.jsx +116 -0
- package/src/HideChromeTrigger.jsx +40 -0
- package/src/InspectorPanel.css +109 -0
- package/src/InspectorPanel.jsx +629 -0
- package/src/PwaInstallBanner.css +42 -0
- package/src/PwaInstallBanner.jsx +124 -0
- package/src/SidePanel.jsx +260 -0
- package/src/ThemeMenuButton.jsx +136 -0
- package/src/autosync/server.js +202 -5
- package/src/autosync/server.test.js +112 -0
- package/src/canvas/__tests__/agent-integration.test.js +593 -0
- package/src/canvas/__tests__/helpers/browser.js +95 -0
- package/src/canvas/__tests__/helpers/canvas-api.js +129 -0
- package/src/canvas/__tests__/helpers/perf.js +118 -0
- package/src/canvas/__tests__/helpers/setup.js +176 -0
- package/src/canvas/__tests__/helpers/tmux.js +130 -0
- package/src/canvas/__tests__/helpers/transcript.js +129 -0
- package/src/canvas/__tests__/terminal-integration.test.js +175 -0
- package/src/canvas/hot-pool.js +757 -0
- package/src/canvas/materializer.js +31 -0
- package/src/canvas/materializer.test.js +56 -0
- package/src/canvas/selectedWidgets.js +65 -7
- package/src/canvas/server.js +1801 -22
- package/src/canvas/server.test.js +239 -0
- package/src/canvas/terminal-config.js +331 -0
- package/src/canvas/terminal-registry.js +38 -0
- package/src/canvas/terminal-server.js +1037 -29
- package/src/canvas/writeGuard.js +51 -3
- package/src/canvasConfig.js +67 -1
- package/src/canvasConfig.test.js +79 -1
- package/src/cli/agent.js +85 -0
- package/src/cli/branch.js +232 -0
- package/src/cli/canvasAdd.js +59 -12
- package/src/cli/canvasBatch.js +98 -0
- package/src/cli/canvasBounds.js +1 -1
- package/src/cli/canvasRead.js +1 -1
- package/src/cli/canvasUpdate.js +179 -0
- package/src/cli/create.js +38 -14
- package/src/cli/dev.js +157 -83
- package/src/cli/exit.js +23 -24
- package/src/cli/index.js +55 -2
- package/src/cli/proxy.js +96 -37
- package/src/cli/schemas.js +22 -4
- package/src/cli/server.js +148 -25
- package/src/cli/serverUrl.js +8 -3
- package/src/cli/sessions.js +131 -5
- package/src/cli/setup.js +109 -11
- package/src/cli/terminal-commands.js +16 -8
- package/src/cli/terminal-messaging.js +231 -0
- package/src/cli/terminal-welcome.js +365 -33
- package/src/commandActions.js +1 -0
- package/src/commandPaletteConfig.js +9 -0
- package/src/comments/auth.js +2 -1
- package/src/comments/ui/AuthModal.jsx +114 -0
- package/src/comments/ui/CommentWindow.jsx +329 -0
- package/src/comments/ui/CommentsDrawer.jsx +102 -0
- package/src/comments/ui/Composer.jsx +64 -0
- package/src/comments/ui/authModal.test.js +1 -1
- package/src/comments/ui/commentWindow.js +16 -17
- package/src/comments/ui/commentsDrawer.js +25 -26
- package/src/comments/ui/composer.js +23 -24
- package/src/comments/ui/index.js +2 -3
- package/src/configSchema.js +59 -1
- package/src/configStore.js +161 -0
- package/src/core-ui-colors.css +12 -0
- package/src/devtools.js +17 -19
- package/src/devtools.test.js +18 -9
- package/src/featureFlags.js +12 -5
- package/src/fuzzySearch.test.js +10 -0
- package/src/index.js +14 -2
- package/src/lib/components/ui/alert/alert-action.jsx +11 -0
- package/src/lib/components/ui/alert/alert-description.jsx +11 -0
- package/src/lib/components/ui/alert/alert-title.jsx +11 -0
- package/src/lib/components/ui/alert/alert.jsx +25 -0
- package/src/lib/components/ui/alert/index.js +15 -15
- package/src/lib/components/ui/avatar/avatar-badge.jsx +22 -0
- package/src/lib/components/ui/avatar/avatar-fallback.jsx +18 -0
- package/src/lib/components/ui/avatar/avatar-group-count.jsx +19 -0
- package/src/lib/components/ui/avatar/avatar-group.jsx +19 -0
- package/src/lib/components/ui/avatar/avatar-image.jsx +15 -0
- package/src/lib/components/ui/avatar/avatar.jsx +19 -0
- package/src/lib/components/ui/avatar/index.js +20 -20
- package/src/lib/components/ui/badge/badge.jsx +31 -0
- package/src/lib/components/ui/badge/index.js +2 -2
- package/src/lib/components/ui/button/button.jsx +100 -0
- package/src/lib/components/ui/button/index.js +9 -9
- package/src/lib/components/ui/card/card-action.jsx +11 -0
- package/src/lib/components/ui/card/card-content.jsx +11 -0
- package/src/lib/components/ui/card/card-description.jsx +11 -0
- package/src/lib/components/ui/card/card-footer.jsx +11 -0
- package/src/lib/components/ui/card/card-header.jsx +19 -0
- package/src/lib/components/ui/card/card-title.jsx +11 -0
- package/src/lib/components/ui/card/card.jsx +17 -0
- package/src/lib/components/ui/card/index.js +23 -23
- package/src/lib/components/ui/checkbox/checkbox.jsx +29 -0
- package/src/lib/components/ui/checkbox/index.js +5 -5
- package/src/lib/components/ui/collapsible/collapsible-content.jsx +7 -0
- package/src/lib/components/ui/collapsible/collapsible-trigger.jsx +7 -0
- package/src/lib/components/ui/collapsible/collapsible.jsx +7 -0
- package/src/lib/components/ui/collapsible/index.js +11 -11
- package/src/lib/components/ui/dialog/dialog-close.jsx +7 -0
- package/src/lib/components/ui/dialog/dialog-content.jsx +34 -0
- package/src/lib/components/ui/dialog/dialog-description.jsx +15 -0
- package/src/lib/components/ui/dialog/dialog-footer.jsx +23 -0
- package/src/lib/components/ui/dialog/dialog-header.jsx +11 -0
- package/src/lib/components/ui/dialog/dialog-overlay.jsx +15 -0
- package/src/lib/components/ui/dialog/dialog-portal.jsx +4 -0
- package/src/lib/components/ui/dialog/dialog-title.jsx +15 -0
- package/src/lib/components/ui/dialog/dialog-trigger.jsx +7 -0
- package/src/lib/components/ui/dialog/dialog.jsx +4 -0
- package/src/lib/components/ui/dialog/index.js +32 -32
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.jsx +8 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.jsx +30 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-content.jsx +22 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.jsx +16 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-group.jsx +7 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-item.jsx +20 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-label.jsx +17 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.jsx +4 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.jsx +7 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.jsx +29 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.jsx +15 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.jsx +16 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.jsx +15 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.jsx +23 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.jsx +4 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.jsx +7 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu.jsx +4 -0
- package/src/lib/components/ui/dropdown-menu/index.js +52 -52
- package/src/lib/components/ui/input/index.js +5 -5
- package/src/lib/components/ui/input/input.jsx +19 -0
- package/src/lib/components/ui/label/index.js +5 -5
- package/src/lib/components/ui/label/label.jsx +19 -0
- package/src/lib/components/ui/panel/index.js +21 -21
- package/src/lib/components/ui/panel/panel-body.jsx +11 -0
- package/src/lib/components/ui/panel/panel-close.jsx +16 -0
- package/src/lib/components/ui/panel/panel-content.jsx +29 -0
- package/src/lib/components/ui/panel/panel-footer.jsx +11 -0
- package/src/lib/components/ui/panel/panel-header.jsx +11 -0
- package/src/lib/components/ui/panel/panel-title.jsx +12 -0
- package/src/lib/components/ui/panel/panel.jsx +4 -0
- package/src/lib/components/ui/popover/index.js +26 -26
- package/src/lib/components/ui/popover/popover-close.jsx +7 -0
- package/src/lib/components/ui/popover/popover-content.jsx +22 -0
- package/src/lib/components/ui/popover/popover-description.jsx +11 -0
- package/src/lib/components/ui/popover/popover-header.jsx +11 -0
- package/src/lib/components/ui/popover/popover-portal.jsx +4 -0
- package/src/lib/components/ui/popover/popover-title.jsx +11 -0
- package/src/lib/components/ui/popover/popover-trigger.jsx +8 -0
- package/src/lib/components/ui/popover/popover.jsx +4 -0
- package/src/lib/components/ui/searchable-list.jsx +159 -0
- package/src/lib/components/ui/select/index.js +35 -35
- package/src/lib/components/ui/select/select-content.jsx +30 -0
- package/src/lib/components/ui/select/select-group-heading.jsx +17 -0
- package/src/lib/components/ui/select/select-group.jsx +15 -0
- package/src/lib/components/ui/select/select-item.jsx +26 -0
- package/src/lib/components/ui/select/select-label.jsx +11 -0
- package/src/lib/components/ui/select/select-portal.jsx +4 -0
- package/src/lib/components/ui/select/select-scroll-down-button.jsx +18 -0
- package/src/lib/components/ui/select/select-scroll-up-button.jsx +18 -0
- package/src/lib/components/ui/select/select-separator.jsx +15 -0
- package/src/lib/components/ui/select/select-trigger.jsx +25 -0
- package/src/lib/components/ui/select/select.jsx +4 -0
- package/src/lib/components/ui/separator/index.js +5 -5
- package/src/lib/components/ui/separator/separator.jsx +22 -0
- package/src/lib/components/ui/sheet/index.js +32 -32
- package/src/lib/components/ui/sheet/sheet-close.jsx +7 -0
- package/src/lib/components/ui/sheet/sheet-content.jsx +35 -0
- package/src/lib/components/ui/sheet/sheet-description.jsx +15 -0
- package/src/lib/components/ui/sheet/sheet-footer.jsx +11 -0
- package/src/lib/components/ui/sheet/sheet-header.jsx +11 -0
- package/src/lib/components/ui/sheet/sheet-overlay.jsx +15 -0
- package/src/lib/components/ui/sheet/sheet-portal.jsx +4 -0
- package/src/lib/components/ui/sheet/sheet-title.jsx +15 -0
- package/src/lib/components/ui/sheet/sheet-trigger.jsx +7 -0
- package/src/lib/components/ui/sheet/sheet.jsx +4 -0
- package/src/lib/components/ui/textarea/index.js +5 -5
- package/src/lib/components/ui/textarea/textarea.jsx +18 -0
- package/src/lib/components/ui/toggle/index.js +6 -9
- package/src/lib/components/ui/toggle/toggle.jsx +36 -0
- package/src/lib/components/ui/toggle-group/index.js +8 -8
- package/src/lib/components/ui/toggle-group/toggle-group-item.jsx +29 -0
- package/src/lib/components/ui/toggle-group/toggle-group.jsx +43 -0
- package/src/lib/components/ui/tooltip/index.js +3 -3
- package/src/lib/components/ui/tooltip/tooltip-content.jsx +21 -0
- package/src/lib/components/ui/tooltip/tooltip-trigger.jsx +23 -0
- package/src/lib/components/ui/tooltip/tooltip.jsx +11 -0
- package/src/lib/components/ui/trigger-button/index.js +3 -3
- package/src/lib/components/ui/trigger-button/trigger-button.css +38 -0
- package/src/lib/components/ui/trigger-button/trigger-button.jsx +63 -0
- package/src/logger/devLogger.js +238 -0
- package/src/logger/devLogger.test.js +193 -0
- package/src/modes.test.js +4 -4
- package/src/mountStoryboardCore.js +123 -27
- package/src/paletteProviders.js +3 -0
- package/src/paletteProviders.test.js +2 -2
- package/src/server/index.js +98 -36
- package/src/sidepanel.css +214 -0
- package/src/styles/tailwind.css +1 -1
- package/src/svelte-plugin-ui/__tests__/ModeSwitch.test.ts +8 -8
- package/src/svelte-plugin-ui/__tests__/ToolbarShell.test.ts +11 -10
- package/src/svelte-plugin-ui/components/Icon.css +11 -0
- package/src/svelte-plugin-ui/components/Icon.jsx +281 -0
- package/src/svelte-plugin-ui/components/ModeSwitch.css +90 -0
- package/src/svelte-plugin-ui/components/ModeSwitch.jsx +47 -0
- package/src/svelte-plugin-ui/components/ToolbarShell.css +80 -0
- package/src/svelte-plugin-ui/components/ToolbarShell.jsx +84 -0
- package/src/svelte-plugin-ui/components/Viewfinder.css +412 -0
- package/src/svelte-plugin-ui/components/Viewfinder.jsx +512 -0
- package/src/svelte-plugin-ui/mount.ts +12 -16
- package/src/toolRegistry.js +4 -4
- package/src/toolbarConfigStore.js +30 -0
- package/src/tools/handlers/autosync.js +1 -1
- package/src/tools/handlers/canvasAddWidget.js +1 -1
- package/src/tools/handlers/canvasAgents.js +19 -0
- package/src/tools/handlers/canvasToolbar.js +8 -8
- package/src/tools/handlers/commandPalette.js +9 -0
- package/src/tools/handlers/comments.js +1 -1
- package/src/tools/handlers/create.js +1 -1
- package/src/tools/handlers/devtools.js +16 -0
- package/src/tools/handlers/devtools.test.js +38 -0
- package/src/tools/handlers/flows.js +1 -1
- package/src/tools/handlers/hideChrome.js +9 -0
- package/src/tools/handlers/paletteTheme.js +35 -0
- package/src/tools/handlers/theme.js +1 -1
- package/src/tools/registry.js +4 -1
- package/src/tools/surfaces/commandList.js +3 -3
- package/src/tools/surfaces/mainToolbar.js +3 -3
- package/src/tools/surfaces/registry.js +4 -4
- package/src/ui/design-modes.ts +2 -2
- package/src/ui/viewfinder.ts +1 -1
- package/src/vite/server-plugin.js +242 -60
- package/src/workshop/features/createCanvas/CreateCanvasForm.jsx +260 -0
- package/src/workshop/features/createCanvas/index.js +1 -1
- package/src/workshop/features/createFlow/CreateFlowForm.jsx +334 -0
- package/src/workshop/features/createFlow/index.js +1 -1
- package/src/workshop/features/createPage/CreatePageForm.jsx +304 -0
- package/src/workshop/features/createPage/index.js +1 -1
- package/src/workshop/features/createPrototype/CreatePrototypeForm.jsx +289 -0
- package/src/workshop/features/createPrototype/index.js +1 -1
- package/src/workshop/features/createPrototype/server.js +98 -0
- package/src/workshop/features/createStory/CreateStoryForm.jsx +208 -0
- package/src/workshop/features/createStory/index.js +1 -1
- package/src/workshop/ui/WorkshopPanel.jsx +98 -0
- package/src/workshop/ui/mount.ts +1 -1
- package/src/worktree/port.js +48 -0
- package/src/worktree/serverRegistry.js +120 -0
- package/toolbar.config.json +93 -42
- package/widgets.config.json +580 -12
- package/src/ActionMenuButton.svelte +0 -119
- package/src/AutosyncMenuButton.svelte +0 -397
- package/src/CanvasCreateMenu.svelte +0 -295
- package/src/CanvasSnap.svelte +0 -87
- package/src/CanvasUndoRedo.svelte +0 -108
- package/src/CanvasZoomControl.svelte +0 -111
- package/src/CanvasZoomToFit.svelte +0 -52
- package/src/CommandMenu.svelte +0 -249
- package/src/CommandPalette.svelte +0 -33
- package/src/CommentsMenuButton.svelte +0 -53
- package/src/CoreUIBar.svelte +0 -847
- package/src/CreateMenuButton.svelte +0 -133
- package/src/DocPanel.svelte +0 -299
- package/src/InspectorPanel.svelte +0 -745
- package/src/PwaInstallBanner.svelte +0 -124
- package/src/SidePanel.svelte +0 -480
- package/src/ThemeMenuButton.svelte +0 -132
- package/src/comments/ui/AuthModal.svelte +0 -108
- package/src/comments/ui/CommentWindow.svelte +0 -333
- package/src/comments/ui/CommentsDrawer.svelte +0 -96
- package/src/comments/ui/Composer.svelte +0 -65
- package/src/lib/components/ui/alert/alert-action.svelte +0 -19
- package/src/lib/components/ui/alert/alert-description.svelte +0 -22
- package/src/lib/components/ui/alert/alert-title.svelte +0 -22
- package/src/lib/components/ui/alert/alert.svelte +0 -38
- package/src/lib/components/ui/avatar/avatar-badge.svelte +0 -25
- package/src/lib/components/ui/avatar/avatar-fallback.svelte +0 -20
- package/src/lib/components/ui/avatar/avatar-group-count.svelte +0 -22
- package/src/lib/components/ui/avatar/avatar-group.svelte +0 -22
- package/src/lib/components/ui/avatar/avatar-image.svelte +0 -17
- package/src/lib/components/ui/avatar/avatar.svelte +0 -24
- package/src/lib/components/ui/badge/badge.svelte +0 -44
- package/src/lib/components/ui/button/button.svelte +0 -108
- package/src/lib/components/ui/card/card-action.svelte +0 -21
- package/src/lib/components/ui/card/card-content.svelte +0 -19
- package/src/lib/components/ui/card/card-description.svelte +0 -19
- package/src/lib/components/ui/card/card-footer.svelte +0 -18
- package/src/lib/components/ui/card/card-header.svelte +0 -21
- package/src/lib/components/ui/card/card-title.svelte +0 -14
- package/src/lib/components/ui/card/card.svelte +0 -21
- package/src/lib/components/ui/checkbox/checkbox.svelte +0 -39
- package/src/lib/components/ui/collapsible/collapsible-content.svelte +0 -7
- package/src/lib/components/ui/collapsible/collapsible-trigger.svelte +0 -7
- package/src/lib/components/ui/collapsible/collapsible.svelte +0 -11
- package/src/lib/components/ui/dialog/dialog-close.svelte +0 -11
- package/src/lib/components/ui/dialog/dialog-content.svelte +0 -42
- package/src/lib/components/ui/dialog/dialog-description.svelte +0 -17
- package/src/lib/components/ui/dialog/dialog-footer.svelte +0 -29
- package/src/lib/components/ui/dialog/dialog-header.svelte +0 -19
- package/src/lib/components/ui/dialog/dialog-overlay.svelte +0 -17
- package/src/lib/components/ui/dialog/dialog-portal.svelte +0 -7
- package/src/lib/components/ui/dialog/dialog-title.svelte +0 -17
- package/src/lib/components/ui/dialog/dialog-trigger.svelte +0 -11
- package/src/lib/components/ui/dialog/dialog.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte +0 -16
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +0 -40
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte +0 -27
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +0 -18
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte +0 -24
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte +0 -20
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +0 -16
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +0 -34
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte +0 -17
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +0 -19
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +0 -17
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +0 -27
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte +0 -7
- package/src/lib/components/ui/input/input.svelte +0 -40
- package/src/lib/components/ui/label/label.svelte +0 -20
- package/src/lib/components/ui/panel/panel-body.svelte +0 -13
- package/src/lib/components/ui/panel/panel-close.svelte +0 -16
- package/src/lib/components/ui/panel/panel-content.svelte +0 -33
- package/src/lib/components/ui/panel/panel-footer.svelte +0 -13
- package/src/lib/components/ui/panel/panel-header.svelte +0 -16
- package/src/lib/components/ui/panel/panel-title.svelte +0 -14
- package/src/lib/components/ui/panel/panel.svelte +0 -15
- package/src/lib/components/ui/popover/popover-close.svelte +0 -7
- package/src/lib/components/ui/popover/popover-content.svelte +0 -27
- package/src/lib/components/ui/popover/popover-description.svelte +0 -19
- package/src/lib/components/ui/popover/popover-header.svelte +0 -19
- package/src/lib/components/ui/popover/popover-portal.svelte +0 -7
- package/src/lib/components/ui/popover/popover-title.svelte +0 -19
- package/src/lib/components/ui/popover/popover-trigger.svelte +0 -17
- package/src/lib/components/ui/popover/popover.svelte +0 -7
- package/src/lib/components/ui/select/select-content.svelte +0 -40
- package/src/lib/components/ui/select/select-group-heading.svelte +0 -19
- package/src/lib/components/ui/select/select-group.svelte +0 -17
- package/src/lib/components/ui/select/select-item.svelte +0 -38
- package/src/lib/components/ui/select/select-label.svelte +0 -18
- package/src/lib/components/ui/select/select-portal.svelte +0 -7
- package/src/lib/components/ui/select/select-scroll-down-button.svelte +0 -20
- package/src/lib/components/ui/select/select-scroll-up-button.svelte +0 -20
- package/src/lib/components/ui/select/select-separator.svelte +0 -17
- package/src/lib/components/ui/select/select-trigger.svelte +0 -27
- package/src/lib/components/ui/select/select.svelte +0 -11
- package/src/lib/components/ui/separator/separator.svelte +0 -23
- package/src/lib/components/ui/sheet/sheet-close.svelte +0 -7
- package/src/lib/components/ui/sheet/sheet-content.svelte +0 -43
- package/src/lib/components/ui/sheet/sheet-description.svelte +0 -17
- package/src/lib/components/ui/sheet/sheet-footer.svelte +0 -18
- package/src/lib/components/ui/sheet/sheet-header.svelte +0 -19
- package/src/lib/components/ui/sheet/sheet-overlay.svelte +0 -17
- package/src/lib/components/ui/sheet/sheet-portal.svelte +0 -7
- package/src/lib/components/ui/sheet/sheet-title.svelte +0 -17
- package/src/lib/components/ui/sheet/sheet-trigger.svelte +0 -7
- package/src/lib/components/ui/sheet/sheet.svelte +0 -7
- package/src/lib/components/ui/textarea/textarea.svelte +0 -21
- package/src/lib/components/ui/toggle/toggle.svelte +0 -45
- package/src/lib/components/ui/toggle-group/toggle-group-item.svelte +0 -35
- package/src/lib/components/ui/toggle-group/toggle-group.svelte +0 -63
- package/src/lib/components/ui/tooltip/tooltip-content.svelte +0 -24
- package/src/lib/components/ui/tooltip/tooltip-trigger.svelte +0 -27
- package/src/lib/components/ui/tooltip/tooltip.svelte +0 -9
- package/src/lib/components/ui/trigger-button/trigger-button.svelte +0 -106
- package/src/svelte-plugin-ui/components/Icon.svelte +0 -181
- package/src/svelte-plugin-ui/components/ModeSwitch.svelte +0 -121
- package/src/svelte-plugin-ui/components/ToolbarShell.svelte +0 -150
- package/src/svelte-plugin-ui/components/Viewfinder.svelte +0 -1001
- package/src/tools/handlers/docs.js +0 -11
- package/src/workshop/features/createCanvas/CreateCanvasForm.svelte +0 -139
- package/src/workshop/features/createFlow/CreateFlowForm.svelte +0 -314
- package/src/workshop/features/createPage/CreatePageForm.svelte +0 -249
- package/src/workshop/features/createPrototype/CreatePrototypeForm.svelte +0 -287
- package/src/workshop/features/createStory/CreateStoryForm.svelte +0 -161
- package/src/workshop/ui/WorkshopPanel.svelte +0 -97
|
@@ -1,745 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
InspectorPanel — Inspector tab for the side panel.
|
|
3
|
-
Select DOM elements and view their React component information.
|
|
4
|
-
Uses mouseMode for element selection and fiberWalker for component introspection.
|
|
5
|
-
-->
|
|
6
|
-
|
|
7
|
-
<script>
|
|
8
|
-
import { onMount, onDestroy } from 'svelte'
|
|
9
|
-
import Icon from './svelte-plugin-ui/components/Icon.svelte'
|
|
10
|
-
import { inspectElement, inspectElementChain } from './inspector/fiberWalker.js'
|
|
11
|
-
import { createMouseMode } from './inspector/mouseMode.js'
|
|
12
|
-
import { getColors, createInspectorHighlighter } from './inspector/highlighter.js'
|
|
13
|
-
|
|
14
|
-
/** @type {{ name: string, props: object, source: { fileName: string, lineNumber: number, columnNumber?: number } | null, owner: string | null } | null} */
|
|
15
|
-
let componentInfo = $state(null)
|
|
16
|
-
|
|
17
|
-
/** @type {Array<{ name: string, source: { fileName: string, lineNumber: number, columnNumber?: number } | null }>} */
|
|
18
|
-
let componentChain = $state([])
|
|
19
|
-
|
|
20
|
-
let inspecting = $state(false)
|
|
21
|
-
let sourceCode = $state('')
|
|
22
|
-
let sourceLoading = $state(false)
|
|
23
|
-
let sourcePath = $state('')
|
|
24
|
-
let matchedLine = $state(-1)
|
|
25
|
-
|
|
26
|
-
/** @type {HTMLElement | null} */
|
|
27
|
-
let sourceContainer = $state(null)
|
|
28
|
-
|
|
29
|
-
/** @type {Element | null} — the currently selected DOM element */
|
|
30
|
-
let selectedElement = $state(null)
|
|
31
|
-
|
|
32
|
-
// ── URL state helpers ─────────────────────────────────────────────
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Build a CSS selector that can re-find `el` later.
|
|
36
|
-
* Prefers id, then data-testid, then an nth-child path from <body>.
|
|
37
|
-
*/
|
|
38
|
-
function generateSelector(el) {
|
|
39
|
-
if (!(el instanceof Element)) return null
|
|
40
|
-
if (el.id) return `#${CSS.escape(el.id)}`
|
|
41
|
-
|
|
42
|
-
const testId = el.getAttribute('data-testid')
|
|
43
|
-
if (testId) return `[data-testid="${CSS.escape(testId)}"]`
|
|
44
|
-
|
|
45
|
-
const parts = []
|
|
46
|
-
let cur = el
|
|
47
|
-
while (cur && cur !== document.body && cur !== document.documentElement) {
|
|
48
|
-
let seg = cur.tagName.toLowerCase()
|
|
49
|
-
if (cur.id) {
|
|
50
|
-
parts.unshift(`#${CSS.escape(cur.id)}`)
|
|
51
|
-
break
|
|
52
|
-
}
|
|
53
|
-
const parent = cur.parentElement
|
|
54
|
-
if (parent) {
|
|
55
|
-
const siblings = Array.from(parent.children)
|
|
56
|
-
const idx = siblings.indexOf(cur) + 1
|
|
57
|
-
seg += `:nth-child(${idx})`
|
|
58
|
-
}
|
|
59
|
-
parts.unshift(seg)
|
|
60
|
-
cur = parent
|
|
61
|
-
}
|
|
62
|
-
return parts.length ? parts.join(' > ') : null
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/** Read the `inspect` search param from the current URL. */
|
|
66
|
-
function getInspectParam() {
|
|
67
|
-
try {
|
|
68
|
-
return new URL(window.location.href).searchParams.get('inspect')
|
|
69
|
-
} catch { return null }
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** Set or clear the `inspect` search param without triggering navigation. */
|
|
73
|
-
function setInspectParam(selector) {
|
|
74
|
-
try {
|
|
75
|
-
const url = new URL(window.location.href)
|
|
76
|
-
if (selector) {
|
|
77
|
-
url.searchParams.set('inspect', selector)
|
|
78
|
-
} else {
|
|
79
|
-
url.searchParams.delete('inspect')
|
|
80
|
-
}
|
|
81
|
-
history.replaceState(history.state, '', url.toString())
|
|
82
|
-
} catch {}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/** @type {string[]} */
|
|
86
|
-
let knownFiles = []
|
|
87
|
-
|
|
88
|
-
/** @type {{ owner: string, name: string } | null} */
|
|
89
|
-
let repoInfo = $state(null)
|
|
90
|
-
|
|
91
|
-
/** @type {{ files: string[], sources: Record<string, string>, repo: { owner: string, name: string } | null } | null} */
|
|
92
|
-
let staticInspectorData = null
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Load the build-time static inspector JSON (production only).
|
|
96
|
-
* Cached after the first successful fetch.
|
|
97
|
-
*/
|
|
98
|
-
async function loadStaticData() {
|
|
99
|
-
if (staticInspectorData) return staticInspectorData
|
|
100
|
-
try {
|
|
101
|
-
// Use window.location to derive base path at runtime, since
|
|
102
|
-
// import.meta.env.BASE_URL is baked at compile time in the UI bundle
|
|
103
|
-
const basePath = window.__STORYBOARD_BASE_PATH__ || '/'
|
|
104
|
-
const res = await fetch(`${basePath}_storyboard/inspector.json`)
|
|
105
|
-
if (res.ok) {
|
|
106
|
-
staticInspectorData = await res.json()
|
|
107
|
-
return staticInspectorData
|
|
108
|
-
}
|
|
109
|
-
} catch {}
|
|
110
|
-
return null
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const _isLocalDev = typeof window !== 'undefined' && window.__SB_LOCAL_DEV__ === true && !new URLSearchParams(window.location.search).has('prodMode')
|
|
114
|
-
const _basePath = (typeof window !== 'undefined' && window.__STORYBOARD_BASE_PATH__) || '/'
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Fetch source file content — uses dev middleware in dev, static JSON in prod.
|
|
118
|
-
*/
|
|
119
|
-
async function fetchSourceContent(filePath) {
|
|
120
|
-
// In local dev, use the live middleware (reads from disk)
|
|
121
|
-
if (_isLocalDev) {
|
|
122
|
-
try {
|
|
123
|
-
const res = await fetch(`${_basePath.replace(/\/$/, '')}/_storyboard/docs/source?path=${encodeURIComponent(filePath)}`)
|
|
124
|
-
if (res.ok) {
|
|
125
|
-
const json = await res.json()
|
|
126
|
-
return json?.content || ''
|
|
127
|
-
}
|
|
128
|
-
} catch {}
|
|
129
|
-
}
|
|
130
|
-
// In production (or if dev middleware failed), use static build-time JSON
|
|
131
|
-
const data = await loadStaticData()
|
|
132
|
-
return data?.sources?.[filePath] || ''
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
let mouseMode = null
|
|
136
|
-
|
|
137
|
-
const hasSelection = $derived(componentInfo !== null)
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Derive the git branch from the URL base path.
|
|
141
|
-
* Branch deploys use /branch--{name}/ in the path.
|
|
142
|
-
* Falls back to 'main'.
|
|
143
|
-
*/
|
|
144
|
-
const gitBranch = $derived.by(() => {
|
|
145
|
-
const m = window.location.pathname.match(/\/branch--([^/]+)/)
|
|
146
|
-
if (m) return m[1].replace(/-/g, '/')
|
|
147
|
-
return 'main'
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
const githubUrl = $derived.by(() => {
|
|
151
|
-
if (!repoInfo || !sourcePath) return null
|
|
152
|
-
const base = `https://github.com/${repoInfo.owner}/${repoInfo.name}/blob/${gitBranch}/${sourcePath}`
|
|
153
|
-
const line = matchedLine > 0 ? matchedLine : componentInfo?.source?.lineNumber
|
|
154
|
-
return line ? `${base}#L${line}` : base
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
const sourceLink = $derived.by(() => {
|
|
158
|
-
if (!sourcePath) return null
|
|
159
|
-
return {
|
|
160
|
-
label: sourcePath.split('/').pop(),
|
|
161
|
-
href: null,
|
|
162
|
-
}
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Find the source file for a component by matching against known files.
|
|
167
|
-
* Strategy:
|
|
168
|
-
* 1. If _debugSource is available (React <19), use that directly
|
|
169
|
-
* Resolve the source file for the current page from the URL.
|
|
170
|
-
* Maps the route path to a file in src/prototypes/ by stripping the
|
|
171
|
-
* base path and matching against known files (which have .folder/
|
|
172
|
-
* segments stripped during route generation).
|
|
173
|
-
*
|
|
174
|
-
* Also tries matching a specific component name as a fallback.
|
|
175
|
-
*/
|
|
176
|
-
function resolveSourceFile(info) {
|
|
177
|
-
// Strategy 1: _debugSource (React <19)
|
|
178
|
-
if (info?.source?.fileName) {
|
|
179
|
-
// Strip Vite query params (e.g. ?v=12345)
|
|
180
|
-
const cleanName = info.source.fileName.split('?')[0]
|
|
181
|
-
const srcIndex = cleanName.indexOf('/src/')
|
|
182
|
-
if (srcIndex !== -1) return cleanName.slice(srcIndex + 1)
|
|
183
|
-
if (cleanName.startsWith('src/')) return cleanName
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Strategy 2: match current URL route to a page file
|
|
187
|
-
const pageFile = resolvePageFile()
|
|
188
|
-
if (pageFile) return pageFile
|
|
189
|
-
|
|
190
|
-
// Strategy 3: match component name to a file basename
|
|
191
|
-
const name = info?.name
|
|
192
|
-
if (name && name !== 'Anonymous' && name !== 'Unknown') {
|
|
193
|
-
const match = knownFiles.find(f => {
|
|
194
|
-
const base = f.split('/').pop()?.replace(/\.(jsx|tsx|js|ts)$/, '')
|
|
195
|
-
return base === name
|
|
196
|
-
})
|
|
197
|
-
if (match) return match
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return null
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Derive the current page's source file from window.location.pathname.
|
|
205
|
-
* Strips the Vite base path, then searches known files for a match.
|
|
206
|
-
*/
|
|
207
|
-
function resolvePageFile() {
|
|
208
|
-
if (knownFiles.length === 0) return null
|
|
209
|
-
|
|
210
|
-
let pathname = window.location.pathname
|
|
211
|
-
|
|
212
|
-
// Strip any base path prefix by progressively removing leading segments
|
|
213
|
-
// until we find a match. This handles /storyboard-source/Example → Example
|
|
214
|
-
// without needing to know the exact base path.
|
|
215
|
-
if (pathname.startsWith('/')) pathname = pathname.slice(1)
|
|
216
|
-
pathname = pathname.replace(/\/$/, '')
|
|
217
|
-
|
|
218
|
-
// Normalize file paths once: strip src/prototypes/, .folder/ segments, extensions
|
|
219
|
-
const normalizedFiles = knownFiles.map(f => ({
|
|
220
|
-
original: f,
|
|
221
|
-
normalized: f
|
|
222
|
-
.replace(/^src\/prototypes\//, '')
|
|
223
|
-
.replace(/[^/]*\.folder\//g, '')
|
|
224
|
-
.replace(/\.(jsx|tsx|js|ts)$/, ''),
|
|
225
|
-
}))
|
|
226
|
-
|
|
227
|
-
// Try matching with progressively fewer leading segments
|
|
228
|
-
const segments = pathname.split('/').filter(Boolean)
|
|
229
|
-
for (let start = 0; start < segments.length; start++) {
|
|
230
|
-
const routeEnd = segments.slice(start).join('/')
|
|
231
|
-
if (!routeEnd) continue
|
|
232
|
-
|
|
233
|
-
for (const { original, normalized } of normalizedFiles) {
|
|
234
|
-
// Match: "Example" → "Example/index" or "Example"
|
|
235
|
-
const withoutIndex = normalized.replace(/\/index$/, '')
|
|
236
|
-
if (withoutIndex === routeEnd || normalized === routeEnd) return original
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Root path fallback
|
|
241
|
-
if (!pathname || segments.length === 0) {
|
|
242
|
-
const idx = knownFiles.find(f => /^src\/prototypes\/index\.(jsx|tsx|js|ts)$/.test(f))
|
|
243
|
-
if (idx) return idx
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return null
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
let highlightedHtml = $state('')
|
|
250
|
-
|
|
251
|
-
// Code theme colors — refreshed on theme change events
|
|
252
|
-
let codeTheme = $state(getColors())
|
|
253
|
-
|
|
254
|
-
/** @type {any} */
|
|
255
|
-
let highlighter = null
|
|
256
|
-
|
|
257
|
-
async function getHighlighter() {
|
|
258
|
-
if (highlighter) return highlighter
|
|
259
|
-
highlighter = await createInspectorHighlighter()
|
|
260
|
-
return highlighter
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/** Re-highlight source code with current theme (called on theme change). */
|
|
264
|
-
async function rehighlight() {
|
|
265
|
-
codeTheme = getColors()
|
|
266
|
-
if (!sourceCode || !sourcePath) return
|
|
267
|
-
try {
|
|
268
|
-
const hl = await getHighlighter()
|
|
269
|
-
highlightedHtml = hl.codeToHtml(sourceCode, {
|
|
270
|
-
lang: getLang(sourcePath),
|
|
271
|
-
theme: 'github-dark',
|
|
272
|
-
lineNumbers: false,
|
|
273
|
-
decorations: matchedLine > 0
|
|
274
|
-
? [{ start: { line: matchedLine - 1, character: 0 }, end: { line: matchedLine - 1, character: Infinity }, properties: { class: 'highlighted-line' } }]
|
|
275
|
-
: [],
|
|
276
|
-
})
|
|
277
|
-
} catch { /* ignore */ }
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* Find the line number of a JSX component in source code by matching
|
|
282
|
-
* the component name and its props against the source lines.
|
|
283
|
-
*
|
|
284
|
-
* Searches for `<ComponentName` followed by prop values from the
|
|
285
|
-
* component's props. Scores each `<ComponentName` occurrence by how
|
|
286
|
-
* many prop values appear nearby, picks the best match.
|
|
287
|
-
*/
|
|
288
|
-
function findComponentLine(code, info) {
|
|
289
|
-
if (!code || !info?.name) return -1
|
|
290
|
-
|
|
291
|
-
const lines = code.split('\n')
|
|
292
|
-
const name = info.name
|
|
293
|
-
const props = info.props || {}
|
|
294
|
-
|
|
295
|
-
// Collect string representations of prop values for matching
|
|
296
|
-
const propSignatures = []
|
|
297
|
-
for (const [key, val] of Object.entries(props)) {
|
|
298
|
-
if (key === 'children') continue
|
|
299
|
-
if (typeof val === 'string') {
|
|
300
|
-
propSignatures.push(`"${val}"`, `'${val}'`, `\`${val}\``, `="${val}"`, `='${val}'`)
|
|
301
|
-
} else if (typeof val === 'number' || typeof val === 'boolean') {
|
|
302
|
-
propSignatures.push(`{${val}}`, `=${val}`)
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Find all lines with `<ComponentName` (opening JSX tag)
|
|
307
|
-
const tagPattern = new RegExp(`<${name}[\\s/>]`)
|
|
308
|
-
const candidates = []
|
|
309
|
-
for (let i = 0; i < lines.length; i++) {
|
|
310
|
-
if (tagPattern.test(lines[i])) {
|
|
311
|
-
candidates.push(i)
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
if (candidates.length === 0) return -1
|
|
316
|
-
if (candidates.length === 1) return candidates[0] + 1
|
|
317
|
-
|
|
318
|
-
// Score each candidate by how many prop values appear in nearby lines
|
|
319
|
-
let bestLine = candidates[0]
|
|
320
|
-
let bestScore = -1
|
|
321
|
-
|
|
322
|
-
for (const lineIdx of candidates) {
|
|
323
|
-
// Look at this line + the next 5 lines for prop values (JSX props are close)
|
|
324
|
-
const window = lines.slice(lineIdx, lineIdx + 6).join(' ')
|
|
325
|
-
let score = 0
|
|
326
|
-
for (const sig of propSignatures) {
|
|
327
|
-
if (window.includes(sig)) score++
|
|
328
|
-
}
|
|
329
|
-
if (score > bestScore) {
|
|
330
|
-
bestScore = score
|
|
331
|
-
bestLine = lineIdx
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
return bestLine + 1 // 1-indexed
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
function getLang(filePath) {
|
|
339
|
-
if (filePath.endsWith('.tsx')) return 'tsx'
|
|
340
|
-
if (filePath.endsWith('.jsx')) return 'jsx'
|
|
341
|
-
if (filePath.endsWith('.ts')) return 'typescript'
|
|
342
|
-
return 'javascript'
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
$effect(() => {
|
|
346
|
-
const path = resolveSourceFile(componentInfo)
|
|
347
|
-
if (path) {
|
|
348
|
-
sourceLoading = true
|
|
349
|
-
sourcePath = path
|
|
350
|
-
highlightedHtml = ''
|
|
351
|
-
fetchSourceContent(path)
|
|
352
|
-
.then(async (content) => {
|
|
353
|
-
sourceCode = content
|
|
354
|
-
// Try the selected component first, then walk up the chain
|
|
355
|
-
matchedLine = findComponentLine(sourceCode, componentInfo)
|
|
356
|
-
if (matchedLine < 0 && componentChain.length > 0) {
|
|
357
|
-
for (const ancestor of componentChain) {
|
|
358
|
-
matchedLine = findComponentLine(sourceCode, { name: ancestor.name, props: {} })
|
|
359
|
-
if (matchedLine > 0) break
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
if (sourceCode) {
|
|
363
|
-
try {
|
|
364
|
-
const hl = await getHighlighter()
|
|
365
|
-
highlightedHtml = hl.codeToHtml(sourceCode, {
|
|
366
|
-
lang: getLang(path),
|
|
367
|
-
theme: 'github-dark',
|
|
368
|
-
lineNumbers: false,
|
|
369
|
-
decorations: matchedLine > 0
|
|
370
|
-
? [{ start: { line: matchedLine - 1, character: 0 }, end: { line: matchedLine - 1, character: Infinity }, properties: { class: 'highlighted-line' } }]
|
|
371
|
-
: [],
|
|
372
|
-
})
|
|
373
|
-
} catch {
|
|
374
|
-
highlightedHtml = ''
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
sourceLoading = false
|
|
378
|
-
})
|
|
379
|
-
.catch(() => { sourceCode = ''; highlightedHtml = ''; matchedLine = -1; sourceLoading = false })
|
|
380
|
-
} else {
|
|
381
|
-
sourceCode = ''
|
|
382
|
-
sourcePath = ''
|
|
383
|
-
highlightedHtml = ''
|
|
384
|
-
}
|
|
385
|
-
})
|
|
386
|
-
|
|
387
|
-
$effect(() => {
|
|
388
|
-
if (sourceContainer && highlightedHtml) {
|
|
389
|
-
requestAnimationFrame(() => {
|
|
390
|
-
const el = sourceContainer.querySelector('.highlighted-line')
|
|
391
|
-
if (el) {
|
|
392
|
-
// Align the highlighted line to the top of the code viewport.
|
|
393
|
-
const targetTop = Math.max(el.offsetTop - 24, 0)
|
|
394
|
-
sourceContainer.scrollTo({ top: targetTop, behavior: 'smooth' })
|
|
395
|
-
} else {
|
|
396
|
-
sourceContainer.scrollTop = 0
|
|
397
|
-
}
|
|
398
|
-
})
|
|
399
|
-
}
|
|
400
|
-
})
|
|
401
|
-
|
|
402
|
-
function handleSelect(el) {
|
|
403
|
-
componentInfo = inspectElement(el)
|
|
404
|
-
componentChain = inspectElementChain(el)
|
|
405
|
-
selectedElement = el
|
|
406
|
-
inspecting = false
|
|
407
|
-
// Show persistent highlight on the selected element
|
|
408
|
-
mouseMode?.showHighlight(el)
|
|
409
|
-
// Persist selection to URL
|
|
410
|
-
setInspectParam(generateSelector(el))
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
function handleDeactivate() {
|
|
414
|
-
inspecting = false
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
function startInspecting() {
|
|
418
|
-
// Hide any persistent highlight before entering mouse mode
|
|
419
|
-
mouseMode?.hideHighlight()
|
|
420
|
-
mouseMode?.activate()
|
|
421
|
-
inspecting = true
|
|
422
|
-
// Clear URL param while re-selecting
|
|
423
|
-
setInspectParam(null)
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
function stopInspecting() {
|
|
427
|
-
mouseMode?.deactivate()
|
|
428
|
-
inspecting = false
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
function toggleInspecting() {
|
|
432
|
-
if (inspecting) stopInspecting()
|
|
433
|
-
else startInspecting()
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
function formatSourceLink(source) {
|
|
437
|
-
if (!source) return null
|
|
438
|
-
const { fileName, lineNumber, columnNumber } = source
|
|
439
|
-
return {
|
|
440
|
-
label: `${fileName.split('/').pop()}:${lineNumber}`,
|
|
441
|
-
href: `vscode://file/${fileName}:${lineNumber}:${columnNumber || 1}`,
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
onMount(async () => {
|
|
446
|
-
mouseMode = createMouseMode({
|
|
447
|
-
onSelect: handleSelect,
|
|
448
|
-
onDeactivate: handleDeactivate,
|
|
449
|
-
})
|
|
450
|
-
|
|
451
|
-
// Re-highlight code when theme changes
|
|
452
|
-
document.addEventListener('storyboard:theme:changed', rehighlight)
|
|
453
|
-
|
|
454
|
-
// Pre-fetch file list and repo info
|
|
455
|
-
// In local dev, try dev middleware; in production, go straight to static JSON
|
|
456
|
-
let filesLoaded = false
|
|
457
|
-
if (_isLocalDev) {
|
|
458
|
-
try {
|
|
459
|
-
const [filesRes, repoRes] = await Promise.all([
|
|
460
|
-
fetch(`${_basePath.replace(/\/$/, '')}/_storyboard/docs/files`),
|
|
461
|
-
fetch(`${_basePath.replace(/\/$/, '')}/_storyboard/docs/repo`),
|
|
462
|
-
])
|
|
463
|
-
if (filesRes.ok) {
|
|
464
|
-
const data = await filesRes.json()
|
|
465
|
-
knownFiles = data.files || []
|
|
466
|
-
filesLoaded = true
|
|
467
|
-
}
|
|
468
|
-
if (repoRes.ok) {
|
|
469
|
-
repoInfo = await repoRes.json()
|
|
470
|
-
}
|
|
471
|
-
} catch {}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
if (!filesLoaded) {
|
|
475
|
-
// Use static build-time JSON
|
|
476
|
-
const data = await loadStaticData()
|
|
477
|
-
if (data) {
|
|
478
|
-
knownFiles = data.files || []
|
|
479
|
-
repoInfo = data.repo || null
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
// Restore inspector selection from URL param (after files are loaded)
|
|
484
|
-
const savedSelector = getInspectParam()
|
|
485
|
-
let restored = false
|
|
486
|
-
if (savedSelector) {
|
|
487
|
-
// Retry with delay — the React page may still be rendering
|
|
488
|
-
for (let attempt = 0; attempt < 5 && !restored; attempt++) {
|
|
489
|
-
if (attempt > 0) await new Promise(r => setTimeout(r, 300))
|
|
490
|
-
try {
|
|
491
|
-
const el = document.querySelector(savedSelector)
|
|
492
|
-
if (el) {
|
|
493
|
-
handleSelect(el)
|
|
494
|
-
restored = true
|
|
495
|
-
}
|
|
496
|
-
} catch {
|
|
497
|
-
break // invalid selector, don't retry
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
if (!restored) setInspectParam(null)
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
if (!restored) {
|
|
504
|
-
startInspecting()
|
|
505
|
-
}
|
|
506
|
-
})
|
|
507
|
-
|
|
508
|
-
onDestroy(() => {
|
|
509
|
-
mouseMode?.deactivate()
|
|
510
|
-
mouseMode?.hideHighlight()
|
|
511
|
-
setInspectParam(null)
|
|
512
|
-
document.removeEventListener('storyboard:theme:changed', rehighlight)
|
|
513
|
-
})
|
|
514
|
-
</script>
|
|
515
|
-
|
|
516
|
-
<div class="flex flex-col h-full" data-inspector-panel>
|
|
517
|
-
<!-- Content -->
|
|
518
|
-
<div class="flex-1 overflow-y-auto min-h-0 flex flex-col">
|
|
519
|
-
<!-- Empty state -->
|
|
520
|
-
{#if !hasSelection && !inspecting}
|
|
521
|
-
<div class="flex flex-col items-center justify-center h-full gap-3 px-6 py-12 text-center">
|
|
522
|
-
<span style:color="var(--fgColor-muted)" class="opacity-40">
|
|
523
|
-
<Icon name="iconoir/square-dashed" size={48} strokeWeight={2} scale={1.05} />
|
|
524
|
-
</span>
|
|
525
|
-
<p class="text-sm font-medium m-0" style:color="var(--fgColor-default)">
|
|
526
|
-
Select an element to start
|
|
527
|
-
</p>
|
|
528
|
-
<p class="text-xs m-0" style:color="var(--fgColor-muted)">
|
|
529
|
-
Click the inspect button to enter selection mode
|
|
530
|
-
</p>
|
|
531
|
-
<button
|
|
532
|
-
class="mt-2 px-4 py-1.5 text-xs font-medium rounded-md border-none cursor-pointer transition-colors"
|
|
533
|
-
style:background="var(--sb--color-purple, #7655a4)"
|
|
534
|
-
style:color="#fff"
|
|
535
|
-
onclick={startInspecting}
|
|
536
|
-
>
|
|
537
|
-
Start inspecting
|
|
538
|
-
</button>
|
|
539
|
-
</div>
|
|
540
|
-
|
|
541
|
-
<!-- Inspecting state -->
|
|
542
|
-
{:else if inspecting}
|
|
543
|
-
<div class="flex flex-col items-center justify-center h-full gap-3 px-6 py-12 text-center">
|
|
544
|
-
<div class="flex items-center gap-2">
|
|
545
|
-
<span class="inspector-pulse-dot"></span>
|
|
546
|
-
<p class="text-sm m-0" style:color="var(--fgColor-default)">
|
|
547
|
-
Click any element on the page to inspect it
|
|
548
|
-
</p>
|
|
549
|
-
</div>
|
|
550
|
-
<button
|
|
551
|
-
class="mt-2 px-4 py-1.5 text-xs font-medium rounded-md border cursor-pointer transition-colors"
|
|
552
|
-
style:background="transparent"
|
|
553
|
-
style:color="var(--fgColor-muted)"
|
|
554
|
-
style:border-color="var(--borderColor-default, var(--sb--color-border, #d1d9e0))"
|
|
555
|
-
onclick={stopInspecting}
|
|
556
|
-
>
|
|
557
|
-
Cancel
|
|
558
|
-
</button>
|
|
559
|
-
</div>
|
|
560
|
-
|
|
561
|
-
<!-- Selected state -->
|
|
562
|
-
{:else}
|
|
563
|
-
<div class="flex flex-col flex-1 min-h-0 p-3 pt-0 gap-3">
|
|
564
|
-
<!-- Component name -->
|
|
565
|
-
<div>
|
|
566
|
-
<h3 class="text-base font-bold m-0 inspector-mono" style:color="var(--sb--color-purple, #7655a4)">
|
|
567
|
-
{componentInfo.name}
|
|
568
|
-
</h3>
|
|
569
|
-
</div>
|
|
570
|
-
|
|
571
|
-
<!-- Source code -->
|
|
572
|
-
{#if sourcePath}
|
|
573
|
-
<div class="border rounded-md overflow-hidden flex-1 min-h-0 flex flex-col" style:background={codeTheme.bg} style:border-color={codeTheme.border}>
|
|
574
|
-
<div
|
|
575
|
-
class="flex items-center justify-between w-full px-3 py-1.5 text-xs font-semibold shrink-0"
|
|
576
|
-
style:background={codeTheme.headerBg}
|
|
577
|
-
style:color={codeTheme.headerFg}
|
|
578
|
-
style:border-bottom="1px solid {codeTheme.border}"
|
|
579
|
-
>
|
|
580
|
-
<span class="flex items-center gap-1.5 min-w-0">
|
|
581
|
-
<Icon name="primer/file-code" size={12} />
|
|
582
|
-
<span class="truncate">{sourcePath}</span>
|
|
583
|
-
</span>
|
|
584
|
-
{#if githubUrl}
|
|
585
|
-
<a
|
|
586
|
-
href={githubUrl}
|
|
587
|
-
target="_blank"
|
|
588
|
-
rel="noopener noreferrer"
|
|
589
|
-
class="flex items-center gap-1 shrink-0 text-xs no-underline hover:underline inspector-mono inspector-code-link"
|
|
590
|
-
style:color={codeTheme.headerFg}
|
|
591
|
-
>
|
|
592
|
-
<Icon name="primer/mark-github" size={14} />
|
|
593
|
-
<span>GitHub</span>
|
|
594
|
-
</a>
|
|
595
|
-
{/if}
|
|
596
|
-
</div>
|
|
597
|
-
|
|
598
|
-
<div class="border-t flex-1 min-h-0 flex flex-col" style:border-color={codeTheme.border}>
|
|
599
|
-
{#if sourceLoading}
|
|
600
|
-
<div class="px-3 py-4 text-xs text-center" style:color={codeTheme.headerFg}>
|
|
601
|
-
Loading source…
|
|
602
|
-
</div>
|
|
603
|
-
{:else if sourceCode}
|
|
604
|
-
<div class="flex-1 min-h-0 overflow-y-auto source-scroll-container" bind:this={sourceContainer} style:--inspector-line-num-color={codeTheme.comment} style:--inspector-line-hover={codeTheme.lineHighlight}>
|
|
605
|
-
{#if highlightedHtml}
|
|
606
|
-
<div class="code-wrapper line-numbers">{@html highlightedHtml}</div>
|
|
607
|
-
{:else}
|
|
608
|
-
<pre class="m-0 text-xs leading-relaxed inspector-mono source-pre line-numbers" style:background={codeTheme.bg} style:color={codeTheme.fg}><code>{#each sourceCode.split('\n') as line, i}<span class="line{matchedLine > 0 && i + 1 === matchedLine ? ' highlighted-line' : ''}">{line}</span>{#if i < sourceCode.split('\n').length - 1}{'\n'}{/if}{/each}</code></pre>
|
|
609
|
-
{/if}
|
|
610
|
-
</div>
|
|
611
|
-
{:else}
|
|
612
|
-
<div class="px-3 py-4 text-xs text-center" style:color={codeTheme.headerFg}>
|
|
613
|
-
Unable to load source
|
|
614
|
-
</div>
|
|
615
|
-
{/if}
|
|
616
|
-
</div>
|
|
617
|
-
</div>
|
|
618
|
-
{/if}
|
|
619
|
-
|
|
620
|
-
<!-- Re-select button -->
|
|
621
|
-
<button
|
|
622
|
-
class="flex items-center justify-center gap-1.5 w-full px-3 py-1.5 text-xs font-medium rounded-md border-none cursor-pointer transition-colors shrink-0"
|
|
623
|
-
style:background="var(--sb--color-purple, #7655a4)"
|
|
624
|
-
style:color="#fff"
|
|
625
|
-
onclick={startInspecting}
|
|
626
|
-
>
|
|
627
|
-
<Icon name="primer/search" size={12} />
|
|
628
|
-
Re-select
|
|
629
|
-
</button>
|
|
630
|
-
</div>
|
|
631
|
-
{/if}
|
|
632
|
-
</div>
|
|
633
|
-
</div>
|
|
634
|
-
|
|
635
|
-
<style>
|
|
636
|
-
.inspector-mono {
|
|
637
|
-
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
.inspector-pulse-dot {
|
|
641
|
-
width: 8px;
|
|
642
|
-
height: 8px;
|
|
643
|
-
border-radius: 50%;
|
|
644
|
-
background: var(--sb--color-purple, #7655a4);
|
|
645
|
-
animation: inspector-pulse 1.5s ease-in-out infinite;
|
|
646
|
-
flex-shrink: 0;
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
@keyframes inspector-pulse {
|
|
650
|
-
0%, 100% { opacity: 1; transform: scale(1); }
|
|
651
|
-
50% { opacity: 0.4; transform: scale(0.85); }
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
pre {
|
|
655
|
-
background: transparent;
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
.source-pre {
|
|
659
|
-
background: transparent;
|
|
660
|
-
tab-size: 2;
|
|
661
|
-
padding: 12px 0;
|
|
662
|
-
color: #c9d1d9;
|
|
663
|
-
overflow-x: auto;
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
.source-pre code {
|
|
667
|
-
font-family: inherit;
|
|
668
|
-
display: block;
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
.source-pre .line {
|
|
672
|
-
padding: 0 12px 0 0;
|
|
673
|
-
display: inline-block;
|
|
674
|
-
width: 100%;
|
|
675
|
-
min-height: 1.5em;
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
.source-pre .line:hover {
|
|
679
|
-
background: var(--inspector-line-hover, rgba(255, 255, 255, 0.04));
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
.source-pre :global(.highlighted-line) {
|
|
683
|
-
background: color-mix(in srgb, var(--sb--color-purple, #7655a4) 20%, transparent);
|
|
684
|
-
border-left: 2px solid var(--sb--color-purple, #7655a4);
|
|
685
|
-
padding-left: 10px;
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
/* Line numbers via CSS counters — works for both highlight.js and plain-text */
|
|
689
|
-
.line-numbers :global(code) {
|
|
690
|
-
counter-reset: line;
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
.line-numbers :global(.line) {
|
|
694
|
-
padding-left: 0 !important;
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
.line-numbers :global(.line::before) {
|
|
698
|
-
counter-increment: line;
|
|
699
|
-
content: counter(line);
|
|
700
|
-
display: inline-block;
|
|
701
|
-
width: 3.5ch;
|
|
702
|
-
margin-right: 1.5ch;
|
|
703
|
-
text-align: right;
|
|
704
|
-
color: var(--inspector-line-num-color, #484f58);
|
|
705
|
-
user-select: none;
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
.code-wrapper :global(pre) {
|
|
709
|
-
margin: 0;
|
|
710
|
-
padding: 12px 0;
|
|
711
|
-
font-size: 12px;
|
|
712
|
-
line-height: 1.6;
|
|
713
|
-
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
|
|
714
|
-
tab-size: 2;
|
|
715
|
-
background: transparent !important;
|
|
716
|
-
overflow-x: auto;
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
.code-wrapper :global(code) {
|
|
720
|
-
font-family: inherit;
|
|
721
|
-
display: block;
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
.code-wrapper :global(.line) {
|
|
725
|
-
padding: 0 12px 0 0;
|
|
726
|
-
display: inline-block;
|
|
727
|
-
width: 100%;
|
|
728
|
-
min-height: 1.5em;
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
.code-wrapper :global(.line:hover) {
|
|
732
|
-
background: var(--inspector-line-hover, rgba(255, 255, 255, 0.04));
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
.code-wrapper :global(.highlighted-line) {
|
|
736
|
-
background: color-mix(in srgb, var(--sb--color-purple, #7655a4) 20%, transparent);
|
|
737
|
-
border-left: 2px solid var(--sb--color-purple, #7655a4);
|
|
738
|
-
padding-left: 10px;
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
/* Force dark chrome on the code block — independent of page theme */
|
|
742
|
-
.inspector-code-link:hover {
|
|
743
|
-
text-decoration: underline;
|
|
744
|
-
}
|
|
745
|
-
</style>
|