schema-components 1.12.11 → 1.14.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 (83) hide show
  1. package/README.md +35 -0
  2. package/dist/core/adapter.d.mts +8 -3
  3. package/dist/core/adapter.mjs +58 -14
  4. package/dist/core/constraints.d.mts +17 -0
  5. package/dist/core/constraints.mjs +150 -0
  6. package/dist/core/diagnostics.d.mts +2 -0
  7. package/dist/core/diagnostics.mjs +33 -0
  8. package/dist/core/errors.d.mts +1 -1
  9. package/dist/core/formats.d.mts +33 -0
  10. package/dist/core/formats.mjs +67 -0
  11. package/dist/core/merge.d.mts +48 -0
  12. package/dist/core/merge.mjs +125 -0
  13. package/dist/core/normalise.d.mts +41 -0
  14. package/dist/core/normalise.mjs +2 -0
  15. package/dist/core/openapi30.d.mts +41 -0
  16. package/dist/core/openapi30.mjs +2 -0
  17. package/dist/core/ref.d.mts +2 -0
  18. package/dist/core/ref.mjs +165 -0
  19. package/dist/core/renderer.d.mts +2 -2
  20. package/dist/core/renderer.mjs +8 -0
  21. package/dist/core/swagger2.d.mts +11 -0
  22. package/dist/core/swagger2.mjs +2 -0
  23. package/dist/core/typeInference.d.mts +2 -0
  24. package/dist/core/typeInference.mjs +1 -0
  25. package/dist/core/types.d.mts +2 -3
  26. package/dist/core/types.mjs +58 -2
  27. package/dist/core/version.d.mts +2 -0
  28. package/dist/core/version.mjs +151 -0
  29. package/dist/core/walkBuilders.d.mts +66 -0
  30. package/dist/core/walkBuilders.mjs +152 -0
  31. package/dist/core/walker.d.mts +3 -10
  32. package/dist/core/walker.mjs +245 -233
  33. package/dist/diagnostics-DzbZmcLI.d.mts +64 -0
  34. package/dist/html/a11y.d.mts +5 -4
  35. package/dist/html/renderToHtml.d.mts +3 -3
  36. package/dist/html/renderToHtml.mjs +23 -379
  37. package/dist/html/renderToHtmlStream.d.mts +29 -47
  38. package/dist/html/renderToHtmlStream.mjs +33 -305
  39. package/dist/html/renderers.d.mts +14 -0
  40. package/dist/html/renderers.mjs +406 -0
  41. package/dist/html/streamRenderers.d.mts +13 -0
  42. package/dist/html/streamRenderers.mjs +243 -0
  43. package/dist/normalise-tL9FckAk.mjs +748 -0
  44. package/dist/openapi/ApiCallbacks.d.mts +16 -0
  45. package/dist/openapi/ApiCallbacks.mjs +34 -0
  46. package/dist/openapi/ApiLinks.d.mts +16 -0
  47. package/dist/openapi/ApiLinks.mjs +42 -0
  48. package/dist/openapi/ApiResponseHeaders.d.mts +16 -0
  49. package/dist/openapi/ApiResponseHeaders.mjs +35 -0
  50. package/dist/openapi/ApiSecurity.d.mts +19 -0
  51. package/dist/openapi/ApiSecurity.mjs +33 -0
  52. package/dist/openapi/bundle.d.mts +47 -0
  53. package/dist/openapi/bundle.mjs +95 -0
  54. package/dist/openapi/components.d.mts +7 -1
  55. package/dist/openapi/components.mjs +30 -6
  56. package/dist/openapi/parser.d.mts +59 -2
  57. package/dist/openapi/parser.mjs +189 -8
  58. package/dist/react/SchemaComponent.d.mts +13 -4
  59. package/dist/react/SchemaComponent.mjs +51 -91
  60. package/dist/react/SchemaView.d.mts +10 -2
  61. package/dist/react/SchemaView.mjs +33 -15
  62. package/dist/react/fieldPath.d.mts +20 -0
  63. package/dist/react/fieldPath.mjs +81 -0
  64. package/dist/react/headless.d.mts +2 -4
  65. package/dist/react/headless.mjs +3 -492
  66. package/dist/react/headlessRenderers.d.mts +23 -0
  67. package/dist/react/headlessRenderers.mjs +507 -0
  68. package/dist/ref-DvWoULcy.d.mts +44 -0
  69. package/dist/renderer-BdSqllx5.d.mts +160 -0
  70. package/dist/themes/mantine.d.mts +1 -1
  71. package/dist/themes/mantine.mjs +2 -1
  72. package/dist/themes/mui.d.mts +1 -1
  73. package/dist/themes/mui.mjs +3 -2
  74. package/dist/themes/radix.d.mts +1 -1
  75. package/dist/themes/radix.mjs +2 -1
  76. package/dist/themes/shadcn.d.mts +1 -1
  77. package/dist/themes/shadcn.mjs +10 -6
  78. package/dist/typeInference-k7FXfTVO.d.mts +335 -0
  79. package/dist/types-D_5ST7SS.d.mts +269 -0
  80. package/dist/version-B5NV-35j.d.mts +69 -0
  81. package/package.json +1 -1
  82. package/dist/types-BJzEgJdX.d.mts +0 -335
  83. /package/dist/{errors-DIKI2C78.d.mts → errors-C5zRC2PU.d.mts} +0 -0
