@powerduck/schema-designer 0.1.0

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 (102) hide show
  1. package/README.md +217 -0
  2. package/dist/InlineSchemaEditor-BssSx3SI.d.ts +6 -0
  3. package/dist/InlineSchemaEditor-Bua-lDhE.d.cts +6 -0
  4. package/dist/chunk-2XUQB6BQ.js +1896 -0
  5. package/dist/chunk-4H3LXOL4.cjs +1900 -0
  6. package/dist/chunk-7LG4MVMD.cjs +2 -0
  7. package/dist/chunk-BXFABOMJ.js +1475 -0
  8. package/dist/chunk-FTALJIVZ.js +1 -0
  9. package/dist/chunk-GTZH37JS.cjs +1120 -0
  10. package/dist/chunk-GWHDTTQK.js +1437 -0
  11. package/dist/chunk-GXXD6ITE.cjs +1477 -0
  12. package/dist/chunk-HI5FBHCO.js +1057 -0
  13. package/dist/chunk-KX3LFFOV.js +88 -0
  14. package/dist/chunk-MADPN2PJ.js +185 -0
  15. package/dist/chunk-NOUORNCI.cjs +1452 -0
  16. package/dist/chunk-O6PTRJQ5.js +1195 -0
  17. package/dist/chunk-OBHJC3I2.cjs +2 -0
  18. package/dist/chunk-OOSNM45O.cjs +264 -0
  19. package/dist/chunk-P5B3HSPY.js +244 -0
  20. package/dist/chunk-PBE36BVA.js +1 -0
  21. package/dist/chunk-PVEYKCM6.js +1 -0
  22. package/dist/chunk-QZADGAP3.cjs +1218 -0
  23. package/dist/chunk-S7GNTGEE.js +1 -0
  24. package/dist/chunk-SMBDRWV2.cjs +2 -0
  25. package/dist/chunk-THYDOHOP.cjs +2 -0
  26. package/dist/chunk-WRHWOMZQ.cjs +190 -0
  27. package/dist/chunk-YNKP5JJA.cjs +32 -0
  28. package/dist/chunk-YWDKCX6N.cjs +91 -0
  29. package/dist/chunk-ZHNYNFGL.js +28 -0
  30. package/dist/compat/inline.cjs +137 -0
  31. package/dist/compat/inline.css +275 -0
  32. package/dist/compat/inline.d.cts +6 -0
  33. package/dist/compat/inline.d.ts +6 -0
  34. package/dist/compat/inline.js +4 -0
  35. package/dist/compat/parameters.cjs +90 -0
  36. package/dist/compat/parameters.css +997 -0
  37. package/dist/compat/parameters.d.cts +70 -0
  38. package/dist/compat/parameters.d.ts +70 -0
  39. package/dist/compat/parameters.js +9 -0
  40. package/dist/compat/tree.cjs +142 -0
  41. package/dist/compat/tree.css +1069 -0
  42. package/dist/compat/tree.d.cts +4 -0
  43. package/dist/compat/tree.d.ts +4 -0
  44. package/dist/compat/tree.js +5 -0
  45. package/dist/compat/variable-editor.cjs +82 -0
  46. package/dist/compat/variable-editor.d.cts +68 -0
  47. package/dist/compat/variable-editor.d.ts +68 -0
  48. package/dist/compat/variable-editor.js +1 -0
  49. package/dist/core/index.cjs +197 -0
  50. package/dist/core/index.d.cts +21 -0
  51. package/dist/core/index.d.ts +21 -0
  52. package/dist/core/index.js +4 -0
  53. package/dist/index.cjs +35 -0
  54. package/dist/index.css +1791 -0
  55. package/dist/index.d.cts +9 -0
  56. package/dist/index.d.ts +9 -0
  57. package/dist/index.js +10 -0
  58. package/dist/parameterValue-2pL9n-3q.d.ts +8 -0
  59. package/dist/parameterValue-Cky9Lnd3.d.cts +8 -0
  60. package/dist/react/index.cjs +35 -0
  61. package/dist/react/index.css +1791 -0
  62. package/dist/react/index.d.cts +9 -0
  63. package/dist/react/index.d.ts +9 -0
  64. package/dist/react/index.js +10 -0
  65. package/dist/react/inlineSchemaEditor/index.cjs +97 -0
  66. package/dist/react/inlineSchemaEditor/index.css +275 -0
  67. package/dist/react/inlineSchemaEditor/index.d.cts +6 -0
  68. package/dist/react/inlineSchemaEditor/index.d.ts +6 -0
  69. package/dist/react/inlineSchemaEditor/index.js +4 -0
  70. package/dist/react/parametersTable/index.cjs +22 -0
  71. package/dist/react/parametersTable/index.css +997 -0
  72. package/dist/react/parametersTable/index.d.cts +7 -0
  73. package/dist/react/parametersTable/index.d.ts +7 -0
  74. package/dist/react/parametersTable/index.js +9 -0
  75. package/dist/react/parametersTable/libs/generateValue.cjs +558 -0
  76. package/dist/react/parametersTable/libs/generateValue.d.cts +17 -0
  77. package/dist/react/parametersTable/libs/generateValue.d.ts +17 -0
  78. package/dist/react/parametersTable/libs/generateValue.js +551 -0
  79. package/dist/react/schemaTreeEditor/index.cjs +18 -0
  80. package/dist/react/schemaTreeEditor/index.css +1069 -0
  81. package/dist/react/schemaTreeEditor/index.d.cts +7 -0
  82. package/dist/react/schemaTreeEditor/index.d.ts +7 -0
  83. package/dist/react/schemaTreeEditor/index.js +5 -0
  84. package/dist/react/variableTextEditor/index.cjs +11 -0
  85. package/dist/react/variableTextEditor/index.css +306 -0
  86. package/dist/react/variableTextEditor/index.d.cts +6 -0
  87. package/dist/react/variableTextEditor/index.d.ts +6 -0
  88. package/dist/react/variableTextEditor/index.js +2 -0
  89. package/dist/schema-CKAPsYeW.d.cts +41 -0
  90. package/dist/schema-o7OJRaJ8.d.ts +41 -0
  91. package/dist/styles.css +1791 -0
  92. package/dist/tree-D06Xa6_N.d.ts +95 -0
  93. package/dist/tree-Dq1Rk-CF.d.cts +95 -0
  94. package/dist/types-B27Dw9do.d.cts +163 -0
  95. package/dist/types-B27Dw9do.d.ts +163 -0
  96. package/dist/types-Bk9rzr6l.d.cts +48 -0
  97. package/dist/types-D2jEaM9Z.d.cts +145 -0
  98. package/dist/types-D2jEaM9Z.d.ts +145 -0
  99. package/dist/types-xAihO_KW.d.ts +48 -0
  100. package/dist/variableTextEditor.types-ClzvARvK.d.cts +49 -0
  101. package/dist/variableTextEditor.types-ClzvARvK.d.ts +49 -0
  102. package/package.json +130 -0
