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

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 (534) hide show
  1. package/package.json +31 -23
  2. package/src/brand/TilepaperAppIcon.tsx +181 -0
  3. package/src/brand/index.ts +2 -0
  4. package/src/brand/tilepaper-app-icon-geometry.ts +201 -0
  5. package/src/icons/WorkbenchIcon.tsx +57 -0
  6. package/src/icons/WorkbenchIconContext.tsx +25 -0
  7. package/src/icons/file-icon.ts +154 -0
  8. package/src/icons/index.ts +17 -0
  9. package/src/icons/resolveWorkbenchIcon.ts +48 -0
  10. package/src/icons/types.ts +28 -0
  11. package/src/index.ts +261 -71
  12. package/src/jdw/JdwPreview.tsx +165 -8
  13. package/src/jdw/JdwPreviewViewport.tsx +190 -0
  14. package/src/jdw/JsonCodeEditorPane.tsx +165 -15
  15. package/src/jdw/builtins/renderBuiltinWidgetLeaf.tsx +101 -0
  16. package/src/jdw/createBuiltinJdwRegistry.ts +330 -5
  17. package/src/jdw/cssRenderBackend.tsx +96 -7
  18. package/src/jdw/document.ts +0 -3
  19. package/src/jdw/fixtures/jdw-sample-screens.ts +10 -8
  20. package/src/jdw/index.ts +9 -4
  21. package/src/jdw/jdw-preview-viewport.css +41 -0
  22. package/src/jdw/renderJdw.tsx +49 -8
  23. package/src/json-config/JsonConfigWorkbench.tsx +11 -14
  24. package/src/layout/ViewEmptyState.tsx +14 -0
  25. package/src/layout/WorkbenchCanvas.tsx +113 -6
  26. package/src/layout/WorkbenchLayout.tsx +3 -0
  27. package/src/layout/WorkbenchLayoutBase.tsx +43 -2
  28. package/src/layout/WorkbenchMediaPreviewViewport.tsx +122 -0
  29. package/src/layout/WorkbenchPropertyOverrideLabel.tsx +90 -0
  30. package/src/layout/WorkbenchPropertyPanel.tsx +153 -17
  31. package/src/layout/WorkbenchPropertySearch.tsx +51 -0
  32. package/src/layout/WorkbenchTree.tsx +9 -10
  33. package/src/layout/canvas/canvas-drag-ghost.css +21 -0
  34. package/src/layout/canvas/canvas-drag-preview-frame.css +15 -0
  35. package/src/layout/canvas/canvas-drop-indicator.css +16 -0
  36. package/src/layout/canvas/canvas-frame-handle.css +37 -0
  37. package/src/layout/canvas/canvas-frame-surface.css +24 -0
  38. package/src/layout/canvas/canvas-guide-block.css +17 -0
  39. package/src/layout/canvas/canvas-guide-layer.css +6 -0
  40. package/src/layout/canvas/canvas-guide-line.css +22 -0
  41. package/src/layout/canvas/canvas-item-badge.css +23 -0
  42. package/src/layout/canvas/canvas-item-frame.css +54 -0
  43. package/src/layout/canvas/canvas-pane-surface.css +9 -0
  44. package/src/layout/canvas/canvas-placeholder.css +21 -0
  45. package/src/layout/canvas/canvas-resize-frame.css +9 -0
  46. package/src/layout/canvas/canvas-resize-handle.css +74 -0
  47. package/src/layout/canvas/canvas-resize-preview.css +11 -0
  48. package/src/layout/canvas/canvas-selection-marquee.css +14 -0
  49. package/src/layout/canvas/canvas-viewport.css +18 -0
  50. package/src/layout/canvas/index.css +19 -0
  51. package/src/layout/canvas/preview-canvas.css +144 -0
  52. package/src/layout/editor/editor-body.css +9 -0
  53. package/src/layout/editor/editor-bottom-panel.css +44 -0
  54. package/src/layout/editor/editor-frame.css +14 -0
  55. package/src/layout/editor/editor-viewport.css +7 -0
  56. package/src/layout/editor/floating-menu.css +91 -0
  57. package/src/layout/editor/index.css +10 -0
  58. package/src/layout/editor/parse-error.css +9 -0
  59. package/src/layout/editor/problem-item.css +52 -0
  60. package/src/layout/editor/problem-list.css +7 -0
  61. package/src/layout/editor/render-surface.css +13 -0
  62. package/src/layout/fillScrollContract.ts +49 -0
  63. package/src/layout/fullscreen/fullscreen-backdrop.css +31 -0
  64. package/src/layout/fullscreen/fullscreen-button.css +44 -0
  65. package/src/layout/fullscreen/fullscreen-carousel.css +20 -0
  66. package/src/layout/fullscreen/fullscreen-content.css +8 -0
  67. package/src/layout/fullscreen/fullscreen-empty.css +16 -0
  68. package/src/layout/fullscreen/fullscreen-header.css +77 -0
  69. package/src/layout/fullscreen/fullscreen-hero.css +41 -0
  70. package/src/layout/fullscreen/fullscreen-nav-button.css +29 -0
  71. package/src/layout/fullscreen/fullscreen-option.css +83 -0
  72. package/src/layout/fullscreen/fullscreen-pill-row.css +6 -0
  73. package/src/layout/fullscreen/fullscreen-pill.css +10 -0
  74. package/src/layout/fullscreen/fullscreen-root.css +11 -0
  75. package/src/layout/fullscreen/index.css +13 -0
  76. package/src/layout/index.ts +156 -0
  77. package/src/layout/layout-base/banner.css +32 -0
  78. package/src/layout/layout-base/center.css +7 -0
  79. package/src/layout/layout-base/column.css +7 -0
  80. package/src/layout/layout-base/divider.css +5 -0
  81. package/src/layout/layout-base/empty.css +12 -0
  82. package/src/layout/layout-base/fill-scroll.css +36 -0
  83. package/src/layout/layout-base/fill.css +18 -0
  84. package/src/layout/layout-base/index.css +13 -0
  85. package/src/layout/layout-base/pane.css +6 -0
  86. package/src/layout/layout-base/panel-scroll.css +5 -0
  87. package/src/layout/layout-base/panel-surface.css +14 -0
  88. package/src/layout/layout-base/root.css +9 -0
  89. package/src/layout/layout-base/section-title.css +8 -0
  90. package/src/layout/layout.css +10 -0
  91. package/src/layout/layoutHelpers.ts +4 -2
  92. package/src/layout/media/index.css +2 -0
  93. package/src/layout/media/media-preview-viewport.css +69 -0
  94. package/src/layout/{Panel.tsx → panel/Panel.tsx} +29 -40
  95. package/src/layout/panel/TemplateGallery.tsx +90 -0
  96. package/src/layout/panel/WorkbenchAuthoringShell.tsx +57 -0
  97. package/src/layout/panel/WorkbenchLabeledPane.tsx +81 -0
  98. package/src/layout/panel/WorkbenchSidebarStack.tsx +15 -0
  99. package/src/layout/panel/filter-bar.css +59 -0
  100. package/src/layout/panel/index.css +7 -0
  101. package/src/layout/panel/index.ts +70 -0
  102. package/src/layout/panel/preview-pane.css +63 -0
  103. package/src/layout/panel/template-gallery.css +131 -0
  104. package/src/layout/panel/workbench-authoring-shell.css +48 -0
  105. package/src/layout/panel/workbench-labeled-pane.css +69 -0
  106. package/src/layout/panel/workbench-sidebar-stack.css +18 -0
  107. package/src/layout/property/color-input.css +8 -0
  108. package/src/layout/property/color-row.css +6 -0
  109. package/src/layout/property/index.css +15 -0
  110. package/src/layout/property/property-card.css +8 -0
  111. package/src/layout/property/property-grid.css +24 -0
  112. package/src/layout/property/property-hint.css +4 -0
  113. package/src/layout/property/property-inline.css +10 -0
  114. package/src/layout/property/property-key-value.css +29 -0
  115. package/src/layout/property/property-override-label.css +34 -0
  116. package/src/layout/property/property-panel.css +20 -0
  117. package/src/layout/property/property-row.css +17 -0
  118. package/src/layout/property/property-search.css +43 -0
  119. package/src/layout/property/property-section.css +97 -0
  120. package/src/layout/property/property-stack.css +11 -0
  121. package/src/layout/property/property-toggle.css +14 -0
  122. package/src/layout/propertyFieldFilter.ts +84 -0
  123. package/src/layout/sidebar/SideBarViewFrame.tsx +235 -0
  124. package/src/layout/sidebar/SideBarViewTabStrip.tsx +60 -0
  125. package/src/layout/sidebar/SideBarViewTitleMenu.tsx +75 -0
  126. package/src/layout/sidebar/SidebarActionIconBar.tsx +242 -0
  127. package/src/layout/sidebar/SidebarSectionNestingContext.tsx +21 -0
  128. package/src/layout/sidebar/SidebarSlotChrome.tsx +32 -0
  129. package/src/layout/sidebar/SidebarToolbar.tsx +10 -0
  130. package/src/layout/sidebar/WorkbenchActionSidebar.tsx +73 -0
  131. package/src/layout/{WorkbenchSidebarActions.tsx → sidebar/WorkbenchSidebarActions.tsx} +105 -51
  132. package/src/layout/sidebar/WorkbenchSidebarSectionStack.tsx +165 -0
  133. package/src/layout/sidebar/index.css +5 -0
  134. package/src/layout/sidebar/index.ts +55 -0
  135. package/src/layout/sidebar/sidebar-chrome.css +95 -0
  136. package/src/layout/sidebar/sidebar-section-stack.css +25 -0
  137. package/src/layout/sidebar/sidebar-section.css +124 -0
  138. package/src/layout/sidebar/sidebar-view.css +290 -0
  139. package/src/layout/tree/drag-preview.css +25 -0
  140. package/src/layout/tree/index.css +10 -0
  141. package/src/layout/tree/template-glyph.css +96 -0
  142. package/src/layout/tree/tree-action.css +20 -0
  143. package/src/layout/tree/tree-drag-overlay.css +13 -0
  144. package/src/layout/tree/tree-drop-line.css +17 -0
  145. package/src/layout/tree/tree-drop-zone.css +13 -0
  146. package/src/layout/tree/tree-expander.css +23 -0
  147. package/src/layout/tree/tree-item.css +93 -0
  148. package/src/layout/tree/tree.css +49 -0
  149. package/src/layout/usePreviewViewport.ts +428 -0
  150. package/src/modal/ConfirmDialog.tsx +1 -1
  151. package/src/modal/Modal.tsx +148 -305
  152. package/src/modal/ModalResizeHandles.tsx +40 -0
  153. package/src/modal/ModalTitlebar.tsx +86 -0
  154. package/src/modal/modal.css +291 -0
  155. package/src/modal/modalContainer.ts +36 -0
  156. package/src/modal/modalPosition.ts +36 -0
  157. package/src/modal/modalSize.ts +84 -0
  158. package/src/modal/modalTypes.ts +13 -0
  159. package/src/modal/useModalContainerViewport.ts +41 -0
  160. package/src/modal/useModalDrag.ts +118 -0
  161. package/src/modal/useModalResize.ts +122 -0
  162. package/src/modal/useModalWindowFrame.ts +122 -0
  163. package/src/overlay/ContextMenu.tsx +28 -50
  164. package/src/overlay/clampFixedOverlayPosition.ts +22 -0
  165. package/src/overlay/context-menu.css +127 -0
  166. package/src/overlay/index.ts +31 -0
  167. package/src/overlay/measureAnchoredOverlayPanel.ts +107 -0
  168. package/src/overlay/overlay.css +2 -0
  169. package/src/overlay/pointerPassthroughRegion.ts +83 -0
  170. package/src/overlay/useAnchoredOverlayPanel.ts +222 -0
  171. package/src/overlay/useClampedFixedOverlayPosition.ts +27 -0
  172. package/src/overlay/useContextMenuState.ts +59 -0
  173. package/src/overlay/useFixedOverlayDismiss.ts +49 -0
  174. package/src/overlay/usePointerPassthroughRegion.ts +85 -0
  175. package/src/primitives/{AbsoluteBox.tsx → absolute-box/AbsoluteBox.tsx} +1 -1
  176. package/src/primitives/absolute-box/index.ts +1 -0
  177. package/src/primitives/{Badge.tsx → badge/Badge.tsx} +4 -2
  178. package/src/primitives/badge/badge.css +20 -0
  179. package/src/primitives/badge/index.ts +1 -0
  180. package/src/primitives/{Button.tsx → button/Button.tsx} +3 -2
  181. package/src/primitives/button/button.css +76 -0
  182. package/src/primitives/button/index.ts +1 -0
  183. package/src/primitives/catalog-browse-card/CatalogBrowseCard.tsx +121 -0
  184. package/src/primitives/catalog-browse-card/catalog-browse-card.css +175 -0
  185. package/src/primitives/catalog-browse-card/index.ts +1 -0
  186. package/src/primitives/catalog-browse-pane/CatalogBrowseFacetChips.tsx +59 -0
  187. package/src/primitives/catalog-browse-pane/CatalogBrowsePane.tsx +360 -0
  188. package/src/primitives/catalog-browse-pane/catalog-browse-facet-chips.css +8 -0
  189. package/src/primitives/catalog-browse-pane/catalog-browse-pane.css +84 -0
  190. package/src/primitives/catalog-browse-pane/filterCatalogBrowseItems.ts +27 -0
  191. package/src/primitives/catalog-browse-pane/index.ts +3 -0
  192. package/src/primitives/catalog-filter-overlay/CatalogFilterOverlay.tsx +73 -0
  193. package/src/primitives/catalog-filter-overlay/catalog-filter-overlay.css +65 -0
  194. package/src/primitives/catalog-filter-overlay/index.ts +1 -0
  195. package/src/primitives/checkbox/Checkbox.tsx +40 -0
  196. package/src/primitives/checkbox/checkbox.css +81 -0
  197. package/src/primitives/checkbox/index.ts +1 -0
  198. package/src/primitives/chip/Chip.tsx +43 -0
  199. package/src/primitives/chip/chip.css +110 -0
  200. package/src/primitives/chip/index.ts +2 -0
  201. package/src/primitives/clearable-text-input/ClearableTextInput.tsx +78 -0
  202. package/src/primitives/clearable-text-input/clearable-text-input.css +15 -0
  203. package/src/primitives/clearable-text-input/index.ts +1 -0
  204. package/src/primitives/codicon/Codicon.tsx +20 -0
  205. package/src/primitives/codicon/index.ts +1 -0
  206. package/src/primitives/{EmptyState.tsx → empty-state/EmptyState.tsx} +9 -3
  207. package/src/primitives/empty-state/empty-state.css +20 -0
  208. package/src/primitives/empty-state/index.ts +1 -0
  209. package/src/primitives/external-link-button/ExternalLinkButton.tsx +56 -0
  210. package/src/primitives/external-link-button/index.ts +1 -0
  211. package/src/primitives/{Field.tsx → field/Field.tsx} +2 -1
  212. package/src/primitives/field/field.css +51 -0
  213. package/src/primitives/field/index.ts +1 -0
  214. package/src/primitives/file-icon/FileIcon.tsx +21 -0
  215. package/src/primitives/file-icon/index.ts +1 -0
  216. package/src/primitives/{IconButton.tsx → icon-button/IconButton.tsx} +6 -4
  217. package/src/primitives/icon-button/icon-button.css +46 -0
  218. package/src/primitives/icon-button/index.ts +1 -0
  219. package/src/primitives/index.ts +210 -50
  220. package/src/primitives/library-detail-layout/LibraryDetailLayout.tsx +135 -0
  221. package/src/primitives/library-detail-layout/index.ts +1 -0
  222. package/src/primitives/library-detail-layout/library-detail-layout.css +169 -0
  223. package/src/primitives/library-facet-filter-panel/LibraryFacetFilterPanel.tsx +454 -0
  224. package/src/primitives/library-facet-filter-panel/index.ts +1 -0
  225. package/src/primitives/library-facet-filter-panel/library-facet-filter-panel.css +205 -0
  226. package/src/primitives/library-facet-filter-strip/LibraryFacetFilterStrip.tsx +527 -0
  227. package/src/primitives/library-facet-filter-strip/index.ts +1 -0
  228. package/src/primitives/library-facet-filter-strip/library-facet-filter-strip.css +31 -0
  229. package/src/primitives/{List.tsx → list/List.tsx} +15 -6
  230. package/src/primitives/list/index.ts +1 -0
  231. package/src/primitives/list/list-empty-state.css +10 -0
  232. package/src/primitives/list/list-item.css +93 -0
  233. package/src/primitives/list/list.css +6 -0
  234. package/src/primitives/number-input/NumberInput.tsx +235 -0
  235. package/src/primitives/number-input/index.ts +1 -0
  236. package/src/primitives/number-input/number-input.css +105 -0
  237. package/src/primitives/panel-loading/PanelLoading.tsx +29 -0
  238. package/src/primitives/panel-loading/index.ts +1 -0
  239. package/src/primitives/panel-loading/panel-loading.css +16 -0
  240. package/src/primitives/panel-surface/panel-surface.css +77 -0
  241. package/src/primitives/primitives.css +36 -0
  242. package/src/primitives/record-media-hero/RecordMediaHero.tsx +81 -0
  243. package/src/primitives/record-media-hero/index.ts +1 -0
  244. package/src/primitives/record-media-hero/record-media-hero.css +84 -0
  245. package/src/primitives/scroll-area/ScrollArea.tsx +200 -0
  246. package/src/primitives/scroll-area/index.ts +1 -0
  247. package/src/primitives/scroll-area/scroll-area-overlay.css +69 -0
  248. package/src/primitives/scroll-area-infinite-load/ScrollAreaInfiniteSentinel.tsx +22 -0
  249. package/src/primitives/scroll-area-infinite-load/index.ts +2 -0
  250. package/src/primitives/scroll-area-infinite-load/scroll-area-infinite-sentinel.css +6 -0
  251. package/src/primitives/scroll-area-infinite-load/useScrollAreaInfiniteLoad.ts +84 -0
  252. package/src/primitives/searchable-multi-select/SearchableMultiSelect.tsx +378 -0
  253. package/src/primitives/searchable-multi-select/index.ts +9 -0
  254. package/src/primitives/searchable-multi-select/overlay.ts +125 -0
  255. package/src/primitives/searchable-multi-select/searchable-multi-select.css +129 -0
  256. package/src/primitives/select/Select.tsx +21 -3
  257. package/src/primitives/select/overlay.ts +23 -4
  258. package/src/primitives/select/select.app.css +5 -2
  259. package/src/primitives/select/select.css +49 -12
  260. package/src/primitives/styles.css +3 -952
  261. package/src/primitives/tabbed-panels/TabbedPanels.tsx +68 -0
  262. package/src/primitives/tabbed-panels/index.ts +2 -0
  263. package/src/primitives/tabbed-panels/tabbed-panels.css +58 -0
  264. package/src/primitives/{TextArea.tsx → text-area/TextArea.tsx} +2 -1
  265. package/src/primitives/text-area/index.ts +1 -0
  266. package/src/primitives/{TextInput.tsx → text-input/TextInput.tsx} +2 -1
  267. package/src/primitives/text-input/index.ts +1 -0
  268. package/src/primitives/text-input/input.css +54 -0
  269. package/src/primitives/{Toolbar.tsx → toolbar/Toolbar.tsx} +1 -1
  270. package/src/primitives/toolbar/index.ts +1 -0
  271. package/src/primitives/visually-hidden/visually-hidden.css +11 -0
  272. package/src/primitives/{WorkbenchEditor.tsx → workbench-editor/WorkbenchEditor.tsx} +81 -43
  273. package/src/primitives/workbench-editor/button-group.css +10 -0
  274. package/src/primitives/workbench-editor/editor-tabs.css +201 -0
  275. package/src/primitives/workbench-editor/index.ts +1 -0
  276. package/src/primitives/workbench-editor/resizable-panels.css +53 -0
  277. package/src/primitives/workbench-editor/segmented-control.css +98 -0
  278. package/src/primitives/workbench-media-slot/WorkbenchMediaPlaceholder.tsx +25 -0
  279. package/src/primitives/workbench-media-slot/WorkbenchMediaSlot.tsx +60 -0
  280. package/src/primitives/workbench-media-slot/index.ts +2 -0
  281. package/src/primitives/workbench-media-slot/media-slot.css +72 -0
  282. package/src/primitives/workbench-thumbnail/WorkbenchThumbnail.tsx +38 -0
  283. package/src/primitives/workbench-thumbnail/index.ts +1 -0
  284. package/src/primitives/workbench-thumbnail/thumbnail.css +69 -0
  285. package/src/scrollbars.css +77 -2
  286. package/src/styles.css +14 -7735
  287. package/src/test-utils/workbenchMonacoMock.tsx +37 -0
  288. package/src/utils/dragMime.ts +89 -0
  289. package/src/utils/useWorkbenchMediaImage.ts +37 -0
  290. package/src/widget-asset/WidgetAssetEditor.tsx +9 -7
  291. package/src/widget-asset/WidgetAssetModeControls.tsx +1 -1
  292. package/src/widget-asset/WidgetAssetWorkbench.tsx +5 -6
  293. package/src/widget-studio/create-widget-studio-workspace-editor.tsx +1 -2
  294. package/src/widget-studio/index.ts +4 -1
  295. package/src/widget-studio/resolve-widget-studio-asset-catalog.ts +27 -10
  296. package/src/widget-tree/WidgetAssetPalette.tsx +35 -7
  297. package/src/widget-tree/WidgetInspectorPanel.tsx +53 -3
  298. package/src/widget-tree/WidgetSourceEditor.tsx +90 -3
  299. package/src/widget-tree/WidgetTreeCanvasPreview.tsx +875 -0
  300. package/src/widget-tree/WidgetTreeLab.tsx +411 -83
  301. package/src/widget-tree/WidgetTreeModeControls.tsx +30 -1
  302. package/src/widget-tree/WidgetTreeSidePanel.tsx +24 -34
  303. package/src/widget-tree/WidgetTreeView.tsx +711 -11
  304. package/src/widget-tree/WidgetTreeWorkbench.tsx +59 -15
  305. package/src/widget-tree/WidgetTreeWorkspaceShell.tsx +26 -8
  306. package/src/widget-tree/index.ts +22 -4
  307. package/src/widget-tree/widget-placement-asset-dnd.ts +35 -0
  308. package/src/widget-tree/widget-tree-document.ts +3 -9
  309. package/src/widget-tree/widget-tree-editor-state.ts +40 -0
  310. package/src/widget-tree/widget-tree-layout.ts +48 -3
  311. package/src/widget-tree/widget-tree-play-helpers.ts +69 -58
  312. package/src/workbench/ActivityBar.tsx +128 -21
  313. package/src/workbench/ArtifactShell.tsx +8 -8
  314. package/src/workbench/CommandGroupShell.tsx +131 -0
  315. package/src/workbench/CommandList.tsx +167 -0
  316. package/src/workbench/CommandPalette.tsx +194 -596
  317. package/src/workbench/ConfirmationFlow.tsx +3 -5
  318. package/src/workbench/MarkdownPreview.tsx +8 -12
  319. package/src/workbench/ShortcutCommandBridge.tsx +1 -4
  320. package/src/workbench/SplitView.tsx +385 -36
  321. package/src/workbench/StatusBar.tsx +4 -2
  322. package/src/workbench/StructuredArtifactEditor.tsx +3 -3
  323. package/src/workbench/Timeline.tsx +2 -7
  324. package/src/workbench/WorkbenchCanvasShell.defaults.ts +106 -0
  325. package/src/workbench/WorkbenchCanvasShell.model.ts +46 -0
  326. package/src/workbench/WorkbenchCanvasShell.tsx +32 -146
  327. package/src/workbench/WorkbenchDesktopTitleBar.tsx +126 -0
  328. package/src/workbench/WorkbenchEditorTabs.tsx +52 -0
  329. package/src/workbench/WorkbenchModalPortal.tsx +52 -0
  330. package/src/workbench/WorkbenchPlatformContext.tsx +31 -0
  331. package/src/workbench/WorkbenchShell.tsx +144 -26
  332. package/src/workbench/WorkbenchShellTitleBarLayoutControls.tsx +80 -0
  333. package/src/workbench/WorkbenchStandaloneShell.tsx +327 -41
  334. package/src/workbench/WorkbenchThemeProvider.tsx +142 -0
  335. package/src/workbench/WorkbenchViewEditor.tsx +75 -0
  336. package/src/workbench/WorkbenchViewSidebar.tsx +85 -0
  337. package/src/workbench/WorkbenchWindowChromeControls.tsx +290 -0
  338. package/src/workbench/activityBarOrder.ts +98 -0
  339. package/src/workbench/appearanceLabels.ts +28 -0
  340. package/src/workbench/auth/WorkbenchLoginView.tsx +4 -6
  341. package/src/workbench/auth/auth-flows.css +440 -0
  342. package/src/workbench/auth/auth.css +3 -0
  343. package/src/workbench/auth/profile-modals.css +115 -0
  344. package/src/workbench/bootstrap/WorkbenchBootstrapGate.tsx +45 -0
  345. package/src/workbench/bootstrap/WorkbenchBootstrapView.tsx +100 -0
  346. package/src/workbench/bootstrap/index.ts +12 -0
  347. package/src/workbench/bootstrap/useWorkbenchBootstrap.ts +130 -0
  348. package/src/workbench/chat/ChatCommandProposalCard.tsx +115 -0
  349. package/src/workbench/chat/ChatComposer.tsx +32 -34
  350. package/src/workbench/chat/ChatConversationBar.tsx +134 -0
  351. package/src/workbench/chat/ChatHistoryMenu.tsx +171 -0
  352. package/src/workbench/chat/ChatHistoryMenuRow.tsx +74 -0
  353. package/src/workbench/chat/ChatMessageCollapsible.tsx +115 -0
  354. package/src/workbench/chat/ChatMessageItem.tsx +293 -19
  355. package/src/workbench/chat/ChatMessageList.tsx +109 -24
  356. package/src/workbench/chat/ChatPanel.tsx +132 -19
  357. package/src/workbench/chat/ChatPhasedRunProgress.tsx +202 -0
  358. package/src/workbench/chat/ChatRenameDialog.tsx +77 -0
  359. package/src/workbench/chat/chat-conversation.css +273 -0
  360. package/src/workbench/chat/chat-ui.css +1124 -0
  361. package/src/workbench/chat/chat.css +3 -0
  362. package/src/workbench/chat/chatConversation.ts +46 -0
  363. package/src/workbench/chat/chatHistoryRowMenuItems.ts +29 -0
  364. package/src/workbench/chat/chatMessageMeta.tsx +252 -0
  365. package/src/workbench/chat/chatScroll.ts +22 -0
  366. package/src/workbench/chat/index.ts +47 -1
  367. package/src/workbench/chat/slashCommand.ts +5 -7
  368. package/src/workbench/chat/types.ts +35 -0
  369. package/src/workbench/chat/useCancelRuntimeOnUnmount.ts +60 -0
  370. package/src/workbench/chat/useChatPrependPagination.ts +233 -0
  371. package/src/workbench/chat/useChatRuntimeState.ts +3 -15
  372. package/src/workbench/chat/useSlashCommandSuggest.ts +76 -23
  373. package/src/workbench/chrome/index.css +6 -0
  374. package/src/workbench/chrome/workbench-desktop-titlebar.css +60 -0
  375. package/src/workbench/chrome/workbench-host.css +85 -0
  376. package/src/workbench/chrome/workbench-layout-regions.css +42 -0
  377. package/src/workbench/chrome/workbench-platform-chrome.css +142 -0
  378. package/src/workbench/chrome/workbench-shell-titlebar.css +124 -0
  379. package/src/workbench/command-execution-policy.ts +61 -0
  380. package/src/workbench/command-model.ts +275 -0
  381. package/src/workbench/command-palette/command-palette.css +156 -0
  382. package/src/workbench/commands.ts +62 -6
  383. package/src/workbench/editor-tabs/index.ts +22 -0
  384. package/src/workbench/editor-tabs-dnd.ts +162 -0
  385. package/src/workbench/editorTabContextMenu.ts +111 -0
  386. package/src/workbench/hardReset.ts +64 -0
  387. package/src/workbench/index.ts +234 -2
  388. package/src/workbench/jdw/jdw-editors.css +4 -0
  389. package/src/workbench/jdw/jdw.css +2 -0
  390. package/src/workbench/management/AccountManagementPanel.tsx +82 -0
  391. package/src/workbench/management/CommandInspectorPanel.tsx +127 -0
  392. package/src/workbench/management/CommandManagementPanel.tsx +129 -0
  393. package/src/workbench/management/CommandManagementSidebar.tsx +318 -0
  394. package/src/workbench/management/ExtensionManagementPanel.tsx +498 -0
  395. package/src/workbench/management/ExtensionManagementSidebar.tsx +492 -0
  396. package/src/workbench/management/IntegrationCommandActions.tsx +78 -0
  397. package/src/workbench/management/IntegrationSettingsSurface.tsx +290 -0
  398. package/src/workbench/management/IntegrationsShell.tsx +53 -0
  399. package/src/workbench/management/KeybindingCaptureField.tsx +142 -0
  400. package/src/workbench/management/KeybindingManagementPanel.tsx +120 -0
  401. package/src/workbench/management/LibraryCatalogPickerDialog.tsx +208 -0
  402. package/src/workbench/management/LibraryFacetFilterDialog.tsx +62 -0
  403. package/src/workbench/management/ManagementCard.tsx +89 -0
  404. package/src/workbench/management/ManagementFilterChips.tsx +41 -0
  405. package/src/workbench/management/ManagementGroup.tsx +56 -0
  406. package/src/workbench/management/ManagementPanelControls.tsx +43 -0
  407. package/src/workbench/management/ManagementPanelFrame.tsx +109 -0
  408. package/src/workbench/management/WorkbenchDialogFrame.tsx +148 -0
  409. package/src/workbench/management/WorkbenchNotice.tsx +211 -0
  410. package/src/workbench/management/build-command-management-groups.ts +157 -0
  411. package/src/workbench/management/command-inspector-uri.ts +26 -0
  412. package/src/workbench/management/extension-category-display.ts +42 -0
  413. package/src/workbench/management/format-command-run-state.ts +19 -0
  414. package/src/workbench/management/index.ts +130 -0
  415. package/src/workbench/management/integration-command-action.ts +25 -0
  416. package/src/workbench/management/library-catalog-picker-dialog.css +56 -0
  417. package/src/workbench/management/library-facet-filter-dialog.css +8 -0
  418. package/src/workbench/management/management-panel.css +444 -0
  419. package/src/workbench/management/management.css +4 -0
  420. package/src/workbench/management/types.ts +126 -0
  421. package/src/workbench/markdownRemarkPlugins.ts +4 -0
  422. package/src/workbench/schema/index.ts +0 -1
  423. package/src/workbench/settings/NavigationPanel.tsx +41 -2
  424. package/src/workbench/settings/SchemaForm.tsx +20 -7
  425. package/src/workbench/settings/SectionTabPanel.tsx +172 -0
  426. package/src/workbench/settings/SectionedPanel.tsx +40 -286
  427. package/src/workbench/settings/StructuredDataForm.tsx +106 -26
  428. package/src/workbench/settings/StructuredDataSchemaPanel.tsx +345 -93
  429. package/src/workbench/settings/StructuredDataTableView.tsx +2 -2
  430. package/src/workbench/settings/WorkbenchPanelRegion.tsx +1 -1
  431. package/src/workbench/settings/WorkbenchSettingsModal.tsx +116 -62
  432. package/src/workbench/settings/WorkbenchSettingsNav.tsx +3 -3
  433. package/src/workbench/settings/extensionSettingsForm.ts +34 -0
  434. package/src/workbench/settings/index.ts +36 -1
  435. package/src/workbench/settings/navigation-panel.css +59 -0
  436. package/src/workbench/settings/panel-region.css +3 -2
  437. package/src/workbench/settings/schema-form.css +36 -0
  438. package/src/workbench/settings/schemaFormSettingSpec.ts +177 -0
  439. package/src/workbench/settings/schemaFormSettingsCategory.tsx +21 -0
  440. package/src/workbench/settings/section-tab-panel.css +157 -0
  441. package/src/workbench/settings/sectionScrollSpyDom.ts +139 -0
  442. package/src/workbench/settings/sectioned-panel.css +162 -0
  443. package/src/workbench/settings/sectionedPanelScrollSpy.ts +158 -28
  444. package/src/workbench/settings/settings-responsive.css +58 -0
  445. package/src/workbench/settings/settings.css +11 -0
  446. package/src/workbench/settings/settingsCommit.tsx +55 -0
  447. package/src/workbench/settings/structured-data-form.css +114 -0
  448. package/src/workbench/settings/structured-data-schema-panel.css +33 -19
  449. package/src/workbench/settings/structuredDataFormModel.ts +140 -0
  450. package/src/workbench/settings/structuredDataSchema.ts +111 -658
  451. package/src/workbench/settings/structuredDataSchemaDate.ts +197 -0
  452. package/src/workbench/settings/structuredDataSchemaField.ts +105 -0
  453. package/src/workbench/settings/structuredDataSchemaSection.ts +74 -0
  454. package/src/workbench/settings/structuredDataSchemaTable.ts +120 -0
  455. package/src/workbench/settings/structuredDataSchemaTypes.ts +308 -0
  456. package/src/workbench/settings/structuredDataSchemaValidation.ts +166 -0
  457. package/src/workbench/settings/useSectionScrollSpy.ts +420 -0
  458. package/src/workbench/settings/workbench-settings-modal.css +273 -0
  459. package/src/workbench/shell/activity-bar.css +245 -0
  460. package/src/workbench/shell/confirmation-flow.css +87 -0
  461. package/src/workbench/shell/index.css +5 -0
  462. package/src/workbench/shell/split-view.css +188 -0
  463. package/src/workbench/shell/status-bar.css +141 -0
  464. package/src/workbench/shell.ts +133 -2
  465. package/src/workbench/shellPresets.ts +36 -0
  466. package/src/workbench/shellState.ts +16 -23
  467. package/src/workbench/shellViewModel.ts +160 -0
  468. package/src/workbench/sidebarViewPlacementDnd.ts +61 -0
  469. package/src/workbench/standalone.ts +9 -9
  470. package/src/workbench/status.ts +10 -6
  471. package/src/workbench/theme.ts +8 -2
  472. package/src/workbench/themePresets.ts +191 -0
  473. package/src/workbench/useDeferredWorkbenchMount.ts +71 -0
  474. package/src/workbench/useEditorTabsStripDnd.ts +262 -0
  475. package/src/workbench/useWorkbenchAppearanceDocumentSync.tsx +17 -0
  476. package/src/workbench/useWorkbenchEditorTabContextMenu.tsx +66 -0
  477. package/src/workbench/useWorkbenchSidebarActionBarDnd.ts +227 -0
  478. package/src/workbench/useWorkbenchSidebarLayout.tsx +232 -0
  479. package/src/workbench/useWorkbenchSidebarViewPlacementDropZone.ts +194 -0
  480. package/src/workbench/useWorkbenchStandaloneShellStateSync.tsx +112 -0
  481. package/src/workbench/views/action-list.css +144 -0
  482. package/src/workbench/views/artifact-preview.css +184 -0
  483. package/src/workbench/views/command-inspector.css +98 -0
  484. package/src/workbench/views/command-list.css +356 -0
  485. package/src/workbench/views/commands-sidebar.css +51 -0
  486. package/src/workbench/views/extensions-sidebar.css +175 -0
  487. package/src/workbench/views/multi-provider-explorer.css +182 -0
  488. package/src/workbench/views/search.css +10 -0
  489. package/src/workbench/views/timeline.css +239 -0
  490. package/src/workbench/views/view-hosts.css +37 -0
  491. package/src/workbench/views/view-sidebar.css +21 -0
  492. package/src/workbench/views/views.css +12 -0
  493. package/src/workbench/widgets/widget-tree.css +598 -0
  494. package/src/workbench/widgets/widgets.css +2 -0
  495. package/src/workbench/workbench-chrome.css +4 -0
  496. package/src/workbench/workbenchContextMenu.ts +18 -0
  497. package/src/workbench/workbenchModalViewState.ts +52 -0
  498. package/src/workbench/workbenchOverlaysContext.tsx +21 -0
  499. package/src/workbench/workbenchPlatformChrome.ts +40 -0
  500. package/src/workbench/workbenchSidebarLayoutContext.ts +46 -0
  501. package/src/workbench/workbenchStandaloneShellReactContext.tsx +80 -0
  502. package/src/workbench/workbenchViewRouteState.ts +151 -0
  503. package/src/workbench/workspace/WorkspaceDraftsContext.tsx +59 -71
  504. package/src/workbench/workspace/WorkspaceEditor.tsx +27 -123
  505. package/src/workbench/workspace/WorkspaceEditorPanel.tsx +67 -8
  506. package/src/workbench/workspace/WorkspaceExplorer.tsx +149 -51
  507. package/src/workbench/workspace/WorkspaceExplorerPanel.tsx +73 -0
  508. package/src/workbench/workspace/WorkspaceFileIcon.tsx +4 -160
  509. package/src/workbench/workspace/WorkspacePathLabel.tsx +42 -0
  510. package/src/workbench/workspace/WorkspaceSearchPanel.tsx +18 -15
  511. package/src/workbench/workspace/WorkspaceSearchResults.tsx +6 -2
  512. package/src/workbench/workspace/build-workspace-explorer-nodes.ts +44 -0
  513. package/src/workbench/workspace/createVirtualWorkspaceExplorerPort.ts +141 -0
  514. package/src/workbench/workspace/explorer-tree-style.ts +18 -0
  515. package/src/workbench/workspace/index.ts +45 -32
  516. package/src/workbench/workspace/json-config-workbench.css +57 -0
  517. package/src/workbench/workspace/monaco-panel.css +71 -0
  518. package/src/workbench/workspace/path.ts +2 -0
  519. package/src/workbench/workspace/useWorkspaceExplorerController.ts +490 -0
  520. package/src/workbench/workspace/workspace-editor.css +235 -0
  521. package/src/workbench/workspace/workspace-explorer-panel.css +33 -0
  522. package/src/workbench/workspace/workspace.css +5 -0
  523. package/src/workbench/workspace/workspaceExplorerController.ts +193 -0
  524. package/src/workbench/workspace/workspaceJsonDiagnostics.ts +2 -2
  525. package/src/workbench-menu-surfaces.css +57 -0
  526. package/src/jdw/builtins/renderBuiltinWidgetNode.tsx +0 -126
  527. package/src/layout/SideBarViewFrame.tsx +0 -367
  528. package/src/primitives/Checkbox.tsx +0 -21
  529. package/src/primitives/NumberInput.tsx +0 -38
  530. package/src/primitives/ScrollArea.tsx +0 -42
  531. package/src/primitives/Select.tsx +0 -1
  532. package/src/primitives/StatusBar.tsx +0 -46
  533. package/src/primitives/WorkbenchChrome.tsx +0 -424
  534. package/src/workbench/workspace/MultiProviderExplorer.tsx +0 -625
