@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 +21 -0
- package/README.md +63 -0
- package/dist/baseui.d.ts +8 -0
- package/dist/baseui.js +89 -0
- package/dist/baseui.js.map +1 -0
- package/dist/factory-CI0_tPhU.js +443 -0
- package/dist/factory-CI0_tPhU.js.map +1 -0
- package/dist/factory-FVm6mlf3.d.ts +151 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -0
- package/dist/radix.d.ts +8 -0
- package/dist/radix.js +88 -0
- package/dist/radix.js.map +1 -0
- package/package.json +78 -0
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.
|
package/dist/baseui.d.ts
ADDED
|
@@ -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
|
package/dist/index.d.ts
ADDED
|
@@ -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';
|
package/dist/radix.d.ts
ADDED
|
@@ -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
|
+
}
|