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