@workbench-kit/react 0.0.1-prototype.0 → 0.0.2-prototype.0.1.2

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 (155) hide show
  1. package/package.json +33 -9
  2. package/src/index.ts +545 -43
  3. package/src/jdw/JdwPreview.tsx +38 -0
  4. package/src/jdw/JsonCodeEditorPane.tsx +274 -0
  5. package/src/jdw/builtins/renderBuiltinWidgetLeaf.tsx +29 -0
  6. package/src/jdw/builtins/renderBuiltinWidgetNode.tsx +126 -0
  7. package/src/jdw/createBuiltinJdwRegistry.ts +111 -0
  8. package/src/jdw/cssRenderBackend.tsx +134 -0
  9. package/src/jdw/document.ts +38 -0
  10. package/src/jdw/fixtures/jdw-fixtures.ts +52 -0
  11. package/src/jdw/fixtures/jdw-sample-screens.ts +522 -0
  12. package/src/jdw/index.ts +45 -0
  13. package/src/jdw/parse.ts +1 -0
  14. package/src/jdw/renderJdw.tsx +32 -0
  15. package/src/json-config/JsonConfigWorkbench.tsx +316 -0
  16. package/src/json-config/index.ts +6 -0
  17. package/src/json-config/json-config-editor-state.ts +42 -0
  18. package/src/layout/Panel.tsx +146 -1
  19. package/src/layout/SideBarViewFrame.tsx +367 -328
  20. package/src/layout/WorkbenchCanvas.tsx +849 -0
  21. package/src/layout/WorkbenchFullscreen.tsx +368 -0
  22. package/src/layout/WorkbenchLayout.tsx +5 -0
  23. package/src/layout/WorkbenchLayoutBase.tsx +294 -0
  24. package/src/layout/WorkbenchPropertyPanel.tsx +497 -0
  25. package/src/layout/WorkbenchSidebarActions.tsx +274 -0
  26. package/src/layout/WorkbenchTree.tsx +351 -0
  27. package/src/layout/layoutHelpers.ts +25 -0
  28. package/src/modal/ConfirmDialog.tsx +61 -53
  29. package/src/modal/Modal.tsx +295 -35
  30. package/src/overlay/ContextMenu.tsx +146 -145
  31. package/src/primitives/AbsoluteBox.tsx +46 -0
  32. package/src/primitives/Badge.tsx +12 -12
  33. package/src/primitives/Button.tsx +44 -14
  34. package/src/primitives/Checkbox.tsx +11 -5
  35. package/src/primitives/EmptyState.tsx +27 -26
  36. package/src/primitives/Field.tsx +38 -38
  37. package/src/primitives/IconButton.tsx +5 -2
  38. package/src/primitives/List.tsx +111 -0
  39. package/src/primitives/NumberInput.tsx +38 -0
  40. package/src/primitives/ScrollArea.tsx +42 -0
  41. package/src/primitives/Select.tsx +1 -12
  42. package/src/primitives/StatusBar.tsx +46 -0
  43. package/src/primitives/TextArea.tsx +36 -0
  44. package/src/primitives/TextInput.tsx +11 -2
  45. package/src/primitives/WorkbenchChrome.tsx +424 -0
  46. package/src/primitives/WorkbenchEditor.tsx +394 -0
  47. package/src/primitives/index.ts +105 -0
  48. package/src/primitives/select/Select.tsx +266 -0
  49. package/src/primitives/select/index.ts +2 -0
  50. package/src/primitives/select/options.ts +38 -0
  51. package/src/primitives/select/overlay.ts +63 -0
  52. package/src/primitives/select/select.app.css +9 -0
  53. package/src/primitives/select/select.css +140 -0
  54. package/src/primitives/select/types.ts +18 -0
  55. package/src/primitives/styles.css +955 -0
  56. package/src/scrollbars.css +69 -0
  57. package/src/styles.css +7738 -1762
  58. package/src/utils/codicon.ts +17 -0
  59. package/src/widget-asset/WidgetAssetEditor.tsx +140 -0
  60. package/src/widget-asset/WidgetAssetMetadataForm.tsx +82 -0
  61. package/src/widget-asset/WidgetAssetModeControls.tsx +42 -0
  62. package/src/widget-asset/WidgetAssetSourceEditor.tsx +50 -0
  63. package/src/widget-asset/WidgetAssetWorkbench.tsx +112 -0
  64. package/src/widget-asset/index.ts +17 -0
  65. package/src/widget-asset/widget-asset-document.ts +37 -0
  66. package/src/widget-asset/widget-asset-mode.ts +3 -0
  67. package/src/widget-studio/builtin-widget-asset-catalog.ts +12 -0
  68. package/src/widget-studio/create-widget-studio-workspace-editor.tsx +79 -0
  69. package/src/widget-studio/index.ts +7 -0
  70. package/src/widget-studio/resolve-widget-studio-asset-catalog.ts +26 -0
  71. package/src/widget-tree/WidgetAssetPalette.tsx +77 -0
  72. package/src/widget-tree/WidgetInspectorPanel.tsx +266 -0
  73. package/src/widget-tree/WidgetSourceEditor.tsx +56 -0
  74. package/src/widget-tree/WidgetTreeLab.tsx +272 -0
  75. package/src/widget-tree/WidgetTreeModeControls.tsx +44 -0
  76. package/src/widget-tree/WidgetTreeSidePanel.tsx +49 -0
  77. package/src/widget-tree/WidgetTreeView.tsx +97 -0
  78. package/src/widget-tree/WidgetTreeWorkbench.tsx +111 -0
  79. package/src/widget-tree/WidgetTreeWorkspaceShell.tsx +154 -0
  80. package/src/widget-tree/demo-registry.ts +32 -0
  81. package/src/widget-tree/demo-widget-assets.ts +4 -0
  82. package/src/widget-tree/index.ts +27 -0
  83. package/src/widget-tree/widget-tree-document.ts +20 -0
  84. package/src/widget-tree/widget-tree-layout.ts +31 -0
  85. package/src/widget-tree/widget-tree-mode.ts +7 -0
  86. package/src/widget-tree/widget-tree-play-helpers.ts +74 -0
  87. package/src/workbench/ActivityBar.tsx +52 -52
  88. package/src/workbench/ArtifactShell.tsx +397 -0
  89. package/src/workbench/CommandPalette.tsx +819 -0
  90. package/src/workbench/ConfirmationFlow.tsx +245 -0
  91. package/src/workbench/MarkdownPreview.tsx +151 -0
  92. package/src/workbench/ShortcutCommandBridge.tsx +368 -0
  93. package/src/workbench/SplitView.tsx +136 -136
  94. package/src/workbench/StatusBar.tsx +178 -123
  95. package/src/workbench/StructuredArtifactEditor.tsx +205 -0
  96. package/src/workbench/Timeline.tsx +302 -0
  97. package/src/workbench/WorkbenchCanvasShell.tsx +941 -0
  98. package/src/workbench/WorkbenchShell.tsx +74 -70
  99. package/src/workbench/WorkbenchStandaloneShell.tsx +318 -291
  100. package/src/workbench/auth/WorkbenchAuthGate.tsx +61 -0
  101. package/src/workbench/auth/WorkbenchLoginView.tsx +635 -0
  102. package/src/workbench/auth/index.ts +19 -0
  103. package/src/workbench/chat/ChatComposer.tsx +165 -148
  104. package/src/workbench/chat/ChatMessageItem.tsx +10 -1
  105. package/src/workbench/chat/index.ts +9 -0
  106. package/src/workbench/chat/slashCommand.ts +28 -0
  107. package/src/workbench/chat/useChatRuntimeState.ts +76 -0
  108. package/src/workbench/chat/useSlashCommandSuggest.ts +101 -0
  109. package/src/workbench/commands.ts +520 -490
  110. package/src/workbench/index.ts +443 -98
  111. package/src/workbench/keyboard.ts +53 -0
  112. package/src/workbench/schema/index.ts +48 -0
  113. package/src/workbench/schema/workbenchDocument.ts +31 -0
  114. package/src/workbench/schema/workbenchDocumentActions.ts +6 -0
  115. package/src/workbench/schema/workbenchDocumentAdapter.ts +9 -0
  116. package/src/workbench/schema/workbenchDocumentPatch.ts +13 -0
  117. package/src/workbench/schema/workbenchDocumentRenderer.tsx +702 -0
  118. package/src/workbench/settings/NavigationPanel.tsx +47 -0
  119. package/src/workbench/settings/SchemaForm.tsx +420 -0
  120. package/src/workbench/settings/SectionedPanel.tsx +415 -0
  121. package/src/workbench/settings/StructuredDataForm.tsx +539 -0
  122. package/src/workbench/settings/StructuredDataSchemaPanel.tsx +559 -0
  123. package/src/workbench/settings/StructuredDataSchemaPanelEmbed.tsx +21 -0
  124. package/src/workbench/settings/StructuredDataSchemaPanelFrame.tsx +76 -0
  125. package/src/workbench/settings/StructuredDataTableView.tsx +127 -0
  126. package/src/workbench/settings/WorkbenchPanelRegion.tsx +46 -0
  127. package/src/workbench/settings/WorkbenchSettingsModal.tsx +21 -12
  128. package/src/workbench/settings/WorkbenchSettingsNav.tsx +38 -22
  129. package/src/workbench/settings/index.ts +135 -0
  130. package/src/workbench/settings/panel-region.css +21 -0
  131. package/src/workbench/settings/sectionedPanelScrollSpy.ts +143 -0
  132. package/src/workbench/settings/structured-data-schema-panel.css +330 -0
  133. package/src/workbench/settings/structured-data-table-view.css +85 -0
  134. package/src/workbench/settings/structuredDataSchema.ts +886 -0
  135. package/src/workbench/shell.ts +15 -0
  136. package/src/workbench/shellState.ts +203 -203
  137. package/src/workbench/standalone.ts +101 -94
  138. package/src/workbench/status.ts +129 -0
  139. package/src/workbench/theme.ts +44 -0
  140. package/src/workbench/workspace/MultiProviderExplorer.tsx +625 -0
  141. package/src/workbench/workspace/WorkspaceDraftsContext.tsx +111 -0
  142. package/src/workbench/workspace/WorkspaceEditor.tsx +47 -12
  143. package/src/workbench/workspace/WorkspaceEditorPanel.tsx +334 -353
  144. package/src/workbench/workspace/WorkspaceExplorer.tsx +532 -524
  145. package/src/workbench/workspace/WorkspaceFileIcon.tsx +32 -2
  146. package/src/workbench/workspace/WorkspaceSearchPanel.tsx +113 -113
  147. package/src/workbench/workspace/WorkspaceSearchResults.tsx +47 -47
  148. package/src/workbench/workspace/index.ts +156 -98
  149. package/src/workbench/workspace/mimeType.ts +45 -0
  150. package/src/workbench/workspace/path.ts +10 -10
  151. package/src/workbench/workspace/search.ts +6 -6
  152. package/src/workbench/workspace/tree.ts +1 -1
  153. package/src/workbench/workspace/types.ts +10 -10
  154. package/src/workbench/workspace/useVirtualWorkspace.ts +111 -98
  155. package/src/workbench/workspace/workspaceJsonDiagnostics.ts +83 -0
