@rachelallyson/hero-hook-form 1.1.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6,8 +6,8 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
6
6
  });
7
7
 
8
8
  // src/components/Form.tsx
9
- import React13 from "react";
10
- import { Button as Button2 } from "@heroui/react";
9
+ import React16 from "react";
10
+ import { Button as Button3 } from "@heroui/react";
11
11
 
12
12
  // src/hooks/useFormHelper.ts
13
13
  import { useState } from "react";
@@ -75,8 +75,8 @@ function useFormHelper({
75
75
  }
76
76
 
77
77
  // src/components/FormField.tsx
78
- import React12 from "react";
79
- import { useWatch } from "react-hook-form";
78
+ import React15 from "react";
79
+ import { useWatch as useWatch3 } from "react-hook-form";
80
80
 
81
81
  // src/fields/CheckboxField.tsx
82
82
  import React2 from "react";
@@ -198,16 +198,16 @@ function CheckboxField(props) {
198
198
  {
199
199
  control,
200
200
  name,
201
- render: ({ field, fieldState }) => /* @__PURE__ */ React2.createElement("div", { className }, /* @__PURE__ */ React2.createElement(
201
+ render: ({ field: field2, fieldState }) => /* @__PURE__ */ React2.createElement("div", { className }, /* @__PURE__ */ React2.createElement(
202
202
  Checkbox,
203
203
  {
204
204
  ...defaults.checkbox,
205
205
  ...checkboxProps,
206
206
  isDisabled,
207
207
  isInvalid: Boolean(fieldState.error),
208
- isSelected: Boolean(field.value),
209
- onBlur: field.onBlur,
210
- onValueChange: (val) => field.onChange(val)
208
+ isSelected: Boolean(field2.value),
209
+ onBlur: field2.onBlur,
210
+ onValueChange: (val) => field2.onChange(val)
211
211
  },
212
212
  label
213
213
  ), 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),
@@ -216,13 +216,43 @@ function CheckboxField(props) {
216
216
  );
217
217
  }
218
218
 
219
- // src/fields/DateField.tsx
219
+ // src/fields/ConditionalField.tsx
220
220
  import React3 from "react";
221
+ import { useWatch, useFormContext } from "react-hook-form";
222
+ function ConditionalField({
223
+ config,
224
+ control,
225
+ className
226
+ }) {
227
+ const { condition, field: field2, name } = config;
228
+ const form = useFormContext();
229
+ const formValues = useWatch({ control });
230
+ const shouldShow = condition(formValues);
231
+ if (!shouldShow) {
232
+ return null;
233
+ }
234
+ return /* @__PURE__ */ React3.createElement("div", { className }, /* @__PURE__ */ React3.createElement(
235
+ FormField,
236
+ {
237
+ config: field2,
238
+ form,
239
+ submissionState: {
240
+ isSubmitting: false,
241
+ isSubmitted: false,
242
+ isSuccess: false,
243
+ error: void 0
244
+ }
245
+ }
246
+ ));
247
+ }
248
+
249
+ // src/fields/DateField.tsx
250
+ import React4 from "react";
221
251
  import { Controller as Controller2 } from "react-hook-form";
222
252
  function CoercedDateInput(props) {
223
- const { dateProps, description, disabled, errorMessage, field, label } = props;
253
+ const { dateProps, description, disabled, errorMessage, field: field2, label } = props;
224
254
  const defaults = useHeroHookFormDefaults();
225
- return /* @__PURE__ */ React3.createElement(
255
+ return /* @__PURE__ */ React4.createElement(
226
256
  DateInput,
227
257
  {
228
258
  ...defaults.dateInput,
@@ -232,9 +262,9 @@ function CoercedDateInput(props) {
232
262
  isDisabled: disabled,
233
263
  isInvalid: Boolean(errorMessage),
234
264
  label,
235
- value: field.value ?? null,
236
- onBlur: field.onBlur,
237
- onChange: field.onChange
265
+ value: field2.value ?? null,
266
+ onBlur: field2.onBlur,
267
+ onChange: field2.onChange
238
268
  }
239
269
  );
240
270
  }
@@ -250,12 +280,12 @@ function DateField(props) {
250
280
  rules,
251
281
  transform
252
282
  } = props;
253
- return /* @__PURE__ */ React3.createElement(
283
+ return /* @__PURE__ */ React4.createElement(
254
284
  Controller2,
255
285
  {
256
286
  control,
257
287
  name,
258
- render: ({ field, fieldState }) => /* @__PURE__ */ React3.createElement("div", { className }, /* @__PURE__ */ React3.createElement(
288
+ render: ({ field: field2, fieldState }) => /* @__PURE__ */ React4.createElement("div", { className }, /* @__PURE__ */ React4.createElement(
259
289
  CoercedDateInput,
260
290
  {
261
291
  dateProps,
@@ -263,8 +293,8 @@ function DateField(props) {
263
293
  disabled: isDisabled,
264
294
  errorMessage: fieldState.error?.message,
265
295
  field: {
266
- ...field,
267
- onChange: (value) => field.onChange(transform ? transform(value) : value)
296
+ ...field2,
297
+ onChange: (value) => field2.onChange(transform ? transform(value) : value)
268
298
  },
269
299
  label
270
300
  }
@@ -274,8 +304,136 @@ function DateField(props) {
274
304
  );
275
305
  }
276
306
 
307
+ // src/fields/DynamicSectionField.tsx
308
+ import React5 from "react";
309
+ import { useWatch as useWatch2, useFormContext as useFormContext2 } from "react-hook-form";
310
+ function DynamicSectionField({
311
+ config,
312
+ control,
313
+ className
314
+ }) {
315
+ const { condition, fields, title, description } = config;
316
+ const form = useFormContext2();
317
+ const formValues = useWatch2({ control });
318
+ const shouldShow = condition(formValues);
319
+ if (!shouldShow) {
320
+ return null;
321
+ }
322
+ 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(
323
+ FormField,
324
+ {
325
+ key: `${fieldConfig.name}-${index}`,
326
+ config: fieldConfig,
327
+ form,
328
+ submissionState: {
329
+ isSubmitting: false,
330
+ isSubmitted: false,
331
+ isSuccess: false,
332
+ error: void 0
333
+ }
334
+ }
335
+ ))));
336
+ }
337
+
338
+ // src/fields/FieldArrayField.tsx
339
+ import React6 from "react";
340
+ import { useFieldArray, useFormContext as useFormContext3 } from "react-hook-form";
341
+ import { Button as Button2 } from "@heroui/react";
342
+ function FieldArrayField({
343
+ config,
344
+ className
345
+ }) {
346
+ const {
347
+ name,
348
+ fields: fieldConfigs,
349
+ min = 0,
350
+ max = 10,
351
+ addButtonText = "Add Item",
352
+ removeButtonText = "Remove"
353
+ } = config;
354
+ const form = useFormContext3();
355
+ if (!form || !form.control) {
356
+ return null;
357
+ }
358
+ const { control } = form;
359
+ const { fields, append, remove } = useFieldArray({
360
+ control,
361
+ name
362
+ // FieldArray name
363
+ });
364
+ const canAdd = fields.length < max;
365
+ const canRemove = fields.length > min;
366
+ const handleAdd = () => {
367
+ if (canAdd) {
368
+ const defaultValues = fieldConfigs.reduce((acc, fieldConfig) => {
369
+ const fieldName = fieldConfig.name;
370
+ if (fieldConfig.type === "checkbox" || fieldConfig.type === "switch") {
371
+ acc[fieldName] = false;
372
+ } else if (fieldConfig.type === "slider") {
373
+ acc[fieldName] = 0;
374
+ } else {
375
+ acc[fieldName] = "";
376
+ }
377
+ return acc;
378
+ }, {});
379
+ append(defaultValues);
380
+ }
381
+ };
382
+ const handleRemove = (index) => {
383
+ if (canRemove) {
384
+ remove(index);
385
+ }
386
+ };
387
+ return /* @__PURE__ */ React6.createElement("div", { className }, /* @__PURE__ */ React6.createElement("div", { className: "space-y-4" }, fields.map((field2, index) => /* @__PURE__ */ React6.createElement("div", { key: field2.id, className: "border border-gray-200 rounded-lg p-4 space-y-4" }, /* @__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(
388
+ Button2,
389
+ {
390
+ size: "sm",
391
+ variant: "light",
392
+ color: "danger",
393
+ startContent: "\u{1F5D1}\uFE0F",
394
+ onPress: () => handleRemove(index),
395
+ "aria-label": `${removeButtonText} ${config.label} ${index + 1}`
396
+ },
397
+ removeButtonText
398
+ )), /* @__PURE__ */ React6.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, fieldConfigs.map((fieldConfig) => /* @__PURE__ */ React6.createElement(
399
+ FormField,
400
+ {
401
+ key: `${fieldConfig.name}-${index}`,
402
+ config: {
403
+ ...fieldConfig,
404
+ name: `${name}.${index}.${fieldConfig.name}`
405
+ },
406
+ form,
407
+ submissionState: {
408
+ isSubmitting: false,
409
+ isSubmitted: false,
410
+ isSuccess: false,
411
+ error: void 0
412
+ }
413
+ }
414
+ ))))), canAdd && /* @__PURE__ */ React6.createElement(
415
+ Button2,
416
+ {
417
+ variant: "bordered",
418
+ startContent: "\u2795",
419
+ onPress: handleAdd,
420
+ className: "w-full"
421
+ },
422
+ addButtonText
423
+ ), 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(
424
+ Button2,
425
+ {
426
+ variant: "bordered",
427
+ startContent: "\u2795",
428
+ onPress: handleAdd,
429
+ className: "mt-2"
430
+ },
431
+ addButtonText
432
+ ))));
433
+ }
434
+
277
435
  // src/fields/FileField.tsx
278
- import React4 from "react";
436
+ import React7 from "react";
279
437
  import { Controller as Controller3 } from "react-hook-form";
280
438
  function CoercedFileInput(props) {
281
439
  const {
@@ -283,13 +441,13 @@ function CoercedFileInput(props) {
283
441
  description,
284
442
  disabled,
285
443
  errorMessage,
286
- field,
444
+ field: field2,
287
445
  fileProps,
288
446
  label,
289
447
  multiple
290
448
  } = props;
291
449
  const defaults = useHeroHookFormDefaults();
292
- return /* @__PURE__ */ React4.createElement(
450
+ return /* @__PURE__ */ React7.createElement(
293
451
  Input,
294
452
  {
295
453
  ...defaults.input,
@@ -302,11 +460,11 @@ function CoercedFileInput(props) {
302
460
  label,
303
461
  multiple,
304
462
  type: "file",
305
- value: field.value ? "" : "",
306
- onBlur: field.onBlur,
463
+ value: field2.value ? "" : "",
464
+ onBlur: field2.onBlur,
307
465
  onChange: (e) => {
308
466
  const target = e.target;
309
- field.onChange(target.files);
467
+ field2.onChange(target.files);
310
468
  }
311
469
  }
312
470
  );
@@ -325,12 +483,12 @@ function FileField(props) {
325
483
  rules,
326
484
  transform
327
485
  } = props;
328
- return /* @__PURE__ */ React4.createElement(
486
+ return /* @__PURE__ */ React7.createElement(
329
487
  Controller3,
330
488
  {
331
489
  control,
332
490
  name,
333
- render: ({ field, fieldState }) => /* @__PURE__ */ React4.createElement("div", { className }, /* @__PURE__ */ React4.createElement(
491
+ render: ({ field: field2, fieldState }) => /* @__PURE__ */ React7.createElement("div", { className }, /* @__PURE__ */ React7.createElement(
334
492
  CoercedFileInput,
335
493
  {
336
494
  accept,
@@ -338,8 +496,8 @@ function FileField(props) {
338
496
  disabled: isDisabled,
339
497
  errorMessage: fieldState.error?.message,
340
498
  field: {
341
- ...field,
342
- onChange: (value) => field.onChange(transform ? transform(value) : value)
499
+ ...field2,
500
+ onChange: (value) => field2.onChange(transform ? transform(value) : value)
343
501
  },
344
502
  fileProps,
345
503
  label,
@@ -352,15 +510,12 @@ function FileField(props) {
352
510
  }
353
511
 
354
512
  // src/fields/FontPickerField.tsx
355
- import React5 from "react";
513
+ import React8 from "react";
356
514
  import { Controller as Controller4 } from "react-hook-form";
357
515
  var FontPickerComponent = null;
358
- try {
359
- const fontPickerModule = __require("@rachelallyson/heroui-font-picker");
360
- FontPickerComponent = fontPickerModule.FontPicker;
361
- } catch (e) {
362
- console.debug("Font picker package not available - FontPickerField will show fallback UI");
363
- }
516
+ var fontPickerLoaded = false;
517
+ var fontPickerLoading = false;
518
+ var loadingCallbacks = [];
364
519
  function FontPickerField(props) {
365
520
  const {
366
521
  className,
@@ -372,21 +527,86 @@ function FontPickerField(props) {
372
527
  name,
373
528
  rules
374
529
  } = props;
375
- if (!FontPickerComponent) {
376
- 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."))));
530
+ const [fontPickerState, setFontPickerState] = React8.useState({
531
+ component: FontPickerComponent,
532
+ loading: false,
533
+ error: null
534
+ });
535
+ React8.useEffect(() => {
536
+ if (fontPickerLoaded && FontPickerComponent) {
537
+ setFontPickerState({
538
+ component: FontPickerComponent,
539
+ loading: false,
540
+ error: null
541
+ });
542
+ return;
543
+ }
544
+ if (fontPickerLoading) {
545
+ setFontPickerState((prev) => ({ ...prev, loading: true }));
546
+ const callback = () => {
547
+ if (fontPickerLoaded && FontPickerComponent) {
548
+ setFontPickerState({
549
+ component: FontPickerComponent,
550
+ loading: false,
551
+ error: null
552
+ });
553
+ } else {
554
+ setFontPickerState({
555
+ component: null,
556
+ loading: false,
557
+ error: "Font picker package not found"
558
+ });
559
+ }
560
+ };
561
+ loadingCallbacks.push(callback);
562
+ return;
563
+ }
564
+ const loadFontPicker = async () => {
565
+ fontPickerLoading = true;
566
+ setFontPickerState((prev) => ({ ...prev, loading: true }));
567
+ try {
568
+ const fontPickerModule = await import("@rachelallyson/heroui-font-picker");
569
+ FontPickerComponent = fontPickerModule.FontPicker || fontPickerModule.default;
570
+ fontPickerLoaded = true;
571
+ fontPickerLoading = false;
572
+ setFontPickerState({
573
+ component: FontPickerComponent,
574
+ loading: false,
575
+ error: null
576
+ });
577
+ loadingCallbacks.forEach((callback) => callback());
578
+ loadingCallbacks.length = 0;
579
+ } catch (error) {
580
+ fontPickerLoading = false;
581
+ setFontPickerState({
582
+ component: null,
583
+ loading: false,
584
+ error: "Font picker package not found"
585
+ });
586
+ loadingCallbacks.forEach((callback) => callback());
587
+ loadingCallbacks.length = 0;
588
+ }
589
+ };
590
+ void loadFontPicker();
591
+ }, []);
592
+ if (fontPickerState.loading) {
593
+ 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..."))));
594
+ }
595
+ if (!fontPickerState.component) {
596
+ 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."))));
377
597
  }
378
- return /* @__PURE__ */ React5.createElement(
598
+ return /* @__PURE__ */ React8.createElement(
379
599
  Controller4,
380
600
  {
381
601
  control,
382
602
  name,
383
- render: ({ field, fieldState }) => /* @__PURE__ */ React5.createElement(
384
- FontPickerComponent,
603
+ render: ({ field: field2, fieldState }) => /* @__PURE__ */ React8.createElement(
604
+ fontPickerState.component,
385
605
  {
386
606
  label,
387
607
  description,
388
- value: field.value ?? "",
389
- onSelectionChange: (value) => field.onChange(value),
608
+ value: field2.value ?? "",
609
+ onSelectionChange: (value) => field2.onChange(value),
390
610
  errorMessage: fieldState.error?.message,
391
611
  isDisabled,
392
612
  className,
@@ -399,12 +619,12 @@ function FontPickerField(props) {
399
619
  }
400
620
 
401
621
  // src/fields/InputField.tsx
402
- import React6 from "react";
622
+ import React9 from "react";
403
623
  import { Controller as Controller5 } from "react-hook-form";
404
624
  function CoercedInput(props) {
405
- const { description, disabled, errorMessage, field, inputProps, label } = props;
625
+ const { description, disabled, errorMessage, field: field2, inputProps, label } = props;
406
626
  const defaults = useHeroHookFormDefaults();
407
- return /* @__PURE__ */ React6.createElement(
627
+ return /* @__PURE__ */ React9.createElement(
408
628
  Input,
409
629
  {
410
630
  ...defaults.input,
@@ -414,13 +634,13 @@ function CoercedInput(props) {
414
634
  isDisabled: disabled,
415
635
  isInvalid: Boolean(errorMessage),
416
636
  label,
417
- value: field.value ?? "",
418
- onBlur: field.onBlur,
419
- onValueChange: field.onChange
637
+ value: field2.value ?? "",
638
+ onBlur: field2.onBlur,
639
+ onValueChange: field2.onChange
420
640
  }
421
641
  );
422
642
  }
423
- function InputField(props) {
643
+ var InputField = React9.memo((props) => {
424
644
  const {
425
645
  className,
426
646
  control,
@@ -432,27 +652,27 @@ function InputField(props) {
432
652
  rules,
433
653
  transform
434
654
  } = props;
435
- return /* @__PURE__ */ React6.createElement(
655
+ return /* @__PURE__ */ React9.createElement(
436
656
  Controller5,
437
657
  {
438
658
  control,
439
659
  name,
440
- render: ({ field, fieldState }) => /* @__PURE__ */ React6.createElement("div", { className }, /* @__PURE__ */ React6.createElement(
660
+ render: ({ field: field2, fieldState }) => /* @__PURE__ */ React9.createElement("div", { className }, /* @__PURE__ */ React9.createElement(
441
661
  CoercedInput,
442
662
  {
443
663
  description,
444
664
  disabled: isDisabled,
445
665
  errorMessage: fieldState.error?.message,
446
666
  field: {
447
- ...field,
667
+ ...field2,
448
668
  onChange: (value) => {
449
669
  if (inputProps?.type === "number") {
450
670
  const numValue = value === "" ? void 0 : Number(value);
451
- field.onChange(
671
+ field2.onChange(
452
672
  transform ? transform(String(numValue)) : numValue
453
673
  );
454
674
  } else {
455
- field.onChange(transform ? transform(value) : value);
675
+ field2.onChange(transform ? transform(value) : value);
456
676
  }
457
677
  }
458
678
  },
@@ -463,10 +683,10 @@ function InputField(props) {
463
683
  rules
464
684
  }
465
685
  );
466
- }
686
+ });
467
687
 
468
688
  // src/fields/RadioGroupField.tsx
469
- import React7 from "react";
689
+ import React10 from "react";
470
690
  import { Controller as Controller6 } from "react-hook-form";
471
691
  function RadioGroupField(props) {
472
692
  const {
@@ -481,12 +701,12 @@ function RadioGroupField(props) {
481
701
  rules
482
702
  } = props;
483
703
  const defaults = useHeroHookFormDefaults();
484
- return /* @__PURE__ */ React7.createElement(
704
+ return /* @__PURE__ */ React10.createElement(
485
705
  Controller6,
486
706
  {
487
707
  control,
488
708
  name,
489
- render: ({ field, fieldState }) => /* @__PURE__ */ React7.createElement("div", { className }, /* @__PURE__ */ React7.createElement(
709
+ render: ({ field: field2, fieldState }) => /* @__PURE__ */ React10.createElement("div", { className }, /* @__PURE__ */ React10.createElement(
490
710
  RadioGroup,
491
711
  {
492
712
  ...defaults.radioGroup,
@@ -495,11 +715,11 @@ function RadioGroupField(props) {
495
715
  isDisabled,
496
716
  isInvalid: Boolean(fieldState.error),
497
717
  label,
498
- value: String(field.value ?? ""),
499
- onBlur: field.onBlur,
500
- onValueChange: (val) => field.onChange(val)
718
+ value: String(field2.value ?? ""),
719
+ onBlur: field2.onBlur,
720
+ onValueChange: (val) => field2.onChange(val)
501
721
  },
502
- options.map((opt) => /* @__PURE__ */ React7.createElement(
722
+ options.map((opt) => /* @__PURE__ */ React10.createElement(
503
723
  Radio,
504
724
  {
505
725
  key: String(opt.value),
@@ -508,14 +728,14 @@ function RadioGroupField(props) {
508
728
  },
509
729
  opt.label
510
730
  ))
511
- ), fieldState.error?.message ? /* @__PURE__ */ React7.createElement("p", { className: "text-tiny text-danger mt-1" }, fieldState.error.message) : null),
731
+ ), fieldState.error?.message ? /* @__PURE__ */ React10.createElement("p", { className: "text-tiny text-danger mt-1" }, fieldState.error.message) : null),
512
732
  rules
513
733
  }
514
734
  );
515
735
  }
516
736
 
517
737
  // src/fields/SelectField.tsx
518
- import React8 from "react";
738
+ import React11 from "react";
519
739
  import { Controller as Controller7 } from "react-hook-form";
520
740
  function SelectField(props) {
521
741
  const {
@@ -531,14 +751,14 @@ function SelectField(props) {
531
751
  selectProps
532
752
  } = props;
533
753
  const defaults = useHeroHookFormDefaults();
534
- return /* @__PURE__ */ React8.createElement(
754
+ return /* @__PURE__ */ React11.createElement(
535
755
  Controller7,
536
756
  {
537
757
  control,
538
758
  name,
539
- render: ({ field, fieldState }) => {
540
- const selectedKey = field.value;
541
- return /* @__PURE__ */ React8.createElement("div", { className }, /* @__PURE__ */ React8.createElement(
759
+ render: ({ field: field2, fieldState }) => {
760
+ const selectedKey = field2.value;
761
+ return /* @__PURE__ */ React11.createElement("div", { className }, /* @__PURE__ */ React11.createElement(
542
762
  Select,
543
763
  {
544
764
  ...defaults.select,
@@ -553,10 +773,10 @@ function SelectField(props) {
553
773
  onSelectionChange: (keys) => {
554
774
  const keyArray = Array.from(keys);
555
775
  const next = keyArray[0] ?? "";
556
- field.onChange(next);
776
+ field2.onChange(next);
557
777
  }
558
778
  },
559
- options.map((opt) => /* @__PURE__ */ React8.createElement(
779
+ options.map((opt) => /* @__PURE__ */ React11.createElement(
560
780
  SelectItem,
561
781
  {
562
782
  key: String(opt.value),
@@ -573,12 +793,12 @@ function SelectField(props) {
573
793
  }
574
794
 
575
795
  // src/fields/SliderField.tsx
576
- import React9 from "react";
796
+ import React12 from "react";
577
797
  import { Controller as Controller8 } from "react-hook-form";
578
798
  function CoercedSlider(props) {
579
- const { description, disabled, errorMessage, field, label, sliderProps } = props;
799
+ const { description, disabled, errorMessage, field: field2, label, sliderProps } = props;
580
800
  const defaults = useHeroHookFormDefaults();
581
- return /* @__PURE__ */ React9.createElement(
801
+ return /* @__PURE__ */ React12.createElement(
582
802
  Slider,
583
803
  {
584
804
  ...defaults.slider,
@@ -588,9 +808,9 @@ function CoercedSlider(props) {
588
808
  isDisabled: disabled,
589
809
  isInvalid: Boolean(errorMessage),
590
810
  label,
591
- value: field.value ?? 0,
592
- onBlur: field.onBlur,
593
- onValueChange: field.onChange
811
+ value: field2.value ?? 0,
812
+ onBlur: field2.onBlur,
813
+ onValueChange: field2.onChange
594
814
  }
595
815
  );
596
816
  }
@@ -606,20 +826,20 @@ function SliderField(props) {
606
826
  sliderProps,
607
827
  transform
608
828
  } = props;
609
- return /* @__PURE__ */ React9.createElement(
829
+ return /* @__PURE__ */ React12.createElement(
610
830
  Controller8,
611
831
  {
612
832
  control,
613
833
  name,
614
- render: ({ field, fieldState }) => /* @__PURE__ */ React9.createElement("div", { className }, /* @__PURE__ */ React9.createElement(
834
+ render: ({ field: field2, fieldState }) => /* @__PURE__ */ React12.createElement("div", { className }, /* @__PURE__ */ React12.createElement(
615
835
  CoercedSlider,
616
836
  {
617
837
  description,
618
838
  disabled: isDisabled,
619
839
  errorMessage: fieldState.error?.message,
620
840
  field: {
621
- ...field,
622
- onChange: (value) => field.onChange(transform ? transform(value) : value)
841
+ ...field2,
842
+ onChange: (value) => field2.onChange(transform ? transform(value) : value)
623
843
  },
624
844
  label,
625
845
  sliderProps
@@ -631,7 +851,7 @@ function SliderField(props) {
631
851
  }
632
852
 
633
853
  // src/fields/SwitchField.tsx
634
- import React10 from "react";
854
+ import React13 from "react";
635
855
  import { Controller as Controller9 } from "react-hook-form";
636
856
  function SwitchField(props) {
637
857
  const {
@@ -645,30 +865,30 @@ function SwitchField(props) {
645
865
  switchProps
646
866
  } = props;
647
867
  const defaults = useHeroHookFormDefaults();
648
- return /* @__PURE__ */ React10.createElement(
868
+ return /* @__PURE__ */ React13.createElement(
649
869
  Controller9,
650
870
  {
651
871
  control,
652
872
  name,
653
- render: ({ field, fieldState }) => /* @__PURE__ */ React10.createElement("div", { className }, /* @__PURE__ */ React10.createElement(
873
+ render: ({ field: field2, fieldState }) => /* @__PURE__ */ React13.createElement("div", { className }, /* @__PURE__ */ React13.createElement(
654
874
  Switch,
655
875
  {
656
876
  ...defaults.switch,
657
877
  ...switchProps,
658
878
  isDisabled,
659
- isSelected: Boolean(field.value),
660
- onBlur: field.onBlur,
661
- onValueChange: (val) => field.onChange(val)
879
+ isSelected: Boolean(field2.value),
880
+ onBlur: field2.onBlur,
881
+ onValueChange: (val) => field2.onChange(val)
662
882
  },
663
883
  label
664
- ), 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),
884
+ ), 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),
665
885
  rules
666
886
  }
667
887
  );
668
888
  }
669
889
 
670
890
  // src/fields/TextareaField.tsx
671
- import React11 from "react";
891
+ import React14 from "react";
672
892
  import { Controller as Controller10 } from "react-hook-form";
673
893
  function TextareaField(props) {
674
894
  const {
@@ -682,12 +902,12 @@ function TextareaField(props) {
682
902
  textareaProps
683
903
  } = props;
684
904
  const defaults = useHeroHookFormDefaults();
685
- return /* @__PURE__ */ React11.createElement(
905
+ return /* @__PURE__ */ React14.createElement(
686
906
  Controller10,
687
907
  {
688
908
  control,
689
909
  name,
690
- render: ({ field, fieldState }) => /* @__PURE__ */ React11.createElement("div", { className }, /* @__PURE__ */ React11.createElement(
910
+ render: ({ field: field2, fieldState }) => /* @__PURE__ */ React14.createElement("div", { className }, /* @__PURE__ */ React14.createElement(
691
911
  Textarea,
692
912
  {
693
913
  ...defaults.textarea,
@@ -697,9 +917,9 @@ function TextareaField(props) {
697
917
  isDisabled,
698
918
  isInvalid: Boolean(fieldState.error),
699
919
  label,
700
- value: field.value ?? "",
701
- onBlur: field.onBlur,
702
- onValueChange: field.onChange
920
+ value: field2.value ?? "",
921
+ onBlur: field2.onBlur,
922
+ onValueChange: field2.onChange
703
923
  }
704
924
  )),
705
925
  rules
@@ -708,13 +928,16 @@ function TextareaField(props) {
708
928
  }
709
929
 
710
930
  // src/components/FormField.tsx
711
- function FormField({
931
+ var FormField = React15.memo(({
712
932
  config,
713
933
  form,
714
934
  submissionState
715
- }) {
935
+ }) => {
936
+ if (!form || !form.control) {
937
+ return null;
938
+ }
716
939
  const { control } = form;
717
- const watchedValues = useWatch({ control });
940
+ const watchedValues = useWatch3({ control });
718
941
  if (config.condition && !config.condition(watchedValues)) {
719
942
  return null;
720
943
  }
@@ -736,7 +959,7 @@ function FormField({
736
959
  };
737
960
  switch (config.type) {
738
961
  case "input":
739
- return /* @__PURE__ */ React12.createElement(
962
+ return /* @__PURE__ */ React15.createElement(
740
963
  InputField,
741
964
  {
742
965
  ...baseProps,
@@ -746,7 +969,7 @@ function FormField({
746
969
  }
747
970
  );
748
971
  case "textarea":
749
- return /* @__PURE__ */ React12.createElement(
972
+ return /* @__PURE__ */ React15.createElement(
750
973
  TextareaField,
751
974
  {
752
975
  ...baseProps,
@@ -756,7 +979,7 @@ function FormField({
756
979
  }
757
980
  );
758
981
  case "select":
759
- return /* @__PURE__ */ React12.createElement(
982
+ return /* @__PURE__ */ React15.createElement(
760
983
  SelectField,
761
984
  {
762
985
  ...baseProps,
@@ -770,7 +993,7 @@ function FormField({
770
993
  }
771
994
  );
772
995
  case "checkbox":
773
- return /* @__PURE__ */ React12.createElement(
996
+ return /* @__PURE__ */ React15.createElement(
774
997
  CheckboxField,
775
998
  {
776
999
  ...baseProps,
@@ -780,7 +1003,7 @@ function FormField({
780
1003
  }
781
1004
  );
782
1005
  case "radio":
783
- return /* @__PURE__ */ React12.createElement(
1006
+ return /* @__PURE__ */ React15.createElement(
784
1007
  RadioGroupField,
785
1008
  {
786
1009
  ...baseProps,
@@ -794,7 +1017,7 @@ function FormField({
794
1017
  }
795
1018
  );
796
1019
  case "switch":
797
- return /* @__PURE__ */ React12.createElement(
1020
+ return /* @__PURE__ */ React15.createElement(
798
1021
  SwitchField,
799
1022
  {
800
1023
  ...baseProps,
@@ -804,7 +1027,7 @@ function FormField({
804
1027
  }
805
1028
  );
806
1029
  case "slider":
807
- return /* @__PURE__ */ React12.createElement(
1030
+ return /* @__PURE__ */ React15.createElement(
808
1031
  SliderField,
809
1032
  {
810
1033
  ...baseProps,
@@ -814,7 +1037,7 @@ function FormField({
814
1037
  }
815
1038
  );
816
1039
  case "date":
817
- return /* @__PURE__ */ React12.createElement(
1040
+ return /* @__PURE__ */ React15.createElement(
818
1041
  DateField,
819
1042
  {
820
1043
  ...baseProps,
@@ -824,7 +1047,7 @@ function FormField({
824
1047
  }
825
1048
  );
826
1049
  case "file":
827
- return /* @__PURE__ */ React12.createElement(
1050
+ return /* @__PURE__ */ React15.createElement(
828
1051
  FileField,
829
1052
  {
830
1053
  ...baseProps,
@@ -836,7 +1059,7 @@ function FormField({
836
1059
  }
837
1060
  );
838
1061
  case "fontPicker":
839
- return /* @__PURE__ */ React12.createElement(
1062
+ return /* @__PURE__ */ React15.createElement(
840
1063
  FontPickerField,
841
1064
  {
842
1065
  ...baseProps,
@@ -853,13 +1076,39 @@ function FormField({
853
1076
  isSubmitting: submissionState.isSubmitting,
854
1077
  name: config.name
855
1078
  });
1079
+ case "conditional":
1080
+ return /* @__PURE__ */ React15.createElement(
1081
+ ConditionalField,
1082
+ {
1083
+ config,
1084
+ control,
1085
+ className: config.className
1086
+ }
1087
+ );
1088
+ case "fieldArray":
1089
+ return /* @__PURE__ */ React15.createElement(
1090
+ FieldArrayField,
1091
+ {
1092
+ config,
1093
+ className: config.className
1094
+ }
1095
+ );
1096
+ case "dynamicSection":
1097
+ return /* @__PURE__ */ React15.createElement(
1098
+ DynamicSectionField,
1099
+ {
1100
+ config,
1101
+ control,
1102
+ className: config.className
1103
+ }
1104
+ );
856
1105
  default: {
857
1106
  const fieldType = config.type;
858
1107
  console.warn(`Unknown field type: ${fieldType}`);
859
1108
  return null;
860
1109
  }
861
1110
  }
862
- }
1111
+ });
863
1112
 
864
1113
  // src/components/Form.tsx
865
1114
  function ConfigurableForm({
@@ -896,16 +1145,16 @@ function ConfigurableForm({
896
1145
  });
897
1146
  const renderFields = () => {
898
1147
  if (layout === "grid") {
899
- return /* @__PURE__ */ React13.createElement(
1148
+ return /* @__PURE__ */ React16.createElement(
900
1149
  "div",
901
1150
  {
902
1151
  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"}`
903
1152
  },
904
- fields.map((field) => /* @__PURE__ */ React13.createElement(
1153
+ fields.map((field2) => /* @__PURE__ */ React16.createElement(
905
1154
  FormField,
906
1155
  {
907
- key: field.name,
908
- config: field,
1156
+ key: field2.name,
1157
+ config: field2,
909
1158
  form,
910
1159
  submissionState
911
1160
  }
@@ -913,21 +1162,21 @@ function ConfigurableForm({
913
1162
  );
914
1163
  }
915
1164
  if (layout === "horizontal") {
916
- return /* @__PURE__ */ React13.createElement("div", { className: `grid gap-${spacing} grid-cols-1 md:grid-cols-2` }, fields.map((field) => /* @__PURE__ */ React13.createElement(
1165
+ return /* @__PURE__ */ React16.createElement("div", { className: `grid gap-${spacing} grid-cols-1 md:grid-cols-2` }, fields.map((field2) => /* @__PURE__ */ React16.createElement(
917
1166
  FormField,
918
1167
  {
919
- key: field.name,
920
- config: field,
1168
+ key: field2.name,
1169
+ config: field2,
921
1170
  form,
922
1171
  submissionState
923
1172
  }
924
1173
  )));
925
1174
  }
926
- return /* @__PURE__ */ React13.createElement("div", { className: `space-y-${spacing}` }, fields.map((field) => /* @__PURE__ */ React13.createElement(
1175
+ return /* @__PURE__ */ React16.createElement("div", { className: `space-y-${spacing}` }, fields.map((field2) => /* @__PURE__ */ React16.createElement(
927
1176
  FormField,
928
1177
  {
929
- key: field.name,
930
- config: field,
1178
+ key: field2.name,
1179
+ config: field2,
931
1180
  form,
932
1181
  submissionState
933
1182
  }
@@ -937,24 +1186,24 @@ function ConfigurableForm({
937
1186
  e.preventDefault();
938
1187
  void handleSubmit();
939
1188
  };
940
- 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(
1189
+ 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(
941
1190
  "div",
942
1191
  {
943
1192
  className: "mb-6 p-4 bg-success-50 border border-success-200 rounded-lg",
944
1193
  "data-testid": "success-message"
945
1194
  },
946
- /* @__PURE__ */ React13.createElement("p", { className: "text-success-800 font-medium" }, "Success!"),
947
- /* @__PURE__ */ React13.createElement("p", { className: "text-success-700 text-sm mt-1" }, "Your request has been processed successfully.")
948
- ), error && /* @__PURE__ */ React13.createElement(
1195
+ /* @__PURE__ */ React16.createElement("p", { className: "text-success-800 font-medium" }, "Success!"),
1196
+ /* @__PURE__ */ React16.createElement("p", { className: "text-success-700 text-sm mt-1" }, "Your request has been processed successfully.")
1197
+ ), error && /* @__PURE__ */ React16.createElement(
949
1198
  "div",
950
1199
  {
951
1200
  className: "mb-6 p-4 bg-danger-50 border border-danger-200 rounded-lg",
952
1201
  "data-testid": "error-message"
953
1202
  },
954
- /* @__PURE__ */ React13.createElement("p", { className: "text-danger-800 font-medium" }, "Error"),
955
- /* @__PURE__ */ React13.createElement("p", { className: "text-danger-700 text-sm mt-1" }, error)
956
- ), renderFields(), /* @__PURE__ */ React13.createElement("div", { className: "mt-6 flex gap-3 justify-end" }, /* @__PURE__ */ React13.createElement(
957
- Button2,
1203
+ /* @__PURE__ */ React16.createElement("p", { className: "text-danger-800 font-medium" }, "Error"),
1204
+ /* @__PURE__ */ React16.createElement("p", { className: "text-danger-700 text-sm mt-1" }, error)
1205
+ ), renderFields(), /* @__PURE__ */ React16.createElement("div", { className: "mt-6 flex gap-3 justify-end" }, /* @__PURE__ */ React16.createElement(
1206
+ Button3,
958
1207
  {
959
1208
  color: "primary",
960
1209
  isDisabled: isSubmitting,
@@ -963,8 +1212,8 @@ function ConfigurableForm({
963
1212
  ...submitButtonProps
964
1213
  },
965
1214
  submitButtonText
966
- ), showResetButton && /* @__PURE__ */ React13.createElement(
967
- Button2,
1215
+ ), showResetButton && /* @__PURE__ */ React16.createElement(
1216
+ Button3,
968
1217
  {
969
1218
  isDisabled: isSubmitting,
970
1219
  type: "button",
@@ -976,9 +1225,9 @@ function ConfigurableForm({
976
1225
  }
977
1226
 
978
1227
  // src/hooks/useHeroForm.ts
979
- import { useFormContext } from "react-hook-form";
1228
+ import { useFormContext as useFormContext4 } from "react-hook-form";
980
1229
  function useHeroForm() {
981
- const form = useFormContext();
1230
+ const form = useFormContext4();
982
1231
  const defaults = useHeroHookFormDefaults();
983
1232
  return {
984
1233
  // All React Hook Form methods and state
@@ -989,10 +1238,10 @@ function useHeroForm() {
989
1238
  }
990
1239
 
991
1240
  // src/providers/FormProvider.tsx
992
- import React14 from "react";
1241
+ import React17 from "react";
993
1242
  import { FormProvider as RHFProvider } from "react-hook-form";
994
1243
  function FormProvider(props) {
995
- return /* @__PURE__ */ React14.createElement(RHFProvider, { ...props.methods }, /* @__PURE__ */ React14.createElement(
1244
+ return /* @__PURE__ */ React17.createElement(RHFProvider, { ...props.methods }, /* @__PURE__ */ React17.createElement(
996
1245
  "form",
997
1246
  {
998
1247
  className: props.className,
@@ -1005,22 +1254,42 @@ function FormProvider(props) {
1005
1254
  }
1006
1255
 
1007
1256
  // src/submit/SubmitButton.tsx
1008
- import React15 from "react";
1257
+ import React18 from "react";
1009
1258
  function SubmitButton(props) {
1010
- const ctx = useFormContext2();
1259
+ const ctx = useFormContext5();
1011
1260
  const loading = props.isLoading ?? ctx.formState.isSubmitting;
1261
+ const enhancedState = props.enhancedState;
1012
1262
  const isDisabledFromProps = props.buttonProps?.isDisabled ?? false;
1013
1263
  const isDisabled = Boolean(isDisabledFromProps) || Boolean(loading);
1014
1264
  const defaults = useHeroHookFormDefaults();
1015
- return /* @__PURE__ */ React15.createElement(
1265
+ const getButtonContent = () => {
1266
+ if (enhancedState?.isSuccess) {
1267
+ return /* @__PURE__ */ React18.createElement("span", { className: "inline-flex items-center gap-2" }, "\u2705", props.successText || "Success!");
1268
+ }
1269
+ if (loading) {
1270
+ return /* @__PURE__ */ React18.createElement("span", { className: "inline-flex items-center gap-2" }, "\u23F3", props.loadingText || "Submitting...");
1271
+ }
1272
+ return props.children;
1273
+ };
1274
+ const getButtonColor = () => {
1275
+ if (enhancedState?.isSuccess) {
1276
+ return "success";
1277
+ }
1278
+ if (enhancedState?.isError) {
1279
+ return "danger";
1280
+ }
1281
+ return props.buttonProps?.color || defaults.submitButton.color;
1282
+ };
1283
+ return /* @__PURE__ */ React18.createElement(
1016
1284
  Button,
1017
1285
  {
1018
1286
  type: "submit",
1019
1287
  ...defaults.submitButton,
1020
1288
  ...props.buttonProps,
1021
- isDisabled
1289
+ isDisabled,
1290
+ color: getButtonColor()
1022
1291
  },
1023
- loading ? /* @__PURE__ */ React15.createElement("span", { className: "inline-flex items-center gap-2" }, /* @__PURE__ */ React15.createElement(Spinner, { size: "sm" }), "Submitting\u2026") : props.children
1292
+ getButtonContent()
1024
1293
  );
1025
1294
  }
1026
1295
 
@@ -1211,13 +1480,69 @@ var commonValidations = {
1211
1480
  requiredCheckbox: (fieldName) => createRequiredCheckboxSchema(fieldName),
1212
1481
  url: createUrlSchema()
1213
1482
  };
1483
+ var crossFieldValidation = {
1484
+ /**
1485
+ * Password confirmation validation
1486
+ */
1487
+ passwordConfirmation: (passwordField, confirmField) => {
1488
+ return z.object({
1489
+ [passwordField]: z.string(),
1490
+ [confirmField]: z.string()
1491
+ }).refine(
1492
+ (data) => data[passwordField] === data[confirmField],
1493
+ {
1494
+ message: "Passwords do not match",
1495
+ path: [confirmField]
1496
+ }
1497
+ );
1498
+ },
1499
+ /**
1500
+ * Date range validation
1501
+ */
1502
+ dateRange: (startField, endField) => {
1503
+ return z.object({
1504
+ [startField]: z.string(),
1505
+ [endField]: z.string()
1506
+ }).refine(
1507
+ (data) => {
1508
+ const startDate = new Date(data[startField]);
1509
+ const endDate = new Date(data[endField]);
1510
+ return startDate < endDate;
1511
+ },
1512
+ {
1513
+ message: "End date must be after start date",
1514
+ path: [endField]
1515
+ }
1516
+ );
1517
+ },
1518
+ /**
1519
+ * Conditional required field validation
1520
+ */
1521
+ conditionalRequired: (field2, conditionField, conditionValue) => {
1522
+ return z.object({
1523
+ [field2]: z.string(),
1524
+ [conditionField]: z.any()
1525
+ }).refine(
1526
+ (data) => {
1527
+ if (data[conditionField] === conditionValue) {
1528
+ return data[field2] && data[field2].trim().length > 0;
1529
+ }
1530
+ return true;
1531
+ },
1532
+ {
1533
+ message: "This field is required",
1534
+ path: [field2]
1535
+ }
1536
+ );
1537
+ }
1538
+ };
1214
1539
 
1215
1540
  // src/index.ts
1216
- import { useFormContext as useFormContext2 } from "react-hook-form";
1541
+ import { useFormContext as useFormContext5 } from "react-hook-form";
1217
1542
 
1218
1543
  // src/components/ZodForm.tsx
1219
- import React16 from "react";
1220
- import { Button as Button3 } from "@heroui/react";
1544
+ import React20 from "react";
1545
+ import { Button as Button5 } from "@heroui/react";
1221
1546
 
1222
1547
  // src/zod-integration.ts
1223
1548
  import { useForm as useForm2 } from "react-hook-form";
@@ -1260,6 +1585,146 @@ function createZodFormConfig(schema, fields, defaultValues) {
1260
1585
  };
1261
1586
  }
1262
1587
 
1588
+ // src/hooks/useEnhancedFormState.ts
1589
+ import { useCallback, useEffect, useState as useState2 } from "react";
1590
+ function useEnhancedFormState(form, options = {}) {
1591
+ const {
1592
+ onSuccess,
1593
+ onError,
1594
+ successMessage = "Form submitted successfully!",
1595
+ errorMessage = "An error occurred. Please try again.",
1596
+ autoReset = true,
1597
+ resetDelay = 3e3
1598
+ } = options;
1599
+ const [status, setStatus] = useState2("idle");
1600
+ const [error, setError] = useState2(void 0);
1601
+ const [submittedData, setSubmittedData] = useState2(void 0);
1602
+ const { formState, getValues } = form;
1603
+ const { errors, touchedFields, dirtyFields, isSubmitting } = formState;
1604
+ useEffect(() => {
1605
+ if (isSubmitting) {
1606
+ setStatus("submitting");
1607
+ }
1608
+ }, [isSubmitting]);
1609
+ useEffect(() => {
1610
+ if (status === "success" && autoReset) {
1611
+ const timer = setTimeout(() => {
1612
+ setStatus("idle");
1613
+ setSubmittedData(void 0);
1614
+ setError(void 0);
1615
+ }, resetDelay);
1616
+ return () => clearTimeout(timer);
1617
+ }
1618
+ }, [status, autoReset, resetDelay]);
1619
+ const handleSuccess = useCallback((data) => {
1620
+ setStatus("success");
1621
+ setSubmittedData(data);
1622
+ setError(void 0);
1623
+ onSuccess?.(data);
1624
+ }, [onSuccess]);
1625
+ const handleError = useCallback((errorMessage2) => {
1626
+ setStatus("error");
1627
+ setError(errorMessage2);
1628
+ setSubmittedData(void 0);
1629
+ onError?.(errorMessage2);
1630
+ }, [onError]);
1631
+ const reset = useCallback(() => {
1632
+ setStatus("idle");
1633
+ setError(void 0);
1634
+ setSubmittedData(void 0);
1635
+ }, []);
1636
+ return {
1637
+ status,
1638
+ isSubmitting,
1639
+ isSuccess: status === "success",
1640
+ isError: status === "error",
1641
+ error,
1642
+ submittedData,
1643
+ touchedFields: new Set(Object.keys(touchedFields)),
1644
+ dirtyFields: new Set(Object.keys(dirtyFields)),
1645
+ hasErrors: Object.keys(errors).length > 0,
1646
+ errorCount: Object.keys(errors).length,
1647
+ handleSuccess,
1648
+ handleError,
1649
+ reset
1650
+ };
1651
+ }
1652
+
1653
+ // src/components/FormStatus.tsx
1654
+ import React19 from "react";
1655
+ import { Button as Button4 } from "@heroui/react";
1656
+ function FormStatus({
1657
+ state,
1658
+ onDismiss,
1659
+ className = "",
1660
+ showDetails = false
1661
+ }) {
1662
+ const { status, isSubmitting, isSuccess, isError, error, submittedData } = state;
1663
+ if (status === "idle") {
1664
+ return null;
1665
+ }
1666
+ if (isSubmitting) {
1667
+ return /* @__PURE__ */ React19.createElement("div", { className: `flex items-center gap-3 p-4 bg-blue-50 border border-blue-200 rounded-lg ${className}` }, /* @__PURE__ */ React19.createElement("span", { className: "text-blue-600" }, "\u23F3"), /* @__PURE__ */ React19.createElement("div", null, /* @__PURE__ */ React19.createElement("p", { className: "text-sm font-medium text-blue-900" }, "Submitting form..."), showDetails && /* @__PURE__ */ React19.createElement("p", { className: "text-xs text-blue-700" }, "Please wait while we process your request.")));
1668
+ }
1669
+ if (isSuccess) {
1670
+ return /* @__PURE__ */ React19.createElement("div", { className: `flex items-center gap-3 p-4 bg-green-50 border border-green-200 rounded-lg ${className}`, "data-testid": "success-message" }, /* @__PURE__ */ React19.createElement("span", { className: "text-green-600" }, "\u2705"), /* @__PURE__ */ React19.createElement("div", { className: "flex-1" }, /* @__PURE__ */ React19.createElement("p", { className: "text-sm font-medium text-green-900" }, "Form submitted successfully!"), showDetails && submittedData && /* @__PURE__ */ React19.createElement("p", { className: "text-xs text-green-700" }, "Your data has been saved. Thank you for your submission.")), onDismiss && /* @__PURE__ */ React19.createElement(
1671
+ Button4,
1672
+ {
1673
+ size: "sm",
1674
+ variant: "light",
1675
+ isIconOnly: true,
1676
+ onPress: onDismiss,
1677
+ "aria-label": "Dismiss success message"
1678
+ },
1679
+ "\u2715"
1680
+ ));
1681
+ }
1682
+ if (isError && error) {
1683
+ return /* @__PURE__ */ React19.createElement("div", { className: `flex items-center gap-3 p-4 bg-red-50 border border-red-200 rounded-lg ${className}`, "data-testid": "error-message" }, /* @__PURE__ */ React19.createElement("span", { className: "text-red-600" }, "\u26A0\uFE0F"), /* @__PURE__ */ React19.createElement("div", { className: "flex-1" }, /* @__PURE__ */ React19.createElement("p", { className: "text-sm font-medium text-red-900" }, "Error submitting form"), /* @__PURE__ */ React19.createElement("p", { className: "text-xs text-red-700" }, error)), onDismiss && /* @__PURE__ */ React19.createElement(
1684
+ Button4,
1685
+ {
1686
+ size: "sm",
1687
+ variant: "light",
1688
+ isIconOnly: true,
1689
+ onPress: onDismiss,
1690
+ "aria-label": "Dismiss error message"
1691
+ },
1692
+ "\u2715"
1693
+ ));
1694
+ }
1695
+ return null;
1696
+ }
1697
+ function FormToast({
1698
+ state,
1699
+ onDismiss,
1700
+ position = "top-right",
1701
+ duration = 5e3
1702
+ }) {
1703
+ const [isVisible, setIsVisible] = React19.useState(false);
1704
+ React19.useEffect(() => {
1705
+ if (state.isSuccess || state.isError) {
1706
+ setIsVisible(true);
1707
+ if (duration > 0) {
1708
+ const timer = setTimeout(() => {
1709
+ setIsVisible(false);
1710
+ onDismiss?.();
1711
+ }, duration);
1712
+ return () => clearTimeout(timer);
1713
+ }
1714
+ }
1715
+ }, [state.isSuccess, state.isError, duration, onDismiss]);
1716
+ if (!isVisible) {
1717
+ return null;
1718
+ }
1719
+ const positionClasses = {
1720
+ "top-right": "top-4 right-4",
1721
+ "top-left": "top-4 left-4",
1722
+ "bottom-right": "bottom-4 right-4",
1723
+ "bottom-left": "bottom-4 left-4"
1724
+ };
1725
+ return /* @__PURE__ */ React19.createElement("div", { className: `fixed z-50 ${positionClasses[position]}` }, /* @__PURE__ */ React19.createElement(FormStatus, { state, onDismiss }));
1726
+ }
1727
+
1263
1728
  // src/components/ZodForm.tsx
1264
1729
  function ZodForm({
1265
1730
  className,
@@ -1280,97 +1745,83 @@ function ZodForm({
1280
1745
  title
1281
1746
  }) {
1282
1747
  const form = useZodForm(config);
1283
- const [submissionState, setSubmissionState] = React16.useState({
1284
- error: void 0,
1285
- isSubmitted: false,
1286
- isSubmitting: false,
1287
- isSuccess: false
1748
+ const enhancedState = useEnhancedFormState(form, {
1749
+ onSuccess,
1750
+ onError: (error) => onError?.({ message: error, field: "form" }),
1751
+ autoReset: true,
1752
+ resetDelay: 3e3
1288
1753
  });
1289
1754
  const handleSubmit = async () => {
1290
- setSubmissionState((prev) => ({
1291
- ...prev,
1292
- error: void 0,
1293
- isSubmitting: true
1294
- }));
1295
- const isValid = await form.trigger();
1296
- if (!isValid) {
1297
- setSubmissionState({
1298
- error: "Please fix the validation errors above",
1299
- isSubmitted: true,
1300
- isSubmitting: false,
1301
- isSuccess: false
1302
- });
1303
- return;
1304
- }
1305
1755
  try {
1306
- await form.handleSubmit(async (formData) => {
1307
- await onSubmit(formData);
1308
- })();
1309
- setSubmissionState({
1310
- error: void 0,
1311
- isSubmitted: true,
1312
- isSubmitting: false,
1313
- isSuccess: true
1314
- });
1315
- onSuccess?.(form.getValues());
1756
+ await form.handleSubmit(
1757
+ async (formData) => {
1758
+ await onSubmit(formData);
1759
+ enhancedState.handleSuccess(formData);
1760
+ },
1761
+ (errors) => {
1762
+ enhancedState.handleError("Please fix the validation errors above");
1763
+ }
1764
+ )();
1316
1765
  } catch (error) {
1317
1766
  const errorMessage = error instanceof Error ? error.message : "An error occurred";
1318
- setSubmissionState({
1319
- error: errorMessage,
1320
- isSubmitted: true,
1321
- isSubmitting: false,
1322
- isSuccess: false
1323
- });
1324
- onError?.({
1325
- message: errorMessage
1326
- });
1767
+ enhancedState.handleError(errorMessage);
1327
1768
  }
1328
1769
  };
1329
1770
  const resetForm = () => {
1330
1771
  form.reset();
1331
- setSubmissionState({
1332
- error: void 0,
1333
- isSubmitted: false,
1334
- isSubmitting: false,
1335
- isSuccess: false
1336
- });
1772
+ enhancedState.reset();
1337
1773
  };
1338
1774
  const renderFields = () => {
1339
1775
  if (layout === "grid") {
1340
- return /* @__PURE__ */ React16.createElement(
1776
+ return /* @__PURE__ */ React20.createElement(
1341
1777
  "div",
1342
1778
  {
1343
1779
  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"}`
1344
1780
  },
1345
- config.fields.map((field) => /* @__PURE__ */ React16.createElement(
1781
+ config.fields.map((field2) => /* @__PURE__ */ React20.createElement(
1346
1782
  FormField,
1347
1783
  {
1348
- key: field.name,
1349
- config: field,
1784
+ key: field2.name,
1785
+ config: field2,
1350
1786
  form,
1351
- submissionState
1787
+ submissionState: {
1788
+ isSubmitting: enhancedState.isSubmitting,
1789
+ isSubmitted: enhancedState.status !== "idle",
1790
+ isSuccess: enhancedState.isSuccess,
1791
+ error: enhancedState.error
1792
+ }
1352
1793
  }
1353
1794
  ))
1354
1795
  );
1355
1796
  }
1356
1797
  if (layout === "horizontal") {
1357
- return /* @__PURE__ */ React16.createElement("div", { className: `grid gap-${spacing} grid-cols-1 md:grid-cols-2` }, config.fields.map((field) => /* @__PURE__ */ React16.createElement(
1798
+ return /* @__PURE__ */ React20.createElement("div", { className: `grid gap-${spacing} grid-cols-1 md:grid-cols-2` }, config.fields.map((field2) => /* @__PURE__ */ React20.createElement(
1358
1799
  FormField,
1359
1800
  {
1360
- key: field.name,
1361
- config: field,
1801
+ key: field2.name,
1802
+ config: field2,
1362
1803
  form,
1363
- submissionState
1804
+ submissionState: {
1805
+ isSubmitting: enhancedState.isSubmitting,
1806
+ isSubmitted: enhancedState.status !== "idle",
1807
+ isSuccess: enhancedState.isSuccess,
1808
+ error: enhancedState.error
1809
+ }
1364
1810
  }
1365
1811
  )));
1366
1812
  }
1367
- return /* @__PURE__ */ React16.createElement("div", { className: `space-y-${spacing}` }, config.fields.map((field) => /* @__PURE__ */ React16.createElement(
1813
+ return /* @__PURE__ */ React20.createElement("div", { className: `space-y-${spacing}` }, config.fields.map((field2) => /* @__PURE__ */ React20.createElement(
1368
1814
  FormField,
1369
1815
  {
1370
- key: field.name,
1371
- config: field,
1816
+ key: field2.name,
1817
+ config: field2,
1372
1818
  form,
1373
- submissionState
1819
+ submissionState: {
1820
+ isSubmitting: enhancedState.isSubmitting,
1821
+ isSubmitted: enhancedState.status !== "idle",
1822
+ isSuccess: enhancedState.isSuccess,
1823
+ error: enhancedState.error
1824
+ }
1374
1825
  }
1375
1826
  )));
1376
1827
  };
@@ -1378,7 +1829,7 @@ function ZodForm({
1378
1829
  e.preventDefault();
1379
1830
  void handleSubmit();
1380
1831
  };
1381
- React16.useEffect(() => {
1832
+ React20.useEffect(() => {
1382
1833
  if (config.onError && Object.keys(form.formState.errors).length > 0) {
1383
1834
  config.onError(form.formState.errors);
1384
1835
  }
@@ -1387,42 +1838,33 @@ function ZodForm({
1387
1838
  return render({
1388
1839
  errors: form.formState.errors,
1389
1840
  form,
1390
- isSubmitted: submissionState.isSubmitted,
1391
- isSubmitting: submissionState.isSubmitting,
1392
- isSuccess: submissionState.isSuccess,
1841
+ isSubmitted: enhancedState.status !== "idle",
1842
+ isSubmitting: enhancedState.isSubmitting,
1843
+ isSuccess: enhancedState.isSuccess,
1393
1844
  values: form.getValues()
1394
1845
  });
1395
1846
  }
1396
- 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(
1397
- "div",
1847
+ return /* @__PURE__ */ React20.createElement("form", { className, role: "form", onSubmit: handleFormSubmit }, title && /* @__PURE__ */ React20.createElement("div", { className: "mb-6" }, /* @__PURE__ */ React20.createElement("h2", { className: "text-xl font-semibold text-foreground mb-2" }, title), subtitle && /* @__PURE__ */ React20.createElement("p", { className: "text-sm text-muted-foreground" }, subtitle)), /* @__PURE__ */ React20.createElement(
1848
+ FormStatus,
1398
1849
  {
1399
- className: "mb-6 p-4 bg-success-50 border border-success-200 rounded-lg",
1400
- "data-testid": "success-message"
1401
- },
1402
- /* @__PURE__ */ React16.createElement("p", { className: "text-success-800 font-medium" }, "Success!"),
1403
- /* @__PURE__ */ React16.createElement("p", { className: "text-success-700 text-sm mt-1" }, "Your request has been processed successfully.")
1404
- ), submissionState.error && errorDisplay !== "none" && /* @__PURE__ */ React16.createElement(
1405
- "div",
1406
- {
1407
- className: "mb-6 p-4 bg-danger-50 border border-danger-200 rounded-lg",
1408
- "data-testid": "error-message"
1409
- },
1410
- /* @__PURE__ */ React16.createElement("p", { className: "text-danger-800 font-medium" }, "Error"),
1411
- /* @__PURE__ */ React16.createElement("p", { className: "text-danger-700 text-sm mt-1" }, submissionState.error)
1412
- ), renderFields(), /* @__PURE__ */ React16.createElement("div", { className: "mt-6 flex gap-3 justify-end" }, /* @__PURE__ */ React16.createElement(
1413
- Button3,
1850
+ state: enhancedState,
1851
+ onDismiss: () => enhancedState.reset(),
1852
+ showDetails: true
1853
+ }
1854
+ ), renderFields(), /* @__PURE__ */ React20.createElement("div", { className: "mt-6 flex gap-3 justify-end" }, /* @__PURE__ */ React20.createElement(
1855
+ Button5,
1414
1856
  {
1415
1857
  color: "primary",
1416
- isDisabled: submissionState.isSubmitting,
1417
- isLoading: submissionState.isSubmitting,
1858
+ isDisabled: enhancedState.isSubmitting,
1859
+ isLoading: enhancedState.isSubmitting,
1418
1860
  type: "submit",
1419
1861
  ...submitButtonProps
1420
1862
  },
1421
- submitButtonText
1422
- ), showResetButton && /* @__PURE__ */ React16.createElement(
1423
- Button3,
1863
+ enhancedState.isSuccess ? "Success!" : submitButtonText
1864
+ ), showResetButton && /* @__PURE__ */ React20.createElement(
1865
+ Button5,
1424
1866
  {
1425
- isDisabled: submissionState.isSubmitting,
1867
+ isDisabled: enhancedState.isSubmitting,
1426
1868
  type: "button",
1427
1869
  variant: "bordered",
1428
1870
  onPress: resetForm
@@ -1430,14 +1872,1209 @@ function ZodForm({
1430
1872
  resetButtonText
1431
1873
  )));
1432
1874
  }
1875
+
1876
+ // src/builders/BasicFormBuilder.ts
1877
+ var BasicFormBuilder = class {
1878
+ constructor() {
1879
+ this.fields = [];
1880
+ }
1881
+ /**
1882
+ * Add an input field
1883
+ */
1884
+ input(name, label, type = "text") {
1885
+ this.fields.push({
1886
+ name,
1887
+ label,
1888
+ type: "input",
1889
+ inputProps: { type }
1890
+ });
1891
+ return this;
1892
+ }
1893
+ /**
1894
+ * Add a textarea field
1895
+ */
1896
+ textarea(name, label, placeholder) {
1897
+ this.fields.push({
1898
+ name,
1899
+ label,
1900
+ type: "textarea",
1901
+ textareaProps: { placeholder }
1902
+ });
1903
+ return this;
1904
+ }
1905
+ /**
1906
+ * Add a select field
1907
+ */
1908
+ select(name, label, options) {
1909
+ this.fields.push({
1910
+ name,
1911
+ label,
1912
+ type: "select",
1913
+ options
1914
+ });
1915
+ return this;
1916
+ }
1917
+ /**
1918
+ * Add a checkbox field
1919
+ */
1920
+ checkbox(name, label) {
1921
+ this.fields.push({
1922
+ name,
1923
+ label,
1924
+ type: "checkbox"
1925
+ });
1926
+ return this;
1927
+ }
1928
+ /**
1929
+ * Add a switch field
1930
+ */
1931
+ switch(name, label) {
1932
+ this.fields.push({
1933
+ name,
1934
+ label,
1935
+ type: "switch"
1936
+ });
1937
+ return this;
1938
+ }
1939
+ /**
1940
+ * Build the final field configuration array
1941
+ */
1942
+ build() {
1943
+ return this.fields;
1944
+ }
1945
+ };
1946
+ function createBasicFormBuilder() {
1947
+ return new BasicFormBuilder();
1948
+ }
1949
+ var FormFieldHelpers = {
1950
+ /**
1951
+ * Create an input field
1952
+ */
1953
+ input: (name, label, type = "text") => ({
1954
+ name,
1955
+ label,
1956
+ type: "input",
1957
+ inputProps: { type }
1958
+ }),
1959
+ /**
1960
+ * Create a textarea field
1961
+ */
1962
+ textarea: (name, label, placeholder) => ({
1963
+ name,
1964
+ label,
1965
+ type: "textarea",
1966
+ textareaProps: { placeholder }
1967
+ }),
1968
+ /**
1969
+ * Create a select field
1970
+ */
1971
+ select: (name, label, options) => ({
1972
+ name,
1973
+ label,
1974
+ type: "select",
1975
+ options
1976
+ }),
1977
+ /**
1978
+ * Create a checkbox field
1979
+ */
1980
+ checkbox: (name, label) => ({
1981
+ name,
1982
+ label,
1983
+ type: "checkbox"
1984
+ }),
1985
+ /**
1986
+ * Create a switch field
1987
+ */
1988
+ switch: (name, label) => ({
1989
+ name,
1990
+ label,
1991
+ type: "switch"
1992
+ })
1993
+ };
1994
+ var CommonFields = {
1995
+ /**
1996
+ * Personal information fields
1997
+ */
1998
+ personal: () => [
1999
+ FormFieldHelpers.input("firstName", "First Name"),
2000
+ FormFieldHelpers.input("lastName", "Last Name"),
2001
+ FormFieldHelpers.input("email", "Email", "email"),
2002
+ FormFieldHelpers.input("phone", "Phone", "tel")
2003
+ ],
2004
+ /**
2005
+ * Address fields
2006
+ */
2007
+ address: () => [
2008
+ FormFieldHelpers.input("street", "Street Address"),
2009
+ FormFieldHelpers.input("city", "City"),
2010
+ FormFieldHelpers.input("state", "State/Province"),
2011
+ FormFieldHelpers.input("zipCode", "ZIP/Postal Code"),
2012
+ FormFieldHelpers.select(
2013
+ "country",
2014
+ "Country",
2015
+ [
2016
+ { label: "Select a country", value: "" },
2017
+ { label: "United States", value: "us" },
2018
+ { label: "Canada", value: "ca" },
2019
+ { label: "United Kingdom", value: "uk" },
2020
+ { label: "Australia", value: "au" },
2021
+ { label: "Germany", value: "de" },
2022
+ { label: "France", value: "fr" }
2023
+ ]
2024
+ )
2025
+ ],
2026
+ /**
2027
+ * Terms and conditions fields
2028
+ */
2029
+ terms: () => [
2030
+ FormFieldHelpers.checkbox("terms", "I agree to the terms and conditions"),
2031
+ FormFieldHelpers.checkbox("privacy", "I agree to the privacy policy"),
2032
+ FormFieldHelpers.checkbox("newsletter", "Subscribe to newsletter")
2033
+ ]
2034
+ };
2035
+
2036
+ // src/builders/AdvancedFormBuilder.ts
2037
+ function inputField(name, label, props) {
2038
+ return {
2039
+ name,
2040
+ label,
2041
+ type: "input",
2042
+ ...props && {
2043
+ inputProps: {
2044
+ type: props.type || "text",
2045
+ placeholder: props.placeholder,
2046
+ description: props.description,
2047
+ disabled: props.isDisabled,
2048
+ className: props.className
2049
+ }
2050
+ }
2051
+ };
2052
+ }
2053
+ function textareaField(name, label, props) {
2054
+ return {
2055
+ name,
2056
+ label,
2057
+ type: "textarea",
2058
+ ...props && {
2059
+ textareaProps: {
2060
+ placeholder: props.placeholder,
2061
+ description: props.description,
2062
+ disabled: props.isDisabled,
2063
+ className: props.className,
2064
+ rows: props.rows
2065
+ }
2066
+ }
2067
+ };
2068
+ }
2069
+ function selectField(name, label, options, props) {
2070
+ return {
2071
+ name,
2072
+ label,
2073
+ type: "select",
2074
+ options
2075
+ };
2076
+ }
2077
+ function checkboxField(name, label, props) {
2078
+ return {
2079
+ name,
2080
+ label,
2081
+ type: "checkbox",
2082
+ ...props && {
2083
+ checkboxProps: {
2084
+ disabled: props.isDisabled,
2085
+ className: props.className
2086
+ }
2087
+ }
2088
+ };
2089
+ }
2090
+ function switchField(name, label, props) {
2091
+ return {
2092
+ name,
2093
+ label,
2094
+ type: "switch",
2095
+ ...props && {
2096
+ switchProps: {
2097
+ disabled: props.isDisabled,
2098
+ className: props.className
2099
+ }
2100
+ }
2101
+ };
2102
+ }
2103
+ function radioField(name, label, options, props) {
2104
+ return {
2105
+ name,
2106
+ label,
2107
+ type: "radio",
2108
+ radioOptions: options,
2109
+ ...props && {
2110
+ radioProps: {
2111
+ isDisabled: props.isDisabled,
2112
+ className: props.className,
2113
+ orientation: props.orientation
2114
+ }
2115
+ }
2116
+ };
2117
+ }
2118
+ function sliderField(name, label, props) {
2119
+ return {
2120
+ name,
2121
+ label,
2122
+ type: "slider",
2123
+ ...props && {
2124
+ sliderProps: {
2125
+ min: props.min || 0,
2126
+ max: props.max || 100,
2127
+ step: props.step || 1,
2128
+ disabled: props.isDisabled || false,
2129
+ className: props.className || ""
2130
+ }
2131
+ }
2132
+ };
2133
+ }
2134
+ function dateField(name, label, props) {
2135
+ return {
2136
+ name,
2137
+ label,
2138
+ type: "date",
2139
+ ...props && {
2140
+ dateProps: {
2141
+ placeholder: props.placeholder || "",
2142
+ disabled: props.isDisabled || false,
2143
+ className: props.className || ""
2144
+ }
2145
+ }
2146
+ };
2147
+ }
2148
+ function fileField(name, label, props) {
2149
+ return {
2150
+ name,
2151
+ label,
2152
+ type: "file",
2153
+ ...props && {
2154
+ fileProps: {
2155
+ accept: props.accept || "",
2156
+ multiple: props.multiple || false,
2157
+ disabled: props.isDisabled || false,
2158
+ className: props.className || ""
2159
+ }
2160
+ }
2161
+ };
2162
+ }
2163
+ function fontPickerField(name, label, props) {
2164
+ return {
2165
+ name,
2166
+ label,
2167
+ type: "fontPicker",
2168
+ ...props && {
2169
+ fontPickerProps: {
2170
+ disabled: props.isDisabled || false,
2171
+ className: props.className || ""
2172
+ }
2173
+ }
2174
+ };
2175
+ }
2176
+ function createField(type, name, label, optionsOrProps, props) {
2177
+ switch (type) {
2178
+ case "input":
2179
+ return inputField(name, label, optionsOrProps);
2180
+ case "textarea":
2181
+ return textareaField(name, label, optionsOrProps);
2182
+ case "select":
2183
+ return selectField(name, label, optionsOrProps, props);
2184
+ case "checkbox":
2185
+ return checkboxField(name, label, optionsOrProps);
2186
+ case "switch":
2187
+ return switchField(name, label, optionsOrProps);
2188
+ case "radio":
2189
+ return radioField(name, label, optionsOrProps, props);
2190
+ case "slider":
2191
+ return sliderField(name, label, optionsOrProps);
2192
+ case "date":
2193
+ return dateField(name, label, optionsOrProps);
2194
+ case "file":
2195
+ return fileField(name, label, optionsOrProps);
2196
+ case "fontPicker":
2197
+ return fontPickerField(name, label, optionsOrProps);
2198
+ default:
2199
+ throw new Error(`Unknown field type: ${type}`);
2200
+ }
2201
+ }
2202
+ var AdvancedFieldBuilder = class {
2203
+ constructor() {
2204
+ this.fields = [];
2205
+ }
2206
+ field(type, name, label, optionsOrProps, props) {
2207
+ this.fields.push(createField(type, name, label, optionsOrProps, props));
2208
+ return this;
2209
+ }
2210
+ /**
2211
+ * Add a conditional field that shows/hides based on form data
2212
+ */
2213
+ conditionalField(name, condition, field2) {
2214
+ this.fields.push({
2215
+ name,
2216
+ type: "conditional",
2217
+ condition,
2218
+ field: field2
2219
+ });
2220
+ return this;
2221
+ }
2222
+ /**
2223
+ * Add a field array for dynamic repeating field groups
2224
+ */
2225
+ fieldArray(name, label, fields, options) {
2226
+ this.fields.push({
2227
+ name,
2228
+ label,
2229
+ type: "fieldArray",
2230
+ fields,
2231
+ min: options?.min,
2232
+ max: options?.max,
2233
+ addButtonText: options?.addButtonText,
2234
+ removeButtonText: options?.removeButtonText
2235
+ });
2236
+ return this;
2237
+ }
2238
+ /**
2239
+ * Add a dynamic section that shows/hides based on form data
2240
+ */
2241
+ dynamicSection(name, condition, fields, options) {
2242
+ this.fields.push({
2243
+ name,
2244
+ type: "dynamicSection",
2245
+ condition,
2246
+ fields,
2247
+ title: options?.title,
2248
+ description: options?.description
2249
+ });
2250
+ return this;
2251
+ }
2252
+ /**
2253
+ * Build the final field configuration array
2254
+ */
2255
+ build() {
2256
+ return this.fields;
2257
+ }
2258
+ };
2259
+ var FieldArrayItemBuilder = class {
2260
+ constructor() {
2261
+ this.fields = [];
2262
+ }
2263
+ field(type, name, label, optionsOrProps, props) {
2264
+ this.fields.push(createField(type, name, label, optionsOrProps, props));
2265
+ return this;
2266
+ }
2267
+ /**
2268
+ * Build the field array item configuration
2269
+ */
2270
+ build() {
2271
+ return this.fields;
2272
+ }
2273
+ };
2274
+ function createFieldArrayItemBuilder() {
2275
+ return new FieldArrayItemBuilder();
2276
+ }
2277
+ var FieldArrayBuilder = class {
2278
+ constructor(arrayName) {
2279
+ this.arrayName = arrayName;
2280
+ this.fields = [];
2281
+ }
2282
+ field(type, name, label, optionsOrProps, props) {
2283
+ const fullPath = `${this.arrayName}.${name}`;
2284
+ const fieldConfig = createField(type, fullPath, label, optionsOrProps, props);
2285
+ this.fields.push(fieldConfig);
2286
+ return this;
2287
+ }
2288
+ build() {
2289
+ return this.fields;
2290
+ }
2291
+ };
2292
+ function createFieldArrayBuilder(arrayName) {
2293
+ return new FieldArrayBuilder(arrayName);
2294
+ }
2295
+ function createAdvancedBuilder() {
2296
+ return new AdvancedFieldBuilder();
2297
+ }
2298
+
2299
+ // src/builders/TypeInferredBuilder.ts
2300
+ import { z as z3 } from "zod";
2301
+ var TypeInferredBuilder = class {
2302
+ constructor() {
2303
+ this.schemaFields = {};
2304
+ this.formFields = [];
2305
+ }
2306
+ /**
2307
+ * Add a text field
2308
+ */
2309
+ text(name, label, options) {
2310
+ const { minLength, maxLength, pattern, ...fieldOptions } = options || {};
2311
+ let zodType = z3.string();
2312
+ if (minLength) zodType = zodType.min(minLength, `${label} must be at least ${minLength} characters`);
2313
+ if (maxLength) zodType = zodType.max(maxLength, `${label} must be no more than ${maxLength} characters`);
2314
+ if (pattern) zodType = zodType.regex(new RegExp(pattern), `${label} format is invalid`);
2315
+ this.schemaFields[name] = zodType;
2316
+ this.formFields.push({
2317
+ name,
2318
+ label,
2319
+ type: "input",
2320
+ inputProps: { type: "text", ...fieldOptions }
2321
+ });
2322
+ return this;
2323
+ }
2324
+ /**
2325
+ * Add an email field
2326
+ */
2327
+ email(name, label, options) {
2328
+ this.schemaFields[name] = z3.string().email(`Please enter a valid email address`);
2329
+ this.formFields.push({
2330
+ name,
2331
+ label,
2332
+ type: "input",
2333
+ inputProps: { type: "email", ...options }
2334
+ });
2335
+ return this;
2336
+ }
2337
+ /**
2338
+ * Add a number field
2339
+ */
2340
+ number(name, label, options) {
2341
+ const { min, max, step, ...fieldOptions } = options || {};
2342
+ let zodType = z3.number();
2343
+ if (min !== void 0) zodType = zodType.min(min, `${label} must be at least ${min}`);
2344
+ if (max !== void 0) zodType = zodType.max(max, `${label} must be no more than ${max}`);
2345
+ this.schemaFields[name] = zodType;
2346
+ this.formFields.push({
2347
+ name,
2348
+ label,
2349
+ type: "input",
2350
+ inputProps: { type: "number", min, max, step, ...fieldOptions }
2351
+ });
2352
+ return this;
2353
+ }
2354
+ /**
2355
+ * Add a textarea field
2356
+ */
2357
+ textarea(name, label, options) {
2358
+ const { minLength, ...fieldOptions } = options || {};
2359
+ let zodType = z3.string();
2360
+ if (minLength) zodType = zodType.min(minLength, `${label} must be at least ${minLength} characters`);
2361
+ this.schemaFields[name] = zodType;
2362
+ this.formFields.push({
2363
+ name,
2364
+ label,
2365
+ type: "textarea",
2366
+ textareaProps: fieldOptions
2367
+ });
2368
+ return this;
2369
+ }
2370
+ /**
2371
+ * Add a select field
2372
+ */
2373
+ select(name, label, options, fieldOptions) {
2374
+ this.schemaFields[name] = z3.string().min(1, `Please select a ${label.toLowerCase()}`);
2375
+ this.formFields.push({
2376
+ name,
2377
+ label,
2378
+ type: "select",
2379
+ options
2380
+ });
2381
+ return this;
2382
+ }
2383
+ /**
2384
+ * Add a checkbox field
2385
+ */
2386
+ checkbox(name, label, options) {
2387
+ const { required = false, ...fieldOptions } = options || {};
2388
+ let zodType = z3.boolean();
2389
+ if (required) {
2390
+ zodType = zodType.refine((val) => val === true, `You must agree to ${label.toLowerCase()}`);
2391
+ }
2392
+ this.schemaFields[name] = zodType;
2393
+ this.formFields.push({
2394
+ name,
2395
+ label,
2396
+ type: "checkbox",
2397
+ checkboxProps: fieldOptions
2398
+ });
2399
+ return this;
2400
+ }
2401
+ /**
2402
+ * Add a switch field
2403
+ */
2404
+ switch(name, label, options) {
2405
+ this.schemaFields[name] = z3.boolean().optional();
2406
+ this.formFields.push({
2407
+ name,
2408
+ label,
2409
+ type: "switch",
2410
+ switchProps: options
2411
+ });
2412
+ return this;
2413
+ }
2414
+ /**
2415
+ * Add a radio field
2416
+ */
2417
+ radio(name, label, options, fieldOptions) {
2418
+ this.schemaFields[name] = z3.string().min(1, `Please select a ${label.toLowerCase()}`);
2419
+ this.formFields.push({
2420
+ name,
2421
+ label,
2422
+ type: "radio",
2423
+ radioOptions: options,
2424
+ radioProps: fieldOptions
2425
+ });
2426
+ return this;
2427
+ }
2428
+ /**
2429
+ * Add a slider field
2430
+ */
2431
+ slider(name, label, options) {
2432
+ const { min = 0, max = 100, step = 1, ...fieldOptions } = options || {};
2433
+ let zodType = z3.number();
2434
+ if (min !== void 0) zodType = zodType.min(min, `${label} must be at least ${min}`);
2435
+ if (max !== void 0) zodType = zodType.max(max, `${label} must be no more than ${max}`);
2436
+ this.schemaFields[name] = zodType;
2437
+ this.formFields.push({
2438
+ name,
2439
+ label,
2440
+ type: "slider",
2441
+ sliderProps: { min, max, step, ...fieldOptions }
2442
+ });
2443
+ return this;
2444
+ }
2445
+ /**
2446
+ * Add a date field
2447
+ */
2448
+ date(name, label, options) {
2449
+ this.schemaFields[name] = z3.string().min(1, `${label} is required`);
2450
+ this.formFields.push({
2451
+ name,
2452
+ label,
2453
+ type: "date",
2454
+ dateProps: options
2455
+ });
2456
+ return this;
2457
+ }
2458
+ /**
2459
+ * Add a file field
2460
+ */
2461
+ file(name, label, options) {
2462
+ this.schemaFields[name] = z3.any().optional();
2463
+ this.formFields.push({
2464
+ name,
2465
+ label,
2466
+ type: "file",
2467
+ fileProps: options
2468
+ });
2469
+ return this;
2470
+ }
2471
+ /**
2472
+ * Build the final schema and fields
2473
+ */
2474
+ build() {
2475
+ return {
2476
+ schema: z3.object(this.schemaFields),
2477
+ fields: this.formFields
2478
+ };
2479
+ }
2480
+ };
2481
+ function createTypeInferredBuilder() {
2482
+ return new TypeInferredBuilder();
2483
+ }
2484
+ function defineInferredForm(fieldDefinitions) {
2485
+ const builder = createTypeInferredBuilder();
2486
+ fieldDefinitions(builder);
2487
+ return builder.build();
2488
+ }
2489
+ var field = {
2490
+ text: (name, label, options) => {
2491
+ const builder = new TypeInferredBuilder();
2492
+ return builder.text(name, label, options);
2493
+ },
2494
+ email: (name, label, options) => {
2495
+ const builder = new TypeInferredBuilder();
2496
+ return builder.email(name, label, options);
2497
+ },
2498
+ number: (name, label, options) => {
2499
+ const builder = new TypeInferredBuilder();
2500
+ return builder.number(name, label, options);
2501
+ },
2502
+ textarea: (name, label, options) => {
2503
+ const builder = new TypeInferredBuilder();
2504
+ return builder.textarea(name, label, options);
2505
+ },
2506
+ select: (name, label, options, fieldOptions) => {
2507
+ const builder = new TypeInferredBuilder();
2508
+ return builder.select(name, label, options, fieldOptions);
2509
+ },
2510
+ checkbox: (name, label, options) => {
2511
+ const builder = new TypeInferredBuilder();
2512
+ return builder.checkbox(name, label, options);
2513
+ },
2514
+ switch: (name, label, options) => {
2515
+ const builder = new TypeInferredBuilder();
2516
+ return builder.switch(name, label, options);
2517
+ },
2518
+ radio: (name, label, options, fieldOptions) => {
2519
+ const builder = new TypeInferredBuilder();
2520
+ return builder.radio(name, label, options, fieldOptions);
2521
+ },
2522
+ slider: (name, label, options) => {
2523
+ const builder = new TypeInferredBuilder();
2524
+ return builder.slider(name, label, options);
2525
+ },
2526
+ date: (name, label, options) => {
2527
+ const builder = new TypeInferredBuilder();
2528
+ return builder.date(name, label, options);
2529
+ },
2530
+ file: (name, label, options) => {
2531
+ const builder = new TypeInferredBuilder();
2532
+ return builder.file(name, label, options);
2533
+ }
2534
+ };
2535
+
2536
+ // src/builders/NestedPathBuilder.ts
2537
+ var NestedPathBuilder = class {
2538
+ constructor() {
2539
+ this.fields = [];
2540
+ }
2541
+ /**
2542
+ * Create a nested object path builder
2543
+ * Usage: builder.nest("address").field("street", "Street Address")
2544
+ */
2545
+ nest(path) {
2546
+ return new NestedObjectBuilder(this, path);
2547
+ }
2548
+ /**
2549
+ * Create a section-based path builder
2550
+ * Usage: builder.section("shipping").field("street", "Street Address")
2551
+ */
2552
+ section(path) {
2553
+ return new SectionBuilder(this, path);
2554
+ }
2555
+ /**
2556
+ * Add a field with single path
2557
+ * Usage: builder.field("firstName", "First Name")
2558
+ */
2559
+ field(name, label, type = "input", props) {
2560
+ this.fields.push({
2561
+ name,
2562
+ label,
2563
+ type,
2564
+ ...props
2565
+ });
2566
+ return this;
2567
+ }
2568
+ /**
2569
+ * Add a field with path segments
2570
+ * Usage: builder.fieldPath(["user", "profile", "name"], "Full Name")
2571
+ */
2572
+ fieldPath(path, label, type = "input", props) {
2573
+ const name = path.join(".");
2574
+ this.fields.push({
2575
+ name,
2576
+ label,
2577
+ type,
2578
+ ...props
2579
+ });
2580
+ return this;
2581
+ }
2582
+ /**
2583
+ * Add a field with template literal path
2584
+ * Usage: builder.field`user.profile.name`("Full Name")
2585
+ */
2586
+ fieldTemplate(path, ...args) {
2587
+ const pathString = path[0];
2588
+ return new FieldTemplateBuilder(this, pathString);
2589
+ }
2590
+ /**
2591
+ * Return to the parent builder (no-op for root builder)
2592
+ */
2593
+ end() {
2594
+ return this;
2595
+ }
2596
+ build() {
2597
+ return this.fields;
2598
+ }
2599
+ };
2600
+ var NestedObjectBuilder = class _NestedObjectBuilder {
2601
+ constructor(parent, path) {
2602
+ this.parent = parent;
2603
+ this.path = path;
2604
+ }
2605
+ /**
2606
+ * Add a field to the current nested path
2607
+ */
2608
+ field(fieldName, label, type = "input", props) {
2609
+ const fullPath = `${this.path}.${fieldName}`;
2610
+ this.parent.fields.push({
2611
+ name: fullPath,
2612
+ label,
2613
+ type,
2614
+ ...props
2615
+ });
2616
+ return this;
2617
+ }
2618
+ /**
2619
+ * Nest deeper into the object
2620
+ */
2621
+ nest(subPath) {
2622
+ return new _NestedObjectBuilder(this.parent, `${this.path}.${subPath}`);
2623
+ }
2624
+ /**
2625
+ * Return to the parent builder
2626
+ */
2627
+ end() {
2628
+ return this.parent;
2629
+ }
2630
+ };
2631
+ var SectionBuilder = class {
2632
+ constructor(parent, path) {
2633
+ this.parent = parent;
2634
+ this.path = path;
2635
+ }
2636
+ /**
2637
+ * Add a field to the current section
2638
+ */
2639
+ field(fieldName, label, type = "input", props) {
2640
+ const fullPath = `${this.path}.${fieldName}`;
2641
+ this.parent.fields.push({
2642
+ name: fullPath,
2643
+ label,
2644
+ type,
2645
+ ...props
2646
+ });
2647
+ return this;
2648
+ }
2649
+ /**
2650
+ * Add multiple fields to the section
2651
+ */
2652
+ fields(fieldDefinitions) {
2653
+ fieldDefinitions.forEach((field2) => {
2654
+ this.field(field2.name, field2.label, field2.type, field2.props);
2655
+ });
2656
+ return this;
2657
+ }
2658
+ /**
2659
+ * Nest deeper into the section
2660
+ */
2661
+ nest(subPath) {
2662
+ return new NestedObjectBuilder(this.parent, `${this.path}.${subPath}`);
2663
+ }
2664
+ /**
2665
+ * Return to the parent builder
2666
+ */
2667
+ end() {
2668
+ return this.parent;
2669
+ }
2670
+ };
2671
+ var FieldTemplateBuilder = class {
2672
+ constructor(parent, path) {
2673
+ this.parent = parent;
2674
+ this.path = path;
2675
+ }
2676
+ /**
2677
+ * Complete the field definition
2678
+ */
2679
+ complete(label, type = "input", props) {
2680
+ this.parent.fields.push({
2681
+ name: this.path,
2682
+ label,
2683
+ type,
2684
+ ...props
2685
+ });
2686
+ return this.parent;
2687
+ }
2688
+ };
2689
+ function createNestedPathBuilder() {
2690
+ return new NestedPathBuilder();
2691
+ }
2692
+
2693
+ // src/hooks/useDebouncedValidation.ts
2694
+ import { useCallback as useCallback2, useEffect as useEffect2, useRef } from "react";
2695
+ function useDebouncedValidation(form, options = {}) {
2696
+ const { delay = 300, fields, enabled = true } = options;
2697
+ const timeoutRef = useRef(void 0);
2698
+ const lastValuesRef = useRef({});
2699
+ const debouncedTrigger = useCallback2(() => {
2700
+ if (!enabled) return;
2701
+ if (timeoutRef.current) {
2702
+ clearTimeout(timeoutRef.current);
2703
+ timeoutRef.current = void 0;
2704
+ }
2705
+ timeoutRef.current = setTimeout(async () => {
2706
+ const currentValues = form.getValues();
2707
+ const lastValues = lastValuesRef.current;
2708
+ const hasChanges = fields ? fields.some((field2) => currentValues[field2] !== lastValues[field2]) : Object.keys(currentValues).some((key) => currentValues[key] !== lastValues[key]);
2709
+ if (hasChanges) {
2710
+ lastValuesRef.current = { ...currentValues };
2711
+ if (fields && fields.length > 0) {
2712
+ await form.trigger(fields);
2713
+ } else {
2714
+ await form.trigger();
2715
+ }
2716
+ }
2717
+ }, delay);
2718
+ }, [form, delay, fields, enabled]);
2719
+ useEffect2(() => {
2720
+ return () => {
2721
+ if (timeoutRef.current) {
2722
+ clearTimeout(timeoutRef.current);
2723
+ timeoutRef.current = void 0;
2724
+ }
2725
+ };
2726
+ }, []);
2727
+ useEffect2(() => {
2728
+ if (form.formState.isSubmitSuccessful) {
2729
+ lastValuesRef.current = {};
2730
+ }
2731
+ }, [form.formState.isSubmitSuccessful]);
2732
+ return {
2733
+ debouncedTrigger,
2734
+ isDebouncing: !!timeoutRef.current
2735
+ };
2736
+ }
2737
+ function useDebouncedFieldValidation(form, fieldName, options = {}) {
2738
+ const { delay = 300, enabled = true } = options;
2739
+ const timeoutRef = useRef(void 0);
2740
+ const debouncedFieldTrigger = useCallback2(() => {
2741
+ if (!enabled) return;
2742
+ if (timeoutRef.current) {
2743
+ clearTimeout(timeoutRef.current);
2744
+ }
2745
+ timeoutRef.current = setTimeout(async () => {
2746
+ await form.trigger(fieldName);
2747
+ }, delay);
2748
+ }, [form, fieldName, delay, enabled]);
2749
+ useEffect2(() => {
2750
+ return () => {
2751
+ if (timeoutRef.current) {
2752
+ clearTimeout(timeoutRef.current);
2753
+ timeoutRef.current = void 0;
2754
+ }
2755
+ };
2756
+ }, []);
2757
+ return {
2758
+ debouncedFieldTrigger,
2759
+ isDebouncing: !!timeoutRef.current
2760
+ };
2761
+ }
2762
+
2763
+ // src/hooks/useInferredForm.ts
2764
+ import { useForm as useForm3 } from "react-hook-form";
2765
+ var zodResolver;
2766
+ try {
2767
+ zodResolver = __require("@hookform/resolvers/zod").zodResolver;
2768
+ } catch {
2769
+ }
2770
+ function useInferredForm(schema, fields, options = {}) {
2771
+ const {
2772
+ defaultValues,
2773
+ mode = "onChange",
2774
+ reValidateMode = "onChange",
2775
+ shouldFocusError = true,
2776
+ shouldUnregister = false,
2777
+ delayError = 0
2778
+ } = options;
2779
+ return useForm3({
2780
+ resolver: zodResolver ? zodResolver(schema) : void 0,
2781
+ defaultValues,
2782
+ mode,
2783
+ reValidateMode,
2784
+ shouldFocusError,
2785
+ shouldUnregister,
2786
+ delayError
2787
+ });
2788
+ }
2789
+ function useTypeInferredForm(formConfig, options = {}) {
2790
+ return useInferredForm(formConfig.schema, formConfig.fields, options);
2791
+ }
2792
+
2793
+ // src/utils/performance.ts
2794
+ import { useCallback as useCallback3, useMemo as useMemo2, useRef as useRef2 } from "react";
2795
+ function debounce(func, delay) {
2796
+ let timeoutId;
2797
+ return (...args) => {
2798
+ clearTimeout(timeoutId);
2799
+ timeoutId = setTimeout(() => func(...args), delay);
2800
+ };
2801
+ }
2802
+ function throttle(func, limit) {
2803
+ let inThrottle;
2804
+ return (...args) => {
2805
+ if (!inThrottle) {
2806
+ func(...args);
2807
+ inThrottle = true;
2808
+ setTimeout(() => inThrottle = false, limit);
2809
+ }
2810
+ };
2811
+ }
2812
+ function useMemoizedCallback(callback, deps) {
2813
+ const callbackRef = useRef2(callback);
2814
+ callbackRef.current = callback;
2815
+ return useCallback3(
2816
+ ((...args) => callbackRef.current(...args)),
2817
+ deps
2818
+ );
2819
+ }
2820
+ function shallowEqual(prevProps, nextProps) {
2821
+ const prevKeys = Object.keys(prevProps);
2822
+ const nextKeys = Object.keys(nextProps);
2823
+ if (prevKeys.length !== nextKeys.length) {
2824
+ return false;
2825
+ }
2826
+ for (const key of prevKeys) {
2827
+ if (prevProps[key] !== nextProps[key]) {
2828
+ return false;
2829
+ }
2830
+ }
2831
+ return true;
2832
+ }
2833
+ function deepEqual(prevProps, nextProps) {
2834
+ if (prevProps === nextProps) {
2835
+ return true;
2836
+ }
2837
+ if (typeof prevProps !== typeof nextProps) {
2838
+ return false;
2839
+ }
2840
+ if (typeof prevProps !== "object" || prevProps === null || nextProps === null) {
2841
+ return prevProps === nextProps;
2842
+ }
2843
+ const prevKeys = Object.keys(prevProps);
2844
+ const nextKeys = Object.keys(nextProps);
2845
+ if (prevKeys.length !== nextKeys.length) {
2846
+ return false;
2847
+ }
2848
+ for (const key of prevKeys) {
2849
+ if (!nextKeys.includes(key)) {
2850
+ return false;
2851
+ }
2852
+ if (!deepEqual(prevProps[key], nextProps[key])) {
2853
+ return false;
2854
+ }
2855
+ }
2856
+ return true;
2857
+ }
2858
+ function usePerformanceMonitor(componentName, enabled = process.env.NODE_ENV === "development") {
2859
+ const renderCountRef = useRef2(0);
2860
+ const lastRenderTimeRef = useRef2(Date.now());
2861
+ if (enabled) {
2862
+ renderCountRef.current += 1;
2863
+ const now = Date.now();
2864
+ const timeSinceLastRender = now - lastRenderTimeRef.current;
2865
+ console.log(`[Performance] ${componentName}:`, {
2866
+ renderCount: renderCountRef.current,
2867
+ timeSinceLastRender: `${timeSinceLastRender}ms`
2868
+ });
2869
+ lastRenderTimeRef.current = now;
2870
+ }
2871
+ return {
2872
+ renderCount: renderCountRef.current,
2873
+ resetRenderCount: () => {
2874
+ renderCountRef.current = 0;
2875
+ }
2876
+ };
2877
+ }
2878
+ function createOptimizedFieldHandler(onChange, options = {}) {
2879
+ const { debounce: debounceMs, throttle: throttleMs, validate = false } = options;
2880
+ let handler = onChange;
2881
+ if (throttleMs) {
2882
+ handler = throttle(handler, throttleMs);
2883
+ }
2884
+ if (debounceMs) {
2885
+ handler = debounce(handler, debounceMs);
2886
+ }
2887
+ return handler;
2888
+ }
2889
+ function useMemoizedFieldProps(props, deps) {
2890
+ return useMemo2(() => props, deps);
2891
+ }
2892
+ function useBatchedFieldUpdates(form, fields) {
2893
+ const batchRef = useRef2({});
2894
+ const timeoutRef = useRef2(void 0);
2895
+ const batchUpdate = useCallback3((fieldName, value) => {
2896
+ batchRef.current[fieldName] = value;
2897
+ if (timeoutRef.current) {
2898
+ clearTimeout(timeoutRef.current);
2899
+ }
2900
+ timeoutRef.current = setTimeout(() => {
2901
+ Object.entries(batchRef.current).forEach(([key, val]) => {
2902
+ form.setValue(key, val);
2903
+ });
2904
+ batchRef.current = {};
2905
+ }, 16);
2906
+ }, [form]);
2907
+ return { batchUpdate };
2908
+ }
2909
+
2910
+ // src/builders/validation-helpers.ts
2911
+ import { z as z4 } from "zod";
2912
+ var validationPatterns = {
2913
+ // Email validation
2914
+ email: z4.string().email("Please enter a valid email address"),
2915
+ // Phone number validation (US format)
2916
+ phoneUS: z4.string().regex(
2917
+ /^\(\d{3}\) \d{3}-\d{4}$/,
2918
+ "Please enter a valid phone number (XXX) XXX-XXXX"
2919
+ ),
2920
+ // Phone number validation (international)
2921
+ phoneInternational: z4.string().regex(
2922
+ /^\+?[\d\s\-\(\)]+$/,
2923
+ "Please enter a valid phone number"
2924
+ ),
2925
+ // URL validation
2926
+ url: z4.string().url("Please enter a valid URL"),
2927
+ // Password validation
2928
+ password: z4.string().min(8, "Password must be at least 8 characters").regex(/[A-Z]/, "Password must contain at least one uppercase letter").regex(/[a-z]/, "Password must contain at least one lowercase letter").regex(/[0-9]/, "Password must contain at least one number").regex(/[^A-Za-z0-9]/, "Password must contain at least one special character"),
2929
+ // Strong password validation
2930
+ strongPassword: z4.string().min(12, "Password must be at least 12 characters").regex(/[A-Z]/, "Password must contain at least one uppercase letter").regex(/[a-z]/, "Password must contain at least one lowercase letter").regex(/[0-9]/, "Password must contain at least one number").regex(/[^A-Za-z0-9]/, "Password must contain at least one special character"),
2931
+ // Credit card validation
2932
+ creditCard: z4.string().regex(
2933
+ /^[0-9]{4}[\s\-]?[0-9]{4}[\s\-]?[0-9]{4}[\s\-]?[0-9]{4}$/,
2934
+ "Please enter a valid credit card number"
2935
+ ),
2936
+ // SSN validation
2937
+ ssn: z4.string().regex(
2938
+ /^\d{3}-\d{2}-\d{4}$/,
2939
+ "Please enter a valid SSN (XXX-XX-XXXX)"
2940
+ ),
2941
+ // ZIP code validation
2942
+ zipCode: z4.string().regex(
2943
+ /^\d{5}(-\d{4})?$/,
2944
+ "Please enter a valid ZIP code"
2945
+ ),
2946
+ // Date validation (MM/DD/YYYY)
2947
+ date: z4.string().regex(
2948
+ /^(0[1-9]|1[0-2])\/(0[1-9]|[12][0-9]|3[01])\/\d{4}$/,
2949
+ "Please enter a valid date (MM/DD/YYYY)"
2950
+ ),
2951
+ // Time validation (HH:MM AM/PM)
2952
+ time: z4.string().regex(
2953
+ /^(0[1-9]|1[0-2]):[0-5][0-9] (AM|PM)$/i,
2954
+ "Please enter a valid time (HH:MM AM/PM)"
2955
+ )
2956
+ };
2957
+ var asyncValidation = {
2958
+ /**
2959
+ * Email availability check
2960
+ */
2961
+ emailAvailability: async (email) => {
2962
+ return new Promise((resolve) => {
2963
+ setTimeout(() => {
2964
+ const takenEmails = ["test@example.com", "admin@example.com"];
2965
+ resolve(!takenEmails.includes(email));
2966
+ }, 1e3);
2967
+ });
2968
+ },
2969
+ /**
2970
+ * Username availability check
2971
+ */
2972
+ usernameAvailability: async (username) => {
2973
+ return new Promise((resolve) => {
2974
+ setTimeout(() => {
2975
+ const takenUsernames = ["admin", "test", "user"];
2976
+ resolve(!takenUsernames.includes(username.toLowerCase()));
2977
+ }, 1e3);
2978
+ });
2979
+ }
2980
+ };
2981
+ var errorMessages = {
2982
+ required: (fieldName) => `${fieldName} is required`,
2983
+ minLength: (fieldName, min) => `${fieldName} must be at least ${min} characters`,
2984
+ maxLength: (fieldName, max) => `${fieldName} must be no more than ${max} characters`,
2985
+ min: (fieldName, min) => `${fieldName} must be at least ${min}`,
2986
+ max: (fieldName, max) => `${fieldName} must be no more than ${max}`,
2987
+ pattern: (fieldName) => `${fieldName} format is invalid`,
2988
+ email: () => "Please enter a valid email address",
2989
+ url: () => "Please enter a valid URL",
2990
+ phone: () => "Please enter a valid phone number",
2991
+ date: () => "Please enter a valid date",
2992
+ time: () => "Please enter a valid time"
2993
+ };
2994
+ var serverValidation = {
2995
+ /**
2996
+ * Apply server errors to form
2997
+ */
2998
+ applyServerErrors: (errors, setError) => {
2999
+ Object.entries(errors).forEach(([field2, messages]) => {
3000
+ setError(field2, {
3001
+ type: "server",
3002
+ message: messages[0]
3003
+ // Use first error message
3004
+ });
3005
+ });
3006
+ },
3007
+ /**
3008
+ * Clear server errors
3009
+ */
3010
+ clearServerErrors: (fields, clearErrors) => {
3011
+ fields.forEach((field2) => {
3012
+ clearErrors(field2, "server");
3013
+ });
3014
+ }
3015
+ };
3016
+ var validationUtils = {
3017
+ /**
3018
+ * Debounced validation
3019
+ */
3020
+ debounceValidation: (fn, delay = 300) => {
3021
+ let timeoutId;
3022
+ return (...args) => {
3023
+ clearTimeout(timeoutId);
3024
+ timeoutId = setTimeout(() => fn(...args), delay);
3025
+ };
3026
+ },
3027
+ /**
3028
+ * Validate form data against schema
3029
+ */
3030
+ validateForm: async (data, schema) => {
3031
+ try {
3032
+ await schema.parseAsync(data);
3033
+ return { success: true, errors: {} };
3034
+ } catch (error) {
3035
+ if (error instanceof z4.ZodError) {
3036
+ const errors = {};
3037
+ error.issues.forEach((err) => {
3038
+ const path = err.path.join(".");
3039
+ errors[path] = err.message;
3040
+ });
3041
+ return { success: false, errors };
3042
+ }
3043
+ throw error;
3044
+ }
3045
+ },
3046
+ /**
3047
+ * Get field error message
3048
+ */
3049
+ getFieldError: (errors, field2) => {
3050
+ return errors[field2];
3051
+ },
3052
+ /**
3053
+ * Check if field has error
3054
+ */
3055
+ hasFieldError: (errors, field2) => {
3056
+ return !!errors[field2];
3057
+ }
3058
+ };
1433
3059
  export {
3060
+ AdvancedFieldBuilder,
3061
+ BasicFormBuilder,
1434
3062
  CheckboxField,
3063
+ CommonFields,
3064
+ ConditionalField,
1435
3065
  ConfigurableForm,
1436
3066
  DateField,
3067
+ DynamicSectionField,
3068
+ FieldArrayBuilder,
3069
+ FieldArrayField,
3070
+ FieldArrayItemBuilder,
1437
3071
  FileField,
1438
3072
  FontPickerField,
1439
3073
  FormField,
3074
+ FormFieldHelpers,
1440
3075
  FormProvider,
3076
+ FormStatus,
3077
+ FormToast,
1441
3078
  HeroHookFormProvider,
1442
3079
  InputField,
1443
3080
  RadioGroupField,
@@ -1446,13 +3083,20 @@ export {
1446
3083
  SubmitButton,
1447
3084
  SwitchField,
1448
3085
  TextareaField,
3086
+ TypeInferredBuilder,
1449
3087
  ZodForm,
1450
3088
  applyServerErrors,
3089
+ asyncValidation,
1451
3090
  commonValidations,
3091
+ createAdvancedBuilder,
3092
+ createBasicFormBuilder,
1452
3093
  createConditionalSchema,
1453
3094
  createConfirmPasswordSchema,
1454
3095
  createDateSchema,
1455
3096
  createEmailSchema,
3097
+ createField,
3098
+ createFieldArrayBuilder,
3099
+ createFieldArrayItemBuilder,
1456
3100
  createFileSchema,
1457
3101
  createFormTestUtils,
1458
3102
  createFutureDateSchema,
@@ -1460,24 +3104,47 @@ export {
1460
3104
  createMinLengthSchema,
1461
3105
  createMockFormData,
1462
3106
  createMockFormErrors,
3107
+ createNestedPathBuilder,
1463
3108
  createNumberRangeSchema,
3109
+ createOptimizedFieldHandler,
1464
3110
  createPasswordSchema,
1465
3111
  createPastDateSchema,
1466
3112
  createPhoneSchema,
1467
3113
  createRequiredCheckboxSchema,
1468
3114
  createRequiredSchema,
3115
+ createTypeInferredBuilder,
1469
3116
  createUrlSchema,
1470
3117
  createZodFormConfig,
3118
+ crossFieldValidation,
3119
+ debounce,
3120
+ deepEqual,
3121
+ defineInferredForm,
3122
+ errorMessages,
3123
+ field,
1471
3124
  getFieldError,
1472
3125
  getFormErrors,
1473
3126
  hasFieldError,
1474
3127
  hasFormErrors,
3128
+ serverValidation,
3129
+ shallowEqual,
1475
3130
  simulateFieldInput,
1476
3131
  simulateFormSubmission,
1477
- useFormContext2 as useFormContext,
3132
+ throttle,
3133
+ useBatchedFieldUpdates,
3134
+ useDebouncedFieldValidation,
3135
+ useDebouncedValidation,
3136
+ useEnhancedFormState,
3137
+ useFormContext5 as useFormContext,
1478
3138
  useFormHelper,
1479
3139
  useHeroForm,
1480
3140
  useHeroHookFormDefaults,
3141
+ useInferredForm,
3142
+ useMemoizedCallback,
3143
+ useMemoizedFieldProps,
3144
+ usePerformanceMonitor,
3145
+ useTypeInferredForm,
1481
3146
  useZodForm,
3147
+ validationPatterns,
3148
+ validationUtils,
1482
3149
  waitForFormState
1483
3150
  };