schema-components 1.22.0 → 1.23.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 (82) hide show
  1. package/README.md +3 -1
  2. package/dist/core/adapter.d.mts +97 -3
  3. package/dist/core/adapter.mjs +260 -111
  4. package/dist/core/constraints.d.mts +2 -2
  5. package/dist/core/constraints.mjs +0 -7
  6. package/dist/core/cssClasses.d.mts +52 -0
  7. package/dist/core/cssClasses.mjs +51 -0
  8. package/dist/core/diagnostics.d.mts +1 -1
  9. package/dist/core/errors.d.mts +1 -1
  10. package/dist/core/errors.mjs +5 -13
  11. package/dist/core/fieldOrder.d.mts +1 -1
  12. package/dist/core/formats.d.mts +9 -2
  13. package/dist/core/formats.mjs +12 -1
  14. package/dist/core/idPath.d.mts +54 -0
  15. package/dist/core/idPath.mjs +66 -0
  16. package/dist/core/merge.d.mts +10 -1
  17. package/dist/core/merge.mjs +49 -10
  18. package/dist/core/normalise.d.mts +14 -3
  19. package/dist/core/normalise.mjs +2 -2
  20. package/dist/core/openapi30.d.mts +15 -1
  21. package/dist/core/openapi30.mjs +2 -2
  22. package/dist/core/openapiConstants.d.mts +67 -0
  23. package/dist/core/openapiConstants.mjs +90 -0
  24. package/dist/core/ref.d.mts +2 -2
  25. package/dist/core/ref.mjs +84 -6
  26. package/dist/core/refChain.d.mts +70 -0
  27. package/dist/core/refChain.mjs +44 -0
  28. package/dist/core/renderer.d.mts +1 -1
  29. package/dist/core/swagger2.d.mts +1 -1
  30. package/dist/core/swagger2.mjs +1 -1
  31. package/dist/core/typeInference.d.mts +982 -2
  32. package/dist/core/types.d.mts +1 -1
  33. package/dist/core/unionMatch.d.mts +36 -0
  34. package/dist/core/unionMatch.mjs +53 -0
  35. package/dist/core/version.d.mts +1 -1
  36. package/dist/core/version.mjs +29 -17
  37. package/dist/core/walkBuilders.d.mts +23 -4
  38. package/dist/core/walkBuilders.mjs +27 -7
  39. package/dist/core/walker.d.mts +1 -1
  40. package/dist/core/walker.mjs +44 -45
  41. package/dist/{diagnostics-D0QCYGv0.d.mts → diagnostics-BS2kaUyE.d.mts} +1 -1
  42. package/dist/{errors-DpFwqs5C.d.mts → errors-g_MCTQel.d.mts} +9 -15
  43. package/dist/html/a11y.d.mts +9 -4
  44. package/dist/html/a11y.mjs +10 -19
  45. package/dist/html/renderToHtml.d.mts +2 -2
  46. package/dist/html/renderToHtmlStream.d.mts +2 -2
  47. package/dist/html/renderToHtmlStream.mjs +12 -1
  48. package/dist/html/renderers.d.mts +43 -8
  49. package/dist/html/renderers.mjs +136 -111
  50. package/dist/html/streamRenderers.d.mts +4 -5
  51. package/dist/html/streamRenderers.mjs +40 -61
  52. package/dist/{normalise-DVEJQmF7.mjs → normalise-DCYp06Sr.mjs} +352 -162
  53. package/dist/openapi/ApiCallbacks.d.mts +1 -1
  54. package/dist/openapi/ApiLinks.d.mts +1 -1
  55. package/dist/openapi/ApiResponseHeaders.d.mts +1 -1
  56. package/dist/openapi/ApiSecurity.d.mts +1 -1
  57. package/dist/openapi/components.d.mts +116 -37
  58. package/dist/openapi/components.mjs +54 -37
  59. package/dist/openapi/parser.d.mts +9 -8
  60. package/dist/openapi/parser.mjs +234 -84
  61. package/dist/openapi/resolve.d.mts +20 -11
  62. package/dist/openapi/resolve.mjs +133 -73
  63. package/dist/react/SchemaComponent.d.mts +32 -7
  64. package/dist/react/SchemaComponent.mjs +45 -21
  65. package/dist/react/SchemaView.d.mts +30 -10
  66. package/dist/react/a11y.d.mts +21 -0
  67. package/dist/react/a11y.mjs +24 -0
  68. package/dist/react/fieldPath.d.mts +1 -1
  69. package/dist/react/headless.d.mts +1 -1
  70. package/dist/react/headlessRenderers.d.mts +8 -9
  71. package/dist/react/headlessRenderers.mjs +41 -72
  72. package/dist/{ref-D-_JBZkF.d.mts → ref-DjLEKa_E.d.mts} +38 -3
  73. package/dist/{renderer-BaRlQIuN.d.mts → renderer-CXJ8y0qw.d.mts} +1 -1
  74. package/dist/themes/mantine.d.mts +1 -1
  75. package/dist/themes/mui.d.mts +1 -1
  76. package/dist/themes/radix.d.mts +1 -1
  77. package/dist/themes/shadcn.d.mts +1 -1
  78. package/dist/themes/shadcn.mjs +2 -1
  79. package/dist/{types-BrRMV0en.d.mts → types-BTB73MB8.d.mts} +32 -4
  80. package/dist/{version-D2jfdX6E.d.mts → version-BFTVLsdb.d.mts} +7 -1
  81. package/package.json +1 -1
  82. package/dist/typeInference-DkcUHfaM.d.mts +0 -982
