@workbench-kit/react 0.0.2-prototype.0.2.13 → 0.0.2-prototype.0.2.15
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 +29 -0
- package/package.json +17 -12
- package/src/index.ts +16 -0
- package/src/jdw/builtins/renderBuiltinWidgetLeaf.tsx +1 -3
- package/src/jdw/createBuiltinJdwRegistry.ts +1 -4
- package/src/jdw/cssRenderBackend.tsx +1 -4
- package/src/layout/index.ts +2 -0
- package/src/modal/modalPosition.ts +3 -6
- package/src/overlay/measureAnchoredOverlayPanel.ts +4 -6
- package/src/primitives/select/Select.tsx +1 -13
- package/src/test-utils/workbenchMonacoMock.tsx +20 -0
- 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/WidgetTreeCanvasPreview.tsx +1 -4
- package/src/workbench/commands/ShortcutCommandBridge.tsx +1 -13
- package/src/workbench/commands/WorkbenchQuickOpen.tsx +410 -0
- package/src/workbench/commands/command-ui.ts +3 -0
- package/src/workbench/commands/createWorkspaceFilesQuickOpenProvider.ts +86 -0
- package/src/workbench/commands/quick-open-model.ts +57 -0
- package/src/workbench/index.ts +16 -0
- package/src/workbench/management/ExtensionManagementPanel.tsx +1 -34
- package/src/workbench/management/ExtensionManagementSidebar.tsx +1 -34
- package/src/workbench/management/IntegrationSettingsSurface.tsx +2 -5
- package/src/workbench/management/KeybindingCaptureField.tsx +1 -9
- package/src/workbench/management/WorkbenchNotice.tsx +2 -5
- package/src/workbench/management/extension-management-filters.ts +38 -0
- package/src/workbench/settings/StructuredDataForm.tsx +1 -4
- package/src/workbench/settings/structuredDataFormModel.ts +2 -1
- package/src/workbench/shell/WorkbenchShell.tsx +40 -1
- package/src/workbench/shell/WorkbenchShellTitleBarLayoutControls.tsx +4 -7
- package/src/workbench/shell/activity-bar.css +47 -0
- package/src/workbench/shell/standalone.ts +12 -0
|
@@ -2,6 +2,7 @@ import { useEffect, useId, useRef, useState, type KeyboardEvent } from 'react';
|
|
|
2
2
|
import { formatKeybindingLabel } from '@workbench-kit/platform';
|
|
3
3
|
import { Button } from '../../primitives/button';
|
|
4
4
|
import { cx } from '../../utils/cx';
|
|
5
|
+
import { normalizeKeyToken } from '../../utils/normalizeKeyToken';
|
|
5
6
|
|
|
6
7
|
export interface KeybindingCaptureFieldProps {
|
|
7
8
|
ariaLabel?: string | undefined;
|
|
@@ -131,12 +132,3 @@ function normalizeKeybindingKeyFromEvent(
|
|
|
131
132
|
parts.push(normalizeKeyToken(event.key));
|
|
132
133
|
return parts.join('+');
|
|
133
134
|
}
|
|
134
|
-
|
|
135
|
-
function normalizeKeyToken(token: string): string {
|
|
136
|
-
const key = token.trim().toLowerCase();
|
|
137
|
-
if (key === 'del') return 'delete';
|
|
138
|
-
if (key === 'esc') return 'escape';
|
|
139
|
-
if (key === 'return') return 'enter';
|
|
140
|
-
if (key === 'spacebar' || key === 'space') return 'space';
|
|
141
|
-
return key.length === 1 ? key : key;
|
|
142
|
-
}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
type ReactNode,
|
|
10
10
|
} from 'react';
|
|
11
11
|
import { IconButton, WorkbenchBanner, WorkbenchBannerMessage } from '../../primitives/index';
|
|
12
|
+
import { cx } from '../../utils/cx';
|
|
12
13
|
|
|
13
14
|
export type WorkbenchNoticeTone = 'error' | 'info' | 'success' | 'warning';
|
|
14
15
|
export type WorkbenchNoticePosition = 'bottom-center' | 'bottom-right';
|
|
@@ -187,7 +188,7 @@ export function useWorkbenchNotice(): WorkbenchNoticeController {
|
|
|
187
188
|
}
|
|
188
189
|
|
|
189
190
|
function resolveNoticeViewportClassName(position: WorkbenchNoticePosition): string {
|
|
190
|
-
return
|
|
191
|
+
return cx(
|
|
191
192
|
'pointer-events-none fixed inset-x-0 bottom-4 z-50 flex flex-col gap-2 px-4',
|
|
192
193
|
position === 'bottom-center' ? 'items-center' : 'items-end',
|
|
193
194
|
);
|
|
@@ -205,7 +206,3 @@ function resolveNoticeBannerStyle(tone: WorkbenchNoticeTone): CSSProperties {
|
|
|
205
206
|
minWidth: 'min(420px, calc(100vw - 32px))',
|
|
206
207
|
};
|
|
207
208
|
}
|
|
208
|
-
|
|
209
|
-
function joinClasses(...classes: Array<string | undefined>): string {
|
|
210
|
-
return classes.filter(Boolean).join(' ');
|
|
211
|
-
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ExtensionCatalogBrowseEntry, ExtensionManagementEntry } from './types.js';
|
|
2
|
+
|
|
3
|
+
export function filterInstalledEntries(
|
|
4
|
+
entries: readonly ExtensionManagementEntry[],
|
|
5
|
+
query: string,
|
|
6
|
+
): readonly ExtensionManagementEntry[] {
|
|
7
|
+
const normalized = query.trim().toLowerCase();
|
|
8
|
+
if (!normalized) {
|
|
9
|
+
return entries;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return entries.filter((entry) =>
|
|
13
|
+
[entry.displayName, entry.id, entry.category, entry.description ?? '']
|
|
14
|
+
.join(' ')
|
|
15
|
+
.toLowerCase()
|
|
16
|
+
.includes(normalized),
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function filterBrowseEntries(
|
|
21
|
+
entries: readonly ExtensionCatalogBrowseEntry[],
|
|
22
|
+
query: string,
|
|
23
|
+
category?: string,
|
|
24
|
+
): readonly ExtensionCatalogBrowseEntry[] {
|
|
25
|
+
const normalized = query.trim().toLowerCase();
|
|
26
|
+
return entries.filter((entry) => {
|
|
27
|
+
if (category && entry.category !== category) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
if (!normalized) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
return [entry.displayName, entry.id, entry.category, entry.description]
|
|
34
|
+
.join(' ')
|
|
35
|
+
.toLowerCase()
|
|
36
|
+
.includes(normalized);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
type WorkbenchStructuredDataSchemaFieldInputProps,
|
|
38
38
|
type WorkbenchStructuredDataTextArrayInputProps,
|
|
39
39
|
} from './structuredDataSchema';
|
|
40
|
+
import { isRenderableWorkbenchStructuredDataFormError } from './structuredDataFormModel';
|
|
40
41
|
|
|
41
42
|
export function WorkbenchStructuredDataForm({
|
|
42
43
|
ariaLabel,
|
|
@@ -156,10 +157,6 @@ export function WorkbenchStructuredDataForm({
|
|
|
156
157
|
);
|
|
157
158
|
}
|
|
158
159
|
|
|
159
|
-
function isRenderableWorkbenchStructuredDataFormError(error: ReactNode) {
|
|
160
|
-
return error !== undefined && error !== null && error !== false && error !== '';
|
|
161
|
-
}
|
|
162
|
-
|
|
163
160
|
function StructuredDataSection({
|
|
164
161
|
data,
|
|
165
162
|
disabled,
|
|
@@ -135,6 +135,7 @@ function isWorkbenchStructuredDataFormEmptyValue(value: WorkbenchStructuredDataF
|
|
|
135
135
|
return value === '' || value === false;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
/** True when a form field error should render (non-empty ReactNode). */
|
|
139
|
+
export function isRenderableWorkbenchStructuredDataFormError(error: ReactNode) {
|
|
139
140
|
return error !== undefined && error !== null && error !== false && error !== '';
|
|
140
141
|
}
|
|
@@ -8,6 +8,16 @@ import { DEFAULT_PRIMARY_SIDEBAR_SIZE_PX } from './shellState';
|
|
|
8
8
|
import { suppressNativeBrowserContextMenu } from '../commands/workbenchContextMenu';
|
|
9
9
|
import { WorkbenchOverlaysProvider } from '../chrome/workbenchOverlaysContext';
|
|
10
10
|
|
|
11
|
+
const DEFAULT_BOTTOM_PANEL_SIZE_PERCENT = 30;
|
|
12
|
+
|
|
13
|
+
function clampBottomPanelSizePercent(value: number): number {
|
|
14
|
+
return Math.min(70, Math.max(10, value));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function clampBottomPanelPrimarySizePercent(value: number): number {
|
|
18
|
+
return Math.min(90, Math.max(30, value));
|
|
19
|
+
}
|
|
20
|
+
|
|
11
21
|
export type WorkbenchShellActivityBarPosition = 'left' | 'top';
|
|
12
22
|
|
|
13
23
|
export interface WorkbenchShellProps {
|
|
@@ -25,10 +35,18 @@ export interface WorkbenchShellProps {
|
|
|
25
35
|
bottomPanel?: {
|
|
26
36
|
isVisible: boolean;
|
|
27
37
|
node: ReactNode;
|
|
38
|
+
/**
|
|
39
|
+
* Panel track size as a percent of the vertical editor+panel split.
|
|
40
|
+
* When set with `onSizePercentChange`, the split is controlled.
|
|
41
|
+
*/
|
|
42
|
+
sizePercent?: number;
|
|
43
|
+
onSizePercentChange?: (sizePercent: number) => void;
|
|
28
44
|
className?: string;
|
|
29
45
|
style?: CSSProperties;
|
|
30
46
|
};
|
|
31
47
|
compactStatus?: boolean;
|
|
48
|
+
/** Accessible name for the status bar region (default “Status bar”). */
|
|
49
|
+
statusBarAriaLabel?: string;
|
|
32
50
|
onStatusItemActivate?: (item: StatusBarItemModel) => void;
|
|
33
51
|
primarySidebar?: {
|
|
34
52
|
isVisible: boolean;
|
|
@@ -58,6 +76,7 @@ export function WorkbenchShell({
|
|
|
58
76
|
auxiliarySidebar,
|
|
59
77
|
bottomPanel,
|
|
60
78
|
compactStatus = true,
|
|
79
|
+
statusBarAriaLabel,
|
|
61
80
|
onStatusItemActivate,
|
|
62
81
|
overlays,
|
|
63
82
|
primarySidebar,
|
|
@@ -85,17 +104,36 @@ export function WorkbenchShell({
|
|
|
85
104
|
const isBottomPanelCollapsed = bottomPanel !== undefined && !bottomPanel.isVisible;
|
|
86
105
|
const isAuxiliarySidebarCollapsed = auxiliarySidebar !== undefined && !auxiliarySidebar.isVisible;
|
|
87
106
|
|
|
107
|
+
const bottomPanelSizePercent =
|
|
108
|
+
bottomPanel?.onSizePercentChange !== undefined
|
|
109
|
+
? (bottomPanel.sizePercent ?? DEFAULT_BOTTOM_PANEL_SIZE_PERCENT)
|
|
110
|
+
: undefined;
|
|
111
|
+
const bottomPanelPrimarySizePercent =
|
|
112
|
+
bottomPanelSizePercent !== undefined
|
|
113
|
+
? clampBottomPanelPrimarySizePercent(100 - bottomPanelSizePercent)
|
|
114
|
+
: undefined;
|
|
115
|
+
|
|
88
116
|
const editorArea = bottomPanel ? (
|
|
89
117
|
<SplitView
|
|
90
118
|
className={cx(
|
|
91
119
|
bottomPanel.className,
|
|
92
120
|
isBottomPanelCollapsed && 'ui-workbench-split-view--secondary-collapsed',
|
|
93
121
|
)}
|
|
94
|
-
defaultPrimarySizePercent={
|
|
122
|
+
defaultPrimarySizePercent={100 - DEFAULT_BOTTOM_PANEL_SIZE_PERCENT}
|
|
95
123
|
maxPrimarySizePercent={90}
|
|
96
124
|
minPrimarySizePercent={30}
|
|
125
|
+
onPrimarySizePercentChange={
|
|
126
|
+
bottomPanel.onSizePercentChange
|
|
127
|
+
? (primarySizePercent) => {
|
|
128
|
+
bottomPanel.onSizePercentChange?.(
|
|
129
|
+
clampBottomPanelSizePercent(100 - primarySizePercent),
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
: undefined
|
|
133
|
+
}
|
|
97
134
|
orientation="vertical"
|
|
98
135
|
primary={secondaryArea}
|
|
136
|
+
primarySizePercent={bottomPanelPrimarySizePercent}
|
|
99
137
|
secondary={bottomPanel.node}
|
|
100
138
|
/>
|
|
101
139
|
) : (
|
|
@@ -178,6 +216,7 @@ export function WorkbenchShell({
|
|
|
178
216
|
{body}
|
|
179
217
|
</div>
|
|
180
218
|
<StatusBar
|
|
219
|
+
aria-label={statusBarAriaLabel}
|
|
181
220
|
compact={compactStatus}
|
|
182
221
|
sections={statusSections}
|
|
183
222
|
onItemActivate={onStatusItemActivate}
|
|
@@ -2,6 +2,7 @@ import '../chrome/workbench-shell-titlebar.css';
|
|
|
2
2
|
import type { JSX } from 'react';
|
|
3
3
|
|
|
4
4
|
import { IconButton } from '../../primitives/icon-button';
|
|
5
|
+
import { cx } from '../../utils/cx';
|
|
5
6
|
|
|
6
7
|
export interface WorkbenchShellTitleBarLayoutControlsProps {
|
|
7
8
|
readonly isAuxiliarySidebarVisible?: boolean;
|
|
@@ -18,10 +19,6 @@ export interface WorkbenchShellTitleBarLayoutControlsProps {
|
|
|
18
19
|
readonly secondarySidebarShowLabel?: string;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
function joinClasses(...classNames: Array<string | false | null | undefined>): string {
|
|
22
|
-
return classNames.filter(Boolean).join(' ');
|
|
23
|
-
}
|
|
24
|
-
|
|
25
22
|
export function WorkbenchShellTitleBarLayoutControls({
|
|
26
23
|
isAuxiliarySidebarVisible = false,
|
|
27
24
|
isPanelVisible = false,
|
|
@@ -40,7 +37,7 @@ export function WorkbenchShellTitleBarLayoutControls({
|
|
|
40
37
|
<div className="workbench-shell-titlebar__layout-controls">
|
|
41
38
|
<IconButton
|
|
42
39
|
aria-pressed={isPrimarySidebarVisible}
|
|
43
|
-
className={
|
|
40
|
+
className={cx(
|
|
44
41
|
'workbench-shell-titlebar__layout-control',
|
|
45
42
|
isPrimarySidebarVisible && 'workbench-shell-titlebar__layout-control--active',
|
|
46
43
|
)}
|
|
@@ -52,7 +49,7 @@ export function WorkbenchShellTitleBarLayoutControls({
|
|
|
52
49
|
{onTogglePanel ? (
|
|
53
50
|
<IconButton
|
|
54
51
|
aria-pressed={isPanelVisible}
|
|
55
|
-
className={
|
|
52
|
+
className={cx(
|
|
56
53
|
'workbench-shell-titlebar__layout-control',
|
|
57
54
|
isPanelVisible && 'workbench-shell-titlebar__layout-control--active',
|
|
58
55
|
)}
|
|
@@ -65,7 +62,7 @@ export function WorkbenchShellTitleBarLayoutControls({
|
|
|
65
62
|
{onToggleAuxiliarySidebar ? (
|
|
66
63
|
<IconButton
|
|
67
64
|
aria-pressed={isAuxiliarySidebarVisible}
|
|
68
|
-
className={
|
|
65
|
+
className={cx(
|
|
69
66
|
'workbench-shell-titlebar__layout-control',
|
|
70
67
|
isAuxiliarySidebarVisible && 'workbench-shell-titlebar__layout-control--active',
|
|
71
68
|
)}
|
|
@@ -32,6 +32,53 @@
|
|
|
32
32
|
border-top: 1px solid var(--vscode-panel-border, var(--color-border));
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
.workbench-bottom-panel__header {
|
|
36
|
+
display: flex;
|
|
37
|
+
flex-shrink: 0;
|
|
38
|
+
align-items: stretch;
|
|
39
|
+
gap: 0;
|
|
40
|
+
min-height: 28px;
|
|
41
|
+
border-bottom: 1px solid var(--vscode-panel-border, var(--color-border));
|
|
42
|
+
background: var(--vscode-panel-background, var(--color-surface));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.workbench-bottom-panel__tab {
|
|
46
|
+
appearance: none;
|
|
47
|
+
border: none;
|
|
48
|
+
background: transparent;
|
|
49
|
+
color: var(--color-text-muted);
|
|
50
|
+
font: inherit;
|
|
51
|
+
font-size: 12px;
|
|
52
|
+
padding: 4px 12px;
|
|
53
|
+
cursor: pointer;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.workbench-bottom-panel__tab:hover {
|
|
57
|
+
color: var(--color-text);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.workbench-bottom-panel__tab--active {
|
|
61
|
+
color: var(--color-text);
|
|
62
|
+
box-shadow: inset 0 -2px 0 var(--color-accent, var(--color-primary));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.workbench-bottom-panel__body {
|
|
66
|
+
flex: 1;
|
|
67
|
+
min-height: 0;
|
|
68
|
+
overflow: auto;
|
|
69
|
+
padding: 8px 12px;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.workbench-bottom-panel__view {
|
|
73
|
+
min-height: 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.workbench-bottom-panel__empty {
|
|
77
|
+
color: var(--color-text-muted);
|
|
78
|
+
font-size: 12px;
|
|
79
|
+
padding: 8px 12px;
|
|
80
|
+
}
|
|
81
|
+
|
|
35
82
|
.ui-workbench-activity-bar__item {
|
|
36
83
|
--ui-button-width: var(--workbench-activity-bar-item-size);
|
|
37
84
|
--ui-button-min-width: 0;
|
|
@@ -99,3 +99,15 @@ export type WorkbenchStandaloneBootstrapEvent<TActivityId extends string = strin
|
|
|
99
99
|
| { type: 'activity-change'; payload: WorkbenchActivityChangeEvent<TActivityId> }
|
|
100
100
|
| { type: 'status-message'; message: string }
|
|
101
101
|
| { type: 'error'; error: Error };
|
|
102
|
+
|
|
103
|
+
export * from './WorkbenchStandaloneShell';
|
|
104
|
+
export {
|
|
105
|
+
createWorkbenchStandaloneShellStateSnapshot,
|
|
106
|
+
useWorkbenchStandaloneShellContext,
|
|
107
|
+
} from './workbenchStandaloneShellReactContext';
|
|
108
|
+
export type {
|
|
109
|
+
WorkbenchStandaloneShellStateChange,
|
|
110
|
+
WorkbenchStandaloneShellStateChangeKind,
|
|
111
|
+
WorkbenchStandaloneShellStateSnapshot,
|
|
112
|
+
} from './workbenchStandaloneShellReactContext';
|
|
113
|
+
export { useWorkbenchStandaloneShellStateSync } from './useWorkbenchStandaloneShellStateSync';
|