@workbench-kit/react 0.0.2-prototype.0.2.4 → 0.0.2-prototype.0.2.41

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 (221) hide show
  1. package/README.md +172 -0
  2. package/package.json +38 -21
  3. package/src/index.ts +74 -34
  4. package/src/jdw/JsonCodeEditorPane.tsx +7 -6
  5. package/src/jdw/builtins/renderBuiltinWidgetLeaf.tsx +1 -3
  6. package/src/jdw/createBuiltinJdwRegistry.ts +1 -4
  7. package/src/jdw/cssRenderBackend.tsx +1 -4
  8. package/src/jdw/fixtures/jdw-fixtures.ts +0 -15
  9. package/src/json-config/JsonConfigWorkbench.tsx +1 -1
  10. package/src/layout/index.ts +11 -2
  11. package/src/layout/panel/Panel.tsx +0 -3
  12. package/src/layout/panel/index.ts +0 -2
  13. package/src/layout/sidebar/SideBarTree.tsx +301 -0
  14. package/src/layout/sidebar/SidebarActionIconBar.tsx +3 -3
  15. package/src/layout/sidebar/WorkbenchSidebarActions.tsx +1 -1
  16. package/src/layout/sidebar/index.ts +13 -0
  17. package/src/modal/Modal.tsx +55 -25
  18. package/src/modal/ModalTitlebar.tsx +8 -8
  19. package/src/modal/modalPosition.ts +3 -6
  20. package/src/modal/useModalFocusTrap.ts +142 -0
  21. package/src/modal/useModalWindowFrame.ts +2 -2
  22. package/src/overlay/ContextMenu.tsx +133 -21
  23. package/src/overlay/context-menu-density.css +22 -0
  24. package/src/overlay/context-menu-item.ts +17 -0
  25. package/src/overlay/context-menu.css +6 -2
  26. package/src/overlay/index.ts +6 -1
  27. package/src/overlay/measureAnchoredOverlayPanel.ts +4 -6
  28. package/src/overlay/pointerPassthroughRegion.ts +17 -1
  29. package/src/overlay/usePointerPassthroughRegion.ts +35 -6
  30. package/src/primitives/absolute-box/AbsoluteBox.tsx +4 -4
  31. package/src/primitives/app-icon/AppIcon.tsx +33 -0
  32. package/src/primitives/app-icon/app-icon.css +28 -0
  33. package/src/primitives/button/Button.tsx +4 -4
  34. package/src/primitives/catalog-browse-card/CatalogBrowseCard.tsx +6 -6
  35. package/src/primitives/catalog-browse-pane/CatalogBrowsePane.tsx +39 -32
  36. package/src/primitives/catalog-browse-pane/catalog-browse-pane.css +4 -0
  37. package/src/primitives/catalog-filter-overlay/CatalogFilterOverlay.tsx +2 -2
  38. package/src/primitives/checkbox/Checkbox.tsx +1 -1
  39. package/src/primitives/chip/Chip.tsx +3 -12
  40. package/src/primitives/chip/index.ts +2 -2
  41. package/src/primitives/codicon/Codicon.tsx +1 -1
  42. package/src/primitives/file-icon/FileIcon.tsx +1 -1
  43. package/src/primitives/icon-button/IconButton.tsx +1 -1
  44. package/src/primitives/index.ts +7 -2
  45. package/src/primitives/library-detail-layout/LibraryDetailLayout.tsx +123 -9
  46. package/src/primitives/library-detail-layout/library-detail-layout.css +57 -0
  47. package/src/primitives/library-detail-layout/resolve-hero-cover-media.ts +80 -0
  48. package/src/primitives/library-facet-filter-panel/LibraryFacetFilterPanel.tsx +12 -12
  49. package/src/primitives/library-facet-filter-strip/LibraryFacetFilterStrip.tsx +4 -4
  50. package/src/primitives/number-input/NumberInput.tsx +5 -5
  51. package/src/primitives/primitives.css +1 -0
  52. package/src/primitives/record-media-hero/RecordMediaHero.tsx +10 -6
  53. package/src/primitives/scroll-area/ScrollArea.tsx +5 -5
  54. package/src/primitives/scroll-area-infinite-load/useScrollAreaInfiniteLoad.ts +5 -5
  55. package/src/primitives/searchable-multi-select/SearchableMultiSelect.tsx +7 -7
  56. package/src/primitives/select/Select.tsx +1 -13
  57. package/src/primitives/text-area/TextArea.tsx +1 -1
  58. package/src/primitives/text-input/TextInput.tsx +1 -1
  59. package/src/primitives/workbench-media-slot/WorkbenchMediaPlaceholder.tsx +2 -2
  60. package/src/primitives/workbench-media-slot/WorkbenchMediaSlot.tsx +16 -10
  61. package/src/primitives/workbench-thumbnail/WorkbenchThumbnail.tsx +4 -4
  62. package/src/scrollbars.css +2 -6
  63. package/src/styles/core.css +16 -0
  64. package/src/styles/foundation.css +4 -0
  65. package/src/styles/overlay.css +2 -0
  66. package/src/styles.css +1 -15
  67. package/src/utils/clamp.ts +4 -0
  68. package/src/utils/normalizeKeyToken.ts +13 -0
  69. package/src/utils/readNumber.ts +4 -0
  70. package/src/widget-tree/WidgetSourceEditor.tsx +0 -14
  71. package/src/widget-tree/WidgetTreeCanvasPreview.tsx +3 -10
  72. package/src/widget-tree/WidgetTreeLab.tsx +2 -23
  73. package/src/widget-tree/WidgetTreeSidePanel.tsx +0 -5
  74. package/src/widget-tree/WidgetTreeWorkspaceShell.tsx +2 -2
  75. package/src/widget-tree/index.ts +1 -5
  76. package/src/workbench/auth/WorkbenchLoginView.tsx +1 -2
  77. package/src/workbench/auth/auth-flows.css +14 -0
  78. package/src/workbench/chat/ChatCommandProposalCard.tsx +4 -4
  79. package/src/workbench/chat/ChatConversationBar.tsx +3 -3
  80. package/src/workbench/chat/ChatHistoryMenu.tsx +1 -1
  81. package/src/workbench/chat/ChatMessageCollapsible.tsx +4 -0
  82. package/src/workbench/chat/ChatMessageItem.tsx +68 -10
  83. package/src/workbench/chat/ChatMessageList.tsx +1 -1
  84. package/src/workbench/chat/ChatPanel.tsx +32 -23
  85. package/src/workbench/chat/ChatPhasedRunProgress.tsx +86 -13
  86. package/src/workbench/chat/ChatRenameDialog.tsx +1 -1
  87. package/src/workbench/chat/chat-conversation.css +2 -2
  88. package/src/workbench/chat/chat-ui.css +8 -0
  89. package/src/workbench/chat/chatConversation.ts +2 -2
  90. package/src/workbench/chat/chatMessageMeta.tsx +4 -4
  91. package/src/workbench/chat/index.ts +1 -0
  92. package/src/workbench/chat/types.ts +7 -7
  93. package/src/workbench/chat/useCancelRuntimeOnUnmount.ts +4 -4
  94. package/src/workbench/chat/useChatPrependPagination.ts +10 -10
  95. package/src/workbench/chat/useSlashCommandSuggest.ts +1 -1
  96. package/src/workbench/{WorkbenchModalPortal.tsx → chrome/WorkbenchModalPortal.tsx} +1 -1
  97. package/src/workbench/chrome/workbench-chrome.css +4 -0
  98. package/src/workbench/chrome/workbench-layout-regions.css +13 -0
  99. package/src/workbench/chrome/workbench-shell-titlebar.css +0 -8
  100. package/src/workbench/{CommandGroupShell.tsx → commands/CommandGroupShell.tsx} +2 -2
  101. package/src/workbench/{CommandList.tsx → commands/CommandList.tsx} +6 -5
  102. package/src/workbench/{CommandPalette.tsx → commands/CommandPalette.tsx} +16 -42
  103. package/src/workbench/{ConfirmationFlow.tsx → commands/ConfirmationFlow.tsx} +5 -5
  104. package/src/workbench/{ShortcutCommandBridge.tsx → commands/ShortcutCommandBridge.tsx} +17 -13
  105. package/src/workbench/commands/WorkbenchQuickOpen.tsx +462 -0
  106. package/src/workbench/{command-model.ts → commands/command-model.ts} +5 -1
  107. package/src/workbench/commands/command-ui.ts +3 -0
  108. package/src/workbench/{commands.ts → commands/commands.ts} +45 -1
  109. package/src/workbench/commands/createWorkspaceFilesQuickOpenProvider.ts +86 -0
  110. package/src/workbench/commands/quick-open-model.ts +66 -0
  111. package/src/workbench/{WorkbenchEditorTabs.tsx → editor/WorkbenchEditorTabs.tsx} +13 -3
  112. package/src/workbench/{editor-tabs-dnd.ts → editor/editor-tabs-dnd.ts} +1 -1
  113. package/src/workbench/{editorTabContextMenu.ts → editor/editorTabContextMenu.ts} +43 -4
  114. package/src/workbench/{useEditorTabsStripDnd.ts → editor/useEditorTabsStripDnd.ts} +1 -1
  115. package/src/workbench/{useWorkbenchEditorTabContextMenu.tsx → editor/useWorkbenchEditorTabContextMenu.tsx} +16 -2
  116. package/src/workbench/editor-tabs/index.ts +10 -9
  117. package/src/workbench/index.ts +114 -74
  118. package/src/workbench/management/CommandManagementSidebar.tsx +16 -30
  119. package/src/workbench/management/ExtensionManagementPanel.tsx +84 -46
  120. package/src/workbench/management/ExtensionManagementSidebar.tsx +79 -45
  121. package/src/workbench/management/IntegrationCommandActions.tsx +8 -1
  122. package/src/workbench/management/IntegrationSettingsSurface.tsx +2 -5
  123. package/src/workbench/management/IntegrationsShell.tsx +1 -1
  124. package/src/workbench/management/KeybindingCaptureField.tsx +1 -9
  125. package/src/workbench/management/WorkbenchDialogFrame.tsx +2 -2
  126. package/src/workbench/management/WorkbenchNotice.tsx +17 -12
  127. package/src/workbench/management/createWorkbenchNotify.tsx +88 -0
  128. package/src/workbench/management/extension-install-approval.ts +72 -0
  129. package/src/workbench/management/extension-management-filters.ts +38 -0
  130. package/src/workbench/management/index.ts +18 -3
  131. package/src/workbench/management/management.css +28 -0
  132. package/src/workbench/management/types.ts +23 -1
  133. package/src/workbench/management/useWorkbenchNotify.ts +10 -0
  134. package/src/workbench/{MarkdownPreview.tsx → markdown/MarkdownPreview.tsx} +22 -7
  135. package/src/workbench/markdown/markdownRemarkPlugins.ts +12 -0
  136. package/src/workbench/markdown/sanitizeMarkdownHref.ts +29 -0
  137. package/src/workbench/schema/workbenchDocumentRenderer.tsx +48 -121
  138. package/src/workbench/settings/StructuredDataForm.tsx +1 -4
  139. package/src/workbench/settings/StructuredDataSchemaPanel.tsx +39 -44
  140. package/src/workbench/settings/sectionedPanelScrollSpy.ts +0 -81
  141. package/src/workbench/settings/structuredDataFormModel.ts +2 -1
  142. package/src/workbench/settings/structuredDataSchema.ts +24 -13
  143. package/src/workbench/settings/structuredDataSchemaSection.ts +4 -0
  144. package/src/workbench/settings/structuredDataSchemaTable.ts +5 -2
  145. package/src/workbench/{ActivityBar.tsx → shell/ActivityBar.tsx} +8 -12
  146. package/src/workbench/{ArtifactShell.tsx → shell/ArtifactShell.tsx} +25 -25
  147. package/src/workbench/{SplitView.tsx → shell/SplitView.tsx} +3 -3
  148. package/src/workbench/{StatusBar.tsx → shell/StatusBar.tsx} +8 -8
  149. package/src/workbench/{StructuredArtifactEditor.tsx → shell/StructuredArtifactEditor.tsx} +9 -9
  150. package/src/workbench/{Timeline.tsx → shell/Timeline.tsx} +77 -20
  151. package/src/workbench/{WorkbenchCanvasShell.defaults.ts → shell/WorkbenchCanvasShell.defaults.ts} +1 -1
  152. package/src/workbench/{WorkbenchCanvasShell.model.ts → shell/WorkbenchCanvasShell.model.ts} +5 -5
  153. package/src/workbench/{WorkbenchCanvasShell.tsx → shell/WorkbenchCanvasShell.tsx} +6 -6
  154. package/src/workbench/{WorkbenchDesktopTitleBar.tsx → shell/WorkbenchDesktopTitleBar.tsx} +15 -15
  155. package/src/workbench/{WorkbenchShell.tsx → shell/WorkbenchShell.tsx} +45 -6
  156. package/src/workbench/{WorkbenchShellTitleBarLayoutControls.tsx → shell/WorkbenchShellTitleBarLayoutControls.tsx} +16 -19
  157. package/src/workbench/{WorkbenchStandaloneShell.tsx → shell/WorkbenchStandaloneShell.tsx} +15 -22
  158. package/src/workbench/{WorkbenchViewEditor.tsx → shell/WorkbenchViewEditor.tsx} +7 -7
  159. package/src/workbench/{WorkbenchViewSidebar.tsx → shell/WorkbenchViewSidebar.tsx} +7 -7
  160. package/src/workbench/{WorkbenchWindowChromeControls.tsx → shell/WorkbenchWindowChromeControls.tsx} +18 -15
  161. package/src/workbench/shell/activity-bar.css +47 -0
  162. package/src/workbench/{activityBarOrder.ts → shell/activityBarOrder.ts} +2 -1
  163. package/src/workbench/{shell.ts → shell/shell.ts} +20 -13
  164. package/src/workbench/{shellViewModel.ts → shell/shellViewModel.ts} +3 -3
  165. package/src/workbench/{standalone.ts → shell/standalone.ts} +14 -2
  166. package/src/workbench/{useDeferredWorkbenchMount.ts → shell/useDeferredWorkbenchMount.ts} +3 -3
  167. package/src/workbench/{useWorkbenchAppearanceDocumentSync.tsx → shell/useWorkbenchAppearanceDocumentSync.tsx} +1 -1
  168. package/src/workbench/{useWorkbenchSidebarActionBarDnd.ts → shell/useWorkbenchSidebarActionBarDnd.ts} +1 -1
  169. package/src/workbench/{useWorkbenchSidebarViewPlacementDropZone.ts → shell/useWorkbenchSidebarViewPlacementDropZone.ts} +2 -2
  170. package/src/workbench/{workbenchSidebarLayoutContext.ts → shell/workbenchSidebarLayoutContext.ts} +0 -6
  171. package/src/workbench/{workbenchViewRouteState.ts → shell/workbenchViewRouteState.ts} +4 -4
  172. package/src/workbench/{WorkbenchThemeProvider.tsx → theme/WorkbenchThemeProvider.tsx} +4 -4
  173. package/src/workbench/{theme.ts → theme/theme.ts} +1 -1
  174. package/src/workbench/{themePresets.ts → theme/themePresets.ts} +39 -64
  175. package/src/workbench/views/command-list-density.css +36 -0
  176. package/src/workbench/views/command-list.css +2 -0
  177. package/src/workbench/views/extensions-sidebar.css +2 -0
  178. package/src/workbench/views/view-hosts.css +3 -3
  179. package/src/workbench/workspace/WorkspaceEditorPanel.tsx +1 -1
  180. package/src/workbench/workspace/WorkspaceExplorer.tsx +105 -4
  181. package/src/workbench/workspace/createVirtualWorkspaceExplorerPort.ts +1 -14
  182. package/src/workbench/workspace/workspaceExplorerKeyboard.ts +109 -0
  183. package/src/workbench/workspace/workspaceJsonDiagnostics.ts +6 -5
  184. package/src/workbench-menu-surfaces.css +3 -57
  185. package/src/brand/TilepaperAppIcon.tsx +0 -181
  186. package/src/brand/index.ts +0 -2
  187. package/src/brand/tilepaper-app-icon-geometry.ts +0 -201
  188. package/src/primitives/absolute-box/index.ts +0 -1
  189. package/src/primitives/catalog-browse-card/index.ts +0 -1
  190. package/src/primitives/catalog-browse-pane/index.ts +0 -3
  191. package/src/primitives/catalog-filter-overlay/index.ts +0 -1
  192. package/src/primitives/codicon/index.ts +0 -1
  193. package/src/primitives/external-link-button/index.ts +0 -1
  194. package/src/primitives/library-detail-layout/index.ts +0 -1
  195. package/src/primitives/library-facet-filter-panel/index.ts +0 -1
  196. package/src/primitives/library-facet-filter-strip/index.ts +0 -1
  197. package/src/primitives/panel-loading/index.ts +0 -1
  198. package/src/primitives/scroll-area-infinite-load/index.ts +0 -2
  199. package/src/primitives/workbench-thumbnail/index.ts +0 -1
  200. package/src/test-utils/workbenchMonacoMock.tsx +0 -37
  201. package/src/workbench/jdw/jdw-editors.css +0 -4
  202. package/src/workbench/jdw/jdw.css +0 -2
  203. package/src/workbench/management/integration-command-action.ts +0 -25
  204. package/src/workbench/markdownRemarkPlugins.ts +0 -4
  205. package/src/workbench/workbench-chrome.css +0 -4
  206. /package/src/workbench/{WorkbenchPlatformContext.tsx → chrome/WorkbenchPlatformContext.tsx} +0 -0
  207. /package/src/workbench/{workbenchModalViewState.ts → chrome/workbenchModalViewState.ts} +0 -0
  208. /package/src/workbench/{workbenchOverlaysContext.tsx → chrome/workbenchOverlaysContext.tsx} +0 -0
  209. /package/src/workbench/{workbenchPlatformChrome.ts → chrome/workbenchPlatformChrome.ts} +0 -0
  210. /package/src/workbench/{command-execution-policy.ts → commands/command-execution-policy.ts} +0 -0
  211. /package/src/workbench/{keyboard.ts → commands/keyboard.ts} +0 -0
  212. /package/src/workbench/{workbenchContextMenu.ts → commands/workbenchContextMenu.ts} +0 -0
  213. /package/src/workbench/{appearanceLabels.ts → shell/appearanceLabels.ts} +0 -0
  214. /package/src/workbench/{hardReset.ts → shell/hardReset.ts} +0 -0
  215. /package/src/workbench/{shellPresets.ts → shell/shellPresets.ts} +0 -0
  216. /package/src/workbench/{shellState.ts → shell/shellState.ts} +0 -0
  217. /package/src/workbench/{sidebarViewPlacementDnd.ts → shell/sidebarViewPlacementDnd.ts} +0 -0
  218. /package/src/workbench/{status.ts → shell/status.ts} +0 -0
  219. /package/src/workbench/{useWorkbenchSidebarLayout.tsx → shell/useWorkbenchSidebarLayout.tsx} +0 -0
  220. /package/src/workbench/{useWorkbenchStandaloneShellStateSync.tsx → shell/useWorkbenchStandaloneShellStateSync.tsx} +0 -0
  221. /package/src/workbench/{workbenchStandaloneShellReactContext.tsx → shell/workbenchStandaloneShellReactContext.tsx} +0 -0