@@ -1,14 +1,17 @@
1
1
  import { isObject } from "../core/guards.mjs";
2
2
  import "../core/limits.mjs";
3
3
  import { emitDiagnostic } from "../core/diagnostics.mjs";
4
+ import { SC_CLASSES } from "../core/cssClasses.mjs";
4
5
  import { getHtmlRenderFn } from "../core/renderer.mjs";
6
+ import { matchUnionOption, resolveDiscriminatedActive } from "../core/unionMatch.mjs";
5
7
  import { VOID_ELEMENTS, h, raw, serialize, serializeAttributes } from "./html.mjs";
6
8
  import { ariaLabelAttrs, buildHintElement, buildInputId, joinPath, requiredIndicator } from "./a11y.mjs";
9
+ import { panelId, tabId } from "./renderers.mjs";
7
10
  import { recursionSentinelHtml } from "./renderToHtml.mjs";
8
11
  //#region src/html/streamRenderers.ts
9
12
  function yieldOpen(el) {
10
13
  const attrStr = serializeAttributes(el.attributes);
11
- if (el.children.length === 0 && VOID_ELEMENTS.has(el.tag)) return `<${el.tag}${attrStr}>`;
14
+ if (VOID_ELEMENTS.has(el.tag)) return `<${el.tag}${attrStr} />`;
12
15
  return `<${el.tag}${attrStr}>`;
13
16
  }
14
17
  function yieldClose(el) {
@@ -27,19 +30,12 @@ function renderLeaf(tree, value, mergedResolver, path) {
27
30
  tree,
28
31
  renderChild: () => ""
29
32
  });
30
- if (value === void 0 || value === null) return serialize(h("span", { class: "sc-value sc-value--empty" }, "—"));
31
- return serialize(h("span", { class: "sc-value" }, typeof value === "string" ? value : JSON.stringify(value)));
33
+ if (value === void 0 || value === null) return serialize(h("span", { class: SC_CLASSES.valueEmpty }, "—"));
34
+ return serialize(h("span", { class: SC_CLASSES.value }, typeof value === "string" ? value : JSON.stringify(value)));
32
35
  }
33
36
  function renderFieldSync(tree, value, mergedResolver, path, rawResolver, currentDepth, diagnostics) {
34
37
  return [...streamField(tree, value, mergedResolver, path, rawResolver, currentDepth, diagnostics)].join("");
35
38
  }
