@juantroconisf/lib 9.4.0 → 11.0.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.d.mts CHANGED
@@ -76,12 +76,19 @@ interface ComponentInputProps {
76
76
  onBlur: () => void;
77
77
  isInvalid: boolean;
78
78
  errorMessage: string;
79
+ /** Derived from the Yup schema — true when the field is marked .required(). */
80
+ isRequired: boolean;
79
81
  }
80
- /** Props returned by on.input() */
82
+ /** Props returned by on.input() — for Input and Textarea */
81
83
  interface ItemInputProps<V = any> extends ComponentInputProps {
82
84
  onValueChange: (value: V) => void;
83
85
  value: V;
84
86
  }
87
+ /** Props returned by on.numberInput() — for NumberInput */
88
+ interface ItemNumberInputProps extends ComponentInputProps {
89
+ onValueChange: (value: number) => void;
90
+ value: number;
91
+ }
85
92
  /** Props returned by on.select() */
86
93
  interface ItemSelectProps extends ComponentInputProps {
87
94
  onSelectionChange: NonNullable<SelectProps["onSelectionChange"]>;
@@ -92,6 +99,16 @@ interface ItemAutocompleteProps extends ComponentInputProps {
92
99
  onSelectionChange: NonNullable<AutocompleteProps["onSelectionChange"]>;
93
100
  selectedKey: SingleSelection["selectedKey"];
94
101
  }
102
+ /** Props returned by on.checkbox() and on.switch() */
103
+ interface ItemToggleProps extends ComponentInputProps {
104
+ onValueChange: (isSelected: boolean) => void;
105
+ isSelected: boolean;
106
+ }
107
+ /** Props returned by on.radio() — for RadioGroup */
108
+ interface ItemRadioGroupProps extends ComponentInputProps {
109
+ onValueChange: (value: string) => void;
110
+ value: string;
111
+ }
95
112
  /**
96
113
  * Interface for the polymorphic 'on' method handlers.
97
114
  */
@@ -102,6 +119,10 @@ interface OnMethods<O extends StateType> {
102
119
  input<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemInputProps<any>;
103
120
  /** Registers a primitive array element by index. */
104
121
  input<K extends ArrayPaths<O>>(arrayKey: K, index: number): ItemInputProps<any>;
122
+ /** Registers a numeric field for NumberInput. */
123
+ numberInput<P extends AllPaths<O>>(id: P): ItemNumberInputProps;
124
+ /** Registers a numeric field within an object array element. */
125
+ numberInput<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemNumberInputProps;
105
126
  /** Registers a scalar or nested object field. */
106
127
  select<P extends AllPaths<O>>(id: P): ItemSelectProps;
107
128
  /** Registers a complete array field for multi-selection. */
@@ -116,6 +137,18 @@ interface OnMethods<O extends StateType> {
116
137
  autocomplete<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemAutocompleteProps;
117
138
  /** Registers a primitive array element by index. */
118
139
  autocomplete<K extends ArrayPaths<O>>(arrayKey: K, index: number): ItemAutocompleteProps;
140
+ /** Registers a boolean field for Checkbox. */
141
+ checkbox<P extends AllPaths<O>>(id: P): ItemToggleProps;
142
+ /** Registers a boolean field within an object array element for Checkbox. */
143
+ checkbox<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemToggleProps;
144
+ /** Registers a boolean field for Switch. */
145
+ switch<P extends AllPaths<O>>(id: P): ItemToggleProps;
146
+ /** Registers a boolean field within an object array element for Switch. */
147
+ switch<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemToggleProps;
148
+ /** Registers a string field for RadioGroup. */
149
+ radio<P extends AllPaths<O>>(id: P): ItemRadioGroupProps;
150
+ /** Registers a string field within an object array element for RadioGroup. */
151
+ radio<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemRadioGroupProps;
119
152
  }
120
153
  /**
121
154
  * Recursive type to find all paths to arrays in the state.
@@ -123,10 +156,6 @@ interface OnMethods<O extends StateType> {
123
156
  type ArrayPaths<T> = T extends object ? {
124
157
  [K in keyof T & string]: NonNullable<T[K]> extends (infer E)[] ? K | (E extends object ? `${K}.${ArrayPaths<E>}` : never) : NonNullable<T[K]> extends object ? NonNullable<T[K]> extends Date ? never : `${K}.${ArrayPaths<NonNullable<T[K]>>}` : never;
125
158
  }[keyof T & string] : never;
126
- /** Keys whose values are arrays of objects (not primitives). */
127
- type ObjectArrayKeys<O extends StateType> = {
128
- [K in keyof O]: O[K] extends Record<string, any>[] ? K : never;
129
- }[keyof O];
130
159
  /**
131
160
  * Helper to get paths for fields within object arrays.
132
161
  * Returns paths like "arrayKey.fieldName".
@@ -137,16 +166,28 @@ type ObjectArrayFieldPaths<O extends StateType> = {
137
166
  type ArrayElement<T> = T extends (infer E)[] ? E : never;
138
167
  /** Resolves the type of the identifier field for an array element (defaults to "id"). */
139
168
  type ItemIdType<O extends StateType, K extends keyof O> = "id" extends keyof ArrayElement<O[K]> ? ArrayElement<O[K]>["id"] : string | number;
169
+ /** Extracts the array key from a composite path e.g. "relatives.age" → "relatives". */
170
+ type ExtractArrayKey<P extends string> = P extends `${infer K}.${string}` ? K : never;
171
+ /**
172
+ * Resolves the identifier field type for the array referenced by a composite path.
173
+ * e.g. if relatives[].id is string, then ArrayItemIdTypeFromPath<O, "relatives.age"> = string
174
+ */
175
+ type ArrayItemIdTypeFromPath<O extends StateType, P extends string> = ExtractArrayKey<P> extends keyof O ? ItemIdType<O, ExtractArrayKey<P>> : string | number;
176
+ /**
177
+ * Resolves the value type for the field referenced by a composite path.
178
+ * e.g. "relatives.age" → number (the type of the `age` field in each relative item)
179
+ */
180
+ type CompositeFieldValue<O extends StateType, P extends string> = P extends `${infer K}.${infer F}` ? K extends keyof O ? O[K] extends (infer E)[] ? F extends keyof E ? NonNullable<E[F]> : any : any : any : any;
140
181
  type NestedFieldValue<T, F extends string> = F extends `${infer First}.${infer Rest}` ? First extends keyof T ? NestedFieldValue<NonNullable<T[First]>, Rest> : NonNullable<T> extends (infer U)[] ? NestedFieldValue<U, F> : any : F extends keyof T ? NonNullable<T[F]> : NonNullable<T> extends (infer U)[] ? F extends keyof U ? NonNullable<U[F]> : any : any;
141
182
  type FieldPaths<T> = T extends Record<string, any> ? {
142
183
  [K in keyof T & string]: T[K] extends any[] ? K : T[K] extends Record<string, any> ? `${K}.${FieldPaths<T[K]>}` : K;
143
184
  }[keyof T & string] : never;
144
185
  type NestedObjectPaths<O extends StateType> = {
145
- [K in keyof O & string]: O[K] extends any[] ? never : O[K] extends Record<string, any> ? `${K}.${FieldPaths<O[K]>}` : never;
186
+ [K in keyof O & string]: NonNullable<O[K]> extends any[] ? never : NonNullable<O[K]> extends Date ? never : NonNullable<O[K]> extends Record<string, any> ? `${K}.${FieldPaths<NonNullable<O[K]>>}` : never;
146
187
  }[keyof O & string];
147
- /** Keys whose values are not arrays and not plain objects (i.e. scalar/primitive fields). */
188
+ /** Keys whose values are not arrays and not plain objects (i.e. scalar/primitive fields). Date is treated as a scalar. */
148
189
  type ScalarKeys<O extends StateType> = {
149
- [K in keyof O]: O[K] extends any[] ? never : O[K] extends Record<string, any> ? never : K;
190
+ [K in keyof O]: NonNullable<O[K]> extends any[] ? never : NonNullable<O[K]> extends Date ? K : NonNullable<O[K]> extends Record<string, any> ? never : K;
150
191
  }[keyof O];
151
192
  type AllPaths<O extends StateType> = ScalarKeys<O> | NestedObjectPaths<O>;
152
193
  /**
@@ -156,17 +197,19 @@ interface HelpersFunc<O extends StateType> {
156
197
  /** Adds a new item to an array. */
157
198
  addItem: <K extends ArrayPaths<O>>(arrayKey: K, item: NestedFieldValue<O, K> extends (infer E)[] ? E : never, index?: number) => void;
158
199
  /** Removes an item from an array by its index. */
159
- removeItem: <K extends ArrayPaths<O>>(arrayKey: K, index: number) => void;
200
+ removeItemByIndexByIndex: <K extends ArrayPaths<O>>(arrayKey: K, index: number) => void;
160
201
  /** Removes an item from an array by its unique identifier. */
161
202
  removeById: <K extends ArrayPaths<O>>(arrayKey: K, itemId: string | number) => void;
162
- /** Replaces an item in an array at the given index. */
163
- updateItem: <K extends ArrayPaths<O>>(arrayKey: K, index: number, value: NestedFieldValue<O, K> extends (infer E)[] ? E : never) => void;
203
+ /** Updates an item in an array at the given index (supports partial updates). */
204
+ updateByIndex: <K extends ArrayPaths<O>>(arrayKey: K, index: number, value: NestedFieldValue<O, K> extends (infer E)[] ? Partial<E> : never) => void;
205
+ /** Updates an item in an array by its unique identifier (supports partial updates). */
206
+ updateById: <K extends ArrayPaths<O>>(arrayKey: K, itemId: string | number, value: NestedFieldValue<O, K> extends (infer E)[] ? Partial<E> : never) => void;
164
207
  /** Moves an item within an array using indices. */
165
- moveItem: <K extends ArrayPaths<O>>(arrayKey: K, from: number, to: number) => void;
208
+ moveItemByIndex: <K extends ArrayPaths<O>>(arrayKey: K, from: number, to: number) => void;
166
209
  /** Moves an item within an array using unique identifiers. */
167
210
  moveById: <K extends ArrayPaths<O>>(arrayKey: K, fromId: string | number, toId: string | number) => void;
168
211
  /** Gets an item from an array by its unique identifier (O(1) via indexMap). */
169
- getItem: <K extends ArrayPaths<O>>(arrayKey: K, itemId: string | number) => (NestedFieldValue<O, K> extends (infer E)[] ? E : never) | undefined;
212
+ getItemById: <K extends ArrayPaths<O>>(arrayKey: K, itemId: string | number) => (NestedFieldValue<O, K> extends (infer E)[] ? E : never) | undefined;
170
213
  }
171
214
  /**
172
215
  * The response object from the useForm hook.
@@ -176,13 +219,26 @@ interface UseFormResponse<O extends StateType> {
176
219
  onFieldBlur: BlurFunc<O>;
177
220
  /** Updates a scalar or nested object field. */
178
221
  onFieldChange<P extends AllPaths<O>>(id: P, value: NestedFieldValue<O, P & string>): void;
179
- /** Updates an object array element's field using composite syntax "array.field". */
180
- onFieldChange<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number, value: any): void;
181
- /** Updates an object array element's field by ID (explicit array key, field, and value). */
182
- onFieldChange<K extends ObjectArrayKeys<O>, F extends keyof ArrayElement<O[K]> & string>(arrayKey: K, itemId: ItemIdType<O, K>, field: F, value: ArrayElement<O[K]>[F]): void;
183
- /** Updates a primitive array element by index. */
184
- onFieldChange<K extends ArrayPaths<O>>(arrayKey: K, index: number, value: any): void;
222
+ /** Manually updates a field within an object array item. */
223
+ onArrayItemChange<P extends ObjectArrayFieldPaths<O>>(options: {
224
+ /** Composite dot-notation path: e.g. "users.name" */
225
+ at: P;
226
+ /** The unique identifier of the target array item — type is inferred from the array element's id field. */
227
+ id: ArrayItemIdTypeFromPath<O, P & string>;
228
+ /** The new value — type is inferred from the field referenced by `at`. */
229
+ value: CompositeFieldValue<O, P & string>;
230
+ }): void;
231
+ /** Manually updates a scalar or nested object selection field. */
185
232
  onSelectionChange: ValueChangeFunc<O, keyof O>;
