schema-components 1.29.0 → 2.0.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/README.md +38 -16
- package/dist/core/adapter.d.mts +213 -3
- package/dist/core/adapter.mjs +1 -1
- package/dist/core/constraintHint.d.mts +15 -0
- package/dist/core/constraintHint.mjs +24 -0
- package/dist/core/constraints.d.mts +2 -2
- package/dist/core/constraints.mjs +1 -1
- package/dist/core/diagnostics.d.mts +1 -1
- package/dist/core/errors.d.mts +1 -1
- package/dist/core/fieldOrder.d.mts +1 -1
- package/dist/core/formats.d.mts +1 -1
- package/dist/core/idPath.d.mts +35 -5
- package/dist/core/idPath.mjs +79 -7
- package/dist/core/inferValue.d.mts +2 -0
- package/dist/core/inferValue.mjs +1 -0
- package/dist/core/limits.d.mts +1 -1
- package/dist/core/limits.mjs +5 -0
- package/dist/core/merge.d.mts +12 -1
- package/dist/core/merge.mjs +66 -3
- package/dist/core/normalise.d.mts +1 -1
- package/dist/core/normalise.mjs +1 -1
- package/dist/core/openapi30.mjs +1 -1
- package/dist/core/ref.d.mts +1 -1
- package/dist/core/refChain.d.mts +3 -4
- package/dist/core/refChain.mjs +2 -3
- package/dist/core/renderer.d.mts +199 -2
- package/dist/core/swagger2.d.mts +1 -1
- package/dist/core/swagger2.mjs +1 -1
- package/dist/core/typeInference.d.mts +3 -3
- package/dist/core/types.d.mts +1 -1
- package/dist/core/unionMatch.d.mts +1 -1
- package/dist/core/uri.d.mts +12 -4
- package/dist/core/uri.mjs +30 -4
- package/dist/core/walkBuilders.d.mts +18 -6
- package/dist/core/walkBuilders.mjs +3 -1
- package/dist/core/walker.d.mts +1 -1
- package/dist/core/walker.mjs +5 -0
- package/dist/{diagnostics-ByEzkjrA.d.mts → diagnostics-BTrm3O6J.d.mts} +1 -1
- package/dist/{errors-D8JndRwI.d.mts → errors-Dki7tji4.d.mts} +1 -1
- package/dist/html/a11y.d.mts +3 -7
- package/dist/html/a11y.mjs +1 -16
- package/dist/html/renderToHtml.d.mts +22 -9
- package/dist/html/renderToHtml.mjs +2 -1
- package/dist/html/renderToHtmlStream.d.mts +24 -11
- package/dist/html/renderToHtmlStream.mjs +2 -1
- package/dist/html/renderers.d.mts +2 -33
- package/dist/html/renderers.mjs +39 -91
- package/dist/html/streamRenderers.d.mts +3 -3
- package/dist/html/streamRenderers.mjs +13 -8
- package/dist/inferValue-PPXWJpbN.d.mts +77 -0
- package/dist/{limits-DswmqWuy.d.mts → limits-x4OiyJxh.d.mts} +5 -0
- package/dist/{normalise-Db1xaxgx.mjs → normalise-DB-Xtjmn.mjs} +43 -2
- package/dist/openapi/ApiCallbacks.d.mts +1 -1
- package/dist/openapi/ApiLinks.d.mts +1 -1
- package/dist/openapi/ApiResponseHeaders.d.mts +1 -1
- package/dist/openapi/ApiSecurity.d.mts +1 -1
- package/dist/openapi/ApiSecurity.mjs +21 -8
- package/dist/openapi/bundle.d.mts +31 -0
- package/dist/openapi/components.d.mts +41 -10
- package/dist/openapi/components.mjs +19 -13
- package/dist/openapi/parser.d.mts +13 -13
- package/dist/openapi/parser.mjs +12 -12
- package/dist/openapi/resolve.d.mts +38 -49
- package/dist/openapi/resolve.mjs +62 -56
- package/dist/react/SchemaComponent.d.mts +19 -95
- package/dist/react/SchemaComponent.mjs +12 -1
- package/dist/react/SchemaView.d.mts +11 -7
- package/dist/react/SchemaView.mjs +3 -1
- package/dist/react/a11y.d.mts +74 -7
- package/dist/react/a11y.mjs +67 -6
- package/dist/react/fieldPath.d.mts +16 -1
- package/dist/react/fieldPath.mjs +25 -1
- package/dist/react/fieldShell.d.mts +49 -0
- package/dist/react/fieldShell.mjs +37 -0
- package/dist/react/headless.d.mts +1 -1
- package/dist/react/headlessRenderers.d.mts +2 -2
- package/dist/react/headlessRenderers.mjs +123 -54
- package/dist/{ref-CPh8rKQ3.d.mts → ref-DdsbekXX.d.mts} +33 -1
- package/dist/themes/mantine.d.mts +36 -20
- package/dist/themes/mantine.mjs +179 -150
- package/dist/themes/mui.d.mts +47 -21
- package/dist/themes/mui.mjs +259 -222
- package/dist/themes/radix.d.mts +38 -23
- package/dist/themes/radix.mjs +208 -180
- package/dist/themes/shadcn.d.mts +6 -3
- package/dist/themes/shadcn.mjs +93 -93
- package/dist/{types-C2Ay1FEh.d.mts → types-BrYbjC7_.d.mts} +7 -0
- package/package.json +4 -1
- package/dist/adapter-DcWi4XXn.d.mts +0 -223
- package/dist/renderer-OaOz-n6-.d.mts +0 -185
package/dist/react/a11y.d.mts
CHANGED
|
@@ -1,21 +1,88 @@
|
|
|
1
|
-
import { j as WalkedField } from "../types-
|
|
1
|
+
import { j as WalkedField } from "../types-BrYbjC7_.mjs";
|
|
2
|
+
import { AllConstraints } from "../core/renderer.mjs";
|
|
2
3
|
|
|
3
4
|
//#region src/react/a11y.d.ts
|
|
4
5
|
/**
|
|
5
6
|
* Build the ARIA attribute bundle for a renderer.
|
|
6
7
|
*
|
|
7
8
|
* - `aria-required="true"` whenever the field is non-optional.
|
|
9
|
+
* - `aria-describedby=<hint-id>` whenever a constraint hint applies.
|
|
8
10
|
* - `aria-label=<description>` when a non-empty description is supplied.
|
|
9
11
|
*
|
|
10
12
|
* Returns a plain `Record<string, string>` (rather than a typed
|
|
11
13
|
* attribute interface) so callers can spread the result into any JSX
|
|
12
14
|
* element type without per-element TypeScript widening.
|
|
13
15
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
16
|
+
* `inputId` and `constraints` together control whether
|
|
17
|
+
* `aria-describedby` is emitted. Pass `undefined` for `constraints`
|
|
18
|
+
* when the renderer never emits a constraint hint (e.g. boolean
|
|
19
|
+
* checkboxes); the helper then skips the attribute entirely. When the
|
|
20
|
+
* caller does emit a hint via `buildHint(...)`, the `aria-describedby`
|
|
21
|
+
* id matches `hintIdFor(inputId)` so the wire-up holds end-to-end.
|
|
18
22
|
*/
|
|
19
|
-
declare function buildAriaAttrs(tree: WalkedField, description?: unknown): Record<string, string>;
|
|
23
|
+
declare function buildAriaAttrs(tree: WalkedField, description?: unknown, inputId?: string, constraints?: AllConstraints): Record<string, string>;
|
|
24
|
+
/**
|
|
25
|
+
* Description for a constraint hint emitted alongside an input.
|
|
26
|
+
*
|
|
27
|
+
* Returned by {@link constraintHint} when the field carries one or
|
|
28
|
+
* more constraint keywords the user should be told about (min/max,
|
|
29
|
+
* pattern, item count, …). Theme adapters render this as a `<small>`
|
|
30
|
+
* element wired to the input via `aria-describedby`.
|
|
31
|
+
*/
|
|
32
|
+
interface Hint {
|
|
33
|
+
/** DOM id matching {@link hintIdFor}(inputId) on the host input. */
|
|
34
|
+
readonly id: string;
|
|
35
|
+
/** Human-readable hint text. */
|
|
36
|
+
readonly text: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Derive the constraint-hint descriptor for a field at `inputId`. Returns
|
|
40
|
+
* `undefined` when the field has no constraint worth announcing — callers
|
|
41
|
+
* skip rendering the `<small>` element entirely rather than emitting an
|
|
42
|
+
* empty node.
|
|
43
|
+
*
|
|
44
|
+
* Shares its text builder with `html/a11y.ts` so the two renderers
|
|
45
|
+
* always announce the same constraint copy for the same schema field.
|
|
46
|
+
*/
|
|
47
|
+
declare function constraintHint(inputId: string, constraints: AllConstraints): Hint | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* True when the supplied field is non-optional and therefore deserves
|
|
50
|
+
* a visual required indicator alongside its label.
|
|
51
|
+
*
|
|
52
|
+
* Exposed as a predicate rather than a JSX element so theme adapters
|
|
53
|
+
* can render the indicator in whatever element type matches their
|
|
54
|
+
* design language (`<span>`, `<sup>`, an icon component, …).
|
|
55
|
+
*/
|
|
56
|
+
declare function isFieldRequired(tree: WalkedField): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Narrow `meta.description` (typed `unknown`) to a string value safe to
|
|
59
|
+
* pass into JSX `aria-label`. Returns `undefined` for non-string or
|
|
60
|
+
* empty-string descriptions so React drops the attribute rather than
|
|
61
|
+
* stringifying e.g. `{}` to `"[object Object]"`.
|
|
62
|
+
*/
|
|
63
|
+
declare function ariaLabel(description: unknown): string | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Structured constraint-hint data for the React renderers.
|
|
66
|
+
*
|
|
67
|
+
* The HTML pipeline emits an inline `<small class="sc-hint">` element
|
|
68
|
+
* next to each input and references it through `aria-describedby`. The
|
|
69
|
+
* React pipeline mirrors that contract: the input takes the
|
|
70
|
+
* `ariaDescribedBy` id, the renderer emits a sibling `<small id={...}>`
|
|
71
|
+
* whose text is `hint`. Returns `undefined` when the field has no
|
|
72
|
+
* advertise-able constraints (`constraintHint` returns `undefined`) so
|
|
73
|
+
* callers can skip both the attribute and the element cleanly.
|
|
74
|
+
*/
|
|
75
|
+
interface HintInfo {
|
|
76
|
+
readonly id: string;
|
|
77
|
+
readonly hint: string;
|
|
78
|
+
readonly ariaDescribedBy: string;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Build {@link HintInfo} for a field at `inputId` given its declared
|
|
82
|
+
* constraints. Returns `undefined` when no constraint message would be
|
|
83
|
+
* produced — the React renderers then skip emitting the hint element
|
|
84
|
+
* entirely so consumers don't see an empty `<small>`.
|
|
85
|
+
*/
|
|
86
|
+
declare function buildHintInfo(inputId: string, constraints: AllConstraints): HintInfo | undefined;
|
|
20
87
|
//#endregion
|
|
21
|
-
export { buildAriaAttrs };
|
|
88
|
+
export { Hint, HintInfo, ariaLabel, buildAriaAttrs, buildHintInfo, constraintHint, isFieldRequired };
|
package/dist/react/a11y.mjs
CHANGED
|
@@ -1,24 +1,85 @@
|
|
|
1
|
+
import { constraintHint as constraintHint$1 } from "../core/constraintHint.mjs";
|
|
2
|
+
import { hintIdFor } from "../core/idPath.mjs";
|
|
1
3
|
//#region src/react/a11y.ts
|
|
2
4
|
/**
|
|
3
5
|
* Build the ARIA attribute bundle for a renderer.
|
|
4
6
|
*
|
|
5
7
|
* - `aria-required="true"` whenever the field is non-optional.
|
|
8
|
+
* - `aria-describedby=<hint-id>` whenever a constraint hint applies.
|
|
6
9
|
* - `aria-label=<description>` when a non-empty description is supplied.
|
|
7
10
|
*
|
|
8
11
|
* Returns a plain `Record<string, string>` (rather than a typed
|
|
9
12
|
* attribute interface) so callers can spread the result into any JSX
|
|
10
13
|
* element type without per-element TypeScript widening.
|
|
11
14
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
15
|
+
* `inputId` and `constraints` together control whether
|
|
16
|
+
* `aria-describedby` is emitted. Pass `undefined` for `constraints`
|
|
17
|
+
* when the renderer never emits a constraint hint (e.g. boolean
|
|
18
|
+
* checkboxes); the helper then skips the attribute entirely. When the
|
|
19
|
+
* caller does emit a hint via `buildHint(...)`, the `aria-describedby`
|
|
20
|
+
* id matches `hintIdFor(inputId)` so the wire-up holds end-to-end.
|
|
16
21
|
*/
|
|
17
|
-
function buildAriaAttrs(tree, description) {
|
|
22
|
+
function buildAriaAttrs(tree, description, inputId, constraints) {
|
|
18
23
|
const attrs = {};
|
|
19
24
|
if (tree.isOptional === false) attrs["aria-required"] = "true";
|
|
25
|
+
if (inputId !== void 0 && constraints !== void 0 && constraintHint$1(constraints) !== void 0) attrs["aria-describedby"] = hintIdFor(inputId);
|
|
20
26
|
if (typeof description === "string" && description.length > 0) attrs["aria-label"] = description;
|
|
21
27
|
return attrs;
|
|
22
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Derive the constraint-hint descriptor for a field at `inputId`. Returns
|
|
31
|
+
* `undefined` when the field has no constraint worth announcing — callers
|
|
32
|
+
* skip rendering the `<small>` element entirely rather than emitting an
|
|
33
|
+
* empty node.
|
|
34
|
+
*
|
|
35
|
+
* Shares its text builder with `html/a11y.ts` so the two renderers
|
|
36
|
+
* always announce the same constraint copy for the same schema field.
|
|
37
|
+
*/
|
|
38
|
+
function constraintHint(inputId, constraints) {
|
|
39
|
+
const text = constraintHint$1(constraints);
|
|
40
|
+
if (text === void 0) return void 0;
|
|
41
|
+
return {
|
|
42
|
+
id: hintIdFor(inputId),
|
|
43
|
+
text
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* True when the supplied field is non-optional and therefore deserves
|
|
48
|
+
* a visual required indicator alongside its label.
|
|
49
|
+
*
|
|
50
|
+
* Exposed as a predicate rather than a JSX element so theme adapters
|
|
51
|
+
* can render the indicator in whatever element type matches their
|
|
52
|
+
* design language (`<span>`, `<sup>`, an icon component, …).
|
|
53
|
+
*/
|
|
54
|
+
function isFieldRequired(tree) {
|
|
55
|
+
return tree.isOptional === false;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Narrow `meta.description` (typed `unknown`) to a string value safe to
|
|
59
|
+
* pass into JSX `aria-label`. Returns `undefined` for non-string or
|
|
60
|
+
* empty-string descriptions so React drops the attribute rather than
|
|
61
|
+
* stringifying e.g. `{}` to `"[object Object]"`.
|
|
62
|
+
*/
|
|
63
|
+
function ariaLabel(description) {
|
|
64
|
+
if (typeof description !== "string") return void 0;
|
|
65
|
+
if (description.length === 0) return void 0;
|
|
66
|
+
return description;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Build {@link HintInfo} for a field at `inputId` given its declared
|
|
70
|
+
* constraints. Returns `undefined` when no constraint message would be
|
|
71
|
+
* produced — the React renderers then skip emitting the hint element
|
|
72
|
+
* entirely so consumers don't see an empty `<small>`.
|
|
73
|
+
*/
|
|
74
|
+
function buildHintInfo(inputId, constraints) {
|
|
75
|
+
const hint = constraintHint$1(constraints);
|
|
76
|
+
if (hint === void 0) return void 0;
|
|
77
|
+
const id = hintIdFor(inputId);
|
|
78
|
+
return {
|
|
79
|
+
id,
|
|
80
|
+
hint,
|
|
81
|
+
ariaDescribedBy: id
|
|
82
|
+
};
|
|
83
|
+
}
|
|
23
84
|
//#endregion
|
|
24
|
-
export { buildAriaAttrs };
|
|
85
|
+
export { ariaLabel, buildAriaAttrs, buildHintInfo, constraintHint, isFieldRequired };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { j as WalkedField } from "../types-
|
|
1
|
+
import { j as WalkedField } from "../types-BrYbjC7_.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/react/fieldPath.d.ts
|
|
4
4
|
/**
|
|
@@ -9,11 +9,26 @@ declare function resolvePath(tree: WalkedField, path: string): WalkedField | und
|
|
|
9
9
|
/**
|
|
10
10
|
* Resolve a dot-separated path through a data value.
|
|
11
11
|
* Supports array index notation: `field[0]`.
|
|
12
|
+
*
|
|
13
|
+
* Path segments naming a prototype-polluting property (`__proto__`,
|
|
14
|
+
* `constructor`, `prototype`) refuse to resolve and return `undefined`.
|
|
15
|
+
* Without the refusal, an attacker-supplied path would read
|
|
16
|
+
* `Object.prototype` (or similar) and surface fields injected into the
|
|
17
|
+
* runtime prototype chain as if they belonged to the user's data.
|
|
12
18
|
*/
|
|
13
19
|
declare function resolveValue(root: unknown, path: string): unknown;
|
|
14
20
|
/**
|
|
15
21
|
* Set a value at a dot-separated path, producing a new root object.
|
|
16
22
|
* Does not mutate the input — returns a shallow-updated copy at each level.
|
|
23
|
+
*
|
|
24
|
+
* Refuses paths whose segments name a prototype-polluting property
|
|
25
|
+
* (`__proto__`, `constructor`, `prototype`). Such a path could otherwise
|
|
26
|
+
* mutate `Object.prototype` (or similar) through the assignment, planting
|
|
27
|
+
* fields visible to every plain object in the runtime. The input `root`
|
|
28
|
+
* is returned unchanged so the caller's onChange handler treats the
|
|
29
|
+
* write as a no-op rather than propagating a poisoned state. This
|
|
30
|
+
* matches the silent-refusal semantics of `dereference` in `core/ref.ts`
|
|
31
|
+
* when a JSON Pointer segment names a prototype-polluting key.
|
|
17
32
|
*/
|
|
18
33
|
declare function setNestedValue(root: unknown, path: string, leafValue: unknown): unknown;
|
|
19
34
|
//#endregion
|
package/dist/react/fieldPath.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isObject } from "../core/guards.mjs";
|
|
2
|
+
import { isPrototypePollutingKey } from "../core/uri.mjs";
|
|
2
3
|
//#region src/react/fieldPath.ts
|
|
3
4
|
/**
|
|
4
5
|
* Resolve a dot-separated path through a WalkedField tree.
|
|
@@ -26,6 +27,12 @@ function resolvePath(tree, path) {
|
|
|
26
27
|
/**
|
|
27
28
|
* Resolve a dot-separated path through a data value.
|
|
28
29
|
* Supports array index notation: `field[0]`.
|
|
30
|
+
*
|
|
31
|
+
* Path segments naming a prototype-polluting property (`__proto__`,
|
|
32
|
+
* `constructor`, `prototype`) refuse to resolve and return `undefined`.
|
|
33
|
+
* Without the refusal, an attacker-supplied path would read
|
|
34
|
+
* `Object.prototype` (or similar) and surface fields injected into the
|
|
35
|
+
* runtime prototype chain as if they belonged to the user's data.
|
|
29
36
|
*/
|
|
30
37
|
function resolveValue(root, path) {
|
|
31
38
|
if (path.length === 0) return root;
|
|
@@ -36,21 +43,38 @@ function resolveValue(root, path) {
|
|
|
36
43
|
const bracketMatch = /^(.+)\[(\d+)\]$/.exec(part);
|
|
37
44
|
if (bracketMatch?.[1] !== void 0 && bracketMatch[2] !== void 0) {
|
|
38
45
|
const key = bracketMatch[1];
|
|
46
|
+
if (isPrototypePollutingKey(key)) return void 0;
|
|
39
47
|
const index = Number(bracketMatch[2]);
|
|
40
48
|
const arr = current[key];
|
|
41
49
|
if (Array.isArray(arr)) current = arr[index];
|
|
42
50
|
else return;
|
|
43
|
-
} else
|
|
51
|
+
} else {
|
|
52
|
+
if (isPrototypePollutingKey(part)) return void 0;
|
|
53
|
+
current = current[part];
|
|
54
|
+
}
|
|
44
55
|
}
|
|
45
56
|
return current;
|
|
46
57
|
}
|
|
47
58
|
/**
|
|
48
59
|
* Set a value at a dot-separated path, producing a new root object.
|
|
49
60
|
* Does not mutate the input — returns a shallow-updated copy at each level.
|
|
61
|
+
*
|
|
62
|
+
* Refuses paths whose segments name a prototype-polluting property
|
|
63
|
+
* (`__proto__`, `constructor`, `prototype`). Such a path could otherwise
|
|
64
|
+
* mutate `Object.prototype` (or similar) through the assignment, planting
|
|
65
|
+
* fields visible to every plain object in the runtime. The input `root`
|
|
66
|
+
* is returned unchanged so the caller's onChange handler treats the
|
|
67
|
+
* write as a no-op rather than propagating a poisoned state. This
|
|
68
|
+
* matches the silent-refusal semantics of `dereference` in `core/ref.ts`
|
|
69
|
+
* when a JSON Pointer segment names a prototype-polluting key.
|
|
50
70
|
*/
|
|
51
71
|
function setNestedValue(root, path, leafValue) {
|
|
52
72
|
if (path.length === 0) return leafValue;
|
|
53
73
|
const parts = path.split(".");
|
|
74
|
+
for (const part of parts) {
|
|
75
|
+
const bracketMatch = /^(.+)\[(\d+)\]$/.exec(part);
|
|
76
|
+
if (isPrototypePollutingKey(bracketMatch?.[1] !== void 0 && bracketMatch[2] !== void 0 ? bracketMatch[1] : part)) return root;
|
|
77
|
+
}
|
|
54
78
|
const result = isObject(root) ? { ...root } : {};
|
|
55
79
|
let current = result;
|
|
56
80
|
for (let i = 0; i < parts.length; i++) {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { RenderProps } from "../core/renderer.mjs";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/react/fieldShell.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Render-time inputs to {@link FieldShell}. The shell does not depend
|
|
7
|
+
* on a theme; it consumes only the field metadata the walker has
|
|
8
|
+
* already produced.
|
|
9
|
+
*/
|
|
10
|
+
interface FieldShellProps {
|
|
11
|
+
/** The walked field props passed to the theme's render function. */
|
|
12
|
+
readonly props: RenderProps;
|
|
13
|
+
/** Stable DOM id for the host input. */
|
|
14
|
+
readonly inputId: string;
|
|
15
|
+
/**
|
|
16
|
+
* Children-as-function. Receives the ARIA attribute bundle so the
|
|
17
|
+
* caller can spread the attributes onto whatever element it
|
|
18
|
+
* produces; the shell does not inject them because the spread
|
|
19
|
+
* point varies between libraries (`inputProps`, top-level, slot
|
|
20
|
+
* props, …).
|
|
21
|
+
*/
|
|
22
|
+
readonly children: (ariaAttrs: Record<string, string>) => ReactNode;
|
|
23
|
+
/**
|
|
24
|
+
* Optional override for the label text. Defaults to
|
|
25
|
+
* `props.meta.description` when undefined.
|
|
26
|
+
*/
|
|
27
|
+
readonly label?: string;
|
|
28
|
+
/**
|
|
29
|
+
* When true, suppress the wrapping `<label>` element. Useful for
|
|
30
|
+
* adapters whose host primitive (e.g. MUI's `TextField`) already
|
|
31
|
+
* renders its own label.
|
|
32
|
+
*/
|
|
33
|
+
readonly hideLabel?: boolean;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Compose label, host primitive, and constraint hint around a render
|
|
37
|
+
* function supplied by the theme adapter. Returns plain JSX — no
|
|
38
|
+
* theme-specific element types — so the same shell works under
|
|
39
|
+
* shadcn, MUI, Mantine, Radix, or any custom theme.
|
|
40
|
+
*/
|
|
41
|
+
declare function FieldShell({
|
|
42
|
+
props,
|
|
43
|
+
inputId,
|
|
44
|
+
children,
|
|
45
|
+
label,
|
|
46
|
+
hideLabel
|
|
47
|
+
}: FieldShellProps): ReactNode;
|
|
48
|
+
//#endregion
|
|
49
|
+
export { FieldShell, FieldShellProps };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { buildAriaAttrs, constraintHint, isFieldRequired } from "./a11y.mjs";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
//#region src/react/fieldShell.tsx
|
|
4
|
+
/**
|
|
5
|
+
* Compose label, host primitive, and constraint hint around a render
|
|
6
|
+
* function supplied by the theme adapter. Returns plain JSX — no
|
|
7
|
+
* theme-specific element types — so the same shell works under
|
|
8
|
+
* shadcn, MUI, Mantine, Radix, or any custom theme.
|
|
9
|
+
*/
|
|
10
|
+
function FieldShell({ props, inputId, children, label, hideLabel }) {
|
|
11
|
+
const description = typeof label === "string" ? label : typeof props.meta.description === "string" ? props.meta.description : void 0;
|
|
12
|
+
const required = isFieldRequired(props.tree);
|
|
13
|
+
const hint = constraintHint(inputId, props.constraints);
|
|
14
|
+
const ariaAttrs = buildAriaAttrs(props.tree, description, inputId, props.constraints);
|
|
15
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
16
|
+
className: "sc-field",
|
|
17
|
+
children: [
|
|
18
|
+
hideLabel !== true && description !== void 0 && /* @__PURE__ */ jsxs("label", {
|
|
19
|
+
htmlFor: inputId,
|
|
20
|
+
children: [description, required && /* @__PURE__ */ jsxs("span", {
|
|
21
|
+
"aria-hidden": "true",
|
|
22
|
+
className: "sc-required",
|
|
23
|
+
style: { color: "#dc2626" },
|
|
24
|
+
children: [" ", "*"]
|
|
25
|
+
})]
|
|
26
|
+
}),
|
|
27
|
+
children(ariaAttrs),
|
|
28
|
+
hint !== void 0 && /* @__PURE__ */ jsx("small", {
|
|
29
|
+
className: "sc-hint",
|
|
30
|
+
id: hint.id,
|
|
31
|
+
children: hint.text
|
|
32
|
+
})
|
|
33
|
+
]
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { FieldShell };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { j as WalkedField } from "../types-
|
|
2
|
-
import {
|
|
1
|
+
import { j as WalkedField } from "../types-BrYbjC7_.mjs";
|
|
2
|
+
import { RenderProps } from "../core/renderer.mjs";
|
|
3
3
|
import { ReactNode } from "react";
|
|
4
4
|
|
|
5
5
|
//#region src/react/headlessRenderers.d.ts
|