@@ -0,0 +1,1195 @@
1
+ import { SettingsPanel, InlineSchemaEditor } from './chunk-2XUQB6BQ.js';
2
+ import { schemaTypeOf, typeLabel, isPlainObject, verifyExternalSchema, cloneSchema, safeRun, flattenSchema, isValidKey, getIn, renameKey, setIn, requiredOwnerPath, renameRequired, remapExpanded, patchSchema, changeSchemaType, pruneExpanded, setRequired, deleteIn, uniqueKey, insertKeyAfter, defaultSchemaFor, reorderKeys, samePath } from './chunk-HI5FBHCO.js';
3
+ import { VscSettingsCompact, VscTrash } from 'react-icons/vsc';
4
+ import * as React from 'react';
5
+ import { Input, createListCollection, Box, Button, Text, Select, Portal, Span, IconButton, Icon, Popover, Menu } from '@chakra-ui/react';
6
+ import { LuLink2 } from 'react-icons/lu';
7
+ import { BiGridVertical } from 'react-icons/bi';
8
+ import { MdAdd } from 'react-icons/md';
9
+ import { FaStarOfLife } from 'react-icons/fa6';
10
+ import { FiChevronRight } from 'react-icons/fi';
11
+ import { jsx, jsxs } from 'react/jsx-runtime';
12
+
13
+ // src/react/schemaTreeEditor/libs/types.ts
14
+ var SCHEMA_TYPES = [
15
+ "string",
16
+ "number",
17
+ "integer",
18
+ "boolean",
19
+ "object",
20
+ "array",
21
+ "null"
22
+ ];
23
+
24
+ // src/react/schemaTreeEditor/SchemaTreeEditor.module.css
25
+ var SchemaTreeEditor_default = {
26
+ nameInput: "SchemaTreeEditor_nameInput",
27
+ descriptionInput: "SchemaTreeEditor_descriptionInput",
28
+ typeSelect: "SchemaTreeEditor_typeSelect",
29
+ root: "SchemaTreeEditor_root",
30
+ toolbar: "SchemaTreeEditor_toolbar",
31
+ toolbarTitle: "SchemaTreeEditor_toolbarTitle",
32
+ toolbarMeta: "SchemaTreeEditor_toolbarMeta",
33
+ toolbarSpacer: "SchemaTreeEditor_toolbarSpacer",
34
+ ghostButton: "SchemaTreeEditor_ghostButton",
35
+ header: "SchemaTreeEditor_header",
36
+ row: "SchemaTreeEditor_row",
37
+ headerCell: "SchemaTreeEditor_headerCell",
38
+ list: "SchemaTreeEditor_list",
39
+ requiredToggle: "SchemaTreeEditor_requiredToggle",
40
+ dropLine: "SchemaTreeEditor_dropLine",
41
+ grip: "SchemaTreeEditor_grip",
42
+ gripPlaceholder: "SchemaTreeEditor_gripPlaceholder",
43
+ nameCell: "SchemaTreeEditor_nameCell",
44
+ chevron: "SchemaTreeEditor_chevron",
45
+ chevronPlaceholder: "SchemaTreeEditor_chevronPlaceholder",
46
+ inputRejected: "SchemaTreeEditor_inputRejected",
47
+ refBadge: "SchemaTreeEditor_refBadge",
48
+ refBadgeIcon: "SchemaTreeEditor_refBadgeIcon",
49
+ refBadgeText: "SchemaTreeEditor_refBadgeText",
50
+ recursiveBadge: "SchemaTreeEditor_recursiveBadge",
51
+ recursiveBadgeText: "SchemaTreeEditor_recursiveBadgeText",
52
+ typeCell: "SchemaTreeEditor_typeCell",
53
+ typeSelectContent: "SchemaTreeEditor_typeSelectContent",
54
+ typeSelectItem: "SchemaTreeEditor_typeSelectItem",
55
+ typeSelectOption: "SchemaTreeEditor_typeSelectOption",
56
+ typeStatic: "SchemaTreeEditor_typeStatic",
57
+ requiredCell: "SchemaTreeEditor_requiredCell",
58
+ descriptionCell: "SchemaTreeEditor_descriptionCell",
59
+ actions: "SchemaTreeEditor_actions",
60
+ iconButton: "SchemaTreeEditor_iconButton",
61
+ dangerArmed: "SchemaTreeEditor_dangerArmed",
62
+ menu: "SchemaTreeEditor_menu",
63
+ empty: "SchemaTreeEditor_empty",
64
+ emptyTitle: "SchemaTreeEditor_emptyTitle",
65
+ emptyHint: "SchemaTreeEditor_emptyHint",
66
+ notice: "SchemaTreeEditor_notice",
67
+ noticeText: "SchemaTreeEditor_noticeText",
68
+ fallback: "SchemaTreeEditor_fallback",
69
+ fallbackTitle: "SchemaTreeEditor_fallbackTitle",
70
+ fallbackMessage: "SchemaTreeEditor_fallbackMessage",
71
+ referenceGroup: "SchemaTreeEditor_referenceGroup",
72
+ tableViewport: "SchemaTreeEditor_tableViewport"
73
+ };
74
+ var INDENT_STEP = 14;
75
+ var DEFAULT_MAX_ROWS = 5e3;
76
+ var CONFIRM_TIMEOUT = 2600;
77
+ var REJECT_FLASH = 900;
78
+ var SchemaErrorBoundary = class extends React.Component {
79
+ state = { failed: false, message: "", retryKey: 0 };
80
+ static getDerivedStateFromError(error) {
81
+ return {
82
+ failed: true,
83
+ message: error instanceof Error ? error.message : String(error),
84
+ retryKey: 0
85
+ };
86
+ }
87
+ componentDidCatch(error) {
88
+ try {
89
+ this.props.onError?.({
90
+ scope: "render",
91
+ message: error instanceof Error ? error.message : String(error),
92
+ cause: error
93
+ });
94
+ } catch {
95
+ }
96
+ }
97
+ handleRetry = () => {
98
+ this.setState((state) => ({
99
+ failed: false,
100
+ message: "",
101
+ retryKey: state.retryKey + 1
102
+ }));
103
+ };
104
+ render() {
105
+ if (!this.state.failed) {
106
+ return /* @__PURE__ */ jsx(React.Fragment, { children: this.props.children }, this.state.retryKey);
107
+ }
108
+ return /* @__PURE__ */ jsxs(Box, { className: SchemaTreeEditor_default.fallback, role: "alert", children: [
109
+ /* @__PURE__ */ jsx(Text, { className: SchemaTreeEditor_default.fallbackTitle, children: "Schema view stopped responding" }),
110
+ /* @__PURE__ */ jsx(Text, { className: SchemaTreeEditor_default.fallbackMessage, children: this.state.message }),
111
+ /* @__PURE__ */ jsx(
112
+ Button,
113
+ {
114
+ className: SchemaTreeEditor_default.ghostButton,
115
+ onClick: this.handleRetry,
116
+ size: "xs",
117
+ children: "Reload view"
118
+ }
119
+ )
120
+ ] });
121
+ }
122
+ };
123
+ var BufferedInput = React.memo(
124
+ ({
125
+ value,
126
+ placeholder,
127
+ className,
128
+ disabled,
129
+ invalidHint,
130
+ ariaLabel,
131
+ onCommit
132
+ }) => {
133
+ const [sync, setSync] = React.useState(() => ({
134
+ draft: value,
135
+ external: value
136
+ }));
137
+ const [rejected, setRejected] = React.useState(false);
138
+ const focused = React.useRef(false);
139
+ const cancelCommit = React.useRef(false);
140
+ const rejectTimer = React.useRef(null);
141
+ const focusExternal = React.useRef(value);
142
+ React.useEffect(() => {
143
+ if (focused.current) return;
144
+ setSync(
145
+ (current) => current.draft === value && current.external === value ? current : { draft: value, external: value }
146
+ );
147
+ }, [value]);
148
+ React.useEffect(
149
+ () => () => {
150
+ if (rejectTimer.current !== null) {
151
+ window.clearTimeout(rejectTimer.current);
152
+ rejectTimer.current = null;
153
+ }
154
+ },
155
+ []
156
+ );
157
+ const flashRejected = React.useCallback(() => {
158
+ setRejected(true);
159
+ if (rejectTimer.current !== null)
160
+ window.clearTimeout(rejectTimer.current);
161
+ rejectTimer.current = window.setTimeout(() => {
162
+ rejectTimer.current = null;
163
+ setRejected(false);
164
+ }, REJECT_FLASH);
165
+ }, []);
166
+ const handleFocus = React.useCallback(() => {
167
+ focused.current = true;
168
+ focusExternal.current = value;
169
+ }, [value]);
170
+ const handleBlur = React.useCallback(() => {
171
+ focused.current = false;
172
+ if (cancelCommit.current || disabled) {
173
+ cancelCommit.current = false;
174
+ setSync({ draft: value, external: value });
175
+ return;
176
+ }
177
+ if (focusExternal.current !== value) {
178
+ setSync({ draft: value, external: value });
179
+ return;
180
+ }
181
+ if (sync.draft === value) {
182
+ setSync({ draft: value, external: value });
183
+ return;
184
+ }
185
+ const accepted = onCommit(sync.draft);
186
+ if (accepted === false) {
187
+ setSync({ draft: value, external: value });
188
+ flashRejected();
189
+ } else {
190
+ setSync({ draft: sync.draft, external: value });
191
+ }
192
+ }, [sync.draft, value, onCommit, flashRejected, disabled]);
193
+ const handleChange = React.useCallback(
194
+ (event) => {
195
+ const draft = event.target.value;
196
+ setSync((current) => ({ ...current, draft }));
197
+ },
198
+ []
199
+ );
200
+ const handleKeyDown = React.useCallback(
201
+ (event) => {
202
+ if (event.nativeEvent.isComposing) return;
203
+ if (event.key === "Enter") {
204
+ event.preventDefault();
205
+ event.currentTarget.blur();
206
+ } else if (event.key === "Escape") {
207
+ event.preventDefault();
208
+ cancelCommit.current = true;
209
+ setSync({ draft: value, external: value });
210
+ event.stopPropagation();
211
+ event.currentTarget.blur();
212
+ }
213
+ },
214
+ [value]
215
+ );
216
+ return /* @__PURE__ */ jsx(
217
+ Input,
218
+ {
219
+ className: [className, rejected ? SchemaTreeEditor_default.inputRejected : null].filter(Boolean).join(" "),
220
+ value: sync.draft,
221
+ placeholder,
222
+ disabled,
223
+ "aria-label": ariaLabel,
224
+ "aria-invalid": rejected || void 0,
225
+ title: rejected ? invalidHint : void 0,
226
+ spellCheck: false,
227
+ autoComplete: "off",
228
+ onFocus: handleFocus,
229
+ onChange: handleChange,
230
+ onBlur: handleBlur,
231
+ onKeyDown: handleKeyDown,
232
+ onMouseDown: (event) => event.stopPropagation()
233
+ }
234
+ );
235
+ }
236
+ );
237
+ BufferedInput.displayName = "BufferedInput";
238
+ var schemaTypeOptions = createListCollection({
239
+ items: SCHEMA_TYPES.map((t) => ({ label: t, value: t }))
240
+ });
241
+ var SchemaRow = React.memo(
242
+ ({ node, index, handlers }) => {
243
+ const [armed, setArmed] = React.useState(false);
244
+ const [draggable, setDraggable] = React.useState(false);
245
+ const confirmTimer = React.useRef(null);
246
+ const clearConfirmTimer = React.useCallback(() => {
247
+ if (confirmTimer.current !== null) {
248
+ window.clearTimeout(confirmTimer.current);
249
+ confirmTimer.current = null;
250
+ }
251
+ }, []);
252
+ React.useEffect(() => clearConfirmTimer, [clearConfirmTimer]);
253
+ const disarm = React.useCallback(() => {
254
+ clearConfirmTimer();
255
+ setArmed(false);
256
+ }, [clearConfirmTimer]);
257
+ React.useEffect(() => {
258
+ if (!armed) return;
259
+ const cancel = () => setArmed(false);
260
+ window.addEventListener("scroll", cancel, {
261
+ passive: true,
262
+ capture: true
263
+ });
264
+ window.addEventListener("resize", cancel);
265
+ window.addEventListener("blur", cancel);
266
+ document.addEventListener("visibilitychange", cancel);
267
+ return () => {
268
+ window.removeEventListener("scroll", cancel, {
269
+ capture: true
270
+ });
271
+ window.removeEventListener("resize", cancel);
272
+ window.removeEventListener("blur", cancel);
273
+ document.removeEventListener("visibilitychange", cancel);
274
+ };
275
+ }, [armed]);
276
+ const handleDeleteClick = React.useCallback(() => {
277
+ if (!armed) {
278
+ setArmed(true);
279
+ clearConfirmTimer();
280
+ confirmTimer.current = window.setTimeout(() => {
281
+ confirmTimer.current = null;
282
+ setArmed(false);
283
+ }, CONFIRM_TIMEOUT);
284
+ return;
285
+ }
286
+ disarm();
287
+ handlers.onDelete(node);
288
+ }, [armed, clearConfirmTimer, disarm, handlers, node]);
289
+ const rowEditable = handlers.editable && !node.readOnly;
290
+ const resolvedType = schemaTypeOf(node.resolved);
291
+ const canAddChild = rowEditable && resolvedType === "object" && !node.schema.$ref;
292
+ const handleRowKeyDown = React.useCallback(
293
+ (event) => {
294
+ if (!node.sortable || !rowEditable) return;
295
+ if (!event.metaKey && !event.ctrlKey) return;
296
+ if (event.key === "ArrowUp") {
297
+ event.preventDefault();
298
+ handlers.onKeyboardMove(node, -1);
299
+ } else if (event.key === "ArrowDown") {
300
+ event.preventDefault();
301
+ handlers.onKeyboardMove(node, 1);
302
+ }
303
+ },
304
+ [handlers, node, rowEditable]
305
+ );
306
+ const description = typeof node.resolved.description === "string" ? node.resolved.description : "";
307
+ return /* @__PURE__ */ jsxs(
308
+ Box,
309
+ {
310
+ className: SchemaTreeEditor_default.row,
311
+ style: { ["--row-depth"]: node.depth },
312
+ "data-ref-segment": node.refSegment,
313
+ "data-readonly": node.readOnly || void 0,
314
+ "data-required": node.required || void 0,
315
+ draggable: draggable || void 0,
316
+ "data-dragging": draggable || void 0,
317
+ onKeyDown: handleRowKeyDown,
318
+ onDragStart: (event) => handlers.onDragStart(node, index, event),
319
+ onDragOver: (event) => handlers.onDragOver(node, index, event),
320
+ onDrop: (event) => handlers.onDrop(node, index, event),
321
+ onDragEnd: () => setDraggable(false),
322
+ onMouseLeave: disarm,
323
+ role: "row",
324
+ children: [
325
+ /* @__PURE__ */ jsxs(
326
+ Box,
327
+ {
328
+ className: SchemaTreeEditor_default.nameCell,
329
+ role: "cell",
330
+ style: { paddingLeft: node.depth * INDENT_STEP },
331
+ children: [
332
+ node.sortable && rowEditable ? /* @__PURE__ */ jsx(
333
+ Box,
334
+ {
335
+ className: SchemaTreeEditor_default.grip,
336
+ "aria-label": `Reorder ${node.key}`,
337
+ title: "Drag to reorder, or Ctrl/Cmd with the arrow keys",
338
+ role: "button",
339
+ tabIndex: -1,
340
+ onMouseDown: () => setDraggable(true),
341
+ onMouseUp: () => setDraggable(false),
342
+ children: /* @__PURE__ */ jsx(BiGridVertical, {})
343
+ }
344
+ ) : /* @__PURE__ */ jsx(Box, { className: SchemaTreeEditor_default.gripPlaceholder }),
345
+ node.expandable ? /* @__PURE__ */ jsx(
346
+ Button,
347
+ {
348
+ className: SchemaTreeEditor_default.chevron,
349
+ "data-expanded": node.expanded || void 0,
350
+ "aria-expanded": node.expanded,
351
+ "aria-label": node.expanded ? `Collapse ${node.key}` : `Expand ${node.key}`,
352
+ onClick: () => handlers.onToggle(node),
353
+ size: "xs",
354
+ variant: "ghost",
355
+ children: /* @__PURE__ */ jsx(FiChevronRight, {})
356
+ }
357
+ ) : /* @__PURE__ */ jsx(Box, { className: SchemaTreeEditor_default.chevronPlaceholder }),
358
+ /* @__PURE__ */ jsx(
359
+ BufferedInput,
360
+ {
361
+ className: SchemaTreeEditor_default.nameInput,
362
+ value: node.key,
363
+ ariaLabel: "Field name",
364
+ placeholder: "fieldName",
365
+ disabled: !rowEditable || node.kind !== "property",
366
+ invalidHint: "Name is invalid or already used",
367
+ onCommit: (next) => handlers.onRename(node, next)
368
+ }
369
+ ),
370
+ node.refName ? /* @__PURE__ */ jsxs(
371
+ Box,
372
+ {
373
+ className: SchemaTreeEditor_default.refBadge,
374
+ title: `Reference: ${node.refName}`,
375
+ children: [
376
+ /* @__PURE__ */ jsx(LuLink2, { className: SchemaTreeEditor_default.refBadgeIcon, strokeWidth: 1.5 }),
377
+ /* @__PURE__ */ jsx(Text, { className: SchemaTreeEditor_default.refBadgeText, children: node.refName })
378
+ ]
379
+ }
380
+ ) : null,
381
+ node.recursive ? /* @__PURE__ */ jsx(
382
+ Box,
383
+ {
384
+ className: SchemaTreeEditor_default.recursiveBadge,
385
+ title: "Recursive reference, expansion stopped",
386
+ children: /* @__PURE__ */ jsx(Text, { className: SchemaTreeEditor_default.recursiveBadgeText, children: "recursive" })
387
+ }
388
+ ) : null
389
+ ]
390
+ }
391
+ ),
392
+ /* @__PURE__ */ jsx(Box, { role: "cell", className: SchemaTreeEditor_default.typeCell, children: typeof node.resolvedValue === "boolean" ? /* @__PURE__ */ jsx(Text, { className: SchemaTreeEditor_default.typeStatic, children: node.resolvedValue ? "Any value" : "Never" }) : rowEditable ? /* @__PURE__ */ jsxs(
393
+ Select.Root,
394
+ {
395
+ collection: schemaTypeOptions,
396
+ size: "xs",
397
+ multiple: false,
398
+ className: SchemaTreeEditor_default.typeSelect,
399
+ value: [resolvedType],
400
+ onValueChange: (details) => {
401
+ const nextType = details.value[0];
402
+ if (!nextType || !SCHEMA_TYPES.includes(nextType)) {
403
+ return;
404
+ }
405
+ handlers.onType(node, nextType);
406
+ },
407
+ children: [
408
+ /* @__PURE__ */ jsx(Select.HiddenSelect, {}),
409
+ /* @__PURE__ */ jsxs(Select.Control, { children: [
410
+ /* @__PURE__ */ jsx(Select.Trigger, { className: `${SchemaTreeEditor_default.typeSelectItem}`, children: /* @__PURE__ */ jsx(
411
+ Select.ValueText,
412
+ {
413
+ className: `${SchemaTreeEditor_default.typeSelectOption}`,
414
+ placeholder: "Select a schema type"
415
+ }
416
+ ) }),
417
+ /* @__PURE__ */ jsx(Select.IndicatorGroup, { children: /* @__PURE__ */ jsx(Select.Indicator, {}) })
418
+ ] }),
419
+ /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Select.Positioner, { children: /* @__PURE__ */ jsx(Select.Content, { className: SchemaTreeEditor_default.typeSelectContent, children: schemaTypeOptions.items.map((item) => /* @__PURE__ */ jsxs(
420
+ Select.Item,
421
+ {
422
+ "aria-label": "Field type",
423
+ item,
424
+ children: [
425
+ /* @__PURE__ */ jsx(Span, { className: `${SchemaTreeEditor_default.typeSelectOption}`, children: item.label }),
426
+ /* @__PURE__ */ jsx(Select.ItemIndicator, {})
427
+ ]
428
+ },
429
+ item.value
430
+ )) }) }) })
431
+ ]
432
+ }
433
+ ) : /* @__PURE__ */ jsx(Text, { className: SchemaTreeEditor_default.typeStatic, children: typeLabel(node.resolved) }) }),
434
+ /* @__PURE__ */ jsx(Box, { role: "cell", className: SchemaTreeEditor_default.requiredCell, children: /* @__PURE__ */ jsx(
435
+ IconButton,
436
+ {
437
+ className: `${SchemaTreeEditor_default.requiredToggle} ${node.required ? "required" : ""}`,
438
+ "data-on": node.required || void 0,
439
+ "aria-pressed": node.required,
440
+ "aria-label": node.required ? "Required, click to make optional" : "Optional, click to make required",
441
+ title: node.required ? "Required" : "Optional",
442
+ disabled: !rowEditable || node.kind !== "property",
443
+ onClick: () => handlers.onRequired(node, !node.required),
444
+ size: "xs",
445
+ variant: "ghost",
446
+ children: /* @__PURE__ */ jsx(Icon, { size: "xs", children: node.required ? /* @__PURE__ */ jsx(FaStarOfLife, {}) : /* @__PURE__ */ jsx(FaStarOfLife, {}) })
447
+ }
448
+ ) }),
449
+ /* @__PURE__ */ jsx(Box, { role: "cell", className: SchemaTreeEditor_default.descriptionCell, children: /* @__PURE__ */ jsx(
450
+ BufferedInput,
451
+ {
452
+ className: SchemaTreeEditor_default.descriptionInput,
453
+ value: description,
454
+ ariaLabel: "Field description",
455
+ placeholder: typeof node.value === "boolean" ? "Boolean schema" : "Describe this field",
456
+ disabled: !rowEditable || typeof node.value === "boolean",
457
+ onCommit: (next) => handlers.onDescription(node, next)
458
+ }
459
+ ) }),
460
+ /* @__PURE__ */ jsxs(Box, { role: "cell", className: SchemaTreeEditor_default.actions, children: [
461
+ handlers.renderAdvanced ? /* @__PURE__ */ jsxs(
462
+ Popover.Root,
463
+ {
464
+ positioning: {
465
+ placement: "bottom-end",
466
+ strategy: "fixed",
467
+ overflowPadding: 12
468
+ },
469
+ lazyMount: true,
470
+ unmountOnExit: true,
471
+ children: [
472
+ /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
473
+ Button,
474
+ {
475
+ className: SchemaTreeEditor_default.iconButton,
476
+ "aria-label": "Advanced settings",
477
+ title: "Advanced settings",
478
+ size: "xs",
479
+ variant: "ghost",
480
+ children: /* @__PURE__ */ jsx(VscSettingsCompact, { size: 16 })
481
+ }
482
+ ) }),
483
+ /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, { children: /* @__PURE__ */ jsx(SettingsPanel, { title: node.key, children: handlers.renderAdvanced({
484
+ required: node.required,
485
+ onRequiredChange: node.kind === "property" ? (value) => handlers.onRequired(node, value) : void 0,
486
+ nested: node.depth > 0,
487
+ schema: node.readOnly ? node.resolvedValue : node.value,
488
+ schemaName: node.key,
489
+ fullSchema: handlers.rootSchema,
490
+ path: node.path,
491
+ readOnly: !rowEditable,
492
+ // Overwritten by the owner's row binding.
493
+ update: () => void 0
494
+ }) }) }) })
495
+ ]
496
+ }
497
+ ) : null,
498
+ rowEditable ? /* @__PURE__ */ jsxs(
499
+ Menu.Root,
500
+ {
501
+ positioning: {
502
+ placement: "bottom-end",
503
+ strategy: "fixed",
504
+ overflowPadding: 12
505
+ },
506
+ lazyMount: true,
507
+ unmountOnExit: true,
508
+ children: [
509
+ /* @__PURE__ */ jsx(Menu.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
510
+ Button,
511
+ {
512
+ className: SchemaTreeEditor_default.iconButton,
513
+ "aria-label": "Add field",
514
+ title: "Add field",
515
+ size: "xs",
516
+ variant: "ghost",
517
+ children: /* @__PURE__ */ jsx(MdAdd, {})
518
+ }
519
+ ) }),
520
+ /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, { children: /* @__PURE__ */ jsxs(Menu.Content, { className: SchemaTreeEditor_default.menu, children: [
521
+ /* @__PURE__ */ jsx(
522
+ Menu.Item,
523
+ {
524
+ value: "sibling",
525
+ disabled: node.kind !== "property",
526
+ onSelect: () => handlers.onAdd(node, "sibling"),
527
+ children: "Add field below"
528
+ }
529
+ ),
530
+ canAddChild ? /* @__PURE__ */ jsx(
531
+ Menu.Item,
532
+ {
533
+ value: "child",
534
+ onSelect: () => handlers.onAdd(node, "child"),
535
+ children: "Add nested field"
536
+ }
537
+ ) : null
538
+ ] }) }) })
539
+ ]
540
+ }
541
+ ) : null,
542
+ rowEditable && node.kind !== "root" ? /* @__PURE__ */ jsx(
543
+ IconButton,
544
+ {
545
+ className: [SchemaTreeEditor_default.iconButton, armed ? SchemaTreeEditor_default.dangerArmed : null].filter(Boolean).join(" "),
546
+ "aria-label": armed ? `Confirm delete ${node.key}` : `Delete ${node.key}`,
547
+ title: armed ? "Click again to confirm" : "Delete field",
548
+ onClick: handleDeleteClick,
549
+ size: "xs",
550
+ variant: "ghost",
551
+ children: /* @__PURE__ */ jsx(VscTrash, {})
552
+ }
553
+ ) : null
554
+ ] })
555
+ ]
556
+ }
557
+ );
558
+ }
559
+ );
560
+ var MemoRow = React.memo(SchemaRow, (prev, next) => {
561
+ const a = prev.node;
562
+ const b = next.node;
563
+ return a.id === b.id && a.key === b.key && a.schema === b.schema && a.resolved === b.resolved && a.required === b.required && a.expanded === b.expanded && a.expandable === b.expandable && a.depth === b.depth && a.refSegment === b.refSegment && a.readOnly === b.readOnly && a.sortable === b.sortable && a.recursive === b.recursive && prev.index === next.index && prev.handlers === next.handlers;
564
+ });
565
+ MemoRow.displayName = "SchemaRow";
566
+ var IDLE_DRAG = Object.freeze({
567
+ active: false,
568
+ key: null,
569
+ ownerPath: null,
570
+ overIndex: null,
571
+ usedDataTransfer: false
572
+ });
573
+ var SchemaTreeEditorInner = React.memo(
574
+ ({
575
+ schema,
576
+ onChange,
577
+ className,
578
+ showType = true,
579
+ showRequired = false,
580
+ showDescription = false,
581
+ readOnly = false,
582
+ defaultExpanded,
583
+ maxRows = DEFAULT_MAX_ROWS,
584
+ renderAdvanced = defaultAdvancedEditor,
585
+ document: referenceDocument,
586
+ onError,
587
+ strictExternalSchema = true
588
+ }) => {
589
+ const reportError = React.useCallback(
590
+ (error) => {
591
+ try {
592
+ onError?.(error);
593
+ } catch {
594
+ }
595
+ },
596
+ [onError]
597
+ );
598
+ const signatureRef = React.useRef("");
599
+ const previousSchemaRef = React.useRef(void 0);
600
+ const safeSchema = React.useMemo(() => {
601
+ if (!strictExternalSchema) {
602
+ return isPlainObject(schema) ? schema : {};
603
+ }
604
+ const check = verifyExternalSchema(
605
+ schema,
606
+ previousSchemaRef.current,
607
+ signatureRef.current,
608
+ reportError
609
+ );
610
+ signatureRef.current = check.signature;
611
+ previousSchemaRef.current = check.schema;
612
+ if (check.mutated) {
613
+ reportError({
614
+ scope: "commit",
615
+ message: "schema prop was mutated in place, rebuilding the tree"
616
+ });
617
+ return cloneSchema(check.schema);
618
+ }
619
+ return check.schema;
620
+ }, [schema, strictExternalSchema, reportError]);
621
+ const [expanded, setExpanded] = React.useState(
622
+ () => new Set(defaultExpanded ?? [])
623
+ );
624
+ const dragRef = React.useRef(IDLE_DRAG);
625
+ const [dropLine, setDropLine] = React.useState(null);
626
+ const rafRef = React.useRef(null);
627
+ const cancelRaf = React.useCallback(() => {
628
+ if (rafRef.current !== null) {
629
+ cancelAnimationFrame(rafRef.current);
630
+ rafRef.current = null;
631
+ }
632
+ }, []);
633
+ const resetDrag = React.useCallback(() => {
634
+ cancelRaf();
635
+ if (dragRef.current !== IDLE_DRAG) dragRef.current = IDLE_DRAG;
636
+ setDropLine((current) => current === null ? current : null);
637
+ }, [cancelRaf]);
638
+ const scheduleDropLine = React.useCallback((index) => {
639
+ if (rafRef.current !== null) return;
640
+ rafRef.current = requestAnimationFrame(() => {
641
+ rafRef.current = null;
642
+ setDropLine((current) => current === index ? current : index);
643
+ });
644
+ }, []);
645
+ React.useEffect(() => {
646
+ const abort = () => resetDrag();
647
+ const onKeyDown = (event) => {
648
+ if (event.key === "Escape") resetDrag();
649
+ };
650
+ const onVisibility = () => {
651
+ if (document.visibilityState === "hidden") resetDrag();
652
+ };
653
+ document.addEventListener("dragend", abort);
654
+ document.addEventListener("keydown", onKeyDown);
655
+ document.addEventListener("visibilitychange", onVisibility);
656
+ window.addEventListener("blur", abort);
657
+ return () => {
658
+ document.removeEventListener("dragend", abort);
659
+ document.removeEventListener("keydown", onKeyDown);
660
+ document.removeEventListener("visibilitychange", onVisibility);
661
+ window.removeEventListener("blur", abort);
662
+ cancelRaf();
663
+ };
664
+ }, [resetDrag, cancelRaf]);
665
+ const commit = React.useCallback(
666
+ (next) => {
667
+ if (readOnly || next === safeSchema) return;
668
+ safeRun(
669
+ "commit",
670
+ () => {
671
+ previousSchemaRef.current = next;
672
+ onChange(next);
673
+ },
674
+ void 0,
675
+ reportError
676
+ );
677
+ },
678
+ [onChange, safeSchema, reportError, readOnly]
679
+ );
680
+ const { nodes, overflow } = React.useMemo(
681
+ () => flattenSchema({
682
+ root: safeSchema,
683
+ document: referenceDocument,
684
+ expanded,
685
+ maxRows,
686
+ onError: reportError
687
+ }),
688
+ [safeSchema, referenceDocument, expanded, maxRows, reportError]
689
+ );
690
+ const rowGroups = React.useMemo(() => {
691
+ const groups = [];
692
+ nodes.forEach((node, index) => {
693
+ const last = groups[groups.length - 1];
694
+ if (last?.reference && node.depth > last.depth && node.refSegment !== "none") {
695
+ last.rows.push({ node, index });
696
+ } else {
697
+ groups.push({
698
+ id: node.id,
699
+ reference: !!node.refName,
700
+ depth: node.depth,
701
+ rows: [{ node, index }]
702
+ });
703
+ }
704
+ });
705
+ return groups;
706
+ }, [nodes]);
707
+ const propertyCount = React.useMemo(
708
+ () => isPlainObject(safeSchema.properties) ? Object.keys(safeSchema.properties).length : 0,
709
+ [safeSchema]
710
+ );
711
+ const editable = !readOnly;
712
+ const handleToggle = React.useCallback((node) => {
713
+ setExpanded((current) => {
714
+ const next = new Set(current);
715
+ if (next.has(node.id)) next.delete(node.id);
716
+ else next.add(node.id);
717
+ return next;
718
+ });
719
+ }, []);
720
+ const handleRename = React.useCallback(
721
+ (node, raw) => {
722
+ const nextKey = raw.trim();
723
+ if (!nextKey || nextKey === node.key) return nextKey === node.key;
724
+ if (!isValidKey(nextKey)) return false;
725
+ const owner = getIn(safeSchema, node.parentPath);
726
+ if (!isPlainObject(owner)) return false;
727
+ if (Object.prototype.hasOwnProperty.call(owner, nextKey)) return false;
728
+ const renamed = renameKey(owner, node.key, nextKey);
729
+ if (renamed === owner) return false;
730
+ let next = setIn(safeSchema, node.parentPath, renamed);
731
+ const ownerPath = requiredOwnerPath(node.parentPath);
732
+ if (ownerPath)
733
+ next = renameRequired(next, ownerPath, node.key, nextKey);
734
+ setExpanded(
735
+ (current) => remapExpanded(current, node.path, [...node.parentPath, nextKey])
736
+ );
737
+ commit(next);
738
+ return true;
739
+ },
740
+ [safeSchema, commit]
741
+ );
742
+ const handleDescription = React.useCallback(
743
+ (node, raw) => {
744
+ const value = raw.trim();
745
+ commit(
746
+ patchSchema(safeSchema, node.path, {
747
+ description: value || void 0
748
+ })
749
+ );
750
+ },
751
+ [safeSchema, commit]
752
+ );
753
+ const handleType = React.useCallback(
754
+ (node, nextType) => {
755
+ if (typeof node.value !== "boolean" && schemaTypeOf(node.resolved) === nextType)
756
+ return;
757
+ const current = isPlainObject(node.schema) ? node.schema : {};
758
+ const next = changeSchemaType(current, nextType);
759
+ setExpanded((existing) => pruneExpanded(existing, node.path));
760
+ commit(setIn(safeSchema, node.path, next));
761
+ },
762
+ [safeSchema, commit]
763
+ );
764
+ const handleRequired = React.useCallback(
765
+ (node, nextRequired) => {
766
+ const ownerPath = requiredOwnerPath(node.parentPath);
767
+ if (!ownerPath) return;
768
+ commit(setRequired(safeSchema, ownerPath, node.key, nextRequired));
769
+ },
770
+ [safeSchema, commit]
771
+ );
772
+ const handleDelete = React.useCallback(
773
+ (node) => {
774
+ let next = deleteIn(safeSchema, node.path);
775
+ if (readOnly || next === safeSchema) return;
776
+ const ownerPath = requiredOwnerPath(node.parentPath);
777
+ if (ownerPath) next = setRequired(next, ownerPath, node.key, false);
778
+ setExpanded((current) => pruneExpanded(current, node.path));
779
+ commit(next);
780
+ },
781
+ [safeSchema, commit]
782
+ );
783
+ const handleAdd = React.useCallback(
784
+ (node, mode) => {
785
+ if (mode === "child") {
786
+ const owner2 = getIn(safeSchema, [...node.path, "properties"]);
787
+ const container2 = isPlainObject(owner2) ? owner2 : {};
788
+ const key2 = uniqueKey(container2, "newField");
789
+ const nextProps2 = insertKeyAfter(
790
+ container2,
791
+ null,
792
+ key2,
793
+ defaultSchemaFor("string")
794
+ );
795
+ const next = setIn(safeSchema, node.path, {
796
+ ...isPlainObject(node.schema) ? node.schema : {},
797
+ type: "object",
798
+ properties: nextProps2
799
+ });
800
+ setExpanded((current) => new Set(current).add(node.id));
801
+ commit(next);
802
+ return;
803
+ }
804
+ const owner = getIn(safeSchema, node.parentPath);
805
+ const container = isPlainObject(owner) ? owner : {};
806
+ const key = uniqueKey(container, "newField");
807
+ const nextProps = insertKeyAfter(
808
+ container,
809
+ node.key,
810
+ key,
811
+ defaultSchemaFor("string")
812
+ );
813
+ commit(setIn(safeSchema, node.parentPath, nextProps));
814
+ },
815
+ [safeSchema, commit]
816
+ );
817
+ const moveKey = React.useCallback(
818
+ (ownerPath, key, targetIndex) => {
819
+ safeRun(
820
+ "reorder",
821
+ () => {
822
+ const owner = getIn(safeSchema, ownerPath);
823
+ if (!isPlainObject(owner)) return;
824
+ const reordered = reorderKeys(owner, key, targetIndex);
825
+ if (reordered === owner) return;
826
+ commit(setIn(safeSchema, ownerPath, reordered));
827
+ },
828
+ void 0,
829
+ reportError,
830
+ ownerPath
831
+ );
832
+ },
833
+ [safeSchema, commit, reportError]
834
+ );
835
+ const handleDragStart = React.useCallback(
836
+ (node, index, event) => {
837
+ if (!node.sortable || !editable) {
838
+ event.preventDefault();
839
+ return;
840
+ }
841
+ let usedDataTransfer = false;
842
+ try {
843
+ event.dataTransfer.effectAllowed = "move";
844
+ event.dataTransfer.setData("text/plain", node.key);
845
+ usedDataTransfer = true;
846
+ } catch {
847
+ usedDataTransfer = false;
848
+ }
849
+ dragRef.current = {
850
+ active: true,
851
+ key: node.key,
852
+ ownerPath: node.parentPath,
853
+ overIndex: index,
854
+ usedDataTransfer
855
+ };
856
+ },
857
+ [editable]
858
+ );
859
+ const handleDragOver = React.useCallback(
860
+ (node, index, event) => {
861
+ const drag = dragRef.current;
862
+ if (!drag.active || !drag.ownerPath) return;
863
+ if (!samePath(node.parentPath, drag.ownerPath)) return;
864
+ event.preventDefault();
865
+ event.dataTransfer.dropEffect = "move";
866
+ if (drag.overIndex !== index) drag.overIndex = index;
867
+ scheduleDropLine(index);
868
+ },
869
+ [scheduleDropLine]
870
+ );
871
+ const handleDrop = React.useCallback(
872
+ (node, _index, event) => {
873
+ const drag = dragRef.current;
874
+ if (!drag.active || !drag.ownerPath || !drag.key) {
875
+ resetDrag();
876
+ return;
877
+ }
878
+ event.preventDefault();
879
+ const ownerPath = drag.ownerPath;
880
+ const movingKey = drag.key;
881
+ resetDrag();
882
+ if (!samePath(node.parentPath, ownerPath)) return;
883
+ const owner = getIn(safeSchema, ownerPath);
884
+ if (!isPlainObject(owner)) return;
885
+ const targetIndex = Object.keys(owner).indexOf(node.key);
886
+ if (targetIndex < 0) return;
887
+ moveKey(ownerPath, movingKey, targetIndex);
888
+ },
889
+ [safeSchema, moveKey, resetDrag]
890
+ );
891
+ const handleKeyboardMove = React.useCallback(
892
+ (node, delta) => {
893
+ const owner = getIn(safeSchema, node.parentPath);
894
+ if (!isPlainObject(owner)) return;
895
+ const from = Object.keys(owner).indexOf(node.key);
896
+ if (from < 0) return;
897
+ moveKey(node.parentPath, node.key, from + delta);
898
+ },
899
+ [safeSchema, moveKey]
900
+ );
901
+ const handleAdvancedUpdate = React.useCallback(
902
+ (node, next) => {
903
+ if (typeof next !== "boolean" && !isPlainObject(next)) {
904
+ reportError({
905
+ scope: "commit",
906
+ message: "advanced editor returned a non-object schema",
907
+ path: node.path
908
+ });
909
+ return;
910
+ }
911
+ commit(setIn(safeSchema, node.path, next));
912
+ },
913
+ [safeSchema, commit, reportError]
914
+ );
915
+ const handleAddRoot = React.useCallback(() => {
916
+ const owner = isPlainObject(safeSchema.properties) ? safeSchema.properties : {};
917
+ const key = uniqueKey(owner, "newField");
918
+ const nextProps = insertKeyAfter(
919
+ owner,
920
+ null,
921
+ key,
922
+ defaultSchemaFor("string")
923
+ );
924
+ commit({ ...safeSchema, type: "object", properties: nextProps });
925
+ }, [safeSchema, commit]);
926
+ const handleToggleAll = React.useCallback(() => {
927
+ if (expanded.size > 0) {
928
+ setExpanded(/* @__PURE__ */ new Set());
929
+ return;
930
+ }
931
+ const result = flattenSchema({
932
+ root: safeSchema,
933
+ document: referenceDocument,
934
+ expanded: /* @__PURE__ */ new Set(),
935
+ expandAll: true,
936
+ maxRows,
937
+ onError: reportError
938
+ });
939
+ setExpanded(
940
+ new Set(
941
+ result.nodes.filter((node) => node.expandable).map((node) => node.id)
942
+ )
943
+ );
944
+ }, [expanded.size, safeSchema, referenceDocument, maxRows, reportError]);
945
+ const handlers = React.useMemo(
946
+ () => ({
947
+ onToggle: handleToggle,
948
+ onRename: handleRename,
949
+ onDescription: handleDescription,
950
+ onType: handleType,
951
+ onRequired: handleRequired,
952
+ onDelete: handleDelete,
953
+ onAdd: handleAdd,
954
+ onDragStart: handleDragStart,
955
+ onDragOver: handleDragOver,
956
+ onDrop: handleDrop,
957
+ onKeyboardMove: handleKeyboardMove,
958
+ renderAdvanced,
959
+ rootSchema: referenceDocument ?? safeSchema,
960
+ editable
961
+ }),
962
+ [
963
+ handleToggle,
964
+ handleRename,
965
+ handleDescription,
966
+ handleType,
967
+ handleRequired,
968
+ handleDelete,
969
+ handleAdd,
970
+ handleDragStart,
971
+ handleDragOver,
972
+ handleDrop,
973
+ handleKeyboardMove,
974
+ renderAdvanced,
975
+ referenceDocument,
976
+ safeSchema,
977
+ editable
978
+ ]
979
+ );
980
+ const advancedCacheRef = React.useRef({
981
+ owner: null,
982
+ byId: /* @__PURE__ */ new Map()
983
+ });
984
+ const rowHandlersFor = React.useCallback(
985
+ (base, node) => {
986
+ if (!base.renderAdvanced) return base;
987
+ const cache = advancedCacheRef.current;
988
+ if (cache.owner !== base) {
989
+ cache.owner = base;
990
+ cache.byId = /* @__PURE__ */ new Map();
991
+ }
992
+ const hit = cache.byId.get(node.id);
993
+ if (hit) return hit;
994
+ const inner = base.renderAdvanced;
995
+ const bound = {
996
+ ...base,
997
+ renderAdvanced: (context) => inner({
998
+ ...context,
999
+ update: (next) => {
1000
+ if (base.editable && !node.readOnly)
1001
+ handleAdvancedUpdate(node, next);
1002
+ }
1003
+ })
1004
+ };
1005
+ cache.byId.set(node.id, bound);
1006
+ return bound;
1007
+ },
1008
+ [handleAdvancedUpdate]
1009
+ );
1010
+ React.useEffect(
1011
+ () => () => {
1012
+ advancedCacheRef.current = { owner: null, byId: /* @__PURE__ */ new Map() };
1013
+ },
1014
+ []
1015
+ );
1016
+ return /* @__PURE__ */ jsxs(
1017
+ Box,
1018
+ {
1019
+ className: [SchemaTreeEditor_default.root, className].filter(Boolean).join(" "),
1020
+ "data-show-type": showType,
1021
+ "data-show-required": showRequired,
1022
+ "data-show-description": showDescription,
1023
+ style: {
1024
+ "--grid-min-width": `${160 + (showType ? 120 : 0) + (showRequired ? 36 : 0) + (showDescription ? 168 : 0) + 150}px`,
1025
+ "--grid-columns": [
1026
+ "minmax(160px, 1fr)",
1027
+ showType && "112px",
1028
+ showRequired && "28px",
1029
+ showDescription && "minmax(160px, 1fr)",
1030
+ "80px"
1031
+ ].filter(Boolean).join(" ")
1032
+ },
1033
+ children: [
1034
+ /* @__PURE__ */ jsxs(Box, { className: SchemaTreeEditor_default.toolbar, children: [
1035
+ /* @__PURE__ */ jsx(Text, { className: SchemaTreeEditor_default.toolbarTitle, children: "Schema" }),
1036
+ /* @__PURE__ */ jsxs(Text, { className: SchemaTreeEditor_default.toolbarMeta, children: [
1037
+ propertyCount,
1038
+ " field",
1039
+ propertyCount === 1 ? "" : "s"
1040
+ ] }),
1041
+ /* @__PURE__ */ jsx(Box, { className: SchemaTreeEditor_default.toolbarSpacer }),
1042
+ /* @__PURE__ */ jsx(
1043
+ Button,
1044
+ {
1045
+ className: SchemaTreeEditor_default.ghostButton,
1046
+ onClick: handleToggleAll,
1047
+ disabled: !nodes.some((node) => node.expandable),
1048
+ size: "xs",
1049
+ variant: "ghost",
1050
+ children: expanded.size > 0 ? "Collapse all" : "Expand all"
1051
+ }
1052
+ ),
1053
+ /* @__PURE__ */ jsxs(
1054
+ Button,
1055
+ {
1056
+ className: SchemaTreeEditor_default.ghostButton,
1057
+ onClick: handleAddRoot,
1058
+ disabled: !editable,
1059
+ size: "xs",
1060
+ variant: "ghost",
1061
+ children: [
1062
+ /* @__PURE__ */ jsx(MdAdd, {}),
1063
+ "Add field"
1064
+ ]
1065
+ }
1066
+ )
1067
+ ] }),
1068
+ /* @__PURE__ */ jsxs(
1069
+ Box,
1070
+ {
1071
+ className: SchemaTreeEditor_default.tableViewport,
1072
+ role: "table",
1073
+ "aria-label": "Schema fields",
1074
+ children: [
1075
+ /* @__PURE__ */ jsxs(Box, { className: SchemaTreeEditor_default.header, role: "row", children: [
1076
+ /* @__PURE__ */ jsx(Text, { role: "columnheader", className: SchemaTreeEditor_default.headerCell, children: "Name" }),
1077
+ /* @__PURE__ */ jsx(Text, { role: "columnheader", className: SchemaTreeEditor_default.headerCell, children: "Type" }),
1078
+ /* @__PURE__ */ jsx(
1079
+ Text,
1080
+ {
1081
+ role: "columnheader",
1082
+ className: SchemaTreeEditor_default.headerCell,
1083
+ title: "Required or optional",
1084
+ children: "Req"
1085
+ }
1086
+ ),
1087
+ /* @__PURE__ */ jsx(Text, { role: "columnheader", className: SchemaTreeEditor_default.headerCell, children: "Description" }),
1088
+ /* @__PURE__ */ jsx(
1089
+ Box,
1090
+ {
1091
+ role: "columnheader",
1092
+ className: SchemaTreeEditor_default.headerCell,
1093
+ "aria-label": "Actions"
1094
+ }
1095
+ )
1096
+ ] }),
1097
+ /* @__PURE__ */ jsx(
1098
+ Box,
1099
+ {
1100
+ className: SchemaTreeEditor_default.list,
1101
+ role: "rowgroup",
1102
+ "data-dragging": dropLine !== null || void 0,
1103
+ onDragLeave: (event) => {
1104
+ if (event.currentTarget.contains(event.relatedTarget))
1105
+ return;
1106
+ scheduleDropLine(null);
1107
+ },
1108
+ children: nodes.length === 0 ? /* @__PURE__ */ jsxs(Box, { className: SchemaTreeEditor_default.empty, children: [
1109
+ /* @__PURE__ */ jsx(Text, { className: SchemaTreeEditor_default.emptyTitle, children: "No fields yet" }),
1110
+ /* @__PURE__ */ jsx(Text, { className: SchemaTreeEditor_default.emptyHint, children: "Add the first field to start describing this object." }),
1111
+ /* @__PURE__ */ jsxs(
1112
+ Button,
1113
+ {
1114
+ className: SchemaTreeEditor_default.ghostButton,
1115
+ onClick: handleAddRoot,
1116
+ disabled: !editable,
1117
+ size: "xs",
1118
+ children: [
1119
+ /* @__PURE__ */ jsx(MdAdd, {}),
1120
+ "Add field"
1121
+ ]
1122
+ }
1123
+ )
1124
+ ] }) : rowGroups.map((group) => /* @__PURE__ */ jsx(
1125
+ "div",
1126
+ {
1127
+ className: group.reference ? SchemaTreeEditor_default.referenceGroup : void 0,
1128
+ children: group.rows.map(({ node, index }) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
1129
+ dropLine === index ? /* @__PURE__ */ jsx(Box, { className: SchemaTreeEditor_default.dropLine, "aria-hidden": "true" }) : null,
1130
+ /* @__PURE__ */ jsx(
1131
+ MemoRow,
1132
+ {
1133
+ node,
1134
+ index,
1135
+ handlers: rowHandlersFor(handlers, node)
1136
+ }
1137
+ )
1138
+ ] }, node.id))
1139
+ },
1140
+ group.id
1141
+ ))
1142
+ }
1143
+ )
1144
+ ]
1145
+ }
1146
+ ),
1147
+ overflow ? /* @__PURE__ */ jsx(Box, { className: SchemaTreeEditor_default.notice, role: "status", children: /* @__PURE__ */ jsxs(Text, { className: SchemaTreeEditor_default.noticeText, children: [
1148
+ "Showing the first ",
1149
+ maxRows,
1150
+ " rows. Collapse a branch to see the rest."
1151
+ ] }) }) : null
1152
+ ]
1153
+ }
1154
+ );
1155
+ }
1156
+ );
1157
+ var SchemaTreeEditor = React.memo(
1158
+ (props) => {
1159
+ const value = props.value !== void 0 ? props.value : props.schema ?? {};
1160
+ return /* @__PURE__ */ jsx(SchemaErrorBoundary, { onError: props.onError, children: typeof value === "boolean" ? /* @__PURE__ */ jsx(
1161
+ InlineSchemaEditor,
1162
+ {
1163
+ value,
1164
+ onChange: props.onChange,
1165
+ disabled: props.readOnly,
1166
+ nested: true
1167
+ }
1168
+ ) : /* @__PURE__ */ jsx(
1169
+ SchemaTreeEditorInner,
1170
+ {
1171
+ ...props,
1172
+ schema: value,
1173
+ onChange: props.onChange
1174
+ }
1175
+ ) });
1176
+ }
1177
+ );
1178
+ function defaultAdvancedEditor(context) {
1179
+ return /* @__PURE__ */ jsx(
1180
+ InlineSchemaEditor,
1181
+ {
1182
+ schema: context.schema,
1183
+ fullSchema: context.fullSchema,
1184
+ required: context.required,
1185
+ onRequiredChange: context.onRequiredChange,
1186
+ schemaName: context.schemaName,
1187
+ path: context.path,
1188
+ nested: true,
1189
+ disabled: context.readOnly,
1190
+ onChange: context.update
1191
+ }
1192
+ );
1193
+ }
1194
+
1195
+ export { SCHEMA_TYPES, SchemaTreeEditor };