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