@rachelallyson/hero-hook-form 2.13.0 → 2.14.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/CHANGELOG.md +9 -0
- package/dist/index.d.ts +69 -15
- package/dist/index.js +68 -16
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [2.14.0] - 2026-01-29
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **Dynamic custom fields in field arrays** – When each array item can be a different control type (e.g. member custom field values: one row is a date, another a dropdown, another short text), you can use **getItemFieldConfig** with **createCustomFieldConfigForItem** instead of wiring multiple conditionals yourself.
|
|
10
|
+
- **getItemFieldConfig** – Pass this to `createFieldArrayCustomConfig`; for each item you return a single field config (or `null`). The library renders one field per item for you.
|
|
11
|
+
- **createCustomFieldConfigForItem(name, def)** – Given a field path and a definition with `fieldType` (e.g. `'DATE'`, `'SHORT_TEXT'`, `'LONG_TEXT'`, `'NUMBER'`, `'DROPDOWN'`), `name` (label), and optional `options` for dropdowns (newline-separated string or `{ label, value }[]`), returns the right config so you don’t write a switch or five conditionals per item.
|
|
12
|
+
- Use it in ZodForm by adding a `createFieldArrayCustomConfig` with `getItemFieldConfig: ({ field, index }) => createCustomFieldConfigForItem(\`items.\${index}.value\`, { fieldType: def.fieldType, name: def.name, options: def.options })` after looking up the definition for that item (e.g. by `customFieldId`). See the **Custom Field Array Demo** in the example app for a full example.
|
|
13
|
+
|
|
5
14
|
## [2.13.0] - 2026-01-29
|
|
6
15
|
|
|
7
16
|
### Added
|
package/dist/index.d.ts
CHANGED
|
@@ -4179,6 +4179,65 @@ interface ArraySyncResult<TItem> {
|
|
|
4179
4179
|
*/
|
|
4180
4180
|
declare function syncArrays<TItem>(options: ArraySyncOptions<TItem>): ArraySyncResult<TItem>;
|
|
4181
4181
|
|
|
4182
|
+
/**
|
|
4183
|
+
* Supported input types for dynamic custom fields (e.g. member custom field values).
|
|
4184
|
+
* Use with createCustomFieldConfigForItem so each array item can render the right control.
|
|
4185
|
+
*/
|
|
4186
|
+
type CustomFieldInputType = "DATE" | "DROPDOWN" | "LONG_TEXT" | "NUMBER" | "SHORT_TEXT";
|
|
4187
|
+
/**
|
|
4188
|
+
* Minimal field definition for creating a single field config by type.
|
|
4189
|
+
* Matches common patterns where each array item has a type and label (e.g. customFieldId → field def).
|
|
4190
|
+
*/
|
|
4191
|
+
interface CustomFieldDef {
|
|
4192
|
+
fieldType: CustomFieldInputType;
|
|
4193
|
+
name: string;
|
|
4194
|
+
/** For DROPDOWN: newline-separated string or array of { label, value } */
|
|
4195
|
+
options?: string | {
|
|
4196
|
+
label: string;
|
|
4197
|
+
value: string | number;
|
|
4198
|
+
}[];
|
|
4199
|
+
}
|
|
4200
|
+
/**
|
|
4201
|
+
* Create the right ZodFormFieldConfig for a single custom field by type.
|
|
4202
|
+
* Use inside createFieldArrayCustomConfig getItemFieldConfig (or renderItem) so each
|
|
4203
|
+
* array item renders one control (date, short text, long text, number, or dropdown)
|
|
4204
|
+
* instead of multiple conditionals.
|
|
4205
|
+
*
|
|
4206
|
+
* @param name - Form path for the value (e.g. `customFieldValues.${index}.value`)
|
|
4207
|
+
* @param def - Field definition with fieldType, name (label), and optional options for DROPDOWN
|
|
4208
|
+
* @returns ZodFormFieldConfig for use with FormField
|
|
4209
|
+
*
|
|
4210
|
+
* @example
|
|
4211
|
+
* ```tsx
|
|
4212
|
+
* createFieldArrayCustomConfig({
|
|
4213
|
+
* name: 'customFieldValues',
|
|
4214
|
+
* getItemFieldConfig: ({ field, form, index }) => {
|
|
4215
|
+
* const fieldDef = fields.find(f => f.id === field.customFieldId);
|
|
4216
|
+
* if (!fieldDef) return null;
|
|
4217
|
+
* return createCustomFieldConfigForItem(
|
|
4218
|
+
* `customFieldValues.${index}.value`,
|
|
4219
|
+
* { fieldType: fieldDef.fieldType, name: fieldDef.name, options: fieldDef.options }
|
|
4220
|
+
* );
|
|
4221
|
+
* },
|
|
4222
|
+
* defaultItem: () => ({ customFieldId: '', value: '' }),
|
|
4223
|
+
* });
|
|
4224
|
+
* ```
|
|
4225
|
+
*/
|
|
4226
|
+
declare function createCustomFieldConfigForItem<T extends FieldValues>(name: Path<T>, def: CustomFieldDef): ZodFormFieldConfig<T>;
|
|
4227
|
+
/** Props passed to renderItem or getItemFieldConfig for each array item */
|
|
4228
|
+
interface FieldArrayItemRenderProps<TFieldValues extends FieldValues, TArrayPath extends ArrayPath<TFieldValues>> {
|
|
4229
|
+
index: number;
|
|
4230
|
+
field: FieldArrayWithId<TFieldValues, TArrayPath>;
|
|
4231
|
+
fields: FieldArrayWithId<TFieldValues, TArrayPath>[];
|
|
4232
|
+
form: UseFormReturn<TFieldValues>;
|
|
4233
|
+
control: Control<TFieldValues>;
|
|
4234
|
+
errors: FieldErrors<TFieldValues>;
|
|
4235
|
+
canMoveUp: boolean;
|
|
4236
|
+
canMoveDown: boolean;
|
|
4237
|
+
onMoveUp: () => void;
|
|
4238
|
+
onMoveDown: () => void;
|
|
4239
|
+
onRemove: () => void;
|
|
4240
|
+
}
|
|
4182
4241
|
/**
|
|
4183
4242
|
* Options for creating a custom field array config
|
|
4184
4243
|
*
|
|
@@ -4189,20 +4248,15 @@ interface CreateFieldArrayCustomConfigOptions<TFieldValues extends FieldValues>
|
|
|
4189
4248
|
name: ArrayPath<TFieldValues>;
|
|
4190
4249
|
/** Optional label for the field array */
|
|
4191
4250
|
label?: string;
|
|
4192
|
-
/**
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
canMoveDown: boolean;
|
|
4202
|
-
onMoveUp: () => void;
|
|
4203
|
-
onMoveDown: () => void;
|
|
4204
|
-
onRemove: () => void;
|
|
4205
|
-
}) => React$1.ReactNode;
|
|
4251
|
+
/**
|
|
4252
|
+
* Return a single field config for this item; the array helper will render one FormField.
|
|
4253
|
+
* Use with createCustomFieldConfigForItem when each item's control type depends on item data
|
|
4254
|
+
* (e.g. custom fields: look up field def by customFieldId, then createCustomFieldConfigForItem).
|
|
4255
|
+
* When provided, renderItem is optional.
|
|
4256
|
+
*/
|
|
4257
|
+
getItemFieldConfig?: (props: FieldArrayItemRenderProps<TFieldValues, ArrayPath<TFieldValues>>) => ZodFormFieldConfig<TFieldValues> | null;
|
|
4258
|
+
/** Render function for each array item (optional if getItemFieldConfig is provided) */
|
|
4259
|
+
renderItem?: (props: FieldArrayItemRenderProps<TFieldValues, ArrayPath<TFieldValues>>) => React$1.ReactNode;
|
|
4206
4260
|
/** Optional render function for add button */
|
|
4207
4261
|
renderAddButton?: (props: {
|
|
4208
4262
|
onAdd: () => void;
|
|
@@ -4379,4 +4433,4 @@ declare const validationUtils: {
|
|
|
4379
4433
|
}>;
|
|
4380
4434
|
};
|
|
4381
4435
|
|
|
4382
|
-
export { AdvancedFieldBuilder, type ArraySyncOptions, type ArraySyncResult, type AutocompleteDefaults, AutocompleteField, type AutocompleteFieldProps, type AutocompleteOption, type AutocompletePassthroughProps, type BaseFormFieldConfig, BasicFormBuilder, type BooleanFieldConfig, type ButtonDefaults, type CheckboxDefaults, CheckboxField, type CheckboxFieldProps, CheckboxGroupField, type CheckboxGroupFieldConfig, type CheckboxGroupFieldProps, type CheckboxGroupPassthroughProps, type CheckboxPassthroughProps, type CommonFieldDefaults, CommonFields, ConditionalField, type ConditionalFieldConfig, type ConditionalFieldProps, type ConditionalValidation, ConfigurableForm, ContentField, type ContentFieldConfig, type CreateFieldArrayCustomConfigOptions, type CustomFieldConfig, DateField, type DateFieldConfig, type DateFieldProps, type DateInputDefaults, type DateInputPassthroughProps, type DynamicSectionConfig, DynamicSectionField, type DynamicSectionFieldProps, type EnhancedFormState, FieldArrayBuilder, type FieldArrayConfig, FieldArrayField, type FieldArrayFieldProps, FieldArrayItemBuilder, type FieldBaseProps, type FieldCreationParams, type FieldGroup, FileField, type FileFieldConfig, type FileFieldProps, type FileInputPassthroughProps, FontPickerField, type FontPickerFieldConfig, type FontPickerFieldProps, type FormConfig, FormField, type FormFieldConfig, FormFieldHelpers, type FormFieldType, type FormProps, FormProvider, FormStatus, type FormStatusProps, type FormStep, type FormSubmissionState, type FormTestUtils, FormToast, type FormToastProps, type FormValidationError, type HeroHookFormDefaultsConfig, HeroHookFormProvider, type HeroHookFormProviderProps, type InputDefaults, InputField, type InputFieldProps, type InputPassthroughProps, type RadioFieldConfig, type RadioGroupDefaults, RadioGroupField, type RadioGroupFieldProps, type RadioGroupPassthroughProps, type SelectDefaults, SelectField, type SelectFieldProps, type SelectPassthroughProps, ServerActionForm, type ServerFieldError, type ServerFormError, SimpleForm, type SimpleFormProps, type SliderDefaults, SliderField, type SliderFieldConfig, type SliderFieldProps, type SliderPassthroughProps, type StringArrayFieldConfig, type StringFieldConfig, SubmitButton, type SubmitButtonProps, type SwitchDefaults, SwitchField, type SwitchFieldProps, type SwitchPassthroughProps, type TextareaDefaults, TextareaField, type TextareaFieldProps, type TextareaPassthroughProps, TypeInferredBuilder, type UseDebouncedValidationOptions, type UseEnhancedFormStateOptions, type UseInferredFormOptions, type ValidationUtils, type WithControl, type WizardFormConfig, ZodForm, type ZodFormConfig, type ZodFormFieldConfig, applyServerErrors, asyncValidation, commonValidations, createAdvancedBuilder, createBasicFormBuilder, createDateSchema, createEmailSchema, createField, createFieldArrayBuilder, createFieldArrayCustomConfig, createFieldArrayItemBuilder, createFileSchema, createFormTestUtils, createFutureDateSchema, createMaxLengthSchema, createMinLengthSchema, createMockFormData, createMockFormErrors, createNestedPathBuilder, createNumberRangeSchema, createOptimizedFieldHandler, createPasswordSchema, createPastDateSchema, createPhoneSchema, createRequiredCheckboxSchema, createRequiredSchema, createTypeInferredBuilder, createUrlSchema, createZodFormConfig, crossFieldValidation, debounce, deepEqual, defineInferredForm, errorMessages, field, getFieldError, getFormErrors, hasFieldError, hasFormErrors, memorySafeFieldArray, pathToString, serverValidation, shallowEqual, simulateFieldInput, simulateFormSubmission, suggestGarbageCollection, syncArrays, throttle, useDebouncedFieldValidation, useDebouncedValidation, useEnhancedFormState, useFieldArrayMemoryCleanup, useFormHelper, useHeroForm, useHeroHookFormDefaults, useInferredForm, useLazyFieldArrayRegistration, useLazyFieldRegistration, useMemoizedCallback, useMemoizedFieldProps, usePerformanceMonitor, useTypeInferredForm, useZodForm, validationPatterns, validationUtils, waitForFormState };
|
|
4436
|
+
export { AdvancedFieldBuilder, type ArraySyncOptions, type ArraySyncResult, type AutocompleteDefaults, AutocompleteField, type AutocompleteFieldProps, type AutocompleteOption, type AutocompletePassthroughProps, type BaseFormFieldConfig, BasicFormBuilder, type BooleanFieldConfig, type ButtonDefaults, type CheckboxDefaults, CheckboxField, type CheckboxFieldProps, CheckboxGroupField, type CheckboxGroupFieldConfig, type CheckboxGroupFieldProps, type CheckboxGroupPassthroughProps, type CheckboxPassthroughProps, type CommonFieldDefaults, CommonFields, ConditionalField, type ConditionalFieldConfig, type ConditionalFieldProps, type ConditionalValidation, ConfigurableForm, ContentField, type ContentFieldConfig, type CreateFieldArrayCustomConfigOptions, type CustomFieldConfig, type CustomFieldDef, type CustomFieldInputType, DateField, type DateFieldConfig, type DateFieldProps, type DateInputDefaults, type DateInputPassthroughProps, type DynamicSectionConfig, DynamicSectionField, type DynamicSectionFieldProps, type EnhancedFormState, FieldArrayBuilder, type FieldArrayConfig, FieldArrayField, type FieldArrayFieldProps, FieldArrayItemBuilder, type FieldArrayItemRenderProps, type FieldBaseProps, type FieldCreationParams, type FieldGroup, FileField, type FileFieldConfig, type FileFieldProps, type FileInputPassthroughProps, FontPickerField, type FontPickerFieldConfig, type FontPickerFieldProps, type FormConfig, FormField, type FormFieldConfig, FormFieldHelpers, type FormFieldType, type FormProps, FormProvider, FormStatus, type FormStatusProps, type FormStep, type FormSubmissionState, type FormTestUtils, FormToast, type FormToastProps, type FormValidationError, type HeroHookFormDefaultsConfig, HeroHookFormProvider, type HeroHookFormProviderProps, type InputDefaults, InputField, type InputFieldProps, type InputPassthroughProps, type RadioFieldConfig, type RadioGroupDefaults, RadioGroupField, type RadioGroupFieldProps, type RadioGroupPassthroughProps, type SelectDefaults, SelectField, type SelectFieldProps, type SelectPassthroughProps, ServerActionForm, type ServerFieldError, type ServerFormError, SimpleForm, type SimpleFormProps, type SliderDefaults, SliderField, type SliderFieldConfig, type SliderFieldProps, type SliderPassthroughProps, type StringArrayFieldConfig, type StringFieldConfig, SubmitButton, type SubmitButtonProps, type SwitchDefaults, SwitchField, type SwitchFieldProps, type SwitchPassthroughProps, type TextareaDefaults, TextareaField, type TextareaFieldProps, type TextareaPassthroughProps, TypeInferredBuilder, type UseDebouncedValidationOptions, type UseEnhancedFormStateOptions, type UseInferredFormOptions, type ValidationUtils, type WithControl, type WizardFormConfig, ZodForm, type ZodFormConfig, type ZodFormFieldConfig, applyServerErrors, asyncValidation, commonValidations, createAdvancedBuilder, createBasicFormBuilder, createCustomFieldConfigForItem, createDateSchema, createEmailSchema, createField, createFieldArrayBuilder, createFieldArrayCustomConfig, createFieldArrayItemBuilder, createFileSchema, createFormTestUtils, createFutureDateSchema, createMaxLengthSchema, createMinLengthSchema, createMockFormData, createMockFormErrors, createNestedPathBuilder, createNumberRangeSchema, createOptimizedFieldHandler, createPasswordSchema, createPastDateSchema, createPhoneSchema, createRequiredCheckboxSchema, createRequiredSchema, createTypeInferredBuilder, createUrlSchema, createZodFormConfig, crossFieldValidation, debounce, deepEqual, defineInferredForm, errorMessages, field, getFieldError, getFormErrors, hasFieldError, hasFormErrors, memorySafeFieldArray, pathToString, serverValidation, shallowEqual, simulateFieldInput, simulateFormSubmission, suggestGarbageCollection, syncArrays, throttle, useDebouncedFieldValidation, useDebouncedValidation, useEnhancedFormState, useFieldArrayMemoryCleanup, useFormHelper, useHeroForm, useHeroHookFormDefaults, useInferredForm, useLazyFieldArrayRegistration, useLazyFieldRegistration, useMemoizedCallback, useMemoizedFieldProps, usePerformanceMonitor, useTypeInferredForm, useZodForm, validationPatterns, validationUtils, waitForFormState };
|
package/dist/index.js
CHANGED
|
@@ -5785,11 +5785,40 @@ function syncArrays(options) {
|
|
|
5785
5785
|
import React27 from "react";
|
|
5786
5786
|
import { useFieldArray as useFieldArray2 } from "react-hook-form";
|
|
5787
5787
|
import { Button as Button6 } from "@heroui/react";
|
|
5788
|
+
function parseDropdownOptions(options) {
|
|
5789
|
+
if (options == null) return [];
|
|
5790
|
+
if (Array.isArray(options)) return options;
|
|
5791
|
+
return options.split("\n").map((o) => o.trim()).filter((o) => o.length > 0).map((o) => ({ label: o, value: o }));
|
|
5792
|
+
}
|
|
5793
|
+
function createCustomFieldConfigForItem(name, def) {
|
|
5794
|
+
const { fieldType, name: label, options } = def;
|
|
5795
|
+
switch (fieldType) {
|
|
5796
|
+
case "DATE":
|
|
5797
|
+
return FormFieldHelpers.date(name, label, { granularity: "day" });
|
|
5798
|
+
case "SHORT_TEXT":
|
|
5799
|
+
return FormFieldHelpers.input(name, label);
|
|
5800
|
+
case "LONG_TEXT":
|
|
5801
|
+
return FormFieldHelpers.textarea(name, label);
|
|
5802
|
+
case "NUMBER":
|
|
5803
|
+
return FormFieldHelpers.input(name, label, { type: "number" });
|
|
5804
|
+
case "DROPDOWN":
|
|
5805
|
+
return FormFieldHelpers.select(
|
|
5806
|
+
name,
|
|
5807
|
+
label,
|
|
5808
|
+
parseDropdownOptions(options)
|
|
5809
|
+
);
|
|
5810
|
+
default: {
|
|
5811
|
+
void fieldType;
|
|
5812
|
+
return FormFieldHelpers.input(name, label);
|
|
5813
|
+
}
|
|
5814
|
+
}
|
|
5815
|
+
}
|
|
5788
5816
|
function createFieldArrayCustomConfig(options) {
|
|
5789
5817
|
const {
|
|
5790
5818
|
className,
|
|
5791
5819
|
defaultItem,
|
|
5792
5820
|
enableReordering = false,
|
|
5821
|
+
getItemFieldConfig,
|
|
5793
5822
|
label,
|
|
5794
5823
|
max = 10,
|
|
5795
5824
|
min = 0,
|
|
@@ -5797,6 +5826,11 @@ function createFieldArrayCustomConfig(options) {
|
|
|
5797
5826
|
renderAddButton,
|
|
5798
5827
|
renderItem
|
|
5799
5828
|
} = options;
|
|
5829
|
+
if (!getItemFieldConfig && !renderItem) {
|
|
5830
|
+
throw new Error(
|
|
5831
|
+
"createFieldArrayCustomConfig: provide either getItemFieldConfig or renderItem"
|
|
5832
|
+
);
|
|
5833
|
+
}
|
|
5800
5834
|
return {
|
|
5801
5835
|
className,
|
|
5802
5836
|
label,
|
|
@@ -5834,23 +5868,40 @@ function createFieldArrayCustomConfig(options) {
|
|
|
5834
5868
|
move(index, index + 1);
|
|
5835
5869
|
}
|
|
5836
5870
|
};
|
|
5871
|
+
const submissionState = {
|
|
5872
|
+
error: void 0,
|
|
5873
|
+
isSubmitted: form.formState.isSubmitted,
|
|
5874
|
+
isSubmitting: form.formState.isSubmitting,
|
|
5875
|
+
isSuccess: false
|
|
5876
|
+
};
|
|
5877
|
+
const itemProps = (index) => ({
|
|
5878
|
+
canMoveDown: enableReordering && index < fields.length - 1,
|
|
5879
|
+
canMoveUp: enableReordering && index > 0,
|
|
5880
|
+
control,
|
|
5881
|
+
errors,
|
|
5882
|
+
field: fields[index],
|
|
5883
|
+
fields,
|
|
5884
|
+
form,
|
|
5885
|
+
index,
|
|
5886
|
+
onMoveDown: () => handleMoveDown(index),
|
|
5887
|
+
onMoveUp: () => handleMoveUp(index),
|
|
5888
|
+
onRemove: () => handleRemove(index)
|
|
5889
|
+
});
|
|
5837
5890
|
return /* @__PURE__ */ React27.createElement("div", { className }, /* @__PURE__ */ React27.createElement("div", { className: "space-y-4" }, fields.map((field2, index) => {
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
onRemove: () => handleRemove(index)
|
|
5853
|
-
}));
|
|
5891
|
+
if (getItemFieldConfig) {
|
|
5892
|
+
const config = getItemFieldConfig(itemProps(index));
|
|
5893
|
+
if (!config) return /* @__PURE__ */ React27.createElement(React27.Fragment, { key: field2.id });
|
|
5894
|
+
return /* @__PURE__ */ React27.createElement(
|
|
5895
|
+
FormField,
|
|
5896
|
+
{
|
|
5897
|
+
key: field2.id,
|
|
5898
|
+
config,
|
|
5899
|
+
form,
|
|
5900
|
+
submissionState
|
|
5901
|
+
}
|
|
5902
|
+
);
|
|
5903
|
+
}
|
|
5904
|
+
return /* @__PURE__ */ React27.createElement(React27.Fragment, { key: field2.id }, renderItem(itemProps(index)));
|
|
5854
5905
|
}), fields.length === 0 && renderAddButton ? /* @__PURE__ */ React27.createElement("div", { className: "text-center py-8 text-gray-500" }, /* @__PURE__ */ React27.createElement("p", null, "No ", label?.toLowerCase() || "items", " added yet."), renderAddButton({ canAdd, onAdd: handleAdd })) : null, fields.length > 0 && renderAddButton ? renderAddButton({ canAdd, onAdd: handleAdd }) : canAdd && /* @__PURE__ */ React27.createElement(
|
|
5855
5906
|
Button6,
|
|
5856
5907
|
{
|
|
@@ -6121,6 +6172,7 @@ export {
|
|
|
6121
6172
|
commonValidations,
|
|
6122
6173
|
createAdvancedBuilder,
|
|
6123
6174
|
createBasicFormBuilder,
|
|
6175
|
+
createCustomFieldConfigForItem,
|
|
6124
6176
|
createDateSchema,
|
|
6125
6177
|
createEmailSchema,
|
|
6126
6178
|
createField,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rachelallyson/hero-hook-form",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.14.0",
|
|
4
4
|
"description": "Typed form helpers that combine React Hook Form and HeroUI components.",
|
|
5
5
|
"author": "Rachel Higley",
|
|
6
6
|
"homepage": "https://rachelallyson.github.io/hero-hook-form/",
|