schema-components 1.28.2 → 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 +21 -2
- package/dist/core/constraintHint.d.mts +15 -0
- package/dist/core/constraintHint.mjs +24 -0
- package/dist/core/constraints.d.mts +34 -2
- package/dist/core/constraints.mjs +33 -1
- package/dist/core/cssClasses.d.mts +1 -0
- package/dist/core/diagnostics.d.mts +1 -1
- package/dist/core/errors.d.mts +1 -1
- package/dist/core/errors.mjs +22 -12
- package/dist/core/fieldOrder.d.mts +1 -1
- package/dist/core/formats.d.mts +7 -1
- package/dist/core/formats.mjs +6 -0
- 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 +6 -0
- package/dist/core/merge.d.mts +22 -1
- package/dist/core/merge.mjs +66 -3
- package/dist/core/normalise.d.mts +17 -2
- package/dist/core/normalise.mjs +1 -1
- package/dist/core/openapi30.mjs +1 -1
- package/dist/core/openapiConstants.d.mts +1 -0
- 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/renderer.mjs +5 -0
- 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/types.mjs +17 -0
- 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/version.d.mts +1 -1
- package/dist/core/walkBuilders.d.mts +63 -6
- package/dist/core/walkBuilders.mjs +33 -1
- package/dist/core/walker.d.mts +14 -1
- package/dist/core/walker.mjs +18 -0
- package/dist/{diagnostics-Cbwak-ZX.d.mts → diagnostics-BTrm3O6J.d.mts} +9 -1
- package/dist/{errors-DQSIK4n1.d.mts → errors-Dki7tji4.d.mts} +23 -13
- package/dist/html/a11y.d.mts +3 -7
- package/dist/html/a11y.mjs +1 -16
- package/dist/html/html.d.mts +11 -0
- package/dist/html/html.mjs +11 -0
- package/dist/html/renderToHtml.d.mts +45 -12
- package/dist/html/renderToHtml.mjs +20 -4
- package/dist/html/renderToHtmlStream.d.mts +63 -18
- package/dist/html/renderToHtmlStream.mjs +34 -8
- package/dist/html/renderers.d.mts +6 -31
- package/dist/html/renderers.mjs +45 -91
- package/dist/html/streamRenderers.d.mts +31 -3
- package/dist/html/streamRenderers.mjs +41 -8
- package/dist/inferValue-PPXWJpbN.d.mts +77 -0
- package/dist/{limits-DJhgx5Ay.d.mts → limits-x4OiyJxh.d.mts} +6 -0
- package/dist/{normalise-Db1xaxgx.mjs → normalise-DB-Xtjmn.mjs} +43 -2
- package/dist/openapi/ApiCallbacks.d.mts +13 -1
- package/dist/openapi/ApiCallbacks.mjs +7 -0
- package/dist/openapi/ApiLinks.d.mts +13 -1
- package/dist/openapi/ApiLinks.mjs +7 -0
- package/dist/openapi/ApiResponseHeaders.d.mts +13 -1
- package/dist/openapi/ApiResponseHeaders.mjs +7 -0
- package/dist/openapi/ApiSecurity.d.mts +14 -1
- package/dist/openapi/ApiSecurity.mjs +29 -8
- package/dist/openapi/bundle.d.mts +31 -0
- package/dist/openapi/components.d.mts +135 -20
- package/dist/openapi/components.mjs +90 -15
- package/dist/openapi/parser.d.mts +140 -13
- package/dist/openapi/parser.mjs +84 -12
- package/dist/openapi/resolve.d.mts +42 -47
- package/dist/openapi/resolve.mjs +62 -56
- package/dist/react/SchemaComponent.d.mts +90 -88
- package/dist/react/SchemaComponent.mjs +74 -2
- package/dist/react/SchemaErrorBoundary.d.mts +18 -1
- package/dist/react/SchemaErrorBoundary.mjs +13 -1
- package/dist/react/SchemaView.d.mts +39 -11
- package/dist/react/SchemaView.mjs +23 -6
- 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 +13 -2
- package/dist/react/headlessRenderers.mjs +134 -54
- package/dist/{ref-TdeMfaV_.d.mts → ref-DdsbekXX.d.mts} +33 -1
- package/dist/themes/mantine.d.mts +54 -12
- package/dist/themes/mantine.mjs +195 -140
- package/dist/themes/mui.d.mts +64 -11
- package/dist/themes/mui.mjs +277 -213
- package/dist/themes/radix.d.mts +67 -15
- package/dist/themes/radix.mjs +235 -170
- package/dist/themes/shadcn.d.mts +25 -1
- package/dist/themes/shadcn.mjs +112 -91
- package/dist/{types-BTB73MB8.d.mts → types-BrYbjC7_.d.mts} +30 -0
- package/dist/{version-ZzL5R6cS.d.mts → version-DL8U5RuA.d.mts} +6 -0
- package/package.json +8 -1
- package/dist/adapter-DqlAnZ_w.d.mts +0 -172
- package/dist/renderer-Ul9taFYp.d.mts +0 -169
package/dist/themes/mui.mjs
CHANGED
|
@@ -1,244 +1,308 @@
|
|
|
1
1
|
import { isObject } from "../core/guards.mjs";
|
|
2
2
|
import { sortFieldsByOrder } from "../core/fieldOrder.mjs";
|
|
3
|
+
import { isFieldRequired } from "../react/a11y.mjs";
|
|
3
4
|
import { inputId, toReactNode } from "../react/headlessRenderers.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import { isValidElement } from "react";
|
|
5
|
+
import { FieldShell } from "../react/fieldShell.mjs";
|
|
6
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { isValidElement } from "react";
|
|
7
8
|
//#region src/themes/mui.tsx
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (props.readOnly) return /* @__PURE__ */ jsx(MuiTypography, {
|
|
16
|
-
id,
|
|
17
|
-
variant: "body2",
|
|
18
|
-
children: strValue || "—"
|
|
19
|
-
});
|
|
20
|
-
return /* @__PURE__ */ jsx(MuiTextField, {
|
|
21
|
-
id,
|
|
22
|
-
label,
|
|
23
|
-
type: props.constraints.format === "email" ? "email" : props.constraints.format === "uri" ? "url" : "text",
|
|
24
|
-
value: props.writeOnly ? "" : strValue,
|
|
25
|
-
onChange: (e) => {
|
|
26
|
-
props.onChange(e.target.value);
|
|
27
|
-
},
|
|
28
|
-
fullWidth: true,
|
|
29
|
-
size: "small",
|
|
30
|
-
variant: "outlined",
|
|
31
|
-
inputProps: {
|
|
32
|
-
minLength: props.constraints.minLength,
|
|
33
|
-
maxLength: props.constraints.maxLength
|
|
34
|
-
},
|
|
35
|
-
...ariaRequired(props.tree)
|
|
36
|
-
});
|
|
9
|
+
/**
|
|
10
|
+
* MUI's TextField / Checkbox use the `required` prop to surface the
|
|
11
|
+
* native asterisk and `aria-required` together. Mirror it from the
|
|
12
|
+
* walked field so callers do not need a second check.
|
|
13
|
+
*/
|
|
14
|
+
function muiRequired(props) {
|
|
15
|
+
return { required: isFieldRequired(props.tree) };
|
|
37
16
|
}
|
|
38
|
-
function
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
17
|
+
function makeRenderStringInput(components) {
|
|
18
|
+
const { TextField, Typography } = components;
|
|
19
|
+
return function renderStringInput(props) {
|
|
20
|
+
const strValue = typeof props.value === "string" ? props.value : "";
|
|
21
|
+
const label = typeof props.meta.description === "string" ? props.meta.description : void 0;
|
|
22
|
+
const id = inputId(props.path);
|
|
23
|
+
if (props.readOnly) return /* @__PURE__ */ jsx(Typography, {
|
|
43
24
|
id,
|
|
44
25
|
variant: "body2",
|
|
45
|
-
children: "—"
|
|
26
|
+
children: strValue || "—"
|
|
46
27
|
});
|
|
47
|
-
return /* @__PURE__ */ jsx(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
28
|
+
return /* @__PURE__ */ jsx(FieldShell, {
|
|
29
|
+
props,
|
|
30
|
+
inputId: id,
|
|
31
|
+
hideLabel: true,
|
|
32
|
+
children: (aria) => /* @__PURE__ */ jsx(TextField, {
|
|
33
|
+
id,
|
|
34
|
+
label,
|
|
35
|
+
type: props.constraints.format === "email" ? "email" : props.constraints.format === "uri" ? "url" : "text",
|
|
36
|
+
value: props.writeOnly ? "" : strValue,
|
|
37
|
+
onChange: (e) => {
|
|
38
|
+
props.onChange(e.target.value);
|
|
39
|
+
},
|
|
40
|
+
fullWidth: true,
|
|
41
|
+
size: "small",
|
|
42
|
+
variant: "outlined",
|
|
43
|
+
inputProps: {
|
|
44
|
+
minLength: props.constraints.minLength,
|
|
45
|
+
maxLength: props.constraints.maxLength,
|
|
46
|
+
...aria
|
|
47
|
+
},
|
|
48
|
+
...muiRequired(props)
|
|
49
|
+
})
|
|
51
50
|
});
|
|
52
|
-
}
|
|
53
|
-
return /* @__PURE__ */ jsx(MuiTextField, {
|
|
54
|
-
id,
|
|
55
|
-
label,
|
|
56
|
-
type: "number",
|
|
57
|
-
value: props.writeOnly ? "" : typeof props.value === "number" ? props.value : "",
|
|
58
|
-
onChange: (e) => {
|
|
59
|
-
props.onChange(Number(e.target.value));
|
|
60
|
-
},
|
|
61
|
-
fullWidth: true,
|
|
62
|
-
size: "small",
|
|
63
|
-
variant: "outlined",
|
|
64
|
-
inputProps: {
|
|
65
|
-
min: props.constraints.minimum,
|
|
66
|
-
max: props.constraints.maximum
|
|
67
|
-
},
|
|
68
|
-
...ariaRequired(props.tree)
|
|
69
|
-
});
|
|
51
|
+
};
|
|
70
52
|
}
|
|
71
|
-
function
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
53
|
+
function makeRenderNumberInput(components) {
|
|
54
|
+
const { TextField, Typography } = components;
|
|
55
|
+
return function renderNumberInput(props) {
|
|
56
|
+
const label = typeof props.meta.description === "string" ? props.meta.description : void 0;
|
|
57
|
+
const id = inputId(props.path);
|
|
58
|
+
if (props.readOnly) {
|
|
59
|
+
if (typeof props.value !== "number") return /* @__PURE__ */ jsx(Typography, {
|
|
60
|
+
id,
|
|
61
|
+
variant: "body2",
|
|
62
|
+
children: "—"
|
|
63
|
+
});
|
|
64
|
+
return /* @__PURE__ */ jsx(Typography, {
|
|
65
|
+
id,
|
|
66
|
+
variant: "body2",
|
|
67
|
+
children: props.value.toLocaleString()
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return /* @__PURE__ */ jsx(FieldShell, {
|
|
71
|
+
props,
|
|
72
|
+
inputId: id,
|
|
73
|
+
hideLabel: true,
|
|
74
|
+
children: (aria) => /* @__PURE__ */ jsx(TextField, {
|
|
75
|
+
id,
|
|
76
|
+
label,
|
|
77
|
+
type: "number",
|
|
78
|
+
value: props.writeOnly ? "" : typeof props.value === "number" ? props.value : "",
|
|
79
|
+
onChange: (e) => {
|
|
80
|
+
props.onChange(Number(e.target.value));
|
|
81
|
+
},
|
|
82
|
+
fullWidth: true,
|
|
83
|
+
size: "small",
|
|
84
|
+
variant: "outlined",
|
|
85
|
+
inputProps: {
|
|
86
|
+
min: props.constraints.minimum,
|
|
87
|
+
max: props.constraints.maximum,
|
|
88
|
+
...aria
|
|
89
|
+
},
|
|
90
|
+
...muiRequired(props)
|
|
91
|
+
})
|
|
79
92
|
});
|
|
80
|
-
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function makeRenderBooleanInput(components) {
|
|
96
|
+
const { Checkbox, Typography, FormControlLabel } = components;
|
|
97
|
+
return function renderBooleanInput(props) {
|
|
98
|
+
const label = typeof props.meta.description === "string" ? props.meta.description : void 0;
|
|
99
|
+
const id = inputId(props.path);
|
|
100
|
+
if (props.readOnly) {
|
|
101
|
+
if (typeof props.value !== "boolean") return /* @__PURE__ */ jsx(Typography, {
|
|
102
|
+
id,
|
|
103
|
+
variant: "body2",
|
|
104
|
+
children: "—"
|
|
105
|
+
});
|
|
106
|
+
return /* @__PURE__ */ jsx(Typography, {
|
|
107
|
+
id,
|
|
108
|
+
variant: "body2",
|
|
109
|
+
children: props.value ? "Yes" : "No"
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return /* @__PURE__ */ jsx(FieldShell, {
|
|
113
|
+
props,
|
|
114
|
+
inputId: id,
|
|
115
|
+
hideLabel: true,
|
|
116
|
+
children: (aria) => /* @__PURE__ */ jsx(FormControlLabel, {
|
|
117
|
+
control: /* @__PURE__ */ jsx(Checkbox, {
|
|
118
|
+
id,
|
|
119
|
+
checked: props.writeOnly ? false : props.value === true,
|
|
120
|
+
onChange: (e) => {
|
|
121
|
+
props.onChange(e.target.checked);
|
|
122
|
+
},
|
|
123
|
+
...aria
|
|
124
|
+
}),
|
|
125
|
+
label
|
|
126
|
+
})
|
|
127
|
+
});
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function makeRenderEnumInput(components) {
|
|
131
|
+
const { TextField, Typography, MenuItem } = components;
|
|
132
|
+
return function renderEnumInput(props) {
|
|
133
|
+
const enumValue = typeof props.value === "string" ? props.value : "";
|
|
134
|
+
const label = typeof props.meta.description === "string" ? props.meta.description : void 0;
|
|
135
|
+
const id = inputId(props.path);
|
|
136
|
+
if (props.readOnly) return /* @__PURE__ */ jsx(Typography, {
|
|
81
137
|
id,
|
|
82
138
|
variant: "body2",
|
|
83
|
-
children:
|
|
139
|
+
children: enumValue || "—"
|
|
84
140
|
});
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
props.onChange(e.target.value);
|
|
113
|
-
},
|
|
114
|
-
fullWidth: true,
|
|
115
|
-
size: "small",
|
|
116
|
-
variant: "outlined",
|
|
117
|
-
...ariaRequired(props.tree),
|
|
118
|
-
children: [/* @__PURE__ */ jsxs(MuiMenuItem, {
|
|
119
|
-
value: "",
|
|
120
|
-
children: ["Select", "…"]
|
|
121
|
-
}), (props.tree.type === "enum" ? props.tree.enumValues : []).map((v) => /* @__PURE__ */ jsx(MuiMenuItem, {
|
|
122
|
-
value: v,
|
|
123
|
-
children: v
|
|
124
|
-
}, v))]
|
|
125
|
-
});
|
|
141
|
+
return /* @__PURE__ */ jsx(FieldShell, {
|
|
142
|
+
props,
|
|
143
|
+
inputId: id,
|
|
144
|
+
hideLabel: true,
|
|
145
|
+
children: (aria) => /* @__PURE__ */ jsxs(TextField, {
|
|
146
|
+
id,
|
|
147
|
+
select: true,
|
|
148
|
+
label,
|
|
149
|
+
value: props.writeOnly ? "" : enumValue,
|
|
150
|
+
onChange: (e) => {
|
|
151
|
+
props.onChange(e.target.value);
|
|
152
|
+
},
|
|
153
|
+
fullWidth: true,
|
|
154
|
+
size: "small",
|
|
155
|
+
variant: "outlined",
|
|
156
|
+
inputProps: aria,
|
|
157
|
+
...muiRequired(props),
|
|
158
|
+
children: [/* @__PURE__ */ jsxs(MenuItem, {
|
|
159
|
+
value: "",
|
|
160
|
+
children: ["Select", "…"]
|
|
161
|
+
}), (props.tree.type === "enum" ? props.tree.enumValues : []).map((v) => /* @__PURE__ */ jsx(MenuItem, {
|
|
162
|
+
value: v,
|
|
163
|
+
children: v
|
|
164
|
+
}, v))]
|
|
165
|
+
})
|
|
166
|
+
});
|
|
167
|
+
};
|
|
126
168
|
}
|
|
127
|
-
function
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
children: props.meta.description
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
169
|
+
function makeRenderObjectContainer(components) {
|
|
170
|
+
const { Box, Typography } = components;
|
|
171
|
+
return function renderObjectContainer(props) {
|
|
172
|
+
if (props.tree.type !== "object") return null;
|
|
173
|
+
const fields = props.tree.fields;
|
|
174
|
+
const obj = isObject(props.value) ? props.value : {};
|
|
175
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
176
|
+
sx: {
|
|
177
|
+
display: "flex",
|
|
178
|
+
flexDirection: "column",
|
|
179
|
+
gap: 2
|
|
180
|
+
},
|
|
181
|
+
children: [typeof props.meta.description === "string" && /* @__PURE__ */ jsx(Typography, {
|
|
182
|
+
variant: "h6",
|
|
183
|
+
children: props.meta.description
|
|
184
|
+
}), sortFieldsByOrder(fields).map(([key, field]) => {
|
|
185
|
+
const childValue = obj[key];
|
|
186
|
+
const childOnChange = (v) => {
|
|
187
|
+
const updated = {};
|
|
188
|
+
for (const [k, val] of Object.entries(obj)) updated[k] = val;
|
|
189
|
+
updated[key] = v;
|
|
190
|
+
props.onChange(updated);
|
|
191
|
+
};
|
|
192
|
+
return /* @__PURE__ */ jsx("div", { children: toReactNode(props.renderChild(field, childValue, childOnChange, key)) }, key);
|
|
193
|
+
})]
|
|
194
|
+
});
|
|
195
|
+
};
|
|
151
196
|
}
|
|
152
|
-
function
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
197
|
+
function makeRenderArrayContainer(components) {
|
|
198
|
+
const { Box } = components;
|
|
199
|
+
return function renderArrayContainer(props) {
|
|
200
|
+
const arr = Array.isArray(props.value) ? props.value : [];
|
|
201
|
+
if (props.tree.type !== "array") return null;
|
|
202
|
+
const element = props.tree.element;
|
|
203
|
+
if (element === void 0) return null;
|
|
204
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
205
|
+
sx: {
|
|
206
|
+
display: "flex",
|
|
207
|
+
flexDirection: "column",
|
|
208
|
+
gap: 1
|
|
209
|
+
},
|
|
210
|
+
children: arr.map((item, i) => {
|
|
211
|
+
const childOnChange = (v) => {
|
|
212
|
+
const next = arr.slice();
|
|
213
|
+
next[i] = v;
|
|
214
|
+
props.onChange(next);
|
|
215
|
+
};
|
|
216
|
+
return /* @__PURE__ */ jsx("div", { children: toReactNode(props.renderChild(element, item, childOnChange, `[${String(i)}]`)) }, String(i));
|
|
217
|
+
})
|
|
218
|
+
});
|
|
219
|
+
};
|
|
172
220
|
}
|
|
173
221
|
/**
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
* This avoids a hard dependency on @mui/material while providing
|
|
179
|
-
* type-safe rendering. If MUI is not installed, these wrappers
|
|
180
|
-
* render basic HTML elements as fallback.
|
|
181
|
-
*
|
|
182
|
-
* To use real MUI components, wrap your app with MuiProvider:
|
|
183
|
-
* import { MuiProvider } from "schema-components/themes/mui";
|
|
184
|
-
* import { TextField, Checkbox, ... } from "@mui/material";
|
|
185
|
-
*
|
|
186
|
-
* <MuiProvider
|
|
187
|
-
* TextField={TextField}
|
|
188
|
-
* Checkbox={Checkbox}
|
|
189
|
-
* ...
|
|
190
|
-
* >
|
|
191
|
-
* <SchemaComponent ... />
|
|
192
|
-
* </MuiProvider>
|
|
222
|
+
* The default `muiResolver` export below is built against these plain
|
|
223
|
+
* HTML stubs so consumers can pull `muiResolver` into a story or test
|
|
224
|
+
* without first wiring up `@mui/material`. Production usage should call
|
|
225
|
+
* `createMuiResolver(...)` directly with the real MUI element types.
|
|
193
226
|
*/
|
|
194
227
|
function stripChildren(props) {
|
|
195
228
|
const rest = { ...props };
|
|
196
229
|
if ("children" in rest) delete rest.children;
|
|
197
230
|
return rest;
|
|
198
231
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
232
|
+
const STUB_COMPONENTS = {
|
|
233
|
+
TextField: (props) => /* @__PURE__ */ jsx("input", { ...stripChildren(props) }),
|
|
234
|
+
Checkbox: (props) => /* @__PURE__ */ jsx("input", {
|
|
235
|
+
type: "checkbox",
|
|
236
|
+
...stripChildren(props)
|
|
237
|
+
}),
|
|
238
|
+
Typography: (props) => /* @__PURE__ */ jsx("span", { ...props }),
|
|
239
|
+
Box: (props) => /* @__PURE__ */ jsx("div", { ...props }),
|
|
240
|
+
MenuItem: (props) => /* @__PURE__ */ jsx("option", { ...props }),
|
|
241
|
+
FormControlLabel: (props) => {
|
|
242
|
+
const { control, label, ...rest } = props;
|
|
243
|
+
return /* @__PURE__ */ jsxs("label", {
|
|
244
|
+
...rest,
|
|
245
|
+
children: [isValidElement(control) ? control : null, typeof label === "string" ? label : null]
|
|
246
|
+
});
|
|
247
|
+
}
|
|
213
248
|
};
|
|
214
249
|
/**
|
|
215
|
-
*
|
|
250
|
+
* Build a MUI-flavoured {@link ComponentResolver} bound to the supplied
|
|
251
|
+
* element types. Each render function captures the supplied components
|
|
252
|
+
* in a closure so two consumers can build different resolvers from the
|
|
253
|
+
* same package without leaking element types through module-level
|
|
254
|
+
* mutable state — making the adapter safe to use in SSR and multi-tenant
|
|
255
|
+
* environments.
|
|
256
|
+
*
|
|
257
|
+
* Returns only the keys this theme actually overrides. The runtime
|
|
258
|
+
* `mergeResolvers` call inside `<SchemaComponent>` / `<SchemaView>`
|
|
259
|
+
* fills any unset keys from `headlessResolver`, so consumers never see
|
|
260
|
+
* an unhandled field type even though this resolver leaves variants
|
|
261
|
+
* like `union`, `discriminatedUnion`, `record`, `file`, and `unknown`
|
|
262
|
+
* unset on purpose.
|
|
263
|
+
*
|
|
264
|
+
* @group Themes
|
|
216
265
|
*/
|
|
217
|
-
function
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
function buildResolver() {
|
|
226
|
-
const resolver = {
|
|
227
|
-
string: renderStringInput,
|
|
228
|
-
number: renderNumberInput,
|
|
229
|
-
boolean: renderBooleanInput,
|
|
230
|
-
enum: renderEnumInput,
|
|
231
|
-
object: renderObjectContainer,
|
|
232
|
-
array: renderArrayContainer
|
|
266
|
+
function createMuiResolver(components) {
|
|
267
|
+
return {
|
|
268
|
+
string: makeRenderStringInput(components),
|
|
269
|
+
number: makeRenderNumberInput(components),
|
|
270
|
+
boolean: makeRenderBooleanInput(components),
|
|
271
|
+
enum: makeRenderEnumInput(components),
|
|
272
|
+
object: makeRenderObjectContainer(components),
|
|
273
|
+
array: makeRenderArrayContainer(components)
|
|
233
274
|
};
|
|
234
|
-
if (headlessResolver.literal !== void 0) resolver.literal = headlessResolver.literal;
|
|
235
|
-
if (headlessResolver.union !== void 0) resolver.union = headlessResolver.union;
|
|
236
|
-
if (headlessResolver.discriminatedUnion !== void 0) resolver.discriminatedUnion = headlessResolver.discriminatedUnion;
|
|
237
|
-
if (headlessResolver.record !== void 0) resolver.record = headlessResolver.record;
|
|
238
|
-
if (headlessResolver.file !== void 0) resolver.file = headlessResolver.file;
|
|
239
|
-
if (headlessResolver.unknown !== void 0) resolver.unknown = headlessResolver.unknown;
|
|
240
|
-
return resolver;
|
|
241
275
|
}
|
|
242
|
-
|
|
276
|
+
/**
|
|
277
|
+
* Component resolver mapping schema field types to MUI (Material UI)
|
|
278
|
+
* primitives — `TextField`, `Checkbox`, `Typography`, etc.
|
|
279
|
+
*
|
|
280
|
+
* This default export is built against minimal HTML stubs so it is
|
|
281
|
+
* usable without wiring up `@mui/material` first — handy for tests,
|
|
282
|
+
* stories, and tree-shaken bundles that want the resolver shape
|
|
283
|
+
* without the runtime dependency. For production usage call
|
|
284
|
+
* {@link createMuiResolver} with the real MUI element types.
|
|
285
|
+
*
|
|
286
|
+
* @group Themes
|
|
287
|
+
* @example
|
|
288
|
+
* ```tsx
|
|
289
|
+
* import TextField from "@mui/material/TextField";
|
|
290
|
+
* import Checkbox from "@mui/material/Checkbox";
|
|
291
|
+
* import Typography from "@mui/material/Typography";
|
|
292
|
+
* import Box from "@mui/material/Box";
|
|
293
|
+
* import MenuItem from "@mui/material/MenuItem";
|
|
294
|
+
* import FormControlLabel from "@mui/material/FormControlLabel";
|
|
295
|
+
* import { createMuiResolver } from "schema-components/themes/mui";
|
|
296
|
+
*
|
|
297
|
+
* const muiResolver = createMuiResolver({
|
|
298
|
+
* TextField, Checkbox, Typography, Box, MenuItem, FormControlLabel,
|
|
299
|
+
* });
|
|
300
|
+
*
|
|
301
|
+
* <SchemaProvider resolver={muiResolver}>
|
|
302
|
+
* <SchemaComponent schema={userSchema} value={user} onChange={setUser} />
|
|
303
|
+
* </SchemaProvider>
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
const muiResolver = createMuiResolver(STUB_COMPONENTS);
|
|
243
307
|
//#endregion
|
|
244
|
-
export {
|
|
308
|
+
export { createMuiResolver, muiResolver };
|
package/dist/themes/radix.d.mts
CHANGED
|
@@ -1,21 +1,73 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ComponentResolver } from "../core/renderer.mjs";
|
|
2
|
+
import { ElementType } from "react";
|
|
2
3
|
|
|
3
4
|
//#region src/themes/radix.d.ts
|
|
4
5
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
6
|
+
* Element types the Radix resolver renders into. Each Select.* slot is
|
|
7
|
+
* passed in separately because Radix exposes those parts as nested
|
|
8
|
+
* properties on the `Select` namespace; flattening them into the
|
|
9
|
+
* dependency bag lets the resolver pass them straight to JSX without
|
|
10
|
+
* touching `Select.Root`-style member expressions at render time.
|
|
11
|
+
*/
|
|
12
|
+
interface RadixComponents {
|
|
13
|
+
Box: ElementType;
|
|
14
|
+
Checkbox: ElementType;
|
|
15
|
+
Flex: ElementType;
|
|
16
|
+
SelectRoot: ElementType;
|
|
17
|
+
SelectTrigger: ElementType;
|
|
18
|
+
SelectContent: ElementType;
|
|
19
|
+
SelectItem: ElementType;
|
|
20
|
+
Text: ElementType;
|
|
21
|
+
TextField: ElementType;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Build a Radix-flavoured {@link ComponentResolver} bound to the
|
|
25
|
+
* supplied element types. Each render function captures the supplied
|
|
26
|
+
* components in a closure so two consumers can build different
|
|
27
|
+
* resolvers from the same package without leaking element types
|
|
28
|
+
* through module-level mutable state.
|
|
29
|
+
*
|
|
30
|
+
* Returns only the keys this theme actually overrides. The runtime
|
|
31
|
+
* `mergeResolvers` call inside `<SchemaComponent>` / `<SchemaView>`
|
|
32
|
+
* fills unset keys from `headlessResolver`, so variants this adapter
|
|
33
|
+
* leaves unset (literal, union, discriminatedUnion, array, record,
|
|
34
|
+
* file, unknown, …) still render via the headless fallback.
|
|
35
|
+
*
|
|
36
|
+
* @group Themes
|
|
37
|
+
*/
|
|
38
|
+
declare function createRadixResolver(components: RadixComponents): ComponentResolver;
|
|
39
|
+
/**
|
|
40
|
+
* Component resolver mapping schema field types to Radix Themes
|
|
41
|
+
* primitives — `Box`, `Checkbox`, `Flex`, `Select.*`, `Text`,
|
|
42
|
+
* `TextField`.
|
|
43
|
+
*
|
|
44
|
+
* Built against minimal HTML stubs so the resolver is usable without
|
|
45
|
+
* wiring up `@radix-ui/themes` first — production usage should call
|
|
46
|
+
* {@link createRadixResolver} with real Radix element types.
|
|
47
|
+
*
|
|
48
|
+
* @group Themes
|
|
49
|
+
* @example
|
|
50
|
+
* ```tsx
|
|
51
|
+
* import * as Radix from "@radix-ui/themes";
|
|
52
|
+
* import { createRadixResolver } from "schema-components/themes/radix";
|
|
53
|
+
*
|
|
54
|
+
* const radixResolver = createRadixResolver({
|
|
55
|
+
* Box: Radix.Box,
|
|
56
|
+
* Checkbox: Radix.Checkbox,
|
|
57
|
+
* Flex: Radix.Flex,
|
|
58
|
+
* SelectRoot: Radix.Select.Root,
|
|
59
|
+
* SelectTrigger: Radix.Select.Trigger,
|
|
60
|
+
* SelectContent: Radix.Select.Content,
|
|
61
|
+
* SelectItem: Radix.Select.Item,
|
|
62
|
+
* Text: Radix.Text,
|
|
63
|
+
* TextField: Radix.TextField.Root,
|
|
64
|
+
* });
|
|
65
|
+
*
|
|
66
|
+
* <SchemaProvider resolver={radixResolver}>
|
|
67
|
+
* <SchemaComponent schema={userSchema} value={user} onChange={setUser} />
|
|
68
|
+
* </SchemaProvider>
|
|
69
|
+
* ```
|
|
7
70
|
*/
|
|
8
|
-
declare function registerRadixComponents(components: {
|
|
9
|
-
Box: React.ElementType;
|
|
10
|
-
Checkbox: React.ElementType;
|
|
11
|
-
Flex: React.ElementType;
|
|
12
|
-
SelectRoot: React.ElementType;
|
|
13
|
-
SelectTrigger: React.ElementType;
|
|
14
|
-
SelectContent: React.ElementType;
|
|
15
|
-
SelectItem: React.ElementType;
|
|
16
|
-
Text: React.ElementType;
|
|
17
|
-
TextField: React.ElementType;
|
|
18
|
-
}): void;
|
|
19
71
|
declare const radixResolver: ComponentResolver;
|
|
20
72
|
//#endregion
|
|
21
|
-
export {
|
|
73
|
+
export { RadixComponents, createRadixResolver, radixResolver };
|