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,7 +1,6 @@
1
1
  import { normaliseSchema } from "../core/adapter.mjs";
2
2
  import { getHtmlRenderFn, mergeHtmlResolvers } from "../core/renderer.mjs";
3
3
  import { walk } from "../core/walker.mjs";
4
- import { h, serialize } from "./html.mjs";
5
4
  import { joinPath } from "./a11y.mjs";
6
5
  import { defaultHtmlResolver } from "./renderers.mjs";
7
6
  //#region src/html/renderToHtml.ts
@@ -59,35 +58,19 @@ function renderFieldHtml(tree, value, resolver, path, renderChild) {
59
58
  const effectiveValue = value ?? tree.defaultValue;
60
59
  const mergedResolver = mergeHtmlResolvers(resolver, defaultHtmlResolver);
61
60
  const renderFn = getHtmlRenderFn(tree.type, mergedResolver);
62
- if (renderFn !== void 0) {
63
- const props = {
64
- value: effectiveValue,
65
- readOnly: tree.editability === "presentation",
66
- writeOnly: tree.editability === "input",
67
- meta: tree.meta,
68
- constraints: tree.constraints,
69
- path,
70
- tree,
71
- renderChild
72
- };
73
- if (tree.type === "enum") props.enumValues = tree.enumValues;
74
- if (tree.type === "array" && tree.element !== void 0) props.element = tree.element;
75
- if (tree.type === "object") props.fields = tree.fields;
76
- if (tree.type === "union" || tree.type === "discriminatedUnion") props.options = tree.options;
77
- if (tree.type === "discriminatedUnion") props.discriminator = tree.discriminator;
78
- if (tree.type === "record") props.keyType = tree.keyType;
79
- if (tree.type === "record") props.valueType = tree.valueType;
80
- if (tree.type === "tuple") props.prefixItems = tree.prefixItems;
81
- if (tree.type === "conditional") props.ifClause = tree.ifClause;
82
- if (tree.type === "conditional" && tree.thenClause !== void 0) props.thenClause = tree.thenClause;
83
- if (tree.type === "conditional" && tree.elseClause !== void 0) props.elseClause = tree.elseClause;
84
- if (tree.type === "negation") props.negated = tree.negated;
85
- if (tree.type === "literal") props.literalValues = tree.literalValues;
86
- if (tree.examples !== void 0) props.examples = tree.examples;
87
- return renderFn(props);
88
- }
89
- if (effectiveValue === void 0 || effectiveValue === null) return serialize(h("span", { class: "sc-value sc-value--empty" }, "—"));
90
- return serialize(h("span", { class: "sc-value" }, typeof effectiveValue === "string" ? effectiveValue : JSON.stringify(effectiveValue)));
61
+ if (renderFn === void 0) throw new Error(`renderToHtml: no HTML renderer registered for type "${tree.type}"`);
62
+ const props = {
63
+ value: effectiveValue,
64
+ readOnly: tree.editability === "presentation",
65
+ writeOnly: tree.editability === "input",
66
+ meta: tree.meta,
67
+ constraints: tree.constraints,
68
+ path,
69
+ tree,
70
+ renderChild
71
+ };
72
+ if (tree.examples !== void 0) props.examples = tree.examples;
73
+ return renderFn(props);
91
74
  }
92
75
  //#endregion
93
76
  export { renderToHtml };
@@ -1,5 +1,5 @@
1
1
  import { T as SchemaMeta } from "../types-D_5ST7SS.mjs";
2
- import { o as HtmlResolver } from "../renderer-DXo-rXHJ.mjs";
2
+ import { o as HtmlResolver } from "../renderer-BQqiXUYP.mjs";
3
3
 
4
4
  //#region src/html/renderToHtmlStream.d.ts
