@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,8 +1,23 @@
1
+ import { useEffect, useMemo, useRef, type ReactNode } from 'react';
1
2
  import type { WidgetRegistryContract } from '@workbench-kit/contracts';
2
- import { parseJsonWidgetData, type LayoutConstraints } from '@workbench-kit/jdw';
3
+ import {
4
+ collectJsonWidgetChangedValuePaths,
5
+ collectJsonWidgetInvalidations,
6
+ expandJsonWidgetDocumentRefs,
7
+ parseJsonWidgetData,
8
+ resolveJsonWidgetValues,
9
+ validateJsonWidgetNode,
10
+ type LayoutConstraints,
11
+ type JsonWidgetValueMap,
12
+ type JsonWidgetInvalidation,
13
+ type ValidationIssue,
14
+ type WidgetPath,
15
+ } from '@workbench-kit/jdw';
3
16
 
4
17
  import { WorkbenchParseError, WorkbenchRenderSurface } from '../layout/WorkbenchLayout.js';
5
- import { useRenderJdw } from './renderJdw.js';
18
+ import { renderJdwWithLayout } from './cssRenderBackend.js';
19
+
20
+ const EMPTY_CHANGED_VALUE_PATHS: readonly string[] = [];
6
21
 
7
22
  export interface JdwPreviewProps {
8
23
  json: string;
@@ -10,6 +25,49 @@ export interface JdwPreviewProps {
10
25
  emptyLabel?: string | undefined;
11
26
  className?: string | undefined;
12
27
  layoutConstraints?: LayoutConstraints | undefined;
28
+ selectedPath?: WidgetPath | null | undefined;
29
+ strictKnownTypes?: boolean | undefined;
30
+ values?: JsonWidgetValueMap | undefined;
31
+ changedValuePaths?: readonly string[] | undefined;
32
+ onSelectPath?: ((path: WidgetPath) => void) | undefined;
33
+ /**
34
+ * When set, expand `type: "ref"` before validate/layout so composed documents
35
+ * draw without mutating the authored JSON shown in Code/Form outline.
36
+ */
37
+ documentPath?: string | null | undefined;
38
+ loadDocument?: ((path: string) => string | null) | undefined;
39
+ }
40
+
41
+ function formatValidationMessage(issue: { readonly message: string; readonly path: string }) {
42
+ return issue.path ? `${issue.path}: ${issue.message}` : issue.message;
43
+ }
44
+
45
+ export function getJdwPreviewInvalidations(
46
+ json: string,
47
+ changedValuePaths: readonly string[] = [],
48
+ ): readonly JsonWidgetInvalidation[] {
49
+ const parsed = parseJsonWidgetData(json);
50
+ if (parsed.parseError !== null || parsed.value === null) {
51
+ return [];
52
+ }
53
+
54
+ return collectJsonWidgetInvalidations(parsed.value, changedValuePaths);
55
+ }
56
+
57
+ function mergeChangedValuePaths(
58
+ first: readonly string[],
59
+ second: readonly string[],
60
+ ): readonly string[] {
61
+ return [
62
+ ...new Set([...first, ...second].map((path) => path.trim()).filter((path) => path.length > 0)),
63
+ ];
64
+ }
65
+
66
+ interface JdwPreviewState {
67
+ readonly invalidations: readonly JsonWidgetInvalidation[];
68
+ readonly issues: readonly ValidationIssue[];
69
+ readonly renderOutput: ReactNode;
70
+ readonly valid: boolean;
13
71
  }
14
72
 
15
73
  export function JdwPreview({
@@ -18,21 +76,120 @@ export function JdwPreview({
18
76
  emptyLabel = 'No render output.',
19
77
  className,
20
78
  layoutConstraints,
79
+ selectedPath = null,
80
+ strictKnownTypes = true,
81
+ values,
82
+ changedValuePaths = EMPTY_CHANGED_VALUE_PATHS,
83
+ onSelectPath,
84
+ documentPath = null,
85
+ loadDocument,
21
86
  }: JdwPreviewProps) {
22
- const parsed = parseJsonWidgetData(json);
23
- const renderOutput = useRenderJdw(json, { registry, emptyLabel, layoutConstraints });
87
+ const previousValuesRef = useRef<JsonWidgetValueMap | undefined>(values);
88
+ const onSelectPathRef = useRef(onSelectPath);
89
+ onSelectPathRef.current = onSelectPath;
90
+
91
+ const changedValuePathsFromValues = useMemo(
92
+ () => collectJsonWidgetChangedValuePaths(previousValuesRef.current, values),
93
+ [values],
94
+ );
95
+ const activeChangedValuePaths = useMemo(
96
+ () => mergeChangedValuePaths(changedValuePaths, changedValuePathsFromValues),
97
+ [changedValuePaths, changedValuePathsFromValues],
98
+ );
99
+
100
+ useEffect(() => {
101
+ previousValuesRef.current = values;
102
+ }, [values]);
103
+
104
+ const previewState = useMemo<JdwPreviewState>(() => {
105
+ const parsed = parseJsonWidgetData(json);
106
+ if (parsed.parseError !== null || parsed.value === null) {
107
+ return {
108
+ invalidations: [],
109
+ issues: [
110
+ {
111
+ path: 'root',
112
+ message: parsed.parseError ?? 'Invalid JSON widget data.',
113
+ },
114
+ ],
115
+ renderOutput: null,
116
+ valid: false,
117
+ };
118
+ }
119
+
120
+ let drawableNode = parsed.value;
121
+ if (loadDocument) {
122
+ const expanded = expandJsonWidgetDocumentRefs(parsed.value, {
123
+ documentPath,
124
+ loadDocument,
125
+ });
126
+ if (expanded.issues.length > 0 || expanded.value === null) {
127
+ return {
128
+ invalidations: [],
129
+ issues: expanded.issues.map((issue) => ({
130
+ path: issue.path,
131
+ message: issue.message,
132
+ })),
133
+ renderOutput: null,
134
+ valid: false,
135
+ };
136
+ }
137
+ drawableNode = expanded.value;
138
+ }
139
+
140
+ const resolvedNode = resolveJsonWidgetValues(drawableNode, values);
141
+ const issues: ValidationIssue[] = [];
142
+ validateJsonWidgetNode(resolvedNode, 'root', issues, {
143
+ registeredTypes: registry?.types(),
144
+ strictKnownTypes,
145
+ });
146
+
147
+ return {
148
+ invalidations: collectJsonWidgetInvalidations(drawableNode, activeChangedValuePaths),
149
+ issues,
150
+ renderOutput:
151
+ issues.length === 0
152
+ ? renderJdwWithLayout(resolvedNode, {
153
+ registry,
154
+ emptyLabel,
155
+ layoutConstraints,
156
+ selectedPath,
157
+ onSelectPath: (path) => onSelectPathRef.current?.(path),
158
+ })
159
+ : null,
160
+ valid: issues.length === 0,
161
+ };
162
+ }, [
163
+ activeChangedValuePaths,
164
+ documentPath,
165
+ emptyLabel,
166
+ json,
167
+ layoutConstraints,
168
+ loadDocument,
169
+ registry,
170
+ selectedPath,
171
+ strictKnownTypes,
172
+ values,
173
+ ]);
24
174
 
25
- if (parsed.parseError !== null) {
175
+ if (!previewState.valid) {
176
+ const firstIssue = previewState.issues[0];
26
177
  return (
27
178
  <WorkbenchParseError role="alert" data-testid="jdw-preview-error">
28
- {parsed.parseError}
179
+ {firstIssue ? formatValidationMessage(firstIssue) : 'Invalid JDW document.'}
29
180
  </WorkbenchParseError>
30
181
  );
31
182
  }
32
183
 
33
184
  return (
34
- <WorkbenchRenderSurface className={className} data-testid="jdw-preview-output">
35
- {renderOutput ?? emptyLabel}
185
+ <WorkbenchRenderSurface
186
+ className={className}
187
+ data-jdw-invalidations={
188
+ previewState.invalidations.length > 0 ? previewState.invalidations.length : undefined
189
+ }
190
+ data-testid="jdw-preview-output"
191
+ >
192
+ {previewState.renderOutput ?? emptyLabel}
36
193
  </WorkbenchRenderSurface>
37
194
  );
38
195
  }
@@ -0,0 +1,190 @@
1
+ import { useLayoutEffect, useMemo, useState, type ReactNode } from 'react';
2
+ import type { WidgetRegistryContract } from '@workbench-kit/contracts';
3
+ import {
4
+ DEFAULT_LAYOUT_CONSTRAINTS,
5
+ createWidgetDocument,
6
+ layoutWidget,
7
+ type LayoutConstraints,
8
+ } from '@workbench-kit/jdw';
9
+
10
+ import { WorkbenchPreviewCanvas } from '../layout/WorkbenchCanvas.js';
11
+ import { usePreviewViewport } from '../layout/usePreviewViewport.js';
12
+ import { cx } from '../utils/cx.js';
13
+ import { JdwPreview, type JdwPreviewProps } from './JdwPreview.js';
14
+
15
+ import './jdw-preview-viewport.css';
16
+
17
+ const FALLBACK_FRAME_SIZE = { height: 320, width: 400 } as const;
18
+
19
+ export type JdwPreviewViewportFit = 'container' | 'content';
20
+
21
+ export interface JdwPreviewViewportProps extends JdwPreviewProps {
22
+ /**
23
+ * `container` (default): outside-in — host size drives layout constraints.
24
+ * `content`: inside-out — document/layoutConstraints size the frame, then scale-to-fit.
25
+ */
26
+ readonly fit?: JdwPreviewViewportFit | undefined;
27
+ readonly help?: ReactNode | undefined;
28
+ readonly showReset?: boolean | undefined;
29
+ readonly showViewportGrid?: boolean | undefined;
30
+ /**
31
+ * When false, only middle-mouse pans (safer when preview nodes are selectable).
32
+ * Default true for read-only preview surfaces.
33
+ */
34
+ readonly enablePrimaryPointerPan?: boolean | undefined;
35
+ }
36
+
37
+ export function resolveJdwPreviewFrameSize(
38
+ json: string,
39
+ layoutConstraints: LayoutConstraints = DEFAULT_LAYOUT_CONSTRAINTS,
40
+ registry?: WidgetRegistryContract<unknown> | undefined,
41
+ ): { readonly height: number; readonly width: number } {
42
+ const document = createWidgetDocument(json);
43
+ if (document.root === null) {
44
+ return FALLBACK_FRAME_SIZE;
45
+ }
46
+
47
+ try {
48
+ const layout = layoutWidget(document.root, layoutConstraints, { x: 0, y: 0 }, { registry });
49
+ return {
50
+ height: Math.max(1, Math.round(layout.rect.height)),
51
+ width: Math.max(1, Math.round(layout.rect.width)),
52
+ };
53
+ } catch {
54
+ return FALLBACK_FRAME_SIZE;
55
+ }
56
+ }
57
+
58
+ export function resolveContainerLayoutConstraints(
59
+ hostWidth: number,
60
+ hostHeight: number,
61
+ inset = 0,
62
+ ): LayoutConstraints {
63
+ return {
64
+ minWidth: 0,
65
+ maxWidth: Math.max(1, Math.floor(hostWidth) - inset),
66
+ minHeight: 0,
67
+ maxHeight: Math.max(1, Math.floor(hostHeight) - inset),
68
+ };
69
+ }
70
+
71
+ export function JdwPreviewViewport({
72
+ className,
73
+ enablePrimaryPointerPan = true,
74
+ fit = 'container',
75
+ help = 'Ctrl + Scroll to zoom | Drag or scroll to pan',
76
+ json,
77
+ layoutConstraints = DEFAULT_LAYOUT_CONSTRAINTS,
78
+ registry,
79
+ showReset = true,
80
+ showViewportGrid = true,
81
+ ...previewProps
82
+ }: JdwPreviewViewportProps) {
83
+ const [hostElement, setHostElement] = useState<HTMLDivElement | null>(null);
84
+ const [hostSize, setHostSize] = useState<{ height: number; width: number } | null>(null);
85
+
86
+ useLayoutEffect(() => {
87
+ if (!hostElement) {
88
+ return undefined;
89
+ }
90
+
91
+ const updateSize = () => {
92
+ const rect = hostElement.getBoundingClientRect();
93
+ const width = Math.max(0, Math.floor(rect.width));
94
+ const height = Math.max(0, Math.floor(rect.height));
95
+ setHostSize((current) =>
96
+ current && current.width === width && current.height === height
97
+ ? current
98
+ : { width, height },
99
+ );
100
+ };
101
+
102
+ updateSize();
103
+ if (typeof ResizeObserver === 'undefined') {
104
+ return undefined;
105
+ }
106
+
107
+ const observer = new ResizeObserver(updateSize);
108
+ observer.observe(hostElement);
109
+ return () => observer.disconnect();
110
+ }, [hostElement]);
111
+
112
+ const effectiveConstraints = useMemo(() => {
113
+ if (fit === 'container' && hostSize && hostSize.width > 0 && hostSize.height > 0) {
114
+ return resolveContainerLayoutConstraints(hostSize.width, hostSize.height);
115
+ }
116
+ return layoutConstraints;
117
+ }, [fit, hostSize, layoutConstraints]);
118
+
119
+ const frame = useMemo(() => {
120
+ if (fit === 'container' && hostSize && hostSize.width > 0 && hostSize.height > 0) {
121
+ // Outside-in: host size is the frame. Layout still uses the same constraints.
122
+ return {
123
+ width: Math.max(1, Math.floor(hostSize.width)),
124
+ height: Math.max(1, Math.floor(hostSize.height)),
125
+ };
126
+ }
127
+ return resolveJdwPreviewFrameSize(json, effectiveConstraints, registry);
128
+ }, [effectiveConstraints, fit, hostSize, json, registry]);
129
+ const viewport = usePreviewViewport({
130
+ contentHeight: frame.height,
131
+ contentWidth: frame.width,
132
+ enablePrimaryPointerPan,
133
+ ignoreInteractiveTargets: true,
134
+ viewportPadding: fit === 'container' ? 0 : 24,
135
+ });
136
+
137
+ const document = useMemo(() => createWidgetDocument(json), [json]);
138
+ const canRenderViewport = document.root !== null && document.parseError === null;
139
+
140
+ return (
141
+ <div
142
+ ref={setHostElement}
143
+ className={cx('ui-jdw-preview-viewport-host', className)}
144
+ data-fit={fit}
145
+ data-testid="jdw-preview-viewport-host"
146
+ >
147
+ {!canRenderViewport ? (
148
+ <JdwPreview
149
+ {...previewProps}
150
+ json={json}
151
+ layoutConstraints={effectiveConstraints}
152
+ registry={registry}
153
+ />
154
+ ) : hostSize === null ? null : (
155
+ <WorkbenchPreviewCanvas
156
+ className="ui-jdw-preview-viewport"
157
+ data-testid="jdw-preview-viewport"
158
+ frameHeight={frame.height}
159
+ frameTitle="JDW Preview"
160
+ frameWidth={frame.width}
161
+ help={help}
162
+ isPanning={viewport.isPanning}
163
+ onResetView={showReset ? viewport.resetView : undefined}
164
+ resetLabel={`Reset (${Math.round(viewport.effectiveZoom * 100)}%)`}
165
+ resetTitle="Reset zoom and pan"
166
+ showViewportGrid={showViewportGrid}
167
+ showWindowFrame={false}
168
+ stageStyle={viewport.stageStyle}
169
+ viewportGridSize={8}
170
+ viewportProps={{
171
+ ref: viewport.setViewportElement,
172
+ }}
173
+ >
174
+ <div
175
+ className="ui-jdw-preview-viewport__stage"
176
+ style={{ width: frame.width, height: frame.height }}
177
+ >
178
+ <JdwPreview
179
+ {...previewProps}
180
+ className="ui-jdw-preview-viewport__render"
181
+ json={json}
182
+ layoutConstraints={effectiveConstraints}
183
+ registry={registry}
184
+ />
185
+ </div>
186
+ </WorkbenchPreviewCanvas>
187
+ )}
188
+ </div>
189
+ );
190
+ }
@@ -1,10 +1,9 @@
1
1
  import { useEffect, useMemo, useRef, useState, type ReactNode } from 'react';
2
2
  import type { WidgetJsonSchema } from '@workbench-kit/contracts';
3
- import type { OnMount } from '@monaco-editor/react';
4
- import type * as Monaco from 'monaco-editor';
3
+ import type { IDisposable, OnMount, WorkbenchMonaco, editor } from '@workbench-kit/monaco';
5
4
 
6
- import { IconButton } from '../primitives/IconButton';
7
- import { ListEmptyState } from '../primitives/List';
5
+ import { IconButton } from '../primitives/icon-button';
6
+ import { ListEmptyState } from '../primitives/list';
8
7
  import {
9
8
  WorkbenchEditorBody,
10
9
  WorkbenchEditorBottomPanel,
@@ -21,11 +20,11 @@ import {
21
20
  StatusBar as WorkbenchStatusBar,
22
21
  StatusBarItem as WorkbenchStatusBarItem,
23
22
  StatusBarSection as WorkbenchStatusBarSection,
24
- } from '../workbench/StatusBar';
23
+ } from '../workbench/shell/StatusBar';
25
24
  import { WorkspaceEditor, type WorkspaceEditorTheme } from '../workbench/workspace/WorkspaceEditor';
26
25
  import type { WorkspaceFile } from '../workbench/workspace/types';
27
26
 
28
- interface JsonEditorProblem {
27
+ export interface JsonEditorProblem {
29
28
  endColumn: number;
30
29
  endLineNumber: number;
31
30
  message: string;
@@ -40,12 +39,69 @@ function toWorkbenchProblemSeverity(severity: number): WorkbenchProblemSeverity
40
39
  return 'info';
41
40
  }
42
41
 
42
+ function pluralizeProblemLabel(count: number, label: string): string {
43
+ return `${count} ${label}${count === 1 ? '' : 's'}`;
44
+ }
45
+
46
+ export function summarizeJsonEditorProblems(problems: readonly JsonEditorProblem[]): {
47
+ readonly icon: string;
48
+ readonly label: string;
49
+ readonly status: 'completed' | 'failed' | 'warning';
50
+ } {
51
+ const errorCount = problems.filter(
52
+ (problem) => toWorkbenchProblemSeverity(problem.severity) === 'error',
53
+ ).length;
54
+ const warningCount = problems.filter(
55
+ (problem) => toWorkbenchProblemSeverity(problem.severity) === 'warning',
56
+ ).length;
57
+
58
+ if (errorCount > 0) {
59
+ return {
60
+ icon: 'error',
61
+ label:
62
+ warningCount > 0
63
+ ? `${pluralizeProblemLabel(errorCount, 'Error')}, ${pluralizeProblemLabel(
64
+ warningCount,
65
+ 'Warning',
66
+ )}`
67
+ : pluralizeProblemLabel(errorCount, 'Error'),
68
+ status: 'failed',
69
+ };
70
+ }
71
+
72
+ if (warningCount > 0) {
73
+ return {
74
+ icon: 'warning',
75
+ label: pluralizeProblemLabel(warningCount, 'Warning'),
76
+ status: 'warning',
77
+ };
78
+ }
79
+
80
+ if (problems.length > 0) {
81
+ return {
82
+ icon: 'info',
83
+ label: pluralizeProblemLabel(problems.length, 'Info'),
84
+ status: 'completed',
85
+ };
86
+ }
87
+
88
+ return {
89
+ icon: 'check',
90
+ label: 'No Problems',
91
+ status: 'completed',
92
+ };
93
+ }
94
+
43
95
  export interface JsonCodeEditorPaneProps {
96
+ activeSourceRange?: JsonEditorRange | null | undefined;
44
97
  documentParseError?: string | null | undefined;
45
98
  file: WorkspaceFile;
46
99
  jsonSchema?: WidgetJsonSchema | null | undefined;
100
+ revealPosition?: JsonEditorPosition | null | undefined;
101
+ onCursorPositionChange?: ((position: JsonEditorPosition) => void) | undefined;
47
102
  onChange: (value: string) => void;
48
103
  onEditorMount?: OnMount | undefined;
104
+ problems?: readonly JsonEditorProblem[] | undefined;
49
105
  onSave?: (() => void) | undefined;
50
106
  readOnly?: boolean | undefined;
51
107
  showProblemsPanel?: boolean | undefined;
@@ -53,25 +109,66 @@ export interface JsonCodeEditorPaneProps {
53
109
  value: string;
54
110
  }
55
111
 
112
+ export interface JsonEditorPosition {
113
+ readonly column: number;
114
+ readonly lineNumber: number;
115
+ }
116
+
117
+ export interface JsonEditorRange {
118
+ readonly startLineNumber: number;
119
+ readonly startColumn: number;
120
+ readonly endLineNumber: number;
121
+ readonly endColumn: number;
122
+ }
123
+
124
+ const MONACO_DECORATION_STICKINESS_NEVER_GROWS = 1;
125
+
126
+ export function createJsonEditorActiveSourceRangeDecorations(
127
+ activeSourceRange: JsonEditorRange | null | undefined,
128
+ ): editor.IModelDeltaDecoration[] {
129
+ if (!activeSourceRange) return [];
130
+
131
+ return [
132
+ {
133
+ range: activeSourceRange,
134
+ options: {
135
+ className: 'ui-json-code-editor-pane__active-source-range',
136
+ stickiness: MONACO_DECORATION_STICKINESS_NEVER_GROWS,
137
+ },
138
+ },
139
+ ];
140
+ }
141
+
56
142
  export function JsonCodeEditorPane({
143
+ activeSourceRange = null,
57
144
  documentParseError = null,
58
145
  file,
59
146
  jsonSchema = null,
147
+ revealPosition = null,
148
+ onCursorPositionChange,
60
149
  onChange,
61
150
  onEditorMount,
151
+ problems: externalProblems = [],
62
152
  onSave,
63
153
  readOnly = false,
64
154
  showProblemsPanel = true,
65
155
  theme = 'dark',
66
156
  value,
67
157
  }: JsonCodeEditorPaneProps) {
68
- const editorRef = useRef<Monaco.editor.IStandaloneCodeEditor | null>(null);
69
- const markerListenerRef = useRef<Monaco.IDisposable | null>(null);
158
+ const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null);
159
+ const activeSourceRangeDecorationsRef = useRef<editor.IEditorDecorationsCollection | null>(null);
160
+ const markerListenerRef = useRef<IDisposable | null>(null);
161
+ const cursorListenerRef = useRef<IDisposable | null>(null);
162
+ const cursorChangeRef = useRef<typeof onCursorPositionChange>(onCursorPositionChange);
70
163
  const [monacoProblems, setMonacoProblems] = useState<JsonEditorProblem[]>([]);
71
164
  const [showProblems, setShowProblems] = useState(false);
72
165
 
166
+ useEffect(() => {
167
+ cursorChangeRef.current = onCursorPositionChange;
168
+ }, [onCursorPositionChange]);
169
+
73
170
  const problems = useMemo(() => {
74
- if (!documentParseError) return monacoProblems;
171
+ if (!documentParseError) return [...externalProblems, ...monacoProblems];
75
172
  return [
76
173
  {
77
174
  endColumn: 1,
@@ -81,9 +178,11 @@ export function JsonCodeEditorPane({
81
178
  startColumn: 1,
82
179
  startLineNumber: 1,
83
180
  },
181
+ ...externalProblems,
84
182
  ...monacoProblems,
85
183
  ];
86
- }, [documentParseError, monacoProblems]);
184
+ }, [documentParseError, externalProblems, monacoProblems]);
185
+ const problemSummary = useMemo(() => summarizeJsonEditorProblems(problems), [problems]);
87
186
 
88
187
  const previousProblemCountRef = useRef(0);
89
188
  useEffect(() => {
@@ -97,18 +196,61 @@ export function JsonCodeEditorPane({
97
196
  () => () => {
98
197
  markerListenerRef.current?.dispose();
99
198
  markerListenerRef.current = null;
199
+ cursorListenerRef.current?.dispose();
200
+ cursorListenerRef.current = null;
201
+ activeSourceRangeDecorationsRef.current?.clear();
202
+ activeSourceRangeDecorationsRef.current = null;
100
203
  },
101
204
  [],
102
205
  );
103
206
 
104
- const configureJsonSchema = (monaco: typeof Monaco, path: string) => {
207
+ useEffect(() => {
208
+ if (!revealPosition) return;
209
+
210
+ const editor = editorRef.current;
211
+ if (!editor) return;
212
+
213
+ editor.setPosition(revealPosition);
214
+ editor.revealPositionInCenter(revealPosition);
215
+ }, [revealPosition?.column, revealPosition?.lineNumber]);
216
+
217
+ const syncActiveSourceRangeDecorations = (monacoEditor: editor.IStandaloneCodeEditor) => {
218
+ const decorations = createJsonEditorActiveSourceRangeDecorations(activeSourceRange);
219
+ if (decorations.length === 0) {
220
+ activeSourceRangeDecorationsRef.current?.clear();
221
+ return;
222
+ }
223
+
224
+ if (!activeSourceRangeDecorationsRef.current) {
225
+ activeSourceRangeDecorationsRef.current =
226
+ monacoEditor.createDecorationsCollection(decorations);
227
+ return;
228
+ }
229
+
230
+ activeSourceRangeDecorationsRef.current.set(decorations);
231
+ };
232
+
233
+ useEffect(() => {
234
+ const monacoEditor = editorRef.current;
235
+ if (!monacoEditor) return;
236
+
237
+ syncActiveSourceRangeDecorations(monacoEditor);
238
+ }, [
239
+ activeSourceRange?.endColumn,
240
+ activeSourceRange?.endLineNumber,
241
+ activeSourceRange?.startColumn,
242
+ activeSourceRange?.startLineNumber,
243
+ ]);
244
+
245
+ const configureJsonSchema = (monaco: WorkbenchMonaco, path: string) => {
105
246
  if (!jsonSchema) return;
106
247
 
107
- const jsonDefaults = (
108
- monaco.languages.json as unknown as {
109
- jsonDefaults?: { setDiagnosticsOptions: (options: unknown) => void };
110
- }
111
- ).jsonDefaults;
248
+ const jsonLanguage = monaco.languages.json as unknown as
249
+ | {
250
+ jsonDefaults?: { setDiagnosticsOptions: (options: unknown) => void };
251
+ }
252
+ | undefined;
253
+ const jsonDefaults = jsonLanguage?.jsonDefaults;
112
254
  if (!jsonDefaults) return;
113
255
 
114
256
  jsonDefaults.setDiagnosticsOptions({
@@ -116,7 +258,7 @@ export function JsonCodeEditorPane({
116
258
  enableSchemaRequest: false,
117
259
  schemas: [
118
260
  {
119
- uri: 'https://workbench-kit.dev/schemas/widget-document.schema.json',
261
+ uri: 'https://workbench-kit.dev/schemas/widget-document.v1.jdw.schema.json',
120
262
  fileMatch: [path],
121
263
  schema: jsonSchema,
122
264
  },
@@ -126,9 +268,18 @@ export function JsonCodeEditorPane({
126
268
 
127
269
  const handleMount: OnMount = (editor, monaco) => {
128
270
  editorRef.current = editor;
271
+ syncActiveSourceRangeDecorations(editor);
129
272
  configureJsonSchema(monaco, file.path);
130
273
  onEditorMount?.(editor, monaco);
131
274
 
275
+ cursorListenerRef.current?.dispose();
276
+ cursorListenerRef.current = editor.onDidChangeCursorPosition((event) => {
277
+ cursorChangeRef.current?.({
278
+ column: event.position.column,
279
+ lineNumber: event.position.lineNumber,
280
+ });
281
+ });
282
+
132
283
  if (onSave) {
133
284
  editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {
134
285
  onSave();
@@ -146,7 +297,7 @@ export function JsonCodeEditorPane({
146
297
  const updateProblems = () => {
147
298
  const markers = monaco.editor.getModelMarkers({ resource: model.uri });
148
299
  setMonacoProblems(
149
- markers.map((marker: Monaco.editor.IMarker) => ({
300
+ markers.map((marker: editor.IMarker) => ({
150
301
  message: marker.message,
151
302
  severity: marker.severity,
152
303
  startLineNumber: marker.startLineNumber,
@@ -225,12 +376,12 @@ export function JsonCodeEditorPane({
225
376
  <WorkbenchStatusBarSection>
226
377
  <WorkbenchStatusBarItem
227
378
  active={showProblems}
228
- icon={problems.length > 0 ? 'error' : 'check'}
229
- status={problems.length > 0 ? 'failed' : 'completed'}
379
+ icon={problemSummary.icon}
380
+ status={problemSummary.status}
230
381
  title="Toggle problems"
231
382
  onClick={() => setShowProblems((current) => !current)}
232
383
  >
233
- {problems.length > 0 ? `${problems.length} Problems` : 'No Problems'}
384
+ {problemSummary.label}
234
385
  </WorkbenchStatusBarItem>
235
386
  </WorkbenchStatusBarSection>
236
387
  </WorkbenchStatusBar>