@@ -23,14 +23,18 @@ import { TextInput } from '../../primitives/text-input';
23
23
  import { cxCodicon } from '../../utils/codicon';
24
24
  import { explorerTreeDepthStyle } from './explorer-tree-style';
25
25
  import { flattenWorkspaceTree } from './tree';
26
+ import {
27
+ resolveWorkspaceExplorerHorizontalNavigationAction,
28
+ resolveWorkspaceExplorerNavigationPath,
29
+ } from './workspaceExplorerKeyboard.js';
26
30
  import { WorkspaceFileIcon } from './WorkspaceFileIcon';
27
31
  import type { WorkspaceTreeNode } from './types';
28
32
 
29
- export const WORKSPACE_EXPLORER_DRAG_DATA_TYPE = 'application/x-newchobo-ui-workspace-paths';
33
+ export const WORKSPACE_EXPLORER_DRAG_DATA_TYPE = 'application/x-workbench-kit-workspace-paths';
30
34
  export const WORKSPACE_EXPLORER_DRAG_METADATA_DATA_TYPE = `${WORKSPACE_EXPLORER_DRAG_DATA_TYPE}.metadata`;
31
35
 
32
36
  export type WorkspaceExplorerSelectionChangeReason =
33
- 'clear' | 'click' | 'context-menu' | 'drag-start' | 'folder-click';
37
+ 'clear' | 'click' | 'context-menu' | 'drag-start' | 'folder-click' | 'keyboard';
34
38
 