@@ -1,291 +1,318 @@
1
- import { useMemo } from 'react';
2
- import type { CSSProperties, MouseEvent, ReactNode } from 'react';
3
- import type { StatusBarItemModel, StatusBarSectionModel } from './StatusBar';
4
- import type { WorkbenchShellProps } from './WorkbenchShell';
5
- import { WorkbenchShell } from './WorkbenchShell';
6
- import type { WorkbenchShellCommandContext } from './commands';
7
- import { useWorkbenchShellState } from './shellState';
8
- import type {
9
- WorkbenchActivityChangeEvent,
10
- WorkbenchActivityDescriptor,
11
- WorkbenchStandaloneBootstrap,
12
- WorkbenchStandaloneBootstrapEvent,
13
- WorkbenchTheme,
14
- } from './standalone';
15
-
16
- const DEFAULT_THEME: WorkbenchTheme = 'dark';
17
- const DEFAULT_ACTIVITY_ID = 'explorer';
18
-
19
- export interface WorkbenchStandaloneShellContext<
20
- TActivityId extends string = string,
21
- TTheme extends WorkbenchTheme = WorkbenchTheme,
22
- > {
23
- activityId: TActivityId;
24
- commandContext: WorkbenchShellCommandContext<TActivityId>;
25
- showActivity: (activityId: TActivityId) => void;
26
- activateActivity: (activityId: TActivityId) => void;
27
- setTheme: (theme: TTheme) => void;
28
- setPrimarySidebarSizePercent: (sizePercent: number) => void;
29
- setPrimarySidebarVisible: (isVisible: boolean) => void;
30
- togglePrimarySidebar: () => void;
31
- openSettings: () => void;
32
- closeSettings: () => void;
33
- setSettingsCategoryId: (settingsCategoryId: string) => void;
34
- setSettingsScopeId: (settingsScopeId: string) => void;
35
- setSettingsSearchValue: (settingsSearchValue: string) => void;
36
- }
37
-
38
- export interface WorkbenchStandaloneShellProps<
39
- TActivityId extends string = string,
40
- TTheme extends WorkbenchTheme = WorkbenchTheme,
41
- > {
42
- bootstrap: WorkbenchStandaloneBootstrap<TActivityId>;
43
- activityBar?: Omit<
44
- WorkbenchShellProps['activityBar'],
45
- 'items' | 'secondaryItems' | 'onContextMenu' | 'onItemActivate'
46
- >;
47
- compactStatus?: boolean;
48
- includeSettings?: boolean;
49
- maxPrimarySidebarSizePercent?: number;
50
- minPrimarySidebarSizePercent?: number;
51
- onActivityActivate?: (
52
- event: WorkbenchActivityChangeEvent<TActivityId>,
53
- context: WorkbenchStandaloneShellContext<TActivityId, TTheme>,
54
- ) => void;
55
- onActivityBarContextMenu?: (
56
- event: MouseEvent<HTMLElement>,
57
- context: WorkbenchStandaloneShellContext<TActivityId, TTheme>,
58
- ) => void;
59
- onActivityBarItemActivate?: (
60
- itemId: TActivityId | string,
61
- context: WorkbenchStandaloneShellContext<TActivityId, TTheme>,
62
- ) => void;
63
- onStatusItemActivate?: (
64
- item: StatusBarItemModel,
65
- context: WorkbenchStandaloneShellContext<TActivityId, TTheme>,
66
- ) => void;
67
- onEvent?: (event: WorkbenchStandaloneBootstrapEvent<TActivityId>) => void;
68
- renderPrimarySidebar: (
69
- context: WorkbenchStandaloneShellContext<TActivityId, TTheme>,
70
- ) => ReactNode;
71
- renderOverlays?: (context: WorkbenchStandaloneShellContext<TActivityId, TTheme>) => ReactNode;
72
- renderSecondaryArea: (context: WorkbenchStandaloneShellContext<TActivityId, TTheme>) => ReactNode;
73
- rootClassName?: string;
74
- rootStyle?: CSSProperties;
75
- settingsItemIcon?: ReactNode;
76
- settingsItemId?: string;
77
- settingsItemLabel?: string;
78
- primarySidebarClassName?: string;
79
- primarySidebarStyle?: CSSProperties;
80
- getStatusSections?: (
81
- context: WorkbenchStandaloneShellContext<TActivityId, TTheme>,
82
- ) => StatusBarSectionModel[];
83
- }
84
-
85
- function toWorkbenchActivityItems<TActivityId extends string>(
86
- activities: WorkbenchActivityDescriptor<TActivityId>[],
87
- ): Array<{ icon: ReactNode; id: TActivityId; label: string }> {
88
- return activities.map((activity) => ({
89
- id: activity.id,
90
- label: activity.label,
91
- icon:
92
- activity.iconNode ?? (activity.icon ? <i className={`codicon ${activity.icon}`} /> : null),
93
- }));
94
- }
95
-
96
- export function WorkbenchStandaloneShell<
97
- TActivityId extends string = string,
98
- TTheme extends WorkbenchTheme = WorkbenchTheme,
99
- >({
100
- bootstrap,
101
- activityBar,
102
- compactStatus = true,
103
- includeSettings = true,
104
- maxPrimarySidebarSizePercent,
105
- minPrimarySidebarSizePercent,
106
- onActivityActivate,
107
- onActivityBarContextMenu,
108
- onActivityBarItemActivate,
109
- onStatusItemActivate,
110
- onEvent,
111
- renderPrimarySidebar,
112
- renderOverlays,
113
- renderSecondaryArea,
114
- rootClassName,
115
- rootStyle,
116
- settingsItemIcon,
117
- settingsItemId = 'settings',
118
- settingsItemLabel = 'Settings',
119
- primarySidebarClassName,
120
- primarySidebarStyle,
121
- getStatusSections,
122
- }: WorkbenchStandaloneShellProps<TActivityId, TTheme>) {
123
- const { contract, initialState } = bootstrap;
124
- const activityIds = useMemo(
125
- () => new Set(contract.activities.map((activity) => activity.id)),
126
- [contract.activities],
127
- );
128
-
129
- const shell = useWorkbenchShellState<TActivityId, TTheme>({
130
- activeActivityId:
131
- initialState?.activeActivityId ??
132
- contract.activities[0]?.id ??
133
- (DEFAULT_ACTIVITY_ID as TActivityId),
134
- isPrimarySidebarVisible: initialState?.isPrimarySidebarVisible ?? true,
135
- isSettingsOpen: initialState?.isSettingsOpen ?? false,
136
- primarySidebarSizePercent: initialState?.primarySidebarSizePercent ?? 24,
137
- settingsCategoryId: initialState?.settingsCategoryId ?? '',
138
- settingsScopeId: initialState?.settingsScopeId ?? '',
139
- settingsSearchValue: initialState?.settingsSearchValue ?? '',
140
- theme: (initialState?.theme ?? contract.initialTheme ?? DEFAULT_THEME) as TTheme,
141
- });
142
- const {
143
- isPrimarySidebarVisible,
144
- isSettingsOpen,
145
- primarySidebarSizePercent,
146
- theme,
147
- activeActivityId,
148
- } = shell.state;
149
-
150
- const emitEvent = (event: WorkbenchStandaloneBootstrapEvent<TActivityId>) => {
151
- onEvent?.(event);
152
- };
153
- const showActivity = (activityId: TActivityId) => {
154
- shell.showActivity(activityId);
155
- emitEvent({ type: 'activity-change', payload: { nextActivityId: activityId } });
156
- onActivityActivate?.(
157
- { nextActivityId: activityId },
158
- createContext({
159
- activityId,
160
- shell,
161
- }),
162
- );
163
- };
164
- const activateActivity = (activityId: TActivityId) => {
165
- shell.activateActivity(activityId);
166
- emitEvent({ type: 'activity-change', payload: { nextActivityId: activityId } });
167
- onActivityActivate?.(
168
- { nextActivityId: activityId },
169
- createContext({
170
- activityId,
171
- shell,
172
- }),
173
- );
174
- };
175
- const createContext = ({
176
- activityId,
177
- shell,
178
- }: {
179
- activityId: TActivityId;
180
- shell: ReturnType<typeof useWorkbenchShellState<TActivityId, TTheme>>;
181
- }): WorkbenchStandaloneShellContext<TActivityId, TTheme> => ({
182
- activityId,
183
- commandContext: {
184
- isPrimarySidebarVisible,
185
- openSettings: shell.openSettings,
186
- showActivity: shell.showActivity,
187
- togglePrimarySidebar: shell.togglePrimarySidebar,
188
- },
189
- showActivity,
190
- activateActivity,
191
- setTheme: shell.setTheme,
192
- setPrimarySidebarSizePercent: shell.setPrimarySidebarSizePercent,
193
- setPrimarySidebarVisible: shell.setPrimarySidebarVisible,
194
- togglePrimarySidebar: shell.togglePrimarySidebar,
195
- openSettings: shell.openSettings,
196
- closeSettings: shell.closeSettings,
197
- setSettingsCategoryId: shell.setSettingsCategoryId,
198
- setSettingsScopeId: shell.setSettingsScopeId,
199
- setSettingsSearchValue: shell.setSettingsSearchValue,
200
- });
201
-
202
- const context = useMemo(
203
- () => createContext({ activityId: activeActivityId, shell }),
204
- [shell, activeActivityId, isPrimarySidebarVisible],
205
- );
206
-
207
- const statusSections = useMemo(
208
- () =>
209
- getStatusSections?.(context) ??
210
- contract.statusSections.map((section) => ({
211
- ...section,
212
- items: section.items.map((item) => ({ ...item })),
213
- })),
214
- [contract.statusSections, context, getStatusSections],
215
- );
216
-
217
- const activityItems = useMemo(
218
- () => toWorkbenchActivityItems(contract.activities),
219
- [contract.activities],
220
- );
221
- const activityBarItems = useMemo(
222
- () =>
223
- activityItems.map((item) => ({
224
- ...item,
225
- active: item.id === activeActivityId,
226
- })),
227
- [activityItems, activeActivityId],
228
- );
229
-
230
- const hasSettingsSection = includeSettings && settingsItemId !== '';
231
-
232
- const primarySidebarNode = renderPrimarySidebar(context);
233
- const secondaryArea = renderSecondaryArea(context);
234
- const overlays = renderOverlays?.(context);
235
-
236
- return (
237
- <WorkbenchShell
238
- activityBar={{
239
- ...activityBar,
240
- items: activityBarItems,
241
- secondaryItems: hasSettingsSection
242
- ? [
243
- {
244
- id: settingsItemId,
245
- icon: settingsItemIcon ?? <i className="codicon codicon-settings-gear" />,
246
- label: settingsItemLabel,
247
- active: isSettingsOpen,
248
- },
249
- ]
250
- : [],
251
- onContextMenu: (event) => onActivityBarContextMenu?.(event, context),
252
- onItemActivate: (item) => {
253
- if (item.id === settingsItemId) {
254
- shell.openSettings();
255
- emitEvent({
256
- type: 'status-message',
257
- message: `Settings ${isSettingsOpen ? 'opened' : 'closed'}`,
258
- });
259
- return;
260
- }
261
-
262
- if (activityIds.has(item.id as TActivityId)) {
263
- activateActivity(item.id as TActivityId);
264
- onActivityBarItemActivate?.(item.id, context);
265
- return;
266
- }
267
-
268
- onActivityBarItemActivate?.(item.id, context);
269
- },
270
- }}
271
- compactStatus={compactStatus}
272
- onStatusItemActivate={(item) => onStatusItemActivate?.(item, context)}
273
- primarySidebar={{
274
- className: primarySidebarClassName,
275
- isVisible: isPrimarySidebarVisible,
276
- maxPrimarySizePercent: maxPrimarySidebarSizePercent,
277
- minPrimarySizePercent: minPrimarySidebarSizePercent,
278
- onSizePercentChange: shell.setPrimarySidebarSizePercent,
279
- primarySizePercent: primarySidebarSizePercent,
280
- node: primarySidebarNode,
281
- style: primarySidebarStyle,
282
- }}
283
- rootClassName={rootClassName}
284
- rootStyle={rootStyle}
285
- secondaryArea={secondaryArea}
286
- statusSections={statusSections}
287
- theme={theme}
288
- overlays={overlays}
289
- />
290
- );
291
- }
1
+ import { useMemo } from 'react';
2
+ import type { CSSProperties, MouseEvent, ReactNode } from 'react';
3
+ import { cxCodicon } from '../utils/codicon';
4
+ import type { StatusBarItemModel, StatusBarSectionModel } from './StatusBar';
5
+ import type { WorkbenchShellProps } from './WorkbenchShell';
6
+ import { WorkbenchShell } from './WorkbenchShell';
7
+ import type { WorkbenchShellCommandContext } from './commands';
8
+ import { DEFAULT_PRIMARY_SIDEBAR_SIZE_PERCENT, useWorkbenchShellState } from './shellState';
9
+ import type {
10
+ WorkbenchActivityChangeEvent,
11
+ WorkbenchActivityDescriptor,
12
+ WorkbenchStandaloneBootstrap,
13
+ WorkbenchStandaloneBootstrapEvent,
14
+ WorkbenchTheme,
15
+ } from './standalone';
16
+ import { WorkspaceDraftsProvider } from './workspace/WorkspaceDraftsContext';
17
+
18
+ const DEFAULT_THEME: WorkbenchTheme = 'dark';
19
+ const DEFAULT_ACTIVITY_ID = 'explorer';
20
+
21
+ /**
22
+ * Stable host context passed to `WorkbenchStandaloneShell` render and event callbacks.
23
+ * See `docs/workbench/standalone-host.md` for the public contract.
24
+ */
25
+ export interface WorkbenchStandaloneShellContext<
26
+ TActivityId extends string = string,
27
+ TTheme extends WorkbenchTheme = WorkbenchTheme,
28
+ > {
29
+ activityId: TActivityId;
30
+ commandContext: WorkbenchShellCommandContext<TActivityId>;
31
+ isPrimarySidebarVisible: boolean;
32
+ isSettingsOpen: boolean;
33
+ primarySidebarSizePercent: number;
34
+ theme: TTheme;
35
+ showActivity: (activityId: TActivityId) => void;
36
+ activateActivity: (activityId: TActivityId) => void;
37
+ setTheme: (theme: TTheme) => void;
38
+ setPrimarySidebarSizePercent: (sizePercent: number) => void;
39
+ setPrimarySidebarVisible: (isVisible: boolean) => void;
40
+ togglePrimarySidebar: () => void;
41
+ openSettings: () => void;
42
+ closeSettings: () => void;
43
+ setSettingsCategoryId: (settingsCategoryId: string) => void;
44
+ setSettingsScopeId: (settingsScopeId: string) => void;
45
+ setSettingsSearchValue: (settingsSearchValue: string) => void;
46
+ }
47
+
48
+ /**
49
+ * Props for the standalone workbench chrome host. Supply `bootstrap` plus render
50
+ * callbacks; the shell manages activity, theme, sidebar, and settings visibility.
51
+ */
52
+ export interface WorkbenchStandaloneShellProps<
53
+ TActivityId extends string = string,
54
+ TTheme extends WorkbenchTheme = WorkbenchTheme,
55
+ > {
56
+ bootstrap: WorkbenchStandaloneBootstrap<TActivityId>;
57
+ activityBar?: Omit<
58
+ WorkbenchShellProps['activityBar'],
59
+ 'items' | 'secondaryItems' | 'onContextMenu' | 'onItemActivate'
60
+ >;
61
+ compactStatus?: boolean;
62
+ includeSettings?: boolean;
63
+ maxPrimarySidebarSizePercent?: number;
64
+ minPrimarySidebarSizePercent?: number;
65
+ onActivityActivate?: (
66
+ event: WorkbenchActivityChangeEvent<TActivityId>,
67
+ context: WorkbenchStandaloneShellContext<TActivityId, TTheme>,
68
+ ) => void;
69
+ onActivityBarContextMenu?: (
70
+ event: MouseEvent<HTMLElement>,
71
+ context: WorkbenchStandaloneShellContext<TActivityId, TTheme>,
72
+ ) => void;
73
+ onActivityBarItemActivate?: (
74
+ itemId: TActivityId | string,
75
+ context: WorkbenchStandaloneShellContext<TActivityId, TTheme>,
76
+ ) => void;
77
+ onStatusItemActivate?: (
78
+ item: StatusBarItemModel,
79
+ context: WorkbenchStandaloneShellContext<TActivityId, TTheme>,
80
+ ) => void;
81
+ onEvent?: (event: WorkbenchStandaloneBootstrapEvent<TActivityId>) => void;
82
+ renderPrimarySidebar: (
83
+ context: WorkbenchStandaloneShellContext<TActivityId, TTheme>,
84
+ ) => ReactNode;
85
+ renderOverlays?: (context: WorkbenchStandaloneShellContext<TActivityId, TTheme>) => ReactNode;
86
+ renderSecondaryArea: (context: WorkbenchStandaloneShellContext<TActivityId, TTheme>) => ReactNode;
87
+ rootClassName?: string;
88
+ rootStyle?: CSSProperties;
89
+ settingsItemIcon?: ReactNode;
90
+ settingsItemId?: string;
91
+ settingsItemLabel?: string;
92
+ primarySidebarClassName?: string;
93
+ primarySidebarStyle?: CSSProperties;
94
+ getStatusSections?: (
95
+ context: WorkbenchStandaloneShellContext<TActivityId, TTheme>,
96
+ ) => StatusBarSectionModel[];
97
+ }
98
+
99
+ function toWorkbenchActivityItems<TActivityId extends string>(
100
+ activities: WorkbenchActivityDescriptor<TActivityId>[],
101
+ ): Array<{ icon: ReactNode; id: TActivityId; label: string }> {
102
+ return activities.map((activity) => ({
103
+ id: activity.id,
104
+ label: activity.label,
105
+ icon: activity.iconNode ?? (activity.icon ? <i className={cxCodicon(activity.icon)} /> : null),
106
+ }));
107
+ }
108
+
109
+ export function WorkbenchStandaloneShell<
110
+ TActivityId extends string = string,
111
+ TTheme extends WorkbenchTheme = WorkbenchTheme,
112
+ >({
113
+ bootstrap,
114
+ activityBar,
115
+ compactStatus = true,
116
+ includeSettings = true,
117
+ maxPrimarySidebarSizePercent,
118
+ minPrimarySidebarSizePercent,
119
+ onActivityActivate,
120
+ onActivityBarContextMenu,
121
+ onActivityBarItemActivate,
122
+ onStatusItemActivate,
123
+ onEvent,
124
+ renderPrimarySidebar,
125
+ renderOverlays,
126
+ renderSecondaryArea,
127
+ rootClassName,
128
+ rootStyle,
129
+ settingsItemIcon,
130
+ settingsItemId = 'settings',
131
+ settingsItemLabel = 'Settings',
132
+ primarySidebarClassName,
133
+ primarySidebarStyle,
134
+ getStatusSections,
135
+ }: WorkbenchStandaloneShellProps<TActivityId, TTheme>) {
136
+ const { contract, initialState } = bootstrap;
137
+ const activityIds = useMemo(
138
+ () => new Set(contract.activities.map((activity) => activity.id)),
139
+ [contract.activities],
140
+ );
141
+
142
+ const shell = useWorkbenchShellState<TActivityId, TTheme>({
143
+ activeActivityId:
144
+ initialState?.activeActivityId ??
145
+ contract.activities[0]?.id ??
146
+ (DEFAULT_ACTIVITY_ID as TActivityId),
147
+ isPrimarySidebarVisible: initialState?.isPrimarySidebarVisible ?? true,
148
+ isSettingsOpen: initialState?.isSettingsOpen ?? false,
149
+ primarySidebarSizePercent:
150
+ initialState?.primarySidebarSizePercent ?? DEFAULT_PRIMARY_SIDEBAR_SIZE_PERCENT,
151
+ settingsCategoryId: initialState?.settingsCategoryId ?? '',
152
+ settingsScopeId: initialState?.settingsScopeId ?? '',
153
+ settingsSearchValue: initialState?.settingsSearchValue ?? '',
154
+ theme: (initialState?.theme ?? contract.initialTheme ?? DEFAULT_THEME) as TTheme,
155
+ });
156
+ const {
157
+ isPrimarySidebarVisible,
158
+ isSettingsOpen,
159
+ primarySidebarSizePercent,
160
+ theme,
161
+ activeActivityId,
162
+ } = shell.state;
163
+
164
+ const emitEvent = (event: WorkbenchStandaloneBootstrapEvent<TActivityId>) => {
165
+ onEvent?.(event);
166
+ };
167
+ const showActivity = (activityId: TActivityId) => {
168
+ shell.showActivity(activityId);
169
+ emitEvent({ type: 'activity-change', payload: { nextActivityId: activityId } });
170
+ onActivityActivate?.(
171
+ { nextActivityId: activityId },
172
+ createContext({
173
+ activityId,
174
+ shell,
175
+ }),
176
+ );
177
+ };
178
+ const activateActivity = (activityId: TActivityId) => {
179
+ shell.activateActivity(activityId);
180
+ emitEvent({ type: 'activity-change', payload: { nextActivityId: activityId } });
181
+ onActivityActivate?.(
182
+ { nextActivityId: activityId },
183
+ createContext({
184
+ activityId,
185
+ shell,
186
+ }),
187
+ );
188
+ };
189
+ const createContext = ({
190
+ activityId,
191
+ shell,
192
+ }: {
193
+ activityId: TActivityId;
194
+ shell: ReturnType<typeof useWorkbenchShellState<TActivityId, TTheme>>;
195
+ }): WorkbenchStandaloneShellContext<TActivityId, TTheme> => ({
196
+ activityId,
197
+ commandContext: {
198
+ isPrimarySidebarVisible,
199
+ openSettings: shell.openSettings,
200
+ showActivity: shell.showActivity,
201
+ togglePrimarySidebar: shell.togglePrimarySidebar,
202
+ },
203
+ isPrimarySidebarVisible,
204
+ isSettingsOpen,
205
+ primarySidebarSizePercent,
206
+ theme,
207
+ showActivity,
208
+ activateActivity,
209
+ setTheme: shell.setTheme,
210
+ setPrimarySidebarSizePercent: shell.setPrimarySidebarSizePercent,
211
+ setPrimarySidebarVisible: shell.setPrimarySidebarVisible,
212
+ togglePrimarySidebar: shell.togglePrimarySidebar,
213
+ openSettings: shell.openSettings,
214
+ closeSettings: shell.closeSettings,
215
+ setSettingsCategoryId: shell.setSettingsCategoryId,
216
+ setSettingsScopeId: shell.setSettingsScopeId,
217
+ setSettingsSearchValue: shell.setSettingsSearchValue,
218
+ });
219
+
220
+ const context = useMemo(
221
+ () => createContext({ activityId: activeActivityId, shell }),
222
+ [
223
+ shell,
224
+ activeActivityId,
225
+ isPrimarySidebarVisible,
226
+ isSettingsOpen,
227
+ primarySidebarSizePercent,
228
+ theme,
229
+ ],
230
+ );
231
+
232
+ const statusSections = useMemo(
233
+ () =>
234
+ getStatusSections?.(context) ??
235
+ contract.statusSections.map((section) => ({
236
+ ...section,
237
+ items: section.items.map((item) => ({ ...item })),
238
+ })),
239
+ [contract.statusSections, context, getStatusSections],
240
+ );
241
+
242
+ const activityItems = useMemo(
243
+ () => toWorkbenchActivityItems(contract.activities),
244
+ [contract.activities],
245
+ );
246
+ const activityBarItems = useMemo(
247
+ () =>
248
+ activityItems.map((item) => ({
249
+ ...item,
250
+ active: item.id === activeActivityId,
251
+ })),
252
+ [activityItems, activeActivityId],
253
+ );
254
+
255
+ const hasSettingsSection = includeSettings && settingsItemId !== '';
256
+
257
+ const primarySidebarNode = renderPrimarySidebar(context);
258
+ const secondaryArea = renderSecondaryArea(context);
259
+ const overlays = renderOverlays?.(context);
260
+
261
+ return (
262
+ <WorkspaceDraftsProvider>
263
+ <WorkbenchShell
264
+ activityBar={{
265
+ ...activityBar,
266
+ items: activityBarItems,
267
+ secondaryItems: hasSettingsSection
268
+ ? [
269
+ {
270
+ id: settingsItemId,
271
+ icon: settingsItemIcon ?? <i className="codicon codicon-settings-gear" />,
272
+ label: settingsItemLabel,
273
+ active: isSettingsOpen,
274
+ },
275
+ ]
276
+ : [],
277
+ onContextMenu: (event) => onActivityBarContextMenu?.(event, context),
278
+ onItemActivate: (item) => {
279
+ if (item.id === settingsItemId) {
280
+ shell.openSettings();
281
+ emitEvent({
282
+ type: 'status-message',
283
+ message: `Settings ${isSettingsOpen ? 'opened' : 'closed'}`,
284
+ });
285
+ return;
286
+ }
287
+
288
+ if (activityIds.has(item.id as TActivityId)) {
289
+ activateActivity(item.id as TActivityId);
290
+ onActivityBarItemActivate?.(item.id, context);
291
+ return;
292
+ }
293
+
294
+ onActivityBarItemActivate?.(item.id, context);
295
+ },
296
+ }}
297
+ compactStatus={compactStatus}
298
+ onStatusItemActivate={(item) => onStatusItemActivate?.(item, context)}
299
+ primarySidebar={{
300
+ className: primarySidebarClassName,
301
+ isVisible: isPrimarySidebarVisible,
302
+ maxPrimarySizePercent: maxPrimarySidebarSizePercent,
303
+ minPrimarySizePercent: minPrimarySidebarSizePercent,
304
+ onSizePercentChange: shell.setPrimarySidebarSizePercent,
305
+ primarySizePercent: primarySidebarSizePercent,
306
+ node: primarySidebarNode,
307
+ style: primarySidebarStyle,
308
+ }}
309
+ rootClassName={rootClassName}
310
+ rootStyle={rootStyle}
311
+ secondaryArea={secondaryArea}
312
+ statusSections={statusSections}
313
+ theme={theme}
314
+ overlays={overlays}
315
+ />
316
+ </WorkspaceDraftsProvider>
317
+ );
318
+ }