@rachelallyson/hero-hook-form 2.10.0 → 2.11.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 CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [2.11.0] - 2026-01-28
6
+
7
+ ### Added
8
+
9
+ - **Dynamic options for autocomplete** – `FormFieldHelpers.autocomplete()` and the builder chain now accept either a static options array or a getter function `() => options`. Use a getter for API-driven autocomplete (e.g. PCO Person, search-as-you-type): the getter is called each render so items stay in sync with state. Config supports `getOptions`; `FormField`, `ServerActionForm`, and `AdvancedFormBuilder` resolve items from `getOptions()` when present, else `options`. No need for `FormFieldHelpers.custom` when you only need dynamic items.
10
+
11
+ ### Changed
12
+
13
+ - **FormFieldHelpers.autocomplete** – Third parameter can be `options[]` or `() => options[]`; JSDoc documents dynamic usage with `onInputChange`.
14
+ - **StringFieldConfig** – Added optional `getOptions?: () => { label: string; value: string | number }[]` for autocomplete fields.
15
+ - **AutocompleteField JSDoc** – Notes dynamic options via getter + `onInputChange`.
16
+
5
17
  ## [2.10.0] - 2026-01-28
6
18
 
7
19
  ### Added
package/dist/index.d.ts CHANGED
@@ -80,10 +80,16 @@ interface StringFieldConfig<TFieldValues extends FieldValues> extends BaseFormFi
80
80
  textareaProps?: TextareaPassthroughProps;
81
81
  selectProps?: SelectPassthroughProps;
82
82
  autocompleteProps?: AutocompletePassthroughProps;
83
+ /** Static options for autocomplete/select. Omit when using getOptions for dynamic items. */
83
84
  options?: {
84
85
  label: string;
85
86
  value: string | number;
86
87
  }[];
88
+ /** Dynamic options for autocomplete: called each render to get current items (e.g. from API/state). */
89
+ getOptions?: () => {
90
+ label: string;
91
+ value: string | number;
92
+ }[];
87
93
  }
88
94
  interface BooleanFieldConfig<TFieldValues extends FieldValues> extends BaseFormFieldConfig<TFieldValues> {
89
95
  type: "checkbox" | "switch";
@@ -635,7 +641,9 @@ type AutocompleteFieldProps<TFieldValues extends FieldValues, TValue extends str
635
641
  *
636
642
  * This component provides a type-safe autocomplete field with validation support,
637
643
  * error handling, and accessibility features. It supports both static option lists
638
- * and async loading via the items prop or children render function.
644
+ * and async loading via the items prop or children render function. For dynamic
645
+ * options (e.g. API search), use FormFieldHelpers.autocomplete with a getter:
646
+ * () => people.map(p => ({ label: p.name, value: p.id })) and onInputChange to fetch.
639
647
  *
640
648
  * @template TFieldValues - The form data type
641
649
  * @template TValue - The value type for the autocomplete field (string or number)
@@ -2424,12 +2432,15 @@ declare class BasicFormBuilder<T extends FieldValues> {
2424
2432
  value: string | number;
2425
2433
  }[]): this;
2426
2434
  /**
2427
- * Add an autocomplete field
2435
+ * Add an autocomplete field (static options array or dynamic getOptions getter).
2428
2436
  */
2429
2437
  autocomplete(name: Path<T>, label: string, items: {
2430
2438
  label: string;
2431
2439
  value: string | number;
2432
- }[], placeholder?: string): this;
2440
+ }[] | (() => {
2441
+ label: string;
2442
+ value: string | number;
2443
+ }[]), placeholder?: string): this;
2433
2444
  /**
2434
2445
  * Add a checkbox field
2435
2446
  */
