@workbench-kit/react 0.0.2-prototype.0.1.2 → 0.0.2-prototype.0.2.10

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 (543) hide show
  1. package/README.md +87 -0
  2. package/package.json +37 -27
  3. package/src/brand/TilepaperAppIcon.tsx +181 -0
  4. package/src/brand/index.ts +2 -0
  5. package/src/brand/tilepaper-app-icon-geometry.ts +201 -0
  6. package/src/icons/WorkbenchIcon.tsx +57 -0
  7. package/src/icons/WorkbenchIconContext.tsx +25 -0
  8. package/src/icons/file-icon.ts +154 -0
  9. package/src/icons/index.ts +17 -0
  10. package/src/icons/resolveWorkbenchIcon.ts +48 -0
  11. package/src/icons/types.ts +28 -0
  12. package/src/index.ts +278 -88
  13. package/src/jdw/JdwPreview.tsx +165 -8
  14. package/src/jdw/JdwPreviewViewport.tsx +190 -0
  15. package/src/jdw/JsonCodeEditorPane.tsx +172 -21
  16. package/src/jdw/builtins/renderBuiltinWidgetLeaf.tsx +101 -0
  17. package/src/jdw/createBuiltinJdwRegistry.ts +330 -5
  18. package/src/jdw/cssRenderBackend.tsx +96 -7
  19. package/src/jdw/document.ts +0 -3
  20. package/src/jdw/fixtures/jdw-sample-screens.ts +10 -8
  21. package/src/jdw/index.ts +9 -4
  22. package/src/jdw/jdw-preview-viewport.css +41 -0
  23. package/src/jdw/renderJdw.tsx +49 -8
  24. package/src/json-config/JsonConfigWorkbench.tsx +12 -15
  25. package/src/layout/ViewEmptyState.tsx +14 -0
  26. package/src/layout/WorkbenchCanvas.tsx +113 -6
  27. package/src/layout/WorkbenchLayout.tsx +3 -0
  28. package/src/layout/WorkbenchLayoutBase.tsx +43 -2
  29. package/src/layout/WorkbenchMediaPreviewViewport.tsx +122 -0
  30. package/src/layout/WorkbenchPropertyOverrideLabel.tsx +90 -0
  31. package/src/layout/WorkbenchPropertyPanel.tsx +153 -17
  32. package/src/layout/WorkbenchPropertySearch.tsx +51 -0
  33. package/src/layout/WorkbenchTree.tsx +9 -10
  34. package/src/layout/canvas/canvas-drag-ghost.css +21 -0
  35. package/src/layout/canvas/canvas-drag-preview-frame.css +15 -0
  36. package/src/layout/canvas/canvas-drop-indicator.css +16 -0
  37. package/src/layout/canvas/canvas-frame-handle.css +37 -0
  38. package/src/layout/canvas/canvas-frame-surface.css +24 -0
  39. package/src/layout/canvas/canvas-guide-block.css +17 -0
  40. package/src/layout/canvas/canvas-guide-layer.css +6 -0
  41. package/src/layout/canvas/canvas-guide-line.css +22 -0
  42. package/src/layout/canvas/canvas-item-badge.css +23 -0
  43. package/src/layout/canvas/canvas-item-frame.css +54 -0
  44. package/src/layout/canvas/canvas-pane-surface.css +9 -0
  45. package/src/layout/canvas/canvas-placeholder.css +21 -0
  46. package/src/layout/canvas/canvas-resize-frame.css +9 -0
  47. package/src/layout/canvas/canvas-resize-handle.css +74 -0
  48. package/src/layout/canvas/canvas-resize-preview.css +11 -0
  49. package/src/layout/canvas/canvas-selection-marquee.css +14 -0
  50. package/src/layout/canvas/canvas-viewport.css +18 -0
  51. package/src/layout/canvas/index.css +19 -0
  52. package/src/layout/canvas/preview-canvas.css +144 -0
  53. package/src/layout/editor/editor-body.css +9 -0
  54. package/src/layout/editor/editor-bottom-panel.css +44 -0
  55. package/src/layout/editor/editor-frame.css +14 -0
  56. package/src/layout/editor/editor-viewport.css +7 -0
  57. package/src/layout/editor/floating-menu.css +91 -0
  58. package/src/layout/editor/index.css +10 -0
  59. package/src/layout/editor/parse-error.css +9 -0
  60. package/src/layout/editor/problem-item.css +52 -0
  61. package/src/layout/editor/problem-list.css +7 -0
  62. package/src/layout/editor/render-surface.css +13 -0
  63. package/src/layout/fillScrollContract.ts +49 -0
  64. package/src/layout/fullscreen/fullscreen-backdrop.css +31 -0
  65. package/src/layout/fullscreen/fullscreen-button.css +44 -0
  66. package/src/layout/fullscreen/fullscreen-carousel.css +20 -0
  67. package/src/layout/fullscreen/fullscreen-content.css +8 -0
  68. package/src/layout/fullscreen/fullscreen-empty.css +16 -0
  69. package/src/layout/fullscreen/fullscreen-header.css +77 -0
  70. package/src/layout/fullscreen/fullscreen-hero.css +41 -0
  71. package/src/layout/fullscreen/fullscreen-nav-button.css +29 -0
  72. package/src/layout/fullscreen/fullscreen-option.css +83 -0
  73. package/src/layout/fullscreen/fullscreen-pill-row.css +6 -0
  74. package/src/layout/fullscreen/fullscreen-pill.css +10 -0
  75. package/src/layout/fullscreen/fullscreen-root.css +11 -0
  76. package/src/layout/fullscreen/index.css +13 -0
  77. package/src/layout/index.ts +156 -0
  78. package/src/layout/layout-base/banner.css +32 -0
  79. package/src/layout/layout-base/center.css +7 -0
  80. package/src/layout/layout-base/column.css +7 -0
  81. package/src/layout/layout-base/divider.css +5 -0
  82. package/src/layout/layout-base/empty.css +12 -0
  83. package/src/layout/layout-base/fill-scroll.css +36 -0
  84. package/src/layout/layout-base/fill.css +18 -0
  85. package/src/layout/layout-base/index.css +13 -0
  86. package/src/layout/layout-base/pane.css +6 -0
  87. package/src/layout/layout-base/panel-scroll.css +5 -0
  88. package/src/layout/layout-base/panel-surface.css +14 -0
  89. package/src/layout/layout-base/root.css +9 -0
  90. package/src/layout/layout-base/section-title.css +8 -0
  91. package/src/layout/layout.css +10 -0
  92. package/src/layout/layoutHelpers.ts +4 -2
  93. package/src/layout/media/index.css +2 -0
  94. package/src/layout/media/media-preview-viewport.css +69 -0
  95. package/src/layout/{Panel.tsx → panel/Panel.tsx} +29 -40
  96. package/src/layout/panel/TemplateGallery.tsx +90 -0
  97. package/src/layout/panel/WorkbenchAuthoringShell.tsx +57 -0
  98. package/src/layout/panel/WorkbenchLabeledPane.tsx +81 -0
  99. package/src/layout/panel/WorkbenchSidebarStack.tsx +15 -0
  100. package/src/layout/panel/filter-bar.css +59 -0
  101. package/src/layout/panel/index.css +7 -0
  102. package/src/layout/panel/index.ts +70 -0
  103. package/src/layout/panel/preview-pane.css +63 -0
  104. package/src/layout/panel/template-gallery.css +131 -0
  105. package/src/layout/panel/workbench-authoring-shell.css +48 -0
  106. package/src/layout/panel/workbench-labeled-pane.css +69 -0
  107. package/src/layout/panel/workbench-sidebar-stack.css +18 -0
  108. package/src/layout/property/color-input.css +8 -0
  109. package/src/layout/property/color-row.css +6 -0
  110. package/src/layout/property/index.css +15 -0
  111. package/src/layout/property/property-card.css +8 -0
  112. package/src/layout/property/property-grid.css +24 -0
  113. package/src/layout/property/property-hint.css +4 -0
  114. package/src/layout/property/property-inline.css +10 -0
  115. package/src/layout/property/property-key-value.css +29 -0
  116. package/src/layout/property/property-override-label.css +34 -0
  117. package/src/layout/property/property-panel.css +20 -0
  118. package/src/layout/property/property-row.css +17 -0
  119. package/src/layout/property/property-search.css +43 -0
  120. package/src/layout/property/property-section.css +97 -0
  121. package/src/layout/property/property-stack.css +11 -0
  122. package/src/layout/property/property-toggle.css +14 -0
  123. package/src/layout/propertyFieldFilter.ts +84 -0
  124. package/src/layout/sidebar/SideBarViewFrame.tsx +235 -0
  125. package/src/layout/sidebar/SideBarViewTabStrip.tsx +60 -0
  126. package/src/layout/sidebar/SideBarViewTitleMenu.tsx +75 -0
  127. package/src/layout/sidebar/SidebarActionIconBar.tsx +242 -0
  128. package/src/layout/sidebar/SidebarSectionNestingContext.tsx +21 -0
  129. package/src/layout/sidebar/SidebarSlotChrome.tsx +32 -0
  130. package/src/layout/sidebar/SidebarToolbar.tsx +10 -0
  131. package/src/layout/sidebar/WorkbenchActionSidebar.tsx +73 -0
  132. package/src/layout/{WorkbenchSidebarActions.tsx → sidebar/WorkbenchSidebarActions.tsx} +105 -51
  133. package/src/layout/sidebar/WorkbenchSidebarSectionStack.tsx +165 -0
  134. package/src/layout/sidebar/index.css +5 -0
  135. package/src/layout/sidebar/index.ts +55 -0
  136. package/src/layout/sidebar/sidebar-chrome.css +95 -0
  137. package/src/layout/sidebar/sidebar-section-stack.css +25 -0
  138. package/src/layout/sidebar/sidebar-section.css +124 -0
  139. package/src/layout/sidebar/sidebar-view.css +290 -0
  140. package/src/layout/tree/drag-preview.css +25 -0
  141. package/src/layout/tree/index.css +10 -0
  142. package/src/layout/tree/template-glyph.css +96 -0
  143. package/src/layout/tree/tree-action.css +20 -0
  144. package/src/layout/tree/tree-drag-overlay.css +13 -0
  145. package/src/layout/tree/tree-drop-line.css +17 -0
  146. package/src/layout/tree/tree-drop-zone.css +13 -0
  147. package/src/layout/tree/tree-expander.css +23 -0
  148. package/src/layout/tree/tree-item.css +93 -0
  149. package/src/layout/tree/tree.css +49 -0
  150. package/src/layout/usePreviewViewport.ts +428 -0
  151. package/src/modal/ConfirmDialog.tsx +1 -1
  152. package/src/modal/Modal.tsx +184 -311
  153. package/src/modal/ModalResizeHandles.tsx +40 -0
  154. package/src/modal/ModalTitlebar.tsx +86 -0
  155. package/src/modal/modal.css +291 -0
  156. package/src/modal/modalContainer.ts +36 -0
  157. package/src/modal/modalPosition.ts +36 -0
  158. package/src/modal/modalSize.ts +84 -0
  159. package/src/modal/modalTypes.ts +13 -0
  160. package/src/modal/useModalContainerViewport.ts +41 -0
  161. package/src/modal/useModalDrag.ts +118 -0
  162. package/src/modal/useModalFocusTrap.ts +142 -0
  163. package/src/modal/useModalResize.ts +122 -0
  164. package/src/modal/useModalWindowFrame.ts +122 -0
  165. package/src/overlay/ContextMenu.tsx +28 -50
  166. package/src/overlay/clampFixedOverlayPosition.ts +22 -0
  167. package/src/overlay/context-menu.css +127 -0
  168. package/src/overlay/index.ts +31 -0
  169. package/src/overlay/measureAnchoredOverlayPanel.ts +107 -0
  170. package/src/overlay/overlay.css +2 -0
  171. package/src/overlay/pointerPassthroughRegion.ts +83 -0
  172. package/src/overlay/useAnchoredOverlayPanel.ts +222 -0
  173. package/src/overlay/useClampedFixedOverlayPosition.ts +27 -0
  174. package/src/overlay/useContextMenuState.ts +59 -0
  175. package/src/overlay/useFixedOverlayDismiss.ts +49 -0
  176. package/src/overlay/usePointerPassthroughRegion.ts +87 -0
  177. package/src/primitives/{AbsoluteBox.tsx → absolute-box/AbsoluteBox.tsx} +5 -5
  178. package/src/primitives/absolute-box/index.ts +1 -0
  179. package/src/primitives/{Badge.tsx → badge/Badge.tsx} +4 -2
  180. package/src/primitives/badge/badge.css +20 -0
  181. package/src/primitives/badge/index.ts +1 -0
  182. package/src/primitives/{Button.tsx → button/Button.tsx} +7 -6
  183. package/src/primitives/button/button.css +76 -0
  184. package/src/primitives/button/index.ts +1 -0
  185. package/src/primitives/catalog-browse-card/CatalogBrowseCard.tsx +121 -0
  186. package/src/primitives/catalog-browse-card/catalog-browse-card.css +175 -0
  187. package/src/primitives/catalog-browse-card/index.ts +1 -0
  188. package/src/primitives/catalog-browse-pane/CatalogBrowseFacetChips.tsx +59 -0
  189. package/src/primitives/catalog-browse-pane/CatalogBrowsePane.tsx +360 -0
  190. package/src/primitives/catalog-browse-pane/catalog-browse-facet-chips.css +8 -0
  191. package/src/primitives/catalog-browse-pane/catalog-browse-pane.css +84 -0
  192. package/src/primitives/catalog-browse-pane/filterCatalogBrowseItems.ts +27 -0
  193. package/src/primitives/catalog-browse-pane/index.ts +3 -0
  194. package/src/primitives/catalog-filter-overlay/CatalogFilterOverlay.tsx +73 -0
  195. package/src/primitives/catalog-filter-overlay/catalog-filter-overlay.css +65 -0
  196. package/src/primitives/catalog-filter-overlay/index.ts +1 -0
  197. package/src/primitives/checkbox/Checkbox.tsx +40 -0
  198. package/src/primitives/checkbox/checkbox.css +81 -0
  199. package/src/primitives/checkbox/index.ts +1 -0
  200. package/src/primitives/chip/Chip.tsx +43 -0
  201. package/src/primitives/chip/chip.css +110 -0
  202. package/src/primitives/chip/index.ts +2 -0
  203. package/src/primitives/clearable-text-input/ClearableTextInput.tsx +78 -0
  204. package/src/primitives/clearable-text-input/clearable-text-input.css +15 -0
  205. package/src/primitives/clearable-text-input/index.ts +1 -0
  206. package/src/primitives/codicon/Codicon.tsx +20 -0
  207. package/src/primitives/codicon/index.ts +1 -0
  208. package/src/primitives/{EmptyState.tsx → empty-state/EmptyState.tsx} +9 -3
  209. package/src/primitives/empty-state/empty-state.css +20 -0
  210. package/src/primitives/empty-state/index.ts +1 -0
  211. package/src/primitives/external-link-button/ExternalLinkButton.tsx +56 -0
  212. package/src/primitives/external-link-button/index.ts +1 -0
  213. package/src/primitives/{Field.tsx → field/Field.tsx} +2 -1
  214. package/src/primitives/field/field.css +51 -0
  215. package/src/primitives/field/index.ts +1 -0
  216. package/src/primitives/file-icon/FileIcon.tsx +21 -0
  217. package/src/primitives/file-icon/index.ts +1 -0
  218. package/src/primitives/{IconButton.tsx → icon-button/IconButton.tsx} +7 -5
  219. package/src/primitives/icon-button/icon-button.css +46 -0
  220. package/src/primitives/icon-button/index.ts +1 -0
  221. package/src/primitives/index.ts +210 -50
  222. package/src/primitives/library-detail-layout/LibraryDetailLayout.tsx +135 -0
  223. package/src/primitives/library-detail-layout/index.ts +1 -0
  224. package/src/primitives/library-detail-layout/library-detail-layout.css +169 -0
  225. package/src/primitives/library-facet-filter-panel/LibraryFacetFilterPanel.tsx +454 -0
  226. package/src/primitives/library-facet-filter-panel/index.ts +1 -0
  227. package/src/primitives/library-facet-filter-panel/library-facet-filter-panel.css +205 -0
  228. package/src/primitives/library-facet-filter-strip/LibraryFacetFilterStrip.tsx +527 -0
  229. package/src/primitives/library-facet-filter-strip/index.ts +1 -0
  230. package/src/primitives/library-facet-filter-strip/library-facet-filter-strip.css +31 -0
  231. package/src/primitives/{List.tsx → list/List.tsx} +15 -6
  232. package/src/primitives/list/index.ts +1 -0
  233. package/src/primitives/list/list-empty-state.css +10 -0
  234. package/src/primitives/list/list-item.css +93 -0
  235. package/src/primitives/list/list.css +6 -0
  236. package/src/primitives/number-input/NumberInput.tsx +235 -0
  237. package/src/primitives/number-input/index.ts +1 -0
  238. package/src/primitives/number-input/number-input.css +105 -0
  239. package/src/primitives/panel-loading/PanelLoading.tsx +29 -0
  240. package/src/primitives/panel-loading/index.ts +1 -0
  241. package/src/primitives/panel-loading/panel-loading.css +16 -0
  242. package/src/primitives/panel-surface/panel-surface.css +77 -0
  243. package/src/primitives/primitives.css +36 -0
  244. package/src/primitives/record-media-hero/RecordMediaHero.tsx +81 -0
  245. package/src/primitives/record-media-hero/index.ts +1 -0
  246. package/src/primitives/record-media-hero/record-media-hero.css +84 -0
  247. package/src/primitives/scroll-area/ScrollArea.tsx +200 -0
  248. package/src/primitives/scroll-area/index.ts +1 -0
  249. package/src/primitives/scroll-area/scroll-area-overlay.css +69 -0
  250. package/src/primitives/scroll-area-infinite-load/ScrollAreaInfiniteSentinel.tsx +22 -0
  251. package/src/primitives/scroll-area-infinite-load/index.ts +2 -0
  252. package/src/primitives/scroll-area-infinite-load/scroll-area-infinite-sentinel.css +6 -0
  253. package/src/primitives/scroll-area-infinite-load/useScrollAreaInfiniteLoad.ts +84 -0
  254. package/src/primitives/searchable-multi-select/SearchableMultiSelect.tsx +378 -0
  255. package/src/primitives/searchable-multi-select/index.ts +9 -0
  256. package/src/primitives/searchable-multi-select/overlay.ts +125 -0
  257. package/src/primitives/searchable-multi-select/searchable-multi-select.css +129 -0
  258. package/src/primitives/select/Select.tsx +21 -3
  259. package/src/primitives/select/overlay.ts +23 -4
  260. package/src/primitives/select/select.app.css +5 -2
  261. package/src/primitives/select/select.css +49 -12
  262. package/src/primitives/styles.css +3 -952
  263. package/src/primitives/tabbed-panels/TabbedPanels.tsx +68 -0
  264. package/src/primitives/tabbed-panels/index.ts +2 -0
  265. package/src/primitives/tabbed-panels/tabbed-panels.css +58 -0
  266. package/src/primitives/{TextArea.tsx → text-area/TextArea.tsx} +3 -2
  267. package/src/primitives/text-area/index.ts +1 -0
  268. package/src/primitives/{TextInput.tsx → text-input/TextInput.tsx} +3 -2
  269. package/src/primitives/text-input/index.ts +1 -0
  270. package/src/primitives/text-input/input.css +54 -0
  271. package/src/primitives/{Toolbar.tsx → toolbar/Toolbar.tsx} +1 -1
  272. package/src/primitives/toolbar/index.ts +1 -0
  273. package/src/primitives/visually-hidden/visually-hidden.css +11 -0
  274. package/src/primitives/{WorkbenchEditor.tsx → workbench-editor/WorkbenchEditor.tsx} +81 -43
  275. package/src/primitives/workbench-editor/button-group.css +10 -0
  276. package/src/primitives/workbench-editor/editor-tabs.css +201 -0
  277. package/src/primitives/workbench-editor/index.ts +1 -0
  278. package/src/primitives/workbench-editor/resizable-panels.css +53 -0
  279. package/src/primitives/workbench-editor/segmented-control.css +98 -0
  280. package/src/primitives/workbench-media-slot/WorkbenchMediaPlaceholder.tsx +25 -0
  281. package/src/primitives/workbench-media-slot/WorkbenchMediaSlot.tsx +60 -0
  282. package/src/primitives/workbench-media-slot/index.ts +2 -0
  283. package/src/primitives/workbench-media-slot/media-slot.css +72 -0
  284. package/src/primitives/workbench-thumbnail/WorkbenchThumbnail.tsx +38 -0
  285. package/src/primitives/workbench-thumbnail/index.ts +1 -0
  286. package/src/primitives/workbench-thumbnail/thumbnail.css +69 -0
  287. package/src/scrollbars.css +77 -2
  288. package/src/styles.css +13 -7735
  289. package/src/test-utils/workbenchMonacoMock.tsx +37 -0
  290. package/src/utils/dragMime.ts +89 -0
  291. package/src/utils/useWorkbenchMediaImage.ts +37 -0
  292. package/src/widget-asset/WidgetAssetEditor.tsx +9 -7
  293. package/src/widget-asset/WidgetAssetModeControls.tsx +1 -1
  294. package/src/widget-asset/WidgetAssetWorkbench.tsx +5 -6
  295. package/src/widget-studio/create-widget-studio-workspace-editor.tsx +1 -2
  296. package/src/widget-studio/index.ts +4 -1
  297. package/src/widget-studio/resolve-widget-studio-asset-catalog.ts +27 -10
  298. package/src/widget-tree/WidgetAssetPalette.tsx +35 -7
  299. package/src/widget-tree/WidgetInspectorPanel.tsx +53 -3
  300. package/src/widget-tree/WidgetSourceEditor.tsx +90 -3
  301. package/src/widget-tree/WidgetTreeCanvasPreview.tsx +875 -0
  302. package/src/widget-tree/WidgetTreeLab.tsx +411 -83
  303. package/src/widget-tree/WidgetTreeModeControls.tsx +30 -1
  304. package/src/widget-tree/WidgetTreeSidePanel.tsx +24 -34
  305. package/src/widget-tree/WidgetTreeView.tsx +711 -11
  306. package/src/widget-tree/WidgetTreeWorkbench.tsx +59 -15
  307. package/src/widget-tree/WidgetTreeWorkspaceShell.tsx +28 -10
  308. package/src/widget-tree/index.ts +22 -4
  309. package/src/widget-tree/widget-placement-asset-dnd.ts +35 -0
  310. package/src/widget-tree/widget-tree-document.ts +3 -9
  311. package/src/widget-tree/widget-tree-editor-state.ts +40 -0
  312. package/src/widget-tree/widget-tree-layout.ts +48 -3
  313. package/src/widget-tree/widget-tree-play-helpers.ts +69 -58
  314. package/src/workbench/auth/WorkbenchLoginView.tsx +4 -6
  315. package/src/workbench/auth/auth-flows.css +440 -0
  316. package/src/workbench/auth/auth.css +3 -0
  317. package/src/workbench/auth/profile-modals.css +115 -0
  318. package/src/workbench/bootstrap/WorkbenchBootstrapGate.tsx +45 -0
  319. package/src/workbench/bootstrap/WorkbenchBootstrapView.tsx +100 -0
  320. package/src/workbench/bootstrap/index.ts +12 -0
  321. package/src/workbench/bootstrap/useWorkbenchBootstrap.ts +130 -0
  322. package/src/workbench/chat/ChatCommandProposalCard.tsx +115 -0
  323. package/src/workbench/chat/ChatComposer.tsx +32 -34
  324. package/src/workbench/chat/ChatConversationBar.tsx +134 -0
  325. package/src/workbench/chat/ChatHistoryMenu.tsx +171 -0
  326. package/src/workbench/chat/ChatHistoryMenuRow.tsx +74 -0
  327. package/src/workbench/chat/ChatMessageCollapsible.tsx +119 -0
  328. package/src/workbench/chat/ChatMessageItem.tsx +351 -19
  329. package/src/workbench/chat/ChatMessageList.tsx +109 -24
  330. package/src/workbench/chat/ChatPanel.tsx +141 -19
  331. package/src/workbench/chat/ChatPhasedRunProgress.tsx +275 -0
  332. package/src/workbench/chat/ChatRenameDialog.tsx +77 -0
  333. package/src/workbench/chat/chat-conversation.css +273 -0
  334. package/src/workbench/chat/chat-ui.css +1132 -0
  335. package/src/workbench/chat/chat.css +3 -0
  336. package/src/workbench/chat/chatConversation.ts +46 -0
  337. package/src/workbench/chat/chatHistoryRowMenuItems.ts +29 -0
  338. package/src/workbench/chat/chatMessageMeta.tsx +252 -0
  339. package/src/workbench/chat/chatScroll.ts +22 -0
  340. package/src/workbench/chat/index.ts +48 -1
  341. package/src/workbench/chat/slashCommand.ts +5 -7
  342. package/src/workbench/chat/types.ts +35 -0
  343. package/src/workbench/chat/useCancelRuntimeOnUnmount.ts +60 -0
  344. package/src/workbench/chat/useChatPrependPagination.ts +233 -0
  345. package/src/workbench/chat/useChatRuntimeState.ts +3 -15
  346. package/src/workbench/chat/useSlashCommandSuggest.ts +77 -24
  347. package/src/workbench/chrome/WorkbenchModalPortal.tsx +52 -0
  348. package/src/workbench/chrome/WorkbenchPlatformContext.tsx +31 -0
  349. package/src/workbench/chrome/index.css +6 -0
  350. package/src/workbench/chrome/workbench-chrome.css +4 -0
  351. package/src/workbench/chrome/workbench-desktop-titlebar.css +60 -0
  352. package/src/workbench/chrome/workbench-host.css +85 -0
  353. package/src/workbench/chrome/workbench-layout-regions.css +42 -0
  354. package/src/workbench/chrome/workbench-platform-chrome.css +142 -0
  355. package/src/workbench/chrome/workbench-shell-titlebar.css +124 -0
  356. package/src/workbench/chrome/workbenchModalViewState.ts +52 -0
  357. package/src/workbench/chrome/workbenchOverlaysContext.tsx +21 -0
  358. package/src/workbench/chrome/workbenchPlatformChrome.ts +40 -0
  359. package/src/workbench/command-palette/command-palette.css +156 -0
  360. package/src/workbench/commands/CommandGroupShell.tsx +131 -0
  361. package/src/workbench/commands/CommandList.tsx +167 -0
  362. package/src/workbench/commands/CommandPalette.tsx +391 -0
  363. package/src/workbench/{ConfirmationFlow.tsx → commands/ConfirmationFlow.tsx} +6 -8
  364. package/src/workbench/{ShortcutCommandBridge.tsx → commands/ShortcutCommandBridge.tsx} +1 -4
  365. package/src/workbench/commands/command-execution-policy.ts +61 -0
  366. package/src/workbench/commands/command-model.ts +279 -0
  367. package/src/workbench/{commands.ts → commands/commands.ts} +63 -7
  368. package/src/workbench/commands/workbenchContextMenu.ts +18 -0
  369. package/src/workbench/editor/WorkbenchEditorTabs.tsx +52 -0
  370. package/src/workbench/editor/editor-tabs-dnd.ts +162 -0
  371. package/src/workbench/editor/editorTabContextMenu.ts +111 -0
  372. package/src/workbench/editor/useEditorTabsStripDnd.ts +262 -0
  373. package/src/workbench/editor/useWorkbenchEditorTabContextMenu.tsx +66 -0
  374. package/src/workbench/editor-tabs/index.ts +22 -0
  375. package/src/workbench/index.ts +288 -37
  376. package/src/workbench/management/AccountManagementPanel.tsx +82 -0
  377. package/src/workbench/management/CommandInspectorPanel.tsx +127 -0
  378. package/src/workbench/management/CommandManagementPanel.tsx +129 -0
  379. package/src/workbench/management/CommandManagementSidebar.tsx +318 -0
  380. package/src/workbench/management/ExtensionManagementPanel.tsx +527 -0
  381. package/src/workbench/management/ExtensionManagementSidebar.tsx +509 -0
  382. package/src/workbench/management/IntegrationCommandActions.tsx +78 -0
  383. package/src/workbench/management/IntegrationSettingsSurface.tsx +290 -0
  384. package/src/workbench/management/IntegrationsShell.tsx +53 -0
  385. package/src/workbench/management/KeybindingCaptureField.tsx +142 -0
  386. package/src/workbench/management/KeybindingManagementPanel.tsx +120 -0
  387. package/src/workbench/management/LibraryCatalogPickerDialog.tsx +208 -0
  388. package/src/workbench/management/LibraryFacetFilterDialog.tsx +62 -0
  389. package/src/workbench/management/ManagementCard.tsx +89 -0
  390. package/src/workbench/management/ManagementFilterChips.tsx +41 -0
  391. package/src/workbench/management/ManagementGroup.tsx +56 -0
  392. package/src/workbench/management/ManagementPanelControls.tsx +43 -0
  393. package/src/workbench/management/ManagementPanelFrame.tsx +109 -0
  394. package/src/workbench/management/WorkbenchDialogFrame.tsx +148 -0
  395. package/src/workbench/management/WorkbenchNotice.tsx +211 -0
  396. package/src/workbench/management/build-command-management-groups.ts +157 -0
  397. package/src/workbench/management/command-inspector-uri.ts +26 -0
  398. package/src/workbench/management/extension-category-display.ts +42 -0
  399. package/src/workbench/management/extension-install-approval.ts +72 -0
  400. package/src/workbench/management/format-command-run-state.ts +19 -0
  401. package/src/workbench/management/index.ts +137 -0
  402. package/src/workbench/management/integration-command-action.ts +25 -0
  403. package/src/workbench/management/library-catalog-picker-dialog.css +56 -0
  404. package/src/workbench/management/library-facet-filter-dialog.css +8 -0
  405. package/src/workbench/management/management-panel.css +444 -0
  406. package/src/workbench/management/management.css +4 -0
  407. package/src/workbench/management/types.ts +139 -0
  408. package/src/workbench/{MarkdownPreview.tsx → markdown/MarkdownPreview.tsx} +26 -15
  409. package/src/workbench/markdown/markdownRemarkPlugins.ts +12 -0
  410. package/src/workbench/markdown/sanitizeMarkdownHref.ts +29 -0
  411. package/src/workbench/schema/index.ts +0 -1
  412. package/src/workbench/settings/NavigationPanel.tsx +41 -2
  413. package/src/workbench/settings/SchemaForm.tsx +20 -7
  414. package/src/workbench/settings/SectionTabPanel.tsx +172 -0
  415. package/src/workbench/settings/SectionedPanel.tsx +40 -286
  416. package/src/workbench/settings/StructuredDataForm.tsx +106 -26
  417. package/src/workbench/settings/StructuredDataSchemaPanel.tsx +345 -93
  418. package/src/workbench/settings/StructuredDataTableView.tsx +2 -2
  419. package/src/workbench/settings/WorkbenchPanelRegion.tsx +1 -1
  420. package/src/workbench/settings/WorkbenchSettingsModal.tsx +116 -62
  421. package/src/workbench/settings/WorkbenchSettingsNav.tsx +3 -3
  422. package/src/workbench/settings/extensionSettingsForm.ts +34 -0
  423. package/src/workbench/settings/index.ts +36 -1
  424. package/src/workbench/settings/navigation-panel.css +59 -0
  425. package/src/workbench/settings/panel-region.css +3 -2
  426. package/src/workbench/settings/schema-form.css +36 -0
  427. package/src/workbench/settings/schemaFormSettingSpec.ts +177 -0
  428. package/src/workbench/settings/schemaFormSettingsCategory.tsx +21 -0
  429. package/src/workbench/settings/section-tab-panel.css +157 -0
  430. package/src/workbench/settings/sectionScrollSpyDom.ts +139 -0
  431. package/src/workbench/settings/sectioned-panel.css +162 -0
  432. package/src/workbench/settings/sectionedPanelScrollSpy.ts +158 -28
  433. package/src/workbench/settings/settings-responsive.css +58 -0
  434. package/src/workbench/settings/settings.css +11 -0
  435. package/src/workbench/settings/settingsCommit.tsx +55 -0
  436. package/src/workbench/settings/structured-data-form.css +114 -0
  437. package/src/workbench/settings/structured-data-schema-panel.css +33 -19
  438. package/src/workbench/settings/structuredDataFormModel.ts +140 -0
  439. package/src/workbench/settings/structuredDataSchema.ts +111 -658
  440. package/src/workbench/settings/structuredDataSchemaDate.ts +197 -0
  441. package/src/workbench/settings/structuredDataSchemaField.ts +105 -0
  442. package/src/workbench/settings/structuredDataSchemaSection.ts +74 -0
  443. package/src/workbench/settings/structuredDataSchemaTable.ts +120 -0
  444. package/src/workbench/settings/structuredDataSchemaTypes.ts +308 -0
  445. package/src/workbench/settings/structuredDataSchemaValidation.ts +166 -0
  446. package/src/workbench/settings/useSectionScrollSpy.ts +420 -0
  447. package/src/workbench/settings/workbench-settings-modal.css +273 -0
  448. package/src/workbench/shell/ActivityBar.tsx +159 -0
  449. package/src/workbench/{ArtifactShell.tsx → shell/ArtifactShell.tsx} +30 -30
  450. package/src/workbench/shell/SplitView.tsx +485 -0
  451. package/src/workbench/{StatusBar.tsx → shell/StatusBar.tsx} +10 -8
  452. package/src/workbench/{StructuredArtifactEditor.tsx → shell/StructuredArtifactEditor.tsx} +9 -9
  453. package/src/workbench/{Timeline.tsx → shell/Timeline.tsx} +19 -24
  454. package/src/workbench/shell/WorkbenchCanvasShell.defaults.ts +106 -0
  455. package/src/workbench/shell/WorkbenchCanvasShell.model.ts +46 -0
  456. package/src/workbench/{WorkbenchCanvasShell.tsx → shell/WorkbenchCanvasShell.tsx} +34 -148
  457. package/src/workbench/shell/WorkbenchDesktopTitleBar.tsx +126 -0
  458. package/src/workbench/shell/WorkbenchShell.tsx +192 -0
  459. package/src/workbench/shell/WorkbenchShellTitleBarLayoutControls.tsx +80 -0
  460. package/src/workbench/shell/WorkbenchStandaloneShell.tsx +604 -0
  461. package/src/workbench/shell/WorkbenchViewEditor.tsx +75 -0
  462. package/src/workbench/shell/WorkbenchViewSidebar.tsx +85 -0
  463. package/src/workbench/shell/WorkbenchWindowChromeControls.tsx +293 -0
  464. package/src/workbench/shell/activity-bar.css +245 -0
  465. package/src/workbench/shell/activityBarOrder.ts +98 -0
  466. package/src/workbench/shell/appearanceLabels.ts +28 -0
  467. package/src/workbench/shell/confirmation-flow.css +87 -0
  468. package/src/workbench/shell/hardReset.ts +64 -0
  469. package/src/workbench/shell/index.css +5 -0
  470. package/src/workbench/shell/shell.ts +152 -0
  471. package/src/workbench/shell/shellPresets.ts +36 -0
  472. package/src/workbench/{shellState.ts → shell/shellState.ts} +16 -23
  473. package/src/workbench/shell/shellViewModel.ts +160 -0
  474. package/src/workbench/shell/sidebarViewPlacementDnd.ts +61 -0
  475. package/src/workbench/shell/split-view.css +188 -0
  476. package/src/workbench/{standalone.ts → shell/standalone.ts} +11 -11
  477. package/src/workbench/shell/status-bar.css +141 -0
  478. package/src/workbench/{status.ts → shell/status.ts} +10 -6
  479. package/src/workbench/shell/useDeferredWorkbenchMount.ts +71 -0
  480. package/src/workbench/shell/useWorkbenchAppearanceDocumentSync.tsx +17 -0
  481. package/src/workbench/shell/useWorkbenchSidebarActionBarDnd.ts +227 -0
  482. package/src/workbench/shell/useWorkbenchSidebarLayout.tsx +232 -0
  483. package/src/workbench/shell/useWorkbenchSidebarViewPlacementDropZone.ts +194 -0
  484. package/src/workbench/shell/useWorkbenchStandaloneShellStateSync.tsx +112 -0
  485. package/src/workbench/shell/workbenchSidebarLayoutContext.ts +46 -0
  486. package/src/workbench/shell/workbenchStandaloneShellReactContext.tsx +80 -0
  487. package/src/workbench/shell/workbenchViewRouteState.ts +151 -0
  488. package/src/workbench/theme/WorkbenchThemeProvider.tsx +142 -0
  489. package/src/workbench/{theme.ts → theme/theme.ts} +9 -3
  490. package/src/workbench/theme/themePresets.ts +191 -0
  491. package/src/workbench/views/action-list.css +144 -0
  492. package/src/workbench/views/artifact-preview.css +184 -0
  493. package/src/workbench/views/command-inspector.css +98 -0
  494. package/src/workbench/views/command-list.css +356 -0
  495. package/src/workbench/views/commands-sidebar.css +51 -0
  496. package/src/workbench/views/extensions-sidebar.css +175 -0
  497. package/src/workbench/views/multi-provider-explorer.css +182 -0
  498. package/src/workbench/views/search.css +10 -0
  499. package/src/workbench/views/timeline.css +239 -0
  500. package/src/workbench/views/view-hosts.css +37 -0
  501. package/src/workbench/views/view-sidebar.css +21 -0
  502. package/src/workbench/views/views.css +12 -0
  503. package/src/workbench/widgets/widget-tree.css +598 -0
  504. package/src/workbench/widgets/widgets.css +2 -0
  505. package/src/workbench/workspace/WorkspaceDraftsContext.tsx +59 -71
  506. package/src/workbench/workspace/WorkspaceEditor.tsx +27 -123
  507. package/src/workbench/workspace/WorkspaceEditorPanel.tsx +68 -9
  508. package/src/workbench/workspace/WorkspaceExplorer.tsx +149 -51
  509. package/src/workbench/workspace/WorkspaceExplorerPanel.tsx +73 -0
  510. package/src/workbench/workspace/WorkspaceFileIcon.tsx +4 -160
  511. package/src/workbench/workspace/WorkspacePathLabel.tsx +42 -0
  512. package/src/workbench/workspace/WorkspaceSearchPanel.tsx +18 -15
  513. package/src/workbench/workspace/WorkspaceSearchResults.tsx +6 -2
  514. package/src/workbench/workspace/build-workspace-explorer-nodes.ts +44 -0
  515. package/src/workbench/workspace/createVirtualWorkspaceExplorerPort.ts +141 -0
  516. package/src/workbench/workspace/explorer-tree-style.ts +18 -0
  517. package/src/workbench/workspace/index.ts +45 -32
  518. package/src/workbench/workspace/json-config-workbench.css +57 -0
  519. package/src/workbench/workspace/monaco-panel.css +71 -0
  520. package/src/workbench/workspace/path.ts +2 -0
  521. package/src/workbench/workspace/useWorkspaceExplorerController.ts +490 -0
  522. package/src/workbench/workspace/workspace-editor.css +235 -0
  523. package/src/workbench/workspace/workspace-explorer-panel.css +33 -0
  524. package/src/workbench/workspace/workspace.css +5 -0
  525. package/src/workbench/workspace/workspaceExplorerController.ts +193 -0
  526. package/src/workbench/workspace/workspaceJsonDiagnostics.ts +8 -7
  527. package/src/workbench-menu-surfaces.css +57 -0
  528. package/src/jdw/builtins/renderBuiltinWidgetNode.tsx +0 -126
  529. package/src/layout/SideBarViewFrame.tsx +0 -367
  530. package/src/primitives/Checkbox.tsx +0 -21
  531. package/src/primitives/NumberInput.tsx +0 -38
  532. package/src/primitives/ScrollArea.tsx +0 -42
  533. package/src/primitives/Select.tsx +0 -1
  534. package/src/primitives/StatusBar.tsx +0 -46
  535. package/src/primitives/WorkbenchChrome.tsx +0 -424
  536. package/src/workbench/ActivityBar.tsx +0 -52
  537. package/src/workbench/CommandPalette.tsx +0 -819
  538. package/src/workbench/SplitView.tsx +0 -136
  539. package/src/workbench/WorkbenchShell.tsx +0 -74
  540. package/src/workbench/WorkbenchStandaloneShell.tsx +0 -318
  541. package/src/workbench/shell.ts +0 -15
  542. package/src/workbench/workspace/MultiProviderExplorer.tsx +0 -625
  543. /package/src/workbench/{keyboard.ts → commands/keyboard.ts} +0 -0
