@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.
- package/README.md +172 -0
- package/package.json +38 -21
- package/src/index.ts +74 -34
- package/src/jdw/JsonCodeEditorPane.tsx +7 -6
- package/src/jdw/builtins/renderBuiltinWidgetLeaf.tsx +1 -3
- package/src/jdw/createBuiltinJdwRegistry.ts +1 -4
- package/src/jdw/cssRenderBackend.tsx +1 -4
- package/src/jdw/fixtures/jdw-fixtures.ts +0 -15
- package/src/json-config/JsonConfigWorkbench.tsx +1 -1
- package/src/layout/index.ts +11 -2
- package/src/layout/panel/Panel.tsx +0 -3
- package/src/layout/panel/index.ts +0 -2
- package/src/layout/sidebar/SideBarTree.tsx +301 -0
- package/src/layout/sidebar/SidebarActionIconBar.tsx +3 -3
- package/src/layout/sidebar/WorkbenchSidebarActions.tsx +1 -1
- package/src/layout/sidebar/index.ts +13 -0
- package/src/modal/Modal.tsx +55 -25
- package/src/modal/ModalTitlebar.tsx +8 -8
- package/src/modal/modalPosition.ts +3 -6
- package/src/modal/useModalFocusTrap.ts +142 -0
- package/src/modal/useModalWindowFrame.ts +2 -2
- package/src/overlay/ContextMenu.tsx +133 -21
- package/src/overlay/context-menu-density.css +22 -0
- package/src/overlay/context-menu-item.ts +17 -0
- package/src/overlay/context-menu.css +6 -2
- package/src/overlay/index.ts +6 -1
- package/src/overlay/measureAnchoredOverlayPanel.ts +4 -6
- package/src/overlay/pointerPassthroughRegion.ts +17 -1
- package/src/overlay/usePointerPassthroughRegion.ts +35 -6
- package/src/primitives/absolute-box/AbsoluteBox.tsx +4 -4
- package/src/primitives/app-icon/AppIcon.tsx +33 -0
- package/src/primitives/app-icon/app-icon.css +28 -0
- package/src/primitives/button/Button.tsx +4 -4
- package/src/primitives/catalog-browse-card/CatalogBrowseCard.tsx +6 -6
- package/src/primitives/catalog-browse-pane/CatalogBrowsePane.tsx +39 -32
- package/src/primitives/catalog-browse-pane/catalog-browse-pane.css +4 -0
- package/src/primitives/catalog-filter-overlay/CatalogFilterOverlay.tsx +2 -2
- package/src/primitives/checkbox/Checkbox.tsx +1 -1
- package/src/primitives/chip/Chip.tsx +3 -12
- package/src/primitives/chip/index.ts +2 -2
- package/src/primitives/codicon/Codicon.tsx +1 -1
- package/src/primitives/file-icon/FileIcon.tsx +1 -1
- package/src/primitives/icon-button/IconButton.tsx +1 -1
- package/src/primitives/index.ts +7 -2
- package/src/primitives/library-detail-layout/LibraryDetailLayout.tsx +123 -9
- package/src/primitives/library-detail-layout/library-detail-layout.css +57 -0
- package/src/primitives/library-detail-layout/resolve-hero-cover-media.ts +80 -0
- package/src/primitives/library-facet-filter-panel/LibraryFacetFilterPanel.tsx +12 -12
- package/src/primitives/library-facet-filter-strip/LibraryFacetFilterStrip.tsx +4 -4
- package/src/primitives/number-input/NumberInput.tsx +5 -5
- package/src/primitives/primitives.css +1 -0
- package/src/primitives/record-media-hero/RecordMediaHero.tsx +10 -6
- package/src/primitives/scroll-area/ScrollArea.tsx +5 -5
- package/src/primitives/scroll-area-infinite-load/useScrollAreaInfiniteLoad.ts +5 -5
- package/src/primitives/searchable-multi-select/SearchableMultiSelect.tsx +7 -7
- package/src/primitives/select/Select.tsx +1 -13
- package/src/primitives/text-area/TextArea.tsx +1 -1
- package/src/primitives/text-input/TextInput.tsx +1 -1
- package/src/primitives/workbench-media-slot/WorkbenchMediaPlaceholder.tsx +2 -2
- package/src/primitives/workbench-media-slot/WorkbenchMediaSlot.tsx +16 -10
- package/src/primitives/workbench-thumbnail/WorkbenchThumbnail.tsx +4 -4
- package/src/scrollbars.css +2 -6
- package/src/styles/core.css +16 -0
- package/src/styles/foundation.css +4 -0
- package/src/styles/overlay.css +2 -0
- package/src/styles.css +1 -15
- package/src/utils/clamp.ts +4 -0
- package/src/utils/normalizeKeyToken.ts +13 -0
- package/src/utils/readNumber.ts +4 -0
- package/src/widget-tree/WidgetSourceEditor.tsx +0 -14
- package/src/widget-tree/WidgetTreeCanvasPreview.tsx +3 -10
- package/src/widget-tree/WidgetTreeLab.tsx +2 -23
- package/src/widget-tree/WidgetTreeSidePanel.tsx +0 -5
- package/src/widget-tree/WidgetTreeWorkspaceShell.tsx +2 -2
- package/src/widget-tree/index.ts +1 -5
- package/src/workbench/auth/WorkbenchLoginView.tsx +1 -2
- package/src/workbench/auth/auth-flows.css +14 -0
- package/src/workbench/chat/ChatCommandProposalCard.tsx +4 -4
- package/src/workbench/chat/ChatConversationBar.tsx +3 -3
- package/src/workbench/chat/ChatHistoryMenu.tsx +1 -1
- package/src/workbench/chat/ChatMessageCollapsible.tsx +4 -0
- package/src/workbench/chat/ChatMessageItem.tsx +68 -10
- package/src/workbench/chat/ChatMessageList.tsx +1 -1
- package/src/workbench/chat/ChatPanel.tsx +32 -23
- package/src/workbench/chat/ChatPhasedRunProgress.tsx +86 -13
- package/src/workbench/chat/ChatRenameDialog.tsx +1 -1
- package/src/workbench/chat/chat-conversation.css +2 -2
- package/src/workbench/chat/chat-ui.css +8 -0
- package/src/workbench/chat/chatConversation.ts +2 -2
- package/src/workbench/chat/chatMessageMeta.tsx +4 -4
- package/src/workbench/chat/index.ts +1 -0
- package/src/workbench/chat/types.ts +7 -7
- package/src/workbench/chat/useCancelRuntimeOnUnmount.ts +4 -4
- package/src/workbench/chat/useChatPrependPagination.ts +10 -10
- package/src/workbench/chat/useSlashCommandSuggest.ts +1 -1
- package/src/workbench/{WorkbenchModalPortal.tsx → chrome/WorkbenchModalPortal.tsx} +1 -1
- package/src/workbench/chrome/workbench-chrome.css +4 -0
- package/src/workbench/chrome/workbench-layout-regions.css +13 -0
- package/src/workbench/chrome/workbench-shell-titlebar.css +0 -8
- package/src/workbench/{CommandGroupShell.tsx → commands/CommandGroupShell.tsx} +2 -2
- package/src/workbench/{CommandList.tsx → commands/CommandList.tsx} +6 -5
- package/src/workbench/{CommandPalette.tsx → commands/CommandPalette.tsx} +16 -42
- package/src/workbench/{ConfirmationFlow.tsx → commands/ConfirmationFlow.tsx} +5 -5
- package/src/workbench/{ShortcutCommandBridge.tsx → commands/ShortcutCommandBridge.tsx} +17 -13
- package/src/workbench/commands/WorkbenchQuickOpen.tsx +462 -0
- package/src/workbench/{command-model.ts → commands/command-model.ts} +5 -1
- package/src/workbench/commands/command-ui.ts +3 -0
- package/src/workbench/{commands.ts → commands/commands.ts} +45 -1
- package/src/workbench/commands/createWorkspaceFilesQuickOpenProvider.ts +86 -0
- package/src/workbench/commands/quick-open-model.ts +66 -0
- package/src/workbench/{WorkbenchEditorTabs.tsx → editor/WorkbenchEditorTabs.tsx} +13 -3
- package/src/workbench/{editor-tabs-dnd.ts → editor/editor-tabs-dnd.ts} +1 -1
- package/src/workbench/{editorTabContextMenu.ts → editor/editorTabContextMenu.ts} +43 -4
- package/src/workbench/{useEditorTabsStripDnd.ts → editor/useEditorTabsStripDnd.ts} +1 -1
- package/src/workbench/{useWorkbenchEditorTabContextMenu.tsx → editor/useWorkbenchEditorTabContextMenu.tsx} +16 -2
- package/src/workbench/editor-tabs/index.ts +10 -9
- package/src/workbench/index.ts +114 -74
- package/src/workbench/management/CommandManagementSidebar.tsx +16 -30
- package/src/workbench/management/ExtensionManagementPanel.tsx +84 -46
- package/src/workbench/management/ExtensionManagementSidebar.tsx +79 -45
- package/src/workbench/management/IntegrationCommandActions.tsx +8 -1
- package/src/workbench/management/IntegrationSettingsSurface.tsx +2 -5
- package/src/workbench/management/IntegrationsShell.tsx +1 -1
- package/src/workbench/management/KeybindingCaptureField.tsx +1 -9
- package/src/workbench/management/WorkbenchDialogFrame.tsx +2 -2
- package/src/workbench/management/WorkbenchNotice.tsx +17 -12
- package/src/workbench/management/createWorkbenchNotify.tsx +88 -0
- package/src/workbench/management/extension-install-approval.ts +72 -0
- package/src/workbench/management/extension-management-filters.ts +38 -0
- package/src/workbench/management/index.ts +18 -3
- package/src/workbench/management/management.css +28 -0
- package/src/workbench/management/types.ts +23 -1
- package/src/workbench/management/useWorkbenchNotify.ts +10 -0
- package/src/workbench/{MarkdownPreview.tsx → markdown/MarkdownPreview.tsx} +22 -7
- package/src/workbench/markdown/markdownRemarkPlugins.ts +12 -0
- package/src/workbench/markdown/sanitizeMarkdownHref.ts +29 -0
- package/src/workbench/schema/workbenchDocumentRenderer.tsx +48 -121
- package/src/workbench/settings/StructuredDataForm.tsx +1 -4
- package/src/workbench/settings/StructuredDataSchemaPanel.tsx +39 -44
- package/src/workbench/settings/sectionedPanelScrollSpy.ts +0 -81
- package/src/workbench/settings/structuredDataFormModel.ts +2 -1
- package/src/workbench/settings/structuredDataSchema.ts +24 -13
- package/src/workbench/settings/structuredDataSchemaSection.ts +4 -0
- package/src/workbench/settings/structuredDataSchemaTable.ts +5 -2
- package/src/workbench/{ActivityBar.tsx → shell/ActivityBar.tsx} +8 -12
- package/src/workbench/{ArtifactShell.tsx → shell/ArtifactShell.tsx} +25 -25
- package/src/workbench/{SplitView.tsx → shell/SplitView.tsx} +3 -3
- package/src/workbench/{StatusBar.tsx → shell/StatusBar.tsx} +8 -8
- package/src/workbench/{StructuredArtifactEditor.tsx → shell/StructuredArtifactEditor.tsx} +9 -9
- package/src/workbench/{Timeline.tsx → shell/Timeline.tsx} +77 -20
- package/src/workbench/{WorkbenchCanvasShell.defaults.ts → shell/WorkbenchCanvasShell.defaults.ts} +1 -1
- package/src/workbench/{WorkbenchCanvasShell.model.ts → shell/WorkbenchCanvasShell.model.ts} +5 -5
- package/src/workbench/{WorkbenchCanvasShell.tsx → shell/WorkbenchCanvasShell.tsx} +6 -6
- package/src/workbench/{WorkbenchDesktopTitleBar.tsx → shell/WorkbenchDesktopTitleBar.tsx} +15 -15
- package/src/workbench/{WorkbenchShell.tsx → shell/WorkbenchShell.tsx} +45 -6
- package/src/workbench/{WorkbenchShellTitleBarLayoutControls.tsx → shell/WorkbenchShellTitleBarLayoutControls.tsx} +16 -19
- package/src/workbench/{WorkbenchStandaloneShell.tsx → shell/WorkbenchStandaloneShell.tsx} +15 -22
- package/src/workbench/{WorkbenchViewEditor.tsx → shell/WorkbenchViewEditor.tsx} +7 -7
- package/src/workbench/{WorkbenchViewSidebar.tsx → shell/WorkbenchViewSidebar.tsx} +7 -7
- package/src/workbench/{WorkbenchWindowChromeControls.tsx → shell/WorkbenchWindowChromeControls.tsx} +18 -15
- package/src/workbench/shell/activity-bar.css +47 -0
- package/src/workbench/{activityBarOrder.ts → shell/activityBarOrder.ts} +2 -1
- package/src/workbench/{shell.ts → shell/shell.ts} +20 -13
- package/src/workbench/{shellViewModel.ts → shell/shellViewModel.ts} +3 -3
- package/src/workbench/{standalone.ts → shell/standalone.ts} +14 -2
- package/src/workbench/{useDeferredWorkbenchMount.ts → shell/useDeferredWorkbenchMount.ts} +3 -3
- package/src/workbench/{useWorkbenchAppearanceDocumentSync.tsx → shell/useWorkbenchAppearanceDocumentSync.tsx} +1 -1
- package/src/workbench/{useWorkbenchSidebarActionBarDnd.ts → shell/useWorkbenchSidebarActionBarDnd.ts} +1 -1
- package/src/workbench/{useWorkbenchSidebarViewPlacementDropZone.ts → shell/useWorkbenchSidebarViewPlacementDropZone.ts} +2 -2
- package/src/workbench/{workbenchSidebarLayoutContext.ts → shell/workbenchSidebarLayoutContext.ts} +0 -6
- package/src/workbench/{workbenchViewRouteState.ts → shell/workbenchViewRouteState.ts} +4 -4
- package/src/workbench/{WorkbenchThemeProvider.tsx → theme/WorkbenchThemeProvider.tsx} +4 -4
- package/src/workbench/{theme.ts → theme/theme.ts} +1 -1
- package/src/workbench/{themePresets.ts → theme/themePresets.ts} +39 -64
- package/src/workbench/views/command-list-density.css +36 -0
- package/src/workbench/views/command-list.css +2 -0
- package/src/workbench/views/extensions-sidebar.css +2 -0
- package/src/workbench/views/view-hosts.css +3 -3
- package/src/workbench/workspace/WorkspaceEditorPanel.tsx +1 -1
- package/src/workbench/workspace/WorkspaceExplorer.tsx +105 -4
- package/src/workbench/workspace/createVirtualWorkspaceExplorerPort.ts +1 -14
- package/src/workbench/workspace/workspaceExplorerKeyboard.ts +109 -0
- package/src/workbench/workspace/workspaceJsonDiagnostics.ts +6 -5
- package/src/workbench-menu-surfaces.css +3 -57
- package/src/brand/TilepaperAppIcon.tsx +0 -181
- package/src/brand/index.ts +0 -2
- package/src/brand/tilepaper-app-icon-geometry.ts +0 -201
- package/src/primitives/absolute-box/index.ts +0 -1
- package/src/primitives/catalog-browse-card/index.ts +0 -1
- package/src/primitives/catalog-browse-pane/index.ts +0 -3
- package/src/primitives/catalog-filter-overlay/index.ts +0 -1
- package/src/primitives/codicon/index.ts +0 -1
- package/src/primitives/external-link-button/index.ts +0 -1
- package/src/primitives/library-detail-layout/index.ts +0 -1
- package/src/primitives/library-facet-filter-panel/index.ts +0 -1
- package/src/primitives/library-facet-filter-strip/index.ts +0 -1
- package/src/primitives/panel-loading/index.ts +0 -1
- package/src/primitives/scroll-area-infinite-load/index.ts +0 -2
- package/src/primitives/workbench-thumbnail/index.ts +0 -1
- package/src/test-utils/workbenchMonacoMock.tsx +0 -37
- package/src/workbench/jdw/jdw-editors.css +0 -4
- package/src/workbench/jdw/jdw.css +0 -2
- package/src/workbench/management/integration-command-action.ts +0 -25
- package/src/workbench/markdownRemarkPlugins.ts +0 -4
- package/src/workbench/workbench-chrome.css +0 -4
- /package/src/workbench/{WorkbenchPlatformContext.tsx → chrome/WorkbenchPlatformContext.tsx} +0 -0
- /package/src/workbench/{workbenchModalViewState.ts → chrome/workbenchModalViewState.ts} +0 -0
- /package/src/workbench/{workbenchOverlaysContext.tsx → chrome/workbenchOverlaysContext.tsx} +0 -0
- /package/src/workbench/{workbenchPlatformChrome.ts → chrome/workbenchPlatformChrome.ts} +0 -0
- /package/src/workbench/{command-execution-policy.ts → commands/command-execution-policy.ts} +0 -0
- /package/src/workbench/{keyboard.ts → commands/keyboard.ts} +0 -0
- /package/src/workbench/{workbenchContextMenu.ts → commands/workbenchContextMenu.ts} +0 -0
- /package/src/workbench/{appearanceLabels.ts → shell/appearanceLabels.ts} +0 -0
- /package/src/workbench/{hardReset.ts → shell/hardReset.ts} +0 -0
- /package/src/workbench/{shellPresets.ts → shell/shellPresets.ts} +0 -0
- /package/src/workbench/{shellState.ts → shell/shellState.ts} +0 -0
- /package/src/workbench/{sidebarViewPlacementDnd.ts → shell/sidebarViewPlacementDnd.ts} +0 -0
- /package/src/workbench/{status.ts → shell/status.ts} +0 -0
- /package/src/workbench/{useWorkbenchSidebarLayout.tsx → shell/useWorkbenchSidebarLayout.tsx} +0 -0
- /package/src/workbench/{useWorkbenchStandaloneShellStateSync.tsx → shell/useWorkbenchStandaloneShellStateSync.tsx} +0 -0
- /package/src/workbench/{workbenchStandaloneShellReactContext.tsx → shell/workbenchStandaloneShellReactContext.tsx} +0 -0
|
@@ -9,7 +9,7 @@ import { IconButton } from '../primitives/icon-button';
|
|
|
9
9
|
import { Toolbar } from '../primitives/toolbar';
|
|
10
10
|
import { JsonCodeEditorPane, JsonConfigValidationBanner } from '../jdw/JsonCodeEditorPane.js';
|
|
11
11
|
import { JdwPreview } from '../jdw/JdwPreview.js';
|
|
12
|
-
import { SplitView } from '../workbench/SplitView';
|
|
12
|
+
import { SplitView } from '../workbench/shell/SplitView';
|
|
13
13
|
import { WorkbenchStructuredDataSchemaPanel } from '../workbench/settings/StructuredDataSchemaPanel';
|
|
14
14
|
import { type WorkbenchStructuredDataSchemaDocument } from '../workbench/settings/StructuredDataForm';
|
|
15
15
|
import { type WorkspaceEditorTheme } from '../workbench/workspace/WorkspaceEditor';
|
package/src/layout/index.ts
CHANGED
|
@@ -2,7 +2,6 @@ export {
|
|
|
2
2
|
FilterBar,
|
|
3
3
|
FilterBarActiveChips,
|
|
4
4
|
FilterBarRow,
|
|
5
|
-
FilterChip,
|
|
6
5
|
HelpText,
|
|
7
6
|
Panel,
|
|
8
7
|
PanelBody,
|
|
@@ -19,7 +18,6 @@ export type {
|
|
|
19
18
|
FilterBarActiveChipsProps,
|
|
20
19
|
FilterBarProps,
|
|
21
20
|
FilterBarRowProps,
|
|
22
|
-
FilterChipProps,
|
|
23
21
|
HelpTextProps,
|
|
24
22
|
PanelBodyProps,
|
|
25
23
|
PanelFooterProps,
|
|
@@ -56,6 +54,7 @@ export {
|
|
|
56
54
|
SideBarListItem,
|
|
57
55
|
SideBarRow,
|
|
58
56
|
SideBarScrollSpacer,
|
|
57
|
+
SideBarTree,
|
|
59
58
|
SideBarViewFrame,
|
|
60
59
|
SideBarViewTabStrip,
|
|
61
60
|
SideBarViewTitleMenu,
|
|
@@ -68,7 +67,11 @@ export {
|
|
|
68
67
|
WorkbenchSidebarSection,
|
|
69
68
|
WorkbenchSidebarSectionHeader,
|
|
70
69
|
WorkbenchSidebarSectionStack,
|
|
70
|
+
flattenVisibleSideBarTreeItems,
|
|
71
|
+
isSideBarTreeBranch,
|
|
72
|
+
selectSideBarTreeIds,
|
|
71
73
|
sideBarTreeDepthStyle,
|
|
74
|
+
toggleSideBarTreeId,
|
|
72
75
|
useSidebarSectionBaseDepth,
|
|
73
76
|
} from './sidebar';
|
|
74
77
|
export type {
|
|
@@ -77,6 +80,10 @@ export type {
|
|
|
77
80
|
SideBarListProps,
|
|
78
81
|
SideBarRowProps,
|
|
79
82
|
SideBarScrollSpacerProps,
|
|
83
|
+
SideBarTreeItem,
|
|
84
|
+
SideBarTreeProps,
|
|
85
|
+
SideBarTreeSelectionMode,
|
|
86
|
+
SideBarTreeVisibleNode,
|
|
80
87
|
SideBarViewFrameProps,
|
|
81
88
|
SideBarViewTabDescriptor,
|
|
82
89
|
SideBarViewTabStripProps,
|
|
@@ -142,6 +149,8 @@ export type {
|
|
|
142
149
|
} from './propertyFieldFilter';
|
|
143
150
|
export { WorkbenchMediaPreviewViewport } from './WorkbenchMediaPreviewViewport';
|
|
144
151
|
export type { WorkbenchMediaPreviewViewportProps } from './WorkbenchMediaPreviewViewport';
|
|
152
|
+
export { WorkbenchPreviewCanvas } from './WorkbenchCanvas';
|
|
153
|
+
export type { WorkbenchPreviewCanvasProps } from './WorkbenchCanvas';
|
|
145
154
|
export {
|
|
146
155
|
clampPreviewViewportZoom,
|
|
147
156
|
computePreviewViewportFitScale,
|
|
@@ -71,9 +71,6 @@ export function FilterBarRow({ className, ...props }: FilterBarRowProps) {
|
|
|
71
71
|
return <div className={cx('ui-filter-bar__row', className)} {...props} />;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
/** @deprecated Use `Chip` / `ChipProps` from `@workbench-kit/react` primitives. */
|
|
75
|
-
export { FilterChip, type FilterChipProps } from '../../primitives/chip';
|
|
76
|
-
|
|
77
74
|
export interface FilterBarActiveChipsProps extends ComponentPropsWithRef<'div'> {
|
|
78
75
|
clearAllLabel?: string | undefined;
|
|
79
76
|
onClearAll?: (() => void) | undefined;
|
|
@@ -2,7 +2,6 @@ export {
|
|
|
2
2
|
FilterBar,
|
|
3
3
|
FilterBarActiveChips,
|
|
4
4
|
FilterBarRow,
|
|
5
|
-
FilterChip,
|
|
6
5
|
HelpText,
|
|
7
6
|
Panel,
|
|
8
7
|
PanelBody,
|
|
@@ -19,7 +18,6 @@ export type {
|
|
|
19
18
|
FilterBarActiveChipsProps,
|
|
20
19
|
FilterBarProps,
|
|
21
20
|
FilterBarRowProps,
|
|
22
|
-
FilterChipProps,
|
|
23
21
|
HelpTextProps,
|
|
24
22
|
PanelBodyProps,
|
|
25
23
|
PanelFooterProps,
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useCallback,
|
|
3
|
+
useMemo,
|
|
4
|
+
useState,
|
|
5
|
+
type KeyboardEvent,
|
|
6
|
+
type MouseEvent,
|
|
7
|
+
type ReactNode,
|
|
8
|
+
} from 'react';
|
|
9
|
+
import { cxCodicon } from '../../utils/codicon';
|
|
10
|
+
import { cx } from '../../utils/cx';
|
|
11
|
+
import { SideBarList, SideBarListItem } from './SideBarViewFrame';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Controlled sidebar tree for library / provider category rows.
|
|
15
|
+
*
|
|
16
|
+
* Branch vs leaf: items with `children` (even empty) render as expandable branches;
|
|
17
|
+
* items without `children` are leaves. Hosts own expand/selection sets.
|
|
18
|
+
*
|
|
19
|
+
* Keyboard (default on): ArrowUp/Down move focus+selection (single mode) or focus
|
|
20
|
+
* (multi mode); ArrowRight expands / moves into first child; ArrowLeft collapses /
|
|
21
|
+
* moves to parent; Enter/Space activates selection. Virtualization and DnD are
|
|
22
|
+
* out of scope for v1.
|
|
23
|
+
*/
|
|
24
|
+
export interface SideBarTreeItem {
|
|
25
|
+
readonly id: string;
|
|
26
|
+
readonly label: ReactNode;
|
|
27
|
+
readonly children?: readonly SideBarTreeItem[];
|
|
28
|
+
readonly disabled?: boolean;
|
|
29
|
+
readonly icon?: ReactNode;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type SideBarTreeSelectionMode = 'single' | 'multi';
|
|
33
|
+
|
|
34
|
+
export interface SideBarTreeProps {
|
|
35
|
+
readonly items: readonly SideBarTreeItem[];
|
|
36
|
+
readonly expandedIds: ReadonlySet<string>;
|
|
37
|
+
readonly selectedIds: ReadonlySet<string>;
|
|
38
|
+
readonly onExpandedIdsChange: (next: Set<string>) => void;
|
|
39
|
+
readonly onSelectedIdsChange: (next: Set<string>) => void;
|
|
40
|
+
readonly selectionMode?: SideBarTreeSelectionMode;
|
|
41
|
+
/** When false, arrow / activation keys are not handled. Default true. */
|
|
42
|
+
readonly keyboardNavigation?: boolean;
|
|
43
|
+
readonly 'aria-label'?: string;
|
|
44
|
+
readonly className?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface SideBarTreeVisibleNode {
|
|
48
|
+
readonly depth: number;
|
|
49
|
+
readonly item: SideBarTreeItem;
|
|
50
|
+
readonly parentId: string | null;
|
|
51
|
+
readonly hasChildren: boolean;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function isSideBarTreeBranch(item: SideBarTreeItem): boolean {
|
|
55
|
+
return item.children !== undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function flattenVisibleSideBarTreeItems(
|
|
59
|
+
items: readonly SideBarTreeItem[],
|
|
60
|
+
expandedIds: ReadonlySet<string>,
|
|
61
|
+
depth = 0,
|
|
62
|
+
parentId: string | null = null,
|
|
63
|
+
): SideBarTreeVisibleNode[] {
|
|
64
|
+
const rows: SideBarTreeVisibleNode[] = [];
|
|
65
|
+
|
|
66
|
+
for (const item of items) {
|
|
67
|
+
const hasChildren = isSideBarTreeBranch(item);
|
|
68
|
+
rows.push({ depth, item, parentId, hasChildren });
|
|
69
|
+
|
|
70
|
+
if (hasChildren && expandedIds.has(item.id) && item.children) {
|
|
71
|
+
rows.push(...flattenVisibleSideBarTreeItems(item.children, expandedIds, depth + 1, item.id));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return rows;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function toggleSideBarTreeId(ids: ReadonlySet<string>, id: string): Set<string> {
|
|
79
|
+
const next = new Set(ids);
|
|
80
|
+
if (next.has(id)) {
|
|
81
|
+
next.delete(id);
|
|
82
|
+
} else {
|
|
83
|
+
next.add(id);
|
|
84
|
+
}
|
|
85
|
+
return next;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function selectSideBarTreeIds(
|
|
89
|
+
current: ReadonlySet<string>,
|
|
90
|
+
id: string,
|
|
91
|
+
mode: SideBarTreeSelectionMode,
|
|
92
|
+
additive: boolean,
|
|
93
|
+
): Set<string> {
|
|
94
|
+
if (mode === 'single' || !additive) {
|
|
95
|
+
return new Set([id]);
|
|
96
|
+
}
|
|
97
|
+
return toggleSideBarTreeId(current, id);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function SideBarTree({
|
|
101
|
+
items,
|
|
102
|
+
expandedIds,
|
|
103
|
+
selectedIds,
|
|
104
|
+
onExpandedIdsChange,
|
|
105
|
+
onSelectedIdsChange,
|
|
106
|
+
selectionMode = 'single',
|
|
107
|
+
keyboardNavigation = true,
|
|
108
|
+
'aria-label': ariaLabel = 'Sidebar tree',
|
|
109
|
+
className,
|
|
110
|
+
}: SideBarTreeProps) {
|
|
111
|
+
const visibleNodes = useMemo(
|
|
112
|
+
() => flattenVisibleSideBarTreeItems(items, expandedIds),
|
|
113
|
+
[expandedIds, items],
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const [focusedId, setFocusedId] = useState<string | null>(null);
|
|
117
|
+
|
|
118
|
+
const focusIndex = useMemo(() => {
|
|
119
|
+
if (focusedId == null) {
|
|
120
|
+
return visibleNodes.length > 0 ? 0 : -1;
|
|
121
|
+
}
|
|
122
|
+
const index = visibleNodes.findIndex((node) => node.item.id === focusedId);
|
|
123
|
+
return index >= 0 ? index : visibleNodes.length > 0 ? 0 : -1;
|
|
124
|
+
}, [focusedId, visibleNodes]);
|
|
125
|
+
|
|
126
|
+
const toggleExpanded = useCallback(
|
|
127
|
+
(id: string) => {
|
|
128
|
+
onExpandedIdsChange(toggleSideBarTreeId(expandedIds, id));
|
|
129
|
+
},
|
|
130
|
+
[expandedIds, onExpandedIdsChange],
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const selectItem = useCallback(
|
|
134
|
+
(id: string, additive: boolean) => {
|
|
135
|
+
onSelectedIdsChange(selectSideBarTreeIds(selectedIds, id, selectionMode, additive));
|
|
136
|
+
setFocusedId(id);
|
|
137
|
+
},
|
|
138
|
+
[onSelectedIdsChange, selectedIds, selectionMode],
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
const handleItemClick = useCallback(
|
|
142
|
+
(event: MouseEvent<HTMLButtonElement>, node: SideBarTreeVisibleNode) => {
|
|
143
|
+
if (node.item.disabled) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const additive = selectionMode === 'multi' && (event.metaKey || event.ctrlKey);
|
|
148
|
+
selectItem(node.item.id, additive);
|
|
149
|
+
|
|
150
|
+
if (node.hasChildren && !additive) {
|
|
151
|
+
toggleExpanded(node.item.id);
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
[selectItem, selectionMode, toggleExpanded],
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const handleKeyDown = useCallback(
|
|
158
|
+
(event: KeyboardEvent<HTMLUListElement>) => {
|
|
159
|
+
if (!keyboardNavigation || visibleNodes.length === 0 || focusIndex < 0) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const current = visibleNodes[focusIndex];
|
|
164
|
+
if (!current) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (event.key === 'ArrowDown') {
|
|
169
|
+
event.preventDefault();
|
|
170
|
+
const next = visibleNodes[Math.min(visibleNodes.length - 1, focusIndex + 1)];
|
|
171
|
+
if (!next || next.item.disabled) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
setFocusedId(next.item.id);
|
|
175
|
+
if (selectionMode === 'single') {
|
|
176
|
+
onSelectedIdsChange(new Set([next.item.id]));
|
|
177
|
+
}
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (event.key === 'ArrowUp') {
|
|
182
|
+
event.preventDefault();
|
|
183
|
+
const next = visibleNodes[Math.max(0, focusIndex - 1)];
|
|
184
|
+
if (!next || next.item.disabled) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
setFocusedId(next.item.id);
|
|
188
|
+
if (selectionMode === 'single') {
|
|
189
|
+
onSelectedIdsChange(new Set([next.item.id]));
|
|
190
|
+
}
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (event.key === 'ArrowRight') {
|
|
195
|
+
event.preventDefault();
|
|
196
|
+
if (!current.hasChildren || current.item.disabled) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (!expandedIds.has(current.item.id)) {
|
|
200
|
+
toggleExpanded(current.item.id);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const firstChild = current.item.children?.[0];
|
|
204
|
+
if (firstChild && !firstChild.disabled) {
|
|
205
|
+
setFocusedId(firstChild.id);
|
|
206
|
+
if (selectionMode === 'single') {
|
|
207
|
+
onSelectedIdsChange(new Set([firstChild.id]));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (event.key === 'ArrowLeft') {
|
|
214
|
+
event.preventDefault();
|
|
215
|
+
if (current.hasChildren && expandedIds.has(current.item.id)) {
|
|
216
|
+
toggleExpanded(current.item.id);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
if (current.parentId) {
|
|
220
|
+
setFocusedId(current.parentId);
|
|
221
|
+
if (selectionMode === 'single') {
|
|
222
|
+
onSelectedIdsChange(new Set([current.parentId]));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
229
|
+
event.preventDefault();
|
|
230
|
+
if (current.item.disabled) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
selectItem(current.item.id, selectionMode === 'multi' && (event.metaKey || event.ctrlKey));
|
|
234
|
+
if (current.hasChildren && selectionMode === 'single') {
|
|
235
|
+
toggleExpanded(current.item.id);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
[
|
|
240
|
+
expandedIds,
|
|
241
|
+
focusIndex,
|
|
242
|
+
keyboardNavigation,
|
|
243
|
+
onSelectedIdsChange,
|
|
244
|
+
selectItem,
|
|
245
|
+
selectionMode,
|
|
246
|
+
toggleExpanded,
|
|
247
|
+
visibleNodes,
|
|
248
|
+
],
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
return (
|
|
252
|
+
<SideBarList
|
|
253
|
+
aria-label={ariaLabel}
|
|
254
|
+
className={cx('ui-sidebar-tree', className)}
|
|
255
|
+
fill
|
|
256
|
+
role="tree"
|
|
257
|
+
onKeyDown={handleKeyDown}
|
|
258
|
+
>
|
|
259
|
+
{visibleNodes.map((node, index) => {
|
|
260
|
+
const { item, depth, hasChildren } = node;
|
|
261
|
+
const expanded = hasChildren && expandedIds.has(item.id);
|
|
262
|
+
const selected = selectedIds.has(item.id);
|
|
263
|
+
const focused = focusIndex === index;
|
|
264
|
+
|
|
265
|
+
return (
|
|
266
|
+
<SideBarListItem
|
|
267
|
+
key={item.id}
|
|
268
|
+
depth={depth}
|
|
269
|
+
disabled={item.disabled}
|
|
270
|
+
selected={selected}
|
|
271
|
+
tabIndex={focused ? 0 : -1}
|
|
272
|
+
wrapperProps={{
|
|
273
|
+
role: 'treeitem',
|
|
274
|
+
'aria-level': depth + 1,
|
|
275
|
+
'aria-selected': selected,
|
|
276
|
+
...(hasChildren ? { 'aria-expanded': expanded } : {}),
|
|
277
|
+
}}
|
|
278
|
+
onClick={(event) => handleItemClick(event, node)}
|
|
279
|
+
onFocus={() => setFocusedId(item.id)}
|
|
280
|
+
>
|
|
281
|
+
<span className="workbench-tree-prefix">
|
|
282
|
+
{hasChildren ? (
|
|
283
|
+
<i
|
|
284
|
+
aria-hidden="true"
|
|
285
|
+
className={cxCodicon(
|
|
286
|
+
expanded ? 'chevron-down' : 'chevron-right',
|
|
287
|
+
'workbench-tree-chevron',
|
|
288
|
+
)}
|
|
289
|
+
/>
|
|
290
|
+
) : (
|
|
291
|
+
<span className="workbench-tree-spacer" />
|
|
292
|
+
)}
|
|
293
|
+
{item.icon}
|
|
294
|
+
</span>
|
|
295
|
+
<span className="workbench-tree-label">{item.label}</span>
|
|
296
|
+
</SideBarListItem>
|
|
297
|
+
);
|
|
298
|
+
})}
|
|
299
|
+
</SideBarList>
|
|
300
|
+
);
|
|
301
|
+
}
|
|
@@ -12,14 +12,14 @@ import { IconButton } from '../../primitives/icon-button';
|
|
|
12
12
|
|
|
13
13
|
import { cx } from '../../utils/cx';
|
|
14
14
|
|
|
15
|
-
import { type ActivityBarOrientation } from '../../workbench/activityBarOrder';
|
|
15
|
+
import { type ActivityBarOrientation } from '../../workbench/shell/activityBarOrder';
|
|
16
16
|
|
|
17
17
|
import {
|
|
18
18
|
mergeWorkbenchSidebarViewPlacementDropZoneProps,
|
|
19
19
|
useWorkbenchSidebarViewPlacementDropZone,
|
|
20
|
-
} from '../../workbench/useWorkbenchSidebarViewPlacementDropZone';
|
|
20
|
+
} from '../../workbench/shell/useWorkbenchSidebarViewPlacementDropZone';
|
|
21
21
|
|
|
22
|
-
import { useWorkbenchSidebarActionBarDnd } from '../../workbench/useWorkbenchSidebarActionBarDnd';
|
|
22
|
+
import { useWorkbenchSidebarActionBarDnd } from '../../workbench/shell/useWorkbenchSidebarActionBarDnd';
|
|
23
23
|
|
|
24
24
|
import { SidebarToolbar } from './SidebarToolbar';
|
|
25
25
|
|
|
@@ -17,6 +17,19 @@ export type {
|
|
|
17
17
|
SideBarScrollSpacerProps,
|
|
18
18
|
SideBarViewFrameProps,
|
|
19
19
|
} from './SideBarViewFrame';
|
|
20
|
+
export {
|
|
21
|
+
SideBarTree,
|
|
22
|
+
flattenVisibleSideBarTreeItems,
|
|
23
|
+
isSideBarTreeBranch,
|
|
24
|
+
selectSideBarTreeIds,
|
|
25
|
+
toggleSideBarTreeId,
|
|
26
|
+
} from './SideBarTree';
|
|
27
|
+
export type {
|
|
28
|
+
SideBarTreeItem,
|
|
29
|
+
SideBarTreeProps,
|
|
30
|
+
SideBarTreeSelectionMode,
|
|
31
|
+
SideBarTreeVisibleNode,
|
|
32
|
+
} from './SideBarTree';
|
|
20
33
|
export { SidebarActionIconBar } from './SidebarActionIconBar';
|
|
21
34
|
export { SidebarSlotChrome } from './SidebarSlotChrome';
|
|
22
35
|
export type { SidebarSlotChromeProps } from './SidebarSlotChrome';
|
package/src/modal/Modal.tsx
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
|
+
useCallback,
|
|
2
3
|
useId,
|
|
4
|
+
useRef,
|
|
3
5
|
type CSSProperties,
|
|
4
6
|
type FormEventHandler,
|
|
5
7
|
type MouseEvent,
|
|
6
8
|
type ReactNode,
|
|
9
|
+
type RefObject,
|
|
7
10
|
} from 'react';
|
|
8
11
|
import { cx } from '../utils/cx';
|
|
9
12
|
import { ModalResizeHandles } from './ModalResizeHandles';
|
|
10
13
|
import { ModalTitlebar } from './ModalTitlebar';
|
|
14
|
+
import { useModalFocusTrap } from './useModalFocusTrap';
|
|
11
15
|
import { useModalWindowFrame } from './useModalWindowFrame';
|
|
12
16
|
import {
|
|
13
17
|
resolveWorkbenchWindowChromeDataAttributes,
|
|
14
18
|
type WorkbenchWindowChromeMode,
|
|
15
|
-
} from '../workbench/workbenchPlatformChrome';
|
|
19
|
+
} from '../workbench/chrome/workbenchPlatformChrome';
|
|
16
20
|
|
|
17
21
|
export type { ModalBounds, ModalPosition, ModalSize } from './modalTypes';
|
|
18
22
|
|
|
@@ -20,44 +24,50 @@ export type ModalBodyLayout = 'block' | 'stack';
|
|
|
20
24
|
export type ModalBodyPadding = 'none' | 'md' | 'lg';
|
|
21
25
|
|
|
22
26
|
export interface ModalProps {
|
|
23
|
-
chrome?: WorkbenchWindowChromeMode
|
|
27
|
+
chrome?: WorkbenchWindowChromeMode;
|
|
24
28
|
title: ReactNode;
|
|
25
|
-
titleSuffix?: ReactNode
|
|
29
|
+
titleSuffix?: ReactNode;
|
|
26
30
|
children: ReactNode;
|
|
27
|
-
footer?: ReactNode
|
|
28
|
-
className?: string
|
|
29
|
-
bodyClassName?: string
|
|
30
|
-
bodyLayout?: ModalBodyLayout
|
|
31
|
-
bodyPadding?: ModalBodyPadding
|
|
32
|
-
bodyScroll?: 'auto' | 'hidden'
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
31
|
+
footer?: ReactNode;
|
|
32
|
+
className?: string;
|
|
33
|
+
bodyClassName?: string;
|
|
34
|
+
bodyLayout?: ModalBodyLayout;
|
|
35
|
+
bodyPadding?: ModalBodyPadding;
|
|
36
|
+
bodyScroll?: 'auto' | 'hidden';
|
|
37
|
+
/** When true (default), Escape calls `onClose`. */
|
|
38
|
+
closeOnEscape?: boolean;
|
|
39
|
+
closeLabel?: string;
|
|
40
|
+
defaultHeight?: number;
|
|
41
|
+
defaultMaximized?: boolean;
|
|
42
|
+
defaultWidth?: number;
|
|
43
|
+
/** Optional element to focus when the modal mounts (must be inside the dialog). */
|
|
44
|
+
initialFocusRef?: RefObject<HTMLElement | null>;
|
|
45
|
+
labelledBy?: string;
|
|
46
|
+
maximizeLabel?: string;
|
|
47
|
+
minHeight?: number;
|
|
48
|
+
minWidth?: number;
|
|
41
49
|
onClose: () => void;
|
|
42
|
-
onSubmit?: FormEventHandler<HTMLFormElement
|
|
43
|
-
|
|
50
|
+
onSubmit?: FormEventHandler<HTMLFormElement>;
|
|
51
|
+
/** When true (default), restore focus to the previously focused element on unmount. */
|
|
52
|
+
restoreFocusOnClose?: boolean;
|
|
53
|
+
restoreLabel?: string;
|
|
44
54
|
}
|
|
45
55
|
|
|
46
56
|
interface ModalFrameProps {
|
|
47
|
-
bodyClassName?: string
|
|
57
|
+
bodyClassName?: string;
|
|
48
58
|
bodyLayout: ModalBodyLayout;
|
|
49
59
|
bodyPadding: ModalBodyPadding;
|
|
50
60
|
bodyScroll: 'auto' | 'hidden';
|
|
51
61
|
children: ReactNode;
|
|
52
62
|
dataAttrs: Record<string, string | undefined>;
|
|
53
|
-
footer?: ReactNode
|
|
63
|
+
footer?: ReactNode;
|
|
54
64
|
frameRef: (node: HTMLDivElement | HTMLFormElement | null) => void;
|
|
55
65
|
modalClassName: string;
|
|
56
66
|
resolvedLabelledBy: string;
|
|
57
|
-
resizeHandles?: ReactNode
|
|
58
|
-
style?: CSSProperties
|
|
67
|
+
resizeHandles?: ReactNode;
|
|
68
|
+
style?: CSSProperties;
|
|
59
69
|
titlebar: ReactNode;
|
|
60
|
-
onSubmit?: FormEventHandler<HTMLFormElement
|
|
70
|
+
onSubmit?: FormEventHandler<HTMLFormElement>;
|
|
61
71
|
}
|
|
62
72
|
|
|
63
73
|
function ModalFrame({
|
|
@@ -133,22 +143,26 @@ export function Modal({
|
|
|
133
143
|
bodyLayout = 'block',
|
|
134
144
|
bodyPadding = 'none',
|
|
135
145
|
bodyScroll = 'hidden',
|
|
146
|
+
closeOnEscape = true,
|
|
136
147
|
closeLabel,
|
|
137
148
|
defaultHeight,
|
|
138
149
|
defaultMaximized = false,
|
|
139
150
|
defaultWidth,
|
|
151
|
+
initialFocusRef,
|
|
140
152
|
labelledBy,
|
|
141
153
|
maximizeLabel,
|
|
142
154
|
minHeight = 200,
|
|
143
155
|
minWidth = 320,
|
|
144
156
|
onClose,
|
|
145
157
|
onSubmit,
|
|
158
|
+
restoreFocusOnClose = true,
|
|
146
159
|
restoreLabel,
|
|
147
160
|
}: ModalProps) {
|
|
148
161
|
const modalClassName = cx('ui-modal', className);
|
|
149
162
|
const chromeAttributes = resolveWorkbenchWindowChromeDataAttributes(chrome);
|
|
150
163
|
const generatedLabelId = useId();
|
|
151
164
|
const resolvedLabelledBy = labelledBy ?? generatedLabelId;
|
|
165
|
+
const dialogRef = useRef<HTMLElement | null>(null);
|
|
152
166
|
|
|
153
167
|
const {
|
|
154
168
|
assignFrameRef,
|
|
@@ -167,6 +181,22 @@ export function Modal({
|
|
|
167
181
|
minWidth,
|
|
168
182
|
});
|
|
169
183
|
|
|
184
|
+
const setFrameRef = useCallback(
|
|
185
|
+
(node: HTMLDivElement | HTMLFormElement | null) => {
|
|
186
|
+
dialogRef.current = node;
|
|
187
|
+
assignFrameRef(node);
|
|
188
|
+
},
|
|
189
|
+
[assignFrameRef],
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
useModalFocusTrap({
|
|
193
|
+
closeOnEscape,
|
|
194
|
+
containerRef: dialogRef,
|
|
195
|
+
initialFocusRef,
|
|
196
|
+
onClose,
|
|
197
|
+
restoreFocusOnClose,
|
|
198
|
+
});
|
|
199
|
+
|
|
170
200
|
const isPositioned = bounds !== null || maximized;
|
|
171
201
|
|
|
172
202
|
return (
|
|
@@ -183,7 +213,7 @@ export function Modal({
|
|
|
183
213
|
...(chromeAttributes ?? {}),
|
|
184
214
|
}}
|
|
185
215
|
footer={footer}
|
|
186
|
-
frameRef={
|
|
216
|
+
frameRef={setFrameRef}
|
|
187
217
|
modalClassName={modalClassName}
|
|
188
218
|
resolvedLabelledBy={resolvedLabelledBy}
|
|
189
219
|
resizeHandles={maximized ? null : <ModalResizeHandles onResizeStart={handleResizeStart} />}
|
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
import type { PointerEvent as ReactPointerEvent, ReactNode } from 'react';
|
|
2
2
|
|
|
3
|
-
import { useWorkbenchHostPlatform } from '../workbench/WorkbenchPlatformContext';
|
|
3
|
+
import { useWorkbenchHostPlatform } from '../workbench/chrome/WorkbenchPlatformContext';
|
|
4
4
|
import {
|
|
5
5
|
shouldUseDarwinPlatformChrome,
|
|
6
6
|
WorkbenchWindowChromeControls,
|
|
7
|
-
} from '../workbench/WorkbenchWindowChromeControls';
|
|
7
|
+
} from '../workbench/shell/WorkbenchWindowChromeControls';
|
|
8
8
|
import {
|
|
9
9
|
resolveWorkbenchWindowChromeDataAttributes,
|
|
10
10
|
type WorkbenchWindowChromeMode,
|
|
11
|
-
} from '../workbench/workbenchPlatformChrome';
|
|
11
|
+
} from '../workbench/chrome/workbenchPlatformChrome';
|
|
12
12
|
|
|
13
13
|
export interface ModalTitlebarProps {
|
|
14
|
-
chrome?: WorkbenchWindowChromeMode
|
|
15
|
-
closeLabel?: string
|
|
14
|
+
chrome?: WorkbenchWindowChromeMode;
|
|
15
|
+
closeLabel?: string;
|
|
16
16
|
labelledBy: string;
|
|
17
17
|
maximized: boolean;
|
|
18
|
-
maximizeLabel?: string
|
|
18
|
+
maximizeLabel?: string;
|
|
19
19
|
onClose: () => void;
|
|
20
20
|
onDoubleClick: () => void;
|
|
21
21
|
onPointerDown: (event: ReactPointerEvent<HTMLDivElement>) => void;
|
|
22
22
|
onToggleMaximized: () => void;
|
|
23
|
-
restoreLabel?: string
|
|
23
|
+
restoreLabel?: string;
|
|
24
24
|
title: ReactNode;
|
|
25
|
-
titleSuffix?: ReactNode
|
|
25
|
+
titleSuffix?: ReactNode;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export function ModalTitlebar({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { clampNumber } from '../utils/clamp';
|
|
1
2
|
import type { ModalBounds, ModalPosition, ModalSize } from './modalTypes';
|
|
2
3
|
import type { ModalContainerBounds } from './modalContainer';
|
|
3
4
|
import { readWindowViewportBounds } from './modalContainer';
|
|
@@ -17,9 +18,9 @@ export function clampModalDragPosition(
|
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
const maxX = Math.max(0, viewport.width - size.width);
|
|
20
|
-
const x =
|
|
21
|
+
const x = clampNumber(nextPosition.x, 0, maxX);
|
|
21
22
|
const maxY = size.height >= viewport.height ? 0 : Math.max(0, viewport.height - size.height);
|
|
22
|
-
const y =
|
|
23
|
+
const y = clampNumber(nextPosition.y, 0, maxY);
|
|
23
24
|
|
|
24
25
|
return { x, y };
|
|
25
26
|
}
|
|
@@ -30,7 +31,3 @@ export function clampModalBoundsPosition(
|
|
|
30
31
|
): ModalBounds {
|
|
31
32
|
return { ...bounds, ...clampModalDragPosition(bounds, bounds, viewport) };
|
|
32
33
|
}
|
|
33
|
-
|
|
34
|
-
function clamp(value: number, min: number, max: number): number {
|
|
35
|
-
return Math.min(Math.max(value, min), max);
|
|
36
|
-
}
|