@rachelallyson/hero-hook-form 1.2.0 → 2.1.0

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