@rachelallyson/hero-hook-form 1.2.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,13 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
1
8
  // src/components/Form.tsx
2
- import React13 from "react";
3
- import { Button as Button2 } from "@heroui/react";
9
+ import React16 from "react";
10
+ import { Button as Button3 } from "@heroui/react";
4
11
 
5
12
  // src/hooks/useFormHelper.ts
6
13
  import { useState } from "react";
@@ -68,8 +75,8 @@ function useFormHelper({
68
75
  }
69
76
 
70
77
  // src/components/FormField.tsx
71
- import React12 from "react";
72
- import { useWatch } from "react-hook-form";
78
+ import React15 from "react";
79
+ import { useWatch as useWatch3 } from "react-hook-form";
73
80
 
74
81
  // src/fields/CheckboxField.tsx
75
82
  import React2 from "react";
@@ -196,16 +203,16 @@ function CheckboxField(props) {
196
203
  {
197
204
  control,
198
205
  name,
199
- render: ({ field, fieldState }) => /* @__PURE__ */ React2.createElement("div", { className }, /* @__PURE__ */ React2.createElement(
206
+ render: ({ field: field2, fieldState }) => /* @__PURE__ */ React2.createElement("div", { className }, /* @__PURE__ */ React2.createElement(
200
207
  Checkbox,
201
208
  {
202
209
  ...defaults.checkbox,
203
210
  ...checkboxProps,
204
211
  isDisabled,
205
212
  isInvalid: Boolean(fieldState.error),
206
- isSelected: Boolean(field.value),
207
- onBlur: field.onBlur,
208
- onValueChange: (val) => field.onChange(val)
213
+ isSelected: Boolean(field2.value),
214
+ onBlur: field2.onBlur,
215
+ onValueChange: (val) => field2.onChange(val)
209
216
  },
210
217
  label
211
218
  ), 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),
@@ -214,13 +221,43 @@ function CheckboxField(props) {
214
221
  );
215
222
  }
216
223
 
217
- // src/fields/DateField.tsx
224
+ // src/fields/ConditionalField.tsx
218
225
  import React3 from "react";
226
+ import { useWatch, useFormContext } from "react-hook-form";
227
+ function ConditionalField({
228
+ className,
229
+ config,
230
+ control
231
+ }) {
232
+ const { condition, field: field2 } = config;
233
+ const form = useFormContext();
234
+ const formValues = useWatch({ control });
235
+ const shouldShow = condition(formValues);
236
+ if (!shouldShow) {
237
+ return null;
238
+ }
239
+ return /* @__PURE__ */ React3.createElement("div", { className }, /* @__PURE__ */ React3.createElement(
240
+ FormField,
241
+ {
242
+ config: field2,
243
+ form,
244
+ submissionState: {
245
+ error: void 0,
246
+ isSubmitted: false,
247
+ isSubmitting: false,
248
+ isSuccess: false
249
+ }
250
+ }
251
+ ));
252
+ }
253
+
254
+ // src/fields/DateField.tsx
255
+ import React4 from "react";
219
256
  import { Controller as Controller2 } from "react-hook-form";
220
257
  function CoercedDateInput(props) {
221
- const { dateProps, description, disabled, errorMessage, field, label } = props;
258
+ const { dateProps, description, disabled, errorMessage, field: field2, label } = props;
222
259
  const defaults = useHeroHookFormDefaults();
223
- return /* @__PURE__ */ React3.createElement(
260
+ return /* @__PURE__ */ React4.createElement(
224
261
  DateInput,
225
262
  {
226
263
  ...defaults.dateInput,
@@ -230,9 +267,9 @@ function CoercedDateInput(props) {
230
267
  isDisabled: disabled,
231
268
  isInvalid: Boolean(errorMessage),
232
269
  label,
233
- value: field.value ?? null,
234
- onBlur: field.onBlur,
235
- onChange: field.onChange
270
+ value: field2.value ?? null,
271
+ onBlur: field2.onBlur,
272
+ onChange: field2.onChange
236
273
  }
237
274
  );
238
275
  }
@@ -248,12 +285,12 @@ function DateField(props) {
248
285
  rules,
249
286
  transform
250
287
  } = props;
251
- return /* @__PURE__ */ React3.createElement(
288
+ return /* @__PURE__ */ React4.createElement(
252
289
  Controller2,
253
290
  {
254
291
  control,
255
292
  name,
256
- render: ({ field, fieldState }) => /* @__PURE__ */ React3.createElement("div", { className }, /* @__PURE__ */ React3.createElement(
293
+ render: ({ field: field2, fieldState }) => /* @__PURE__ */ React4.createElement("div", { className }, /* @__PURE__ */ React4.createElement(
257
294
  CoercedDateInput,
258
295
  {
259
296
  dateProps,
@@ -261,8 +298,8 @@ function DateField(props) {
261
298
  disabled: isDisabled,
262
299
  errorMessage: fieldState.error?.message,
263
300
  field: {
264
- ...field,
265
- onChange: (value) => field.onChange(transform ? transform(value) : value)
301
+ ...field2,
302
+ onChange: (value) => field2.onChange(transform ? transform(value) : value)
266
303
  },
267
304
  label
268
305
  }
@@ -272,8 +309,144 @@ function DateField(props) {
272
309
  );
273
310
  }
274
311
 
312
+ // src/fields/DynamicSectionField.tsx
313
+ import React5 from "react";
314
+ import { useWatch as useWatch2, useFormContext as useFormContext2 } from "react-hook-form";
315
+ function DynamicSectionField({
316
+ className,
317
+ config,
318
+ control
319
+ }) {
320
+ const { condition, description, fields, title } = config;
321
+ const form = useFormContext2();
322
+ const formValues = useWatch2({ control });
323
+ const shouldShow = condition(formValues);
324
+ if (!shouldShow) {
325
+ return null;
326
+ }
327
+ return /* @__PURE__ */ React5.createElement("div", { className }, (title || description) && /* @__PURE__ */ React5.createElement("div", { className: "mb-6" }, title && /* @__PURE__ */ React5.createElement("h3", { className: "text-lg font-semibold text-gray-900 mb-2" }, title), description && /* @__PURE__ */ React5.createElement("p", { className: "text-sm text-gray-600" }, description)), /* @__PURE__ */ React5.createElement("div", { className: "space-y-4" }, fields.map((fieldConfig, index) => /* @__PURE__ */ React5.createElement(
328
+ FormField,
329
+ {
330
+ key: `${fieldConfig.name}-${index}`,
331
+ config: fieldConfig,
332
+ form,
333
+ submissionState: {
334
+ error: void 0,
335
+ isSubmitted: false,
336
+ isSubmitting: false,
337
+ isSuccess: false
338
+ }
339
+ }
340
+ ))));
341
+ }
342
+
343
+ // src/fields/FieldArrayField.tsx
344
+ import React6 from "react";
345
+ import { useFieldArray, useFormContext as useFormContext3 } from "react-hook-form";
346
+ import { Button as Button2 } from "@heroui/react";
347
+ function FieldArrayField({
348
+ className,
349
+ config
350
+ }) {
351
+ const {
352
+ addButtonText = "Add Item",
353
+ fields: fieldConfigs,
354
+ max = 10,
355
+ min = 0,
356
+ name,
357
+ removeButtonText = "Remove"
358
+ } = config;
359
+ const form = useFormContext3();
360
+ if (!form || !form.control) {
361
+ return null;
362
+ }
363
+ const { control } = form;
364
+ const { append, fields, remove } = useFieldArray({
365
+ control,
366
+ name
367
+ // FieldArray name
368
+ });
369
+ const canAdd = fields.length < max;
370
+ const canRemove = fields.length > min;
371
+ const handleAdd = () => {
372
+ if (canAdd) {
373
+ const defaultValues = fieldConfigs.reduce((acc, fieldConfig) => {
374
+ const fieldName = fieldConfig.name;
375
+ if (fieldConfig.type === "checkbox" || fieldConfig.type === "switch") {
376
+ acc[fieldName] = false;
377
+ } else if (fieldConfig.type === "slider") {
378
+ acc[fieldName] = 0;
379
+ } else {
380
+ acc[fieldName] = "";
381
+ }
382
+ return acc;
383
+ }, {});
384
+ append(defaultValues);
385
+ }
386
+ };
387
+ const handleRemove = (index) => {
388
+ if (canRemove) {
389
+ remove(index);
390
+ }
391
+ };
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
+ {
395
+ key: field2.id,
396
+ className: "border border-gray-200 rounded-lg p-4 space-y-4"
397
+ },
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}`
407
+ },
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
+ }
425
+ }
426
+ )))
427
+ )), canAdd && /* @__PURE__ */ React6.createElement(
428
+ Button2,
429
+ {
430
+ variant: "bordered",
431
+ startContent: "\u2795",
432
+ onPress: handleAdd,
433
+ className: "w-full"
434
+ },
435
+ addButtonText
436
+ ), fields.length === 0 && /* @__PURE__ */ React6.createElement("div", { className: "text-center py-8 text-gray-500" }, /* @__PURE__ */ React6.createElement("p", null, "No ", config.label?.toLowerCase(), " added yet."), /* @__PURE__ */ React6.createElement(
437
+ Button2,
438
+ {
439
+ variant: "bordered",
440
+ startContent: "\u2795",
441
+ onPress: handleAdd,
442
+ className: "mt-2"
443
+ },
444
+ addButtonText
445
+ ))));
446
+ }
447
+
275
448
  // src/fields/FileField.tsx
276
- import React4 from "react";
449
+ import React7 from "react";
277
450
  import { Controller as Controller3 } from "react-hook-form";
278
451
  function CoercedFileInput(props) {
279
452
  const {
@@ -281,13 +454,13 @@ function CoercedFileInput(props) {
281
454
  description,
282
455
  disabled,
283
456
  errorMessage,
284
- field,
457
+ field: field2,
285
458
  fileProps,
286
459
  label,
287
460
  multiple
288
461
  } = props;
289
462
  const defaults = useHeroHookFormDefaults();
290
- return /* @__PURE__ */ React4.createElement(
463
+ return /* @__PURE__ */ React7.createElement(
291
464
  Input,
292
465
  {
293
466
  ...defaults.input,
@@ -300,11 +473,11 @@ function CoercedFileInput(props) {
300
473
  label,
301
474
  multiple,
302
475
  type: "file",
303
- value: field.value ? "" : "",
304
- onBlur: field.onBlur,
476
+ value: field2.value ? "" : "",
477
+ onBlur: field2.onBlur,
305
478
  onChange: (e) => {
306
479
  const target = e.target;
307
- field.onChange(target.files);
480
+ field2.onChange(target.files);
308
481
  }
309
482
  }
310
483
  );
@@ -323,12 +496,12 @@ function FileField(props) {
323
496
  rules,
324
497
  transform
325
498
  } = props;
326
- return /* @__PURE__ */ React4.createElement(
499
+ return /* @__PURE__ */ React7.createElement(
327
500
  Controller3,
328
501
  {
329
502
  control,
330
503
  name,
331
- render: ({ field, fieldState }) => /* @__PURE__ */ React4.createElement("div", { className }, /* @__PURE__ */ React4.createElement(
504
+ render: ({ field: field2, fieldState }) => /* @__PURE__ */ React7.createElement("div", { className }, /* @__PURE__ */ React7.createElement(
332
505
  CoercedFileInput,
333
506
  {
334
507
  accept,
@@ -336,8 +509,8 @@ function FileField(props) {
336
509
  disabled: isDisabled,
337
510
  errorMessage: fieldState.error?.message,
338
511
  field: {
339
- ...field,
340
- onChange: (value) => field.onChange(transform ? transform(value) : value)
512
+ ...field2,
513
+ onChange: (value) => field2.onChange(transform ? transform(value) : value)
341
514
  },
342
515
  fileProps,
343
516
  label,
@@ -350,7 +523,7 @@ function FileField(props) {
350
523
  }
351
524
 
352
525
  // src/fields/FontPickerField.tsx
353
- import React5 from "react";
526
+ import React8 from "react";
354
527
  import { Controller as Controller4 } from "react-hook-form";
355
528
  var FontPickerComponent = null;
356
529
  var fontPickerLoaded = false;
@@ -367,17 +540,17 @@ function FontPickerField(props) {
367
540
  name,
368
541
  rules
369
542
  } = props;
370
- const [fontPickerState, setFontPickerState] = React5.useState({
543
+ const [fontPickerState, setFontPickerState] = React8.useState({
371
544
  component: FontPickerComponent,
372
- loading: false,
373
- error: null
545
+ error: null,
546
+ loading: false
374
547
  });
375
- React5.useEffect(() => {
548
+ React8.useEffect(() => {
376
549
  if (fontPickerLoaded && FontPickerComponent) {
377
550
  setFontPickerState({
378
551
  component: FontPickerComponent,
379
- loading: false,
380
- error: null
552
+ error: null,
553
+ loading: false
381
554
  });
382
555
  return;
383
556
  }
@@ -387,14 +560,14 @@ function FontPickerField(props) {
387
560
  if (fontPickerLoaded && FontPickerComponent) {
388
561
  setFontPickerState({
389
562
  component: FontPickerComponent,
390
- loading: false,
391
- error: null
563
+ error: null,
564
+ loading: false
392
565
  });
393
566
  } else {
394
567
  setFontPickerState({
395
568
  component: null,
396
- loading: false,
397
- error: "Font picker package not found"
569
+ error: "Font picker package not found",
570
+ loading: false
398
571
  });
399
572
  }
400
573
  };
@@ -411,17 +584,17 @@ function FontPickerField(props) {
411
584
  fontPickerLoading = false;
412
585
  setFontPickerState({
413
586
  component: FontPickerComponent,
414
- loading: false,
415
- error: null
587
+ error: null,
588
+ loading: false
416
589
  });
417
590
  loadingCallbacks.forEach((callback) => callback());
418
591
  loadingCallbacks.length = 0;
419
- } catch (error) {
592
+ } catch {
420
593
  fontPickerLoading = false;
421
594
  setFontPickerState({
422
595
  component: null,
423
- loading: false,
424
- error: "Font picker package not found"
596
+ error: "Font picker package not found",
597
+ loading: false
425
598
  });
426
599
  loadingCallbacks.forEach((callback) => callback());
427
600
  loadingCallbacks.length = 0;
@@ -430,23 +603,23 @@ function FontPickerField(props) {
430
603
  void loadFontPicker();
431
604
  }, []);
432
605
  if (fontPickerState.loading) {
433
- return /* @__PURE__ */ React5.createElement("div", { className }, /* @__PURE__ */ React5.createElement("div", { className: "space-y-2" }, label && /* @__PURE__ */ React5.createElement("label", { className: "block text-sm font-medium text-foreground" }, label), description && /* @__PURE__ */ React5.createElement("p", { className: "text-sm text-muted-foreground" }, description), /* @__PURE__ */ React5.createElement("div", { className: "p-4 border border-default-200 bg-default-50 rounded-medium" }, /* @__PURE__ */ React5.createElement("p", { className: "text-default-600 text-sm" }, "Loading font picker..."))));
606
+ return /* @__PURE__ */ React8.createElement("div", { className }, /* @__PURE__ */ React8.createElement("div", { className: "space-y-2" }, label && /* @__PURE__ */ React8.createElement("label", { className: "block text-sm font-medium text-foreground" }, label), description && /* @__PURE__ */ React8.createElement("p", { className: "text-sm text-muted-foreground" }, description), /* @__PURE__ */ React8.createElement("div", { className: "p-4 border border-default-200 bg-default-50 rounded-medium" }, /* @__PURE__ */ React8.createElement("p", { className: "text-default-600 text-sm" }, "Loading font picker..."))));
434
607
  }
435
608
  if (!fontPickerState.component) {
436
- return /* @__PURE__ */ React5.createElement("div", { className }, /* @__PURE__ */ React5.createElement("div", { className: "space-y-2" }, label && /* @__PURE__ */ React5.createElement("label", { className: "block text-sm font-medium text-foreground" }, label), description && /* @__PURE__ */ React5.createElement("p", { className: "text-sm text-muted-foreground" }, description), /* @__PURE__ */ React5.createElement("div", { className: "p-4 border border-warning-200 bg-warning-50 rounded-medium" }, /* @__PURE__ */ React5.createElement("p", { className: "text-warning-800 text-sm" }, "Font picker requires the @rachelallyson/heroui-font-picker package. Please install it as a peer dependency for advanced font selection features."))));
609
+ return /* @__PURE__ */ React8.createElement("div", { className }, /* @__PURE__ */ React8.createElement("div", { className: "space-y-2" }, label && /* @__PURE__ */ React8.createElement("label", { className: "block text-sm font-medium text-foreground" }, label), description && /* @__PURE__ */ React8.createElement("p", { className: "text-sm text-muted-foreground" }, description), /* @__PURE__ */ React8.createElement("div", { className: "p-4 border border-warning-200 bg-warning-50 rounded-medium" }, /* @__PURE__ */ React8.createElement("p", { className: "text-warning-800 text-sm" }, "Font picker requires the @rachelallyson/heroui-font-picker package. Please install it as a peer dependency for advanced font selection features."))));
437
610
  }
438
- return /* @__PURE__ */ React5.createElement(
611
+ return /* @__PURE__ */ React8.createElement(
439
612
  Controller4,
440
613
  {
441
614
  control,
442
615
  name,
443
- render: ({ field, fieldState }) => /* @__PURE__ */ React5.createElement(
616
+ render: ({ field: field2, fieldState }) => /* @__PURE__ */ React8.createElement(
444
617
  fontPickerState.component,
445
618
  {
446
619
  label,
447
620
  description,
448
- value: field.value ?? "",
449
- onSelectionChange: (value) => field.onChange(value),
621
+ value: field2.value ?? "",
622
+ onSelectionChange: (value) => field2.onChange(value),
450
623
  errorMessage: fieldState.error?.message,
451
624
  isDisabled,
452
625
  className,
@@ -459,12 +632,12 @@ function FontPickerField(props) {
459
632
  }
460
633
 
461
634
  // src/fields/InputField.tsx
462
- import React6 from "react";
635
+ import React9 from "react";
463
636
  import { Controller as Controller5 } from "react-hook-form";
464
637
  function CoercedInput(props) {
465
- const { description, disabled, errorMessage, field, inputProps, label } = props;
638
+ const { description, disabled, errorMessage, field: field2, inputProps, label } = props;
466
639
  const defaults = useHeroHookFormDefaults();
467
- return /* @__PURE__ */ React6.createElement(
640
+ return /* @__PURE__ */ React9.createElement(
468
641
  Input,
469
642
  {
470
643
  ...defaults.input,
@@ -474,59 +647,61 @@ function CoercedInput(props) {
474
647
  isDisabled: disabled,
475
648
  isInvalid: Boolean(errorMessage),
476
649
  label,
477
- value: field.value ?? "",
478
- onBlur: field.onBlur,
479
- onValueChange: field.onChange
650
+ value: field2.value ?? "",
651
+ onBlur: field2.onBlur,
652
+ onValueChange: field2.onChange
480
653
  }
481
654
  );
482
655
  }
483
- function InputField(props) {
484
- const {
485
- className,
486
- control,
487
- description,
488
- inputProps,
489
- isDisabled,
490
- label,
491
- name,
492
- rules,
493
- transform
494
- } = props;
495
- return /* @__PURE__ */ React6.createElement(
496
- Controller5,
497
- {
656
+ var InputField = React9.memo(
657
+ (props) => {
658
+ const {
659
+ className,
498
660
  control,
661
+ description,
662
+ inputProps,
663
+ isDisabled,
664
+ label,
499
665
  name,
500
- render: ({ field, fieldState }) => /* @__PURE__ */ React6.createElement("div", { className }, /* @__PURE__ */ React6.createElement(
501
- CoercedInput,
502
- {
503
- description,
504
- disabled: isDisabled,
505
- errorMessage: fieldState.error?.message,
506
- field: {
507
- ...field,
508
- onChange: (value) => {
509
- if (inputProps?.type === "number") {
510
- const numValue = value === "" ? void 0 : Number(value);
511
- field.onChange(
512
- transform ? transform(String(numValue)) : numValue
513
- );
514
- } else {
515
- field.onChange(transform ? transform(value) : value);
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
+ }
516
691
  }
517
- }
518
- },
519
- inputProps,
520
- label
521
- }
522
- )),
523
- rules
524
- }
525
- );
526
- }
692
+ },
693
+ inputProps,
694
+ label
695
+ }
696
+ )),
697
+ rules
698
+ }
699
+ );
700
+ }
701
+ );
527
702
 
528
703
  // src/fields/RadioGroupField.tsx
529
- import React7 from "react";
704
+ import React10 from "react";
530
705
  import { Controller as Controller6 } from "react-hook-form";
531
706
  function RadioGroupField(props) {
532
707
  const {
@@ -541,12 +716,12 @@ function RadioGroupField(props) {
541
716
  rules
542
717
  } = props;
543
718
  const defaults = useHeroHookFormDefaults();
544
- return /* @__PURE__ */ React7.createElement(
719
+ return /* @__PURE__ */ React10.createElement(
545
720
  Controller6,
546
721
  {
547
722
  control,
548
723
  name,
549
- render: ({ field, fieldState }) => /* @__PURE__ */ React7.createElement("div", { className }, /* @__PURE__ */ React7.createElement(
724
+ render: ({ field: field2, fieldState }) => /* @__PURE__ */ React10.createElement("div", { className }, /* @__PURE__ */ React10.createElement(
550
725
  RadioGroup,
551
726
  {
552
727
  ...defaults.radioGroup,
@@ -555,11 +730,11 @@ function RadioGroupField(props) {
555
730
  isDisabled,
556
731
  isInvalid: Boolean(fieldState.error),
557
732
  label,
558
- value: String(field.value ?? ""),
559
- onBlur: field.onBlur,
560
- onValueChange: (val) => field.onChange(val)
733
+ value: String(field2.value ?? ""),
734
+ onBlur: field2.onBlur,
735
+ onValueChange: (val) => field2.onChange(val)
561
736
  },
562
- options.map((opt) => /* @__PURE__ */ React7.createElement(
737
+ options.map((opt) => /* @__PURE__ */ React10.createElement(
563
738
  Radio,
564
739
  {
565
740
  key: String(opt.value),
@@ -568,14 +743,14 @@ function RadioGroupField(props) {
568
743
  },
569
744
  opt.label
570
745
  ))
571
- ), fieldState.error?.message ? /* @__PURE__ */ React7.createElement("p", { className: "text-tiny text-danger mt-1" }, fieldState.error.message) : null),
746
+ ), fieldState.error?.message ? /* @__PURE__ */ React10.createElement("p", { className: "text-tiny text-danger mt-1" }, fieldState.error.message) : null),
572
747
  rules
573
748
  }
574
749
  );
575
750
  }
576
751
 
577
752
  // src/fields/SelectField.tsx
578
- import React8 from "react";
753
+ import React11 from "react";
579
754
  import { Controller as Controller7 } from "react-hook-form";
580
755
  function SelectField(props) {
581
756
  const {
@@ -591,14 +766,14 @@ function SelectField(props) {
591
766
  selectProps
592
767
  } = props;
593
768
  const defaults = useHeroHookFormDefaults();
594
- return /* @__PURE__ */ React8.createElement(
769
+ return /* @__PURE__ */ React11.createElement(
595
770
  Controller7,
596
771
  {
597
772
  control,
598
773
  name,
599
- render: ({ field, fieldState }) => {
600
- const selectedKey = field.value;
601
- return /* @__PURE__ */ React8.createElement("div", { className }, /* @__PURE__ */ React8.createElement(
774
+ render: ({ field: field2, fieldState }) => {
775
+ const selectedKey = field2.value;
776
+ return /* @__PURE__ */ React11.createElement("div", { className }, /* @__PURE__ */ React11.createElement(
602
777
  Select,
603
778
  {
604
779
  ...defaults.select,
@@ -613,10 +788,10 @@ function SelectField(props) {
613
788
  onSelectionChange: (keys) => {
614
789
  const keyArray = Array.from(keys);
615
790
  const next = keyArray[0] ?? "";
616
- field.onChange(next);
791
+ field2.onChange(next);
617
792
  }
618
793
  },
619
- options.map((opt) => /* @__PURE__ */ React8.createElement(
794
+ options.map((opt) => /* @__PURE__ */ React11.createElement(
620
795
  SelectItem,
621
796
  {
622
797
  key: String(opt.value),
@@ -633,12 +808,12 @@ function SelectField(props) {
633
808
  }
634
809
 
635
810
  // src/fields/SliderField.tsx
636
- import React9 from "react";
811
+ import React12 from "react";
637
812
  import { Controller as Controller8 } from "react-hook-form";
638
813
  function CoercedSlider(props) {
639
- const { description, disabled, errorMessage, field, label, sliderProps } = props;
814
+ const { description, disabled, errorMessage, field: field2, label, sliderProps } = props;
640
815
  const defaults = useHeroHookFormDefaults();
641
- return /* @__PURE__ */ React9.createElement(
816
+ return /* @__PURE__ */ React12.createElement(
642
817
  Slider,
643
818
  {
644
819
  ...defaults.slider,
@@ -648,9 +823,9 @@ function CoercedSlider(props) {
648
823
  isDisabled: disabled,
649
824
  isInvalid: Boolean(errorMessage),
650
825
  label,
651
- value: field.value ?? 0,
652
- onBlur: field.onBlur,
653
- onValueChange: field.onChange
826
+ value: field2.value ?? 0,
827
+ onBlur: field2.onBlur,
828
+ onValueChange: field2.onChange
654
829
  }
655
830
  );
656
831
  }
@@ -666,20 +841,20 @@ function SliderField(props) {
666
841
  sliderProps,
667
842
  transform
668
843
  } = props;
669
- return /* @__PURE__ */ React9.createElement(
844
+ return /* @__PURE__ */ React12.createElement(
670
845
  Controller8,
671
846
  {
672
847
  control,
673
848
  name,
674
- render: ({ field, fieldState }) => /* @__PURE__ */ React9.createElement("div", { className }, /* @__PURE__ */ React9.createElement(
849
+ render: ({ field: field2, fieldState }) => /* @__PURE__ */ React12.createElement("div", { className }, /* @__PURE__ */ React12.createElement(
675
850
  CoercedSlider,
676
851
  {
677
852
  description,
678
853
  disabled: isDisabled,
679
854
  errorMessage: fieldState.error?.message,
680
855
  field: {
681
- ...field,
682
- onChange: (value) => field.onChange(transform ? transform(value) : value)
856
+ ...field2,
857
+ onChange: (value) => field2.onChange(transform ? transform(value) : value)
683
858
  },
684
859
  label,
685
860
  sliderProps
@@ -691,7 +866,7 @@ function SliderField(props) {
691
866
  }
692
867
 
693
868
  // src/fields/SwitchField.tsx
694
- import React10 from "react";
869
+ import React13 from "react";
695
870
  import { Controller as Controller9 } from "react-hook-form";
696
871
  function SwitchField(props) {
697
872
  const {
@@ -705,30 +880,30 @@ function SwitchField(props) {
705
880
  switchProps
706
881
  } = props;
707
882
  const defaults = useHeroHookFormDefaults();
708
- return /* @__PURE__ */ React10.createElement(
883
+ return /* @__PURE__ */ React13.createElement(
709
884
  Controller9,
710
885
  {
711
886
  control,
712
887
  name,
713
- render: ({ field, fieldState }) => /* @__PURE__ */ React10.createElement("div", { className }, /* @__PURE__ */ React10.createElement(
888
+ render: ({ field: field2, fieldState }) => /* @__PURE__ */ React13.createElement("div", { className }, /* @__PURE__ */ React13.createElement(
714
889
  Switch,
715
890
  {
716
891
  ...defaults.switch,
717
892
  ...switchProps,
718
893
  isDisabled,
719
- isSelected: Boolean(field.value),
720
- onBlur: field.onBlur,
721
- onValueChange: (val) => field.onChange(val)
894
+ isSelected: Boolean(field2.value),
895
+ onBlur: field2.onBlur,
896
+ onValueChange: (val) => field2.onChange(val)
722
897
  },
723
898
  label
724
- ), description ? /* @__PURE__ */ React10.createElement("p", { className: "text-small text-default-400" }, description) : null, fieldState.error?.message ? /* @__PURE__ */ React10.createElement("p", { className: "text-tiny text-danger mt-1" }, fieldState.error.message) : null),
899
+ ), description ? /* @__PURE__ */ React13.createElement("p", { className: "text-small text-default-400" }, description) : null, fieldState.error?.message ? /* @__PURE__ */ React13.createElement("p", { className: "text-tiny text-danger mt-1" }, fieldState.error.message) : null),
725
900
  rules
726
901
  }
727
902
  );
728
903
  }
729
904
 
730
905
  // src/fields/TextareaField.tsx
731
- import React11 from "react";
906
+ import React14 from "react";
732
907
  import { Controller as Controller10 } from "react-hook-form";
733
908
  function TextareaField(props) {
734
909
  const {
@@ -742,12 +917,12 @@ function TextareaField(props) {
742
917
  textareaProps
743
918
  } = props;
744
919
  const defaults = useHeroHookFormDefaults();
745
- return /* @__PURE__ */ React11.createElement(
920
+ return /* @__PURE__ */ React14.createElement(
746
921
  Controller10,
747
922
  {
748
923
  control,
749
924
  name,
750
- render: ({ field, fieldState }) => /* @__PURE__ */ React11.createElement("div", { className }, /* @__PURE__ */ React11.createElement(
925
+ render: ({ field: field2, fieldState }) => /* @__PURE__ */ React14.createElement("div", { className }, /* @__PURE__ */ React14.createElement(
751
926
  Textarea,
752
927
  {
753
928
  ...defaults.textarea,
@@ -757,9 +932,9 @@ function TextareaField(props) {
757
932
  isDisabled,
758
933
  isInvalid: Boolean(fieldState.error),
759
934
  label,
760
- value: field.value ?? "",
761
- onBlur: field.onBlur,
762
- onValueChange: field.onChange
935
+ value: field2.value ?? "",
936
+ onBlur: field2.onBlur,
937
+ onValueChange: field2.onChange
763
938
  }
764
939
  )),
765
940
  rules
@@ -768,158 +943,189 @@ function TextareaField(props) {
768
943
  }
769
944
 
770
945
  // src/components/FormField.tsx
771
- function FormField({
772
- config,
773
- form,
774
- submissionState
775
- }) {
776
- const { control } = form;
777
- const watchedValues = useWatch({ control });
778
- if (config.condition && !config.condition(watchedValues)) {
779
- return null;
780
- }
781
- if (config.dependsOn) {
782
- const dependentValue = watchedValues[config.dependsOn];
783
- 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) {
784
953
  return null;
785
954
  }
786
- }
787
- const baseProps = {
788
- ariaDescribedBy: config.ariaDescribedBy,
789
- ariaLabel: config.ariaLabel,
790
- className: config.className,
791
- description: config.description,
792
- isDisabled: config.isDisabled ?? submissionState.isSubmitting,
793
- label: config.label,
794
- name: config.name,
795
- rules: config.rules
796
- };
797
- switch (config.type) {
798
- case "input":
799
- return /* @__PURE__ */ React12.createElement(
800
- InputField,
801
- {
802
- ...baseProps,
803
- control,
804
- defaultValue: config.defaultValue,
805
- inputProps: config.inputProps
806
- }
807
- );
808
- case "textarea":
809
- return /* @__PURE__ */ React12.createElement(
810
- TextareaField,
811
- {
812
- ...baseProps,
813
- control,
814
- defaultValue: config.defaultValue,
815
- textareaProps: config.textareaProps
816
- }
817
- );
818
- case "select":
819
- return /* @__PURE__ */ React12.createElement(
820
- SelectField,
821
- {
822
- ...baseProps,
823
- control,
824
- defaultValue: config.defaultValue,
825
- options: (config.options ?? []).map((opt) => ({
826
- label: opt.label,
827
- value: String(opt.value)
828
- })),
829
- selectProps: config.selectProps
830
- }
831
- );
832
- case "checkbox":
833
- return /* @__PURE__ */ React12.createElement(
834
- CheckboxField,
835
- {
836
- ...baseProps,
837
- checkboxProps: config.checkboxProps,
838
- control,
839
- defaultValue: config.defaultValue
840
- }
841
- );
842
- case "radio":
843
- return /* @__PURE__ */ React12.createElement(
844
- RadioGroupField,
845
- {
846
- ...baseProps,
847
- control,
848
- defaultValue: config.defaultValue,
849
- options: (config.radioOptions ?? []).map((opt) => ({
850
- label: opt.label,
851
- value: String(opt.value)
852
- })),
853
- radioGroupProps: config.radioProps
854
- }
855
- );
856
- case "switch":
857
- return /* @__PURE__ */ React12.createElement(
858
- SwitchField,
859
- {
860
- ...baseProps,
861
- control,
862
- defaultValue: config.defaultValue,
863
- switchProps: config.switchProps
864
- }
865
- );
866
- case "slider":
867
- return /* @__PURE__ */ React12.createElement(
868
- SliderField,
869
- {
870
- ...baseProps,
871
- control,
872
- defaultValue: config.defaultValue,
873
- sliderProps: config.sliderProps
874
- }
875
- );
876
- case "date":
877
- return /* @__PURE__ */ React12.createElement(
878
- DateField,
879
- {
880
- ...baseProps,
881
- control,
882
- dateProps: config.dateProps,
883
- defaultValue: config.defaultValue
884
- }
885
- );
886
- case "file":
887
- return /* @__PURE__ */ React12.createElement(
888
- FileField,
889
- {
890
- ...baseProps,
891
- accept: config.accept,
892
- control,
893
- defaultValue: config.defaultValue,
894
- fileProps: config.fileProps,
895
- multiple: config.multiple
896
- }
897
- );
898
- case "fontPicker":
899
- return /* @__PURE__ */ React12.createElement(
900
- FontPickerField,
901
- {
902
- ...baseProps,
903
- control,
904
- defaultValue: config.defaultValue,
905
- fontPickerProps: config.fontPickerProps
906
- }
907
- );
908
- case "custom":
909
- return config.render({
910
- control,
911
- errors: form.formState.errors,
912
- form,
913
- isSubmitting: submissionState.isSubmitting,
914
- name: config.name
915
- });
916
- default: {
917
- const fieldType = config.type;
918
- console.warn(`Unknown field type: ${fieldType}`);
955
+ const { control } = form;
956
+ const watchedValues = useWatch3({ control });
957
+ if (config.condition && !config.condition(watchedValues)) {
919
958
  return null;
920
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
+ }
921
1127
  }
922
- }
1128
+ );
923
1129
 
924
1130
  // src/components/Form.tsx
925
1131
  function ConfigurableForm({
@@ -956,16 +1162,16 @@ function ConfigurableForm({
956
1162
  });
957
1163
  const renderFields = () => {
958
1164
  if (layout === "grid") {
959
- return /* @__PURE__ */ React13.createElement(
1165
+ return /* @__PURE__ */ React16.createElement(
960
1166
  "div",
961
1167
  {
962
1168
  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"}`
963
1169
  },
964
- fields.map((field) => /* @__PURE__ */ React13.createElement(
1170
+ fields.map((field2) => /* @__PURE__ */ React16.createElement(
965
1171
  FormField,
966
1172
  {
967
- key: field.name,
968
- config: field,
1173
+ key: field2.name,
1174
+ config: field2,
969
1175
  form,
970
1176
  submissionState
971
1177
  }
@@ -973,21 +1179,21 @@ function ConfigurableForm({
973
1179
  );
974
1180
  }
975
1181
  if (layout === "horizontal") {
976
- return /* @__PURE__ */ React13.createElement("div", { className: `grid gap-${spacing} grid-cols-1 md:grid-cols-2` }, fields.map((field) => /* @__PURE__ */ React13.createElement(
1182
+ return /* @__PURE__ */ React16.createElement("div", { className: `grid gap-${spacing} grid-cols-1 md:grid-cols-2` }, fields.map((field2) => /* @__PURE__ */ React16.createElement(
977
1183
  FormField,
978
1184
  {
979
- key: field.name,
980
- config: field,
1185
+ key: field2.name,
1186
+ config: field2,
981
1187
  form,
982
1188
  submissionState
983
1189
  }
984
1190
  )));
985
1191
  }
986
- return /* @__PURE__ */ React13.createElement("div", { className: `space-y-${spacing}` }, fields.map((field) => /* @__PURE__ */ React13.createElement(
1192
+ return /* @__PURE__ */ React16.createElement("div", { className: `space-y-${spacing}` }, fields.map((field2) => /* @__PURE__ */ React16.createElement(
987
1193
  FormField,
988
1194
  {
989
- key: field.name,
990
- config: field,
1195
+ key: field2.name,
1196
+ config: field2,
991
1197
  form,
992
1198
  submissionState
993
1199
  }
@@ -997,24 +1203,24 @@ function ConfigurableForm({
997
1203
  e.preventDefault();
998
1204
  void handleSubmit();
999
1205
  };
1000
- return /* @__PURE__ */ React13.createElement("form", { className, role: "form", onSubmit: handleFormSubmit }, title && /* @__PURE__ */ React13.createElement("div", { className: "mb-6" }, /* @__PURE__ */ React13.createElement("h2", { className: "text-xl font-semibold text-foreground mb-2" }, title), subtitle && /* @__PURE__ */ React13.createElement("p", { className: "text-sm text-muted-foreground" }, subtitle)), isSubmitted && isSuccess && /* @__PURE__ */ React13.createElement(
1206
+ return /* @__PURE__ */ React16.createElement("form", { className, role: "form", onSubmit: handleFormSubmit }, title && /* @__PURE__ */ React16.createElement("div", { className: "mb-6" }, /* @__PURE__ */ React16.createElement("h2", { className: "text-xl font-semibold text-foreground mb-2" }, title), subtitle && /* @__PURE__ */ React16.createElement("p", { className: "text-sm text-muted-foreground" }, subtitle)), isSubmitted && isSuccess && /* @__PURE__ */ React16.createElement(
1001
1207
  "div",
1002
1208
  {
1003
1209
  className: "mb-6 p-4 bg-success-50 border border-success-200 rounded-lg",
1004
1210
  "data-testid": "success-message"
1005
1211
  },
1006
- /* @__PURE__ */ React13.createElement("p", { className: "text-success-800 font-medium" }, "Success!"),
1007
- /* @__PURE__ */ React13.createElement("p", { className: "text-success-700 text-sm mt-1" }, "Your request has been processed successfully.")
1008
- ), error && /* @__PURE__ */ React13.createElement(
1212
+ /* @__PURE__ */ React16.createElement("p", { className: "text-success-800 font-medium" }, "Success!"),
1213
+ /* @__PURE__ */ React16.createElement("p", { className: "text-success-700 text-sm mt-1" }, "Your request has been processed successfully.")
1214
+ ), error && /* @__PURE__ */ React16.createElement(
1009
1215
  "div",
1010
1216
  {
1011
1217
  className: "mb-6 p-4 bg-danger-50 border border-danger-200 rounded-lg",
1012
1218
  "data-testid": "error-message"
1013
1219
  },
1014
- /* @__PURE__ */ React13.createElement("p", { className: "text-danger-800 font-medium" }, "Error"),
1015
- /* @__PURE__ */ React13.createElement("p", { className: "text-danger-700 text-sm mt-1" }, error)
1016
- ), renderFields(), /* @__PURE__ */ React13.createElement("div", { className: "mt-6 flex gap-3 justify-end" }, /* @__PURE__ */ React13.createElement(
1017
- Button2,
1220
+ /* @__PURE__ */ React16.createElement("p", { className: "text-danger-800 font-medium" }, "Error"),
1221
+ /* @__PURE__ */ React16.createElement("p", { className: "text-danger-700 text-sm mt-1" }, error)
1222
+ ), renderFields(), /* @__PURE__ */ React16.createElement("div", { className: "mt-6 flex gap-3 justify-end" }, /* @__PURE__ */ React16.createElement(
1223
+ Button3,
1018
1224
  {
1019
1225
  color: "primary",
1020
1226
  isDisabled: isSubmitting,
@@ -1023,8 +1229,8 @@ function ConfigurableForm({
1023
1229
  ...submitButtonProps
1024
1230
  },
1025
1231
  submitButtonText
1026
- ), showResetButton && /* @__PURE__ */ React13.createElement(
1027
- Button2,
1232
+ ), showResetButton && /* @__PURE__ */ React16.createElement(
1233
+ Button3,
1028
1234
  {
1029
1235
  isDisabled: isSubmitting,
1030
1236
  type: "button",
@@ -1035,10 +1241,338 @@ function ConfigurableForm({
1035
1241
  )));
1036
1242
  }
1037
1243
 
1244
+ // src/components/ServerActionForm.tsx
1245
+ import React17 from "react";
1246
+ import {
1247
+ Button as Button4,
1248
+ Checkbox as Checkbox2,
1249
+ Input as Input2,
1250
+ Select as Select2,
1251
+ SelectItem as SelectItem2,
1252
+ Textarea as Textarea2
1253
+ } from "@heroui/react";
1254
+ import { useActionState } from "react";
1255
+ function ServerActionForm({
1256
+ action,
1257
+ className,
1258
+ clientValidationSchema,
1259
+ columns = 1,
1260
+ defaultValues,
1261
+ fields,
1262
+ initialState,
1263
+ layout = "vertical",
1264
+ onError,
1265
+ onSuccess,
1266
+ resetButtonText = "Reset",
1267
+ showResetButton = false,
1268
+ spacing = "4",
1269
+ submitButtonProps = {},
1270
+ submitButtonText = "Submit",
1271
+ subtitle,
1272
+ title
1273
+ }) {
1274
+ const [state, formAction, pending] = useActionState(
1275
+ action,
1276
+ initialState ?? { errors: void 0, message: void 0, success: false }
1277
+ );
1278
+ const formRef = React17.useRef(null);
1279
+ const [clientErrors, setClientErrors] = React17.useState({});
1280
+ const lastSubmittedFormData = React17.useRef(null);
1281
+ React17.useEffect(() => {
1282
+ if (state && (state.errors || state.message && !state.success)) {
1283
+ onError?.({
1284
+ errors: state.errors,
1285
+ message: state.message
1286
+ });
1287
+ }
1288
+ }, [state, onError]);
1289
+ React17.useEffect(() => {
1290
+ if (state?.success && lastSubmittedFormData.current) {
1291
+ onSuccess?.(lastSubmittedFormData.current);
1292
+ }
1293
+ }, [state?.success, onSuccess]);
1294
+ const handleReset = () => {
1295
+ formRef.current?.reset();
1296
+ setClientErrors({});
1297
+ };
1298
+ const handleSubmit = async (e) => {
1299
+ e.preventDefault();
1300
+ if (clientValidationSchema) {
1301
+ const formData2 = new FormData(e.currentTarget);
1302
+ const values = {};
1303
+ formData2.forEach((val, key) => {
1304
+ if (val === "on") {
1305
+ values[key] = true;
1306
+ } else if (val === "") {
1307
+ if (!values[key]) {
1308
+ values[key] = false;
1309
+ }
1310
+ } else {
1311
+ values[key] = val;
1312
+ }
1313
+ });
1314
+ const result = clientValidationSchema.safeParse(values);
1315
+ if (!result.success) {
1316
+ const errors = {};
1317
+ result.error.issues.forEach((issue) => {
1318
+ const path = issue.path.join(".");
1319
+ errors[path] = issue.message;
1320
+ });
1321
+ setClientErrors((prev) => ({ ...prev, ...errors }));
1322
+ return;
1323
+ }
1324
+ setClientErrors({});
1325
+ }
1326
+ const formData = new FormData(e.currentTarget);
1327
+ lastSubmittedFormData.current = formData;
1328
+ formAction(formData);
1329
+ };
1330
+ const renderFields = () => {
1331
+ if (layout === "grid") {
1332
+ return /* @__PURE__ */ React17.createElement(
1333
+ "div",
1334
+ {
1335
+ className: `grid gap-${spacing} ${columns === 1 ? "grid-cols-1" : columns === 2 ? "grid-cols-1 md:grid-cols-2" : "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"}`
1336
+ },
1337
+ fields.map((field2) => /* @__PURE__ */ React17.createElement(
1338
+ ServerActionField,
1339
+ {
1340
+ key: field2.name,
1341
+ clientErrors,
1342
+ defaultValues,
1343
+ errors: state?.errors,
1344
+ field: field2
1345
+ }
1346
+ ))
1347
+ );
1348
+ }
1349
+ if (layout === "horizontal") {
1350
+ return /* @__PURE__ */ React17.createElement("div", { className: `grid gap-${spacing} grid-cols-1 md:grid-cols-2` }, fields.map((field2) => /* @__PURE__ */ React17.createElement(
1351
+ ServerActionField,
1352
+ {
1353
+ key: field2.name,
1354
+ clientErrors,
1355
+ defaultValues,
1356
+ errors: state?.errors,
1357
+ field: field2
1358
+ }
1359
+ )));
1360
+ }
1361
+ return /* @__PURE__ */ React17.createElement("div", { className: `space-y-${spacing}` }, fields.map((field2) => /* @__PURE__ */ React17.createElement(
1362
+ ServerActionField,
1363
+ {
1364
+ key: field2.name,
1365
+ clientErrors,
1366
+ defaultValues,
1367
+ errors: state?.errors,
1368
+ field: field2
1369
+ }
1370
+ )));
1371
+ };
1372
+ return /* @__PURE__ */ React17.createElement(
1373
+ "form",
1374
+ {
1375
+ ref: formRef,
1376
+ className,
1377
+ role: "form",
1378
+ onSubmit: handleSubmit
1379
+ },
1380
+ title && /* @__PURE__ */ React17.createElement("div", { className: "mb-6" }, /* @__PURE__ */ React17.createElement("h2", { className: "text-xl font-semibold text-foreground mb-2" }, title), subtitle && /* @__PURE__ */ React17.createElement("p", { className: "text-sm text-muted-foreground" }, subtitle)),
1381
+ state?.success && !pending && /* @__PURE__ */ React17.createElement(
1382
+ "div",
1383
+ {
1384
+ className: "mb-6 p-4 bg-success-50 border border-success-200 rounded-lg",
1385
+ "data-testid": "success-message"
1386
+ },
1387
+ /* @__PURE__ */ React17.createElement("p", { className: "text-success-800 font-medium" }, "Success!"),
1388
+ state.message && /* @__PURE__ */ React17.createElement("p", { className: "text-success-700 text-sm mt-1" }, state.message)
1389
+ ),
1390
+ state?.message && !state.success && /* @__PURE__ */ React17.createElement(
1391
+ "div",
1392
+ {
1393
+ className: "mb-6 p-4 bg-danger-50 border border-danger-200 rounded-lg",
1394
+ "data-testid": "error-message"
1395
+ },
1396
+ /* @__PURE__ */ React17.createElement("p", { className: "text-danger-800 font-medium" }, "Error"),
1397
+ /* @__PURE__ */ React17.createElement("p", { className: "text-danger-700 text-sm mt-1" }, state.message)
1398
+ ),
1399
+ renderFields(),
1400
+ /* @__PURE__ */ React17.createElement("div", { className: "mt-6 flex gap-3 justify-end" }, /* @__PURE__ */ React17.createElement(
1401
+ Button4,
1402
+ {
1403
+ color: "primary",
1404
+ isDisabled: pending,
1405
+ isLoading: pending,
1406
+ type: "submit",
1407
+ ...submitButtonProps
1408
+ },
1409
+ submitButtonText
1410
+ ), showResetButton && /* @__PURE__ */ React17.createElement(
1411
+ Button4,
1412
+ {
1413
+ isDisabled: pending,
1414
+ type: "button",
1415
+ variant: "bordered",
1416
+ onPress: handleReset
1417
+ },
1418
+ resetButtonText
1419
+ ))
1420
+ );
1421
+ }
1422
+ function ServerActionField({
1423
+ clientErrors,
1424
+ defaultValues,
1425
+ errors,
1426
+ field: field2
1427
+ }) {
1428
+ const fieldName = field2.name;
1429
+ const fieldErrors = errors?.[fieldName];
1430
+ const clientError = clientErrors?.[fieldName];
1431
+ const errorMessage = clientError || (fieldErrors && fieldErrors.length > 0 ? fieldErrors[0] : void 0);
1432
+ const getDefaultValue = () => {
1433
+ const fromProps = defaultValues?.[fieldName];
1434
+ const fromField = field2.defaultValue;
1435
+ if (fromProps !== void 0 && fromProps !== null) {
1436
+ return typeof fromProps === "string" ? fromProps : String(fromProps);
1437
+ }
1438
+ if (fromField !== void 0 && fromField !== null) {
1439
+ return typeof fromField === "string" ? fromField : String(fromField);
1440
+ }
1441
+ return "";
1442
+ };
1443
+ const getDefaultChecked = () => {
1444
+ const fromProps = defaultValues?.[fieldName];
1445
+ const fromField = field2.defaultValue;
1446
+ if (fromProps !== void 0 && fromProps !== null) {
1447
+ return typeof fromProps === "boolean" ? fromProps : false;
1448
+ }
1449
+ if (fromField !== void 0 && fromField !== null) {
1450
+ return typeof fromField === "boolean" ? fromField : false;
1451
+ }
1452
+ return false;
1453
+ };
1454
+ const [value, setValue] = React17.useState(getDefaultValue);
1455
+ const [checked, setChecked] = React17.useState(getDefaultChecked);
1456
+ React17.useEffect(() => {
1457
+ const newDefaultValue = defaultValues?.[fieldName];
1458
+ if (newDefaultValue !== void 0 && newDefaultValue !== null) {
1459
+ if (field2.type === "checkbox") {
1460
+ setChecked(
1461
+ typeof newDefaultValue === "boolean" ? newDefaultValue : false
1462
+ );
1463
+ } else {
1464
+ setValue(
1465
+ typeof newDefaultValue === "string" ? newDefaultValue : String(newDefaultValue)
1466
+ );
1467
+ }
1468
+ }
1469
+ }, [defaultValues, fieldName, field2.type]);
1470
+ React17.useEffect(() => {
1471
+ const hiddenInput = document.querySelector(
1472
+ `input[type="hidden"][name="${fieldName}"]`
1473
+ );
1474
+ if (hiddenInput) {
1475
+ if (field2.type === "checkbox") {
1476
+ hiddenInput.value = checked ? "on" : "";
1477
+ } else {
1478
+ hiddenInput.value = value;
1479
+ }
1480
+ }
1481
+ }, [value, checked, fieldName, field2.type]);
1482
+ switch (field2.type) {
1483
+ case "input": {
1484
+ const inputType = field2.inputProps?.type || "text";
1485
+ return /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("input", { type: "hidden", name: fieldName, value }), /* @__PURE__ */ React17.createElement(
1486
+ Input2,
1487
+ {
1488
+ ...field2.inputProps,
1489
+ "data-field-name": fieldName,
1490
+ type: inputType,
1491
+ label: field2.label,
1492
+ description: field2.description,
1493
+ isDisabled: field2.isDisabled,
1494
+ isInvalid: Boolean(errorMessage),
1495
+ errorMessage,
1496
+ value,
1497
+ onValueChange: setValue
1498
+ }
1499
+ ));
1500
+ }
1501
+ case "textarea": {
1502
+ return /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("input", { type: "hidden", name: fieldName, value }), /* @__PURE__ */ React17.createElement(
1503
+ Textarea2,
1504
+ {
1505
+ ...field2.textareaProps,
1506
+ "data-field-name": fieldName,
1507
+ label: field2.label,
1508
+ description: field2.description,
1509
+ isDisabled: field2.isDisabled,
1510
+ isInvalid: Boolean(errorMessage),
1511
+ errorMessage,
1512
+ value,
1513
+ onValueChange: setValue
1514
+ }
1515
+ ));
1516
+ }
1517
+ case "checkbox": {
1518
+ return /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("input", { type: "hidden", name: fieldName, value: checked ? "on" : "" }), /* @__PURE__ */ React17.createElement(
1519
+ Checkbox2,
1520
+ {
1521
+ ...field2.checkboxProps,
1522
+ "data-field-name": fieldName,
1523
+ isDisabled: field2.isDisabled,
1524
+ isSelected: checked,
1525
+ onValueChange: setChecked,
1526
+ isInvalid: Boolean(errorMessage),
1527
+ errorMessage
1528
+ },
1529
+ field2.label
1530
+ ));
1531
+ }
1532
+ case "select": {
1533
+ const options = field2.options || [];
1534
+ return /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("input", { type: "hidden", name: fieldName, value }), /* @__PURE__ */ React17.createElement(
1535
+ Select2,
1536
+ {
1537
+ ...field2.selectProps,
1538
+ "data-field-name": fieldName,
1539
+ label: field2.label,
1540
+ description: field2.description,
1541
+ isDisabled: field2.isDisabled,
1542
+ isInvalid: Boolean(errorMessage),
1543
+ errorMessage,
1544
+ selectedKeys: value ? [value] : [],
1545
+ onSelectionChange: (keys) => {
1546
+ const selectedValue = Array.from(keys)[0];
1547
+ setValue(selectedValue || "");
1548
+ }
1549
+ },
1550
+ options.map(
1551
+ (option) => /* @__PURE__ */ React17.createElement(SelectItem2, { key: String(option.value) }, option.label)
1552
+ )
1553
+ ));
1554
+ }
1555
+ default:
1556
+ return /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("input", { type: "hidden", name: fieldName, value }), /* @__PURE__ */ React17.createElement(
1557
+ Input2,
1558
+ {
1559
+ "data-field-name": fieldName,
1560
+ label: field2.label,
1561
+ description: field2.description,
1562
+ isDisabled: field2.isDisabled,
1563
+ isInvalid: Boolean(errorMessage),
1564
+ errorMessage,
1565
+ value,
1566
+ onValueChange: setValue
1567
+ }
1568
+ ));
1569
+ }
1570
+ }
1571
+
1038
1572
  // src/hooks/useHeroForm.ts
1039
- import { useFormContext } from "react-hook-form";
1573
+ import { useFormContext as useFormContext4 } from "react-hook-form";
1040
1574
  function useHeroForm() {
1041
- const form = useFormContext();
1575
+ const form = useFormContext4();
1042
1576
  const defaults = useHeroHookFormDefaults();
1043
1577
  return {
1044
1578
  // All React Hook Form methods and state
@@ -1049,10 +1583,10 @@ function useHeroForm() {
1049
1583
  }
1050
1584
 
1051
1585
  // src/providers/FormProvider.tsx
1052
- import React14 from "react";
1586
+ import React18 from "react";
1053
1587
  import { FormProvider as RHFProvider } from "react-hook-form";
1054
1588
  function FormProvider(props) {
1055
- return /* @__PURE__ */ React14.createElement(RHFProvider, { ...props.methods }, /* @__PURE__ */ React14.createElement(
1589
+ return /* @__PURE__ */ React18.createElement(RHFProvider, { ...props.methods }, /* @__PURE__ */ React18.createElement(
1056
1590
  "form",
1057
1591
  {
1058
1592
  className: props.className,
@@ -1065,22 +1599,42 @@ function FormProvider(props) {
1065
1599
  }
1066
1600
 
1067
1601
  // src/submit/SubmitButton.tsx
1068
- import React15 from "react";
1602
+ import React19 from "react";
1069
1603
  function SubmitButton(props) {
1070
- const ctx = useFormContext2();
1604
+ const ctx = useFormContext5();
1071
1605
  const loading = props.isLoading ?? ctx.formState.isSubmitting;
1606
+ const enhancedState = props.enhancedState;
1072
1607
  const isDisabledFromProps = props.buttonProps?.isDisabled ?? false;
1073
1608
  const isDisabled = Boolean(isDisabledFromProps) || Boolean(loading);
1074
1609
  const defaults = useHeroHookFormDefaults();
1075
- return /* @__PURE__ */ React15.createElement(
1610
+ const getButtonContent = () => {
1611
+ if (enhancedState?.isSuccess) {
1612
+ return /* @__PURE__ */ React19.createElement("span", { className: "inline-flex items-center gap-2" }, "\u2705", props.successText || "Success!");
1613
+ }
1614
+ if (loading) {
1615
+ return /* @__PURE__ */ React19.createElement("span", { className: "inline-flex items-center gap-2" }, "\u23F3", props.loadingText || "Submitting...");
1616
+ }
1617
+ return props.children;
1618
+ };
1619
+ const getButtonColor = () => {
1620
+ if (enhancedState?.isSuccess) {
1621
+ return "success";
1622
+ }
1623
+ if (enhancedState?.isError) {
1624
+ return "danger";
1625
+ }
1626
+ return props.buttonProps?.color || defaults.submitButton.color;
1627
+ };
1628
+ return /* @__PURE__ */ React19.createElement(
1076
1629
  Button,
1077
1630
  {
1078
1631
  type: "submit",
1079
1632
  ...defaults.submitButton,
1080
1633
  ...props.buttonProps,
1081
- isDisabled
1634
+ isDisabled,
1635
+ color: getButtonColor()
1082
1636
  },
1083
- loading ? /* @__PURE__ */ React15.createElement("span", { className: "inline-flex items-center gap-2" }, /* @__PURE__ */ React15.createElement(Spinner, { size: "sm" }), "Submitting\u2026") : props.children
1637
+ getButtonContent()
1084
1638
  );
1085
1639
  }
1086
1640
 
@@ -1220,14 +1774,6 @@ var createPasswordSchema = (minLength = 8) => z.string().min(minLength, `Passwor
1220
1774
  /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/,
1221
1775
  "Password must contain at least one uppercase letter, one lowercase letter, and one number"
1222
1776
  );
1223
- var createConfirmPasswordSchema = (passwordField) => z.string().refine(
1224
- (val) => {
1225
- return true;
1226
- },
1227
- {
1228
- message: "Passwords do not match"
1229
- }
1230
- );
1231
1777
  var createNumberRangeSchema = (min, max, fieldName) => z.number().min(min, `${fieldName} must be at least ${min}`).max(max, `${fieldName} must be no more than ${max}`);
1232
1778
  var createDateSchema = (fieldName) => z.date({ message: `${fieldName} is required` });
1233
1779
  var createFutureDateSchema = (fieldName) => z.date({ message: `${fieldName} is required` }).refine((date) => date > /* @__PURE__ */ new Date(), {
@@ -1246,17 +1792,61 @@ var createFileSchema = (maxSizeInMB = 5, allowedTypes = ["image/jpeg", "image/pn
1246
1792
  var createRequiredCheckboxSchema = (fieldName) => z.boolean().refine((val) => val === true, {
1247
1793
  message: `You must agree to ${fieldName}`
1248
1794
  });
1249
- var createConditionalSchema = (condition, schema, errorMessage = "This field is required") => z.any().refine(
1250
- (val) => {
1251
- return true;
1795
+ var crossFieldValidation = {
1796
+ /**
1797
+ * Conditional required field validation
1798
+ */
1799
+ conditionalRequired: (field2, conditionField, conditionValue) => {
1800
+ return z.object({
1801
+ [conditionField]: z.any(),
1802
+ [field2]: z.string()
1803
+ }).refine(
1804
+ (data) => {
1805
+ if (data[conditionField] === conditionValue) {
1806
+ return data[field2] && data[field2].trim().length > 0;
1807
+ }
1808
+ return true;
1809
+ },
1810
+ {
1811
+ message: "This field is required",
1812
+ path: [field2]
1813
+ }
1814
+ );
1815
+ },
1816
+ /**
1817
+ * Date range validation
1818
+ */
1819
+ dateRange: (startField, endField) => {
1820
+ return z.object({
1821
+ [endField]: z.string(),
1822
+ [startField]: z.string()
1823
+ }).refine(
1824
+ (data) => {
1825
+ const startDate = new Date(data[startField]);
1826
+ const endDate = new Date(data[endField]);
1827
+ return startDate < endDate;
1828
+ },
1829
+ {
1830
+ message: "End date must be after start date",
1831
+ path: [endField]
1832
+ }
1833
+ );
1252
1834
  },
1253
- {
1254
- message: errorMessage
1835
+ /**
1836
+ * Password confirmation validation
1837
+ */
1838
+ passwordConfirmation: (passwordField, confirmField) => {
1839
+ return z.object({
1840
+ [confirmField]: z.string(),
1841
+ [passwordField]: z.string()
1842
+ }).refine((data) => data[passwordField] === data[confirmField], {
1843
+ message: "Passwords do not match",
1844
+ path: [confirmField]
1845
+ });
1255
1846
  }
1256
- );
1847
+ };
1257
1848
  var commonValidations = {
1258
- conditional: (condition, schema, errorMessage) => createConditionalSchema(condition, schema, errorMessage),
1259
- confirmPassword: (passwordField) => createConfirmPasswordSchema(passwordField),
1849
+ confirmPassword: (passwordField, confirmField) => crossFieldValidation.passwordConfirmation(passwordField, confirmField),
1260
1850
  date: (fieldName) => createDateSchema(fieldName),
1261
1851
  email: createEmailSchema(),
1262
1852
  file: (maxSizeInMB, allowedTypes) => createFileSchema(maxSizeInMB, allowedTypes),
@@ -1273,17 +1863,17 @@ var commonValidations = {
1273
1863
  };
1274
1864
 
1275
1865
  // src/index.ts
1276
- import { useFormContext as useFormContext2 } from "react-hook-form";
1866
+ import { useFormContext as useFormContext5 } from "react-hook-form";
1277
1867
 
1278
1868
  // src/components/ZodForm.tsx
1279
- import React16 from "react";
1280
- import { Button as Button3 } from "@heroui/react";
1869
+ import React21 from "react";
1870
+ import { Button as Button6 } from "@heroui/react";
1281
1871
 
1282
1872
  // src/zod-integration.ts
1283
1873
  import { useForm as useForm2 } from "react-hook-form";
1284
1874
  import { z as z2 } from "zod";
1285
1875
  function createZodResolver(schema) {
1286
- return async (values, context) => {
1876
+ return async (values) => {
1287
1877
  try {
1288
1878
  const result = await schema.parseAsync(values);
1289
1879
  return {
@@ -1314,10 +1904,185 @@ function useZodForm(config) {
1314
1904
  }
1315
1905
  function createZodFormConfig(schema, fields, defaultValues) {
1316
1906
  return {
1317
- schema,
1318
1907
  fields,
1319
- ...defaultValues && { defaultValues }
1908
+ schema,
1909
+ ...defaultValues && {
1910
+ defaultValues
1911
+ }
1912
+ };
1913
+ }
1914
+
1915
+ // src/hooks/useEnhancedFormState.ts
1916
+ import { useCallback, useEffect, useState as useState2 } from "react";
1917
+ function useEnhancedFormState(form, options = {}) {
1918
+ const {
1919
+ autoReset = true,
1920
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1921
+ errorMessage: _errorMessage = "An error occurred. Please try again.",
1922
+ onError,
1923
+ onSuccess,
1924
+ resetDelay = 3e3,
1925
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1926
+ successMessage: _successMessage = "Form submitted successfully!"
1927
+ } = options;
1928
+ const [status, setStatus] = useState2("idle");
1929
+ const [error, setError] = useState2(void 0);
1930
+ const [submittedData, setSubmittedData] = useState2(void 0);
1931
+ const { formState, getValues: _getValues } = form;
1932
+ const { dirtyFields, errors, isSubmitting, touchedFields } = formState;
1933
+ useEffect(() => {
1934
+ if (isSubmitting) {
1935
+ setStatus("submitting");
1936
+ }
1937
+ }, [isSubmitting]);
1938
+ useEffect(() => {
1939
+ if (status === "success" && autoReset) {
1940
+ const timer = setTimeout(() => {
1941
+ setStatus("idle");
1942
+ setSubmittedData(void 0);
1943
+ setError(void 0);
1944
+ }, resetDelay);
1945
+ return () => clearTimeout(timer);
1946
+ }
1947
+ }, [status, autoReset, resetDelay]);
1948
+ const handleSuccess = useCallback(
1949
+ (data) => {
1950
+ setStatus("success");
1951
+ setSubmittedData(data);
1952
+ setError(void 0);
1953
+ onSuccess?.(data);
1954
+ },
1955
+ [onSuccess]
1956
+ );
1957
+ const handleError = useCallback(
1958
+ (errorMessage) => {
1959
+ setStatus("error");
1960
+ setError(errorMessage);
1961
+ setSubmittedData(void 0);
1962
+ onError?.(errorMessage);
1963
+ },
1964
+ [onError]
1965
+ );
1966
+ const reset = useCallback(() => {
1967
+ setStatus("idle");
1968
+ setError(void 0);
1969
+ setSubmittedData(void 0);
1970
+ }, []);
1971
+ return {
1972
+ dirtyFields: new Set(Object.keys(dirtyFields)),
1973
+ error,
1974
+ errorCount: Object.keys(errors).length,
1975
+ handleError,
1976
+ handleSuccess,
1977
+ hasErrors: Object.keys(errors).length > 0,
1978
+ isError: status === "error",
1979
+ isSubmitting,
1980
+ isSuccess: status === "success",
1981
+ reset,
1982
+ status,
1983
+ submittedData,
1984
+ touchedFields: new Set(Object.keys(touchedFields))
1985
+ };
1986
+ }
1987
+
1988
+ // src/components/FormStatus.tsx
1989
+ import React20 from "react";
1990
+ import { Button as Button5 } from "@heroui/react";
1991
+ function FormStatus({
1992
+ className = "",
1993
+ onDismiss,
1994
+ showDetails = false,
1995
+ state
1996
+ }) {
1997
+ const { error, isError, isSubmitting, isSuccess, status, submittedData } = state;
1998
+ if (status === "idle") {
1999
+ return null;
2000
+ }
2001
+ if (isSubmitting) {
2002
+ return /* @__PURE__ */ React20.createElement(
2003
+ "div",
2004
+ {
2005
+ className: `flex items-center gap-3 p-4 bg-blue-50 border border-blue-200 rounded-lg ${className}`
2006
+ },
2007
+ /* @__PURE__ */ React20.createElement("span", { className: "text-blue-600" }, "\u23F3"),
2008
+ /* @__PURE__ */ React20.createElement("div", null, /* @__PURE__ */ React20.createElement("p", { className: "text-sm font-medium text-blue-900" }, "Submitting form..."), showDetails && /* @__PURE__ */ React20.createElement("p", { className: "text-xs text-blue-700" }, "Please wait while we process your request."))
2009
+ );
2010
+ }
2011
+ if (isSuccess) {
2012
+ return /* @__PURE__ */ React20.createElement(
2013
+ "div",
2014
+ {
2015
+ className: `flex items-center gap-3 p-4 bg-green-50 border border-green-200 rounded-lg ${className}`,
2016
+ "data-testid": "success-message"
2017
+ },
2018
+ /* @__PURE__ */ React20.createElement("span", { className: "text-green-600" }, "\u2705"),
2019
+ /* @__PURE__ */ React20.createElement("div", { className: "flex-1" }, /* @__PURE__ */ React20.createElement("p", { className: "text-sm font-medium text-green-900" }, "Form submitted successfully!"), showDetails && submittedData && /* @__PURE__ */ React20.createElement("p", { className: "text-xs text-green-700" }, "Your data has been saved. Thank you for your submission.")),
2020
+ onDismiss && /* @__PURE__ */ React20.createElement(
2021
+ Button5,
2022
+ {
2023
+ size: "sm",
2024
+ variant: "light",
2025
+ isIconOnly: true,
2026
+ onPress: onDismiss,
2027
+ "aria-label": "Dismiss success message"
2028
+ },
2029
+ "\u2715"
2030
+ )
2031
+ );
2032
+ }
2033
+ if (isError && error) {
2034
+ return /* @__PURE__ */ React20.createElement(
2035
+ "div",
2036
+ {
2037
+ className: `flex items-center gap-3 p-4 bg-red-50 border border-red-200 rounded-lg ${className}`,
2038
+ "data-testid": "error-message"
2039
+ },
2040
+ /* @__PURE__ */ React20.createElement("span", { className: "text-red-600" }, "\u26A0\uFE0F"),
2041
+ /* @__PURE__ */ React20.createElement("div", { className: "flex-1" }, /* @__PURE__ */ React20.createElement("p", { className: "text-sm font-medium text-red-900" }, "Error submitting form"), /* @__PURE__ */ React20.createElement("p", { className: "text-xs text-red-700" }, error)),
2042
+ onDismiss && /* @__PURE__ */ React20.createElement(
2043
+ Button5,
2044
+ {
2045
+ size: "sm",
2046
+ variant: "light",
2047
+ isIconOnly: true,
2048
+ onPress: onDismiss,
2049
+ "aria-label": "Dismiss error message"
2050
+ },
2051
+ "\u2715"
2052
+ )
2053
+ );
2054
+ }
2055
+ return null;
2056
+ }
2057
+ function FormToast({
2058
+ duration = 5e3,
2059
+ onDismiss,
2060
+ position = "top-right",
2061
+ state
2062
+ }) {
2063
+ const [isVisible, setIsVisible] = React20.useState(false);
2064
+ React20.useEffect(() => {
2065
+ if (state.isSuccess || state.isError) {
2066
+ setIsVisible(true);
2067
+ if (duration > 0) {
2068
+ const timer = setTimeout(() => {
2069
+ setIsVisible(false);
2070
+ onDismiss?.();
2071
+ }, duration);
2072
+ return () => clearTimeout(timer);
2073
+ }
2074
+ }
2075
+ }, [state.isSuccess, state.isError, duration, onDismiss]);
2076
+ if (!isVisible) {
2077
+ return null;
2078
+ }
2079
+ const positionClasses = {
2080
+ "bottom-left": "bottom-4 left-4",
2081
+ "bottom-right": "bottom-4 right-4",
2082
+ "top-left": "top-4 left-4",
2083
+ "top-right": "top-4 right-4"
1320
2084
  };
2085
+ return /* @__PURE__ */ React20.createElement("div", { className: `fixed z-50 ${positionClasses[position]}` }, /* @__PURE__ */ React20.createElement(FormStatus, { state, onDismiss }));
1321
2086
  }
1322
2087
 
1323
2088
  // src/components/ZodForm.tsx
@@ -1325,7 +2090,6 @@ function ZodForm({
1325
2090
  className,
1326
2091
  columns = 1,
1327
2092
  config,
1328
- errorDisplay = "inline",
1329
2093
  layout = "vertical",
1330
2094
  onError,
1331
2095
  onSubmit,
@@ -1340,97 +2104,84 @@ function ZodForm({
1340
2104
  title
1341
2105
  }) {
1342
2106
  const form = useZodForm(config);
1343
- const [submissionState, setSubmissionState] = React16.useState({
1344
- error: void 0,
1345
- isSubmitted: false,
1346
- isSubmitting: false,
1347
- isSuccess: false
2107
+ const enhancedState = useEnhancedFormState(form, {
2108
+ autoReset: true,
2109
+ onError: (error) => onError?.({ field: "form", message: error }),
2110
+ onSuccess,
2111
+ resetDelay: 3e3
1348
2112
  });
1349
2113
  const handleSubmit = async () => {
1350
- setSubmissionState((prev) => ({
1351
- ...prev,
1352
- error: void 0,
1353
- isSubmitting: true
1354
- }));
1355
- const isValid = await form.trigger();
1356
- if (!isValid) {
1357
- setSubmissionState({
1358
- error: "Please fix the validation errors above",
1359
- isSubmitted: true,
1360
- isSubmitting: false,
1361
- isSuccess: false
1362
- });
1363
- return;
1364
- }
1365
2114
  try {
1366
- await form.handleSubmit(async (formData) => {
1367
- await onSubmit(formData);
1368
- })();
1369
- setSubmissionState({
1370
- error: void 0,
1371
- isSubmitted: true,
1372
- isSubmitting: false,
1373
- isSuccess: true
1374
- });
1375
- onSuccess?.(form.getValues());
2115
+ await form.handleSubmit(
2116
+ async (formData) => {
2117
+ await onSubmit(formData);
2118
+ enhancedState.handleSuccess(formData);
2119
+ },
2120
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2121
+ (_errors) => {
2122
+ enhancedState.handleError("Please fix the validation errors above");
2123
+ }
2124
+ )();
1376
2125
  } catch (error) {
1377
2126
  const errorMessage = error instanceof Error ? error.message : "An error occurred";
1378
- setSubmissionState({
1379
- error: errorMessage,
1380
- isSubmitted: true,
1381
- isSubmitting: false,
1382
- isSuccess: false
1383
- });
1384
- onError?.({
1385
- message: errorMessage
1386
- });
2127
+ enhancedState.handleError(errorMessage);
1387
2128
  }
1388
2129
  };
1389
2130
  const resetForm = () => {
1390
2131
  form.reset();
1391
- setSubmissionState({
1392
- error: void 0,
1393
- isSubmitted: false,
1394
- isSubmitting: false,
1395
- isSuccess: false
1396
- });
2132
+ enhancedState.reset();
1397
2133
  };
1398
2134
  const renderFields = () => {
1399
2135
  if (layout === "grid") {
1400
- return /* @__PURE__ */ React16.createElement(
2136
+ return /* @__PURE__ */ React21.createElement(
1401
2137
  "div",
1402
2138
  {
1403
2139
  className: `grid gap-${spacing} ${columns === 1 ? "grid-cols-1" : columns === 2 ? "grid-cols-1 md:grid-cols-2" : "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"}`
1404
2140
  },
1405
- config.fields.map((field) => /* @__PURE__ */ React16.createElement(
2141
+ config.fields.map((field2) => /* @__PURE__ */ React21.createElement(
1406
2142
  FormField,
1407
2143
  {
1408
- key: field.name,
1409
- config: field,
2144
+ key: field2.name,
2145
+ config: field2,
1410
2146
  form,
1411
- submissionState
2147
+ submissionState: {
2148
+ error: enhancedState.error,
2149
+ isSubmitted: enhancedState.status !== "idle",
2150
+ isSubmitting: enhancedState.isSubmitting,
2151
+ isSuccess: enhancedState.isSuccess
2152
+ }
1412
2153
  }
1413
2154
  ))
1414
2155
  );
1415
2156
  }
1416
2157
  if (layout === "horizontal") {
1417
- return /* @__PURE__ */ React16.createElement("div", { className: `grid gap-${spacing} grid-cols-1 md:grid-cols-2` }, config.fields.map((field) => /* @__PURE__ */ React16.createElement(
2158
+ return /* @__PURE__ */ React21.createElement("div", { className: `grid gap-${spacing} grid-cols-1 md:grid-cols-2` }, config.fields.map((field2) => /* @__PURE__ */ React21.createElement(
1418
2159
  FormField,
1419
2160
  {
1420
- key: field.name,
1421
- config: field,
2161
+ key: field2.name,
2162
+ config: field2,
1422
2163
  form,
1423
- submissionState
2164
+ submissionState: {
2165
+ error: enhancedState.error,
2166
+ isSubmitted: enhancedState.status !== "idle",
2167
+ isSubmitting: enhancedState.isSubmitting,
2168
+ isSuccess: enhancedState.isSuccess
2169
+ }
1424
2170
  }
1425
2171
  )));
1426
2172
  }
1427
- return /* @__PURE__ */ React16.createElement("div", { className: `space-y-${spacing}` }, config.fields.map((field) => /* @__PURE__ */ React16.createElement(
2173
+ return /* @__PURE__ */ React21.createElement("div", { className: `space-y-${spacing}` }, config.fields.map((field2) => /* @__PURE__ */ React21.createElement(
1428
2174
  FormField,
1429
2175
  {
1430
- key: field.name,
1431
- config: field,
2176
+ key: field2.name,
2177
+ config: field2,
1432
2178
  form,
1433
- submissionState
2179
+ submissionState: {
2180
+ error: enhancedState.error,
2181
+ isSubmitted: enhancedState.status !== "idle",
2182
+ isSubmitting: enhancedState.isSubmitting,
2183
+ isSuccess: enhancedState.isSuccess
2184
+ }
1434
2185
  }
1435
2186
  )));
1436
2187
  };
@@ -1438,7 +2189,7 @@ function ZodForm({
1438
2189
  e.preventDefault();
1439
2190
  void handleSubmit();
1440
2191
  };
1441
- React16.useEffect(() => {
2192
+ React21.useEffect(() => {
1442
2193
  if (config.onError && Object.keys(form.formState.errors).length > 0) {
1443
2194
  config.onError(form.formState.errors);
1444
2195
  }
@@ -1447,42 +2198,33 @@ function ZodForm({
1447
2198
  return render({
1448
2199
  errors: form.formState.errors,
1449
2200
  form,
1450
- isSubmitted: submissionState.isSubmitted,
1451
- isSubmitting: submissionState.isSubmitting,
1452
- isSuccess: submissionState.isSuccess,
2201
+ isSubmitted: enhancedState.status !== "idle",
2202
+ isSubmitting: enhancedState.isSubmitting,
2203
+ isSuccess: enhancedState.isSuccess,
1453
2204
  values: form.getValues()
1454
2205
  });
1455
2206
  }
1456
- return /* @__PURE__ */ React16.createElement("form", { className, role: "form", onSubmit: handleFormSubmit }, title && /* @__PURE__ */ React16.createElement("div", { className: "mb-6" }, /* @__PURE__ */ React16.createElement("h2", { className: "text-xl font-semibold text-foreground mb-2" }, title), subtitle && /* @__PURE__ */ React16.createElement("p", { className: "text-sm text-muted-foreground" }, subtitle)), submissionState.isSubmitted && submissionState.isSuccess && /* @__PURE__ */ React16.createElement(
1457
- "div",
1458
- {
1459
- className: "mb-6 p-4 bg-success-50 border border-success-200 rounded-lg",
1460
- "data-testid": "success-message"
1461
- },
1462
- /* @__PURE__ */ React16.createElement("p", { className: "text-success-800 font-medium" }, "Success!"),
1463
- /* @__PURE__ */ React16.createElement("p", { className: "text-success-700 text-sm mt-1" }, "Your request has been processed successfully.")
1464
- ), submissionState.error && errorDisplay !== "none" && /* @__PURE__ */ React16.createElement(
1465
- "div",
2207
+ return /* @__PURE__ */ React21.createElement("form", { className, role: "form", onSubmit: handleFormSubmit }, title && /* @__PURE__ */ React21.createElement("div", { className: "mb-6" }, /* @__PURE__ */ React21.createElement("h2", { className: "text-xl font-semibold text-foreground mb-2" }, title), subtitle && /* @__PURE__ */ React21.createElement("p", { className: "text-sm text-muted-foreground" }, subtitle)), /* @__PURE__ */ React21.createElement(
2208
+ FormStatus,
1466
2209
  {
1467
- className: "mb-6 p-4 bg-danger-50 border border-danger-200 rounded-lg",
1468
- "data-testid": "error-message"
1469
- },
1470
- /* @__PURE__ */ React16.createElement("p", { className: "text-danger-800 font-medium" }, "Error"),
1471
- /* @__PURE__ */ React16.createElement("p", { className: "text-danger-700 text-sm mt-1" }, submissionState.error)
1472
- ), renderFields(), /* @__PURE__ */ React16.createElement("div", { className: "mt-6 flex gap-3 justify-end" }, /* @__PURE__ */ React16.createElement(
1473
- Button3,
2210
+ state: enhancedState,
2211
+ onDismiss: () => enhancedState.reset(),
2212
+ showDetails: true
2213
+ }
2214
+ ), renderFields(), /* @__PURE__ */ React21.createElement("div", { className: "mt-6 flex gap-3 justify-end" }, /* @__PURE__ */ React21.createElement(
2215
+ Button6,
1474
2216
  {
1475
2217
  color: "primary",
1476
- isDisabled: submissionState.isSubmitting,
1477
- isLoading: submissionState.isSubmitting,
2218
+ isDisabled: enhancedState.isSubmitting,
2219
+ isLoading: enhancedState.isSubmitting,
1478
2220
  type: "submit",
1479
2221
  ...submitButtonProps
1480
2222
  },
1481
- submitButtonText
1482
- ), showResetButton && /* @__PURE__ */ React16.createElement(
1483
- Button3,
2223
+ enhancedState.isSuccess ? "Success!" : submitButtonText
2224
+ ), showResetButton && /* @__PURE__ */ React21.createElement(
2225
+ Button6,
1484
2226
  {
1485
- isDisabled: submissionState.isSubmitting,
2227
+ isDisabled: enhancedState.isSubmitting,
1486
2228
  type: "button",
1487
2229
  variant: "bordered",
1488
2230
  onPress: resetForm
@@ -1490,29 +2232,1257 @@ function ZodForm({
1490
2232
  resetButtonText
1491
2233
  )));
1492
2234
  }
2235
+
2236
+ // src/builders/BasicFormBuilder.ts
2237
+ var BasicFormBuilder = class {
2238
+ constructor() {
2239
+ this.fields = [];
2240
+ }
2241
+ /**
2242
+ * Add an input field
2243
+ */
2244
+ input(name, label, type = "text") {
2245
+ this.fields.push({
2246
+ inputProps: { type },
2247
+ label,
2248
+ name,
2249
+ type: "input"
2250
+ });
2251
+ return this;
2252
+ }
2253
+ /**
2254
+ * Add a textarea field
2255
+ */
2256
+ textarea(name, label, placeholder) {
2257
+ this.fields.push({
2258
+ label,
2259
+ name,
2260
+ textareaProps: { placeholder },
2261
+ type: "textarea"
2262
+ });
2263
+ return this;
2264
+ }
2265
+ /**
2266
+ * Add a select field
2267
+ */
2268
+ select(name, label, options) {
2269
+ this.fields.push({
2270
+ label,
2271
+ name,
2272
+ options,
2273
+ type: "select"
2274
+ });
2275
+ return this;
2276
+ }
2277
+ /**
2278
+ * Add a checkbox field
2279
+ */
2280
+ checkbox(name, label) {
2281
+ this.fields.push({
2282
+ label,
2283
+ name,
2284
+ type: "checkbox"
2285
+ });
2286
+ return this;
2287
+ }
2288
+ /**
2289
+ * Add a switch field
2290
+ */
2291
+ switch(name, label) {
2292
+ this.fields.push({
2293
+ label,
2294
+ name,
2295
+ type: "switch"
2296
+ });
2297
+ return this;
2298
+ }
2299
+ /**
2300
+ * Build the final field configuration array
2301
+ */
2302
+ build() {
2303
+ return this.fields;
2304
+ }
2305
+ };
2306
+ function createBasicFormBuilder() {
2307
+ return new BasicFormBuilder();
2308
+ }
2309
+ var FormFieldHelpers = {
2310
+ /**
2311
+ * Create a checkbox field
2312
+ */
2313
+ checkbox: (name, label) => ({
2314
+ label,
2315
+ name,
2316
+ type: "checkbox"
2317
+ }),
2318
+ /**
2319
+ * Create an input field
2320
+ */
2321
+ input: (name, label, type = "text") => ({
2322
+ inputProps: { type },
2323
+ label,
2324
+ name,
2325
+ type: "input"
2326
+ }),
2327
+ /**
2328
+ * Create a select field
2329
+ */
2330
+ select: (name, label, options) => ({
2331
+ label,
2332
+ name,
2333
+ options,
2334
+ type: "select"
2335
+ }),
2336
+ /**
2337
+ * Create a switch field
2338
+ */
2339
+ switch: (name, label) => ({
2340
+ label,
2341
+ name,
2342
+ type: "switch"
2343
+ }),
2344
+ /**
2345
+ * Create a textarea field
2346
+ */
2347
+ textarea: (name, label, placeholder) => ({
2348
+ label,
2349
+ name,
2350
+ textareaProps: { placeholder },
2351
+ type: "textarea"
2352
+ })
2353
+ };
2354
+ var CommonFields = {
2355
+ /**
2356
+ * Address fields
2357
+ */
2358
+ address: () => [
2359
+ FormFieldHelpers.input("street", "Street Address"),
2360
+ FormFieldHelpers.input("city", "City"),
2361
+ FormFieldHelpers.input("state", "State/Province"),
2362
+ FormFieldHelpers.input("zipCode", "ZIP/Postal Code"),
2363
+ FormFieldHelpers.select("country", "Country", [
2364
+ { label: "Select a country", value: "" },
2365
+ { label: "United States", value: "us" },
2366
+ { label: "Canada", value: "ca" },
2367
+ { label: "United Kingdom", value: "uk" },
2368
+ { label: "Australia", value: "au" },
2369
+ { label: "Germany", value: "de" },
2370
+ { label: "France", value: "fr" }
2371
+ ])
2372
+ ],
2373
+ /**
2374
+ * Personal information fields
2375
+ */
2376
+ personal: () => [
2377
+ FormFieldHelpers.input("firstName", "First Name"),
2378
+ FormFieldHelpers.input("lastName", "Last Name"),
2379
+ FormFieldHelpers.input("email", "Email", "email"),
2380
+ FormFieldHelpers.input("phone", "Phone", "tel")
2381
+ ],
2382
+ /**
2383
+ * Terms and conditions fields
2384
+ */
2385
+ terms: () => [
2386
+ FormFieldHelpers.checkbox(
2387
+ "terms",
2388
+ "I agree to the terms and conditions"
2389
+ ),
2390
+ FormFieldHelpers.checkbox(
2391
+ "privacy",
2392
+ "I agree to the privacy policy"
2393
+ ),
2394
+ FormFieldHelpers.checkbox(
2395
+ "newsletter",
2396
+ "Subscribe to newsletter"
2397
+ )
2398
+ ]
2399
+ };
2400
+
2401
+ // src/builders/AdvancedFormBuilder.ts
2402
+ function inputField(name, label, props) {
2403
+ return {
2404
+ label,
2405
+ name,
2406
+ type: "input",
2407
+ ...props && {
2408
+ inputProps: {
2409
+ className: props.className,
2410
+ description: props.description,
2411
+ disabled: props.isDisabled,
2412
+ placeholder: props.placeholder,
2413
+ type: props.type || "text"
2414
+ }
2415
+ }
2416
+ };
2417
+ }
2418
+ function textareaField(name, label, props) {
2419
+ return {
2420
+ label,
2421
+ name,
2422
+ type: "textarea",
2423
+ ...props && {
2424
+ textareaProps: {
2425
+ className: props.className,
2426
+ description: props.description,
2427
+ disabled: props.isDisabled,
2428
+ placeholder: props.placeholder,
2429
+ rows: props.rows
2430
+ }
2431
+ }
2432
+ };
2433
+ }
2434
+ function selectField(name, label, options) {
2435
+ return {
2436
+ label,
2437
+ name,
2438
+ options,
2439
+ type: "select"
2440
+ };
2441
+ }
2442
+ function checkboxField(name, label, props) {
2443
+ return {
2444
+ label,
2445
+ name,
2446
+ type: "checkbox",
2447
+ ...props && {
2448
+ checkboxProps: {
2449
+ className: props.className,
2450
+ disabled: props.isDisabled
2451
+ }
2452
+ }
2453
+ };
2454
+ }
2455
+ function switchField(name, label, props) {
2456
+ return {
2457
+ label,
2458
+ name,
2459
+ type: "switch",
2460
+ ...props && {
2461
+ switchProps: {
2462
+ className: props.className,
2463
+ disabled: props.isDisabled
2464
+ }
2465
+ }
2466
+ };
2467
+ }
2468
+ function radioField(name, label, options, props) {
2469
+ return {
2470
+ label,
2471
+ name,
2472
+ radioOptions: options,
2473
+ type: "radio",
2474
+ ...props && {
2475
+ radioProps: {
2476
+ className: props.className,
2477
+ isDisabled: props.isDisabled,
2478
+ orientation: props.orientation
2479
+ }
2480
+ }
2481
+ };
2482
+ }
2483
+ function sliderField(name, label, props) {
2484
+ return {
2485
+ label,
2486
+ name,
2487
+ type: "slider",
2488
+ ...props && {
2489
+ sliderProps: {
2490
+ className: props.className || "",
2491
+ disabled: props.isDisabled || false,
2492
+ max: props.max || 100,
2493
+ min: props.min || 0,
2494
+ step: props.step || 1
2495
+ }
2496
+ }
2497
+ };
2498
+ }
2499
+ function dateField(name, label, props) {
2500
+ return {
2501
+ label,
2502
+ name,
2503
+ type: "date",
2504
+ ...props && {
2505
+ dateProps: {
2506
+ className: props.className || "",
2507
+ disabled: props.isDisabled || false,
2508
+ placeholder: props.placeholder || ""
2509
+ }
2510
+ }
2511
+ };
2512
+ }
2513
+ function fileField(name, label, props) {
2514
+ return {
2515
+ label,
2516
+ name,
2517
+ type: "file",
2518
+ ...props && {
2519
+ fileProps: {
2520
+ accept: props.accept || "",
2521
+ className: props.className || "",
2522
+ disabled: props.isDisabled || false,
2523
+ multiple: props.multiple || false
2524
+ }
2525
+ }
2526
+ };
2527
+ }
2528
+ function fontPickerField(name, label, props) {
2529
+ return {
2530
+ label,
2531
+ name,
2532
+ type: "fontPicker",
2533
+ ...props && {
2534
+ fontPickerProps: {
2535
+ className: props.className || "",
2536
+ disabled: props.isDisabled || false
2537
+ }
2538
+ }
2539
+ };
2540
+ }
2541
+ function createField(type, name, label, optionsOrProps, props) {
2542
+ switch (type) {
2543
+ case "input":
2544
+ return inputField(name, label, optionsOrProps);
2545
+ case "textarea":
2546
+ return textareaField(name, label, optionsOrProps);
2547
+ case "select":
2548
+ return selectField(name, label, optionsOrProps);
2549
+ case "checkbox":
2550
+ return checkboxField(name, label, optionsOrProps);
2551
+ case "switch":
2552
+ return switchField(name, label, optionsOrProps);
2553
+ case "radio":
2554
+ return radioField(name, label, optionsOrProps, props);
2555
+ case "slider":
2556
+ return sliderField(name, label, optionsOrProps);
2557
+ case "date":
2558
+ return dateField(name, label, optionsOrProps);
2559
+ case "file":
2560
+ return fileField(name, label, optionsOrProps);
2561
+ case "fontPicker":
2562
+ return fontPickerField(name, label, optionsOrProps);
2563
+ default:
2564
+ throw new Error(`Unknown field type: ${type}`);
2565
+ }
2566
+ }
2567
+ var AdvancedFieldBuilder = class {
2568
+ constructor() {
2569
+ this.fields = [];
2570
+ }
2571
+ field(type, name, label, optionsOrProps, props) {
2572
+ this.fields.push(createField(type, name, label, optionsOrProps, props));
2573
+ return this;
2574
+ }
2575
+ /**
2576
+ * Add a conditional field that shows/hides based on form data
2577
+ */
2578
+ conditionalField(name, condition, field2) {
2579
+ this.fields.push({
2580
+ condition,
2581
+ field: field2,
2582
+ name,
2583
+ type: "conditional"
2584
+ });
2585
+ return this;
2586
+ }
2587
+ /**
2588
+ * Add a field array for dynamic repeating field groups
2589
+ */
2590
+ fieldArray(name, label, fields, options) {
2591
+ this.fields.push({
2592
+ addButtonText: options?.addButtonText,
2593
+ fields,
2594
+ label,
2595
+ max: options?.max,
2596
+ min: options?.min,
2597
+ name,
2598
+ removeButtonText: options?.removeButtonText,
2599
+ type: "fieldArray"
2600
+ });
2601
+ return this;
2602
+ }
2603
+ /**
2604
+ * Add a dynamic section that shows/hides based on form data
2605
+ */
2606
+ dynamicSection(name, condition, fields, options) {
2607
+ this.fields.push({
2608
+ condition,
2609
+ description: options?.description,
2610
+ fields,
2611
+ name,
2612
+ title: options?.title,
2613
+ type: "dynamicSection"
2614
+ });
2615
+ return this;
2616
+ }
2617
+ /**
2618
+ * Build the final field configuration array
2619
+ */
2620
+ build() {
2621
+ return this.fields;
2622
+ }
2623
+ };
2624
+ var FieldArrayItemBuilder = class {
2625
+ constructor() {
2626
+ this.fields = [];
2627
+ }
2628
+ field(type, name, label, optionsOrProps, props) {
2629
+ this.fields.push(createField(type, name, label, optionsOrProps, props));
2630
+ return this;
2631
+ }
2632
+ /**
2633
+ * Build the field array item configuration
2634
+ */
2635
+ build() {
2636
+ return this.fields;
2637
+ }
2638
+ };
2639
+ function createFieldArrayItemBuilder() {
2640
+ return new FieldArrayItemBuilder();
2641
+ }
2642
+ var FieldArrayBuilder = class {
2643
+ constructor(arrayName) {
2644
+ this.arrayName = arrayName;
2645
+ this.fields = [];
2646
+ }
2647
+ field(type, name, label, optionsOrProps, props) {
2648
+ const fullPath = `${this.arrayName}.${name}`;
2649
+ const fieldConfig = createField(
2650
+ type,
2651
+ fullPath,
2652
+ label,
2653
+ optionsOrProps,
2654
+ props
2655
+ );
2656
+ this.fields.push(fieldConfig);
2657
+ return this;
2658
+ }
2659
+ build() {
2660
+ return this.fields;
2661
+ }
2662
+ };
2663
+ function createFieldArrayBuilder(arrayName) {
2664
+ return new FieldArrayBuilder(arrayName);
2665
+ }
2666
+ function createAdvancedBuilder() {
2667
+ return new AdvancedFieldBuilder();
2668
+ }
2669
+
2670
+ // src/builders/TypeInferredBuilder.ts
2671
+ import { z as z3 } from "zod";
2672
+ var TypeInferredBuilder = class {
2673
+ constructor() {
2674
+ this.schemaFields = {};
2675
+ this.formFields = [];
2676
+ }
2677
+ /**
2678
+ * Add a text field
2679
+ */
2680
+ text(name, label, options) {
2681
+ const { maxLength, minLength, pattern, ...fieldOptions } = options || {};
2682
+ let zodType = z3.string();
2683
+ if (minLength)
2684
+ zodType = zodType.min(
2685
+ minLength,
2686
+ `${label} must be at least ${minLength} characters`
2687
+ );
2688
+ if (maxLength)
2689
+ zodType = zodType.max(
2690
+ maxLength,
2691
+ `${label} must be no more than ${maxLength} characters`
2692
+ );
2693
+ if (pattern)
2694
+ zodType = zodType.regex(
2695
+ new RegExp(pattern),
2696
+ `${label} format is invalid`
2697
+ );
2698
+ this.schemaFields[name] = zodType;
2699
+ this.formFields.push({
2700
+ inputProps: { type: "text", ...fieldOptions },
2701
+ label,
2702
+ name,
2703
+ type: "input"
2704
+ });
2705
+ return this;
2706
+ }
2707
+ /**
2708
+ * Add an email field
2709
+ */
2710
+ email(name, label, options) {
2711
+ this.schemaFields[name] = z3.string().email(`Please enter a valid email address`);
2712
+ this.formFields.push({
2713
+ inputProps: { type: "email", ...options },
2714
+ label,
2715
+ name,
2716
+ type: "input"
2717
+ });
2718
+ return this;
2719
+ }
2720
+ /**
2721
+ * Add a number field
2722
+ */
2723
+ number(name, label, options) {
2724
+ const { max, min, step, ...fieldOptions } = options || {};
2725
+ let zodType = z3.number();
2726
+ if (min !== void 0)
2727
+ zodType = zodType.min(min, `${label} must be at least ${min}`);
2728
+ if (max !== void 0)
2729
+ zodType = zodType.max(max, `${label} must be no more than ${max}`);
2730
+ this.schemaFields[name] = zodType;
2731
+ this.formFields.push({
2732
+ inputProps: { max, min, step, type: "number", ...fieldOptions },
2733
+ label,
2734
+ name,
2735
+ type: "input"
2736
+ });
2737
+ return this;
2738
+ }
2739
+ /**
2740
+ * Add a textarea field
2741
+ */
2742
+ textarea(name, label, options) {
2743
+ const { minLength, ...fieldOptions } = options || {};
2744
+ let zodType = z3.string();
2745
+ if (minLength)
2746
+ zodType = zodType.min(
2747
+ minLength,
2748
+ `${label} must be at least ${minLength} characters`
2749
+ );
2750
+ this.schemaFields[name] = zodType;
2751
+ this.formFields.push({
2752
+ label,
2753
+ name,
2754
+ textareaProps: fieldOptions,
2755
+ type: "textarea"
2756
+ });
2757
+ return this;
2758
+ }
2759
+ /**
2760
+ * Add a select field
2761
+ */
2762
+ select(name, label, options) {
2763
+ this.schemaFields[name] = z3.string().min(1, `Please select a ${label.toLowerCase()}`);
2764
+ this.formFields.push({
2765
+ label,
2766
+ name,
2767
+ options,
2768
+ type: "select"
2769
+ });
2770
+ return this;
2771
+ }
2772
+ /**
2773
+ * Add a checkbox field
2774
+ */
2775
+ checkbox(name, label, options) {
2776
+ const { required = false, ...fieldOptions } = options || {};
2777
+ let zodType = z3.boolean();
2778
+ if (required) {
2779
+ zodType = zodType.refine(
2780
+ (val) => val === true,
2781
+ `You must agree to ${label.toLowerCase()}`
2782
+ );
2783
+ }
2784
+ this.schemaFields[name] = zodType;
2785
+ this.formFields.push({
2786
+ checkboxProps: fieldOptions,
2787
+ label,
2788
+ name,
2789
+ type: "checkbox"
2790
+ });
2791
+ return this;
2792
+ }
2793
+ /**
2794
+ * Add a switch field
2795
+ */
2796
+ switch(name, label, options) {
2797
+ this.schemaFields[name] = z3.boolean().optional();
2798
+ this.formFields.push({
2799
+ label,
2800
+ name,
2801
+ switchProps: options,
2802
+ type: "switch"
2803
+ });
2804
+ return this;
2805
+ }
2806
+ /**
2807
+ * Add a radio field
2808
+ */
2809
+ radio(name, label, options, fieldOptions) {
2810
+ this.schemaFields[name] = z3.string().min(1, `Please select a ${label.toLowerCase()}`);
2811
+ this.formFields.push({
2812
+ label,
2813
+ name,
2814
+ radioOptions: options,
2815
+ radioProps: fieldOptions,
2816
+ type: "radio"
2817
+ });
2818
+ return this;
2819
+ }
2820
+ /**
2821
+ * Add a slider field
2822
+ */
2823
+ slider(name, label, options) {
2824
+ const { max = 100, min = 0, step = 1, ...fieldOptions } = options || {};
2825
+ let zodType = z3.number();
2826
+ if (min !== void 0)
2827
+ zodType = zodType.min(min, `${label} must be at least ${min}`);
2828
+ if (max !== void 0)
2829
+ zodType = zodType.max(max, `${label} must be no more than ${max}`);
2830
+ this.schemaFields[name] = zodType;
2831
+ this.formFields.push({
2832
+ label,
2833
+ name,
2834
+ sliderProps: { max, min, step, ...fieldOptions },
2835
+ type: "slider"
2836
+ });
2837
+ return this;
2838
+ }
2839
+ /**
2840
+ * Add a date field
2841
+ */
2842
+ date(name, label, options) {
2843
+ this.schemaFields[name] = z3.string().min(1, `${label} is required`);
2844
+ this.formFields.push({
2845
+ dateProps: options,
2846
+ label,
2847
+ name,
2848
+ type: "date"
2849
+ });
2850
+ return this;
2851
+ }
2852
+ /**
2853
+ * Add a file field
2854
+ */
2855
+ file(name, label, options) {
2856
+ this.schemaFields[name] = z3.any().optional();
2857
+ this.formFields.push({
2858
+ fileProps: options,
2859
+ label,
2860
+ name,
2861
+ type: "file"
2862
+ });
2863
+ return this;
2864
+ }
2865
+ /**
2866
+ * Build the final schema and fields
2867
+ */
2868
+ build() {
2869
+ return {
2870
+ fields: this.formFields,
2871
+ schema: z3.object(this.schemaFields)
2872
+ };
2873
+ }
2874
+ };
2875
+ function createTypeInferredBuilder() {
2876
+ return new TypeInferredBuilder();
2877
+ }
2878
+ function defineInferredForm(fieldDefinitions) {
2879
+ const builder = createTypeInferredBuilder();
2880
+ fieldDefinitions(builder);
2881
+ return builder.build();
2882
+ }
2883
+ var field = {
2884
+ checkbox: (name, label, options) => {
2885
+ const builder = new TypeInferredBuilder();
2886
+ return builder.checkbox(name, label, options);
2887
+ },
2888
+ date: (name, label, options) => {
2889
+ const builder = new TypeInferredBuilder();
2890
+ return builder.date(name, label, options);
2891
+ },
2892
+ email: (name, label, options) => {
2893
+ const builder = new TypeInferredBuilder();
2894
+ return builder.email(name, label, options);
2895
+ },
2896
+ file: (name, label, options) => {
2897
+ const builder = new TypeInferredBuilder();
2898
+ return builder.file(name, label, options);
2899
+ },
2900
+ number: (name, label, options) => {
2901
+ const builder = new TypeInferredBuilder();
2902
+ return builder.number(name, label, options);
2903
+ },
2904
+ radio: (name, label, options, fieldOptions) => {
2905
+ const builder = new TypeInferredBuilder();
2906
+ return builder.radio(name, label, options, fieldOptions);
2907
+ },
2908
+ select: (name, label, options) => {
2909
+ const builder = new TypeInferredBuilder();
2910
+ return builder.select(name, label, options);
2911
+ },
2912
+ slider: (name, label, options) => {
2913
+ const builder = new TypeInferredBuilder();
2914
+ return builder.slider(name, label, options);
2915
+ },
2916
+ switch: (name, label, options) => {
2917
+ const builder = new TypeInferredBuilder();
2918
+ return builder.switch(name, label, options);
2919
+ },
2920
+ text: (name, label, options) => {
2921
+ const builder = new TypeInferredBuilder();
2922
+ return builder.text(name, label, options);
2923
+ },
2924
+ textarea: (name, label, options) => {
2925
+ const builder = new TypeInferredBuilder();
2926
+ return builder.textarea(name, label, options);
2927
+ }
2928
+ };
2929
+
2930
+ // src/builders/NestedPathBuilder.ts
2931
+ var NestedPathBuilder = class {
2932
+ constructor() {
2933
+ this.fields = [];
2934
+ }
2935
+ /**
2936
+ * Create a nested object path builder
2937
+ * Usage: builder.nest("address").field("street", "Street Address")
2938
+ */
2939
+ nest(path) {
2940
+ return new NestedObjectBuilder(this, path);
2941
+ }
2942
+ /**
2943
+ * Create a section-based path builder
2944
+ * Usage: builder.section("shipping").field("street", "Street Address")
2945
+ */
2946
+ section(path) {
2947
+ return new SectionBuilder(this, path);
2948
+ }
2949
+ /**
2950
+ * Add a field with single path
2951
+ * Usage: builder.field("firstName", "First Name")
2952
+ */
2953
+ field(name, label, type = "input", props) {
2954
+ this.fields.push({
2955
+ label,
2956
+ name,
2957
+ type,
2958
+ ...props
2959
+ });
2960
+ return this;
2961
+ }
2962
+ /**
2963
+ * Add a field with path segments
2964
+ * Usage: builder.fieldPath(["user", "profile", "name"], "Full Name")
2965
+ */
2966
+ fieldPath(path, label, type = "input", props) {
2967
+ const name = path.join(".");
2968
+ this.fields.push({
2969
+ label,
2970
+ name,
2971
+ type,
2972
+ ...props
2973
+ });
2974
+ return this;
2975
+ }
2976
+ /**
2977
+ * Add a field with template literal path
2978
+ * Usage: builder.field`user.profile.name`("Full Name")
2979
+ */
2980
+ fieldTemplate(path) {
2981
+ const pathString = path[0];
2982
+ return new FieldTemplateBuilder(this, pathString);
2983
+ }
2984
+ /**
2985
+ * Return to the parent builder (no-op for root builder)
2986
+ */
2987
+ end() {
2988
+ return this;
2989
+ }
2990
+ build() {
2991
+ return this.fields;
2992
+ }
2993
+ };
2994
+ var NestedObjectBuilder = class _NestedObjectBuilder {
2995
+ constructor(parent, path) {
2996
+ this.parent = parent;
2997
+ this.path = path;
2998
+ }
2999
+ /**
3000
+ * Add a field to the current nested path
3001
+ */
3002
+ field(fieldName, label, type = "input", props) {
3003
+ const fullPath = `${this.path}.${fieldName}`;
3004
+ this.parent.fields.push({
3005
+ label,
3006
+ name: fullPath,
3007
+ type,
3008
+ ...props
3009
+ });
3010
+ return this;
3011
+ }
3012
+ /**
3013
+ * Nest deeper into the object
3014
+ */
3015
+ nest(subPath) {
3016
+ return new _NestedObjectBuilder(
3017
+ this.parent,
3018
+ `${this.path}.${subPath}`
3019
+ );
3020
+ }
3021
+ /**
3022
+ * Return to the parent builder
3023
+ */
3024
+ end() {
3025
+ return this.parent;
3026
+ }
3027
+ };
3028
+ var SectionBuilder = class {
3029
+ constructor(parent, path) {
3030
+ this.parent = parent;
3031
+ this.path = path;
3032
+ }
3033
+ /**
3034
+ * Add a field to the current section
3035
+ */
3036
+ field(fieldName, label, type = "input", props) {
3037
+ const fullPath = `${this.path}.${fieldName}`;
3038
+ this.parent.fields.push({
3039
+ label,
3040
+ name: fullPath,
3041
+ type,
3042
+ ...props
3043
+ });
3044
+ return this;
3045
+ }
3046
+ /**
3047
+ * Add multiple fields to the section
3048
+ */
3049
+ fields(fieldDefinitions) {
3050
+ fieldDefinitions.forEach((field2) => {
3051
+ this.field(field2.name, field2.label, field2.type, field2.props);
3052
+ });
3053
+ return this;
3054
+ }
3055
+ /**
3056
+ * Nest deeper into the section
3057
+ */
3058
+ nest(subPath) {
3059
+ return new NestedObjectBuilder(
3060
+ this.parent,
3061
+ `${this.path}.${subPath}`
3062
+ );
3063
+ }
3064
+ /**
3065
+ * Return to the parent builder
3066
+ */
3067
+ end() {
3068
+ return this.parent;
3069
+ }
3070
+ };
3071
+ var FieldTemplateBuilder = class {
3072
+ constructor(parent, path) {
3073
+ this.parent = parent;
3074
+ this.path = path;
3075
+ }
3076
+ /**
3077
+ * Complete the field definition
3078
+ */
3079
+ complete(label, type = "input", props) {
3080
+ this.parent.fields.push({
3081
+ label,
3082
+ name: this.path,
3083
+ type,
3084
+ ...props
3085
+ });
3086
+ return this.parent;
3087
+ }
3088
+ };
3089
+ function createNestedPathBuilder() {
3090
+ return new NestedPathBuilder();
3091
+ }
3092
+
3093
+ // src/hooks/useDebouncedValidation.ts
3094
+ import { useCallback as useCallback2, useEffect as useEffect2, useRef } from "react";
3095
+ function useDebouncedValidation(form, options = {}) {
3096
+ const { delay = 300, enabled = true, fields } = options;
3097
+ const timeoutRef = useRef(
3098
+ void 0
3099
+ );
3100
+ const lastValuesRef = useRef({});
3101
+ const debouncedTrigger = useCallback2(() => {
3102
+ if (!enabled) return;
3103
+ if (timeoutRef.current) {
3104
+ clearTimeout(timeoutRef.current);
3105
+ timeoutRef.current = void 0;
3106
+ }
3107
+ timeoutRef.current = setTimeout(async () => {
3108
+ const currentValues = form.getValues();
3109
+ const lastValues = lastValuesRef.current;
3110
+ const hasChanges = fields ? fields.some((field2) => currentValues[field2] !== lastValues[field2]) : Object.keys(currentValues).some(
3111
+ (key) => currentValues[key] !== lastValues[key]
3112
+ );
3113
+ if (hasChanges) {
3114
+ lastValuesRef.current = { ...currentValues };
3115
+ if (fields && fields.length > 0) {
3116
+ await form.trigger(fields);
3117
+ } else {
3118
+ await form.trigger();
3119
+ }
3120
+ }
3121
+ }, delay);
3122
+ }, [form, delay, fields, enabled]);
3123
+ useEffect2(() => {
3124
+ return () => {
3125
+ if (timeoutRef.current) {
3126
+ clearTimeout(timeoutRef.current);
3127
+ timeoutRef.current = void 0;
3128
+ }
3129
+ };
3130
+ }, []);
3131
+ useEffect2(() => {
3132
+ if (form.formState.isSubmitSuccessful) {
3133
+ lastValuesRef.current = {};
3134
+ }
3135
+ }, [form.formState.isSubmitSuccessful]);
3136
+ return {
3137
+ debouncedTrigger,
3138
+ isDebouncing: !!timeoutRef.current
3139
+ };
3140
+ }
3141
+ function useDebouncedFieldValidation(form, fieldName, options = {}) {
3142
+ const { delay = 300, enabled = true } = options;
3143
+ const timeoutRef = useRef(
3144
+ void 0
3145
+ );
3146
+ const debouncedFieldTrigger = useCallback2(() => {
3147
+ if (!enabled) return;
3148
+ if (timeoutRef.current) {
3149
+ clearTimeout(timeoutRef.current);
3150
+ }
3151
+ timeoutRef.current = setTimeout(async () => {
3152
+ await form.trigger(fieldName);
3153
+ }, delay);
3154
+ }, [form, fieldName, delay, enabled]);
3155
+ useEffect2(() => {
3156
+ return () => {
3157
+ if (timeoutRef.current) {
3158
+ clearTimeout(timeoutRef.current);
3159
+ timeoutRef.current = void 0;
3160
+ }
3161
+ };
3162
+ }, []);
3163
+ return {
3164
+ debouncedFieldTrigger,
3165
+ isDebouncing: !!timeoutRef.current
3166
+ };
3167
+ }
3168
+
3169
+ // src/hooks/useInferredForm.ts
3170
+ import { useForm as useForm3 } from "react-hook-form";
3171
+ var zodResolver;
3172
+ try {
3173
+ zodResolver = __require("@hookform/resolvers/zod").zodResolver;
3174
+ } catch {
3175
+ }
3176
+ function useInferredForm(schema, fields, options = {}) {
3177
+ const {
3178
+ defaultValues,
3179
+ delayError = 0,
3180
+ mode = "onChange",
3181
+ reValidateMode = "onChange",
3182
+ shouldFocusError = true,
3183
+ shouldUnregister = false
3184
+ } = options;
3185
+ return useForm3({
3186
+ defaultValues,
3187
+ delayError,
3188
+ mode,
3189
+ resolver: zodResolver ? zodResolver(schema) : void 0,
3190
+ reValidateMode,
3191
+ shouldFocusError,
3192
+ shouldUnregister
3193
+ });
3194
+ }
3195
+ function useTypeInferredForm(formConfig, options = {}) {
3196
+ return useInferredForm(formConfig.schema, formConfig.fields, options);
3197
+ }
3198
+
3199
+ // src/utils/performance.ts
3200
+ import { useCallback as useCallback3, useMemo as useMemo2, useRef as useRef2 } from "react";
3201
+ function debounce(func, delay) {
3202
+ let timeoutId;
3203
+ return (...args) => {
3204
+ clearTimeout(timeoutId);
3205
+ timeoutId = setTimeout(() => func(...args), delay);
3206
+ };
3207
+ }
3208
+ function throttle(func, limit) {
3209
+ let inThrottle;
3210
+ return (...args) => {
3211
+ if (!inThrottle) {
3212
+ func(...args);
3213
+ inThrottle = true;
3214
+ setTimeout(() => inThrottle = false, limit);
3215
+ }
3216
+ };
3217
+ }
3218
+ function useMemoizedCallback(callback, deps) {
3219
+ const callbackRef = useRef2(callback);
3220
+ callbackRef.current = callback;
3221
+ return useCallback3(
3222
+ ((...args) => callbackRef.current(...args)),
3223
+ deps
3224
+ );
3225
+ }
3226
+ function shallowEqual(prevProps, nextProps) {
3227
+ const prevKeys = Object.keys(prevProps);
3228
+ const nextKeys = Object.keys(nextProps);
3229
+ if (prevKeys.length !== nextKeys.length) {
3230
+ return false;
3231
+ }
3232
+ for (const key of prevKeys) {
3233
+ if (prevProps[key] !== nextProps[key]) {
3234
+ return false;
3235
+ }
3236
+ }
3237
+ return true;
3238
+ }
3239
+ function deepEqual(prevProps, nextProps) {
3240
+ if (prevProps === nextProps) {
3241
+ return true;
3242
+ }
3243
+ if (typeof prevProps !== typeof nextProps) {
3244
+ return false;
3245
+ }
3246
+ if (typeof prevProps !== "object" || prevProps === null || nextProps === null) {
3247
+ return prevProps === nextProps;
3248
+ }
3249
+ const prevKeys = Object.keys(prevProps);
3250
+ const nextKeys = Object.keys(nextProps);
3251
+ if (prevKeys.length !== nextKeys.length) {
3252
+ return false;
3253
+ }
3254
+ for (const key of prevKeys) {
3255
+ if (!nextKeys.includes(key)) {
3256
+ return false;
3257
+ }
3258
+ if (!deepEqual(prevProps[key], nextProps[key])) {
3259
+ return false;
3260
+ }
3261
+ }
3262
+ return true;
3263
+ }
3264
+ function usePerformanceMonitor(componentName, enabled = false) {
3265
+ const renderCountRef = useRef2(0);
3266
+ const lastRenderTimeRef = useRef2(Date.now());
3267
+ if (enabled) {
3268
+ renderCountRef.current += 1;
3269
+ const now = Date.now();
3270
+ const timeSinceLastRender = now - lastRenderTimeRef.current;
3271
+ console.log(`[Performance] ${componentName}:`, {
3272
+ renderCount: renderCountRef.current,
3273
+ timeSinceLastRender: `${timeSinceLastRender}ms`
3274
+ });
3275
+ lastRenderTimeRef.current = now;
3276
+ }
3277
+ return {
3278
+ renderCount: renderCountRef.current,
3279
+ resetRenderCount: () => {
3280
+ renderCountRef.current = 0;
3281
+ }
3282
+ };
3283
+ }
3284
+ function createOptimizedFieldHandler(onChange, options = {}) {
3285
+ const { debounce: debounceMs, throttle: throttleMs } = options;
3286
+ let handler = onChange;
3287
+ if (throttleMs) {
3288
+ handler = throttle(handler, throttleMs);
3289
+ }
3290
+ if (debounceMs) {
3291
+ handler = debounce(handler, debounceMs);
3292
+ }
3293
+ return handler;
3294
+ }
3295
+ function useMemoizedFieldProps(props, deps) {
3296
+ return useMemo2(() => props, deps);
3297
+ }
3298
+
3299
+ // src/builders/validation-helpers.ts
3300
+ import { z as z4 } from "zod";
3301
+ var validationPatterns = {
3302
+ // Credit card validation
3303
+ creditCard: z4.string().regex(
3304
+ // eslint-disable-next-line no-useless-escape
3305
+ /^[0-9]{4}[\s\-]?[0-9]{4}[\s\-]?[0-9]{4}[\s\-]?[0-9]{4}$/,
3306
+ "Please enter a valid credit card number"
3307
+ ),
3308
+ // Date validation (MM/DD/YYYY)
3309
+ date: z4.string().regex(
3310
+ /^(0[1-9]|1[0-2])\/(0[1-9]|[12][0-9]|3[01])\/\d{4}$/,
3311
+ "Please enter a valid date (MM/DD/YYYY)"
3312
+ ),
3313
+ // Email validation
3314
+ email: z4.string().email("Please enter a valid email address"),
3315
+ // Password validation
3316
+ password: z4.string().min(8, "Password must be at least 8 characters").regex(/[A-Z]/, "Password must contain at least one uppercase letter").regex(/[a-z]/, "Password must contain at least one lowercase letter").regex(/[0-9]/, "Password must contain at least one number").regex(
3317
+ /[^A-Za-z0-9]/,
3318
+ "Password must contain at least one special character"
3319
+ ),
3320
+ // Phone number validation (international)
3321
+ phoneInternational: z4.string().regex(/^\+?[\d\s\-\(\)]+$/, "Please enter a valid phone number"),
3322
+ // Phone number validation (US format)
3323
+ phoneUS: z4.string().regex(
3324
+ /^\(\d{3}\) \d{3}-\d{4}$/,
3325
+ "Please enter a valid phone number (XXX) XXX-XXXX"
3326
+ ),
3327
+ // SSN validation
3328
+ ssn: z4.string().regex(/^\d{3}-\d{2}-\d{4}$/, "Please enter a valid SSN (XXX-XX-XXXX)"),
3329
+ // Strong password validation
3330
+ strongPassword: z4.string().min(12, "Password must be at least 12 characters").regex(/[A-Z]/, "Password must contain at least one uppercase letter").regex(/[a-z]/, "Password must contain at least one lowercase letter").regex(/[0-9]/, "Password must contain at least one number").regex(
3331
+ /[^A-Za-z0-9]/,
3332
+ "Password must contain at least one special character"
3333
+ ),
3334
+ // Time validation (HH:MM AM/PM)
3335
+ time: z4.string().regex(
3336
+ /^(0[1-9]|1[0-2]):[0-5][0-9] (AM|PM)$/i,
3337
+ "Please enter a valid time (HH:MM AM/PM)"
3338
+ ),
3339
+ // URL validation
3340
+ url: z4.string().url("Please enter a valid URL"),
3341
+ // ZIP code validation
3342
+ zipCode: z4.string().regex(/^\d{5}(-\d{4})?$/, "Please enter a valid ZIP code")
3343
+ };
3344
+ var asyncValidation = {
3345
+ /**
3346
+ * Email availability check
3347
+ */
3348
+ emailAvailability: async (email) => {
3349
+ return new Promise((resolve) => {
3350
+ setTimeout(() => {
3351
+ const takenEmails = ["test@example.com", "admin@example.com"];
3352
+ resolve(!takenEmails.includes(email));
3353
+ }, 1e3);
3354
+ });
3355
+ },
3356
+ /**
3357
+ * Username availability check
3358
+ */
3359
+ usernameAvailability: async (username) => {
3360
+ return new Promise((resolve) => {
3361
+ setTimeout(() => {
3362
+ const takenUsernames = ["admin", "test", "user"];
3363
+ resolve(!takenUsernames.includes(username.toLowerCase()));
3364
+ }, 1e3);
3365
+ });
3366
+ }
3367
+ };
3368
+ var errorMessages = {
3369
+ date: () => "Please enter a valid date",
3370
+ email: () => "Please enter a valid email address",
3371
+ max: (fieldName, max) => `${fieldName} must be no more than ${max}`,
3372
+ maxLength: (fieldName, max) => `${fieldName} must be no more than ${max} characters`,
3373
+ min: (fieldName, min) => `${fieldName} must be at least ${min}`,
3374
+ minLength: (fieldName, min) => `${fieldName} must be at least ${min} characters`,
3375
+ pattern: (fieldName) => `${fieldName} format is invalid`,
3376
+ phone: () => "Please enter a valid phone number",
3377
+ required: (fieldName) => `${fieldName} is required`,
3378
+ time: () => "Please enter a valid time",
3379
+ url: () => "Please enter a valid URL"
3380
+ };
3381
+ var serverValidation = {
3382
+ /**
3383
+ * Apply server errors to form
3384
+ */
3385
+ applyServerErrors: (errors, setError) => {
3386
+ Object.entries(errors).forEach(([field2, messages]) => {
3387
+ setError(field2, {
3388
+ message: messages[0],
3389
+ type: "server"
3390
+ // Use first error message
3391
+ });
3392
+ });
3393
+ },
3394
+ /**
3395
+ * Clear server errors
3396
+ */
3397
+ clearServerErrors: (fields, clearErrors) => {
3398
+ fields.forEach((field2) => {
3399
+ clearErrors(field2, "server");
3400
+ });
3401
+ }
3402
+ };
3403
+ var validationUtils = {
3404
+ /**
3405
+ * Debounced validation
3406
+ */
3407
+ debounceValidation: (fn, delay = 300) => {
3408
+ let timeoutId;
3409
+ return (...args) => {
3410
+ clearTimeout(timeoutId);
3411
+ timeoutId = setTimeout(() => fn(...args), delay);
3412
+ };
3413
+ },
3414
+ /**
3415
+ * Get field error message
3416
+ */
3417
+ getFieldError: (errors, field2) => {
3418
+ return errors[field2];
3419
+ },
3420
+ /**
3421
+ * Check if field has error
3422
+ */
3423
+ hasFieldError: (errors, field2) => {
3424
+ return !!errors[field2];
3425
+ },
3426
+ /**
3427
+ * Validate form data against schema
3428
+ */
3429
+ validateForm: async (data, schema) => {
3430
+ try {
3431
+ await schema.parseAsync(data);
3432
+ return { errors: {}, success: true };
3433
+ } catch (error) {
3434
+ if (error instanceof z4.ZodError) {
3435
+ const errors = {};
3436
+ error.issues.forEach((err) => {
3437
+ const path = err.path.join(".");
3438
+ errors[path] = err.message;
3439
+ });
3440
+ return { errors, success: false };
3441
+ }
3442
+ throw error;
3443
+ }
3444
+ }
3445
+ };
1493
3446
  export {
3447
+ AdvancedFieldBuilder,
3448
+ BasicFormBuilder,
1494
3449
  CheckboxField,
3450
+ CommonFields,
3451
+ ConditionalField,
1495
3452
  ConfigurableForm,
1496
3453
  DateField,
3454
+ DynamicSectionField,
3455
+ FieldArrayBuilder,
3456
+ FieldArrayField,
3457
+ FieldArrayItemBuilder,
1497
3458
  FileField,
1498
3459
  FontPickerField,
1499
3460
  FormField,
3461
+ FormFieldHelpers,
1500
3462
  FormProvider,
3463
+ FormStatus,
3464
+ FormToast,
1501
3465
  HeroHookFormProvider,
1502
3466
  InputField,
1503
3467
  RadioGroupField,
1504
3468
  SelectField,
3469
+ ServerActionForm,
1505
3470
  SliderField,
1506
3471
  SubmitButton,
1507
3472
  SwitchField,
1508
3473
  TextareaField,
3474
+ TypeInferredBuilder,
1509
3475
  ZodForm,
1510
3476
  applyServerErrors,
3477
+ asyncValidation,
1511
3478
  commonValidations,
1512
- createConditionalSchema,
1513
- createConfirmPasswordSchema,
3479
+ createAdvancedBuilder,
3480
+ createBasicFormBuilder,
1514
3481
  createDateSchema,
1515
3482
  createEmailSchema,
3483
+ createField,
3484
+ createFieldArrayBuilder,
3485
+ createFieldArrayItemBuilder,
1516
3486
  createFileSchema,
1517
3487
  createFormTestUtils,
1518
3488
  createFutureDateSchema,
@@ -1520,24 +3490,46 @@ export {
1520
3490
  createMinLengthSchema,
1521
3491
  createMockFormData,
1522
3492
  createMockFormErrors,
3493
+ createNestedPathBuilder,
1523
3494
  createNumberRangeSchema,
3495
+ createOptimizedFieldHandler,
1524
3496
  createPasswordSchema,
1525
3497
  createPastDateSchema,
1526
3498
  createPhoneSchema,
1527
3499
  createRequiredCheckboxSchema,
1528
3500
  createRequiredSchema,
3501
+ createTypeInferredBuilder,
1529
3502
  createUrlSchema,
1530
3503
  createZodFormConfig,
3504
+ crossFieldValidation,
3505
+ debounce,
3506
+ deepEqual,
3507
+ defineInferredForm,
3508
+ errorMessages,
3509
+ field,
1531
3510
  getFieldError,
1532
3511
  getFormErrors,
1533
3512
  hasFieldError,
1534
3513
  hasFormErrors,
3514
+ serverValidation,
3515
+ shallowEqual,
1535
3516
  simulateFieldInput,
1536
3517
  simulateFormSubmission,
1537
- useFormContext2 as useFormContext,
3518
+ throttle,
3519
+ useDebouncedFieldValidation,
3520
+ useDebouncedValidation,
3521
+ useEnhancedFormState,
3522
+ useFormContext5 as useFormContext,
1538
3523
  useFormHelper,
1539
3524
  useHeroForm,
1540
3525
  useHeroHookFormDefaults,
3526
+ useInferredForm,
3527
+ useMemoizedCallback,
3528
+ useMemoizedFieldProps,
3529
+ usePerformanceMonitor,
3530
+ useTypeInferredForm,
1541
3531
  useZodForm,
3532
+ validationPatterns,
3533
+ validationUtils,
1542
3534
  waitForFormState
1543
3535
  };