233
+ /** Manually updates a selection-based field within an object array item. */
234
+ onArraySelectionChange<P extends ObjectArrayFieldPaths<O>>(options: {
235
+ /** Composite dot-notation path: e.g. "users.role" */
236
+ at: P;
237
+ /** The unique identifier of the target array item — type is inferred from the array element's id field. */
238
+ id: ArrayItemIdTypeFromPath<O, P & string>;
239
+ /** The new selection value — type is inferred from the field referenced by `at`. */
240
+ value: CompositeFieldValue<O, P & string>;
241
+ }): void;
186
242
  state: O;
187
243
  setState: React.Dispatch<React.SetStateAction<O>>;
188
244
  metadata: MetadataType;
package/dist/index.d.ts CHANGED
@@ -76,12 +76,19 @@ interface ComponentInputProps {
76
76
  onBlur: () => void;
77
77
  isInvalid: boolean;
78
78
  errorMessage: string;
79
+ /** Derived from the Yup schema — true when the field is marked .required(). */
80
+ isRequired: boolean;
79
81
  }
80
- /** Props returned by on.input() */
82
+ /** Props returned by on.input() — for Input and Textarea */
81
83
  interface ItemInputProps<V = any> extends ComponentInputProps {
82
84
  onValueChange: (value: V) => void;
83
85
  value: V;
84
86
  }
