@workbench-kit/react 0.0.2-prototype.0.1.4 → 0.0.2-prototype.0.2.11

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 (548) 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 +292 -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 +165 -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/SideBarTree.tsx +301 -0
  125. package/src/layout/sidebar/SideBarViewFrame.tsx +235 -0
  126. package/src/layout/sidebar/SideBarViewTabStrip.tsx +60 -0
  127. package/src/layout/sidebar/SideBarViewTitleMenu.tsx +75 -0
  128. package/src/layout/sidebar/SidebarActionIconBar.tsx +242 -0
  129. package/src/layout/sidebar/SidebarSectionNestingContext.tsx +21 -0
  130. package/src/layout/sidebar/SidebarSlotChrome.tsx +32 -0
  131. package/src/layout/sidebar/SidebarToolbar.tsx +10 -0
  132. package/src/layout/sidebar/WorkbenchActionSidebar.tsx +73 -0
  133. package/src/layout/{WorkbenchSidebarActions.tsx → sidebar/WorkbenchSidebarActions.tsx} +105 -51
  134. package/src/layout/sidebar/WorkbenchSidebarSectionStack.tsx +165 -0
  135. package/src/layout/sidebar/index.css +5 -0
  136. package/src/layout/sidebar/index.ts +68 -0
  137. package/src/layout/sidebar/sidebar-chrome.css +95 -0
  138. package/src/layout/sidebar/sidebar-section-stack.css +25 -0
  139. package/src/layout/sidebar/sidebar-section.css +124 -0
  140. package/src/layout/sidebar/sidebar-view.css +290 -0
  141. package/src/layout/tree/drag-preview.css +25 -0
  142. package/src/layout/tree/index.css +10 -0
  143. package/src/layout/tree/template-glyph.css +96 -0
  144. package/src/layout/tree/tree-action.css +20 -0
  145. package/src/layout/tree/tree-drag-overlay.css +13 -0
  146. package/src/layout/tree/tree-drop-line.css +17 -0
  147. package/src/layout/tree/tree-drop-zone.css +13 -0
  148. package/src/layout/tree/tree-expander.css +23 -0
  149. package/src/layout/tree/tree-item.css +93 -0
  150. package/src/layout/tree/tree.css +49 -0
  151. package/src/layout/usePreviewViewport.ts +428 -0
  152. package/src/modal/ConfirmDialog.tsx +1 -1
  153. package/src/modal/Modal.tsx +184 -311
  154. package/src/modal/ModalResizeHandles.tsx +40 -0
  155. package/src/modal/ModalTitlebar.tsx +86 -0
  156. package/src/modal/modal.css +291 -0
  157. package/src/modal/modalContainer.ts +36 -0
  158. package/src/modal/modalPosition.ts +36 -0
  159. package/src/modal/modalSize.ts +84 -0
  160. package/src/modal/modalTypes.ts +13 -0
  161. package/src/modal/useModalContainerViewport.ts +41 -0
  162. package/src/modal/useModalDrag.ts +118 -0
  163. package/src/modal/useModalFocusTrap.ts +142 -0
  164. package/src/modal/useModalResize.ts +122 -0
  165. package/src/modal/useModalWindowFrame.ts +122 -0
  166. package/src/overlay/ContextMenu.tsx +139 -54
  167. package/src/overlay/clampFixedOverlayPosition.ts +22 -0
  168. package/src/overlay/context-menu.css +129 -0
  169. package/src/overlay/index.ts +31 -0
  170. package/src/overlay/measureAnchoredOverlayPanel.ts +107 -0
  171. package/src/overlay/overlay.css +2 -0
  172. package/src/overlay/pointerPassthroughRegion.ts +83 -0
  173. package/src/overlay/useAnchoredOverlayPanel.ts +222 -0
  174. package/src/overlay/useClampedFixedOverlayPosition.ts +27 -0
  175. package/src/overlay/useContextMenuState.ts +59 -0
  176. package/src/overlay/useFixedOverlayDismiss.ts +49 -0
  177. package/src/overlay/usePointerPassthroughRegion.ts +87 -0
  178. package/src/primitives/{AbsoluteBox.tsx → absolute-box/AbsoluteBox.tsx} +5 -5
  179. package/src/primitives/absolute-box/index.ts +1 -0
  180. package/src/primitives/{Badge.tsx → badge/Badge.tsx} +4 -2
  181. package/src/primitives/badge/badge.css +20 -0
  182. package/src/primitives/badge/index.ts +1 -0
  183. package/src/primitives/{Button.tsx → button/Button.tsx} +7 -6
  184. package/src/primitives/button/button.css +76 -0
  185. package/src/primitives/button/index.ts +1 -0
  186. package/src/primitives/catalog-browse-card/CatalogBrowseCard.tsx +121 -0
  187. package/src/primitives/catalog-browse-card/catalog-browse-card.css +175 -0
  188. package/src/primitives/catalog-browse-card/index.ts +1 -0
  189. package/src/primitives/catalog-browse-pane/CatalogBrowseFacetChips.tsx +59 -0
  190. package/src/primitives/catalog-browse-pane/CatalogBrowsePane.tsx +360 -0
  191. package/src/primitives/catalog-browse-pane/catalog-browse-facet-chips.css +8 -0
  192. package/src/primitives/catalog-browse-pane/catalog-browse-pane.css +84 -0
  193. package/src/primitives/catalog-browse-pane/filterCatalogBrowseItems.ts +27 -0
  194. package/src/primitives/catalog-browse-pane/index.ts +3 -0
  195. package/src/primitives/catalog-filter-overlay/CatalogFilterOverlay.tsx +73 -0
  196. package/src/primitives/catalog-filter-overlay/catalog-filter-overlay.css +65 -0
  197. package/src/primitives/catalog-filter-overlay/index.ts +1 -0
  198. package/src/primitives/checkbox/Checkbox.tsx +40 -0
  199. package/src/primitives/checkbox/checkbox.css +81 -0
  200. package/src/primitives/checkbox/index.ts +1 -0
  201. package/src/primitives/chip/Chip.tsx +43 -0
  202. package/src/primitives/chip/chip.css +110 -0
  203. package/src/primitives/chip/index.ts +2 -0
  204. package/src/primitives/clearable-text-input/ClearableTextInput.tsx +78 -0
  205. package/src/primitives/clearable-text-input/clearable-text-input.css +15 -0
  206. package/src/primitives/clearable-text-input/index.ts +1 -0
  207. package/src/primitives/codicon/Codicon.tsx +20 -0
  208. package/src/primitives/codicon/index.ts +1 -0
  209. package/src/primitives/{EmptyState.tsx → empty-state/EmptyState.tsx} +9 -3
  210. package/src/primitives/empty-state/empty-state.css +20 -0
  211. package/src/primitives/empty-state/index.ts +1 -0
  212. package/src/primitives/external-link-button/ExternalLinkButton.tsx +56 -0
  213. package/src/primitives/external-link-button/index.ts +1 -0
  214. package/src/primitives/{Field.tsx → field/Field.tsx} +2 -1
  215. package/src/primitives/field/field.css +51 -0
  216. package/src/primitives/field/index.ts +1 -0
  217. package/src/primitives/file-icon/FileIcon.tsx +21 -0
  218. package/src/primitives/file-icon/index.ts +1 -0
  219. package/src/primitives/{IconButton.tsx → icon-button/IconButton.tsx} +7 -5
  220. package/src/primitives/icon-button/icon-button.css +46 -0
  221. package/src/primitives/icon-button/index.ts +1 -0
  222. package/src/primitives/index.ts +215 -50
  223. package/src/primitives/library-detail-layout/LibraryDetailLayout.tsx +249 -0
  224. package/src/primitives/library-detail-layout/index.ts +6 -0
  225. package/src/primitives/library-detail-layout/library-detail-layout.css +226 -0
  226. package/src/primitives/library-detail-layout/resolve-hero-cover-media.ts +80 -0
  227. package/src/primitives/library-facet-filter-panel/LibraryFacetFilterPanel.tsx +454 -0
  228. package/src/primitives/library-facet-filter-panel/index.ts +1 -0
  229. package/src/primitives/library-facet-filter-panel/library-facet-filter-panel.css +205 -0
  230. package/src/primitives/library-facet-filter-strip/LibraryFacetFilterStrip.tsx +527 -0
  231. package/src/primitives/library-facet-filter-strip/index.ts +1 -0
  232. package/src/primitives/library-facet-filter-strip/library-facet-filter-strip.css +31 -0
  233. package/src/primitives/{List.tsx → list/List.tsx} +15 -6
  234. package/src/primitives/list/index.ts +1 -0
  235. package/src/primitives/list/list-empty-state.css +10 -0
  236. package/src/primitives/list/list-item.css +93 -0
  237. package/src/primitives/list/list.css +6 -0
  238. package/src/primitives/number-input/NumberInput.tsx +235 -0
  239. package/src/primitives/number-input/index.ts +1 -0
  240. package/src/primitives/number-input/number-input.css +105 -0
  241. package/src/primitives/panel-loading/PanelLoading.tsx +29 -0
  242. package/src/primitives/panel-loading/index.ts +1 -0
  243. package/src/primitives/panel-loading/panel-loading.css +16 -0
  244. package/src/primitives/panel-surface/panel-surface.css +77 -0
  245. package/src/primitives/primitives.css +36 -0
  246. package/src/primitives/record-media-hero/RecordMediaHero.tsx +85 -0
  247. package/src/primitives/record-media-hero/index.ts +1 -0
  248. package/src/primitives/record-media-hero/record-media-hero.css +84 -0
  249. package/src/primitives/scroll-area/ScrollArea.tsx +200 -0
  250. package/src/primitives/scroll-area/index.ts +1 -0
  251. package/src/primitives/scroll-area/scroll-area-overlay.css +69 -0
  252. package/src/primitives/scroll-area-infinite-load/ScrollAreaInfiniteSentinel.tsx +22 -0
  253. package/src/primitives/scroll-area-infinite-load/index.ts +2 -0
  254. package/src/primitives/scroll-area-infinite-load/scroll-area-infinite-sentinel.css +6 -0
  255. package/src/primitives/scroll-area-infinite-load/useScrollAreaInfiniteLoad.ts +84 -0
  256. package/src/primitives/searchable-multi-select/SearchableMultiSelect.tsx +378 -0
  257. package/src/primitives/searchable-multi-select/index.ts +9 -0
  258. package/src/primitives/searchable-multi-select/overlay.ts +125 -0
  259. package/src/primitives/searchable-multi-select/searchable-multi-select.css +129 -0
  260. package/src/primitives/select/Select.tsx +21 -3
  261. package/src/primitives/select/overlay.ts +23 -4
  262. package/src/primitives/select/select.app.css +5 -2
  263. package/src/primitives/select/select.css +49 -12
  264. package/src/primitives/styles.css +3 -952
  265. package/src/primitives/tabbed-panels/TabbedPanels.tsx +68 -0
  266. package/src/primitives/tabbed-panels/index.ts +2 -0
  267. package/src/primitives/tabbed-panels/tabbed-panels.css +58 -0
  268. package/src/primitives/{TextArea.tsx → text-area/TextArea.tsx} +3 -2
  269. package/src/primitives/text-area/index.ts +1 -0
  270. package/src/primitives/{TextInput.tsx → text-input/TextInput.tsx} +3 -2
  271. package/src/primitives/text-input/index.ts +1 -0
  272. package/src/primitives/text-input/input.css +54 -0
  273. package/src/primitives/{Toolbar.tsx → toolbar/Toolbar.tsx} +1 -1
  274. package/src/primitives/toolbar/index.ts +1 -0
  275. package/src/primitives/visually-hidden/visually-hidden.css +11 -0
  276. package/src/primitives/{WorkbenchEditor.tsx → workbench-editor/WorkbenchEditor.tsx} +81 -43
  277. package/src/primitives/workbench-editor/button-group.css +10 -0
  278. package/src/primitives/workbench-editor/editor-tabs.css +201 -0
  279. package/src/primitives/workbench-editor/index.ts +1 -0
  280. package/src/primitives/workbench-editor/resizable-panels.css +53 -0
  281. package/src/primitives/workbench-editor/segmented-control.css +98 -0
  282. package/src/primitives/workbench-media-slot/WorkbenchMediaPlaceholder.tsx +25 -0
  283. package/src/primitives/workbench-media-slot/WorkbenchMediaSlot.tsx +66 -0
  284. package/src/primitives/workbench-media-slot/index.ts +2 -0
  285. package/src/primitives/workbench-media-slot/media-slot.css +72 -0
  286. package/src/primitives/workbench-thumbnail/WorkbenchThumbnail.tsx +38 -0
  287. package/src/primitives/workbench-thumbnail/index.ts +1 -0
  288. package/src/primitives/workbench-thumbnail/thumbnail.css +69 -0
  289. package/src/scrollbars.css +77 -2
  290. package/src/styles.css +13 -7735
  291. package/src/test-utils/workbenchMonacoMock.tsx +37 -0
  292. package/src/utils/dragMime.ts +89 -0
  293. package/src/utils/useWorkbenchMediaImage.ts +37 -0
  294. package/src/widget-asset/WidgetAssetEditor.tsx +9 -7
  295. package/src/widget-asset/WidgetAssetModeControls.tsx +1 -1
  296. package/src/widget-asset/WidgetAssetWorkbench.tsx +5 -6
  297. package/src/widget-studio/create-widget-studio-workspace-editor.tsx +1 -2
  298. package/src/widget-studio/index.ts +4 -1
  299. package/src/widget-studio/resolve-widget-studio-asset-catalog.ts +27 -10
  300. package/src/widget-tree/WidgetAssetPalette.tsx +35 -7
  301. package/src/widget-tree/WidgetInspectorPanel.tsx +53 -3
  302. package/src/widget-tree/WidgetSourceEditor.tsx +90 -3
  303. package/src/widget-tree/WidgetTreeCanvasPreview.tsx +875 -0
  304. package/src/widget-tree/WidgetTreeLab.tsx +411 -83
  305. package/src/widget-tree/WidgetTreeModeControls.tsx +30 -1
  306. package/src/widget-tree/WidgetTreeSidePanel.tsx +24 -34
  307. package/src/widget-tree/WidgetTreeView.tsx +711 -11
  308. package/src/widget-tree/WidgetTreeWorkbench.tsx +59 -15
  309. package/src/widget-tree/WidgetTreeWorkspaceShell.tsx +28 -10
  310. package/src/widget-tree/index.ts +22 -4
  311. package/src/widget-tree/widget-placement-asset-dnd.ts +35 -0
  312. package/src/widget-tree/widget-tree-document.ts +3 -9
  313. package/src/widget-tree/widget-tree-editor-state.ts +40 -0
  314. package/src/widget-tree/widget-tree-layout.ts +48 -3
  315. package/src/widget-tree/widget-tree-play-helpers.ts +69 -58
  316. package/src/workbench/auth/WorkbenchLoginView.tsx +4 -6
  317. package/src/workbench/auth/auth-flows.css +440 -0
  318. package/src/workbench/auth/auth.css +3 -0
  319. package/src/workbench/auth/profile-modals.css +115 -0
  320. package/src/workbench/bootstrap/WorkbenchBootstrapGate.tsx +45 -0
  321. package/src/workbench/bootstrap/WorkbenchBootstrapView.tsx +100 -0
  322. package/src/workbench/bootstrap/index.ts +12 -0
  323. package/src/workbench/bootstrap/useWorkbenchBootstrap.ts +130 -0
  324. package/src/workbench/chat/ChatCommandProposalCard.tsx +115 -0
  325. package/src/workbench/chat/ChatComposer.tsx +32 -34
  326. package/src/workbench/chat/ChatConversationBar.tsx +134 -0
  327. package/src/workbench/chat/ChatHistoryMenu.tsx +171 -0
  328. package/src/workbench/chat/ChatHistoryMenuRow.tsx +74 -0
  329. package/src/workbench/chat/ChatMessageCollapsible.tsx +119 -0
  330. package/src/workbench/chat/ChatMessageItem.tsx +351 -19
  331. package/src/workbench/chat/ChatMessageList.tsx +109 -24
  332. package/src/workbench/chat/ChatPanel.tsx +141 -19
  333. package/src/workbench/chat/ChatPhasedRunProgress.tsx +275 -0
  334. package/src/workbench/chat/ChatRenameDialog.tsx +77 -0
  335. package/src/workbench/chat/chat-conversation.css +273 -0
  336. package/src/workbench/chat/chat-ui.css +1132 -0
  337. package/src/workbench/chat/chat.css +3 -0
  338. package/src/workbench/chat/chatConversation.ts +46 -0
  339. package/src/workbench/chat/chatHistoryRowMenuItems.ts +29 -0
  340. package/src/workbench/chat/chatMessageMeta.tsx +252 -0
  341. package/src/workbench/chat/chatScroll.ts +22 -0
  342. package/src/workbench/chat/index.ts +48 -1
  343. package/src/workbench/chat/slashCommand.ts +5 -7
  344. package/src/workbench/chat/types.ts +35 -0
  345. package/src/workbench/chat/useCancelRuntimeOnUnmount.ts +60 -0
  346. package/src/workbench/chat/useChatPrependPagination.ts +233 -0
  347. package/src/workbench/chat/useChatRuntimeState.ts +3 -15
  348. package/src/workbench/chat/useSlashCommandSuggest.ts +77 -24
  349. package/src/workbench/chrome/WorkbenchModalPortal.tsx +52 -0
  350. package/src/workbench/chrome/WorkbenchPlatformContext.tsx +31 -0
  351. package/src/workbench/chrome/index.css +6 -0
  352. package/src/workbench/chrome/workbench-chrome.css +4 -0
  353. package/src/workbench/chrome/workbench-desktop-titlebar.css +60 -0
  354. package/src/workbench/chrome/workbench-host.css +85 -0
  355. package/src/workbench/chrome/workbench-layout-regions.css +42 -0
  356. package/src/workbench/chrome/workbench-platform-chrome.css +142 -0
  357. package/src/workbench/chrome/workbench-shell-titlebar.css +124 -0
  358. package/src/workbench/chrome/workbenchModalViewState.ts +52 -0
  359. package/src/workbench/chrome/workbenchOverlaysContext.tsx +21 -0
  360. package/src/workbench/chrome/workbenchPlatformChrome.ts +40 -0
  361. package/src/workbench/command-palette/command-palette.css +156 -0
  362. package/src/workbench/commands/CommandGroupShell.tsx +131 -0
  363. package/src/workbench/commands/CommandList.tsx +167 -0
  364. package/src/workbench/commands/CommandPalette.tsx +391 -0
  365. package/src/workbench/{ConfirmationFlow.tsx → commands/ConfirmationFlow.tsx} +6 -8
  366. package/src/workbench/{ShortcutCommandBridge.tsx → commands/ShortcutCommandBridge.tsx} +1 -4
  367. package/src/workbench/commands/command-execution-policy.ts +61 -0
  368. package/src/workbench/commands/command-model.ts +279 -0
  369. package/src/workbench/{commands.ts → commands/commands.ts} +63 -7
  370. package/src/workbench/commands/workbenchContextMenu.ts +18 -0
  371. package/src/workbench/editor/WorkbenchEditorTabs.tsx +52 -0
  372. package/src/workbench/editor/editor-tabs-dnd.ts +162 -0
  373. package/src/workbench/editor/editorTabContextMenu.ts +111 -0
  374. package/src/workbench/editor/useEditorTabsStripDnd.ts +262 -0
  375. package/src/workbench/editor/useWorkbenchEditorTabContextMenu.tsx +66 -0
  376. package/src/workbench/editor-tabs/index.ts +22 -0
  377. package/src/workbench/index.ts +288 -37
  378. package/src/workbench/management/AccountManagementPanel.tsx +82 -0
  379. package/src/workbench/management/CommandInspectorPanel.tsx +127 -0
  380. package/src/workbench/management/CommandManagementPanel.tsx +129 -0
  381. package/src/workbench/management/CommandManagementSidebar.tsx +318 -0
  382. package/src/workbench/management/ExtensionManagementPanel.tsx +527 -0
  383. package/src/workbench/management/ExtensionManagementSidebar.tsx +509 -0
  384. package/src/workbench/management/IntegrationCommandActions.tsx +78 -0
  385. package/src/workbench/management/IntegrationSettingsSurface.tsx +290 -0
  386. package/src/workbench/management/IntegrationsShell.tsx +53 -0
  387. package/src/workbench/management/KeybindingCaptureField.tsx +142 -0
  388. package/src/workbench/management/KeybindingManagementPanel.tsx +120 -0
  389. package/src/workbench/management/LibraryCatalogPickerDialog.tsx +208 -0
  390. package/src/workbench/management/LibraryFacetFilterDialog.tsx +62 -0
  391. package/src/workbench/management/ManagementCard.tsx +89 -0
  392. package/src/workbench/management/ManagementFilterChips.tsx +41 -0
  393. package/src/workbench/management/ManagementGroup.tsx +56 -0
  394. package/src/workbench/management/ManagementPanelControls.tsx +43 -0
  395. package/src/workbench/management/ManagementPanelFrame.tsx +109 -0
  396. package/src/workbench/management/WorkbenchDialogFrame.tsx +148 -0
  397. package/src/workbench/management/WorkbenchNotice.tsx +211 -0
  398. package/src/workbench/management/build-command-management-groups.ts +157 -0
  399. package/src/workbench/management/command-inspector-uri.ts +26 -0
  400. package/src/workbench/management/createWorkbenchNotify.tsx +88 -0
  401. package/src/workbench/management/extension-category-display.ts +42 -0
  402. package/src/workbench/management/extension-install-approval.ts +72 -0
  403. package/src/workbench/management/format-command-run-state.ts +19 -0
  404. package/src/workbench/management/index.ts +144 -0
  405. package/src/workbench/management/integration-command-action.ts +25 -0
  406. package/src/workbench/management/library-catalog-picker-dialog.css +56 -0
  407. package/src/workbench/management/library-facet-filter-dialog.css +8 -0
  408. package/src/workbench/management/management-panel.css +444 -0
  409. package/src/workbench/management/management.css +32 -0
  410. package/src/workbench/management/types.ts +139 -0
  411. package/src/workbench/management/useWorkbenchNotify.ts +10 -0
  412. package/src/workbench/{MarkdownPreview.tsx → markdown/MarkdownPreview.tsx} +26 -15
  413. package/src/workbench/markdown/markdownRemarkPlugins.ts +12 -0
  414. package/src/workbench/markdown/sanitizeMarkdownHref.ts +29 -0
  415. package/src/workbench/schema/index.ts +0 -1
  416. package/src/workbench/settings/NavigationPanel.tsx +41 -2
  417. package/src/workbench/settings/SchemaForm.tsx +20 -7
  418. package/src/workbench/settings/SectionTabPanel.tsx +172 -0
  419. package/src/workbench/settings/SectionedPanel.tsx +40 -286
  420. package/src/workbench/settings/StructuredDataForm.tsx +106 -26
  421. package/src/workbench/settings/StructuredDataSchemaPanel.tsx +345 -93
  422. package/src/workbench/settings/StructuredDataTableView.tsx +2 -2
  423. package/src/workbench/settings/WorkbenchPanelRegion.tsx +1 -1
  424. package/src/workbench/settings/WorkbenchSettingsModal.tsx +116 -62
  425. package/src/workbench/settings/WorkbenchSettingsNav.tsx +3 -3
  426. package/src/workbench/settings/extensionSettingsForm.ts +34 -0
  427. package/src/workbench/settings/index.ts +36 -1
  428. package/src/workbench/settings/navigation-panel.css +59 -0
  429. package/src/workbench/settings/panel-region.css +3 -2
  430. package/src/workbench/settings/schema-form.css +36 -0
  431. package/src/workbench/settings/schemaFormSettingSpec.ts +177 -0
  432. package/src/workbench/settings/schemaFormSettingsCategory.tsx +21 -0
  433. package/src/workbench/settings/section-tab-panel.css +157 -0
  434. package/src/workbench/settings/sectionScrollSpyDom.ts +139 -0
  435. package/src/workbench/settings/sectioned-panel.css +162 -0
  436. package/src/workbench/settings/sectionedPanelScrollSpy.ts +158 -28
  437. package/src/workbench/settings/settings-responsive.css +58 -0
  438. package/src/workbench/settings/settings.css +11 -0
  439. package/src/workbench/settings/settingsCommit.tsx +55 -0
  440. package/src/workbench/settings/structured-data-form.css +114 -0
  441. package/src/workbench/settings/structured-data-schema-panel.css +33 -19
  442. package/src/workbench/settings/structuredDataFormModel.ts +140 -0
  443. package/src/workbench/settings/structuredDataSchema.ts +111 -658
  444. package/src/workbench/settings/structuredDataSchemaDate.ts +197 -0
  445. package/src/workbench/settings/structuredDataSchemaField.ts +105 -0
  446. package/src/workbench/settings/structuredDataSchemaSection.ts +74 -0
  447. package/src/workbench/settings/structuredDataSchemaTable.ts +120 -0
  448. package/src/workbench/settings/structuredDataSchemaTypes.ts +308 -0
  449. package/src/workbench/settings/structuredDataSchemaValidation.ts +166 -0
  450. package/src/workbench/settings/useSectionScrollSpy.ts +420 -0
  451. package/src/workbench/settings/workbench-settings-modal.css +273 -0
  452. package/src/workbench/shell/ActivityBar.tsx +159 -0
  453. package/src/workbench/{ArtifactShell.tsx → shell/ArtifactShell.tsx} +30 -30
  454. package/src/workbench/shell/SplitView.tsx +485 -0
  455. package/src/workbench/{StatusBar.tsx → shell/StatusBar.tsx} +10 -8
  456. package/src/workbench/{StructuredArtifactEditor.tsx → shell/StructuredArtifactEditor.tsx} +9 -9
  457. package/src/workbench/{Timeline.tsx → shell/Timeline.tsx} +19 -24
  458. package/src/workbench/shell/WorkbenchCanvasShell.defaults.ts +106 -0
  459. package/src/workbench/shell/WorkbenchCanvasShell.model.ts +46 -0
  460. package/src/workbench/{WorkbenchCanvasShell.tsx → shell/WorkbenchCanvasShell.tsx} +34 -148
  461. package/src/workbench/shell/WorkbenchDesktopTitleBar.tsx +126 -0
  462. package/src/workbench/shell/WorkbenchShell.tsx +192 -0
  463. package/src/workbench/shell/WorkbenchShellTitleBarLayoutControls.tsx +80 -0
  464. package/src/workbench/shell/WorkbenchStandaloneShell.tsx +604 -0
  465. package/src/workbench/shell/WorkbenchViewEditor.tsx +75 -0
  466. package/src/workbench/shell/WorkbenchViewSidebar.tsx +85 -0
  467. package/src/workbench/shell/WorkbenchWindowChromeControls.tsx +293 -0
  468. package/src/workbench/shell/activity-bar.css +245 -0
  469. package/src/workbench/shell/activityBarOrder.ts +98 -0
  470. package/src/workbench/shell/appearanceLabels.ts +28 -0
  471. package/src/workbench/shell/confirmation-flow.css +87 -0
  472. package/src/workbench/shell/hardReset.ts +64 -0
  473. package/src/workbench/shell/index.css +5 -0
  474. package/src/workbench/shell/shell.ts +152 -0
  475. package/src/workbench/shell/shellPresets.ts +36 -0
  476. package/src/workbench/{shellState.ts → shell/shellState.ts} +16 -23
  477. package/src/workbench/shell/shellViewModel.ts +160 -0
  478. package/src/workbench/shell/sidebarViewPlacementDnd.ts +61 -0
  479. package/src/workbench/shell/split-view.css +188 -0
  480. package/src/workbench/{standalone.ts → shell/standalone.ts} +11 -11
  481. package/src/workbench/shell/status-bar.css +141 -0
  482. package/src/workbench/{status.ts → shell/status.ts} +10 -6
  483. package/src/workbench/shell/useDeferredWorkbenchMount.ts +71 -0
  484. package/src/workbench/shell/useWorkbenchAppearanceDocumentSync.tsx +17 -0
  485. package/src/workbench/shell/useWorkbenchSidebarActionBarDnd.ts +227 -0
  486. package/src/workbench/shell/useWorkbenchSidebarLayout.tsx +232 -0
  487. package/src/workbench/shell/useWorkbenchSidebarViewPlacementDropZone.ts +194 -0
  488. package/src/workbench/shell/useWorkbenchStandaloneShellStateSync.tsx +112 -0
  489. package/src/workbench/shell/workbenchSidebarLayoutContext.ts +46 -0
  490. package/src/workbench/shell/workbenchStandaloneShellReactContext.tsx +80 -0
  491. package/src/workbench/shell/workbenchViewRouteState.ts +151 -0
  492. package/src/workbench/theme/WorkbenchThemeProvider.tsx +142 -0
  493. package/src/workbench/{theme.ts → theme/theme.ts} +9 -3
  494. package/src/workbench/theme/themePresets.ts +192 -0
  495. package/src/workbench/views/action-list.css +144 -0
  496. package/src/workbench/views/artifact-preview.css +184 -0
  497. package/src/workbench/views/command-inspector.css +98 -0
  498. package/src/workbench/views/command-list.css +356 -0
  499. package/src/workbench/views/commands-sidebar.css +51 -0
  500. package/src/workbench/views/extensions-sidebar.css +175 -0
  501. package/src/workbench/views/multi-provider-explorer.css +182 -0
  502. package/src/workbench/views/search.css +10 -0
  503. package/src/workbench/views/timeline.css +239 -0
  504. package/src/workbench/views/view-hosts.css +37 -0
  505. package/src/workbench/views/view-sidebar.css +21 -0
  506. package/src/workbench/views/views.css +12 -0
  507. package/src/workbench/widgets/widget-tree.css +598 -0
  508. package/src/workbench/widgets/widgets.css +2 -0
  509. package/src/workbench/workspace/WorkspaceDraftsContext.tsx +59 -71
  510. package/src/workbench/workspace/WorkspaceEditor.tsx +27 -123
  511. package/src/workbench/workspace/WorkspaceEditorPanel.tsx +68 -9
  512. package/src/workbench/workspace/WorkspaceExplorer.tsx +252 -53
  513. package/src/workbench/workspace/WorkspaceExplorerPanel.tsx +73 -0
  514. package/src/workbench/workspace/WorkspaceFileIcon.tsx +4 -160
  515. package/src/workbench/workspace/WorkspacePathLabel.tsx +42 -0
  516. package/src/workbench/workspace/WorkspaceSearchPanel.tsx +18 -15
  517. package/src/workbench/workspace/WorkspaceSearchResults.tsx +6 -2
  518. package/src/workbench/workspace/build-workspace-explorer-nodes.ts +44 -0
  519. package/src/workbench/workspace/createVirtualWorkspaceExplorerPort.ts +141 -0
  520. package/src/workbench/workspace/explorer-tree-style.ts +18 -0
  521. package/src/workbench/workspace/index.ts +45 -32
  522. package/src/workbench/workspace/json-config-workbench.css +57 -0
  523. package/src/workbench/workspace/monaco-panel.css +71 -0
  524. package/src/workbench/workspace/path.ts +2 -0
  525. package/src/workbench/workspace/useWorkspaceExplorerController.ts +490 -0
  526. package/src/workbench/workspace/workspace-editor.css +235 -0
  527. package/src/workbench/workspace/workspace-explorer-panel.css +33 -0
  528. package/src/workbench/workspace/workspace.css +5 -0
  529. package/src/workbench/workspace/workspaceExplorerController.ts +193 -0
  530. package/src/workbench/workspace/workspaceExplorerKeyboard.ts +109 -0
  531. package/src/workbench/workspace/workspaceJsonDiagnostics.ts +8 -7
  532. package/src/workbench-menu-surfaces.css +57 -0
  533. package/src/jdw/builtins/renderBuiltinWidgetNode.tsx +0 -126
  534. package/src/layout/SideBarViewFrame.tsx +0 -367
  535. package/src/primitives/Checkbox.tsx +0 -21
  536. package/src/primitives/NumberInput.tsx +0 -38
  537. package/src/primitives/ScrollArea.tsx +0 -42
  538. package/src/primitives/Select.tsx +0 -1
  539. package/src/primitives/StatusBar.tsx +0 -46
  540. package/src/primitives/WorkbenchChrome.tsx +0 -424
  541. package/src/workbench/ActivityBar.tsx +0 -52
  542. package/src/workbench/CommandPalette.tsx +0 -819
  543. package/src/workbench/SplitView.tsx +0 -136
  544. package/src/workbench/WorkbenchShell.tsx +0 -74
  545. package/src/workbench/WorkbenchStandaloneShell.tsx +0 -318
  546. package/src/workbench/shell.ts +0 -15
  547. package/src/workbench/workspace/MultiProviderExplorer.tsx +0 -625
  548. /package/src/workbench/{keyboard.ts → commands/keyboard.ts} +0 -0
