@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/README.md +304 -244
- package/dist/index.d.mts +75 -19
- package/dist/index.d.ts +75 -19
- package/dist/index.js +129 -16
- package/dist/index.mjs +129 -16
- package/package.json +1 -1
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]
|
|
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
|
-
|
|
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
|
-
/**
|
|
163
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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]
|
|
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
|
-
|
|
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
|
-
/**
|
|
163
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
802
|
-
(
|
|
803
|
-
const
|
|
804
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
1004
|
+
onFieldChange: scalarOnFieldChange,
|
|
1005
|
+
onArrayItemChange: arrayItemChange,
|
|
896
1006
|
onFieldBlur: onBlur,
|
|
897
|
-
onSelectionChange:
|
|
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
|
-
|
|
911
|
-
|
|
1021
|
+
scalarOnFieldChange,
|
|
1022
|
+
arrayItemChange,
|
|
1023
|
+
scalarOnSelectionChange,
|
|
1024
|
+
arraySelectionChange,
|
|
912
1025
|
validateAll,
|
|
913
1026
|
onFormSubmit,
|
|
914
1027
|
ControlledForm,
|