@juantroconisf/lib 6.1.0 → 8.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 CHANGED
@@ -1,65 +1,112 @@
1
1
  # @juantroconisf/lib
2
2
 
3
- A powerful, type-safe form management and validation library optimized for **HeroUI** (formerly NextUI).
3
+ A powerful, type-safe form management and validation library optimized for **HeroUI** (formerly NextUI) and **React**.
4
4
 
5
- ## Key Features
5
+ Designed for complex applications, it provides **O(1) value updates**, stable **ID-based array management**, and deep nesting support, all while fully integrating with **Yup** for schema validation.
6
+
7
+ ---
8
+
9
+ ## Table of Contents
10
+
11
+ - [Features](#features)
12
+ - [Installation](#installation)
13
+ - [Quick Start](#quick-start)
14
+ - [Usage Guide](#usage-guide)
15
+ - [Scalar Fields](#scalar-fields)
16
+ - [Nested Objects](#nested-objects)
17
+ - [Managing Arrays](#managing-arrays)
18
+ - [Validation](#validation)
19
+ - [Submitting Forms](#submitting-forms)
20
+ - [API Reference](#api-reference)
21
+ - [useForm](#useform)
22
+ - [The `on` Object](#the-on-object)
23
+ - [Array Helpers](#array-helpers)
24
+ - [Metadata & Reset](#metadata--reset)
25
+
26
+ ---
27
+
28
+ ## Features
6
29
 
7
30
  - 🎯 **Polymorphic `on` API**: Single consistent interface for `input`, `select`, and `autocomplete`.
8
31
  - 🧩 **Deep Nesting**: Effortlessly manage complex objects with dot-notation support (e.g., `address.city`).
9
- - 🔢 **ID-Based Arrays**: Stable state management for dynamic lists. Items are tracked by unique identifiers, preventing state loss during reordering or deletions.
32
+ - 🔢 **ID-Based Arrays**: Stable state management for dynamic lists. Items are tracked by unique identifiers (default: `id`), preventing state loss during reordering or deletions.
10
33
  - ⚡ **O(1) Performance**: Internal mapping for array items ensures lightning-fast updates regardless of list size.
11
34
  - 🛡️ **Total Type Safety**: Best-in-class Intellisense for paths, types, and array identifiers.
12
- - 🎨 **HeroUI Optimized**: Returns props ready to be spread directly onto HeroUI components (`isInvalid`, `errorMessage`, `onBlur`, etc.).
35
+ - 🎨 **HeroUI Optimized**: Returns props ready to be spread directly onto HeroUI components (`isInvalid`, `errorMessage`, `onFieldBlur`, etc.).
36
+ - ✅ **Yup Integration**: Built-in support for Yup schemas for validation.
13
37
 
14
38
  ---
15
39
 
16
40
  ## Installation
17
41
 
18
42
  ```bash
19
- pnpm add @juantroconisf/lib
43
+ pnpm add @juantroconisf/lib yup
20
44
  ```
21
45
 
22
46
  ---
23
47
 
24
48
  ## Quick Start
25
49
 
50
+ Here is a complete example demonstrating scalar fields, object arrays, and validation.
51
+
26
52
  ```tsx
27
53
  import { useForm } from "@juantroconisf/lib";
54
+ import { string, number, array, object } from "yup";
55
+ import { Input, Button } from "@heroui/react";
28
56
 
29
57
  const MyForm = () => {
30
- const { on, state, helpers } = useForm({
31
- name: "Juan",
32
- lines: [
33
- { id: 1, amount: 10 }
34
- ]
35
- }, {
36
- rules: {
37
- name: { required: true }
38
- },
39
- arrayRules: {
40
- lines: {
41
- amount: (item, index) => ({ min: 1 })
42
- }
43
- }
58
+ const { on, state, helpers, onSubmit } = useForm({
59
+ name: string().required("Name is required").default(""),
60
+ items: array()
61
+ .of(
62
+ object().shape({
63
+ id: number().required(),
64
+ label: string().required("Label is required"),
65
+ }),
66
+ )
67
+ .default([{ id: 1, label: "Initial Item" }]),
44
68
  });
45
69
 
70
+ const handleSubmit = (data) => {
71
+ console.log("Submitted:", data);
72
+ };
73
+
46
74
  return (
47
- <form>
48
- {/* Scalar/Nested Registration */}
49
- <Input {...on.input("name")} label="Name" />
50
-
51
- {/* Array Registration (By ID) */}
52
- {state.lines.map((line) => (
53
- <Input
54
- key={line.id}
55
- {...on.input("lines", line.id, "amount")}
56
- label="Amount"
57
- />
75
+ <form onSubmit={onSubmit(handleSubmit)} className='flex flex-col gap-4'>
76
+ {/* 1. Scalar Registration */}
77
+ <Input {...on.input("name")} label='Name' />
78
+
79
+ {/* 2. Array Registration */}
80
+ {state.items.map((item) => (
81
+ <div key={item.id} className='flex gap-2 items-center'>
82
+
83
+ {/*
84
+ Bind by Path + ID
85
+ This ensures that even if the array order changes,
86
+ the input remains bound to the correct item.
87
+ */}
88
+ <Input
89
+ {...on.input("items.label", item.id)}
90
+ label='Item Label'
91
+ />
92
+
93
+ <Button
94
+ color="danger"
95
+ onClick={() => helpers.removeById("items", item.id)}
96
+ >
97
+ Remove
98
+ </Button>
99
+ </div>
58
100
  ))}
59
-
60
- <Button onClick={() => helpers.removeById("lines", 1)}>
61
- Remove First
62
- </Button>
101
+
102
+ <div className="flex gap-2">
103
+ <Button
104
+ onClick={() => helpers.addItem("items", { id: Date.now(), label: "" })}
105
+ >
106
+ Add Item
107
+ </Button>
108
+ <Button type='submit' color="primary">Submit</Button>
109
+ </div>
63
110
  </form>
64
111
  );
65
112
  };
@@ -67,31 +114,166 @@ const MyForm = () => {
67
114
 
68
115
  ---
69
116
 
117
+ ## Usage Guide
118
+
119
+ ### Scalar Fields
120
+
121
+ Scalar fields are the bread and butter of any form. Use `on.input`, `on.select`, or `on.autocomplete` to bind them.
122
+
123
+ ```tsx
124
+ <Input {...on.input("fullName")} label="Full Name" />
125
+ <Input {...on.input("email")} type="email" label="Email" />
126
+ ```
127
+
128
+ ### Nested Objects
129
+
130
+ No special configuration needed. Just use standard dot notation.
131
+
132
+ ```tsx
133
+ const { on } = useForm({
134
+ settings: object({
135
+ theme: object({
136
+ mode: string().default("dark"),
137
+ }),
138
+ }),
139
+ });
140
+
141
+ <Input {...on.input("settings.theme.mode")} />
142
+ ```
143
+
144
+ ### Managing Arrays
145
+
146
+ The library shines with arrays. It tracks items by ID, so you can reorder or delete items without losing focus or state.
147
+
148
+ **1. Binding Inputs:**
149
+
150
+ Always bind using the composite syntax: `path.field` + `itemId`.
151
+
152
+ ```tsx
153
+ // ✅ Correct: Binds to the item with ID 123
154
+ on.input("users.name", 123)
155
+
156
+ // ❌ Avoid (unless primitive array): Binds to index 0
157
+ on.input("users", 0)
158
+ ```
159
+
160
+ **2. Manipulating the Array:**
161
+
162
+ Use the `helpers` object.
163
+
164
+ ```tsx
165
+ // Add
166
+ helpers.addItem("users", { id: "new-id", name: "" });
167
+
168
+ // Remove by ID (Safe)
169
+ helpers.removeById("users", "user-id-123");
170
+
171
+ // Move (Reorder)
172
+ helpers.moveById("users", "from-id", "to-id");
173
+ ```
174
+
175
+ ### Validation
176
+
177
+ Validation is "Schema-First" via Yup.
178
+
179
+ 1. **Define Rules**: Pass a Yup schema to `useForm`.
180
+ 2. **Auto-Validation**:
181
+ - Fields validate on `blur`.
182
+ - If a field is `touched` and `invalid`, it re-validates on every keystroke (`onChange`).
183
+ 3. **Submit Validation**: Use `onSubmit` wrapper to validate all fields before executing your handler.
184
+
185
+ ### Submitting Forms
186
+
187
+ The `onSubmit` wrapper handles `preventDefault`, runs full validation, and only executes your callback if valid.
188
+
189
+ ```tsx
190
+ const { onSubmit } = useForm(...);
191
+
192
+ const handleSubmit = (data) => {
193
+ // 1. Validation has already passed!
194
+ // 2. Proceed with submission
195
+ api.post("/users", data);
196
+ };
197
+
198
+ return <form onSubmit={onSubmit(handleSubmit)}>...</form>;
199
+ ```
200
+
201
+ ---
202
+
70
203
  ## API Reference
71
204
 
72
- ### `useForm(initialState, options)`
205
+ ### `useForm`
206
+
207
+ ```ts
208
+ const {
209
+ state,
210
+ on,
211
+ helpers,
212
+ metadata,
213
+ reset,
214
+ onSubmit,
215
+ reset,
216
+ onSubmit,
217
+ isDirty,
218
+ onFieldChange,
219
+ onFieldBlur
220
+ } = useForm(schema, options?);
221
+ ```
222
+
223
+ #### Arguments
224
+
225
+ | Argument | Type | Description |
226
+ | :--- | :--- | :--- |
227
+ | **`schema`** | `Yup.Schema` | A Yup schema object defining structure, default values, and validation rules. |
228
+ | **`options`** | `FormOptions` | Configuration object. |
73
229
 
74
230
  #### Options
75
- - **`rules`**: Validation rules for root/nested fields.
76
- - **`messages`**: Custom error messages for root/nested fields.
77
- - **`arrayRules`**: Validation rules for array items. Receives `(item, index)`.
78
- - **`arrayMessages`**: Custom error messages for array items.
79
- - **`arrayIdentifiers`**: Mapping of array keys to their unique ID property (defaults to `"id"`).
231
+
232
+ - **`arrayIdentifiers`**: Mapping of array paths to their unique ID property (default: `"id"`).
80
233
 
81
234
  ### The `on` Object
82
- Provides methods to register components with the form state. Support both scalar/nested paths and array tracking.
83
-
84
- - **`on.input(path)`** / **`on.input(arrayKey, itemId, field)`**
85
- - **`on.select(path)`** / **`on.select(arrayKey, itemId, field)`**
86
- - **`on.autocomplete(path)`** / **`on.autocomplete(arrayKey, itemId, field)`**
87
-
88
- ### Helpers
89
- Utilities for common state manipulations:
90
- - **`addItem(arrayKey, item, index?)`**
91
- - **`removeItem(arrayKey, index)`**
92
- - **`removeById(arrayKey, itemId)`**
93
- - **`moveItem(arrayKey, from, to)`**
94
- - **`moveById(arrayKey, fromId, toId)`**
235
+
236
+ The `on` object generates props for your components: `value`, `onValueChange`, `isInvalid`, `errorMessage`, `onBlur`.
237
+
238
+ | Method | Signature | Description |
239
+ | :--- | :--- | :--- |
240
+ | **`on.input`** | `(path, [id])` | Generic input handler. Returns standard input props. |
241
+ | **`on.select`** | `(path, [id])` | Returns props compatible with `Select` (handles `selectedKeys`). |
242
+ | **`on.autocomplete`** | `(path, [id])` | Returns props compatible with `Autocomplete` (handles `selectedKey`). |
243
+
244
+ ### Array Helpers
245
+
246
+ Utilities for manipulating array state.
247
+
248
+ | Method | Description |
249
+ | :--- | :--- |
250
+ | **`addItem(key, item, index?)`** | Adds an item to the array. |
251
+ | **`removeItem(key, index)`** | Removes an item at a specific index. |
252
+ | **`removeById(key, id)`** | **Recommended**. Removes an item by its unique ID. |
253
+ | **`updateItem(key, index, val)`** | Replaces an item at a specific index. |
254
+ | **`moveItem(key, from, to)`** | Moves an item from one index to another. |
255
+ | **`moveById(key, fromId, toId)`** | Moves an item by ID. |
256
+ | **`getItem(key, id)`** | Retrieval helper. |
257
+
258
+ ### Metadata & Reset
259
+
260
+ | Property | Type | Description |
261
+ | :--- | :--- | :--- |
262
+ | **`metadata`** | `Map<string, FieldMetadata>` | Contains validation state (`isInvalid`, `errorMessage`) and `isTouched`. |
263
+ | **`reset`** | `(options?) => void` | Resets form state and metadata to initial values. |
264
+
265
+ **Reset Options:**
266
+
267
+ ```ts
268
+ // Reset everything
269
+ reset();
270
+
271
+ // Keep specific fields
272
+ reset({ keys: ["organizationId"] });
273
+
274
+ // Only clear touched status (keep values)
275
+ reset({ onlyTouched: true });
276
+ ```
95
277
 
96
278
  ---
97
279
 
package/dist/index.d.mts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { SelectProps, AutocompleteProps } from '@heroui/react';
2
2
  import { SingleSelection } from '@react-types/shared';
3
+ import { Schema, InferType } from 'yup';
3
4
 
4
5
  type StateType = Record<string, any>;
5
6
  interface NestedChangeProps<O extends StateType> {
@@ -13,82 +14,63 @@ declare class NextUIError {
13
14
  errorMessage: string;
14
15
  constructor(bool?: boolean, msg?: string);
15
16
  }
16
- type ValidatorFunction<T, U> = (val: T, ...args: U[]) => boolean;
17
- interface Validator<T, U = any> {
18
- validate: ValidatorFunction<T, U>;
19
- msg: string;
20
- }
21
- interface ValidatorTypes {
22
- required: Validator<string | number, boolean>;
23
- min: Validator<number | string, number | string>;
24
- max: Validator<number | string, number | string>;
25
- minLength: Validator<string, number>;
26
- maxLength: Validator<string, number>;
27
- pattern: Validator<string, RegExp>;
28
- equal: Validator<string, string>;
29
- numberIsEqual: Validator<number, number>;
30
- email: Validator<string, boolean>;
31
- password: Validator<string, boolean>;
32
- custom: Validator<any, boolean>;
33
- }
34
- type ValidatorParams = {
35
- [K in keyof ValidatorTypes]?: ValidatorTypes[K] extends Validator<any, infer U> ? U : never;
36
- };
37
- type ValidatorErrorMessage = {
38
- [K in keyof ValidatorTypes]?: string;
39
- };
40
17
 
41
18
  /**
42
- * Validation rules for individual fields in an array item.
43
- * @template O The state type.
44
- * @template K The key of the array in the state.
19
+ * Valid types for the initial state configuration.
20
+ * Can be a raw value or a Yup schema.
45
21
  */
46
- type ValidatorRule<item = any> = ValidatorParams | ((item: item, ...args: any[]) => ValidatorParams);
47
- type RulePath<T> = T extends object ? {
48
- [K in keyof T & string]: NonNullable<T[K]> extends (infer E)[] ? K | (E extends object ? `${K}.${RulePath<E>}` : never) : NonNullable<T[K]> extends object ? NonNullable<T[K]> extends Date ? K : K | `${K}.${RulePath<NonNullable<T[K]>>}` : K;
49
- }[keyof T & string] : never;
22
+ type ConfigType = any | Schema<any>;
23
+ /**
24
+ * Helper to infer the state type from the configuration object.
25
+ * If a value is a Yup schema, infer its return type.
26
+ * Otherwise, use the value's type directly.
27
+ */
28
+ type InferState<S extends Record<string, ConfigType>> = {
29
+ [K in keyof S]: S[K] extends Schema<any, any, any, any> ? InferType<S[K]> : S[K];
30
+ };
50
31
  /**
51
32
  * Options for the useForm hook.
52
33
  * @template O The state type.
53
34
  */
54
35
  interface FormOptions<O extends StateType> {
55
- /** Validation rules for top-level fields. */
56
- rules?: Partial<Record<RulePath<O>, ValidatorRule>>;
57
- /** Custom error messages for top-level fields. */
58
- messages?: Partial<Record<RulePath<O>, ValidatorErrorMessage>>;
59
36
  /**
60
37
  * Custom property names used as unique identifiers for items in specific arrays.
61
38
  * Default is "id".
62
39
  */
63
- arrayIdentifiers?: Partial<Record<ArrayKeys<O>, string>>;
40
+ arrayIdentifiers?: Partial<Record<ArrayPaths<O>, string>>;
41
+ }
42
+ type FieldMetadata = {
43
+ isTouched: boolean;
44
+ isInvalid: boolean;
45
+ errorMessage: string;
46
+ };
47
+ type MetadataType = Map<string, FieldMetadata>;
48
+ type SubmitHandler<O extends StateType> = (data: O, e: React.FormEvent) => void;
49
+ interface ResetOptions<O> {
50
+ preservedStateKeys?: (keyof O)[];
51
+ preserveTouched?: boolean;
64
52
  }
65
- type TouchedType = Map<string, boolean>;
66
- type ErrorsType = Map<string, NextUIError>;
67
53
  type ValueChangeFunc<O extends StateType, K extends keyof O> = (id: K, value: O[K]) => void;
68
54
  type BlurFunc<O extends StateType> = (id: keyof O) => void;
69
- interface ComponentInputProps<O extends StateType> {
55
+ interface ComponentInputProps {
70
56
  id: string;
71
57
  onBlur: () => void;
72
58
  isInvalid: boolean;
73
59
  errorMessage: string;
74
60
  }
75
- type UXProps<O extends StateType> = Record<keyof O, {
76
- isInvalid: boolean;
77
- errorMessage: string;
78
- }>;
79
61
  /** Props returned by on.input() */
80
- interface ItemInputProps<V = any> extends ComponentInputProps<any> {
62
+ interface ItemInputProps<V = any> extends ComponentInputProps {
81
63
  onValueChange: (value: V) => void;
82
64
  value: V;
83
65
  }
84
66
  /** Props returned by on.select() */
85
- interface ItemSelectProps extends ComponentInputProps<any> {
86
- onSelectionChange: SelectProps["onSelectionChange"];
67
+ interface ItemSelectProps extends ComponentInputProps {
68
+ onSelectionChange: NonNullable<SelectProps["onSelectionChange"]>;
87
69
  selectedKeys: string[] | number[] | string | null;
88
70
  }
89
71
  /** Props returned by on.autocomplete() */
90
- interface ItemAutocompleteProps extends ComponentInputProps<any> {
91
- onSelectionChange: AutocompleteProps["onSelectionChange"];
72
+ interface ItemAutocompleteProps extends ComponentInputProps {
73
+ onSelectionChange: NonNullable<AutocompleteProps["onSelectionChange"]>;
92
74
  selectedKey: SingleSelection["selectedKey"];
93
75
  }
94
76
  /**
@@ -98,23 +80,50 @@ interface OnMethods<O extends StateType> {
98
80
  /** Registers a scalar or nested object field. */
99
81
  input<P extends AllPaths<O>>(id: P): ItemInputProps<NestedFieldValue<O, P & string>>;
100
82
  /** Registers an array element — adapts to primitive arrays (by index) or object arrays (by ID + field). */
101
- input<K extends ArrayKeys<O>>(arrayKey: K, ...args: O[K] extends Record<string, any>[] ? [itemId: ItemIdType<O, K>, field: FieldPaths<ArrayElement<O[K]>>] | [itemId: ItemIdType<O, K>, field: string, index: number] : [index: number]): ItemInputProps<any>;
83
+ /** Registers an array element adapts to primitive arrays (by index). */
84
+ input<K extends ArrayKeys<O>>(arrayKey: K, index: number): ItemInputProps<any>;
85
+ /** Registers an object array element's field using composite syntax "array.field". */
86
+ input<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: ItemIdType<O, GetArrayKeyFromPath<O, P>>): ItemInputProps<any>;
102
87
  /** Registers a scalar or nested object field. */
103
88
  select<P extends AllPaths<O>>(id: P): ItemSelectProps;
89
+ /** Registers a complete array field for multi-selection. */
90
+ select<K extends ArrayKeys<O>>(arrayKey: K): ItemSelectProps;
104
91
  /** Registers an array element — adapts to primitive arrays (by index) or object arrays (by ID + field). */
105
- select<K extends ArrayKeys<O>>(arrayKey: K, ...args: O[K] extends Record<string, any>[] ? [itemId: ItemIdType<O, K>, field: FieldPaths<ArrayElement<O[K]>>] | [itemId: ItemIdType<O, K>, field: string, index: number] : [index: number]): ItemSelectProps;
92
+ select<K extends ArrayKeys<O>>(arrayKey: K, index: number): ItemSelectProps;
93
+ /** Registers an object array element's field using composite syntax "array.field". */
94
+ select<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: ItemIdType<O, GetArrayKeyFromPath<O, P>>): ItemSelectProps;
106
95
  /** Registers a scalar or nested object field. */
107
96
  autocomplete<P extends AllPaths<O>>(id: P): ItemAutocompleteProps;
108
97
  /** Registers an array element — adapts to primitive arrays (by index) or object arrays (by ID + field). */
109
- autocomplete<K extends ArrayKeys<O>>(arrayKey: K, ...args: O[K] extends Record<string, any>[] ? [itemId: ItemIdType<O, K>, field: FieldPaths<ArrayElement<O[K]>>] | [itemId: ItemIdType<O, K>, field: string, index: number] : [index: number]): ItemAutocompleteProps;
98
+ /** Registers an array element adapts to primitive arrays (by index). */
99
+ autocomplete<K extends ArrayKeys<O>>(arrayKey: K, index: number): ItemAutocompleteProps;
100
+ /** Registers an object array element's field using composite syntax "array.field". */
101
+ autocomplete<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: ItemIdType<O, GetArrayKeyFromPath<O, P>>): ItemAutocompleteProps;
110
102
  }
111
103
  type ArrayKeys<O extends StateType> = {
112
104
  [K in keyof O]: O[K] extends any[] ? K : never;
113
105
  }[keyof O];
106
+ /**
107
+ * Recursive type to find all paths to arrays in the state.
108
+ */
109
+ type ArrayPaths<T> = T extends object ? {
110
+ [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;
111
+ }[keyof T & string] : never;
114
112
  /** Keys whose values are arrays of objects (not primitives). */
115
113
  type ObjectArrayKeys<O extends StateType> = {
116
114
  [K in keyof O]: O[K] extends Record<string, any>[] ? K : never;
117
115
  }[keyof O];
116
+ /**
117
+ * Helper to get paths for fields within object arrays.
118
+ * Returns paths like "arrayKey.fieldName".
119
+ */
120
+ type ObjectArrayFieldPaths<O extends StateType> = {
121
+ [K in keyof O]: O[K] extends Record<string, any>[] ? `${K & string}.${FieldPaths<ArrayElement<O[K]>>}` : never;
122
+ }[keyof O];
123
+ /**
124
+ * Helper to extract the array key from a path string like "arrayKey.field".
125
+ */
126
+ type GetArrayKeyFromPath<O extends StateType, P extends string> = P extends `${infer K}.${string}` ? K extends keyof O ? O[K] extends any[] ? K : never : never : never;
118
127
  type ArrayElement<T> = T extends (infer E)[] ? E : never;
119
128
  /** Resolves the type of the identifier field for an array element (defaults to "id"). */
120
129
  type ItemIdType<O extends StateType, K extends keyof O> = "id" extends keyof ArrayElement<O[K]> ? ArrayElement<O[K]>["id"] : string | number;
@@ -154,29 +163,33 @@ interface HelpersFunc<O extends StateType> {
154
163
  * @template O The state type.
155
164
  */
156
165
  interface UseFormResponse<O extends StateType> {
157
- onBlur: BlurFunc<O>;
166
+ onFieldBlur: BlurFunc<O>;
158
167
  /** Updates an object array element's field by ID. */
159
- onValueChange<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;
168
+ 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;
160
169
  /** Updates a scalar or nested object field. */
161
- onValueChange<P extends AllPaths<O>>(id: P, value: NestedFieldValue<O, P & string>): void;
170
+ onFieldChange<P extends AllPaths<O>>(id: P, value: NestedFieldValue<O, P & string>): void;
162
171
  onSelectionChange: ValueChangeFunc<O, keyof O>;
163
172
  state: O;
164
173
  setState: React.Dispatch<React.SetStateAction<O>>;
165
- touched: TouchedType;
166
- errors: ErrorsType;
174
+ metadata: MetadataType;
167
175
  /** Main object to bind form elements to the state. */
168
176
  on: OnMethods<O>;
169
177
  /** Array manipulation helpers. */
170
178
  helpers: HelpersFunc<O>;
171
179
  isDirty: boolean;
172
- /** Manually triggers all validations and marks all fields as touched. Returns true if any error is found. */
173
- hasInvalidValues: () => boolean;
174
- /** Resets the form state and metadata. */
175
- resetForm: (preservedKeys?: (keyof O)[]) => void;
176
- /** Resets the touched metadata. */
177
- resetTouched: (preservedKeys?: (keyof O)[]) => void;
180
+ /**
181
+ * Resets the form state and metadata.
182
+ * @param options Configuration for the reset (preserve keys, preserve touched).
183
+ */
184
+ reset: (options?: ResetOptions<O>) => void;
185
+ /**
186
+ * Wraps a form submission handler to automatically validate the form.
187
+ * If validation fails, identifying errors and touching fields.
188
+ * If validation succeeds, calls the provided handler with the current state.
189
+ */
190
+ onSubmit: (fn: SubmitHandler<O>) => (e: React.FormEvent) => void;
178
191
  }
179
192
 
180
- declare function useForm<O extends StateType>(initialState: O, { rules, messages, arrayIdentifiers }?: FormOptions<O>): UseFormResponse<O>;
193
+ declare function useForm<S extends Record<string, ConfigType>>(schema: S, { arrayIdentifiers }?: FormOptions<InferState<S>>): UseFormResponse<InferState<S>>;
181
194
 
182
- export { type BlurFunc, type ErrorsType, type FormOptions, type HelpersFunc, type NestedChangeProps, NextUIError, type OnMethods, type StateType, type TouchedType, type UXProps, type UseFormResponse, type Validator, type ValidatorErrorMessage, type ValidatorParams, type ValidatorRule, type ValidatorTypes, type ValueChangeFunc, useForm };
195
+ export { type BlurFunc, type ConfigType, type FieldMetadata, type FormOptions, type HelpersFunc, type InferState, type MetadataType, type NestedChangeProps, NextUIError, type OnMethods, type StateType, type SubmitHandler, type UseFormResponse, type ValueChangeFunc, useForm };