@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,559 @@
1
+ import { useId, type ReactNode } from 'react';
2
+ import { Button } from '../../primitives/Button';
3
+ import { Field } from '../../primitives/Field';
4
+ import { IconButton } from '../../primitives/IconButton';
5
+ import { ScrollArea } from '../../primitives/ScrollArea';
6
+ import { cx } from '../../utils/cx';
7
+ import { WorkbenchSectionedPanel } from './SectionedPanel';
8
+ import {
9
+ WorkbenchStructuredDataSchemaFieldInput,
10
+ appendWorkbenchStructuredDataSchemaTableRow,
11
+ asWorkbenchStructuredDataRecord,
12
+ createWorkbenchStructuredDataSchemaDocumentEmptyRow,
13
+ createWorkbenchStructuredDataSchemaFallbackSection,
14
+ formatWorkbenchStructuredDataSchemaLabel,
15
+ formatWorkbenchStructuredDataSchemaValue,
16
+ getWorkbenchStructuredDataSchemaDocumentColumnDefinition,
17
+ getWorkbenchStructuredDataSchemaDocumentColumnLabel,
18
+ getWorkbenchStructuredDataSchemaDocumentFieldLabel,
19
+ getWorkbenchStructuredDataSchemaDocumentPanelData,
20
+ getWorkbenchStructuredDataSchemaDocumentSectionValue,
21
+ getWorkbenchStructuredDataSchemaDocumentSections,
22
+ getWorkbenchStructuredDataSchemaDocumentTableColumns,
23
+ getWorkbenchStructuredDataSchemaFieldDataPath,
24
+ getWorkbenchStructuredDataSchemaFieldDescription,
25
+ getWorkbenchStructuredDataSchemaSectionAnchorId,
26
+ getWorkbenchStructuredDataSchemaSectionId,
27
+ getWorkbenchStructuredDataSchemaTableCellPath,
28
+ getWorkbenchStructuredDataSchemaTablePath,
29
+ getWorkbenchStructuredDataSchemaTableRowKey,
30
+ getWorkbenchStructuredDataSchemaTableRows,
31
+ getWorkbenchStructuredDataValue,
32
+ removeWorkbenchStructuredDataSchemaTableRow,
33
+ setWorkbenchStructuredDataPathOrRootValue,
34
+ type WorkbenchStructuredDataSchemaDocument,
35
+ type WorkbenchStructuredDataSchemaSectionAliases,
36
+ type WorkbenchStructuredDataSchemaSectionSummary,
37
+ type WorkbenchStructuredDataPath,
38
+ } from './StructuredDataForm';
39
+
40
+ export interface WorkbenchStructuredDataSchemaPanelClassNames {
41
+ checkbox?: string | undefined;
42
+ empty?: string | undefined;
43
+ field?: string | undefined;
44
+ fieldInput?: string | undefined;
45
+ root?: string | undefined;
46
+ section?: string | undefined;
47
+ sectionActions?: string | undefined;
48
+ sectionHeader?: string | undefined;
49
+ settingControl?: string | undefined;
50
+ settingControlTextarea?: string | undefined;
51
+ settingRow?: string | undefined;
52
+ settingsList?: string | undefined;
53
+ tableActions?: string | undefined;
54
+ tableEditor?: string | undefined;
55
+ tableFooter?: string | undefined;
56
+ tableGrid?: string | undefined;
57
+ tableHeaderRow?: string | undefined;
58
+ tableRow?: string | undefined;
59
+ tableScroll?: string | undefined;
60
+ }
61
+
62
+ export interface WorkbenchStructuredDataSchemaPanelLabels {
63
+ addRow?: ReactNode | undefined;
64
+ addTextArrayItem?: ReactNode | undefined;
65
+ deleteRow?: string | undefined;
66
+ removeTextArrayItem?: string | undefined;
67
+ }
68
+
69
+ export interface WorkbenchStructuredDataSchemaPanelProps {
70
+ activePattern?: string | undefined;
71
+ ariaLabel: string;
72
+ classNames?: WorkbenchStructuredDataSchemaPanelClassNames | undefined;
73
+ data: unknown;
74
+ fill?: boolean | undefined;
75
+ headerActions?: ReactNode | undefined;
76
+ labels?: WorkbenchStructuredDataSchemaPanelLabels | undefined;
77
+ preferredTableColumns?: readonly string[] | undefined;
78
+ readOnly?: boolean | undefined;
79
+ schema: WorkbenchStructuredDataSchemaDocument | null | undefined;
80
+ sectionValueAliases?: WorkbenchStructuredDataSchemaSectionAliases | undefined;
81
+ titleFallback?: string | undefined;
82
+ onDataChange?: ((data: unknown) => void) | undefined;
83
+ }
84
+
85
+ interface WorkbenchStructuredDataSchemaSectionView {
86
+ data: unknown;
87
+ schema: WorkbenchStructuredDataSchemaDocument | null | undefined;
88
+ section: WorkbenchStructuredDataSchemaSectionSummary;
89
+ value: unknown;
90
+ }
91
+
92
+ const defaultSchemaPanelClassNames: Required<WorkbenchStructuredDataSchemaPanelClassNames> = {
93
+ checkbox: 'ui-workbench-structured-data-schema-panel__checkbox',
94
+ empty: 'ui-workbench-structured-data-schema-panel__empty',
95
+ field: 'ui-workbench-structured-data-schema-panel__field',
96
+ fieldInput: 'ui-workbench-structured-data-schema-panel__field-input',
97
+ root: 'ui-workbench-structured-data-schema-panel',
98
+ section: 'ui-workbench-structured-data-schema-panel__section',
99
+ sectionActions: 'ui-workbench-structured-data-schema-panel__section-actions',
100
+ sectionHeader: 'ui-workbench-structured-data-schema-panel__section-header',
101
+ settingControl: 'ui-workbench-structured-data-schema-panel__control',
102
+ settingControlTextarea: 'ui-workbench-structured-data-schema-panel__control--textarea',
103
+ settingRow: 'ui-workbench-structured-data-schema-panel__setting-row',
104
+ settingsList: 'ui-workbench-structured-data-schema-panel__settings-list',
105
+ tableActions: 'ui-workbench-structured-data-schema-panel__table-actions',
106
+ tableEditor: 'ui-workbench-structured-data-schema-panel__table-editor',
107
+ tableFooter: 'ui-workbench-structured-data-schema-panel__table-footer',
108
+ tableGrid: 'ui-workbench-structured-data-schema-panel__table-grid',
109
+ tableHeaderRow:
110
+ 'ui-workbench-structured-data-schema-panel__table-row ui-workbench-structured-data-schema-panel__table-row--head',
111
+ tableRow: 'ui-workbench-structured-data-schema-panel__table-row',
112
+ tableScroll: 'ui-workbench-structured-data-schema-panel__table-scroll',
113
+ };
114
+
115
+ function resolveSchemaPanelClassNames(
116
+ classNames: WorkbenchStructuredDataSchemaPanelClassNames | undefined,
117
+ ): Required<WorkbenchStructuredDataSchemaPanelClassNames> {
118
+ return Object.fromEntries(
119
+ Object.entries(defaultSchemaPanelClassNames).map(([key, className]) => [
120
+ key,
121
+ cx(className, classNames?.[key as keyof WorkbenchStructuredDataSchemaPanelClassNames]),
122
+ ]),
123
+ ) as Required<WorkbenchStructuredDataSchemaPanelClassNames>;
124
+ }
125
+
126
+ function getSchemaFieldValue({
127
+ data,
128
+ fieldPath,
129
+ section,
130
+ sectionValue,
131
+ }: {
132
+ data: unknown;
133
+ fieldPath: string;
134
+ section: WorkbenchStructuredDataSchemaSectionSummary;
135
+ sectionValue: unknown;
136
+ }) {
137
+ const fullPath = getWorkbenchStructuredDataSchemaFieldDataPath(section, fieldPath);
138
+ const rootValue = getWorkbenchStructuredDataValue(data, fullPath.split('.'));
139
+ if (rootValue !== null && rootValue !== undefined) return rootValue;
140
+
141
+ const record = asWorkbenchStructuredDataRecord(sectionValue);
142
+ return record?.[fieldPath] ?? null;
143
+ }
144
+
145
+ function renderSchemaFormSection({
146
+ classNames = {},
147
+ data,
148
+ labels = {},
149
+ onDataValueChange,
150
+ readOnly,
151
+ schema,
152
+ section,
153
+ value,
154
+ }: WorkbenchStructuredDataSchemaSectionView & {
155
+ classNames?: WorkbenchStructuredDataSchemaPanelClassNames | undefined;
156
+ labels?: WorkbenchStructuredDataSchemaPanelLabels | undefined;
157
+ onDataValueChange: (path: string[], value: unknown) => void;
158
+ readOnly: boolean;
159
+ }) {
160
+ const fields = section.fields ?? [];
161
+ if (fields.length) {
162
+ return (
163
+ <div className={classNames.settingsList}>
164
+ {fields.map((fieldPath) => {
165
+ const definition = getWorkbenchStructuredDataSchemaDocumentColumnDefinition(
166
+ schema,
167
+ section,
168
+ fieldPath,
169
+ );
170
+ const dataPath = getWorkbenchStructuredDataSchemaFieldDataPath(section, fieldPath);
171
+
172
+ return (
173
+ <div key={fieldPath} className={classNames.settingRow}>
174
+ <Field
175
+ className={classNames.field}
176
+ description={getWorkbenchStructuredDataSchemaFieldDescription(definition)}
177
+ label={getWorkbenchStructuredDataSchemaDocumentFieldLabel(
178
+ schema,
179
+ section,
180
+ fieldPath,
181
+ )}
182
+ >
183
+ <div className={classNames.fieldInput}>
184
+ <WorkbenchStructuredDataSchemaFieldInput
185
+ addTextArrayLabel={labels.addTextArrayItem}
186
+ checkboxClassName={classNames.checkbox}
187
+ className={classNames.settingControl}
188
+ definition={definition}
189
+ fieldPath={dataPath}
190
+ readOnly={readOnly}
191
+ removeTextArrayLabel={labels.removeTextArrayItem}
192
+ textareaClassName={classNames.settingControlTextarea}
193
+ value={getSchemaFieldValue({ data, fieldPath, section, sectionValue: value })}
194
+ onValueChange={(nextValue) => onDataValueChange(dataPath.split('.'), nextValue)}
195
+ />
196
+ </div>
197
+ </Field>
198
+ </div>
199
+ );
200
+ })}
201
+ </div>
202
+ );
203
+ }
204
+
205
+ const record = asWorkbenchStructuredDataRecord(value);
206
+ if (!record) {
207
+ return <p className={classNames.empty}>{formatWorkbenchStructuredDataSchemaValue(value)}</p>;
208
+ }
209
+
210
+ return (
211
+ <div className={classNames.settingsList}>
212
+ {Object.entries(record)
213
+ .slice(0, 10)
214
+ .map(([key, entry]) => (
215
+ <div key={key} className={classNames.settingRow}>
216
+ <Field
217
+ className={classNames.field}
218
+ label={formatWorkbenchStructuredDataSchemaLabel(key)}
219
+ >
220
+ <div className={classNames.fieldInput}>
221
+ <WorkbenchStructuredDataSchemaFieldInput
222
+ checkboxClassName={classNames.checkbox}
223
+ className={classNames.settingControl}
224
+ definition={undefined}
225
+ fieldPath={key}
226
+ readOnly={readOnly}
227
+ textareaClassName={classNames.settingControlTextarea}
228
+ value={entry}
229
+ onValueChange={(nextValue) =>
230
+ onDataValueChange(
231
+ getWorkbenchStructuredDataSchemaFieldDataPath(section, key).split('.'),
232
+ nextValue,
233
+ )
234
+ }
235
+ />
236
+ </div>
237
+ </Field>
238
+ </div>
239
+ ))}
240
+ </div>
241
+ );
242
+ }
243
+
244
+ function renderSchemaTableSection({
245
+ classNames = {},
246
+ labels = {},
247
+ onDataValueChange,
248
+ preferredTableColumns = [],
249
+ readOnly,
250
+ schema,
251
+ section,
252
+ value,
253
+ ...sectionView
254
+ }: WorkbenchStructuredDataSchemaSectionView & {
255
+ classNames?: WorkbenchStructuredDataSchemaPanelClassNames | undefined;
256
+ labels?: WorkbenchStructuredDataSchemaPanelLabels | undefined;
257
+ onDataValueChange: (path: string[], value: unknown) => void;
258
+ preferredTableColumns?: readonly string[] | undefined;
259
+ readOnly: boolean;
260
+ }) {
261
+ const rows = getWorkbenchStructuredDataSchemaTableRows(value);
262
+ const columns = getWorkbenchStructuredDataSchemaDocumentTableColumns({
263
+ preferredColumns: preferredTableColumns,
264
+ rows,
265
+ schema,
266
+ section,
267
+ });
268
+ if (!rows.length || !columns.length) {
269
+ return renderSchemaFormSection({
270
+ ...sectionView,
271
+ classNames,
272
+ labels,
273
+ onDataValueChange,
274
+ readOnly,
275
+ schema,
276
+ section,
277
+ value,
278
+ });
279
+ }
280
+
281
+ const tablePathSegments = getWorkbenchStructuredDataSchemaTablePath(section);
282
+ const isArrayTable = Array.isArray(value);
283
+
284
+ return (
285
+ <div className={classNames.tableEditor}>
286
+ <ScrollArea className={classNames.tableScroll} gutter="auto" orientation="both">
287
+ <div className={classNames.tableGrid} role="table">
288
+ <div className={classNames.tableHeaderRow} role="row">
289
+ {columns.map((column) => (
290
+ <span key={column} role="columnheader">
291
+ {getWorkbenchStructuredDataSchemaDocumentColumnLabel(schema, section, column)}
292
+ </span>
293
+ ))}
294
+ {readOnly ? null : <span role="columnheader">Actions</span>}
295
+ </div>
296
+ {rows.slice(0, 12).map((row, rowIndex) => {
297
+ const rowKey = getWorkbenchStructuredDataSchemaTableRowKey({ row, rowIndex, value });
298
+
299
+ return (
300
+ <div key={rowKey} className={classNames.tableRow} role="row">
301
+ {columns.map((column) => (
302
+ <span key={column} role="cell">
303
+ <WorkbenchStructuredDataSchemaFieldInput
304
+ addTextArrayLabel={labels.addTextArrayItem}
305
+ checkboxClassName={classNames.checkbox}
306
+ className={classNames.settingControl}
307
+ definition={getWorkbenchStructuredDataSchemaDocumentColumnDefinition(
308
+ schema,
309
+ section,
310
+ column,
311
+ )}
312
+ fieldPath={column}
313
+ readOnly={readOnly}
314
+ removeTextArrayLabel={labels.removeTextArrayItem}
315
+ textareaClassName={classNames.settingControlTextarea}
316
+ value={row[column]}
317
+ onValueChange={(nextValue) => {
318
+ onDataValueChange(
319
+ getWorkbenchStructuredDataSchemaTableCellPath({
320
+ column,
321
+ rowKey,
322
+ section,
323
+ }),
324
+ nextValue,
325
+ );
326
+ }}
327
+ />
328
+ </span>
329
+ ))}
330
+ {readOnly ? null : (
331
+ <span className={classNames.tableActions} role="cell">
332
+ <IconButton
333
+ compact
334
+ icon="trash"
335
+ label={labels.deleteRow ?? 'Delete row'}
336
+ onClick={() => {
337
+ onDataValueChange(
338
+ tablePathSegments,
339
+ removeWorkbenchStructuredDataSchemaTableRow({
340
+ rowIndex,
341
+ rowKey,
342
+ value,
343
+ }),
344
+ );
345
+ }}
346
+ />
347
+ </span>
348
+ )}
349
+ </div>
350
+ );
351
+ })}
352
+ </div>
353
+ </ScrollArea>
354
+ {readOnly ? null : (
355
+ <div className={classNames.tableFooter}>
356
+ <Button
357
+ onClick={() => {
358
+ const emptyRow = createWorkbenchStructuredDataSchemaDocumentEmptyRow({
359
+ columns,
360
+ schema,
361
+ section,
362
+ });
363
+ if (isArrayTable && Array.isArray(value)) {
364
+ onDataValueChange(
365
+ tablePathSegments,
366
+ appendWorkbenchStructuredDataSchemaTableRow({
367
+ row: emptyRow,
368
+ rowKey: '',
369
+ value,
370
+ }),
371
+ );
372
+ return;
373
+ }
374
+
375
+ const nextKey = `row_${Date.now()}`;
376
+ onDataValueChange(
377
+ tablePathSegments,
378
+ appendWorkbenchStructuredDataSchemaTableRow({
379
+ row: emptyRow,
380
+ rowKey: nextKey,
381
+ value,
382
+ }),
383
+ );
384
+ }}
385
+ >
386
+ {labels.addRow ?? 'Add row'}
387
+ </Button>
388
+ </div>
389
+ )}
390
+ </div>
391
+ );
392
+ }
393
+
394
+ function renderSchemaPanelSection({
395
+ anchorId,
396
+ classNames = {},
397
+ headerActions,
398
+ labels,
399
+ onDataValueChange,
400
+ preferredTableColumns,
401
+ readOnly,
402
+ sectionView,
403
+ }: {
404
+ anchorId?: string | undefined;
405
+ classNames?: WorkbenchStructuredDataSchemaPanelClassNames | undefined;
406
+ headerActions?: ReactNode | undefined;
407
+ labels?: WorkbenchStructuredDataSchemaPanelLabels | undefined;
408
+ onDataValueChange: (path: string[], value: unknown) => void;
409
+ preferredTableColumns?: readonly string[] | undefined;
410
+ readOnly: boolean;
411
+ sectionView: WorkbenchStructuredDataSchemaSectionView;
412
+ }) {
413
+ const { section, value } = sectionView;
414
+ const isTable = section.type === 'table' || Array.isArray(value);
415
+ const sectionId = getWorkbenchStructuredDataSchemaSectionId(section);
416
+
417
+ return (
418
+ <section
419
+ key={anchorId ?? sectionId ?? section.title}
420
+ className={classNames.section}
421
+ id={anchorId}
422
+ >
423
+ <header className={classNames.sectionHeader}>
424
+ <div>
425
+ <h2>{section.title ?? sectionId ?? 'Data'}</h2>
426
+ </div>
427
+ {headerActions ? <div className={classNames.sectionActions}>{headerActions}</div> : null}
428
+ </header>
429
+ {isTable
430
+ ? renderSchemaTableSection({
431
+ ...sectionView,
432
+ classNames,
433
+ labels,
434
+ onDataValueChange,
435
+ preferredTableColumns,
436
+ readOnly,
437
+ })
438
+ : renderSchemaFormSection({
439
+ ...sectionView,
440
+ classNames,
441
+ labels,
442
+ onDataValueChange,
443
+ readOnly,
444
+ })}
445
+ </section>
446
+ );
447
+ }
448
+
449
+ export function WorkbenchStructuredDataSchemaPanel({
450
+ activePattern,
451
+ ariaLabel,
452
+ classNames,
453
+ data,
454
+ fill = false,
455
+ headerActions,
456
+ labels,
457
+ preferredTableColumns,
458
+ readOnly = false,
459
+ schema,
460
+ sectionValueAliases,
461
+ titleFallback = 'Data',
462
+ onDataChange,
463
+ }: WorkbenchStructuredDataSchemaPanelProps) {
464
+ const resolvedClassNames = resolveSchemaPanelClassNames(classNames);
465
+ const panelId = useId().replace(/:/g, '');
466
+ const pattern = activePattern ?? schema?.activePattern ?? schema?.pattern ?? 'DBtoDB';
467
+ const panelData = getWorkbenchStructuredDataSchemaDocumentPanelData({ data, pattern, schema });
468
+ const schemaSections = getWorkbenchStructuredDataSchemaDocumentSections(schema, pattern);
469
+ const sections = schemaSections.length
470
+ ? schemaSections
471
+ : [
472
+ createWorkbenchStructuredDataSchemaFallbackSection({
473
+ data: panelData,
474
+ title: titleFallback,
475
+ }),
476
+ ];
477
+ const sectionItems = sections.map((section, index) => ({
478
+ anchorId: getWorkbenchStructuredDataSchemaSectionAnchorId({ index, panelId, section }),
479
+ count: section.fields?.length ?? section.columns?.length ?? section.fieldCount,
480
+ section,
481
+ title: section.title ?? getWorkbenchStructuredDataSchemaSectionId(section) ?? 'Data',
482
+ }));
483
+
484
+ const handleDataValueChange = (path: string[], value: unknown) => {
485
+ if (readOnly) return;
486
+ if (!path.length) {
487
+ onDataChange?.(value);
488
+ return;
489
+ }
490
+
491
+ let resolvedPath: WorkbenchStructuredDataPath = path;
492
+ const [sectionKey, ...rest] = path;
493
+ const aliases = sectionValueAliases?.[sectionKey];
494
+ if (aliases && aliases.length > 0) {
495
+ let foundAlias = false;
496
+ for (const aliasPath of aliases) {
497
+ if (aliasPath.length === 0) continue;
498
+ const val = getWorkbenchStructuredDataValue(panelData, aliasPath);
499
+ if (val !== null && val !== undefined) {
500
+ resolvedPath = [...aliasPath, ...rest];
501
+ foundAlias = true;
502
+ break;
503
+ }
504
+ }
505
+ if (!foundAlias) {
506
+ const firstAlias = aliases[0];
507
+ if (firstAlias !== undefined) {
508
+ resolvedPath = [...firstAlias, ...rest];
509
+ }
510
+ }
511
+ }
512
+
513
+ onDataChange?.(
514
+ setWorkbenchStructuredDataPathOrRootValue({
515
+ data: panelData,
516
+ path: resolvedPath,
517
+ value,
518
+ }),
519
+ );
520
+ };
521
+
522
+ return (
523
+ <WorkbenchSectionedPanel
524
+ ariaLabel={ariaLabel}
525
+ className={cx(
526
+ resolvedClassNames.root,
527
+ fill && 'ui-workbench-structured-data-schema-panel--fill',
528
+ )}
529
+ items={sectionItems.map(({ anchorId, count, section, title }, index) => ({
530
+ anchorId,
531
+ count,
532
+ title,
533
+ render: () =>
534
+ renderSchemaPanelSection({
535
+ anchorId,
536
+ classNames: resolvedClassNames,
537
+ headerActions: index === 0 ? headerActions : undefined,
538
+ labels,
539
+ onDataValueChange: handleDataValueChange,
540
+ preferredTableColumns,
541
+ readOnly,
542
+ sectionView: {
543
+ data: panelData,
544
+ schema,
545
+ section,
546
+ value: schemaSections.length
547
+ ? getWorkbenchStructuredDataSchemaDocumentSectionValue({
548
+ aliases: sectionValueAliases,
549
+ data: panelData,
550
+ section,
551
+ })
552
+ : panelData,
553
+ },
554
+ }),
555
+ }))}
556
+ readOnly={readOnly}
557
+ />
558
+ );
559
+ }
@@ -0,0 +1,21 @@
1
+ import type { ComponentPropsWithRef } from 'react';
2
+ import { cx } from '../../utils/cx';
3
+ import {
4
+ WorkbenchStructuredDataSchemaPanel,
5
+ type WorkbenchStructuredDataSchemaPanelProps,
6
+ } from './StructuredDataSchemaPanel';
7
+
8
+ export interface WorkbenchStructuredDataSchemaPanelEmbedProps
9
+ extends WorkbenchStructuredDataSchemaPanelProps, Omit<ComponentPropsWithRef<'div'>, 'children'> {}
10
+
11
+ export function WorkbenchStructuredDataSchemaPanelEmbed({
12
+ className,
13
+ fill = true,
14
+ ...panelProps
15
+ }: WorkbenchStructuredDataSchemaPanelEmbedProps) {
16
+ return (
17
+ <div className={cx('ui-workbench-structured-data-schema-panel-embed', className)}>
18
+ <WorkbenchStructuredDataSchemaPanel {...panelProps} fill={fill} />
19
+ </div>
20
+ );
21
+ }
@@ -0,0 +1,76 @@
1
+ import type { ComponentPropsWithRef, ReactNode } from 'react';
2
+ import { cx } from '../../utils/cx';
3
+ import {
4
+ WorkbenchStructuredDataSchemaPanelEmbed,
5
+ type WorkbenchStructuredDataSchemaPanelEmbedProps,
6
+ } from './StructuredDataSchemaPanelEmbed';
7
+
8
+ export interface WorkbenchStructuredDataSchemaPanelFrameHeaderContent {
9
+ eyebrow?: ReactNode | undefined;
10
+ icon?: ReactNode | undefined;
11
+ meta?: ReactNode | undefined;
12
+ subtitle?: ReactNode | undefined;
13
+ title?: ReactNode | undefined;
14
+ }
15
+
16
+ export interface WorkbenchStructuredDataSchemaPanelFrameProps extends WorkbenchStructuredDataSchemaPanelEmbedProps {
17
+ frameClassName?: string | undefined;
18
+ frameProps?: Omit<ComponentPropsWithRef<'div'>, 'children' | 'className'> | undefined;
19
+ header?: ReactNode | undefined;
20
+ headerClassName?: string | undefined;
21
+ headerContent?: WorkbenchStructuredDataSchemaPanelFrameHeaderContent | undefined;
22
+ }
23
+
24
+ function renderFrameHeaderContent(content: WorkbenchStructuredDataSchemaPanelFrameHeaderContent) {
25
+ return (
26
+ <>
27
+ <div className="ui-workbench-structured-data-schema-panel-frame__title-group">
28
+ {content.icon ? (
29
+ <span className="ui-workbench-structured-data-schema-panel-frame__icon">
30
+ {content.icon}
31
+ </span>
32
+ ) : null}
33
+ <div>
34
+ {content.eyebrow ? (
35
+ <span className="ui-workbench-structured-data-schema-panel-frame__eyebrow">
36
+ {content.eyebrow}
37
+ </span>
38
+ ) : null}
39
+ {content.title ? <h2>{content.title}</h2> : null}
40
+ {content.subtitle ? <p>{content.subtitle}</p> : null}
41
+ </div>
42
+ </div>
43
+ {content.meta ? (
44
+ <div className="ui-workbench-structured-data-schema-panel-frame__meta">{content.meta}</div>
45
+ ) : null}
46
+ </>
47
+ );
48
+ }
49
+
50
+ export function WorkbenchStructuredDataSchemaPanelFrame({
51
+ header,
52
+ headerClassName,
53
+ headerContent,
54
+ frameClassName,
55
+ frameProps,
56
+ className,
57
+ ...panelProps
58
+ }: WorkbenchStructuredDataSchemaPanelFrameProps) {
59
+ const resolvedHeader = header ?? (headerContent ? renderFrameHeaderContent(headerContent) : null);
60
+
61
+ return (
62
+ <div
63
+ className={cx('ui-workbench-structured-data-schema-panel-frame', frameClassName)}
64
+ {...frameProps}
65
+ >
66
+ {resolvedHeader ? (
67
+ <header
68
+ className={cx('ui-workbench-structured-data-schema-panel-frame__header', headerClassName)}
69
+ >
70
+ {resolvedHeader}
71
+ </header>
72
+ ) : null}
73
+ <WorkbenchStructuredDataSchemaPanelEmbed {...panelProps} className={className} />
74
+ </div>
75
+ );
76
+ }