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.
- package/dist/core/adapter.d.mts +1 -1
- package/dist/core/adapter.mjs +77 -14
- package/dist/core/constraints.d.mts +1 -1
- package/dist/core/diagnostics.d.mts +1 -1
- package/dist/core/errors.d.mts +1 -1
- package/dist/core/errors.mjs +7 -1
- package/dist/core/fieldOrder.d.mts +10 -0
- package/dist/core/fieldOrder.mjs +12 -0
- package/dist/core/formats.mjs +9 -1
- package/dist/core/merge.d.mts +1 -1
- package/dist/core/merge.mjs +30 -2
- package/dist/core/normalise.d.mts +38 -5
- package/dist/core/normalise.mjs +2 -2
- package/dist/core/openapi30.d.mts +33 -4
- package/dist/core/openapi30.mjs +2 -2
- package/dist/core/ref.d.mts +1 -1
- package/dist/core/renderer.d.mts +1 -1
- package/dist/core/renderer.mjs +7 -21
- package/dist/core/swagger2.d.mts +1 -1
- package/dist/core/swagger2.mjs +1 -1
- package/dist/core/version.d.mts +2 -2
- package/dist/core/version.mjs +19 -9
- package/dist/core/walkBuilders.d.mts +2 -2
- package/dist/{diagnostics-BYk63jsC.d.mts → diagnostics-VgEKI_Ct.d.mts} +1 -1
- package/dist/{errors-C5zRC2PU.d.mts → errors-CnGjT1cg.d.mts} +7 -2
- package/dist/html/a11y.d.mts +1 -1
- package/dist/html/renderToHtml.d.mts +1 -1
- package/dist/html/renderToHtml.mjs +13 -30
- package/dist/html/renderToHtmlStream.d.mts +1 -1
- package/dist/html/renderers.d.mts +1 -1
- package/dist/html/renderers.mjs +56 -23
- package/dist/html/streamRenderers.d.mts +1 -1
- package/dist/html/streamRenderers.mjs +10 -21
- package/dist/{normalise-tL9FckAk.mjs → normalise-C0ofw3W6.mjs} +418 -97
- package/dist/openapi/ApiSecurity.mjs +1 -1
- package/dist/openapi/bundle.mjs +1 -0
- package/dist/openapi/components.mjs +6 -2
- package/dist/openapi/parser.d.mts +2 -2
- package/dist/openapi/parser.mjs +8 -5
- package/dist/openapi/resolve.d.mts +6 -5
- package/dist/openapi/resolve.mjs +7 -6
- package/dist/react/SchemaComponent.d.mts +4 -4
- package/dist/react/SchemaComponent.mjs +4 -14
- package/dist/react/SchemaView.d.mts +2 -2
- package/dist/react/SchemaView.mjs +2 -1
- package/dist/react/headless.d.mts +7 -1
- package/dist/react/headless.mjs +13 -1
- package/dist/react/headlessRenderers.d.mts +53 -2
- package/dist/react/headlessRenderers.mjs +175 -33
- package/dist/{ref-Ckt5liZs.d.mts → ref-Bb43ZURY.d.mts} +1 -1
- package/dist/{renderer-DXo-rXHJ.d.mts → renderer-BQqiXUYP.d.mts} +15 -32
- package/dist/themes/mantine.d.mts +1 -1
- package/dist/themes/mantine.mjs +2 -1
- package/dist/themes/mui.d.mts +1 -1
- package/dist/themes/mui.mjs +3 -2
- package/dist/themes/radix.d.mts +1 -1
- package/dist/themes/radix.mjs +2 -1
- package/dist/themes/shadcn.d.mts +1 -1
- package/dist/themes/shadcn.mjs +2 -1
- package/dist/{version-B5NV-35j.d.mts → version-XNH7PRGP.d.mts} +8 -1
- 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
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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 { M as WalkedField } from "../types-D_5ST7SS.mjs";
|
|
2
|
-
import { o as HtmlResolver } from "../renderer-
|
|
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;
|
package/dist/html/renderers.mjs
CHANGED
|
@@ -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
|
|
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
|
-
|
|
157
|
-
|
|
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 =
|
|
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
|
-
|
|
242
|
-
|
|
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
|
|
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:
|
|
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":
|
|
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.
|
|
369
|
-
|
|
370
|
-
|
|
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-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
}
|