35
39
  export interface WorkspaceExplorerSelectionChangeMeta {
36
40
  event?: DragEvent<HTMLButtonElement> | MouseEvent<HTMLButtonElement>;
@@ -91,6 +95,8 @@ export interface WorkspaceExplorerInlineEditCommitMeta {
91
95
 
92
96
  export interface WorkspaceExplorerProps {
93
97
  activePath?: string;
98
+ /** Accessible name for the `role="tree"` list. Defaults to "Workspace files". */
99
+ ariaLabel?: string;
94
100
  dragDataType?: string;
95
101
  dragMetadataDataType?: string;
96
102
  dragMetadataFactory?: WorkspaceExplorerDragMetadataFactory;
@@ -120,10 +126,16 @@ export interface WorkspaceExplorerProps {
120
126
  renderItemActions?: (node: WorkspaceTreeNode, meta: WorkspaceExplorerItemActionMeta) => ReactNode;
121
127
  selectedPaths?: Iterable<string>;
122
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;
123
134
  }
124
135
 
125
136
  export function WorkspaceExplorer({
126
137
  activePath,
138
+ ariaLabel = 'Workspace files',
127
139
  dragDataType = WORKSPACE_EXPLORER_DRAG_DATA_TYPE,
128
140
  dragMetadataDataType = WORKSPACE_EXPLORER_DRAG_METADATA_DATA_TYPE,
129
141
  dragMetadataFactory,
@@ -146,6 +158,7 @@ export function WorkspaceExplorer({
146
158
  renderItemActions,
147
159
  selectedPaths = [],
148
160
  selectionAnchorPath,
161
+ selectionFollowsFocus = true,
149
162
  }: WorkspaceExplorerProps) {
150
163
  const sectionBaseDepth = useSidebarSectionBaseDepth();
151
164
  const draggedPathsRef = useRef<string[]>([]);
@@ -311,7 +324,85 @@ export function WorkspaceExplorer({
311
324
  onItemContextMenu?.(event, node, meta);
312
325
  };
313
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
+
314
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
+
315
406
  if (event.key !== 'Delete' && event.key !== 'F2') return;
316
407
 
317
408
  const meta = getItemActionMeta(node);
@@ -506,8 +597,10 @@ export function WorkspaceExplorer({
506
597
  return (
507
598
  <SideBarList
508
599
  fill
509
- aria-label="Workspace files"
600
+ aria-keyshortcuts="ArrowLeft ArrowRight ArrowUp ArrowDown Home End Delete F2"
601
+ aria-label={ariaLabel}
510
602
  dropTarget={dropTargetPath === ''}
603
+ role="tree"
511
604
  onContextMenu={(event) => {
512
605
  onBackgroundContextMenu?.(event);
513
606
  }}
@@ -520,7 +613,7 @@ export function WorkspaceExplorer({
520
613
  }
521
614
  }}
522
615
  >
523
- {visibleNodes.map(({ depth, node }) => {
616
+ {visibleNodes.map(({ depth, node }, index) => {
524
617
  const isFolder = node.type === 'folder';
525
618
  const expanded = expandedPaths.has(node.path) || Boolean(filterQuery.trim());
526
619
  const isFocused = focusedPath === node.path;
@@ -528,6 +621,7 @@ export function WorkspaceExplorer({
528
621
  const dropTarget = isFolder && dropTargetPath === node.path;
529
622
  const editingRename =
530
623
  inlineEdit?.kind.startsWith('rename') && inlineEdit.path === node.path;
624
+ const tabIndex = isFocused || (!focusedPath && index === 0) ? 0 : -1;
531
625
 
532
626
  return editingRename ? (
533
627
  renderInlineEdit({
@@ -553,6 +647,13 @@ export function WorkspaceExplorer({
553
647
  draggable={Boolean(onRequestMove)}
554
648
  dropTarget={dropTarget}
555
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
+ }}
556
657
  onClick={(event) => {
557
658
  if (isFolder) {
558
659
  selectFolder(event, node);
@@ -6,10 +6,7 @@ import {
6
6
  } from '@workbench-kit/workspace';
7
7
 
8
8
  import type { VirtualWorkspaceApi } from './useVirtualWorkspace';
9
- import type {
10
- WorkspaceExplorerControllerPort,
11
- WorkspaceExplorerMutationResult,
12
- } from './workspaceExplorerController';
9
+ import type { WorkspaceExplorerControllerPort } from './workspaceExplorerController';
13
10
 
14
11
  export function createVirtualWorkspaceExplorerPort({
15
12
  onNotify,
@@ -129,13 +126,3 @@ export function applyVirtualWorkspaceRenameSelection(
129
126
  paths: selection.paths.map(renameDescendantPath),
130
127
  };
131
128
  }
132
-
133
- export function toWorkspaceExplorerMutationResult(
134
- value: WorkspaceExplorerMutationResult | void | undefined,
135
- ): WorkspaceExplorerMutationResult | undefined {
136
- if (!value) {
137
- return undefined;
138
- }
139
-
140
- return value;
141
- }
@@ -0,0 +1,109 @@
1
+ import { parentPathOf } from '@workbench-kit/workspace';
2
+
3
+ import type { WorkspaceTreeNode } from './types.js';
4
+
5
+ export type WorkspaceExplorerVisibleRow = {
6
+ readonly depth: number;
7
+ readonly node: WorkspaceTreeNode;
8
+ };
9
+
10
+ export type WorkspaceExplorerVerticalNavigationKey = 'ArrowDown' | 'ArrowUp' | 'Home' | 'End';
11
+
12
+ export type WorkspaceExplorerHorizontalNavigationKey = 'ArrowLeft' | 'ArrowRight';
13
+
14
+ export type WorkspaceExplorerHorizontalNavigationAction =
15
+ | { readonly type: 'toggle'; readonly path: string }
16
+ | { readonly type: 'focus'; readonly path: string };
17
+
18
+ function rowIndexByPath(
19
+ rows: readonly WorkspaceExplorerVisibleRow[],
20
+ path: string | undefined,
21
+ ): number {
22
+ if (!path) {
23
+ return -1;
24
+ }
25
+ return rows.findIndex((row) => row.node.path === path);
26
+ }
27
+
28
+ /**
29
+ * Resolve the next focused path for vertical tree navigation over visible
30
+ * (already collapse-filtered) explorer rows.
31
+ */
32
+ export function resolveWorkspaceExplorerNavigationPath(
33
+ rows: readonly WorkspaceExplorerVisibleRow[],
34
+ focusedPath: string | undefined,
35
+ key: WorkspaceExplorerVerticalNavigationKey,
36
+ ): string | null {
37
+ if (rows.length === 0) {
38
+ return null;
39
+ }
40
+
41
+ const currentIndex = rowIndexByPath(rows, focusedPath);
42
+ const fallbackIndex = currentIndex >= 0 ? currentIndex : 0;
43
+
44
+ if (key === 'Home') {
45
+ return rows[0]?.node.path ?? null;
46
+ }
47
+ if (key === 'End') {
48
+ return rows[rows.length - 1]?.node.path ?? null;
49
+ }
50
+ if (key === 'ArrowDown') {
51
+ return rows[Math.min(rows.length - 1, fallbackIndex + 1)]?.node.path ?? null;
52
+ }
53
+ return rows[Math.max(0, fallbackIndex - 1)]?.node.path ?? null;
54
+ }
55
+
56
+ function firstChildPath(
57
+ rows: readonly WorkspaceExplorerVisibleRow[],
58
+ parentPath: string,
59
+ ): string | null {
60
+ return rows.find((row) => parentPathOf(row.node.path) === parentPath)?.node.path ?? null;
61
+ }
62
+
63
+ /**
64
+ * Resolve expand/collapse/parent focus for ArrowLeft/ArrowRight.
65
+ * Call `onToggleFolder` only for `toggle` actions (toggle-only host API).
66
+ */
67
+ export function resolveWorkspaceExplorerHorizontalNavigationAction(
68
+ rows: readonly WorkspaceExplorerVisibleRow[],
69
+ focusedPath: string | undefined,
70
+ expandedPaths: ReadonlySet<string>,
71
+ key: WorkspaceExplorerHorizontalNavigationKey,
72
+ options: { readonly filterActive?: boolean } = {},
73
+ ): WorkspaceExplorerHorizontalNavigationAction | null {
74
+ const currentIndex = rowIndexByPath(rows, focusedPath);
75
+ const current = rows[currentIndex >= 0 ? currentIndex : 0];
76
+ if (!current) {
77
+ return null;
78
+ }
79
+
80
+ const { node } = current;
81
+ const filterActive = options.filterActive ?? false;
82
+ const isFolder = node.type === 'folder';
83
+ const expanded = isFolder && (expandedPaths.has(node.path) || filterActive);
84
+
85
+ if (key === 'ArrowRight') {
86
+ if (!isFolder) {
87
+ return null;
88
+ }
89
+ if (!expanded && !filterActive) {
90
+ return { type: 'toggle', path: node.path };
91
+ }
92
+ const childPath = firstChildPath(rows, node.path);
93
+ return childPath ? { type: 'focus', path: childPath } : null;
94
+ }
95
+
96
+ // ArrowLeft
97
+ if (isFolder && expanded && !filterActive) {
98
+ return { type: 'toggle', path: node.path };
99
+ }
100
+
101
+ const parentPath = parentPathOf(node.path);
102
+ if (!parentPath) {
103
+ return null;
104
+ }
105
+ if (rowIndexByPath(rows, parentPath) < 0) {
106
+ return null;
107
+ }
108
+ return { type: 'focus', path: parentPath };
109
+ }
@@ -68,11 +68,12 @@ export function configureWorkspaceEditorJsonDiagnostics(
68
68
  const schemas = getWorkspaceEditorJsonDiagnosticsSchemas(file);
69
69
  if (schemas.length === 0) return;
70
70
 
71
- const jsonDefaults = (
72
- monacoInstance.languages.json as unknown as {
73
- jsonDefaults?: { setDiagnosticsOptions: (options: unknown) => void };
74
- }
75
- ).jsonDefaults;
71
+ const jsonLanguage = monacoInstance.languages.json as unknown as
72
+ | {
73
+ jsonDefaults?: { setDiagnosticsOptions: (options: unknown) => void };
74
+ }
75
+ | undefined;
76
+ const jsonDefaults = jsonLanguage?.jsonDefaults;
76
77
  if (!jsonDefaults) return;
77
78
 
78
79
  jsonDefaults.setDiagnosticsOptions({
@@ -1,57 +1,3 @@
1
- /* Optional compact menu density for context menus and command lists. */
2
-
3
- .ui-context-menu__item,
4
- .ui-context-menu__item.ui-button {
5
- --ui-button-min-height: 28px;
6
- --ui-button-height: auto;
7
- --ui-button-padding: 4px 10px;
8
- --ui-button-border-radius: 0;
9
- border-radius: 0;
10
- min-height: 28px;
11
- height: auto;
12
- padding: 4px 10px;
13
- }
14
-
15
- .ui-context-menu__separator {
16
- margin: 0;
17
- }
18
-
19
- .ui-context-menu__shortcut {
20
- font-size: var(--font-size-xs);
21
- color: var(--color-text-subtle);
22
- }
23
-
24
- .ui-workbench-command-list {
25
- padding: 0;
26
- }
27
-
28
- .ui-workbench-command-item,
29
- .ui-workbench-command-item.ui-button {
30
- --ui-button-height: auto;
31
- --ui-button-padding: 7px 10px;
32
- --ui-button-border-radius: 0;
33
- border-radius: 0;
34
- height: auto;
35
- padding: 7px 10px;
36
- }
37
-
38
- .ui-workbench-command-group-shell__nav {
39
- padding: 0;
40
- }
41
-
42
- .ui-workbench-command-group-shell__nav-link {
43
- border-radius: 0;
44
- }
45
-
46
- .ui-workbench-command-group-shell__content {
47
- padding: 0;
48
- }
49
-
50
- .ui-workbench-command-group-shell__section {
51
- padding: 0;
52
- }
53
-
54
- .ui-workbench-command-group-shell__section-header {
55
- min-height: 28px;
56
- padding: 4px 10px;
57
- }
1
+ /* Compatibility entry for consumers that opt into both compact menu surfaces. */
2
+ @import './overlay/context-menu-density.css';
3
+ @import './workbench/views/command-list-density.css';
@@ -1,181 +0,0 @@
1
- import { useId, type SVGProps } from 'react';
2
- import { cx } from '../utils/cx';
3
- import {
4
- TILEPAPER_ICON_CANVAS,
5
- TILEPAPER_ICON_GRADIENTS,
6
- TILEPAPER_ICON_GRID,
7
- TILEPAPER_ICON_ROOT_ELEVATION,
8
- TILEPAPER_ICON_ROOT_PANEL,
9
- TILEPAPER_ICON_TILES,
10
- tilepaperPaperFoldPaths,
11
- } from './tilepaper-app-icon-geometry.js';
12
-
13
- export type TilepaperAppIconProps = Omit<SVGProps<SVGSVGElement>, 'viewBox'> & {
14
- /** Flat rendering for small surfaces (e.g. titlebar) where elevation blur reads muddy. */
15
- compact?: boolean;
16
- };
17
-
18
- export function TilepaperAppIcon({ className, compact = false, ...props }: TilepaperAppIconProps) {
19
- const idPrefix = `tilepaper-icon-${useId().replace(/:/g, '')}`;
20
- const bgId = `${idPrefix}-bg`;
21
- const panelId = `${idPrefix}-panel`;
22
- const elevationId = `${idPrefix}-elevation`;
23
- const blueId = `${idPrefix}-blue`;
24
- const paperId = `${idPrefix}-paper`;
25
- const tealId = `${idPrefix}-teal`;
26
- const violetId = `${idPrefix}-violet`;
27
- const { tileRx, tileSize } = TILEPAPER_ICON_GRID;
28
- const fold = tilepaperPaperFoldPaths(
29
- TILEPAPER_ICON_TILES.paper.x,
30
- TILEPAPER_ICON_TILES.paper.y,
31
- tileSize,
32
- );
33
-
34
- return (
35
- <svg
36
- aria-hidden="true"
37
- className={cx('tilepaper-app-icon', className)}
38
- fill="none"
39
- viewBox={`0 0 ${TILEPAPER_ICON_CANVAS.size} ${TILEPAPER_ICON_CANVAS.size}`}
40
- xmlns="http://www.w3.org/2000/svg"
41
- {...props}
42
- >
43
- <defs>
44
- {compact ? null : (
45
- <filter
46
- id={elevationId}
47
- x="-12%"
48
- y="-8%"
49
- width="124%"
50
- height="128%"
51
- colorInterpolationFilters="sRGB"
52
- >
53
- <feDropShadow
54
- dx="0"
55
- dy={TILEPAPER_ICON_ROOT_ELEVATION.dy}
56
- floodColor={TILEPAPER_ICON_ROOT_ELEVATION.floodColor}
57
- floodOpacity={TILEPAPER_ICON_ROOT_ELEVATION.floodOpacity}
58
- stdDeviation={TILEPAPER_ICON_ROOT_ELEVATION.stdDeviation}
59
- />
60
- </filter>
61
- )}
62
- <linearGradient
63
- id={bgId}
64
- x1={TILEPAPER_ICON_GRADIENTS.bg.x1}
65
- x2={TILEPAPER_ICON_GRADIENTS.bg.x2}
66
- y1={TILEPAPER_ICON_GRADIENTS.bg.y1}
67
- y2={TILEPAPER_ICON_GRADIENTS.bg.y2}
68
- gradientUnits="userSpaceOnUse"
69
- >
70
- <stop offset="0" stopColor="#0A1020" />
71
- <stop offset="1" stopColor="#121C33" />
72
- </linearGradient>
73
- <linearGradient
74
- id={panelId}
75
- x1={TILEPAPER_ICON_GRADIENTS.panel.x1}
76
- x2={TILEPAPER_ICON_GRADIENTS.panel.x2}
77
- y1={TILEPAPER_ICON_GRADIENTS.panel.y1}
78
- y2={TILEPAPER_ICON_GRADIENTS.panel.y2}
79
- gradientUnits="userSpaceOnUse"
80
- >
81
- <stop offset="0" stopColor="#1A2C4D" />
82
- <stop offset="0.42" stopColor="#162844" />
83
- <stop offset="1" stopColor="#111D35" />
84
- </linearGradient>
85
- <linearGradient
86
- id={blueId}
87
- x1={TILEPAPER_ICON_GRADIENTS.blue.x1}
88
- x2={TILEPAPER_ICON_GRADIENTS.blue.x2}
89
- y1={TILEPAPER_ICON_GRADIENTS.blue.y1}
90
- y2={TILEPAPER_ICON_GRADIENTS.blue.y2}
91
- gradientUnits="userSpaceOnUse"
92
- >
93
- <stop offset="0" stopColor="#5D88FF" />
94
- <stop offset="1" stopColor="#3158D6" />
95
- </linearGradient>
96
- <linearGradient
97
- id={paperId}
98
- x1={TILEPAPER_ICON_GRADIENTS.paper.x1}
99
- x2={TILEPAPER_ICON_GRADIENTS.paper.x2}
100
- y1={TILEPAPER_ICON_GRADIENTS.paper.y1}
101
- y2={TILEPAPER_ICON_GRADIENTS.paper.y2}
102
- gradientUnits="userSpaceOnUse"
103
- >
104
- <stop offset="0" stopColor="#FFF9EE" />
105
- <stop offset="1" stopColor="#DDD9D1" />
106
- </linearGradient>
107
- <linearGradient
108
- id={tealId}
109
- x1={TILEPAPER_ICON_GRADIENTS.teal.x1}
110
- x2={TILEPAPER_ICON_GRADIENTS.teal.x2}
111
- y1={TILEPAPER_ICON_GRADIENTS.teal.y1}
112
- y2={TILEPAPER_ICON_GRADIENTS.teal.y2}
113
- gradientUnits="userSpaceOnUse"
114
- >
115
- <stop offset="0" stopColor="#2FD6C1" />
116
- <stop offset="1" stopColor="#149685" />
117
- </linearGradient>
118
- <linearGradient
119
- id={violetId}
120
- x1={TILEPAPER_ICON_GRADIENTS.violet.x1}
121
- x2={TILEPAPER_ICON_GRADIENTS.violet.x2}
122
- y1={TILEPAPER_ICON_GRADIENTS.violet.y1}
123
- y2={TILEPAPER_ICON_GRADIENTS.violet.y2}
124
- gradientUnits="userSpaceOnUse"
125
- >
126
- <stop offset="0" stopColor="#8A67FF" />
127
- <stop offset="1" stopColor="#5D3AC8" />
128
- </linearGradient>
129
- </defs>
130
- <rect
131
- width={TILEPAPER_ICON_CANVAS.size}
132
- height={TILEPAPER_ICON_CANVAS.size}
133
- rx={TILEPAPER_ICON_CANVAS.rx}
134
- fill={`url(#${bgId})`}
135
- />
136
- <rect
137
- filter={compact ? undefined : `url(#${elevationId})`}
138
- fill={`url(#${panelId})`}
139
- height={TILEPAPER_ICON_ROOT_PANEL.size}
140
- rx={TILEPAPER_ICON_ROOT_PANEL.rx}
141
- width={TILEPAPER_ICON_ROOT_PANEL.size}
142
- x={TILEPAPER_ICON_ROOT_PANEL.x}
143
- y={TILEPAPER_ICON_ROOT_PANEL.y}
144
- />
145
- <rect
146
- x={TILEPAPER_ICON_TILES.blue.x}
147
- y={TILEPAPER_ICON_TILES.blue.y}
148
- width={tileSize}
149
- height={tileSize}
150
- rx={tileRx}
151
- fill={`url(#${blueId})`}
152
- />
153
- <rect
154
- x={TILEPAPER_ICON_TILES.teal.x}
155
- y={TILEPAPER_ICON_TILES.teal.y}
156
- width={tileSize}
157
- height={tileSize}
158
- rx={tileRx}
159
- fill={`url(#${tealId})`}
160
- />
161
- <rect
162
- x={TILEPAPER_ICON_TILES.violet.x}
163
- y={TILEPAPER_ICON_TILES.violet.y}
164
- width={tileSize}
165
- height={tileSize}
166
- rx={tileRx}
167
- fill={`url(#${violetId})`}
168
- />
169
- <rect
170
- x={TILEPAPER_ICON_TILES.paper.x}
171
- y={TILEPAPER_ICON_TILES.paper.y}
172
- width={tileSize}
173
- height={tileSize}
174
- rx={tileRx}
175
- fill={`url(#${paperId})`}
176
- />
177
- <path d={fold.highlight} fill="white" fillOpacity="0.92" />
178
- <path d={fold.shadow} fill="#C9C3B7" fillOpacity="0.74" />
179
- </svg>
180
- );
181
- }
@@ -1,2 +0,0 @@
1
- export { TilepaperAppIcon } from './TilepaperAppIcon';
2
- export type { TilepaperAppIconProps } from './TilepaperAppIcon';