@rachelallyson/hero-hook-form 2.0.0 → 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/CHANGELOG.md +16 -0
- package/README.md +176 -0
- package/dist/index.d.ts +147 -98
- package/dist/index.js +1069 -689
- package/dist/react/index.d.ts +147 -98
- package/dist/react/index.js +1069 -689
- package/package.json +58 -33
package/dist/index.js
CHANGED
|
@@ -220,11 +220,11 @@ function CheckboxField(props) {
|
|
|
220
220
|
import React3 from "react";
|
|
221
221
|
import { useWatch, useFormContext } from "react-hook-form";
|
|
222
222
|
function ConditionalField({
|
|
223
|
+
className,
|
|
223
224
|
config,
|
|
224
|
-
control
|
|
225
|
-
className
|
|
225
|
+
control
|
|
226
226
|
}) {
|
|
227
|
-
const { condition, field: field2
|
|
227
|
+
const { condition, field: field2 } = config;
|
|
228
228
|
const form = useFormContext();
|
|
229
229
|
const formValues = useWatch({ control });
|
|
230
230
|
const shouldShow = condition(formValues);
|
|
@@ -237,10 +237,10 @@ function ConditionalField({
|
|
|
237
237
|
config: field2,
|
|
238
238
|
form,
|
|
239
239
|
submissionState: {
|
|
240
|
-
|
|
240
|
+
error: void 0,
|
|
241
241
|
isSubmitted: false,
|
|
242
|
-
|
|
243
|
-
|
|
242
|
+
isSubmitting: false,
|
|
243
|
+
isSuccess: false
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
246
|
));
|
|
@@ -308,11 +308,11 @@ function DateField(props) {
|
|
|
308
308
|
import React5 from "react";
|
|
309
309
|
import { useWatch as useWatch2, useFormContext as useFormContext2 } from "react-hook-form";
|
|
310
310
|
function DynamicSectionField({
|
|
311
|
+
className,
|
|
311
312
|
config,
|
|
312
|
-
control
|
|
313
|
-
className
|
|
313
|
+
control
|
|
314
314
|
}) {
|
|
315
|
-
const { condition, fields, title
|
|
315
|
+
const { condition, description, fields, title } = config;
|
|
316
316
|
const form = useFormContext2();
|
|
317
317
|
const formValues = useWatch2({ control });
|
|
318
318
|
const shouldShow = condition(formValues);
|
|
@@ -326,10 +326,10 @@ function DynamicSectionField({
|
|
|
326
326
|
config: fieldConfig,
|
|
327
327
|
form,
|
|
328
328
|
submissionState: {
|
|
329
|
-
|
|
329
|
+
error: void 0,
|
|
330
330
|
isSubmitted: false,
|
|
331
|
-
|
|
332
|
-
|
|
331
|
+
isSubmitting: false,
|
|
332
|
+
isSuccess: false
|
|
333
333
|
}
|
|
334
334
|
}
|
|
335
335
|
))));
|
|
@@ -340,15 +340,15 @@ import React6 from "react";
|
|
|
340
340
|
import { useFieldArray, useFormContext as useFormContext3 } from "react-hook-form";
|
|
341
341
|
import { Button as Button2 } from "@heroui/react";
|
|
342
342
|
function FieldArrayField({
|
|
343
|
-
|
|
344
|
-
|
|
343
|
+
className,
|
|
344
|
+
config
|
|
345
345
|
}) {
|
|
346
346
|
const {
|
|
347
|
-
|
|
347
|
+
addButtonText = "Add Item",
|
|
348
348
|
fields: fieldConfigs,
|
|
349
|
-
min = 0,
|
|
350
349
|
max = 10,
|
|
351
|
-
|
|
350
|
+
min = 0,
|
|
351
|
+
name,
|
|
352
352
|
removeButtonText = "Remove"
|
|
353
353
|
} = config;
|
|
354
354
|
const form = useFormContext3();
|
|
@@ -356,7 +356,7 @@ function FieldArrayField({
|
|
|
356
356
|
return null;
|
|
357
357
|
}
|
|
358
358
|
const { control } = form;
|
|
359
|
-
const {
|
|
359
|
+
const { append, fields, remove } = useFieldArray({
|
|
360
360
|
control,
|
|
361
361
|
name
|
|
362
362
|
// FieldArray name
|
|
@@ -384,34 +384,42 @@ function FieldArrayField({
|
|
|
384
384
|
remove(index);
|
|
385
385
|
}
|
|
386
386
|
};
|
|
387
|
-
return /* @__PURE__ */ React6.createElement("div", { className }, /* @__PURE__ */ React6.createElement("div", { className: "space-y-4" }, fields.map((field2, index) => /* @__PURE__ */ React6.createElement(
|
|
388
|
-
|
|
387
|
+
return /* @__PURE__ */ React6.createElement("div", { className }, /* @__PURE__ */ React6.createElement("div", { className: "space-y-4" }, fields.map((field2, index) => /* @__PURE__ */ React6.createElement(
|
|
388
|
+
"div",
|
|
389
389
|
{
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
color: "danger",
|
|
393
|
-
startContent: "\u{1F5D1}\uFE0F",
|
|
394
|
-
onPress: () => handleRemove(index),
|
|
395
|
-
"aria-label": `${removeButtonText} ${config.label} ${index + 1}`
|
|
390
|
+
key: field2.id,
|
|
391
|
+
className: "border border-gray-200 rounded-lg p-4 space-y-4"
|
|
396
392
|
},
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
393
|
+
/* @__PURE__ */ React6.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React6.createElement("h4", { className: "text-sm font-medium text-gray-700" }, config.label, " #", index + 1), canRemove && /* @__PURE__ */ React6.createElement(
|
|
394
|
+
Button2,
|
|
395
|
+
{
|
|
396
|
+
size: "sm",
|
|
397
|
+
variant: "light",
|
|
398
|
+
color: "danger",
|
|
399
|
+
startContent: "\u{1F5D1}\uFE0F",
|
|
400
|
+
onPress: () => handleRemove(index),
|
|
401
|
+
"aria-label": `${removeButtonText} ${config.label} ${index + 1}`
|
|
405
402
|
},
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
403
|
+
removeButtonText
|
|
404
|
+
)),
|
|
405
|
+
/* @__PURE__ */ React6.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, fieldConfigs.map((fieldConfig) => /* @__PURE__ */ React6.createElement(
|
|
406
|
+
FormField,
|
|
407
|
+
{
|
|
408
|
+
key: `${fieldConfig.name}-${index}`,
|
|
409
|
+
config: {
|
|
410
|
+
...fieldConfig,
|
|
411
|
+
name: `${name}.${index}.${fieldConfig.name}`
|
|
412
|
+
},
|
|
413
|
+
form,
|
|
414
|
+
submissionState: {
|
|
415
|
+
error: void 0,
|
|
416
|
+
isSubmitted: false,
|
|
417
|
+
isSubmitting: false,
|
|
418
|
+
isSuccess: false
|
|
419
|
+
}
|
|
412
420
|
}
|
|
413
|
-
|
|
414
|
-
))
|
|
421
|
+
)))
|
|
422
|
+
)), canAdd && /* @__PURE__ */ React6.createElement(
|
|
415
423
|
Button2,
|
|
416
424
|
{
|
|
417
425
|
variant: "bordered",
|
|
@@ -529,15 +537,15 @@ function FontPickerField(props) {
|
|
|
529
537
|
} = props;
|
|
530
538
|
const [fontPickerState, setFontPickerState] = React8.useState({
|
|
531
539
|
component: FontPickerComponent,
|
|
532
|
-
|
|
533
|
-
|
|
540
|
+
error: null,
|
|
541
|
+
loading: false
|
|
534
542
|
});
|
|
535
543
|
React8.useEffect(() => {
|
|
536
544
|
if (fontPickerLoaded && FontPickerComponent) {
|
|
537
545
|
setFontPickerState({
|
|
538
546
|
component: FontPickerComponent,
|
|
539
|
-
|
|
540
|
-
|
|
547
|
+
error: null,
|
|
548
|
+
loading: false
|
|
541
549
|
});
|
|
542
550
|
return;
|
|
543
551
|
}
|
|
@@ -547,14 +555,14 @@ function FontPickerField(props) {
|
|
|
547
555
|
if (fontPickerLoaded && FontPickerComponent) {
|
|
548
556
|
setFontPickerState({
|
|
549
557
|
component: FontPickerComponent,
|
|
550
|
-
|
|
551
|
-
|
|
558
|
+
error: null,
|
|
559
|
+
loading: false
|
|
552
560
|
});
|
|
553
561
|
} else {
|
|
554
562
|
setFontPickerState({
|
|
555
563
|
component: null,
|
|
556
|
-
|
|
557
|
-
|
|
564
|
+
error: "Font picker package not found",
|
|
565
|
+
loading: false
|
|
558
566
|
});
|
|
559
567
|
}
|
|
560
568
|
};
|
|
@@ -571,17 +579,17 @@ function FontPickerField(props) {
|
|
|
571
579
|
fontPickerLoading = false;
|
|
572
580
|
setFontPickerState({
|
|
573
581
|
component: FontPickerComponent,
|
|
574
|
-
|
|
575
|
-
|
|
582
|
+
error: null,
|
|
583
|
+
loading: false
|
|
576
584
|
});
|
|
577
585
|
loadingCallbacks.forEach((callback) => callback());
|
|
578
586
|
loadingCallbacks.length = 0;
|
|
579
|
-
} catch
|
|
587
|
+
} catch {
|
|
580
588
|
fontPickerLoading = false;
|
|
581
589
|
setFontPickerState({
|
|
582
590
|
component: null,
|
|
583
|
-
|
|
584
|
-
|
|
591
|
+
error: "Font picker package not found",
|
|
592
|
+
loading: false
|
|
585
593
|
});
|
|
586
594
|
loadingCallbacks.forEach((callback) => callback());
|
|
587
595
|
loadingCallbacks.length = 0;
|
|
@@ -640,50 +648,52 @@ function CoercedInput(props) {
|
|
|
640
648
|
}
|
|
641
649
|
);
|
|
642
650
|
}
|
|
643
|
-
var InputField = React9.memo(
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
description,
|
|
648
|
-
inputProps,
|
|
649
|
-
isDisabled,
|
|
650
|
-
label,
|
|
651
|
-
name,
|
|
652
|
-
rules,
|
|
653
|
-
transform
|
|
654
|
-
} = props;
|
|
655
|
-
return /* @__PURE__ */ React9.createElement(
|
|
656
|
-
Controller5,
|
|
657
|
-
{
|
|
651
|
+
var InputField = React9.memo(
|
|
652
|
+
(props) => {
|
|
653
|
+
const {
|
|
654
|
+
className,
|
|
658
655
|
control,
|
|
656
|
+
description,
|
|
657
|
+
inputProps,
|
|
658
|
+
isDisabled,
|
|
659
|
+
label,
|
|
659
660
|
name,
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
661
|
+
rules,
|
|
662
|
+
transform
|
|
663
|
+
} = props;
|
|
664
|
+
return /* @__PURE__ */ React9.createElement(
|
|
665
|
+
Controller5,
|
|
666
|
+
{
|
|
667
|
+
control,
|
|
668
|
+
name,
|
|
669
|
+
render: ({ field: field2, fieldState }) => /* @__PURE__ */ React9.createElement("div", { className }, /* @__PURE__ */ React9.createElement(
|
|
670
|
+
CoercedInput,
|
|
671
|
+
{
|
|
672
|
+
description,
|
|
673
|
+
disabled: isDisabled,
|
|
674
|
+
errorMessage: fieldState.error?.message,
|
|
675
|
+
field: {
|
|
676
|
+
...field2,
|
|
677
|
+
onChange: (value) => {
|
|
678
|
+
if (inputProps?.type === "number") {
|
|
679
|
+
const numValue = value === "" ? void 0 : Number(value);
|
|
680
|
+
field2.onChange(
|
|
681
|
+
transform ? transform(String(numValue)) : numValue
|
|
682
|
+
);
|
|
683
|
+
} else {
|
|
684
|
+
field2.onChange(transform ? transform(value) : value);
|
|
685
|
+
}
|
|
676
686
|
}
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
+
},
|
|
688
|
+
inputProps,
|
|
689
|
+
label
|
|
690
|
+
}
|
|
691
|
+
)),
|
|
692
|
+
rules
|
|
693
|
+
}
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
);
|
|
687
697
|
|
|
688
698
|
// src/fields/RadioGroupField.tsx
|
|
689
699
|
import React10 from "react";
|
|
@@ -928,187 +938,189 @@ function TextareaField(props) {
|
|
|
928
938
|
}
|
|
929
939
|
|
|
930
940
|
// src/components/FormField.tsx
|
|
931
|
-
var FormField = React15.memo(
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
}
|
|
939
|
-
const { control } = form;
|
|
940
|
-
const watchedValues = useWatch3({ control });
|
|
941
|
-
if (config.condition && !config.condition(watchedValues)) {
|
|
942
|
-
return null;
|
|
943
|
-
}
|
|
944
|
-
if (config.dependsOn) {
|
|
945
|
-
const dependentValue = watchedValues[config.dependsOn];
|
|
946
|
-
if (config.dependsOnValue !== void 0 && dependentValue !== config.dependsOnValue) {
|
|
941
|
+
var FormField = React15.memo(
|
|
942
|
+
({
|
|
943
|
+
config,
|
|
944
|
+
form,
|
|
945
|
+
submissionState
|
|
946
|
+
}) => {
|
|
947
|
+
if (!form || !form.control) {
|
|
947
948
|
return null;
|
|
948
949
|
}
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
ariaLabel: config.ariaLabel,
|
|
953
|
-
className: config.className,
|
|
954
|
-
description: config.description,
|
|
955
|
-
isDisabled: config.isDisabled ?? submissionState.isSubmitting,
|
|
956
|
-
label: config.label,
|
|
957
|
-
name: config.name,
|
|
958
|
-
rules: config.rules
|
|
959
|
-
};
|
|
960
|
-
switch (config.type) {
|
|
961
|
-
case "input":
|
|
962
|
-
return /* @__PURE__ */ React15.createElement(
|
|
963
|
-
InputField,
|
|
964
|
-
{
|
|
965
|
-
...baseProps,
|
|
966
|
-
control,
|
|
967
|
-
defaultValue: config.defaultValue,
|
|
968
|
-
inputProps: config.inputProps
|
|
969
|
-
}
|
|
970
|
-
);
|
|
971
|
-
case "textarea":
|
|
972
|
-
return /* @__PURE__ */ React15.createElement(
|
|
973
|
-
TextareaField,
|
|
974
|
-
{
|
|
975
|
-
...baseProps,
|
|
976
|
-
control,
|
|
977
|
-
defaultValue: config.defaultValue,
|
|
978
|
-
textareaProps: config.textareaProps
|
|
979
|
-
}
|
|
980
|
-
);
|
|
981
|
-
case "select":
|
|
982
|
-
return /* @__PURE__ */ React15.createElement(
|
|
983
|
-
SelectField,
|
|
984
|
-
{
|
|
985
|
-
...baseProps,
|
|
986
|
-
control,
|
|
987
|
-
defaultValue: config.defaultValue,
|
|
988
|
-
options: (config.options ?? []).map((opt) => ({
|
|
989
|
-
label: opt.label,
|
|
990
|
-
value: String(opt.value)
|
|
991
|
-
})),
|
|
992
|
-
selectProps: config.selectProps
|
|
993
|
-
}
|
|
994
|
-
);
|
|
995
|
-
case "checkbox":
|
|
996
|
-
return /* @__PURE__ */ React15.createElement(
|
|
997
|
-
CheckboxField,
|
|
998
|
-
{
|
|
999
|
-
...baseProps,
|
|
1000
|
-
checkboxProps: config.checkboxProps,
|
|
1001
|
-
control,
|
|
1002
|
-
defaultValue: config.defaultValue
|
|
1003
|
-
}
|
|
1004
|
-
);
|
|
1005
|
-
case "radio":
|
|
1006
|
-
return /* @__PURE__ */ React15.createElement(
|
|
1007
|
-
RadioGroupField,
|
|
1008
|
-
{
|
|
1009
|
-
...baseProps,
|
|
1010
|
-
control,
|
|
1011
|
-
defaultValue: config.defaultValue,
|
|
1012
|
-
options: (config.radioOptions ?? []).map((opt) => ({
|
|
1013
|
-
label: opt.label,
|
|
1014
|
-
value: String(opt.value)
|
|
1015
|
-
})),
|
|
1016
|
-
radioGroupProps: config.radioProps
|
|
1017
|
-
}
|
|
1018
|
-
);
|
|
1019
|
-
case "switch":
|
|
1020
|
-
return /* @__PURE__ */ React15.createElement(
|
|
1021
|
-
SwitchField,
|
|
1022
|
-
{
|
|
1023
|
-
...baseProps,
|
|
1024
|
-
control,
|
|
1025
|
-
defaultValue: config.defaultValue,
|
|
1026
|
-
switchProps: config.switchProps
|
|
1027
|
-
}
|
|
1028
|
-
);
|
|
1029
|
-
case "slider":
|
|
1030
|
-
return /* @__PURE__ */ React15.createElement(
|
|
1031
|
-
SliderField,
|
|
1032
|
-
{
|
|
1033
|
-
...baseProps,
|
|
1034
|
-
control,
|
|
1035
|
-
defaultValue: config.defaultValue,
|
|
1036
|
-
sliderProps: config.sliderProps
|
|
1037
|
-
}
|
|
1038
|
-
);
|
|
1039
|
-
case "date":
|
|
1040
|
-
return /* @__PURE__ */ React15.createElement(
|
|
1041
|
-
DateField,
|
|
1042
|
-
{
|
|
1043
|
-
...baseProps,
|
|
1044
|
-
control,
|
|
1045
|
-
dateProps: config.dateProps,
|
|
1046
|
-
defaultValue: config.defaultValue
|
|
1047
|
-
}
|
|
1048
|
-
);
|
|
1049
|
-
case "file":
|
|
1050
|
-
return /* @__PURE__ */ React15.createElement(
|
|
1051
|
-
FileField,
|
|
1052
|
-
{
|
|
1053
|
-
...baseProps,
|
|
1054
|
-
accept: config.accept,
|
|
1055
|
-
control,
|
|
1056
|
-
defaultValue: config.defaultValue,
|
|
1057
|
-
fileProps: config.fileProps,
|
|
1058
|
-
multiple: config.multiple
|
|
1059
|
-
}
|
|
1060
|
-
);
|
|
1061
|
-
case "fontPicker":
|
|
1062
|
-
return /* @__PURE__ */ React15.createElement(
|
|
1063
|
-
FontPickerField,
|
|
1064
|
-
{
|
|
1065
|
-
...baseProps,
|
|
1066
|
-
control,
|
|
1067
|
-
defaultValue: config.defaultValue,
|
|
1068
|
-
fontPickerProps: config.fontPickerProps
|
|
1069
|
-
}
|
|
1070
|
-
);
|
|
1071
|
-
case "custom":
|
|
1072
|
-
return config.render({
|
|
1073
|
-
control,
|
|
1074
|
-
errors: form.formState.errors,
|
|
1075
|
-
form,
|
|
1076
|
-
isSubmitting: submissionState.isSubmitting,
|
|
1077
|
-
name: config.name
|
|
1078
|
-
});
|
|
1079
|
-
case "conditional":
|
|
1080
|
-
return /* @__PURE__ */ React15.createElement(
|
|
1081
|
-
ConditionalField,
|
|
1082
|
-
{
|
|
1083
|
-
config,
|
|
1084
|
-
control,
|
|
1085
|
-
className: config.className
|
|
1086
|
-
}
|
|
1087
|
-
);
|
|
1088
|
-
case "fieldArray":
|
|
1089
|
-
return /* @__PURE__ */ React15.createElement(
|
|
1090
|
-
FieldArrayField,
|
|
1091
|
-
{
|
|
1092
|
-
config,
|
|
1093
|
-
className: config.className
|
|
1094
|
-
}
|
|
1095
|
-
);
|
|
1096
|
-
case "dynamicSection":
|
|
1097
|
-
return /* @__PURE__ */ React15.createElement(
|
|
1098
|
-
DynamicSectionField,
|
|
1099
|
-
{
|
|
1100
|
-
config,
|
|
1101
|
-
control,
|
|
1102
|
-
className: config.className
|
|
1103
|
-
}
|
|
1104
|
-
);
|
|
1105
|
-
default: {
|
|
1106
|
-
const fieldType = config.type;
|
|
1107
|
-
console.warn(`Unknown field type: ${fieldType}`);
|
|
950
|
+
const { control } = form;
|
|
951
|
+
const watchedValues = useWatch3({ control });
|
|
952
|
+
if (config.condition && !config.condition(watchedValues)) {
|
|
1108
953
|
return null;
|
|
1109
954
|
}
|
|
955
|
+
if (config.dependsOn) {
|
|
956
|
+
const dependentValue = watchedValues[config.dependsOn];
|
|
957
|
+
if (config.dependsOnValue !== void 0 && dependentValue !== config.dependsOnValue) {
|
|
958
|
+
return null;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
const baseProps = {
|
|
962
|
+
ariaDescribedBy: config.ariaDescribedBy,
|
|
963
|
+
ariaLabel: config.ariaLabel,
|
|
964
|
+
className: config.className,
|
|
965
|
+
description: config.description,
|
|
966
|
+
isDisabled: config.isDisabled ?? submissionState.isSubmitting,
|
|
967
|
+
label: config.label,
|
|
968
|
+
name: config.name,
|
|
969
|
+
rules: config.rules
|
|
970
|
+
};
|
|
971
|
+
switch (config.type) {
|
|
972
|
+
case "input":
|
|
973
|
+
return /* @__PURE__ */ React15.createElement(
|
|
974
|
+
InputField,
|
|
975
|
+
{
|
|
976
|
+
...baseProps,
|
|
977
|
+
control,
|
|
978
|
+
defaultValue: config.defaultValue,
|
|
979
|
+
inputProps: config.inputProps
|
|
980
|
+
}
|
|
981
|
+
);
|
|
982
|
+
case "textarea":
|
|
983
|
+
return /* @__PURE__ */ React15.createElement(
|
|
984
|
+
TextareaField,
|
|
985
|
+
{
|
|
986
|
+
...baseProps,
|
|
987
|
+
control,
|
|
988
|
+
defaultValue: config.defaultValue,
|
|
989
|
+
textareaProps: config.textareaProps
|
|
990
|
+
}
|
|
991
|
+
);
|
|
992
|
+
case "select":
|
|
993
|
+
return /* @__PURE__ */ React15.createElement(
|
|
994
|
+
SelectField,
|
|
995
|
+
{
|
|
996
|
+
...baseProps,
|
|
997
|
+
control,
|
|
998
|
+
defaultValue: config.defaultValue,
|
|
999
|
+
options: (config.options ?? []).map((opt) => ({
|
|
1000
|
+
label: opt.label,
|
|
1001
|
+
value: String(opt.value)
|
|
1002
|
+
})),
|
|
1003
|
+
selectProps: config.selectProps
|
|
1004
|
+
}
|
|
1005
|
+
);
|
|
1006
|
+
case "checkbox":
|
|
1007
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1008
|
+
CheckboxField,
|
|
1009
|
+
{
|
|
1010
|
+
...baseProps,
|
|
1011
|
+
checkboxProps: config.checkboxProps,
|
|
1012
|
+
control,
|
|
1013
|
+
defaultValue: config.defaultValue
|
|
1014
|
+
}
|
|
1015
|
+
);
|
|
1016
|
+
case "radio":
|
|
1017
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1018
|
+
RadioGroupField,
|
|
1019
|
+
{
|
|
1020
|
+
...baseProps,
|
|
1021
|
+
control,
|
|
1022
|
+
defaultValue: config.defaultValue,
|
|
1023
|
+
options: (config.radioOptions ?? []).map((opt) => ({
|
|
1024
|
+
label: opt.label,
|
|
1025
|
+
value: String(opt.value)
|
|
1026
|
+
})),
|
|
1027
|
+
radioGroupProps: config.radioProps
|
|
1028
|
+
}
|
|
1029
|
+
);
|
|
1030
|
+
case "switch":
|
|
1031
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1032
|
+
SwitchField,
|
|
1033
|
+
{
|
|
1034
|
+
...baseProps,
|
|
1035
|
+
control,
|
|
1036
|
+
defaultValue: config.defaultValue,
|
|
1037
|
+
switchProps: config.switchProps
|
|
1038
|
+
}
|
|
1039
|
+
);
|
|
1040
|
+
case "slider":
|
|
1041
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1042
|
+
SliderField,
|
|
1043
|
+
{
|
|
1044
|
+
...baseProps,
|
|
1045
|
+
control,
|
|
1046
|
+
defaultValue: config.defaultValue,
|
|
1047
|
+
sliderProps: config.sliderProps
|
|
1048
|
+
}
|
|
1049
|
+
);
|
|
1050
|
+
case "date":
|
|
1051
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1052
|
+
DateField,
|
|
1053
|
+
{
|
|
1054
|
+
...baseProps,
|
|
1055
|
+
control,
|
|
1056
|
+
dateProps: config.dateProps,
|
|
1057
|
+
defaultValue: config.defaultValue
|
|
1058
|
+
}
|
|
1059
|
+
);
|
|
1060
|
+
case "file":
|
|
1061
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1062
|
+
FileField,
|
|
1063
|
+
{
|
|
1064
|
+
...baseProps,
|
|
1065
|
+
accept: config.accept,
|
|
1066
|
+
control,
|
|
1067
|
+
defaultValue: config.defaultValue,
|
|
1068
|
+
fileProps: config.fileProps,
|
|
1069
|
+
multiple: config.multiple
|
|
1070
|
+
}
|
|
1071
|
+
);
|
|
1072
|
+
case "fontPicker":
|
|
1073
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1074
|
+
FontPickerField,
|
|
1075
|
+
{
|
|
1076
|
+
...baseProps,
|
|
1077
|
+
control,
|
|
1078
|
+
defaultValue: config.defaultValue,
|
|
1079
|
+
fontPickerProps: config.fontPickerProps
|
|
1080
|
+
}
|
|
1081
|
+
);
|
|
1082
|
+
case "custom":
|
|
1083
|
+
return config.render({
|
|
1084
|
+
control,
|
|
1085
|
+
errors: form.formState.errors,
|
|
1086
|
+
form,
|
|
1087
|
+
isSubmitting: submissionState.isSubmitting,
|
|
1088
|
+
name: config.name
|
|
1089
|
+
});
|
|
1090
|
+
case "conditional":
|
|
1091
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1092
|
+
ConditionalField,
|
|
1093
|
+
{
|
|
1094
|
+
config,
|
|
1095
|
+
control,
|
|
1096
|
+
className: config.className
|
|
1097
|
+
}
|
|
1098
|
+
);
|
|
1099
|
+
case "fieldArray":
|
|
1100
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1101
|
+
FieldArrayField,
|
|
1102
|
+
{
|
|
1103
|
+
config,
|
|
1104
|
+
className: config.className
|
|
1105
|
+
}
|
|
1106
|
+
);
|
|
1107
|
+
case "dynamicSection":
|
|
1108
|
+
return /* @__PURE__ */ React15.createElement(
|
|
1109
|
+
DynamicSectionField,
|
|
1110
|
+
{
|
|
1111
|
+
config,
|
|
1112
|
+
control,
|
|
1113
|
+
className: config.className
|
|
1114
|
+
}
|
|
1115
|
+
);
|
|
1116
|
+
default: {
|
|
1117
|
+
const fieldType = config.type;
|
|
1118
|
+
console.warn(`Unknown field type: ${fieldType}`);
|
|
1119
|
+
return null;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1110
1122
|
}
|
|
1111
|
-
|
|
1123
|
+
);
|
|
1112
1124
|
|
|
1113
1125
|
// src/components/Form.tsx
|
|
1114
1126
|
function ConfigurableForm({
|
|
@@ -1224,6 +1236,334 @@ function ConfigurableForm({
|
|
|
1224
1236
|
)));
|
|
1225
1237
|
}
|
|
1226
1238
|
|
|
1239
|
+
// src/components/ServerActionForm.tsx
|
|
1240
|
+
import React17 from "react";
|
|
1241
|
+
import {
|
|
1242
|
+
Button as Button4,
|
|
1243
|
+
Checkbox as Checkbox2,
|
|
1244
|
+
Input as Input2,
|
|
1245
|
+
Select as Select2,
|
|
1246
|
+
SelectItem as SelectItem2,
|
|
1247
|
+
Textarea as Textarea2
|
|
1248
|
+
} from "@heroui/react";
|
|
1249
|
+
import { useActionState } from "react";
|
|
1250
|
+
function ServerActionForm({
|
|
1251
|
+
action,
|
|
1252
|
+
className,
|
|
1253
|
+
clientValidationSchema,
|
|
1254
|
+
columns = 1,
|
|
1255
|
+
defaultValues,
|
|
1256
|
+
fields,
|
|
1257
|
+
initialState,
|
|
1258
|
+
layout = "vertical",
|
|
1259
|
+
onError,
|
|
1260
|
+
onSuccess,
|
|
1261
|
+
resetButtonText = "Reset",
|
|
1262
|
+
showResetButton = false,
|
|
1263
|
+
spacing = "4",
|
|
1264
|
+
submitButtonProps = {},
|
|
1265
|
+
submitButtonText = "Submit",
|
|
1266
|
+
subtitle,
|
|
1267
|
+
title
|
|
1268
|
+
}) {
|
|
1269
|
+
const [state, formAction, pending] = useActionState(
|
|
1270
|
+
action,
|
|
1271
|
+
initialState ?? { errors: void 0, message: void 0, success: false }
|
|
1272
|
+
);
|
|
1273
|
+
const formRef = React17.useRef(null);
|
|
1274
|
+
const [clientErrors, setClientErrors] = React17.useState({});
|
|
1275
|
+
const lastSubmittedFormData = React17.useRef(null);
|
|
1276
|
+
React17.useEffect(() => {
|
|
1277
|
+
if (state && (state.errors || state.message && !state.success)) {
|
|
1278
|
+
onError?.({
|
|
1279
|
+
errors: state.errors,
|
|
1280
|
+
message: state.message
|
|
1281
|
+
});
|
|
1282
|
+
}
|
|
1283
|
+
}, [state, onError]);
|
|
1284
|
+
React17.useEffect(() => {
|
|
1285
|
+
if (state?.success && lastSubmittedFormData.current) {
|
|
1286
|
+
onSuccess?.(lastSubmittedFormData.current);
|
|
1287
|
+
}
|
|
1288
|
+
}, [state?.success, onSuccess]);
|
|
1289
|
+
const handleReset = () => {
|
|
1290
|
+
formRef.current?.reset();
|
|
1291
|
+
setClientErrors({});
|
|
1292
|
+
};
|
|
1293
|
+
const handleSubmit = async (e) => {
|
|
1294
|
+
e.preventDefault();
|
|
1295
|
+
if (clientValidationSchema) {
|
|
1296
|
+
const formData2 = new FormData(e.currentTarget);
|
|
1297
|
+
const values = {};
|
|
1298
|
+
formData2.forEach((val, key) => {
|
|
1299
|
+
if (val === "on") {
|
|
1300
|
+
values[key] = true;
|
|
1301
|
+
} else if (val === "") {
|
|
1302
|
+
if (!values[key]) {
|
|
1303
|
+
values[key] = false;
|
|
1304
|
+
}
|
|
1305
|
+
} else {
|
|
1306
|
+
values[key] = val;
|
|
1307
|
+
}
|
|
1308
|
+
});
|
|
1309
|
+
const result = clientValidationSchema.safeParse(values);
|
|
1310
|
+
if (!result.success) {
|
|
1311
|
+
const errors = {};
|
|
1312
|
+
result.error.issues.forEach((issue) => {
|
|
1313
|
+
const path = issue.path.join(".");
|
|
1314
|
+
errors[path] = issue.message;
|
|
1315
|
+
});
|
|
1316
|
+
setClientErrors((prev) => ({ ...prev, ...errors }));
|
|
1317
|
+
return;
|
|
1318
|
+
}
|
|
1319
|
+
setClientErrors({});
|
|
1320
|
+
}
|
|
1321
|
+
const formData = new FormData(e.currentTarget);
|
|
1322
|
+
lastSubmittedFormData.current = formData;
|
|
1323
|
+
formAction(formData);
|
|
1324
|
+
};
|
|
1325
|
+
const renderFields = () => {
|
|
1326
|
+
if (layout === "grid") {
|
|
1327
|
+
return /* @__PURE__ */ React17.createElement(
|
|
1328
|
+
"div",
|
|
1329
|
+
{
|
|
1330
|
+
className: `grid gap-${spacing} ${columns === 1 ? "grid-cols-1" : columns === 2 ? "grid-cols-1 md:grid-cols-2" : "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"}`
|
|
1331
|
+
},
|
|
1332
|
+
fields.map((field2) => /* @__PURE__ */ React17.createElement(
|
|
1333
|
+
ServerActionField,
|
|
1334
|
+
{
|
|
1335
|
+
key: field2.name,
|
|
1336
|
+
clientErrors,
|
|
1337
|
+
defaultValues,
|
|
1338
|
+
errors: state?.errors,
|
|
1339
|
+
field: field2
|
|
1340
|
+
}
|
|
1341
|
+
))
|
|
1342
|
+
);
|
|
1343
|
+
}
|
|
1344
|
+
if (layout === "horizontal") {
|
|
1345
|
+
return /* @__PURE__ */ React17.createElement("div", { className: `grid gap-${spacing} grid-cols-1 md:grid-cols-2` }, fields.map((field2) => /* @__PURE__ */ React17.createElement(
|
|
1346
|
+
ServerActionField,
|
|
1347
|
+
{
|
|
1348
|
+
key: field2.name,
|
|
1349
|
+
clientErrors,
|
|
1350
|
+
defaultValues,
|
|
1351
|
+
errors: state?.errors,
|
|
1352
|
+
field: field2
|
|
1353
|
+
}
|
|
1354
|
+
)));
|
|
1355
|
+
}
|
|
1356
|
+
return /* @__PURE__ */ React17.createElement("div", { className: `space-y-${spacing}` }, fields.map((field2) => /* @__PURE__ */ React17.createElement(
|
|
1357
|
+
ServerActionField,
|
|
1358
|
+
{
|
|
1359
|
+
key: field2.name,
|
|
1360
|
+
clientErrors,
|
|
1361
|
+
defaultValues,
|
|
1362
|
+
errors: state?.errors,
|
|
1363
|
+
field: field2
|
|
1364
|
+
}
|
|
1365
|
+
)));
|
|
1366
|
+
};
|
|
1367
|
+
return /* @__PURE__ */ React17.createElement(
|
|
1368
|
+
"form",
|
|
1369
|
+
{
|
|
1370
|
+
ref: formRef,
|
|
1371
|
+
className,
|
|
1372
|
+
role: "form",
|
|
1373
|
+
onSubmit: handleSubmit
|
|
1374
|
+
},
|
|
1375
|
+
title && /* @__PURE__ */ React17.createElement("div", { className: "mb-6" }, /* @__PURE__ */ React17.createElement("h2", { className: "text-xl font-semibold text-foreground mb-2" }, title), subtitle && /* @__PURE__ */ React17.createElement("p", { className: "text-sm text-muted-foreground" }, subtitle)),
|
|
1376
|
+
state?.success && !pending && /* @__PURE__ */ React17.createElement(
|
|
1377
|
+
"div",
|
|
1378
|
+
{
|
|
1379
|
+
className: "mb-6 p-4 bg-success-50 border border-success-200 rounded-lg",
|
|
1380
|
+
"data-testid": "success-message"
|
|
1381
|
+
},
|
|
1382
|
+
/* @__PURE__ */ React17.createElement("p", { className: "text-success-800 font-medium" }, "Success!"),
|
|
1383
|
+
state.message && /* @__PURE__ */ React17.createElement("p", { className: "text-success-700 text-sm mt-1" }, state.message)
|
|
1384
|
+
),
|
|
1385
|
+
state?.message && !state.success && /* @__PURE__ */ React17.createElement(
|
|
1386
|
+
"div",
|
|
1387
|
+
{
|
|
1388
|
+
className: "mb-6 p-4 bg-danger-50 border border-danger-200 rounded-lg",
|
|
1389
|
+
"data-testid": "error-message"
|
|
1390
|
+
},
|
|
1391
|
+
/* @__PURE__ */ React17.createElement("p", { className: "text-danger-800 font-medium" }, "Error"),
|
|
1392
|
+
/* @__PURE__ */ React17.createElement("p", { className: "text-danger-700 text-sm mt-1" }, state.message)
|
|
1393
|
+
),
|
|
1394
|
+
renderFields(),
|
|
1395
|
+
/* @__PURE__ */ React17.createElement("div", { className: "mt-6 flex gap-3 justify-end" }, /* @__PURE__ */ React17.createElement(
|
|
1396
|
+
Button4,
|
|
1397
|
+
{
|
|
1398
|
+
color: "primary",
|
|
1399
|
+
isDisabled: pending,
|
|
1400
|
+
isLoading: pending,
|
|
1401
|
+
type: "submit",
|
|
1402
|
+
...submitButtonProps
|
|
1403
|
+
},
|
|
1404
|
+
submitButtonText
|
|
1405
|
+
), showResetButton && /* @__PURE__ */ React17.createElement(
|
|
1406
|
+
Button4,
|
|
1407
|
+
{
|
|
1408
|
+
isDisabled: pending,
|
|
1409
|
+
type: "button",
|
|
1410
|
+
variant: "bordered",
|
|
1411
|
+
onPress: handleReset
|
|
1412
|
+
},
|
|
1413
|
+
resetButtonText
|
|
1414
|
+
))
|
|
1415
|
+
);
|
|
1416
|
+
}
|
|
1417
|
+
function ServerActionField({
|
|
1418
|
+
clientErrors,
|
|
1419
|
+
defaultValues,
|
|
1420
|
+
errors,
|
|
1421
|
+
field: field2
|
|
1422
|
+
}) {
|
|
1423
|
+
const fieldName = field2.name;
|
|
1424
|
+
const fieldErrors = errors?.[fieldName];
|
|
1425
|
+
const clientError = clientErrors?.[fieldName];
|
|
1426
|
+
const errorMessage = clientError || (fieldErrors && fieldErrors.length > 0 ? fieldErrors[0] : void 0);
|
|
1427
|
+
const getDefaultValue = () => {
|
|
1428
|
+
const fromProps = defaultValues?.[fieldName];
|
|
1429
|
+
const fromField = field2.defaultValue;
|
|
1430
|
+
if (fromProps !== void 0 && fromProps !== null) {
|
|
1431
|
+
return typeof fromProps === "string" ? fromProps : String(fromProps);
|
|
1432
|
+
}
|
|
1433
|
+
if (fromField !== void 0 && fromField !== null) {
|
|
1434
|
+
return typeof fromField === "string" ? fromField : String(fromField);
|
|
1435
|
+
}
|
|
1436
|
+
return "";
|
|
1437
|
+
};
|
|
1438
|
+
const getDefaultChecked = () => {
|
|
1439
|
+
const fromProps = defaultValues?.[fieldName];
|
|
1440
|
+
const fromField = field2.defaultValue;
|
|
1441
|
+
if (fromProps !== void 0 && fromProps !== null) {
|
|
1442
|
+
return typeof fromProps === "boolean" ? fromProps : false;
|
|
1443
|
+
}
|
|
1444
|
+
if (fromField !== void 0 && fromField !== null) {
|
|
1445
|
+
return typeof fromField === "boolean" ? fromField : false;
|
|
1446
|
+
}
|
|
1447
|
+
return false;
|
|
1448
|
+
};
|
|
1449
|
+
const [value, setValue] = React17.useState(getDefaultValue);
|
|
1450
|
+
const [checked, setChecked] = React17.useState(getDefaultChecked);
|
|
1451
|
+
React17.useEffect(() => {
|
|
1452
|
+
const newDefaultValue = defaultValues?.[fieldName];
|
|
1453
|
+
if (newDefaultValue !== void 0 && newDefaultValue !== null) {
|
|
1454
|
+
if (field2.type === "checkbox") {
|
|
1455
|
+
setChecked(
|
|
1456
|
+
typeof newDefaultValue === "boolean" ? newDefaultValue : false
|
|
1457
|
+
);
|
|
1458
|
+
} else {
|
|
1459
|
+
setValue(
|
|
1460
|
+
typeof newDefaultValue === "string" ? newDefaultValue : String(newDefaultValue)
|
|
1461
|
+
);
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
}, [defaultValues, fieldName, field2.type]);
|
|
1465
|
+
React17.useEffect(() => {
|
|
1466
|
+
const hiddenInput = document.querySelector(
|
|
1467
|
+
`input[type="hidden"][name="${fieldName}"]`
|
|
1468
|
+
);
|
|
1469
|
+
if (hiddenInput) {
|
|
1470
|
+
if (field2.type === "checkbox") {
|
|
1471
|
+
hiddenInput.value = checked ? "on" : "";
|
|
1472
|
+
} else {
|
|
1473
|
+
hiddenInput.value = value;
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
}, [value, checked, fieldName, field2.type]);
|
|
1477
|
+
switch (field2.type) {
|
|
1478
|
+
case "input": {
|
|
1479
|
+
const inputType = field2.inputProps?.type || "text";
|
|
1480
|
+
return /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("input", { type: "hidden", name: fieldName, value }), /* @__PURE__ */ React17.createElement(
|
|
1481
|
+
Input2,
|
|
1482
|
+
{
|
|
1483
|
+
...field2.inputProps,
|
|
1484
|
+
"data-field-name": fieldName,
|
|
1485
|
+
type: inputType,
|
|
1486
|
+
label: field2.label,
|
|
1487
|
+
description: field2.description,
|
|
1488
|
+
isDisabled: field2.isDisabled,
|
|
1489
|
+
isInvalid: Boolean(errorMessage),
|
|
1490
|
+
errorMessage,
|
|
1491
|
+
value,
|
|
1492
|
+
onValueChange: setValue
|
|
1493
|
+
}
|
|
1494
|
+
));
|
|
1495
|
+
}
|
|
1496
|
+
case "textarea": {
|
|
1497
|
+
return /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("input", { type: "hidden", name: fieldName, value }), /* @__PURE__ */ React17.createElement(
|
|
1498
|
+
Textarea2,
|
|
1499
|
+
{
|
|
1500
|
+
...field2.textareaProps,
|
|
1501
|
+
"data-field-name": fieldName,
|
|
1502
|
+
label: field2.label,
|
|
1503
|
+
description: field2.description,
|
|
1504
|
+
isDisabled: field2.isDisabled,
|
|
1505
|
+
isInvalid: Boolean(errorMessage),
|
|
1506
|
+
errorMessage,
|
|
1507
|
+
value,
|
|
1508
|
+
onValueChange: setValue
|
|
1509
|
+
}
|
|
1510
|
+
));
|
|
1511
|
+
}
|
|
1512
|
+
case "checkbox": {
|
|
1513
|
+
return /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("input", { type: "hidden", name: fieldName, value: checked ? "on" : "" }), /* @__PURE__ */ React17.createElement(
|
|
1514
|
+
Checkbox2,
|
|
1515
|
+
{
|
|
1516
|
+
...field2.checkboxProps,
|
|
1517
|
+
"data-field-name": fieldName,
|
|
1518
|
+
isDisabled: field2.isDisabled,
|
|
1519
|
+
isSelected: checked,
|
|
1520
|
+
onValueChange: setChecked,
|
|
1521
|
+
isInvalid: Boolean(errorMessage),
|
|
1522
|
+
errorMessage
|
|
1523
|
+
},
|
|
1524
|
+
field2.label
|
|
1525
|
+
));
|
|
1526
|
+
}
|
|
1527
|
+
case "select": {
|
|
1528
|
+
const options = field2.options || [];
|
|
1529
|
+
return /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("input", { type: "hidden", name: fieldName, value }), /* @__PURE__ */ React17.createElement(
|
|
1530
|
+
Select2,
|
|
1531
|
+
{
|
|
1532
|
+
...field2.selectProps,
|
|
1533
|
+
"data-field-name": fieldName,
|
|
1534
|
+
label: field2.label,
|
|
1535
|
+
description: field2.description,
|
|
1536
|
+
isDisabled: field2.isDisabled,
|
|
1537
|
+
isInvalid: Boolean(errorMessage),
|
|
1538
|
+
errorMessage,
|
|
1539
|
+
selectedKeys: value ? [value] : [],
|
|
1540
|
+
onSelectionChange: (keys) => {
|
|
1541
|
+
const selectedValue = Array.from(keys)[0];
|
|
1542
|
+
setValue(selectedValue || "");
|
|
1543
|
+
}
|
|
1544
|
+
},
|
|
1545
|
+
options.map(
|
|
1546
|
+
(option) => /* @__PURE__ */ React17.createElement(SelectItem2, { key: String(option.value) }, option.label)
|
|
1547
|
+
)
|
|
1548
|
+
));
|
|
1549
|
+
}
|
|
1550
|
+
default:
|
|
1551
|
+
return /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("input", { type: "hidden", name: fieldName, value }), /* @__PURE__ */ React17.createElement(
|
|
1552
|
+
Input2,
|
|
1553
|
+
{
|
|
1554
|
+
"data-field-name": fieldName,
|
|
1555
|
+
label: field2.label,
|
|
1556
|
+
description: field2.description,
|
|
1557
|
+
isDisabled: field2.isDisabled,
|
|
1558
|
+
isInvalid: Boolean(errorMessage),
|
|
1559
|
+
errorMessage,
|
|
1560
|
+
value,
|
|
1561
|
+
onValueChange: setValue
|
|
1562
|
+
}
|
|
1563
|
+
));
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1227
1567
|
// src/hooks/useHeroForm.ts
|
|
1228
1568
|
import { useFormContext as useFormContext4 } from "react-hook-form";
|
|
1229
1569
|
function useHeroForm() {
|
|
@@ -1238,10 +1578,10 @@ function useHeroForm() {
|
|
|
1238
1578
|
}
|
|
1239
1579
|
|
|
1240
1580
|
// src/providers/FormProvider.tsx
|
|
1241
|
-
import
|
|
1581
|
+
import React18 from "react";
|
|
1242
1582
|
import { FormProvider as RHFProvider } from "react-hook-form";
|
|
1243
1583
|
function FormProvider(props) {
|
|
1244
|
-
return /* @__PURE__ */
|
|
1584
|
+
return /* @__PURE__ */ React18.createElement(RHFProvider, { ...props.methods }, /* @__PURE__ */ React18.createElement(
|
|
1245
1585
|
"form",
|
|
1246
1586
|
{
|
|
1247
1587
|
className: props.className,
|
|
@@ -1254,7 +1594,7 @@ function FormProvider(props) {
|
|
|
1254
1594
|
}
|
|
1255
1595
|
|
|
1256
1596
|
// src/submit/SubmitButton.tsx
|
|
1257
|
-
import
|
|
1597
|
+
import React19 from "react";
|
|
1258
1598
|
function SubmitButton(props) {
|
|
1259
1599
|
const ctx = useFormContext5();
|
|
1260
1600
|
const loading = props.isLoading ?? ctx.formState.isSubmitting;
|
|
@@ -1264,10 +1604,10 @@ function SubmitButton(props) {
|
|
|
1264
1604
|
const defaults = useHeroHookFormDefaults();
|
|
1265
1605
|
const getButtonContent = () => {
|
|
1266
1606
|
if (enhancedState?.isSuccess) {
|
|
1267
|
-
return /* @__PURE__ */
|
|
1607
|
+
return /* @__PURE__ */ React19.createElement("span", { className: "inline-flex items-center gap-2" }, "\u2705", props.successText || "Success!");
|
|
1268
1608
|
}
|
|
1269
1609
|
if (loading) {
|
|
1270
|
-
return /* @__PURE__ */
|
|
1610
|
+
return /* @__PURE__ */ React19.createElement("span", { className: "inline-flex items-center gap-2" }, "\u23F3", props.loadingText || "Submitting...");
|
|
1271
1611
|
}
|
|
1272
1612
|
return props.children;
|
|
1273
1613
|
};
|
|
@@ -1280,7 +1620,7 @@ function SubmitButton(props) {
|
|
|
1280
1620
|
}
|
|
1281
1621
|
return props.buttonProps?.color || defaults.submitButton.color;
|
|
1282
1622
|
};
|
|
1283
|
-
return /* @__PURE__ */
|
|
1623
|
+
return /* @__PURE__ */ React19.createElement(
|
|
1284
1624
|
Button,
|
|
1285
1625
|
{
|
|
1286
1626
|
type: "submit",
|
|
@@ -1429,14 +1769,6 @@ var createPasswordSchema = (minLength = 8) => z.string().min(minLength, `Passwor
|
|
|
1429
1769
|
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/,
|
|
1430
1770
|
"Password must contain at least one uppercase letter, one lowercase letter, and one number"
|
|
1431
1771
|
);
|
|
1432
|
-
var createConfirmPasswordSchema = (passwordField) => z.string().refine(
|
|
1433
|
-
(val) => {
|
|
1434
|
-
return true;
|
|
1435
|
-
},
|
|
1436
|
-
{
|
|
1437
|
-
message: "Passwords do not match"
|
|
1438
|
-
}
|
|
1439
|
-
);
|
|
1440
1772
|
var createNumberRangeSchema = (min, max, fieldName) => z.number().min(min, `${fieldName} must be at least ${min}`).max(max, `${fieldName} must be no more than ${max}`);
|
|
1441
1773
|
var createDateSchema = (fieldName) => z.date({ message: `${fieldName} is required` });
|
|
1442
1774
|
var createFutureDateSchema = (fieldName) => z.date({ message: `${fieldName} is required` }).refine((date) => date > /* @__PURE__ */ new Date(), {
|
|
@@ -1455,44 +1787,24 @@ var createFileSchema = (maxSizeInMB = 5, allowedTypes = ["image/jpeg", "image/pn
|
|
|
1455
1787
|
var createRequiredCheckboxSchema = (fieldName) => z.boolean().refine((val) => val === true, {
|
|
1456
1788
|
message: `You must agree to ${fieldName}`
|
|
1457
1789
|
});
|
|
1458
|
-
var createConditionalSchema = (condition, schema, errorMessage = "This field is required") => z.any().refine(
|
|
1459
|
-
(val) => {
|
|
1460
|
-
return true;
|
|
1461
|
-
},
|
|
1462
|
-
{
|
|
1463
|
-
message: errorMessage
|
|
1464
|
-
}
|
|
1465
|
-
);
|
|
1466
|
-
var commonValidations = {
|
|
1467
|
-
conditional: (condition, schema, errorMessage) => createConditionalSchema(condition, schema, errorMessage),
|
|
1468
|
-
confirmPassword: (passwordField) => createConfirmPasswordSchema(passwordField),
|
|
1469
|
-
date: (fieldName) => createDateSchema(fieldName),
|
|
1470
|
-
email: createEmailSchema(),
|
|
1471
|
-
file: (maxSizeInMB, allowedTypes) => createFileSchema(maxSizeInMB, allowedTypes),
|
|
1472
|
-
futureDate: (fieldName) => createFutureDateSchema(fieldName),
|
|
1473
|
-
maxLength: (max, fieldName) => createMaxLengthSchema(max, fieldName),
|
|
1474
|
-
minLength: (min, fieldName) => createMinLengthSchema(min, fieldName),
|
|
1475
|
-
numberRange: (min, max, fieldName) => createNumberRangeSchema(min, max, fieldName),
|
|
1476
|
-
password: (minLength) => createPasswordSchema(minLength),
|
|
1477
|
-
pastDate: (fieldName) => createPastDateSchema(fieldName),
|
|
1478
|
-
phone: createPhoneSchema(),
|
|
1479
|
-
required: (fieldName) => createRequiredSchema(fieldName),
|
|
1480
|
-
requiredCheckbox: (fieldName) => createRequiredCheckboxSchema(fieldName),
|
|
1481
|
-
url: createUrlSchema()
|
|
1482
|
-
};
|
|
1483
1790
|
var crossFieldValidation = {
|
|
1484
1791
|
/**
|
|
1485
|
-
*
|
|
1792
|
+
* Conditional required field validation
|
|
1486
1793
|
*/
|
|
1487
|
-
|
|
1794
|
+
conditionalRequired: (field2, conditionField, conditionValue) => {
|
|
1488
1795
|
return z.object({
|
|
1489
|
-
[
|
|
1490
|
-
[
|
|
1796
|
+
[conditionField]: z.any(),
|
|
1797
|
+
[field2]: z.string()
|
|
1491
1798
|
}).refine(
|
|
1492
|
-
(data) =>
|
|
1799
|
+
(data) => {
|
|
1800
|
+
if (data[conditionField] === conditionValue) {
|
|
1801
|
+
return data[field2] && data[field2].trim().length > 0;
|
|
1802
|
+
}
|
|
1803
|
+
return true;
|
|
1804
|
+
},
|
|
1493
1805
|
{
|
|
1494
|
-
message: "
|
|
1495
|
-
path: [
|
|
1806
|
+
message: "This field is required",
|
|
1807
|
+
path: [field2]
|
|
1496
1808
|
}
|
|
1497
1809
|
);
|
|
1498
1810
|
},
|
|
@@ -1501,8 +1813,8 @@ var crossFieldValidation = {
|
|
|
1501
1813
|
*/
|
|
1502
1814
|
dateRange: (startField, endField) => {
|
|
1503
1815
|
return z.object({
|
|
1504
|
-
[
|
|
1505
|
-
[
|
|
1816
|
+
[endField]: z.string(),
|
|
1817
|
+
[startField]: z.string()
|
|
1506
1818
|
}).refine(
|
|
1507
1819
|
(data) => {
|
|
1508
1820
|
const startDate = new Date(data[startField]);
|
|
@@ -1516,39 +1828,47 @@ var crossFieldValidation = {
|
|
|
1516
1828
|
);
|
|
1517
1829
|
},
|
|
1518
1830
|
/**
|
|
1519
|
-
*
|
|
1831
|
+
* Password confirmation validation
|
|
1520
1832
|
*/
|
|
1521
|
-
|
|
1833
|
+
passwordConfirmation: (passwordField, confirmField) => {
|
|
1522
1834
|
return z.object({
|
|
1523
|
-
[
|
|
1524
|
-
[
|
|
1525
|
-
}).refine(
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
}
|
|
1530
|
-
return true;
|
|
1531
|
-
},
|
|
1532
|
-
{
|
|
1533
|
-
message: "This field is required",
|
|
1534
|
-
path: [field2]
|
|
1535
|
-
}
|
|
1536
|
-
);
|
|
1835
|
+
[confirmField]: z.string(),
|
|
1836
|
+
[passwordField]: z.string()
|
|
1837
|
+
}).refine((data) => data[passwordField] === data[confirmField], {
|
|
1838
|
+
message: "Passwords do not match",
|
|
1839
|
+
path: [confirmField]
|
|
1840
|
+
});
|
|
1537
1841
|
}
|
|
1538
1842
|
};
|
|
1843
|
+
var commonValidations = {
|
|
1844
|
+
confirmPassword: (passwordField, confirmField) => crossFieldValidation.passwordConfirmation(passwordField, confirmField),
|
|
1845
|
+
date: (fieldName) => createDateSchema(fieldName),
|
|
1846
|
+
email: createEmailSchema(),
|
|
1847
|
+
file: (maxSizeInMB, allowedTypes) => createFileSchema(maxSizeInMB, allowedTypes),
|
|
1848
|
+
futureDate: (fieldName) => createFutureDateSchema(fieldName),
|
|
1849
|
+
maxLength: (max, fieldName) => createMaxLengthSchema(max, fieldName),
|
|
1850
|
+
minLength: (min, fieldName) => createMinLengthSchema(min, fieldName),
|
|
1851
|
+
numberRange: (min, max, fieldName) => createNumberRangeSchema(min, max, fieldName),
|
|
1852
|
+
password: (minLength) => createPasswordSchema(minLength),
|
|
1853
|
+
pastDate: (fieldName) => createPastDateSchema(fieldName),
|
|
1854
|
+
phone: createPhoneSchema(),
|
|
1855
|
+
required: (fieldName) => createRequiredSchema(fieldName),
|
|
1856
|
+
requiredCheckbox: (fieldName) => createRequiredCheckboxSchema(fieldName),
|
|
1857
|
+
url: createUrlSchema()
|
|
1858
|
+
};
|
|
1539
1859
|
|
|
1540
1860
|
// src/index.ts
|
|
1541
1861
|
import { useFormContext as useFormContext5 } from "react-hook-form";
|
|
1542
1862
|
|
|
1543
1863
|
// src/components/ZodForm.tsx
|
|
1544
|
-
import
|
|
1545
|
-
import { Button as
|
|
1864
|
+
import React21 from "react";
|
|
1865
|
+
import { Button as Button6 } from "@heroui/react";
|
|
1546
1866
|
|
|
1547
1867
|
// src/zod-integration.ts
|
|
1548
1868
|
import { useForm as useForm2 } from "react-hook-form";
|
|
1549
1869
|
import { z as z2 } from "zod";
|
|
1550
1870
|
function createZodResolver(schema) {
|
|
1551
|
-
return async (values
|
|
1871
|
+
return async (values) => {
|
|
1552
1872
|
try {
|
|
1553
1873
|
const result = await schema.parseAsync(values);
|
|
1554
1874
|
return {
|
|
@@ -1579,9 +1899,11 @@ function useZodForm(config) {
|
|
|
1579
1899
|
}
|
|
1580
1900
|
function createZodFormConfig(schema, fields, defaultValues) {
|
|
1581
1901
|
return {
|
|
1582
|
-
schema,
|
|
1583
1902
|
fields,
|
|
1584
|
-
|
|
1903
|
+
schema,
|
|
1904
|
+
...defaultValues && {
|
|
1905
|
+
defaultValues
|
|
1906
|
+
}
|
|
1585
1907
|
};
|
|
1586
1908
|
}
|
|
1587
1909
|
|
|
@@ -1589,18 +1911,20 @@ function createZodFormConfig(schema, fields, defaultValues) {
|
|
|
1589
1911
|
import { useCallback, useEffect, useState as useState2 } from "react";
|
|
1590
1912
|
function useEnhancedFormState(form, options = {}) {
|
|
1591
1913
|
const {
|
|
1592
|
-
onSuccess,
|
|
1593
|
-
onError,
|
|
1594
|
-
successMessage = "Form submitted successfully!",
|
|
1595
|
-
errorMessage = "An error occurred. Please try again.",
|
|
1596
1914
|
autoReset = true,
|
|
1597
|
-
|
|
1915
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1916
|
+
errorMessage: _errorMessage = "An error occurred. Please try again.",
|
|
1917
|
+
onError,
|
|
1918
|
+
onSuccess,
|
|
1919
|
+
resetDelay = 3e3,
|
|
1920
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1921
|
+
successMessage: _successMessage = "Form submitted successfully!"
|
|
1598
1922
|
} = options;
|
|
1599
1923
|
const [status, setStatus] = useState2("idle");
|
|
1600
1924
|
const [error, setError] = useState2(void 0);
|
|
1601
1925
|
const [submittedData, setSubmittedData] = useState2(void 0);
|
|
1602
|
-
const { formState, getValues } = form;
|
|
1603
|
-
const {
|
|
1926
|
+
const { formState, getValues: _getValues } = form;
|
|
1927
|
+
const { dirtyFields, errors, isSubmitting, touchedFields } = formState;
|
|
1604
1928
|
useEffect(() => {
|
|
1605
1929
|
if (isSubmitting) {
|
|
1606
1930
|
setStatus("submitting");
|
|
@@ -1616,92 +1940,123 @@ function useEnhancedFormState(form, options = {}) {
|
|
|
1616
1940
|
return () => clearTimeout(timer);
|
|
1617
1941
|
}
|
|
1618
1942
|
}, [status, autoReset, resetDelay]);
|
|
1619
|
-
const handleSuccess = useCallback(
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1943
|
+
const handleSuccess = useCallback(
|
|
1944
|
+
(data) => {
|
|
1945
|
+
setStatus("success");
|
|
1946
|
+
setSubmittedData(data);
|
|
1947
|
+
setError(void 0);
|
|
1948
|
+
onSuccess?.(data);
|
|
1949
|
+
},
|
|
1950
|
+
[onSuccess]
|
|
1951
|
+
);
|
|
1952
|
+
const handleError = useCallback(
|
|
1953
|
+
(errorMessage) => {
|
|
1954
|
+
setStatus("error");
|
|
1955
|
+
setError(errorMessage);
|
|
1956
|
+
setSubmittedData(void 0);
|
|
1957
|
+
onError?.(errorMessage);
|
|
1958
|
+
},
|
|
1959
|
+
[onError]
|
|
1960
|
+
);
|
|
1631
1961
|
const reset = useCallback(() => {
|
|
1632
1962
|
setStatus("idle");
|
|
1633
1963
|
setError(void 0);
|
|
1634
1964
|
setSubmittedData(void 0);
|
|
1635
1965
|
}, []);
|
|
1636
1966
|
return {
|
|
1637
|
-
status,
|
|
1638
|
-
isSubmitting,
|
|
1639
|
-
isSuccess: status === "success",
|
|
1640
|
-
isError: status === "error",
|
|
1641
|
-
error,
|
|
1642
|
-
submittedData,
|
|
1643
|
-
touchedFields: new Set(Object.keys(touchedFields)),
|
|
1644
1967
|
dirtyFields: new Set(Object.keys(dirtyFields)),
|
|
1645
|
-
|
|
1968
|
+
error,
|
|
1646
1969
|
errorCount: Object.keys(errors).length,
|
|
1647
|
-
handleSuccess,
|
|
1648
1970
|
handleError,
|
|
1649
|
-
|
|
1971
|
+
handleSuccess,
|
|
1972
|
+
hasErrors: Object.keys(errors).length > 0,
|
|
1973
|
+
isError: status === "error",
|
|
1974
|
+
isSubmitting,
|
|
1975
|
+
isSuccess: status === "success",
|
|
1976
|
+
reset,
|
|
1977
|
+
status,
|
|
1978
|
+
submittedData,
|
|
1979
|
+
touchedFields: new Set(Object.keys(touchedFields))
|
|
1650
1980
|
};
|
|
1651
1981
|
}
|
|
1652
1982
|
|
|
1653
1983
|
// src/components/FormStatus.tsx
|
|
1654
|
-
import
|
|
1655
|
-
import { Button as
|
|
1984
|
+
import React20 from "react";
|
|
1985
|
+
import { Button as Button5 } from "@heroui/react";
|
|
1656
1986
|
function FormStatus({
|
|
1657
|
-
state,
|
|
1658
|
-
onDismiss,
|
|
1659
1987
|
className = "",
|
|
1660
|
-
|
|
1988
|
+
onDismiss,
|
|
1989
|
+
showDetails = false,
|
|
1990
|
+
state
|
|
1661
1991
|
}) {
|
|
1662
|
-
const {
|
|
1992
|
+
const { error, isError, isSubmitting, isSuccess, status, submittedData } = state;
|
|
1663
1993
|
if (status === "idle") {
|
|
1664
1994
|
return null;
|
|
1665
1995
|
}
|
|
1666
1996
|
if (isSubmitting) {
|
|
1667
|
-
return /* @__PURE__ */
|
|
1997
|
+
return /* @__PURE__ */ React20.createElement(
|
|
1998
|
+
"div",
|
|
1999
|
+
{
|
|
2000
|
+
className: `flex items-center gap-3 p-4 bg-blue-50 border border-blue-200 rounded-lg ${className}`
|
|
2001
|
+
},
|
|
2002
|
+
/* @__PURE__ */ React20.createElement("span", { className: "text-blue-600" }, "\u23F3"),
|
|
2003
|
+
/* @__PURE__ */ React20.createElement("div", null, /* @__PURE__ */ React20.createElement("p", { className: "text-sm font-medium text-blue-900" }, "Submitting form..."), showDetails && /* @__PURE__ */ React20.createElement("p", { className: "text-xs text-blue-700" }, "Please wait while we process your request."))
|
|
2004
|
+
);
|
|
1668
2005
|
}
|
|
1669
2006
|
if (isSuccess) {
|
|
1670
|
-
return /* @__PURE__ */
|
|
1671
|
-
|
|
2007
|
+
return /* @__PURE__ */ React20.createElement(
|
|
2008
|
+
"div",
|
|
1672
2009
|
{
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
isIconOnly: true,
|
|
1676
|
-
onPress: onDismiss,
|
|
1677
|
-
"aria-label": "Dismiss success message"
|
|
2010
|
+
className: `flex items-center gap-3 p-4 bg-green-50 border border-green-200 rounded-lg ${className}`,
|
|
2011
|
+
"data-testid": "success-message"
|
|
1678
2012
|
},
|
|
1679
|
-
"\
|
|
1680
|
-
|
|
2013
|
+
/* @__PURE__ */ React20.createElement("span", { className: "text-green-600" }, "\u2705"),
|
|
2014
|
+
/* @__PURE__ */ React20.createElement("div", { className: "flex-1" }, /* @__PURE__ */ React20.createElement("p", { className: "text-sm font-medium text-green-900" }, "Form submitted successfully!"), showDetails && submittedData && /* @__PURE__ */ React20.createElement("p", { className: "text-xs text-green-700" }, "Your data has been saved. Thank you for your submission.")),
|
|
2015
|
+
onDismiss && /* @__PURE__ */ React20.createElement(
|
|
2016
|
+
Button5,
|
|
2017
|
+
{
|
|
2018
|
+
size: "sm",
|
|
2019
|
+
variant: "light",
|
|
2020
|
+
isIconOnly: true,
|
|
2021
|
+
onPress: onDismiss,
|
|
2022
|
+
"aria-label": "Dismiss success message"
|
|
2023
|
+
},
|
|
2024
|
+
"\u2715"
|
|
2025
|
+
)
|
|
2026
|
+
);
|
|
1681
2027
|
}
|
|
1682
2028
|
if (isError && error) {
|
|
1683
|
-
return /* @__PURE__ */
|
|
1684
|
-
|
|
2029
|
+
return /* @__PURE__ */ React20.createElement(
|
|
2030
|
+
"div",
|
|
1685
2031
|
{
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
isIconOnly: true,
|
|
1689
|
-
onPress: onDismiss,
|
|
1690
|
-
"aria-label": "Dismiss error message"
|
|
2032
|
+
className: `flex items-center gap-3 p-4 bg-red-50 border border-red-200 rounded-lg ${className}`,
|
|
2033
|
+
"data-testid": "error-message"
|
|
1691
2034
|
},
|
|
1692
|
-
"\
|
|
1693
|
-
|
|
2035
|
+
/* @__PURE__ */ React20.createElement("span", { className: "text-red-600" }, "\u26A0\uFE0F"),
|
|
2036
|
+
/* @__PURE__ */ React20.createElement("div", { className: "flex-1" }, /* @__PURE__ */ React20.createElement("p", { className: "text-sm font-medium text-red-900" }, "Error submitting form"), /* @__PURE__ */ React20.createElement("p", { className: "text-xs text-red-700" }, error)),
|
|
2037
|
+
onDismiss && /* @__PURE__ */ React20.createElement(
|
|
2038
|
+
Button5,
|
|
2039
|
+
{
|
|
2040
|
+
size: "sm",
|
|
2041
|
+
variant: "light",
|
|
2042
|
+
isIconOnly: true,
|
|
2043
|
+
onPress: onDismiss,
|
|
2044
|
+
"aria-label": "Dismiss error message"
|
|
2045
|
+
},
|
|
2046
|
+
"\u2715"
|
|
2047
|
+
)
|
|
2048
|
+
);
|
|
1694
2049
|
}
|
|
1695
2050
|
return null;
|
|
1696
2051
|
}
|
|
1697
2052
|
function FormToast({
|
|
1698
|
-
|
|
2053
|
+
duration = 5e3,
|
|
1699
2054
|
onDismiss,
|
|
1700
2055
|
position = "top-right",
|
|
1701
|
-
|
|
2056
|
+
state
|
|
1702
2057
|
}) {
|
|
1703
|
-
const [isVisible, setIsVisible] =
|
|
1704
|
-
|
|
2058
|
+
const [isVisible, setIsVisible] = React20.useState(false);
|
|
2059
|
+
React20.useEffect(() => {
|
|
1705
2060
|
if (state.isSuccess || state.isError) {
|
|
1706
2061
|
setIsVisible(true);
|
|
1707
2062
|
if (duration > 0) {
|
|
@@ -1717,12 +2072,12 @@ function FormToast({
|
|
|
1717
2072
|
return null;
|
|
1718
2073
|
}
|
|
1719
2074
|
const positionClasses = {
|
|
1720
|
-
"
|
|
1721
|
-
"top-left": "top-4 left-4",
|
|
2075
|
+
"bottom-left": "bottom-4 left-4",
|
|
1722
2076
|
"bottom-right": "bottom-4 right-4",
|
|
1723
|
-
"
|
|
2077
|
+
"top-left": "top-4 left-4",
|
|
2078
|
+
"top-right": "top-4 right-4"
|
|
1724
2079
|
};
|
|
1725
|
-
return /* @__PURE__ */
|
|
2080
|
+
return /* @__PURE__ */ React20.createElement("div", { className: `fixed z-50 ${positionClasses[position]}` }, /* @__PURE__ */ React20.createElement(FormStatus, { state, onDismiss }));
|
|
1726
2081
|
}
|
|
1727
2082
|
|
|
1728
2083
|
// src/components/ZodForm.tsx
|
|
@@ -1730,7 +2085,6 @@ function ZodForm({
|
|
|
1730
2085
|
className,
|
|
1731
2086
|
columns = 1,
|
|
1732
2087
|
config,
|
|
1733
|
-
errorDisplay = "inline",
|
|
1734
2088
|
layout = "vertical",
|
|
1735
2089
|
onError,
|
|
1736
2090
|
onSubmit,
|
|
@@ -1746,9 +2100,9 @@ function ZodForm({
|
|
|
1746
2100
|
}) {
|
|
1747
2101
|
const form = useZodForm(config);
|
|
1748
2102
|
const enhancedState = useEnhancedFormState(form, {
|
|
1749
|
-
onSuccess,
|
|
1750
|
-
onError: (error) => onError?.({ message: error, field: "form" }),
|
|
1751
2103
|
autoReset: true,
|
|
2104
|
+
onError: (error) => onError?.({ field: "form", message: error }),
|
|
2105
|
+
onSuccess,
|
|
1752
2106
|
resetDelay: 3e3
|
|
1753
2107
|
});
|
|
1754
2108
|
const handleSubmit = async () => {
|
|
@@ -1758,7 +2112,8 @@ function ZodForm({
|
|
|
1758
2112
|
await onSubmit(formData);
|
|
1759
2113
|
enhancedState.handleSuccess(formData);
|
|
1760
2114
|
},
|
|
1761
|
-
|
|
2115
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2116
|
+
(_errors) => {
|
|
1762
2117
|
enhancedState.handleError("Please fix the validation errors above");
|
|
1763
2118
|
}
|
|
1764
2119
|
)();
|
|
@@ -1773,54 +2128,54 @@ function ZodForm({
|
|
|
1773
2128
|
};
|
|
1774
2129
|
const renderFields = () => {
|
|
1775
2130
|
if (layout === "grid") {
|
|
1776
|
-
return /* @__PURE__ */
|
|
2131
|
+
return /* @__PURE__ */ React21.createElement(
|
|
1777
2132
|
"div",
|
|
1778
2133
|
{
|
|
1779
2134
|
className: `grid gap-${spacing} ${columns === 1 ? "grid-cols-1" : columns === 2 ? "grid-cols-1 md:grid-cols-2" : "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"}`
|
|
1780
2135
|
},
|
|
1781
|
-
config.fields.map((field2) => /* @__PURE__ */
|
|
2136
|
+
config.fields.map((field2) => /* @__PURE__ */ React21.createElement(
|
|
1782
2137
|
FormField,
|
|
1783
2138
|
{
|
|
1784
2139
|
key: field2.name,
|
|
1785
2140
|
config: field2,
|
|
1786
2141
|
form,
|
|
1787
2142
|
submissionState: {
|
|
1788
|
-
|
|
2143
|
+
error: enhancedState.error,
|
|
1789
2144
|
isSubmitted: enhancedState.status !== "idle",
|
|
1790
|
-
|
|
1791
|
-
|
|
2145
|
+
isSubmitting: enhancedState.isSubmitting,
|
|
2146
|
+
isSuccess: enhancedState.isSuccess
|
|
1792
2147
|
}
|
|
1793
2148
|
}
|
|
1794
2149
|
))
|
|
1795
2150
|
);
|
|
1796
2151
|
}
|
|
1797
2152
|
if (layout === "horizontal") {
|
|
1798
|
-
return /* @__PURE__ */
|
|
2153
|
+
return /* @__PURE__ */ React21.createElement("div", { className: `grid gap-${spacing} grid-cols-1 md:grid-cols-2` }, config.fields.map((field2) => /* @__PURE__ */ React21.createElement(
|
|
1799
2154
|
FormField,
|
|
1800
2155
|
{
|
|
1801
2156
|
key: field2.name,
|
|
1802
2157
|
config: field2,
|
|
1803
2158
|
form,
|
|
1804
2159
|
submissionState: {
|
|
1805
|
-
|
|
2160
|
+
error: enhancedState.error,
|
|
1806
2161
|
isSubmitted: enhancedState.status !== "idle",
|
|
1807
|
-
|
|
1808
|
-
|
|
2162
|
+
isSubmitting: enhancedState.isSubmitting,
|
|
2163
|
+
isSuccess: enhancedState.isSuccess
|
|
1809
2164
|
}
|
|
1810
2165
|
}
|
|
1811
2166
|
)));
|
|
1812
2167
|
}
|
|
1813
|
-
return /* @__PURE__ */
|
|
2168
|
+
return /* @__PURE__ */ React21.createElement("div", { className: `space-y-${spacing}` }, config.fields.map((field2) => /* @__PURE__ */ React21.createElement(
|
|
1814
2169
|
FormField,
|
|
1815
2170
|
{
|
|
1816
2171
|
key: field2.name,
|
|
1817
2172
|
config: field2,
|
|
1818
2173
|
form,
|
|
1819
2174
|
submissionState: {
|
|
1820
|
-
|
|
2175
|
+
error: enhancedState.error,
|
|
1821
2176
|
isSubmitted: enhancedState.status !== "idle",
|
|
1822
|
-
|
|
1823
|
-
|
|
2177
|
+
isSubmitting: enhancedState.isSubmitting,
|
|
2178
|
+
isSuccess: enhancedState.isSuccess
|
|
1824
2179
|
}
|
|
1825
2180
|
}
|
|
1826
2181
|
)));
|
|
@@ -1829,7 +2184,7 @@ function ZodForm({
|
|
|
1829
2184
|
e.preventDefault();
|
|
1830
2185
|
void handleSubmit();
|
|
1831
2186
|
};
|
|
1832
|
-
|
|
2187
|
+
React21.useEffect(() => {
|
|
1833
2188
|
if (config.onError && Object.keys(form.formState.errors).length > 0) {
|
|
1834
2189
|
config.onError(form.formState.errors);
|
|
1835
2190
|
}
|
|
@@ -1844,15 +2199,15 @@ function ZodForm({
|
|
|
1844
2199
|
values: form.getValues()
|
|
1845
2200
|
});
|
|
1846
2201
|
}
|
|
1847
|
-
return /* @__PURE__ */
|
|
2202
|
+
return /* @__PURE__ */ React21.createElement("form", { className, role: "form", onSubmit: handleFormSubmit }, title && /* @__PURE__ */ React21.createElement("div", { className: "mb-6" }, /* @__PURE__ */ React21.createElement("h2", { className: "text-xl font-semibold text-foreground mb-2" }, title), subtitle && /* @__PURE__ */ React21.createElement("p", { className: "text-sm text-muted-foreground" }, subtitle)), /* @__PURE__ */ React21.createElement(
|
|
1848
2203
|
FormStatus,
|
|
1849
2204
|
{
|
|
1850
2205
|
state: enhancedState,
|
|
1851
2206
|
onDismiss: () => enhancedState.reset(),
|
|
1852
2207
|
showDetails: true
|
|
1853
2208
|
}
|
|
1854
|
-
), renderFields(), /* @__PURE__ */
|
|
1855
|
-
|
|
2209
|
+
), renderFields(), /* @__PURE__ */ React21.createElement("div", { className: "mt-6 flex gap-3 justify-end" }, /* @__PURE__ */ React21.createElement(
|
|
2210
|
+
Button6,
|
|
1856
2211
|
{
|
|
1857
2212
|
color: "primary",
|
|
1858
2213
|
isDisabled: enhancedState.isSubmitting,
|
|
@@ -1861,8 +2216,8 @@ function ZodForm({
|
|
|
1861
2216
|
...submitButtonProps
|
|
1862
2217
|
},
|
|
1863
2218
|
enhancedState.isSuccess ? "Success!" : submitButtonText
|
|
1864
|
-
), showResetButton && /* @__PURE__ */
|
|
1865
|
-
|
|
2219
|
+
), showResetButton && /* @__PURE__ */ React21.createElement(
|
|
2220
|
+
Button6,
|
|
1866
2221
|
{
|
|
1867
2222
|
isDisabled: enhancedState.isSubmitting,
|
|
1868
2223
|
type: "button",
|
|
@@ -1883,10 +2238,10 @@ var BasicFormBuilder = class {
|
|
|
1883
2238
|
*/
|
|
1884
2239
|
input(name, label, type = "text") {
|
|
1885
2240
|
this.fields.push({
|
|
1886
|
-
|
|
2241
|
+
inputProps: { type },
|
|
1887
2242
|
label,
|
|
1888
|
-
|
|
1889
|
-
|
|
2243
|
+
name,
|
|
2244
|
+
type: "input"
|
|
1890
2245
|
});
|
|
1891
2246
|
return this;
|
|
1892
2247
|
}
|
|
@@ -1895,10 +2250,10 @@ var BasicFormBuilder = class {
|
|
|
1895
2250
|
*/
|
|
1896
2251
|
textarea(name, label, placeholder) {
|
|
1897
2252
|
this.fields.push({
|
|
1898
|
-
name,
|
|
1899
2253
|
label,
|
|
1900
|
-
|
|
1901
|
-
textareaProps: { placeholder }
|
|
2254
|
+
name,
|
|
2255
|
+
textareaProps: { placeholder },
|
|
2256
|
+
type: "textarea"
|
|
1902
2257
|
});
|
|
1903
2258
|
return this;
|
|
1904
2259
|
}
|
|
@@ -1907,10 +2262,10 @@ var BasicFormBuilder = class {
|
|
|
1907
2262
|
*/
|
|
1908
2263
|
select(name, label, options) {
|
|
1909
2264
|
this.fields.push({
|
|
1910
|
-
name,
|
|
1911
2265
|
label,
|
|
1912
|
-
|
|
1913
|
-
options
|
|
2266
|
+
name,
|
|
2267
|
+
options,
|
|
2268
|
+
type: "select"
|
|
1914
2269
|
});
|
|
1915
2270
|
return this;
|
|
1916
2271
|
}
|
|
@@ -1919,8 +2274,8 @@ var BasicFormBuilder = class {
|
|
|
1919
2274
|
*/
|
|
1920
2275
|
checkbox(name, label) {
|
|
1921
2276
|
this.fields.push({
|
|
1922
|
-
name,
|
|
1923
2277
|
label,
|
|
2278
|
+
name,
|
|
1924
2279
|
type: "checkbox"
|
|
1925
2280
|
});
|
|
1926
2281
|
return this;
|
|
@@ -1930,8 +2285,8 @@ var BasicFormBuilder = class {
|
|
|
1930
2285
|
*/
|
|
1931
2286
|
switch(name, label) {
|
|
1932
2287
|
this.fields.push({
|
|
1933
|
-
name,
|
|
1934
2288
|
label,
|
|
2289
|
+
name,
|
|
1935
2290
|
type: "switch"
|
|
1936
2291
|
});
|
|
1937
2292
|
return this;
|
|
@@ -1948,59 +2303,50 @@ function createBasicFormBuilder() {
|
|
|
1948
2303
|
}
|
|
1949
2304
|
var FormFieldHelpers = {
|
|
1950
2305
|
/**
|
|
1951
|
-
* Create
|
|
2306
|
+
* Create a checkbox field
|
|
1952
2307
|
*/
|
|
1953
|
-
|
|
1954
|
-
name,
|
|
2308
|
+
checkbox: (name, label) => ({
|
|
1955
2309
|
label,
|
|
1956
|
-
|
|
1957
|
-
|
|
2310
|
+
name,
|
|
2311
|
+
type: "checkbox"
|
|
1958
2312
|
}),
|
|
1959
2313
|
/**
|
|
1960
|
-
* Create
|
|
2314
|
+
* Create an input field
|
|
1961
2315
|
*/
|
|
1962
|
-
|
|
1963
|
-
|
|
2316
|
+
input: (name, label, type = "text") => ({
|
|
2317
|
+
inputProps: { type },
|
|
1964
2318
|
label,
|
|
1965
|
-
|
|
1966
|
-
|
|
2319
|
+
name,
|
|
2320
|
+
type: "input"
|
|
1967
2321
|
}),
|
|
1968
2322
|
/**
|
|
1969
2323
|
* Create a select field
|
|
1970
2324
|
*/
|
|
1971
2325
|
select: (name, label, options) => ({
|
|
1972
|
-
name,
|
|
1973
2326
|
label,
|
|
1974
|
-
type: "select",
|
|
1975
|
-
options
|
|
1976
|
-
}),
|
|
1977
|
-
/**
|
|
1978
|
-
* Create a checkbox field
|
|
1979
|
-
*/
|
|
1980
|
-
checkbox: (name, label) => ({
|
|
1981
2327
|
name,
|
|
1982
|
-
|
|
1983
|
-
type: "
|
|
2328
|
+
options,
|
|
2329
|
+
type: "select"
|
|
1984
2330
|
}),
|
|
1985
2331
|
/**
|
|
1986
2332
|
* Create a switch field
|
|
1987
2333
|
*/
|
|
1988
2334
|
switch: (name, label) => ({
|
|
1989
|
-
name,
|
|
1990
2335
|
label,
|
|
2336
|
+
name,
|
|
1991
2337
|
type: "switch"
|
|
2338
|
+
}),
|
|
2339
|
+
/**
|
|
2340
|
+
* Create a textarea field
|
|
2341
|
+
*/
|
|
2342
|
+
textarea: (name, label, placeholder) => ({
|
|
2343
|
+
label,
|
|
2344
|
+
name,
|
|
2345
|
+
textareaProps: { placeholder },
|
|
2346
|
+
type: "textarea"
|
|
1992
2347
|
})
|
|
1993
2348
|
};
|
|
1994
2349
|
var CommonFields = {
|
|
1995
|
-
/**
|
|
1996
|
-
* Personal information fields
|
|
1997
|
-
*/
|
|
1998
|
-
personal: () => [
|
|
1999
|
-
FormFieldHelpers.input("firstName", "First Name"),
|
|
2000
|
-
FormFieldHelpers.input("lastName", "Last Name"),
|
|
2001
|
-
FormFieldHelpers.input("email", "Email", "email"),
|
|
2002
|
-
FormFieldHelpers.input("phone", "Phone", "tel")
|
|
2003
|
-
],
|
|
2004
2350
|
/**
|
|
2005
2351
|
* Address fields
|
|
2006
2352
|
*/
|
|
@@ -2009,107 +2355,121 @@ var CommonFields = {
|
|
|
2009
2355
|
FormFieldHelpers.input("city", "City"),
|
|
2010
2356
|
FormFieldHelpers.input("state", "State/Province"),
|
|
2011
2357
|
FormFieldHelpers.input("zipCode", "ZIP/Postal Code"),
|
|
2012
|
-
FormFieldHelpers.select(
|
|
2013
|
-
"country",
|
|
2014
|
-
"
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2358
|
+
FormFieldHelpers.select("country", "Country", [
|
|
2359
|
+
{ label: "Select a country", value: "" },
|
|
2360
|
+
{ label: "United States", value: "us" },
|
|
2361
|
+
{ label: "Canada", value: "ca" },
|
|
2362
|
+
{ label: "United Kingdom", value: "uk" },
|
|
2363
|
+
{ label: "Australia", value: "au" },
|
|
2364
|
+
{ label: "Germany", value: "de" },
|
|
2365
|
+
{ label: "France", value: "fr" }
|
|
2366
|
+
])
|
|
2367
|
+
],
|
|
2368
|
+
/**
|
|
2369
|
+
* Personal information fields
|
|
2370
|
+
*/
|
|
2371
|
+
personal: () => [
|
|
2372
|
+
FormFieldHelpers.input("firstName", "First Name"),
|
|
2373
|
+
FormFieldHelpers.input("lastName", "Last Name"),
|
|
2374
|
+
FormFieldHelpers.input("email", "Email", "email"),
|
|
2375
|
+
FormFieldHelpers.input("phone", "Phone", "tel")
|
|
2025
2376
|
],
|
|
2026
2377
|
/**
|
|
2027
2378
|
* Terms and conditions fields
|
|
2028
2379
|
*/
|
|
2029
2380
|
terms: () => [
|
|
2030
|
-
FormFieldHelpers.checkbox(
|
|
2031
|
-
|
|
2032
|
-
|
|
2381
|
+
FormFieldHelpers.checkbox(
|
|
2382
|
+
"terms",
|
|
2383
|
+
"I agree to the terms and conditions"
|
|
2384
|
+
),
|
|
2385
|
+
FormFieldHelpers.checkbox(
|
|
2386
|
+
"privacy",
|
|
2387
|
+
"I agree to the privacy policy"
|
|
2388
|
+
),
|
|
2389
|
+
FormFieldHelpers.checkbox(
|
|
2390
|
+
"newsletter",
|
|
2391
|
+
"Subscribe to newsletter"
|
|
2392
|
+
)
|
|
2033
2393
|
]
|
|
2034
2394
|
};
|
|
2035
2395
|
|
|
2036
2396
|
// src/builders/AdvancedFormBuilder.ts
|
|
2037
2397
|
function inputField(name, label, props) {
|
|
2038
2398
|
return {
|
|
2039
|
-
name,
|
|
2040
2399
|
label,
|
|
2400
|
+
name,
|
|
2041
2401
|
type: "input",
|
|
2042
2402
|
...props && {
|
|
2043
2403
|
inputProps: {
|
|
2044
|
-
|
|
2045
|
-
placeholder: props.placeholder,
|
|
2404
|
+
className: props.className,
|
|
2046
2405
|
description: props.description,
|
|
2047
2406
|
disabled: props.isDisabled,
|
|
2048
|
-
|
|
2407
|
+
placeholder: props.placeholder,
|
|
2408
|
+
type: props.type || "text"
|
|
2049
2409
|
}
|
|
2050
2410
|
}
|
|
2051
2411
|
};
|
|
2052
2412
|
}
|
|
2053
2413
|
function textareaField(name, label, props) {
|
|
2054
2414
|
return {
|
|
2055
|
-
name,
|
|
2056
2415
|
label,
|
|
2416
|
+
name,
|
|
2057
2417
|
type: "textarea",
|
|
2058
2418
|
...props && {
|
|
2059
2419
|
textareaProps: {
|
|
2060
|
-
|
|
2420
|
+
className: props.className,
|
|
2061
2421
|
description: props.description,
|
|
2062
2422
|
disabled: props.isDisabled,
|
|
2063
|
-
|
|
2423
|
+
placeholder: props.placeholder,
|
|
2064
2424
|
rows: props.rows
|
|
2065
2425
|
}
|
|
2066
2426
|
}
|
|
2067
2427
|
};
|
|
2068
2428
|
}
|
|
2069
|
-
function selectField(name, label, options
|
|
2429
|
+
function selectField(name, label, options) {
|
|
2070
2430
|
return {
|
|
2071
|
-
name,
|
|
2072
2431
|
label,
|
|
2073
|
-
|
|
2074
|
-
options
|
|
2432
|
+
name,
|
|
2433
|
+
options,
|
|
2434
|
+
type: "select"
|
|
2075
2435
|
};
|
|
2076
2436
|
}
|
|
2077
2437
|
function checkboxField(name, label, props) {
|
|
2078
2438
|
return {
|
|
2079
|
-
name,
|
|
2080
2439
|
label,
|
|
2440
|
+
name,
|
|
2081
2441
|
type: "checkbox",
|
|
2082
2442
|
...props && {
|
|
2083
2443
|
checkboxProps: {
|
|
2084
|
-
|
|
2085
|
-
|
|
2444
|
+
className: props.className,
|
|
2445
|
+
disabled: props.isDisabled
|
|
2086
2446
|
}
|
|
2087
2447
|
}
|
|
2088
2448
|
};
|
|
2089
2449
|
}
|
|
2090
2450
|
function switchField(name, label, props) {
|
|
2091
2451
|
return {
|
|
2092
|
-
name,
|
|
2093
2452
|
label,
|
|
2453
|
+
name,
|
|
2094
2454
|
type: "switch",
|
|
2095
2455
|
...props && {
|
|
2096
2456
|
switchProps: {
|
|
2097
|
-
|
|
2098
|
-
|
|
2457
|
+
className: props.className,
|
|
2458
|
+
disabled: props.isDisabled
|
|
2099
2459
|
}
|
|
2100
2460
|
}
|
|
2101
2461
|
};
|
|
2102
2462
|
}
|
|
2103
2463
|
function radioField(name, label, options, props) {
|
|
2104
2464
|
return {
|
|
2105
|
-
name,
|
|
2106
2465
|
label,
|
|
2107
|
-
|
|
2466
|
+
name,
|
|
2108
2467
|
radioOptions: options,
|
|
2468
|
+
type: "radio",
|
|
2109
2469
|
...props && {
|
|
2110
2470
|
radioProps: {
|
|
2111
|
-
isDisabled: props.isDisabled,
|
|
2112
2471
|
className: props.className,
|
|
2472
|
+
isDisabled: props.isDisabled,
|
|
2113
2473
|
orientation: props.orientation
|
|
2114
2474
|
}
|
|
2115
2475
|
}
|
|
@@ -2117,58 +2477,58 @@ function radioField(name, label, options, props) {
|
|
|
2117
2477
|
}
|
|
2118
2478
|
function sliderField(name, label, props) {
|
|
2119
2479
|
return {
|
|
2120
|
-
name,
|
|
2121
2480
|
label,
|
|
2481
|
+
name,
|
|
2122
2482
|
type: "slider",
|
|
2123
2483
|
...props && {
|
|
2124
2484
|
sliderProps: {
|
|
2125
|
-
|
|
2126
|
-
max: props.max || 100,
|
|
2127
|
-
step: props.step || 1,
|
|
2485
|
+
className: props.className || "",
|
|
2128
2486
|
disabled: props.isDisabled || false,
|
|
2129
|
-
|
|
2487
|
+
max: props.max || 100,
|
|
2488
|
+
min: props.min || 0,
|
|
2489
|
+
step: props.step || 1
|
|
2130
2490
|
}
|
|
2131
2491
|
}
|
|
2132
2492
|
};
|
|
2133
2493
|
}
|
|
2134
2494
|
function dateField(name, label, props) {
|
|
2135
2495
|
return {
|
|
2136
|
-
name,
|
|
2137
2496
|
label,
|
|
2497
|
+
name,
|
|
2138
2498
|
type: "date",
|
|
2139
2499
|
...props && {
|
|
2140
2500
|
dateProps: {
|
|
2141
|
-
|
|
2501
|
+
className: props.className || "",
|
|
2142
2502
|
disabled: props.isDisabled || false,
|
|
2143
|
-
|
|
2503
|
+
placeholder: props.placeholder || ""
|
|
2144
2504
|
}
|
|
2145
2505
|
}
|
|
2146
2506
|
};
|
|
2147
2507
|
}
|
|
2148
2508
|
function fileField(name, label, props) {
|
|
2149
2509
|
return {
|
|
2150
|
-
name,
|
|
2151
2510
|
label,
|
|
2511
|
+
name,
|
|
2152
2512
|
type: "file",
|
|
2153
2513
|
...props && {
|
|
2154
2514
|
fileProps: {
|
|
2155
2515
|
accept: props.accept || "",
|
|
2156
|
-
|
|
2516
|
+
className: props.className || "",
|
|
2157
2517
|
disabled: props.isDisabled || false,
|
|
2158
|
-
|
|
2518
|
+
multiple: props.multiple || false
|
|
2159
2519
|
}
|
|
2160
2520
|
}
|
|
2161
2521
|
};
|
|
2162
2522
|
}
|
|
2163
2523
|
function fontPickerField(name, label, props) {
|
|
2164
2524
|
return {
|
|
2165
|
-
name,
|
|
2166
2525
|
label,
|
|
2526
|
+
name,
|
|
2167
2527
|
type: "fontPicker",
|
|
2168
2528
|
...props && {
|
|
2169
2529
|
fontPickerProps: {
|
|
2170
|
-
|
|
2171
|
-
|
|
2530
|
+
className: props.className || "",
|
|
2531
|
+
disabled: props.isDisabled || false
|
|
2172
2532
|
}
|
|
2173
2533
|
}
|
|
2174
2534
|
};
|
|
@@ -2180,7 +2540,7 @@ function createField(type, name, label, optionsOrProps, props) {
|
|
|
2180
2540
|
case "textarea":
|
|
2181
2541
|
return textareaField(name, label, optionsOrProps);
|
|
2182
2542
|
case "select":
|
|
2183
|
-
return selectField(name, label, optionsOrProps
|
|
2543
|
+
return selectField(name, label, optionsOrProps);
|
|
2184
2544
|
case "checkbox":
|
|
2185
2545
|
return checkboxField(name, label, optionsOrProps);
|
|
2186
2546
|
case "switch":
|
|
@@ -2212,10 +2572,10 @@ var AdvancedFieldBuilder = class {
|
|
|
2212
2572
|
*/
|
|
2213
2573
|
conditionalField(name, condition, field2) {
|
|
2214
2574
|
this.fields.push({
|
|
2215
|
-
name,
|
|
2216
|
-
type: "conditional",
|
|
2217
2575
|
condition,
|
|
2218
|
-
field: field2
|
|
2576
|
+
field: field2,
|
|
2577
|
+
name,
|
|
2578
|
+
type: "conditional"
|
|
2219
2579
|
});
|
|
2220
2580
|
return this;
|
|
2221
2581
|
}
|
|
@@ -2224,14 +2584,14 @@ var AdvancedFieldBuilder = class {
|
|
|
2224
2584
|
*/
|
|
2225
2585
|
fieldArray(name, label, fields, options) {
|
|
2226
2586
|
this.fields.push({
|
|
2227
|
-
|
|
2228
|
-
label,
|
|
2229
|
-
type: "fieldArray",
|
|
2587
|
+
addButtonText: options?.addButtonText,
|
|
2230
2588
|
fields,
|
|
2231
|
-
|
|
2589
|
+
label,
|
|
2232
2590
|
max: options?.max,
|
|
2233
|
-
|
|
2234
|
-
|
|
2591
|
+
min: options?.min,
|
|
2592
|
+
name,
|
|
2593
|
+
removeButtonText: options?.removeButtonText,
|
|
2594
|
+
type: "fieldArray"
|
|
2235
2595
|
});
|
|
2236
2596
|
return this;
|
|
2237
2597
|
}
|
|
@@ -2240,12 +2600,12 @@ var AdvancedFieldBuilder = class {
|
|
|
2240
2600
|
*/
|
|
2241
2601
|
dynamicSection(name, condition, fields, options) {
|
|
2242
2602
|
this.fields.push({
|
|
2243
|
-
name,
|
|
2244
|
-
type: "dynamicSection",
|
|
2245
2603
|
condition,
|
|
2604
|
+
description: options?.description,
|
|
2246
2605
|
fields,
|
|
2606
|
+
name,
|
|
2247
2607
|
title: options?.title,
|
|
2248
|
-
|
|
2608
|
+
type: "dynamicSection"
|
|
2249
2609
|
});
|
|
2250
2610
|
return this;
|
|
2251
2611
|
}
|
|
@@ -2281,7 +2641,13 @@ var FieldArrayBuilder = class {
|
|
|
2281
2641
|
}
|
|
2282
2642
|
field(type, name, label, optionsOrProps, props) {
|
|
2283
2643
|
const fullPath = `${this.arrayName}.${name}`;
|
|
2284
|
-
const fieldConfig = createField(
|
|
2644
|
+
const fieldConfig = createField(
|
|
2645
|
+
type,
|
|
2646
|
+
fullPath,
|
|
2647
|
+
label,
|
|
2648
|
+
optionsOrProps,
|
|
2649
|
+
props
|
|
2650
|
+
);
|
|
2285
2651
|
this.fields.push(fieldConfig);
|
|
2286
2652
|
return this;
|
|
2287
2653
|
}
|
|
@@ -2307,17 +2673,29 @@ var TypeInferredBuilder = class {
|
|
|
2307
2673
|
* Add a text field
|
|
2308
2674
|
*/
|
|
2309
2675
|
text(name, label, options) {
|
|
2310
|
-
const {
|
|
2676
|
+
const { maxLength, minLength, pattern, ...fieldOptions } = options || {};
|
|
2311
2677
|
let zodType = z3.string();
|
|
2312
|
-
if (minLength)
|
|
2313
|
-
|
|
2314
|
-
|
|
2678
|
+
if (minLength)
|
|
2679
|
+
zodType = zodType.min(
|
|
2680
|
+
minLength,
|
|
2681
|
+
`${label} must be at least ${minLength} characters`
|
|
2682
|
+
);
|
|
2683
|
+
if (maxLength)
|
|
2684
|
+
zodType = zodType.max(
|
|
2685
|
+
maxLength,
|
|
2686
|
+
`${label} must be no more than ${maxLength} characters`
|
|
2687
|
+
);
|
|
2688
|
+
if (pattern)
|
|
2689
|
+
zodType = zodType.regex(
|
|
2690
|
+
new RegExp(pattern),
|
|
2691
|
+
`${label} format is invalid`
|
|
2692
|
+
);
|
|
2315
2693
|
this.schemaFields[name] = zodType;
|
|
2316
2694
|
this.formFields.push({
|
|
2317
|
-
|
|
2695
|
+
inputProps: { type: "text", ...fieldOptions },
|
|
2318
2696
|
label,
|
|
2319
|
-
|
|
2320
|
-
|
|
2697
|
+
name,
|
|
2698
|
+
type: "input"
|
|
2321
2699
|
});
|
|
2322
2700
|
return this;
|
|
2323
2701
|
}
|
|
@@ -2327,10 +2705,10 @@ var TypeInferredBuilder = class {
|
|
|
2327
2705
|
email(name, label, options) {
|
|
2328
2706
|
this.schemaFields[name] = z3.string().email(`Please enter a valid email address`);
|
|
2329
2707
|
this.formFields.push({
|
|
2330
|
-
|
|
2708
|
+
inputProps: { type: "email", ...options },
|
|
2331
2709
|
label,
|
|
2332
|
-
|
|
2333
|
-
|
|
2710
|
+
name,
|
|
2711
|
+
type: "input"
|
|
2334
2712
|
});
|
|
2335
2713
|
return this;
|
|
2336
2714
|
}
|
|
@@ -2338,16 +2716,18 @@ var TypeInferredBuilder = class {
|
|
|
2338
2716
|
* Add a number field
|
|
2339
2717
|
*/
|
|
2340
2718
|
number(name, label, options) {
|
|
2341
|
-
const {
|
|
2719
|
+
const { max, min, step, ...fieldOptions } = options || {};
|
|
2342
2720
|
let zodType = z3.number();
|
|
2343
|
-
if (min !== void 0)
|
|
2344
|
-
|
|
2721
|
+
if (min !== void 0)
|
|
2722
|
+
zodType = zodType.min(min, `${label} must be at least ${min}`);
|
|
2723
|
+
if (max !== void 0)
|
|
2724
|
+
zodType = zodType.max(max, `${label} must be no more than ${max}`);
|
|
2345
2725
|
this.schemaFields[name] = zodType;
|
|
2346
2726
|
this.formFields.push({
|
|
2347
|
-
|
|
2727
|
+
inputProps: { max, min, step, type: "number", ...fieldOptions },
|
|
2348
2728
|
label,
|
|
2349
|
-
|
|
2350
|
-
|
|
2729
|
+
name,
|
|
2730
|
+
type: "input"
|
|
2351
2731
|
});
|
|
2352
2732
|
return this;
|
|
2353
2733
|
}
|
|
@@ -2357,26 +2737,30 @@ var TypeInferredBuilder = class {
|
|
|
2357
2737
|
textarea(name, label, options) {
|
|
2358
2738
|
const { minLength, ...fieldOptions } = options || {};
|
|
2359
2739
|
let zodType = z3.string();
|
|
2360
|
-
if (minLength)
|
|
2740
|
+
if (minLength)
|
|
2741
|
+
zodType = zodType.min(
|
|
2742
|
+
minLength,
|
|
2743
|
+
`${label} must be at least ${minLength} characters`
|
|
2744
|
+
);
|
|
2361
2745
|
this.schemaFields[name] = zodType;
|
|
2362
2746
|
this.formFields.push({
|
|
2363
|
-
name,
|
|
2364
2747
|
label,
|
|
2365
|
-
|
|
2366
|
-
textareaProps: fieldOptions
|
|
2748
|
+
name,
|
|
2749
|
+
textareaProps: fieldOptions,
|
|
2750
|
+
type: "textarea"
|
|
2367
2751
|
});
|
|
2368
2752
|
return this;
|
|
2369
2753
|
}
|
|
2370
2754
|
/**
|
|
2371
2755
|
* Add a select field
|
|
2372
2756
|
*/
|
|
2373
|
-
select(name, label, options
|
|
2757
|
+
select(name, label, options) {
|
|
2374
2758
|
this.schemaFields[name] = z3.string().min(1, `Please select a ${label.toLowerCase()}`);
|
|
2375
2759
|
this.formFields.push({
|
|
2376
|
-
name,
|
|
2377
2760
|
label,
|
|
2378
|
-
|
|
2379
|
-
options
|
|
2761
|
+
name,
|
|
2762
|
+
options,
|
|
2763
|
+
type: "select"
|
|
2380
2764
|
});
|
|
2381
2765
|
return this;
|
|
2382
2766
|
}
|
|
@@ -2387,14 +2771,17 @@ var TypeInferredBuilder = class {
|
|
|
2387
2771
|
const { required = false, ...fieldOptions } = options || {};
|
|
2388
2772
|
let zodType = z3.boolean();
|
|
2389
2773
|
if (required) {
|
|
2390
|
-
zodType = zodType.refine(
|
|
2774
|
+
zodType = zodType.refine(
|
|
2775
|
+
(val) => val === true,
|
|
2776
|
+
`You must agree to ${label.toLowerCase()}`
|
|
2777
|
+
);
|
|
2391
2778
|
}
|
|
2392
2779
|
this.schemaFields[name] = zodType;
|
|
2393
2780
|
this.formFields.push({
|
|
2394
|
-
|
|
2781
|
+
checkboxProps: fieldOptions,
|
|
2395
2782
|
label,
|
|
2396
|
-
|
|
2397
|
-
|
|
2783
|
+
name,
|
|
2784
|
+
type: "checkbox"
|
|
2398
2785
|
});
|
|
2399
2786
|
return this;
|
|
2400
2787
|
}
|
|
@@ -2404,10 +2791,10 @@ var TypeInferredBuilder = class {
|
|
|
2404
2791
|
switch(name, label, options) {
|
|
2405
2792
|
this.schemaFields[name] = z3.boolean().optional();
|
|
2406
2793
|
this.formFields.push({
|
|
2407
|
-
name,
|
|
2408
2794
|
label,
|
|
2409
|
-
|
|
2410
|
-
switchProps: options
|
|
2795
|
+
name,
|
|
2796
|
+
switchProps: options,
|
|
2797
|
+
type: "switch"
|
|
2411
2798
|
});
|
|
2412
2799
|
return this;
|
|
2413
2800
|
}
|
|
@@ -2417,11 +2804,11 @@ var TypeInferredBuilder = class {
|
|
|
2417
2804
|
radio(name, label, options, fieldOptions) {
|
|
2418
2805
|
this.schemaFields[name] = z3.string().min(1, `Please select a ${label.toLowerCase()}`);
|
|
2419
2806
|
this.formFields.push({
|
|
2420
|
-
name,
|
|
2421
2807
|
label,
|
|
2422
|
-
|
|
2808
|
+
name,
|
|
2423
2809
|
radioOptions: options,
|
|
2424
|
-
radioProps: fieldOptions
|
|
2810
|
+
radioProps: fieldOptions,
|
|
2811
|
+
type: "radio"
|
|
2425
2812
|
});
|
|
2426
2813
|
return this;
|
|
2427
2814
|
}
|
|
@@ -2429,16 +2816,18 @@ var TypeInferredBuilder = class {
|
|
|
2429
2816
|
* Add a slider field
|
|
2430
2817
|
*/
|
|
2431
2818
|
slider(name, label, options) {
|
|
2432
|
-
const {
|
|
2819
|
+
const { max = 100, min = 0, step = 1, ...fieldOptions } = options || {};
|
|
2433
2820
|
let zodType = z3.number();
|
|
2434
|
-
if (min !== void 0)
|
|
2435
|
-
|
|
2821
|
+
if (min !== void 0)
|
|
2822
|
+
zodType = zodType.min(min, `${label} must be at least ${min}`);
|
|
2823
|
+
if (max !== void 0)
|
|
2824
|
+
zodType = zodType.max(max, `${label} must be no more than ${max}`);
|
|
2436
2825
|
this.schemaFields[name] = zodType;
|
|
2437
2826
|
this.formFields.push({
|
|
2438
|
-
name,
|
|
2439
2827
|
label,
|
|
2440
|
-
|
|
2441
|
-
sliderProps: {
|
|
2828
|
+
name,
|
|
2829
|
+
sliderProps: { max, min, step, ...fieldOptions },
|
|
2830
|
+
type: "slider"
|
|
2442
2831
|
});
|
|
2443
2832
|
return this;
|
|
2444
2833
|
}
|
|
@@ -2448,10 +2837,10 @@ var TypeInferredBuilder = class {
|
|
|
2448
2837
|
date(name, label, options) {
|
|
2449
2838
|
this.schemaFields[name] = z3.string().min(1, `${label} is required`);
|
|
2450
2839
|
this.formFields.push({
|
|
2451
|
-
|
|
2840
|
+
dateProps: options,
|
|
2452
2841
|
label,
|
|
2453
|
-
|
|
2454
|
-
|
|
2842
|
+
name,
|
|
2843
|
+
type: "date"
|
|
2455
2844
|
});
|
|
2456
2845
|
return this;
|
|
2457
2846
|
}
|
|
@@ -2461,10 +2850,10 @@ var TypeInferredBuilder = class {
|
|
|
2461
2850
|
file(name, label, options) {
|
|
2462
2851
|
this.schemaFields[name] = z3.any().optional();
|
|
2463
2852
|
this.formFields.push({
|
|
2464
|
-
|
|
2853
|
+
fileProps: options,
|
|
2465
2854
|
label,
|
|
2466
|
-
|
|
2467
|
-
|
|
2855
|
+
name,
|
|
2856
|
+
type: "file"
|
|
2468
2857
|
});
|
|
2469
2858
|
return this;
|
|
2470
2859
|
}
|
|
@@ -2473,8 +2862,8 @@ var TypeInferredBuilder = class {
|
|
|
2473
2862
|
*/
|
|
2474
2863
|
build() {
|
|
2475
2864
|
return {
|
|
2476
|
-
|
|
2477
|
-
|
|
2865
|
+
fields: this.formFields,
|
|
2866
|
+
schema: z3.object(this.schemaFields)
|
|
2478
2867
|
};
|
|
2479
2868
|
}
|
|
2480
2869
|
};
|
|
@@ -2487,49 +2876,49 @@ function defineInferredForm(fieldDefinitions) {
|
|
|
2487
2876
|
return builder.build();
|
|
2488
2877
|
}
|
|
2489
2878
|
var field = {
|
|
2490
|
-
|
|
2879
|
+
checkbox: (name, label, options) => {
|
|
2491
2880
|
const builder = new TypeInferredBuilder();
|
|
2492
|
-
return builder.
|
|
2881
|
+
return builder.checkbox(name, label, options);
|
|
2882
|
+
},
|
|
2883
|
+
date: (name, label, options) => {
|
|
2884
|
+
const builder = new TypeInferredBuilder();
|
|
2885
|
+
return builder.date(name, label, options);
|
|
2493
2886
|
},
|
|
2494
2887
|
email: (name, label, options) => {
|
|
2495
2888
|
const builder = new TypeInferredBuilder();
|
|
2496
2889
|
return builder.email(name, label, options);
|
|
2497
2890
|
},
|
|
2891
|
+
file: (name, label, options) => {
|
|
2892
|
+
const builder = new TypeInferredBuilder();
|
|
2893
|
+
return builder.file(name, label, options);
|
|
2894
|
+
},
|
|
2498
2895
|
number: (name, label, options) => {
|
|
2499
2896
|
const builder = new TypeInferredBuilder();
|
|
2500
2897
|
return builder.number(name, label, options);
|
|
2501
2898
|
},
|
|
2502
|
-
|
|
2899
|
+
radio: (name, label, options, fieldOptions) => {
|
|
2503
2900
|
const builder = new TypeInferredBuilder();
|
|
2504
|
-
return builder.
|
|
2901
|
+
return builder.radio(name, label, options, fieldOptions);
|
|
2505
2902
|
},
|
|
2506
|
-
select: (name, label, options
|
|
2903
|
+
select: (name, label, options) => {
|
|
2507
2904
|
const builder = new TypeInferredBuilder();
|
|
2508
|
-
return builder.select(name, label, options
|
|
2905
|
+
return builder.select(name, label, options);
|
|
2509
2906
|
},
|
|
2510
|
-
|
|
2907
|
+
slider: (name, label, options) => {
|
|
2511
2908
|
const builder = new TypeInferredBuilder();
|
|
2512
|
-
return builder.
|
|
2909
|
+
return builder.slider(name, label, options);
|
|
2513
2910
|
},
|
|
2514
2911
|
switch: (name, label, options) => {
|
|
2515
2912
|
const builder = new TypeInferredBuilder();
|
|
2516
2913
|
return builder.switch(name, label, options);
|
|
2517
2914
|
},
|
|
2518
|
-
|
|
2519
|
-
const builder = new TypeInferredBuilder();
|
|
2520
|
-
return builder.radio(name, label, options, fieldOptions);
|
|
2521
|
-
},
|
|
2522
|
-
slider: (name, label, options) => {
|
|
2523
|
-
const builder = new TypeInferredBuilder();
|
|
2524
|
-
return builder.slider(name, label, options);
|
|
2525
|
-
},
|
|
2526
|
-
date: (name, label, options) => {
|
|
2915
|
+
text: (name, label, options) => {
|
|
2527
2916
|
const builder = new TypeInferredBuilder();
|
|
2528
|
-
return builder.
|
|
2917
|
+
return builder.text(name, label, options);
|
|
2529
2918
|
},
|
|
2530
|
-
|
|
2919
|
+
textarea: (name, label, options) => {
|
|
2531
2920
|
const builder = new TypeInferredBuilder();
|
|
2532
|
-
return builder.
|
|
2921
|
+
return builder.textarea(name, label, options);
|
|
2533
2922
|
}
|
|
2534
2923
|
};
|
|
2535
2924
|
|
|
@@ -2558,8 +2947,8 @@ var NestedPathBuilder = class {
|
|
|
2558
2947
|
*/
|
|
2559
2948
|
field(name, label, type = "input", props) {
|
|
2560
2949
|
this.fields.push({
|
|
2561
|
-
name,
|
|
2562
2950
|
label,
|
|
2951
|
+
name,
|
|
2563
2952
|
type,
|
|
2564
2953
|
...props
|
|
2565
2954
|
});
|
|
@@ -2572,8 +2961,8 @@ var NestedPathBuilder = class {
|
|
|
2572
2961
|
fieldPath(path, label, type = "input", props) {
|
|
2573
2962
|
const name = path.join(".");
|
|
2574
2963
|
this.fields.push({
|
|
2575
|
-
name,
|
|
2576
2964
|
label,
|
|
2965
|
+
name,
|
|
2577
2966
|
type,
|
|
2578
2967
|
...props
|
|
2579
2968
|
});
|
|
@@ -2583,7 +2972,7 @@ var NestedPathBuilder = class {
|
|
|
2583
2972
|
* Add a field with template literal path
|
|
2584
2973
|
* Usage: builder.field`user.profile.name`("Full Name")
|
|
2585
2974
|
*/
|
|
2586
|
-
fieldTemplate(path
|
|
2975
|
+
fieldTemplate(path) {
|
|
2587
2976
|
const pathString = path[0];
|
|
2588
2977
|
return new FieldTemplateBuilder(this, pathString);
|
|
2589
2978
|
}
|
|
@@ -2608,8 +2997,8 @@ var NestedObjectBuilder = class _NestedObjectBuilder {
|
|
|
2608
2997
|
field(fieldName, label, type = "input", props) {
|
|
2609
2998
|
const fullPath = `${this.path}.${fieldName}`;
|
|
2610
2999
|
this.parent.fields.push({
|
|
2611
|
-
name: fullPath,
|
|
2612
3000
|
label,
|
|
3001
|
+
name: fullPath,
|
|
2613
3002
|
type,
|
|
2614
3003
|
...props
|
|
2615
3004
|
});
|
|
@@ -2619,7 +3008,10 @@ var NestedObjectBuilder = class _NestedObjectBuilder {
|
|
|
2619
3008
|
* Nest deeper into the object
|
|
2620
3009
|
*/
|
|
2621
3010
|
nest(subPath) {
|
|
2622
|
-
return new _NestedObjectBuilder(
|
|
3011
|
+
return new _NestedObjectBuilder(
|
|
3012
|
+
this.parent,
|
|
3013
|
+
`${this.path}.${subPath}`
|
|
3014
|
+
);
|
|
2623
3015
|
}
|
|
2624
3016
|
/**
|
|
2625
3017
|
* Return to the parent builder
|
|
@@ -2639,8 +3031,8 @@ var SectionBuilder = class {
|
|
|
2639
3031
|
field(fieldName, label, type = "input", props) {
|
|
2640
3032
|
const fullPath = `${this.path}.${fieldName}`;
|
|
2641
3033
|
this.parent.fields.push({
|
|
2642
|
-
name: fullPath,
|
|
2643
3034
|
label,
|
|
3035
|
+
name: fullPath,
|
|
2644
3036
|
type,
|
|
2645
3037
|
...props
|
|
2646
3038
|
});
|
|
@@ -2659,7 +3051,10 @@ var SectionBuilder = class {
|
|
|
2659
3051
|
* Nest deeper into the section
|
|
2660
3052
|
*/
|
|
2661
3053
|
nest(subPath) {
|
|
2662
|
-
return new NestedObjectBuilder(
|
|
3054
|
+
return new NestedObjectBuilder(
|
|
3055
|
+
this.parent,
|
|
3056
|
+
`${this.path}.${subPath}`
|
|
3057
|
+
);
|
|
2663
3058
|
}
|
|
2664
3059
|
/**
|
|
2665
3060
|
* Return to the parent builder
|
|
@@ -2678,8 +3073,8 @@ var FieldTemplateBuilder = class {
|
|
|
2678
3073
|
*/
|
|
2679
3074
|
complete(label, type = "input", props) {
|
|
2680
3075
|
this.parent.fields.push({
|
|
2681
|
-
name: this.path,
|
|
2682
3076
|
label,
|
|
3077
|
+
name: this.path,
|
|
2683
3078
|
type,
|
|
2684
3079
|
...props
|
|
2685
3080
|
});
|
|
@@ -2693,8 +3088,10 @@ function createNestedPathBuilder() {
|
|
|
2693
3088
|
// src/hooks/useDebouncedValidation.ts
|
|
2694
3089
|
import { useCallback as useCallback2, useEffect as useEffect2, useRef } from "react";
|
|
2695
3090
|
function useDebouncedValidation(form, options = {}) {
|
|
2696
|
-
const { delay = 300,
|
|
2697
|
-
const timeoutRef = useRef(
|
|
3091
|
+
const { delay = 300, enabled = true, fields } = options;
|
|
3092
|
+
const timeoutRef = useRef(
|
|
3093
|
+
void 0
|
|
3094
|
+
);
|
|
2698
3095
|
const lastValuesRef = useRef({});
|
|
2699
3096
|
const debouncedTrigger = useCallback2(() => {
|
|
2700
3097
|
if (!enabled) return;
|
|
@@ -2705,7 +3102,9 @@ function useDebouncedValidation(form, options = {}) {
|
|
|
2705
3102
|
timeoutRef.current = setTimeout(async () => {
|
|
2706
3103
|
const currentValues = form.getValues();
|
|
2707
3104
|
const lastValues = lastValuesRef.current;
|
|
2708
|
-
const hasChanges = fields ? fields.some((field2) => currentValues[field2] !== lastValues[field2]) : Object.keys(currentValues).some(
|
|
3105
|
+
const hasChanges = fields ? fields.some((field2) => currentValues[field2] !== lastValues[field2]) : Object.keys(currentValues).some(
|
|
3106
|
+
(key) => currentValues[key] !== lastValues[key]
|
|
3107
|
+
);
|
|
2709
3108
|
if (hasChanges) {
|
|
2710
3109
|
lastValuesRef.current = { ...currentValues };
|
|
2711
3110
|
if (fields && fields.length > 0) {
|
|
@@ -2736,7 +3135,9 @@ function useDebouncedValidation(form, options = {}) {
|
|
|
2736
3135
|
}
|
|
2737
3136
|
function useDebouncedFieldValidation(form, fieldName, options = {}) {
|
|
2738
3137
|
const { delay = 300, enabled = true } = options;
|
|
2739
|
-
const timeoutRef = useRef(
|
|
3138
|
+
const timeoutRef = useRef(
|
|
3139
|
+
void 0
|
|
3140
|
+
);
|
|
2740
3141
|
const debouncedFieldTrigger = useCallback2(() => {
|
|
2741
3142
|
if (!enabled) return;
|
|
2742
3143
|
if (timeoutRef.current) {
|
|
@@ -2770,20 +3171,20 @@ try {
|
|
|
2770
3171
|
function useInferredForm(schema, fields, options = {}) {
|
|
2771
3172
|
const {
|
|
2772
3173
|
defaultValues,
|
|
3174
|
+
delayError = 0,
|
|
2773
3175
|
mode = "onChange",
|
|
2774
3176
|
reValidateMode = "onChange",
|
|
2775
3177
|
shouldFocusError = true,
|
|
2776
|
-
shouldUnregister = false
|
|
2777
|
-
delayError = 0
|
|
3178
|
+
shouldUnregister = false
|
|
2778
3179
|
} = options;
|
|
2779
3180
|
return useForm3({
|
|
2780
|
-
resolver: zodResolver ? zodResolver(schema) : void 0,
|
|
2781
3181
|
defaultValues,
|
|
3182
|
+
delayError,
|
|
2782
3183
|
mode,
|
|
3184
|
+
resolver: zodResolver ? zodResolver(schema) : void 0,
|
|
2783
3185
|
reValidateMode,
|
|
2784
3186
|
shouldFocusError,
|
|
2785
|
-
shouldUnregister
|
|
2786
|
-
delayError
|
|
3187
|
+
shouldUnregister
|
|
2787
3188
|
});
|
|
2788
3189
|
}
|
|
2789
3190
|
function useTypeInferredForm(formConfig, options = {}) {
|
|
@@ -2876,7 +3277,7 @@ function usePerformanceMonitor(componentName, enabled = process.env.NODE_ENV ===
|
|
|
2876
3277
|
};
|
|
2877
3278
|
}
|
|
2878
3279
|
function createOptimizedFieldHandler(onChange, options = {}) {
|
|
2879
|
-
const { debounce: debounceMs, throttle: throttleMs
|
|
3280
|
+
const { debounce: debounceMs, throttle: throttleMs } = options;
|
|
2880
3281
|
let handler = onChange;
|
|
2881
3282
|
if (throttleMs) {
|
|
2882
3283
|
handler = throttle(handler, throttleMs);
|
|
@@ -2889,70 +3290,51 @@ function createOptimizedFieldHandler(onChange, options = {}) {
|
|
|
2889
3290
|
function useMemoizedFieldProps(props, deps) {
|
|
2890
3291
|
return useMemo2(() => props, deps);
|
|
2891
3292
|
}
|
|
2892
|
-
function useBatchedFieldUpdates(form, fields) {
|
|
2893
|
-
const batchRef = useRef2({});
|
|
2894
|
-
const timeoutRef = useRef2(void 0);
|
|
2895
|
-
const batchUpdate = useCallback3((fieldName, value) => {
|
|
2896
|
-
batchRef.current[fieldName] = value;
|
|
2897
|
-
if (timeoutRef.current) {
|
|
2898
|
-
clearTimeout(timeoutRef.current);
|
|
2899
|
-
}
|
|
2900
|
-
timeoutRef.current = setTimeout(() => {
|
|
2901
|
-
Object.entries(batchRef.current).forEach(([key, val]) => {
|
|
2902
|
-
form.setValue(key, val);
|
|
2903
|
-
});
|
|
2904
|
-
batchRef.current = {};
|
|
2905
|
-
}, 16);
|
|
2906
|
-
}, [form]);
|
|
2907
|
-
return { batchUpdate };
|
|
2908
|
-
}
|
|
2909
3293
|
|
|
2910
3294
|
// src/builders/validation-helpers.ts
|
|
2911
3295
|
import { z as z4 } from "zod";
|
|
2912
3296
|
var validationPatterns = {
|
|
2913
|
-
// Email validation
|
|
2914
|
-
email: z4.string().email("Please enter a valid email address"),
|
|
2915
|
-
// Phone number validation (US format)
|
|
2916
|
-
phoneUS: z4.string().regex(
|
|
2917
|
-
/^\(\d{3}\) \d{3}-\d{4}$/,
|
|
2918
|
-
"Please enter a valid phone number (XXX) XXX-XXXX"
|
|
2919
|
-
),
|
|
2920
|
-
// Phone number validation (international)
|
|
2921
|
-
phoneInternational: z4.string().regex(
|
|
2922
|
-
/^\+?[\d\s\-\(\)]+$/,
|
|
2923
|
-
"Please enter a valid phone number"
|
|
2924
|
-
),
|
|
2925
|
-
// URL validation
|
|
2926
|
-
url: z4.string().url("Please enter a valid URL"),
|
|
2927
|
-
// Password validation
|
|
2928
|
-
password: z4.string().min(8, "Password must be at least 8 characters").regex(/[A-Z]/, "Password must contain at least one uppercase letter").regex(/[a-z]/, "Password must contain at least one lowercase letter").regex(/[0-9]/, "Password must contain at least one number").regex(/[^A-Za-z0-9]/, "Password must contain at least one special character"),
|
|
2929
|
-
// Strong password validation
|
|
2930
|
-
strongPassword: z4.string().min(12, "Password must be at least 12 characters").regex(/[A-Z]/, "Password must contain at least one uppercase letter").regex(/[a-z]/, "Password must contain at least one lowercase letter").regex(/[0-9]/, "Password must contain at least one number").regex(/[^A-Za-z0-9]/, "Password must contain at least one special character"),
|
|
2931
3297
|
// Credit card validation
|
|
2932
3298
|
creditCard: z4.string().regex(
|
|
3299
|
+
// eslint-disable-next-line no-useless-escape
|
|
2933
3300
|
/^[0-9]{4}[\s\-]?[0-9]{4}[\s\-]?[0-9]{4}[\s\-]?[0-9]{4}$/,
|
|
2934
3301
|
"Please enter a valid credit card number"
|
|
2935
3302
|
),
|
|
2936
|
-
// SSN validation
|
|
2937
|
-
ssn: z4.string().regex(
|
|
2938
|
-
/^\d{3}-\d{2}-\d{4}$/,
|
|
2939
|
-
"Please enter a valid SSN (XXX-XX-XXXX)"
|
|
2940
|
-
),
|
|
2941
|
-
// ZIP code validation
|
|
2942
|
-
zipCode: z4.string().regex(
|
|
2943
|
-
/^\d{5}(-\d{4})?$/,
|
|
2944
|
-
"Please enter a valid ZIP code"
|
|
2945
|
-
),
|
|
2946
3303
|
// Date validation (MM/DD/YYYY)
|
|
2947
3304
|
date: z4.string().regex(
|
|
2948
3305
|
/^(0[1-9]|1[0-2])\/(0[1-9]|[12][0-9]|3[01])\/\d{4}$/,
|
|
2949
3306
|
"Please enter a valid date (MM/DD/YYYY)"
|
|
2950
3307
|
),
|
|
3308
|
+
// Email validation
|
|
3309
|
+
email: z4.string().email("Please enter a valid email address"),
|
|
3310
|
+
// Password validation
|
|
3311
|
+
password: z4.string().min(8, "Password must be at least 8 characters").regex(/[A-Z]/, "Password must contain at least one uppercase letter").regex(/[a-z]/, "Password must contain at least one lowercase letter").regex(/[0-9]/, "Password must contain at least one number").regex(
|
|
3312
|
+
/[^A-Za-z0-9]/,
|
|
3313
|
+
"Password must contain at least one special character"
|
|
3314
|
+
),
|
|
3315
|
+
// Phone number validation (international)
|
|
3316
|
+
phoneInternational: z4.string().regex(/^\+?[\d\s\-\(\)]+$/, "Please enter a valid phone number"),
|
|
3317
|
+
// Phone number validation (US format)
|
|
3318
|
+
phoneUS: z4.string().regex(
|
|
3319
|
+
/^\(\d{3}\) \d{3}-\d{4}$/,
|
|
3320
|
+
"Please enter a valid phone number (XXX) XXX-XXXX"
|
|
3321
|
+
),
|
|
3322
|
+
// SSN validation
|
|
3323
|
+
ssn: z4.string().regex(/^\d{3}-\d{2}-\d{4}$/, "Please enter a valid SSN (XXX-XX-XXXX)"),
|
|
3324
|
+
// Strong password validation
|
|
3325
|
+
strongPassword: z4.string().min(12, "Password must be at least 12 characters").regex(/[A-Z]/, "Password must contain at least one uppercase letter").regex(/[a-z]/, "Password must contain at least one lowercase letter").regex(/[0-9]/, "Password must contain at least one number").regex(
|
|
3326
|
+
/[^A-Za-z0-9]/,
|
|
3327
|
+
"Password must contain at least one special character"
|
|
3328
|
+
),
|
|
2951
3329
|
// Time validation (HH:MM AM/PM)
|
|
2952
3330
|
time: z4.string().regex(
|
|
2953
3331
|
/^(0[1-9]|1[0-2]):[0-5][0-9] (AM|PM)$/i,
|
|
2954
3332
|
"Please enter a valid time (HH:MM AM/PM)"
|
|
2955
|
-
)
|
|
3333
|
+
),
|
|
3334
|
+
// URL validation
|
|
3335
|
+
url: z4.string().url("Please enter a valid URL"),
|
|
3336
|
+
// ZIP code validation
|
|
3337
|
+
zipCode: z4.string().regex(/^\d{5}(-\d{4})?$/, "Please enter a valid ZIP code")
|
|
2956
3338
|
};
|
|
2957
3339
|
var asyncValidation = {
|
|
2958
3340
|
/**
|
|
@@ -2979,17 +3361,17 @@ var asyncValidation = {
|
|
|
2979
3361
|
}
|
|
2980
3362
|
};
|
|
2981
3363
|
var errorMessages = {
|
|
2982
|
-
|
|
2983
|
-
|
|
3364
|
+
date: () => "Please enter a valid date",
|
|
3365
|
+
email: () => "Please enter a valid email address",
|
|
3366
|
+
max: (fieldName, max) => `${fieldName} must be no more than ${max}`,
|
|
2984
3367
|
maxLength: (fieldName, max) => `${fieldName} must be no more than ${max} characters`,
|
|
2985
3368
|
min: (fieldName, min) => `${fieldName} must be at least ${min}`,
|
|
2986
|
-
|
|
3369
|
+
minLength: (fieldName, min) => `${fieldName} must be at least ${min} characters`,
|
|
2987
3370
|
pattern: (fieldName) => `${fieldName} format is invalid`,
|
|
2988
|
-
email: () => "Please enter a valid email address",
|
|
2989
|
-
url: () => "Please enter a valid URL",
|
|
2990
3371
|
phone: () => "Please enter a valid phone number",
|
|
2991
|
-
|
|
2992
|
-
time: () => "Please enter a valid time"
|
|
3372
|
+
required: (fieldName) => `${fieldName} is required`,
|
|
3373
|
+
time: () => "Please enter a valid time",
|
|
3374
|
+
url: () => "Please enter a valid URL"
|
|
2993
3375
|
};
|
|
2994
3376
|
var serverValidation = {
|
|
2995
3377
|
/**
|
|
@@ -2998,8 +3380,8 @@ var serverValidation = {
|
|
|
2998
3380
|
applyServerErrors: (errors, setError) => {
|
|
2999
3381
|
Object.entries(errors).forEach(([field2, messages]) => {
|
|
3000
3382
|
setError(field2, {
|
|
3001
|
-
|
|
3002
|
-
|
|
3383
|
+
message: messages[0],
|
|
3384
|
+
type: "server"
|
|
3003
3385
|
// Use first error message
|
|
3004
3386
|
});
|
|
3005
3387
|
});
|
|
@@ -3024,13 +3406,25 @@ var validationUtils = {
|
|
|
3024
3406
|
timeoutId = setTimeout(() => fn(...args), delay);
|
|
3025
3407
|
};
|
|
3026
3408
|
},
|
|
3409
|
+
/**
|
|
3410
|
+
* Get field error message
|
|
3411
|
+
*/
|
|
3412
|
+
getFieldError: (errors, field2) => {
|
|
3413
|
+
return errors[field2];
|
|
3414
|
+
},
|
|
3415
|
+
/**
|
|
3416
|
+
* Check if field has error
|
|
3417
|
+
*/
|
|
3418
|
+
hasFieldError: (errors, field2) => {
|
|
3419
|
+
return !!errors[field2];
|
|
3420
|
+
},
|
|
3027
3421
|
/**
|
|
3028
3422
|
* Validate form data against schema
|
|
3029
3423
|
*/
|
|
3030
3424
|
validateForm: async (data, schema) => {
|
|
3031
3425
|
try {
|
|
3032
3426
|
await schema.parseAsync(data);
|
|
3033
|
-
return {
|
|
3427
|
+
return { errors: {}, success: true };
|
|
3034
3428
|
} catch (error) {
|
|
3035
3429
|
if (error instanceof z4.ZodError) {
|
|
3036
3430
|
const errors = {};
|
|
@@ -3038,22 +3432,10 @@ var validationUtils = {
|
|
|
3038
3432
|
const path = err.path.join(".");
|
|
3039
3433
|
errors[path] = err.message;
|
|
3040
3434
|
});
|
|
3041
|
-
return { success: false
|
|
3435
|
+
return { errors, success: false };
|
|
3042
3436
|
}
|
|
3043
3437
|
throw error;
|
|
3044
3438
|
}
|
|
3045
|
-
},
|
|
3046
|
-
/**
|
|
3047
|
-
* Get field error message
|
|
3048
|
-
*/
|
|
3049
|
-
getFieldError: (errors, field2) => {
|
|
3050
|
-
return errors[field2];
|
|
3051
|
-
},
|
|
3052
|
-
/**
|
|
3053
|
-
* Check if field has error
|
|
3054
|
-
*/
|
|
3055
|
-
hasFieldError: (errors, field2) => {
|
|
3056
|
-
return !!errors[field2];
|
|
3057
3439
|
}
|
|
3058
3440
|
};
|
|
3059
3441
|
export {
|
|
@@ -3079,6 +3461,7 @@ export {
|
|
|
3079
3461
|
InputField,
|
|
3080
3462
|
RadioGroupField,
|
|
3081
3463
|
SelectField,
|
|
3464
|
+
ServerActionForm,
|
|
3082
3465
|
SliderField,
|
|
3083
3466
|
SubmitButton,
|
|
3084
3467
|
SwitchField,
|
|
@@ -3090,8 +3473,6 @@ export {
|
|
|
3090
3473
|
commonValidations,
|
|
3091
3474
|
createAdvancedBuilder,
|
|
3092
3475
|
createBasicFormBuilder,
|
|
3093
|
-
createConditionalSchema,
|
|
3094
|
-
createConfirmPasswordSchema,
|
|
3095
3476
|
createDateSchema,
|
|
3096
3477
|
createEmailSchema,
|
|
3097
3478
|
createField,
|
|
@@ -3130,7 +3511,6 @@ export {
|
|
|
3130
3511
|
simulateFieldInput,
|
|
3131
3512
|
simulateFormSubmission,
|
|
3132
3513
|
throttle,
|
|
3133
|
-
useBatchedFieldUpdates,
|
|
3134
3514
|
useDebouncedFieldValidation,
|
|
3135
3515
|
useDebouncedValidation,
|
|
3136
3516
|
useEnhancedFormState,
|