@rachelallyson/hero-hook-form 2.5.1 → 2.7.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
@@ -76,7 +76,7 @@ function useFormHelper({
76
76
 
77
77
  // src/components/FormField.tsx
78
78
  import React17 from "react";
79
- import { useWatch as useWatch3 } from "react-hook-form";
79
+ import { get, useWatch as useWatch3 } from "react-hook-form";
80
80
 
81
81
  // src/fields/AutocompleteField.tsx
82
82
  import React from "react";
@@ -432,18 +432,23 @@ function FieldArrayField({
432
432
  }) {
433
433
  const {
434
434
  addButtonText = "Add Item",
435
+ defaultItem,
436
+ enableReordering = false,
435
437
  fields: fieldConfigs,
436
438
  max = 10,
437
439
  min = 0,
438
440
  name,
439
- removeButtonText = "Remove"
441
+ removeButtonText = "Remove",
442
+ renderAddButton,
443
+ renderItem,
444
+ reorderButtonText = { down: "\u2193", up: "\u2191" }
440
445
  } = config;
441
446
  const form = useFormContext3();
442
447
  if (!form || !form.control) {
443
448
  return null;
444
449
  }
445
450
  const { control } = form;
446
- const { append, fields, remove } = useFieldArray({
451
+ const { append, fields, move, remove } = useFieldArray({
447
452
  control,
448
453
  name
449
454
  // FieldArray name
@@ -452,18 +457,22 @@ function FieldArrayField({
452
457
  const canRemove = fields.length > min;
453
458
  const handleAdd = () => {
454
459
  if (canAdd) {
455
- const defaultValues = fieldConfigs.reduce((acc, fieldConfig) => {
456
- const fieldName = fieldConfig.name;
457
- if (fieldConfig.type === "checkbox" || fieldConfig.type === "switch") {
458
- acc[fieldName] = false;
459
- } else if (fieldConfig.type === "slider") {
460
- acc[fieldName] = 0;
461
- } else {
462
- acc[fieldName] = "";
463
- }
464
- return acc;
465
- }, {});
466
- append(defaultValues);
460
+ if (defaultItem) {
461
+ append(defaultItem());
462
+ } else {
463
+ const defaultValues = fieldConfigs.reduce((acc, fieldConfig) => {
464
+ const fieldName = fieldConfig.name;
465
+ if (fieldConfig.type === "checkbox" || fieldConfig.type === "switch") {
466
+ acc[fieldName] = false;
467
+ } else if (fieldConfig.type === "slider") {
468
+ acc[fieldName] = 0;
469
+ } else {
470
+ acc[fieldName] = "";
471
+ }
472
+ return acc;
473
+ }, {});
474
+ append(defaultValues);
475
+ }
467
476
  }
468
477
  };
469
478
  const handleRemove = (index) => {
@@ -471,60 +480,131 @@ function FieldArrayField({
471
480
  remove(index);
472
481
  }
473
482
  };
474
- return /* @__PURE__ */ React8.createElement("div", { className }, /* @__PURE__ */ React8.createElement("div", { className: "space-y-4" }, fields.map((field2, index) => /* @__PURE__ */ React8.createElement(
475
- "div",
476
- {
477
- key: field2.id,
478
- className: "border border-gray-200 rounded-lg p-4 space-y-4"
479
- },
480
- /* @__PURE__ */ React8.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React8.createElement("h4", { className: "text-sm font-medium text-gray-700" }, config.label, " #", index + 1), canRemove && /* @__PURE__ */ React8.createElement(
483
+ const handleMoveUp = (index) => {
484
+ if (index > 0) {
485
+ move(index, index - 1);
486
+ }
487
+ };
488
+ const handleMoveDown = (index) => {
489
+ if (index < fields.length - 1) {
490
+ move(index, index + 1);
491
+ }
492
+ };
493
+ const renderFieldArrayItems = () => {
494
+ return fields.map((field2, index) => {
495
+ const canMoveUp = enableReordering && index > 0;
496
+ const canMoveDown = enableReordering && index < fields.length - 1;
497
+ const itemCanRemove = canRemove;
498
+ const fieldElements = fieldConfigs.map((fieldConfig) => {
499
+ const fieldName = fieldConfig.name;
500
+ const fullPath = `${name}.${index}.${fieldName}`;
501
+ let processedConfig = { ...fieldConfig, name: fullPath };
502
+ if ("dependsOn" in fieldConfig && fieldConfig.dependsOn && typeof fieldConfig.dependsOn === "string") {
503
+ const dependsOnPath = fieldConfig.dependsOn;
504
+ if (!dependsOnPath.startsWith(`${name}.`)) {
505
+ processedConfig = {
506
+ ...processedConfig,
507
+ dependsOn: `${name}.${index}.${dependsOnPath}`,
508
+ // Preserve dependsOnValue if it exists
509
+ ..."dependsOnValue" in fieldConfig && {
510
+ dependsOnValue: fieldConfig.dependsOnValue
511
+ }
512
+ };
513
+ }
514
+ }
515
+ return /* @__PURE__ */ React8.createElement(
516
+ FormField,
517
+ {
518
+ key: `${fieldConfig.name}-${index}`,
519
+ config: processedConfig,
520
+ form,
521
+ submissionState: {
522
+ error: void 0,
523
+ isSubmitted: false,
524
+ isSubmitting: false,
525
+ isSuccess: false
526
+ }
527
+ }
528
+ );
529
+ });
530
+ if (renderItem) {
531
+ return /* @__PURE__ */ React8.createElement(React8.Fragment, { key: field2.id }, renderItem({
532
+ canMoveDown,
533
+ canMoveUp,
534
+ canRemove: itemCanRemove,
535
+ children: /* @__PURE__ */ React8.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, fieldElements),
536
+ field: field2,
537
+ fields,
538
+ index,
539
+ onMoveDown: () => handleMoveDown(index),
540
+ onMoveUp: () => handleMoveUp(index),
541
+ onRemove: () => handleRemove(index)
542
+ }));
543
+ }
544
+ return /* @__PURE__ */ React8.createElement(
545
+ "div",
546
+ {
547
+ key: field2.id,
548
+ className: "border border-gray-200 rounded-lg p-4 space-y-4"
549
+ },
550
+ /* @__PURE__ */ React8.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React8.createElement("h4", { className: "text-sm font-medium text-gray-700" }, config.label, " #", index + 1), /* @__PURE__ */ React8.createElement("div", { className: "flex gap-2" }, enableReordering && /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(
551
+ Button2,
552
+ {
553
+ size: "sm",
554
+ variant: "light",
555
+ isDisabled: !canMoveUp,
556
+ onPress: () => handleMoveUp(index),
557
+ "aria-label": `Move ${config.label} ${index + 1} up`
558
+ },
559
+ reorderButtonText.up
560
+ ), /* @__PURE__ */ React8.createElement(
561
+ Button2,
562
+ {
563
+ size: "sm",
564
+ variant: "light",
565
+ isDisabled: !canMoveDown,
566
+ onPress: () => handleMoveDown(index),
567
+ "aria-label": `Move ${config.label} ${index + 1} down`
568
+ },
569
+ reorderButtonText.down
570
+ )), itemCanRemove && /* @__PURE__ */ React8.createElement(
571
+ Button2,
572
+ {
573
+ size: "sm",
574
+ variant: "light",
575
+ color: "danger",
576
+ startContent: "\u{1F5D1}\uFE0F",
577
+ onPress: () => handleRemove(index),
578
+ "aria-label": `${removeButtonText} ${config.label} ${index + 1}`
579
+ },
580
+ removeButtonText
581
+ ))),
582
+ /* @__PURE__ */ React8.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, fieldElements)
583
+ );
584
+ });
585
+ };
586
+ const renderAddButtonElement = () => {
587
+ if (renderAddButton) {
588
+ return renderAddButton({
589
+ canAdd,
590
+ onAdd: handleAdd
591
+ });
592
+ }
593
+ if (!canAdd) {
594
+ return null;
595
+ }
596
+ return /* @__PURE__ */ React8.createElement(
481
597
  Button2,
482
598
  {
483
- size: "sm",
484
- variant: "light",
485
- color: "danger",
486
- startContent: "\u{1F5D1}\uFE0F",
487
- onPress: () => handleRemove(index),
488
- "aria-label": `${removeButtonText} ${config.label} ${index + 1}`
599
+ variant: "bordered",
600
+ startContent: "\u2795",
601
+ onPress: handleAdd,
602
+ className: "w-full"
489
603
  },
490
- removeButtonText
491
- )),
492
- /* @__PURE__ */ React8.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, fieldConfigs.map((fieldConfig) => /* @__PURE__ */ React8.createElement(
493
- FormField,
494
- {
495
- key: `${fieldConfig.name}-${index}`,
496
- config: {
497
- ...fieldConfig,
498
- name: `${name}.${index}.${fieldConfig.name}`
499
- },
500
- form,
501
- submissionState: {
502
- error: void 0,
503
- isSubmitted: false,
504
- isSubmitting: false,
505
- isSuccess: false
506
- }
507
- }
508
- )))
509
- )), canAdd && /* @__PURE__ */ React8.createElement(
510
- Button2,
511
- {
512
- variant: "bordered",
513
- startContent: "\u2795",
514
- onPress: handleAdd,
515
- className: "w-full"
516
- },
517
- addButtonText
518
- ), fields.length === 0 && /* @__PURE__ */ React8.createElement("div", { className: "text-center py-8 text-gray-500" }, /* @__PURE__ */ React8.createElement("p", null, "No ", config.label?.toLowerCase(), " added yet."), /* @__PURE__ */ React8.createElement(
519
- Button2,
520
- {
521
- variant: "bordered",
522
- startContent: "\u2795",
523
- onPress: handleAdd,
524
- className: "mt-2"
525
- },
526
- addButtonText
527
- ))));
604
+ addButtonText
605
+ );
606
+ };
607
+ return /* @__PURE__ */ React8.createElement("div", { className }, /* @__PURE__ */ React8.createElement("div", { className: "space-y-4" }, fields.length > 0 ? renderFieldArrayItems() : /* @__PURE__ */ React8.createElement("div", { className: "text-center py-8 text-gray-500" }, /* @__PURE__ */ React8.createElement("p", null, "No ", config.label?.toLowerCase(), " added yet."), renderAddButtonElement()), fields.length > 0 && renderAddButtonElement()));
528
608
  }
529
609
 
530
610
  // src/fields/FileField.tsx
@@ -1050,7 +1130,7 @@ var FormField = React17.memo(
1050
1130
  return null;
1051
1131
  }
1052
1132
  if (config.dependsOn) {
1053
- const dependentValue = watchedValues[config.dependsOn];
1133
+ const dependentValue = get(watchedValues, config.dependsOn);
1054
1134
  if (config.dependsOnValue !== void 0 && dependentValue !== config.dependsOnValue) {
1055
1135
  return null;
1056
1136
  }
@@ -2334,6 +2414,44 @@ function ZodForm({
2334
2414
  ))));
2335
2415
  }
2336
2416
 
2417
+ // src/components/SimpleForm.tsx
2418
+ import React24 from "react";
2419
+ function SimpleForm({
2420
+ className,
2421
+ defaultValues,
2422
+ field: field2,
2423
+ hideSubmitButton = false,
2424
+ onError,
2425
+ onSubmit,
2426
+ onSuccess,
2427
+ schema,
2428
+ submitButton,
2429
+ subtitle,
2430
+ title
2431
+ }) {
2432
+ return /* @__PURE__ */ React24.createElement(
2433
+ ZodForm,
2434
+ {
2435
+ className,
2436
+ config: {
2437
+ defaultValues,
2438
+ fields: [field2],
2439
+ schema
2440
+ },
2441
+ onError,
2442
+ onSubmit,
2443
+ onSuccess,
2444
+ showResetButton: false,
2445
+ submitButtonText: hideSubmitButton ? "" : "Submit",
2446
+ subtitle,
2447
+ title,
2448
+ submitButtonProps: hideSubmitButton && submitButton ? {
2449
+ style: { display: "none" }
2450
+ } : {}
2451
+ }
2452
+ );
2453
+ }
2454
+
2337
2455
  // src/builders/BasicFormBuilder.ts
2338
2456
  var BasicFormBuilder = class {
2339
2457
  constructor() {
@@ -2438,9 +2556,27 @@ function createBasicFormBuilder() {
2438
2556
  var FormFieldHelpers = {
2439
2557
  /**
2440
2558
  * Create an autocomplete field
2559
+ *
2560
+ * @example
2561
+ * ```tsx
2562
+ * // Simple autocomplete
2563
+ * FormFieldHelpers.autocomplete("country", "Country", options)
2564
+ *
2565
+ * // With placeholder
2566
+ * FormFieldHelpers.autocomplete("country", "Country", options, "Search countries")
2567
+ *
2568
+ * // With full customization
2569
+ * FormFieldHelpers.autocomplete("country", "Country", options, "Search countries", {
2570
+ * classNames: { base: "custom-autocomplete" },
2571
+ * allowsCustomValue: true
2572
+ * })
2573
+ * ```
2441
2574
  */
2442
- autocomplete: (name, label, items, placeholder) => ({
2443
- autocompleteProps: placeholder ? { placeholder } : void 0,
2575
+ autocomplete: (name, label, items, placeholder, autocompleteProps) => ({
2576
+ autocompleteProps: {
2577
+ ...placeholder && { placeholder },
2578
+ ...autocompleteProps
2579
+ },
2444
2580
  label,
2445
2581
  name,
2446
2582
  options: items,
@@ -2448,8 +2584,21 @@ var FormFieldHelpers = {
2448
2584
  }),
2449
2585
  /**
2450
2586
  * Create a checkbox field
2587
+ *
2588
+ * @example
2589
+ * ```tsx
2590
+ * // Simple checkbox
2591
+ * FormFieldHelpers.checkbox("newsletter", "Subscribe to newsletter")
2592
+ *
2593
+ * // With full customization
2594
+ * FormFieldHelpers.checkbox("newsletter", "Subscribe to newsletter", {
2595
+ * classNames: { base: "custom-checkbox" },
2596
+ * size: "lg"
2597
+ * })
2598
+ * ```
2451
2599
  */
2452
- checkbox: (name, label) => ({
2600
+ checkbox: (name, label, checkboxProps) => ({
2601
+ checkboxProps,
2453
2602
  label,
2454
2603
  name,
2455
2604
  type: "checkbox"
@@ -2511,6 +2660,19 @@ var FormFieldHelpers = {
2511
2660
  },
2512
2661
  /**
2513
2662
  * Create a date field
2663
+ *
2664
+ * @example
2665
+ * ```tsx
2666
+ * // Simple date field
2667
+ * FormFieldHelpers.date("birthDate", "Birth Date")
2668
+ *
2669
+ * // With full customization
2670
+ * FormFieldHelpers.date("birthDate", "Birth Date", {
2671
+ * label: "Select your birth date",
2672
+ * granularity: "day",
2673
+ * minValue: new CalendarDate(1900, 1, 1)
2674
+ * })
2675
+ * ```
2514
2676
  */
2515
2677
  date: (name, label, dateProps) => ({
2516
2678
  dateProps,
@@ -2518,40 +2680,211 @@ var FormFieldHelpers = {
2518
2680
  name,
2519
2681
  type: "date"
2520
2682
  }),
2683
+ /**
2684
+ * Create a file upload field
2685
+ *
2686
+ * @example
2687
+ * ```tsx
2688
+ * // Simple file field
2689
+ * FormFieldHelpers.file("avatar", "Profile Picture")
2690
+ *
2691
+ * // With accept and multiple
2692
+ * FormFieldHelpers.file("avatar", "Profile Picture", {
2693
+ * accept: "image/*",
2694
+ * multiple: true
2695
+ * })
2696
+ *
2697
+ * // With full customization
2698
+ * FormFieldHelpers.file("avatar", "Profile Picture", {
2699
+ * accept: "image/*",
2700
+ * multiple: false,
2701
+ * fileProps: { className: "custom-file-input" }
2702
+ * })
2703
+ * ```
2704
+ */
2705
+ file: (name, label, options) => ({
2706
+ accept: options?.accept,
2707
+ fileProps: options?.fileProps,
2708
+ label,
2709
+ multiple: options?.multiple,
2710
+ name,
2711
+ type: "file"
2712
+ }),
2713
+ /**
2714
+ * Create a font picker field
2715
+ *
2716
+ * @example
2717
+ * ```tsx
2718
+ * // Simple font picker
2719
+ * FormFieldHelpers.fontPicker("font", "Choose Font")
2720
+ *
2721
+ * // With full customization
2722
+ * FormFieldHelpers.fontPicker("font", "Choose Font", {
2723
+ * showFontPreview: true,
2724
+ * loadAllVariants: false,
2725
+ * fontsLoadedTimeout: 5000
2726
+ * })
2727
+ * ```
2728
+ */
2729
+ fontPicker: (name, label, fontPickerProps) => ({
2730
+ fontPickerProps,
2731
+ label,
2732
+ name,
2733
+ type: "fontPicker"
2734
+ }),
2521
2735
  /**
2522
2736
  * Create an input field
2737
+ *
2738
+ * @example
2739
+ * ```tsx
2740
+ * // Simple input
2741
+ * FormFieldHelpers.input("name", "Name")
2742
+ *
2743
+ * // With type
2744
+ * FormFieldHelpers.input("email", "Email", "email")
2745
+ *
2746
+ * // With full customization
2747
+ * FormFieldHelpers.input("email", "Email", "email", {
2748
+ * placeholder: "Enter your email",
2749
+ * classNames: { input: "custom-input" },
2750
+ * startContent: <MailIcon />,
2751
+ * description: "We'll never share your email"
2752
+ * })
2753
+ * ```
2523
2754
  */
2524
- input: (name, label, type = "text") => ({
2525
- inputProps: { type },
2755
+ input: (name, label, type, inputProps) => ({
2756
+ inputProps: {
2757
+ type: type || "text",
2758
+ ...inputProps
2759
+ },
2526
2760
  label,
2527
2761
  name,
2528
2762
  type: "input"
2529
2763
  }),
2764
+ /**
2765
+ * Create a radio group field
2766
+ *
2767
+ * @example
2768
+ * ```tsx
2769
+ * // Simple radio group
2770
+ * FormFieldHelpers.radio("gender", "Gender", [
2771
+ * { label: "Male", value: "male" },
2772
+ * { label: "Female", value: "female" }
2773
+ * ])
2774
+ *
2775
+ * // With full customization
2776
+ * FormFieldHelpers.radio("gender", "Gender", options, {
2777
+ * orientation: "horizontal",
2778
+ * classNames: { base: "custom-radio" }
2779
+ * })
2780
+ * ```
2781
+ */
2782
+ radio: (name, label, options, radioProps) => ({
2783
+ label,
2784
+ name,
2785
+ radioOptions: options,
2786
+ radioProps,
2787
+ type: "radio"
2788
+ }),
2530
2789
  /**
2531
2790
  * Create a select field
2791
+ *
2792
+ * @example
2793
+ * ```tsx
2794
+ * // Simple select
2795
+ * FormFieldHelpers.select("country", "Country", options)
2796
+ *
2797
+ * // With full customization
2798
+ * FormFieldHelpers.select("country", "Country", options, {
2799
+ * placeholder: "Select a country",
2800
+ * classNames: { trigger: "custom-select" },
2801
+ * selectionMode: "multiple"
2802
+ * })
2803
+ * ```
2532
2804
  */
2533
- select: (name, label, options) => ({
2805
+ select: (name, label, options, selectProps) => ({
2534
2806
  label,
2535
2807
  name,
2536
2808
  options,
2809
+ selectProps,
2537
2810
  type: "select"
2538
2811
  }),
2812
+ /**
2813
+ * Create a slider field
2814
+ *
2815
+ * @example
2816
+ * ```tsx
2817
+ * // Simple slider
2818
+ * FormFieldHelpers.slider("rating", "Rating")
2819
+ *
2820
+ * // With full customization
2821
+ * FormFieldHelpers.slider("rating", "Rating", {
2822
+ * minValue: 1,
2823
+ * maxValue: 5,
2824
+ * step: 1,
2825
+ * showSteps: true,
2826
+ * classNames: { base: "custom-slider" }
2827
+ * })
2828
+ * ```
2829
+ */
2830
+ slider: (name, label, sliderProps) => ({
2831
+ label,
2832
+ name,
2833
+ sliderProps,
2834
+ type: "slider"
2835
+ }),
2539
2836
  /**
2540
2837
  * Create a switch field
2838
+ *
2839
+ * @example
2840
+ * ```tsx
2841
+ * // Simple switch
2842
+ * FormFieldHelpers.switch("notifications", "Enable notifications")
2843
+ *
2844
+ * // With description
2845
+ * FormFieldHelpers.switch("notifications", "Enable notifications", "Receive email notifications")
2846
+ *
2847
+ * // With full customization
2848
+ * FormFieldHelpers.switch("notifications", "Enable notifications", "Receive email notifications", {
2849
+ * classNames: { base: "custom-switch" },
2850
+ * size: "lg",
2851
+ * color: "primary"
2852
+ * })
2853
+ * ```
2541
2854
  */
2542
- switch: (name, label, description) => ({
2855
+ switch: (name, label, description, switchProps) => ({
2543
2856
  description,
2544
2857
  label,
2545
2858
  name,
2859
+ switchProps,
2546
2860
  type: "switch"
2547
2861
  }),
2548
2862
  /**
2549
2863
  * Create a textarea field
2864
+ *
2865
+ * @example
2866
+ * ```tsx
2867
+ * // Simple textarea
2868
+ * FormFieldHelpers.textarea("message", "Message")
2869
+ *
2870
+ * // With placeholder
2871
+ * FormFieldHelpers.textarea("message", "Message", "Enter your message")
2872
+ *
2873
+ * // With full customization
2874
+ * FormFieldHelpers.textarea("message", "Message", "Enter your message", {
2875
+ * classNames: { input: "custom-textarea" },
2876
+ * minRows: 3,
2877
+ * maxRows: 10
2878
+ * })
2879
+ * ```
2550
2880
  */
2551
- textarea: (name, label, placeholder) => ({
2881
+ textarea: (name, label, placeholder, textareaProps) => ({
2552
2882
  label,
2553
2883
  name,
2554
- textareaProps: { placeholder },
2884
+ textareaProps: {
2885
+ ...placeholder && { placeholder },
2886
+ ...textareaProps
2887
+ },
2555
2888
  type: "textarea"
2556
2889
  })
2557
2890
  };
@@ -2692,11 +3025,10 @@ function sliderField(name, label, props) {
2692
3025
  type: "slider",
2693
3026
  ...props && {
2694
3027
  sliderProps: {
2695
- className: props.className || "",
2696
- disabled: props.isDisabled || false,
2697
- max: props.max || 100,
2698
- min: props.min || 0,
2699
- step: props.step || 1
3028
+ className: props.className,
3029
+ maxValue: props.max ?? 100,
3030
+ minValue: props.min ?? 0,
3031
+ step: props.step ?? 1
2700
3032
  }
2701
3033
  }
2702
3034
  };
@@ -2708,9 +3040,8 @@ function dateField(name, label, props) {
2708
3040
  type: "date",
2709
3041
  ...props && {
2710
3042
  dateProps: {
2711
- className: props.className || "",
2712
- disabled: props.isDisabled || false,
2713
- placeholder: props.placeholder || ""
3043
+ className: props.className,
3044
+ placeholder: props.placeholder
2714
3045
  }
2715
3046
  }
2716
3047
  };
@@ -2732,15 +3063,12 @@ function fileField(name, label, props) {
2732
3063
  }
2733
3064
  function fontPickerField(name, label, props) {
2734
3065
  return {
3066
+ className: props?.className,
3067
+ description: props?.description,
3068
+ fontPickerProps: props?.fontPickerProps,
2735
3069
  label,
2736
3070
  name,
2737
- type: "fontPicker",
2738
- ...props && {
2739
- fontPickerProps: {
2740
- className: props.className || "",
2741
- disabled: props.isDisabled || false
2742
- }
2743
- }
3071
+ type: "fontPicker"
2744
3072
  };
2745
3073
  }
2746
3074
  function contentField(title, description, options) {
@@ -3062,7 +3390,12 @@ var TypeInferredBuilder = class {
3062
3390
  this.formFields.push({
3063
3391
  label,
3064
3392
  name,
3065
- sliderProps: { max, min, step, ...fieldOptions },
3393
+ sliderProps: {
3394
+ maxValue: max,
3395
+ minValue: min,
3396
+ step,
3397
+ ...fieldOptions
3398
+ },
3066
3399
  type: "slider"
3067
3400
  });
3068
3401
  return this;
@@ -3527,6 +3860,131 @@ function useMemoizedFieldProps(props, deps) {
3527
3860
  return useMemo2(() => props, deps);
3528
3861
  }
3529
3862
 
3863
+ // src/utils/arraySync.ts
3864
+ function syncArrays(options) {
3865
+ const { current, existing, getId } = options;
3866
+ const existingMap = /* @__PURE__ */ new Map();
3867
+ const currentMap = /* @__PURE__ */ new Map();
3868
+ existing.forEach((item) => {
3869
+ const id = getId(item);
3870
+ if (id !== void 0) {
3871
+ existingMap.set(id, item);
3872
+ }
3873
+ });
3874
+ current.forEach((item) => {
3875
+ const id = getId(item);
3876
+ if (id !== void 0) {
3877
+ currentMap.set(id, item);
3878
+ }
3879
+ });
3880
+ const toDelete = [];
3881
+ existingMap.forEach((item, id) => {
3882
+ if (!currentMap.has(id)) {
3883
+ toDelete.push(item);
3884
+ }
3885
+ });
3886
+ const toUpdate = [];
3887
+ existingMap.forEach((existingItem, id) => {
3888
+ const currentItem = currentMap.get(id);
3889
+ if (currentItem) {
3890
+ toUpdate.push({ current: currentItem, existing: existingItem });
3891
+ }
3892
+ });
3893
+ const toCreate = [];
3894
+ currentMap.forEach((item, id) => {
3895
+ if (!existingMap.has(id)) {
3896
+ toCreate.push(item);
3897
+ }
3898
+ });
3899
+ return {
3900
+ toCreate,
3901
+ toDelete,
3902
+ toUpdate
3903
+ };
3904
+ }
3905
+
3906
+ // src/utils/createFieldArrayCustomConfig.tsx
3907
+ import React25 from "react";
3908
+ import { useFieldArray as useFieldArray2 } from "react-hook-form";
3909
+ import { Button as Button6 } from "@heroui/react";
3910
+ function createFieldArrayCustomConfig(options) {
3911
+ const {
3912
+ className,
3913
+ defaultItem,
3914
+ enableReordering = false,
3915
+ label,
3916
+ max = 10,
3917
+ min = 0,
3918
+ name,
3919
+ renderAddButton,
3920
+ renderItem
3921
+ } = options;
3922
+ return {
3923
+ className,
3924
+ label,
3925
+ name,
3926
+ // ArrayPath is compatible with Path for CustomFieldConfig
3927
+ render: ({ control, errors, form }) => {
3928
+ const { append, fields, move, remove } = useFieldArray2({
3929
+ control,
3930
+ name
3931
+ });
3932
+ const canAdd = fields.length < max;
3933
+ const canRemove = fields.length > min;
3934
+ const handleAdd = () => {
3935
+ if (canAdd) {
3936
+ if (defaultItem) {
3937
+ append(defaultItem());
3938
+ } else {
3939
+ append({});
3940
+ }
3941
+ }
3942
+ };
3943
+ const handleRemove = (index) => {
3944
+ if (canRemove) {
3945
+ remove(index);
3946
+ }
3947
+ };
3948
+ const handleMoveUp = (index) => {
3949
+ if (enableReordering && index > 0) {
3950
+ move(index, index - 1);
3951
+ }
3952
+ };
3953
+ const handleMoveDown = (index) => {
3954
+ if (enableReordering && index < fields.length - 1) {
3955
+ move(index, index + 1);
3956
+ }
3957
+ };
3958
+ return /* @__PURE__ */ React25.createElement("div", { className }, /* @__PURE__ */ React25.createElement("div", { className: "space-y-4" }, fields.map((field2, index) => {
3959
+ const canMoveUp = enableReordering && index > 0;
3960
+ const canMoveDown = enableReordering && index < fields.length - 1;
3961
+ return /* @__PURE__ */ React25.createElement(React25.Fragment, { key: field2.id }, renderItem({
3962
+ canMoveDown,
3963
+ canMoveUp,
3964
+ control,
3965
+ errors,
3966
+ field: field2,
3967
+ fields,
3968
+ form,
3969
+ index,
3970
+ onMoveDown: () => handleMoveDown(index),
3971
+ onMoveUp: () => handleMoveUp(index),
3972
+ onRemove: () => handleRemove(index)
3973
+ }));
3974
+ }), fields.length === 0 && renderAddButton ? /* @__PURE__ */ React25.createElement("div", { className: "text-center py-8 text-gray-500" }, /* @__PURE__ */ React25.createElement("p", null, "No ", label?.toLowerCase() || "items", " added yet."), renderAddButton({ canAdd, onAdd: handleAdd })) : null, fields.length > 0 && renderAddButton ? renderAddButton({ canAdd, onAdd: handleAdd }) : canAdd && /* @__PURE__ */ React25.createElement(
3975
+ Button6,
3976
+ {
3977
+ variant: "bordered",
3978
+ onPress: handleAdd,
3979
+ className: "w-full"
3980
+ },
3981
+ "Add Item"
3982
+ )));
3983
+ },
3984
+ type: "custom"
3985
+ };
3986
+ }
3987
+
3530
3988
  // src/builders/validation-helpers.ts
3531
3989
  import { z as z4 } from "zod";
3532
3990
  var validationPatterns = {
@@ -3700,6 +4158,7 @@ export {
3700
4158
  RadioGroupField,
3701
4159
  SelectField,
3702
4160
  ServerActionForm,
4161
+ SimpleForm,
3703
4162
  SliderField,
3704
4163
  SubmitButton,
3705
4164
  SwitchField,
@@ -3715,6 +4174,7 @@ export {
3715
4174
  createEmailSchema,
3716
4175
  createField,
3717
4176
  createFieldArrayBuilder,
4177
+ createFieldArrayCustomConfig,
3718
4178
  createFieldArrayItemBuilder,
3719
4179
  createFileSchema,
3720
4180
  createFormTestUtils,
@@ -3748,6 +4208,7 @@ export {
3748
4208
  shallowEqual,
3749
4209
  simulateFieldInput,
3750
4210
  simulateFormSubmission,
4211
+ syncArrays,
3751
4212
  throttle,
3752
4213
  useDebouncedFieldValidation,
3753
4214
  useDebouncedValidation,