@@ -1,58 +1,205 @@
1
- import { useEffect, useMemo, useState } from 'react';
1
+ import { useEffect, useMemo, useRef, useState } from 'react';
2
2
  import type { WidgetRegistryContract } from '@workbench-kit/contracts';
3
3
  import type { WidgetAssetCatalogContract, WidgetPlacementAsset } from '@workbench-kit/contracts';
4
4
  import {
5
5
  applyWidgetDocumentPatch,
6
+ collectJsonWidgetListenBindings,
6
7
  createJdwDocumentJsonSchema,
7
8
  createWidgetDocument,
8
9
  firstSelectedWidgetPath,
10
+ findSourceRangeForPath,
9
11
  getWidgetAtPath,
10
12
  getWidgetChildren,
11
13
  materializeWidgetPlacementAsset,
12
14
  normalizeWidgetForParent,
15
+ reflowGridChildren,
13
16
  ROOT_WIDGET_PATH,
14
17
  selectWidgetPath,
15
18
  validateJsonWidgetData,
16
19
  type GenericWidget,
20
+ type JsonWidgetNode,
21
+ type JsonWidgetValueMap,
22
+ type ValidationIssue,
23
+ type WidgetPatch,
17
24
  type WidgetPath,
25
+ type WidgetPathSegment,
18
26
  type WidgetSelectionState,
19
27
  } from '@workbench-kit/jdw';
