@dfosco/storyboard-core 4.2.0-beta.3 → 4.2.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.
Files changed (419) hide show
  1. package/commandpalette.config.json +109 -24
  2. package/dist/storyboard-ui.css +1 -1
  3. package/dist/storyboard-ui.js +16711 -27239
  4. package/dist/storyboard-ui.js.map +1 -1
  5. package/dist/tailwind.css +1 -1
  6. package/package.json +5 -2
  7. package/scaffold/agents/prompt-agent.agent.md +181 -0
  8. package/scaffold/agents/terminal-agent.agent.md +351 -0
  9. package/scaffold/codex/config.toml +246 -0
  10. package/scaffold/manifest.json +5 -10
  11. package/scaffold/skills/canvas/SKILL.md +5 -4
  12. package/scaffold/skills/ship/SKILL.md +1 -1
  13. package/scaffold/storyboard.config.json +11 -1
  14. package/src/ActionMenuButton.jsx +103 -0
  15. package/src/AutosyncMenuButton.css +67 -0
  16. package/src/AutosyncMenuButton.jsx +242 -0
  17. package/src/BranchSelect.jsx +29 -0
  18. package/src/BranchSelect.module.css +30 -0
  19. package/src/CanvasAgentsMenu.jsx +89 -0
  20. package/src/CanvasCreateMenu.jsx +611 -0
  21. package/src/CanvasSnap.css +27 -0
  22. package/src/CanvasSnap.jsx +51 -0
  23. package/src/CanvasUndoRedo.css +36 -0
  24. package/src/CanvasUndoRedo.jsx +62 -0
  25. package/src/CanvasZoomControl.css +53 -0
  26. package/src/CanvasZoomControl.jsx +49 -0
  27. package/src/CanvasZoomToFit.css +18 -0
  28. package/src/CanvasZoomToFit.jsx +26 -0
  29. package/src/CommandMenu.css +8 -0
  30. package/src/CommandMenu.jsx +287 -0
  31. package/src/CommandPalette.jsx +35 -0
  32. package/src/CommandPaletteTrigger.jsx +25 -0
  33. package/src/CommentsMenuButton.jsx +40 -0
  34. package/src/CoreUIBar.css +47 -0
  35. package/src/CoreUIBar.jsx +858 -0
  36. package/src/CreateMenuButton.jsx +117 -0
  37. package/src/HideChromeTrigger.jsx +40 -0
  38. package/src/InspectorPanel.css +109 -0
  39. package/src/InspectorPanel.jsx +632 -0
  40. package/src/PwaInstallBanner.css +42 -0
  41. package/src/PwaInstallBanner.jsx +124 -0
  42. package/src/SidePanel.jsx +261 -0
  43. package/src/ThemeMenuButton.jsx +139 -0
  44. package/src/autosync/server.js +202 -5
  45. package/src/autosync/server.test.js +111 -0
  46. package/src/canvas/__tests__/agent-integration.test.js +596 -0
  47. package/src/canvas/__tests__/helpers/browser.js +95 -0
  48. package/src/canvas/__tests__/helpers/canvas-api.js +129 -0
  49. package/src/canvas/__tests__/helpers/perf.js +118 -0
  50. package/src/canvas/__tests__/helpers/setup.js +176 -0
  51. package/src/canvas/__tests__/helpers/tmux.js +130 -0
  52. package/src/canvas/__tests__/helpers/transcript.js +132 -0
  53. package/src/canvas/__tests__/terminal-integration.test.js +177 -0
  54. package/src/canvas/hot-pool.js +756 -0
  55. package/src/canvas/materializer.js +31 -0
  56. package/src/canvas/materializer.test.js +56 -0
  57. package/src/canvas/selectedWidgets.js +65 -7
  58. package/src/canvas/server.js +1802 -22
  59. package/src/canvas/server.test.js +239 -0
  60. package/src/canvas/terminal-config.js +330 -0
  61. package/src/canvas/terminal-registry.js +41 -3
  62. package/src/canvas/terminal-server.js +1098 -37
  63. package/src/canvas/writeGuard.js +51 -3
  64. package/src/canvasConfig.js +67 -1
  65. package/src/canvasConfig.test.js +79 -1
  66. package/src/cli/agent.js +85 -0
  67. package/src/cli/branch.js +232 -0
  68. package/src/cli/canvasAdd.js +61 -14
  69. package/src/cli/canvasBatch.js +98 -0
  70. package/src/cli/canvasBounds.js +1 -1
  71. package/src/cli/canvasRead.js +1 -1
  72. package/src/cli/canvasUpdate.js +179 -0
  73. package/src/cli/compact.js +0 -2
  74. package/src/cli/create.js +40 -16
  75. package/src/cli/dev.js +158 -84
  76. package/src/cli/exit.js +23 -24
  77. package/src/cli/index.js +55 -2
  78. package/src/cli/proxy.js +96 -37
  79. package/src/cli/schemas.js +22 -4
  80. package/src/cli/server.js +149 -26
  81. package/src/cli/serverUrl.js +8 -3
  82. package/src/cli/sessions.js +133 -7
  83. package/src/cli/setup.js +138 -12
  84. package/src/cli/terminal-commands.js +20 -9
  85. package/src/cli/terminal-messaging.js +231 -0
  86. package/src/cli/terminal-welcome.js +449 -34
  87. package/src/cli/updateVersion.js +1 -1
  88. package/src/commandActions.js +1 -0
  89. package/src/commandPaletteConfig.js +9 -0
  90. package/src/comments/auth.js +2 -1
  91. package/src/comments/ui/AuthModal.jsx +114 -0
  92. package/src/comments/ui/CommentWindow.jsx +329 -0
  93. package/src/comments/ui/CommentsDrawer.jsx +102 -0
  94. package/src/comments/ui/Composer.jsx +64 -0
  95. package/src/comments/ui/authModal.test.js +1 -1
  96. package/src/comments/ui/commentWindow.js +16 -17
  97. package/src/comments/ui/commentsDrawer.js +25 -26
  98. package/src/comments/ui/composer.js +23 -24
  99. package/src/comments/ui/index.js +2 -3
  100. package/src/configSchema.js +59 -1
  101. package/src/configStore.js +161 -0
  102. package/src/core-ui-colors.css +12 -0
  103. package/src/devtools.js +17 -19
  104. package/src/devtools.test.js +18 -9
  105. package/src/featureFlags.js +12 -5
  106. package/src/fuzzySearch.test.js +10 -0
  107. package/src/index.js +15 -3
  108. package/src/lib/components/ui/alert/alert-action.jsx +11 -0
  109. package/src/lib/components/ui/alert/alert-description.jsx +11 -0
  110. package/src/lib/components/ui/alert/alert-title.jsx +11 -0
  111. package/src/lib/components/ui/alert/alert.jsx +25 -0
  112. package/src/lib/components/ui/alert/index.js +15 -15
  113. package/src/lib/components/ui/avatar/avatar-badge.jsx +22 -0
  114. package/src/lib/components/ui/avatar/avatar-fallback.jsx +18 -0
  115. package/src/lib/components/ui/avatar/avatar-group-count.jsx +19 -0
  116. package/src/lib/components/ui/avatar/avatar-group.jsx +19 -0
  117. package/src/lib/components/ui/avatar/avatar-image.jsx +15 -0
  118. package/src/lib/components/ui/avatar/avatar.jsx +19 -0
  119. package/src/lib/components/ui/avatar/index.js +20 -20
  120. package/src/lib/components/ui/badge/badge.jsx +31 -0
  121. package/src/lib/components/ui/badge/index.js +2 -2
  122. package/src/lib/components/ui/button/button.jsx +100 -0
  123. package/src/lib/components/ui/button/index.js +9 -9
  124. package/src/lib/components/ui/card/card-action.jsx +11 -0
  125. package/src/lib/components/ui/card/card-content.jsx +11 -0
  126. package/src/lib/components/ui/card/card-description.jsx +11 -0
  127. package/src/lib/components/ui/card/card-footer.jsx +11 -0
  128. package/src/lib/components/ui/card/card-header.jsx +19 -0
  129. package/src/lib/components/ui/card/card-title.jsx +11 -0
  130. package/src/lib/components/ui/card/card.jsx +17 -0
  131. package/src/lib/components/ui/card/index.js +23 -23
  132. package/src/lib/components/ui/checkbox/checkbox.jsx +29 -0
  133. package/src/lib/components/ui/checkbox/index.js +5 -5
  134. package/src/lib/components/ui/collapsible/collapsible-content.jsx +7 -0
  135. package/src/lib/components/ui/collapsible/collapsible-trigger.jsx +7 -0
  136. package/src/lib/components/ui/collapsible/collapsible.jsx +7 -0
  137. package/src/lib/components/ui/collapsible/index.js +11 -11
  138. package/src/lib/components/ui/dialog/dialog-close.jsx +7 -0
  139. package/src/lib/components/ui/dialog/dialog-content.jsx +34 -0
  140. package/src/lib/components/ui/dialog/dialog-description.jsx +15 -0
  141. package/src/lib/components/ui/dialog/dialog-footer.jsx +23 -0
  142. package/src/lib/components/ui/dialog/dialog-header.jsx +11 -0
  143. package/src/lib/components/ui/dialog/dialog-overlay.jsx +15 -0
  144. package/src/lib/components/ui/dialog/dialog-portal.jsx +4 -0
  145. package/src/lib/components/ui/dialog/dialog-title.jsx +15 -0
  146. package/src/lib/components/ui/dialog/dialog-trigger.jsx +7 -0
  147. package/src/lib/components/ui/dialog/dialog.jsx +4 -0
  148. package/src/lib/components/ui/dialog/index.js +32 -32
  149. package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.jsx +8 -0
  150. package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.jsx +30 -0
  151. package/src/lib/components/ui/dropdown-menu/dropdown-menu-content.jsx +22 -0
  152. package/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.jsx +16 -0
  153. package/src/lib/components/ui/dropdown-menu/dropdown-menu-group.jsx +7 -0
  154. package/src/lib/components/ui/dropdown-menu/dropdown-menu-item.jsx +20 -0
  155. package/src/lib/components/ui/dropdown-menu/dropdown-menu-label.jsx +17 -0
  156. package/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.jsx +4 -0
  157. package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.jsx +7 -0
  158. package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.jsx +29 -0
  159. package/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.jsx +15 -0
  160. package/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.jsx +16 -0
  161. package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.jsx +15 -0
  162. package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.jsx +23 -0
  163. package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.jsx +4 -0
  164. package/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.jsx +7 -0
  165. package/src/lib/components/ui/dropdown-menu/dropdown-menu.jsx +4 -0
  166. package/src/lib/components/ui/dropdown-menu/index.js +52 -52
  167. package/src/lib/components/ui/input/index.js +5 -5
  168. package/src/lib/components/ui/input/input.jsx +19 -0
  169. package/src/lib/components/ui/label/index.js +5 -5
  170. package/src/lib/components/ui/label/label.jsx +19 -0
  171. package/src/lib/components/ui/panel/index.js +21 -21
  172. package/src/lib/components/ui/panel/panel-body.jsx +11 -0
  173. package/src/lib/components/ui/panel/panel-close.jsx +16 -0
  174. package/src/lib/components/ui/panel/panel-content.jsx +29 -0
  175. package/src/lib/components/ui/panel/panel-footer.jsx +11 -0
  176. package/src/lib/components/ui/panel/panel-header.jsx +11 -0
  177. package/src/lib/components/ui/panel/panel-title.jsx +12 -0
  178. package/src/lib/components/ui/panel/panel.jsx +4 -0
  179. package/src/lib/components/ui/popover/index.js +26 -26
  180. package/src/lib/components/ui/popover/popover-close.jsx +7 -0
  181. package/src/lib/components/ui/popover/popover-content.jsx +22 -0
  182. package/src/lib/components/ui/popover/popover-description.jsx +11 -0
  183. package/src/lib/components/ui/popover/popover-header.jsx +11 -0
  184. package/src/lib/components/ui/popover/popover-portal.jsx +4 -0
  185. package/src/lib/components/ui/popover/popover-title.jsx +11 -0
  186. package/src/lib/components/ui/popover/popover-trigger.jsx +8 -0
  187. package/src/lib/components/ui/popover/popover.jsx +4 -0
  188. package/src/lib/components/ui/searchable-list.jsx +160 -0
  189. package/src/lib/components/ui/select/index.js +35 -35
  190. package/src/lib/components/ui/select/select-content.jsx +30 -0
  191. package/src/lib/components/ui/select/select-group-heading.jsx +17 -0
  192. package/src/lib/components/ui/select/select-group.jsx +15 -0
  193. package/src/lib/components/ui/select/select-item.jsx +26 -0
  194. package/src/lib/components/ui/select/select-label.jsx +11 -0
  195. package/src/lib/components/ui/select/select-portal.jsx +4 -0
  196. package/src/lib/components/ui/select/select-scroll-down-button.jsx +18 -0
  197. package/src/lib/components/ui/select/select-scroll-up-button.jsx +18 -0
  198. package/src/lib/components/ui/select/select-separator.jsx +15 -0
  199. package/src/lib/components/ui/select/select-trigger.jsx +25 -0
  200. package/src/lib/components/ui/select/select.jsx +4 -0
  201. package/src/lib/components/ui/separator/index.js +5 -5
  202. package/src/lib/components/ui/separator/separator.jsx +22 -0
  203. package/src/lib/components/ui/sheet/index.js +32 -32
  204. package/src/lib/components/ui/sheet/sheet-close.jsx +7 -0
  205. package/src/lib/components/ui/sheet/sheet-content.jsx +35 -0
  206. package/src/lib/components/ui/sheet/sheet-description.jsx +15 -0
  207. package/src/lib/components/ui/sheet/sheet-footer.jsx +11 -0
  208. package/src/lib/components/ui/sheet/sheet-header.jsx +11 -0
  209. package/src/lib/components/ui/sheet/sheet-overlay.jsx +15 -0
  210. package/src/lib/components/ui/sheet/sheet-portal.jsx +4 -0
  211. package/src/lib/components/ui/sheet/sheet-title.jsx +15 -0
  212. package/src/lib/components/ui/sheet/sheet-trigger.jsx +7 -0
  213. package/src/lib/components/ui/sheet/sheet.jsx +4 -0
  214. package/src/lib/components/ui/textarea/index.js +5 -5
  215. package/src/lib/components/ui/textarea/textarea.jsx +18 -0
  216. package/src/lib/components/ui/toggle/index.js +6 -9
  217. package/src/lib/components/ui/toggle/toggle.jsx +36 -0
  218. package/src/lib/components/ui/toggle-group/index.js +8 -8
  219. package/src/lib/components/ui/toggle-group/toggle-group-item.jsx +29 -0
  220. package/src/lib/components/ui/toggle-group/toggle-group.jsx +43 -0
  221. package/src/lib/components/ui/tooltip/index.js +3 -3
  222. package/src/lib/components/ui/tooltip/tooltip-content.jsx +21 -0
  223. package/src/lib/components/ui/tooltip/tooltip-trigger.jsx +23 -0
  224. package/src/lib/components/ui/tooltip/tooltip.jsx +11 -0
  225. package/src/lib/components/ui/trigger-button/index.js +3 -3
  226. package/src/lib/components/ui/trigger-button/trigger-button.css +38 -0
  227. package/src/lib/components/ui/trigger-button/trigger-button.jsx +63 -0
  228. package/src/logger/devLogger.js +238 -0
  229. package/src/logger/devLogger.test.js +193 -0
  230. package/src/modes.test.js +4 -4
  231. package/src/mountStoryboardCore.js +133 -35
  232. package/src/paletteProviders.js +3 -0
  233. package/src/paletteProviders.test.js +2 -2
  234. package/src/server/index.js +104 -40
  235. package/src/sidepanel.css +214 -0
  236. package/src/smoothCorners.js +1 -1
  237. package/src/styles/tailwind.css +1 -1
  238. package/src/svelte-plugin-ui/__tests__/ModeSwitch.test.ts +8 -8
  239. package/src/svelte-plugin-ui/__tests__/ToolbarShell.test.ts +11 -10
  240. package/src/svelte-plugin-ui/components/Icon.css +11 -0
  241. package/src/svelte-plugin-ui/components/Icon.jsx +281 -0
  242. package/src/svelte-plugin-ui/components/ModeSwitch.css +90 -0
  243. package/src/svelte-plugin-ui/components/ModeSwitch.jsx +47 -0
  244. package/src/svelte-plugin-ui/components/ToolbarShell.css +80 -0
  245. package/src/svelte-plugin-ui/components/ToolbarShell.jsx +84 -0
  246. package/src/svelte-plugin-ui/components/Viewfinder.css +412 -0
  247. package/src/svelte-plugin-ui/components/Viewfinder.jsx +513 -0
  248. package/src/svelte-plugin-ui/mount.ts +12 -16
  249. package/src/toolRegistry.js +4 -4
  250. package/src/toolbarConfigStore.js +30 -0
  251. package/src/tools/handlers/autosync.js +1 -1
  252. package/src/tools/handlers/canvasAddWidget.js +1 -1
  253. package/src/tools/handlers/canvasAgents.js +20 -0
  254. package/src/tools/handlers/canvasToolbar.js +8 -8
  255. package/src/tools/handlers/commandPalette.js +9 -0
  256. package/src/tools/handlers/comments.js +2 -2
  257. package/src/tools/handlers/create.js +1 -1
  258. package/src/tools/handlers/devtools.js +19 -3
  259. package/src/tools/handlers/devtools.test.js +38 -0
  260. package/src/tools/handlers/featureFlags.js +1 -1
  261. package/src/tools/handlers/flows.js +3 -3
  262. package/src/tools/handlers/hideChrome.js +9 -0
  263. package/src/tools/handlers/paletteTheme.js +35 -0
  264. package/src/tools/handlers/theme.js +1 -1
  265. package/src/tools/registry.js +4 -1
  266. package/src/tools/surfaces/commandList.js +3 -3
  267. package/src/tools/surfaces/mainToolbar.js +3 -3
  268. package/src/tools/surfaces/registry.js +4 -4
  269. package/src/ui/design-modes.ts +2 -2
  270. package/src/ui/viewfinder.ts +1 -1
  271. package/src/vite/server-plugin.js +243 -61
  272. package/src/workshop/features/createCanvas/CreateCanvasForm.jsx +260 -0
  273. package/src/workshop/features/createCanvas/index.js +1 -1
  274. package/src/workshop/features/createFlow/CreateFlowForm.jsx +334 -0
  275. package/src/workshop/features/createFlow/index.js +1 -1
  276. package/src/workshop/features/createPage/CreatePageForm.jsx +304 -0
  277. package/src/workshop/features/createPage/index.js +1 -1
  278. package/src/workshop/features/createPrototype/CreatePrototypeForm.jsx +289 -0
  279. package/src/workshop/features/createPrototype/index.js +1 -1
  280. package/src/workshop/features/createPrototype/server.js +98 -0
  281. package/src/workshop/features/createStory/CreateStoryForm.jsx +208 -0
  282. package/src/workshop/features/createStory/index.js +1 -1
  283. package/src/workshop/ui/WorkshopPanel.jsx +98 -0
  284. package/src/workshop/ui/mount.ts +1 -1
  285. package/src/worktree/port.js +48 -0
  286. package/src/worktree/serverRegistry.js +120 -0
  287. package/toolbar.config.json +93 -42
  288. package/widgets.config.json +580 -12
  289. package/scaffold/commandpalette.config.json +0 -4
  290. package/scaffold/toolbar.config.json +0 -4
  291. package/src/ActionMenuButton.svelte +0 -119
  292. package/src/AutosyncMenuButton.svelte +0 -397
  293. package/src/CanvasCreateMenu.svelte +0 -295
  294. package/src/CanvasSnap.svelte +0 -87
  295. package/src/CanvasUndoRedo.svelte +0 -108
  296. package/src/CanvasZoomControl.svelte +0 -111
  297. package/src/CanvasZoomToFit.svelte +0 -52
  298. package/src/CommandMenu.svelte +0 -249
  299. package/src/CommandPalette.svelte +0 -33
  300. package/src/CommentsMenuButton.svelte +0 -53
  301. package/src/CoreUIBar.svelte +0 -847
  302. package/src/CreateMenuButton.svelte +0 -133
  303. package/src/DocPanel.svelte +0 -299
  304. package/src/InspectorPanel.svelte +0 -745
  305. package/src/PwaInstallBanner.svelte +0 -124
  306. package/src/SidePanel.svelte +0 -480
  307. package/src/ThemeMenuButton.svelte +0 -132
  308. package/src/comments/ui/AuthModal.svelte +0 -108
  309. package/src/comments/ui/CommentWindow.svelte +0 -333
  310. package/src/comments/ui/CommentsDrawer.svelte +0 -96
  311. package/src/comments/ui/Composer.svelte +0 -65
  312. package/src/lib/components/ui/alert/alert-action.svelte +0 -19
  313. package/src/lib/components/ui/alert/alert-description.svelte +0 -22
  314. package/src/lib/components/ui/alert/alert-title.svelte +0 -22
  315. package/src/lib/components/ui/alert/alert.svelte +0 -38
  316. package/src/lib/components/ui/avatar/avatar-badge.svelte +0 -25
  317. package/src/lib/components/ui/avatar/avatar-fallback.svelte +0 -20
  318. package/src/lib/components/ui/avatar/avatar-group-count.svelte +0 -22
  319. package/src/lib/components/ui/avatar/avatar-group.svelte +0 -22
  320. package/src/lib/components/ui/avatar/avatar-image.svelte +0 -17
  321. package/src/lib/components/ui/avatar/avatar.svelte +0 -24
  322. package/src/lib/components/ui/badge/badge.svelte +0 -44
  323. package/src/lib/components/ui/button/button.svelte +0 -108
  324. package/src/lib/components/ui/card/card-action.svelte +0 -21
  325. package/src/lib/components/ui/card/card-content.svelte +0 -19
  326. package/src/lib/components/ui/card/card-description.svelte +0 -19
  327. package/src/lib/components/ui/card/card-footer.svelte +0 -18
  328. package/src/lib/components/ui/card/card-header.svelte +0 -21
  329. package/src/lib/components/ui/card/card-title.svelte +0 -14
  330. package/src/lib/components/ui/card/card.svelte +0 -21
  331. package/src/lib/components/ui/checkbox/checkbox.svelte +0 -39
  332. package/src/lib/components/ui/collapsible/collapsible-content.svelte +0 -7
  333. package/src/lib/components/ui/collapsible/collapsible-trigger.svelte +0 -7
  334. package/src/lib/components/ui/collapsible/collapsible.svelte +0 -11
  335. package/src/lib/components/ui/dialog/dialog-close.svelte +0 -11
  336. package/src/lib/components/ui/dialog/dialog-content.svelte +0 -42
  337. package/src/lib/components/ui/dialog/dialog-description.svelte +0 -17
  338. package/src/lib/components/ui/dialog/dialog-footer.svelte +0 -29
  339. package/src/lib/components/ui/dialog/dialog-header.svelte +0 -19
  340. package/src/lib/components/ui/dialog/dialog-overlay.svelte +0 -17
  341. package/src/lib/components/ui/dialog/dialog-portal.svelte +0 -7
  342. package/src/lib/components/ui/dialog/dialog-title.svelte +0 -17
  343. package/src/lib/components/ui/dialog/dialog-trigger.svelte +0 -11
  344. package/src/lib/components/ui/dialog/dialog.svelte +0 -7
  345. package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte +0 -16
  346. package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +0 -40
  347. package/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte +0 -27
  348. package/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +0 -18
  349. package/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte +0 -7
  350. package/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte +0 -24
  351. package/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte +0 -20
  352. package/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte +0 -7
  353. package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +0 -16
  354. package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +0 -34
  355. package/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte +0 -17
  356. package/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +0 -19
  357. package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +0 -17
  358. package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +0 -27
  359. package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte +0 -7
  360. package/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +0 -7
  361. package/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte +0 -7
  362. package/src/lib/components/ui/input/input.svelte +0 -40
  363. package/src/lib/components/ui/label/label.svelte +0 -20
  364. package/src/lib/components/ui/panel/panel-body.svelte +0 -13
  365. package/src/lib/components/ui/panel/panel-close.svelte +0 -16
  366. package/src/lib/components/ui/panel/panel-content.svelte +0 -33
  367. package/src/lib/components/ui/panel/panel-footer.svelte +0 -13
  368. package/src/lib/components/ui/panel/panel-header.svelte +0 -16
  369. package/src/lib/components/ui/panel/panel-title.svelte +0 -14
  370. package/src/lib/components/ui/panel/panel.svelte +0 -15
  371. package/src/lib/components/ui/popover/popover-close.svelte +0 -7
  372. package/src/lib/components/ui/popover/popover-content.svelte +0 -27
  373. package/src/lib/components/ui/popover/popover-description.svelte +0 -19
  374. package/src/lib/components/ui/popover/popover-header.svelte +0 -19
  375. package/src/lib/components/ui/popover/popover-portal.svelte +0 -7
  376. package/src/lib/components/ui/popover/popover-title.svelte +0 -19
  377. package/src/lib/components/ui/popover/popover-trigger.svelte +0 -17
  378. package/src/lib/components/ui/popover/popover.svelte +0 -7
  379. package/src/lib/components/ui/select/select-content.svelte +0 -40
  380. package/src/lib/components/ui/select/select-group-heading.svelte +0 -19
  381. package/src/lib/components/ui/select/select-group.svelte +0 -17
  382. package/src/lib/components/ui/select/select-item.svelte +0 -38
  383. package/src/lib/components/ui/select/select-label.svelte +0 -18
  384. package/src/lib/components/ui/select/select-portal.svelte +0 -7
  385. package/src/lib/components/ui/select/select-scroll-down-button.svelte +0 -20
  386. package/src/lib/components/ui/select/select-scroll-up-button.svelte +0 -20
  387. package/src/lib/components/ui/select/select-separator.svelte +0 -17
  388. package/src/lib/components/ui/select/select-trigger.svelte +0 -27
  389. package/src/lib/components/ui/select/select.svelte +0 -11
  390. package/src/lib/components/ui/separator/separator.svelte +0 -23
  391. package/src/lib/components/ui/sheet/sheet-close.svelte +0 -7
  392. package/src/lib/components/ui/sheet/sheet-content.svelte +0 -43
  393. package/src/lib/components/ui/sheet/sheet-description.svelte +0 -17
  394. package/src/lib/components/ui/sheet/sheet-footer.svelte +0 -18
  395. package/src/lib/components/ui/sheet/sheet-header.svelte +0 -19
  396. package/src/lib/components/ui/sheet/sheet-overlay.svelte +0 -17
  397. package/src/lib/components/ui/sheet/sheet-portal.svelte +0 -7
  398. package/src/lib/components/ui/sheet/sheet-title.svelte +0 -17
  399. package/src/lib/components/ui/sheet/sheet-trigger.svelte +0 -7
  400. package/src/lib/components/ui/sheet/sheet.svelte +0 -7
  401. package/src/lib/components/ui/textarea/textarea.svelte +0 -21
  402. package/src/lib/components/ui/toggle/toggle.svelte +0 -45
  403. package/src/lib/components/ui/toggle-group/toggle-group-item.svelte +0 -35
  404. package/src/lib/components/ui/toggle-group/toggle-group.svelte +0 -63
  405. package/src/lib/components/ui/tooltip/tooltip-content.svelte +0 -24
  406. package/src/lib/components/ui/tooltip/tooltip-trigger.svelte +0 -27
  407. package/src/lib/components/ui/tooltip/tooltip.svelte +0 -9
  408. package/src/lib/components/ui/trigger-button/trigger-button.svelte +0 -106
  409. package/src/svelte-plugin-ui/components/Icon.svelte +0 -181
  410. package/src/svelte-plugin-ui/components/ModeSwitch.svelte +0 -121
  411. package/src/svelte-plugin-ui/components/ToolbarShell.svelte +0 -150
  412. package/src/svelte-plugin-ui/components/Viewfinder.svelte +0 -1001
  413. package/src/tools/handlers/docs.js +0 -11
  414. package/src/workshop/features/createCanvas/CreateCanvasForm.svelte +0 -139
  415. package/src/workshop/features/createFlow/CreateFlowForm.svelte +0 -314
  416. package/src/workshop/features/createPage/CreatePageForm.svelte +0 -249
  417. package/src/workshop/features/createPrototype/CreatePrototypeForm.svelte +0 -287
  418. package/src/workshop/features/createStory/CreateStoryForm.svelte +0 -161
  419. package/src/workshop/ui/WorkshopPanel.svelte +0 -97