87
+ /** Props returned by on.numberInput() — for NumberInput */
88
+ interface ItemNumberInputProps extends ComponentInputProps {
89
+ onValueChange: (value: number) => void;
90
+ value: number;
91
+ }
85
92
  /** Props returned by on.select() */
86
93
  interface ItemSelectProps extends ComponentInputProps {
87
94
  onSelectionChange: NonNullable<SelectProps["onSelectionChange"]>;
@@ -92,6 +99,16 @@ interface ItemAutocompleteProps extends ComponentInputProps {
92
99
  onSelectionChange: NonNullable<AutocompleteProps["onSelectionChange"]>;
93
100
  selectedKey: SingleSelection["selectedKey"];
94
101
  }
102
+ /** Props returned by on.checkbox() and on.switch() */
103
+ interface ItemToggleProps extends ComponentInputProps {
104
+ onValueChange: (isSelected: boolean) => void;
105
+ isSelected: boolean;
106
+ }
107
+ /** Props returned by on.radio() — for RadioGroup */
108
+ interface ItemRadioGroupProps extends ComponentInputProps {
109
+ onValueChange: (value: string) => void;
110
+ value: string;
111
+ }
95
112
  /**
96
113
  * Interface for the polymorphic 'on' method handlers.
97
114
  */
@@ -102,6 +119,10 @@ interface OnMethods<O extends StateType> {
102
119
  input<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemInputProps<any>;
103
120
  /** Registers a primitive array element by index. */
104
121
  input<K extends ArrayPaths<O>>(arrayKey: K, index: number): ItemInputProps<any>;
122
+ /** Registers a numeric field for NumberInput. */
123
+ numberInput<P extends AllPaths<O>>(id: P): ItemNumberInputProps;
124
+ /** Registers a numeric field within an object array element. */
125
+ numberInput<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemNumberInputProps;
105
126
  /** Registers a scalar or nested object field. */
106
127
  select<P extends AllPaths<O>>(id: P): ItemSelectProps;
107
128
  /** Registers a complete array field for multi-selection. */
@@ -116,6 +137,18 @@ interface OnMethods<O extends StateType> {
116
137
  autocomplete<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemAutocompleteProps;
117
138
  /** Registers a primitive array element by index. */
118
139
  autocomplete<K extends ArrayPaths<O>>(arrayKey: K, index: number): ItemAutocompleteProps;
140
+ /** Registers a boolean field for Checkbox. */
141
+ checkbox<P extends AllPaths<O>>(id: P): ItemToggleProps;
142
+ /** Registers a boolean field within an object array element for Checkbox. */
143
+ checkbox<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemToggleProps;
144
+ /** Registers a boolean field for Switch. */
145
+ switch<P extends AllPaths<O>>(id: P): ItemToggleProps;
146
+ /** Registers a boolean field within an object array element for Switch. */
147
+ switch<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemToggleProps;
148
+ /** Registers a string field for RadioGroup. */
149
+ radio<P extends AllPaths<O>>(id: P): ItemRadioGroupProps;
150
+ /** Registers a string field within an object array element for RadioGroup. */
151
+ radio<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemRadioGroupProps;
119
152
  }
120
153
  /**
121
154
  * Recursive type to find all paths to arrays in the state.
@@ -123,10 +156,6 @@ interface OnMethods<O extends StateType> {
123
156
  type ArrayPaths<T> = T extends object ? {
124
157
  [K in keyof T & string]: NonNullable<T[K]> extends (infer E)[] ? K | (E extends object ? `${K}.${ArrayPaths<E>}` : never) : NonNullable<T[K]> extends object ? NonNullable<T[K]> extends Date ? never : `${K}.${ArrayPaths<NonNullable<T[K]>>}` : never;
125
158
  }[keyof T & string] : never;
126
- /** Keys whose values are arrays of objects (not primitives). */
127
- type ObjectArrayKeys<O extends StateType> = {
128
- [K in keyof O]: O[K] extends Record<string, any>[] ? K : never;
129
- }[keyof O];
130
159
  /**
131
160
  * Helper to get paths for fields within object arrays.
132
161
  * Returns paths like "arrayKey.fieldName".
@@ -137,16 +166,28 @@ type ObjectArrayFieldPaths<O extends StateType> = {
137
166
  type ArrayElement<T> = T extends (infer E)[] ? E : never;
138
167
  /** Resolves the type of the identifier field for an array element (defaults to "id"). */
139
168
  type ItemIdType<O extends StateType, K extends keyof O> = "id" extends keyof ArrayElement<O[K]> ? ArrayElement<O[K]>["id"] : string | number;
169
+ /** Extracts the array key from a composite path e.g. "relatives.age" → "relatives". */
170
+ type ExtractArrayKey<P extends string> = P extends `${infer K}.${string}` ? K : never;
171
+ /**
172
+ * Resolves the identifier field type for the array referenced by a composite path.
173
+ * e.g. if relatives[].id is string, then ArrayItemIdTypeFromPath<O, "relatives.age"> = string
174
+ */
175
+ type ArrayItemIdTypeFromPath<O extends StateType, P extends string> = ExtractArrayKey<P> extends keyof O ? ItemIdType<O, ExtractArrayKey<P>> : string | number;
176
+ /**
177
+ * Resolves the value type for the field referenced by a composite path.
178
+ * e.g. "relatives.age" → number (the type of the `age` field in each relative item)
179
+ */
180
+ type CompositeFieldValue<O extends StateType, P extends string> = P extends `${infer K}.${infer F}` ? K extends keyof O ? O[K] extends (infer E)[] ? F extends keyof E ? NonNullable<E[F]> : any : any : any : any;
140
181
  type NestedFieldValue<T, F extends string> = F extends `${infer First}.${infer Rest}` ? First extends keyof T ? NestedFieldValue<NonNullable<T[First]>, Rest> : NonNullable<T> extends (infer U)[] ? NestedFieldValue<U, F> : any : F extends keyof T ? NonNullable<T[F]> : NonNullable<T> extends (infer U)[] ? F extends keyof U ? NonNullable<U[F]> : any : any;
141
182
  type FieldPaths<T> = T extends Record<string, any> ? {
142
183
  [K in keyof T & string]: T[K] extends any[] ? K : T[K] extends Record<string, any> ? `${K}.${FieldPaths<T[K]>}` : K;
143
184
  }[keyof T & string] : never;
144
185
  type NestedObjectPaths<O extends StateType> = {
145
- [K in keyof O & string]: O[K] extends any[] ? never : O[K] extends Record<string, any> ? `${K}.${FieldPaths<O[K]>}` : never;
186
+ [K in keyof O & string]: NonNullable<O[K]> extends any[] ? never : NonNullable<O[K]> extends Date ? never : NonNullable<O[K]> extends Record<string, any> ? `${K}.${FieldPaths<NonNullable<O[K]>>}` : never;
146
187
  }[keyof O & string];
147
- /** Keys whose values are not arrays and not plain objects (i.e. scalar/primitive fields). */
188
+ /** Keys whose values are not arrays and not plain objects (i.e. scalar/primitive fields). Date is treated as a scalar. */
148
189
  type ScalarKeys<O extends StateType> = {
149
- [K in keyof O]: O[K] extends any[] ? never : O[K] extends Record<string, any> ? never : K;
190
+ [K in keyof O]: NonNullable<O[K]> extends any[] ? never : NonNullable<O[K]> extends Date ? K : NonNullable<O[K]> extends Record<string, any> ? never : K;
150
191
  }[keyof O];
151
192
  type AllPaths<O extends StateType> = ScalarKeys<O> | NestedObjectPaths<O>;
152
193
  /**
@@ -156,17 +197,19 @@ interface HelpersFunc<O extends StateType> {
156
197
  /** Adds a new item to an array. */
157
198
  addItem: <K extends ArrayPaths<O>>(arrayKey: K, item: NestedFieldValue<O, K> extends (infer E)[] ? E : never, index?: number) => void;
158
199
  /** Removes an item from an array by its index. */
159
- removeItem: <K extends ArrayPaths<O>>(arrayKey: K, index: number) => void;
200
+ removeItemByIndexByIndex: <K extends ArrayPaths<O>>(arrayKey: K, index: number) => void;
160
201
  /** Removes an item from an array by its unique identifier. */
161
202
  removeById: <K extends ArrayPaths<O>>(arrayKey: K, itemId: string | number) => void;
162
- /** Replaces an item in an array at the given index. */
163
- updateItem: <K extends ArrayPaths<O>>(arrayKey: K, index: number, value: NestedFieldValue<O, K> extends (infer E)[] ? E : never) => void;
203
+ /** Updates an item in an array at the given index (supports partial updates). */
204
+ updateByIndex: <K extends ArrayPaths<O>>(arrayKey: K, index: number, value: NestedFieldValue<O, K> extends (infer E)[] ? Partial<E> : never) => void;
205
+ /** Updates an item in an array by its unique identifier (supports partial updates). */
206
+ updateById: <K extends ArrayPaths<O>>(arrayKey: K, itemId: string | number, value: NestedFieldValue<O, K> extends (infer E)[] ? Partial<E> : never) => void;
164
207
  /** Moves an item within an array using indices. */
165
- moveItem: <K extends ArrayPaths<O>>(arrayKey: K, from: number, to: number) => void;
208
+ moveItemByIndex: <K extends ArrayPaths<O>>(arrayKey: K, from: number, to: number) => void;
166
209
  /** Moves an item within an array using unique identifiers. */
167
210
  moveById: <K extends ArrayPaths<O>>(arrayKey: K, fromId: string | number, toId: string | number) => void;
168
211
  /** Gets an item from an array by its unique identifier (O(1) via indexMap). */
169
- getItem: <K extends ArrayPaths<O>>(arrayKey: K, itemId: string | number) => (NestedFieldValue<O, K> extends (infer E)[] ? E : never) | undefined;
212
+ getItemById: <K extends ArrayPaths<O>>(arrayKey: K, itemId: string | number) => (NestedFieldValue<O, K> extends (infer E)[] ? E : never) | undefined;
170
213
  }
171
214
  /**
172
215
  * The response object from the useForm hook.
@@ -176,13 +219,26 @@ interface UseFormResponse<O extends StateType> {
176
219
  onFieldBlur: BlurFunc<O>;
177
220
  /** Updates a scalar or nested object field. */
178
221
  onFieldChange<P extends AllPaths<O>>(id: P, value: NestedFieldValue<O, P & string>): void;
179
- /** Updates an object array element's field using composite syntax "array.field". */
180
- onFieldChange<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number, value: any): void;
181
- /** Updates an object array element's field by ID (explicit array key, field, and value). */
182
- onFieldChange<K extends ObjectArrayKeys<O>, F extends keyof ArrayElement<O[K]> & string>(arrayKey: K, itemId: ItemIdType<O, K>, field: F, value: ArrayElement<O[K]>[F]): void;
183
- /** Updates a primitive array element by index. */
184
- onFieldChange<K extends ArrayPaths<O>>(arrayKey: K, index: number, value: any): void;
222
+ /** Manually updates a field within an object array item. */
223
+ onArrayItemChange<P extends ObjectArrayFieldPaths<O>>(options: {
224
+ /** Composite dot-notation path: e.g. "users.name" */
225
+ at: P;
226
+ /** The unique identifier of the target array item — type is inferred from the array element's id field. */
227
+ id: ArrayItemIdTypeFromPath<O, P & string>;
228
+ /** The new value — type is inferred from the field referenced by `at`. */
229
+ value: CompositeFieldValue<O, P & string>;
230
+ }): void;
231
+ /** Manually updates a scalar or nested object selection field. */
185
232
  onSelectionChange: ValueChangeFunc<O, keyof O>;
