pdyform 2.0.1 → 2.1.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/package.json +9 -3
- package/packages/core/dist/chunk-TP3IHKWV.js +69 -0
- package/packages/core/dist/{chunk-GQASS6PM.js → chunk-WEDHXOHH.js} +22 -0
- package/packages/core/dist/formState.cjs +187 -0
- package/packages/core/dist/formState.d.cts +17 -0
- package/packages/core/dist/formState.d.ts +17 -0
- package/packages/core/dist/formState.js +15 -0
- package/packages/core/dist/index.cjs +92 -2
- package/packages/core/dist/index.d.cts +2 -1
- package/packages/core/dist/index.d.ts +2 -1
- package/packages/core/dist/index.js +21 -3
- package/packages/core/dist/utils.cjs +27 -2
- package/packages/core/dist/utils.d.cts +4 -1
- package/packages/core/dist/utils.d.ts +4 -1
- package/packages/core/dist/utils.js +9 -3
- package/packages/react/dist/index.cjs +14 -43
- package/packages/react/dist/index.js +20 -43
- package/packages/vue/dist/index.d.ts +2 -36
- package/packages/vue/dist/index.js +1 -28
- package/packages/vue/dist/index.mjs +267 -6530
- package/eslint.config.mjs +0 -53
- package/example/README.md +0 -36
- package/example/react-demo/index.html +0 -12
- package/example/react-demo/node_modules/.bin/browserslist +0 -17
- package/example/react-demo/node_modules/.bin/tsc +0 -17
- package/example/react-demo/node_modules/.bin/tsserver +0 -17
- package/example/react-demo/node_modules/.bin/vite +0 -17
- package/example/react-demo/node_modules/.vite/deps/@radix-ui_react-checkbox.js +0 -300
- package/example/react-demo/node_modules/.vite/deps/@radix-ui_react-checkbox.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/@radix-ui_react-label.js +0 -194
- package/example/react-demo/node_modules/.vite/deps/@radix-ui_react-label.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/@radix-ui_react-radio-group.js +0 -530
- package/example/react-demo/node_modules/.vite/deps/@radix-ui_react-radio-group.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/@radix-ui_react-select.js +0 -4808
- package/example/react-demo/node_modules/.vite/deps/@radix-ui_react-select.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/_metadata.json +0 -115
- package/example/react-demo/node_modules/.vite/deps/chunk-3D5PZ6F6.js +0 -49
- package/example/react-demo/node_modules/.vite/deps/chunk-3D5PZ6F6.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/chunk-5Q2RBQLA.js +0 -127
- package/example/react-demo/node_modules/.vite/deps/chunk-5Q2RBQLA.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/chunk-G3PMV62Z.js +0 -36
- package/example/react-demo/node_modules/.vite/deps/chunk-G3PMV62Z.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/chunk-GX7YZ5KV.js +0 -370
- package/example/react-demo/node_modules/.vite/deps/chunk-GX7YZ5KV.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/chunk-PUFJGYAC.js +0 -928
- package/example/react-demo/node_modules/.vite/deps/chunk-PUFJGYAC.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/chunk-SIU35MPB.js +0 -21
- package/example/react-demo/node_modules/.vite/deps/chunk-SIU35MPB.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/chunk-TOMGVNQP.js +0 -1906
- package/example/react-demo/node_modules/.vite/deps/chunk-TOMGVNQP.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/chunk-YYN6DZAU.js +0 -21628
- package/example/react-demo/node_modules/.vite/deps/chunk-YYN6DZAU.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/chunk-ZE5VSJFE.js +0 -144
- package/example/react-demo/node_modules/.vite/deps/chunk-ZE5VSJFE.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/class-variance-authority.js +0 -51
- package/example/react-demo/node_modules/.vite/deps/class-variance-authority.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/clsx.js +0 -10
- package/example/react-demo/node_modules/.vite/deps/clsx.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/lucide-react.js +0 -29725
- package/example/react-demo/node_modules/.vite/deps/lucide-react.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/package.json +0 -3
- package/example/react-demo/node_modules/.vite/deps/react-dom.js +0 -7
- package/example/react-demo/node_modules/.vite/deps/react-dom.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/react-dom_client.js +0 -39
- package/example/react-demo/node_modules/.vite/deps/react-dom_client.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/react.js +0 -6
- package/example/react-demo/node_modules/.vite/deps/react.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/react_jsx-dev-runtime.js +0 -913
- package/example/react-demo/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/react_jsx-runtime.js +0 -7
- package/example/react-demo/node_modules/.vite/deps/react_jsx-runtime.js.map +0 -7
- package/example/react-demo/node_modules/.vite/deps/tailwind-merge.js +0 -2534
- package/example/react-demo/node_modules/.vite/deps/tailwind-merge.js.map +0 -7
- package/example/react-demo/package.json +0 -23
- package/example/react-demo/postcss.config.mjs +0 -6
- package/example/react-demo/src/App.tsx +0 -64
- package/example/react-demo/src/main.tsx +0 -10
- package/example/react-demo/src/styles.css +0 -102
- package/example/react-demo/tailwind.config.mjs +0 -50
- package/example/react-demo/tsconfig.json +0 -16
- package/example/react-demo/vite.config.ts +0 -14
- package/example/shared/defaultSchema.ts +0 -68
- package/example/vue-demo/index.html +0 -12
- package/example/vue-demo/node_modules/.bin/tsc +0 -17
- package/example/vue-demo/node_modules/.bin/tsserver +0 -17
- package/example/vue-demo/node_modules/.bin/vite +0 -17
- package/example/vue-demo/node_modules/.vite/deps/_metadata.json +0 -46
- package/example/vue-demo/node_modules/.vite/deps/chunk-PZ5AY32C.js +0 -10
- package/example/vue-demo/node_modules/.vite/deps/chunk-PZ5AY32C.js.map +0 -7
- package/example/vue-demo/node_modules/.vite/deps/chunk-TCXBSQ4M.js +0 -12877
- package/example/vue-demo/node_modules/.vite/deps/chunk-TCXBSQ4M.js.map +0 -7
- package/example/vue-demo/node_modules/.vite/deps/clsx.js +0 -22
- package/example/vue-demo/node_modules/.vite/deps/clsx.js.map +0 -7
- package/example/vue-demo/node_modules/.vite/deps/lucide-vue-next.js +0 -29720
- package/example/vue-demo/node_modules/.vite/deps/lucide-vue-next.js.map +0 -7
- package/example/vue-demo/node_modules/.vite/deps/package.json +0 -3
- package/example/vue-demo/node_modules/.vite/deps/radix-vue.js +0 -24321
- package/example/vue-demo/node_modules/.vite/deps/radix-vue.js.map +0 -7
- package/example/vue-demo/node_modules/.vite/deps/tailwind-merge.js +0 -2534
- package/example/vue-demo/node_modules/.vite/deps/tailwind-merge.js.map +0 -7
- package/example/vue-demo/node_modules/.vite/deps/vue.js +0 -348
- package/example/vue-demo/node_modules/.vite/deps/vue.js.map +0 -7
- package/example/vue-demo/package.json +0 -20
- package/example/vue-demo/postcss.config.mjs +0 -6
- package/example/vue-demo/src/App.vue +0 -61
- package/example/vue-demo/src/env.d.ts +0 -1
- package/example/vue-demo/src/main.ts +0 -5
- package/example/vue-demo/src/style.css +0 -102
- package/example/vue-demo/tailwind.config.mjs +0 -50
- package/example/vue-demo/tsconfig.json +0 -15
- package/example/vue-demo/vite.config.ts +0 -14
- package/packages/core/dist/parser.cjs +0 -1
- package/packages/core/dist/parser.d.cts +0 -2
- package/packages/core/dist/parser.d.ts +0 -2
- package/packages/core/dist/parser.js +0 -0
- package/packages/core/node_modules/.bin/api-extractor +0 -17
- package/packages/core/node_modules/.bin/esbuild +0 -14
- package/packages/core/node_modules/.bin/jiti +0 -17
- package/packages/core/node_modules/.bin/tsc +0 -17
- package/packages/core/node_modules/.bin/tsserver +0 -17
- package/packages/core/node_modules/.bin/tsup +0 -17
- package/packages/core/node_modules/.bin/tsup-node +0 -17
- package/packages/core/node_modules/.bin/vitest +0 -17
- package/packages/core/node_modules/.vite/vitest/results.json +0 -1
- package/packages/core/package.json +0 -37
- package/packages/core/src/index.ts +0 -2
- package/packages/core/src/parser.ts +0 -0
- package/packages/core/src/types.ts +0 -42
- package/packages/core/src/utils.ts +0 -80
- package/packages/core/test/utils.test.ts +0 -99
- package/packages/core/tsconfig.json +0 -15
- package/packages/core/tsup.config.ts +0 -9
- package/packages/react/node_modules/.bin/api-extractor +0 -17
- package/packages/react/node_modules/.bin/browserslist +0 -17
- package/packages/react/node_modules/.bin/esbuild +0 -14
- package/packages/react/node_modules/.bin/jiti +0 -17
- package/packages/react/node_modules/.bin/tsc +0 -17
- package/packages/react/node_modules/.bin/tsserver +0 -17
- package/packages/react/node_modules/.bin/tsup +0 -17
- package/packages/react/node_modules/.bin/tsup-node +0 -17
- package/packages/react/node_modules/.bin/vite +0 -17
- package/packages/react/node_modules/.bin/vitest +0 -17
- package/packages/react/node_modules/.vite/vitest/results.json +0 -1
- package/packages/react/package.json +0 -57
- package/packages/react/postcss.config.mjs +0 -6
- package/packages/react/src/DynamicForm.tsx +0 -93
- package/packages/react/src/FormFieldRenderer.tsx +0 -50
- package/packages/react/src/components/Checkbox.tsx +0 -28
- package/packages/react/src/components/CheckboxRenderer.tsx +0 -37
- package/packages/react/src/components/Input.tsx +0 -24
- package/packages/react/src/components/InputRenderer.tsx +0 -29
- package/packages/react/src/components/Label.tsx +0 -24
- package/packages/react/src/components/RadioGroup.tsx +0 -42
- package/packages/react/src/components/RadioRenderer.tsx +0 -29
- package/packages/react/src/components/Select.tsx +0 -93
- package/packages/react/src/components/SelectRenderer.tsx +0 -27
- package/packages/react/src/components/Textarea.tsx +0 -23
- package/packages/react/src/components/TextareaRenderer.tsx +0 -17
- package/packages/react/src/components/index.ts +0 -55
- package/packages/react/src/components/types.ts +0 -17
- package/packages/react/src/index.tsx +0 -3
- package/packages/react/src/utils.ts +0 -7
- package/packages/react/tailwind.config.mjs +0 -10
- package/packages/react/test/DynamicForm.test.tsx +0 -25
- package/packages/react/test/FormFieldRenderer.test.tsx +0 -127
- package/packages/react/tsconfig.json +0 -15
- package/packages/react/vitest.config.ts +0 -16
- package/packages/vue/node_modules/.bin/rollup +0 -17
- package/packages/vue/node_modules/.bin/tsc +0 -17
- package/packages/vue/node_modules/.bin/tsserver +0 -17
- package/packages/vue/node_modules/.bin/vite +0 -17
- package/packages/vue/node_modules/.bin/vitest +0 -17
- package/packages/vue/node_modules/.bin/vue-tsc +0 -17
- package/packages/vue/node_modules/.vite/vitest/results.json +0 -1
- package/packages/vue/node_modules/.vue-global-types/vue_3.5_0_0_0.d.ts +0 -118
- package/packages/vue/node_modules/.vue-global-types/vue_3.5_false.d.ts +0 -128
- package/packages/vue/package.json +0 -53
- package/packages/vue/postcss.config.mjs +0 -6
- package/packages/vue/src/DynamicForm.vue +0 -81
- package/packages/vue/src/FormFieldRenderer.vue +0 -70
- package/packages/vue/src/components/Checkbox.vue +0 -28
- package/packages/vue/src/components/CheckboxRenderer.vue +0 -35
- package/packages/vue/src/components/Input.vue +0 -21
- package/packages/vue/src/components/InputRenderer.vue +0 -28
- package/packages/vue/src/components/Label.vue +0 -21
- package/packages/vue/src/components/RadioGroup.vue +0 -30
- package/packages/vue/src/components/RadioGroupItem.vue +0 -26
- package/packages/vue/src/components/RadioRenderer.vue +0 -24
- package/packages/vue/src/components/Select.vue +0 -40
- package/packages/vue/src/components/SelectContent.vue +0 -38
- package/packages/vue/src/components/SelectItem.vue +0 -43
- package/packages/vue/src/components/SelectRenderer.vue +0 -30
- package/packages/vue/src/components/SelectTrigger.vue +0 -27
- package/packages/vue/src/components/Textarea.vue +0 -19
- package/packages/vue/src/components/TextareaRenderer.vue +0 -18
- package/packages/vue/src/components/index.ts +0 -24
- package/packages/vue/src/env.d.ts +0 -7
- package/packages/vue/src/fieldComponentMap.ts +0 -34
- package/packages/vue/src/index.ts +0 -4
- package/packages/vue/src/utils.ts +0 -6
- package/packages/vue/tailwind.config.mjs +0 -10
- package/packages/vue/test/DynamicForm.test.ts +0 -19
- package/packages/vue/test/FormFieldRenderer.test.ts +0 -133
- package/packages/vue/tsconfig.json +0 -16
- package/packages/vue/vite.config.ts +0 -29
- package/packages/vue/vitest.config.ts +0 -16
- package/pnpm-workspace.yaml +0 -4
- package/tsconfig.json +0 -21
- package/turbo.json +0 -25
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "pdyform-react",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "React components for pdyform based on Shadcn UI.",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"dynamic-form",
|
|
7
|
-
"schema-form",
|
|
8
|
-
"react",
|
|
9
|
-
"shadcn"
|
|
10
|
-
],
|
|
11
|
-
"type": "module",
|
|
12
|
-
"main": "./dist/index.js",
|
|
13
|
-
"module": "./dist/index.mjs",
|
|
14
|
-
"types": "./dist/index.d.ts",
|
|
15
|
-
"files": [
|
|
16
|
-
"dist"
|
|
17
|
-
],
|
|
18
|
-
"homepage": "https://github.com/LaoChen1994/pdyform",
|
|
19
|
-
"repository": {
|
|
20
|
-
"type": "git",
|
|
21
|
-
"url": "https://github.com/LaoChen1994/pdyform"
|
|
22
|
-
},
|
|
23
|
-
"scripts": {
|
|
24
|
-
"build": "tsup src/index.tsx --format cjs,esm --dts --clean --external react --external pdyform",
|
|
25
|
-
"dev": "tsup src/index.tsx --format cjs,esm --watch --dts --external react --external pdyform",
|
|
26
|
-
"test": "vitest run",
|
|
27
|
-
"lint": "eslint src/**/*.{ts,tsx} --no-error-on-unmatched-pattern"
|
|
28
|
-
},
|
|
29
|
-
"dependencies": {
|
|
30
|
-
"@radix-ui/react-checkbox": "^1.3.3",
|
|
31
|
-
"@radix-ui/react-label": "^2.1.8",
|
|
32
|
-
"@radix-ui/react-radio-group": "^1.3.8",
|
|
33
|
-
"@radix-ui/react-select": "^2.2.6",
|
|
34
|
-
"class-variance-authority": "^0.7.1",
|
|
35
|
-
"clsx": "^2.1.1",
|
|
36
|
-
"lucide-react": "^0.300.0",
|
|
37
|
-
"pdyform": "workspace:*",
|
|
38
|
-
"tailwind-merge": "^2.6.1"
|
|
39
|
-
},
|
|
40
|
-
"peerDependencies": {
|
|
41
|
-
"react": "^18.0.0",
|
|
42
|
-
"react-dom": "^18.0.0"
|
|
43
|
-
},
|
|
44
|
-
"devDependencies": {
|
|
45
|
-
"@testing-library/jest-dom": "^6.9.1",
|
|
46
|
-
"@testing-library/react": "^16.3.2",
|
|
47
|
-
"@types/react": "^18.0.0",
|
|
48
|
-
"@types/react-dom": "^18.0.0",
|
|
49
|
-
"@vitejs/plugin-react": "^5.1.4",
|
|
50
|
-
"jsdom": "^22.1.0",
|
|
51
|
-
"react": "^18.0.0",
|
|
52
|
-
"react-dom": "^18.0.0",
|
|
53
|
-
"tsup": "^8.0.0",
|
|
54
|
-
"typescript": "^5.0.0",
|
|
55
|
-
"vitest": "^1.0.0"
|
|
56
|
-
}
|
|
57
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import { FormSchema, validateField, getDefaultValues } from 'pdyform/core';
|
|
3
|
-
import { FormFieldRenderer } from './FormFieldRenderer';
|
|
4
|
-
|
|
5
|
-
interface DynamicFormProps {
|
|
6
|
-
schema: FormSchema;
|
|
7
|
-
onSubmit: (values: Record<string, any>) => void;
|
|
8
|
-
className?: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export const DynamicForm: React.FC<DynamicFormProps> = ({ schema, onSubmit, className }) => {
|
|
12
|
-
const [values, setValues] = useState<Record<string, any>>(getDefaultValues(schema.fields));
|
|
13
|
-
const [errors, setErrors] = useState<Record<string, string>>({});
|
|
14
|
-
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
15
|
-
|
|
16
|
-
const handleFieldChange = (name: string, value: any) => {
|
|
17
|
-
setValues((prev) => ({ ...prev, [name]: value }));
|
|
18
|
-
|
|
19
|
-
// Validate on change
|
|
20
|
-
const field = schema.fields.find(f => f.name === name);
|
|
21
|
-
if (field) {
|
|
22
|
-
const error = validateField(value, field);
|
|
23
|
-
setErrors((prev) => ({
|
|
24
|
-
...prev,
|
|
25
|
-
[name]: error || ''
|
|
26
|
-
}));
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
const handleFieldBlur = (name: string) => {
|
|
31
|
-
const field = schema.fields.find(f => f.name === name);
|
|
32
|
-
if (field) {
|
|
33
|
-
const error = validateField(values[name], field);
|
|
34
|
-
setErrors((prev) => ({
|
|
35
|
-
...prev,
|
|
36
|
-
[name]: error || ''
|
|
37
|
-
}));
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const handleSubmit = (e: React.FormEvent) => {
|
|
42
|
-
e.preventDefault();
|
|
43
|
-
setIsSubmitting(true);
|
|
44
|
-
|
|
45
|
-
const newErrors: Record<string, string> = {};
|
|
46
|
-
let hasError = false;
|
|
47
|
-
|
|
48
|
-
schema.fields.forEach((field) => {
|
|
49
|
-
const error = validateField(values[field.name], field);
|
|
50
|
-
if (error) {
|
|
51
|
-
newErrors[field.name] = error;
|
|
52
|
-
hasError = true;
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
setErrors(newErrors);
|
|
57
|
-
|
|
58
|
-
if (!hasError) {
|
|
59
|
-
onSubmit(values);
|
|
60
|
-
}
|
|
61
|
-
setIsSubmitting(false);
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
return (
|
|
65
|
-
<form onSubmit={handleSubmit} className={`space-y-6 ${className || ''}`}>
|
|
66
|
-
{schema.title && <h2 className="text-2xl font-bold tracking-tight">{schema.title}</h2>}
|
|
67
|
-
{schema.description && <p className="text-muted-foreground">{schema.description}</p>}
|
|
68
|
-
|
|
69
|
-
<div className="space-y-4">
|
|
70
|
-
{schema.fields.map((field) => (
|
|
71
|
-
!field.hidden && (
|
|
72
|
-
<FormFieldRenderer
|
|
73
|
-
key={field.name}
|
|
74
|
-
field={field}
|
|
75
|
-
value={values[field.name]}
|
|
76
|
-
onChange={(val) => handleFieldChange(field.name, val)}
|
|
77
|
-
onBlur={() => handleFieldBlur(field.name)}
|
|
78
|
-
error={errors[field.name]}
|
|
79
|
-
/>
|
|
80
|
-
)
|
|
81
|
-
))}
|
|
82
|
-
</div>
|
|
83
|
-
|
|
84
|
-
<button
|
|
85
|
-
type="submit"
|
|
86
|
-
disabled={isSubmitting}
|
|
87
|
-
className="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 w-full"
|
|
88
|
-
>
|
|
89
|
-
{isSubmitting ? 'Submitting...' : (schema.submitButtonText || 'Submit')}
|
|
90
|
-
</button>
|
|
91
|
-
</form>
|
|
92
|
-
);
|
|
93
|
-
};
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { FormField } from 'pdyform/core';
|
|
3
|
-
import { Label, defaultComponentMap, InputRenderer } from './components';
|
|
4
|
-
import type { FieldComponentMap } from './components';
|
|
5
|
-
|
|
6
|
-
export interface FormFieldRendererProps {
|
|
7
|
-
field: FormField;
|
|
8
|
-
value: any;
|
|
9
|
-
onChange: (value: any) => void;
|
|
10
|
-
onBlur?: () => void;
|
|
11
|
-
error?: string;
|
|
12
|
-
/**
|
|
13
|
-
* Custom component map merged with the default map — external entries win.
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```tsx
|
|
17
|
-
* import { defaultComponentMap } from 'pdyform-react';
|
|
18
|
-
* const myMap = { ...defaultComponentMap, text: MyInput, rating: StarRating };
|
|
19
|
-
* <FormFieldRenderer componentMap={myMap} ... />
|
|
20
|
-
* ```
|
|
21
|
-
*/
|
|
22
|
-
componentMap?: FieldComponentMap;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export const FormFieldRenderer: React.FC<FormFieldRendererProps> = ({
|
|
26
|
-
field,
|
|
27
|
-
value,
|
|
28
|
-
onChange,
|
|
29
|
-
onBlur,
|
|
30
|
-
error,
|
|
31
|
-
componentMap,
|
|
32
|
-
}) => {
|
|
33
|
-
const { label, description, name, type } = field;
|
|
34
|
-
const fieldId = `field-${name}`;
|
|
35
|
-
|
|
36
|
-
const resolvedMap: FieldComponentMap = componentMap
|
|
37
|
-
? { ...defaultComponentMap, ...componentMap }
|
|
38
|
-
: defaultComponentMap;
|
|
39
|
-
|
|
40
|
-
const FieldComponent = resolvedMap[type] ?? InputRenderer;
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<div className={`space-y-2 ${field.className || ''}`}>
|
|
44
|
-
{label && <Label htmlFor={fieldId}>{label}</Label>}
|
|
45
|
-
<FieldComponent field={field} value={value} onChange={onChange} onBlur={onBlur} fieldId={fieldId} />
|
|
46
|
-
{description && <p className="text-[0.8rem] text-muted-foreground">{description}</p>}
|
|
47
|
-
{error && <p className="text-[0.8rem] font-medium text-destructive">{error}</p>}
|
|
48
|
-
</div>
|
|
49
|
-
);
|
|
50
|
-
};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
|
|
3
|
-
import { Check } from "lucide-react"
|
|
4
|
-
|
|
5
|
-
import { cn } from "../utils"
|
|
6
|
-
|
|
7
|
-
const Checkbox = React.forwardRef<
|
|
8
|
-
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
|
9
|
-
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
|
|
10
|
-
>(({ className, ...props }, ref) => (
|
|
11
|
-
<CheckboxPrimitive.Root
|
|
12
|
-
ref={ref}
|
|
13
|
-
className={cn(
|
|
14
|
-
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
|
15
|
-
className
|
|
16
|
-
)}
|
|
17
|
-
{...props}
|
|
18
|
-
>
|
|
19
|
-
<CheckboxPrimitive.Indicator
|
|
20
|
-
className={cn("flex items-center justify-center text-current")}
|
|
21
|
-
>
|
|
22
|
-
<Check className="h-4 w-4" />
|
|
23
|
-
</CheckboxPrimitive.Indicator>
|
|
24
|
-
</CheckboxPrimitive.Root>
|
|
25
|
-
))
|
|
26
|
-
Checkbox.displayName = CheckboxPrimitive.Root.displayName
|
|
27
|
-
|
|
28
|
-
export { Checkbox }
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { FieldRenderContext } from './types';
|
|
3
|
-
import { Checkbox } from './Checkbox';
|
|
4
|
-
import { Label } from './Label';
|
|
5
|
-
|
|
6
|
-
const CheckboxRenderer: React.FC<FieldRenderContext> = ({ field, value, onChange, onBlur }) => (
|
|
7
|
-
<div className="flex flex-wrap gap-4">
|
|
8
|
-
{field.options?.map((opt) => {
|
|
9
|
-
const checked = Array.isArray(value) && value.includes(opt.value);
|
|
10
|
-
return (
|
|
11
|
-
<div key={opt.value} className="flex items-center space-x-2">
|
|
12
|
-
<Checkbox
|
|
13
|
-
id={`checkbox-${field.name}-${opt.value}`}
|
|
14
|
-
checked={checked}
|
|
15
|
-
disabled={field.disabled}
|
|
16
|
-
onCheckedChange={(c) => {
|
|
17
|
-
const next = Array.isArray(value) ? [...value] : [];
|
|
18
|
-
if (c) {
|
|
19
|
-
next.push(opt.value);
|
|
20
|
-
} else {
|
|
21
|
-
const idx = next.indexOf(opt.value);
|
|
22
|
-
if (idx > -1) next.splice(idx, 1);
|
|
23
|
-
}
|
|
24
|
-
onChange(next);
|
|
25
|
-
}}
|
|
26
|
-
onBlur={onBlur}
|
|
27
|
-
/>
|
|
28
|
-
<Label htmlFor={`checkbox-${field.name}-${opt.value}`} className="font-normal">
|
|
29
|
-
{opt.label}
|
|
30
|
-
</Label>
|
|
31
|
-
</div>
|
|
32
|
-
);
|
|
33
|
-
})}
|
|
34
|
-
</div>
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
export default CheckboxRenderer;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import { cn } from "../utils"
|
|
3
|
-
|
|
4
|
-
export interface InputProps
|
|
5
|
-
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
|
6
|
-
|
|
7
|
-
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
8
|
-
({ className, type, ...props }, ref) => {
|
|
9
|
-
return (
|
|
10
|
-
<input
|
|
11
|
-
type={type}
|
|
12
|
-
className={cn(
|
|
13
|
-
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
14
|
-
className
|
|
15
|
-
)}
|
|
16
|
-
ref={ref}
|
|
17
|
-
{...props}
|
|
18
|
-
/>
|
|
19
|
-
)
|
|
20
|
-
}
|
|
21
|
-
)
|
|
22
|
-
Input.displayName = "Input"
|
|
23
|
-
|
|
24
|
-
export { Input }
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { FieldRenderContext } from './types';
|
|
3
|
-
import { Input } from './Input';
|
|
4
|
-
|
|
5
|
-
const InputRenderer: React.FC<FieldRenderContext> = ({ field, value, onChange, onBlur, fieldId }) => {
|
|
6
|
-
const handleChange = (nextValue: string) => {
|
|
7
|
-
if (field.type !== 'number') {
|
|
8
|
-
onChange(nextValue);
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
onChange(nextValue === '' ? '' : Number(nextValue));
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
return (
|
|
16
|
-
<Input
|
|
17
|
-
id={fieldId}
|
|
18
|
-
type={field.type}
|
|
19
|
-
placeholder={field.placeholder}
|
|
20
|
-
value={value ?? ''}
|
|
21
|
-
onChange={(e) => handleChange(e.target.value)}
|
|
22
|
-
onBlur={onBlur}
|
|
23
|
-
disabled={field.disabled}
|
|
24
|
-
name={field.name}
|
|
25
|
-
/>
|
|
26
|
-
);
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export default InputRenderer;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import * as LabelPrimitive from "@radix-ui/react-label"
|
|
3
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
4
|
-
|
|
5
|
-
import { cn } from "../utils"
|
|
6
|
-
|
|
7
|
-
const labelVariants = cva(
|
|
8
|
-
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
const Label = React.forwardRef<
|
|
12
|
-
React.ElementRef<typeof LabelPrimitive.Root>,
|
|
13
|
-
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
|
|
14
|
-
VariantProps<typeof labelVariants>
|
|
15
|
-
>(({ className, ...props }, ref) => (
|
|
16
|
-
<LabelPrimitive.Root
|
|
17
|
-
ref={ref}
|
|
18
|
-
className={cn(labelVariants(), className)}
|
|
19
|
-
{...props}
|
|
20
|
-
/>
|
|
21
|
-
))
|
|
22
|
-
Label.displayName = LabelPrimitive.Root.displayName
|
|
23
|
-
|
|
24
|
-
export { Label }
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
|
|
3
|
-
import { Circle } from "lucide-react"
|
|
4
|
-
|
|
5
|
-
import { cn } from "../utils"
|
|
6
|
-
|
|
7
|
-
const RadioGroup = React.forwardRef<
|
|
8
|
-
React.ElementRef<typeof RadioGroupPrimitive.Root>,
|
|
9
|
-
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
|
|
10
|
-
>(({ className, ...props }, ref) => {
|
|
11
|
-
return (
|
|
12
|
-
<RadioGroupPrimitive.Root
|
|
13
|
-
className={cn("grid gap-2", className)}
|
|
14
|
-
{...props}
|
|
15
|
-
ref={ref}
|
|
16
|
-
/>
|
|
17
|
-
)
|
|
18
|
-
})
|
|
19
|
-
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName
|
|
20
|
-
|
|
21
|
-
const RadioGroupItem = React.forwardRef<
|
|
22
|
-
React.ElementRef<typeof RadioGroupPrimitive.Item>,
|
|
23
|
-
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
|
|
24
|
-
>(({ className, ...props }, ref) => {
|
|
25
|
-
return (
|
|
26
|
-
<RadioGroupPrimitive.Item
|
|
27
|
-
ref={ref}
|
|
28
|
-
className={cn(
|
|
29
|
-
"aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
30
|
-
className
|
|
31
|
-
)}
|
|
32
|
-
{...props}
|
|
33
|
-
>
|
|
34
|
-
<RadioGroupPrimitive.Indicator className="flex items-center justify-center">
|
|
35
|
-
<Circle className="h-2.5 w-2.5 fill-current text-current" />
|
|
36
|
-
</RadioGroupPrimitive.Indicator>
|
|
37
|
-
</RadioGroupPrimitive.Item>
|
|
38
|
-
)
|
|
39
|
-
})
|
|
40
|
-
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName
|
|
41
|
-
|
|
42
|
-
export { RadioGroup, RadioGroupItem }
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { FieldRenderContext } from './types';
|
|
3
|
-
import { RadioGroup, RadioGroupItem } from './RadioGroup';
|
|
4
|
-
import { Label } from './Label';
|
|
5
|
-
|
|
6
|
-
const RadioRenderer: React.FC<FieldRenderContext> = ({ field, value, onChange, onBlur }) => (
|
|
7
|
-
<RadioGroup
|
|
8
|
-
value={value != null ? String(value) : ''}
|
|
9
|
-
onValueChange={onChange}
|
|
10
|
-
disabled={field.disabled}
|
|
11
|
-
name={field.name}
|
|
12
|
-
className="flex flex-wrap gap-4"
|
|
13
|
-
>
|
|
14
|
-
{field.options?.map((opt) => (
|
|
15
|
-
<div key={opt.value} className="flex items-center space-x-2">
|
|
16
|
-
<RadioGroupItem
|
|
17
|
-
value={String(opt.value)}
|
|
18
|
-
id={`radio-${field.name}-${opt.value}`}
|
|
19
|
-
onBlur={onBlur}
|
|
20
|
-
/>
|
|
21
|
-
<Label htmlFor={`radio-${field.name}-${opt.value}`} className="font-normal">
|
|
22
|
-
{opt.label}
|
|
23
|
-
</Label>
|
|
24
|
-
</div>
|
|
25
|
-
))}
|
|
26
|
-
</RadioGroup>
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
export default RadioRenderer;
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import * as SelectPrimitive from "@radix-ui/react-select"
|
|
3
|
-
import { Check, ChevronDown, ChevronUp } from "lucide-react"
|
|
4
|
-
|
|
5
|
-
import { cn } from "../utils"
|
|
6
|
-
|
|
7
|
-
const Select = SelectPrimitive.Root
|
|
8
|
-
|
|
9
|
-
const SelectGroup = SelectPrimitive.Group
|
|
10
|
-
|
|
11
|
-
const SelectValue = SelectPrimitive.Value
|
|
12
|
-
|
|
13
|
-
const SelectTrigger = React.forwardRef<
|
|
14
|
-
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
|
15
|
-
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
|
|
16
|
-
>(({ className, children, ...props }, ref) => (
|
|
17
|
-
<SelectPrimitive.Trigger
|
|
18
|
-
ref={ref}
|
|
19
|
-
className={cn(
|
|
20
|
-
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
21
|
-
className
|
|
22
|
-
)}
|
|
23
|
-
{...props}
|
|
24
|
-
>
|
|
25
|
-
{children}
|
|
26
|
-
<SelectPrimitive.Icon asChild>
|
|
27
|
-
<ChevronDown className="h-4 w-4 opacity-50" />
|
|
28
|
-
</SelectPrimitive.Icon>
|
|
29
|
-
</SelectPrimitive.Trigger>
|
|
30
|
-
))
|
|
31
|
-
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
|
|
32
|
-
|
|
33
|
-
const SelectContent = React.forwardRef<
|
|
34
|
-
React.ElementRef<typeof SelectPrimitive.Content>,
|
|
35
|
-
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
|
36
|
-
>(({ className, children, position = "popper", ...props }, ref) => (
|
|
37
|
-
<SelectPrimitive.Portal>
|
|
38
|
-
<SelectPrimitive.Content
|
|
39
|
-
ref={ref}
|
|
40
|
-
className={cn(
|
|
41
|
-
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
42
|
-
position === "popper" &&
|
|
43
|
-
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
|
44
|
-
className
|
|
45
|
-
)}
|
|
46
|
-
position={position}
|
|
47
|
-
{...props}
|
|
48
|
-
>
|
|
49
|
-
<SelectPrimitive.Viewport
|
|
50
|
-
className={cn(
|
|
51
|
-
"p-1",
|
|
52
|
-
position === "popper" &&
|
|
53
|
-
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
|
54
|
-
)}
|
|
55
|
-
>
|
|
56
|
-
{children}
|
|
57
|
-
</SelectPrimitive.Viewport>
|
|
58
|
-
</SelectPrimitive.Content>
|
|
59
|
-
</SelectPrimitive.Portal>
|
|
60
|
-
))
|
|
61
|
-
SelectContent.displayName = SelectPrimitive.Content.displayName
|
|
62
|
-
|
|
63
|
-
const SelectItem = React.forwardRef<
|
|
64
|
-
React.ElementRef<typeof SelectPrimitive.Item>,
|
|
65
|
-
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
|
|
66
|
-
>(({ className, children, ...props }, ref) => (
|
|
67
|
-
<SelectPrimitive.Item
|
|
68
|
-
ref={ref}
|
|
69
|
-
className={cn(
|
|
70
|
-
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
71
|
-
className
|
|
72
|
-
)}
|
|
73
|
-
{...props}
|
|
74
|
-
>
|
|
75
|
-
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
76
|
-
<SelectPrimitive.ItemIndicator>
|
|
77
|
-
<Check className="h-4 w-4" />
|
|
78
|
-
</SelectPrimitive.ItemIndicator>
|
|
79
|
-
</span>
|
|
80
|
-
|
|
81
|
-
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
|
82
|
-
</SelectPrimitive.Item>
|
|
83
|
-
))
|
|
84
|
-
SelectItem.displayName = SelectPrimitive.Item.displayName
|
|
85
|
-
|
|
86
|
-
export {
|
|
87
|
-
Select,
|
|
88
|
-
SelectGroup,
|
|
89
|
-
SelectValue,
|
|
90
|
-
SelectTrigger,
|
|
91
|
-
SelectContent,
|
|
92
|
-
SelectItem,
|
|
93
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { FieldRenderContext } from './types';
|
|
3
|
-
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from './Select';
|
|
4
|
-
|
|
5
|
-
const SelectRenderer: React.FC<FieldRenderContext> = ({ field, value, onChange, onBlur, fieldId }) => (
|
|
6
|
-
<Select
|
|
7
|
-
value={value != null ? String(value) : ''}
|
|
8
|
-
onValueChange={onChange}
|
|
9
|
-
disabled={field.disabled}
|
|
10
|
-
name={field.name}
|
|
11
|
-
>
|
|
12
|
-
<SelectTrigger id={fieldId} onBlur={onBlur}>
|
|
13
|
-
<SelectValue placeholder={field.placeholder || 'Select an option'} />
|
|
14
|
-
</SelectTrigger>
|
|
15
|
-
<SelectContent>
|
|
16
|
-
<SelectGroup>
|
|
17
|
-
{field.options?.map((opt) => (
|
|
18
|
-
<SelectItem key={opt.value} value={String(opt.value)}>
|
|
19
|
-
{opt.label}
|
|
20
|
-
</SelectItem>
|
|
21
|
-
))}
|
|
22
|
-
</SelectGroup>
|
|
23
|
-
</SelectContent>
|
|
24
|
-
</Select>
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
export default SelectRenderer;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import { cn } from "../utils"
|
|
3
|
-
|
|
4
|
-
export interface TextareaProps
|
|
5
|
-
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
|
6
|
-
|
|
7
|
-
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
8
|
-
({ className, ...props }, ref) => {
|
|
9
|
-
return (
|
|
10
|
-
<textarea
|
|
11
|
-
className={cn(
|
|
12
|
-
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
13
|
-
className
|
|
14
|
-
)}
|
|
15
|
-
ref={ref}
|
|
16
|
-
{...props}
|
|
17
|
-
/>
|
|
18
|
-
)
|
|
19
|
-
}
|
|
20
|
-
)
|
|
21
|
-
Textarea.displayName = "Textarea"
|
|
22
|
-
|
|
23
|
-
export { Textarea }
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { FieldRenderContext } from './types';
|
|
3
|
-
import { Textarea } from './Textarea';
|
|
4
|
-
|
|
5
|
-
const TextareaRenderer: React.FC<FieldRenderContext> = ({ field, value, onChange, onBlur, fieldId }) => (
|
|
6
|
-
<Textarea
|
|
7
|
-
id={fieldId}
|
|
8
|
-
placeholder={field.placeholder}
|
|
9
|
-
value={value ?? ''}
|
|
10
|
-
onChange={(e) => onChange(e.target.value)}
|
|
11
|
-
onBlur={onBlur}
|
|
12
|
-
disabled={field.disabled}
|
|
13
|
-
name={field.name}
|
|
14
|
-
/>
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
export default TextareaRenderer;
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
// ─── Primitive UI components ─────────────────────────────────────────────────
|
|
2
|
-
export { Input } from './Input';
|
|
3
|
-
export { Textarea } from './Textarea';
|
|
4
|
-
export { Checkbox } from './Checkbox';
|
|
5
|
-
export { RadioGroup, RadioGroupItem } from './RadioGroup';
|
|
6
|
-
export {
|
|
7
|
-
Select,
|
|
8
|
-
SelectGroup,
|
|
9
|
-
SelectValue,
|
|
10
|
-
SelectTrigger,
|
|
11
|
-
SelectContent,
|
|
12
|
-
SelectItem,
|
|
13
|
-
} from './Select';
|
|
14
|
-
export { Label } from './Label';
|
|
15
|
-
|
|
16
|
-
// ─── Field renderer components ────────────────────────────────────────────────
|
|
17
|
-
export { default as InputRenderer } from './InputRenderer';
|
|
18
|
-
export { default as TextareaRenderer } from './TextareaRenderer';
|
|
19
|
-
export { default as SelectRenderer } from './SelectRenderer';
|
|
20
|
-
export { default as CheckboxRenderer } from './CheckboxRenderer';
|
|
21
|
-
export { default as RadioRenderer } from './RadioRenderer';
|
|
22
|
-
|
|
23
|
-
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
24
|
-
export type { FieldRenderContext, FieldRenderer, FieldComponentMap } from './types';
|
|
25
|
-
|
|
26
|
-
// ─── Default component map ───────────────────────────────────────────────────
|
|
27
|
-
import InputRenderer from './InputRenderer';
|
|
28
|
-
import TextareaRenderer from './TextareaRenderer';
|
|
29
|
-
import SelectRenderer from './SelectRenderer';
|
|
30
|
-
import CheckboxRenderer from './CheckboxRenderer';
|
|
31
|
-
import RadioRenderer from './RadioRenderer';
|
|
32
|
-
import type { FieldComponentMap } from './types';
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* The default built-in component map.
|
|
36
|
-
* Import and spread this to extend or override individual field types:
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```tsx
|
|
40
|
-
* import { defaultComponentMap } from 'pdyform-react';
|
|
41
|
-
* const myMap = { ...defaultComponentMap, text: MyInput, rating: StarRating };
|
|
42
|
-
* <FormFieldRenderer componentMap={myMap} ... />
|
|
43
|
-
* ```
|
|
44
|
-
*/
|
|
45
|
-
export const defaultComponentMap: FieldComponentMap = {
|
|
46
|
-
text: InputRenderer,
|
|
47
|
-
number: InputRenderer,
|
|
48
|
-
password: InputRenderer,
|
|
49
|
-
email: InputRenderer,
|
|
50
|
-
date: InputRenderer,
|
|
51
|
-
textarea: TextareaRenderer,
|
|
52
|
-
select: SelectRenderer,
|
|
53
|
-
checkbox: CheckboxRenderer,
|
|
54
|
-
radio: RadioRenderer,
|
|
55
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type React from 'react';
|
|
2
|
-
import type { FormField } from 'pdyform/core';
|
|
3
|
-
|
|
4
|
-
/** All props passed into each individual field renderer component */
|
|
5
|
-
export interface FieldRenderContext {
|
|
6
|
-
field: FormField;
|
|
7
|
-
value: any;
|
|
8
|
-
onChange: (value: any) => void;
|
|
9
|
-
onBlur?: () => void;
|
|
10
|
-
fieldId: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/** A React component that renders a specific field type */
|
|
14
|
-
export type FieldRenderer = React.ComponentType<FieldRenderContext>;
|
|
15
|
-
|
|
16
|
-
/** Map from field `type` string to its renderer component */
|
|
17
|
-
export type FieldComponentMap = Record<string, FieldRenderer>;
|