@@ -10,6 +10,7 @@ import {
10
10
  type ReactNode,
11
11
  } from 'react';
12
12
  import {
13
+ createEmptyWorkspaceSelection,
13
14
  getWorkspaceSelectionActionPaths,
14
15
  normalizeWorkspaceSelectionPaths,
15
16
  parentPathOf,
@@ -17,20 +18,29 @@ import {
17
18
  type WorkspaceSelectionMode,
18
19
  type WorkspaceSelectionState,
19
20
  } from '@workbench-kit/workspace';
20
- import { SideBarList, SideBarListItem, sideBarTreeDepthStyle } from '../../layout/SideBarViewFrame';
21
+ import { SideBarList, SideBarListItem, useSidebarSectionBaseDepth } from '../../layout/sidebar';
22
+ import { TextInput } from '../../primitives/text-input';
21
23
  import { cxCodicon } from '../../utils/codicon';
24
+ import { explorerTreeDepthStyle } from './explorer-tree-style';
22
25
  import { flattenWorkspaceTree } from './tree';
26
+ import {
27
+ resolveWorkspaceExplorerHorizontalNavigationAction,
28
+ resolveWorkspaceExplorerNavigationPath,
29
+ } from './workspaceExplorerKeyboard.js';
23
30
  import { WorkspaceFileIcon } from './WorkspaceFileIcon';
24
31
  import type { WorkspaceTreeNode } from './types';
25
32
 
26
33
  export const WORKSPACE_EXPLORER_DRAG_DATA_TYPE = 'application/x-newchobo-ui-workspace-paths';
27
34
  export const WORKSPACE_EXPLORER_DRAG_METADATA_DATA_TYPE = `${WORKSPACE_EXPLORER_DRAG_DATA_TYPE}.metadata`;
28
35
 
36
+ export type WorkspaceExplorerSelectionChangeReason =
37
+ 'clear' | 'click' | 'context-menu' | 'drag-start' | 'folder-click' | 'keyboard';
38
+
29
39
  export interface WorkspaceExplorerSelectionChangeMeta {
30
- event: DragEvent<HTMLButtonElement> | MouseEvent<HTMLButtonElement>;
31
- mode: WorkspaceSelectionMode;
32
- node: WorkspaceTreeNode;
33
- reason: 'click' | 'context-menu' | 'drag-start';
40
+ event?: DragEvent<HTMLButtonElement> | MouseEvent<HTMLButtonElement>;
41
+ mode?: WorkspaceSelectionMode;
42
+ node?: WorkspaceTreeNode;
43
+ reason: WorkspaceExplorerSelectionChangeReason;
34
44
  }
35
45
 
36
46
  export interface WorkspaceExplorerItemActionMeta {
@@ -67,10 +77,7 @@ export interface WorkspaceExplorerMoveRequestMeta {
67
77
  }
68
78
 
69
79
  export type WorkspaceExplorerInlineEditKind =
70
- | 'create-file'
71
- | 'create-folder'
72
- | 'rename-file'
73
- | 'rename-folder';
80
+ 'create-file' | 'create-folder' | 'rename-file' | 'rename-folder';
74
81
 
75
82
  export interface WorkspaceExplorerInlineEditState {
76
83
  error?: ReactNode;
@@ -88,6 +95,8 @@ export interface WorkspaceExplorerInlineEditCommitMeta {
88
95
 
89
96
  export interface WorkspaceExplorerProps {
90
97
  activePath?: string;
98
+ /** Accessible name for the `role="tree"` list. Defaults to "Workspace files". */
99
+ ariaLabel?: string;
91
100
  dragDataType?: string;
92
101
  dragMetadataDataType?: string;
93
102
  dragMetadataFactory?: WorkspaceExplorerDragMetadataFactory;
@@ -99,6 +108,7 @@ export interface WorkspaceExplorerProps {
99
108
  onInlineEditCancel?: (edit: WorkspaceExplorerInlineEditState) => void;
100
109
  onInlineEditCommit?: (meta: WorkspaceExplorerInlineEditCommitMeta) => void;
101
110
  onInlineEditValueChange?: (value: string, edit: WorkspaceExplorerInlineEditState) => void;
111
+ onBackgroundContextMenu?: (event: MouseEvent<HTMLUListElement>) => void;
102
112
  onItemContextMenu?: (
103
113
  event: MouseEvent<HTMLButtonElement>,
104
114
  node: WorkspaceTreeNode,
@@ -112,20 +122,30 @@ export interface WorkspaceExplorerProps {
112
122
  meta: WorkspaceExplorerSelectionChangeMeta,
113
123
  ) => void;
114
124
  onToggleFolder: (path: string) => void;
125
+ focusedPath?: string | undefined;
126
+ renderItemActions?: (node: WorkspaceTreeNode, meta: WorkspaceExplorerItemActionMeta) => ReactNode;
115
127
  selectedPaths?: Iterable<string>;
116
128
  selectionAnchorPath?: string;
129
+ /**
130
+ * When true (default), Arrow/Home/End focus updates also emit selection
131
+ * (file → single `paths`; folder → `{ focusedPath, paths: [] }`).
132
+ */
133
+ selectionFollowsFocus?: boolean;
117
134
  }
118
135
 
119
136
  export function WorkspaceExplorer({
120
137
  activePath,
138
+ ariaLabel = 'Workspace files',
121
139
  dragDataType = WORKSPACE_EXPLORER_DRAG_DATA_TYPE,
122
140
  dragMetadataDataType = WORKSPACE_EXPLORER_DRAG_METADATA_DATA_TYPE,
123
141
  dragMetadataFactory,
124
142
  expandedPaths,
125
143
  filterQuery = '',
144
+ focusedPath,
126
145
  inlineEdit,
127
146
  nodes,
128
147
  onActivateFile,
148
+ onBackgroundContextMenu,
129
149
  onInlineEditCancel,
130
150
  onInlineEditCommit,
131
151
  onInlineEditValueChange,
@@ -135,11 +155,15 @@ export function WorkspaceExplorer({
135
155
  onRequestRename,
136
156
  onSelectionChange,
137
157
  onToggleFolder,
158
+ renderItemActions,
138
159
  selectedPaths = [],
139
160
  selectionAnchorPath,
161
+ selectionFollowsFocus = true,
140
162
  }: WorkspaceExplorerProps) {
163
+ const sectionBaseDepth = useSidebarSectionBaseDepth();
141
164
  const draggedPathsRef = useRef<string[]>([]);
142
165
  const inlineEditInputRef = useRef<HTMLInputElement>(null);
166
+ const inlineEditCommitStartedRef = useRef(false);
143
167
  const [dropTargetPath, setDropTargetPath] = useState<string | null>(null);
144
168
  const visibleNodes = useMemo(
145
169
  () => flattenWorkspaceTree({ expandedPaths, filterQuery, nodes }),
@@ -170,6 +194,7 @@ export function WorkspaceExplorer({
170
194
  : undefined;
171
195
 
172
196
  useEffect(() => {
197
+ inlineEditCommitStartedRef.current = false;
173
198
  const input = inlineEditInputRef.current;
174
199
  if (!input) return;
175
200
 
@@ -177,19 +202,29 @@ export function WorkspaceExplorer({
177
202
  input.select();
178
203
  }, [inlineEditKey]);
179
204
 
205
+ useEffect(() => {
206
+ // Validation failures keep the same draft id; allow Enter/blur retry after an error.
207
+ if (inlineEdit?.error) {
208
+ inlineEditCommitStartedRef.current = false;
209
+ }
210
+ }, [inlineEdit?.error]);
211
+
180
212
  const selectFile = (event: MouseEvent<HTMLButtonElement>, node: WorkspaceTreeNode) => {
181
213
  const mode = resolveSelectionMode(event);
214
+ const nextSelection = onSelectionChange
215
+ ? {
216
+ ...updateWorkspaceSelection({
217
+ mode,
218
+ orderedPaths: visibleFilePaths,
219
+ selection: currentSelection,
220
+ targetPath: node.path,
221
+ }),
222
+ focusedPath: node.path,
223
+ }
224
+ : currentSelection;
182
225
 
183
226
  if (onSelectionChange) {
184
- onSelectionChange(
185
- updateWorkspaceSelection({
186
- mode,
187
- orderedPaths: visibleFilePaths,
188
- selection: currentSelection,
189
- targetPath: node.path,
190
- }),
191
- { event, mode, node, reason: 'click' },
192
- );
227
+ onSelectionChange(nextSelection, { event, mode, node, reason: 'click' });
193
228
  }
194
229
 
195
230
  if (mode === 'single' || !onSelectionChange) {
@@ -197,15 +232,48 @@ export function WorkspaceExplorer({
197
232
  }
198
233
  };
199
234
 
235
+ const selectFolder = (event: MouseEvent<HTMLButtonElement>, node: WorkspaceTreeNode) => {
236
+ onSelectionChange?.(
237
+ {
238
+ anchorPath: undefined,
239
+ focusedPath: node.path,
240
+ paths: [],
241
+ },
242
+ { event, mode: 'single', node, reason: 'folder-click' },
243
+ );
244
+ onToggleFolder(node.path);
245
+ };
246
+
247
+ const clearSelection = () => {
248
+ onSelectionChange?.(createEmptyWorkspaceSelection(), { reason: 'clear' });
249
+ };
250
+
200
251
  const getItemActionMeta = (node: WorkspaceTreeNode): WorkspaceExplorerItemActionMeta => {
201
- const selected = node.type === 'file' && selectedPathSet.has(node.path);
202
- const selection =
203
- node.type === 'file' && !selected
204
- ? {
205
- anchorPath: node.path,
206
- paths: [node.path],
207
- }
208
- : currentSelection;
252
+ if (node.type === 'folder') {
253
+ const selection = {
254
+ anchorPath: undefined,
255
+ focusedPath: node.path,
256
+ paths: [] as string[],
257
+ };
258
+
259
+ return {
260
+ actionPaths: [node.path],
261
+ selected: focusedPath === node.path,
262
+ selection,
263
+ };
264
+ }
265
+
266
+ const selected = selectedPathSet.has(node.path);
267
+ const selection = !selected
268
+ ? {
269
+ anchorPath: node.path,
270
+ focusedPath: node.path,
271
+ paths: [node.path],
272
+ }
273
+ : {
274
+ ...currentSelection,
275
+ focusedPath: node.path,
276
+ };
209
277
 
210
278
  return {
211
279
  actionPaths: getWorkspaceSelectionActionPaths({
@@ -218,27 +286,129 @@ export function WorkspaceExplorer({
218
286
  };
219
287
 
220
288
  const handleItemContextMenu = (event: MouseEvent<HTMLButtonElement>, node: WorkspaceTreeNode) => {
289
+ // Keep item menus from bubbling to the list background handler.
290
+ event.stopPropagation();
221
291
  const meta = getItemActionMeta(node);
222
292
 
223
293
  if (node.type === 'file' && !meta.selected) {
224
- onSelectionChange?.(meta.selection, {
225
- event,
226
- mode: 'single',
227
- node,
228
- reason: 'context-menu',
229
- });
294
+ onSelectionChange?.(
295
+ {
296
+ ...meta.selection,
297
+ focusedPath: node.path,
298
+ },
299
+ {
300
+ event,
301
+ mode: 'single',
302
+ node,
303
+ reason: 'context-menu',
304
+ },
305
+ );
306
+ }
307
+
308
+ if (node.type === 'folder') {
309
+ onSelectionChange?.(
310
+ {
311
+ anchorPath: undefined,
312
+ focusedPath: node.path,
313
+ paths: [],
314
+ },
315
+ {
316
+ event,
317
+ mode: 'single',
318
+ node,
319
+ reason: 'context-menu',
320
+ },
321
+ );
230
322
  }
231
323
 
232
324
  onItemContextMenu?.(event, node, meta);
233
325
  };
234
326
 
327
+ const focusPath = (path: string, node: WorkspaceTreeNode | undefined) => {
328
+ if (!onSelectionChange || !selectionFollowsFocus) {
329
+ if (onSelectionChange) {
330
+ onSelectionChange(
331
+ {
332
+ ...currentSelection,
333
+ focusedPath: path,
334
+ paths: node?.type === 'folder' ? [] : currentSelection.paths,
335
+ },
336
+ { mode: 'single', node, reason: 'keyboard' },
337
+ );
338
+ }
339
+ return;
340
+ }
341
+
342
+ if (node?.type === 'folder') {
343
+ onSelectionChange(
344
+ { ...currentSelection, focusedPath: path, paths: [] },
345
+ { mode: 'single', node, reason: 'keyboard' },
346
+ );
347
+ return;
348
+ }
349
+
350
+ onSelectionChange(
351
+ {
352
+ ...updateWorkspaceSelection({
353
+ mode: 'single',
354
+ orderedPaths: visibleFilePaths,
355
+ selection: currentSelection,
356
+ targetPath: path,
357
+ }),
358
+ focusedPath: path,
359
+ },
360
+ { mode: 'single', node, reason: 'keyboard' },
361
+ );
362
+ };
363
+
235
364
  const handleItemKeyDown = (event: KeyboardEvent<HTMLButtonElement>, node: WorkspaceTreeNode) => {
365
+ if (
366
+ event.key === 'ArrowDown' ||
367
+ event.key === 'ArrowUp' ||
368
+ event.key === 'Home' ||
369
+ event.key === 'End'
370
+ ) {
371
+ const nextPath = resolveWorkspaceExplorerNavigationPath(
372
+ visibleNodes,
373
+ focusedPath ?? node.path,
374
+ event.key,
375
+ );
376
+ if (!nextPath || nextPath === (focusedPath ?? node.path)) {
377
+ return;
378
+ }
379
+ event.preventDefault();
380
+ const nextNode = visibleNodes.find((row) => row.node.path === nextPath)?.node;
381
+ focusPath(nextPath, nextNode);
382
+ return;
383
+ }
384
+
385
+ if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
386
+ const action = resolveWorkspaceExplorerHorizontalNavigationAction(
387
+ visibleNodes,
388
+ focusedPath ?? node.path,
389
+ expandedPaths,
390
+ event.key,
391
+ { filterActive: Boolean(filterQuery.trim()) },
392
+ );
393
+ if (!action) {
394
+ return;
395
+ }
396
+ event.preventDefault();
397
+ if (action.type === 'toggle') {
398
+ onToggleFolder(action.path);
399
+ return;
400
+ }
401
+ const nextNode = visibleNodes.find((row) => row.node.path === action.path)?.node;
402
+ focusPath(action.path, nextNode);
403
+ return;
404
+ }
405
+
236
406
  if (event.key !== 'Delete' && event.key !== 'F2') return;
237
407
 
238
408
  const meta = getItemActionMeta(node);
239
409
 
240
410
  if (event.key === 'Delete') {
241
- if (node.type === 'file' && meta.actionPaths.length === 0) return;
411
+ if (meta.actionPaths.length === 0) return;
242
412
 
243
413
  event.preventDefault();
244
414
  onRequestDelete?.({ ...meta, event, node });
@@ -355,8 +525,10 @@ export function WorkspaceExplorer({
355
525
  };
356
526
 
357
527
  const commitInlineEdit = () => {
358
- if (!inlineEdit) return;
528
+ if (!inlineEdit || inlineEditCommitStartedRef.current) return;
359
529
 
530
+ // Enter commits then blurs the same input; commit only once per draft.
531
+ inlineEditCommitStartedRef.current = true;
360
532
  onInlineEditCommit?.({
361
533
  edit: inlineEdit,
362
534
  value: inlineEdit.value.trim(),
@@ -393,27 +565,28 @@ export function WorkspaceExplorer({
393
565
  }) => {
394
566
  if (!inlineEdit) return null;
395
567
 
396
- const depthStyle = sideBarTreeDepthStyle(depth);
568
+ const depthStyle = explorerTreeDepthStyle(sectionBaseDepth + depth);
397
569
 
398
570
  return (
399
- <li key={key} className="ui-side-bar-list-entry">
400
- <div className="ui-side-bar-inline-edit" style={depthStyle}>
571
+ <li key={key} className="ui-sidebar-list-entry">
572
+ <div className="ui-sidebar-inline-edit" style={depthStyle}>
401
573
  <span className="workbench-tree-prefix">
402
574
  <span className="workbench-tree-spacer" />
403
575
  <WorkspaceFileIcon directory={directory} mimeType={mimeType} path={path} />
404
576
  </span>
405
- <input
577
+ <TextInput
406
578
  ref={inlineEditInputRef}
407
579
  aria-label="Workspace item name"
408
- className="ui-side-bar-inline-edit__input"
580
+ className="ui-sidebar-inline-edit__input"
581
+ controlWidth="full"
409
582
  value={inlineEdit.value}
410
583
  onBlur={commitInlineEdit}
411
- onChange={(event) => onInlineEditValueChange?.(event.currentTarget.value, inlineEdit)}
584
+ onValueChange={(value) => onInlineEditValueChange?.(value, inlineEdit)}
412
585
  onKeyDown={handleInlineEditKeyDown}
413
586
  />
414
587
  </div>
415
588
  {inlineEdit.error ? (
416
- <div className="ui-side-bar-inline-edit__error" style={depthStyle}>
589
+ <div className="ui-sidebar-inline-edit__error" style={depthStyle}>
417
590
  {inlineEdit.error}
418
591
  </div>
419
592
  ) : null}
@@ -424,27 +597,31 @@ export function WorkspaceExplorer({
424
597
  return (
425
598
  <SideBarList
426
599
  fill
427
- aria-label="Workspace files"
600
+ aria-keyshortcuts="ArrowLeft ArrowRight ArrowUp ArrowDown Home End Delete F2"
601
+ aria-label={ariaLabel}
428
602
  dropTarget={dropTargetPath === ''}
603
+ role="tree"
604
+ onContextMenu={(event) => {
605
+ onBackgroundContextMenu?.(event);
606
+ }}
429
607
  onDragLeave={(event) => handleDropTargetDragLeave(event, '')}
430
608
  onDragOver={(event) => handleDropTargetDragOver(event, '')}
431
609
  onDrop={(event) => handleDrop(event, '')}
610
+ onMouseDown={(event) => {
611
+ if (event.target === event.currentTarget) {
612
+ clearSelection();
613
+ }
614
+ }}
432
615
  >
433
- {inlineEdit?.kind.startsWith('create') && !inlineEdit.parentPath
434
- ? renderInlineEdit({
435
- depth: 0,
436
- directory: inlineEdit.kind === 'create-folder',
437
- key: `inline-edit:${inlineEditKey}`,
438
- path: inlineEdit.value,
439
- })
440
- : null}
441
- {visibleNodes.map(({ depth, node }) => {
616
+ {visibleNodes.map(({ depth, node }, index) => {
442
617
  const isFolder = node.type === 'folder';
443
618
  const expanded = expandedPaths.has(node.path) || Boolean(filterQuery.trim());
444
- const selected = node.type === 'file' && selectedPathSet.has(node.path);
619
+ const isFocused = focusedPath === node.path;
620
+ const selected = isFocused || (node.type === 'file' && selectedPathSet.has(node.path));
445
621
  const dropTarget = isFolder && dropTargetPath === node.path;
446
622
  const editingRename =
447
623
  inlineEdit?.kind.startsWith('rename') && inlineEdit.path === node.path;
624
+ const tabIndex = isFocused || (!focusedPath && index === 0) ? 0 : -1;
448
625
 
449
626
  return editingRename ? (
450
627
  renderInlineEdit({
@@ -458,14 +635,28 @@ export function WorkspaceExplorer({
458
635
  <Fragment key={node.path}>
459
636
  <SideBarListItem
460
637
  active={activePath === node.path}
638
+ after={
639
+ renderItemActions ? (
640
+ <span className="ui-workspace-explorer-item-actions">
641
+ {renderItemActions(node, getItemActionMeta(node))}
642
+ </span>
643
+ ) : undefined
644
+ }
461
645
  data-workspace-path={node.path}
462
646
  depth={depth}
463
647
  draggable={Boolean(onRequestMove)}
464
648
  dropTarget={dropTarget}
465
649
  selected={selected}
650
+ tabIndex={tabIndex}
651
+ wrapperProps={{
652
+ role: 'treeitem',
653
+ 'aria-level': depth + 1,
654
+ 'aria-selected': selected,
655
+ ...(isFolder ? { 'aria-expanded': expanded } : {}),
656
+ }}
466
657
  onClick={(event) => {
467
658
  if (isFolder) {
468
- onToggleFolder(node.path);
659
+ selectFolder(event, node);
469
660
  return;
470
661
  }
471
662
  selectFile(event, node);
@@ -516,6 +707,14 @@ export function WorkspaceExplorer({
516
707
  </Fragment>
517
708
  );
518
709
  })}
710
+ {inlineEdit?.kind.startsWith('create') && !inlineEdit.parentPath
711
+ ? renderInlineEdit({
712
+ depth: 0,
713
+ directory: inlineEdit.kind === 'create-folder',
714
+ key: `inline-edit:${inlineEditKey}`,
715
+ path: inlineEdit.value,
716
+ })
717
+ : null}
519
718
  {visibleNodes.length === 0 ? <SideBarListItem disabled>No files</SideBarListItem> : null}
520
719
  </SideBarList>
521
720
  );
@@ -0,0 +1,73 @@
1
+ import type { ReactNode } from 'react';
2
+ import { SideBarViewFrame, SidebarToolbar, WorkbenchSidebarSection } from '../../layout/sidebar';
3
+ import { IconButton } from '../../primitives/icon-button';
4
+ import { cx } from '../../utils/cx';
5
+ import { WorkspaceExplorer, type WorkspaceExplorerProps } from './WorkspaceExplorer';
6
+
7
+ export interface WorkspaceExplorerPanelProps extends WorkspaceExplorerProps {
8
+ 'aria-label'?: string | undefined;
9
+ className?: string | undefined;
10
+ onNewFile?: (() => void) | undefined;
11
+ onNewFolder?: (() => void) | undefined;
12
+ onRefresh?: (() => void) | undefined;
13
+ refreshLabel?: string;
14
+ sectionTitle?: string;
15
+ title?: string;
16
+ toolbarLeading?: ReactNode;
17
+ toolbarStatus?: ReactNode;
18
+ toolbarTrailing?: ReactNode;
19
+ }
20
+
21
+ export function WorkspaceExplorerPanel({
22
+ 'aria-label': ariaLabel,
23
+ className,
24
+ onNewFile,
25
+ onNewFolder,
26
+ onRefresh,
27
+ refreshLabel = 'Refresh Explorer',
28
+ sectionTitle = 'Workspace',
29
+ title = 'Explorer',
30
+ toolbarLeading,
31
+ toolbarStatus,
32
+ toolbarTrailing,
33
+ ...explorerProps
34
+ }: WorkspaceExplorerPanelProps) {
35
+ const hasDefaultActions = Boolean(onNewFile || onNewFolder || onRefresh);
36
+ const hasToolbarSlots = Boolean(toolbarLeading || toolbarTrailing || toolbarStatus);
37
+ const headerActions =
38
+ hasDefaultActions || hasToolbarSlots ? (
39
+ <SidebarToolbar
40
+ aria-label="Explorer actions"
41
+ className="ui-explorer-action-bar"
42
+ role="toolbar"
43
+ >
44
+ {toolbarLeading}
45
+ {onNewFile ? (
46
+ <IconButton compact icon="codicon-new-file" label="New file" onClick={onNewFile} />
47
+ ) : null}
48
+ {onNewFolder ? (
49
+ <IconButton compact icon="codicon-new-folder" label="New folder" onClick={onNewFolder} />
50
+ ) : null}
51
+ {onRefresh ? (
52
+ <IconButton compact icon="codicon-refresh" label={refreshLabel} onClick={onRefresh} />
53
+ ) : null}
54
+ {toolbarTrailing}
55
+ {toolbarStatus ? (
56
+ <span className="ui-explorer-action-bar__status">{toolbarStatus}</span>
57
+ ) : null}
58
+ </SidebarToolbar>
59
+ ) : undefined;
60
+
61
+ return (
62
+ <SideBarViewFrame
63
+ actions={headerActions}
64
+ aria-label={ariaLabel}
65
+ className={cx('workbench-explorer-view', 'ui-workspace-explorer-panel', className)}
66
+ title={title}
67
+ >
68
+ <WorkbenchSidebarSection id="workspace-explorer-section" title={sectionTitle}>
69
+ <WorkspaceExplorer {...explorerProps} />
70
+ </WorkbenchSidebarSection>
71
+ </SideBarViewFrame>
72
+ );
73
+ }