20
28
 
21
- import { ResizablePanels } from '../primitives/WorkbenchEditor.js';
29
+ import { ResizablePanels } from '../primitives/workbench-editor';
30
+ import { WorkbenchLabeledPane } from '../layout/panel';
22
31
  import type { WorkspaceEditorTheme } from '../workbench/workspace/WorkspaceEditor.js';
23
- import { JdwPreview } from '../jdw/JdwPreview.js';
32
+ import type { JsonEditorProblem } from '../jdw/JsonCodeEditorPane.js';
24
33
  import { WidgetAssetPalette } from './WidgetAssetPalette.js';
34
+ import {
35
+ WidgetTreeCanvasPreview,
36
+ type WidgetTreeCanvasAssetDropOperation,
37
+ } from './WidgetTreeCanvasPreview.js';
25
38
  import { WidgetInspectorPanel } from './WidgetInspectorPanel.js';
26
39
  import { WidgetSourceEditor } from './WidgetSourceEditor.js';
27
40
  import { WidgetTreeSidePanel } from './WidgetTreeSidePanel.js';
28
- import { WidgetTreeView } from './WidgetTreeView.js';
29
- import { canAddChildren } from './widget-tree-layout.js';
41
+ import {
42
+ WidgetTreeView,
43
+ type WidgetTreeAssetDropOperation,
44
+ type WidgetTreeMoveOperation,
45
+ } from './WidgetTreeView.js';
46
+ import { canAddChildren, insertedWidgetPathForParent } from './widget-tree-layout.js';
30
47
  import {
31
48
  DEFAULT_WIDGET_TREE_VIEW_MODE,
32
49
  resolveWidgetTreeLabMode,
33
50
  type WidgetTreeViewMode,
34
51
  } from './widget-tree-mode.js';
