@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
@@ -0,0 +1,415 @@
1
+ import {
2
+ Fragment,
3
+ useEffect,
4
+ useRef,
5
+ useState,
6
+ type ComponentPropsWithRef,
7
+ type ReactNode,
8
+ } from 'react';
9
+ import { IconButton } from '../../primitives/IconButton';
10
+ import { cx } from '../../utils/cx';
11
+ import { WorkbenchNavigationPanel } from './NavigationPanel';
12
+ import {
13
+ WORKBENCH_SECTIONED_PANEL_SCROLL_SPY_OFFSET,
14
+ createWorkbenchSectionedPanelIntersectionRootMargin,
15
+ isWorkbenchSectionedPanelScrollable,
16
+ resolveWorkbenchSectionedPanelActiveAnchorFromScroll,
17
+ resolveWorkbenchSectionedPanelScrollTop,
18
+ } from './sectionedPanelScrollSpy';
19
+
20
+ const PROGRAMMATIC_SCROLL_SETTLE_MS = 400;
21
+
22
+ export interface WorkbenchSectionedPanelItem {
23
+ anchorId: string;
24
+ count?: number | undefined;
25
+ render: () => ReactNode;
26
+ title: ReactNode;
27
+ }
28
+
29
+ export interface WorkbenchSectionedPanelProps extends Omit<
30
+ ComponentPropsWithRef<'div'>,
31
+ 'children'
32
+ > {
33
+ activeAnchorId?: string | undefined;
34
+ ariaLabel: string;
35
+ contentClassName?: string | undefined;
36
+ defaultActiveAnchorId?: string | undefined;
37
+ items: readonly WorkbenchSectionedPanelItem[];
38
+ navClassName?: string | undefined;
39
+ navLinkClassName?: string | undefined;
40
+ onActiveAnchorChange?: ((anchorId: string | undefined) => void) | undefined;
41
+ onSectionNavCollapsedChange?: ((collapsed: boolean) => void) | undefined;
42
+ readOnly?: boolean | undefined;
43
+ scrollSpy?: boolean | 'auto' | undefined;
44
+ sectionNavCollapsed?: boolean | undefined;
45
+ sectionNavCollapsible?: boolean | undefined;
46
+ defaultSectionNavCollapsed?: boolean | undefined;
47
+ }
48
+
49
+ function findPanelSection(content: HTMLElement, anchorId: string) {
50
+ return (
51
+ Array.from(content.children).find(
52
+ (child): child is HTMLElement => child instanceof HTMLElement && child.id === anchorId,
53
+ ) ?? null
54
+ );
55
+ }
56
+
57
+ function readSectionTop(content: HTMLElement, section: HTMLElement) {
58
+ if (section.parentElement === content) {
59
+ return section.offsetTop;
60
+ }
61
+
62
+ const containerRect = content.getBoundingClientRect();
63
+ const sectionRect = section.getBoundingClientRect();
64
+ return sectionRect.top - containerRect.top + content.scrollTop;
65
+ }
66
+
67
+ export function WorkbenchSectionedPanel({
68
+ activeAnchorId,
69
+ ariaLabel,
70
+ className,
71
+ contentClassName,
72
+ defaultActiveAnchorId,
73
+ items,
74
+ navClassName,
75
+ navLinkClassName,
76
+ onActiveAnchorChange,
77
+ onSectionNavCollapsedChange,
78
+ readOnly = false,
79
+ scrollSpy = 'auto',
80
+ sectionNavCollapsed,
81
+ sectionNavCollapsible,
82
+ defaultSectionNavCollapsed = false,
83
+ ...props
84
+ }: WorkbenchSectionedPanelProps) {
85
+ const contentRef = useRef<HTMLDivElement | null>(null);
86
+ const isProgrammaticScrollRef = useRef(false);
87
+ const programmaticScrollTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
88
+ const intersectionObserverRef = useRef<IntersectionObserver | null>(null);
89
+ const scrollSpyRafRef = useRef<number | null>(null);
90
+ const trackedActiveAnchorIdRef = useRef<string | undefined>(undefined);
91
+ const scrollSpyEnabledRef = useRef(false);
92
+ const [scrollSpyEnabled, setScrollSpyEnabled] = useState(false);
93
+ const [uncontrolledActiveAnchorId, setUncontrolledActiveAnchorId] = useState<string | undefined>(
94
+ defaultActiveAnchorId ?? items[0]?.anchorId,
95
+ );
96
+ const showSectionNav = items.length > 1;
97
+ const canCollapseSectionNav = showSectionNav && (sectionNavCollapsible ?? true);
98
+ const [uncontrolledSectionNavCollapsed, setUncontrolledSectionNavCollapsed] = useState(
99
+ defaultSectionNavCollapsed,
100
+ );
101
+ const sectionNavIsCollapsed =
102
+ canCollapseSectionNav && (sectionNavCollapsed ?? uncontrolledSectionNavCollapsed);
103
+ const anchorOrder = items.map((item) => item.anchorId);
104
+ const preferredActiveAnchorId = activeAnchorId ?? uncontrolledActiveAnchorId;
105
+ const resolvedActiveAnchorId =
106
+ preferredActiveAnchorId && items.some((item) => item.anchorId === preferredActiveAnchorId)
107
+ ? preferredActiveAnchorId
108
+ : items[0]?.anchorId;
109
+
110
+ trackedActiveAnchorIdRef.current = resolvedActiveAnchorId;
111
+
112
+ const setSectionNavCollapsed = (collapsed: boolean) => {
113
+ if (sectionNavCollapsed === undefined) {
114
+ setUncontrolledSectionNavCollapsed(collapsed);
115
+ }
116
+
117
+ onSectionNavCollapsedChange?.(collapsed);
118
+ };
119
+
120
+ const commitActiveAnchorId = (anchorId: string | undefined) => {
121
+ if (!anchorId || anchorId === trackedActiveAnchorIdRef.current) {
122
+ return;
123
+ }
124
+
125
+ trackedActiveAnchorIdRef.current = anchorId;
126
+
127
+ if (activeAnchorId === undefined) {
128
+ setUncontrolledActiveAnchorId(anchorId);
129
+ }
130
+
131
+ onActiveAnchorChange?.(anchorId);
132
+ };
133
+
134
+ const setActiveAnchorId = (anchorId: string | undefined) => {
135
+ if (!anchorId) return;
136
+
137
+ trackedActiveAnchorIdRef.current = anchorId;
138
+
139
+ if (activeAnchorId === undefined) {
140
+ setUncontrolledActiveAnchorId(anchorId);
141
+ }
142
+
143
+ onActiveAnchorChange?.(anchorId);
144
+ };
145
+
146
+ const resolveScrollSpyEnabled = (content: HTMLElement) => {
147
+ if (scrollSpy === false) return false;
148
+ if (scrollSpy === true) return true;
149
+ return isWorkbenchSectionedPanelScrollable({
150
+ clientHeight: content.clientHeight,
151
+ scrollHeight: content.scrollHeight,
152
+ });
153
+ };
154
+
155
+ const updateScrollSpyEnabled = () => {
156
+ const content = contentRef.current;
157
+ if (!content) return false;
158
+
159
+ const nextEnabled = resolveScrollSpyEnabled(content);
160
+ scrollSpyEnabledRef.current = nextEnabled;
161
+ setScrollSpyEnabled(nextEnabled);
162
+ return nextEnabled;
163
+ };
164
+
165
+ const readSectionPositions = (content: HTMLElement) =>
166
+ items
167
+ .map((item) => {
168
+ const section = findPanelSection(content, item.anchorId);
169
+ if (!section) return null;
170
+
171
+ return {
172
+ anchorId: item.anchorId,
173
+ top: readSectionTop(content, section),
174
+ };
175
+ })
176
+ .filter((section): section is { anchorId: string; top: number } => section !== null);
177
+
178
+ const applyScrollSpyActiveAnchor = () => {
179
+ scrollSpyRafRef.current = null;
180
+
181
+ const content = contentRef.current;
182
+ if (
183
+ !content ||
184
+ items.length === 0 ||
185
+ !scrollSpyEnabledRef.current ||
186
+ isProgrammaticScrollRef.current
187
+ ) {
188
+ return;
189
+ }
190
+
191
+ const nextActive = resolveWorkbenchSectionedPanelActiveAnchorFromScroll({
192
+ anchorOrder,
193
+ clientHeight: content.clientHeight,
194
+ fallbackAnchorId: items[0]?.anchorId,
195
+ scrollHeight: content.scrollHeight,
196
+ scrollTop: content.scrollTop,
197
+ sectionPositions: readSectionPositions(content),
198
+ });
199
+
200
+ commitActiveAnchorId(nextActive);
201
+ };
202
+
203
+ const scheduleScrollSpyUpdate = () => {
204
+ if (scrollSpyRafRef.current !== null) return;
205
+
206
+ scrollSpyRafRef.current = requestAnimationFrame(applyScrollSpyActiveAnchor);
207
+ };
208
+
209
+ const handleIntersection = () => {
210
+ if (items.length === 0 || !scrollSpyEnabledRef.current || isProgrammaticScrollRef.current) {
211
+ return;
212
+ }
213
+
214
+ scheduleScrollSpyUpdate();
215
+ };
216
+
217
+ const disconnectIntersectionObserver = () => {
218
+ intersectionObserverRef.current?.disconnect();
219
+ intersectionObserverRef.current = null;
220
+ };
221
+
222
+ const setupIntersectionObserver = () => {
223
+ const content = contentRef.current;
224
+ if (!content || typeof IntersectionObserver === 'undefined' || !scrollSpyEnabledRef.current) {
225
+ disconnectIntersectionObserver();
226
+ return;
227
+ }
228
+
229
+ disconnectIntersectionObserver();
230
+
231
+ const observer = new IntersectionObserver(handleIntersection, {
232
+ root: content,
233
+ rootMargin: createWorkbenchSectionedPanelIntersectionRootMargin(
234
+ WORKBENCH_SECTIONED_PANEL_SCROLL_SPY_OFFSET,
235
+ ),
236
+ threshold: [0],
237
+ });
238
+
239
+ for (const item of items) {
240
+ const section = findPanelSection(content, item.anchorId);
241
+ if (section) {
242
+ observer.observe(section);
243
+ }
244
+ }
245
+
246
+ intersectionObserverRef.current = observer;
247
+ };
248
+
249
+ const refreshScrollSpy = () => {
250
+ const enabled = updateScrollSpyEnabled();
251
+ if (enabled) {
252
+ setupIntersectionObserver();
253
+ scheduleScrollSpyUpdate();
254
+ return;
255
+ }
256
+
257
+ disconnectIntersectionObserver();
258
+ };
259
+
260
+ const scrollToSection = (anchorId: string) => {
261
+ const content = contentRef.current;
262
+ if (!content) {
263
+ setActiveAnchorId(anchorId);
264
+ return;
265
+ }
266
+
267
+ const section = findPanelSection(content, anchorId);
268
+ if (!section) {
269
+ setActiveAnchorId(anchorId);
270
+ return;
271
+ }
272
+
273
+ setActiveAnchorId(anchorId);
274
+
275
+ if (!scrollSpyEnabledRef.current) {
276
+ return;
277
+ }
278
+
279
+ const targetTop = resolveWorkbenchSectionedPanelScrollTop({
280
+ sectionTop: readSectionTop(content, section),
281
+ });
282
+
283
+ isProgrammaticScrollRef.current = true;
284
+ content.scrollTo({ top: targetTop });
285
+
286
+ if (programmaticScrollTimerRef.current) {
287
+ clearTimeout(programmaticScrollTimerRef.current);
288
+ }
289
+
290
+ programmaticScrollTimerRef.current = setTimeout(() => {
291
+ isProgrammaticScrollRef.current = false;
292
+ scheduleScrollSpyUpdate();
293
+ }, PROGRAMMATIC_SCROLL_SETTLE_MS);
294
+ };
295
+
296
+ useEffect(() => {
297
+ const content = contentRef.current;
298
+ if (!content) return undefined;
299
+
300
+ refreshScrollSpy();
301
+
302
+ const resizeObserver =
303
+ typeof ResizeObserver === 'undefined'
304
+ ? null
305
+ : new ResizeObserver(() => {
306
+ refreshScrollSpy();
307
+ });
308
+ resizeObserver?.observe(content);
309
+
310
+ return () => {
311
+ resizeObserver?.disconnect();
312
+ disconnectIntersectionObserver();
313
+
314
+ if (scrollSpyRafRef.current !== null) {
315
+ cancelAnimationFrame(scrollSpyRafRef.current);
316
+ scrollSpyRafRef.current = null;
317
+ }
318
+ };
319
+ }, [items, scrollSpy]);
320
+
321
+ useEffect(
322
+ () => () => {
323
+ if (programmaticScrollTimerRef.current) {
324
+ clearTimeout(programmaticScrollTimerRef.current);
325
+ }
326
+
327
+ if (scrollSpyRafRef.current !== null) {
328
+ cancelAnimationFrame(scrollSpyRafRef.current);
329
+ scrollSpyRafRef.current = null;
330
+ }
331
+
332
+ disconnectIntersectionObserver();
333
+ },
334
+ [],
335
+ );
336
+
337
+ const sectionNavLinks = items.map((item) => {
338
+ const active = resolvedActiveAnchorId === item.anchorId;
339
+
340
+ return (
341
+ <a
342
+ key={item.anchorId}
343
+ aria-current={active ? 'location' : undefined}
344
+ className={cx('ui-workbench-sectioned-panel__nav-link', navLinkClassName)}
345
+ data-active={active ? 'true' : undefined}
346
+ href={`#${item.anchorId}`}
347
+ onClick={(event) => {
348
+ event.preventDefault();
349
+ scrollToSection(item.anchorId);
350
+ }}
351
+ >
352
+ <span>{item.title}</span>
353
+ {item.count !== undefined ? <em>{item.count}</em> : null}
354
+ </a>
355
+ );
356
+ });
357
+
358
+ return (
359
+ <div className="ui-workbench-sectioned-panel-host">
360
+ <WorkbenchNavigationPanel
361
+ className={cx('ui-workbench-sectioned-panel', className)}
362
+ content={
363
+ <div
364
+ ref={contentRef}
365
+ className="ui-workbench-sectioned-panel__scroll"
366
+ onScroll={scheduleScrollSpyUpdate}
367
+ >
368
+ {items.map((item) => (
369
+ <Fragment key={item.anchorId}>{item.render()}</Fragment>
370
+ ))}
371
+ </div>
372
+ }
373
+ contentClassName={cx('ui-workbench-sectioned-panel__body', contentClassName)}
374
+ data-nav-collapsed={sectionNavIsCollapsed ? 'true' : undefined}
375
+ data-readonly={readOnly ? 'true' : undefined}
376
+ data-scroll-spy={scrollSpyEnabled ? 'true' : 'false'}
377
+ nav={
378
+ showSectionNav && !sectionNavIsCollapsed ? (
379
+ <div className="ui-workbench-sectioned-panel__nav-shell">
380
+ <div className="ui-workbench-sectioned-panel__nav-links">{sectionNavLinks}</div>
381
+ {canCollapseSectionNav ? (
382
+ <div className="ui-workbench-sectioned-panel__nav-footer">
383
+ <IconButton
384
+ compact
385
+ className="ui-workbench-sectioned-panel__nav-toggle"
386
+ icon="codicon-chevron-left"
387
+ label="Hide section navigation"
388
+ onClick={() => setSectionNavCollapsed(true)}
389
+ />
390
+ </div>
391
+ ) : null}
392
+ </div>
393
+ ) : null
394
+ }
395
+ navClassName={cx('ui-workbench-sectioned-panel__nav', navClassName)}
396
+ navProps={{ 'aria-label': ariaLabel }}
397
+ {...props}
398
+ />
399
+
400
+ {sectionNavIsCollapsed && canCollapseSectionNav ? (
401
+ <div className="ui-workbench-sectioned-panel__nav-reveal-zone">
402
+ <div className="ui-workbench-sectioned-panel__nav-open-overlay">
403
+ <IconButton
404
+ compact
405
+ className="ui-workbench-sectioned-panel__nav-toggle ui-workbench-sectioned-panel__nav-toggle--overlay"
406
+ icon="codicon-chevron-right"
407
+ label="Show section navigation"
408
+ onClick={() => setSectionNavCollapsed(false)}
409
+ />
410
+ </div>
411
+ </div>
412
+ ) : null}
413
+ </div>
414
+ );
415
+ }