@rachelallyson/hero-hook-form 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1256 @@
1
+ // src/components/Form.tsx
2
+ import React12 from "react";
3
+ import { Button as Button2 } from "@heroui/react";
4
+
5
+ // src/hooks/useFormHelper.ts
6
+ import { useState } from "react";
7
+ import { useForm } from "react-hook-form";
8
+ function useFormHelper({
9
+ defaultValues,
10
+ methods,
11
+ onError,
12
+ onSubmit,
13
+ onSuccess
14
+ }) {
15
+ const [submissionState, setSubmissionState] = useState({
16
+ isSubmitted: false,
17
+ isSubmitting: false,
18
+ isSuccess: false
19
+ });
20
+ const form = methods ?? useForm({ defaultValues });
21
+ const handleSubmit = async () => {
22
+ setSubmissionState((prev) => ({
23
+ ...prev,
24
+ error: void 0,
25
+ isSubmitting: true
26
+ }));
27
+ try {
28
+ await form.handleSubmit(async (formData) => {
29
+ await onSubmit(formData);
30
+ })();
31
+ setSubmissionState({
32
+ isSubmitted: true,
33
+ isSubmitting: false,
34
+ isSuccess: true
35
+ });
36
+ onSuccess?.(form.getValues());
37
+ } catch (error) {
38
+ const errorMessage = error instanceof Error ? error.message : "An error occurred";
39
+ setSubmissionState({
40
+ error: errorMessage,
41
+ isSubmitted: true,
42
+ isSubmitting: false,
43
+ isSuccess: false
44
+ });
45
+ onError?.({
46
+ message: errorMessage
47
+ });
48
+ }
49
+ };
50
+ const resetForm = () => {
51
+ form.reset();
52
+ setSubmissionState({
53
+ isSubmitted: false,
54
+ isSubmitting: false,
55
+ isSuccess: false
56
+ });
57
+ };
58
+ return {
59
+ error: submissionState.error,
60
+ form,
61
+ handleSubmit,
62
+ isSubmitted: submissionState.isSubmitted,
63
+ isSubmitting: submissionState.isSubmitting,
64
+ isSuccess: submissionState.isSuccess,
65
+ resetForm,
66
+ submissionState
67
+ };
68
+ }
69
+
70
+ // src/components/FormField.tsx
71
+ import React11 from "react";
72
+
73
+ // src/fields/CheckboxField.tsx
74
+ import React2 from "react";
75
+ import { Controller } from "react-hook-form";
76
+
77
+ // src/providers/ConfigProvider.tsx
78
+ import React, { createContext, useContext, useMemo } from "react";
79
+ var DefaultsContext = createContext(null);
80
+ function HeroHookFormProvider(props) {
81
+ const value = useMemo(() => props.defaults ?? {}, [props.defaults]);
82
+ return /* @__PURE__ */ React.createElement(DefaultsContext.Provider, { value }, props.children);
83
+ }
84
+ function useHeroHookFormDefaults() {
85
+ const cfg = useContext(DefaultsContext) ?? {};
86
+ const common = cfg.common ?? {};
87
+ const commonInput = {
88
+ ...common.color !== void 0 ? { color: common.color } : {},
89
+ ...common.size !== void 0 ? { size: common.size } : {},
90
+ ...common.variant !== void 0 ? { variant: common.variant } : {},
91
+ ...common.radius !== void 0 ? { radius: common.radius } : {},
92
+ ...common.labelPlacement !== void 0 ? {
93
+ labelPlacement: common.labelPlacement
94
+ } : {}
95
+ };
96
+ const commonTextarea = {
97
+ ...common.color !== void 0 ? { color: common.color } : {},
98
+ ...common.size !== void 0 ? { size: common.size } : {},
99
+ ...common.variant !== void 0 ? { variant: common.variant } : {},
100
+ ...common.radius !== void 0 ? { radius: common.radius } : {},
101
+ ...common.labelPlacement !== void 0 ? {
102
+ labelPlacement: common.labelPlacement
103
+ } : {}
104
+ };
105
+ const commonSelect = {
106
+ ...common.color !== void 0 ? { color: common.color } : {},
107
+ ...common.size !== void 0 ? { size: common.size } : {},
108
+ ...common.variant !== void 0 ? { variant: common.variant } : {},
109
+ ...common.radius !== void 0 ? { radius: common.radius } : {},
110
+ ...common.labelPlacement !== void 0 ? {
111
+ labelPlacement: common.labelPlacement
112
+ } : {}
113
+ };
114
+ const commonCheckbox = {
115
+ ...common.color !== void 0 ? {
116
+ color: common.color
117
+ } : {},
118
+ ...common.size !== void 0 ? { size: common.size } : {}
119
+ };
120
+ const commonRadioGroup = {
121
+ ...common.color !== void 0 ? {
122
+ color: common.color
123
+ } : {},
124
+ ...common.size !== void 0 ? { size: common.size } : {}
125
+ };
126
+ const commonDateInput = {
127
+ ...common.color !== void 0 ? {
128
+ color: common.color
129
+ } : {},
130
+ ...common.size !== void 0 ? { size: common.size } : {},
131
+ ...common.variant !== void 0 ? {
132
+ variant: common.variant
133
+ } : {},
134
+ ...common.radius !== void 0 ? {
135
+ radius: common.radius
136
+ } : {}
137
+ };
138
+ const commonSlider = {
139
+ ...common.color !== void 0 ? { color: common.color } : {},
140
+ ...common.size !== void 0 ? { size: common.size } : {}
141
+ };
142
+ const commonSwitch = {
143
+ ...common.color !== void 0 ? { color: common.color } : {},
144
+ ...common.size !== void 0 ? { size: common.size } : {}
145
+ };
146
+ const commonButton = {
147
+ ...common.color !== void 0 ? { color: common.color } : {},
148
+ ...common.size !== void 0 ? { size: common.size } : {}
149
+ };
150
+ return {
151
+ checkbox: { ...commonCheckbox, ...cfg.checkbox ?? {} },
152
+ dateInput: { ...commonDateInput, ...cfg.dateInput ?? {} },
153
+ input: { ...commonInput, ...cfg.input ?? {} },
154
+ radioGroup: { ...commonRadioGroup, ...cfg.radioGroup ?? {} },
155
+ select: { ...commonSelect, ...cfg.select ?? {} },
156
+ slider: { ...commonSlider, ...cfg.slider ?? {} },
157
+ submitButton: { ...commonButton, ...cfg.submitButton ?? {} },
158
+ switch: { ...commonSwitch, ...cfg.switch ?? {} },
159
+ textarea: { ...commonTextarea, ...cfg.textarea ?? {} }
160
+ };
161
+ }
162
+
163
+ // src/ui/react.ts
164
+ import {
165
+ Button,
166
+ Checkbox,
167
+ DateInput,
168
+ DatePicker,
169
+ Input,
170
+ Radio,
171
+ RadioGroup,
172
+ Select,
173
+ SelectItem,
174
+ Slider,
175
+ Spinner,
176
+ Switch,
177
+ Textarea
178
+ } from "@heroui/react";
179
+
180
+ // src/fields/CheckboxField.tsx
181
+ function CheckboxField(props) {
182
+ const {
183
+ checkboxProps,
184
+ className,
185
+ control,
186
+ description,
187
+ isDisabled,
188
+ label,
189
+ name,
190
+ rules
191
+ } = props;
192
+ const defaults = useHeroHookFormDefaults();
193
+ return /* @__PURE__ */ React2.createElement(
194
+ Controller,
195
+ {
196
+ control,
197
+ name,
198
+ render: ({ field, fieldState }) => /* @__PURE__ */ React2.createElement("div", { className }, /* @__PURE__ */ React2.createElement(
199
+ Checkbox,
200
+ {
201
+ ...defaults.checkbox,
202
+ ...checkboxProps,
203
+ isDisabled,
204
+ isInvalid: Boolean(fieldState.error),
205
+ isSelected: Boolean(field.value),
206
+ onBlur: field.onBlur,
207
+ onValueChange: (val) => field.onChange(val)
208
+ },
209
+ label
210
+ ), description ? /* @__PURE__ */ React2.createElement("p", { className: "text-small text-default-400" }, description) : null, fieldState.error?.message ? /* @__PURE__ */ React2.createElement("p", { className: "text-tiny text-danger mt-1" }, fieldState.error.message) : null),
211
+ rules
212
+ }
213
+ );
214
+ }
215
+
216
+ // src/fields/DateField.tsx
217
+ import React3 from "react";
218
+ import { Controller as Controller2 } from "react-hook-form";
219
+ function CoercedDateInput(props) {
220
+ const { dateProps, description, disabled, errorMessage, field, label } = props;
221
+ const defaults = useHeroHookFormDefaults();
222
+ return /* @__PURE__ */ React3.createElement(
223
+ DateInput,
224
+ {
225
+ ...defaults.dateInput,
226
+ ...dateProps,
227
+ description,
228
+ errorMessage,
229
+ isDisabled: disabled,
230
+ isInvalid: Boolean(errorMessage),
231
+ label,
232
+ value: field.value ?? null,
233
+ onBlur: field.onBlur,
234
+ onChange: field.onChange
235
+ }
236
+ );
237
+ }
238
+ function DateField(props) {
239
+ const {
240
+ className,
241
+ control,
242
+ dateProps,
243
+ description,
244
+ isDisabled,
245
+ label,
246
+ name,
247
+ rules,
248
+ transform
249
+ } = props;
250
+ return /* @__PURE__ */ React3.createElement(
251
+ Controller2,
252
+ {
253
+ control,
254
+ name,
255
+ render: ({ field, fieldState }) => /* @__PURE__ */ React3.createElement("div", { className }, /* @__PURE__ */ React3.createElement(
256
+ CoercedDateInput,
257
+ {
258
+ dateProps,
259
+ description,
260
+ disabled: isDisabled,
261
+ errorMessage: fieldState.error?.message,
262
+ field: {
263
+ ...field,
264
+ onChange: (value) => field.onChange(transform ? transform(value) : value)
265
+ },
266
+ label
267
+ }
268
+ )),
269
+ rules
270
+ }
271
+ );
272
+ }
273
+
274
+ // src/fields/FileField.tsx
275
+ import React4 from "react";
276
+ import { Controller as Controller3 } from "react-hook-form";
277
+ function CoercedFileInput(props) {
278
+ const {
279
+ accept,
280
+ description,
281
+ disabled,
282
+ errorMessage,
283
+ field,
284
+ fileProps,
285
+ label,
286
+ multiple
287
+ } = props;
288
+ const defaults = useHeroHookFormDefaults();
289
+ return /* @__PURE__ */ React4.createElement(
290
+ Input,
291
+ {
292
+ ...defaults.input,
293
+ ...fileProps,
294
+ accept,
295
+ description,
296
+ errorMessage,
297
+ isDisabled: disabled,
298
+ isInvalid: Boolean(errorMessage),
299
+ label,
300
+ multiple,
301
+ type: "file",
302
+ value: field.value ? "" : "",
303
+ onBlur: field.onBlur,
304
+ onChange: (e2) => {
305
+ const target = e2.target;
306
+ field.onChange(target.files);
307
+ }
308
+ }
309
+ );
310
+ }
311
+ function FileField(props) {
312
+ const {
313
+ accept,
314
+ className,
315
+ control,
316
+ description,
317
+ fileProps,
318
+ isDisabled,
319
+ label,
320
+ multiple = false,
321
+ name,
322
+ rules,
323
+ transform
324
+ } = props;
325
+ return /* @__PURE__ */ React4.createElement(
326
+ Controller3,
327
+ {
328
+ control,
329
+ name,
330
+ render: ({ field, fieldState }) => /* @__PURE__ */ React4.createElement("div", { className }, /* @__PURE__ */ React4.createElement(
331
+ CoercedFileInput,
332
+ {
333
+ accept,
334
+ description,
335
+ disabled: isDisabled,
336
+ errorMessage: fieldState.error?.message,
337
+ field: {
338
+ ...field,
339
+ onChange: (value) => field.onChange(transform ? transform(value) : value)
340
+ },
341
+ fileProps,
342
+ label,
343
+ multiple
344
+ }
345
+ )),
346
+ rules
347
+ }
348
+ );
349
+ }
350
+
351
+ // src/fields/InputField.tsx
352
+ import React5 from "react";
353
+ import { Controller as Controller4 } from "react-hook-form";
354
+ function CoercedInput(props) {
355
+ const { description, disabled, errorMessage, field, inputProps, label } = props;
356
+ const defaults = useHeroHookFormDefaults();
357
+ return /* @__PURE__ */ React5.createElement(
358
+ Input,
359
+ {
360
+ ...defaults.input,
361
+ ...inputProps,
362
+ description,
363
+ errorMessage,
364
+ isDisabled: disabled,
365
+ isInvalid: Boolean(errorMessage),
366
+ label,
367
+ value: field.value ?? "",
368
+ onBlur: field.onBlur,
369
+ onValueChange: field.onChange
370
+ }
371
+ );
372
+ }
373
+ function InputField(props) {
374
+ const {
375
+ className,
376
+ control,
377
+ description,
378
+ inputProps,
379
+ isDisabled,
380
+ label,
381
+ name,
382
+ rules,
383
+ transform
384
+ } = props;
385
+ return /* @__PURE__ */ React5.createElement(
386
+ Controller4,
387
+ {
388
+ control,
389
+ name,
390
+ render: ({ field, fieldState }) => /* @__PURE__ */ React5.createElement("div", { className }, /* @__PURE__ */ React5.createElement(
391
+ CoercedInput,
392
+ {
393
+ description,
394
+ disabled: isDisabled,
395
+ errorMessage: fieldState.error?.message,
396
+ field: {
397
+ ...field,
398
+ onChange: (value) => {
399
+ if (inputProps?.type === "number") {
400
+ const numValue = value === "" ? void 0 : Number(value);
401
+ field.onChange(
402
+ transform ? transform(String(numValue)) : numValue
403
+ );
404
+ } else {
405
+ field.onChange(transform ? transform(value) : value);
406
+ }
407
+ }
408
+ },
409
+ inputProps,
410
+ label
411
+ }
412
+ )),
413
+ rules
414
+ }
415
+ );
416
+ }
417
+
418
+ // src/fields/RadioGroupField.tsx
419
+ import React6 from "react";
420
+ import { Controller as Controller5 } from "react-hook-form";
421
+ function RadioGroupField(props) {
422
+ const {
423
+ className,
424
+ control,
425
+ description,
426
+ isDisabled,
427
+ label,
428
+ name,
429
+ options,
430
+ radioGroupProps,
431
+ rules
432
+ } = props;
433
+ const defaults = useHeroHookFormDefaults();
434
+ return /* @__PURE__ */ React6.createElement(
435
+ Controller5,
436
+ {
437
+ control,
438
+ name,
439
+ render: ({ field, fieldState }) => /* @__PURE__ */ React6.createElement("div", { className }, /* @__PURE__ */ React6.createElement(
440
+ RadioGroup,
441
+ {
442
+ ...defaults.radioGroup,
443
+ ...radioGroupProps,
444
+ description,
445
+ isDisabled,
446
+ isInvalid: Boolean(fieldState.error),
447
+ label,
448
+ value: String(field.value ?? ""),
449
+ onBlur: field.onBlur,
450
+ onValueChange: (val) => field.onChange(val)
451
+ },
452
+ options.map((opt) => /* @__PURE__ */ React6.createElement(
453
+ Radio,
454
+ {
455
+ key: String(opt.value),
456
+ isDisabled: opt.disabled,
457
+ value: String(opt.value)
458
+ },
459
+ opt.label
460
+ ))
461
+ ), fieldState.error?.message ? /* @__PURE__ */ React6.createElement("p", { className: "text-tiny text-danger mt-1" }, fieldState.error.message) : null),
462
+ rules
463
+ }
464
+ );
465
+ }
466
+
467
+ // src/fields/SelectField.tsx
468
+ import React7 from "react";
469
+ import { Controller as Controller6 } from "react-hook-form";
470
+ function SelectField(props) {
471
+ const {
472
+ className,
473
+ control,
474
+ description,
475
+ isDisabled,
476
+ label,
477
+ name,
478
+ options,
479
+ placeholder,
480
+ rules,
481
+ selectProps
482
+ } = props;
483
+ const defaults = useHeroHookFormDefaults();
484
+ return /* @__PURE__ */ React7.createElement(
485
+ Controller6,
486
+ {
487
+ control,
488
+ name,
489
+ render: ({ field, fieldState }) => {
490
+ const selectedKey = field.value;
491
+ return /* @__PURE__ */ React7.createElement("div", { className }, /* @__PURE__ */ React7.createElement(
492
+ Select,
493
+ {
494
+ ...defaults.select,
495
+ ...selectProps,
496
+ description,
497
+ errorMessage: fieldState.error?.message,
498
+ isDisabled,
499
+ isInvalid: Boolean(fieldState.error),
500
+ label,
501
+ placeholder,
502
+ selectedKeys: selectedKey != null ? /* @__PURE__ */ new Set([String(selectedKey)]) : /* @__PURE__ */ new Set(),
503
+ onSelectionChange: (keys) => {
504
+ const keyArray = Array.from(keys);
505
+ const next = keyArray[0] ?? "";
506
+ field.onChange(next);
507
+ }
508
+ },
509
+ options.map((opt) => /* @__PURE__ */ React7.createElement(
510
+ SelectItem,
511
+ {
512
+ key: String(opt.value),
513
+ isDisabled: opt.disabled,
514
+ textValue: String(opt.value)
515
+ },
516
+ opt.label
517
+ ))
518
+ ));
519
+ },
520
+ rules
521
+ }
522
+ );
523
+ }
524
+
525
+ // src/fields/SliderField.tsx
526
+ import React8 from "react";
527
+ import { Controller as Controller7 } from "react-hook-form";
528
+ function CoercedSlider(props) {
529
+ const { description, disabled, errorMessage, field, label, sliderProps } = props;
530
+ const defaults = useHeroHookFormDefaults();
531
+ return /* @__PURE__ */ React8.createElement(
532
+ Slider,
533
+ {
534
+ ...defaults.slider,
535
+ ...sliderProps,
536
+ description,
537
+ errorMessage,
538
+ isDisabled: disabled,
539
+ isInvalid: Boolean(errorMessage),
540
+ label,
541
+ value: field.value ?? 0,
542
+ onBlur: field.onBlur,
543
+ onValueChange: field.onChange
544
+ }
545
+ );
546
+ }
547
+ function SliderField(props) {
548
+ const {
549
+ className,
550
+ control,
551
+ description,
552
+ isDisabled,
553
+ label,
554
+ name,
555
+ rules,
556
+ sliderProps,
557
+ transform
558
+ } = props;
559
+ return /* @__PURE__ */ React8.createElement(
560
+ Controller7,
561
+ {
562
+ control,
563
+ name,
564
+ render: ({ field, fieldState }) => /* @__PURE__ */ React8.createElement("div", { className }, /* @__PURE__ */ React8.createElement(
565
+ CoercedSlider,
566
+ {
567
+ description,
568
+ disabled: isDisabled,
569
+ errorMessage: fieldState.error?.message,
570
+ field: {
571
+ ...field,
572
+ onChange: (value) => field.onChange(transform ? transform(value) : value)
573
+ },
574
+ label,
575
+ sliderProps
576
+ }
577
+ )),
578
+ rules
579
+ }
580
+ );
581
+ }
582
+
583
+ // src/fields/SwitchField.tsx
584
+ import React9 from "react";
585
+ import { Controller as Controller8 } from "react-hook-form";
586
+ function SwitchField(props) {
587
+ const {
588
+ className,
589
+ control,
590
+ description,
591
+ isDisabled,
592
+ label,
593
+ name,
594
+ rules,
595
+ switchProps
596
+ } = props;
597
+ const defaults = useHeroHookFormDefaults();
598
+ return /* @__PURE__ */ React9.createElement(
599
+ Controller8,
600
+ {
601
+ control,
602
+ name,
603
+ render: ({ field, fieldState }) => /* @__PURE__ */ React9.createElement("div", { className }, /* @__PURE__ */ React9.createElement(
604
+ Switch,
605
+ {
606
+ ...defaults.switch,
607
+ ...switchProps,
608
+ isDisabled,
609
+ isSelected: Boolean(field.value),
610
+ onBlur: field.onBlur,
611
+ onValueChange: (val) => field.onChange(val)
612
+ },
613
+ label
614
+ ), description ? /* @__PURE__ */ React9.createElement("p", { className: "text-small text-default-400" }, description) : null, fieldState.error?.message ? /* @__PURE__ */ React9.createElement("p", { className: "text-tiny text-danger mt-1" }, fieldState.error.message) : null),
615
+ rules
616
+ }
617
+ );
618
+ }
619
+
620
+ // src/fields/TextareaField.tsx
621
+ import React10 from "react";
622
+ import { Controller as Controller9 } from "react-hook-form";
623
+ function TextareaField(props) {
624
+ const {
625
+ className,
626
+ control,
627
+ description,
628
+ isDisabled,
629
+ label,
630
+ name,
631
+ rules,
632
+ textareaProps
633
+ } = props;
634
+ const defaults = useHeroHookFormDefaults();
635
+ return /* @__PURE__ */ React10.createElement(
636
+ Controller9,
637
+ {
638
+ control,
639
+ name,
640
+ render: ({ field, fieldState }) => /* @__PURE__ */ React10.createElement("div", { className }, /* @__PURE__ */ React10.createElement(
641
+ Textarea,
642
+ {
643
+ ...defaults.textarea,
644
+ ...textareaProps,
645
+ description,
646
+ errorMessage: fieldState.error?.message,
647
+ isDisabled,
648
+ isInvalid: Boolean(fieldState.error),
649
+ label,
650
+ value: field.value ?? "",
651
+ onBlur: field.onBlur,
652
+ onValueChange: field.onChange
653
+ }
654
+ )),
655
+ rules
656
+ }
657
+ );
658
+ }
659
+
660
+ // src/components/FormField.tsx
661
+ function FormField({
662
+ config,
663
+ form,
664
+ submissionState
665
+ }) {
666
+ const { control } = form;
667
+ const baseProps = {
668
+ className: config.className,
669
+ description: config.description,
670
+ isDisabled: config.isDisabled ?? submissionState.isSubmitting,
671
+ label: config.label,
672
+ name: config.name,
673
+ rules: config.rules
674
+ };
675
+ switch (config.type) {
676
+ case "input":
677
+ return /* @__PURE__ */ React11.createElement(
678
+ InputField,
679
+ {
680
+ ...baseProps,
681
+ control,
682
+ defaultValue: config.defaultValue,
683
+ inputProps: config.inputProps
684
+ }
685
+ );
686
+ case "textarea":
687
+ return /* @__PURE__ */ React11.createElement(
688
+ TextareaField,
689
+ {
690
+ ...baseProps,
691
+ control,
692
+ defaultValue: config.defaultValue,
693
+ textareaProps: config.textareaProps
694
+ }
695
+ );
696
+ case "select":
697
+ return /* @__PURE__ */ React11.createElement(
698
+ SelectField,
699
+ {
700
+ ...baseProps,
701
+ control,
702
+ defaultValue: config.defaultValue,
703
+ options: (config.options ?? []).map((opt) => ({
704
+ label: opt.label,
705
+ value: String(opt.value)
706
+ })),
707
+ selectProps: config.selectProps
708
+ }
709
+ );
710
+ case "checkbox":
711
+ return /* @__PURE__ */ React11.createElement(
712
+ CheckboxField,
713
+ {
714
+ ...baseProps,
715
+ checkboxProps: config.checkboxProps,
716
+ control,
717
+ defaultValue: config.defaultValue
718
+ }
719
+ );
720
+ case "radio":
721
+ return /* @__PURE__ */ React11.createElement(
722
+ RadioGroupField,
723
+ {
724
+ ...baseProps,
725
+ control,
726
+ defaultValue: config.defaultValue,
727
+ options: (config.radioOptions ?? []).map((opt) => ({
728
+ label: opt.label,
729
+ value: String(opt.value)
730
+ })),
731
+ radioGroupProps: config.radioProps
732
+ }
733
+ );
734
+ case "switch":
735
+ return /* @__PURE__ */ React11.createElement(
736
+ SwitchField,
737
+ {
738
+ ...baseProps,
739
+ control,
740
+ defaultValue: config.defaultValue,
741
+ switchProps: config.switchProps
742
+ }
743
+ );
744
+ case "slider":
745
+ return /* @__PURE__ */ React11.createElement(
746
+ SliderField,
747
+ {
748
+ ...baseProps,
749
+ control,
750
+ defaultValue: config.defaultValue,
751
+ sliderProps: config.sliderProps
752
+ }
753
+ );
754
+ case "date":
755
+ return /* @__PURE__ */ React11.createElement(
756
+ DateField,
757
+ {
758
+ ...baseProps,
759
+ control,
760
+ dateProps: config.dateProps,
761
+ defaultValue: config.defaultValue
762
+ }
763
+ );
764
+ case "file":
765
+ return /* @__PURE__ */ React11.createElement(
766
+ FileField,
767
+ {
768
+ ...baseProps,
769
+ accept: config.accept,
770
+ control,
771
+ defaultValue: config.defaultValue,
772
+ fileProps: config.fileProps,
773
+ multiple: config.multiple
774
+ }
775
+ );
776
+ default: {
777
+ const fieldType = config.type;
778
+ console.warn(`Unknown field type: ${fieldType}`);
779
+ return null;
780
+ }
781
+ }
782
+ }
783
+
784
+ // src/components/Form.tsx
785
+ function ConfigurableForm({
786
+ className,
787
+ columns = 1,
788
+ defaultValues,
789
+ fields,
790
+ layout = "vertical",
791
+ onError,
792
+ onSubmit,
793
+ onSuccess,
794
+ resetButtonText = "Reset",
795
+ showResetButton = false,
796
+ spacing = "4",
797
+ submitButtonProps = {},
798
+ submitButtonText = "Submit",
799
+ subtitle,
800
+ title
801
+ }) {
802
+ const {
803
+ error,
804
+ form,
805
+ handleSubmit,
806
+ isSubmitted,
807
+ isSubmitting,
808
+ isSuccess,
809
+ resetForm,
810
+ submissionState
811
+ } = useFormHelper({
812
+ defaultValues,
813
+ onError,
814
+ onSubmit,
815
+ onSuccess
816
+ });
817
+ const renderFields = () => {
818
+ if (layout === "grid") {
819
+ return /* @__PURE__ */ React12.createElement(
820
+ "div",
821
+ {
822
+ 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"}`
823
+ },
824
+ fields.map((field) => /* @__PURE__ */ React12.createElement(
825
+ FormField,
826
+ {
827
+ key: field.name,
828
+ config: field,
829
+ form,
830
+ submissionState
831
+ }
832
+ ))
833
+ );
834
+ }
835
+ if (layout === "horizontal") {
836
+ return /* @__PURE__ */ React12.createElement("div", { className: `grid gap-${spacing} grid-cols-1 md:grid-cols-2` }, fields.map((field) => /* @__PURE__ */ React12.createElement(
837
+ FormField,
838
+ {
839
+ key: field.name,
840
+ config: field,
841
+ form,
842
+ submissionState
843
+ }
844
+ )));
845
+ }
846
+ return /* @__PURE__ */ React12.createElement("div", { className: `space-y-${spacing}` }, fields.map((field) => /* @__PURE__ */ React12.createElement(
847
+ FormField,
848
+ {
849
+ key: field.name,
850
+ config: field,
851
+ form,
852
+ submissionState
853
+ }
854
+ )));
855
+ };
856
+ const handleFormSubmit = (e2) => {
857
+ e2.preventDefault();
858
+ void handleSubmit();
859
+ };
860
+ return /* @__PURE__ */ React12.createElement("form", { className, role: "form", onSubmit: handleFormSubmit }, title && /* @__PURE__ */ React12.createElement("div", { className: "mb-6" }, /* @__PURE__ */ React12.createElement("h2", { className: "text-xl font-semibold text-foreground mb-2" }, title), subtitle && /* @__PURE__ */ React12.createElement("p", { className: "text-sm text-muted-foreground" }, subtitle)), isSubmitted && isSuccess && /* @__PURE__ */ React12.createElement(
861
+ "div",
862
+ {
863
+ className: "mb-6 p-4 bg-success-50 border border-success-200 rounded-lg",
864
+ "data-testid": "success-message"
865
+ },
866
+ /* @__PURE__ */ React12.createElement("p", { className: "text-success-800 font-medium" }, "Success!"),
867
+ /* @__PURE__ */ React12.createElement("p", { className: "text-success-700 text-sm mt-1" }, "Your request has been processed successfully.")
868
+ ), error && /* @__PURE__ */ React12.createElement(
869
+ "div",
870
+ {
871
+ className: "mb-6 p-4 bg-danger-50 border border-danger-200 rounded-lg",
872
+ "data-testid": "error-message"
873
+ },
874
+ /* @__PURE__ */ React12.createElement("p", { className: "text-danger-800 font-medium" }, "Error"),
875
+ /* @__PURE__ */ React12.createElement("p", { className: "text-danger-700 text-sm mt-1" }, error)
876
+ ), renderFields(), /* @__PURE__ */ React12.createElement("div", { className: "mt-6 flex gap-3 justify-end" }, /* @__PURE__ */ React12.createElement(
877
+ Button2,
878
+ {
879
+ color: "primary",
880
+ isDisabled: isSubmitting,
881
+ isLoading: isSubmitting,
882
+ type: "submit",
883
+ ...submitButtonProps
884
+ },
885
+ submitButtonText
886
+ ), showResetButton && /* @__PURE__ */ React12.createElement(
887
+ Button2,
888
+ {
889
+ isDisabled: isSubmitting,
890
+ type: "button",
891
+ variant: "bordered",
892
+ onPress: resetForm
893
+ },
894
+ resetButtonText
895
+ )));
896
+ }
897
+
898
+ // src/providers/FormProvider.tsx
899
+ import React13 from "react";
900
+ import { FormProvider as RHFProvider } from "react-hook-form";
901
+ function FormProvider(props) {
902
+ return /* @__PURE__ */ React13.createElement(RHFProvider, { ...props.methods }, /* @__PURE__ */ React13.createElement(
903
+ "form",
904
+ {
905
+ className: props.className,
906
+ id: props.id,
907
+ noValidate: props.noValidate,
908
+ onSubmit: (event) => void props.methods.handleSubmit(props.onSubmit)(event)
909
+ },
910
+ props.children
911
+ ));
912
+ }
913
+
914
+ // src/submit/SubmitButton.tsx
915
+ import React14 from "react";
916
+ import { useFormContext } from "react-hook-form";
917
+ function SubmitButton(props) {
918
+ const ctx = useFormContext();
919
+ const loading = props.isLoading ?? ctx.formState.isSubmitting;
920
+ const isDisabledFromProps = props.buttonProps?.isDisabled ?? false;
921
+ const isDisabled = Boolean(isDisabledFromProps) || Boolean(loading);
922
+ const defaults = useHeroHookFormDefaults();
923
+ return /* @__PURE__ */ React14.createElement(
924
+ Button,
925
+ {
926
+ type: "submit",
927
+ ...defaults.submitButton,
928
+ ...props.buttonProps,
929
+ isDisabled
930
+ },
931
+ loading ? /* @__PURE__ */ React14.createElement("span", { className: "inline-flex items-center gap-2" }, /* @__PURE__ */ React14.createElement(Spinner, { size: "sm" }), "Submitting\u2026") : props.children
932
+ );
933
+ }
934
+
935
+ // src/utils/applyServerErrors.ts
936
+ function applyServerErrors(setError, serverError) {
937
+ if (!serverError.fieldErrors?.length) return;
938
+ for (const err of serverError.fieldErrors) {
939
+ setError(err.path, { message: err.message, type: err.type });
940
+ }
941
+ }
942
+
943
+ // src/components/ZodForm.tsx
944
+ import React15 from "react";
945
+ import { Button as Button3 } from "@heroui/react";
946
+
947
+ // node_modules/@hookform/resolvers/dist/resolvers.mjs
948
+ import { get as e, set as t } from "react-hook-form";
949
+ var r = (t3, r2, o3) => {
950
+ if (t3 && "reportValidity" in t3) {
951
+ const s3 = e(o3, r2);
952
+ t3.setCustomValidity(s3 && s3.message || ""), t3.reportValidity();
953
+ }
954
+ };
955
+ var o = (e2, t3) => {
956
+ for (const o3 in t3.fields) {
957
+ const s3 = t3.fields[o3];
958
+ s3 && s3.ref && "reportValidity" in s3.ref ? r(s3.ref, o3, e2) : s3 && s3.refs && s3.refs.forEach((t4) => r(t4, o3, e2));
959
+ }
960
+ };
961
+ var s = (r2, s3) => {
962
+ s3.shouldUseNativeValidation && o(r2, s3);
963
+ const n3 = {};
964
+ for (const o3 in r2) {
965
+ const f = e(s3.fields, o3), c = Object.assign(r2[o3] || {}, { ref: f && f.ref });
966
+ if (i(s3.names || Object.keys(r2), o3)) {
967
+ const r3 = Object.assign({}, e(n3, o3));
968
+ t(r3, "root", c), t(n3, o3, r3);
969
+ } else t(n3, o3, c);
970
+ }
971
+ return n3;
972
+ };
973
+ var i = (e2, t3) => {
974
+ const r2 = n(t3);
975
+ return e2.some((e3) => n(e3).match(`^${r2}\\.\\d+`));
976
+ };
977
+ function n(e2) {
978
+ return e2.replace(/\]|\[/g, "");
979
+ }
980
+
981
+ // node_modules/@hookform/resolvers/zod/dist/zod.mjs
982
+ import { appendErrors as o2 } from "react-hook-form";
983
+ import * as n2 from "zod/v4/core";
984
+ function t2(r2, e2) {
985
+ try {
986
+ var o3 = r2();
987
+ } catch (r3) {
988
+ return e2(r3);
989
+ }
990
+ return o3 && o3.then ? o3.then(void 0, e2) : o3;
991
+ }
992
+ function s2(r2, e2) {
993
+ for (var n3 = {}; r2.length; ) {
994
+ var t3 = r2[0], s3 = t3.code, i3 = t3.message, a2 = t3.path.join(".");
995
+ if (!n3[a2]) if ("unionErrors" in t3) {
996
+ var u = t3.unionErrors[0].errors[0];
997
+ n3[a2] = { message: u.message, type: u.code };
998
+ } else n3[a2] = { message: i3, type: s3 };
999
+ if ("unionErrors" in t3 && t3.unionErrors.forEach(function(e3) {
1000
+ return e3.errors.forEach(function(e4) {
1001
+ return r2.push(e4);
1002
+ });
1003
+ }), e2) {
1004
+ var c = n3[a2].types, f = c && c[t3.code];
1005
+ n3[a2] = o2(a2, e2, n3, s3, f ? [].concat(f, t3.message) : t3.message);
1006
+ }
1007
+ r2.shift();
1008
+ }
1009
+ return n3;
1010
+ }
1011
+ function i2(r2, e2) {
1012
+ for (var n3 = {}; r2.length; ) {
1013
+ var t3 = r2[0], s3 = t3.code, i3 = t3.message, a2 = t3.path.join(".");
1014
+ if (!n3[a2]) if ("invalid_union" === t3.code && t3.errors.length > 0) {
1015
+ var u = t3.errors[0][0];
1016
+ n3[a2] = { message: u.message, type: u.code };
1017
+ } else n3[a2] = { message: i3, type: s3 };
1018
+ if ("invalid_union" === t3.code && t3.errors.forEach(function(e3) {
1019
+ return e3.forEach(function(e4) {
1020
+ return r2.push(e4);
1021
+ });
1022
+ }), e2) {
1023
+ var c = n3[a2].types, f = c && c[t3.code];
1024
+ n3[a2] = o2(a2, e2, n3, s3, f ? [].concat(f, t3.message) : t3.message);
1025
+ }
1026
+ r2.shift();
1027
+ }
1028
+ return n3;
1029
+ }
1030
+ function a(o3, a2, u) {
1031
+ if (void 0 === u && (u = {}), (function(r2) {
1032
+ return "_def" in r2 && "object" == typeof r2._def && "typeName" in r2._def;
1033
+ })(o3)) return function(n3, i3, c) {
1034
+ try {
1035
+ return Promise.resolve(t2(function() {
1036
+ return Promise.resolve(o3["sync" === u.mode ? "parse" : "parseAsync"](n3, a2)).then(function(e2) {
1037
+ return c.shouldUseNativeValidation && o({}, c), { errors: {}, values: u.raw ? Object.assign({}, n3) : e2 };
1038
+ });
1039
+ }, function(r2) {
1040
+ if ((function(r3) {
1041
+ return Array.isArray(null == r3 ? void 0 : r3.issues);
1042
+ })(r2)) return { values: {}, errors: s(s2(r2.errors, !c.shouldUseNativeValidation && "all" === c.criteriaMode), c) };
1043
+ throw r2;
1044
+ }));
1045
+ } catch (r2) {
1046
+ return Promise.reject(r2);
1047
+ }
1048
+ };
1049
+ if ((function(r2) {
1050
+ return "_zod" in r2 && "object" == typeof r2._zod;
1051
+ })(o3)) return function(s3, c, f) {
1052
+ try {
1053
+ return Promise.resolve(t2(function() {
1054
+ return Promise.resolve(("sync" === u.mode ? n2.parse : n2.parseAsync)(o3, s3, a2)).then(function(e2) {
1055
+ return f.shouldUseNativeValidation && o({}, f), { errors: {}, values: u.raw ? Object.assign({}, s3) : e2 };
1056
+ });
1057
+ }, function(r2) {
1058
+ if ((function(r3) {
1059
+ return r3 instanceof n2.$ZodError;
1060
+ })(r2)) return { values: {}, errors: s(i2(r2.issues, !f.shouldUseNativeValidation && "all" === f.criteriaMode), f) };
1061
+ throw r2;
1062
+ }));
1063
+ } catch (r2) {
1064
+ return Promise.reject(r2);
1065
+ }
1066
+ };
1067
+ throw new Error("Invalid input: not a Zod schema");
1068
+ }
1069
+
1070
+ // src/zod-integration.ts
1071
+ import { useForm as useForm2 } from "react-hook-form";
1072
+ function useZodForm(config) {
1073
+ if (!config.resolver && config.schema) {
1074
+ const resolver = a(config.schema);
1075
+ config.resolver = resolver;
1076
+ }
1077
+ const formConfig = {
1078
+ ...config
1079
+ };
1080
+ return useForm2(formConfig);
1081
+ }
1082
+
1083
+ // src/components/ZodForm.tsx
1084
+ function ZodForm({
1085
+ className,
1086
+ columns = 1,
1087
+ config,
1088
+ layout = "vertical",
1089
+ onError,
1090
+ onSubmit,
1091
+ onSuccess,
1092
+ resetButtonText = "Reset",
1093
+ showResetButton = false,
1094
+ spacing = "4",
1095
+ submitButtonProps = {},
1096
+ submitButtonText = "Submit",
1097
+ subtitle,
1098
+ title
1099
+ }) {
1100
+ const form = useZodForm(config);
1101
+ const [submissionState, setSubmissionState] = React15.useState({
1102
+ error: void 0,
1103
+ isSubmitted: false,
1104
+ isSubmitting: false,
1105
+ isSuccess: false
1106
+ });
1107
+ const handleSubmit = async () => {
1108
+ setSubmissionState((prev) => ({
1109
+ ...prev,
1110
+ error: void 0,
1111
+ isSubmitting: true
1112
+ }));
1113
+ const isValid = await form.trigger();
1114
+ if (!isValid) {
1115
+ setSubmissionState({
1116
+ error: "Please fix the validation errors above",
1117
+ isSubmitted: true,
1118
+ isSubmitting: false,
1119
+ isSuccess: false
1120
+ });
1121
+ return;
1122
+ }
1123
+ try {
1124
+ await form.handleSubmit(async (formData) => {
1125
+ await onSubmit(formData);
1126
+ })();
1127
+ setSubmissionState({
1128
+ error: void 0,
1129
+ isSubmitted: true,
1130
+ isSubmitting: false,
1131
+ isSuccess: true
1132
+ });
1133
+ onSuccess?.(form.getValues());
1134
+ } catch (error) {
1135
+ const errorMessage = error instanceof Error ? error.message : "An error occurred";
1136
+ setSubmissionState({
1137
+ error: errorMessage,
1138
+ isSubmitted: true,
1139
+ isSubmitting: false,
1140
+ isSuccess: false
1141
+ });
1142
+ onError?.({
1143
+ message: errorMessage
1144
+ });
1145
+ }
1146
+ };
1147
+ const resetForm = () => {
1148
+ form.reset();
1149
+ setSubmissionState({
1150
+ error: void 0,
1151
+ isSubmitted: false,
1152
+ isSubmitting: false,
1153
+ isSuccess: false
1154
+ });
1155
+ };
1156
+ const renderFields = () => {
1157
+ if (layout === "grid") {
1158
+ return /* @__PURE__ */ React15.createElement(
1159
+ "div",
1160
+ {
1161
+ 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"}`
1162
+ },
1163
+ config.fields.map((field) => /* @__PURE__ */ React15.createElement(
1164
+ FormField,
1165
+ {
1166
+ key: field.name,
1167
+ config: field,
1168
+ form,
1169
+ submissionState
1170
+ }
1171
+ ))
1172
+ );
1173
+ }
1174
+ if (layout === "horizontal") {
1175
+ return /* @__PURE__ */ React15.createElement("div", { className: `grid gap-${spacing} grid-cols-1 md:grid-cols-2` }, config.fields.map((field) => /* @__PURE__ */ React15.createElement(
1176
+ FormField,
1177
+ {
1178
+ key: field.name,
1179
+ config: field,
1180
+ form,
1181
+ submissionState
1182
+ }
1183
+ )));
1184
+ }
1185
+ return /* @__PURE__ */ React15.createElement("div", { className: `space-y-${spacing}` }, config.fields.map((field) => /* @__PURE__ */ React15.createElement(
1186
+ FormField,
1187
+ {
1188
+ key: field.name,
1189
+ config: field,
1190
+ form,
1191
+ submissionState
1192
+ }
1193
+ )));
1194
+ };
1195
+ const handleFormSubmit = (e2) => {
1196
+ e2.preventDefault();
1197
+ void handleSubmit();
1198
+ };
1199
+ return /* @__PURE__ */ React15.createElement("form", { className, role: "form", onSubmit: handleFormSubmit }, title && /* @__PURE__ */ React15.createElement("div", { className: "mb-6" }, /* @__PURE__ */ React15.createElement("h2", { className: "text-xl font-semibold text-foreground mb-2" }, title), subtitle && /* @__PURE__ */ React15.createElement("p", { className: "text-sm text-muted-foreground" }, subtitle)), submissionState.isSubmitted && submissionState.isSuccess && /* @__PURE__ */ React15.createElement(
1200
+ "div",
1201
+ {
1202
+ className: "mb-6 p-4 bg-success-50 border border-success-200 rounded-lg",
1203
+ "data-testid": "success-message"
1204
+ },
1205
+ /* @__PURE__ */ React15.createElement("p", { className: "text-success-800 font-medium" }, "Success!"),
1206
+ /* @__PURE__ */ React15.createElement("p", { className: "text-success-700 text-sm mt-1" }, "Your request has been processed successfully.")
1207
+ ), submissionState.error && /* @__PURE__ */ React15.createElement(
1208
+ "div",
1209
+ {
1210
+ className: "mb-6 p-4 bg-danger-50 border border-danger-200 rounded-lg",
1211
+ "data-testid": "error-message"
1212
+ },
1213
+ /* @__PURE__ */ React15.createElement("p", { className: "text-danger-800 font-medium" }, "Error"),
1214
+ /* @__PURE__ */ React15.createElement("p", { className: "text-danger-700 text-sm mt-1" }, submissionState.error)
1215
+ ), renderFields(), /* @__PURE__ */ React15.createElement("div", { className: "mt-6 flex gap-3 justify-end" }, /* @__PURE__ */ React15.createElement(
1216
+ Button3,
1217
+ {
1218
+ color: "primary",
1219
+ isDisabled: submissionState.isSubmitting,
1220
+ isLoading: submissionState.isSubmitting,
1221
+ type: "submit",
1222
+ ...submitButtonProps
1223
+ },
1224
+ submitButtonText
1225
+ ), showResetButton && /* @__PURE__ */ React15.createElement(
1226
+ Button3,
1227
+ {
1228
+ isDisabled: submissionState.isSubmitting,
1229
+ type: "button",
1230
+ variant: "bordered",
1231
+ onPress: resetForm
1232
+ },
1233
+ resetButtonText
1234
+ )));
1235
+ }
1236
+ export {
1237
+ CheckboxField,
1238
+ ConfigurableForm,
1239
+ DateField,
1240
+ FileField,
1241
+ FormField,
1242
+ FormProvider,
1243
+ HeroHookFormProvider,
1244
+ InputField,
1245
+ RadioGroupField,
1246
+ SelectField,
1247
+ SliderField,
1248
+ SubmitButton,
1249
+ SwitchField,
1250
+ TextareaField,
1251
+ ZodForm,
1252
+ applyServerErrors,
1253
+ useFormHelper,
1254
+ useHeroHookFormDefaults,
1255
+ useZodForm
1256
+ };