@@ -2530,27 +2541,31 @@ declare function inputHelper<T extends FieldValues>(name: Path<T>, label: string
2530
2541
  declare function inputHelper<T extends FieldValues>(name: Path<T>, label: string, type: "text" | "email" | "tel" | "password", inputProps: InputPassthroughProps): ZodFormFieldConfig<T>;
2531
2542
  declare const FormFieldHelpers: {
2532
2543
  /**
2533
- * Create an autocomplete field
2544
+ * Create an autocomplete field with static or dynamic options.
2545
+ *
2546
+ * Pass an array for a fixed list, or a getter function for dynamic/API-driven options
2547
+ * (e.g. search-as-you-type). The getter is called each render so it sees current state;
2548
+ * use with autocompleteProps.onInputChange to fetch options when the user types.
2534
2549
  *
2535
2550
  * @example
2536
2551
  * ```tsx
2537
- * // Simple autocomplete
2538
- * FormFieldHelpers.autocomplete("country", "Country", options)
2539
- *
2540
- * // With placeholder
2541
- * FormFieldHelpers.autocomplete("country", "Country", options, "Search countries")
2552
+ * // Static
2553
+ * FormFieldHelpers.autocomplete("country", "Country", options, "Search countries", { allowsCustomValue: true })
2542
2554
  *
2543
- * // With full customization
2544
- * FormFieldHelpers.autocomplete("country", "Country", options, "Search countries", {
2545
- * classNames: { base: "custom-autocomplete" },
2546
- * allowsCustomValue: true
2555
+ * // Dynamic (e.g. PCO Person)
2556
+ * const [people, setPeople] = useState([]);
2557
+ * FormFieldHelpers.autocomplete("personId", "Person", () => people.map(p => ({ label: p.name, value: p.id })), "Search people", {
2558
+ * onInputChange: (q) => fetchPeople(q).then(setPeople),
2547
2559
  * })
2548
2560
  * ```
2549
2561
  */
2550
2562
  autocomplete: <T extends FieldValues>(name: Path<T>, label: string, items: {
2551
2563
  label: string;
2552
2564
  value: string | number;
2553
- }[], placeholder?: string, autocompleteProps?: AutocompletePassthroughProps) => ZodFormFieldConfig<T>;
2565
+ }[] | (() => {
2566
+ label: string;
2567
+ value: string | number;
2568
+ }[]), placeholder?: string, autocompleteProps?: AutocompletePassthroughProps) => ZodFormFieldConfig<T>;
2554
2569
  /**
2555
2570
  * Create a checkbox field
2556
2571
  *
@@ -2988,7 +3003,11 @@ type FieldCreationParams<T extends FieldValues> = {
2988
3003
  type: "autocomplete";
2989
3004
  name: Path<T>;
2990
3005
  label: string;
2991
- options: {
3006
+ options?: {
3007
+ label: string;
3008
+ value: string | number;
3009
+ }[];
3010
+ getOptions?: () => {
2992
3011
  label: string;
2993
3012
  value: string | number;
2994
3013
  }[];
package/dist/index.js CHANGED
@@ -2335,6 +2335,7 @@ function FormFieldComponent({
2335
2335
  );
2336
2336
  }
2337
2337
  case "autocomplete": {
2338
+ const autocompleteOptions = "getOptions" in fieldConfig && typeof fieldConfig.getOptions === "function" ? fieldConfig.getOptions() : "options" in fieldConfig && fieldConfig.options ? fieldConfig.options : [];
2338
2339
  return /* @__PURE__ */ React19.createElement(
2339
2340
  AutocompleteField,
2340
2341
  {
@@ -2342,7 +2343,7 @@ function FormFieldComponent({
2342
2343
  name: fieldConfig.name,
2343
2344
  control,
2344
2345
  defaultValue: "defaultValue" in fieldConfig ? fieldConfig.defaultValue : void 0,
2345
- items: ("options" in fieldConfig && fieldConfig.options ? fieldConfig.options : []).map((opt) => ({
2346
+ items: autocompleteOptions.map((opt) => ({
2346
2347
  label: opt.label,
2347
2348
  value: String(opt.value)
2348
2349
  })),
@@ -3120,10 +3121,11 @@ function ServerActionField({
3120
3121
  }
3121
3122
  case "autocomplete": {
3122
3123
  const stringConfig = fieldConfig;
3123
- const items = stringConfig.options?.map((opt) => ({
3124
+ const rawItems = typeof stringConfig.getOptions === "function" ? stringConfig.getOptions() : stringConfig.options ?? [];
3125
+ const items = rawItems.map((opt) => ({
3124
3126
  label: opt.label,
3125
3127
  value: String(opt.value)
3126
- })) || [];
3128
+ }));
3127
3129
  return /* @__PURE__ */ React21.createElement(
3128
3130
  Autocomplete,
3129
3131
  {
@@ -4048,14 +4050,15 @@ var BasicFormBuilder = class {
4048
4050
  return this;
4049
4051
  }
4050
4052
  /**
4051
- * Add an autocomplete field
4053
+ * Add an autocomplete field (static options array or dynamic getOptions getter).
4052
4054
  */
4053
4055
  autocomplete(name, label, items, placeholder) {
4056
+ const isGetter = typeof items === "function";
4054
4057
  this.fields.push({
4055
4058
  autocompleteProps: placeholder ? { placeholder } : void 0,
4056
4059
  label,
4057
4060
  name,
4058
- options: items,
4061
+ ...isGetter ? { getOptions: items } : { options: items },
4059
4062
  type: "autocomplete"
4060
4063
  });
4061
4064
  return this;
@@ -4132,33 +4135,37 @@ function inputHelper(name, label, typeOrProps, inputProps) {
4132
4135
  }
4133
4136
  var FormFieldHelpers = {
4134
4137
  /**
4135
- * Create an autocomplete field
4138
+ * Create an autocomplete field with static or dynamic options.
4139
+ *
4140
+ * Pass an array for a fixed list, or a getter function for dynamic/API-driven options
4141
+ * (e.g. search-as-you-type). The getter is called each render so it sees current state;
4142
+ * use with autocompleteProps.onInputChange to fetch options when the user types.
4136
4143
  *
4137
4144
  * @example
4138
4145
  * ```tsx
4139
- * // Simple autocomplete
4140
- * FormFieldHelpers.autocomplete("country", "Country", options)
4146
+ * // Static
4147
+ * FormFieldHelpers.autocomplete("country", "Country", options, "Search countries", { allowsCustomValue: true })
4141
4148
  *
4142
- * // With placeholder
4143
- * FormFieldHelpers.autocomplete("country", "Country", options, "Search countries")
4144
- *
4145
- * // With full customization
4146
- * FormFieldHelpers.autocomplete("country", "Country", options, "Search countries", {
4147
- * classNames: { base: "custom-autocomplete" },
4148
- * allowsCustomValue: true
4149
+ * // Dynamic (e.g. PCO Person)
4150
+ * const [people, setPeople] = useState([]);
4151
+ * FormFieldHelpers.autocomplete("personId", "Person", () => people.map(p => ({ label: p.name, value: p.id })), "Search people", {
4152
+ * onInputChange: (q) => fetchPeople(q).then(setPeople),
4149
4153
  * })
4150
4154
  * ```
4151
4155
  */
4152
- autocomplete: (name, label, items, placeholder, autocompleteProps) => ({
4153
- autocompleteProps: {
4154
- ...placeholder && { placeholder },
4155
- ...autocompleteProps
4156
- },
4157
- label,
4158
- name,
4159
- options: items,
4160
- type: "autocomplete"
4161
- }),
4156
+ autocomplete: (name, label, items, placeholder, autocompleteProps) => {
4157
+ const isGetter = typeof items === "function";
4158
+ return {
4159
+ autocompleteProps: {
4160
+ ...placeholder && { placeholder },
4161
+ ...autocompleteProps
4162
+ },
4163
+ ...isGetter ? { getOptions: items } : { options: items },
4164
+ label,
4165
+ name,
4166
+ type: "autocomplete"
4167
+ };
4168
+ },
4162
4169
  /**
4163
4170
  * Create a checkbox field
4164
4171
  *
@@ -4830,7 +4837,7 @@ function createFieldFromParams(params) {
4830
4837
  autocompleteProps: params.props,
4831
4838
  label: params.label,
4832
4839
  name: params.name,
4833
- options: params.options,
4840
+ ...typeof params.getOptions === "function" ? { getOptions: params.getOptions } : { options: params.options },
4834
4841
  type: "autocomplete"
4835
4842
  };
4836
4843
  case "content":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rachelallyson/hero-hook-form",
3
- "version": "2.10.0",
3
+ "version": "2.11.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/",