5
5
  interface StreamRenderOptions {
@@ -1,5 +1,5 @@
1
1
  import { M as WalkedField } from "../types-D_5ST7SS.mjs";
2
- import { o as HtmlResolver } from "../renderer-DXo-rXHJ.mjs";
2
+ import { o as HtmlResolver } from "../renderer-BQqiXUYP.mjs";
3
3
 
4
4
  //#region src/html/renderers.d.ts
5
5
  declare function dateInputType(format: string | undefined): string | undefined;
@@ -1,3 +1,4 @@
1
+ import { sortFieldsByOrder } from "../core/fieldOrder.mjs";
1
2
  import { h, raw, serialize } from "./html.mjs";
2
3
  import { ariaDescribedByAttrs, ariaLabelAttrs, ariaReadonlyAttrs, ariaRequiredAttrs, buildHintElement, buildInputId, requiredIndicator } from "./a11y.mjs";
3
4
  //#region src/html/renderers.ts
@@ -135,7 +136,8 @@ function renderEnumEditable(props) {
135
136
  const enumValue = typeof props.value === "string" ? props.value : "";
136
137
  const id = fieldId(props.path);
137
138
  const selectedValue = props.writeOnly ? "" : enumValue;
138
- const optionNodes = [h("option", { value: "" }, "Select…"), ...(props.enumValues ?? []).map((v) => {
139
+ const enumValues = props.tree.type === "enum" ? props.tree.enumValues : [];
140
+ const optionNodes = [h("option", { value: "" }, "Select…"), ...enumValues.map((v) => {
139
141
  const display = v === null ? "null" : typeof v === "string" ? v : String(v);
140
142
  const attrs = { value: display };
141
143
  if (display === selectedValue) attrs.selected = true;
@@ -153,15 +155,13 @@ function renderObjectHtml(props) {
153
155
  return serialize(renderObjectNode(props));
154
156
  }
155
157
  function renderObjectNode(props) {
156
- const fields = props.fields;
157
- if (fields === void 0) return "";
158
+ if (props.tree.type !== "object") return "";
159
+ const fields = props.tree.fields;
158
160
  const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
159
161
  const obj = isRecord(props.value) ? props.value : {};
160
162
  const descriptionText = typeof props.meta.description === "string" ? props.meta.description : void 0;
161
163
  const legend = descriptionText !== void 0 ? h("legend", {}, descriptionText) : void 0;
162
- const sortedEntries = Object.entries(fields).sort((a, b) => {
163
- return (typeof a[1].meta.order === "number" ? a[1].meta.order : Infinity) - (typeof b[1].meta.order === "number" ? b[1].meta.order : Infinity);
164
- }).filter(([, field]) => field.meta.visible !== false);
164
+ const sortedEntries = sortFieldsByOrder(fields).filter(([, field]) => field.meta.visible !== false);
165
165
  if (props.readOnly) {
166
166
  const children = [];
167
167
  if (legend !== void 0) children.push(legend);
@@ -203,7 +203,7 @@ function renderArrayHtml(props) {
203
203
  }
204
204
  function renderArrayNode(props) {
205
205
  const arr = Array.isArray(props.value) ? props.value : [];
206
- const element = props.element;
206
+ const element = props.tree.type === "array" ? props.tree.element : void 0;
207
207
  if (element === void 0) return "";
208
208
  const childHtmls = arr.map((item, i) => props.renderChild(element, item, `[${String(i)}]`));
209
209
  if (props.readOnly) return h("ul", { class: "sc-array" }, ...childHtmls.map((childHtml) => h("li", { class: "sc-item" }, raw(childHtml))));
@@ -213,10 +213,10 @@ function renderRecordHtml(props) {
213
213
  return serialize(renderRecordNode(props));
214
214
  }
215
215
  function renderRecordNode(props) {
216
+ if (props.tree.type !== "record") return "";
216
217
  const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
217
218
  const obj = isRecord(props.value) ? props.value : {};
218
- const valueType = props.valueType;
219
- if (valueType === void 0) return "";
219
+ const valueType = props.tree.valueType;
220
220
  const attrs = {
221
221
  class: "sc-record",
222
222
  role: "group"
@@ -238,12 +238,13 @@ function renderRecordNode(props) {
238
238
  return h("div", attrs, ...children);
239
239
  }
240
240
  function renderLiteralHtml(props) {
241
- const values = props.literalValues;
242
- if (values === void 0 || values.length === 0) return serialize(h("span", { class: "sc-value sc-value--empty" }, "—"));
241
+ if (props.tree.type !== "literal") return serialize(h("span", { class: "sc-value sc-value--empty" }, "—"));
242
+ const values = props.tree.literalValues;
243
+ if (values.length === 0) return serialize(h("span", { class: "sc-value sc-value--empty" }, "—"));
243
244
  return serialize(h("span", { class: "sc-value" }, values.map((v) => v === null ? "null" : String(v)).join(", ")));
244
245
  }
245
246
  function renderUnionHtml(props) {
246
- const options = props.options;
247
+ const options = props.tree.type === "union" || props.tree.type === "discriminatedUnion" ? props.tree.options : void 0;
247
248
  if (options === void 0 || options.length === 0) {
248
249
  if (props.value === void 0 || props.value === null) return serialize(h("span", { class: "sc-value sc-value--empty" }, "—"));
249
250
  return serialize(h("span", { class: "sc-value" }, JSON.stringify(props.value)));
@@ -255,8 +256,8 @@ function renderUnionHtml(props) {
255
256
  return serialize(h("span", { class: "sc-value sc-value--empty" }, "—"));
256
257
  }
257
258
  function renderDiscriminatedUnionHtml(props) {
258
- const options = props.options;
259
- const discriminator = props.discriminator;
259
+ const options = props.tree.type === "discriminatedUnion" ? props.tree.options : void 0;
260
+ const discriminator = props.tree.type === "discriminatedUnion" ? props.tree.discriminator : void 0;
260
261
  if (options === void 0 || options.length === 0) {
261
262
  if (props.value === void 0 || props.value === null) return serialize(h("span", { class: "sc-value sc-value--empty" }, "—"));
262
263
  return serialize(h("span", { class: "sc-value" }, JSON.stringify(props.value)));
@@ -285,7 +286,9 @@ function renderDiscriminatedUnionHtml(props) {
285
286
  if (activeOption !== void 0) return props.renderChild(activeOption, props.value);
286
287
  return serialize(h("span", { class: "sc-value sc-value--empty" }, "—"));
287
288
  }
288
- const panelId = `sc-${props.path}-panel`;
289
+ const baseId = fieldId(props.path);
290
+ const panelId = `${baseId}-panel`;
291
+ const tabId = (i) => `${baseId}-tab-${String(i)}`;
289
292
  const children = [h("div", {
290
293
  role: "tablist",
291
294
  class: "sc-tabs",
@@ -295,7 +298,7 @@ function renderDiscriminatedUnionHtml(props) {
295
298
  type: "button",
296
299
  role: "tab",
297
300
  class: i === activeIndex ? "sc-tab sc-tab--active" : "sc-tab",
298
- id: `sc-${props.path}-tab-${String(i)}`,
301
+ id: tabId(i),
299
302
  "aria-selected": i === activeIndex ? "true" : void 0,
300
303
  "aria-controls": panelId,
301
304
  tabindex: i === activeIndex ? "0" : "-1"
@@ -306,7 +309,7 @@ function renderDiscriminatedUnionHtml(props) {
306
309
  children.push(h("div", {
307
310
  role: "tabpanel",
308
311
  id: panelId,
309
- "aria-labelledby": `sc-${props.path}-tab-${String(activeIndex)}`
312
+ "aria-labelledby": tabId(activeIndex)
310
313
  }, raw(childHtml)));
311
314
  }
312
315
  return serialize(h("div", { class: "sc-discriminated-union" }, ...children));
@@ -331,7 +334,7 @@ function renderFileHtml(props) {
331
334
  return serialize(h("input", attrs));
332
335
  }
333
336
  function renderRecursiveHtml(props) {
334
- const refTarget = props.refTarget ?? "";
337
+ const refTarget = props.tree.type === "recursive" ? props.tree.refTarget : "";
335
338
  return serialize(h("fieldset", { class: "sc-recursive" }, `↻ ${typeof props.meta.description === "string" ? props.meta.description : refTarget} (recursive)`));
336
339
  }
337
340
  function renderUnknownHtml(props) {
@@ -350,9 +353,9 @@ function renderUnknownHtml(props) {
350
353
  return serialize(h("input", attrs));
351
354
  }
352
355
  function renderTupleHtml(props) {
356
+ if (props.tree.type !== "tuple") return renderUnknownHtml(props);
353
357
  const arr = Array.isArray(props.value) ? props.value : [];
354
- const prefixItems = props.prefixItems;
355
- if (prefixItems === void 0) return renderUnknownHtml(props);
358
+ const prefixItems = props.tree.prefixItems;
356
359
  const children = [];
357
360
  for (let i = 0; i < prefixItems.length; i++) {
358
361
  const itemValue = arr[i];
@@ -365,14 +368,42 @@ function renderTupleHtml(props) {
365
368
  }
366
369
  function renderConditionalHtml(props) {
367
370
  const children = [];
368
- if (props.ifClause !== void 0) children.push(h("div", { class: "sc-conditional-if" }, raw("if: ...")));
369
- if (props.thenClause !== void 0) children.push(h("div", { class: "sc-conditional-then" }, raw("then: ...")));
370
- if (props.elseClause !== void 0) children.push(h("div", { class: "sc-conditional-else" }, raw("else: ...")));
371
+ if (props.tree.type === "conditional") {
372
+ children.push(h("div", { class: "sc-conditional-if" }, raw("if: ...")));
373
+ if (props.tree.thenClause !== void 0) children.push(h("div", { class: "sc-conditional-then" }, raw("then: ...")));
374
+ if (props.tree.elseClause !== void 0) children.push(h("div", { class: "sc-conditional-else" }, raw("else: ...")));
375
+ }
371
376
  return serialize(h("div", { class: "sc-conditional" }, ...children));
372
377
  }
373
378
  function renderNegationHtml(props) {
374
379
  return serialize(h("div", { class: "sc-negation" }, raw("not: ...")));
375
380
  }
381
+ /**
382
+ * Render a null field — `z.null()` or `{ type: "null" }`.
383
+ *
384
+ * The only valid value is `null`, so render an em-dash placeholder.
385
+ */
386
+ function renderNullHtml(props) {
387
+ return serialize(h("span", {
388
+ class: "sc-value sc-value--empty",
389
+ id: fieldId(props.path),
390
+ ...ariaReadonlyAttrs()
391
+ }, "—"));
392
+ }
393
+ /**
394
+ * Render a never field — `z.never()` or a `false` schema.
395
+ *
396
+ * `never` indicates a position that cannot hold any value. Render a
397
+ * visible placeholder rather than throwing because some valid schemas
398
+ * intentionally contain `never` branches.
399
+ */
400
+ function renderNeverHtml(props) {
401
+ return serialize(h("span", {
402
+ class: "sc-value sc-never",
403
+ id: fieldId(props.path),
404
+ ...ariaReadonlyAttrs()
405
+ }, h("em", {}, "never matches")));
406
+ }
376
407
  function matchUnionOption(options, value) {
377
408
  if (typeof value === "string") return options.find((o) => o.type === "string" || o.type === "enum");
378
409
  if (typeof value === "number") return options.find((o) => o.type === "number");
@@ -384,6 +415,7 @@ const defaultHtmlResolver = {
384
415
  string: renderStringHtml,
385
416
  number: renderNumberHtml,
386
417
  boolean: renderBooleanHtml,
418
+ null: renderNullHtml,
387
419
  enum: renderEnumHtml,
388
420
  object: renderObjectHtml,
389
421
  array: renderArrayHtml,
@@ -396,6 +428,7 @@ const defaultHtmlResolver = {
396
428
  negation: renderNegationHtml,
397
429
  recursive: renderRecursiveHtml,
398
430
  file: renderFileHtml,
431
+ never: renderNeverHtml,
399
432
  unknown: renderUnknownHtml
400
433
  };
401
434
  //#endregion
@@ -1,5 +1,5 @@
1
1
  import { M as WalkedField } from "../types-D_5ST7SS.mjs";
2
- import { o as HtmlResolver } from "../renderer-DXo-rXHJ.mjs";
2
+ import { o as HtmlResolver } from "../renderer-BQqiXUYP.mjs";
3
3
  import { HtmlElement } from "./html.mjs";
4
4
 
5
5
  //#region src/html/streamRenderers.d.ts
@@ -14,27 +14,16 @@ function yieldClose(el) {
14
14
  }
15
15
  function renderLeaf(tree, value, mergedResolver, path) {
16
16
  const renderFn = getHtmlRenderFn(tree.type, mergedResolver);
17
- if (renderFn !== void 0) {
18
- const props = {
19
- value,
20
- readOnly: tree.editability === "presentation",
21
- writeOnly: tree.editability === "input",
22
- meta: tree.meta,
23
- constraints: tree.constraints,
24
- path,
25
- tree,
26
- renderChild: () => ""
27
- };
28
- if (tree.type === "enum") props.enumValues = tree.enumValues;
29
- if (tree.type === "literal") props.literalValues = tree.literalValues;
30
- if (tree.type === "array" && tree.element !== void 0) props.element = tree.element;
31
- if (tree.type === "object") props.fields = tree.fields;
32
- if (tree.type === "union") props.options = tree.options;
33
- if (tree.type === "discriminatedUnion") props.discriminator = tree.discriminator;
34
- if (tree.type === "record") props.keyType = tree.keyType;
35
- if (tree.type === "record") props.valueType = tree.valueType;
36
- return renderFn(props);
37
- }
17
+ if (renderFn !== void 0) return renderFn({
18
+ value,
19
+ readOnly: tree.editability === "presentation",
20
+ writeOnly: tree.editability === "input",
21
+ meta: tree.meta,
22
+ constraints: tree.constraints,
23
+ path,
24
+ tree,
25
+ renderChild: () => ""
26
+ });
38
27
  if (value === void 0 || value === null) return serialize(h("span", { class: "sc-value sc-value--empty" }, "—"));
39
28
  return serialize(h("span", { class: "sc-value" }, typeof value === "string" ? value : JSON.stringify(value)));
40
29
  }