shadcn-zod-formkit 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -4
- package/dist/index.cjs +122 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +8 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.mjs +123 -42
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
📦 A React library for creating **dynamic forms** with **Zod validations**, supporting multiple input types: text, number, email, switch, color, date, select, file, and
|
|
7
|
+
📦 A React library for creating **dynamic forms** with **Zod validations**, supporting multiple input types: text, number, email, switch, color, date, select, file, OTP and others.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -26,7 +26,7 @@ yarn add shadcn-zod-formkit
|
|
|
26
26
|
You need installa shadcn basic components
|
|
27
27
|
```typescript
|
|
28
28
|
# Add Shadcn Basics
|
|
29
|
-
npx shadcn@latest add accordion alert badge button calendar card checkbox dialog popover form input label select sonner tooltip switch textarea input-otp collapsible input-group radio-group slider
|
|
29
|
+
npx shadcn@latest add accordion alert badge button calendar card checkbox dialog popover form input label select sonner tooltip switch textarea input-otp collapsible input-group radio-group slider button-group
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
|
|
@@ -58,6 +58,7 @@ export default function Home() {
|
|
|
58
58
|
|
|
59
59
|
return (
|
|
60
60
|
<DynamicForm
|
|
61
|
+
formTitle="Title Form"
|
|
61
62
|
fields={mockFields}
|
|
62
63
|
record={record}
|
|
63
64
|
onSubmit={(data) => console.log("📤 Resultado final:", data)}
|
|
@@ -96,11 +97,16 @@ const mockFields: Array<FieldProps |FieldProps[]> = [
|
|
|
96
97
|
| **Switch List** | `InputTypes.GROUPED_SWITCH_LIST` |
|
|
97
98
|
| **Radio Group** | `InputTypes.RADIO_GROUP` |
|
|
98
99
|
| **Tags** | `InputTypes.TAGS` |
|
|
100
|
+
| **Input Date Time** | `InputTypes.DATE_TIME` |
|
|
101
|
+
| **Input Time** | `InputTypes.TIME` |
|
|
102
|
+
| **Upload Multi File** | `InputTypes.FILE_MULTI_UPLOAD` |
|
|
103
|
+
| **Button Group** | `InputTypes.BUTTON_GROUP` |
|
|
104
|
+
|
|
99
105
|
|
|
100
106
|
|
|
101
107
|
## ✅ Features
|
|
102
108
|
- Fully dynamic fields array support.
|
|
103
|
-
- Multiple input types (text, email, number, color, date, select, switch, file, OTP).
|
|
109
|
+
- Multiple input types (text, email, number, color, date, select, switch, file, OTP, and others).
|
|
104
110
|
- Zod validation integration for robust form validation.
|
|
105
111
|
- Supports default values via record prop.
|
|
106
112
|
- Works seamlessly with React 18+ and TypeScript.
|
|
@@ -108,4 +114,11 @@ const mockFields: Array<FieldProps |FieldProps[]> = [
|
|
|
108
114
|
## 💡 Tips
|
|
109
115
|
- Use peerDependencies for React to avoid version conflicts.
|
|
110
116
|
- Wrap your forms inside a "use client" component if using Next.js App Router.
|
|
111
|
-
- Combine multiple FieldProps in arrays for grouped fields (like age + color).
|
|
117
|
+
- Combine multiple FieldProps in arrays for grouped fields (like age + color).
|
|
118
|
+
|
|
119
|
+
## 🧠 Acknowledgements
|
|
120
|
+
React - A JavaScript library for building user interfaces.
|
|
121
|
+
Next.js - The React framework for production.
|
|
122
|
+
Tailwind CSS - A utility-first CSS framework for creating custom designs.
|
|
123
|
+
Zod - TypeScript-first schema declaration and validation.
|
|
124
|
+
|
package/dist/index.cjs
CHANGED
|
@@ -148,27 +148,30 @@ var CustomAlert = ({
|
|
|
148
148
|
variant = "info"
|
|
149
149
|
}) => {
|
|
150
150
|
const variantClasses = {
|
|
151
|
-
info: "bg-blue-
|
|
152
|
-
warning: "bg-yellow-
|
|
153
|
-
error: "bg-red-
|
|
154
|
-
success: "bg-green-
|
|
151
|
+
info: "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200",
|
|
152
|
+
warning: "bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200",
|
|
153
|
+
error: "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200",
|
|
154
|
+
success: "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200"
|
|
155
155
|
};
|
|
156
156
|
const variantIcons = {
|
|
157
|
-
info: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageCircleWarning, { size: 32, className: "text-blue-
|
|
158
|
-
warning: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageCircleWarning, { size: 32, className: "text-yellow-
|
|
159
|
-
error: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageCircleWarning, { size: 32, className: "text-red-
|
|
160
|
-
success: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.InfoCircledIcon, { className: "w-8 h-8 text-green-
|
|
157
|
+
info: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageCircleWarning, { size: 32, className: "text-blue-500 dark:text-blue-300" }),
|
|
158
|
+
warning: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageCircleWarning, { size: 32, className: "text-yellow-500 dark:text-yellow-300" }),
|
|
159
|
+
error: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageCircleWarning, { size: 32, className: "text-red-500 dark:text-red-300" }),
|
|
160
|
+
success: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.InfoCircledIcon, { className: "w-8 h-8 text-green-500 dark:text-green-300" })
|
|
161
161
|
};
|
|
162
162
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
163
163
|
Alert,
|
|
164
164
|
{
|
|
165
|
-
className: cn(
|
|
166
|
-
|
|
165
|
+
className: cn(
|
|
166
|
+
"mb-4 flex items-start gap-3 border-l-4 p-4 rounded-lg",
|
|
167
|
+
variantClasses[variant],
|
|
168
|
+
className
|
|
169
|
+
),
|
|
167
170
|
children: [
|
|
168
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col shrink-0
|
|
171
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col shrink-0", children: variantIcons[variant] }),
|
|
169
172
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
170
|
-
/* @__PURE__ */ jsxRuntime.jsx(AlertTitle, { className: "font-semibold text-
|
|
171
|
-
/* @__PURE__ */ jsxRuntime.jsx(AlertDescription, { className: "text-sm text-muted-foreground", children: description })
|
|
173
|
+
/* @__PURE__ */ jsxRuntime.jsx(AlertTitle, { className: "font-semibold text-lg", children: title }),
|
|
174
|
+
/* @__PURE__ */ jsxRuntime.jsx(AlertDescription, { className: "text-sm text-muted-foreground dark:text-gray-300", children: description })
|
|
172
175
|
] })
|
|
173
176
|
]
|
|
174
177
|
}
|
|
@@ -259,9 +262,11 @@ var InputTypes = /* @__PURE__ */ ((InputTypes2) => {
|
|
|
259
262
|
InputTypes2["TIME"] = "time";
|
|
260
263
|
InputTypes2["FILE_MULTI_UPLOAD"] = "file_multi_upload";
|
|
261
264
|
InputTypes2["SLIDER"] = "slider";
|
|
265
|
+
InputTypes2["BUTTON_GROUP"] = "button_group";
|
|
262
266
|
return InputTypes2;
|
|
263
267
|
})(InputTypes || {});
|
|
264
268
|
var inputFieldComp = [
|
|
269
|
+
"button_group" /* BUTTON_GROUP */,
|
|
265
270
|
"slider" /* SLIDER */,
|
|
266
271
|
"file_multi_upload" /* FILE_MULTI_UPLOAD */,
|
|
267
272
|
"time" /* TIME */,
|
|
@@ -1748,6 +1753,65 @@ var AccordionGroupedSwitches = ({ form, input, groups = [], onChange, isSubmitti
|
|
|
1748
1753
|
input.name
|
|
1749
1754
|
);
|
|
1750
1755
|
};
|
|
1756
|
+
var buttonGroupVariants = classVarianceAuthority.cva(
|
|
1757
|
+
"flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2",
|
|
1758
|
+
{
|
|
1759
|
+
variants: {
|
|
1760
|
+
orientation: {
|
|
1761
|
+
horizontal: "[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none",
|
|
1762
|
+
vertical: "flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none"
|
|
1763
|
+
}
|
|
1764
|
+
},
|
|
1765
|
+
defaultVariants: {
|
|
1766
|
+
orientation: "horizontal"
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
);
|
|
1770
|
+
function ButtonGroup({
|
|
1771
|
+
className,
|
|
1772
|
+
orientation,
|
|
1773
|
+
...props
|
|
1774
|
+
}) {
|
|
1775
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1776
|
+
"div",
|
|
1777
|
+
{
|
|
1778
|
+
role: "group",
|
|
1779
|
+
"data-slot": "button-group",
|
|
1780
|
+
"data-orientation": orientation,
|
|
1781
|
+
className: cn(buttonGroupVariants({ orientation }), className),
|
|
1782
|
+
...props
|
|
1783
|
+
}
|
|
1784
|
+
);
|
|
1785
|
+
}
|
|
1786
|
+
var ButtonGroupInput = class extends BaseInput {
|
|
1787
|
+
render() {
|
|
1788
|
+
const { input, form, isSubmitting } = this;
|
|
1789
|
+
return /* @__PURE__ */ jsxRuntime.jsx(FieldButtonGroup, { input, form, isSubmitting });
|
|
1790
|
+
}
|
|
1791
|
+
};
|
|
1792
|
+
var FieldButtonGroup = ({ input, form, isSubmitting }) => {
|
|
1793
|
+
const options = (input.listConfig?.list ?? []).filter((option) => "name" in option);
|
|
1794
|
+
const handleSelect = (value) => {
|
|
1795
|
+
form.setValue(input.name, value, { shouldValidate: true });
|
|
1796
|
+
};
|
|
1797
|
+
const selectedValue = form.watch(input.name);
|
|
1798
|
+
return (
|
|
1799
|
+
// <div className="flex flex-col gap-1 w-full">
|
|
1800
|
+
// <label className="font-semibold">{input.label}</label>
|
|
1801
|
+
// <div className="flex flex-wrap gap-2">
|
|
1802
|
+
/* @__PURE__ */ jsxRuntime.jsx(ButtonGroup, { children: options.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1803
|
+
Button,
|
|
1804
|
+
{
|
|
1805
|
+
type: "button",
|
|
1806
|
+
variant: selectedValue === option.value ? "default" : "outline",
|
|
1807
|
+
onClick: () => handleSelect(option.value),
|
|
1808
|
+
disabled: isSubmitting,
|
|
1809
|
+
children: option.label ?? option.name
|
|
1810
|
+
},
|
|
1811
|
+
option.value
|
|
1812
|
+
)) })
|
|
1813
|
+
);
|
|
1814
|
+
};
|
|
1751
1815
|
var CheckListInput = class extends BaseInput {
|
|
1752
1816
|
render() {
|
|
1753
1817
|
const { input, isSubmitting } = this;
|
|
@@ -3472,7 +3536,7 @@ function cleanEscapedString(input) {
|
|
|
3472
3536
|
var DateInput = class extends BaseInput {
|
|
3473
3537
|
render() {
|
|
3474
3538
|
const { input, form, isSubmitting } = this;
|
|
3475
|
-
|
|
3539
|
+
const formField = /* @__PURE__ */ jsxRuntime.jsx(
|
|
3476
3540
|
FormField,
|
|
3477
3541
|
{
|
|
3478
3542
|
control: form.control,
|
|
@@ -3524,6 +3588,7 @@ var DateInput = class extends BaseInput {
|
|
|
3524
3588
|
},
|
|
3525
3589
|
input.name
|
|
3526
3590
|
);
|
|
3591
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: formField });
|
|
3527
3592
|
}
|
|
3528
3593
|
};
|
|
3529
3594
|
var DateTimeInput = class extends BaseInput {
|
|
@@ -3680,7 +3745,7 @@ var FieldFileMultiUpload = ({ input, form, isSubmitting }) => {
|
|
|
3680
3745
|
form.setValue(input.name, updatedFiles);
|
|
3681
3746
|
setDragOver(false);
|
|
3682
3747
|
};
|
|
3683
|
-
|
|
3748
|
+
const formField = /* @__PURE__ */ jsxRuntime.jsx(
|
|
3684
3749
|
FormField,
|
|
3685
3750
|
{
|
|
3686
3751
|
control: form.control,
|
|
@@ -3746,6 +3811,7 @@ var FieldFileMultiUpload = ({ input, form, isSubmitting }) => {
|
|
|
3746
3811
|
},
|
|
3747
3812
|
input.name
|
|
3748
3813
|
);
|
|
3814
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: formField });
|
|
3749
3815
|
};
|
|
3750
3816
|
var TextInputGroup = class extends BaseInput {
|
|
3751
3817
|
render() {
|
|
@@ -3768,7 +3834,7 @@ var FieldTextGroup = ({ form, input, isSubmitting }) => {
|
|
|
3768
3834
|
const fieldState = form.getFieldState(input.name);
|
|
3769
3835
|
return !fieldState.error && value !== void 0 && value !== "";
|
|
3770
3836
|
});
|
|
3771
|
-
|
|
3837
|
+
const formField = /* @__PURE__ */ jsxRuntime.jsx(
|
|
3772
3838
|
FormField,
|
|
3773
3839
|
{
|
|
3774
3840
|
control: form.control,
|
|
@@ -3805,6 +3871,7 @@ var FieldTextGroup = ({ form, input, isSubmitting }) => {
|
|
|
3805
3871
|
},
|
|
3806
3872
|
input.name
|
|
3807
3873
|
);
|
|
3874
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: formField });
|
|
3808
3875
|
};
|
|
3809
3876
|
var NumberInput = class extends BaseInput {
|
|
3810
3877
|
render() {
|
|
@@ -3902,8 +3969,7 @@ var FieldRadioGroup = ({ input, form, isSubmitting }) => {
|
|
|
3902
3969
|
},
|
|
3903
3970
|
input.name
|
|
3904
3971
|
);
|
|
3905
|
-
|
|
3906
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 space-y-3", children: formField });
|
|
3972
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: formField });
|
|
3907
3973
|
};
|
|
3908
3974
|
var SelectInput = class extends BaseInput {
|
|
3909
3975
|
render() {
|
|
@@ -4039,8 +4105,7 @@ var FieldSimpleCheckList = ({ input, value, onChange, isSubmitting }) => {
|
|
|
4039
4105
|
)) }) }),
|
|
4040
4106
|
/* @__PURE__ */ jsxRuntime.jsx(FormMessage, {})
|
|
4041
4107
|
] });
|
|
4042
|
-
|
|
4043
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 space-y-3", children: formField });
|
|
4108
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: formField });
|
|
4044
4109
|
};
|
|
4045
4110
|
function Slider({
|
|
4046
4111
|
className,
|
|
@@ -4202,8 +4267,7 @@ var FieldTags = ({ input, form, isSubmitting }) => {
|
|
|
4202
4267
|
},
|
|
4203
4268
|
input.name
|
|
4204
4269
|
);
|
|
4205
|
-
|
|
4206
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 space-y-3", children: formField });
|
|
4270
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: formField });
|
|
4207
4271
|
};
|
|
4208
4272
|
var SPLITTER_REGEX = /[\n#?=&\t,./-]+/;
|
|
4209
4273
|
var FORMATTING_REGEX = /^[^a-zA-Z0-9]*|[^a-zA-Z0-9]*$/g;
|
|
@@ -4601,6 +4665,7 @@ var inputMap = {
|
|
|
4601
4665
|
["date_time" /* DATE_TIME */]: DateTimeInput,
|
|
4602
4666
|
["time" /* TIME */]: TimeInput,
|
|
4603
4667
|
["file_multi_upload" /* FILE_MULTI_UPLOAD */]: FileMultiUploadInput,
|
|
4668
|
+
["button_group" /* BUTTON_GROUP */]: ButtonGroupInput,
|
|
4604
4669
|
//ToDos: ============================================================
|
|
4605
4670
|
["slider" /* SLIDER */]: SliderInput,
|
|
4606
4671
|
//ToDo: // PENDIENTE ... VISUALMENTE NO SE VE BIEN.!!!
|
|
@@ -4614,13 +4679,15 @@ var inputMap = {
|
|
|
4614
4679
|
// [InputTypes.IMAGE_UPLOAD]: TextInput,
|
|
4615
4680
|
// [InputTypes.AUDIO_UPLOAD]: TextInput,
|
|
4616
4681
|
// [InputTypes.VIDEO_UPLOAD]: TextInput,
|
|
4682
|
+
// [InputTypes.CREDIT_CARD]: TextInput,
|
|
4617
4683
|
};
|
|
4618
4684
|
var InputFactory = class {
|
|
4619
4685
|
static create(input, form, isSubmitting = false) {
|
|
4620
4686
|
const inputType = input.inputType ?? "text" /* TEXT */;
|
|
4621
4687
|
const InputClass = inputMap[inputType] ?? TextInput;
|
|
4622
4688
|
const instance = new InputClass(input, form, isSubmitting);
|
|
4623
|
-
return instance.render();
|
|
4689
|
+
if (!input.wrapInCard) return instance.render();
|
|
4690
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 space-y-3", children: instance.render() });
|
|
4624
4691
|
}
|
|
4625
4692
|
};
|
|
4626
4693
|
function getDefaultValues(entity) {
|
|
@@ -4654,17 +4721,23 @@ function getDefaultValues(entity) {
|
|
|
4654
4721
|
}
|
|
4655
4722
|
return defaults;
|
|
4656
4723
|
}
|
|
4657
|
-
var getDynamicSchema = (fields) => {
|
|
4724
|
+
var getDynamicSchema = (fields, extraValidations) => {
|
|
4658
4725
|
const flatFields = fields.flatMap((f) => Array.isArray(f) ? f : [f]);
|
|
4659
4726
|
const shape = {};
|
|
4660
4727
|
flatFields.forEach((f) => {
|
|
4661
|
-
shape[f.name] = f.
|
|
4728
|
+
shape[f.name] = f.zodType ?? z2__default.default.any();
|
|
4662
4729
|
});
|
|
4663
|
-
|
|
4730
|
+
let schema = z2__default.default.object(shape);
|
|
4731
|
+
if (extraValidations && extraValidations.length > 0) {
|
|
4732
|
+
extraValidations.forEach((fn) => {
|
|
4733
|
+
schema = fn(schema);
|
|
4734
|
+
});
|
|
4735
|
+
}
|
|
4736
|
+
return schema;
|
|
4664
4737
|
};
|
|
4665
4738
|
var FormErrorsAlert = ({ formState, fields }) => {
|
|
4666
4739
|
const flatFields = fields.flatMap((f) => Array.isArray(f) ? f : [f]);
|
|
4667
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4740
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: 4 }, children: Object.entries(formState.errors).length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4668
4741
|
CustomAlert,
|
|
4669
4742
|
{
|
|
4670
4743
|
title: "Revisar los siguientes criterios",
|
|
@@ -4686,17 +4759,20 @@ var getFieldLabel = (fieldErrorKey, fields) => {
|
|
|
4686
4759
|
return findedField?.label ?? fieldErrorKey;
|
|
4687
4760
|
};
|
|
4688
4761
|
var DynamicForm = ({
|
|
4762
|
+
formTitle,
|
|
4763
|
+
formSubTitle,
|
|
4689
4764
|
fields,
|
|
4690
4765
|
record = {},
|
|
4691
4766
|
onSubmit,
|
|
4767
|
+
extraValidations,
|
|
4692
4768
|
withCard = false,
|
|
4693
4769
|
withErrorsAlert = true,
|
|
4694
4770
|
errorAlertPosition = "up",
|
|
4695
4771
|
submitBtnClass = "",
|
|
4696
4772
|
submitBtnLabel = "Submit"
|
|
4697
4773
|
}) => {
|
|
4698
|
-
const [isPending,
|
|
4699
|
-
const schema = React8.useMemo(() => getDynamicSchema(fields), [fields]);
|
|
4774
|
+
const [isPending, startTransition] = React8.useTransition();
|
|
4775
|
+
const schema = React8.useMemo(() => getDynamicSchema(fields, extraValidations), [fields, extraValidations]);
|
|
4700
4776
|
const defaultValues = React8.useMemo(() => getDefaultValues(record), [record]);
|
|
4701
4777
|
const form = reactHookForm.useForm({
|
|
4702
4778
|
resolver: zod.zodResolver(schema),
|
|
@@ -4708,7 +4784,7 @@ var DynamicForm = ({
|
|
|
4708
4784
|
}, []);
|
|
4709
4785
|
const handleSubmit = (data) => {
|
|
4710
4786
|
try {
|
|
4711
|
-
|
|
4787
|
+
startTransition(async () => {
|
|
4712
4788
|
const resp = { data, form };
|
|
4713
4789
|
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
4714
4790
|
onSubmit?.(resp);
|
|
@@ -4717,7 +4793,11 @@ var DynamicForm = ({
|
|
|
4717
4793
|
console.error("Ocurri\xF3 un error al enviar el formulario.");
|
|
4718
4794
|
}
|
|
4719
4795
|
};
|
|
4720
|
-
const formContent = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4796
|
+
const formContent = /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
4797
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { className: "flex items-center gap-2 p-2 border-b", children: [
|
|
4798
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings, { className: "h-5 w-5" }),
|
|
4799
|
+
formTitle
|
|
4800
|
+
] }),
|
|
4721
4801
|
withErrorsAlert && errorAlertPosition == "up" && /* @__PURE__ */ jsxRuntime.jsx(FormErrorsAlert, { formState: form.formState, fields }),
|
|
4722
4802
|
/* @__PURE__ */ jsxRuntime.jsx(Form, { ...form, children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: form.handleSubmit(handleSubmit), className: "flex flex-col gap-2", children: [
|
|
4723
4803
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full grid grid-cols-1", children: fields.map(
|
|
@@ -4748,6 +4828,7 @@ var DynamicFormExample = () => {
|
|
|
4748
4828
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4749
4829
|
DynamicForm,
|
|
4750
4830
|
{
|
|
4831
|
+
formTitle: "User Form",
|
|
4751
4832
|
fields: mockFields,
|
|
4752
4833
|
record,
|
|
4753
4834
|
onSubmit: (data) => console.log("\u{1F4E4} Resultado final:", data)
|
|
@@ -4761,7 +4842,7 @@ var mockFields = [
|
|
|
4761
4842
|
label: "Nombre de usuario",
|
|
4762
4843
|
inputType: "text" /* TEXT */,
|
|
4763
4844
|
required: true,
|
|
4764
|
-
|
|
4845
|
+
zodType: z2__default.default.string().min(3, "El nombre debe tener al menos 3 caracteres").max(20, "El nombre no puede tener m\xE1s de 20 caracteres")
|
|
4765
4846
|
},
|
|
4766
4847
|
// 📧 Campo de correo con validación personalizada (ZodTypeAny)
|
|
4767
4848
|
{
|
|
@@ -4769,7 +4850,7 @@ var mockFields = [
|
|
|
4769
4850
|
label: "Correo electr\xF3nico",
|
|
4770
4851
|
inputType: "text" /* TEXT */,
|
|
4771
4852
|
required: false,
|
|
4772
|
-
|
|
4853
|
+
zodType: z2__default.default.string().email("Correo inv\xE1lido").toLowerCase().refine((val) => !val.endsWith("@spam.com"), {
|
|
4773
4854
|
message: "No se permiten correos de spam.com"
|
|
4774
4855
|
})
|
|
4775
4856
|
},
|
|
@@ -4780,7 +4861,7 @@ var mockFields = [
|
|
|
4780
4861
|
inputType: "text" /* TEXT */,
|
|
4781
4862
|
required: false,
|
|
4782
4863
|
keyboardType: "password" /* PASSWORD */,
|
|
4783
|
-
|
|
4864
|
+
zodType: z2__default.default.string().min(6, "Debe tener al menos 6 caracteres").max(20, "No m\xE1s de 20 caracteres").optional()
|
|
4784
4865
|
},
|
|
4785
4866
|
// 🟢 Campo tipo switch (boolean)
|
|
4786
4867
|
{
|
|
@@ -4788,7 +4869,7 @@ var mockFields = [
|
|
|
4788
4869
|
label: "Usuario activo",
|
|
4789
4870
|
inputType: "switch" /* SWITCH */,
|
|
4790
4871
|
required: false,
|
|
4791
|
-
|
|
4872
|
+
zodType: z2__default.default.boolean().default(true)
|
|
4792
4873
|
},
|
|
4793
4874
|
// 🎨 Color con validación personalizada
|
|
4794
4875
|
[
|
|
@@ -4797,7 +4878,7 @@ var mockFields = [
|
|
|
4797
4878
|
label: "Color favorito",
|
|
4798
4879
|
inputType: "color" /* COLOR */,
|
|
4799
4880
|
required: false,
|
|
4800
|
-
|
|
4881
|
+
zodType: z2__default.default.string().regex(/^#([0-9A-Fa-f]{6})$/, "Debe ser un color hexadecimal v\xE1lido")
|
|
4801
4882
|
},
|
|
4802
4883
|
// 🔢 Número con rango
|
|
4803
4884
|
{
|
|
@@ -4805,7 +4886,7 @@ var mockFields = [
|
|
|
4805
4886
|
label: "Edad",
|
|
4806
4887
|
inputType: "number" /* NUMBER */,
|
|
4807
4888
|
required: true,
|
|
4808
|
-
|
|
4889
|
+
zodType: z2__default.default.coerce.number().min(18, "Debe ser mayor de 18").max(99, "Debe ser menor de 99")
|
|
4809
4890
|
}
|
|
4810
4891
|
],
|
|
4811
4892
|
// 📅 Fecha
|
|
@@ -4814,7 +4895,7 @@ var mockFields = [
|
|
|
4814
4895
|
label: "Fecha de nacimiento",
|
|
4815
4896
|
inputType: "date" /* DATE */,
|
|
4816
4897
|
required: true,
|
|
4817
|
-
|
|
4898
|
+
zodType: z2__default.default.coerce.date().refine((d) => d < /* @__PURE__ */ new Date(), {
|
|
4818
4899
|
message: "La fecha no puede ser futura"
|
|
4819
4900
|
})
|
|
4820
4901
|
},
|
|
@@ -4833,7 +4914,7 @@ var mockFields = [
|
|
|
4833
4914
|
{ id: 3, name: "Lector", value: "reader" }
|
|
4834
4915
|
]
|
|
4835
4916
|
},
|
|
4836
|
-
|
|
4917
|
+
zodType: z2__default.default.enum(["admin", "editor", "reader"])
|
|
4837
4918
|
},
|
|
4838
4919
|
// 🧾 Campo tipo archivo (file)
|
|
4839
4920
|
{
|
|
@@ -4841,7 +4922,7 @@ var mockFields = [
|
|
|
4841
4922
|
label: "Imagen de perfil",
|
|
4842
4923
|
inputType: "file" /* FILE */,
|
|
4843
4924
|
required: false,
|
|
4844
|
-
|
|
4925
|
+
zodType: z2__default.default.any().refine(
|
|
4845
4926
|
(file) => {
|
|
4846
4927
|
if (!file) return true;
|
|
4847
4928
|
return file.size <= 10 * 1024 * 1024 && ["image/jpeg", "image/png"].includes(file.type);
|
|
@@ -4855,7 +4936,7 @@ var mockFields = [
|
|
|
4855
4936
|
label: "C\xF3digo OTP",
|
|
4856
4937
|
inputType: "otp" /* OTP */,
|
|
4857
4938
|
required: true,
|
|
4858
|
-
|
|
4939
|
+
zodType: z2__default.default.string().min(4, "Debe tener al menos 4 d\xEDgitos").max(6, "Debe tener m\xE1ximo 6 d\xEDgitos")
|
|
4859
4940
|
}
|
|
4860
4941
|
];
|
|
4861
4942
|
var InputList = ({ handleAddInput, inputsTypes }) => {
|