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