@@ -0,0 +1,513 @@
1
+ /**
2
+ * Viewfinder — prototype index and flow dashboard.
3
+ *
4
+ * Full-page component that lists prototypes as expandable groups,
5
+ * each showing its flows. Global flows (not belonging to any prototype)
6
+ * appear as an "Other flows" group.
7
+ *
8
+ * Mounted via mountViewfinder() from the viewfinder plugin entry point.
9
+ */
10
+
11
+ import { useState, useMemo, useEffect, useCallback } from 'react'
12
+ import './Viewfinder.css'
13
+ import { buildPrototypeIndex } from '../../viewfinder.js'
14
+ import { getLocal, setLocal } from '../../localStorage.js'
15
+ import { Icon } from './Icon.jsx'
16
+
17
+ const VIEW_MODE_KEY = 'viewfinder.viewMode'
18
+ const EXPANDED_KEY = 'viewfinder.expanded'
19
+
20
+ function loadExpanded() {
21
+ const raw = getLocal(EXPANDED_KEY)
22
+ if (!raw) return {}
23
+ try { return JSON.parse(raw) } catch { return {} }
24
+ }
25
+
26
+ function formatName(name) {
27
+ return name
28
+ .split('-')
29
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
30
+ .join(' ')
31
+ }
32
+
33
+ function placeholderSvg(name) {
34
+ const h = (function hashStr(s) {
35
+ let v = 0
36
+ for (let i = 0; i < s.length; i++) v = ((v << 5) - v + s.charCodeAt(i)) | 0
37
+ return Math.abs(v)
38
+ })(name)
39
+
40
+ let rects = ''
41
+ for (let i = 0; i < 12; i++) {
42
+ const s = h * (i + 1)
43
+ const x = (s * 7 + i * 31) % 320
44
+ const y = (s * 13 + i * 17) % 200
45
+ const w = 20 + (s * (i + 3)) % 80
46
+ const ht = 8 + (s * (i + 7)) % 40
47
+ const opacity = 0.06 + ((s * (i + 2)) % 20) / 100
48
+ const fill = i % 3 === 0 ? 'var(--sb--placeholder-accent)' : i % 3 === 1 ? 'var(--sb--placeholder-fg)' : 'var(--sb--placeholder-muted)'
49
+ rects += `<rect x="${x}" y="${y}" width="${w}" height="${ht}" rx="2" fill="${fill}" opacity="${opacity}" />`
50
+ }
51
+
52
+ let lines = ''
53
+ for (let i = 0; i < 6; i++) {
54
+ const s = h * (i + 5)
55
+ const y = 10 + (s % 180)
56
+ lines += `<line x1="0" y1="${y}" x2="320" y2="${y}" stroke="var(--sb--placeholder-grid)" stroke-width="0.5" opacity="0.4" />`
57
+ }
58
+ for (let i = 0; i < 8; i++) {
59
+ const s = h * (i + 9)
60
+ const x = 10 + (s % 300)
61
+ lines += `<line x1="${x}" y1="0" x2="${x}" y2="200" stroke="var(--sb--placeholder-grid)" stroke-width="0.5" opacity="0.3" />`
62
+ }
63
+
64
+ return `<svg viewBox="0 0 320 200" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="320" height="200" fill="var(--sb--placeholder-bg)" />${lines}${rects}</svg>`
65
+ }
66
+
67
+ /* ── Author block ── */
68
+ function AuthorBlock({ author, gitAuthor }) {
69
+ if (author) {
70
+ const authors = Array.isArray(author) ? author : [author]
71
+ return (
72
+ <div className="author">
73
+ <span className="authorAvatars">
74
+ {authors.map((a) => (
75
+ <img key={a} src={`https://github.com/${a}.png?size=48`} alt={a} className="authorAvatar" />
76
+ ))}
77
+ </span>
78
+ <span className="authorName">{authors.join(', ')}</span>
79
+ </div>
80
+ )
81
+ }
82
+ if (gitAuthor) {
83
+ return <p className="authorPlain">{gitAuthor}</p>
84
+ }
85
+ return null
86
+ }
87
+
88
+ /* ── Proto entry ── */
89
+ function ProtoEntry({ proto, isExpanded, toggle, withBase, showThumbnails }) {
90
+ if (proto.isExternal) {
91
+ return (
92
+ <section className="protoGroup">
93
+ <a className="listItem" href={proto.externalUrl} target="_blank" rel="noopener noreferrer">
94
+ <div className="cardBody">
95
+ <p className="protoName">
96
+ {proto.icon && <span className="protoIcon">{proto.icon}</span>}
97
+ {proto.name}
98
+ <span className="externalBadge">
99
+ <Icon size={12} color="var(--fgColor-muted)" name="primer/link-external" offsetY={-2} />
100
+ external
101
+ </span>
102
+ </p>
103
+ {proto.description && <p className="protoDesc">{proto.description}</p>}
104
+ <AuthorBlock author={proto.author} gitAuthor={proto.gitAuthor} />
105
+ </div>
106
+ </a>
107
+ </section>
108
+ )
109
+ }
110
+
111
+ if (proto.hideFlows && proto.flows.length === 1) {
112
+ return (
113
+ <section className="protoGroup">
114
+ <a className="listItem" href={withBase(proto.flows[0].route)}>
115
+ <div className="cardBody">
116
+ <p className={`protoName${proto.dirName === '__global__' ? ' otherflows' : ''}`}>
117
+ {proto.icon && <span className="protoIcon">{proto.icon}</span>}
118
+ {proto.name}
119
+ </p>
120
+ {proto.description && <p className="protoDesc">{proto.description}</p>}
121
+ <AuthorBlock author={proto.author} gitAuthor={proto.gitAuthor} />
122
+ </div>
123
+ </a>
124
+ </section>
125
+ )
126
+ }
127
+
128
+ if (proto.flows.length > 0) {
129
+ const expanded = isExpanded(proto.dirName)
130
+ return (
131
+ <section className="protoGroup">
132
+ <button
133
+ className="listItem protoHeader"
134
+ onClick={() => toggle(proto.dirName)}
135
+ aria-expanded={expanded}
136
+ >
137
+ <div className="cardBody">
138
+ <p className={`protoName${proto.dirName === '__global__' ? ' otherflows' : ''}`}>
139
+ {proto.icon && <span className="protoIcon">{proto.icon}</span>}
140
+ {proto.name}
141
+ <span className="protoChevron">
142
+ {expanded
143
+ ? <Icon size={12} color="var(--fgColor-disabled)" name="primer/chevron-down" offsetY={-3} offsetX={2} />
144
+ : <Icon size={12} color="var(--fgColor-disabled)" name="primer/chevron-right" offsetY={-3} offsetX={2} />
145
+ }
146
+ </span>
147
+ </p>
148
+ {proto.description && <p className="protoDesc">{proto.description}</p>}
149
+ <AuthorBlock author={proto.author} gitAuthor={proto.gitAuthor} />
150
+ </div>
151
+ </button>
152
+
153
+ {!(proto.hideFlows && proto.flows.length === 1) && expanded && proto.flows.length > 0 && (
154
+ <div className="flowList">
155
+ {proto.flows.map((flow) => (
156
+ <a key={flow.key} href={withBase(flow.route)} className="listItem flowItem">
157
+ {showThumbnails && (
158
+ <div className="thumbnail" dangerouslySetInnerHTML={{ __html: placeholderSvg(flow.key) }} />
159
+ )}
160
+ <div className="cardBody">
161
+ <p className="protoName">{flow.meta?.title || formatName(flow.name)}</p>
162
+ {flow.meta?.description && <p className="flowDesc">{flow.meta.description}</p>}
163
+ </div>
164
+ </a>
165
+ ))}
166
+ </div>
167
+ )}
168
+ </section>
169
+ )
170
+ }
171
+
172
+ // Prototype with no flows — navigates directly
173
+ return (
174
+ <section className="protoGroup">
175
+ <a className="listItem" href={withBase(`/${proto.dirName}`)}>
176
+ <div className="cardBody">
177
+ <p className={`protoName${proto.dirName === '__global__' ? ' otherflows' : ''}`}>
178
+ {proto.icon && <span className="protoIcon">{proto.icon}</span>}
179
+ {proto.name}
180
+ </p>
181
+ {proto.description && <p className="protoDesc">{proto.description}</p>}
182
+ <AuthorBlock author={proto.author} gitAuthor={proto.gitAuthor} />
183
+ </div>
184
+ </a>
185
+ </section>
186
+ )
187
+ }
188
+
189
+ /* ── Canvas entry ── */
190
+ function CanvasEntry({ canvas, withBase }) {
191
+ const authors = canvas.author
192
+ ? (Array.isArray(canvas.author) ? canvas.author : [canvas.author])
193
+ : null
194
+
195
+ return (
196
+ <section className="protoGroup">
197
+ <a className="listItem" href={withBase(canvas.route)}>
198
+ <div className="cardBody">
199
+ <p className="protoName">
200
+ <span className="protoIcon">{canvas.icon || ''}</span>
201
+ {canvas.name}
202
+ </p>
203
+ {canvas.description && <p className="protoDesc">{canvas.description}</p>}
204
+ {authors ? (
205
+ <div className="author">
206
+ <span className="authorAvatars">
207
+ {authors.map((a) => (
208
+ <img key={a} src={`https://github.com/${a}.png?size=48`} alt={a} className="authorAvatar" />
209
+ ))}
210
+ </span>
211
+ <span className="authorName">{authors.join(', ')}</span>
212
+ </div>
213
+ ) : canvas.gitAuthor ? (
214
+ <p className="authorPlain">{canvas.gitAuthor}</p>
215
+ ) : null}
216
+ </div>
217
+ </a>
218
+ </section>
219
+ )
220
+ }
221
+
222
+ /* ── Folder section ── */
223
+ function FolderSection({ folder, isExpanded, toggle, renderItems, itemKey = 'prototypes' }) {
224
+ const key = `folder:${folder.dirName}`
225
+ const expanded = isExpanded(key)
226
+ const items = folder[itemKey] || []
227
+
228
+ return (
229
+ <section className={`folderGroup${expanded ? ' folderGroupOpen' : ''}`}>
230
+ <button
231
+ className="folderHeader"
232
+ onClick={() => toggle(key)}
233
+ aria-expanded={expanded}
234
+ >
235
+ <p className="folderName">
236
+ <span>
237
+ {expanded
238
+ ? <Icon size={20} offsetY={-1.5} name="folder-open" color="#54aeff" />
239
+ : <Icon size={20} offsetY={-1.5} name="folder" color="#54aeff" />
240
+ }
241
+ </span>
242
+ {folder.name}
243
+ </p>
244
+ {folder.description && <p className="folderDesc">{folder.description}</p>}
245
+ </button>
246
+ {expanded && items.length > 0 && (
247
+ <div className="folderContent">
248
+ {renderItems(items)}
249
+ </div>
250
+ )}
251
+ </section>
252
+ )
253
+ }
254
+
255
+ /* ── Main Viewfinder component ── */
256
+ export function Viewfinder({
257
+ title = 'Storyboard',
258
+ subtitle = '',
259
+ basePath = '/',
260
+ knownRoutes = [],
261
+ showThumbnails = false,
262
+ hideDefaultFlow = false,
263
+ }) {
264
+ const prototypeIndex = useMemo(() => buildPrototypeIndex(knownRoutes), [knownRoutes])
265
+
266
+ const globalFlows = useMemo(() => {
267
+ return hideDefaultFlow
268
+ ? prototypeIndex.globalFlows.filter((f) => f.key !== 'default')
269
+ : prototypeIndex.globalFlows
270
+ }, [prototypeIndex, hideDefaultFlow])
271
+
272
+ const ungroupedProtos = prototypeIndex.prototypes
273
+ const folders = prototypeIndex.folders || []
274
+
275
+ const otherFlows = useMemo(() => {
276
+ if (globalFlows.length === 0) return null
277
+ return {
278
+ name: 'Other flows',
279
+ dirName: '__global__',
280
+ description: null,
281
+ author: null,
282
+ gitAuthor: null,
283
+ lastModified: null,
284
+ icon: null,
285
+ team: null,
286
+ tags: null,
287
+ flows: globalFlows,
288
+ }
289
+ }, [globalFlows])
290
+
291
+ const totalProtos = ungroupedProtos.length + folders.reduce((sum, f) => sum + f.prototypes.length, 0)
292
+
293
+ // Sorting
294
+ const [sortBy, setSortBy] = useState('updated')
295
+ const sortedProtos = prototypeIndex.sorted?.[sortBy]?.prototypes ?? ungroupedProtos
296
+ const _sortedFolders = prototypeIndex.sorted?.[sortBy]?.folders ?? folders
297
+ void _sortedFolders
298
+
299
+ // Canvases
300
+ const ungroupedCanvases = prototypeIndex.canvases || []
301
+ const sortedCanvases = prototypeIndex.sorted?.[sortBy]?.canvases ?? ungroupedCanvases
302
+ const totalCanvases = ungroupedCanvases.length + folders.reduce((sum, f) => sum + (f.canvases?.length || 0), 0)
303
+
304
+ // View mode
305
+ const [viewMode, setViewMode] = useState(() =>
306
+ getLocal(VIEW_MODE_KEY) === 'canvases' ? 'canvases' : 'prototypes'
307
+ )
308
+
309
+ useEffect(() => {
310
+ setLocal(VIEW_MODE_KEY, viewMode)
311
+ }, [viewMode])
312
+
313
+ // Canvas folders
314
+ const canvasFolders = useMemo(() => {
315
+ const src = prototypeIndex.sorted?.[sortBy]?.folders ?? folders
316
+ return src
317
+ .filter((f) => f.canvases && f.canvases.length > 0)
318
+ .map((f) => ({ ...f, prototypes: [], canvases: f.canvases }))
319
+ }, [prototypeIndex, sortBy, folders])
320
+
321
+ // Proto-only folders
322
+ const protoOnlyFolders = useMemo(() => {
323
+ const src = prototypeIndex.sorted?.[sortBy]?.folders ?? folders
324
+ return src
325
+ .filter((f) => f.prototypes.length > 0)
326
+ .map((f) => ({ ...f, canvases: [] }))
327
+ }, [prototypeIndex, sortBy, folders])
328
+
329
+ // Expanded state
330
+ const [expanded, setExpanded] = useState(loadExpanded)
331
+
332
+ const isExpandedFn = useCallback((dirName) => expanded[dirName] ?? false, [expanded])
333
+
334
+ const toggleFn = useCallback((dirName) => {
335
+ setExpanded((prev) => {
336
+ const next = { ...prev, [dirName]: !(prev[dirName] ?? false) }
337
+ setLocal(EXPANDED_KEY, JSON.stringify(next))
338
+ return next
339
+ })
340
+ }, [])
341
+
342
+ // URL helpers
343
+ const withBase = useCallback((route) => {
344
+ const normalizedRoute = route.startsWith('/') ? route : `/${route}`
345
+ const normalizedBase = (basePath || '/').replace(/\/+$/, '')
346
+ if (!normalizedBase || normalizedBase === '/') return normalizedRoute
347
+ return `${normalizedBase}${normalizedRoute}`.replace(/\/+/g, '/')
348
+ }, [basePath])
349
+
350
+ // Branch switching
351
+ const branches = (typeof window !== 'undefined' && Array.isArray(window.__SB_BRANCHES__))
352
+ ? window.__SB_BRANCHES__
353
+ : null
354
+
355
+ const branchBasePath = (basePath || '/storyboard-source/').replace(/\/branch--[^/]*\/$/, '/')
356
+ const currentBranch = useMemo(() => {
357
+ const m = (basePath || '').match(/\/branch--([^/]+)\/?$/)
358
+ return m ? m[1] : 'main'
359
+ }, [basePath])
360
+
361
+ function handleBranchChange(e) {
362
+ const folder = e.target.value
363
+ if (folder) {
364
+ window.location.href = `${branchBasePath}${folder}/`
365
+ }
366
+ }
367
+
368
+ return (
369
+ <div className="container">
370
+ <header className="header">
371
+ <div className="headerTop">
372
+ <div>
373
+ <h1 className="title">{title}</h1>
374
+ {subtitle && <p className="subtitle">{subtitle}</p>}
375
+ </div>
376
+ </div>
377
+ <div className="controlsRow">
378
+ {/* View mode toggle */}
379
+ <div className="sortToggle">
380
+ <button
381
+ className={`sortButton${viewMode === 'prototypes' ? ' sortButtonActive' : ''}`}
382
+ onClick={() => setViewMode('prototypes')}
383
+ >
384
+ Prototypes
385
+ </button>
386
+ <button
387
+ className={`sortButton${viewMode === 'canvases' ? ' sortButtonActive' : ''}`}
388
+ onClick={() => setViewMode('canvases')}
389
+ >
390
+ Canvas
391
+ </button>
392
+ </div>
393
+ {/* Sort toggle — hidden for now */}
394
+ <div className="sortToggle" style={{ display: 'none' }}>
395
+ <button
396
+ className={`sortButton${sortBy === 'updated' ? ' sortButtonActive' : ''}`}
397
+ onClick={() => setSortBy('updated')}
398
+ >
399
+ <Icon name="primer/clock" size={14} color="var(--fgColor-muted)" />
400
+ Last updated
401
+ </button>
402
+ <button
403
+ className={`sortButton${sortBy === 'title' ? ' sortButtonActive' : ''}`}
404
+ onClick={() => setSortBy('title')}
405
+ >
406
+ <Icon name="primer/sort-asc" size={14} color="var(--fgColor-muted)" />
407
+ Title A–Z
408
+ </button>
409
+ </div>
410
+ {branches && branches.length > 0 && (
411
+ <div className="branchDropdown">
412
+ <span className="branchIcon">
413
+ <Icon size={16} color="var(--fgColor-muted)" offsetY={-1} offsetX={2} name="primer/git-branch" />
414
+ </span>
415
+ <select
416
+ className="branchSelect"
417
+ onChange={handleBranchChange}
418
+ aria-label="Switch branch"
419
+ defaultValue=""
420
+ >
421
+ <option value="" disabled>{currentBranch}</option>
422
+ {branches.map((b) => (
423
+ <option key={b.folder} value={b.folder}>{b.branch}</option>
424
+ ))}
425
+ </select>
426
+ </div>
427
+ )}
428
+ </div>
429
+ </header>
430
+
431
+ {viewMode === 'prototypes' && totalProtos === 0 && folders.length === 0 ? (
432
+ <p className="empty">No flows found. Add a <code>*.flow.json</code> file to get started.</p>
433
+ ) : viewMode === 'canvases' && totalCanvases === 0 ? (
434
+ <p className="empty">No canvases found. Add a <code>*.canvas.jsonl</code> file to get started.</p>
435
+ ) : (
436
+ <div className="list">
437
+ {viewMode === 'prototypes' ? (
438
+ <>
439
+ {protoOnlyFolders.map((folder) => (
440
+ <FolderSection
441
+ key={folder.dirName}
442
+ folder={folder}
443
+ isExpanded={isExpandedFn}
444
+ toggle={toggleFn}
445
+ renderItems={(protos) =>
446
+ protos.map((proto) => (
447
+ <ProtoEntry
448
+ key={proto.dirName}
449
+ proto={proto}
450
+ isExpanded={isExpandedFn}
451
+ toggle={toggleFn}
452
+ withBase={withBase}
453
+ showThumbnails={showThumbnails}
454
+ />
455
+ ))
456
+ }
457
+ />
458
+ ))}
459
+
460
+ {sortedProtos.map((proto) => (
461
+ <ProtoEntry
462
+ key={proto.dirName}
463
+ proto={proto}
464
+ isExpanded={isExpandedFn}
465
+ toggle={toggleFn}
466
+ withBase={withBase}
467
+ showThumbnails={showThumbnails}
468
+ />
469
+ ))}
470
+
471
+ {otherFlows && (
472
+ <ProtoEntry
473
+ proto={otherFlows}
474
+ isExpanded={isExpandedFn}
475
+ toggle={toggleFn}
476
+ withBase={withBase}
477
+ showThumbnails={showThumbnails}
478
+ />
479
+ )}
480
+ </>
481
+ ) : (
482
+ <>
483
+ <div className="canvasWarning">
484
+ <Icon size={14} name="primer/alert" color="#9a6700" offsetY={-1} />
485
+ <span>Canvas is an experimental feature. Use with caution.</span>
486
+ </div>
487
+ {canvasFolders.map((folder) => (
488
+ <FolderSection
489
+ key={folder.dirName}
490
+ folder={folder}
491
+ isExpanded={isExpandedFn}
492
+ toggle={toggleFn}
493
+ itemKey="canvases"
494
+ renderItems={(canvases) =>
495
+ canvases.map((canvas) => (
496
+ <CanvasEntry key={canvas.dirName} canvas={canvas} withBase={withBase} />
497
+ ))
498
+ }
499
+ />
500
+ ))}
501
+
502
+ {sortedCanvases.map((canvas) => (
503
+ <CanvasEntry key={canvas.dirName} canvas={canvas} withBase={withBase} />
504
+ ))}
505
+ </>
506
+ )}
507
+ </div>
508
+ )}
509
+ </div>
510
+ )
511
+ }
512
+
513
+ export default Viewfinder
@@ -1,19 +1,20 @@
1
1
  /**
2
- * Generic mount utility for Svelte plugin components.
2
+ * Generic mount utility for React plugin components.
3
3
  *
4
- * Provides a framework-agnostic way to mount Svelte components into any
4
+ * Provides a framework-agnostic way to mount React components into any
5
5
  * DOM target. Handles shared style injection (idempotent) and returns
6
6
  * a destroy handle for cleanup.
7
7
  *
8
8
  * Usage:
9
9
  * import { mountSveltePlugin } from '@dfosco/storyboard-core/svelte-plugin-ui'
10
- * import MyComponent from './MyComponent.svelte'
10
+ * import MyComponent from './MyComponent.jsx'
11
11
  *
12
12
  * const handle = mountSveltePlugin(document.body, MyComponent, { someProp: 'value' })
13
13
  * // later: handle.destroy()
14
14
  */
