schema-components 1.18.0 → 1.19.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 (61) hide show
  1. package/dist/core/adapter.d.mts +1 -1
  2. package/dist/core/adapter.mjs +77 -14
  3. package/dist/core/constraints.d.mts +1 -1
  4. package/dist/core/diagnostics.d.mts +1 -1
  5. package/dist/core/errors.d.mts +1 -1
  6. package/dist/core/errors.mjs +7 -1
  7. package/dist/core/fieldOrder.d.mts +10 -0
  8. package/dist/core/fieldOrder.mjs +12 -0
  9. package/dist/core/formats.mjs +9 -1
  10. package/dist/core/merge.d.mts +1 -1
  11. package/dist/core/merge.mjs +30 -2
  12. package/dist/core/normalise.d.mts +38 -5
  13. package/dist/core/normalise.mjs +2 -2
  14. package/dist/core/openapi30.d.mts +33 -4
  15. package/dist/core/openapi30.mjs +2 -2
  16. package/dist/core/ref.d.mts +1 -1
  17. package/dist/core/renderer.d.mts +1 -1
  18. package/dist/core/renderer.mjs +7 -21
  19. package/dist/core/swagger2.d.mts +1 -1
  20. package/dist/core/swagger2.mjs +1 -1
  21. package/dist/core/version.d.mts +2 -2
  22. package/dist/core/version.mjs +19 -9
  23. package/dist/core/walkBuilders.d.mts +2 -2
  24. package/dist/{diagnostics-BYk63jsC.d.mts → diagnostics-VgEKI_Ct.d.mts} +1 -1
  25. package/dist/{errors-C5zRC2PU.d.mts → errors-CnGjT1cg.d.mts} +7 -2
  26. package/dist/html/a11y.d.mts +1 -1
  27. package/dist/html/renderToHtml.d.mts +1 -1
  28. package/dist/html/renderToHtml.mjs +13 -30
  29. package/dist/html/renderToHtmlStream.d.mts +1 -1
  30. package/dist/html/renderers.d.mts +1 -1
  31. package/dist/html/renderers.mjs +56 -23
  32. package/dist/html/streamRenderers.d.mts +1 -1
  33. package/dist/html/streamRenderers.mjs +10 -21
  34. package/dist/{normalise-tL9FckAk.mjs → normalise-C0ofw3W6.mjs} +418 -97
  35. package/dist/openapi/ApiSecurity.mjs +1 -1
  36. package/dist/openapi/bundle.mjs +1 -0
  37. package/dist/openapi/components.mjs +6 -2
  38. package/dist/openapi/parser.d.mts +2 -2
  39. package/dist/openapi/parser.mjs +8 -5
  40. package/dist/openapi/resolve.d.mts +6 -5
  41. package/dist/openapi/resolve.mjs +7 -6
  42. package/dist/react/SchemaComponent.d.mts +4 -4
  43. package/dist/react/SchemaComponent.mjs +4 -14
  44. package/dist/react/SchemaView.d.mts +2 -2
  45. package/dist/react/SchemaView.mjs +2 -1
  46. package/dist/react/headless.d.mts +7 -1
  47. package/dist/react/headless.mjs +13 -1
  48. package/dist/react/headlessRenderers.d.mts +53 -2
  49. package/dist/react/headlessRenderers.mjs +175 -33
  50. package/dist/{ref-Ckt5liZs.d.mts → ref-Bb43ZURY.d.mts} +1 -1
  51. package/dist/{renderer-DXo-rXHJ.d.mts → renderer-BQqiXUYP.d.mts} +15 -32
  52. package/dist/themes/mantine.d.mts +1 -1
  53. package/dist/themes/mantine.mjs +2 -1
  54. package/dist/themes/mui.d.mts +1 -1
  55. package/dist/themes/mui.mjs +3 -2
  56. package/dist/themes/radix.d.mts +1 -1
  57. package/dist/themes/radix.mjs +2 -1
  58. package/dist/themes/shadcn.d.mts +1 -1
  59. package/dist/themes/shadcn.mjs +2 -1
  60. package/dist/{version-B5NV-35j.d.mts → version-XNH7PRGP.d.mts} +8 -1
  61. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import { isObject } from "../core/guards.mjs";