@@ -1,20 +1,25 @@
1
- import { useState, type ReactNode } from 'react';
1
+ import { useMemo, useState, type KeyboardEvent, type ReactNode } from 'react';
2
2
  import type { WidgetAssetCatalogContract, WidgetRegistryContract } from '@workbench-kit/contracts';
3
3
 
4
- import { Panel, PanelBody, PanelHeader } from '../layout/Panel';
5
- import { Button } from '../primitives/Button';
6
- import { Toolbar } from '../primitives/Toolbar';
4
+ import { Panel, PanelBody, PanelHeader } from '../layout/panel';
5
+ import { Button } from '../primitives/button';
6
+ import { Toolbar } from '../primitives/toolbar';
7
+ import { JsonConfigValidationBanner } from '../jdw/JsonCodeEditorPane.js';
7
8
  import type { WorkspaceEditorTheme } from '../workbench/workspace/WorkspaceEditor.js';
8
9
  import { fileNameOfPath } from '../workbench/workspace/path';
10
+ import { WorkspacePathLabel } from '../workbench/workspace/WorkspacePathLabel';
9
11
  import { WidgetTreeLab } from './WidgetTreeLab.js';
10
- import { WidgetTreeModeControls } from './WidgetTreeModeControls.js';
12
+ import { resolveWidgetTreeModeShortcut, WidgetTreeModeControls } from './WidgetTreeModeControls.js';
11
13
  import { DEFAULT_WIDGET_TREE_VIEW_MODE, type WidgetTreeViewMode } from './widget-tree-mode.js';