15
15
 
16
- import { mount, unmount, type Component } from 'svelte'
16
+ import { createElement, type ComponentType } from 'react'
17
+ import { createRoot, type Root } from 'react-dom/client'
17
18
 
18
19
  const STYLE_ID = 'sb-svelte-ui-styles'
19
20
 
@@ -69,28 +70,25 @@ export function injectStyles(): Promise<void> {
69
70
  export interface PluginHandle {
70
71
  /** Remove the component and its wrapper from the DOM */
71
72
  destroy: () => void
72
- /** The wrapper element containing the Svelte component */
73
+ /** The wrapper element containing the React component */
73
74
  element: HTMLElement
74
75
  /** Resolves when all styles are loaded and the component is ready to show */
75
76
  ready: Promise<void>
76
77
  }
77
78
 
78
79
  /**
79
- * Mount a Svelte component into a DOM target.
80
+ * Mount a React component into a DOM target.
80
81
  *
81
82
  * @param target - DOM element to append the component wrapper to
82
- * @param ComponentClass - Svelte component constructor
83
+ * @param ComponentClass - React component
83
84
  * @param props - Props to pass to the component
84
85
  * @returns Handle with destroy() method and a `ready` promise
85
86
  */
86
87
  export function mountSveltePlugin<T extends Record<string, unknown>>(
87
88
  target: HTMLElement,
88
- ComponentClass: Component<T>,
89
+ ComponentClass: ComponentType<T>,
89
90
  props?: T,
90
91
  ): PluginHandle {
91
- // Fire-and-forget — styles are either already present (Vite bundle)
92
- // or will load in parallel. The `ready` promise on PluginHandle can
93
- // be awaited by callers that need to wait for CSS.
94
92
  const stylesReady = injectStyles()
95
93
 
96
94
  const wrapper = document.createElement('div')
@@ -98,16 +96,14 @@ export function mountSveltePlugin<T extends Record<string, unknown>>(
98
96
  wrapper.style.display = 'contents'
99
97
  target.appendChild(wrapper)
100
98
 
101
- const instance = mount(ComponentClass, {
102
- target: wrapper,
103
- props: props ?? ({} as T),
104
- })
99
+ const root: Root = createRoot(wrapper)
100
+ root.render(createElement(ComponentClass, props ?? ({} as T)))
105
101
 
106
102
  return {
107
103
  element: wrapper,
108
104
  ready: stylesReady,
109
105
  destroy() {
110
- unmount(instance)
106
+ root.unmount()
111
107
  wrapper.remove()
112
108
  },
113
109
  }
@@ -2,8 +2,8 @@
2
2
  * Tool Registry — config-driven state management for toolbar tools.
3
3
  *
4
4
  * Every tool is declared in toolbar.config.json under the `tools` key.
5
- * Each tool specifies a `toolbar` target (main-toolbar, secondary-toolbar,
6
- * command-list) and a `render` type (button, menu, sidepanel, submenu, link).
5
+ * Each tool specifies a `toolbar` target (command-toolbar, canvas-toolbar,
6
+ * command-palette) and a `render` type (button, menu, sidepanel, submenu, link).
7
7
  *
8
8
  * Code modules register themselves via registerToolModule() to provide
9
9
  * component, handler, setup, and guard functions.
@@ -58,7 +58,7 @@ export function initToolRegistry(config) {
58
58
  *
59
59
  * @param {string} id - Tool id (matches key in toolbar.config.json tools)
60
60
  * @param {object} mod
61
- * @param {Function} [mod.component] - () => import('./SomeComponent.svelte')
61
+ * @param {Function} [mod.component] - () => import('./SomeComponent.jsx')
62
62
  * @param {object|Function} [mod.handler] - Command action handler
63
63
  * @param {Function} [mod.setup] - async (ctx) => void — called once at mount
64
64
  * @param {Function} [mod.guard] - async (ctx) => boolean — return false to hide
@@ -117,7 +117,7 @@ export function getToolModule(id) {
117
117
  /**
118
118
  * Get tools for a specific toolbar target, filtered by mode and visibility.
119
119
  *
120
- * @param {string} toolbar - "main-toolbar" | "secondary-toolbar" | "command-list"
120
+ * @param {string} toolbar - "command-toolbar" | "canvas-toolbar" | "command-palette"
121
121
  * @param {string} mode - Current mode name
122
122
  * @param {object} [options]
123
123
  * @param {boolean} [options.isLocalDev] - Whether running in local dev
@@ -25,6 +25,9 @@ let _mergedConfig = {}
25
25
  /** @type {Set<Function>} */
26
26
  const _listeners = new Set()
27
27
 
28
+ /** @type {object|null} Client-repo toolbar overrides (set by virtual module before mount) */
29
+ let _clientOverrides = null
30
+
28
31
  let _snapshotVersion = 0
29
32
 
30
33
  // ---------------------------------------------------------------------------
@@ -122,6 +125,32 @@ function _recompute() {
122
125
  }
123
126
  }
124
127
 
128
+ // ---------------------------------------------------------------------------
129
+ // Client overrides (set by Vite data plugin before mountStoryboardCore runs)
130
+ // ---------------------------------------------------------------------------
131
+
132
+ /**
133
+ * Store client-repo toolbar overrides from a root toolbar.config.json.
134
+ * Called from the generated virtual module at import time.
135
+ *
136
+ * @param {object} config - Client toolbar config (tools, surfaces, etc.)
137
+ */
138
+ export function setClientToolbarOverrides(config) {
139
+ _clientOverrides = config
140
+ }
141
+
142
+ /**
143
+ * Consume and clear pending client overrides.
144
+ * Called once by mountStoryboardCore during toolbar config init.
145
+ *
146
+ * @returns {object|null}
147
+ */
148
+ export function consumeClientToolbarOverrides() {
149
+ const overrides = _clientOverrides
150
+ _clientOverrides = null
151
+ return overrides
152
+ }
153
+
125
154
  // ---------------------------------------------------------------------------
126
155
  // Test helpers
127
156
  // ---------------------------------------------------------------------------
@@ -129,6 +158,7 @@ function _recompute() {
129
158
  export function _resetToolbarConfig() {
130
159
  _baseConfig = {}
131
160
  _prototypeConfig = null
161
+ _clientOverrides = null
132
162
  _mergedConfig = {}
133
163
  _listeners.clear()
134
164
  _snapshotVersion = 0
@@ -7,6 +7,6 @@
7
7
  export const id = 'autosync'
8
8
 
9
9
  export async function component() {
10
- const mod = await import('../../AutosyncMenuButton.svelte')
10
+ const mod = await import('../../AutosyncMenuButton.jsx')
11
11
  return mod.default
12
12
  }
@@ -6,6 +6,6 @@
6
6
  export const id = 'canvas-add-widget'
7
7
 
8
8
  export async function component() {
9
- const mod = await import('../../CanvasCreateMenu.svelte')
9
+ const mod = await import('../../CanvasCreateMenu.jsx')
10
10
  return mod.default
11
11
  }