@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
@@ -0,0 +1,107 @@
1
+ export type AnchoredOverlayPlacement = 'side' | 'below' | 'above';
2
+
3
+ export interface MeasureAnchoredOverlayPanelOptions {
4
+ readonly panelWidthPx?: number;
5
+ readonly viewportPaddingPx?: number;
6
+ readonly anchorGapPx?: number;
7
+ readonly maxHeightRatio?: number;
8
+ readonly sidePreferTriggerLeftRatio?: number;
9
+ }
10
+
11
+ export interface AnchoredOverlayPanelRect {
12
+ readonly top: number;
13
+ readonly left: number;
14
+ readonly width: number;
15
+ readonly maxHeight: number;
16
+ readonly placement: AnchoredOverlayPlacement;
17
+ }
18
+
19
+ const DEFAULT_PANEL_WIDTH_PX = 360;
20
+ const DEFAULT_VIEWPORT_PADDING_PX = 8;
21
+ const DEFAULT_ANCHOR_GAP_PX = 6;
22
+ const DEFAULT_MAX_HEIGHT_RATIO = 0.72;
23
+ const DEFAULT_SIDE_PREFER_TRIGGER_LEFT_RATIO = 0.42;
24
+ /** Assumed minimum panel height when clamping side placement into the viewport. */
25
+ const SIDE_MIN_VISIBLE_HEIGHT_PX = 240;
26
+ /** Prefer below when at least this many pixels are available under the trigger. */
27
+ const BELOW_MIN_SPACE_PX = 12;
28
+
29
+ function clamp(value: number, min: number, max: number): number {
30
+ return Math.min(Math.max(value, min), max);
31
+ }
32
+
33
+ /**
34
+ * Measure a panel-sized overlay anchored to a trigger element.
35
+ * Prefers a side flyout when the trigger sits in the left portion of the
36
+ * viewport and there is room; otherwise places below or above.
37
+ */
38
+ export function measureAnchoredOverlayPanel(
39
+ trigger: HTMLElement,
40
+ options: MeasureAnchoredOverlayPanelOptions = {},
41
+ ): AnchoredOverlayPanelRect {
42
+ const panelWidthPx = options.panelWidthPx ?? DEFAULT_PANEL_WIDTH_PX;
43
+ const viewportPaddingPx = options.viewportPaddingPx ?? DEFAULT_VIEWPORT_PADDING_PX;
44
+ const anchorGapPx = options.anchorGapPx ?? DEFAULT_ANCHOR_GAP_PX;
45
+ const maxHeightRatio = options.maxHeightRatio ?? DEFAULT_MAX_HEIGHT_RATIO;
46
+ const sidePreferTriggerLeftRatio =
47
+ options.sidePreferTriggerLeftRatio ?? DEFAULT_SIDE_PREFER_TRIGGER_LEFT_RATIO;
48
+
49
+ const viewportWidth = window.innerWidth;
50
+ const viewportHeight = window.innerHeight;
51
+ const triggerRect = trigger.getBoundingClientRect();
52
+
53
+ const maxHeight = Math.min(
54
+ viewportHeight * maxHeightRatio,
55
+ viewportHeight - viewportPaddingPx * 2,
56
+ );
57
+ const width = Math.min(panelWidthPx, viewportWidth - viewportPaddingPx * 2);
58
+
59
+ const spaceRight = Math.max(0, viewportWidth - triggerRect.right - viewportPaddingPx);
60
+ const spaceBelow = Math.max(0, viewportHeight - triggerRect.bottom - viewportPaddingPx);
61
+ const spaceAbove = Math.max(0, triggerRect.top - viewportPaddingPx);
62
+
63
+ const preferSide =
64
+ triggerRect.left < sidePreferTriggerLeftRatio * viewportWidth && spaceRight >= width;
65
+
66
+ if (preferSide) {
67
+ const minVisibleHeight = Math.min(SIDE_MIN_VISIBLE_HEIGHT_PX, maxHeight);
68
+ const top = clamp(
69
+ triggerRect.top,
70
+ viewportPaddingPx,
71
+ viewportHeight - viewportPaddingPx - minVisibleHeight,
72
+ );
73
+ return {
74
+ placement: 'side',
75
+ top,
76
+ left: triggerRect.right + anchorGapPx,
77
+ width,
78
+ maxHeight,
79
+ };
80
+ }
81
+
82
+ // Align the panel's right edge toward the trigger's right, then clamp.
83
+ const left = clamp(
84
+ triggerRect.right - width,
85
+ viewportPaddingPx,
86
+ viewportWidth - viewportPaddingPx - width,
87
+ );
88
+
89
+ if (spaceBelow >= BELOW_MIN_SPACE_PX || spaceBelow >= spaceAbove) {
90
+ return {
91
+ placement: 'below',
92
+ top: triggerRect.bottom + anchorGapPx,
93
+ left,
94
+ width,
95
+ maxHeight,
96
+ };
97
+ }
98
+
99
+ const aboveHeight = Math.min(maxHeight, spaceAbove);
100
+ return {
101
+ placement: 'above',
102
+ top: triggerRect.top - anchorGapPx - aboveHeight,
103
+ left,
104
+ width,
105
+ maxHeight,
106
+ };
107
+ }
@@ -0,0 +1,2 @@
1
+ /* Overlay surfaces */
2
+ @import './context-menu.css';
@@ -0,0 +1,83 @@
1
+ export interface PointerPassthroughPort {
2
+ setPointerPassthrough(enabled: boolean): void | Promise<void>;
3
+ }
4
+
5
+ export interface PointerOverHitRegionOptions {
6
+ readonly hitSelectors: readonly string[];
7
+ readonly controlSelectors?: readonly string[];
8
+ readonly root?: HTMLElement | null;
9
+ }
10
+
11
+ /**
12
+ * Returns true when `target` matches any host-provided hit/control selector
13
+ * (and, when `root` is set, lies inside that root).
14
+ */
15
+ export function isPointerOverHitRegion(
16
+ target: EventTarget | null,
17
+ options: PointerOverHitRegionOptions,
18
+ ): boolean {
19
+ if (!(target instanceof Element)) {
20
+ return false;
21
+ }
22
+
23
+ const root = options.root ?? null;
24
+ if (root !== null && !root.contains(target)) {
25
+ return false;
26
+ }
27
+
28
+ const selectors = [...options.hitSelectors, ...(options.controlSelectors ?? [])];
29
+ for (const selector of selectors) {
30
+ if (selector.length === 0) {
31
+ continue;
32
+ }
33
+ if (target.closest(selector) !== null) {
34
+ return true;
35
+ }
36
+ }
37
+ return false;
38
+ }
39
+
40
+ export interface PointerPassthroughControllerOptions extends PointerOverHitRegionOptions {
41
+ readonly enabled: boolean;
42
+ readonly port: PointerPassthroughPort;
43
+ }
44
+
45
+ export interface PointerPassthroughController {
46
+ handlePointerTarget(target: EventTarget | null): void;
47
+ /** Force the next decision to notify the port even if unchanged. */
48
+ reset(): void;
49
+ }
50
+
51
+ /**
52
+ * Pure controller for overlay click-through: when the pointer is outside
53
+ * host-provided selectors, ask the port to enable passthrough.
54
+ * Pair with platform `applyWindowResidency(..., 'click-through')` on the main side.
55
+ */
56
+ export function createPointerPassthroughController(
57
+ options: PointerPassthroughControllerOptions,
58
+ ): PointerPassthroughController {
59
+ let lastPassthrough: boolean | null = null;
60
+
61
+ return {
62
+ reset() {
63
+ lastPassthrough = null;
64
+ },
65
+ handlePointerTarget(target: EventTarget | null) {
66
+ if (!options.enabled) {
67
+ if (lastPassthrough !== false) {
68
+ lastPassthrough = false;
69
+ void options.port.setPointerPassthrough(false);
70
+ }
71
+ return;
72
+ }
73
+
74
+ const overHit = isPointerOverHitRegion(target, options);
75
+ const passthrough = !overHit;
76
+ if (passthrough === lastPassthrough) {
77
+ return;
78
+ }
79
+ lastPassthrough = passthrough;
80
+ void options.port.setPointerPassthrough(passthrough);
81
+ },
82
+ };
83
+ }
@@ -0,0 +1,222 @@
1
+ import {
2
+ useCallback,
3
+ useEffect,
4
+ useLayoutEffect,
5
+ useRef,
6
+ useState,
7
+ type CSSProperties,
8
+ type RefCallback,
9
+ type RefObject,
10
+ } from 'react';
11
+
12
+ import {
13
+ isSearchableMultiSelectPortalTarget,
14
+ resolvePortalContainer,
15
+ } from '../primitives/searchable-multi-select/overlay';
16
+ import {
17
+ measureAnchoredOverlayPanel,
18
+ type MeasureAnchoredOverlayPanelOptions,
19
+ } from './measureAnchoredOverlayPanel';
20
+
21
+ export interface UseAnchoredOverlayPanelOptions {
22
+ readonly open: boolean;
23
+ readonly onOpenChange: (open: boolean) => void;
24
+ readonly triggerRef: RefObject<HTMLElement | null>;
25
+ readonly panelRef?: RefObject<HTMLElement | null>;
26
+ readonly measureOptions?: MeasureAnchoredOverlayPanelOptions;
27
+ /** Extra "inside" predicates (e.g. host markers). */
28
+ readonly isInsideExtra?: (target: EventTarget | null) => boolean;
29
+ }
30
+
31
+ export interface UseAnchoredOverlayPanelResult {
32
+ readonly style: CSSProperties | null;
33
+ readonly portalRoot: HTMLElement;
34
+ readonly panelProps: {
35
+ /** Always a callback ref so it composes with host `panelRef` and panel shells. */
36
+ ref: RefCallback<HTMLElement>;
37
+ tabIndex: number;
38
+ style: CSSProperties | null;
39
+ };
40
+ }
41
+
42
+ function assignRef<T>(
43
+ ref: RefObject<T | null> | RefCallback<T> | null | undefined,
44
+ value: T | null,
45
+ ): void {
46
+ if (typeof ref === 'function') {
47
+ ref(value);
48
+ return;
49
+ }
50
+ if (ref) {
51
+ (ref as { current: T | null }).current = value;
52
+ }
53
+ }
54
+
55
+ function isInsideCatalogFilterOverlay(target: EventTarget | null): boolean {
56
+ if (!(target instanceof Element)) {
57
+ return false;
58
+ }
59
+ return target.closest('[data-ui-catalog-filter-overlay]') !== null;
60
+ }
61
+
62
+ /**
63
+ * Host-neutral anchored overlay panel helper: trigger-relative placement,
64
+ * viewport clamping, dismiss lifecycle, remeasure on resize/scroll, and portal root.
65
+ *
66
+ * Pair with `CatalogFilterOverlay` (or a similar panel shell). Unlike
67
+ * `useFixedOverlayDismiss`, scroll and resize remeasure instead of closing.
68
+ */
69
+ export function useAnchoredOverlayPanel({
70
+ open,
71
+ onOpenChange,
72
+ triggerRef,
73
+ panelRef: externalPanelRef,
74
+ measureOptions,
75
+ isInsideExtra,
76
+ }: UseAnchoredOverlayPanelOptions): UseAnchoredOverlayPanelResult {
77
+ const internalPanelRef = useRef<HTMLElement | null>(null);
78
+ const [style, setStyle] = useState<CSSProperties | null>(null);
79
+ const didFocusOnOpenRef = useRef(false);
80
+
81
+ const setPanelNode = useCallback<RefCallback<HTMLElement>>(
82
+ (node) => {
83
+ internalPanelRef.current = node;
84
+ assignRef(externalPanelRef, node);
85
+ },
86
+ [externalPanelRef],
87
+ );
88
+
89
+ const remeasure = useCallback(() => {
90
+ const trigger = triggerRef.current;
91
+ if (!open || !trigger) {
92
+ setStyle(null);
93
+ return;
94
+ }
95
+
96
+ const rect = measureAnchoredOverlayPanel(trigger, measureOptions);
97
+ setStyle({
98
+ position: 'fixed',
99
+ top: rect.top,
100
+ left: rect.left,
101
+ width: rect.width,
102
+ maxHeight: rect.maxHeight,
103
+ });
104
+ }, [measureOptions, open, triggerRef]);
105
+
106
+ useLayoutEffect(() => {
107
+ remeasure();
108
+ }, [remeasure]);
109
+
110
+ useEffect(() => {
111
+ if (!open) {
112
+ didFocusOnOpenRef.current = false;
113
+ return;
114
+ }
115
+
116
+ const handleResize = () => {
117
+ remeasure();
118
+ };
119
+ const handleScroll = () => {
120
+ remeasure();
121
+ };
122
+
123
+ window.addEventListener('resize', handleResize);
124
+ window.addEventListener('scroll', handleScroll, true);
125
+
126
+ return () => {
127
+ window.removeEventListener('resize', handleResize);
128
+ window.removeEventListener('scroll', handleScroll, true);
129
+ };
130
+ }, [open, remeasure]);
131
+
132
+ useEffect(() => {
133
+ if (!open) {
134
+ return;
135
+ }
136
+
137
+ const isInside = (target: EventTarget | null): boolean => {
138
+ const trigger = triggerRef.current;
139
+ const panel = internalPanelRef.current;
140
+ if (trigger && target instanceof Node && trigger.contains(target)) {
141
+ return true;
142
+ }
143
+ if (panel && target instanceof Node && panel.contains(target)) {
144
+ return true;
145
+ }
146
+ if (isInsideCatalogFilterOverlay(target)) {
147
+ return true;
148
+ }
149
+ if (isSearchableMultiSelectPortalTarget(target)) {
150
+ return true;
151
+ }
152
+ if (isInsideExtra?.(target)) {
153
+ return true;
154
+ }
155
+ return false;
156
+ };
157
+
158
+ const handleKeyDown = (event: KeyboardEvent) => {
159
+ if (event.key !== 'Escape') {
160
+ return;
161
+ }
162
+ if (event.defaultPrevented) {
163
+ return;
164
+ }
165
+ event.preventDefault();
166
+ onOpenChange(false);
167
+ };
168
+
169
+ const handlePointerDown = (event: PointerEvent) => {
170
+ if (event.defaultPrevented) {
171
+ return;
172
+ }
173
+ if (isInside(event.target)) {
174
+ return;
175
+ }
176
+ onOpenChange(false);
177
+ };
178
+
179
+ window.addEventListener('keydown', handleKeyDown);
180
+ window.addEventListener('pointerdown', handlePointerDown, true);
181
+
182
+ return () => {
183
+ window.removeEventListener('keydown', handleKeyDown);
184
+ window.removeEventListener('pointerdown', handlePointerDown, true);
185
+ };
186
+ }, [isInsideExtra, onOpenChange, open, triggerRef]);
187
+
188
+ useEffect(() => {
189
+ if (!open) {
190
+ return;
191
+ }
192
+ if (didFocusOnOpenRef.current) {
193
+ return;
194
+ }
195
+
196
+ const panel = internalPanelRef.current;
197
+ if (!panel) {
198
+ return;
199
+ }
200
+
201
+ const active = document.activeElement;
202
+ if (active instanceof Node && panel.contains(active)) {
203
+ didFocusOnOpenRef.current = true;
204
+ return;
205
+ }
206
+
207
+ panel.focus();
208
+ didFocusOnOpenRef.current = true;
209
+ }, [open, style]);
210
+
211
+ const portalRoot = resolvePortalContainer(triggerRef.current);
212
+
213
+ return {
214
+ style,
215
+ portalRoot,
216
+ panelProps: {
217
+ ref: setPanelNode,
218
+ tabIndex: -1,
219
+ style,
220
+ },
221
+ };
222
+ }
@@ -0,0 +1,27 @@
1
+ import { useEffect, useState, type RefObject } from 'react';
2
+ import { clampFixedOverlayPosition } from './clampFixedOverlayPosition';
3
+
4
+ export function useClampedFixedOverlayPosition(
5
+ containerRef: RefObject<HTMLElement | null>,
6
+ anchor: { x: number; y: number },
7
+ repositionKey: unknown,
8
+ ): { x: number; y: number } {
9
+ const [position, setPosition] = useState(anchor);
10
+
11
+ useEffect(() => {
12
+ setPosition(anchor);
13
+ }, [anchor.x, anchor.y]);
14
+
15
+ useEffect(() => {
16
+ const element = containerRef.current;
17
+ if (!element || typeof window === 'undefined') return;
18
+
19
+ const frame = window.requestAnimationFrame(() => {
20
+ setPosition(clampFixedOverlayPosition(anchor.x, anchor.y, element.getBoundingClientRect()));
21
+ });
22
+
23
+ return () => window.cancelAnimationFrame(frame);
24
+ }, [anchor.x, anchor.y, containerRef, repositionKey]);
25
+
26
+ return position;
27
+ }
@@ -0,0 +1,59 @@
1
+ import { useCallback, useState } from 'react';
2
+
3
+ export interface ContextMenuPointerState<T> {
4
+ readonly target: T;
5
+ readonly x: number;
6
+ readonly y: number;
7
+ }
8
+
9
+ /** Minimal pointer event shape accepted by `open` (React or DOM). */
10
+ export interface ContextMenuPointerEvent {
11
+ readonly clientX: number;
12
+ readonly clientY: number;
13
+ preventDefault(): void;
14
+ stopPropagation(): void;
15
+ }
16
+
17
+ export interface UseContextMenuStateResult<T> {
18
+ readonly close: () => void;
19
+ readonly open: (event: ContextMenuPointerEvent, target: T) => void;
20
+ readonly openAt: (position: { readonly x: number; readonly y: number }, target: T) => void;
21
+ readonly state: ContextMenuPointerState<T> | null;
22
+ }
23
+
24
+ /**
25
+ * Host-owned context-menu pointer state (target + viewport coordinates).
26
+ * Does not build menu items or change selection — callers own those policies.
27
+ */
28
+ export function useContextMenuState<T>(): UseContextMenuStateResult<T> {
29
+ const [state, setState] = useState<ContextMenuPointerState<T> | null>(null);
30
+
31
+ const close = useCallback(() => {
32
+ setState(null);
33
+ }, []);
34
+
35
+ const openAt = useCallback((position: { readonly x: number; readonly y: number }, target: T) => {
36
+ setState({
37
+ target,
38
+ x: position.x,
39
+ y: position.y,
40
+ });
41
+ }, []);
42
+
43
+ const open = useCallback((event: ContextMenuPointerEvent, target: T) => {
44
+ event.preventDefault();
45
+ event.stopPropagation();
46
+ setState({
47
+ target,
48
+ x: event.clientX,
49
+ y: event.clientY,
50
+ });
51
+ }, []);
52
+
53
+ return {
54
+ close,
55
+ open,
56
+ openAt,
57
+ state,
58
+ };
59
+ }
@@ -0,0 +1,49 @@
1
+ import { useEffect, type RefObject } from 'react';
2
+
3
+ import { isSearchableMultiSelectPortalTarget } from '../primitives/searchable-multi-select/overlay';
4
+
5
+ export interface FixedOverlayDismissOptions {
6
+ containerRef: RefObject<HTMLElement | null>;
7
+ onClose: () => void;
8
+ /** Return true when Escape was handled by nested UI (skip closing the root overlay). */
9
+ onEscape?: (() => boolean) | undefined;
10
+ /** When true, outside pointer events do not close the root overlay. */
11
+ ignoreOutsidePointer?: boolean | undefined;
12
+ }
13
+
14
+ export function useFixedOverlayDismiss({
15
+ containerRef,
16
+ onClose,
17
+ onEscape,
18
+ ignoreOutsidePointer = false,
19
+ }: FixedOverlayDismissOptions): void {
20
+ useEffect(() => {
21
+ const handleKeyDown = (event: KeyboardEvent) => {
22
+ if (event.key !== 'Escape') return;
23
+ if (onEscape?.()) return;
24
+
25
+ event.preventDefault();
26
+ onClose();
27
+ };
28
+
29
+ const handlePointerDown = (event: PointerEvent) => {
30
+ if (ignoreOutsidePointer) return;
31
+ if (containerRef.current?.contains(event.target as Node)) return;
32
+ // Portaled SMS listbox is not a DOM child of the overlay root.
33
+ if (isSearchableMultiSelectPortalTarget(event.target)) return;
34
+ onClose();
35
+ };
36
+
37
+ window.addEventListener('keydown', handleKeyDown);
38
+ window.addEventListener('pointerdown', handlePointerDown, true);
39
+ window.addEventListener('resize', onClose);
40
+ window.addEventListener('scroll', onClose, true);
41
+
42
+ return () => {
43
+ window.removeEventListener('keydown', handleKeyDown);
44
+ window.removeEventListener('pointerdown', handlePointerDown, true);
45
+ window.removeEventListener('resize', onClose);
46
+ window.removeEventListener('scroll', onClose, true);
47
+ };
48
+ }, [containerRef, ignoreOutsidePointer, onClose, onEscape]);
49
+ }
@@ -0,0 +1,87 @@
1
+ import { useEffect, useRef, type RefObject } from 'react';
2
+
3
+ import {
4
+ createPointerPassthroughController,
5
+ type PointerPassthroughPort,
6
+ } from './pointerPassthroughRegion';
7
+
8
+ export interface UsePointerPassthroughRegionOptions {
9
+ readonly enabled: boolean;
10
+ readonly port: PointerPassthroughPort;
11
+ /** Host-provided CSS selectors for interactive hit regions. */
12
+ readonly hitSelectors: readonly string[];
13
+ /** Optional extra control chrome selectors (also treated as hit). */
14
+ readonly controlSelectors?: readonly string[];
15
+ /** Limit hit-testing to a subtree; defaults to the document. */
16
+ readonly rootRef?: RefObject<HTMLElement | null>;
17
+ }
18
+
19
+ /**
20
+ * Toggles host pointer passthrough from renderer hit-testing.
21
+ * Uses `requestAnimationFrame` coalescing for pointermove; no product selectors in kit.
22
+ *
23
+ * Host responsibilities:
24
+ * - Provide selector lists
25
+ * - Implement `port.setPointerPassthrough` (usually IPC → ignore-mouse-events)
26
+ * - Pair with platform residency applicator for the main-process half
27
+ */
28
+ export function usePointerPassthroughRegion(options: UsePointerPassthroughRegionOptions): void {
29
+ const { enabled, port, hitSelectors, controlSelectors, rootRef } = options;
30
+
31
+ const portRef = useRef(port);
32
+ portRef.current = port;
33
+ const hitSelectorsRef = useRef(hitSelectors);
34
+ hitSelectorsRef.current = hitSelectors;
35
+ const controlSelectorsRef = useRef(controlSelectors);
36
+ controlSelectorsRef.current = controlSelectors;
37
+
38
+ useEffect(() => {
39
+ const controller = createPointerPassthroughController({
40
+ enabled,
41
+ port: {
42
+ setPointerPassthrough: (value) => portRef.current.setPointerPassthrough(value),
43
+ },
44
+ get hitSelectors() {
45
+ return hitSelectorsRef.current;
46
+ },
47
+ get controlSelectors() {
48
+ return controlSelectorsRef.current;
49
+ },
50
+ get root() {
51
+ return rootRef?.current ?? null;
52
+ },
53
+ });
54
+
55
+ if (!enabled) {
56
+ controller.handlePointerTarget(null);
57
+ return;
58
+ }
59
+
60
+ let frame = 0;
61
+ let pendingTarget: EventTarget | null = null;
62
+
63
+ const flush = () => {
64
+ frame = 0;
65
+ controller.handlePointerTarget(pendingTarget);
66
+ };
67
+
68
+ const onPointerMove = (event: PointerEvent) => {
69
+ pendingTarget = event.target;
70
+ if (frame !== 0) {
71
+ return;
72
+ }
73
+ frame = window.requestAnimationFrame(flush);
74
+ };
75
+
76
+ window.addEventListener('pointermove', onPointerMove, { passive: true });
77
+
78
+ return () => {
79
+ window.removeEventListener('pointermove', onPointerMove);
80
+ if (frame !== 0) {
81
+ window.cancelAnimationFrame(frame);
82
+ }
83
+ // Do not leave the host window stuck in click-through after unmount.
84
+ void portRef.current.setPointerPassthrough(false);
85
+ };
86
+ }, [enabled, rootRef]);
87
+ }
@@ -1,5 +1,5 @@
1
1
  import type { CSSProperties, ReactNode } from 'react';
