@formadapter/shadcn 0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ludicrous
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # `@formadapter/shadcn`
2
+
3
+ Connect FormAdapter to the shadcn/ui components your application owns. Nothing
4
+ is styled or copied by this package: pass your generated components once and
5
+ FormAdapter renders those exact components.
6
+
7
+ ```sh
8
+ bun add @formadapter/react @formadapter/shadcn
9
+ bunx shadcn@latest add alert button checkbox field input native-select progress radio-group spinner textarea
10
+ ```
11
+
12
+ Use the entry point matching the primitives selected in `components.json`:
13
+
14
+ ```tsx
15
+ "use client";
16
+
17
+ import { createShadcn } from "@formadapter/shadcn/baseui";
18
+ // For Radix UI instead:
19
+ // import { createShadcn } from "@formadapter/shadcn/radix";
20
+
21
+ import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
22
+ import { Button } from "@/components/ui/button";
23
+ import { Checkbox } from "@/components/ui/checkbox";
24
+ import {
25
+ Field, FieldContent, FieldDescription, FieldError, FieldGroup,
26
+ FieldLabel, FieldLegend, FieldSet, FieldTitle,
27
+ } from "@/components/ui/field";
28
+ import { Input } from "@/components/ui/input";
29
+ import { NativeSelect, NativeSelectOption } from "@/components/ui/native-select";
30
+ import { Progress } from "@/components/ui/progress";
31
+ import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
32
+ import { Spinner } from "@/components/ui/spinner";
33
+ import { Textarea } from "@/components/ui/textarea";
34
+
35
+ export const shadcn = createShadcn({
36
+ Alert, AlertDescription, AlertTitle, Button, Checkbox,
37
+ Field, FieldContent, FieldDescription, FieldError, FieldGroup,
38
+ FieldLabel, FieldLegend, FieldSet, FieldTitle,
39
+ Input, NativeSelect, NativeSelectOption, Progress,
40
+ RadioGroup, RadioGroupItem, Spinner, Textarea,
41
+ });
42
+
43
+ export const ShadcnProvider = shadcn.Provider;
44
+ ```
45
+
46
+ Mount the returned provider once. Neutral forms created with
47
+ `@formadapter/react` use the nearest provider:
48
+
49
+ ```tsx
50
+ <ShadcnProvider>
51
+ <App />
52
+ </ShadcnProvider>
53
+ ```
54
+
55
+ The setup also returns `adapter` for scoped extensions and an adapter-bound
56
+ `createForm` for forms that should not depend on a provider:
57
+
58
+ ```tsx
59
+ export const { adapter, createForm } = shadcn;
60
+ ```
61
+
62
+ Do not import CSS from `@formadapter/shadcn`. Your generated components and
63
+ existing shadcn theme remain the only styling source.
@@ -0,0 +1,8 @@
1
+ 'use client';
2
+ import { n as ShadcnSetup, r as BaseUIShadcnComponents, t as ShadcnProviderProps } from "./factory-FVm6mlf3.js";
3
+
4
+ //#region src/baseui.d.ts
5
+ declare function createShadcn(components: BaseUIShadcnComponents): ShadcnSetup;
6
+ //#endregion
7
+ export { type BaseUIShadcnComponents, type ShadcnProviderProps, type ShadcnSetup, createShadcn };
8
+ //# sourceMappingURL=baseui.d.ts.map
package/dist/baseui.js ADDED
@@ -0,0 +1,89 @@
1
+ 'use client';
2
+ import { t as createShadcnSetup } from "./factory-CI0_tPhU.js";
3
+ import { nativeControlProps, optionForValue, selectedOptionValue, serializedOptionValue } from "@formadapter/html/native";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/baseui-controls.tsx
6
+ function requiresCheckedValue(field) {
7
+ return typeof field.source === "object" && field.source !== null && field.source.const === true;
8
+ }
9
+ function createBaseUIChoiceControls(components) {
10
+ const { Checkbox, Field, FieldLabel, RadioGroup, RadioGroupItem } = components;
11
+ function CheckboxControl({ controlRef, disabled, field, id, inputProps, invalid, name, onBlur, onValueChange, readOnly, required, value }) {
12
+ const configured = nativeControlProps(field);
13
+ return /* @__PURE__ */ jsx(Checkbox, {
14
+ ...configured.props,
15
+ ...inputProps,
16
+ "aria-invalid": invalid || void 0,
17
+ "aria-readonly": readOnly || void 0,
18
+ checked: value === true,
19
+ className: configured.className,
20
+ disabled,
21
+ id,
22
+ inputRef: controlRef,
23
+ name,
24
+ onBlur,
25
+ onCheckedChange: (checked) => {
26
+ if (!readOnly) onValueChange(checked);
27
+ },
28
+ readOnly,
29
+ required: required && requiresCheckedValue(field),
30
+ style: configured.style,
31
+ value: "true"
32
+ });
33
+ }
34
+ function RadioControl({ controlRef, disabled, field, id, inputProps, invalid, name, onBlur, onValueChange, readOnly, required, value }) {
35
+ const options = field.options ?? [];
36
+ const configured = nativeControlProps(field);
37
+ return /* @__PURE__ */ jsx(RadioGroup, {
38
+ ...configured.props,
39
+ ...inputProps,
40
+ "aria-invalid": invalid || void 0,
41
+ "aria-label": inputProps["aria-label"] ?? field.label,
42
+ "aria-readonly": readOnly || void 0,
43
+ className: configured.className,
44
+ disabled,
45
+ name,
46
+ onBlur,
47
+ onValueChange: (nextValue) => {
48
+ if (readOnly) return;
49
+ const selected = optionForValue(options, nextValue);
50
+ if (selected) onValueChange(selected.value);
51
+ },
52
+ readOnly,
53
+ ref: options.length === 0 ? controlRef : void 0,
54
+ required,
55
+ style: configured.style,
56
+ tabIndex: options.length === 0 ? -1 : void 0,
57
+ value: selectedOptionValue(options, value),
58
+ children: options.map((option, index) => {
59
+ const optionId = index === 0 ? id : `${id}-${index}`;
60
+ return /* @__PURE__ */ jsxs(Field, {
61
+ orientation: "horizontal",
62
+ children: [/* @__PURE__ */ jsx(RadioGroupItem, {
63
+ "aria-invalid": invalid || void 0,
64
+ disabled,
65
+ id: optionId,
66
+ inputRef: index === 0 ? controlRef : void 0,
67
+ value: serializedOptionValue(option.value)
68
+ }), /* @__PURE__ */ jsx(FieldLabel, {
69
+ htmlFor: optionId,
70
+ children: option.label
71
+ })]
72
+ }, optionId);
73
+ })
74
+ });
75
+ }
76
+ return {
77
+ checkbox: CheckboxControl,
78
+ radio: RadioControl
79
+ };
80
+ }
81
+ //#endregion
82
+ //#region src/baseui.ts
83
+ function createShadcn(components) {
84
+ return createShadcnSetup("shadcn/ui (Base UI)", components, createBaseUIChoiceControls(components));
85
+ }
86
+ //#endregion
87
+ export { createShadcn };
88
+
89
+ //# sourceMappingURL=baseui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseui.js","names":[],"sources":["../src/baseui-controls.tsx","../src/baseui.ts"],"sourcesContent":["import {\n nativeControlProps,\n optionForValue,\n selectedOptionValue,\n serializedOptionValue,\n} from \"@formadapter/html/native\";\nimport type { ControlProps } from \"@formadapter/react\";\n\nimport type { BaseUIShadcnComponents } from \"./components\";\nimport type { ChoiceControls } from \"./factory\";\n\nfunction requiresCheckedValue(field: ControlProps[\"field\"]): boolean {\n return typeof field.source === \"object\" && field.source !== null &&\n field.source.const === true;\n}\n\nexport function createBaseUIChoiceControls(\n components: BaseUIShadcnComponents,\n): ChoiceControls {\n const {\n Checkbox,\n Field,\n FieldLabel,\n RadioGroup,\n RadioGroupItem,\n } = components;\n\n function CheckboxControl({\n controlRef,\n disabled,\n field,\n id,\n inputProps,\n invalid,\n name,\n onBlur,\n onValueChange,\n readOnly,\n required,\n value,\n }: ControlProps): React.JSX.Element {\n const configured = nativeControlProps<Record<string, unknown>>(field);\n\n return (\n <Checkbox\n {...configured.props}\n {...inputProps}\n aria-invalid={invalid || undefined}\n aria-readonly={readOnly || undefined}\n checked={value === true}\n className={configured.className}\n disabled={disabled}\n id={id}\n inputRef={controlRef}\n name={name}\n onBlur={onBlur}\n onCheckedChange={(checked) => {\n if (!readOnly) onValueChange(checked);\n }}\n readOnly={readOnly}\n required={required && requiresCheckedValue(field)}\n style={configured.style}\n value=\"true\"\n />\n );\n }\n\n function RadioControl({\n controlRef,\n disabled,\n field,\n id,\n inputProps,\n invalid,\n name,\n onBlur,\n onValueChange,\n readOnly,\n required,\n value,\n }: ControlProps): React.JSX.Element {\n const options = field.options ?? [];\n const configured = nativeControlProps<Record<string, unknown>>(field);\n\n return (\n <RadioGroup\n {...configured.props}\n {...inputProps}\n aria-invalid={invalid || undefined}\n aria-label={inputProps[\"aria-label\"] ?? field.label}\n aria-readonly={readOnly || undefined}\n className={configured.className}\n disabled={disabled}\n name={name}\n onBlur={onBlur}\n onValueChange={(nextValue) => {\n if (readOnly) return;\n const selected = optionForValue(options, nextValue);\n if (selected) onValueChange(selected.value);\n }}\n readOnly={readOnly}\n ref={options.length === 0 ? controlRef : undefined}\n required={required}\n style={configured.style}\n tabIndex={options.length === 0 ? -1 : undefined}\n value={selectedOptionValue(options, value)}\n >\n {options.map((option, index) => {\n const optionId = index === 0 ? id : `${id}-${index}`;\n return (\n <Field key={optionId} orientation=\"horizontal\">\n <RadioGroupItem\n aria-invalid={invalid || undefined}\n disabled={disabled}\n id={optionId}\n inputRef={index === 0 ? controlRef : undefined}\n value={serializedOptionValue(option.value)}\n />\n <FieldLabel htmlFor={optionId}>{option.label}</FieldLabel>\n </Field>\n );\n })}\n </RadioGroup>\n );\n }\n\n return { checkbox: CheckboxControl, radio: RadioControl };\n}\n","import type { BaseUIShadcnComponents } from \"./components\";\nimport { createBaseUIChoiceControls } from \"./baseui-controls\";\nimport { createShadcnSetup, type ShadcnSetup } from \"./factory\";\n\nexport type { BaseUIShadcnComponents } from \"./components\";\nexport type { ShadcnProviderProps, ShadcnSetup } from \"./factory\";\n\nexport function createShadcn(\n components: BaseUIShadcnComponents,\n): ShadcnSetup {\n return createShadcnSetup(\n \"shadcn/ui (Base UI)\",\n components,\n createBaseUIChoiceControls(components),\n );\n}\n"],"mappings":";;;;;AAWA,SAAS,qBAAqB,OAAuC;AACnE,QAAO,OAAO,MAAM,WAAW,YAAY,MAAM,WAAW,QAC1D,MAAM,OAAO,UAAU;;AAG3B,SAAgB,2BACd,YACgB;CAChB,MAAM,EACJ,UACA,OACA,YACA,YACA,mBACE;CAEJ,SAAS,gBAAgB,EACvB,YACA,UACA,OACA,IACA,YACA,SACA,MACA,QACA,eACA,UACA,UACA,SACkC;EAClC,MAAM,aAAa,mBAA4C,MAAM;AAErE,SACE,oBAAC,UAAD;GACE,GAAI,WAAW;GACf,GAAI;GACJ,gBAAc,WAAW,KAAA;GACzB,iBAAe,YAAY,KAAA;GAC3B,SAAS,UAAU;GACnB,WAAW,WAAW;GACZ;GACN;GACJ,UAAU;GACJ;GACE;GACR,kBAAkB,YAAY;AAC5B,QAAI,CAAC,SAAU,eAAc,QAAQ;;GAE7B;GACV,UAAU,YAAY,qBAAqB,MAAM;GACjD,OAAO,WAAW;GAClB,OAAM;GACN,CAAA;;CAIN,SAAS,aAAa,EACpB,YACA,UACA,OACA,IACA,YACA,SACA,MACA,QACA,eACA,UACA,UACA,SACkC;EAClC,MAAM,UAAU,MAAM,WAAW,EAAE;EACnC,MAAM,aAAa,mBAA4C,MAAM;AAErE,SACE,oBAAC,YAAD;GACE,GAAI,WAAW;GACf,GAAI;GACJ,gBAAc,WAAW,KAAA;GACzB,cAAY,WAAW,iBAAiB,MAAM;GAC9C,iBAAe,YAAY,KAAA;GAC3B,WAAW,WAAW;GACZ;GACJ;GACE;GACR,gBAAgB,cAAc;AAC5B,QAAI,SAAU;IACd,MAAM,WAAW,eAAe,SAAS,UAAU;AACnD,QAAI,SAAU,eAAc,SAAS,MAAM;;GAEnC;GACV,KAAK,QAAQ,WAAW,IAAI,aAAa,KAAA;GAC/B;GACV,OAAO,WAAW;GAClB,UAAU,QAAQ,WAAW,IAAI,KAAK,KAAA;GACtC,OAAO,oBAAoB,SAAS,MAAM;aAEzC,QAAQ,KAAK,QAAQ,UAAU;IAC9B,MAAM,WAAW,UAAU,IAAI,KAAK,GAAG,GAAG,GAAG;AAC7C,WACE,qBAAC,OAAD;KAAsB,aAAY;eAAlC,CACE,oBAAC,gBAAD;MACE,gBAAc,WAAW,KAAA;MACf;MACV,IAAI;MACJ,UAAU,UAAU,IAAI,aAAa,KAAA;MACrC,OAAO,sBAAsB,OAAO,MAAM;MAC1C,CAAA,EACF,oBAAC,YAAD;MAAY,SAAS;gBAAW,OAAO;MAAmB,CAAA,CACpD;OATI,SASJ;KAEV;GACS,CAAA;;AAIjB,QAAO;EAAE,UAAU;EAAiB,OAAO;EAAc;;;;ACvH3D,SAAgB,aACd,YACa;AACb,QAAO,kBACL,uBACA,YACA,2BAA2B,WAAW,CACvC"}
@@ -0,0 +1,443 @@
1
+ 'use client';
2
+ import { changedInputValue, inputType, inputValue, nativeControlProps, optionForValue, selectedOptionValue, serializedOptionValue } from "@formadapter/html/native";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ import { FormAdapterProvider, createAdapter, createFormFactory } from "@formadapter/react";
5
+ import { useCallback, useEffect, useId, useRef } from "react";
6
+ //#region src/native-controls.tsx
7
+ function isFileMetadata(value) {
8
+ return typeof value === "object" && value !== null && typeof value.lastModified === "number" && typeof value.name === "string" && typeof value.size === "number" && typeof value.type === "string";
9
+ }
10
+ function controlledFiles(value) {
11
+ if (isFileMetadata(value)) return [value];
12
+ if (typeof FileList !== "undefined" && value instanceof FileList) return Array.from(value).filter(isFileMetadata);
13
+ if (!Array.isArray(value)) return [];
14
+ return value.filter(isFileMetadata);
15
+ }
16
+ function nativeFilesMatch(value, files) {
17
+ const controlled = controlledFiles(value);
18
+ if (controlled.length === 0 || files?.length !== controlled.length) return false;
19
+ return controlled.every((file, index) => {
20
+ const nativeFile = files.item(index);
21
+ return nativeFile !== null && (Object.is(file, nativeFile) || file.name === nativeFile.name && file.size === nativeFile.size && file.type === nativeFile.type && file.lastModified === nativeFile.lastModified);
22
+ });
23
+ }
24
+ function createNativeControls(components) {
25
+ const { Input: ShadcnInput, NativeSelect, NativeSelectOption, Textarea: ShadcnTextarea } = components;
26
+ function InputControl({ controlRef, disabled, field, id, inputProps, name, onBlur, onValueChange, readOnly, required, value }) {
27
+ const configured = nativeControlProps(field);
28
+ const type = inputType(field);
29
+ return /* @__PURE__ */ jsx(ShadcnInput, {
30
+ ...configured.props,
31
+ ...inputProps,
32
+ className: configured.className,
33
+ disabled: disabled || readOnly && type === "range",
34
+ id,
35
+ max: field.constraints.maximum,
36
+ maxLength: field.constraints.maxLength,
37
+ min: field.constraints.minimum,
38
+ minLength: field.constraints.minLength,
39
+ name,
40
+ onBlur,
41
+ onChange: (event) => {
42
+ if (readOnly) return;
43
+ onValueChange(changedInputValue(field, event.currentTarget.value, event.currentTarget.valueAsNumber));
44
+ },
45
+ pattern: field.constraints.pattern,
46
+ placeholder: field.config.placeholder ?? configured.props.placeholder,
47
+ readOnly,
48
+ ref: controlRef,
49
+ required,
50
+ step: field.constraints.multipleOf ?? (field.dataType === "integer" ? 1 : field.dataType === "number" ? "any" : void 0),
51
+ style: configured.style,
52
+ type,
53
+ value: inputValue(value, type)
54
+ });
55
+ }
56
+ function TextareaControl({ controlRef, disabled, field, id, inputProps, name, onBlur, onValueChange, readOnly, required, value }) {
57
+ const configured = nativeControlProps(field);
58
+ return /* @__PURE__ */ jsx(ShadcnTextarea, {
59
+ ...configured.props,
60
+ ...inputProps,
61
+ className: configured.className,
62
+ disabled,
63
+ id,
64
+ maxLength: field.constraints.maxLength,
65
+ minLength: field.constraints.minLength,
66
+ name,
67
+ onBlur,
68
+ onChange: (event) => {
69
+ if (!readOnly) onValueChange(event.currentTarget.value);
70
+ },
71
+ placeholder: field.config.placeholder ?? configured.props.placeholder,
72
+ readOnly,
73
+ ref: controlRef,
74
+ required,
75
+ style: configured.style,
76
+ value: inputValue(value)
77
+ });
78
+ }
79
+ function SelectControl({ controlRef, disabled, field, id, inputProps, name, onBlur, onValueChange, readOnly, required, value }) {
80
+ const configured = nativeControlProps(field);
81
+ const { size: _configuredSize, ...configuredProps } = configured.props;
82
+ const options = field.options ?? [];
83
+ const placeholder = field.config.placeholder ?? "Select an option";
84
+ return /* @__PURE__ */ jsxs(NativeSelect, {
85
+ ...configuredProps,
86
+ ...inputProps,
87
+ "aria-readonly": readOnly || void 0,
88
+ className: configured.className,
89
+ disabled: disabled || readOnly,
90
+ id,
91
+ name,
92
+ onBlur,
93
+ onChange: (event) => {
94
+ if (readOnly) return;
95
+ const selected = optionForValue(options, event.currentTarget.value);
96
+ onValueChange(selected ? selected.value : "");
97
+ },
98
+ ref: controlRef,
99
+ required,
100
+ style: configured.style,
101
+ value: selectedOptionValue(options, value),
102
+ children: [/* @__PURE__ */ jsx(NativeSelectOption, {
103
+ disabled: required,
104
+ value: "",
105
+ children: placeholder
106
+ }), options.map((option, index) => /* @__PURE__ */ jsx(NativeSelectOption, {
107
+ value: serializedOptionValue(option.value),
108
+ children: option.label
109
+ }, `${serializedOptionValue(option.value)}-${index}`))]
110
+ });
111
+ }
112
+ function FileControl({ controlRef, disabled, field, id, inputProps, name, onBlur, onValueChange, readOnly, required, value }) {
113
+ const configured = nativeControlProps(field);
114
+ const input = useRef(null);
115
+ const setControlRef = useCallback((instance) => {
116
+ input.current = instance;
117
+ controlRef(instance);
118
+ }, [controlRef]);
119
+ useEffect(() => {
120
+ const current = input.current;
121
+ if (current?.value && !nativeFilesMatch(value, current.files)) current.value = "";
122
+ }, [value]);
123
+ return /* @__PURE__ */ jsx(ShadcnInput, {
124
+ ...configured.props,
125
+ ...inputProps,
126
+ accept: field.constraints.accept ?? field.constraints.contentMediaType ?? configured.props.accept,
127
+ className: configured.className,
128
+ disabled: disabled || readOnly,
129
+ id,
130
+ multiple: field.config.multiple || field.constraints.multiple,
131
+ name,
132
+ onBlur,
133
+ onChange: (event) => {
134
+ const files = event.currentTarget.files;
135
+ onValueChange(field.config.multiple || field.constraints.multiple ? Array.from(files ?? []) : files?.[0] ?? "");
136
+ },
137
+ ref: setControlRef,
138
+ required,
139
+ style: configured.style,
140
+ type: "file"
141
+ });
142
+ }
143
+ return {
144
+ file: FileControl,
145
+ input: InputControl,
146
+ select: SelectControl,
147
+ textarea: TextareaControl
148
+ };
149
+ }
150
+ //#endregion
151
+ //#region src/slots.tsx
152
+ function requiredLabel(label, required) {
153
+ return /* @__PURE__ */ jsxs(Fragment, { children: [label, required ? /* @__PURE__ */ jsx("span", {
154
+ "aria-hidden": "true",
155
+ children: " *"
156
+ }) : null] });
157
+ }
158
+ function buttonVariant(intent) {
159
+ if (intent === "remove") return "destructive";
160
+ if (intent === "move-up" || intent === "move-down" || intent === "previous") return "outline";
161
+ return "default";
162
+ }
163
+ function createSlots(components) {
164
+ const { Alert, AlertDescription, AlertTitle, Button: ShadcnButton, Field: ShadcnField, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSet, FieldTitle, Progress, Spinner } = components;
165
+ function Form({ children, ...props }) {
166
+ return /* @__PURE__ */ jsx("form", {
167
+ ...props,
168
+ "data-slot": "form",
169
+ children
170
+ });
171
+ }
172
+ function Field({ children, controlId, descriptionId, error, errorId, field, invalid, required, validating, ...props }) {
173
+ if (field.control === "hidden" || field.inputType === "hidden") return children;
174
+ const checkbox = field.control === "checkbox";
175
+ return /* @__PURE__ */ jsxs(ShadcnField, {
176
+ ...props,
177
+ "data-field-path": field.path,
178
+ "data-invalid": invalid || void 0,
179
+ "data-validating": validating || void 0,
180
+ orientation: checkbox ? "horizontal" : "vertical",
181
+ children: [
182
+ checkbox ? /* @__PURE__ */ jsxs(FieldLabel, {
183
+ htmlFor: controlId,
184
+ children: [children, requiredLabel(field.label, required)]
185
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(FieldLabel, {
186
+ htmlFor: controlId,
187
+ children: requiredLabel(field.label, required)
188
+ }), children] }),
189
+ field.description ? /* @__PURE__ */ jsx(FieldDescription, {
190
+ id: descriptionId,
191
+ children: field.description
192
+ }) : null,
193
+ validating ? /* @__PURE__ */ jsx(FieldDescription, { children: /* @__PURE__ */ jsx("output", { children: "Checking…" }) }) : null,
194
+ error ? /* @__PURE__ */ jsx(FieldError, {
195
+ id: errorId,
196
+ children: error
197
+ }) : null
198
+ ]
199
+ });
200
+ }
201
+ function Group({ children, disabled, error, errorId, field, readOnly, required, ...props }) {
202
+ const descriptionId = useId();
203
+ const describedBy = [
204
+ props["aria-describedby"],
205
+ field.description ? descriptionId : void 0,
206
+ error ? errorId : void 0
207
+ ].filter(Boolean).join(" ") || void 0;
208
+ return /* @__PURE__ */ jsxs(FieldSet, {
209
+ ...props,
210
+ "aria-describedby": describedBy,
211
+ "aria-disabled": disabled || void 0,
212
+ "aria-invalid": error ? true : void 0,
213
+ "data-field-path": field.path,
214
+ "data-invalid": error ? true : void 0,
215
+ "data-readonly": readOnly || void 0,
216
+ disabled,
217
+ children: [
218
+ /* @__PURE__ */ jsx(FieldLegend, { children: requiredLabel(field.label, required) }),
219
+ field.description ? /* @__PURE__ */ jsx(FieldDescription, {
220
+ id: descriptionId,
221
+ children: field.description
222
+ }) : null,
223
+ /* @__PURE__ */ jsx(FieldGroup, { children }),
224
+ error ? /* @__PURE__ */ jsx(FieldError, {
225
+ id: errorId,
226
+ children: error
227
+ }) : null
228
+ ]
229
+ });
230
+ }
231
+ function Array({ actions, children, disabled, error, errorId, field, itemCount, readOnly, required, ...props }) {
232
+ const descriptionId = useId();
233
+ const describedBy = [
234
+ props["aria-describedby"],
235
+ field.description ? descriptionId : void 0,
236
+ error ? errorId : void 0
237
+ ].filter(Boolean).join(" ") || void 0;
238
+ return /* @__PURE__ */ jsxs(FieldSet, {
239
+ ...props,
240
+ "aria-describedby": describedBy,
241
+ "aria-disabled": disabled || void 0,
242
+ "aria-invalid": error ? true : void 0,
243
+ "data-field-path": field.path,
244
+ "data-invalid": error ? true : void 0,
245
+ "data-item-count": itemCount,
246
+ "data-readonly": readOnly || void 0,
247
+ disabled,
248
+ children: [
249
+ /* @__PURE__ */ jsx(FieldLegend, { children: requiredLabel(field.label, required) }),
250
+ field.description ? /* @__PURE__ */ jsx(FieldDescription, {
251
+ id: descriptionId,
252
+ children: field.description
253
+ }) : null,
254
+ /* @__PURE__ */ jsx(FieldGroup, {
255
+ "data-slot": "array-items",
256
+ children
257
+ }),
258
+ /* @__PURE__ */ jsx(ShadcnField, {
259
+ "data-slot": "array-actions",
260
+ orientation: "horizontal",
261
+ children: actions
262
+ }),
263
+ error ? /* @__PURE__ */ jsx(FieldError, {
264
+ id: errorId,
265
+ children: error
266
+ }) : null
267
+ ]
268
+ });
269
+ }
270
+ function ArrayItem({ actions, children, field, index, label, ...props }) {
271
+ const labelId = useId();
272
+ return /* @__PURE__ */ jsxs(ShadcnField, {
273
+ ...props,
274
+ "aria-labelledby": props["aria-labelledby"] ?? labelId,
275
+ "data-array-path": field.path,
276
+ "data-item-index": index,
277
+ role: props.role ?? "group",
278
+ children: [/* @__PURE__ */ jsxs(ShadcnField, {
279
+ orientation: "horizontal",
280
+ children: [/* @__PURE__ */ jsx(FieldTitle, {
281
+ id: labelId,
282
+ children: label
283
+ }), /* @__PURE__ */ jsx("div", {
284
+ "data-slot": "array-item-actions",
285
+ children: actions
286
+ })]
287
+ }), /* @__PURE__ */ jsx(FieldContent, { children })]
288
+ });
289
+ }
290
+ function Button({ ariaLabel, children, disabled, intent, onClick, pending, type }) {
291
+ return /* @__PURE__ */ jsxs(ShadcnButton, {
292
+ "aria-busy": pending || void 0,
293
+ "aria-label": ariaLabel,
294
+ "data-intent": intent,
295
+ disabled,
296
+ onClick,
297
+ type,
298
+ variant: buttonVariant(intent),
299
+ children: [pending ? /* @__PURE__ */ jsx(Spinner, {
300
+ "aria-hidden": "true",
301
+ "data-icon": "inline-start"
302
+ }) : null, children]
303
+ });
304
+ }
305
+ function ErrorSummary({ errors, items, onSelect, title }) {
306
+ const resolvedItems = items ?? errors.map((message) => ({ message }));
307
+ if (resolvedItems.length === 0) return null;
308
+ return /* @__PURE__ */ jsxs(Alert, {
309
+ role: "alert",
310
+ variant: "destructive",
311
+ children: [/* @__PURE__ */ jsx(AlertTitle, { children: title }), /* @__PURE__ */ jsx(AlertDescription, { children: /* @__PURE__ */ jsx("ul", { children: resolvedItems.map((item, index) => {
312
+ const focusPath = item.focusPath;
313
+ return /* @__PURE__ */ jsx("li", { children: focusPath && onSelect ? /* @__PURE__ */ jsx(ShadcnButton, {
314
+ "data-intent": "error-link",
315
+ onClick: () => onSelect(focusPath),
316
+ type: "button",
317
+ variant: "link",
318
+ children: item.message
319
+ }) : item.message }, `${item.path ?? "form"}-${item.message}-${index}`);
320
+ }) }) })]
321
+ });
322
+ }
323
+ function FormMessage({ kind, message }) {
324
+ return /* @__PURE__ */ jsx(Alert, {
325
+ "data-kind": kind,
326
+ role: kind === "error" ? "alert" : "status",
327
+ variant: kind === "error" ? "destructive" : "default",
328
+ children: /* @__PURE__ */ jsx(AlertDescription, { children: message })
329
+ });
330
+ }
331
+ function Unsupported({ field, reason }) {
332
+ return /* @__PURE__ */ jsxs(Alert, {
333
+ role: "alert",
334
+ children: [/* @__PURE__ */ jsx(AlertTitle, { children: field.label }), /* @__PURE__ */ jsx(AlertDescription, { children: reason })]
335
+ });
336
+ }
337
+ function Wizard({ children, currentStep, description, navigation, steps, title, totalSteps, ...props }) {
338
+ const headingId = useId();
339
+ const heading = useRef(null);
340
+ const previousStep = useRef(currentStep);
341
+ useEffect(() => {
342
+ if (previousStep.current !== currentStep) heading.current?.focus();
343
+ previousStep.current = currentStep;
344
+ }, [currentStep]);
345
+ return /* @__PURE__ */ jsxs("section", {
346
+ ...props,
347
+ "aria-labelledby": props["aria-labelledby"] ?? headingId,
348
+ "data-step-count": steps?.length,
349
+ "data-slot": "wizard",
350
+ children: [
351
+ steps && steps.length > 0 ? /* @__PURE__ */ jsx("ol", {
352
+ "aria-label": "Form steps",
353
+ "data-slot": "wizard-steps",
354
+ children: steps.map((step, index) => /* @__PURE__ */ jsxs("li", {
355
+ "aria-label": `${step.title}${step.completed ? ", completed" : ""}`,
356
+ "aria-current": step.current ? "step" : void 0,
357
+ "data-completed": step.completed || void 0,
358
+ children: [/* @__PURE__ */ jsx("span", {
359
+ "aria-hidden": "true",
360
+ children: index + 1
361
+ }), /* @__PURE__ */ jsx("span", {
362
+ "aria-hidden": "true",
363
+ children: step.title
364
+ })]
365
+ }, step.id))
366
+ }) : null,
367
+ /* @__PURE__ */ jsxs("div", { children: [
368
+ /* @__PURE__ */ jsxs("p", {
369
+ "aria-live": "polite",
370
+ children: [
371
+ "Step ",
372
+ currentStep,
373
+ " of ",
374
+ totalSteps
375
+ ]
376
+ }),
377
+ /* @__PURE__ */ jsx("h2", {
378
+ id: headingId,
379
+ ref: heading,
380
+ tabIndex: -1,
381
+ children: title
382
+ }),
383
+ description ? /* @__PURE__ */ jsx("p", { children: description }) : null
384
+ ] }),
385
+ /* @__PURE__ */ jsx(Progress, {
386
+ "aria-label": `Step ${currentStep} of ${totalSteps}`,
387
+ max: totalSteps,
388
+ value: currentStep
389
+ }),
390
+ /* @__PURE__ */ jsx(FieldGroup, { children }),
391
+ /* @__PURE__ */ jsx("nav", {
392
+ "aria-label": "Wizard navigation",
393
+ children: navigation
394
+ })
395
+ ]
396
+ });
397
+ }
398
+ return {
399
+ Array,
400
+ ArrayItem,
401
+ Button,
402
+ ErrorSummary,
403
+ Field,
404
+ Form,
405
+ FormMessage,
406
+ Group,
407
+ Unsupported,
408
+ Wizard
409
+ };
410
+ }
411
+ //#endregion
412
+ //#region src/factory.tsx
413
+ function createShadcnSetup(name, components, choices) {
414
+ const native = createNativeControls(components);
415
+ const adapter = createAdapter({
416
+ name,
417
+ controls: {
418
+ checkbox: choices.checkbox,
419
+ custom: {},
420
+ file: native.file,
421
+ input: native.input,
422
+ radio: choices.radio,
423
+ select: native.select,
424
+ textarea: native.textarea
425
+ },
426
+ slots: createSlots(components)
427
+ });
428
+ function Provider({ children }) {
429
+ return /* @__PURE__ */ jsx(FormAdapterProvider, {
430
+ adapter,
431
+ children
432
+ });
433
+ }
434
+ return {
435
+ adapter,
436
+ createForm: createFormFactory(adapter),
437
+ Provider
438
+ };
439
+ }
440
+ //#endregion
441
+ export { createShadcnSetup as t };
442
+
443
+ //# sourceMappingURL=factory-CI0_tPhU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory-CI0_tPhU.js","names":[],"sources":["../src/native-controls.tsx","../src/slots.tsx","../src/factory.tsx"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useRef,\n type ChangeEvent,\n type InputHTMLAttributes,\n type SelectHTMLAttributes,\n type TextareaHTMLAttributes,\n} from \"react\";\n\nimport {\n changedInputValue,\n inputType,\n inputValue,\n nativeControlProps,\n optionForValue,\n selectedOptionValue,\n serializedOptionValue,\n} from \"@formadapter/html/native\";\nimport type { ControlComponent, ControlProps } from \"@formadapter/react\";\n\nimport type { CommonShadcnComponents } from \"./components\";\n\ninterface FileMetadata {\n readonly lastModified: number;\n readonly name: string;\n readonly size: number;\n readonly type: string;\n}\n\nfunction isFileMetadata(value: unknown): value is FileMetadata {\n return typeof value === \"object\" && value !== null &&\n typeof (value as Partial<FileMetadata>).lastModified === \"number\" &&\n typeof (value as Partial<FileMetadata>).name === \"string\" &&\n typeof (value as Partial<FileMetadata>).size === \"number\" &&\n typeof (value as Partial<FileMetadata>).type === \"string\";\n}\n\nfunction controlledFiles(value: unknown): readonly FileMetadata[] {\n if (isFileMetadata(value)) return [value];\n if (typeof FileList !== \"undefined\" && value instanceof FileList) {\n return Array.from(value).filter(isFileMetadata);\n }\n if (!Array.isArray(value)) return [];\n return value.filter(isFileMetadata);\n}\n\nfunction nativeFilesMatch(value: unknown, files: FileList | null): boolean {\n const controlled = controlledFiles(value);\n if (controlled.length === 0 || files?.length !== controlled.length) {\n return false;\n }\n return controlled.every((file, index) => {\n const nativeFile = files.item(index);\n return nativeFile !== null &&\n (Object.is(file, nativeFile) ||\n (file.name === nativeFile.name &&\n file.size === nativeFile.size &&\n file.type === nativeFile.type &&\n file.lastModified === nativeFile.lastModified));\n });\n}\n\nexport interface NativeControls {\n readonly file: ControlComponent;\n readonly input: ControlComponent;\n readonly select: ControlComponent;\n readonly textarea: ControlComponent;\n}\n\nexport function createNativeControls(\n components: CommonShadcnComponents,\n): NativeControls {\n const {\n Input: ShadcnInput,\n NativeSelect,\n NativeSelectOption,\n Textarea: ShadcnTextarea,\n } = components;\n\n function InputControl({\n controlRef,\n disabled,\n field,\n id,\n inputProps,\n name,\n onBlur,\n onValueChange,\n readOnly,\n required,\n value,\n }: ControlProps): React.JSX.Element {\n const configured = nativeControlProps<InputHTMLAttributes<HTMLInputElement>>(\n field,\n );\n const type = inputType(field);\n\n return (\n <ShadcnInput\n {...configured.props}\n {...inputProps}\n className={configured.className}\n disabled={disabled || (readOnly && type === \"range\")}\n id={id}\n max={field.constraints.maximum}\n maxLength={field.constraints.maxLength}\n min={field.constraints.minimum}\n minLength={field.constraints.minLength}\n name={name}\n onBlur={onBlur}\n onChange={(event: ChangeEvent<HTMLInputElement>) => {\n if (readOnly) return;\n onValueChange(\n changedInputValue(\n field,\n event.currentTarget.value,\n event.currentTarget.valueAsNumber,\n ),\n );\n }}\n pattern={field.constraints.pattern}\n placeholder={field.config.placeholder ?? configured.props.placeholder}\n readOnly={readOnly}\n ref={controlRef}\n required={required}\n step={\n field.constraints.multipleOf ??\n (field.dataType === \"integer\"\n ? 1\n : field.dataType === \"number\"\n ? \"any\"\n : undefined)\n }\n style={configured.style}\n type={type}\n value={inputValue(value, type)}\n />\n );\n }\n\n function TextareaControl({\n controlRef,\n disabled,\n field,\n id,\n inputProps,\n name,\n onBlur,\n onValueChange,\n readOnly,\n required,\n value,\n }: ControlProps): React.JSX.Element {\n const configured =\n nativeControlProps<TextareaHTMLAttributes<HTMLTextAreaElement>>(field);\n\n return (\n <ShadcnTextarea\n {...configured.props}\n {...inputProps}\n className={configured.className}\n disabled={disabled}\n id={id}\n maxLength={field.constraints.maxLength}\n minLength={field.constraints.minLength}\n name={name}\n onBlur={onBlur}\n onChange={(event: ChangeEvent<HTMLTextAreaElement>) => {\n if (!readOnly) onValueChange(event.currentTarget.value);\n }}\n placeholder={field.config.placeholder ?? configured.props.placeholder}\n readOnly={readOnly}\n ref={controlRef}\n required={required}\n style={configured.style}\n value={inputValue(value)}\n />\n );\n }\n\n function SelectControl({\n controlRef,\n disabled,\n field,\n id,\n inputProps,\n name,\n onBlur,\n onValueChange,\n readOnly,\n required,\n value,\n }: ControlProps): React.JSX.Element {\n const configured =\n nativeControlProps<SelectHTMLAttributes<HTMLSelectElement>>(field);\n const { size: _configuredSize, ...configuredProps } = configured.props;\n const options = field.options ?? [];\n const placeholder = field.config.placeholder ?? \"Select an option\";\n\n return (\n <NativeSelect\n {...configuredProps}\n {...inputProps}\n aria-readonly={readOnly || undefined}\n className={configured.className}\n disabled={disabled || readOnly}\n id={id}\n name={name}\n onBlur={onBlur}\n onChange={(event: ChangeEvent<HTMLSelectElement>) => {\n if (readOnly) return;\n const selected = optionForValue(options, event.currentTarget.value);\n onValueChange(selected ? selected.value : \"\");\n }}\n ref={controlRef}\n required={required}\n style={configured.style}\n value={selectedOptionValue(options, value)}\n >\n <NativeSelectOption disabled={required} value=\"\">\n {placeholder}\n </NativeSelectOption>\n {options.map((option, index) => (\n <NativeSelectOption\n key={`${serializedOptionValue(option.value)}-${index}`}\n value={serializedOptionValue(option.value)}\n >\n {option.label}\n </NativeSelectOption>\n ))}\n </NativeSelect>\n );\n }\n\n function FileControl({\n controlRef,\n disabled,\n field,\n id,\n inputProps,\n name,\n onBlur,\n onValueChange,\n readOnly,\n required,\n value,\n }: ControlProps): React.JSX.Element {\n const configured = nativeControlProps<InputHTMLAttributes<HTMLInputElement>>(\n field,\n );\n const input = useRef<HTMLInputElement | null>(null);\n const setControlRef = useCallback((instance: HTMLInputElement | null) => {\n input.current = instance;\n controlRef(instance);\n }, [controlRef]);\n\n useEffect(() => {\n const current = input.current;\n if (current?.value && !nativeFilesMatch(value, current.files)) {\n current.value = \"\";\n }\n }, [value]);\n\n return (\n <ShadcnInput\n {...configured.props}\n {...inputProps}\n accept={\n field.constraints.accept ??\n field.constraints.contentMediaType ??\n configured.props.accept\n }\n className={configured.className}\n disabled={disabled || readOnly}\n id={id}\n multiple={field.config.multiple || field.constraints.multiple}\n name={name}\n onBlur={onBlur}\n onChange={(event: ChangeEvent<HTMLInputElement>) => {\n const files = event.currentTarget.files;\n onValueChange(\n field.config.multiple || field.constraints.multiple\n ? Array.from(files ?? [])\n : files?.[0] ?? \"\",\n );\n }}\n ref={setControlRef}\n required={required}\n style={configured.style}\n type=\"file\"\n />\n );\n }\n\n return {\n file: FileControl,\n input: InputControl,\n select: SelectControl,\n textarea: TextareaControl,\n };\n}\n","import {\n useEffect,\n useId,\n useRef,\n type ReactNode,\n} from \"react\";\n\nimport type {\n ArrayItemSlotProps,\n ArraySlotProps,\n ButtonIntent,\n ButtonSlotProps,\n ErrorSummarySlotProps,\n FieldSlotProps,\n FormAdapterSlots,\n FormMessageSlotProps,\n FormSlotProps,\n GroupSlotProps,\n UnsupportedSlotProps,\n WizardSlotProps,\n} from \"@formadapter/react\";\n\nimport type { CommonShadcnComponents } from \"./components\";\n\nfunction requiredLabel(label: string, required: boolean): ReactNode {\n return (\n <>\n {label}\n {required ? <span aria-hidden=\"true\"> *</span> : null}\n </>\n );\n}\n\nfunction buttonVariant(\n intent: ButtonIntent,\n): \"default\" | \"destructive\" | \"outline\" {\n if (intent === \"remove\") return \"destructive\";\n if (intent === \"move-up\" || intent === \"move-down\" || intent === \"previous\") {\n return \"outline\";\n }\n return \"default\";\n}\n\nexport function createSlots(\n components: CommonShadcnComponents,\n): FormAdapterSlots {\n const {\n Alert,\n AlertDescription,\n AlertTitle,\n Button: ShadcnButton,\n Field: ShadcnField,\n FieldContent,\n FieldDescription,\n FieldError,\n FieldGroup,\n FieldLabel,\n FieldLegend,\n FieldSet,\n FieldTitle,\n Progress,\n Spinner,\n } = components;\n\n function Form({ children, ...props }: FormSlotProps): ReactNode {\n return (\n <form {...props} data-slot=\"form\">\n {children}\n </form>\n );\n }\n\n function Field({\n children,\n controlId,\n descriptionId,\n error,\n errorId,\n field,\n invalid,\n required,\n validating,\n ...props\n }: FieldSlotProps): ReactNode {\n if (field.control === \"hidden\" || field.inputType === \"hidden\") {\n return children;\n }\n\n const checkbox = field.control === \"checkbox\";\n\n return (\n <ShadcnField\n {...props}\n data-field-path={field.path}\n data-invalid={invalid || undefined}\n data-validating={validating || undefined}\n orientation={checkbox ? \"horizontal\" : \"vertical\"}\n >\n {checkbox ? (\n <FieldLabel htmlFor={controlId}>\n {children}\n {requiredLabel(field.label, required)}\n </FieldLabel>\n ) : (\n <>\n <FieldLabel htmlFor={controlId}>\n {requiredLabel(field.label, required)}\n </FieldLabel>\n {children}\n </>\n )}\n {field.description ? (\n <FieldDescription id={descriptionId}>\n {field.description}\n </FieldDescription>\n ) : null}\n {validating ? (\n <FieldDescription>\n <output>Checking…</output>\n </FieldDescription>\n ) : null}\n {error ? <FieldError id={errorId}>{error}</FieldError> : null}\n </ShadcnField>\n );\n }\n\n function Group({\n children,\n disabled,\n error,\n errorId,\n field,\n readOnly,\n required,\n ...props\n }: GroupSlotProps): ReactNode {\n const descriptionId = useId();\n const describedBy = [\n props[\"aria-describedby\"],\n field.description ? descriptionId : undefined,\n error ? errorId : undefined,\n ].filter(Boolean).join(\" \") || undefined;\n\n return (\n <FieldSet\n {...props}\n aria-describedby={describedBy}\n aria-disabled={disabled || undefined}\n aria-invalid={error ? true : undefined}\n data-field-path={field.path}\n data-invalid={error ? true : undefined}\n data-readonly={readOnly || undefined}\n disabled={disabled}\n >\n <FieldLegend>{requiredLabel(field.label, required)}</FieldLegend>\n {field.description ? (\n <FieldDescription id={descriptionId}>\n {field.description}\n </FieldDescription>\n ) : null}\n <FieldGroup>{children}</FieldGroup>\n {error ? <FieldError id={errorId}>{error}</FieldError> : null}\n </FieldSet>\n );\n }\n\n function Array({\n actions,\n children,\n disabled,\n error,\n errorId,\n field,\n itemCount,\n readOnly,\n required,\n ...props\n }: ArraySlotProps): ReactNode {\n const descriptionId = useId();\n const describedBy = [\n props[\"aria-describedby\"],\n field.description ? descriptionId : undefined,\n error ? errorId : undefined,\n ].filter(Boolean).join(\" \") || undefined;\n\n return (\n <FieldSet\n {...props}\n aria-describedby={describedBy}\n aria-disabled={disabled || undefined}\n aria-invalid={error ? true : undefined}\n data-field-path={field.path}\n data-invalid={error ? true : undefined}\n data-item-count={itemCount}\n data-readonly={readOnly || undefined}\n disabled={disabled}\n >\n <FieldLegend>{requiredLabel(field.label, required)}</FieldLegend>\n {field.description ? (\n <FieldDescription id={descriptionId}>\n {field.description}\n </FieldDescription>\n ) : null}\n <FieldGroup data-slot=\"array-items\">{children}</FieldGroup>\n <ShadcnField data-slot=\"array-actions\" orientation=\"horizontal\">\n {actions}\n </ShadcnField>\n {error ? <FieldError id={errorId}>{error}</FieldError> : null}\n </FieldSet>\n );\n }\n\n function ArrayItem({\n actions,\n children,\n field,\n index,\n label,\n ...props\n }: ArrayItemSlotProps): ReactNode {\n const labelId = useId();\n\n return (\n <ShadcnField\n {...props}\n aria-labelledby={props[\"aria-labelledby\"] ?? labelId}\n data-array-path={field.path}\n data-item-index={index}\n role={props.role ?? \"group\"}\n >\n <ShadcnField orientation=\"horizontal\">\n <FieldTitle id={labelId}>{label}</FieldTitle>\n <div data-slot=\"array-item-actions\">{actions}</div>\n </ShadcnField>\n <FieldContent>{children}</FieldContent>\n </ShadcnField>\n );\n }\n\n function Button({\n ariaLabel,\n children,\n disabled,\n intent,\n onClick,\n pending,\n type,\n }: ButtonSlotProps): ReactNode {\n return (\n <ShadcnButton\n aria-busy={pending || undefined}\n aria-label={ariaLabel}\n data-intent={intent}\n disabled={disabled}\n onClick={onClick}\n type={type}\n variant={buttonVariant(intent)}\n >\n {pending ? <Spinner aria-hidden=\"true\" data-icon=\"inline-start\" /> : null}\n {children}\n </ShadcnButton>\n );\n }\n\n function ErrorSummary({\n errors,\n items,\n onSelect,\n title,\n }: ErrorSummarySlotProps): ReactNode {\n const resolvedItems: NonNullable<ErrorSummarySlotProps[\"items\"]> =\n items ?? errors.map((message) => ({ message }));\n\n if (resolvedItems.length === 0) return null;\n\n return (\n <Alert role=\"alert\" variant=\"destructive\">\n <AlertTitle>{title}</AlertTitle>\n <AlertDescription>\n <ul>\n {resolvedItems.map((item, index) => {\n const focusPath = item.focusPath;\n return (\n <li key={`${item.path ?? \"form\"}-${item.message}-${index}`}>\n {focusPath && onSelect ? (\n <ShadcnButton\n data-intent=\"error-link\"\n onClick={() => onSelect(focusPath)}\n type=\"button\"\n variant=\"link\"\n >\n {item.message}\n </ShadcnButton>\n ) : item.message}\n </li>\n );\n })}\n </ul>\n </AlertDescription>\n </Alert>\n );\n }\n\n function FormMessage({ kind, message }: FormMessageSlotProps): ReactNode {\n return (\n <Alert\n data-kind={kind}\n role={kind === \"error\" ? \"alert\" : \"status\"}\n variant={kind === \"error\" ? \"destructive\" : \"default\"}\n >\n <AlertDescription>{message}</AlertDescription>\n </Alert>\n );\n }\n\n function Unsupported({ field, reason }: UnsupportedSlotProps): ReactNode {\n return (\n <Alert role=\"alert\">\n <AlertTitle>{field.label}</AlertTitle>\n <AlertDescription>{reason}</AlertDescription>\n </Alert>\n );\n }\n\n function Wizard({\n children,\n currentStep,\n description,\n navigation,\n steps,\n title,\n totalSteps,\n ...props\n }: WizardSlotProps): ReactNode {\n const headingId = useId();\n const heading = useRef<HTMLHeadingElement | null>(null);\n const previousStep = useRef(currentStep);\n\n useEffect(() => {\n if (previousStep.current !== currentStep) heading.current?.focus();\n previousStep.current = currentStep;\n }, [currentStep]);\n\n return (\n <section\n {...props}\n aria-labelledby={props[\"aria-labelledby\"] ?? headingId}\n data-step-count={steps?.length}\n data-slot=\"wizard\"\n >\n {steps && steps.length > 0 ? (\n <ol aria-label=\"Form steps\" data-slot=\"wizard-steps\">\n {steps.map((step, index) => (\n <li\n aria-label={`${step.title}${step.completed ? \", completed\" : \"\"}`}\n aria-current={step.current ? \"step\" : undefined}\n data-completed={step.completed || undefined}\n key={step.id}\n >\n <span aria-hidden=\"true\">{index + 1}</span>\n <span aria-hidden=\"true\">{step.title}</span>\n </li>\n ))}\n </ol>\n ) : null}\n <div>\n <p aria-live=\"polite\">Step {currentStep} of {totalSteps}</p>\n <h2 id={headingId} ref={heading} tabIndex={-1}>{title}</h2>\n {description ? <p>{description}</p> : null}\n </div>\n <Progress\n aria-label={`Step ${currentStep} of ${totalSteps}`}\n max={totalSteps}\n value={currentStep}\n />\n <FieldGroup>{children}</FieldGroup>\n <nav aria-label=\"Wizard navigation\">{navigation}</nav>\n </section>\n );\n }\n\n return {\n Array,\n ArrayItem,\n Button,\n ErrorSummary,\n Field,\n Form,\n FormMessage,\n Group,\n Unsupported,\n Wizard,\n };\n}\n","import type { ComponentType, ReactNode } from \"react\";\n\nimport {\n createAdapter,\n createFormFactory,\n FormAdapterProvider,\n type ControlComponent,\n type CreateForm,\n type FormAdapter,\n} from \"@formadapter/react\";\n\nimport type { CommonShadcnComponents } from \"./components\";\nimport { createNativeControls } from \"./native-controls\";\nimport { createSlots } from \"./slots\";\n\ntype EmptyControls = Record<never, never>;\ntype ShadcnFormAdapter = FormAdapter<EmptyControls>;\n\nexport interface ShadcnProviderProps {\n readonly children: ReactNode;\n}\n\nexport interface ShadcnSetup {\n readonly adapter: ShadcnFormAdapter;\n readonly createForm: CreateForm<ShadcnFormAdapter>;\n readonly Provider: ComponentType<ShadcnProviderProps>;\n}\n\nexport interface ChoiceControls {\n readonly checkbox: ControlComponent;\n readonly radio: ControlComponent;\n}\n\nexport function createShadcnSetup(\n name: string,\n components: CommonShadcnComponents,\n choices: ChoiceControls,\n): ShadcnSetup {\n const native = createNativeControls(components);\n const adapter: ShadcnFormAdapter = createAdapter({\n name,\n controls: {\n checkbox: choices.checkbox,\n custom: {},\n file: native.file,\n input: native.input,\n radio: choices.radio,\n select: native.select,\n textarea: native.textarea,\n },\n slots: createSlots(components),\n });\n\n function Provider({ children }: ShadcnProviderProps): ReactNode {\n return (\n <FormAdapterProvider adapter={adapter}>\n {children}\n </FormAdapterProvider>\n );\n }\n\n return {\n adapter,\n createForm: createFormFactory(adapter),\n Provider,\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,151 @@
1
+ 'use client';
2
+ import { CreateForm, FormAdapter } from "@formadapter/react";
3
+ import { CSSProperties, ComponentPropsWithRef, ComponentType, ElementType, FocusEventHandler, ReactNode, Ref } from "react";
4
+
5
+ //#region src/components.d.ts
6
+ type ButtonProps = {
7
+ readonly "aria-busy"?: boolean | undefined;
8
+ readonly "aria-label"?: string | undefined;
9
+ readonly children?: ReactNode | undefined;
10
+ readonly "data-intent"?: string | undefined;
11
+ readonly disabled?: boolean | undefined;
12
+ readonly onClick?: (() => void) | undefined;
13
+ readonly type?: "button" | "submit" | undefined;
14
+ readonly variant: "default" | "destructive" | "outline" | "link";
15
+ };
16
+ type InputProps = Omit<ComponentPropsWithRef<"input">, "size">;
17
+ type TextareaProps = ComponentPropsWithRef<"textarea">;
18
+ type NativeSelectProps = Omit<ComponentPropsWithRef<"select">, "size">;
19
+ type NativeSelectOptionProps = ComponentPropsWithRef<"option">;
20
+ type FieldProps = ComponentPropsWithRef<"div"> & {
21
+ readonly orientation?: "vertical" | "horizontal";
22
+ };
23
+ type FieldContentProps = ComponentPropsWithRef<"div">;
24
+ type FieldDescriptionProps = ComponentPropsWithRef<"p">;
25
+ type FieldErrorProps = ComponentPropsWithRef<"div">;
26
+ type FieldGroupProps = ComponentPropsWithRef<"div">;
27
+ type FieldLabelProps = ComponentPropsWithRef<"label">;
28
+ type FieldLegendProps = ComponentPropsWithRef<"legend">;
29
+ type FieldSetProps = ComponentPropsWithRef<"fieldset">;
30
+ type FieldTitleProps = ComponentPropsWithRef<"div">;
31
+ type AlertProps = ComponentPropsWithRef<"div"> & {
32
+ readonly variant?: "default" | "destructive";
33
+ };
34
+ type AlertDescriptionProps = ComponentPropsWithRef<"div">;
35
+ type AlertTitleProps = ComponentPropsWithRef<"div">;
36
+ type SpinnerProps = ComponentPropsWithRef<"svg">;
37
+ type ProgressProps = {
38
+ readonly "aria-label"?: string | undefined;
39
+ readonly max: number;
40
+ readonly value: number;
41
+ };
42
+ interface CommonShadcnComponents {
43
+ readonly Alert: ElementType<AlertProps>;
44
+ readonly AlertDescription: ElementType<AlertDescriptionProps>;
45
+ readonly AlertTitle: ElementType<AlertTitleProps>;
46
+ readonly Button: ElementType<ButtonProps>;
47
+ readonly Field: ElementType<FieldProps>;
48
+ readonly FieldContent: ElementType<FieldContentProps>;
49
+ readonly FieldDescription: ElementType<FieldDescriptionProps>;
50
+ readonly FieldError: ElementType<FieldErrorProps>;
51
+ readonly FieldGroup: ElementType<FieldGroupProps>;
52
+ readonly FieldLabel: ElementType<FieldLabelProps>;
53
+ readonly FieldLegend: ElementType<FieldLegendProps>;
54
+ readonly FieldSet: ElementType<FieldSetProps>;
55
+ readonly FieldTitle: ElementType<FieldTitleProps>;
56
+ readonly Input: ElementType<InputProps>;
57
+ readonly NativeSelect: ElementType<NativeSelectProps>;
58
+ readonly NativeSelectOption: ElementType<NativeSelectOptionProps>;
59
+ readonly Progress: ElementType<ProgressProps>;
60
+ readonly Spinner: ElementType<SpinnerProps>;
61
+ readonly Textarea: ElementType<TextareaProps>;
62
+ }
63
+ type AccessiblePrimitiveProps = {
64
+ readonly "aria-describedby"?: string | undefined;
65
+ readonly "aria-invalid"?: true | undefined;
66
+ readonly "aria-label"?: string | undefined;
67
+ readonly "aria-readonly"?: boolean | undefined;
68
+ readonly className?: string | undefined;
69
+ readonly style?: CSSProperties | undefined;
70
+ };
71
+ type BaseUICheckboxProps = AccessiblePrimitiveProps & {
72
+ readonly checked: boolean;
73
+ readonly disabled: boolean;
74
+ readonly id: string;
75
+ readonly inputRef: Ref<HTMLInputElement>;
76
+ readonly name: string;
77
+ readonly onBlur: FocusEventHandler<HTMLElement>;
78
+ readonly onCheckedChange: (checked: boolean) => void;
79
+ readonly readOnly: boolean;
80
+ readonly required: boolean;
81
+ readonly tabIndex?: number | undefined;
82
+ readonly value: string;
83
+ };
84
+ type BaseUIRadioGroupProps = AccessiblePrimitiveProps & {
85
+ readonly disabled: boolean;
86
+ readonly name: string;
87
+ readonly onBlur: FocusEventHandler<HTMLElement>;
88
+ readonly onValueChange: (value: string) => void;
89
+ readonly readOnly: boolean;
90
+ readonly ref?: Ref<HTMLDivElement> | undefined;
91
+ readonly required: boolean;
92
+ readonly tabIndex?: number | undefined;
93
+ readonly value: string;
94
+ };
95
+ type BaseUIRadioGroupItemProps = AccessiblePrimitiveProps & {
96
+ readonly disabled: boolean;
97
+ readonly id: string;
98
+ readonly inputRef?: Ref<HTMLInputElement> | undefined;
99
+ readonly value: string;
100
+ };
101
+ interface BaseUIShadcnComponents extends CommonShadcnComponents {
102
+ readonly Checkbox: ElementType<BaseUICheckboxProps>;
103
+ readonly RadioGroup: ElementType<BaseUIRadioGroupProps>;
104
+ readonly RadioGroupItem: ElementType<BaseUIRadioGroupItemProps>;
105
+ }
106
+ type RadixCheckboxProps = AccessiblePrimitiveProps & {
107
+ readonly checked: boolean;
108
+ readonly disabled: boolean;
109
+ readonly id: string;
110
+ readonly name: string;
111
+ readonly onBlur: FocusEventHandler<HTMLButtonElement>;
112
+ readonly onCheckedChange: (checked: boolean | "indeterminate") => void;
113
+ readonly ref: Ref<HTMLButtonElement>;
114
+ readonly required: boolean;
115
+ readonly value: string;
116
+ };
117
+ type RadixRadioGroupProps = AccessiblePrimitiveProps & {
118
+ readonly disabled: boolean;
119
+ readonly name: string;
120
+ readonly onBlur: FocusEventHandler<HTMLDivElement>;
121
+ readonly onValueChange: (value: string) => void;
122
+ readonly ref?: Ref<HTMLDivElement> | undefined;
123
+ readonly required: boolean;
124
+ readonly value: string;
125
+ };
126
+ type RadixRadioGroupItemProps = AccessiblePrimitiveProps & {
127
+ readonly disabled: boolean;
128
+ readonly id: string;
129
+ readonly ref?: Ref<HTMLButtonElement> | undefined;
130
+ readonly value: string;
131
+ };
132
+ interface RadixShadcnComponents extends CommonShadcnComponents {
133
+ readonly Checkbox: ElementType<RadixCheckboxProps>;
134
+ readonly RadioGroup: ElementType<RadixRadioGroupProps>;
135
+ readonly RadioGroupItem: ElementType<RadixRadioGroupItemProps>;
136
+ }
137
+ //#endregion
138
+ //#region src/factory.d.ts
139
+ type EmptyControls = Record<never, never>;
140
+ type ShadcnFormAdapter = FormAdapter<EmptyControls>;
141
+ interface ShadcnProviderProps {
142
+ readonly children: ReactNode;
143
+ }
144
+ interface ShadcnSetup {
145
+ readonly adapter: ShadcnFormAdapter;
146
+ readonly createForm: CreateForm<ShadcnFormAdapter>;
147
+ readonly Provider: ComponentType<ShadcnProviderProps>;
148
+ }
149
+ //#endregion
150
+ export { RadixShadcnComponents as a, CommonShadcnComponents as i, ShadcnSetup as n, BaseUIShadcnComponents as r, ShadcnProviderProps as t };
151
+ //# sourceMappingURL=factory-FVm6mlf3.d.ts.map
@@ -0,0 +1,3 @@
1
+ 'use client';
2
+ import { a as RadixShadcnComponents, i as CommonShadcnComponents, n as ShadcnSetup, r as BaseUIShadcnComponents, t as ShadcnProviderProps } from "./factory-FVm6mlf3.js";
3
+ export { type BaseUIShadcnComponents, type CommonShadcnComponents, type RadixShadcnComponents, type ShadcnProviderProps, type ShadcnSetup };
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ 'use client';
@@ -0,0 +1,8 @@
1
+ 'use client';
2
+ import { a as RadixShadcnComponents, n as ShadcnSetup, t as ShadcnProviderProps } from "./factory-FVm6mlf3.js";
3
+
4
+ //#region src/radix.d.ts
5
+ declare function createShadcn(components: RadixShadcnComponents): ShadcnSetup;
6
+ //#endregion
7
+ export { type RadixShadcnComponents, type ShadcnProviderProps, type ShadcnSetup, createShadcn };
8
+ //# sourceMappingURL=radix.d.ts.map
package/dist/radix.js ADDED
@@ -0,0 +1,88 @@
1
+ 'use client';
2
+ import { t as createShadcnSetup } from "./factory-CI0_tPhU.js";
3
+ import { nativeControlProps, optionForValue, selectedOptionValue, serializedOptionValue } from "@formadapter/html/native";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/radix-controls.tsx
6
+ function requiresCheckedValue(field) {
7
+ return typeof field.source === "object" && field.source !== null && field.source.const === true;
8
+ }
9
+ function createRadixChoiceControls(components) {
10
+ const { Checkbox, Field, FieldLabel, RadioGroup, RadioGroupItem } = components;
11
+ function CheckboxControl({ controlRef, disabled, field, id, inputProps, invalid, name, onBlur, onValueChange, readOnly, required, value }) {
12
+ const configured = nativeControlProps(field);
13
+ return /* @__PURE__ */ jsx(Checkbox, {
14
+ ...configured.props,
15
+ ...inputProps,
16
+ "aria-invalid": invalid || void 0,
17
+ "aria-readonly": readOnly || void 0,
18
+ checked: value === true,
19
+ className: configured.className,
20
+ disabled: disabled || readOnly,
21
+ id,
22
+ name,
23
+ onBlur,
24
+ onCheckedChange: (checked) => {
25
+ if (!readOnly) onValueChange(checked === true);
26
+ },
27
+ ref: controlRef,
28
+ required: required && requiresCheckedValue(field),
29
+ style: configured.style,
30
+ value: "true"
31
+ });
32
+ }
33
+ function RadioControl({ controlRef, disabled, field, id, inputProps, invalid, name, onBlur, onValueChange, readOnly, required, value }) {
34
+ const options = field.options ?? [];
35
+ const unavailable = disabled || readOnly;
36
+ const configured = nativeControlProps(field);
37
+ return /* @__PURE__ */ jsx(RadioGroup, {
38
+ ...configured.props,
39
+ ...inputProps,
40
+ "aria-invalid": invalid || void 0,
41
+ "aria-label": inputProps["aria-label"] ?? field.label,
42
+ "aria-readonly": readOnly || void 0,
43
+ className: configured.className,
44
+ disabled: unavailable,
45
+ name,
46
+ onBlur,
47
+ onValueChange: (nextValue) => {
48
+ if (readOnly) return;
49
+ const selected = optionForValue(options, nextValue);
50
+ if (selected) onValueChange(selected.value);
51
+ },
52
+ ref: options.length === 0 ? controlRef : void 0,
53
+ required,
54
+ style: configured.style,
55
+ tabIndex: options.length === 0 ? -1 : void 0,
56
+ value: selectedOptionValue(options, value),
57
+ children: options.map((option, index) => {
58
+ const optionId = index === 0 ? id : `${id}-${index}`;
59
+ return /* @__PURE__ */ jsxs(Field, {
60
+ orientation: "horizontal",
61
+ children: [/* @__PURE__ */ jsx(RadioGroupItem, {
62
+ "aria-invalid": invalid || void 0,
63
+ disabled: unavailable,
64
+ id: optionId,
65
+ ref: index === 0 ? controlRef : void 0,
66
+ value: serializedOptionValue(option.value)
67
+ }), /* @__PURE__ */ jsx(FieldLabel, {
68
+ htmlFor: optionId,
69
+ children: option.label
70
+ })]
71
+ }, optionId);
72
+ })
73
+ });
74
+ }
75
+ return {
76
+ checkbox: CheckboxControl,
77
+ radio: RadioControl
78
+ };
79
+ }
80
+ //#endregion
81
+ //#region src/radix.ts
82
+ function createShadcn(components) {
83
+ return createShadcnSetup("shadcn/ui (Radix UI)", components, createRadixChoiceControls(components));
84
+ }
85
+ //#endregion
86
+ export { createShadcn };
87
+
88
+ //# sourceMappingURL=radix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radix.js","names":[],"sources":["../src/radix-controls.tsx","../src/radix.ts"],"sourcesContent":["import {\n nativeControlProps,\n optionForValue,\n selectedOptionValue,\n serializedOptionValue,\n} from \"@formadapter/html/native\";\nimport type { ControlProps } from \"@formadapter/react\";\n\nimport type { RadixShadcnComponents } from \"./components\";\nimport type { ChoiceControls } from \"./factory\";\n\nfunction requiresCheckedValue(field: ControlProps[\"field\"]): boolean {\n return typeof field.source === \"object\" && field.source !== null &&\n field.source.const === true;\n}\n\nexport function createRadixChoiceControls(\n components: RadixShadcnComponents,\n): ChoiceControls {\n const {\n Checkbox,\n Field,\n FieldLabel,\n RadioGroup,\n RadioGroupItem,\n } = components;\n\n function CheckboxControl({\n controlRef,\n disabled,\n field,\n id,\n inputProps,\n invalid,\n name,\n onBlur,\n onValueChange,\n readOnly,\n required,\n value,\n }: ControlProps): React.JSX.Element {\n const configured = nativeControlProps<Record<string, unknown>>(field);\n\n return (\n <Checkbox\n {...configured.props}\n {...inputProps}\n aria-invalid={invalid || undefined}\n aria-readonly={readOnly || undefined}\n checked={value === true}\n className={configured.className}\n disabled={disabled || readOnly}\n id={id}\n name={name}\n onBlur={onBlur}\n onCheckedChange={(checked) => {\n if (!readOnly) onValueChange(checked === true);\n }}\n ref={controlRef}\n required={required && requiresCheckedValue(field)}\n style={configured.style}\n value=\"true\"\n />\n );\n }\n\n function RadioControl({\n controlRef,\n disabled,\n field,\n id,\n inputProps,\n invalid,\n name,\n onBlur,\n onValueChange,\n readOnly,\n required,\n value,\n }: ControlProps): React.JSX.Element {\n const options = field.options ?? [];\n const unavailable = disabled || readOnly;\n const configured = nativeControlProps<Record<string, unknown>>(field);\n\n return (\n <RadioGroup\n {...configured.props}\n {...inputProps}\n aria-invalid={invalid || undefined}\n aria-label={inputProps[\"aria-label\"] ?? field.label}\n aria-readonly={readOnly || undefined}\n className={configured.className}\n disabled={unavailable}\n name={name}\n onBlur={onBlur}\n onValueChange={(nextValue) => {\n if (readOnly) return;\n const selected = optionForValue(options, nextValue);\n if (selected) onValueChange(selected.value);\n }}\n ref={options.length === 0 ? controlRef : undefined}\n required={required}\n style={configured.style}\n tabIndex={options.length === 0 ? -1 : undefined}\n value={selectedOptionValue(options, value)}\n >\n {options.map((option, index) => {\n const optionId = index === 0 ? id : `${id}-${index}`;\n return (\n <Field key={optionId} orientation=\"horizontal\">\n <RadioGroupItem\n aria-invalid={invalid || undefined}\n disabled={unavailable}\n id={optionId}\n ref={index === 0 ? controlRef : undefined}\n value={serializedOptionValue(option.value)}\n />\n <FieldLabel htmlFor={optionId}>{option.label}</FieldLabel>\n </Field>\n );\n })}\n </RadioGroup>\n );\n }\n\n return { checkbox: CheckboxControl, radio: RadioControl };\n}\n","import type { RadixShadcnComponents } from \"./components\";\nimport { createShadcnSetup, type ShadcnSetup } from \"./factory\";\nimport { createRadixChoiceControls } from \"./radix-controls\";\n\nexport type { RadixShadcnComponents } from \"./components\";\nexport type { ShadcnProviderProps, ShadcnSetup } from \"./factory\";\n\nexport function createShadcn(\n components: RadixShadcnComponents,\n): ShadcnSetup {\n return createShadcnSetup(\n \"shadcn/ui (Radix UI)\",\n components,\n createRadixChoiceControls(components),\n );\n}\n"],"mappings":";;;;;AAWA,SAAS,qBAAqB,OAAuC;AACnE,QAAO,OAAO,MAAM,WAAW,YAAY,MAAM,WAAW,QAC1D,MAAM,OAAO,UAAU;;AAG3B,SAAgB,0BACd,YACgB;CAChB,MAAM,EACJ,UACA,OACA,YACA,YACA,mBACE;CAEJ,SAAS,gBAAgB,EACvB,YACA,UACA,OACA,IACA,YACA,SACA,MACA,QACA,eACA,UACA,UACA,SACkC;EAClC,MAAM,aAAa,mBAA4C,MAAM;AAErE,SACE,oBAAC,UAAD;GACE,GAAI,WAAW;GACf,GAAI;GACJ,gBAAc,WAAW,KAAA;GACzB,iBAAe,YAAY,KAAA;GAC3B,SAAS,UAAU;GACnB,WAAW,WAAW;GACtB,UAAU,YAAY;GAClB;GACE;GACE;GACR,kBAAkB,YAAY;AAC5B,QAAI,CAAC,SAAU,eAAc,YAAY,KAAK;;GAEhD,KAAK;GACL,UAAU,YAAY,qBAAqB,MAAM;GACjD,OAAO,WAAW;GAClB,OAAM;GACN,CAAA;;CAIN,SAAS,aAAa,EACpB,YACA,UACA,OACA,IACA,YACA,SACA,MACA,QACA,eACA,UACA,UACA,SACkC;EAClC,MAAM,UAAU,MAAM,WAAW,EAAE;EACnC,MAAM,cAAc,YAAY;EAChC,MAAM,aAAa,mBAA4C,MAAM;AAErE,SACE,oBAAC,YAAD;GACE,GAAI,WAAW;GACf,GAAI;GACJ,gBAAc,WAAW,KAAA;GACzB,cAAY,WAAW,iBAAiB,MAAM;GAC9C,iBAAe,YAAY,KAAA;GAC3B,WAAW,WAAW;GACtB,UAAU;GACJ;GACE;GACR,gBAAgB,cAAc;AAC5B,QAAI,SAAU;IACd,MAAM,WAAW,eAAe,SAAS,UAAU;AACnD,QAAI,SAAU,eAAc,SAAS,MAAM;;GAE7C,KAAK,QAAQ,WAAW,IAAI,aAAa,KAAA;GAC/B;GACV,OAAO,WAAW;GAClB,UAAU,QAAQ,WAAW,IAAI,KAAK,KAAA;GACtC,OAAO,oBAAoB,SAAS,MAAM;aAEzC,QAAQ,KAAK,QAAQ,UAAU;IAC9B,MAAM,WAAW,UAAU,IAAI,KAAK,GAAG,GAAG,GAAG;AAC7C,WACE,qBAAC,OAAD;KAAsB,aAAY;eAAlC,CACE,oBAAC,gBAAD;MACE,gBAAc,WAAW,KAAA;MACzB,UAAU;MACV,IAAI;MACJ,KAAK,UAAU,IAAI,aAAa,KAAA;MAChC,OAAO,sBAAsB,OAAO,MAAM;MAC1C,CAAA,EACF,oBAAC,YAAD;MAAY,SAAS;gBAAW,OAAO;MAAmB,CAAA,CACpD;OATI,SASJ;KAEV;GACS,CAAA;;AAIjB,QAAO;EAAE,UAAU;EAAiB,OAAO;EAAc;;;;ACtH3D,SAAgB,aACd,YACa;AACb,QAAO,kBACL,wBACA,YACA,0BAA0B,WAAW,CACtC"}
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "@formadapter/shadcn",
3
+ "version": "0.0.0",
4
+ "description": "Typed Base UI and Radix bridges from FormAdapter to your shadcn/ui components.",
5
+ "keywords": [
6
+ "forms",
7
+ "react",
8
+ "schema",
9
+ "shadcn",
10
+ "tailwindcss",
11
+ "typescript"
12
+ ],
13
+ "homepage": "https://formadapter.com",
14
+ "bugs": {
15
+ "url": "https://github.com/ludicroushq/formadapter/issues"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/ludicroushq/formadapter.git",
20
+ "directory": "packages/shadcn"
21
+ },
22
+ "license": "MIT",
23
+ "author": "ludicrous",
24
+ "type": "module",
25
+ "sideEffects": false,
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "files": [
30
+ "dist",
31
+ "README.md",
32
+ "LICENSE"
33
+ ],
34
+ "main": "./dist/index.js",
35
+ "module": "./dist/index.js",
36
+ "types": "./dist/index.d.ts",
37
+ "exports": {
38
+ ".": {
39
+ "types": "./dist/index.d.ts",
40
+ "import": "./dist/index.js",
41
+ "default": "./dist/index.js"
42
+ },
43
+ "./baseui": {
44
+ "types": "./dist/baseui.d.ts",
45
+ "import": "./dist/baseui.js",
46
+ "default": "./dist/baseui.js"
47
+ },
48
+ "./radix": {
49
+ "types": "./dist/radix.d.ts",
50
+ "import": "./dist/radix.js",
51
+ "default": "./dist/radix.js"
52
+ },
53
+ "./package.json": "./package.json"
54
+ },
55
+ "dependencies": {
56
+ "@formadapter/html": "^0.0.0",
57
+ "@formadapter/react": "^0.0.0"
58
+ },
59
+ "peerDependencies": {
60
+ "react": "^19.0.0"
61
+ },
62
+ "devDependencies": {
63
+ "@formadapter/core": "^0.0.0",
64
+ "@types/react": "^19.2.17",
65
+ "@types/react-dom": "^19.2.3",
66
+ "react": "19.2.7",
67
+ "react-dom": "19.2.7",
68
+ "zod": "4.4.3"
69
+ },
70
+ "scripts": {
71
+ "build": "tsdown",
72
+ "clean": "rm -rf dist tsconfig.tsbuildinfo .turbo",
73
+ "dev": "tsdown --watch",
74
+ "test": "vitest run --config vitest.config.ts",
75
+ "test:coverage": "vitest run --config vitest.config.ts --coverage",
76
+ "typecheck": "tsc --project tsconfig.json --noEmit"
77
+ }
78
+ }