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