36
- function matchUnionOption(options, value) {
37
- if (typeof value === "string") return options.find((o) => o.type === "string" || o.type === "enum");
38
- if (typeof value === "number") return options.find((o) => o.type === "number");
39
- if (typeof value === "boolean") return options.find((o) => o.type === "boolean");
40
- if (Array.isArray(value)) return options.find((o) => o.type === "array");
41
- if (typeof value === "object" && value !== null) return options.find((o) => o.type === "object");
42
- }
43
39
  /**
44
40
  * Build a visible placeholder element used when a value does not match
45
41
  * the shape implied by its field type. The expected-shape label is
@@ -110,7 +106,7 @@ function* streamObject(tree, value, mergedResolver, path, rawResolver, currentDe
110
106
  const descriptionText = typeof tree.meta.description === "string" ? tree.meta.description : void 0;
111
107
  const labelAttrs = ariaLabelAttrs(descriptionText);
112
108
  if (readOnly) {
113
- const dlAttrs = { class: "sc-object" };
109
+ const dlAttrs = { class: SC_CLASSES.object };
114
110
  Object.assign(dlAttrs, labelAttrs);
115
111
  const dl = h("dl", dlAttrs);
116
112
  const legend = descriptionText !== void 0 ? serialize(h("legend", {}, descriptionText)) : "";
@@ -119,11 +115,11 @@ function* streamObject(tree, value, mergedResolver, path, rawResolver, currentDe
119
115
  const label = typeof field.meta.description === "string" ? field.meta.description : key;
120
116
  const childValue = obj[key];
121
117
  const childHtml = renderFieldSync(field, childValue, mergedResolver, joinPath(path, key), rawResolver, currentDepth + 1, diagnostics);
122
- yield `${serialize(h("dt", { class: "sc-label" }, label))}${serialize(h("dd", { class: "sc-value" }, raw(childHtml)))}`;
118
+ yield `${serialize(h("dt", { class: SC_CLASSES.label }, label))}${serialize(h("dd", { class: SC_CLASSES.value }, raw(childHtml)))}`;
123
119
  }
124
120
  yield yieldClose(dl);
125
121
  } else {
126
- const fieldsetAttrs = { class: "sc-object" };
122
+ const fieldsetAttrs = { class: SC_CLASSES.object };
127
123
  Object.assign(fieldsetAttrs, labelAttrs);
128
124
  const fieldset = h("fieldset", fieldsetAttrs);
129
125
  const legend = descriptionText !== void 0 ? serialize(h("legend", {}, descriptionText)) : "";
@@ -137,12 +133,12 @@ function* streamObject(tree, value, mergedResolver, path, rawResolver, currentDe
137
133
  const labelContent = [label];
138
134
  if (required !== void 0) labelContent.push(required);
139
135
  const fieldChildren = [h("label", {
140
- class: "sc-label",
136
+ class: SC_CLASSES.label,
141
137
  for: fieldId
142
138
  }, ...labelContent), raw(childChunks)];
143
139
  const hint = buildHintElement(key, field.constraints);
144
140
  if (hint !== void 0) fieldChildren.push(hint);
145
- yield serialize(h("div", { class: "sc-field" }, ...fieldChildren));
141
+ yield serialize(h("div", { class: SC_CLASSES.field }, ...fieldChildren));
146
142
  }
147
143
  yield yieldClose(fieldset);
148
144
  }
@@ -167,12 +163,12 @@ function* streamArray(tree, value, mergedResolver, path, rawResolver, currentDep
167
163
  }
168
164
  const arr = Array.isArray(value) ? value : [];
169
165
  if (tree.editability === "presentation") {
170
- const ul = h("ul", { class: "sc-array" });
166
+ const ul = h("ul", { class: SC_CLASSES.array });
171
167
  yield yieldOpen(ul);
172
168
  for (const [i, item] of arr.entries()) yield serialize(h("li", { class: "sc-item" }, raw(renderFieldSync(element, item, mergedResolver, joinPath(path, `[${String(i)}]`), rawResolver, currentDepth + 1, diagnostics))));
173
169
  yield yieldClose(ul);
174
170
  } else {
175
- const div = h("div", { class: "sc-array" });
171
+ const div = h("div", { class: SC_CLASSES.array });
176
172
  yield yieldOpen(div);
177
173
  for (const [i, item] of arr.entries()) yield serialize(h("div", {}, raw(renderFieldSync(element, item, mergedResolver, joinPath(path, `[${String(i)}]`), rawResolver, currentDepth + 1, diagnostics))));
178
174
  yield yieldClose(div);
@@ -198,7 +194,7 @@ function* streamRecord(tree, value, mergedResolver, path, rawResolver, currentDe
198
194
  const obj = isObject(value) ? value : {};
199
195
  const readOnly = tree.editability === "presentation";
200
196
  const attrs = {
201
- class: "sc-record",
197
+ class: SC_CLASSES.record,
202
198
  role: "group"
203
199
  };
204
200
  if (readOnly) {
@@ -206,7 +202,7 @@ function* streamRecord(tree, value, mergedResolver, path, rawResolver, currentDe
206
202
  yield yieldOpen(dl);
207
203
  for (const [key, val] of Object.entries(obj)) {
208
204
  const childHtml = renderFieldSync(valueType, val, mergedResolver, joinPath(path, key), rawResolver, currentDepth + 1, diagnostics);
209
- yield `${serialize(h("dt", { class: "sc-label" }, key))}${serialize(h("dd", { class: "sc-value" }, raw(childHtml)))}`;
205
+ yield `${serialize(h("dt", { class: SC_CLASSES.label }, key))}${serialize(h("dd", { class: SC_CLASSES.value }, raw(childHtml)))}`;
210
206
  }
211
207
  yield yieldClose(dl);
212
208
  } else {
@@ -214,7 +210,7 @@ function* streamRecord(tree, value, mergedResolver, path, rawResolver, currentDe
214
210
  yield yieldOpen(container);
215
211
  for (const [key, val] of Object.entries(obj)) {
216
212
  const childHtml = renderFieldSync(valueType, val, mergedResolver, joinPath(path, key), rawResolver, currentDepth + 1, diagnostics);
217
- yield serialize(h("div", { class: "sc-field" }, h("label", { class: "sc-label" }, key), raw(childHtml)));
213
+ yield serialize(h("div", { class: SC_CLASSES.field }, h("label", { class: SC_CLASSES.label }, key), raw(childHtml)));
218
214
  }
219
215
  yield yieldClose(container);
220
216
  }
@@ -222,67 +218,50 @@ function* streamRecord(tree, value, mergedResolver, path, rawResolver, currentDe
222
218
  function* streamUnion(tree, value, mergedResolver, path, rawResolver, currentDepth, diagnostics) {
223
219
  const options = tree.type === "union" ? tree.options : void 0;
224
220
  if (options === void 0 || options.length === 0) {
225
- if (value === void 0 || value === null) yield serialize(h("span", { class: "sc-value sc-value--empty" }, "—"));
226
- else yield serialize(h("span", { class: "sc-value" }, JSON.stringify(value)));
221
+ if (value === void 0 || value === null) yield serialize(h("span", { class: SC_CLASSES.valueEmpty }, "—"));
222
+ else yield serialize(h("span", { class: SC_CLASSES.value }, JSON.stringify(value)));
227
223
  return;
228
224
  }
229
225
  const target = matchUnionOption(options, value) ?? options[0];
230
226
  if (target !== void 0) yield* streamField(target, value, mergedResolver, path, rawResolver, currentDepth + 1, diagnostics);
231
- else yield serialize(h("span", { class: "sc-value sc-value--empty" }, "—"));
227
+ else yield serialize(h("span", { class: SC_CLASSES.valueEmpty }, "—"));
232
228
  }
233
229
  function* streamDiscriminatedUnion(tree, value, mergedResolver, path, rawResolver, currentDepth, diagnostics) {
234
- const options = tree.type === "discriminatedUnion" ? tree.options : void 0;
235
- const discriminator = tree.type === "discriminatedUnion" ? tree.discriminator : void 0;
236
- if (options === void 0 || options.length === 0) {
237
- if (value === void 0 || value === null) yield serialize(h("span", { class: "sc-value sc-value--empty" }, "—"));
238
- else yield serialize(h("span", { class: "sc-value" }, JSON.stringify(value)));
230
+ if (tree.type !== "discriminatedUnion") return;
231
+ const { options, discriminator } = tree;
232
+ if (options.length === 0) {
233
+ if (value === void 0 || value === null) yield serialize(h("span", { class: SC_CLASSES.valueEmpty }, "—"));
234
+ else yield serialize(h("span", { class: SC_CLASSES.value }, JSON.stringify(value)));
239
235
  return;
240
236
  }
241
- const obj = isObject(value) ? value : {};
242
- const discKey = discriminator ?? "";
243
- const currentDiscriminatorValue = typeof obj[discKey] === "string" ? obj[discKey] : void 0;
244
- const optionLabels = options.map((opt) => {
245
- if (opt.type === "object") {
246
- const discriminatorField = opt.fields[discKey];
247
- if (discriminatorField?.type === "literal") {
248
- const constVal = discriminatorField.literalValues[0];
249
- if (typeof constVal === "string") return constVal;
250
- }
251
- }
252
- return typeof opt.meta.title === "string" ? opt.meta.title : opt.type;
253
- });
254
- let activeIndex = 0;
255
- if (currentDiscriminatorValue !== void 0) {
256
- const found = optionLabels.indexOf(currentDiscriminatorValue);
257
- if (found !== -1) activeIndex = found;
258
- }
259
- const activeOption = options[activeIndex];
237
+ const { optionLabels, activeIndex, activeOption } = resolveDiscriminatedActive(options, discriminator, isObject(value) ? value : void 0);
260
238
  if (tree.editability === "presentation") {
261
239
  if (activeOption !== void 0) yield* streamField(activeOption, value, mergedResolver, path, rawResolver, currentDepth + 1, diagnostics);
262
240
  return;
263
241
  }
264
- const panelId = `sc-${path}-panel`;
265
- const wrapper = h("div", { class: "sc-discriminated-union" });
242
+ const tabPanelId = panelId(path);
243
+ const wrapper = h("div", { class: SC_CLASSES.discriminatedUnion });
266
244
  yield yieldOpen(wrapper);
267
- yield serialize(h("div", {
268
- role: "tablist",
269
- class: "sc-tabs",
270
- "aria-label": "Select variant"
271
- }, ...options.map((_opt, i) => {
245
+ const tabButtons = options.map((_opt, i) => {
272
246
  return h("button", {
273
247
  type: "button",
274
248
  role: "tab",
275
- class: i === activeIndex ? "sc-tab sc-tab--active" : "sc-tab",
276
- id: `sc-${path}-tab-${String(i)}`,
249
+ class: i === activeIndex ? SC_CLASSES.tabActive : SC_CLASSES.tab,
250
+ id: tabId(path, i),
277
251
  "aria-selected": i === activeIndex ? "true" : void 0,
278
- "aria-controls": panelId,
252
+ "aria-controls": tabPanelId,
279
253
  tabindex: i === activeIndex ? "0" : "-1"
280
254
  }, optionLabels[i]);
281
- })));
255
+ });
256
+ yield serialize(h("div", {
257
+ role: "tablist",
258
+ class: SC_CLASSES.tabs,
259
+ "aria-label": "Select variant"
260
+ }, ...tabButtons));
282
261
  const panelOpen = h("div", {
283
262
  role: "tabpanel",
284
- id: panelId,
285
- "aria-labelledby": `sc-${path}-tab-${String(activeIndex)}`
263
+ id: tabPanelId,
264
+ "aria-labelledby": tabId(path, activeIndex)
286
265
  });
287
266
  yield yieldOpen(panelOpen);
288
267
  if (activeOption !== void 0) yield* streamField(activeOption, value, mergedResolver, path, rawResolver, currentDepth + 1, diagnostics);
@@ -290,4 +269,4 @@ function* streamDiscriminatedUnion(tree, value, mergedResolver, path, rawResolve
290
269
  yield yieldClose(wrapper);
291
270
  }
292
271
  //#endregion
293
- export { matchUnionOption, renderFieldSync, renderLeaf, streamField, yieldClose, yieldOpen };
272
+ export { renderFieldSync, renderLeaf, streamField, yieldClose, yieldOpen };