@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,1896 @@
1
+ import { getSchemaType, stringifySchemaValue, canParseSchemaValue, parseSchemaValue, getEnumValues, getComposition, getSchemaSummary, getArrayItems, getPrefixItems, parseOptionalNumber, toInputValue, getProperties, getRequiredProperties, updateProperty, cloneSchema2, removeProperty, setPropertyRequired, renameProperty, toSchemaRecord, createSchemaForType, setComposition, mergeSchema, getReferenceOptions, normalizeFormatOptions, diffSchemaLines } from './chunk-HI5FBHCO.js';
2
+ import { createListCollection, Stack, HStack, VStack, Field, Input, Switch, Text, Grid, Textarea, Button, Box, IconButton, Collapsible, Popover, Portal, Tabs, NativeSelect, Select } from '@chakra-ui/react';
3
+ import { memo, useMemo, useState, useEffect, useRef, useCallback } from 'react';
4
+ import { jsxs, jsx } from 'react/jsx-runtime';
5
+ import { VscSettingsCompact } from 'react-icons/vsc';
6
+ import { LuX } from 'react-icons/lu';
7
+
8
+ function useSchemaEditor(schema, externalType) {
9
+ return useMemo(
10
+ () => ({
11
+ schema: toSchemaRecord(schema),
12
+ type: externalType ?? getSchemaType(schema)
13
+ }),
14
+ [schema, externalType]
15
+ );
16
+ }
17
+ function useSchemaPatch(schema, update) {
18
+ const patch = useCallback(
19
+ (next) => update(next),
20
+ [update]
21
+ );
22
+ const replace = useCallback(
23
+ (next) => {
24
+ const current = schema ?? {};
25
+ const patchValue = { ...next };
26
+ Object.keys(current).forEach((key) => {
27
+ if (!Object.hasOwn(next, key))
28
+ Object.defineProperty(patchValue, key, {
29
+ value: void 0,
30
+ enumerable: true,
31
+ configurable: true,
32
+ writable: true
33
+ });
34
+ });
35
+ update(patchValue);
36
+ },
37
+ [schema, update]
38
+ );
39
+ return { patch, replace };
40
+ }
41
+ var OPTIONS = createListCollection({
42
+ items: [
43
+ { value: "any", label: "Any" },
44
+ { value: "string", label: "String" },
45
+ { value: "number", label: "Number" },
46
+ { value: "integer", label: "Integer" },
47
+ { value: "boolean", label: "Boolean" },
48
+ { value: "array", label: "Array" },
49
+ { value: "object", label: "Object" },
50
+ { value: "null", label: "Null" }
51
+ ]
52
+ });
53
+ function SchemaTypeSelector(props) {
54
+ return /* @__PURE__ */ jsxs(
55
+ Select.Root,
56
+ {
57
+ collection: OPTIONS,
58
+ size: "sm",
59
+ width: "132px",
60
+ value: [props.value],
61
+ disabled: props.disabled,
62
+ onValueChange: (e) => props.onChange(e.value?.[0] ?? "any"),
63
+ children: [
64
+ /* @__PURE__ */ jsx(Select.HiddenSelect, {}),
65
+ /* @__PURE__ */ jsxs(Select.Control, { children: [
66
+ /* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.ValueText, { placeholder: "Select type" }) }),
67
+ /* @__PURE__ */ jsx(Select.IndicatorGroup, { children: /* @__PURE__ */ jsx(Select.Indicator, {}) })
68
+ ] }),
69
+ /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Select.Positioner, { children: /* @__PURE__ */ jsx(
70
+ Select.Content,
71
+ {
72
+ className: "pdDesignerSelectMenu",
73
+ background: "var(--color-surface)",
74
+ color: "var(--color-text-primary)",
75
+ borderColor: "var(--color-border-default)",
76
+ fontSize: "12px",
77
+ children: OPTIONS.items.map((item) => /* @__PURE__ */ jsxs(Select.Item, { item, children: [
78
+ item.label,
79
+ /* @__PURE__ */ jsx(Select.ItemIndicator, {})
80
+ ] }, item.value))
81
+ }
82
+ ) }) })
83
+ ]
84
+ }
85
+ );
86
+ }
87
+ var SchemaHeader = memo(function SchemaHeader2(props) {
88
+ return /* @__PURE__ */ jsxs(Stack, { gap: "2", className: "pdDesignerSchemaSection", children: [
89
+ /* @__PURE__ */ jsxs(HStack, { justify: "space-between", gap: "2", align: "start", flexWrap: "wrap", children: [
90
+ !props.hideName && /* @__PURE__ */ jsx(VStack, { flex: "1", children: !props.hideName ? /* @__PURE__ */ jsxs(Field.Root, { children: [
91
+ /* @__PURE__ */ jsx(Field.Label, { children: "Field name" }),
92
+ /* @__PURE__ */ jsx(
93
+ Input,
94
+ {
95
+ size: "sm",
96
+ value: props.name ?? "",
97
+ disabled: props.disabled,
98
+ placeholder: "customerEmail",
99
+ onChange: (e) => props.onNameChange?.(e.target.value)
100
+ }
101
+ )
102
+ ] }) : null }),
103
+ /* @__PURE__ */ jsxs(HStack, { gap: "4", flexShrink: 0, align: "end", children: [
104
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
105
+ /* @__PURE__ */ jsx(Field.Label, { children: "Type" }),
106
+ /* @__PURE__ */ jsx(
107
+ SchemaTypeSelector,
108
+ {
109
+ value: props.type,
110
+ disabled: props.disabled,
111
+ onChange: props.onTypeChange
112
+ }
113
+ )
114
+ ] }),
115
+ /* @__PURE__ */ jsx(HStack, { gap: "2", align: "center", flexWrap: "wrap", children: props.onRequiredChange ? /* @__PURE__ */ jsxs(
116
+ Switch.Root,
117
+ {
118
+ checked: !!props.required,
119
+ disabled: props.disabled,
120
+ onCheckedChange: (e) => props.onRequiredChange?.(!!e.checked),
121
+ children: [
122
+ /* @__PURE__ */ jsx(Switch.HiddenInput, {}),
123
+ /* @__PURE__ */ jsx(Switch.Control, {}),
124
+ /* @__PURE__ */ jsx(Switch.Label, { children: "Required" })
125
+ ]
126
+ }
127
+ ) : null })
128
+ ] })
129
+ ] }),
130
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
131
+ /* @__PURE__ */ jsx(Field.Label, { children: "Description" }),
132
+ /* @__PURE__ */ jsx(
133
+ Input,
134
+ {
135
+ size: "sm",
136
+ value: props.description ?? "",
137
+ disabled: props.disabled,
138
+ placeholder: "Helpful summary for API consumers",
139
+ onChange: (e) => props.onDescriptionChange?.(e.target.value)
140
+ }
141
+ )
142
+ ] })
143
+ ] });
144
+ });
145
+ function SchemaReferenceEditor(props) {
146
+ const record = toSchemaRecord(props.schema);
147
+ const ref = typeof record.$ref === "string" ? record.$ref : "";
148
+ const options = getReferenceOptions(props.fullSchema);
149
+ if (ref && !options.includes(ref)) options.unshift(ref);
150
+ return /* @__PURE__ */ jsxs(Stack, { gap: "2", className: "pdDesignerSchemaSection", children: [
151
+ /* @__PURE__ */ jsx(HStack, { justify: "space-between", align: "center", flexWrap: "wrap", children: /* @__PURE__ */ jsxs(HStack, { gap: "2", children: [
152
+ ref ? /* @__PURE__ */ jsx(
153
+ Button,
154
+ {
155
+ size: "xs",
156
+ variant: "ghost",
157
+ onClick: props.onClearReference,
158
+ disabled: props.disabled,
159
+ children: "Use inline schema"
160
+ }
161
+ ) : null,
162
+ props.hasDraft && !ref ? /* @__PURE__ */ jsx(
163
+ Button,
164
+ {
165
+ size: "xs",
166
+ variant: "ghost",
167
+ onClick: props.onRestoreDraft,
168
+ disabled: props.disabled,
169
+ children: "Restore draft"
170
+ }
171
+ ) : null
172
+ ] }) }),
173
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
174
+ /* @__PURE__ */ jsx(Field.Label, { children: "$ref" }),
175
+ /* @__PURE__ */ jsxs(NativeSelect.Root, { size: "sm", disabled: props.disabled, children: [
176
+ /* @__PURE__ */ jsxs(
177
+ NativeSelect.Field,
178
+ {
179
+ value: ref,
180
+ onChange: (event) => {
181
+ const value = event.target.value;
182
+ props.update({ $ref: value || void 0 });
183
+ },
184
+ children: [
185
+ /* @__PURE__ */ jsx("option", { value: "", children: "No reference" }),
186
+ options.map((value) => /* @__PURE__ */ jsx("option", { value, children: value }, value))
187
+ ]
188
+ }
189
+ ),
190
+ /* @__PURE__ */ jsx(NativeSelect.Indicator, {})
191
+ ] })
192
+ ] })
193
+ ] });
194
+ }
195
+ function SchemaValueEditor(props) {
196
+ const externalText = stringifySchemaValue(props.value);
197
+ const [draft, setDraft] = useState(externalText);
198
+ useEffect(() => {
199
+ setDraft(externalText);
200
+ }, [externalText, props.type]);
201
+ const booleanCollection = useMemo(
202
+ () => createListCollection({
203
+ items: [
204
+ { label: "Unset", value: "" },
205
+ { label: "True", value: "true" },
206
+ { label: "False", value: "false" }
207
+ ]
208
+ }),
209
+ []
210
+ );
211
+ const change = (text) => {
212
+ setDraft(text);
213
+ props.onTextChange?.(text);
214
+ if (canParseSchemaValue(text, props.type)) {
215
+ props.onChange(parseSchemaValue(text, props.type));
216
+ }
217
+ };
218
+ if (props.type === "boolean") {
219
+ return /* @__PURE__ */ jsxs(Field.Root, { invalid: !!props.error, children: [
220
+ /* @__PURE__ */ jsxs(
221
+ Select.Root,
222
+ {
223
+ collection: booleanCollection,
224
+ size: "sm",
225
+ disabled: props.disabled,
226
+ value: [String(props.value ?? "")],
227
+ onValueChange: (e) => change(e.value?.[0] ?? ""),
228
+ children: [
229
+ /* @__PURE__ */ jsx(Select.HiddenSelect, {}),
230
+ /* @__PURE__ */ jsxs(Select.Control, { children: [
231
+ /* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.ValueText, { placeholder: "Unset" }) }),
232
+ /* @__PURE__ */ jsx(Select.IndicatorGroup, { children: /* @__PURE__ */ jsx(Select.Indicator, {}) })
233
+ ] }),
234
+ /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Select.Positioner, { children: /* @__PURE__ */ jsx(Select.Content, { className: "pdDesignerSelectMenu", children: booleanCollection.items.map((item) => /* @__PURE__ */ jsxs(Select.Item, { item, children: [
235
+ item.label,
236
+ /* @__PURE__ */ jsx(Select.ItemIndicator, {})
237
+ ] }, item.value)) }) }) })
238
+ ]
239
+ }
240
+ ),
241
+ props.error && /* @__PURE__ */ jsx(Field.ErrorText, { children: props.error })
242
+ ] });
243
+ }
244
+ const multiline = ["array", "object", "any"].includes(props.type);
245
+ const value = draft;
246
+ return /* @__PURE__ */ jsxs(Field.Root, { invalid: !!props.error, children: [
247
+ multiline ? /* @__PURE__ */ jsx(
248
+ Textarea,
249
+ {
250
+ value,
251
+ disabled: props.disabled,
252
+ placeholder: props.placeholder,
253
+ minH: "96px",
254
+ fontFamily: "mono",
255
+ fontSize: "xs",
256
+ onChange: (e) => change(e.target.value)
257
+ }
258
+ ) : /* @__PURE__ */ jsx(
259
+ Input,
260
+ {
261
+ size: "sm",
262
+ value,
263
+ disabled: props.disabled,
264
+ placeholder: props.placeholder,
265
+ onChange: (e) => change(e.target.value)
266
+ }
267
+ ),
268
+ props.error && /* @__PURE__ */ jsx(Field.ErrorText, { children: props.error })
269
+ ] });
270
+ }
271
+ function readRecord(value) {
272
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
273
+ }
274
+ function getValueError(type, text) {
275
+ if (!text.trim()) return "";
276
+ if (type === "boolean")
277
+ return text === "true" || text === "false" ? "" : "Pick true or false.";
278
+ if (type === "integer")
279
+ return Number.isInteger(Number(text)) ? "" : "Enter a valid integer.";
280
+ if (type === "number")
281
+ return Number.isFinite(Number(text)) ? "" : "Enter a valid number.";
282
+ if (type === "null") return text.trim() === "null" ? "" : 'Use "null".';
283
+ if (["array", "object"].includes(type))
284
+ return canParseSchemaValue(text, type) ? "" : "Enter valid JSON.";
285
+ return "";
286
+ }
287
+ var SchemaAdvancedEditor = memo(function SchemaAdvancedEditor2(props) {
288
+ const s = props.schema;
289
+ const schemaType = getSchemaType(s);
290
+ const examples = useMemo(
291
+ () => Array.isArray(s.examples) ? [...s.examples] : [],
292
+ [s.examples]
293
+ );
294
+ const [exampleDrafts, setExampleDrafts] = useState(
295
+ () => examples.map((item) => stringifySchemaValue(item))
296
+ );
297
+ const [exampleDraft, setExampleDraft] = useState(
298
+ () => stringifySchemaValue(s.example)
299
+ );
300
+ const [defaultDraft, setDefaultDraft] = useState(
301
+ () => stringifySchemaValue(s.default)
302
+ );
303
+ const exampleError = getValueError(schemaType, exampleDraft);
304
+ const defaultError = getValueError(schemaType, defaultDraft);
305
+ useEffect(() => {
306
+ setExampleDrafts(examples.map((item) => stringifySchemaValue(item)));
307
+ }, [examples]);
308
+ useEffect(() => {
309
+ setExampleDraft(stringifySchemaValue(s.example));
310
+ }, [s.example]);
311
+ useEffect(() => {
312
+ setDefaultDraft(stringifySchemaValue(s.default));
313
+ }, [s.default]);
314
+ const updateExamples = (next, drafts) => {
315
+ if (drafts) setExampleDrafts(drafts);
316
+ props.update({ examples: next.length ? next : void 0 });
317
+ };
318
+ return /* @__PURE__ */ jsxs(Stack, { gap: "4", className: "pdDesignerSchemaSection", children: [
319
+ /* @__PURE__ */ jsx(Text, { fontSize: "sm", fontWeight: "600", children: "Advanced options" }),
320
+ /* @__PURE__ */ jsxs(Grid, { templateColumns: "repeat(2, minmax(0, 1fr))", gap: "3", children: [
321
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
322
+ /* @__PURE__ */ jsx(Field.Label, { children: "Title" }),
323
+ /* @__PURE__ */ jsx(
324
+ Input,
325
+ {
326
+ size: "sm",
327
+ value: typeof s.title === "string" ? s.title : "",
328
+ disabled: props.disabled,
329
+ onChange: (e) => props.update({ title: e.target.value || void 0 })
330
+ }
331
+ )
332
+ ] }),
333
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
334
+ /* @__PURE__ */ jsx(Field.Label, { children: "Const" }),
335
+ /* @__PURE__ */ jsx(
336
+ Input,
337
+ {
338
+ size: "sm",
339
+ value: typeof s.const === "string" ? s.const : s.const === void 0 ? "" : JSON.stringify(s.const),
340
+ disabled: props.disabled,
341
+ onChange: (e) => {
342
+ const raw = e.target.value;
343
+ if (!raw) props.update({ const: void 0 });
344
+ else {
345
+ try {
346
+ props.update({ const: JSON.parse(raw) });
347
+ } catch {
348
+ props.update({ const: raw });
349
+ }
350
+ }
351
+ }
352
+ }
353
+ )
354
+ ] })
355
+ ] }),
356
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
357
+ /* @__PURE__ */ jsx(Field.Label, { children: "Description" }),
358
+ /* @__PURE__ */ jsx(
359
+ Textarea,
360
+ {
361
+ size: "sm",
362
+ minH: "80px",
363
+ value: typeof s.description === "string" ? s.description : "",
364
+ disabled: props.disabled,
365
+ onChange: (e) => props.update({ description: e.target.value || void 0 })
366
+ }
367
+ )
368
+ ] }),
369
+ /* @__PURE__ */ jsxs(Grid, { templateColumns: "repeat(2, minmax(0, 1fr))", gap: "3", children: [
370
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
371
+ /* @__PURE__ */ jsx(Field.Label, { children: "Example" }),
372
+ /* @__PURE__ */ jsx(
373
+ SchemaValueEditor,
374
+ {
375
+ value: s.example,
376
+ type: schemaType,
377
+ disabled: props.disabled,
378
+ placeholder: schemaType === "object" || schemaType === "array" ? "Enter valid JSON" : void 0,
379
+ error: exampleError,
380
+ onTextChange: setExampleDraft,
381
+ onChange: (value) => props.update({ example: value })
382
+ }
383
+ )
384
+ ] }),
385
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
386
+ /* @__PURE__ */ jsx(Field.Label, { children: "Default" }),
387
+ /* @__PURE__ */ jsx(
388
+ SchemaValueEditor,
389
+ {
390
+ value: s.default,
391
+ type: schemaType,
392
+ disabled: props.disabled,
393
+ error: defaultError,
394
+ onTextChange: setDefaultDraft,
395
+ onChange: (value) => props.update({ default: value })
396
+ }
397
+ )
398
+ ] })
399
+ ] }),
400
+ /* @__PURE__ */ jsxs(Stack, { gap: "3", children: [
401
+ /* @__PURE__ */ jsxs(HStack, { justify: "space-between", align: "center", children: [
402
+ /* @__PURE__ */ jsx(Text, { fontSize: "sm", fontWeight: "600", children: "Examples" }),
403
+ /* @__PURE__ */ jsx(
404
+ Button,
405
+ {
406
+ size: "xs",
407
+ variant: "outline",
408
+ disabled: props.disabled,
409
+ onClick: () => {
410
+ const seed = schemaType === "boolean" ? true : schemaType === "integer" || schemaType === "number" ? 0 : schemaType === "null" ? null : schemaType === "array" ? [] : schemaType === "object" ? {} : "";
411
+ const next = [...examples, seed];
412
+ updateExamples(
413
+ next,
414
+ next.map((item) => stringifySchemaValue(item))
415
+ );
416
+ },
417
+ children: "Add example"
418
+ }
419
+ )
420
+ ] }),
421
+ examples.length === 0 ? /* @__PURE__ */ jsx(Text, { fontSize: "xs", color: "var(--color-text-secondary)", children: "No examples." }) : null,
422
+ examples.map((value, index) => {
423
+ const text = exampleDrafts[index] ?? stringifySchemaValue(value);
424
+ const error = getValueError(schemaType, text);
425
+ return /* @__PURE__ */ jsx(
426
+ Box,
427
+ {
428
+ p: "3",
429
+ border: "1px solid var(--color-border-subtle)",
430
+ borderRadius: "var(--radius-lg)",
431
+ bg: "var(--color-surface-subtle)",
432
+ children: /* @__PURE__ */ jsxs(HStack, { align: "start", gap: "2", children: [
433
+ /* @__PURE__ */ jsxs(Field.Root, { invalid: !!error, flex: "1", children: [
434
+ /* @__PURE__ */ jsxs(Field.Label, { children: [
435
+ "Example ",
436
+ index + 1
437
+ ] }),
438
+ /* @__PURE__ */ jsx(
439
+ Input,
440
+ {
441
+ size: "sm",
442
+ value: text,
443
+ disabled: props.disabled,
444
+ onChange: (e) => {
445
+ const nextDrafts = [...exampleDrafts];
446
+ nextDrafts[index] = e.target.value;
447
+ setExampleDrafts(nextDrafts);
448
+ if (canParseSchemaValue(e.target.value, schemaType)) {
449
+ const next = [...examples];
450
+ next[index] = parseSchemaValue(
451
+ e.target.value,
452
+ schemaType
453
+ );
454
+ updateExamples(next);
455
+ }
456
+ }
457
+ }
458
+ ),
459
+ error ? /* @__PURE__ */ jsx(Field.ErrorText, { children: error }) : null
460
+ ] }),
461
+ /* @__PURE__ */ jsx(
462
+ IconButton,
463
+ {
464
+ mt: "6",
465
+ size: "xs",
466
+ variant: "plain",
467
+ "aria-label": "Remove example",
468
+ disabled: props.disabled,
469
+ onClick: () => {
470
+ const next = [...examples];
471
+ next.splice(index, 1);
472
+ const nextDrafts = [...exampleDrafts];
473
+ nextDrafts.splice(index, 1);
474
+ updateExamples(next, nextDrafts);
475
+ },
476
+ children: "\xD7"
477
+ }
478
+ )
479
+ ] })
480
+ },
481
+ index
482
+ );
483
+ })
484
+ ] }),
485
+ /* @__PURE__ */ jsxs(Collapsible.Root, { defaultOpen: false, children: [
486
+ /* @__PURE__ */ jsx(Collapsible.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "xs", variant: "ghost", alignSelf: "flex-start", children: "Show less common options" }) }),
487
+ /* @__PURE__ */ jsx(Collapsible.Content, { children: /* @__PURE__ */ jsxs(Stack, { gap: "4", pt: "3", children: [
488
+ /* @__PURE__ */ jsxs(Grid, { templateColumns: "repeat(2, minmax(0, 1fr))", gap: "3", children: [
489
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
490
+ /* @__PURE__ */ jsx(Field.Label, { children: "Content encoding" }),
491
+ /* @__PURE__ */ jsx(
492
+ Input,
493
+ {
494
+ size: "sm",
495
+ value: typeof s.contentEncoding === "string" ? s.contentEncoding : "",
496
+ disabled: props.disabled,
497
+ onChange: (e) => props.update({
498
+ contentEncoding: e.target.value || void 0
499
+ })
500
+ }
501
+ )
502
+ ] }),
503
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
504
+ /* @__PURE__ */ jsx(Field.Label, { children: "Content media type" }),
505
+ /* @__PURE__ */ jsx(
506
+ Input,
507
+ {
508
+ size: "sm",
509
+ value: typeof s.contentMediaType === "string" ? s.contentMediaType : "",
510
+ disabled: props.disabled,
511
+ onChange: (e) => props.update({
512
+ contentMediaType: e.target.value || void 0
513
+ })
514
+ }
515
+ )
516
+ ] })
517
+ ] }),
518
+ /* @__PURE__ */ jsxs(
519
+ Switch.Root,
520
+ {
521
+ checked: s.deprecated === true,
522
+ disabled: props.disabled,
523
+ onCheckedChange: (e) => props.update({ deprecated: e.checked ? true : void 0 }),
524
+ children: [
525
+ /* @__PURE__ */ jsx(Switch.HiddenInput, {}),
526
+ /* @__PURE__ */ jsx(Switch.Control, {}),
527
+ /* @__PURE__ */ jsx(Switch.Label, { children: "Deprecated" })
528
+ ]
529
+ }
530
+ ),
531
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
532
+ /* @__PURE__ */ jsx(Field.Label, { children: "Write only" }),
533
+ /* @__PURE__ */ jsxs(
534
+ Switch.Root,
535
+ {
536
+ checked: s.writeOnly === true,
537
+ disabled: props.disabled,
538
+ onCheckedChange: (e) => props.update({ writeOnly: e.checked ? true : void 0 }),
539
+ children: [
540
+ /* @__PURE__ */ jsx(Switch.HiddenInput, {}),
541
+ /* @__PURE__ */ jsx(Switch.Control, {}),
542
+ /* @__PURE__ */ jsx(Switch.Label, { children: "Hidden from responses" })
543
+ ]
544
+ }
545
+ )
546
+ ] }),
547
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
548
+ /* @__PURE__ */ jsx(Field.Label, { children: "Read only" }),
549
+ /* @__PURE__ */ jsxs(
550
+ Switch.Root,
551
+ {
552
+ checked: s.readOnly === true,
553
+ disabled: props.disabled,
554
+ onCheckedChange: (e) => props.update({ readOnly: e.checked ? true : void 0 }),
555
+ children: [
556
+ /* @__PURE__ */ jsx(Switch.HiddenInput, {}),
557
+ /* @__PURE__ */ jsx(Switch.Control, {}),
558
+ /* @__PURE__ */ jsx(Switch.Label, { children: "Hidden from requests" })
559
+ ]
560
+ }
561
+ )
562
+ ] }),
563
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
564
+ /* @__PURE__ */ jsx(Field.Label, { children: "External docs URL" }),
565
+ /* @__PURE__ */ jsx(
566
+ Input,
567
+ {
568
+ size: "sm",
569
+ value: typeof readRecord(s.externalDocs).url === "string" ? String(readRecord(s.externalDocs).url) : "",
570
+ disabled: props.disabled,
571
+ onChange: (e) => props.update({
572
+ externalDocs: e.target.value ? { ...readRecord(s.externalDocs), url: e.target.value } : void 0
573
+ })
574
+ }
575
+ )
576
+ ] })
577
+ ] }) })
578
+ ] })
579
+ ] });
580
+ });
581
+ function validateEnumText(type, text) {
582
+ if (!text.trim())
583
+ return type === "string" ? "" : "Enter a value or remove this entry.";
584
+ if (type === "integer") {
585
+ return Number.isInteger(Number(text)) ? "" : "Enter a valid integer.";
586
+ }
587
+ if (type === "number") {
588
+ return Number.isFinite(Number(text)) ? "" : "Enter a valid number.";
589
+ }
590
+ if (type === "boolean") {
591
+ return text === "true" || text === "false" ? "" : "Use true or false.";
592
+ }
593
+ if (type === "null") {
594
+ return text.trim() === "null" ? "" : 'Use "null".';
595
+ }
596
+ if (["array", "object", "any"].includes(type)) {
597
+ return canParseSchemaValue(text, type) ? "" : "Enter valid JSON.";
598
+ }
599
+ return "";
600
+ }
601
+ var SchemaEnumEditor = memo(function SchemaEnumEditor2(props) {
602
+ const values = useMemo(
603
+ () => getEnumValues(props.schema),
604
+ [props.schema.enum]
605
+ );
606
+ const [drafts, setDrafts] = useState(
607
+ () => values.map((value) => stringifySchemaValue(value))
608
+ );
609
+ useEffect(() => {
610
+ setDrafts(values.map((value) => stringifySchemaValue(value)));
611
+ }, [values]);
612
+ const commit = (next) => {
613
+ props.update({ enum: next.length ? next : void 0 });
614
+ };
615
+ const createSeedValue = () => {
616
+ if (props.type === "integer" || props.type === "number") return 0;
617
+ if (props.type === "boolean") return true;
618
+ if (props.type === "null") return null;
619
+ if (props.type === "array") return [];
620
+ if (props.type === "object") return {};
621
+ return "";
622
+ };
623
+ return /* @__PURE__ */ jsxs(Stack, { gap: "3", children: [
624
+ /* @__PURE__ */ jsxs(HStack, { justify: "space-between", align: "center", children: [
625
+ /* @__PURE__ */ jsx(Text, { fontSize: "sm", fontWeight: "600", children: "Enum" }),
626
+ /* @__PURE__ */ jsx(
627
+ Button,
628
+ {
629
+ size: "xs",
630
+ variant: "outline",
631
+ disabled: props.disabled,
632
+ onClick: () => {
633
+ const nextValues = [...values, createSeedValue()];
634
+ setDrafts(nextValues.map((value) => stringifySchemaValue(value)));
635
+ commit(nextValues);
636
+ },
637
+ children: "Add enum"
638
+ }
639
+ )
640
+ ] }),
641
+ values.map((value, index) => {
642
+ const text = drafts[index] ?? stringifySchemaValue(value);
643
+ const error = validateEnumText(props.type, text);
644
+ return /* @__PURE__ */ jsx(
645
+ Box,
646
+ {
647
+ p: "3",
648
+ border: "1px solid var(--color-border-subtle)",
649
+ borderRadius: "var(--radius-lg)",
650
+ bg: "var(--color-surface-subtle)",
651
+ children: /* @__PURE__ */ jsxs(HStack, { align: "start", gap: "2", children: [
652
+ /* @__PURE__ */ jsxs(Field.Root, { invalid: !!error, flex: "1", children: [
653
+ /* @__PURE__ */ jsxs(Field.Label, { children: [
654
+ "Value ",
655
+ index + 1
656
+ ] }),
657
+ /* @__PURE__ */ jsx(
658
+ Input,
659
+ {
660
+ size: "sm",
661
+ value: text,
662
+ disabled: props.disabled,
663
+ onChange: (e) => {
664
+ const nextDrafts = [...drafts];
665
+ nextDrafts[index] = e.target.value;
666
+ setDrafts(nextDrafts);
667
+ if (!validateEnumText(props.type, e.target.value)) {
668
+ const next = [...values];
669
+ next[index] = parseSchemaValue(
670
+ e.target.value,
671
+ props.type
672
+ );
673
+ commit(next);
674
+ }
675
+ }
676
+ }
677
+ ),
678
+ error ? /* @__PURE__ */ jsx(Field.ErrorText, { children: error }) : null
679
+ ] }),
680
+ /* @__PURE__ */ jsx(
681
+ IconButton,
682
+ {
683
+ mt: "6",
684
+ size: "xs",
685
+ variant: "plain",
686
+ className: "pdDesignerSchemaIconButton",
687
+ "aria-label": "Remove enum value",
688
+ disabled: props.disabled,
689
+ onClick: () => {
690
+ const next = [...values];
691
+ next.splice(index, 1);
692
+ const nextDrafts = [...drafts];
693
+ nextDrafts.splice(index, 1);
694
+ setDrafts(nextDrafts);
695
+ commit(next);
696
+ },
697
+ children: "\xD7"
698
+ }
699
+ )
700
+ ] })
701
+ },
702
+ index
703
+ );
704
+ }),
705
+ values.length === 0 ? /* @__PURE__ */ jsx(Text, { fontSize: "xs", color: "var(--color-text-secondary)", children: "No enum values." }) : null
706
+ ] });
707
+ });
708
+
709
+ // src/react/shared/SettingsPanel.module.css
710
+ var SettingsPanel_default = {
711
+ panel: "SettingsPanel_panel",
712
+ header: "SettingsPanel_header",
713
+ title: "SettingsPanel_title",
714
+ close: "SettingsPanel_close",
715
+ body: "SettingsPanel_body"
716
+ };
717
+ function SettingsPanel({
718
+ title,
719
+ children
720
+ }) {
721
+ return /* @__PURE__ */ jsxs(Popover.Content, { className: SettingsPanel_default.panel, children: [
722
+ /* @__PURE__ */ jsxs(Popover.Header, { className: SettingsPanel_default.header, children: [
723
+ /* @__PURE__ */ jsx(Popover.Title, { className: SettingsPanel_default.title, children: title }),
724
+ /* @__PURE__ */ jsx(
725
+ Popover.CloseTrigger,
726
+ {
727
+ className: SettingsPanel_default.close,
728
+ "aria-label": "Close settings",
729
+ children: /* @__PURE__ */ jsx(LuX, { size: 14 })
730
+ }
731
+ )
732
+ ] }),
733
+ /* @__PURE__ */ jsx(Popover.Body, { className: SettingsPanel_default.body, children })
734
+ ] });
735
+ }
736
+ var KEYS = ["allOf", "anyOf", "oneOf"];
737
+ var CompositionList = memo(function CompositionList2(props) {
738
+ const { schema, fullSchema, keyName, disabled, onChange } = props;
739
+ const values = getComposition(schema, keyName);
740
+ const commit = (nextValues) => onChange(setComposition(schema, keyName, nextValues));
741
+ return /* @__PURE__ */ jsxs(Stack, { gap: "3", className: "pdDesignerSchemaSection", children: [
742
+ /* @__PURE__ */ jsxs(
743
+ Button,
744
+ {
745
+ size: "xs",
746
+ alignSelf: "flex-start",
747
+ variant: "outline",
748
+ disabled,
749
+ onClick: () => commit([
750
+ ...values,
751
+ { type: "object", properties: {} }
752
+ ]),
753
+ children: [
754
+ "Add ",
755
+ keyName,
756
+ " item"
757
+ ]
758
+ }
759
+ ),
760
+ values.length === 0 ? /* @__PURE__ */ jsxs(Text, { fontSize: "xs", color: "var(--color-text-secondary)", children: [
761
+ "No ",
762
+ keyName,
763
+ " rules."
764
+ ] }) : null,
765
+ values.map((item, index) => {
766
+ return /* @__PURE__ */ jsx(
767
+ Box,
768
+ {
769
+ className: "pdDesignerSchemaNestedCard",
770
+ children: /* @__PURE__ */ jsxs(HStack, { justify: "space-between", align: "center", gap: "3", children: [
771
+ /* @__PURE__ */ jsxs(Box, { flex: "1", minW: "0", children: [
772
+ /* @__PURE__ */ jsxs(Text, { fontSize: "sm", fontWeight: "600", children: [
773
+ keyName,
774
+ "[",
775
+ index,
776
+ "]"
777
+ ] }),
778
+ /* @__PURE__ */ jsx(
779
+ Text,
780
+ {
781
+ fontSize: "xs",
782
+ color: "var(--color-text-secondary)",
783
+ lineClamp: 2,
784
+ children: getSchemaSummary(item)
785
+ }
786
+ )
787
+ ] }),
788
+ /* @__PURE__ */ jsxs(HStack, { gap: "1", flexShrink: 0, children: [
789
+ /* @__PURE__ */ jsxs(
790
+ Popover.Root,
791
+ {
792
+ lazyMount: true,
793
+ unmountOnExit: true,
794
+ positioning: { placement: "left-start", strategy: "fixed" },
795
+ children: [
796
+ /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
797
+ IconButton,
798
+ {
799
+ size: "xs",
800
+ variant: "outline",
801
+ "aria-label": `Configure ${keyName} item ${index + 1}`,
802
+ className: "pdDesignerSchemaIconButton",
803
+ children: /* @__PURE__ */ jsx(VscSettingsCompact, { size: 16 })
804
+ }
805
+ ) }),
806
+ /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, { children: /* @__PURE__ */ jsx(SettingsPanel, { title: `${keyName} \xB7 ${index + 1}`, children: /* @__PURE__ */ jsx(
807
+ InlineSchemaEditor,
808
+ {
809
+ schema: item,
810
+ fullSchema,
811
+ disabled,
812
+ nested: true,
813
+ path: [keyName, String(index)],
814
+ onChange: (value) => {
815
+ const next = [...values];
816
+ next[index] = value;
817
+ commit(next);
818
+ }
819
+ }
820
+ ) }) }) })
821
+ ]
822
+ }
823
+ ),
824
+ /* @__PURE__ */ jsx(
825
+ IconButton,
826
+ {
827
+ size: "xs",
828
+ variant: "plain",
829
+ "aria-label": `Remove ${keyName} item ${index + 1}`,
830
+ className: "pdDesignerSchemaIconButton",
831
+ disabled,
832
+ onClick: () => commit(values.filter((_, itemIndex) => itemIndex !== index)),
833
+ children: /* @__PURE__ */ jsx(LuX, { size: 14, strokeWidth: 1.5 })
834
+ }
835
+ )
836
+ ] })
837
+ ] })
838
+ },
839
+ `${keyName}-${index}`
840
+ );
841
+ })
842
+ ] });
843
+ });
844
+ var SchemaCompositionEditor = memo(
845
+ function SchemaCompositionEditor2(props) {
846
+ return /* @__PURE__ */ jsxs(Tabs.Root, { size: "sm", defaultValue: "allOf", variant: "plain", lazyMount: true, children: [
847
+ /* @__PURE__ */ jsx(Tabs.List, { className: "pdDesignerSchemaTabsList", children: KEYS.map((key) => /* @__PURE__ */ jsx(Tabs.Trigger, { value: key, children: key }, key)) }),
848
+ KEYS.map((key) => /* @__PURE__ */ jsx(Tabs.Content, { value: key, pt: "3", children: /* @__PURE__ */ jsx(
849
+ CompositionList,
850
+ {
851
+ schema: props.schema,
852
+ fullSchema: props.fullSchema,
853
+ keyName: key,
854
+ disabled: props.disabled,
855
+ onChange: props.onChange
856
+ }
857
+ ) }, key))
858
+ ] });
859
+ }
860
+ );
861
+ function previewText(schema) {
862
+ try {
863
+ return JSON.stringify(schema, null, 2);
864
+ } catch {
865
+ return "Schema preview unavailable: input contains a cyclic or non-JSON value.";
866
+ }
867
+ }
868
+ function SchemaPreview(props) {
869
+ const [copied, setCopied] = useState(false);
870
+ const [baselineText, setBaselineText] = useState(
871
+ () => previewText(props.schema)
872
+ );
873
+ const [lastStableText, setLastStableText] = useState(
874
+ () => previewText(props.schema)
875
+ );
876
+ const currentText = useMemo(() => previewText(props.schema), [props.schema]);
877
+ const copyTimerRef = useRef(
878
+ void 0
879
+ );
880
+ useEffect(() => () => clearTimeout(copyTimerRef.current), []);
881
+ const timerRef = useRef(null);
882
+ useEffect(() => {
883
+ if (currentText === lastStableText) return;
884
+ if (timerRef.current) window.clearTimeout(timerRef.current);
885
+ timerRef.current = window.setTimeout(() => {
886
+ setBaselineText(lastStableText);
887
+ setLastStableText(currentText);
888
+ timerRef.current = null;
889
+ }, 1400);
890
+ return () => {
891
+ if (timerRef.current) window.clearTimeout(timerRef.current);
892
+ };
893
+ }, [currentText, lastStableText]);
894
+ const lines = useMemo(
895
+ () => diffSchemaLines(baselineText, currentText),
896
+ [baselineText, currentText]
897
+ );
898
+ const pathText = (props.path?.length ? props.path.join(" / ") : "root").replace(/\./g, " / ");
899
+ return /* @__PURE__ */ jsxs(Stack, { gap: "3", h: "100%", children: [
900
+ /* @__PURE__ */ jsxs(HStack, { justify: "space-between", align: "start", children: [
901
+ /* @__PURE__ */ jsxs(Box, { minW: "0", children: [
902
+ /* @__PURE__ */ jsx(
903
+ Text,
904
+ {
905
+ fontSize: "sm",
906
+ fontWeight: "700",
907
+ color: "var(--color-text-primary)",
908
+ children: "Generated schema"
909
+ }
910
+ ),
911
+ /* @__PURE__ */ jsx(
912
+ Text,
913
+ {
914
+ fontSize: "xs",
915
+ color: "var(--color-text-secondary)",
916
+ whiteSpace: "nowrap",
917
+ overflow: "hidden",
918
+ textOverflow: "ellipsis",
919
+ children: pathText
920
+ }
921
+ )
922
+ ] }),
923
+ /* @__PURE__ */ jsx(
924
+ Button,
925
+ {
926
+ size: "xs",
927
+ variant: "outline",
928
+ onClick: async () => {
929
+ try {
930
+ await navigator.clipboard.writeText(currentText);
931
+ setCopied(true);
932
+ clearTimeout(copyTimerRef.current);
933
+ copyTimerRef.current = setTimeout(() => setCopied(false), 1400);
934
+ } catch {
935
+ setCopied(false);
936
+ }
937
+ },
938
+ children: copied ? "Copied" : "Copy"
939
+ }
940
+ )
941
+ ] }),
942
+ /* @__PURE__ */ jsx(
943
+ Box,
944
+ {
945
+ flex: "1",
946
+ minH: "0",
947
+ overflow: "auto",
948
+ border: "1px solid var(--color-border-subtle)",
949
+ borderRadius: "var(--radius-xl)",
950
+ bg: "var(--color-surface-subtle)",
951
+ p: "3",
952
+ fontFamily: "mono",
953
+ fontSize: "12px",
954
+ children: lines.map((line, index) => /* @__PURE__ */ jsx(
955
+ Box,
956
+ {
957
+ px: "2",
958
+ py: "0.5",
959
+ borderRadius: "var(--radius-sm)",
960
+ bg: line.kind === "added" ? "var(--color-success-soft)" : line.kind === "removed" ? "var(--color-danger-soft)" : "transparent",
961
+ color: line.kind === "added" ? "var(--color-success)" : line.kind === "removed" ? "var(--color-danger)" : "var(--color-text-primary)",
962
+ textDecoration: line.kind === "removed" ? "line-through" : "none",
963
+ whiteSpace: "pre",
964
+ children: line.value || " "
965
+ },
966
+ `${index}-${line.kind}-${line.value}`
967
+ ))
968
+ }
969
+ ),
970
+ copied ? /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(
971
+ Box,
972
+ {
973
+ position: "fixed",
974
+ top: "20px",
975
+ right: "20px",
976
+ zIndex: 2e3,
977
+ bg: "var(--color-surface)",
978
+ color: "var(--color-text-primary)",
979
+ border: "1px solid var(--color-border-default)",
980
+ borderRadius: "var(--radius-lg)",
981
+ boxShadow: "var(--shadow-md)",
982
+ px: "3",
983
+ py: "2",
984
+ children: "Copied schema JSON"
985
+ }
986
+ ) }) : null
987
+ ] });
988
+ }
989
+ function StringSchemaEditor(props) {
990
+ const formats = normalizeFormatOptions(props.formatOptions);
991
+ const collection = createListCollection({
992
+ items: [
993
+ { value: "", label: "None" },
994
+ ...formats.map((value) => ({ value, label: value }))
995
+ ]
996
+ });
997
+ return /* @__PURE__ */ jsx(Stack, { gap: "3", children: /* @__PURE__ */ jsxs(Grid, { templateColumns: "repeat(2, minmax(0, 1fr))", gap: "3", children: [
998
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
999
+ /* @__PURE__ */ jsx(Field.Label, { children: "Format" }),
1000
+ /* @__PURE__ */ jsxs(
1001
+ Select.Root,
1002
+ {
1003
+ collection,
1004
+ size: "sm",
1005
+ disabled: props.disabled,
1006
+ value: [
1007
+ typeof props.schema.format === "string" ? props.schema.format : ""
1008
+ ],
1009
+ onValueChange: (e) => props.update({ format: e.value?.[0] || void 0 }),
1010
+ children: [
1011
+ /* @__PURE__ */ jsx(Select.HiddenSelect, {}),
1012
+ /* @__PURE__ */ jsxs(Select.Control, { children: [
1013
+ /* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.ValueText, { placeholder: "None" }) }),
1014
+ /* @__PURE__ */ jsx(Select.IndicatorGroup, { children: /* @__PURE__ */ jsx(Select.Indicator, {}) })
1015
+ ] }),
1016
+ /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Select.Positioner, { children: /* @__PURE__ */ jsx(Select.Content, { className: "pdDesignerSelectMenu", children: collection.items.map((item) => /* @__PURE__ */ jsxs(Select.Item, { item, children: [
1017
+ item.label,
1018
+ /* @__PURE__ */ jsx(Select.ItemIndicator, {})
1019
+ ] }, item.value)) }) }) })
1020
+ ]
1021
+ }
1022
+ )
1023
+ ] }),
1024
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
1025
+ /* @__PURE__ */ jsx(Field.Label, { children: "Pattern" }),
1026
+ /* @__PURE__ */ jsx(
1027
+ Input,
1028
+ {
1029
+ size: "sm",
1030
+ disabled: props.disabled,
1031
+ value: toInputValue(props.schema.pattern),
1032
+ onChange: (e) => props.update({ pattern: e.target.value || void 0 })
1033
+ }
1034
+ )
1035
+ ] }),
1036
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
1037
+ /* @__PURE__ */ jsx(Field.Label, { children: "Min length" }),
1038
+ /* @__PURE__ */ jsx(
1039
+ Input,
1040
+ {
1041
+ size: "sm",
1042
+ type: "number",
1043
+ disabled: props.disabled,
1044
+ value: toInputValue(props.schema.minLength),
1045
+ onChange: (e) => props.update({ minLength: parseOptionalNumber(e.target.value) })
1046
+ }
1047
+ )
1048
+ ] }),
1049
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
1050
+ /* @__PURE__ */ jsx(Field.Label, { children: "Max length" }),
1051
+ /* @__PURE__ */ jsx(
1052
+ Input,
1053
+ {
1054
+ size: "sm",
1055
+ type: "number",
1056
+ disabled: props.disabled,
1057
+ value: toInputValue(props.schema.maxLength),
1058
+ onChange: (e) => props.update({ maxLength: parseOptionalNumber(e.target.value) })
1059
+ }
1060
+ )
1061
+ ] })
1062
+ ] }) });
1063
+ }
1064
+ function NumberSchemaEditor(props) {
1065
+ const formats = normalizeFormatOptions(props.formatOptions);
1066
+ const collection = createListCollection({
1067
+ items: [
1068
+ { value: "", label: "None" },
1069
+ ...formats.map((value) => ({ value, label: value }))
1070
+ ]
1071
+ });
1072
+ const numeric = (key, value) => props.update({
1073
+ [key]: parseOptionalNumber(value)
1074
+ });
1075
+ return /* @__PURE__ */ jsx(Stack, { gap: "3", children: /* @__PURE__ */ jsxs(Grid, { templateColumns: "repeat(2, minmax(0, 1fr))", gap: "3", children: [
1076
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
1077
+ /* @__PURE__ */ jsx(Field.Label, { children: "Format" }),
1078
+ /* @__PURE__ */ jsxs(
1079
+ Select.Root,
1080
+ {
1081
+ collection,
1082
+ size: "sm",
1083
+ disabled: props.disabled,
1084
+ value: [
1085
+ typeof props.schema.format === "string" ? props.schema.format : ""
1086
+ ],
1087
+ onValueChange: (e) => props.update({ format: e.value?.[0] || void 0 }),
1088
+ children: [
1089
+ /* @__PURE__ */ jsx(Select.HiddenSelect, {}),
1090
+ /* @__PURE__ */ jsxs(Select.Control, { children: [
1091
+ /* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.ValueText, { placeholder: "None" }) }),
1092
+ /* @__PURE__ */ jsx(Select.IndicatorGroup, { children: /* @__PURE__ */ jsx(Select.Indicator, {}) })
1093
+ ] }),
1094
+ /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Select.Positioner, { children: /* @__PURE__ */ jsx(Select.Content, { className: "pdDesignerSelectMenu", children: collection.items.map((item) => /* @__PURE__ */ jsxs(Select.Item, { item, children: [
1095
+ item.label,
1096
+ /* @__PURE__ */ jsx(Select.ItemIndicator, {})
1097
+ ] }, item.value)) }) }) })
1098
+ ]
1099
+ }
1100
+ )
1101
+ ] }),
1102
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
1103
+ /* @__PURE__ */ jsx(Field.Label, { children: "Multiple of" }),
1104
+ /* @__PURE__ */ jsx(
1105
+ Input,
1106
+ {
1107
+ size: "sm",
1108
+ type: "number",
1109
+ disabled: props.disabled,
1110
+ value: toInputValue(props.schema.multipleOf),
1111
+ onChange: (e) => numeric("multipleOf", e.target.value)
1112
+ }
1113
+ )
1114
+ ] }),
1115
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
1116
+ /* @__PURE__ */ jsx(Field.Label, { children: "Minimum" }),
1117
+ /* @__PURE__ */ jsx(
1118
+ Input,
1119
+ {
1120
+ size: "sm",
1121
+ type: "number",
1122
+ disabled: props.disabled,
1123
+ value: toInputValue(props.schema.minimum),
1124
+ onChange: (e) => numeric("minimum", e.target.value)
1125
+ }
1126
+ )
1127
+ ] }),
1128
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
1129
+ /* @__PURE__ */ jsx(Field.Label, { children: "Maximum" }),
1130
+ /* @__PURE__ */ jsx(
1131
+ Input,
1132
+ {
1133
+ size: "sm",
1134
+ type: "number",
1135
+ disabled: props.disabled,
1136
+ value: toInputValue(props.schema.maximum),
1137
+ onChange: (e) => numeric("maximum", e.target.value)
1138
+ }
1139
+ )
1140
+ ] }),
1141
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
1142
+ /* @__PURE__ */ jsx(Field.Label, { children: "Exclusive minimum" }),
1143
+ /* @__PURE__ */ jsx(
1144
+ Input,
1145
+ {
1146
+ size: "sm",
1147
+ type: "number",
1148
+ disabled: props.disabled,
1149
+ value: toInputValue(props.schema.exclusiveMinimum),
1150
+ onChange: (e) => numeric("exclusiveMinimum", e.target.value)
1151
+ }
1152
+ )
1153
+ ] }),
1154
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
1155
+ /* @__PURE__ */ jsx(Field.Label, { children: "Exclusive maximum" }),
1156
+ /* @__PURE__ */ jsx(
1157
+ Input,
1158
+ {
1159
+ size: "sm",
1160
+ type: "number",
1161
+ disabled: props.disabled,
1162
+ value: toInputValue(props.schema.exclusiveMaximum),
1163
+ onChange: (e) => numeric("exclusiveMaximum", e.target.value)
1164
+ }
1165
+ )
1166
+ ] })
1167
+ ] }) });
1168
+ }
1169
+ var NestedSchemaCard = memo(function NestedSchemaCard2(props) {
1170
+ const triggerRef = useRef(null);
1171
+ return /* @__PURE__ */ jsx(Box, { className: "pdDesignerSchemaNestedCard", children: /* @__PURE__ */ jsxs(HStack, { justify: "space-between", align: "center", gap: "3", children: [
1172
+ /* @__PURE__ */ jsxs(Box, { flex: "1", minW: "0", children: [
1173
+ /* @__PURE__ */ jsx(Text, { fontWeight: "600", fontSize: "sm", children: props.title }),
1174
+ /* @__PURE__ */ jsx(Text, { fontSize: "xs", color: "var(--color-text-secondary)", mb: "1", children: props.description }),
1175
+ /* @__PURE__ */ jsx(Text, { fontSize: "xs", color: "var(--color-text-secondary)", lineClamp: 2, children: getSchemaSummary(props.schema) })
1176
+ ] }),
1177
+ props.onRemove && /* @__PURE__ */ jsx(
1178
+ Button,
1179
+ {
1180
+ size: "xs",
1181
+ variant: "ghost",
1182
+ disabled: props.disabled,
1183
+ onClick: props.onRemove,
1184
+ "aria-label": `Remove ${props.title.toLowerCase()}`,
1185
+ children: "Remove"
1186
+ }
1187
+ ),
1188
+ /* @__PURE__ */ jsxs(
1189
+ Popover.Root,
1190
+ {
1191
+ lazyMount: true,
1192
+ unmountOnExit: true,
1193
+ positioning: { placement: "left-start", strategy: "fixed" },
1194
+ onOpenChange: (details) => {
1195
+ if (!details.open && triggerRef.current) {
1196
+ window.requestAnimationFrame(() => triggerRef.current?.focus());
1197
+ }
1198
+ },
1199
+ children: [
1200
+ /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
1201
+ IconButton,
1202
+ {
1203
+ ref: triggerRef,
1204
+ size: "xs",
1205
+ variant: "outline",
1206
+ "aria-label": `Configure ${props.title.toLowerCase()}`,
1207
+ className: "pdDesignerSchemaIconButton",
1208
+ children: /* @__PURE__ */ jsx(VscSettingsCompact, { size: 16 })
1209
+ }
1210
+ ) }),
1211
+ /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, { children: /* @__PURE__ */ jsx(SettingsPanel, { title: props.title, children: /* @__PURE__ */ jsx(
1212
+ InlineSchemaEditor,
1213
+ {
1214
+ schema: props.schema,
1215
+ onChange: props.onChange,
1216
+ fullSchema: props.fullSchema,
1217
+ disabled: props.disabled,
1218
+ nested: true,
1219
+ path: props.path
1220
+ }
1221
+ ) }) }) })
1222
+ ]
1223
+ }
1224
+ )
1225
+ ] }) });
1226
+ });
1227
+ var ArraySchemaEditor = memo(function ArraySchemaEditor2(props) {
1228
+ const items = getArrayItems(props.schema) ?? { type: "string" };
1229
+ const prefixItems = getPrefixItems(props.schema);
1230
+ const contains = typeof props.schema.contains === "boolean" || typeof props.schema.contains === "object" && props.schema.contains ? props.schema.contains : { type: "string" };
1231
+ return /* @__PURE__ */ jsxs(Stack, { gap: "4", children: [
1232
+ /* @__PURE__ */ jsx(
1233
+ NestedSchemaCard,
1234
+ {
1235
+ title: "Items schema",
1236
+ description: "Define the schema used by each array item.",
1237
+ schema: items,
1238
+ fullSchema: props.fullSchema,
1239
+ disabled: props.disabled,
1240
+ path: ["items"],
1241
+ onChange: (next) => props.onChange({
1242
+ ...props.schema,
1243
+ type: "array",
1244
+ items: next
1245
+ })
1246
+ }
1247
+ ),
1248
+ /* @__PURE__ */ jsx(Grid, { templateColumns: "repeat(2, minmax(0, 1fr))", gap: "3", children: ["minItems", "maxItems", "minContains", "maxContains"].map((key) => /* @__PURE__ */ jsxs(Field.Root, { children: [
1249
+ /* @__PURE__ */ jsx(Field.Label, { children: key }),
1250
+ /* @__PURE__ */ jsx(
1251
+ Input,
1252
+ {
1253
+ size: "sm",
1254
+ type: "number",
1255
+ disabled: props.disabled,
1256
+ value: toInputValue(props.schema[key]),
1257
+ onChange: (e) => props.onChange({
1258
+ ...props.schema,
1259
+ [key]: parseOptionalNumber(e.target.value)
1260
+ })
1261
+ }
1262
+ )
1263
+ ] }, key)) }),
1264
+ /* @__PURE__ */ jsxs(
1265
+ Switch.Root,
1266
+ {
1267
+ checked: props.schema.uniqueItems === true,
1268
+ disabled: props.disabled,
1269
+ onCheckedChange: (e) => props.onChange({
1270
+ ...props.schema,
1271
+ uniqueItems: e.checked ? true : void 0
1272
+ }),
1273
+ children: [
1274
+ /* @__PURE__ */ jsx(Switch.HiddenInput, {}),
1275
+ /* @__PURE__ */ jsx(Switch.Control, {}),
1276
+ /* @__PURE__ */ jsx(Switch.Label, { children: "Unique items" })
1277
+ ]
1278
+ }
1279
+ ),
1280
+ /* @__PURE__ */ jsx(
1281
+ NestedSchemaCard,
1282
+ {
1283
+ title: "Contains schema",
1284
+ description: "Require at least one array item to match this schema.",
1285
+ schema: contains,
1286
+ fullSchema: props.fullSchema,
1287
+ disabled: props.disabled,
1288
+ path: ["contains"],
1289
+ onChange: (next) => props.onChange({ ...props.schema, contains: next })
1290
+ }
1291
+ ),
1292
+ /* @__PURE__ */ jsxs(Stack, { gap: "2", className: "pdDesignerSchemaSection", children: [
1293
+ /* @__PURE__ */ jsxs(HStack, { justify: "space-between", align: "center", children: [
1294
+ /* @__PURE__ */ jsx(Text, { fontSize: "sm", fontWeight: "700", children: "Tuple prefix items" }),
1295
+ /* @__PURE__ */ jsx(
1296
+ Button,
1297
+ {
1298
+ size: "xs",
1299
+ variant: "outline",
1300
+ disabled: props.disabled,
1301
+ onClick: () => props.onChange({
1302
+ ...props.schema,
1303
+ prefixItems: [...prefixItems, { type: "string" }]
1304
+ }),
1305
+ children: "Add prefix item"
1306
+ }
1307
+ )
1308
+ ] }),
1309
+ prefixItems.length === 0 ? /* @__PURE__ */ jsx(Text, { fontSize: "xs", color: "var(--color-text-secondary)", children: "No tuple prefix items." }) : null,
1310
+ prefixItems.map((item, index) => /* @__PURE__ */ jsx(
1311
+ NestedSchemaCard,
1312
+ {
1313
+ title: `Prefix item ${index + 1}`,
1314
+ description: "Schema for the positional tuple item.",
1315
+ schema: item,
1316
+ fullSchema: props.fullSchema,
1317
+ disabled: props.disabled,
1318
+ path: ["prefixItems", String(index)],
1319
+ onRemove: () => props.onChange({
1320
+ ...props.schema,
1321
+ prefixItems: prefixItems.filter(
1322
+ (_, position) => position !== index
1323
+ )
1324
+ }),
1325
+ onChange: (next) => {
1326
+ const values = [...prefixItems];
1327
+ values[index] = next;
1328
+ props.onChange({
1329
+ ...props.schema,
1330
+ prefixItems: values
1331
+ });
1332
+ }
1333
+ },
1334
+ `prefix-${index}`
1335
+ ))
1336
+ ] })
1337
+ ] });
1338
+ });
1339
+ var SchemaPropertyRow = memo(function SchemaPropertyRow2(props) {
1340
+ const [name, setName] = useState(props.name);
1341
+ const [error, setError] = useState("");
1342
+ const triggerRef = useRef(null);
1343
+ useEffect(() => {
1344
+ setName(props.name);
1345
+ setError("");
1346
+ }, [props.name]);
1347
+ const validate = (next) => {
1348
+ const trimmed = next.trim();
1349
+ if (!trimmed) return "Property name is required.";
1350
+ if (trimmed !== props.name && props.siblingNames.includes(trimmed)) {
1351
+ return "Property name already exists.";
1352
+ }
1353
+ return "";
1354
+ };
1355
+ const commitRename = () => {
1356
+ const nextError = validate(name);
1357
+ setError(nextError);
1358
+ if (!nextError && name.trim() !== props.name) {
1359
+ props.onRename(name.trim());
1360
+ }
1361
+ };
1362
+ return /* @__PURE__ */ jsx(Box, { className: "pdDesignerSchemaNestedCard", children: /* @__PURE__ */ jsxs(HStack, { align: "start", gap: "3", className: "schemaPropertyRow", children: [
1363
+ /* @__PURE__ */ jsxs(Field.Root, { invalid: !!error, flex: "1", minW: "0", children: [
1364
+ /* @__PURE__ */ jsx(Field.Label, { children: "Property" }),
1365
+ /* @__PURE__ */ jsx(
1366
+ Input,
1367
+ {
1368
+ size: "sm",
1369
+ value: name,
1370
+ disabled: props.disabled,
1371
+ onChange: (e) => {
1372
+ setName(e.target.value);
1373
+ setError(validate(e.target.value));
1374
+ },
1375
+ onBlur: commitRename,
1376
+ onKeyDown: (e) => {
1377
+ if (e.key === "Enter") {
1378
+ e.preventDefault();
1379
+ commitRename();
1380
+ }
1381
+ if (e.key === "Escape") {
1382
+ setName(props.name);
1383
+ setError("");
1384
+ }
1385
+ if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === "d") {
1386
+ e.preventDefault();
1387
+ props.onDuplicate();
1388
+ }
1389
+ if ((e.metaKey || e.ctrlKey) && e.key === "Backspace") {
1390
+ e.preventDefault();
1391
+ props.onRemove();
1392
+ }
1393
+ },
1394
+ placeholder: "Property name"
1395
+ }
1396
+ ),
1397
+ error ? /* @__PURE__ */ jsx(Field.ErrorText, { children: error }) : null,
1398
+ /* @__PURE__ */ jsx(Text, { fontSize: "xs", color: "var(--color-text-secondary)", mt: "1", children: getSchemaSummary(props.schema) })
1399
+ ] }),
1400
+ /* @__PURE__ */ jsxs(Stack, { gap: "2", pt: "6", minW: "88px", flexShrink: 0, children: [
1401
+ /* @__PURE__ */ jsx(Text, { fontSize: "xs", color: "var(--color-text-secondary)", children: getSchemaType(props.schema) }),
1402
+ /* @__PURE__ */ jsxs(
1403
+ Switch.Root,
1404
+ {
1405
+ checked: props.required,
1406
+ disabled: props.disabled,
1407
+ onCheckedChange: (e) => props.onRequiredChange(!!e.checked),
1408
+ children: [
1409
+ /* @__PURE__ */ jsx(Switch.HiddenInput, {}),
1410
+ /* @__PURE__ */ jsx(Switch.Control, {}),
1411
+ /* @__PURE__ */ jsx(Switch.Label, { fontSize: "xs", children: "Required" })
1412
+ ]
1413
+ }
1414
+ )
1415
+ ] }),
1416
+ /* @__PURE__ */ jsxs(HStack, { pt: "6", gap: "1", flexShrink: 0, children: [
1417
+ /* @__PURE__ */ jsxs(
1418
+ Popover.Root,
1419
+ {
1420
+ lazyMount: true,
1421
+ unmountOnExit: true,
1422
+ positioning: { placement: "left-start", strategy: "fixed" },
1423
+ onOpenChange: (details) => {
1424
+ if (!details.open && triggerRef.current) {
1425
+ window.requestAnimationFrame(() => triggerRef.current?.focus());
1426
+ }
1427
+ },
1428
+ children: [
1429
+ /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
1430
+ IconButton,
1431
+ {
1432
+ ref: triggerRef,
1433
+ size: "xs",
1434
+ variant: "outline",
1435
+ "aria-label": "Configure property",
1436
+ className: "pdDesignerSchemaIconButton",
1437
+ children: /* @__PURE__ */ jsx(VscSettingsCompact, { size: 16 })
1438
+ }
1439
+ ) }),
1440
+ /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, { children: /* @__PURE__ */ jsx(SettingsPanel, { title: props.name, children: /* @__PURE__ */ jsx(
1441
+ InlineSchemaEditor,
1442
+ {
1443
+ schema: props.schema,
1444
+ onChange: props.onChange,
1445
+ fullSchema: props.fullSchema,
1446
+ disabled: props.disabled,
1447
+ nested: true,
1448
+ path: [props.name]
1449
+ }
1450
+ ) }) }) })
1451
+ ]
1452
+ }
1453
+ ),
1454
+ /* @__PURE__ */ jsx(
1455
+ IconButton,
1456
+ {
1457
+ pt: "0",
1458
+ size: "xs",
1459
+ variant: "plain",
1460
+ "aria-label": "Duplicate property",
1461
+ className: "pdDesignerSchemaIconButton",
1462
+ disabled: props.disabled,
1463
+ onClick: props.onDuplicate,
1464
+ children: "\u29C9"
1465
+ }
1466
+ ),
1467
+ /* @__PURE__ */ jsx(
1468
+ IconButton,
1469
+ {
1470
+ pt: "0",
1471
+ size: "xs",
1472
+ variant: "plain",
1473
+ "aria-label": "Remove property",
1474
+ className: "pdDesignerSchemaIconButton",
1475
+ disabled: props.disabled,
1476
+ onClick: props.onRemove,
1477
+ children: "\xD7"
1478
+ }
1479
+ )
1480
+ ] })
1481
+ ] }) });
1482
+ });
1483
+ var SchemaPropertyList = memo(function SchemaPropertyList2(props) {
1484
+ const properties = useMemo(() => getProperties(props.schema), [props.schema]);
1485
+ const required = useMemo(
1486
+ () => getRequiredProperties(props.schema),
1487
+ [props.schema]
1488
+ );
1489
+ const names = useMemo(() => Object.keys(properties), [properties]);
1490
+ const add = useCallback(() => {
1491
+ let index = names.length + 1;
1492
+ let name = `property${index}`;
1493
+ while (name in properties) name = `property${++index}`;
1494
+ props.onChange(
1495
+ updateProperty(props.schema, name, { type: "string" })
1496
+ );
1497
+ }, [names, properties, props]);
1498
+ const duplicate = useCallback(
1499
+ (name) => {
1500
+ let index = 2;
1501
+ let nextName = `${name}Copy`;
1502
+ while (nextName in properties) nextName = `${name}Copy${index++}`;
1503
+ props.onChange(
1504
+ updateProperty(props.schema, nextName, cloneSchema2(properties[name]))
1505
+ );
1506
+ },
1507
+ [properties, props]
1508
+ );
1509
+ return /* @__PURE__ */ jsxs(Stack, { gap: "3", className: "pdDesignerSchemaSection", children: [
1510
+ /* @__PURE__ */ jsxs(HStack, { justify: "space-between", align: "center", children: [
1511
+ /* @__PURE__ */ jsx(Text, { fontWeight: "700", fontSize: "sm", children: "Properties" }),
1512
+ /* @__PURE__ */ jsx(
1513
+ Button,
1514
+ {
1515
+ size: "xs",
1516
+ variant: "outline",
1517
+ disabled: props.disabled,
1518
+ onClick: add,
1519
+ children: "Add property"
1520
+ }
1521
+ )
1522
+ ] }),
1523
+ names.map((name) => /* @__PURE__ */ jsx(
1524
+ SchemaPropertyRow,
1525
+ {
1526
+ name,
1527
+ schema: properties[name],
1528
+ required: required.has(name),
1529
+ siblingNames: names,
1530
+ fullSchema: props.fullSchema,
1531
+ disabled: props.disabled,
1532
+ onRename: (next) => props.onChange(renameProperty(props.schema, name, next)),
1533
+ onDuplicate: () => duplicate(name),
1534
+ onRequiredChange: (value) => props.onChange(setPropertyRequired(props.schema, name, value)),
1535
+ onChange: (schema) => props.onChange(updateProperty(props.schema, name, schema)),
1536
+ onRemove: () => props.onChange(removeProperty(props.schema, name))
1537
+ },
1538
+ name
1539
+ )),
1540
+ !names.length ? /* @__PURE__ */ jsx(Text, { fontSize: "xs", color: "var(--color-text-secondary)", children: "No properties defined." }) : null
1541
+ ] });
1542
+ });
1543
+ var ObjectSchemaEditor = memo(function ObjectSchemaEditor2(props) {
1544
+ const triggerRef = useRef(null);
1545
+ const mode = props.schema.additionalProperties === false ? "deny" : typeof props.schema.additionalProperties === "object" ? "schema" : "allow";
1546
+ const additional = typeof props.schema.additionalProperties === "object" && props.schema.additionalProperties !== null ? props.schema.additionalProperties : { type: "string" };
1547
+ return /* @__PURE__ */ jsxs(Stack, { gap: "4", children: [
1548
+ /* @__PURE__ */ jsx(
1549
+ SchemaPropertyList,
1550
+ {
1551
+ schema: props.schema,
1552
+ fullSchema: props.fullSchema,
1553
+ disabled: props.disabled,
1554
+ onChange: props.onChange
1555
+ }
1556
+ ),
1557
+ /* @__PURE__ */ jsx(Grid, { templateColumns: "repeat(2, minmax(0, 1fr))", gap: "3", children: ["minProperties", "maxProperties"].map((key) => /* @__PURE__ */ jsxs(Field.Root, { children: [
1558
+ /* @__PURE__ */ jsx(Field.Label, { children: key }),
1559
+ /* @__PURE__ */ jsx(
1560
+ Input,
1561
+ {
1562
+ size: "sm",
1563
+ type: "number",
1564
+ disabled: props.disabled,
1565
+ value: toInputValue(props.schema[key]),
1566
+ onChange: (e) => props.onChange({
1567
+ ...props.schema,
1568
+ [key]: parseOptionalNumber(e.target.value)
1569
+ })
1570
+ }
1571
+ )
1572
+ ] }, key)) }),
1573
+ /* @__PURE__ */ jsxs(Stack, { gap: "2", className: "pdDesignerSchemaSection", children: [
1574
+ /* @__PURE__ */ jsx(Text, { fontSize: "sm", fontWeight: "700", children: "Additional properties" }),
1575
+ /* @__PURE__ */ jsx(Field.Root, { children: /* @__PURE__ */ jsxs(NativeSelect.Root, { size: "sm", disabled: props.disabled, children: [
1576
+ /* @__PURE__ */ jsxs(
1577
+ NativeSelect.Field,
1578
+ {
1579
+ value: mode,
1580
+ onChange: (e) => {
1581
+ const value = e.target.value;
1582
+ props.onChange({
1583
+ ...props.schema,
1584
+ additionalProperties: value === "deny" ? false : value === "schema" ? additional : void 0
1585
+ });
1586
+ },
1587
+ children: [
1588
+ /* @__PURE__ */ jsx("option", { value: "allow", children: "Allow any property" }),
1589
+ /* @__PURE__ */ jsx("option", { value: "deny", children: "Disallow extra properties" }),
1590
+ /* @__PURE__ */ jsx("option", { value: "schema", children: "Validate with schema" })
1591
+ ]
1592
+ }
1593
+ ),
1594
+ /* @__PURE__ */ jsx(NativeSelect.Indicator, {})
1595
+ ] }) }),
1596
+ mode === "schema" ? /* @__PURE__ */ jsx(Box, { className: "pdDesignerSchemaNestedCard", children: /* @__PURE__ */ jsxs(HStack, { justify: "space-between", align: "center", gap: "3", children: [
1597
+ /* @__PURE__ */ jsxs(Box, { flex: "1", minW: "0", children: [
1598
+ /* @__PURE__ */ jsx(Text, { fontSize: "sm", fontWeight: "600", children: "Additional property schema" }),
1599
+ /* @__PURE__ */ jsx(
1600
+ Text,
1601
+ {
1602
+ fontSize: "xs",
1603
+ color: "var(--color-text-secondary)",
1604
+ lineClamp: 2,
1605
+ children: getSchemaSummary(additional)
1606
+ }
1607
+ )
1608
+ ] }),
1609
+ /* @__PURE__ */ jsxs(
1610
+ Popover.Root,
1611
+ {
1612
+ lazyMount: true,
1613
+ unmountOnExit: true,
1614
+ positioning: { placement: "left-start", strategy: "fixed" },
1615
+ onOpenChange: (details) => {
1616
+ if (!details.open && triggerRef.current) {
1617
+ window.requestAnimationFrame(
1618
+ () => triggerRef.current?.focus()
1619
+ );
1620
+ }
1621
+ },
1622
+ children: [
1623
+ /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
1624
+ IconButton,
1625
+ {
1626
+ ref: triggerRef,
1627
+ size: "xs",
1628
+ variant: "outline",
1629
+ "aria-label": "Configure additional property schema",
1630
+ className: "pdDesignerSchemaIconButton",
1631
+ children: /* @__PURE__ */ jsx(VscSettingsCompact, { size: 16 })
1632
+ }
1633
+ ) }),
1634
+ /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, { children: /* @__PURE__ */ jsx(SettingsPanel, { title: "Additional properties", children: /* @__PURE__ */ jsx(
1635
+ InlineSchemaEditor,
1636
+ {
1637
+ schema: additional,
1638
+ fullSchema: props.fullSchema,
1639
+ disabled: props.disabled,
1640
+ nested: true,
1641
+ path: ["additionalProperties"],
1642
+ onChange: (value) => props.onChange({
1643
+ ...props.schema,
1644
+ additionalProperties: value
1645
+ })
1646
+ }
1647
+ ) }) }) })
1648
+ ]
1649
+ }
1650
+ )
1651
+ ] }) }) : null
1652
+ ] })
1653
+ ] });
1654
+ });
1655
+ function BooleanSchemaEditor() {
1656
+ return /* @__PURE__ */ jsx(Text, { fontSize: "sm", color: "var(--color-text-secondary)", children: "Boolean schemas do not expose type-specific constraints in this compact editor." });
1657
+ }
1658
+
1659
+ // src/react/inlineSchemaEditor/InlineSchemaEditor.module.css
1660
+ var InlineSchemaEditor_default = {
1661
+ root: "InlineSchemaEditor_root",
1662
+ shell: "InlineSchemaEditor_shell",
1663
+ editorPane: "InlineSchemaEditor_editorPane",
1664
+ previewPane: "InlineSchemaEditor_previewPane",
1665
+ reference: "InlineSchemaEditor_reference",
1666
+ tabsList: "InlineSchemaEditor_tabsList"
1667
+ };
1668
+ var STRING_FORMATS = [
1669
+ "date",
1670
+ "date-time",
1671
+ "time",
1672
+ "duration",
1673
+ "email",
1674
+ "idn-email",
1675
+ "hostname",
1676
+ "idn-hostname",
1677
+ "ipv4",
1678
+ "ipv6",
1679
+ "uri",
1680
+ "uri-reference",
1681
+ "iri",
1682
+ "iri-reference",
1683
+ "uuid",
1684
+ "regex",
1685
+ "json-pointer",
1686
+ "relative-json-pointer"
1687
+ ];
1688
+ var NUMBER_FORMATS = ["float", "double"];
1689
+ var INTEGER_FORMATS = ["int32", "int64"];
1690
+ function InlineSchemaEditor(props) {
1691
+ const current = props.value !== void 0 ? props.value : props.schema;
1692
+ const update = (patch) => {
1693
+ if (props.disabled) return;
1694
+ props.onChange?.(mergeSchema(current, patch));
1695
+ props.update?.(patch);
1696
+ if (Object.hasOwn(patch, "example")) props.onExampleChange?.(patch.example);
1697
+ if (Object.hasOwn(patch, "default")) props.onDefaultChange?.(patch.default);
1698
+ };
1699
+ if (typeof current === "boolean")
1700
+ return /* @__PURE__ */ jsx(Box, { className: InlineSchemaEditor_default.root, children: /* @__PURE__ */ jsxs(Stack, { gap: "3", children: [
1701
+ /* @__PURE__ */ jsx(Text, { fontWeight: "600", children: current ? "Any value is allowed" : "No values are allowed" }),
1702
+ /* @__PURE__ */ jsx(Text, { fontSize: "sm", children: "This is a boolean JSON Schema." }),
1703
+ props.onRequiredChange && /* @__PURE__ */ jsxs(
1704
+ Switch.Root,
1705
+ {
1706
+ checked: !!props.required,
1707
+ disabled: props.disabled,
1708
+ onCheckedChange: (event) => props.onRequiredChange?.(event.checked),
1709
+ children: [
1710
+ /* @__PURE__ */ jsx(Switch.HiddenInput, {}),
1711
+ /* @__PURE__ */ jsx(Switch.Control, {}),
1712
+ /* @__PURE__ */ jsx(Switch.Label, { children: "Required" })
1713
+ ]
1714
+ }
1715
+ ),
1716
+ /* @__PURE__ */ jsx(
1717
+ Button,
1718
+ {
1719
+ size: "sm",
1720
+ disabled: props.disabled || !props.onChange,
1721
+ onClick: () => props.onChange?.(!current),
1722
+ children: current ? "Disallow all values" : "Allow all values"
1723
+ }
1724
+ ),
1725
+ /* @__PURE__ */ jsx(
1726
+ Button,
1727
+ {
1728
+ size: "sm",
1729
+ variant: "outline",
1730
+ disabled: props.disabled,
1731
+ onClick: () => update({}),
1732
+ children: "Configure constraints"
1733
+ }
1734
+ )
1735
+ ] }) });
1736
+ return /* @__PURE__ */ jsx(ObjectSchemaEditorView, { ...props, schema: current, update });
1737
+ }
1738
+ function ObjectSchemaEditorView(props) {
1739
+ const { schema, type } = useSchemaEditor(props.schema, props.schemaType);
1740
+ const { patch, replace } = useSchemaPatch(props.schema, props.update);
1741
+ const record = toSchemaRecord(schema);
1742
+ const isRefMode = typeof record.$ref === "string" && record.$ref.length > 0;
1743
+ const onTypeChange = useCallback(
1744
+ (nextType) => {
1745
+ const next = createSchemaForType(nextType, schema);
1746
+ replace(next);
1747
+ props.onTypeChange?.(nextType);
1748
+ },
1749
+ [props, replace, schema]
1750
+ );
1751
+ const formatOptions = useMemo(
1752
+ () => props.formatOptions ?? (type === "string" ? STRING_FORMATS : type === "number" ? NUMBER_FORMATS : type === "integer" ? INTEGER_FORMATS : []),
1753
+ [props.formatOptions, type]
1754
+ );
1755
+ const mergeSchema2 = useCallback(
1756
+ (next) => replace(next),
1757
+ [replace]
1758
+ );
1759
+ const previewVisible = props.showLiveJson !== false && !props.nested;
1760
+ const handleRefUpdate = useCallback(
1761
+ (nextPatch) => {
1762
+ patch(nextPatch);
1763
+ },
1764
+ [isRefMode, patch, replace, schema]
1765
+ );
1766
+ const showBasicEnum = !["object", "array", "null", "any"].includes(type);
1767
+ const content = /* @__PURE__ */ jsxs(Stack, { gap: "2", minW: "0", flex: "1", children: [
1768
+ /* @__PURE__ */ jsx(
1769
+ SchemaHeader,
1770
+ {
1771
+ name: props.schemaName,
1772
+ description: typeof schema.description === "string" ? schema.description : "",
1773
+ type,
1774
+ required: props.required,
1775
+ disabled: props.disabled,
1776
+ onTypeChange,
1777
+ onRequiredChange: props.onRequiredChange,
1778
+ onNameChange: props.onNameChange,
1779
+ hideName: !!props.nested,
1780
+ onDescriptionChange: (value) => patch({ description: value || void 0 })
1781
+ }
1782
+ ),
1783
+ /* @__PURE__ */ jsxs("details", { className: InlineSchemaEditor_default.reference, open: isRefMode || void 0, children: [
1784
+ /* @__PURE__ */ jsxs("summary", { children: [
1785
+ "Reference",
1786
+ isRefMode ? " linked" : " (optional)"
1787
+ ] }),
1788
+ /* @__PURE__ */ jsx(
1789
+ SchemaReferenceEditor,
1790
+ {
1791
+ schema,
1792
+ fullSchema: props.fullSchema,
1793
+ disabled: props.disabled,
1794
+ onClearReference: () => handleRefUpdate({ $ref: void 0 }),
1795
+ update: handleRefUpdate
1796
+ }
1797
+ )
1798
+ ] }),
1799
+ !isRefMode && /* @__PURE__ */ jsxs(
1800
+ Tabs.Root,
1801
+ {
1802
+ size: "sm",
1803
+ defaultValue: "core",
1804
+ variant: "plain",
1805
+ lazyMount: true,
1806
+ unmountOnExit: true,
1807
+ children: [
1808
+ /* @__PURE__ */ jsxs(Tabs.List, { className: InlineSchemaEditor_default.tabsList, children: [
1809
+ /* @__PURE__ */ jsx(Tabs.Trigger, { value: "core", children: "Core" }),
1810
+ /* @__PURE__ */ jsx(Tabs.Trigger, { value: "validation", children: "Validation" }),
1811
+ props.showAdvanced !== false && /* @__PURE__ */ jsx(Tabs.Trigger, { value: "advanced", children: "Advanced" })
1812
+ ] }),
1813
+ /* @__PURE__ */ jsx(Tabs.Content, { value: "core", pt: "2", children: /* @__PURE__ */ jsxs(Stack, { gap: "2", children: [
1814
+ type === "string" && /* @__PURE__ */ jsx(
1815
+ StringSchemaEditor,
1816
+ {
1817
+ schema,
1818
+ disabled: props.disabled,
1819
+ formatOptions,
1820
+ update: patch
1821
+ }
1822
+ ),
1823
+ (type === "number" || type === "integer") && /* @__PURE__ */ jsx(
1824
+ NumberSchemaEditor,
1825
+ {
1826
+ schema,
1827
+ disabled: props.disabled,
1828
+ formatOptions,
1829
+ update: patch
1830
+ }
1831
+ ),
1832
+ type === "boolean" && /* @__PURE__ */ jsx(BooleanSchemaEditor, {}),
1833
+ type === "array" && /* @__PURE__ */ jsx(
1834
+ ArraySchemaEditor,
1835
+ {
1836
+ schema,
1837
+ fullSchema: props.fullSchema,
1838
+ disabled: props.disabled,
1839
+ onChange: mergeSchema2
1840
+ }
1841
+ ),
1842
+ type === "object" && /* @__PURE__ */ jsx(
1843
+ ObjectSchemaEditor,
1844
+ {
1845
+ schema,
1846
+ fullSchema: props.fullSchema,
1847
+ disabled: props.disabled,
1848
+ onChange: mergeSchema2
1849
+ }
1850
+ )
1851
+ ] }) }),
1852
+ /* @__PURE__ */ jsx(Tabs.Content, { value: "validation", pt: "2", children: /* @__PURE__ */ jsxs(Stack, { gap: "2", children: [
1853
+ showBasicEnum ? /* @__PURE__ */ jsx(
1854
+ SchemaEnumEditor,
1855
+ {
1856
+ schema,
1857
+ type,
1858
+ disabled: props.disabled,
1859
+ update: patch
1860
+ }
1861
+ ) : null,
1862
+ props.showComposition !== false && /* @__PURE__ */ jsxs("details", { className: InlineSchemaEditor_default.reference, children: [
1863
+ /* @__PURE__ */ jsx("summary", { children: "Composition rules (allOf / anyOf / oneOf)" }),
1864
+ /* @__PURE__ */ jsx(
1865
+ SchemaCompositionEditor,
1866
+ {
1867
+ schema,
1868
+ fullSchema: props.fullSchema,
1869
+ disabled: props.disabled,
1870
+ onChange: mergeSchema2
1871
+ }
1872
+ )
1873
+ ] })
1874
+ ] }) }),
1875
+ /* @__PURE__ */ jsx(Tabs.Content, { value: "advanced", pt: "2", children: /* @__PURE__ */ jsx(
1876
+ SchemaAdvancedEditor,
1877
+ {
1878
+ schema,
1879
+ disabled: props.disabled,
1880
+ update: patch
1881
+ }
1882
+ ) })
1883
+ ]
1884
+ }
1885
+ )
1886
+ ] });
1887
+ if (props.nested) {
1888
+ return /* @__PURE__ */ jsx(Box, { className: InlineSchemaEditor_default.root, children: content });
1889
+ }
1890
+ return /* @__PURE__ */ jsx(Box, { className: InlineSchemaEditor_default.root, children: /* @__PURE__ */ jsxs(Box, { className: InlineSchemaEditor_default.shell, children: [
1891
+ /* @__PURE__ */ jsx(Box, { className: InlineSchemaEditor_default.editorPane, children: content }),
1892
+ previewVisible && /* @__PURE__ */ jsx(Box, { className: InlineSchemaEditor_default.previewPane, children: /* @__PURE__ */ jsx(SchemaPreview, { schema, path: props.path }) })
1893
+ ] }) });
1894
+ }
1895
+
1896
+ export { InlineSchemaEditor, InlineSchemaEditor_default, SettingsPanel };