35
52
 
53
+ type JsonEditorProblemLocation = Pick<
54
+ JsonEditorProblem,
55
+ 'startLineNumber' | 'startColumn' | 'endLineNumber' | 'endColumn'
56
+ >;
57
+
58
+ function fallbackJsonEditorProblemLocation(): JsonEditorProblemLocation {
59
+ return {
60
+ startLineNumber: 1,
61
+ startColumn: 1,
62
+ endLineNumber: 1,
63
+ endColumn: 2,
64
+ };
65
+ }
66
+
67
+ function resolveWidgetProblemLocation(source: string, path: WidgetPath): JsonEditorProblemLocation {
68
+ for (let depth = path.length; depth >= 0; depth--) {
69
+ const candidate = findSourceRangeForPath(source, path.slice(0, depth));
70
+ if (candidate) return candidate;
71
+ }
72
+
73
+ return fallbackJsonEditorProblemLocation();
74
+ }
75
+
76
+ export function widgetPathFromJdwIssuePath(issuePath: string): WidgetPath {
77
+ const path: WidgetPathSegment[] = [];
78
+ const childPattern = /\.args\.(children\[(\d+)\]|child)/g;
79
+ let match: RegExpExecArray | null;
80
+
81
+ while ((match = childPattern.exec(issuePath)) !== null) {
82
+ if (match[1] === 'child') {
83
+ path.push({ kind: 'child' });
84
+ continue;
85
+ }
86
+
87
+ const index = Number(match[2]);
88
+ if (Number.isInteger(index) && index >= 0) {
89
+ path.push({ kind: 'children', index });
90
+ }
91
+ }
92
+
93
+ return path;
94
+ }
95
+
96
+ export function createWidgetTreeValidationProblems(
97
+ source: string,
98
+ issues: readonly ValidationIssue[],
99
+ ): readonly JsonEditorProblem[] {
100
+ return issues.map((issue) => ({
101
+ ...resolveWidgetProblemLocation(source, widgetPathFromJdwIssuePath(issue.path)),
102
+ message: `${issue.path}: ${issue.message}`,
103
+ severity: 8,
104
+ }));
105
+ }
106
+
107
+ export function createWidgetTreeListenProblems(
108
+ source: string,
109
+ node: JsonWidgetNode,
110
+ ): readonly JsonEditorProblem[] {
111
+ return collectJsonWidgetListenBindings(node).flatMap((binding) => {
112
+ const location = resolveWidgetProblemLocation(source, binding.widgetPath);
113
+ return [
114
+ ...binding.missingListen.map((dependency) => ({
115
+ ...location,
116
+ message: `${binding.nodePath}: listen is missing "${dependency}" for a dynamic value.`,
117
+ severity: 4,
118
+ })),
119
+ ...binding.unusedListen.map((dependency) => ({
120
+ ...location,
121
+ message: `${binding.nodePath}: listen includes "${dependency}" but this node does not reference it.`,
122
+ severity: 4,
123
+ })),
124
+ ];
125
+ });
126
+ }
127
+
36
128
  export interface WidgetTreeLabProps {
37
129
  readonly path?: string | undefined;
38
130
  readonly value: string;
39
131
  readonly onChange: (value: string) => void;
40
132
  readonly onSave?: (() => void) | undefined;
133
+ /** Fires when outline/preview selection changes (including auto-select root). */
134
+ readonly onSelectedPathChange?: ((path: WidgetPath | null) => void) | undefined;
135
+ readonly previewValues?: JsonWidgetValueMap | undefined;
41
136
  readonly registry?: WidgetRegistryContract<unknown>;
42
137
  readonly assetCatalog?: WidgetAssetCatalogContract | undefined;
138
+ readonly loadDocument?: ((path: string) => string | null) | undefined;
43
139
  readonly readOnly?: boolean;
140
+ /** When false, Design mode omits the Monaco source column (host Code pane owns source). */
141
+ readonly showDesignSource?: boolean | undefined;
44
142
  readonly theme?: WorkspaceEditorTheme | undefined;
45
143
  readonly viewMode?: WidgetTreeViewMode;
46
144
  }