@@ -0,0 +1,507 @@
1
+ import { isObject } from "../core/guards.mjs";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { isValidElement, useCallback, useRef } from "react";
4
+ //#region src/react/headlessRenderers.tsx
5
+ /**
6
+ * Headless renderer functions — one per schema type.
7
+ *
8
+ * Produces plain React elements for every schema type. These functions
9
+ * are composed into `headlessResolver` by `headless.tsx`.
10
+ *
11
+ * This module contains the individual render functions, date/time helpers,
12
+ * ID generation, union matching, and the discriminated union tabs component.
13
+ */
14
+ /**
15
+ * Coerce an unknown render result into a React node.
16
+ * Returns `null` for unrecognised values.
17
+ */
18
+ function toReactNode(value) {
19
+ if (value === null || value === void 0) return null;
20
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
21
+ if (isValidElement(value)) return value;
22
+ return null;
23
+ }
24
+ function formatDateTime(value) {
25
+ if (typeof value !== "string" || value.length === 0) return void 0;
26
+ try {
27
+ const date = new Date(value);
28
+ if (isNaN(date.getTime())) return void 0;
29
+ return date.toLocaleString();
30
+ } catch {
31
+ return;
32
+ }
33
+ }
34
+ function formatDate(value) {
35
+ if (typeof value !== "string" || value.length === 0) return void 0;
36
+ try {
37
+ const date = new Date(value);
38
+ if (isNaN(date.getTime())) return void 0;
39
+ return date.toLocaleDateString();
40
+ } catch {
41
+ return;
42
+ }
43
+ }
44
+ function formatTime(value) {
45
+ if (typeof value !== "string" || value.length === 0) return void 0;
46
+ try {
47
+ const date = new Date(value);
48
+ if (isNaN(date.getTime())) return void 0;
49
+ return date.toLocaleTimeString();
50
+ } catch {
51
+ return;
52
+ }
53
+ }
54
+ function dateInputType(format) {
55
+ if (format === "date") return "date";
56
+ if (format === "time") return "time";
57
+ if (format === "date-time" || format === "datetime") return "datetime-local";
58
+ }
59
+ /**
60
+ * Build a stable, unique-ish input ID from the path.
61
+ * Used for `htmlFor`/`id` association between labels and inputs.
62
+ */
63
+ function inputId(path) {
64
+ if (path.length === 0) return "sc-field";
65
+ return `sc-${path}`;
66
+ }
67
+ function renderString(props) {
68
+ const id = inputId(props.path);
69
+ if (props.readOnly) {
70
+ const strValue = typeof props.value === "string" ? props.value : void 0;
71
+ if (strValue === void 0 || strValue.length === 0) return /* @__PURE__ */ jsx("span", {
72
+ id,
73
+ "aria-readonly": "true",
74
+ children: "\\u2014"
75
+ });
76
+ const format = props.constraints.format;
77
+ if (format === "email") return /* @__PURE__ */ jsx("a", {
78
+ href: `mailto:${strValue}`,
79
+ id,
80
+ "aria-readonly": "true",
81
+ children: strValue
82
+ });
83
+ if (format === "uri" || format === "url") return /* @__PURE__ */ jsx("a", {
84
+ href: strValue,
85
+ id,
86
+ "aria-readonly": "true",
87
+ children: strValue
88
+ });
89
+ if (format === "date") return /* @__PURE__ */ jsx("span", {
90
+ id,
91
+ "aria-readonly": "true",
92
+ children: formatDate(strValue) ?? strValue
93
+ });
94
+ if (format === "time") return /* @__PURE__ */ jsx("span", {
95
+ id,
96
+ "aria-readonly": "true",
97
+ children: formatTime(strValue) ?? strValue
98
+ });
99
+ if (format === "date-time" || format === "datetime") return /* @__PURE__ */ jsx("span", {
100
+ id,
101
+ "aria-readonly": "true",
102
+ children: formatDateTime(strValue) ?? strValue
103
+ });
104
+ return /* @__PURE__ */ jsx("span", {
105
+ id,
106
+ "aria-readonly": "true",
107
+ children: strValue
108
+ });
109
+ }
110
+ const strValue = typeof props.value === "string" ? props.value : "";
111
+ const dateType = dateInputType(props.constraints.format);
112
+ const ariaAttrs = {};
113
+ if (props.tree.isOptional === false) ariaAttrs["aria-required"] = "true";
114
+ if (dateType !== void 0) return /* @__PURE__ */ jsx("input", {
115
+ id,
116
+ type: dateType,
117
+ value: props.writeOnly ? "" : strValue,
118
+ onChange: (e) => {
119
+ props.onChange(e.target.value);
120
+ },
121
+ ...ariaAttrs
122
+ });
123
+ if (props.enumValues !== void 0 && props.enumValues.length > 0) return /* @__PURE__ */ jsxs("select", {
124
+ id,
125
+ value: strValue,
126
+ onChange: (e) => {
127
+ props.onChange(e.target.value);
128
+ },
129
+ ...ariaAttrs,
130
+ children: [/* @__PURE__ */ jsx("option", {
131
+ value: "",
132
+ children: "Select\\u2026"
133
+ }), props.enumValues.map((v) => {
134
+ const display = v === null ? "null" : typeof v === "string" ? v : String(v);
135
+ return /* @__PURE__ */ jsx("option", {
136
+ value: display,
137
+ children: display
138
+ }, display);
139
+ })]
140
+ });
141
+ return /* @__PURE__ */ jsx("input", {
142
+ id,
143
+ type: props.constraints.format === "email" ? "email" : props.constraints.format === "uri" ? "url" : "text",
144
+ value: props.writeOnly ? "" : strValue,
145
+ onChange: (e) => {
146
+ props.onChange(e.target.value);
147
+ },
148
+ placeholder: typeof props.meta.description === "string" ? props.meta.description : void 0,
149
+ minLength: props.constraints.minLength,
150
+ maxLength: props.constraints.maxLength,
151
+ ...ariaAttrs
152
+ });
153
+ }
154
+ function renderNumber(props) {
155
+ const id = inputId(props.path);
156
+ if (props.readOnly) {
157
+ if (typeof props.value !== "number") return /* @__PURE__ */ jsx("span", {
158
+ id,
159
+ "aria-readonly": "true",
160
+ children: "\\u2014"
161
+ });
162
+ return /* @__PURE__ */ jsx("span", {
163
+ id,
164
+ "aria-readonly": "true",
165
+ children: props.value.toLocaleString()
166
+ });
167
+ }
168
+ const numValue = typeof props.value === "number" ? props.value : "";
169
+ const ariaAttrs = {};
170
+ if (props.tree.isOptional === false) ariaAttrs["aria-required"] = "true";
171
+ return /* @__PURE__ */ jsx("input", {
172
+ id,
173
+ type: "number",
174
+ value: props.writeOnly ? "" : numValue,
175
+ onChange: (e) => {
176
+ props.onChange(Number(e.target.value));
177
+ },
178
+ min: props.constraints.minimum,
179
+ max: props.constraints.maximum,
180
+ ...ariaAttrs
181
+ });
182
+ }
183
+ function renderBoolean(props) {
184
+ const id = inputId(props.path);
185
+ if (props.readOnly) {
186
+ if (typeof props.value !== "boolean") return /* @__PURE__ */ jsx("span", {
187
+ id,
188
+ "aria-readonly": "true",
189
+ children: "\\u2014"
190
+ });
191
+ return /* @__PURE__ */ jsx("span", {
192
+ id,
193
+ "aria-readonly": "true",
194
+ children: props.value ? "Yes" : "No"
195
+ });
196
+ }
197
+ const ariaAttrs = {};
198
+ if (props.tree.isOptional === false) ariaAttrs["aria-required"] = "true";
199
+ if (typeof props.meta.description === "string") ariaAttrs["aria-label"] = props.meta.description;
200
+ return /* @__PURE__ */ jsx("input", {
201
+ id,
202
+ type: "checkbox",
203
+ checked: props.writeOnly ? false : props.value === true,
204
+ onChange: (e) => {
205
+ props.onChange(e.target.checked);
206
+ },
207
+ ...ariaAttrs
208
+ });
209
+ }
210
+ function renderEnum(props) {
211
+ const id = inputId(props.path);
212
+ const enumValue = typeof props.value === "string" ? props.value : "";
213
+ if (props.readOnly) return /* @__PURE__ */ jsx("span", {
214
+ id,
215
+ "aria-readonly": "true",
216
+ children: enumValue || "—"
217
+ });
218
+ const ariaAttrs = {};
219
+ if (props.tree.isOptional === false) ariaAttrs["aria-required"] = "true";
220
+ return /* @__PURE__ */ jsxs("select", {
221
+ id,
222
+ value: props.writeOnly ? "" : enumValue,
223
+ onChange: (e) => {
224
+ props.onChange(e.target.value);
225
+ },
226
+ ...ariaAttrs,
227
+ children: [/* @__PURE__ */ jsx("option", {
228
+ value: "",
229
+ children: "Select\\u2026"
230
+ }), props.enumValues?.map((v) => {
231
+ const display = v === null ? "null" : typeof v === "string" ? v : String(v);
232
+ return /* @__PURE__ */ jsx("option", {
233
+ value: display,
234
+ children: display
235
+ }, display);
236
+ })]
237
+ });
238
+ }
239
+ function renderObject(props) {
240
+ const obj = isObject(props.value) ? props.value : {};
241
+ const fields = props.fields;
242
+ if (fields === void 0) return null;
243
+ const sortedEntries = Object.entries(fields).sort((a, b) => {
244
+ return (typeof a[1].meta.order === "number" ? a[1].meta.order : Infinity) - (typeof b[1].meta.order === "number" ? b[1].meta.order : Infinity);
245
+ });
246
+ return /* @__PURE__ */ jsxs("fieldset", { children: [typeof props.meta.description === "string" && /* @__PURE__ */ jsx("legend", { children: props.meta.description }), sortedEntries.filter(([, field]) => field.meta.visible !== false).map(([key, field]) => {
247
+ const childValue = obj[key];
248
+ const childId = inputId(props.path ? `${props.path}.${key}` : key);
249
+ const childOnChange = (v) => {
250
+ const updated = {};
251
+ for (const [k, val] of Object.entries(obj)) updated[k] = val;
252
+ updated[key] = v;
253
+ props.onChange(updated);
254
+ };
255
+ const child = toReactNode(props.renderChild(field, childValue, childOnChange));
256
+ if (child === null || child === void 0) return null;
257
+ return /* @__PURE__ */ jsxs("div", { children: [typeof field.meta.description === "string" && /* @__PURE__ */ jsxs("label", {
258
+ htmlFor: childId,
259
+ children: [field.meta.description, field.isOptional === false && /* @__PURE__ */ jsxs("span", {
260
+ "aria-hidden": "true",
261
+ style: { color: "#dc2626" },
262
+ children: [" ", "*"]
263
+ })]
264
+ }), child] }, key);
265
+ })] });
266
+ }
267
+ function renderRecord(props) {
268
+ const obj = isObject(props.value) ? props.value : {};
269
+ const valueType = props.valueType;
270
+ if (valueType === void 0) return null;
271
+ const entries = Object.entries(obj);
272
+ if (entries.length === 0) return /* @__PURE__ */ jsx("span", {
273
+ "aria-readonly": props.readOnly ? "true" : void 0,
274
+ children: "—"
275
+ });
276
+ return /* @__PURE__ */ jsx("div", {
277
+ role: "group",
278
+ "aria-label": props.meta.description ?? "Record",
279
+ children: entries.map(([key, value]) => {
280
+ const childId = inputId(props.path ? `${props.path}.${key}` : key);
281
+ const childOnChange = (nextValue) => {
282
+ const updated = {};
283
+ for (const [k, val] of Object.entries(obj)) updated[k] = val;
284
+ updated[key] = nextValue;
285
+ props.onChange(updated);
286
+ };
287
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("label", {
288
+ htmlFor: childId,
289
+ children: key
290
+ }), toReactNode(props.renderChild(valueType, value, childOnChange))] }, key);
291
+ })
292
+ });
293
+ }
294
+ function renderArray(props) {
295
+ const arr = Array.isArray(props.value) ? props.value : [];
296
+ const element = props.element;
297
+ if (element === void 0) return null;
298
+ if (arr.length === 0) return null;
299
+ return /* @__PURE__ */ jsx("div", {
300
+ role: "group",
301
+ "aria-label": props.meta.description ?? void 0,
302
+ children: arr.map((item, i) => {
303
+ const childOnChange = (v) => {
304
+ const next = arr.slice();
305
+ next[i] = v;
306
+ props.onChange(next);
307
+ };
308
+ return /* @__PURE__ */ jsx("div", { children: toReactNode(props.renderChild(element, item, childOnChange)) }, String(i));
309
+ })
310
+ });
311
+ }
312
+ function renderUnion(props) {
313
+ const options = props.options;
314
+ if (options === void 0 || options.length === 0) {
315
+ if (props.value === void 0 || props.value === null) return /* @__PURE__ */ jsx("span", { children: "\\u2014" });
316
+ return /* @__PURE__ */ jsx("span", { children: JSON.stringify(props.value) });
317
+ }
318
+ const matched = matchUnionOption(options, props.value);
319
+ if (matched !== void 0) return toReactNode(props.renderChild(matched, props.value, props.onChange));
320
+ const firstOption = options[0];
321
+ if (firstOption !== void 0) return toReactNode(props.renderChild(firstOption, props.value, props.onChange));
322
+ return /* @__PURE__ */ jsx("span", { children: "\\u2014" });
323
+ }
324
+ function renderDiscriminatedUnion(props) {
325
+ const options = props.options;
326
+ const discriminator = props.discriminator;
327
+ if (options === void 0 || options.length === 0) {
328
+ if (props.value === void 0 || props.value === null) return /* @__PURE__ */ jsx("span", { children: "\\u2014" });
329
+ return /* @__PURE__ */ jsx("span", { children: JSON.stringify(props.value) });
330
+ }
331
+ const obj = isObject(props.value) ? props.value : {};
332
+ const discKey = discriminator ?? "";
333
+ const currentDiscriminatorValue = typeof obj[discKey] === "string" ? obj[discKey] : void 0;
334
+ const optionLabels = options.map((opt) => {
335
+ if (opt.type === "object") {
336
+ const discriminatorField = opt.fields[discKey];
337
+ if (discriminatorField?.type === "literal") {
338
+ const constVal = discriminatorField.literalValues[0];
339
+ if (typeof constVal === "string") return constVal;
340
+ }
341
+ }
342
+ return typeof opt.meta.title === "string" ? opt.meta.title : opt.type;
343
+ });
344
+ let activeIndex = 0;
345
+ if (currentDiscriminatorValue !== void 0) {
346
+ const found = optionLabels.indexOf(currentDiscriminatorValue);
347
+ if (found !== -1) activeIndex = found;
348
+ }
349
+ const activeOption = options[activeIndex];
350
+ const panelId = inputId(props.path);
351
+ if (props.readOnly) {
352
+ if (activeOption !== void 0) return toReactNode(props.renderChild(activeOption, props.value, props.onChange));
353
+ return /* @__PURE__ */ jsx("span", { children: "\\u2014" });
354
+ }
355
+ return /* @__PURE__ */ jsx(DiscriminatedUnionTabs, {
356
+ options,
357
+ optionLabels,
358
+ activeIndex,
359
+ panelId,
360
+ discKey,
361
+ props
362
+ });
363
+ }
364
+ /**
365
+ * WAI-ARIA tabs component for discriminated unions.
366
+ * Implements the full tabs keyboard pattern:
367
+ * - Left/Right arrow keys move between tabs
368
+ * - Home/End move to first/last tab
369
+ * - Tab moves focus into the active panel
370
+ * - aria-selected, aria-controls, role="tablist"/"tab"/"tabpanel"
371
+ */
372
+ function DiscriminatedUnionTabs({ options, optionLabels, activeIndex, panelId, discKey, props }) {
373
+ const tabRefs = useRef([]);
374
+ const handleTabChange = useCallback((newIndex) => {
375
+ const label = optionLabels[newIndex];
376
+ if (label === void 0) return;
377
+ props.onChange({ [discKey]: label });
378
+ }, [
379
+ optionLabels,
380
+ discKey,
381
+ props
382
+ ]);
383
+ const focusTab = useCallback((index) => {
384
+ const clamped = (index % options.length + options.length) % options.length;
385
+ tabRefs.current[clamped]?.focus();
386
+ }, [options.length]);
387
+ const handleKeyDown = useCallback((e) => {
388
+ if (e.key === "ArrowRight") {
389
+ e.preventDefault();
390
+ focusTab(activeIndex + 1);
391
+ } else if (e.key === "ArrowLeft") {
392
+ e.preventDefault();
393
+ focusTab(activeIndex - 1);
394
+ } else if (e.key === "Home") {
395
+ e.preventDefault();
396
+ focusTab(0);
397
+ } else if (e.key === "End") {
398
+ e.preventDefault();
399
+ focusTab(options.length - 1);
400
+ }
401
+ }, [
402
+ activeIndex,
403
+ focusTab,
404
+ options.length
405
+ ]);
406
+ const activeOption = options[activeIndex];
407
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
408
+ role: "tablist",
409
+ "aria-label": "Select variant",
410
+ style: {
411
+ display: "flex",
412
+ gap: "0.25rem",
413
+ marginBottom: "0.5rem"
414
+ },
415
+ onKeyDown: handleKeyDown,
416
+ children: options.map((_opt, i) => /* @__PURE__ */ jsx("button", {
417
+ ref: (el) => {
418
+ tabRefs.current[i] = el;
419
+ },
420
+ type: "button",
421
+ role: "tab",
422
+ "aria-selected": i === activeIndex ? "true" : void 0,
423
+ "aria-controls": `${panelId}-panel`,
424
+ tabIndex: i === activeIndex ? 0 : -1,
425
+ onClick: () => {
426
+ handleTabChange(i);
427
+ },
428
+ style: {
429
+ padding: "0.25rem 0.75rem",
430
+ border: i === activeIndex ? "1px solid #3b82f6" : "1px solid #d1d5db",
431
+ borderRadius: "0.25rem",
432
+ background: i === activeIndex ? "#eff6ff" : "transparent",
433
+ cursor: "pointer",
434
+ fontSize: "0.875rem"
435
+ },
436
+ children: optionLabels[i]
437
+ }, String(i)))
438
+ }), /* @__PURE__ */ jsx("div", {
439
+ role: "tabpanel",
440
+ id: `${panelId}-panel`,
441
+ "aria-labelledby": `${panelId}-tab-${String(activeIndex)}`,
442
+ children: activeOption !== void 0 && toReactNode(props.renderChild(activeOption, props.value, props.onChange))
443
+ })] });
444
+ }
445
+ function renderFile(props) {
446
+ const id = inputId(props.path);
447
+ const accept = props.constraints.mimeTypes?.join(",");
448
+ if (props.readOnly) return /* @__PURE__ */ jsx("span", {
449
+ id,
450
+ "aria-readonly": "true",
451
+ children: "File field"
452
+ });
453
+ const ariaAttrs = {};
454
+ if (props.tree.isOptional === false) ariaAttrs["aria-required"] = "true";
455
+ if (typeof props.meta.description === "string") ariaAttrs["aria-label"] = props.meta.description;
456
+ return /* @__PURE__ */ jsx("input", {
457
+ id,
458
+ type: "file",
459
+ accept,
460
+ onChange: (e) => {
461
+ const file = e.target.files?.[0];
462
+ if (file !== void 0) props.onChange(file);
463
+ },
464
+ ...ariaAttrs
465
+ });
466
+ }
467
+ function renderRecursive(props) {
468
+ const refTarget = props.refTarget ?? "";
469
+ return /* @__PURE__ */ jsx("fieldset", { children: /* @__PURE__ */ jsxs("em", { children: [
470
+ "↻ ",
471
+ typeof props.meta.description === "string" ? props.meta.description : refTarget,
472
+ " (recursive)"
473
+ ] }) });
474
+ }
475
+ function renderUnknown(props) {
476
+ const id = inputId(props.path);
477
+ if (props.readOnly) {
478
+ if (props.value === void 0 || props.value === null) return /* @__PURE__ */ jsx("span", {
479
+ id,
480
+ "aria-readonly": "true",
481
+ children: "\\u2014"
482
+ });
483
+ return /* @__PURE__ */ jsx("span", {
484
+ id,
485
+ "aria-readonly": "true",
486
+ children: typeof props.value === "string" ? props.value : JSON.stringify(props.value)
487
+ });
488
+ }
489
+ const strValue = typeof props.value === "string" ? props.value : "";
490
+ return /* @__PURE__ */ jsx("input", {
491
+ id,
492
+ type: "text",
493
+ value: props.writeOnly ? "" : strValue,
494
+ onChange: (e) => {
495
+ props.onChange(e.target.value);
496
+ }
497
+ });
498
+ }
499
+ function matchUnionOption(options, value) {
500
+ if (typeof value === "string") return options.find((o) => o.type === "string" || o.type === "enum");
501
+ if (typeof value === "number") return options.find((o) => o.type === "number");
502
+ if (typeof value === "boolean") return options.find((o) => o.type === "boolean");
503
+ if (Array.isArray(value)) return options.find((o) => o.type === "array");
504
+ if (typeof value === "object" && value !== null) return options.find((o) => o.type === "object");
505
+ }
506
+ //#endregion
507
+ export { renderArray, renderBoolean, renderDiscriminatedUnion, renderEnum, renderFile, renderNumber, renderObject, renderRecord, renderRecursive, renderString, renderUnion, renderUnknown, toReactNode };
@@ -0,0 +1,44 @@
1
+ import { i as DiagnosticsOptions } from "./diagnostics-DzbZmcLI.mjs";
2
+
3
+ //#region src/core/ref.d.ts
4
+ /**
5
+ * Resolver function for external $ref URIs.
6
+ * Called with the URI portion (everything before `#`) of an external ref.
7
+ * Returns the parsed document (JSON object) or undefined.
8
+ */
9
+ type ExternalResolver = (uri: string) => unknown;
10
+ /**
11
+ * Options for $ref resolution.
12
+ */
13
+ interface RefOptions {
14
+ diagnostics?: DiagnosticsOptions;
15
+ externalResolver?: ExternalResolver;
16
+ }
17
+ /**
18
+ * Count all distinct `$ref` strings reachable from a root document.
19
+ * A chain longer than the number of distinct refs is necessarily cyclic.
20
+ * Returns at least 1 so that single-ref schemas have a usable bound.
21
+ */
22
+ declare function countDistinctRefs(root: Record<string, unknown>): number;
23
+ /**
24
+ * Resolve a `$ref` in a schema against a root document.
25
+ * Returns the original schema if no `$ref` is present.
26
+ * Returns an unknown-schema placeholder on cycle or depth exceeded.
27
+ *
28
+ * The depth bound is derived from the number of distinct `$ref` strings
29
+ * in the root document — a chain longer than that count is necessarily
30
+ * cyclic. When `maxDepth` is not provided, a reasonable default is used.
31
+ */
32
+ declare function resolveRef(schema: Record<string, unknown>, rootDocument: Record<string, unknown>, visited: Set<string>, diagnostics?: DiagnosticsOptions, maxDepth?: number, externalResolver?: ExternalResolver): Record<string, unknown>;
33
+ /**
34
+ * Dereference a JSON Pointer fragment (`#/path/to/schema`) or an
35
+ * `$anchor` (`#SomeName`) against a root document.
36
+ */
37
+ declare function dereference(ref: string, root: Record<string, unknown>): Record<string, unknown> | undefined;
38
+ /**
39
+ * Recursively scan a schema document for a `$anchor` matching the given name.
40
+ * Returns the schema object containing the anchor, or undefined.
41
+ */
42
+ declare function findAnchor(node: unknown, anchorName: string): Record<string, unknown> | undefined;
43
+ //#endregion
44
+ export { findAnchor as a, dereference as i, RefOptions as n, resolveRef as o, countDistinctRefs as r, ExternalResolver as t };