233
+ /** Manually updates a selection-based field within an object array item. */
234
+ onArraySelectionChange<P extends ObjectArrayFieldPaths<O>>(options: {
235
+ /** Composite dot-notation path: e.g. "users.role" */
236
+ at: P;
237
+ /** The unique identifier of the target array item — type is inferred from the array element's id field. */
238
+ id: ArrayItemIdTypeFromPath<O, P & string>;
239
+ /** The new selection value — type is inferred from the field referenced by `at`. */
240
+ value: CompositeFieldValue<O, P & string>;
241
+ }): void;
186
242
  state: O;
187
243
  setState: React.Dispatch<React.SetStateAction<O>>;
188
244
  metadata: MetadataType;
package/dist/index.js CHANGED
@@ -592,10 +592,17 @@ function useForm(schema, {
592
592
  const { compositeKey, fieldPath, realPath, value } = resolution;
593
593
  const meta = metadataRef.current.get(compositeKey);
594
594
  const isTouched = meta?.isTouched;
595
+ let isRequired = false;
596
+ try {
597
+ const rule = getRule(fieldPath, validationSchema);
598
+ if (rule) isRequired = rule.describe().optional === false;
599
+ } catch {
600
+ }
595
601
  return {
596
602
  id: compositeKey,
597
603
  isInvalid: Boolean(isTouched && meta?.isInvalid),
598
604
  errorMessage: isTouched ? meta?.errorMessage || "" : "",
605
+ isRequired,
599
606
  onBlur: () => {
600
607
  if (metadataRef.current.get(compositeKey)?.isTouched) return;
601
608
  validateField(
@@ -618,7 +625,7 @@ function useForm(schema, {
618
625
  }
619
626
  };
620
627
  },
621
- [validateField]
628
+ [validateField, getRule, validationSchema]
622
629
  );
623
630
  const on = (0, import_react2.useMemo)(
624
631
  () => ({
@@ -670,6 +677,62 @@ function useForm(schema, {
670
677
  handleFieldChange(data, fixed);
671
678
  }
672
679
  };
680
+ },
681
+ numberInput: (...args) => {
682
+ const data = resolveFieldData(
683
+ args,
684
+ stateRef.current,
685
+ getIndex,
686
+ getNestedValue
687
+ );
688
+ if (!data) return {};
689
+ return {
690
+ ...createHandlers(data),
691
+ value: data.value ?? 0,
692
+ onValueChange: (v) => handleFieldChange(data, v)
693
+ };
694
+ },
695
+ checkbox: (...args) => {
696
+ const data = resolveFieldData(
697
+ args,
698
+ stateRef.current,
699
+ getIndex,
700
+ getNestedValue
701
+ );
702
+ if (!data) return {};
703
+ return {
704
+ ...createHandlers(data),
705
+ isSelected: Boolean(data.value),
706
+ onValueChange: (v) => handleFieldChange(data, v)
707
+ };
708
+ },
709
+ switch: (...args) => {
710
+ const data = resolveFieldData(
711
+ args,
712
+ stateRef.current,
713
+ getIndex,
714
+ getNestedValue
715
+ );
716
+ if (!data) return {};
717
+ return {
718
+ ...createHandlers(data),
719
+ isSelected: Boolean(data.value),
720
+ onValueChange: (v) => handleFieldChange(data, v)
721
+ };
722
+ },
723
+ radio: (...args) => {
724
+ const data = resolveFieldData(
725
+ args,
726
+ stateRef.current,
727
+ getIndex,
728
+ getNestedValue
729
+ );
730
+ if (!data) return {};
731
+ return {
732
+ ...createHandlers(data),
733
+ value: data.value ?? "",
734
+ onValueChange: (v) => handleFieldChange(data, v)
735
+ };
673
736
  }
674
737
  }),
675
738
  [createHandlers, getIndex, handleFieldChange]
@@ -689,7 +752,7 @@ function useForm(schema, {
689
752
  });
690
753
  });
691
754
  },