47
145
 
146
+ function widgetPathSegmentEquals(
147
+ left: WidgetPath[number],
148
+ right: WidgetPath[number] | undefined,
149
+ ): boolean {
150
+ if (!right || left.kind !== right.kind) return false;
151
+ if (left.kind === 'child') return true;
152
+ return right.kind === 'children' && left.index === right.index;
153
+ }
154
+
155
+ function adjustReparentTargetParentPath(
156
+ fromPath: WidgetPath,
157
+ toParentPath: WidgetPath,
158
+ ): WidgetPath {
159
+ const removedSegment = fromPath[fromPath.length - 1];
160
+ if (!removedSegment || removedSegment.kind !== 'children') return toParentPath;
161
+
162
+ const removedParentPath = fromPath.slice(0, -1);
163
+ return toParentPath.map((segment, depth) => {
164
+ if (segment.kind !== 'children' || depth !== removedParentPath.length) return segment;
165
+
166
+ const sameParent = removedParentPath.every((parentSegment, index) =>
167
+ widgetPathSegmentEquals(parentSegment, toParentPath[index]),
168
+ );
169
+ if (sameParent && removedSegment.index < segment.index) {
170
+ return { kind: 'children', index: segment.index - 1 } as const;
171
+ }
172
+
173
+ return segment;
174
+ });
175
+ }
176
+
177
+ function resolveReparentedSelectionPath(
178
+ root: GenericWidget,
179
+ patch: Extract<WidgetPatch, { type: 'reparent-widget' }>,
180
+ ): WidgetPath | null {
181
+ const targetParent = getWidgetAtPath(root, patch.toParentPath);
182
+ if (!targetParent) return null;
183
+
184
+ return insertedWidgetPathForParent(
185
+ targetParent,
186
+ adjustReparentTargetParentPath(patch.fromPath, patch.toParentPath),
187
+ patch.insertIndex,
188
+ );
189
+ }
190
+
48
191
  export function WidgetTreeLab({
49
192
  path,
50
193
  value,
51
194
  onChange,
52
195
  onSave,
196
+ onSelectedPathChange,
197
+ previewValues,
53
198
  registry,
54
199
  assetCatalog,
200
+ loadDocument,
55
201
  readOnly = false,
202
+ showDesignSource = true,
56
203
  theme = 'dark',
57
204
  viewMode = DEFAULT_WIDGET_TREE_VIEW_MODE,
58
205
  }: WidgetTreeLabProps) {
@@ -70,23 +217,25 @@ export function WidgetTreeLab({
70
217
 
71
218
  return validateJsonWidgetData(value, {
72
219
  registeredTypes,
73
- strictKnownTypes: Boolean(registry),
220
+ strictKnownTypes: true,
74
221
  });
75
222
  }, [document.parseError, registry, registeredTypes, value]);
76
- const sourceValidationError = useMemo(() => {
77
- if (document.parseError !== null) {
78
- return document.parseError;
223
+ const sourceProblems = useMemo<readonly JsonEditorProblem[]>(() => {
224
+ if (!validation) {
225
+ return [];
79
226
  }
80
227
 
81
- if (!validation || validation.valid || validation.issues.length === 0) {
82
- return null;
228
+ const validationProblems = createWidgetTreeValidationProblems(value, validation.issues);
229
+ if (!validation.valid || !validation.value) {
230
+ return validationProblems;
83
231
  }
84
232
 
85
- const [firstIssue] = validation.issues;
86
- return firstIssue ? `${firstIssue.path}: ${firstIssue.message}` : null;
87
- }, [document.parseError, validation]);
233
+ return [...validationProblems, ...createWidgetTreeListenProblems(value, validation.value)];
234
+ }, [validation, value]);
88
235
 
89
236
  const [selection, setSelection] = useState<WidgetSelectionState>({ pathKeys: new Set() });
237
+ const [inspectorFocusRequest, setInspectorFocusRequest] = useState(0);
238
+ const inspectorPanelRef = useRef<HTMLDivElement | null>(null);
90
239
 
91
240
  useEffect(() => {
92
241
  if (document.parseError !== null || document.root === null) {
@@ -115,21 +264,71 @@ export function WidgetTreeLab({
115
264
  return getWidgetAtPath(document.root, selectedPath.slice(0, -1));
116
265
  }, [document.root, selectedPath]);
117
266
 
267
+ useEffect(() => {
268
+ onSelectedPathChange?.(selectedPath);
269
+ }, [onSelectedPathChange, selectedPath]);
270
+
271
+ useEffect(() => {
272
+ if (inspectorFocusRequest === 0) return;
273
+
274
+ const panel = inspectorPanelRef.current;
275
+ const focusTarget = panel?.querySelector<HTMLElement>(
276
+ 'input:not(:disabled), select:not(:disabled), textarea:not(:disabled), button:not(:disabled), [tabindex]:not([tabindex="-1"])',
277
+ );
278
+
279
+ (focusTarget ?? panel)?.focus();
280
+ }, [inspectorFocusRequest, selectedPath]);
281
+
282
+ const focusPropertyDetailTab = () => {
283
+ setInspectorFocusRequest((current) => current + 1);
284
+ };
285
+
118
286
  const handleSelectPath = (nextPath: WidgetPath) => {
119
287
  setSelection((current) => selectWidgetPath(current, nextPath));
120
288
  };
121
289
 
122
- const applyPatch = (patch: Parameters<typeof applyWidgetDocumentPatch>[1]) => {
290
+ const handleActivatePath = (nextPath: WidgetPath) => {
291
+ setSelection((current) => selectWidgetPath(current, nextPath));
292
+ focusPropertyDetailTab();
293
+ };
294
+
295
+ const handlePreviewSelectPath = (nextPath: WidgetPath) => {
296
+ setSelection((current) => selectWidgetPath(current, nextPath));
297
+ };
298
+
299
+ const applyPatch = (patch: WidgetPatch): boolean => {
123
300
  const nextSource = applyWidgetDocumentPatch(value, patch);
124
301
  if (nextSource !== null) {
125
302
  onChange(nextSource);
303
+ return nextSource !== value;
126
304
  }
305
+
306
+ return false;
307
+ };
308
+
309
+ const handleCanvasPatch = (patch: WidgetPatch): boolean => {
310
+ const nextSelectionPath =
311
+ patch.type === 'reparent-widget' && document.root
312
+ ? resolveReparentedSelectionPath(document.root, patch)
313
+ : null;
314
+ const changed = applyPatch(patch);
315
+ if (changed && nextSelectionPath) {
316
+ setSelection((current) => selectWidgetPath(current, nextSelectionPath));
317
+ focusPropertyDetailTab();
318
+ }
319
+ return changed;
127
320
  };
128
321
 
129
322
  const handleInspectorPatch = (nextWidget: GenericWidget) => {
130
323
  if (!selectedPath) return;
131
- const widget =
324
+ const normalizedWidget =
132
325
  parentWidget !== null ? normalizeWidgetForParent(nextWidget, parentWidget) : nextWidget;
326
+ const widget =
327
+ selectedWidget?.type === 'grid' &&
328
+ normalizedWidget.type === 'grid' &&
329
+ selectedWidget.columns !== normalizedWidget.columns
330
+ ? reflowGridChildren(normalizedWidget)
331
+ : normalizedWidget;
133
332
  applyPatch({
134
333
  type: 'replace-widget',
135
334
  path: selectedPath,
@@ -140,12 +339,17 @@ export function WidgetTreeLab({
140
339
  const handleInsertChild = (child: GenericWidget) => {
141
340
  if (!selectedPath || !selectedWidget) return;
142
341
  const index = getWidgetChildren(selectedWidget).length;
143
- applyPatch({
342
+ const insertedPath = insertedWidgetPathForParent(selectedWidget, selectedPath, index);
343
+ const changed = applyPatch({
144
344
  type: 'insert-child',
145
345
  parentPath: selectedPath,
146
346
  index,
147
347
  child,
148
348
  });
349
+ if (changed) {
350
+ setSelection((current) => selectWidgetPath(current, insertedPath));
351
+ focusPropertyDetailTab();
352
+ }
149
353
  };
150
354
 
151
355
  const handlePlaceAsset = (asset: WidgetPlacementAsset) => {
@@ -153,74 +357,171 @@ export function WidgetTreeLab({
153
357
  handleInsertChild(materializeWidgetPlacementAsset(asset, selectedWidget));
154
358
  };
155
359
 
156
- const handleRemove = () => {
157
- if (!selectedPath || selectedPath.length === 0) return;
360
+ const handlePlaceAssetPath = (operation: WidgetTreeAssetDropOperation) => {
361
+ if (!document.root) return;
362
+
363
+ const parent = getWidgetAtPath(document.root, operation.parentPath);
364
+ if (!parent || !canAddChildren(parent)) return;
365
+
366
+ const changed = applyPatch({
367
+ type: 'insert-child',
368
+ parentPath: operation.parentPath,
369
+ index: operation.insertIndex,
370
+ child: materializeWidgetPlacementAsset(operation.asset, parent),
371
+ });
372
+ if (changed) {
373
+ setSelection((current) => selectWidgetPath(current, operation.nextPath));
374
+ focusPropertyDetailTab();
375
+ }
376
+ };
377
+
378
+ const handlePlaceAssetPreviewPath = (operation: WidgetTreeCanvasAssetDropOperation) => {
379
+ if (!document.root) return;
380
+
381
+ const parent = getWidgetAtPath(document.root, operation.parentPath);
382
+ if (!parent || !canAddChildren(parent)) return;
383
+
384
+ const changed = applyPatch({
385
+ type: 'insert-child',
386
+ parentPath: operation.parentPath,
387
+ index: operation.insertIndex,
388
+ child: materializeWidgetPlacementAsset(operation.asset, parent),
389
+ });
390
+ if (changed) {
391
+ setSelection((current) => selectWidgetPath(current, operation.nextPath));
392
+ focusPropertyDetailTab();
393
+ }
394
+ };
395
+
396
+ const handleRemovePath = (pathToRemove: WidgetPath) => {
397
+ if (pathToRemove.length === 0) return;
398
+ const parentPath = pathToRemove.slice(0, -1);
158
399
  applyPatch({
159
400
  type: 'remove-widget',
160
- path: selectedPath,
401
+ path: pathToRemove,
161
402
  });
162
- setSelection((current) => selectWidgetPath(current, ROOT_WIDGET_PATH));
403
+ setSelection((current) => selectWidgetPath(current, parentPath));
404
+ };
405
+
406
+ const handleRemove = () => {
407
+ if (!selectedPath) return;
408
+ handleRemovePath(selectedPath);
409
+ };
410
+
411
+ const handleMovePath = (operation: WidgetTreeMoveOperation) => {
412
+ const changed =
413
+ operation.kind === 'reorder'
414
+ ? applyPatch({
415
+ type: 'reorder-child',
416
+ parentPath: operation.parentPath,
417
+ fromIndex: operation.fromIndex,
418
+ toIndex: operation.toIndex,
419
+ })
420
+ : applyPatch({
421
+ type: 'reparent-widget',
422
+ fromPath: operation.fromPath,
423
+ toParentPath: operation.toParentPath,
424
+ insertIndex: operation.insertIndex,
425
+ });
426
+ if (changed) {
427
+ setSelection((current) => selectWidgetPath(current, operation.nextPath));
428
+ }
163
429
  };
164
430
 
165
431
  const sourcePane = (
166
432
  <WidgetSourceEditor
167
433
  jsonSchema={jsonSchema}
168
- parseError={sourceValidationError}
434
+ parseError={document.parseError}
169
435
  path={path}
436
+ problems={sourceProblems}
170
437
  readOnly={readOnly}
438
+ root={document.root}
439
+ selectedPath={selectedPath}
171
440
  showProblemsPanel
172
441
  theme={theme}
173
442
  value={value}
174
443
  onChange={onChange}
175
444
  onSave={onSave}
445
+ onSelectPath={handleSelectPath}
176
446
  />
177
447
  );
178
448
 
179
- const sidePanel = (
180
- <WidgetTreeSidePanel
181
- assets={
182
- assetCatalog ? (
183
- <WidgetAssetPalette
184
- assetsByCategory={assetCatalog.assetsByCategory()}
185
- readOnly={readOnly}
186
- selectedContainer={canAddChildren(selectedWidget) ? selectedWidget : null}
187
- onPlaceAsset={handlePlaceAsset}
188
- />
189
- ) : (
190
- <div className="widget-tree-asset-palette widget-tree-asset-palette--empty">
191
- No asset catalog configured.
192
- </div>
193
- )
194
- }
195
- outline={
196
- <WidgetTreeView
197
- parseError={document.parseError}
198
- root={document.root}
199
- selection={selection}
200
- onSelectPath={handleSelectPath}
201
- />
202
- }
203
- properties={
204
- <WidgetInspectorPanel
205
- parentWidget={parentWidget}
206
- path={selectedPath}
449
+ const assetsSidebar = (
450
+ <div
451
+ aria-label="Widget assets"
452
+ className="widget-tree-lab__sidebar widget-tree-lab__sidebar--left"
453
+ data-testid="widget-tree-lab-assets-sidebar"
454
+ role="region"
455
+ >
456
+ {assetCatalog ? (
457
+ <WidgetAssetPalette
458
+ assetsByCategory={assetCatalog.assetsByCategory()}
207
459
  readOnly={readOnly}
208
- widget={selectedWidget}
209
- widgetRegistry={registry}
210
- onPatch={handleInspectorPatch}
211
- onRemove={handleRemove}
460
+ selectedContainer={canAddChildren(selectedWidget) ? selectedWidget : null}
461
+ onPlaceAsset={handlePlaceAsset}
212
462
  />
213
- }
214
- />
463
+ ) : (
464
+ <div className="widget-tree-asset-palette widget-tree-asset-palette--empty">
465
+ No asset catalog configured.
466
+ </div>
467
+ )}
468
+ </div>
469
+ );
470
+
471
+ const authoringSidebar = (
472
+ <div
473
+ className="widget-tree-lab__sidebar widget-tree-lab__sidebar--right"
474
+ data-testid="widget-tree-lab-authoring-sidebar"
475
+ >
476
+ <WidgetTreeSidePanel
477
+ outline={
478
+ <WidgetTreeView
479
+ parseError={document.parseError}
480
+ root={document.root}
481
+ selection={selection}
482
+ onActivatePath={handleActivatePath}
483
+ onDeletePath={readOnly ? undefined : handleRemovePath}
484
+ onMovePath={readOnly ? undefined : handleMovePath}
485
+ onPlaceAssetPath={readOnly ? undefined : handlePlaceAssetPath}
486
+ onSelectPath={handleSelectPath}
487
+ />
488
+ }
489
+ properties={
490
+ <WidgetInspectorPanel
491
+ panelRef={inspectorPanelRef}
492
+ parentWidget={parentWidget}
493
+ path={selectedPath}
494
+ readOnly={readOnly}
495
+ widget={selectedWidget}
496
+ widgetRegistry={registry}
497
+ onPatch={handleInspectorPatch}
498
+ onRemove={handleRemove}
499
+ />
500
+ }
501
+ />
502
+ </div>
215
503
  );
216
504
 
217
505
  const previewPane = (
218
- <section aria-label="Widget preview" className="widget-tree-lab__preview">
219
- <header className="widget-tree-lab__preview-header">Preview</header>
220
- <div className="widget-tree-lab__preview-body">
221
- <JdwPreview json={value} registry={registry} />
222
- </div>
223
- </section>
506
+ <WorkbenchLabeledPane
507
+ aria-label="Widget preview"
508
+ className="widget-tree-lab__preview"
509
+ title="Preview"
510
+ >
511
+ <WidgetTreeCanvasPreview
512
+ documentPath={path ?? null}
513
+ json={value}
514
+ loadDocument={loadDocument}
515
+ previewValues={previewValues}
516
+ readOnly={readOnly}
517
+ registry={registry}
518
+ root={document.root}
519
+ selectedPath={selectedPath}
520
+ onPatch={handleCanvasPatch}
521
+ onPlaceAssetPath={readOnly ? undefined : handlePlaceAssetPreviewPath}
522
+ onSelectPath={handlePreviewSelectPath}
523
+ />
524
+ </WorkbenchLabeledPane>
224
525
  );
225
526
 
226
527
  if (resolvedMode === 'code') {
@@ -235,37 +536,64 @@ export function WidgetTreeLab({
235
536
  );
236
537
  }
237
538
 
539
+ const mainPane = showDesignSource ? (
540
+ <ResizablePanels
541
+ className="widget-tree-lab__main"
542
+ data-testid="widget-tree-lab-main-pane"
543
+ defaultFirstSize={280}
544
+ direction="vertical"
545
+ minFirstSize={140}
546
+ minSecondSize={200}
547
+ style={{ height: '100%', minHeight: 0 }}
548
+ first={<div className="widget-tree-lab__design-source">{sourcePane}</div>}
549
+ second={
550
+ <div className="widget-tree-lab__design-render" data-testid="widget-tree-lab-render-pane">
551
+ {previewPane}
552
+ </div>
553
+ }
554
+ />
555
+ ) : (
556
+ <div
557
+ className="widget-tree-lab__main widget-tree-lab__main--preview-only"
558
+ data-testid="widget-tree-lab-main-pane"
559
+ style={{ height: '100%', minHeight: 0 }}
560
+ >
561
+ <div className="widget-tree-lab__design-render" data-testid="widget-tree-lab-render-pane">
562
+ {previewPane}
563
+ </div>
564
+ </div>
565
+ );
566
+
567
+ const centerAndRight = (
568
+ <ResizablePanels
569
+ className="widget-tree-lab__center-right"
570
+ data-testid="widget-tree-lab-center-right"
571
+ defaultFirstSize={280}
572
+ minFirstSize={200}
573
+ minSecondSize={220}
574
+ sizedPanel="second"
575
+ style={{ height: '100%', minHeight: 0 }}
576
+ first={mainPane}
577
+ second={authoringSidebar}
578
+ />
579
+ );
580
+
238
581
  return (
239
582
  <div
240
583
  className="widget-tree-lab widget-tree-lab--design"
241
584
  data-mode="design"
585
+ data-show-design-source={showDesignSource ? 'true' : 'false'}
242
586
  data-testid="widget-tree-lab"
243
587
  >
244
588
  <ResizablePanels
245
589
  className="widget-tree-lab__design"
246
590
  data-testid="widget-tree-workspace"
247
- defaultFirstSize={560}
248
- minFirstSize={360}
249
- minSecondSize={280}
591
+ defaultFirstSize={220}
592
+ minFirstSize={160}
593
+ minSecondSize={420}
250
594
  style={{ height: '100%', minHeight: 0 }}
251
- first={
252
- <ResizablePanels
253
- className="widget-tree-lab__design-data"
254
- data-testid="widget-tree-lab-data-pane"
255
- defaultFirstSize={320}
256
- direction="vertical"
257
- minFirstSize={160}
258
- minSecondSize={180}
259
- style={{ height: '100%', minHeight: 0 }}
260
- first={<div className="widget-tree-lab__design-source">{sourcePane}</div>}
261
- second={<div className="widget-tree-lab__design-tools">{sidePanel}</div>}
262
- />
263
- }
264
- second={
265
- <div className="widget-tree-lab__design-render" data-testid="widget-tree-lab-render-pane">
266
- {previewPane}
267
- </div>
268
- }
595
+ first={assetsSidebar}
596
+ second={centerAndRight}
269
597
  />
270
598
  </div>
271
599
  );
@@ -1,4 +1,5 @@
1
- import { IconButton } from '../primitives/IconButton';
1
+ import type { KeyboardEvent as ReactKeyboardEvent } from 'react';
2
+ import { IconButton } from '../primitives/icon-button';
2
3
  import { cx } from '../utils/cx';
3
4
  import { resolveWidgetTreeLabMode, type WidgetTreeViewMode } from './widget-tree-mode.js';
4
5
 
@@ -8,6 +9,28 @@ export interface WidgetTreeModeControlsProps {
8
9
  readonly onModeChange: (mode: WidgetTreeViewMode) => void;
9
10
  }
10
11
 
12
+ /** Ctrl/Cmd+1 → Design, Ctrl/Cmd+2 → Code. Ignores Alt/Shift chords. */
13
+ export function resolveWidgetTreeModeShortcut(
14
+ event: Pick<
15
+ KeyboardEvent | ReactKeyboardEvent,
16
+ 'key' | 'ctrlKey' | 'metaKey' | 'altKey' | 'shiftKey'
17
+ >,
18
+ ): WidgetTreeViewMode | null {
19
+ if (!(event.ctrlKey || event.metaKey) || event.altKey || event.shiftKey) {
20
+ return null;
21
+ }
22
+
23
+ if (event.key === '1') {
24
+ return 'design';
25
+ }
26
+
27
+ if (event.key === '2') {
28
+ return 'code';
29
+ }
30
+
31
+ return null;
32
+ }
33
+
11
34
  export function WidgetTreeModeControls({
12
35
  className,
13
36
  mode,
@@ -17,7 +40,11 @@ export function WidgetTreeModeControls({
17
40
 
18
41
  return (
19
42
  <div
43
+ aria-keyshortcuts="Control+1 Control+2 Meta+1 Meta+2"
44
+ aria-label="Widget editor mode"
20
45
  className={cx('ui-workbench-artifact-shell__modes', 'widget-tree-mode-controls', className)}
46
+ data-testid="widget-tree-mode-controls"
47
+ role="toolbar"
21
48
  >
22
49
  <IconButton
23
50
  aria-pressed={resolvedMode === 'design'}
@@ -27,6 +54,7 @@ export function WidgetTreeModeControls({
27
54
  )}
28
55
  icon="codicon-layout-sidebar-right"
29
56
  label="Design"
57
+ title="Design (Ctrl+1)"
30
58
  onClick={() => onModeChange('design')}
31
59
  />
32
60
  <IconButton
@@ -37,6 +65,7 @@ export function WidgetTreeModeControls({
37
65
  )}
38
66
  icon="codicon-code"
39
67
  label="Code"
68
+ title="Code (Ctrl+2)"
40
69
  onClick={() => onModeChange('code')}
41
70
  />
42
71
  </div>