@workbench-kit/react 0.0.2-prototype.0.2.13 → 0.0.2-prototype.0.2.14
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 +10 -10
- 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/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/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/README.md
CHANGED
|
@@ -63,6 +63,35 @@ Full walkthrough: [Getting Started](../../docs/guides/getting-started.md).
|
|
|
63
63
|
|
|
64
64
|
Import **only** through `exports`. Do not deep-import `src/` paths.
|
|
65
65
|
|
|
66
|
+
## Quick Open providers
|
|
67
|
+
|
|
68
|
+
`WorkbenchQuickOpen` is a file/provider overlay distinct from the command palette.
|
|
69
|
+
Hosts (or `@workbench-kit/shell-react` `WorkbenchCommandHost`) pass pluggable
|
|
70
|
+
providers; the default workspace-files provider wraps
|
|
71
|
+
`searchWorkspaceFiles` from `@workbench-kit/workspace`.
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import {
|
|
75
|
+
WorkbenchQuickOpen,
|
|
76
|
+
createWorkspaceFilesQuickOpenProvider,
|
|
77
|
+
type QuickOpenProvider,
|
|
78
|
+
} from '@workbench-kit/react/workbench';
|
|
79
|
+
|
|
80
|
+
const providers: QuickOpenProvider[] = [
|
|
81
|
+
createWorkspaceFilesQuickOpenProvider({
|
|
82
|
+
files: workspaceFiles,
|
|
83
|
+
recentPaths: ['src/App.tsx'],
|
|
84
|
+
}),
|
|
85
|
+
];
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Contract:
|
|
89
|
+
|
|
90
|
+
- `provider.search(query)` returns items (sync or `Promise`)
|
|
91
|
+
- Empty query → all files, with optional `recentPaths` elevated first
|
|
92
|
+
- Enter selects the active item; Escape closes (modal focus trap)
|
|
93
|
+
- Shell default: Ctrl/Cmd+P opens Quick Open; Ctrl/Cmd+Shift+P opens the command palette
|
|
94
|
+
|
|
66
95
|
## Learn more
|
|
67
96
|
|
|
68
97
|
| Doc | Purpose |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workbench-kit/react",
|
|
3
|
-
"version": "0.0.2-prototype.0.2.
|
|
3
|
+
"version": "0.0.2-prototype.0.2.14",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -58,15 +58,15 @@
|
|
|
58
58
|
"@vscode/codicons": "^0.0.45",
|
|
59
59
|
"remark-gfm": "^4.0.1",
|
|
60
60
|
"rehype-sanitize": "^6.0.0",
|
|
61
|
-
"@workbench-kit/
|
|
62
|
-
"@workbench-kit/
|
|
63
|
-
"@workbench-kit/
|
|
64
|
-
"@workbench-kit/
|
|
65
|
-
"@workbench-kit/
|
|
66
|
-
"@workbench-kit/
|
|
67
|
-
"@workbench-kit/workspace": "0.0.2-prototype.0.2.
|
|
68
|
-
"@workbench-kit/
|
|
69
|
-
"@workbench-kit/
|
|
61
|
+
"@workbench-kit/contracts": "0.0.2-prototype.0.2.14",
|
|
62
|
+
"@workbench-kit/jdw": "0.0.2-prototype.0.2.14",
|
|
63
|
+
"@workbench-kit/adapters": "0.0.2-prototype.0.2.14",
|
|
64
|
+
"@workbench-kit/monaco": "0.0.2-prototype.0.2.14",
|
|
65
|
+
"@workbench-kit/runtime": "0.0.2-prototype.0.2.14",
|
|
66
|
+
"@workbench-kit/services": "0.0.2-prototype.0.2.14",
|
|
67
|
+
"@workbench-kit/workspace": "0.0.2-prototype.0.2.14",
|
|
68
|
+
"@workbench-kit/platform": "0.0.2-prototype.0.2.14",
|
|
69
|
+
"@workbench-kit/tokens": "0.0.2-prototype.0.2.14"
|
|
70
70
|
},
|
|
71
71
|
"peerDependencies": {
|
|
72
72
|
"react": "^19.0.0",
|
package/src/index.ts
CHANGED
|
@@ -59,6 +59,15 @@ export {
|
|
|
59
59
|
groupWorkbenchCommands,
|
|
60
60
|
isWorkbenchCommandRunnable,
|
|
61
61
|
} from './workbench/commands/CommandPalette';
|
|
62
|
+
export {
|
|
63
|
+
DEFAULT_QUICK_OPEN_SEARCH_DEBOUNCE_MS,
|
|
64
|
+
WORKSPACE_FILES_QUICK_OPEN_PROVIDER_ID,
|
|
65
|
+
WorkbenchQuickOpen,
|
|
66
|
+
createWorkspaceFilesQuickOpenProvider,
|
|
67
|
+
getNextQuickOpenItemIndex,
|
|
68
|
+
isQuickOpenItemSelectable,
|
|
69
|
+
resolveQuickOpenItemPath,
|
|
70
|
+
} from './workbench/commands/WorkbenchQuickOpen';
|
|
62
71
|
export {
|
|
63
72
|
WorkbenchShortcutCommandBridge,
|
|
64
73
|
getWorkbenchShortcutCommandBindings,
|
|
@@ -87,6 +96,13 @@ export type {
|
|
|
87
96
|
WorkbenchCommandStatus,
|
|
88
97
|
WorkbenchCommandSuggestProps,
|
|
89
98
|
} from './workbench/commands/CommandPalette';
|
|
99
|
+
export type {
|
|
100
|
+
CreateWorkspaceFilesQuickOpenProviderOptions,
|
|
101
|
+
QuickOpenItem,
|
|
102
|
+
QuickOpenProvider,
|
|
103
|
+
QuickOpenSelectContext,
|
|
104
|
+
WorkbenchQuickOpenProps,
|
|
105
|
+
} from './workbench/commands/WorkbenchQuickOpen';
|
|
90
106
|
export type {
|
|
91
107
|
UseWorkbenchShortcutCommandsOptions,
|
|
92
108
|
WorkbenchShortcutCommandBinding,
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { createElement, type CSSProperties, type ReactNode } from 'react';
|
|
2
2
|
import type { GenericWidget } from '@workbench-kit/jdw';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
|
6
|
-
}
|
|
4
|
+
import { readNumber } from '../../utils/readNumber';
|
|
7
5
|
|
|
8
6
|
function readString(value: unknown): string | undefined {
|
|
9
7
|
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type GenericWidget,
|
|
11
11
|
} from '@workbench-kit/jdw';
|
|
12
12
|
|
|
13
|
+
import { readNumber } from '../utils/readNumber';
|
|
13
14
|
import { renderBuiltinWidgetLeaf } from './builtins/renderBuiltinWidgetLeaf.js';
|
|
14
15
|
|
|
15
16
|
const LAYOUT_INSPECTOR = [
|
|
@@ -73,10 +74,6 @@ function build(widget: WidgetTypeShape) {
|
|
|
73
74
|
return renderBuiltinWidgetLeaf(widget as GenericWidget);
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
function readNumber(value: unknown): number | undefined {
|
|
77
|
-
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
77
|
function readString(value: unknown): string | undefined {
|
|
81
78
|
return typeof value === 'string' && value.trim().length > 0 ? value : undefined;
|
|
82
79
|
}
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
type WidgetPath,
|
|
23
23
|
} from '@workbench-kit/jdw';
|
|
24
24
|
|
|
25
|
+
import { readNumber } from '../utils/readNumber';
|
|
25
26
|
import { renderBuiltinWidgetLeaf } from './builtins/renderBuiltinWidgetLeaf.js';
|
|
26
27
|
import { BUILTIN_JDW_REGISTRY } from './createBuiltinJdwRegistry.js';
|
|
27
28
|
export interface CssRenderBackendOptions {
|
|
@@ -45,10 +46,6 @@ const LAYOUT_CONTAINER_TYPES = new Set([
|
|
|
45
46
|
'sized_box',
|
|
46
47
|
]);
|
|
47
48
|
|
|
48
|
-
function readNumber(value: unknown): number | undefined {
|
|
49
|
-
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
49
|
function renderFromRegistry(
|
|
53
50
|
registry: WidgetRegistryContract<unknown>,
|
|
54
51
|
widget: GenericWidget,
|
|
@@ -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
|
-
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { clampNumber } from '../utils/clamp';
|
|
2
|
+
|
|
1
3
|
export type AnchoredOverlayPlacement = 'side' | 'below' | 'above';
|
|
2
4
|
|
|
3
5
|
export interface MeasureAnchoredOverlayPanelOptions {
|
|
@@ -26,10 +28,6 @@ const SIDE_MIN_VISIBLE_HEIGHT_PX = 240;
|
|
|
26
28
|
/** Prefer below when at least this many pixels are available under the trigger. */
|
|
27
29
|
const BELOW_MIN_SPACE_PX = 12;
|
|
28
30
|
|
|
29
|
-
function clamp(value: number, min: number, max: number): number {
|
|
30
|
-
return Math.min(Math.max(value, min), max);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
31
|
/**
|
|
34
32
|
* Measure a panel-sized overlay anchored to a trigger element.
|
|
35
33
|
* Prefers a side flyout when the trigger sits in the left portion of the
|
|
@@ -65,7 +63,7 @@ export function measureAnchoredOverlayPanel(
|
|
|
65
63
|
|
|
66
64
|
if (preferSide) {
|
|
67
65
|
const minVisibleHeight = Math.min(SIDE_MIN_VISIBLE_HEIGHT_PX, maxHeight);
|
|
68
|
-
const top =
|
|
66
|
+
const top = clampNumber(
|
|
69
67
|
triggerRect.top,
|
|
70
68
|
viewportPaddingPx,
|
|
71
69
|
viewportHeight - viewportPaddingPx - minVisibleHeight,
|
|
@@ -80,7 +78,7 @@ export function measureAnchoredOverlayPanel(
|
|
|
80
78
|
}
|
|
81
79
|
|
|
82
80
|
// Align the panel's right edge toward the trigger's right, then clamp.
|
|
83
|
-
const left =
|
|
81
|
+
const left = clampNumber(
|
|
84
82
|
triggerRect.right - width,
|
|
85
83
|
viewportPaddingPx,
|
|
86
84
|
viewportWidth - viewportPaddingPx - width,
|
|
@@ -16,6 +16,7 @@ import type { ControlWidth } from '../text-input/TextInput';
|
|
|
16
16
|
import { cxCodicon } from '../../utils/codicon';
|
|
17
17
|
import { cx } from '../../utils/cx';
|
|
18
18
|
import { getEnabledOptionIndex, parseOptions } from './options';
|
|
19
|
+
import { resolvePortalContainer } from '../searchable-multi-select/overlay';
|
|
19
20
|
import { isTriggerVisible, measureOverlayPosition, overlayListboxStyle } from './overlay';
|
|
20
21
|
import type { OverlayPosition, ParsedOption } from './types';
|
|
21
22
|
|
|
@@ -24,19 +25,6 @@ export interface SelectProps extends ComponentPropsWithRef<'select'> {
|
|
|
24
25
|
onValueChange?: (value: string, event: ChangeEvent<HTMLSelectElement>) => void;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
/**
|
|
28
|
-
* Portaling straight to `document.body` escapes the workbench root (`[data-theme-preset]`),
|
|
29
|
-
* which re-declares theme tokens locally and shadows whatever a contributed theme overrides
|
|
30
|
-
* on `document.documentElement`. Prefer themed hosts / overlay roots when present.
|
|
31
|
-
*/
|
|
32
|
-
function resolvePortalContainer(trigger: HTMLElement | null): HTMLElement {
|
|
33
|
-
return (
|
|
34
|
-
trigger?.closest<HTMLElement>(
|
|
35
|
-
'[data-theme-preset], [data-theme], .ui-workbench-host-root, .ide-workbench-overlays',
|
|
36
|
-
) ?? document.body
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
28
|
export function Select({
|
|
41
29
|
className,
|
|
42
30
|
controlWidth = 'default',
|
|
@@ -9,14 +9,34 @@ export interface MockWorkbenchMonacoEditorProps {
|
|
|
9
9
|
value?: string;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
export interface MockWorkbenchMonacoDiffEditorProps {
|
|
13
|
+
language?: string;
|
|
14
|
+
modified?: string;
|
|
15
|
+
onModifiedChange?: (value: string) => void;
|
|
16
|
+
original?: string;
|
|
17
|
+
readOnly?: boolean;
|
|
18
|
+
theme?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
12
21
|
export function createWorkbenchMonacoMockModule(
|
|
13
22
|
renderEditor?: (props: MockWorkbenchMonacoEditorProps) => ReactNode,
|
|
14
23
|
) {
|
|
15
24
|
const defaultRender = ({ value }: MockWorkbenchMonacoEditorProps) =>
|
|
16
25
|
createElement('div', { 'data-testid': 'monaco-editor' }, value ?? 'Mocked Monaco Editor');
|
|
17
26
|
|
|
27
|
+
const defaultDiffRender = ({ modified, original }: MockWorkbenchMonacoDiffEditorProps) =>
|
|
28
|
+
createElement(
|
|
29
|
+
'div',
|
|
30
|
+
{ 'data-testid': 'monaco-diff-editor' },
|
|
31
|
+
original ?? '',
|
|
32
|
+
'\n---\n',
|
|
33
|
+
modified ?? '',
|
|
34
|
+
);
|
|
35
|
+
|
|
18
36
|
return {
|
|
19
37
|
WorkbenchMonacoEditor: renderEditor ?? defaultRender,
|
|
38
|
+
WorkbenchMonacoDiffEditor: defaultDiffRender,
|
|
39
|
+
DiffEditor: defaultDiffRender,
|
|
20
40
|
useMonacoWorkbenchThemeSync: () => undefined,
|
|
21
41
|
prepareMonacoWorkbenchEditor: () => undefined,
|
|
22
42
|
monacoThemeForWorkspaceTheme: (theme: string) =>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Normalize a keyboard shortcut token to a stable lowercase key name. */
|
|
2
|
+
export function normalizeKeyToken(token: string): string {
|
|
3
|
+
const key = token.trim().toLowerCase();
|
|
4
|
+
if (key === 'del') return 'delete';
|
|
5
|
+
if (key === 'esc') return 'escape';
|
|
6
|
+
if (key === 'return') return 'enter';
|
|
7
|
+
if (key === 'spacebar' || key === 'space') return 'space';
|
|
8
|
+
if (key === 'arrowup' || key === 'up') return 'arrowup';
|
|
9
|
+
if (key === 'arrowdown' || key === 'down') return 'arrowdown';
|
|
10
|
+
if (key === 'arrowleft' || key === 'left') return 'arrowleft';
|
|
11
|
+
if (key === 'arrowright' || key === 'right') return 'arrowright';
|
|
12
|
+
return key;
|
|
13
|
+
}
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
type WidgetResizeHandlePosition,
|
|
27
27
|
} from '@workbench-kit/jdw';
|
|
28
28
|
|
|
29
|
+
import { readNumber } from '../utils/readNumber';
|
|
29
30
|
import {
|
|
30
31
|
WorkbenchCanvasFrameHandle,
|
|
31
32
|
WorkbenchCanvasItemFrame,
|
|
@@ -221,10 +222,6 @@ function readPositiveInteger(value: unknown): number | null {
|
|
|
221
222
|
return Math.floor(value);
|
|
222
223
|
}
|
|
223
224
|
|
|
224
|
-
function readNumber(value: unknown): number | undefined {
|
|
225
|
-
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
225
|
function appendLineRect(rect: Rect, axis: 'x' | 'y', children: readonly LayoutNodeResult[]): Rect {
|
|
229
226
|
const lastChildRect = children[children.length - 1]?.rect;
|
|
230
227
|
if (axis === 'x') {
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
type CommandRegistry,
|
|
6
6
|
type CommandValue,
|
|
7
7
|
} from '@workbench-kit/platform';
|
|
8
|
+
import { normalizeKeyToken } from '../../utils/normalizeKeyToken';
|
|
8
9
|
|
|
9
10
|
export type WorkbenchShortcutPlatform = 'linux' | 'mac' | 'unknown' | 'windows';
|
|
10
11
|
|
|
@@ -105,19 +106,6 @@ function getDefaultShortcutPlatform(): WorkbenchShortcutPlatform {
|
|
|
105
106
|
return 'unknown';
|
|
106
107
|
}
|
|
107
108
|
|
|
108
|
-
function normalizeKeyToken(token: string) {
|
|
109
|
-
const key = token.trim().toLowerCase();
|
|
110
|
-
if (key === 'del') return 'delete';
|
|
111
|
-
if (key === 'esc') return 'escape';
|
|
112
|
-
if (key === 'return') return 'enter';
|
|
113
|
-
if (key === 'spacebar' || key === 'space') return 'space';
|
|
114
|
-
if (key === 'arrowup' || key === 'up') return 'arrowup';
|
|
115
|
-
if (key === 'arrowdown' || key === 'down') return 'arrowdown';
|
|
116
|
-
if (key === 'arrowleft' || key === 'left') return 'arrowleft';
|
|
117
|
-
if (key === 'arrowright' || key === 'right') return 'arrowright';
|
|
118
|
-
return key;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
109
|
function normalizeEventKey(key: string) {
|
|
122
110
|
if (key === ' ') return 'space';
|
|
123
111
|
return normalizeKeyToken(key);
|