692
- removeItem: (arrayKey, index) => {
755
+ removeItemByIndexByIndex: (arrayKey, index) => {
693
756
  const currentArr = getNestedValue(stateRef.current, arrayKey) || [];
694
757
  const item = currentArr[index];
695
758
  const idKey = arrayIdentifiers?.[arrayKey] || "id";
@@ -726,10 +789,10 @@ function useForm(schema, {
726
789
  setMetadata((prev) => removeCompositeKeysByPrefix(prev, prefix));
727
790
  }
728
791
  },
729
- updateItem: (arrayKey, index, value) => {
792
+ updateByIndex: (arrayKey, index, value) => {
730
793
  setState((prev) => {
731
794
  const arr = [...getNestedValue(prev, arrayKey) || []];
732
- arr[index] = value;
795
+ arr[index] = typeof arr[index] === "object" && typeof value === "object" ? { ...arr[index], ...value } : value;
733
796
  return handleNestedChange({
734
797
  state: prev,
735
798
  id: arrayKey,
@@ -738,7 +801,22 @@ function useForm(schema, {
738
801
  });
739
802
  });
740
803
  },
741
- moveItem: (arrayKey, from, to) => {
804
+ updateById: (arrayKey, itemId, value) => {
805
+ const index = getIndex(arrayKey, itemId);
806
+ if (index !== void 0) {
807
+ setState((prev) => {
808
+ const arr = [...getNestedValue(prev, arrayKey) || []];
809
+ arr[index] = typeof arr[index] === "object" && typeof value === "object" ? { ...arr[index], ...value } : value;
810
+ return handleNestedChange({
811
+ state: prev,
812
+ id: arrayKey,
813
+ value: arr,
814
+ hasNestedValues: String(arrayKey).includes(".")
815
+ });
816
+ });
817
+ }
818
+ },
819
+ moveItemByIndex: (arrayKey, from, to) => {
742
820
  setState((prev) => {
743
821
  const arr = [...getNestedValue(prev, arrayKey) || []];
744
822
  const [item] = arr.splice(from, 1);
@@ -768,7 +846,7 @@ function useForm(schema, {
768
846
  });
769
847
  }
770
848
  },
771
- getItem: (arrayKey, itemId) => {
849
+ getItemById: (arrayKey, itemId) => {
772
850
  const index = getIndex(arrayKey, itemId);
773
851
  if (index === void 0) return void 0;
774
852
  return getNestedValue(stateRef.current, arrayKey)[index];
@@ -798,12 +876,26 @@ function useForm(schema, {
798
876
  },
799
877
  [validateField]
800
878
  );
801
- const polymorphicOnValueChange = (0, import_react2.useCallback)(
802
- (...args) => {
803
- const value = args[args.length - 1];
804
- const idArgs = args.slice(0, args.length - 1);
879
+ const scalarOnFieldChange = (0, import_react2.useCallback)(
880
+ (id, value) => {
881
+ const data = resolveFieldData(
882
+ [id],
883
+ stateRef.current,
884
+ getIndex,
885
+ getNestedValue
886
+ );
887
+ if (data) handleFieldChange(data, value);
888
+ },
889
+ [getIndex, handleFieldChange]
890
+ );
891
+ const arrayItemChange = (0, import_react2.useCallback)(
892
+ ({
893
+ at: compositePath,
894
+ id: itemId,
895
+ value
896
+ }) => {
805
897
  const data = resolveFieldData(
806
- idArgs,
898
+ [compositePath, itemId],
807
899
  stateRef.current,
808
900
  getIndex,
809
901
  getNestedValue
@@ -812,7 +904,7 @@ function useForm(schema, {
812
904
  },
813
905
  [getIndex, handleFieldChange]
814
906
  );
815
- const polymorphicOnSelectionChange = (0, import_react2.useCallback)(
907
+ const scalarOnSelectionChange = (0, import_react2.useCallback)(
816
908
  (id, val) => {
817
909
  const fixed = typeof val === "string" || val === null ? val : Array.from(val);
818
910
  let nextState = handleNestedChange({
@@ -826,6 +918,23 @@ function useForm(schema, {
826
918
  },
827
919
  [validateField]
828
920
  );
921
+ const arraySelectionChange = (0, import_react2.useCallback)(
922
+ ({
923
+ at: compositePath,
924
+ id: itemId,
925
+ value: val
926
+ }) => {
927
+ const fixed = typeof val === "string" || val === null ? val : Array.from(val);
928
+ const data = resolveFieldData(
929
+ [compositePath, itemId],
930
+ stateRef.current,
931
+ getIndex,
932
+ getNestedValue
933
+ );
934
+ if (data) handleFieldChange(data, fixed);
935
+ },
936
+ [getIndex, handleFieldChange]
937
+ );
829
938
  const onFormSubmit = (0, import_react2.useCallback)(
830
939
  (fn) => (e) => {
831
940
  e.preventDefault();
@@ -892,9 +1001,11 @@ function useForm(schema, {
892
1001
  metadata,
893
1002
  on,
894
1003
  helpers,
895
- onFieldChange: polymorphicOnValueChange,
1004
+ onFieldChange: scalarOnFieldChange,
1005
+ onArrayItemChange: arrayItemChange,
896
1006
  onFieldBlur: onBlur,
897
- onSelectionChange: polymorphicOnSelectionChange,
1007
+ onSelectionChange: scalarOnSelectionChange,
1008
+ onArraySelectionChange: arraySelectionChange,
898
1009
  isDirty: Array.from(metadata.values()).some((m) => m.isTouched),
899
1010
  onFormReset: handleReset,
900
1011
  onFormSubmit,
@@ -907,8 +1018,10 @@ function useForm(schema, {
907
1018
  on,
908
1019
  helpers,
909
1020
  onBlur,
910
- polymorphicOnValueChange,
911
- polymorphicOnSelectionChange,
1021
+ scalarOnFieldChange,
1022
+ arrayItemChange,
1023
+ scalarOnSelectionChange,
1024
+ arraySelectionChange,
912
1025
  validateAll,
913
1026
  onFormSubmit,
914
1027
  ControlledForm,