@dfosco/storyboard 0.7.1 → 0.9.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/dist/storyboard-ui.css +1 -1
- package/dist/storyboard-ui.js +14128 -10953
- package/dist/storyboard-ui.js.map +1 -1
- package/dist/tailwind.css +1 -1
- package/dist/tiny-canvas.css +1 -1
- package/package.json +138 -128
- package/scaffold/AGENTS.md +9 -7
- package/scaffold/README.md +18 -0
- package/scaffold/deploy.yml +21 -0
- package/scaffold/gitignore +8 -14
- package/scaffold/preview.yml +40 -0
- package/scaffold/{manifest.json → scaffold.config.json} +73 -3
- package/scaffold/scripts/aggregate-artifacts.mjs +257 -0
- package/scaffold/skills/canvas/SKILL.md +1 -1
- package/scaffold/skills/migrate-0.5.0/SKILL.md +1 -1
- package/scaffold/skills/ship/SKILL.md +2 -2
- package/scaffold/skills/worktree/SKILL.md +1 -1
- package/scaffold/src/_prototype.jsx +17 -0
- package/scaffold/src/_story.jsx +13 -0
- package/scaffold/src/library/README.md +34 -0
- package/scaffold/src/library/_app.jsx +41 -0
- package/scaffold/src/library/_app.module.css +2 -0
- package/scaffold/src/library/create.jsx +10 -0
- package/scaffold/src/library/index.jsx +14 -0
- package/scaffold/src/library/mount.jsx +51 -0
- package/scaffold/src/library/prototypes-entry.jsx +57 -0
- package/scaffold/src/library/routes.jsx +205 -0
- package/scaffold/src/library/viewfinder.jsx +13 -0
- package/scaffold/src/library/workspace.jsx +17 -0
- package/scripts/aggregate-artifacts.mjs +257 -0
- package/src/canvas/style.css +16 -16
- package/src/core/artifact/operations.js +54 -15
- package/src/core/artifact/schemas/canvas.schema.json +7 -1
- package/src/core/autosync/server.test.js +1 -1
- package/src/core/canvas/hot-pool.js +21 -33
- package/src/core/canvas/materializer.js +39 -13
- package/src/core/canvas/selectedWidgets.js +1 -1
- package/src/core/canvas/server.js +376 -100
- package/src/core/canvas/server.test.js +472 -2
- package/src/core/canvas/terminal-server.js +144 -57
- package/src/core/canvas/undoRedo.js +174 -0
- package/src/core/canvas/undoRedo.test.js +250 -0
- package/src/core/cli/artifact.js +2 -0
- package/src/core/cli/buildManifest.js +34 -0
- package/src/core/cli/canvasRedo.js +44 -0
- package/src/core/cli/canvasUndo.js +40 -0
- package/src/core/cli/create.js +151 -23
- package/src/core/cli/dev.js +23 -35
- package/src/core/cli/index.js +21 -0
- package/src/core/cli/schemas.js +8 -4
- package/src/core/cli/serverUrl.js +24 -0
- package/src/core/cli/setup.js +14 -25
- package/src/core/cli/terminal-welcome.js +12 -6
- package/src/core/cli/updateVersion.js +42 -2
- package/src/core/cli/workleaf.js +140 -0
- package/src/core/comments/api.js +1 -1
- package/src/core/comments/queries.js +3 -0
- package/src/core/comments/ui/CommentWindow.jsx +3 -2
- package/src/core/comments/ui/comment-layout.css +14 -14
- package/src/core/data/artifactIndex.js +235 -0
- package/src/core/data/artifactIndex.test.js +203 -0
- package/src/core/data/artifactManifest.js +290 -0
- package/src/core/data/artifactManifest.test.js +207 -0
- package/src/core/data/viewfinder.js +47 -7
- package/src/core/index.js +24 -1
- package/src/core/inspector/highlighter.js +1 -1
- package/src/core/inspector/mouseMode.js +2 -2
- package/src/core/lib/components/ui/avatar/avatar-fallback.jsx +2 -2
- package/src/core/lib/components/ui/avatar/avatar-image.jsx +2 -2
- package/src/core/lib/components/ui/avatar/avatar.jsx +2 -2
- package/src/core/lib/components/ui/checkbox/checkbox.jsx +12 -9
- package/src/core/lib/components/ui/dialog/dialog-content.jsx +45 -31
- package/src/core/lib/components/ui/dialog/dialog-trigger.jsx +9 -5
- package/src/core/lib/components/ui/dialog/dialog.jsx +12 -3
- package/src/core/lib/components/ui/dialog/dialog.module.css +118 -0
- package/src/core/lib/components/ui/dialog/index.js +4 -34
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.jsx +3 -3
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.jsx +19 -9
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-content.jsx +8 -8
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.jsx +2 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-group.jsx +2 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-item.jsx +15 -4
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-portal.jsx +2 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.jsx +2 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.jsx +14 -7
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-separator.jsx +2 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.jsx +8 -4
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.jsx +4 -4
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub.jsx +2 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-trigger.jsx +8 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu.jsx +2 -2
- package/src/core/lib/components/ui/label/label.jsx +1 -2
- package/src/core/lib/components/ui/panel/panel-close.jsx +7 -4
- package/src/core/lib/components/ui/panel/panel-content.jsx +7 -9
- package/src/core/lib/components/ui/panel/panel-title.jsx +3 -3
- package/src/core/lib/components/ui/panel/panel.jsx +11 -2
- package/src/core/lib/components/ui/separator/separator.jsx +6 -4
- package/src/core/lib/components/ui/tooltip/tooltip-content.jsx +7 -6
- package/src/core/lib/components/ui/tooltip/tooltip-trigger.jsx +13 -6
- package/src/core/lib/components/ui/tooltip/tooltip.jsx +5 -5
- package/src/core/modes/modes.css +4 -4
- package/src/core/mountStoryboardCore.js +287 -83
- package/src/core/mountStoryboardCore.test.js +198 -0
- package/src/core/rename-watcher/config.json +1 -1
- package/src/core/rename-watcher/watcher.js +330 -37
- package/src/core/rename-watcher/watcher.test.js +253 -0
- package/src/core/scaffold/fragments.js +287 -0
- package/src/core/scaffold/fragments.test.js +401 -0
- package/src/core/scaffold/index.js +291 -0
- package/src/core/scaffold/migrateLegacyGitignore.js +157 -0
- package/src/core/scaffold/scaffold-integration.test.js +247 -0
- package/src/core/scaffold.js +4 -97
- package/src/core/stores/canvasInteractionStore.js +120 -0
- package/src/core/stores/canvasInteractionStore.test.js +126 -0
- package/src/core/stores/configSchema.js +64 -8
- package/src/core/stores/configSchema.test.js +3 -0
- package/src/core/stores/customerModeConfig.js +24 -3
- package/src/core/stores/customerModeConfig.test.js +46 -0
- package/src/core/stores/presentationStore.js +118 -0
- package/src/core/stores/presentationStore.test.js +114 -0
- package/src/core/stores/recentArtifacts.js +49 -2
- package/src/core/stores/recentArtifacts.test.js +59 -6
- package/src/core/stores/themeBootstrap.js +264 -0
- package/src/core/stores/themeBootstrap.test.js +211 -0
- package/src/core/stores/themeStore.test.js +154 -0
- package/src/core/stores/themeStore.ts +235 -220
- package/src/core/stores/uiConfig.js +10 -2
- package/src/core/styles/generateThemesCss.js +63 -0
- package/src/core/styles/tailwind.css +150 -94
- package/src/core/styles/workspace-chrome.css +13 -0
- package/src/core/tools/handlers/paletteTheme.js +11 -8
- package/src/core/ui/ActionMenuButton.jsx +2 -1
- package/src/core/ui/AutosyncMenuButton.css +7 -7
- package/src/core/ui/BranchSelect.module.css +5 -5
- package/src/core/ui/CanvasCreateMenu.jsx +1 -19
- package/src/core/ui/ChromeSlot.jsx +92 -0
- package/src/core/ui/ChromeSlot.test.jsx +140 -0
- package/src/core/ui/CoreUIBar.css +5 -5
- package/src/core/ui/CoreUIBar.jsx +170 -142
- package/src/core/ui/InspectorPanel.css +5 -5
- package/src/core/ui/InspectorPanel.jsx +9 -9
- package/src/core/ui/PwaInstallBanner.css +5 -5
- package/src/core/ui/PwaInstallBanner.jsx +5 -5
- package/src/core/ui/ThemeMenuButton.jsx +45 -30
- package/src/core/ui/core-ui-colors.css +28 -66
- package/src/core/ui/sidepanel.css +12 -12
- package/src/core/vite/server-plugin.js +13 -0
- package/src/core/workleaf/cleanup.js +102 -0
- package/src/core/workleaf/create.js +199 -0
- package/src/core/workleaf/delete.js +101 -0
- package/src/core/workleaf/list.js +57 -0
- package/src/core/workleaf/merge.js +238 -0
- package/src/core/workleaf/paths.js +146 -0
- package/src/core/workleaf/paths.test.js +230 -0
- package/src/core/workshop/features/createCanvas/CreateCanvasForm.jsx +130 -34
- package/src/core/workshop/features/createFlow/server.js +5 -1
- package/src/core/workshop/features/createPrototype/server.js +5 -1
- package/src/core/workshop/features/templateIndex.js +28 -1
- package/src/core/worktree/port.js +48 -5
- package/src/core/worktree/port.test.js +42 -0
- package/src/internals/ArtifactForm/ArtifactForm.jsx +173 -112
- package/src/internals/ArtifactForm/ArtifactForm.module.css +51 -69
- package/src/internals/ArtifactForm/artifactSchemas.js +40 -5
- package/src/internals/AuthModal/AuthModal.module.css +34 -34
- package/src/internals/BaseUiForm/BaseUiForm.jsx +293 -0
- package/src/internals/BaseUiForm/BaseUiForm.module.css +542 -0
- package/src/internals/BranchBar/BranchBar.module.css +4 -4
- package/src/internals/BranchesDropdown/BranchesDropdown.jsx +69 -0
- package/src/internals/BranchesDropdown/BranchesDropdown.module.css +84 -0
- package/src/internals/CommandPalette/CommandPalette.jsx +41 -29
- package/src/internals/CommandPalette/CreateArtifactForm.jsx +150 -0
- package/src/internals/CommandPalette/CreateDialog.jsx +20 -110
- package/src/internals/CommandPalette/WidgetArtifactDialog.css +16 -16
- package/src/internals/CommandPalette/WidgetArtifactDialog.jsx +1 -1
- package/src/internals/CommandPalette/command-palette.css +14 -14
- package/src/internals/CommandPalette/createHelpers.js +30 -0
- package/src/internals/CreatePage/CreatePage.jsx +57 -0
- package/src/internals/CreatePage/CreatePage.module.css +34 -0
- package/src/internals/Dialog.jsx +51 -0
- package/src/internals/FlowError.module.css +5 -5
- package/src/internals/PrototypeErrorBoundary.module.css +15 -15
- package/src/internals/SimpleWorkspace/SimpleWorkspace.jsx +534 -0
- package/src/internals/SimpleWorkspace/SimpleWorkspace.module.css +323 -0
- package/src/internals/Tooltip.jsx +39 -0
- package/src/internals/Viewfinder.jsx +229 -64
- package/src/internals/Viewfinder.module.css +253 -182
- package/src/internals/canvas/CanvasControls.module.css +11 -11
- package/src/internals/canvas/CanvasPage.bridge.test.jsx +11 -37
- package/src/internals/canvas/CanvasPage.jsx +358 -217
- package/src/internals/canvas/CanvasPage.module.css +20 -19
- package/src/internals/canvas/CanvasPage.multiselect.test.jsx +39 -26
- package/src/internals/canvas/CanvasToolbar.module.css +11 -11
- package/src/internals/canvas/ConnectorLayer.jsx +39 -2
- package/src/internals/canvas/ConnectorLayer.module.css +10 -10
- package/src/internals/canvas/PageSelector.jsx +15 -1
- package/src/internals/canvas/PageSelector.module.css +41 -27
- package/src/internals/canvas/canvasApi.js +40 -5
- package/src/internals/canvas/canvasTheme.js +22 -111
- package/src/internals/canvas/isolation/createIsolationMiddleware.js +68 -0
- package/src/internals/canvas/isolation/mountIsolationApp.jsx +88 -0
- package/src/internals/canvas/isolation/prototypeRoutes.jsx +140 -0
- package/src/internals/canvas/isolation/prototypesEntry.jsx +28 -0
- package/src/internals/canvas/isolation/storiesEntry.jsx +20 -0
- package/src/internals/canvas/isolation/storyRoutes.jsx +55 -0
- package/src/internals/canvas/useUndoRedo.js +75 -60
- package/src/internals/canvas/useUndoRedo.test.js +46 -178
- package/src/internals/canvas/widgets/CodePenEmbed.jsx +16 -36
- package/src/internals/canvas/widgets/CodePenEmbed.module.css +12 -12
- package/src/internals/canvas/widgets/CropOverlay.module.css +23 -23
- package/src/internals/canvas/widgets/ExpandedPane.module.css +8 -8
- package/src/internals/canvas/widgets/ExpandedPaneTopBar.jsx +1 -1
- package/src/internals/canvas/widgets/FigmaEmbed.jsx +15 -36
- package/src/internals/canvas/widgets/FigmaEmbed.module.css +15 -15
- package/src/internals/canvas/widgets/FrozenTerminalOverlay.jsx +30 -21
- package/src/internals/canvas/widgets/FrozenTerminalOverlay.module.css +5 -5
- package/src/internals/canvas/widgets/ImageWidget.jsx +7 -2
- package/src/internals/canvas/widgets/ImageWidget.module.css +3 -3
- package/src/internals/canvas/widgets/LinkPreview.module.css +79 -80
- package/src/internals/canvas/widgets/MarkdownBlock.module.css +31 -31
- package/src/internals/canvas/widgets/PromptWidget.jsx +2 -16
- package/src/internals/canvas/widgets/PromptWidget.module.css +33 -33
- package/src/internals/canvas/widgets/PrototypeEmbed.jsx +92 -17
- package/src/internals/canvas/widgets/PrototypeEmbed.module.css +58 -56
- package/src/internals/canvas/widgets/PrototypeEmbed.test.jsx +118 -4
- package/src/internals/canvas/widgets/ResizeHandle.module.css +4 -4
- package/src/internals/canvas/widgets/StorySetWidget.jsx +53 -25
- package/src/internals/canvas/widgets/StoryWidget.jsx +71 -56
- package/src/internals/canvas/widgets/StoryWidget.module.css +22 -20
- package/src/internals/canvas/widgets/TerminalReadWidget.jsx +13 -15
- package/src/internals/canvas/widgets/TerminalReadWidget.module.css +4 -4
- package/src/internals/canvas/widgets/TerminalWidget.jsx +56 -45
- package/src/internals/canvas/widgets/TerminalWidget.module.css +10 -10
- package/src/internals/canvas/widgets/TilesWidget.module.css +17 -17
- package/src/internals/canvas/widgets/WidgetChrome.jsx +1 -1
- package/src/internals/canvas/widgets/WidgetChrome.module.css +76 -61
- package/src/internals/canvas/widgets/WidgetWrapper.module.css +2 -2
- package/src/internals/canvas/widgets/embedOverlay.module.css +14 -4
- package/src/internals/canvas/widgets/embedTheme.js +12 -104
- package/src/internals/canvas/widgets/expandUtils.js +19 -19
- package/src/internals/canvas/widgets/normalizeLegacyEmbedSrc.js +74 -0
- package/src/internals/canvas/widgets/widgetConfig.js +5 -5
- package/src/internals/context.jsx +22 -1
- package/src/internals/context.test.jsx +47 -0
- package/src/internals/hooks/useArtifactIndex.js +31 -0
- package/src/internals/hooks/useArtifactIndex.test.js +45 -0
- package/src/internals/hooks/usePrototypeReloadGuard.js +14 -8
- package/src/internals/index.js +6 -0
- package/src/internals/loadConsumerWrapper.js +60 -0
- package/src/internals/story/ComponentSetPage.jsx +75 -34
- package/src/internals/story/ComponentSetPage.module.css +14 -14
- package/src/internals/story/StoryPage.jsx +16 -25
- package/src/internals/story/StoryPage.module.css +2 -2
- package/src/internals/vite/data-plugin.js +317 -149
- package/src/internals/vite/data-plugin.test.js +11 -11
- package/{scaffold/storyboard.config.json → storyboard.config.json} +25 -0
- package/terminal.config.json +1 -1
- package/src/core/lib/components/ui/card/card-action.jsx +0 -11
- package/src/core/lib/components/ui/card/card-content.jsx +0 -11
- package/src/core/lib/components/ui/card/card-description.jsx +0 -11
- package/src/core/lib/components/ui/card/card-footer.jsx +0 -11
- package/src/core/lib/components/ui/card/card-header.jsx +0 -19
- package/src/core/lib/components/ui/card/card-title.jsx +0 -11
- package/src/core/lib/components/ui/card/card.jsx +0 -17
- package/src/core/lib/components/ui/card/index.js +0 -25
- package/src/core/lib/components/ui/collapsible/collapsible-content.jsx +0 -7
- package/src/core/lib/components/ui/collapsible/collapsible-trigger.jsx +0 -7
- package/src/core/lib/components/ui/collapsible/collapsible.jsx +0 -7
- package/src/core/lib/components/ui/collapsible/index.js +0 -13
- package/src/core/lib/components/ui/dialog/dialog-close.jsx +0 -7
- package/src/core/lib/components/ui/dialog/dialog-description.jsx +0 -15
- package/src/core/lib/components/ui/dialog/dialog-footer.jsx +0 -23
- package/src/core/lib/components/ui/dialog/dialog-header.jsx +0 -11
- package/src/core/lib/components/ui/dialog/dialog-overlay.jsx +0 -15
- package/src/core/lib/components/ui/dialog/dialog-portal.jsx +0 -4
- package/src/core/lib/components/ui/dialog/dialog-title.jsx +0 -15
- package/src/core/lib/components/ui/popover/index.js +0 -28
- package/src/core/lib/components/ui/popover/popover-close.jsx +0 -7
- package/src/core/lib/components/ui/popover/popover-content.jsx +0 -22
- package/src/core/lib/components/ui/popover/popover-description.jsx +0 -11
- package/src/core/lib/components/ui/popover/popover-header.jsx +0 -11
- package/src/core/lib/components/ui/popover/popover-portal.jsx +0 -4
- package/src/core/lib/components/ui/popover/popover-title.jsx +0 -11
- package/src/core/lib/components/ui/popover/popover-trigger.jsx +0 -8
- package/src/core/lib/components/ui/popover/popover.jsx +0 -4
- package/src/core/lib/components/ui/select/index.js +0 -37
- package/src/core/lib/components/ui/select/select-content.jsx +0 -30
- package/src/core/lib/components/ui/select/select-group-heading.jsx +0 -17
- package/src/core/lib/components/ui/select/select-group.jsx +0 -15
- package/src/core/lib/components/ui/select/select-item.jsx +0 -26
- package/src/core/lib/components/ui/select/select-label.jsx +0 -11
- package/src/core/lib/components/ui/select/select-portal.jsx +0 -4
- package/src/core/lib/components/ui/select/select-scroll-down-button.jsx +0 -18
- package/src/core/lib/components/ui/select/select-scroll-up-button.jsx +0 -18
- package/src/core/lib/components/ui/select/select-separator.jsx +0 -15
- package/src/core/lib/components/ui/select/select-trigger.jsx +0 -25
- package/src/core/lib/components/ui/select/select.jsx +0 -4
- package/src/core/lib/components/ui/sheet/index.js +0 -34
- package/src/core/lib/components/ui/sheet/sheet-close.jsx +0 -7
- package/src/core/lib/components/ui/sheet/sheet-content.jsx +0 -35
- package/src/core/lib/components/ui/sheet/sheet-description.jsx +0 -15
- package/src/core/lib/components/ui/sheet/sheet-footer.jsx +0 -11
- package/src/core/lib/components/ui/sheet/sheet-header.jsx +0 -11
- package/src/core/lib/components/ui/sheet/sheet-overlay.jsx +0 -15
- package/src/core/lib/components/ui/sheet/sheet-portal.jsx +0 -4
- package/src/core/lib/components/ui/sheet/sheet-title.jsx +0 -15
- package/src/core/lib/components/ui/sheet/sheet-trigger.jsx +0 -7
- package/src/core/lib/components/ui/sheet/sheet.jsx +0 -4
- package/src/core/lib/components/ui/toggle/index.js +0 -8
- package/src/core/lib/components/ui/toggle/toggle.jsx +0 -36
- package/src/core/lib/components/ui/toggle-group/index.js +0 -10
- package/src/core/lib/components/ui/toggle-group/toggle-group-item.jsx +0 -29
- package/src/core/lib/components/ui/toggle-group/toggle-group.jsx +0 -43
- package/src/internals/canvas/StoryErrorBoundary.jsx +0 -47
- package/src/internals/canvas/WebGLContextPool.jsx +0 -291
- package/src/internals/canvas/WebGLContextPool.test.jsx +0 -165
- package/src/internals/canvas/componentIsolate.jsx +0 -144
- package/src/internals/canvas/componentSetIsolate.jsx +0 -300
- package/src/internals/canvas/widgets/ComponentSetWidget.module.css +0 -89
- package/src/internals/canvas/widgets/InlineStoryRenderer.jsx +0 -129
- package/src/internals/canvas/widgets/InlineStoryRenderer.test.jsx +0 -68
- package/src/internals/canvas/widgets/StorySetWidget.module.css +0 -89
- package/src/primer/ThemeSync.jsx +0 -73
- package/src/primer/index.js +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
.block {
|
|
2
2
|
position: relative;
|
|
3
3
|
min-height: 80px;
|
|
4
|
-
--sb--markdown-bg: var(--
|
|
5
|
-
--sb--markdown-fg: var(--
|
|
6
|
-
--sb--markdown-muted: var(--
|
|
7
|
-
--sb--markdown-accent: var(--
|
|
4
|
+
--sb--markdown-bg: var(--color-background, #ffffff);
|
|
5
|
+
--sb--markdown-fg: var(--color-foreground, #1f2328);
|
|
6
|
+
--sb--markdown-muted: var(--color-foreground-muted, #656d76);
|
|
7
|
+
--sb--markdown-accent: var(--color-background-accent-emphasis, #2f81f7);
|
|
8
8
|
background: var(--sb--markdown-bg);
|
|
9
9
|
color: var(--sb--markdown-fg);
|
|
10
10
|
font-family: var(--tc-font-stack, system-ui, -apple-system, sans-serif);
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
max-width: 100%;
|
|
50
50
|
height: auto;
|
|
51
51
|
border-radius: 6px;
|
|
52
|
-
border: 1px solid var(--
|
|
52
|
+
border: 1px solid var(--color-border, #d0d7de);
|
|
53
53
|
margin: 8px 0;
|
|
54
54
|
display: block;
|
|
55
55
|
pointer-events: auto;
|
|
@@ -59,11 +59,11 @@
|
|
|
59
59
|
max-width: 100%;
|
|
60
60
|
height: auto;
|
|
61
61
|
border-radius: 6px;
|
|
62
|
-
border: 1px solid var(--
|
|
62
|
+
border: 1px solid var(--color-border, #d0d7de);
|
|
63
63
|
margin: 8px 0;
|
|
64
64
|
display: block;
|
|
65
65
|
pointer-events: auto;
|
|
66
|
-
background: var(--
|
|
66
|
+
background: var(--color-background-muted, #f6f8fa);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
.preview h1 {
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
.preview code {
|
|
95
|
-
background: var(--
|
|
95
|
+
background: var(--color-background-neutral-muted, #afb8c133);
|
|
96
96
|
padding: 2px 5px;
|
|
97
97
|
border-radius: 4px;
|
|
98
98
|
font-size: 12px;
|
|
@@ -145,13 +145,13 @@
|
|
|
145
145
|
|
|
146
146
|
.preview th,
|
|
147
147
|
.preview td {
|
|
148
|
-
border: 1px solid var(--
|
|
148
|
+
border: 1px solid var(--color-border, #d0d7de);
|
|
149
149
|
padding: 6px 12px;
|
|
150
150
|
text-align: left;
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
.preview th {
|
|
154
|
-
background: var(--
|
|
154
|
+
background: var(--color-background-muted, #f6f8fa);
|
|
155
155
|
font-weight: 600;
|
|
156
156
|
}
|
|
157
157
|
|
|
@@ -159,17 +159,17 @@
|
|
|
159
159
|
.preview pre {
|
|
160
160
|
padding: 12px 16px;
|
|
161
161
|
border-radius: 6px;
|
|
162
|
-
border: 1px solid var(--
|
|
162
|
+
border: 1px solid var(--color-border-muted, #d8dee4);
|
|
163
163
|
overflow-x: auto;
|
|
164
164
|
margin: 8px 0;
|
|
165
|
-
background: var(--
|
|
165
|
+
background: var(--color-background-neutral-muted, #afb8c133);
|
|
166
166
|
line-height: 1.4;
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
/* When inspector highlighter sets inline background, let it through */
|
|
170
170
|
.preview pre[style] {
|
|
171
171
|
border-radius: 6px;
|
|
172
|
-
border: 1px solid var(--
|
|
172
|
+
border: 1px solid var(--color-border-muted, #d8dee4);
|
|
173
173
|
overflow-x: auto;
|
|
174
174
|
margin: 8px 0;
|
|
175
175
|
}
|
|
@@ -193,7 +193,7 @@
|
|
|
193
193
|
|
|
194
194
|
/* Blockquotes */
|
|
195
195
|
.preview blockquote {
|
|
196
|
-
border-left: 4px solid var(--
|
|
196
|
+
border-left: 4px solid var(--color-border, #d0d7de);
|
|
197
197
|
margin: 8px 0;
|
|
198
198
|
padding: 4px 16px;
|
|
199
199
|
color: var(--sb--markdown-muted);
|
|
@@ -202,7 +202,7 @@
|
|
|
202
202
|
/* Horizontal rules */
|
|
203
203
|
.preview hr {
|
|
204
204
|
border: none;
|
|
205
|
-
border-top: 1px solid var(--
|
|
205
|
+
border-top: 1px solid var(--color-border, #d0d7de);
|
|
206
206
|
margin: 16px 0;
|
|
207
207
|
}
|
|
208
208
|
|
|
@@ -231,10 +231,10 @@
|
|
|
231
231
|
/* ── Expanded preview in modal ──────────────────────────────────── */
|
|
232
232
|
|
|
233
233
|
.expandedPreview {
|
|
234
|
-
--sb--markdown-bg: var(--
|
|
235
|
-
--sb--markdown-fg: var(--
|
|
236
|
-
--sb--markdown-muted: var(--
|
|
237
|
-
--sb--markdown-accent: var(--
|
|
234
|
+
--sb--markdown-bg: var(--color-background, #ffffff);
|
|
235
|
+
--sb--markdown-fg: var(--color-foreground, #1f2328);
|
|
236
|
+
--sb--markdown-muted: var(--color-foreground-muted, #656d76);
|
|
237
|
+
--sb--markdown-accent: var(--color-background-accent-emphasis, #2f81f7);
|
|
238
238
|
padding: 32px 40px;
|
|
239
239
|
font-size: 15px;
|
|
240
240
|
line-height: 1.7;
|
|
@@ -264,7 +264,7 @@
|
|
|
264
264
|
max-width: 100%;
|
|
265
265
|
height: auto;
|
|
266
266
|
border-radius: 6px;
|
|
267
|
-
border: 1px solid var(--
|
|
267
|
+
border: 1px solid var(--color-border, #d0d7de);
|
|
268
268
|
margin: 8px 0;
|
|
269
269
|
display: block;
|
|
270
270
|
}
|
|
@@ -273,7 +273,7 @@
|
|
|
273
273
|
max-width: 100%;
|
|
274
274
|
height: auto;
|
|
275
275
|
border-radius: 6px;
|
|
276
|
-
border: 1px solid var(--
|
|
276
|
+
border: 1px solid var(--color-border, #d0d7de);
|
|
277
277
|
margin: 8px 0;
|
|
278
278
|
display: block;
|
|
279
279
|
}
|
|
@@ -284,7 +284,7 @@
|
|
|
284
284
|
.expandedPreview p { margin: 0 0 12px; }
|
|
285
285
|
|
|
286
286
|
.expandedPreview code {
|
|
287
|
-
background: var(--
|
|
287
|
+
background: var(--color-background-neutral-muted, #afb8c133);
|
|
288
288
|
padding: 2px 5px;
|
|
289
289
|
border-radius: 4px;
|
|
290
290
|
font-size: 13px;
|
|
@@ -294,10 +294,10 @@
|
|
|
294
294
|
.expandedPreview pre {
|
|
295
295
|
padding: 12px 16px;
|
|
296
296
|
border-radius: 6px;
|
|
297
|
-
border: 1px solid var(--
|
|
297
|
+
border: 1px solid var(--color-border-muted, #d8dee4);
|
|
298
298
|
overflow-x: auto;
|
|
299
299
|
margin: 8px 0;
|
|
300
|
-
background: var(--
|
|
300
|
+
background: var(--color-background-neutral-muted, #afb8c133);
|
|
301
301
|
line-height: 1.4;
|
|
302
302
|
}
|
|
303
303
|
|
|
@@ -314,7 +314,7 @@
|
|
|
314
314
|
.expandedPreview li { margin: 0 0 4px; display: list-item; }
|
|
315
315
|
|
|
316
316
|
.expandedPreview blockquote {
|
|
317
|
-
border-left: 4px solid var(--
|
|
317
|
+
border-left: 4px solid var(--color-border, #d0d7de);
|
|
318
318
|
margin: 12px 0;
|
|
319
319
|
padding: 4px 16px;
|
|
320
320
|
color: var(--sb--markdown-muted);
|
|
@@ -329,19 +329,19 @@
|
|
|
329
329
|
|
|
330
330
|
.expandedPreview th,
|
|
331
331
|
.expandedPreview td {
|
|
332
|
-
border: 1px solid var(--
|
|
332
|
+
border: 1px solid var(--color-border, #d0d7de);
|
|
333
333
|
padding: 6px 12px;
|
|
334
334
|
text-align: left;
|
|
335
335
|
}
|
|
336
336
|
|
|
337
337
|
.expandedPreview th {
|
|
338
|
-
background: var(--
|
|
338
|
+
background: var(--color-background-muted, #f6f8fa);
|
|
339
339
|
font-weight: 600;
|
|
340
340
|
}
|
|
341
341
|
|
|
342
342
|
.expandedPreview hr {
|
|
343
343
|
border: none;
|
|
344
|
-
border-top: 1px solid var(--
|
|
344
|
+
border-top: 1px solid var(--color-border, #d0d7de);
|
|
345
345
|
margin: 16px 0;
|
|
346
346
|
}
|
|
347
347
|
|
|
@@ -365,7 +365,7 @@
|
|
|
365
365
|
height: 100%;
|
|
366
366
|
min-height: 0;
|
|
367
367
|
overflow: hidden;
|
|
368
|
-
background: var(--
|
|
368
|
+
background: var(--color-background, #ffffff);
|
|
369
369
|
}
|
|
370
370
|
|
|
371
371
|
.expandedEditor {
|
|
@@ -380,10 +380,10 @@
|
|
|
380
380
|
border: none;
|
|
381
381
|
outline: none;
|
|
382
382
|
resize: none;
|
|
383
|
-
background: var(--
|
|
383
|
+
background: var(--color-background, #ffffff);
|
|
384
384
|
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
385
385
|
font-size: 14px;
|
|
386
386
|
line-height: 1.6;
|
|
387
|
-
color: var(--
|
|
387
|
+
color: var(--color-foreground, #1f2328);
|
|
388
388
|
overflow: auto;
|
|
389
389
|
}
|
|
@@ -2,7 +2,6 @@ import { useState, useCallback, useEffect, useRef, forwardRef, useImperativeHand
|
|
|
2
2
|
import { readProp, promptSchema } from './widgetProps.js'
|
|
3
3
|
import { CopilotIcon, SquareFillIcon, CheckCircleIcon, XIcon } from '@primer/octicons-react'
|
|
4
4
|
import ResizeHandle from './ResizeHandle.jsx'
|
|
5
|
-
import { useWebGLSlot, Priority } from '../WebGLContextPool.jsx'
|
|
6
5
|
import styles from './PromptWidget.module.css'
|
|
7
6
|
|
|
8
7
|
function getBase() {
|
|
@@ -122,18 +121,6 @@ const PromptWidget = forwardRef(function PromptWidget({ id, props, onUpdate, res
|
|
|
122
121
|
const termDisposedRef = useRef(false)
|
|
123
122
|
const textareaRef = useRef(null)
|
|
124
123
|
|
|
125
|
-
// ── WebGL context pool integration ──
|
|
126
|
-
// Only request a live slot when the output terminal is actually shown
|
|
127
|
-
const { isLive, setPriority } = useWebGLSlot(id)
|
|
128
|
-
|
|
129
|
-
useEffect(() => {
|
|
130
|
-
if (showOutput && execStatus !== 'idle') {
|
|
131
|
-
setPriority(Priority.VISIBLE)
|
|
132
|
-
} else {
|
|
133
|
-
setPriority(Priority.OFFSCREEN)
|
|
134
|
-
}
|
|
135
|
-
}, [showOutput, execStatus, setPriority])
|
|
136
|
-
|
|
137
124
|
const onUpdateRef = useRef(onUpdate)
|
|
138
125
|
useEffect(() => { onUpdateRef.current = onUpdate }, [onUpdate])
|
|
139
126
|
|
|
@@ -304,9 +291,8 @@ const PromptWidget = forwardRef(function PromptWidget({ id, props, onUpdate, res
|
|
|
304
291
|
}
|
|
305
292
|
}, [onUpdate])
|
|
306
293
|
|
|
307
|
-
// Embedded read-only terminal
|
|
294
|
+
// Embedded read-only terminal — created when the prompt has an active session
|
|
308
295
|
useEffect(() => {
|
|
309
|
-
if (!isLive) return
|
|
310
296
|
if (!showOutput || execStatus === 'idle') return
|
|
311
297
|
if (!termContainerRef.current) return
|
|
312
298
|
|
|
@@ -376,7 +362,7 @@ const PromptWidget = forwardRef(function PromptWidget({ id, props, onUpdate, res
|
|
|
376
362
|
termRef.current = null
|
|
377
363
|
wsRef.current = null
|
|
378
364
|
}
|
|
379
|
-
}, [
|
|
365
|
+
}, [showOutput, execStatus, id, width, height])
|
|
380
366
|
|
|
381
367
|
const isPending = execStatus === 'pending'
|
|
382
368
|
const isDone = execStatus === 'done'
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/* ── Loom-style prompt widget ── */
|
|
2
2
|
|
|
3
3
|
.wrapper {
|
|
4
|
-
background: var(--
|
|
5
|
-
border: 1px solid var(--
|
|
4
|
+
background: var(--color-background, #fff);
|
|
5
|
+
border: 1px solid var(--color-border, #d0d7de);
|
|
6
6
|
border-radius: 16px;
|
|
7
7
|
padding: 20px;
|
|
8
8
|
min-width: 200px;
|
|
9
|
-
font-family: var(--
|
|
9
|
+
font-family: var(--font-sans, -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif);
|
|
10
10
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08), 0 0 1px rgba(0, 0, 0, 0.06);
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -23,24 +23,24 @@
|
|
|
23
23
|
width: 32px;
|
|
24
24
|
height: 32px;
|
|
25
25
|
border-radius: 50%;
|
|
26
|
-
background: var(--
|
|
26
|
+
background: var(--color-background-neutral-muted, #eaeef2);
|
|
27
27
|
display: flex;
|
|
28
28
|
align-items: center;
|
|
29
29
|
justify-content: center;
|
|
30
30
|
flex-shrink: 0;
|
|
31
|
-
color: var(--
|
|
31
|
+
color: var(--color-foreground-muted, #636c76);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
.avatarDone {
|
|
35
|
-
background: var(--
|
|
36
|
-
color: var(--
|
|
35
|
+
background: var(--color-background-success-muted, #dafbe1);
|
|
36
|
+
color: var(--color-foreground-success, #1a7f37);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
.textarea {
|
|
40
40
|
flex: 1;
|
|
41
41
|
border: none;
|
|
42
42
|
background: transparent;
|
|
43
|
-
color: var(--
|
|
43
|
+
color: var(--color-foreground, #1f2328);
|
|
44
44
|
font-size: 14px;
|
|
45
45
|
font-family: inherit;
|
|
46
46
|
line-height: 1.5;
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
.textarea::placeholder {
|
|
58
|
-
color: var(--
|
|
58
|
+
color: var(--color-foreground-muted, #636c76);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
/* ── Toolbar: icons + submit ── */
|
|
@@ -72,9 +72,9 @@
|
|
|
72
72
|
font-size: 12px;
|
|
73
73
|
padding: 4px 14px;
|
|
74
74
|
border-radius: 6px;
|
|
75
|
-
border: 1px solid var(--
|
|
76
|
-
background: var(--
|
|
77
|
-
color: var(--
|
|
75
|
+
border: 1px solid var(--color-border, #d0d7de);
|
|
76
|
+
background: var(--color-background, #fff);
|
|
77
|
+
color: var(--color-foreground-muted, #636c76);
|
|
78
78
|
cursor: pointer;
|
|
79
79
|
white-space: nowrap;
|
|
80
80
|
font-weight: 500;
|
|
@@ -82,8 +82,8 @@
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
.submitBtn:hover:not(:disabled) {
|
|
85
|
-
background: var(--
|
|
86
|
-
color: var(--
|
|
85
|
+
background: var(--color-background-neutral-muted, rgba(175, 184, 193, 0.2));
|
|
86
|
+
color: var(--color-foreground, #1f2328);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
.submitBtn:disabled {
|
|
@@ -96,9 +96,9 @@
|
|
|
96
96
|
.errorText {
|
|
97
97
|
margin: 0 0 12px;
|
|
98
98
|
padding: 6px 10px;
|
|
99
|
-
background: var(--
|
|
99
|
+
background: var(--color-background-danger-muted, #ffebe9);
|
|
100
100
|
border-radius: 8px;
|
|
101
|
-
color: var(--
|
|
101
|
+
color: var(--color-foreground-danger, #cf222e);
|
|
102
102
|
font-size: 12px;
|
|
103
103
|
line-height: 1.4;
|
|
104
104
|
overflow: hidden;
|
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
|
|
123
123
|
.pendingText {
|
|
124
124
|
font-size: 14px;
|
|
125
|
-
color: var(--
|
|
125
|
+
color: var(--color-foreground, #1f2328);
|
|
126
126
|
line-height: 1.5;
|
|
127
127
|
margin: 0;
|
|
128
128
|
padding-top: 4px;
|
|
@@ -136,7 +136,7 @@
|
|
|
136
136
|
|
|
137
137
|
.pendingHint {
|
|
138
138
|
font-size: 12px;
|
|
139
|
-
color: var(--
|
|
139
|
+
color: var(--color-foreground-muted, #636c76);
|
|
140
140
|
margin: 0;
|
|
141
141
|
}
|
|
142
142
|
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
border: none;
|
|
150
150
|
border-radius: 6px;
|
|
151
151
|
cursor: pointer;
|
|
152
|
-
color: var(--
|
|
152
|
+
color: var(--color-foreground-accent, #0969da);
|
|
153
153
|
transition: background 0.15s;
|
|
154
154
|
position: relative;
|
|
155
155
|
width: 24px;
|
|
@@ -157,18 +157,18 @@
|
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
.cancelBtn:hover {
|
|
160
|
-
background: var(--
|
|
160
|
+
background: var(--color-background-neutral-muted, rgba(175, 184, 193, 0.2));
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
.spinnerSvg {
|
|
164
164
|
animation: spin 1s linear infinite;
|
|
165
|
-
color: var(--
|
|
165
|
+
color: var(--color-foreground-accent, #0969da);
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
.stopIcon {
|
|
169
169
|
display: none;
|
|
170
170
|
position: absolute;
|
|
171
|
-
color: var(--
|
|
171
|
+
color: var(--color-foreground-danger, #cf222e);
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
.cancelBtn:hover .spinnerSvg {
|
|
@@ -200,7 +200,7 @@
|
|
|
200
200
|
|
|
201
201
|
.doneText {
|
|
202
202
|
font-size: 14px;
|
|
203
|
-
color: var(--
|
|
203
|
+
color: var(--color-foreground, #1f2328);
|
|
204
204
|
line-height: 1.5;
|
|
205
205
|
margin: 0;
|
|
206
206
|
padding-top: 4px;
|
|
@@ -210,8 +210,8 @@
|
|
|
210
210
|
align-self: flex-end;
|
|
211
211
|
padding: 4px 14px;
|
|
212
212
|
background: transparent;
|
|
213
|
-
color: var(--
|
|
214
|
-
border: 1px solid var(--
|
|
213
|
+
color: var(--color-foreground-accent, #0969da);
|
|
214
|
+
border: 1px solid var(--color-border, #d0d7de);
|
|
215
215
|
border-radius: 6px;
|
|
216
216
|
font-size: 12px;
|
|
217
217
|
cursor: pointer;
|
|
@@ -219,14 +219,14 @@
|
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
.resetBtn:hover {
|
|
222
|
-
background: var(--
|
|
222
|
+
background: var(--color-background-muted, #f6f8fa);
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
/* ── Inline terminal output (flush to bottom edge) ── */
|
|
226
226
|
|
|
227
227
|
.terminalArea {
|
|
228
228
|
margin: 16px -20px -20px;
|
|
229
|
-
border-top: 1px solid var(--
|
|
229
|
+
border-top: 1px solid var(--color-border-muted, #d8dee4);
|
|
230
230
|
overflow: hidden;
|
|
231
231
|
border-radius: 0 0 16px 16px;
|
|
232
232
|
}
|
|
@@ -236,14 +236,14 @@
|
|
|
236
236
|
align-items: center;
|
|
237
237
|
justify-content: space-between;
|
|
238
238
|
padding: 4px 10px;
|
|
239
|
-
background: var(--
|
|
240
|
-
border-bottom: 1px solid var(--
|
|
239
|
+
background: var(--color-background-muted, #f6f8fa);
|
|
240
|
+
border-bottom: 1px solid var(--color-border-muted, #d8dee4);
|
|
241
241
|
}
|
|
242
242
|
|
|
243
243
|
.terminalLabel {
|
|
244
244
|
font-size: 11px;
|
|
245
245
|
font-weight: 600;
|
|
246
|
-
color: var(--
|
|
246
|
+
color: var(--color-foreground-muted, #636c76);
|
|
247
247
|
text-transform: uppercase;
|
|
248
248
|
letter-spacing: 0.5px;
|
|
249
249
|
}
|
|
@@ -257,13 +257,13 @@
|
|
|
257
257
|
border: none;
|
|
258
258
|
border-radius: 4px;
|
|
259
259
|
cursor: pointer;
|
|
260
|
-
color: var(--
|
|
260
|
+
color: var(--color-foreground-muted, #636c76);
|
|
261
261
|
transition: background 0.15s;
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
.terminalClose:hover {
|
|
265
|
-
background: var(--
|
|
266
|
-
color: var(--
|
|
265
|
+
background: var(--color-background-neutral-muted, rgba(175, 184, 193, 0.2));
|
|
266
|
+
color: var(--color-foreground, #1f2328);
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
.terminalContainer {
|
|
@@ -7,6 +7,7 @@ import { readProp, prototypeEmbedSchema } from './widgetProps.js'
|
|
|
7
7
|
import { getEmbedChromeVars } from './embedTheme.js'
|
|
8
8
|
import { useIframeDevLogs } from './iframeDevLogs.js'
|
|
9
9
|
import { findAllConnectedSplitTargets, getSplitPaneLabel, buildPaneForWidget, buildSplitLayout } from './expandUtils.js'
|
|
10
|
+
import { normalizeLegacyEmbedSrc } from './normalizeLegacyEmbedSrc.js'
|
|
10
11
|
import ExpandedPane from './ExpandedPane.jsx'
|
|
11
12
|
import styles from './PrototypeEmbed.module.css'
|
|
12
13
|
import overlayStyles from './embedOverlay.module.css'
|
|
@@ -46,27 +47,87 @@ function resolveCanvasThemeFromStorage() {
|
|
|
46
47
|
const HEADER_HEIGHT = 37
|
|
47
48
|
|
|
48
49
|
export default forwardRef(function PrototypeEmbed({ id: widgetId, props, onUpdate, resizable }, ref) {
|
|
49
|
-
const
|
|
50
|
+
const rawStoredSrc = readProp(props, 'src', prototypeEmbedSchema)
|
|
51
|
+
const src = normalizeLegacyEmbedSrc(rawStoredSrc)
|
|
50
52
|
const width = readProp(props, 'width', prototypeEmbedSchema) || 800
|
|
51
53
|
const height = readProp(props, 'height', prototypeEmbedSchema) || 600
|
|
52
54
|
const zoom = readProp(props, 'zoom', prototypeEmbedSchema) || 100
|
|
53
55
|
const label = readProp(props, 'label', prototypeEmbedSchema) || src
|
|
54
56
|
|
|
57
|
+
// Self-healing write-back: if normalization changed the src, persist the
|
|
58
|
+
// clean form so the canvas JSONL stops carrying the broken URL. Without
|
|
59
|
+
// this, every render keeps recovering at runtime but the file stays
|
|
60
|
+
// poisoned and any consumer on an older library still sees the bug.
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (!onUpdate) return
|
|
63
|
+
if (typeof rawStoredSrc !== 'string' || rawStoredSrc === src) return
|
|
64
|
+
onUpdate({ src })
|
|
65
|
+
}, [rawStoredSrc, src, onUpdate])
|
|
66
|
+
|
|
55
67
|
const basePath = (import.meta.env.BASE_URL || '/').replace(/\/$/, '')
|
|
56
68
|
const baseSegment = basePath.replace(/^\//, '')
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
69
|
+
// Two URLs are derived from `src`:
|
|
70
|
+
// - rawSrc — the iframe URL. In DEV this routes through the isolated
|
|
71
|
+
// prototypes.html entry so a broken prototype's transform/HMR errors
|
|
72
|
+
// stay inside the iframe (see .agents/plans/vite-isolation.md):
|
|
73
|
+
// /MyProto/SignupForm becomes prototypes.html/MyProto/SignupForm.
|
|
74
|
+
// Routing happens in the *pathname* (createBrowserRouter), not in the
|
|
75
|
+
// hash, so the hash and search stay free for storyboard URL state
|
|
76
|
+
// (`?flow=...` and `#key=value` overrides). In PROD it loads the
|
|
77
|
+
// prototype path directly through the canvas SPA (prototypes.html is
|
|
78
|
+
// a build-time isolation artifact that must not leak into deployed URLs).
|
|
79
|
+
// - externalSrc — the URL used by "Open in new tab". Always direct
|
|
80
|
+
// (`${basePath}/<protoPath>`), never prototypes.html, even in dev —
|
|
81
|
+
// opening prototypes.html/... in a fresh tab is a leaky surprise
|
|
82
|
+
// for users navigating from the canvas.
|
|
83
|
+
// External http(s) URLs are left alone in both cases. basePath already
|
|
84
|
+
// carries the /branch--xxx/ prefix on branch deploys, so both work for
|
|
85
|
+
// main and branch deploys alike.
|
|
86
|
+
const { rawSrc, externalSrc } = useMemo(() => {
|
|
87
|
+
if (!src) return { rawSrc: '', externalSrc: '' }
|
|
88
|
+
if (/^https?:\/\//.test(src)) return { rawSrc: src, externalSrc: src }
|
|
60
89
|
const cleaned = src.replace(/^\/branch--[^/]+/, '')
|
|
61
|
-
|
|
62
|
-
if (baseSegment && cleaned.startsWith(
|
|
63
|
-
|
|
90
|
+
let normalized
|
|
91
|
+
if (baseSegment && cleaned.startsWith(basePath)) normalized = cleaned
|
|
92
|
+
else if (baseSegment && cleaned.startsWith(baseSegment)) normalized = `/${cleaned}`
|
|
93
|
+
else normalized = `${basePath}${cleaned}`
|
|
94
|
+
// Strip basePath so we can split path/query/hash cleanly and
|
|
95
|
+
// re-anchor for whichever mode we're in. Any pre-existing #hash on
|
|
96
|
+
// the original src is preserved.
|
|
97
|
+
const withoutBase = baseSegment && normalized.startsWith(basePath)
|
|
98
|
+
? normalized.slice(basePath.length) || '/'
|
|
99
|
+
: normalized
|
|
100
|
+
const hashIdx = withoutBase.indexOf('#')
|
|
101
|
+
const innerHash = hashIdx >= 0 ? withoutBase.slice(hashIdx + 1) : ''
|
|
102
|
+
const pathAndQuery = hashIdx >= 0 ? withoutBase.slice(0, hashIdx) : withoutBase
|
|
103
|
+
const routePath = pathAndQuery.startsWith('/') ? pathAndQuery : `/${pathAndQuery}`
|
|
104
|
+
const suffix = innerHash ? `#${innerHash}` : ''
|
|
105
|
+
// Direct path through the canvas SPA — used in prod for the iframe and
|
|
106
|
+
// always for "Open in new tab".
|
|
107
|
+
const directUrl = `${basePath}${routePath}${suffix}`
|
|
108
|
+
if (import.meta.env.PROD) {
|
|
109
|
+
return { rawSrc: directUrl, externalSrc: directUrl }
|
|
110
|
+
}
|
|
111
|
+
// Dev iframe: prototypes.html with the route as a sub-path. The library
|
|
112
|
+
// middleware (`data-plugin.js`) serves the same HTML shell for
|
|
113
|
+
// `/prototypes.html/*` so a hard reload / open-in-new-tab works. The
|
|
114
|
+
// prototype name (first path segment) narrows getRoutesForProto so a
|
|
115
|
+
// broken sibling prototype can't poison the lazy() chain. Hash and
|
|
116
|
+
// search stay attached so storyboard URL state (`#key=value` overrides,
|
|
117
|
+
// `?flow=name`) survives the redirect through the isolation entry.
|
|
118
|
+
const iframeUrl = `${basePath}/prototypes.html${routePath}${suffix}`
|
|
119
|
+
return { rawSrc: iframeUrl, externalSrc: directUrl }
|
|
64
120
|
}, [src, basePath, baseSegment])
|
|
65
121
|
|
|
66
122
|
const scale = zoom / 100
|
|
67
123
|
|
|
68
124
|
const [editing, setEditing] = useState(false)
|
|
69
125
|
const [interactive, setInteractive] = useState(false)
|
|
126
|
+
// Track which src URL has fired its onLoad callback so we can overlay a
|
|
127
|
+
// spinner while a new iframe is fetching. Stored as the URL itself (not
|
|
128
|
+
// a boolean) so changing src naturally invalidates the loaded state
|
|
129
|
+
// without an effect.
|
|
130
|
+
const [loadedSrc, setLoadedSrc] = useState(null)
|
|
70
131
|
const [expandOverride, setExpandOverride, clearExpandOverride] = useOverride(`_prototype_expanded_${widgetId}`)
|
|
71
132
|
const expandMode = expandOverride === 'immersive' ? 'immersive' : expandOverride === 'split' ? 'split' : expandOverride === 'single' ? 'single' : null
|
|
72
133
|
const setExpandMode = useCallback((mode) => {
|
|
@@ -268,7 +329,10 @@ export default forwardRef(function PrototypeEmbed({ id: widgetId, props, onUpdat
|
|
|
268
329
|
function handleMessage(e) {
|
|
269
330
|
if (e.source !== iframeRef.current?.contentWindow) return
|
|
270
331
|
if (e.data?.type !== 'storyboard:embed:navigate') return
|
|
271
|
-
|
|
332
|
+
// Defensive: older consumer embeds reported `/prototypes.html#/route`
|
|
333
|
+
// here (loader path + hash). Normalize to the inner route so we never
|
|
334
|
+
// persist the broken form.
|
|
335
|
+
const newSrc = normalizeLegacyEmbedSrc(e.data.src)
|
|
272
336
|
if (newSrc && newSrc !== src) {
|
|
273
337
|
const originalSrc = readProp(props, 'originalSrc', prototypeEmbedSchema)
|
|
274
338
|
onUpdate?.({ src: newSrc, originalSrc: originalSrc || src })
|
|
@@ -295,7 +359,7 @@ export default forwardRef(function PrototypeEmbed({ id: widgetId, props, onUpdat
|
|
|
295
359
|
} else if (actionId === 'split-screen') {
|
|
296
360
|
setExpandMode('split')
|
|
297
361
|
} else if (actionId === 'open-external') {
|
|
298
|
-
if (
|
|
362
|
+
if (externalSrc) window.open(externalSrc, '_blank', 'noopener')
|
|
299
363
|
} else if (actionId === 'refresh-frame') {
|
|
300
364
|
const iframe = iframeRef.current
|
|
301
365
|
if (iframe) {
|
|
@@ -310,7 +374,7 @@ export default forwardRef(function PrototypeEmbed({ id: widgetId, props, onUpdat
|
|
|
310
374
|
onUpdate?.({ zoom: Math.max(25, zoom - step) })
|
|
311
375
|
}
|
|
312
376
|
},
|
|
313
|
-
}), [
|
|
377
|
+
}), [externalSrc, zoom, onUpdate])
|
|
314
378
|
|
|
315
379
|
function handlePickRoute(route) {
|
|
316
380
|
onUpdate?.({ src: route })
|
|
@@ -340,12 +404,18 @@ export default forwardRef(function PrototypeEmbed({ id: widgetId, props, onUpdat
|
|
|
340
404
|
<WidgetWrapper>
|
|
341
405
|
<div
|
|
342
406
|
ref={embedRef}
|
|
343
|
-
className=
|
|
344
|
-
style={{
|
|
407
|
+
className="relative overflow-hidden rounded-lg bg-background shadow-[0_4px_16px_rgba(0,0,0,0.08)]"
|
|
408
|
+
style={{
|
|
409
|
+
width,
|
|
410
|
+
height,
|
|
411
|
+
...chromeVars,
|
|
412
|
+
}}
|
|
345
413
|
>
|
|
346
|
-
<div
|
|
347
|
-
|
|
348
|
-
|
|
414
|
+
<div
|
|
415
|
+
className="flex items-center gap-1.5 px-2.5 py-2.5 text-xs font-medium whitespace-nowrap overflow-hidden text-ellipsis select-none border-b border-border-muted bg-background-muted text-foreground-muted"
|
|
416
|
+
>
|
|
417
|
+
<span className="inline-flex flex-shrink-0"><CollageFrameIcon size={16} /></span>
|
|
418
|
+
<span className="overflow-hidden text-ellipsis">{prototypeTitle}</span>
|
|
349
419
|
</div>
|
|
350
420
|
{editing ? (
|
|
351
421
|
<div
|
|
@@ -420,9 +490,14 @@ export default forwardRef(function PrototypeEmbed({ id: widgetId, props, onUpdat
|
|
|
420
490
|
}}
|
|
421
491
|
title={`${prototypeTitle} prototype`}
|
|
422
492
|
sandbox="allow-same-origin allow-scripts allow-forms allow-popups"
|
|
423
|
-
|
|
493
|
+
onLoad={(e) => { e.target.blur(); setLoadedSrc(effectiveSrc) }}
|
|
424
494
|
/>
|
|
425
|
-
|
|
495
|
+
{loadedSrc !== effectiveSrc && (
|
|
496
|
+
<div className={styles.placeholder} aria-hidden="true">
|
|
497
|
+
<div className={styles.spinner} />
|
|
498
|
+
</div>
|
|
499
|
+
)}
|
|
500
|
+
</div>
|
|
426
501
|
{!interactive && !expanded && (
|
|
427
502
|
<div
|
|
428
503
|
className={overlayStyles.interactOverlay}
|