2
- import { isValidElement, useCallback, useEffect, useRef } from "react";
2
+ import { sortFieldsByOrder } from "../core/fieldOrder.mjs";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { isValidElement, useCallback, useEffect, useRef } from "react";
4
5
  //#region src/react/headlessRenderers.tsx
5
6
  /**
6
7
  * Headless renderer functions — one per schema type.
@@ -128,24 +129,27 @@ function renderString(props) {
128
129
  },
129
130
  ...ariaAttrs
130
131
  });
131
- if (props.enumValues !== void 0 && props.enumValues.length > 0) return /* @__PURE__ */ jsxs("select", {
132
- id,
133
- value: strValue,
134
- onChange: (e) => {
135
- props.onChange(e.target.value);
136
- },
137
- ...ariaAttrs,
138
- children: [/* @__PURE__ */ jsxs("option", {
139
- value: "",
140
- children: ["Select", "…"]
141
- }), props.enumValues.map((v) => {
142
- const display = v === null ? "null" : typeof v === "string" ? v : String(v);
143
- return /* @__PURE__ */ jsx("option", {
144
- value: display,
145
- children: display
146
- }, display);
147
- })]
148
- });
132
+ if (props.tree.type === "enum" && props.tree.enumValues.length > 0) {
133
+ const enumValues = props.tree.enumValues;
134
+ return /* @__PURE__ */ jsxs("select", {
135
+ id,
136
+ value: strValue,
137
+ onChange: (e) => {
138
+ props.onChange(e.target.value);
139
+ },
140
+ ...ariaAttrs,
141
+ children: [/* @__PURE__ */ jsxs("option", {
142
+ value: "",
143
+ children: ["Select", ""]
144
+ }), enumValues.map((v) => {
145
+ const display = v === null ? "null" : typeof v === "string" ? v : String(v);
146
+ return /* @__PURE__ */ jsx("option", {
147
+ value: display,
148
+ children: display
149
+ }, display);
150
+ })]
151
+ });
152
+ }
149
153
  return /* @__PURE__ */ jsx("input", {
150
154
  id,
151
155
  type: props.constraints.format === "email" ? "email" : props.constraints.format === "uri" ? "url" : "text",
@@ -225,6 +229,7 @@ function renderEnum(props) {
225
229
  });
226
230
  const ariaAttrs = {};
227
231
  if (props.tree.isOptional === false) ariaAttrs["aria-required"] = "true";
232
+ const enumValues = props.tree.type === "enum" ? props.tree.enumValues : [];
228
233
  return /* @__PURE__ */ jsxs("select", {
229
234
  id,
230
235
  value: props.writeOnly ? "" : enumValue,
@@ -235,7 +240,7 @@ function renderEnum(props) {
235
240
  children: [/* @__PURE__ */ jsxs("option", {
236
241
  value: "",
237
242
  children: ["Select", "…"]
238
- }), props.enumValues?.map((v) => {
243
+ }), enumValues.map((v) => {
239
244
  const display = v === null ? "null" : typeof v === "string" ? v : String(v);
240
245
  return /* @__PURE__ */ jsx("option", {
241
246
  value: display,
@@ -245,12 +250,10 @@ function renderEnum(props) {
245
250
  });
246
251
  }
247
252
  function renderObject(props) {
253
+ if (props.tree.type !== "object") return null;
248
254
  const obj = isObject(props.value) ? props.value : {};
249
- const fields = props.fields;
250
- if (fields === void 0) return null;
251
- const sortedEntries = Object.entries(fields).sort((a, b) => {
252
- return (typeof a[1].meta.order === "number" ? a[1].meta.order : Infinity) - (typeof b[1].meta.order === "number" ? b[1].meta.order : Infinity);
253
- });
255
+ const fields = props.tree.fields;
256
+ const sortedEntries = sortFieldsByOrder(fields);
254
257
  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]) => {
255
258
  const childValue = obj[key];
256
259
  const childId = inputId(`${props.path}.${key}`);
@@ -312,9 +315,9 @@ function renameRecordKey(obj, oldKey, newKey) {
312
315
  return renamed;
313
316
  }
314
317
  function renderRecord(props) {
318
+ if (props.tree.type !== "record") return null;
315
319
  const obj = isObject(props.value) ? props.value : {};
316
- const valueType = props.valueType;
317
- if (valueType === void 0) return null;
320
+ const valueType = props.tree.valueType;
318
321
  const entries = Object.entries(obj);
319
322
  if (props.readOnly) {
320
323
  if (entries.length === 0) return /* @__PURE__ */ jsx("span", {
@@ -392,8 +395,9 @@ function renderRecord(props) {
392
395
  });
393
396
  }
394
397
  function renderArray(props) {
398
+ if (props.tree.type !== "array") return null;
395
399
  const arr = Array.isArray(props.value) ? props.value : [];
396
- const element = props.element;
400
+ const element = props.tree.element;
397
401
  if (element === void 0) return null;
398
402
  if (arr.length === 0) return null;
399
403
  return /* @__PURE__ */ jsx("div", {
@@ -410,7 +414,7 @@ function renderArray(props) {
410
414
  });
411
415
  }
412
416
  function renderUnion(props) {
413
- const options = props.options;
417
+ const options = props.tree.type === "union" || props.tree.type === "discriminatedUnion" ? props.tree.options : void 0;
414
418
  if (options === void 0 || options.length === 0) {
415
419
  if (props.value === void 0 || props.value === null) return /* @__PURE__ */ jsx("span", { children: "—" });
416
420
  return /* @__PURE__ */ jsx("span", { children: JSON.stringify(props.value) });
@@ -422,8 +426,8 @@ function renderUnion(props) {
422
426
  return /* @__PURE__ */ jsx("span", { children: "—" });
423
427
  }
424
428
  function renderDiscriminatedUnion(props) {
425
- const options = props.options;
426
- const discriminator = props.discriminator;
429
+ const options = props.tree.type === "discriminatedUnion" ? props.tree.options : void 0;
430
+ const discriminator = props.tree.type === "discriminatedUnion" ? props.tree.discriminator : void 0;
427
431
  if (options === void 0 || options.length === 0) {
428
432
  if (props.value === void 0 || props.value === null) return /* @__PURE__ */ jsx("span", { children: "—" });
429
433
  return /* @__PURE__ */ jsx("span", { children: JSON.stringify(props.value) });
@@ -584,13 +588,151 @@ function renderFile(props) {
584
588
  });
585
589
  }
586
590
  function renderRecursive(props) {
587
- const refTarget = props.refTarget ?? "";
591
+ const refTarget = props.tree.type === "recursive" ? props.tree.refTarget : "";
588
592
  return /* @__PURE__ */ jsx("fieldset", { children: /* @__PURE__ */ jsxs("em", { children: [
589
593
  "↻ ",
590
594
  typeof props.meta.description === "string" ? props.meta.description : refTarget,
591
595
  " (recursive)"
592
596
  ] }) });
593
597
  }
598
+ /**
599
+ * Render a literal field — `z.literal("a")` or `{ const: 5 }`.
600
+ *
601
+ * Literals are non-editable by nature (the value is fixed at the schema
602
+ * level), so both read-only and editable modes display the literal value(s).
603
+ * Multiple literals (`z.literal(["a", "b"])`) render comma-separated.
604
+ */
605
+ function renderLiteral(props) {
606
+ const id = inputId(props.path);
607
+ if (props.tree.type !== "literal") return null;
608
+ const values = props.tree.literalValues;
609
+ if (values.length === 0) return /* @__PURE__ */ jsx("span", {
610
+ id,
611
+ "aria-readonly": "true",
612
+ children: "—"
613
+ });
614
+ return /* @__PURE__ */ jsx("span", {
615
+ id,
616
+ "aria-readonly": "true",
617
+ children: values.map((v) => v === null ? "null" : String(v)).join(", ")
618
+ });
619
+ }
620
+ /**
621
+ * Render a null field — `z.null()` or `{ type: "null" }`.
622
+ *
623
+ * The only valid value is `null`, so render an em-dash placeholder
624
+ * regardless of mode. There is nothing the user can usefully change.
625
+ */
626
+ function renderNull(props) {
627
+ return /* @__PURE__ */ jsx("span", {
628
+ id: inputId(props.path),
629
+ "aria-readonly": "true",
630
+ children: "—"
631
+ });
632
+ }
633
+ /**
634
+ * Render a never field — `z.never()` or `{ not: {} }` / `false` schema.
635
+ *
636
+ * `never` indicates a position that cannot hold any value. We render a
637
+ * visible placeholder rather than throwing because some valid schemas
638
+ * intentionally contain `never` branches (e.g. exhaustive discriminated
639
+ * unions), and a runtime crash on render would be worse than a visible
640
+ * indicator.
641
+ */
642
+ function renderNever(props) {
643
+ return /* @__PURE__ */ jsx("span", {
644
+ id: inputId(props.path),
645
+ "aria-readonly": "true",
646
+ className: "sc-never",
647
+ children: /* @__PURE__ */ jsx("em", { children: "never matches" })
648
+ });
649
+ }
650
+ /**
651
+ * Render a tuple field — `z.tuple([z.string(), z.number()])` or
652
+ * `{ prefixItems: [...] }`.
653
+ *
654
+ * Positional rendering: each `prefixItems` entry is rendered at its index.
655
+ * The structural index (e.g. `[0]`) is passed as the path suffix so
656
+ * children get unique ids and labels.
657
+ */
658
+ function renderTuple(props) {
659
+ if (props.tree.type !== "tuple") return null;
660
+ const prefixItems = props.tree.prefixItems;
661
+ if (prefixItems.length === 0) return null;
662
+ const arr = Array.isArray(props.value) ? props.value : [];
663
+ return /* @__PURE__ */ jsx("div", {
664
+ role: "group",
665
+ "aria-label": props.meta.description ?? void 0,
666
+ children: prefixItems.map((element, i) => {
667
+ const itemValue = arr[i];
668
+ const childOnChange = (v) => {
669
+ const next = arr.slice();
670
+ next[i] = v;
671
+ props.onChange(next);
672
+ };
673
+ return /* @__PURE__ */ jsx("div", { children: toReactNode(props.renderChild(element, itemValue, childOnChange, `[${String(i)}]`)) }, String(i));
674
+ })
675
+ });
676
+ }
677
+ /**
678
+ * Render a conditional field — JSON Schema `if`/`then`/`else`.
679
+ *
680
+ * Conditional schemas describe constraints rather than a single value
681
+ * shape, so the renderer surfaces each clause as a labelled fieldset.
682
+ * This mirrors the HTML renderer's annotation approach and gives a
683
+ * predictable structure for theme adapters that want to override it.
684
+ */
685
+ function renderConditional(props) {
686
+ if (props.tree.type !== "conditional") return null;
687
+ const { ifClause, thenClause, elseClause } = props.tree;
688
+ return /* @__PURE__ */ jsxs("fieldset", {
689
+ className: "sc-conditional",
690
+ children: [
691
+ /* @__PURE__ */ jsxs("div", {
692
+ className: "sc-conditional-if",
693
+ children: [
694
+ /* @__PURE__ */ jsx("strong", { children: "if:" }),
695
+ " ",
696
+ toReactNode(props.renderChild(ifClause, props.value, props.onChange))
697
+ ]
698
+ }),
699
+ thenClause !== void 0 && /* @__PURE__ */ jsxs("div", {
700
+ className: "sc-conditional-then",
701
+ children: [
702
+ /* @__PURE__ */ jsx("strong", { children: "then:" }),
703
+ " ",
704
+ toReactNode(props.renderChild(thenClause, props.value, props.onChange))
705
+ ]
706
+ }),
707
+ elseClause !== void 0 && /* @__PURE__ */ jsxs("div", {
708
+ className: "sc-conditional-else",
709
+ children: [
710
+ /* @__PURE__ */ jsx("strong", { children: "else:" }),
711
+ " ",
712
+ toReactNode(props.renderChild(elseClause, props.value, props.onChange))
713
+ ]
714
+ })
715
+ ]
716
+ });
717
+ }
718
+ /**
719
+ * Render a negation field — JSON Schema `{ not: { ... } }`.
720
+ *
721
+ * Negation describes a constraint ("value must NOT match this schema")
722
+ * rather than a value shape. The renderer surfaces the negated schema
723
+ * beneath an explanatory preamble.
724
+ */
725
+ function renderNegation(props) {
726
+ if (props.tree.type !== "negation") return null;
727
+ return /* @__PURE__ */ jsxs("fieldset", {
728
+ className: "sc-negation",
729
+ children: [
730
+ /* @__PURE__ */ jsx("strong", { children: "Must NOT match:" }),
731
+ " ",
732
+ toReactNode(props.renderChild(props.tree.negated, props.value, props.onChange))
733
+ ]
734
+ });
735
+ }
594
736
  function renderUnknown(props) {
595
737
  const id = inputId(props.path);
596
738
  if (props.readOnly) {
@@ -623,4 +765,4 @@ function matchUnionOption(options, value) {
623
765
  if (typeof value === "object" && value !== null) return options.find((o) => o.type === "object");
624
766
  }
625
767
  //#endregion
626
- export { defaultRecordValue, discriminatedUnionValueForTab, inputId, nextRecordKey, renameRecordKey, renderArray, renderBoolean, renderDiscriminatedUnion, renderEnum, renderFile, renderNumber, renderObject, renderRecord, renderRecursive, renderString, renderUnion, renderUnknown, toReactNode };
768
+ export { defaultRecordValue, discriminatedUnionValueForTab, inputId, nextRecordKey, renameRecordKey, renderArray, renderBoolean, renderConditional, renderDiscriminatedUnion, renderEnum, renderFile, renderLiteral, renderNegation, renderNever, renderNull, renderNumber, renderObject, renderRecord, renderRecursive, renderString, renderTuple, renderUnion, renderUnknown, toReactNode };
@@ -1,4 +1,4 @@
1
- import { i as DiagnosticsOptions } from "./diagnostics-BYk63jsC.mjs";
1
+ import { i as DiagnosticsOptions } from "./diagnostics-VgEKI_Ct.mjs";
2
2
 
3
3
  //#region src/core/ref.d.ts
4
4
  /**
@@ -13,6 +13,13 @@ type AllConstraints = StringConstraints & NumberConstraints & ArrayConstraints &
13
13
  /**
14
14
  * Properties available on every schema field, regardless of rendering target.
15
15
  * Both React and HTML renderers receive these.
16
+ *
17
+ * Per-type schema data — enum values, object fields, array element schema,
18
+ * union options, record key/value types, tuple `prefixItems`, conditional
19
+ * if/then/else clauses, negation `negated`, recursive `refTarget`, literal
20
+ * values — lives on the discriminated `tree`. Renderers narrow on
21
+ * `tree.type` and read from the matching variant; there are no duplicate
22
+ * sibling fields on these props.
16
23
  */
17
24
  interface BaseFieldProps {
18
25
  /** Current field value. */
@@ -27,31 +34,6 @@ interface BaseFieldProps {
27
34
  constraints: AllConstraints;
28
35
  /** Dot-separated path from root (e.g. "address.city"). */
29
36
  path: string;
30
- /** For enums: the allowed values. */
31
- enumValues?: (string | number | boolean | null)[];
32
- /** For arrays: the element schema. */
33
- element?: WalkedField;
34
- /** For tuples: positional element schemas from prefixItems. */
35
- prefixItems?: WalkedField[];
36
- /** For conditionals: the if/then/else sub-schemas. */
37
- ifClause?: WalkedField;
38
- thenClause?: WalkedField;
39
- elseClause?: WalkedField;
40
- /** For negations: the negated sub-schema. */
41
- negated?: WalkedField;
42
- /** For recursive fields: the $ref string that would create the cycle. */
43
- refTarget?: string;
44
- /** For objects: map of field name → WalkedField. */
45
- fields?: Record<string, WalkedField>;
46
- /** For unions: the option schemas. */
47
- options?: WalkedField[];
48
- /** For discriminated unions: the discriminator key. */
49
- discriminator?: string;
50
- /** For records: key and value schemas. */
51
- keyType?: WalkedField;
52
- valueType?: WalkedField;
53
- /** For literals: the literal value(s). */
54
- literalValues?: (string | number | boolean | null)[];
55
37
  /** Example values from the schema's `examples` keyword. */
56
38
  examples?: unknown[];
57
39
  /** Walked field tree for recursive rendering. */
@@ -109,11 +91,6 @@ interface HtmlRenderProps extends BaseFieldProps {
109
91
  * a noop `onChange` is wired up, `readOnly` is forced to `true`, and
110
92
  * `writeOnly` is forced to `false`. Otherwise the editability is taken
111
93
  * from `tree.editability`.
112
- *
113
- * The duplicate sibling fields (`enumValues`, `element`, `fields`, etc.)
114
- * are populated for backwards compatibility with renderers that have not
115
- * yet migrated to reading from `tree` directly. New renderers should
116
- * narrow on `tree.type` and read from `tree`.
117
94
  */
118
95
  declare function buildRenderProps(tree: WalkedField, value: unknown, onChange: ((next: unknown) => void) | undefined, renderChild: RenderProps["renderChild"], path: string): RenderProps;
119
96
  type RenderFunction = (props: RenderProps) => unknown;
@@ -121,6 +98,7 @@ interface ComponentResolver {
121
98
  string?: RenderFunction;
122
99
  number?: RenderFunction;
123
100
  boolean?: RenderFunction;
101
+ null?: RenderFunction;
124
102
  enum?: RenderFunction;
125
103
  object?: RenderFunction;
126
104
  array?: RenderFunction;
@@ -133,6 +111,7 @@ interface ComponentResolver {
133
111
  recursive?: RenderFunction;
134
112
  literal?: RenderFunction;
135
113
  file?: RenderFunction;
114
+ never?: RenderFunction;
136
115
  unknown?: RenderFunction;
137
116
  }
138
117
  /** An HTML render function returns a string. */
@@ -145,6 +124,7 @@ interface HtmlResolver {
145
124
  string?: HtmlRenderFunction;
146
125
  number?: HtmlRenderFunction;
147
126
  boolean?: HtmlRenderFunction;
127
+ null?: HtmlRenderFunction;
148
128
  enum?: HtmlRenderFunction;
149
129
  object?: HtmlRenderFunction;
150
130
  array?: HtmlRenderFunction;
@@ -157,13 +137,16 @@ interface HtmlResolver {
157
137
  recursive?: HtmlRenderFunction;
158
138
  literal?: HtmlRenderFunction;
159
139
  file?: HtmlRenderFunction;
140
+ never?: HtmlRenderFunction;
160
141
  unknown?: HtmlRenderFunction;
161
142
  }
162
- declare const RESOLVER_KEYS: readonly ["string", "number", "boolean", "enum", "object", "array", "tuple", "record", "union", "discriminatedUnion", "conditional", "negation", "recursive", "literal", "file", "unknown"];
143
+ declare const RESOLVER_KEYS: readonly ["string", "number", "boolean", "null", "enum", "object", "array", "tuple", "record", "union", "discriminatedUnion", "conditional", "negation", "recursive", "literal", "file", "never", "unknown"];
163
144
  type ResolverKey = (typeof RESOLVER_KEYS)[number];
164
145
  /**
165
146
  * Map a schema type to the resolver key that handles it.
166
- * `discriminatedUnion` `union`. Unknown types `unknown`.
147
+ * Every WalkedField variant has a direct resolver key — exhaustive switch
148
+ * ensures new variants surface as a type error rather than silently
149
+ * falling through to "unknown".
167
150
  */
168
151
  declare function typeToKey(type: WalkedField["type"]): ResolverKey;
169
152
  /**
@@ -1,4 +1,4 @@
1
- import { r as ComponentResolver } from "../renderer-DXo-rXHJ.mjs";
1
+ import { r as ComponentResolver } from "../renderer-BQqiXUYP.mjs";
2
2
 
3
3
  //#region src/themes/mantine.d.ts
4
4
  /**
@@ -1,4 +1,5 @@
1
1
  import { isObject } from "../core/guards.mjs";
2
+ import { sortFieldsByOrder } from "../core/fieldOrder.mjs";
2
3
  import { inputId, toReactNode } from "../react/headlessRenderers.mjs";
3
4
  import { headlessResolver } from "../react/headless.mjs";
4
5
  import { jsx } from "react/jsx-runtime";
@@ -123,7 +124,7 @@ function renderObjectContainer(props) {
123
124
  const obj = isObject(props.value) ? props.value : {};
124
125
  return /* @__PURE__ */ jsx(MantineFieldset, {
125
126
  legend: getLabel(props),
126
- children: Object.entries(fields).filter(([, field]) => field.meta.visible !== false).map(([key, field]) => {
127
+ children: sortFieldsByOrder(fields).filter(([, field]) => field.meta.visible !== false).map(([key, field]) => {
127
128
  const childValue = obj[key];
128
129
  const childOnChange = (v) => {
129
130
  const updated = {};
@@ -1,4 +1,4 @@
1
- import { r as ComponentResolver } from "../renderer-DXo-rXHJ.mjs";
1
+ import { r as ComponentResolver } from "../renderer-BQqiXUYP.mjs";
2
2
 
3
3
  //#region src/themes/mui.d.ts
4
4
  /**
@@ -1,8 +1,9 @@
1
1
  import { isObject } from "../core/guards.mjs";
2
+ import { sortFieldsByOrder } from "../core/fieldOrder.mjs";
2
3
  import { inputId, toReactNode } from "../react/headlessRenderers.mjs";
3
4
  import { headlessResolver } from "../react/headless.mjs";
4
- import { isValidElement } from "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { isValidElement } from "react";
6
7
  //#region src/themes/mui.tsx
7
8
  function ariaRequired(tree) {
8
9
  return { required: tree.isOptional === false };
@@ -136,7 +137,7 @@ function renderObjectContainer(props) {
136
137
  children: [typeof props.meta.description === "string" && /* @__PURE__ */ jsx(MuiTypography, {
137
138
  variant: "h6",
138
139
  children: props.meta.description
139
- }), Object.entries(fields).map(([key, field]) => {
140
+ }), sortFieldsByOrder(fields).map(([key, field]) => {
140
141
  const childValue = obj[key];
141
142
  const childOnChange = (v) => {
142
143
  const updated = {};
@@ -1,4 +1,4 @@
1
- import { r as ComponentResolver } from "../renderer-DXo-rXHJ.mjs";
1
+ import { r as ComponentResolver } from "../renderer-BQqiXUYP.mjs";
2
2
 
3
3
  //#region src/themes/radix.d.ts
4
4
  /**
@@ -1,4 +1,5 @@
1
1
  import { isObject } from "../core/guards.mjs";
2
+ import { sortFieldsByOrder } from "../core/fieldOrder.mjs";
2
3
  import { inputId, toReactNode } from "../react/headlessRenderers.mjs";
3
4
  import { headlessResolver } from "../react/headless.mjs";
4
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -161,7 +162,7 @@ function renderObjectContainer(props) {
161
162
  }), /* @__PURE__ */ jsx(RadixFlex, {
162
163
  direction: "column",
163
164
  gap: "3",
164
- children: Object.entries(fields).filter(([, field]) => field.meta.visible !== false).map(([key, field]) => {
165
+ children: sortFieldsByOrder(fields).filter(([, field]) => field.meta.visible !== false).map(([key, field]) => {
165
166
  const childValue = obj[key];
166
167
  const childOnChange = (v) => {
167
168
  const updated = {};
@@ -1,4 +1,4 @@
1
- import { r as ComponentResolver } from "../renderer-DXo-rXHJ.mjs";
1
+ import { r as ComponentResolver } from "../renderer-BQqiXUYP.mjs";
2
2
 
3
3
  //#region src/themes/shadcn.d.ts
4
4
  declare const shadcnResolver: ComponentResolver;
@@ -1,4 +1,5 @@
1
1
  import { toRecord } from "../core/guards.mjs";
2
+ import { sortFieldsByOrder } from "../core/fieldOrder.mjs";
2
3
  import { inputId, toReactNode } from "../react/headlessRenderers.mjs";
3
4
  import { headlessResolver } from "../react/headless.mjs";
4
5
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -102,7 +103,7 @@ function renderObjectContainer(props) {
102
103
  children: [typeof props.meta.description === "string" && /* @__PURE__ */ jsx("h3", {
103
104
  className: "text-lg font-medium",
104
105
  children: props.meta.description
105
- }), Object.entries(fields).map(([key, field]) => {
106
+ }), sortFieldsByOrder(fields).map(([key, field]) => {
106
107
  const childValue = toRecord(obj)[key];
107
108
  const childId = inputId(`${props.path}.${key}`);
108
109
  const childOnChange = (v) => {
@@ -7,6 +7,13 @@
7
7
  * before the walker processes the schema.
8
8
  */
9
9
  type JsonSchemaDraft = "draft-04" | "draft-06" | "draft-07" | "draft-2019-09" | "draft-2020-12";
10
+ /**
11
+ * Match a `$schema` URI string to a known draft. Returns `undefined`
12
+ * when the URI matches none of the documented Draft 04 – Draft 2020-12
13
+ * schema URIs (including the known prefix patterns) — callers can use
14
+ * this to distinguish an authoritative match from a silent fallback.
15
+ */
16
+ declare function matchJsonSchemaDraftUri(uri: string): JsonSchemaDraft | undefined;
10
17
  /**
11
18
  * Detect the JSON Schema draft version from a schema's `$schema` URI.
12
19
  * When `$schema` is absent, uses heuristic keyword detection via
@@ -66,4 +73,4 @@ declare function isOpenApi31(version: OpenApiVersionInfo): boolean;
66
73
  */
67
74
  declare function isSwagger2(version: OpenApiVersionInfo): boolean;
68
75
  //#endregion
69
- export { detectOpenApiVersion as a, isOpenApi30 as c, detectJsonSchemaDraft as i, isOpenApi31 as l, JsonSchemaDraft as n, inferJsonSchemaDraft as o, OpenApiVersionInfo as r, inferJsonSchemaDraftWithReason as s, InferredDraft as t, isSwagger2 as u };
76
+ export { detectOpenApiVersion as a, isOpenApi30 as c, matchJsonSchemaDraftUri as d, detectJsonSchemaDraft as i, isOpenApi31 as l, JsonSchemaDraft as n, inferJsonSchemaDraft as o, OpenApiVersionInfo as r, inferJsonSchemaDraftWithReason as s, InferredDraft as t, isSwagger2 as u };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "schema-components",
3
- "version": "1.18.0",
3
+ "version": "1.19.0",
4
4
  "description": "React components that render UI from Zod schemas, JSON Schema, and OpenAPI documents",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",