schema-components 3.3.0 → 3.5.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/{SchemaComponent-CRgCVDhz.d.mts → SchemaComponent-BWl1psB0.d.mts} +4 -11
- package/dist/core/idPath.d.mts +28 -1
- package/dist/core/idPath.mjs +37 -1
- package/dist/openapi/components.mjs +2 -1
- package/dist/preact/SchemaComponent.d.mts +1 -1
- package/dist/react/SchemaComponent.d.mts +2 -2
- package/dist/react/SchemaComponent.mjs +4 -59
- package/dist/react/headlessRenderers.mjs +1 -2
- package/dist/react/renderField.d.mts +33 -0
- package/dist/react/renderField.mjs +79 -0
- package/dist/solid/renderers.mjs +1 -2
- package/package.json +2 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { w as SchemaMeta } from "./types-BBQaEPfE.mjs";
|
|
2
2
|
import { t as Diagnostic } from "./diagnostics-mftUZI7c.mjs";
|
|
3
3
|
import { r as SchemaIoSide } from "./adapter-ktQaheWB.mjs";
|
|
4
4
|
import { d as WidgetMap, i as ComponentResolver, u as RenderProps } from "./renderer-ab9E52Bp.mjs";
|
|
@@ -215,16 +215,9 @@ declare function sanitisePrefix(value: string): string;
|
|
|
215
215
|
* resolver / headless pipeline. Used internally by
|
|
216
216
|
* {@link SchemaComponent} and {@link SchemaField}, exported so other
|
|
217
217
|
* React-side components (e.g. the OpenAPI renderers) can dispatch
|
|
218
|
-
* into the same fallback chain.
|
|
219
|
-
*
|
|
220
|
-
* Thin React-flavoured wrapper around the framework-agnostic
|
|
221
|
-
* `dispatchRenderField` (from `core/renderField`): it constructs a
|
|
222
|
-
* React-shaped `DispatchConfig` (widget lookup against the
|
|
223
|
-
* instance → context → global chain, recursion sentinel as a React
|
|
224
|
-
* `<fieldset>`, fallback as a `<span>`-wrapped value) and forwards
|
|
225
|
-
* the call.
|
|
218
|
+
* into the same fallback chain. Implementation lives in `./renderField.tsx`;
|
|
219
|
+
* re-exported here for the public `react/SchemaComponent` entry point.
|
|
226
220
|
*/
|
|
227
|
-
declare function renderField(tree: WalkedField, value: unknown, onChange: (v: unknown) => void, userResolver: ComponentResolver | undefined, renderChild: (tree: WalkedField, value: unknown, onChange: (v: unknown) => void, pathSuffix?: string) => ReactNode, path: string, instanceWidgets?: WidgetMap, contextWidgets?: WidgetMap, depth?: number): ReactNode;
|
|
228
221
|
/**
|
|
229
222
|
* Infer the schema's output type for SchemaField path inference.
|
|
230
223
|
*/
|
|
@@ -286,4 +279,4 @@ declare function SchemaField<T = unknown, SchemaRef extends string | undefined =
|
|
|
286
279
|
onValidationError
|
|
287
280
|
}: SchemaFieldProps<T, SchemaRef, P>): ReactNode;
|
|
288
281
|
//#endregion
|
|
289
|
-
export { SchemaProvider as a, registerWidget as c, SchemaFieldProps as i,
|
|
282
|
+
export { SchemaProvider as a, registerWidget as c, SchemaFieldProps as i, sanitisePrefix as l, SchemaComponentProps as n, __clearGlobalWidgets as o, SchemaField as r, joinPath as s, SchemaComponent as t };
|
package/dist/core/idPath.d.mts
CHANGED
|
@@ -80,5 +80,32 @@ declare function panelIdFor(path: string): string;
|
|
|
80
80
|
* `id` across all renderers.
|
|
81
81
|
*/
|
|
82
82
|
declare function tabIdFor(path: string, index: number): string;
|
|
83
|
+
/**
|
|
84
|
+
* Append a child path suffix to a parent path. When the suffix is omitted
|
|
85
|
+
* (e.g. transparent wrappers like union options), the parent path is
|
|
86
|
+
* returned unchanged so the child inherits the parent's id.
|
|
87
|
+
*
|
|
88
|
+
* Bracketed array indices like `[0]` append directly so `tags` + `[0]`
|
|
89
|
+
* becomes `tags[0]` rather than `tags.[0]` — matching the canonical form
|
|
90
|
+
* used by `core/fieldPath.ts` `resolvePath`, which already parses bracket
|
|
91
|
+
* notation when navigating WalkedField trees.
|
|
92
|
+
*
|
|
93
|
+
* This is the single authoritative implementation. The copies in
|
|
94
|
+
* `react/SchemaComponent.tsx`, `html/a11y.ts`, `solid/SchemaComponent.tsx`,
|
|
95
|
+
* and `vue/idPrefix.ts` are kept for backward compatibility but delegate
|
|
96
|
+
* here.
|
|
97
|
+
*/
|
|
98
|
+
declare function joinPath(parent: string, suffix: string | undefined): string;
|
|
99
|
+
/**
|
|
100
|
+
* Normalise a framework `useId()`-style value into a DOM-id-safe prefix.
|
|
101
|
+
* Framework `useId` implementations often return values containing `:` or
|
|
102
|
+
* other characters that are invalid in CSS selectors. This function replaces
|
|
103
|
+
* any run of non-alphanumeric characters with a single hyphen and trims
|
|
104
|
+
* leading/trailing hyphens.
|
|
105
|
+
*
|
|
106
|
+
* Throws when the sanitised result is empty so callers receive an actionable
|
|
107
|
+
* error rather than a silent empty-string id.
|
|
108
|
+
*/
|
|
109
|
+
declare function sanitisePrefix(value: string): string;
|
|
83
110
|
//#endregion
|
|
84
|
-
export { fieldDomId, hintIdFor, normaliseIdSegment, panelIdFor, tabIdFor };
|
|
111
|
+
export { fieldDomId, hintIdFor, joinPath, normaliseIdSegment, panelIdFor, sanitisePrefix, tabIdFor };
|
package/dist/core/idPath.mjs
CHANGED
|
@@ -134,5 +134,41 @@ function panelIdFor(path) {
|
|
|
134
134
|
function tabIdFor(path, index) {
|
|
135
135
|
return `${fieldDomId(path)}-tab-${String(index)}`;
|
|
136
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Append a child path suffix to a parent path. When the suffix is omitted
|
|
139
|
+
* (e.g. transparent wrappers like union options), the parent path is
|
|
140
|
+
* returned unchanged so the child inherits the parent's id.
|
|
141
|
+
*
|
|
142
|
+
* Bracketed array indices like `[0]` append directly so `tags` + `[0]`
|
|
143
|
+
* becomes `tags[0]` rather than `tags.[0]` — matching the canonical form
|
|
144
|
+
* used by `core/fieldPath.ts` `resolvePath`, which already parses bracket
|
|
145
|
+
* notation when navigating WalkedField trees.
|
|
146
|
+
*
|
|
147
|
+
* This is the single authoritative implementation. The copies in
|
|
148
|
+
* `react/SchemaComponent.tsx`, `html/a11y.ts`, `solid/SchemaComponent.tsx`,
|
|
149
|
+
* and `vue/idPrefix.ts` are kept for backward compatibility but delegate
|
|
150
|
+
* here.
|
|
151
|
+
*/
|
|
152
|
+
function joinPath(parent, suffix) {
|
|
153
|
+
if (suffix === void 0 || suffix.length === 0) return parent;
|
|
154
|
+
if (parent.length === 0) return suffix;
|
|
155
|
+
if (suffix.startsWith("[")) return `${parent}${suffix}`;
|
|
156
|
+
return `${parent}.${suffix}`;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Normalise a framework `useId()`-style value into a DOM-id-safe prefix.
|
|
160
|
+
* Framework `useId` implementations often return values containing `:` or
|
|
161
|
+
* other characters that are invalid in CSS selectors. This function replaces
|
|
162
|
+
* any run of non-alphanumeric characters with a single hyphen and trims
|
|
163
|
+
* leading/trailing hyphens.
|
|
164
|
+
*
|
|
165
|
+
* Throws when the sanitised result is empty so callers receive an actionable
|
|
166
|
+
* error rather than a silent empty-string id.
|
|
167
|
+
*/
|
|
168
|
+
function sanitisePrefix(value) {
|
|
169
|
+
const sanitised = value.replace(/[^a-zA-Z0-9_]+/g, "-").replace(/^-+|-+$/g, "");
|
|
170
|
+
if (sanitised.length === 0) throw new Error(`Cannot derive a DOM-safe id prefix from "${value}". Pass an explicit idPrefix prop.`);
|
|
171
|
+
return sanitised;
|
|
172
|
+
}
|
|
137
173
|
//#endregion
|
|
138
|
-
export { fieldDomId, hintIdFor, normaliseIdSegment, panelIdFor, tabIdFor };
|
|
174
|
+
export { fieldDomId, hintIdFor, joinPath, normaliseIdSegment, panelIdFor, sanitisePrefix, tabIdFor };
|
|
@@ -2,13 +2,14 @@ import { isObject, toRecordOrUndefined } from "../core/guards.mjs";
|
|
|
2
2
|
import { emitDiagnostic } from "../core/diagnostics.mjs";
|
|
3
3
|
import { isSafeHyperlink } from "../core/uri.mjs";
|
|
4
4
|
import { extractRootMetaFromJson } from "../core/adapter.mjs";
|
|
5
|
+
import { joinPath, sanitisePrefix } from "../core/idPath.mjs";
|
|
5
6
|
import { walk } from "../core/walker.mjs";
|
|
6
7
|
import { ApiCallbacks } from "./ApiCallbacks.mjs";
|
|
7
8
|
import { ApiLinks } from "./ApiLinks.mjs";
|
|
8
9
|
import { ApiResponseHeaders } from "./ApiResponseHeaders.mjs";
|
|
9
10
|
import { ApiSecurity } from "./ApiSecurity.mjs";
|
|
10
11
|
import { extractExternalDocs, extractLinks, extractSecurityRequirements, extractSecuritySchemes, extractXmlInfo, listCallbacks, listWebhooks } from "./parser.mjs";
|
|
11
|
-
import {
|
|
12
|
+
import { renderField } from "../react/renderField.mjs";
|
|
12
13
|
import { getParsed, resolveOperation, resolveParameters, resolveRequestBody, resolveResponse, toDoc } from "./resolve.mjs";
|
|
13
14
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
14
15
|
import { useId } from "react";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { a as InferredValue, i as InferredOutputValue, r as InferredInputValue, t as InferFields } from "../inferValue-eAnh50EM.mjs";
|
|
2
|
-
import { a as SchemaProvider, c as registerWidget, i as SchemaFieldProps, n as SchemaComponentProps, r as SchemaField, t as SchemaComponent } from "../SchemaComponent-
|
|
2
|
+
import { a as SchemaProvider, c as registerWidget, i as SchemaFieldProps, n as SchemaComponentProps, r as SchemaField, t as SchemaComponent } from "../SchemaComponent-BWl1psB0.mjs";
|
|
3
3
|
export { type InferFields, type InferredInputValue, type InferredOutputValue, type InferredValue, SchemaComponent, type SchemaComponentProps, SchemaField, type SchemaFieldProps, SchemaProvider, registerWidget };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { a as InferredValue, i as InferredOutputValue, r as InferredInputValue, t as InferFields } from "../inferValue-eAnh50EM.mjs";
|
|
2
|
-
import { a as SchemaProvider, c as registerWidget, i as SchemaFieldProps, l as
|
|
3
|
-
export { InferFields, InferredInputValue, InferredOutputValue, InferredValue, SchemaComponent, SchemaComponentProps, SchemaField, SchemaFieldProps, SchemaProvider, __clearGlobalWidgets, joinPath, registerWidget,
|
|
2
|
+
import { a as SchemaProvider, c as registerWidget, i as SchemaFieldProps, l as sanitisePrefix, n as SchemaComponentProps, o as __clearGlobalWidgets, r as SchemaField, s as joinPath, t as SchemaComponent } from "../SchemaComponent-BWl1psB0.mjs";
|
|
3
|
+
export { InferFields, InferredInputValue, InferredOutputValue, InferredValue, SchemaComponent, SchemaComponentProps, SchemaField, SchemaFieldProps, SchemaProvider, __clearGlobalWidgets, joinPath, registerWidget, sanitisePrefix };
|
|
@@ -3,13 +3,11 @@ import { isObject, toRecordOrUndefined } from "../core/guards.mjs";
|
|
|
3
3
|
import { SchemaFieldError, SchemaNormalisationError } from "../core/errors.mjs";
|
|
4
4
|
import { isCodecSchema, normaliseSchema } from "../core/adapter.mjs";
|
|
5
5
|
import { resolvePath, resolveValue, setNestedValue } from "../core/fieldPath.mjs";
|
|
6
|
-
import { dispatchRenderField } from "../core/renderField.mjs";
|
|
7
|
-
import { buildRenderProps, getRenderFunction, mergeResolvers } from "../core/renderer.mjs";
|
|
8
6
|
import { walk } from "../core/walker.mjs";
|
|
9
|
-
import {
|
|
7
|
+
import { globalWidgets, renderField } from "./renderField.mjs";
|
|
10
8
|
import { z } from "zod";
|
|
11
|
-
import { jsx
|
|
12
|
-
import { createContext,
|
|
9
|
+
import { jsx } from "react/jsx-runtime";
|
|
10
|
+
import { createContext, useCallback, useContext, useId, useMemo } from "react";
|
|
13
11
|
//#region src/react/SchemaComponent.tsx
|
|
14
12
|
/**
|
|
15
13
|
* <SchemaComponent> — renders UI from Zod, JSON Schema, or OpenAPI schemas.
|
|
@@ -56,8 +54,6 @@ function SchemaProvider({ resolver, widgets, children }) {
|
|
|
56
54
|
})
|
|
57
55
|
});
|
|
58
56
|
}
|
|
59
|
-
/** Global widget registry — app-wide defaults. */
|
|
60
|
-
const globalWidgets = /* @__PURE__ */ new Map();
|
|
61
57
|
/**
|
|
62
58
|
* Register a widget globally. The widget is resolved when a schema field
|
|
63
59
|
* has `.meta({ component: name })`.
|
|
@@ -276,57 +272,6 @@ function runValidation(zodSchema, jsonSchema, value, io, onDiagnostic) {
|
|
|
276
272
|
}
|
|
277
273
|
}
|
|
278
274
|
/**
|
|
279
|
-
* Render a single walked field through the resolved widget /
|
|
280
|
-
* resolver / headless pipeline. Used internally by
|
|
281
|
-
* {@link SchemaComponent} and {@link SchemaField}, exported so other
|
|
282
|
-
* React-side components (e.g. the OpenAPI renderers) can dispatch
|
|
283
|
-
* into the same fallback chain.
|
|
284
|
-
*
|
|
285
|
-
* Thin React-flavoured wrapper around the framework-agnostic
|
|
286
|
-
* `dispatchRenderField` (from `core/renderField`): it constructs a
|
|
287
|
-
* React-shaped `DispatchConfig` (widget lookup against the
|
|
288
|
-
* instance → context → global chain, recursion sentinel as a React
|
|
289
|
-
* `<fieldset>`, fallback as a `<span>`-wrapped value) and forwards
|
|
290
|
-
* the call.
|
|
291
|
-
*/
|
|
292
|
-
function renderField(tree, value, onChange, userResolver, renderChild, path, instanceWidgets, contextWidgets, depth = 0) {
|
|
293
|
-
if (path.length === 0) throw new Error("renderField requires a non-empty path. Pass the root path (derived from `idPrefix` or `useId()`) for the root field, and use renderChild's pathSuffix to derive child paths.");
|
|
294
|
-
return dispatchRenderField({
|
|
295
|
-
tree,
|
|
296
|
-
value,
|
|
297
|
-
path,
|
|
298
|
-
depth,
|
|
299
|
-
resolver: userResolver !== void 0 ? mergeResolvers(userResolver, headlessResolver) : headlessResolver,
|
|
300
|
-
config: {
|
|
301
|
-
buildProps: (fieldTree, fieldPath) => buildRenderProps(fieldTree, value, onChange, renderChild, fieldPath),
|
|
302
|
-
lookupRenderFn: (type, mergedResolver) => getRenderFunction(type, mergedResolver),
|
|
303
|
-
lookupWidget: (name) => instanceWidgets?.get(name) ?? contextWidgets?.get(name) ?? globalWidgets.get(name),
|
|
304
|
-
recursionSentinel: (fieldTree) => {
|
|
305
|
-
return /* @__PURE__ */ jsx("fieldset", { children: /* @__PURE__ */ jsxs("em", { children: [
|
|
306
|
-
"↻ ",
|
|
307
|
-
typeof fieldTree.meta.description === "string" ? fieldTree.meta.description : "schema",
|
|
308
|
-
" (recursive)"
|
|
309
|
-
] }) });
|
|
310
|
-
},
|
|
311
|
-
fallback: (_fieldTree, fieldValue) => {
|
|
312
|
-
if (fieldValue === void 0 || fieldValue === null) return /* @__PURE__ */ jsx("span", { children: "—" });
|
|
313
|
-
return /* @__PURE__ */ jsx("span", { children: typeof fieldValue === "string" ? fieldValue : JSON.stringify(fieldValue) });
|
|
314
|
-
},
|
|
315
|
-
coerceResult: (result, step) => {
|
|
316
|
-
if (step === "widget") {
|
|
317
|
-
if (result === void 0 || result === null) return void 0;
|
|
318
|
-
if (isValidElement(result)) return result;
|
|
319
|
-
if (typeof result === "string" || typeof result === "number") return result;
|
|
320
|
-
return null;
|
|
321
|
-
}
|
|
322
|
-
if (result === void 0 || result === null) return null;
|
|
323
|
-
if (isValidElement(result)) return result;
|
|
324
|
-
if (typeof result === "string" || typeof result === "number") return result;
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
275
|
* Render a single field from a schema by dot-separated `path`.
|
|
331
276
|
*
|
|
332
277
|
* Walks the full schema tree and resolves the field at the supplied
|
|
@@ -425,4 +370,4 @@ function isCallable(value) {
|
|
|
425
370
|
return typeof value === "function";
|
|
426
371
|
}
|
|
427
372
|
//#endregion
|
|
428
|
-
export { SchemaComponent, SchemaField, SchemaProvider, __clearGlobalWidgets, joinPath, registerWidget,
|
|
373
|
+
export { SchemaComponent, SchemaField, SchemaProvider, __clearGlobalWidgets, joinPath, registerWidget, sanitisePrefix };
|
|
@@ -74,13 +74,11 @@ function renderString(props) {
|
|
|
74
74
|
if (format === "email" && isSafeMailtoAddress(strValue)) return /* @__PURE__ */ jsx("a", {
|
|
75
75
|
href: `mailto:${strValue}`,
|
|
76
76
|
id,
|
|
77
|
-
"aria-readonly": "true",
|
|
78
77
|
children: strValue
|
|
79
78
|
});
|
|
80
79
|
if ((format === "uri" || format === "url") && isSafeHyperlink(strValue)) return /* @__PURE__ */ jsx("a", {
|
|
81
80
|
href: strValue,
|
|
82
81
|
id,
|
|
83
|
-
"aria-readonly": "true",
|
|
84
82
|
children: strValue
|
|
85
83
|
});
|
|
86
84
|
if (format === "date") return /* @__PURE__ */ jsx("span", {
|
|
@@ -573,6 +571,7 @@ function DiscriminatedUnionTabs({ options, optionLabels, activeIndex, path, disc
|
|
|
573
571
|
role: "tablist",
|
|
574
572
|
"aria-label": "Select variant",
|
|
575
573
|
"aria-orientation": "horizontal",
|
|
574
|
+
tabIndex: -1,
|
|
576
575
|
style: {
|
|
577
576
|
display: "flex",
|
|
578
577
|
gap: "0.25rem",
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { j as WalkedField } from "../types-BBQaEPfE.mjs";
|
|
2
|
+
import { d as WidgetMap, i as ComponentResolver, u as RenderProps } from "../renderer-ab9E52Bp.mjs";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
|
|
5
|
+
//#region src/react/renderField.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Global widget registry — app-wide defaults.
|
|
8
|
+
*
|
|
9
|
+
* Exported so `react/SchemaComponent.tsx` can define `registerWidget` and
|
|
10
|
+
* `__clearGlobalWidgets` as direct exports (not re-exports, which the
|
|
11
|
+
* `custom/no-re-exports` rule bans in non-index files) while sharing the
|
|
12
|
+
* same Map with `renderField`.
|
|
13
|
+
*
|
|
14
|
+
* @internal — callers outside this module should use `registerWidget`.
|
|
15
|
+
*/
|
|
16
|
+
declare const globalWidgets: Map<string, (props: RenderProps) => unknown>;
|
|
17
|
+
/**
|
|
18
|
+
* Render a single walked field through the resolved widget /
|
|
19
|
+
* resolver / headless pipeline. Used internally by
|
|
20
|
+
* {@link SchemaComponent} and {@link SchemaField}, exported so other
|
|
21
|
+
* React-side components (e.g. the OpenAPI renderers) can dispatch
|
|
22
|
+
* into the same fallback chain.
|
|
23
|
+
*
|
|
24
|
+
* Thin React-flavoured wrapper around the framework-agnostic
|
|
25
|
+
* `dispatchRenderField` (from `core/renderField`): it constructs a
|
|
26
|
+
* React-shaped `DispatchConfig` (widget lookup against the
|
|
27
|
+
* instance → context → global chain, recursion sentinel as a React
|
|
28
|
+
* `<fieldset>`, fallback as a `<span>`-wrapped value) and forwards
|
|
29
|
+
* the call.
|
|
30
|
+
*/
|
|
31
|
+
declare function renderField(tree: WalkedField, value: unknown, onChange: (v: unknown) => void, userResolver: ComponentResolver | undefined, renderChild: (tree: WalkedField, value: unknown, onChange: (v: unknown) => void, pathSuffix?: string) => ReactNode, path: string, instanceWidgets?: WidgetMap, contextWidgets?: WidgetMap, depth?: number): ReactNode;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { globalWidgets, renderField };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { dispatchRenderField } from "../core/renderField.mjs";
|
|
2
|
+
import { buildRenderProps, getRenderFunction, mergeResolvers } from "../core/renderer.mjs";
|
|
3
|
+
import { headlessResolver } from "./headless.mjs";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { isValidElement } from "react";
|
|
6
|
+
//#region src/react/renderField.tsx
|
|
7
|
+
/**
|
|
8
|
+
* React-side `renderField` dispatcher and global widget registry.
|
|
9
|
+
*
|
|
10
|
+
* Extracted from `react/SchemaComponent.tsx` so that `openapi/components.tsx`
|
|
11
|
+
* can import the dispatcher without depending on the full SchemaComponent
|
|
12
|
+
* module (which includes React context, hooks, and the component tree). The
|
|
13
|
+
* public API at `react/SchemaComponent` re-exports everything here so
|
|
14
|
+
* consumers importing via the historic path continue to work unchanged.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Global widget registry — app-wide defaults.
|
|
18
|
+
*
|
|
19
|
+
* Exported so `react/SchemaComponent.tsx` can define `registerWidget` and
|
|
20
|
+
* `__clearGlobalWidgets` as direct exports (not re-exports, which the
|
|
21
|
+
* `custom/no-re-exports` rule bans in non-index files) while sharing the
|
|
22
|
+
* same Map with `renderField`.
|
|
23
|
+
*
|
|
24
|
+
* @internal — callers outside this module should use `registerWidget`.
|
|
25
|
+
*/
|
|
26
|
+
const globalWidgets = /* @__PURE__ */ new Map();
|
|
27
|
+
/**
|
|
28
|
+
* Render a single walked field through the resolved widget /
|
|
29
|
+
* resolver / headless pipeline. Used internally by
|
|
30
|
+
* {@link SchemaComponent} and {@link SchemaField}, exported so other
|
|
31
|
+
* React-side components (e.g. the OpenAPI renderers) can dispatch
|
|
32
|
+
* into the same fallback chain.
|
|
33
|
+
*
|
|
34
|
+
* Thin React-flavoured wrapper around the framework-agnostic
|
|
35
|
+
* `dispatchRenderField` (from `core/renderField`): it constructs a
|
|
36
|
+
* React-shaped `DispatchConfig` (widget lookup against the
|
|
37
|
+
* instance → context → global chain, recursion sentinel as a React
|
|
38
|
+
* `<fieldset>`, fallback as a `<span>`-wrapped value) and forwards
|
|
39
|
+
* the call.
|
|
40
|
+
*/
|
|
41
|
+
function renderField(tree, value, onChange, userResolver, renderChild, path, instanceWidgets, contextWidgets, depth = 0) {
|
|
42
|
+
if (path.length === 0) throw new Error("renderField requires a non-empty path. Pass the root path (derived from `idPrefix` or `useId()`) for the root field, and use renderChild's pathSuffix to derive child paths.");
|
|
43
|
+
return dispatchRenderField({
|
|
44
|
+
tree,
|
|
45
|
+
value,
|
|
46
|
+
path,
|
|
47
|
+
depth,
|
|
48
|
+
resolver: userResolver !== void 0 ? mergeResolvers(userResolver, headlessResolver) : headlessResolver,
|
|
49
|
+
config: {
|
|
50
|
+
buildProps: (fieldTree, fieldPath) => buildRenderProps(fieldTree, value, onChange, renderChild, fieldPath),
|
|
51
|
+
lookupRenderFn: (type, mergedResolver) => getRenderFunction(type, mergedResolver),
|
|
52
|
+
lookupWidget: (name) => instanceWidgets?.get(name) ?? contextWidgets?.get(name) ?? globalWidgets.get(name),
|
|
53
|
+
recursionSentinel: (fieldTree) => {
|
|
54
|
+
return /* @__PURE__ */ jsx("fieldset", { children: /* @__PURE__ */ jsxs("em", { children: [
|
|
55
|
+
"↻ ",
|
|
56
|
+
typeof fieldTree.meta.description === "string" ? fieldTree.meta.description : "schema",
|
|
57
|
+
" (recursive)"
|
|
58
|
+
] }) });
|
|
59
|
+
},
|
|
60
|
+
fallback: (_fieldTree, fieldValue) => {
|
|
61
|
+
if (fieldValue === void 0 || fieldValue === null) return /* @__PURE__ */ jsx("span", { children: "—" });
|
|
62
|
+
return /* @__PURE__ */ jsx("span", { children: typeof fieldValue === "string" ? fieldValue : JSON.stringify(fieldValue) });
|
|
63
|
+
},
|
|
64
|
+
coerceResult: (result, step) => {
|
|
65
|
+
if (step === "widget") {
|
|
66
|
+
if (result === void 0 || result === null) return void 0;
|
|
67
|
+
if (isValidElement(result)) return result;
|
|
68
|
+
if (typeof result === "string" || typeof result === "number") return result;
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
if (result === void 0 || result === null) return null;
|
|
72
|
+
if (isValidElement(result)) return result;
|
|
73
|
+
if (typeof result === "string" || typeof result === "number") return result;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
79
|
+
export { globalWidgets, renderField };
|
package/dist/solid/renderers.mjs
CHANGED
|
@@ -80,13 +80,11 @@ function renderString(props) {
|
|
|
80
80
|
if (format === "email" && isSafeMailtoAddress(strValue)) return /* @__PURE__ */ jsx("a", {
|
|
81
81
|
href: `mailto:${strValue}`,
|
|
82
82
|
id,
|
|
83
|
-
"aria-readonly": "true",
|
|
84
83
|
children: strValue
|
|
85
84
|
});
|
|
86
85
|
if ((format === "uri" || format === "url") && isSafeHyperlink(strValue)) return /* @__PURE__ */ jsx("a", {
|
|
87
86
|
href: strValue,
|
|
88
87
|
id,
|
|
89
|
-
"aria-readonly": "true",
|
|
90
88
|
children: strValue
|
|
91
89
|
});
|
|
92
90
|
if (format === "date") return /* @__PURE__ */ jsx("span", {
|
|
@@ -608,6 +606,7 @@ function DiscriminatedUnionTabs(props) {
|
|
|
608
606
|
role: "tablist",
|
|
609
607
|
"aria-label": "Select variant",
|
|
610
608
|
"aria-orientation": "horizontal",
|
|
609
|
+
tabIndex: -1,
|
|
611
610
|
style: {
|
|
612
611
|
display: "flex",
|
|
613
612
|
gap: "0.25rem",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "schema-components",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.0",
|
|
4
4
|
"description": "React components that render UI from Zod schemas, JSON Schema, and OpenAPI documents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -73,7 +73,6 @@
|
|
|
73
73
|
"_build": "tsdown && cp src/html/styles.css dist/html/styles.css",
|
|
74
74
|
"_typedoc": "typedoc",
|
|
75
75
|
"_api-urls": "node scripts/build-api-urls.mjs",
|
|
76
|
-
"_readme": "node scripts/build-readme-inventory.mjs",
|
|
77
76
|
"typecheck": "turbo run _typecheck",
|
|
78
77
|
"lint": "turbo run _lint",
|
|
79
78
|
"lint:fix": "turbo run _lint:fix",
|
|
@@ -87,8 +86,7 @@
|
|
|
87
86
|
"validate": "turbo run _validate",
|
|
88
87
|
"build": "turbo run _build",
|
|
89
88
|
"typedoc": "turbo run _typedoc",
|
|
90
|
-
"api-urls": "turbo run _api-urls"
|
|
91
|
-
"readme": "turbo run _readme"
|
|
89
|
+
"api-urls": "turbo run _api-urls"
|
|
92
90
|
},
|
|
93
91
|
"keywords": [
|
|
94
92
|
"react",
|