2
- import { cx } from '../utils/cx';
2
+ import { cx } from '../../utils/cx';
3
3
 
4
4
  export interface WorkbenchRect {
5
5
  x: number;
@@ -9,12 +9,12 @@ export interface WorkbenchRect {
9
9
  }
10
10
 
11
11
  export interface AbsoluteBoxProps {
12
- background?: string | undefined;
12
+ background?: string;
13
13
  children?: ReactNode;
14
- className?: string | undefined;
15
- overflow?: CSSProperties['overflow'] | undefined;
14
+ className?: string;
15
+ overflow?: CSSProperties['overflow'];
16
16
  rect: WorkbenchRect;
17
- style?: CSSProperties | undefined;
17
+ style?: CSSProperties;
18
18
  }
19
19
 
20
20
  export function AbsoluteBox({
@@ -0,0 +1 @@
1
+ export * from './AbsoluteBox';
@@ -1,9 +1,11 @@
1
- import type { ComponentPropsWithRef } from 'react';
2
- import { cx } from '../utils/cx';
1
+ import './badge.css';
2
+ import type { ComponentPropsWithRef, ReactNode } from 'react';
3
+ import { cx } from '../../utils/cx';
3
4
 
4
5
  type BadgeVariant = 'accent' | 'muted' | 'danger';
5
6
 
6
7
  export interface BadgeProps extends ComponentPropsWithRef<'span'> {
8
+ children?: ReactNode;
7
9
  variant?: BadgeVariant;
8
10
  }
9
11
 
@@ -0,0 +1,20 @@
1
+ .ui-badge {
2
+ padding: 1px 6px;
3
+ border-radius: var(--radius-sm);
4
+ font-size: 10px;
5
+ font-weight: 600;
6
+ line-height: 16px;
7
+ color: #fff;
8
+ background: var(--color-accent);
9
+ }
10
+
11
+ .ui-badge[data-variant='muted'] {
12
+ color: var(--color-text-muted);
13
+ background: var(--color-surface);
14
+ border: 1px solid var(--color-border);
15
+ }
16
+
17
+ .ui-badge[data-variant='danger'] {
18
+ color: #fff;
19
+ background: var(--color-danger);
20
+ }