14
+ import { createWidgetTreeEditorState } from './widget-tree-editor-state.js';
12
15
 
13
16
  export interface WidgetTreeWorkbenchProps {
14
17
  readonly path?: string | undefined;
15
18
  readonly title?: ReactNode | undefined;
16
19
  readonly value: string;
17
20
  readonly onChange: (value: string) => void;
21
+ readonly baselineValue?: string | undefined;
22
+ readonly onApply?: (() => void) | undefined;
18
23
  readonly onSave?: (() => void) | undefined;
19
24
  readonly onDiscard?: (() => void) | undefined;
20
25
  readonly dirty?: boolean | undefined;
@@ -32,9 +37,11 @@ export function WidgetTreeWorkbench({
32
37
  title,
33
38
  value,
34
39
  onChange,
40
+ baselineValue,
41
+ onApply,
35
42
  onSave,
36
43
  onDiscard,
37
- dirty = false,
44
+ dirty,
38
45
  readOnly = false,
39
46
  registry,
40
47
  assetCatalog,
@@ -55,21 +62,55 @@ export function WidgetTreeWorkbench({
55
62
  };
56
63
 
57
64
  const resolvedTitle = title ?? (path ? fileNameOfPath(path) : 'Widget document');
65
+ const registeredTypes = useMemo(
66
+ () => registry?.definitions().map((definition) => definition.type),
67
+ [registry],
68
+ );
69
+ const editorState = useMemo(
70
+ () =>
71
+ createWidgetTreeEditorState({
72
+ baselineValue: baselineValue ?? value,
73
+ currentValue: value,
74
+ registeredTypes,
75
+ }),
76
+ [baselineValue, registeredTypes, value],
77
+ );
78
+ const resolvedDirty = dirty ?? (baselineValue !== undefined && editorState.textDirty);
79
+ const canApply = Boolean(resolvedDirty && editorState.validationOk);
80
+ const saveEnabled = Boolean(onSave && canApply && !readOnly);
81
+ const resolvedOnSave = saveEnabled ? onSave : undefined;
82
+ const showApply = Boolean(canApply && onApply && !readOnly);
83
+
84
+ const handleWorkbenchKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
85
+ const nextMode = resolveWidgetTreeModeShortcut(event);
86
+ if (nextMode === null) {
87
+ return;
88
+ }
89
+
90
+ event.preventDefault();
91
+ setViewMode(nextMode);
92
+ };
58
93
 
59
94
  return (
60
95
  <Panel
61
96
  className="widget-tree-workbench"
62
97
  data-mode={resolvedViewMode}
63
98
  data-testid="widget-tree-workbench"
99
+ onKeyDown={handleWorkbenchKeyDown}
64
100
  >
65
101
  <PanelHeader
66
102
  actions={
67
103
  <Toolbar>
68
- {dirty && !readOnly ? (
104
+ {showApply ? (
105
+ <Button data-testid="widget-tree-workbench-apply" variant="primary" onClick={onApply}>
106
+ Apply
107
+ </Button>
108
+ ) : null}
109
+ {resolvedDirty && !readOnly ? (
69
110
  <>
70
111
  {onDiscard ? <Button onClick={onDiscard}>Discard</Button> : null}
71
112
  {onSave ? (
72
- <Button variant="primary" onClick={onSave}>
113
+ <Button disabled={!saveEnabled} variant="primary" onClick={resolvedOnSave}>
73
114
  Save
74
115
  </Button>
75
116
  ) : null}
@@ -81,12 +122,8 @@ export function WidgetTreeWorkbench({
81
122
  >
82
123
  <span className="widget-tree-workbench__title">
83
124
  {resolvedTitle}
84
- {path ? (
85
- <span className="widget-tree-workbench__path" title={path}>
86
- {path}
87
- </span>
88
- ) : null}
89
- {dirty ? (
125
+ {path ? <WorkspacePathLabel className="widget-tree-workbench__path" path={path} /> : null}
126
+ {resolvedDirty ? (
90
127
  <span className="widget-tree-workbench__dirty-indicator" title="Unsaved changes">
91
128
 
92
129
  </span>
@@ -94,6 +131,13 @@ export function WidgetTreeWorkbench({
94
131
  </span>
95
132
  </PanelHeader>
96
133
  <PanelBody className="widget-tree-workbench__body">
134
+ {!editorState.validationOk || canApply ? (
135
+ <JsonConfigValidationBanner
136
+ canApply={canApply}
137
+ firstError={editorState.firstError}
138
+ validationOk={editorState.validationOk}
139
+ />
140
+ ) : null}
97
141
  <WidgetTreeLab
98
142
  assetCatalog={assetCatalog}
99
143
  path={path}
@@ -103,7 +147,7 @@ export function WidgetTreeWorkbench({
103
147
  value={value}
104
148
  viewMode={resolvedViewMode}
105
149
  onChange={onChange}
106
- onSave={onSave}
150
+ onSave={resolvedOnSave}
107
151
  />
108
152
  </PanelBody>
109
153
  </Panel>
@@ -3,8 +3,9 @@ import {
3
3
  integratedShellWorkspaceFiles,
4
4
  integratedShellWorkspaceFolders,
5
5
  } from '@workbench-kit/adapters';
6
+ import { validateJsonWidgetData } from '@workbench-kit/jdw';
6
7
 
7
- import { SideBarViewFrame } from '../layout/SideBarViewFrame.js';
8
+ import { SideBarViewFrame } from '../layout/sidebar';
8
9
  import { WorkbenchShell } from '../workbench/WorkbenchShell.js';
9
10
  import type { StatusBarSectionModel } from '../workbench/StatusBar.js';
10
11
  import {
@@ -17,8 +18,9 @@ import {
17
18
  } from '../workbench/workspace/index.js';
18
19
  import { createWidgetStudioWorkspaceEditorRenderer } from '../widget-studio/create-widget-studio-workspace-editor.js';
19
20
  import { WIDGET_TREE_DEMO_REGISTRY, WIDGET_TREE_WELCOME_DOCUMENT } from './demo-registry.js';
21
+ import { isWidgetTreeDocument } from './widget-tree-document.js';
20
22
 
21
- const JDW_WORKSPACE_DEFAULT_WIDGET_PATH = 'src/widgets/home.widget.json';
23
+ const JDW_WORKSPACE_DEFAULT_WIDGET_PATH = 'src/widgets/home.jdw.json';
22
24
 
23
25
  function withJdwWelcomeDocument(files: readonly WorkspaceFile[]): WorkspaceFile[] {
24
26
  return files.map((file) =>
@@ -35,6 +37,19 @@ const statusSections: StatusBarSectionModel[] = [
35
37
  },
36
38
  ];
37
39
 
40
+ const registeredWidgetTypes = WIDGET_TREE_DEMO_REGISTRY.definitions().map(
41
+ (definition) => definition.type,
42
+ );
43
+
44
+ export function canSaveWidgetTreeWorkspaceFile(file: WorkspaceFile, content: string): boolean {
45
+ if (!isWidgetTreeDocument(file)) return true;
46
+
47
+ return validateJsonWidgetData(content, {
48
+ registeredTypes: registeredWidgetTypes,
49
+ strictKnownTypes: true,
50
+ }).valid;
51
+ }
52
+
38
53
  export interface WidgetTreeWorkspaceShellProps {
39
54
  readonly initialSelectedPath?: string | undefined;
40
55
  readonly initialTheme?: WorkspaceEditorTheme | undefined;
@@ -45,7 +60,7 @@ export function WidgetTreeWorkspaceShell({
45
60
  initialTheme = 'dark',
46
61
  }: WidgetTreeWorkspaceShellProps = {}) {
47
62
  const [sidebarVisible, setSidebarVisible] = useState(true);
48
- const [sidebarSizePercent, setSidebarSizePercent] = useState(20);
63
+ const [sidebarSizePx, setSidebarSizePx] = useState(260);
49
64
 
50
65
  const workspaceFiles = useMemo(() => withJdwWelcomeDocument(integratedShellWorkspaceFiles), []);
51
66
 
@@ -99,10 +114,10 @@ export function WidgetTreeWorkspaceShell({
99
114
  primarySidebar={{
100
115
  className: 'ui-workbench-story-shell-split',
101
116
  isVisible: sidebarVisible,
102
- maxPrimarySizePercent: 36,
103
- minPrimarySizePercent: 16,
117
+ maxPrimarySizePx: 480,
118
+ minPrimarySizePx: 200,
104
119
  node: (
105
- <aside aria-label="Explorer sidebar" className="workbench-primary-side-bar">
120
+ <aside aria-label="Explorer sidebar" className="workbench-primary-sidebar">
106
121
  <SideBarViewFrame title="Explorer">
107
122
  <WorkspaceExplorer
108
123
  activePath={selectedPath}
@@ -114,14 +129,17 @@ export function WidgetTreeWorkspaceShell({
114
129
  </SideBarViewFrame>
115
130
  </aside>
116
131
  ),
117
- onSizePercentChange: setSidebarSizePercent,
118
- primarySizePercent: sidebarSizePercent,
132
+ onSizePxChange: setSidebarSizePx,
133
+ primarySizePx: sidebarSizePx,
119
134
  }}
120
135
  rootClassName="ide-root jdw-workspace-shell"
121
136
  rootStyle={{ height: '100%', minHeight: 0 }}
122
137
  secondaryArea={
123
138
  <main className="workbench-editor-area jdw-workspace-shell__editor">
124
139
  <WorkspaceEditorPanel
140
+ canSaveFile={(_path, content, file) =>
141
+ canSaveWidgetTreeWorkspaceFile(file, content)
142
+ }
125
143
  files={files}
126
144
  openPaths={openPaths}
127
145
  renderEditor={(context) =>
@@ -2,14 +2,27 @@ export { WidgetTreeLab } from './WidgetTreeLab.js';
2
2
  export type { WidgetTreeLabProps } from './WidgetTreeLab.js';
3
3
  export { WidgetTreeWorkbench } from './WidgetTreeWorkbench.js';
4
4
  export type { WidgetTreeWorkbenchProps } from './WidgetTreeWorkbench.js';
5
+ export {
6
+ createWidgetTreeEditorState,
7
+ type WidgetTreeEditorState,
8
+ type WidgetTreeValidationState,
9
+ } from './widget-tree-editor-state.js';
5
10
  export { WidgetTreeWorkspaceShell } from './WidgetTreeWorkspaceShell.js';
6
11
  export type { WidgetTreeWorkspaceShellProps } from './WidgetTreeWorkspaceShell.js';
7
12
  export { WidgetTreeView } from './WidgetTreeView.js';
8
- export type { WidgetTreeViewProps } from './WidgetTreeView.js';
13
+ export type {
14
+ WidgetTreeAssetDropOperation,
15
+ WidgetTreeMoveOperation,
16
+ WidgetTreeViewProps,
17
+ } from './WidgetTreeView.js';
9
18
  export { WidgetInspectorPanel } from './WidgetInspectorPanel.js';
10
19
  export type { WidgetInspectorPanelProps } from './WidgetInspectorPanel.js';
11
20
  export { WidgetTreeSidePanel } from './WidgetTreeSidePanel.js';
12
- export type { WidgetTreeSidePanelProps, WidgetTreeSidePanelTab } from './WidgetTreeSidePanel.js';
21
+ export type {
22
+ WidgetTreeSidePanelProps,
23
+ WidgetTreeSidePanelDetailTab,
24
+ WidgetTreeSidePanelTab,
25
+ } from './WidgetTreeSidePanel.js';
13
26
  export { WidgetAssetPalette } from './WidgetAssetPalette.js';
14
27
  export type { WidgetAssetPaletteProps } from './WidgetAssetPalette.js';
15
28
  export {
@@ -19,9 +32,14 @@ export {
19
32
  } from './widget-tree-mode.js';
20
33
  export { WidgetSourceEditor } from './WidgetSourceEditor.js';
21
34
  export type { WidgetSourceEditorProps } from './WidgetSourceEditor.js';
22
- export { WidgetTreeModeControls } from './WidgetTreeModeControls.js';
35
+ export { resolveWidgetTreeModeShortcut, WidgetTreeModeControls } from './WidgetTreeModeControls.js';
23
36
  export type { WidgetTreeModeControlsProps } from './WidgetTreeModeControls.js';
24
- export { isWidgetTreeDocument, WIDGET_TREE_DOCUMENT_MIME } from './widget-tree-document.js';
37
+ export { isWidgetTreeDocument } from './widget-tree-document.js';
25
38
  export type { WidgetTreeDocumentRef } from './widget-tree-document.js';
39
+ export {
40
+ WIDGET_PLACEMENT_ASSET_DRAG_MIME,
41
+ readWidgetPlacementAssetDragData,
42
+ writeWidgetPlacementAssetDragData,
43
+ } from './widget-placement-asset-dnd.js';
26
44
  export { WIDGET_TREE_DEMO_REGISTRY, WIDGET_TREE_WELCOME_DOCUMENT } from './demo-registry.js';
27
45
  export { WIDGET_TREE_DEMO_ASSET_CATALOG } from './demo-widget-assets.js';
@@ -0,0 +1,35 @@
1
+ import type { WidgetPlacementAsset } from '@workbench-kit/contracts';
2
+
3
+ export const WIDGET_PLACEMENT_ASSET_DRAG_MIME =
4
+ 'application/vnd.workbench-kit.widget-placement-asset+json';
5
+
6
+ function isRecord(value: unknown): value is Record<string, unknown> {
7
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
8
+ }
9
+
10
+ export function writeWidgetPlacementAssetDragData(
11
+ dataTransfer: DataTransfer,
12
+ asset: WidgetPlacementAsset,
13
+ ): void {
14
+ dataTransfer.setData(WIDGET_PLACEMENT_ASSET_DRAG_MIME, JSON.stringify(asset));
15
+ dataTransfer.setData('text/plain', asset.label);
16
+ dataTransfer.effectAllowed = 'copy';
17
+ }
18
+
19
+ export function readWidgetPlacementAssetDragData(
20
+ dataTransfer: DataTransfer | null,
21
+ ): WidgetPlacementAsset | null {
22
+ const raw = dataTransfer?.getData(WIDGET_PLACEMENT_ASSET_DRAG_MIME);
23
+ if (!raw) return null;
24
+
25
+ try {
26
+ const parsed = JSON.parse(raw) as unknown;
27
+ if (!isRecord(parsed) || !isRecord(parsed.content)) return null;
28
+ if (typeof parsed.id !== 'string' || typeof parsed.label !== 'string') return null;
29
+ if (typeof parsed.category !== 'string') return null;
30
+
31
+ return parsed as unknown as WidgetPlacementAsset;
32
+ } catch {
33
+ return null;
34
+ }
35
+ }
@@ -1,7 +1,4 @@
1
- import { JDW_DOCUMENT_MIME, isJdwDocumentPath } from '../jdw/document';
2
-
3
- export const WIDGET_TREE_DOCUMENT_MIME = 'application/vnd.workbench-kit.widget+json';
4
- export const WIDGET_TREE_DOCUMENT_FILE_EXTENSION = '.widget.json';
1
+ import { JDW_WIDGET_DOCUMENT_MIME, isJdwDocumentPath } from '../jdw/document';
5
2
 
6
3
  export interface WidgetTreeDocumentRef {
7
4
  readonly path: string;
@@ -9,12 +6,9 @@ export interface WidgetTreeDocumentRef {
9
6
  }
10
7
 
11
8
  export function isWidgetTreeDocument(file: WidgetTreeDocumentRef): boolean {
12
- if (file.mimeType === WIDGET_TREE_DOCUMENT_MIME || file.mimeType === JDW_DOCUMENT_MIME) {
9
+ if (file.mimeType === JDW_WIDGET_DOCUMENT_MIME) {
13
10
  return true;
14
11
  }
15
12
 
16
- const normalizedPath = file.path.toLowerCase();
17
- return (
18
- normalizedPath.endsWith(WIDGET_TREE_DOCUMENT_FILE_EXTENSION) || isJdwDocumentPath(file.path)
19
- );
13
+ return isJdwDocumentPath(file.path);
20
14
  }
@@ -0,0 +1,40 @@
1
+ import { validateJsonWidgetData } from '@workbench-kit/jdw';
2
+
3
+ export type WidgetTreeValidationState = 'invalid' | 'unchanged' | 'valid-changed';
4
+
5
+ export interface WidgetTreeEditorState {
6
+ readonly canApply: boolean;
7
+ readonly firstError: string | null;
8
+ readonly textDirty: boolean;
9
+ readonly validationOk: boolean;
10
+ readonly validationState: WidgetTreeValidationState;
11
+ }
12
+
13
+ export function createWidgetTreeEditorState(input: {
14
+ readonly baselineValue: string;
15
+ readonly currentValue: string;
16
+ readonly registeredTypes?: readonly string[] | undefined;
17
+ }): WidgetTreeEditorState {
18
+ const textDirty = input.currentValue !== input.baselineValue;
19
+ const validation = validateJsonWidgetData(input.currentValue, {
20
+ registeredTypes: input.registeredTypes,
21
+ strictKnownTypes: true,
22
+ });
23
+ const validationOk = validation.valid;
24
+ const firstIssue = validation.issues[0];
25
+ const firstError = firstIssue === undefined ? null : `${firstIssue.path}: ${firstIssue.message}`;
26
+ const canApply = textDirty && validationOk;
27
+ const validationState: WidgetTreeValidationState = !validationOk
28
+ ? 'invalid'
29
+ : textDirty
30
+ ? 'valid-changed'
31
+ : 'unchanged';
32
+
33
+ return {
34
+ canApply,
35
+ firstError,
36
+ textDirty,
37
+ validationOk,
38
+ validationState,
39
+ };
40
+ }
@@ -1,7 +1,42 @@
1
- import { isContainerWidget, type GenericWidget } from '@workbench-kit/jdw';
1
+ import {
2
+ appendBoxChildPath,
3
+ appendChildrenPath,
4
+ type GenericWidget,
5
+ type WidgetPath,
6
+ } from '@workbench-kit/jdw';
7
+
8
+ const ARRAY_CHILD_CONTAINER_TYPES = new Set(['row', 'column', 'grid', 'stack', 'list-view']);
9
+ const SINGLE_CHILD_CONTAINER_TYPES = new Set([
10
+ 'box',
11
+ 'container',
12
+ 'padding',
13
+ 'align',
14
+ 'center',
15
+ 'sized_box',
16
+ ]);
2
17
 
3
18
  export function canAddChildren(widget: GenericWidget | null): widget is GenericWidget {
4
- return widget !== null && isContainerWidget(widget) && widget.type !== 'box';
19
+ if (widget === null) {
20
+ return false;
21
+ }
22
+
23
+ if (SINGLE_CHILD_CONTAINER_TYPES.has(widget.type)) {
24
+ return widget.child === undefined;
25
+ }
26
+
27
+ return ARRAY_CHILD_CONTAINER_TYPES.has(widget.type) || Array.isArray(widget.children);
28
+ }
29
+
30
+ export function insertedWidgetPathForParent(
31
+ parent: GenericWidget,
32
+ parentPath: WidgetPath,
33
+ index: number,
34
+ ): WidgetPath {
35
+ if (SINGLE_CHILD_CONTAINER_TYPES.has(parent.type) && parent.child === undefined) {
36
+ return appendBoxChildPath(parentPath);
37
+ }
38
+
39
+ return appendChildrenPath(parentPath, index);
5
40
  }
6
41
 
7
42
  export function formatWidgetPlacementMeta(
@@ -23,8 +58,18 @@ export function formatWidgetPlacementMeta(
23
58
 
24
59
  if (parentType === 'row' || parentType === 'column') {
25
60
  const flex = typeof widget.flex === 'number' ? `flex ${widget.flex}` : null;
61
+ const flexFit =
62
+ widget.flexFit === 'tight' || widget.flexFit === 'loose' ? widget.flexFit : null;
26
63
  const align = typeof widget.align === 'string' ? widget.align : null;
27
- return [flex, align].filter(Boolean).join(' · ') || null;
64
+ return [flex, flexFit, align].filter(Boolean).join(' · ') || null;
65
+ }
66
+
67
+ if (parentType === 'stack') {
68
+ const left = typeof widget.left === 'number' ? `l${widget.left}` : null;
69
+ const top = typeof widget.top === 'number' ? `t${widget.top}` : null;
70
+ const right = typeof widget.right === 'number' ? `r${widget.right}` : null;
71
+ const bottom = typeof widget.bottom === 'number' ? `b${widget.bottom}` : null;
72
+ return [left, top, right, bottom].filter(Boolean).join(' · ') || null;
28
73
  }
29
74
 
30
75
  return null;
@@ -1,74 +1,85 @@
1
- import { expect, userEvent, waitFor } from 'storybook/test';
1
+ import { expect, waitFor } from 'storybook/test';
2
2
 
3
- interface MonacoEditorHandle {
4
- getDomNode: () => HTMLElement | null;
5
- getValue: () => string;
6
- }
3
+ function resolveWidgetTreeSurface(root: ParentNode | Element | null): Element | null {
4
+ if (!root || !(root instanceof Element)) {
5
+ return null;
6
+ }
7
7
 
8
- interface MonacoGlobal {
9
- editor: {
10
- getEditors: () => MonacoEditorHandle[];
11
- };
12
- }
8
+ const testId = root.getAttribute('data-testid');
9
+ if (
10
+ testId === 'widget-tree-lab' ||
11
+ testId === 'widget-tree-workbench' ||
12
+ testId === 'widget-tree-source'
13
+ ) {
14
+ return root;
15
+ }
13
16
 
14
- export async function waitForWidgetTreeSourcePane(canvasElement: HTMLElement): Promise<void> {
15
- await waitFor(
16
- () => {
17
- const pane =
18
- canvasElement.querySelector('.widget-tree-source .ui-json-code-editor-pane') ??
19
- canvasElement.querySelector('[data-testid="widget-tree-source"]');
20
- expect(pane).toBeTruthy();
21
- },
22
- { timeout: 15000 },
17
+ if (root.matches('.widget-tree-source .ui-json-code-editor-pane')) {
18
+ return root;
19
+ }
20
+
21
+ return (
22
+ root.querySelector('[data-testid="widget-tree-lab"]') ??
23
+ root.querySelector('[data-testid="widget-tree-workbench"]') ??
24
+ root.querySelector('.widget-tree-source .ui-json-code-editor-pane') ??
25
+ root.querySelector('[data-testid="widget-tree-source"]')
23
26
  );
24
27
  }
25
28
 
26
- export async function waitForWidgetTreeMonaco(canvasElement: HTMLElement): Promise<void> {
27
- await waitForWidgetTreeSourcePane(canvasElement);
29
+ /** Wait until Widget Tree Lab / Workbench chrome is mounted (Form or Code surface). */
30
+ export async function waitForWidgetTreeSourcePane(canvasElement: HTMLElement): Promise<void> {
31
+ const doc = canvasElement.ownerDocument ?? document;
28
32
 
29
33
  await waitFor(
30
34
  () => {
31
- const editorRoot = canvasElement.querySelector('.widget-tree-source .monaco-editor');
32
- expect(editorRoot).toBeTruthy();
33
- expect(editorRoot?.textContent ?? '').not.toContain('Loading editor');
35
+ const surface = resolveWidgetTreeSurface(canvasElement) ?? resolveWidgetTreeSurface(doc.body);
36
+ expect(surface).toBeTruthy();
34
37
  },
35
- { timeout: 15000 },
38
+ { timeout: 60_000 },
36
39
  );
37
40
  }
38
41
 
39
- export async function setWidgetTreeSourceJson(
40
- canvasElement: HTMLElement,
41
- value: string,
42
- ): Promise<void> {
43
- await waitForWidgetTreeMonaco(canvasElement);
44
-
45
- const editorRoot = canvasElement.querySelector('.widget-tree-source .monaco-editor');
46
- if (!editorRoot) {
47
- throw new Error('Monaco editor root was not found.');
48
- }
49
-
50
- const textarea = editorRoot.querySelector('textarea');
51
- if (textarea) {
52
- await userEvent.click(textarea);
53
- await userEvent.clear(textarea);
54
- await userEvent.paste(value);
55
- } else {
56
- await userEvent.click(editorRoot);
57
- await userEvent.keyboard('{Control>}a{/Control}');
58
- await userEvent.keyboard('{Delete}');
59
- await userEvent.paste(value);
60
- }
42
+ /**
43
+ * Match WidgetTreeCanvasPreview unit tests: synthetic pointers have no active
44
+ * capture target, so setPointerCapture throws NotFoundError (swallowed by canvas).
45
+ */
46
+ export function mockPointerCapture(handle: HTMLElement): void {
47
+ Object.defineProperty(handle, 'setPointerCapture', {
48
+ configurable: true,
49
+ value: () => {
50
+ throw new DOMException('No active pointer.', 'NotFoundError');
51
+ },
52
+ });
53
+ Object.defineProperty(handle, 'hasPointerCapture', {
54
+ configurable: true,
55
+ value: () => false,
56
+ });
57
+ }
61
58
 
62
- await waitFor(
63
- () => {
64
- const monacoGlobal = (window as Window & { monaco?: MonacoGlobal }).monaco;
65
- const editor = monacoGlobal?.editor.getEditors().find((candidate) => {
66
- const domNode = candidate.getDomNode();
67
- return domNode ? editorRoot.contains(domNode) : false;
68
- });
59
+ export function createPointerLikeEvent(
60
+ type: string,
61
+ clientX: number,
62
+ clientY: number,
63
+ pointerId = 1,
64
+ ): PointerEvent {
65
+ const event = new MouseEvent(type, {
66
+ bubbles: true,
67
+ button: 0,
68
+ buttons: type === 'pointerup' ? 0 : 1,
69
+ cancelable: true,
70
+ clientX,
71
+ clientY,
72
+ }) as PointerEvent;
73
+ Object.defineProperty(event, 'pointerId', { configurable: true, value: pointerId });
74
+ return event;
75
+ }
69
76
 
70
- expect(editor?.getValue()).toBe(value);
71
- },
72
- { timeout: 5000 },
73
- );
77
+ export function dispatchCanvasPointer(
78
+ handle: HTMLElement,
79
+ type: 'pointerdown' | 'pointermove' | 'pointerup',
80
+ clientX: number,
81
+ clientY: number,
82
+ pointerId = 1,
83
+ ): void {
84
+ handle.dispatchEvent(createPointerLikeEvent(type, clientX, clientY, pointerId));
74
85
  }