@juantroconisf/lib 9.0.1 → 9.2.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 +236 -156
- package/dist/index.d.mts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -7
- package/dist/index.mjs +6 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @juantroconisf/lib
|
|
2
2
|
|
|
3
|
-
A powerful, type-safe form management and validation library
|
|
3
|
+
A powerful, type-safe form management and validation library tailored for **HeroUI** and **React**.
|
|
4
4
|
|
|
5
|
-
Designed for complex applications, it provides **O(1) value updates**, stable **ID-based array management**, and deep nesting support, all
|
|
5
|
+
Designed for complex applications, it provides **O(1) value updates**, stable **ID-based array management**, and deep nesting support, all seamlessly integrated with **Yup** schemas.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -10,30 +10,31 @@ Designed for complex applications, it provides **O(1) value updates**, stable **
|
|
|
10
10
|
|
|
11
11
|
- [Features](#features)
|
|
12
12
|
- [Installation](#installation)
|
|
13
|
+
- [Localization](#localization)
|
|
13
14
|
- [Quick Start](#quick-start)
|
|
14
15
|
- [Usage Guide](#usage-guide)
|
|
15
16
|
- [Scalar Fields](#scalar-fields)
|
|
16
17
|
- [Nested Objects](#nested-objects)
|
|
17
18
|
- [Managing Arrays](#managing-arrays)
|
|
18
|
-
- [
|
|
19
|
-
- [Submitting Forms](#submitting-forms)
|
|
19
|
+
- [Form Submission](#form-submission)
|
|
20
20
|
- [API Reference](#api-reference)
|
|
21
21
|
- [useForm](#useform)
|
|
22
|
-
- [The `on`
|
|
22
|
+
- [The `on` API](#the-on-api)
|
|
23
|
+
- [ControlledForm](#controlledform)
|
|
23
24
|
- [Array Helpers](#array-helpers)
|
|
24
|
-
- [
|
|
25
|
+
- [Form Controls](#form-controls)
|
|
25
26
|
|
|
26
27
|
---
|
|
27
28
|
|
|
28
29
|
## Features
|
|
29
30
|
|
|
30
|
-
- 🎯 **Polymorphic `on` API**:
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
31
|
+
- 🎯 **Polymorphic `on` API**: A unified interface (`on.input`, `on.select`, `on.autocomplete`) saving lines of boilerplate.
|
|
32
|
+
- 🧱 **ControlledForm Component**: Zero-boilerplate validated submissions leveraging the `@heroui/react` Form component directly.
|
|
33
|
+
- 🧩 **Deep Nesting**: Dot-notation support (e.g., `settings.theme`) out of the box.
|
|
34
|
+
- 🔢 **ID-Based Arrays**: List items are tracked by unique identifiers (default: `id`), ensuring states survive mapping, reordering, and deletions.
|
|
35
|
+
- ⚡ **O(1) Performance**: Internal mapping for array updates offers incredible speed regardless of data density.
|
|
36
|
+
- 🛡️ **Complete Type Safety**: TypeScript infers all acceptable paths, data structures, and outputs natively.
|
|
37
|
+
- 🌍 **Built-in Localization**: Ships with English and Spanish validation translations via runtime cookies.
|
|
37
38
|
|
|
38
39
|
---
|
|
39
40
|
|
|
@@ -45,69 +46,107 @@ pnpm add @juantroconisf/lib yup
|
|
|
45
46
|
|
|
46
47
|
---
|
|
47
48
|
|
|
49
|
+
## Localization
|
|
50
|
+
|
|
51
|
+
Validation strings (e.g., minimum length, required fields) are localized automatically. The library checks for a browser cookie named `LOCALE` on initialization.
|
|
52
|
+
|
|
53
|
+
- **Supported Locales**: `en` (English - default) and `es` (Spanish).
|
|
54
|
+
- **How to Set**:
|
|
55
|
+
Set the cookie in your client application:
|
|
56
|
+
```ts
|
|
57
|
+
document.cookie = "LOCALE=es; path=/; max-age=31536000"; // Sets language to Spanish
|
|
58
|
+
```
|
|
59
|
+
If no cookie is detected, or the value is unrecognized, the library gracefully falls back to English (`en`).
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
48
63
|
## Quick Start
|
|
49
64
|
|
|
50
|
-
|
|
65
|
+
Throughout this documentation, we will refer to a common, diverse schema. It includes simple scalars, deep objects, and complex arrays.
|
|
51
66
|
|
|
52
67
|
```tsx
|
|
53
68
|
import { useForm } from "@juantroconisf/lib";
|
|
54
|
-
import { string, number, array, object } from "yup";
|
|
55
|
-
import { Input, Button } from "@heroui/react";
|
|
69
|
+
import { string, number, array, object, boolean } from "yup";
|
|
70
|
+
import { Input, Switch, Select, SelectItem, Button } from "@heroui/react";
|
|
56
71
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
.
|
|
68
|
-
|
|
72
|
+
// 1. Define your diverse schema structure
|
|
73
|
+
const mySchema = {
|
|
74
|
+
fullName: string().required("Name is required").default(""),
|
|
75
|
+
age: number().min(18).default(18),
|
|
76
|
+
settings: object({
|
|
77
|
+
theme: string().oneOf(["light", "dark"]).default("dark"),
|
|
78
|
+
notifications: boolean().default(true),
|
|
79
|
+
}),
|
|
80
|
+
users: array()
|
|
81
|
+
.of(
|
|
82
|
+
object().shape({
|
|
83
|
+
id: number().required(),
|
|
84
|
+
role: string().required(),
|
|
85
|
+
}),
|
|
86
|
+
)
|
|
87
|
+
.default([{ id: Date.now(), role: "admin" }]),
|
|
88
|
+
};
|
|
69
89
|
|
|
70
|
-
|
|
71
|
-
|
|
90
|
+
const MyForm = () => {
|
|
91
|
+
// 2. Initialize the hook with fully inferred types
|
|
92
|
+
const { on, state, helpers, ControlledForm } = useForm(mySchema);
|
|
93
|
+
|
|
94
|
+
// 3. Types are perfectly inferred from your Yup schema
|
|
95
|
+
const handleSubmit = (data, event) => {
|
|
96
|
+
console.log("Submitted payload:", data);
|
|
97
|
+
// data.fullName -> string
|
|
98
|
+
// data.settings.theme -> "light" | "dark"
|
|
99
|
+
// data.users[0].role -> string
|
|
72
100
|
};
|
|
73
101
|
|
|
74
102
|
return (
|
|
75
|
-
<
|
|
76
|
-
{/*
|
|
77
|
-
<Input {...on.input("
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
{
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
<
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
+
<ControlledForm onSubmit={handleSubmit} className='flex flex-col gap-4'>
|
|
104
|
+
{/* Scalar Fields */}
|
|
105
|
+
<Input {...on.input("fullName")} label='Full Name' />
|
|
106
|
+
<Input {...on.input("age")} type='number' label='Age' />
|
|
107
|
+
|
|
108
|
+
{/* Nested Object Fields */}
|
|
109
|
+
<Switch {...on.input("settings.notifications")}>
|
|
110
|
+
Enable Notifications
|
|
111
|
+
</Switch>
|
|
112
|
+
<Select {...on.select("settings.theme")} label='Theme'>
|
|
113
|
+
<SelectItem key='light'>Light</SelectItem>
|
|
114
|
+
<SelectItem key='dark'>Dark</SelectItem>
|
|
115
|
+
</Select>
|
|
116
|
+
|
|
117
|
+
{/* Array Fields */}
|
|
118
|
+
<div className='flex flex-col gap-2'>
|
|
119
|
+
<h3>Users</h3>
|
|
120
|
+
{state.users.map((user) => (
|
|
121
|
+
<div key={user.id} className='flex gap-2 items-center'>
|
|
122
|
+
{/* Bind by Array Path + Item ID */}
|
|
123
|
+
<Select {...on.select("users.role", user.id)} label='Role'>
|
|
124
|
+
<SelectItem key='admin'>Admin</SelectItem>
|
|
125
|
+
<SelectItem key='guest'>Guest</SelectItem>
|
|
126
|
+
</Select>
|
|
127
|
+
<Button
|
|
128
|
+
color='danger'
|
|
129
|
+
onPress={() => helpers.removeById("users", user.id)}
|
|
130
|
+
>
|
|
131
|
+
Remove
|
|
132
|
+
</Button>
|
|
133
|
+
</div>
|
|
134
|
+
))}
|
|
135
|
+
</div>
|
|
136
|
+
|
|
137
|
+
<div className='flex gap-2'>
|
|
103
138
|
<Button
|
|
104
|
-
|
|
139
|
+
onPress={() =>
|
|
140
|
+
helpers.addItem("users", { id: Date.now(), role: "guest" })
|
|
141
|
+
}
|
|
105
142
|
>
|
|
106
|
-
Add
|
|
143
|
+
Add User
|
|
144
|
+
</Button>
|
|
145
|
+
<Button type='submit' color='primary'>
|
|
146
|
+
Submit
|
|
107
147
|
</Button>
|
|
108
|
-
<Button type='submit' color="primary">Submit</Button>
|
|
109
148
|
</div>
|
|
110
|
-
</
|
|
149
|
+
</ControlledForm>
|
|
111
150
|
);
|
|
112
151
|
};
|
|
113
152
|
```
|
|
@@ -116,86 +155,122 @@ const MyForm = () => {
|
|
|
116
155
|
|
|
117
156
|
## Usage Guide
|
|
118
157
|
|
|
158
|
+
All examples below continue referencing the `mySchema` definition from the Quick Start.
|
|
159
|
+
|
|
119
160
|
### Scalar Fields
|
|
120
161
|
|
|
121
|
-
Scalar fields
|
|
162
|
+
Scalar fields map directly to your schema definitions. Use `on.input`, `on.select`, or `on.autocomplete` to yield binding props instantly compatible with HeroUI.
|
|
122
163
|
|
|
123
164
|
```tsx
|
|
124
165
|
<Input {...on.input("fullName")} label="Full Name" />
|
|
125
|
-
<Input {...on.input("
|
|
166
|
+
<Input {...on.input("age")} type="number" label="Age" />
|
|
126
167
|
```
|
|
127
168
|
|
|
128
169
|
### Nested Objects
|
|
129
170
|
|
|
130
|
-
|
|
171
|
+
Nested state is managed intuitively via dot-notation directly on your identifiers. Your TypeScript types will validate that the path points to real endpoints on your data shape.
|
|
131
172
|
|
|
132
173
|
```tsx
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
<Input {...on.input("settings.theme.mode")} />
|
|
174
|
+
// Binds seamlessly to state.settings.theme
|
|
175
|
+
<Select {...on.select("settings.theme")} label="Theme">
|
|
176
|
+
<SelectItem key="light">Light</SelectItem>
|
|
177
|
+
<SelectItem key="dark">Dark</SelectItem>
|
|
178
|
+
</Select>
|
|
179
|
+
|
|
180
|
+
// Booleans map smoothly to Switches/Checkboxes
|
|
181
|
+
<Switch {...on.input("settings.notifications")}>Enable Alerts</Switch>
|
|
142
182
|
```
|
|
143
183
|
|
|
144
184
|
### Managing Arrays
|
|
145
185
|
|
|
146
|
-
|
|
186
|
+
Array management is uniquely built around tracking entries by ID (`'id'` field by default). This stops issues where UI inputs lose state references if the array gets shifted.
|
|
147
187
|
|
|
148
|
-
**
|
|
188
|
+
**Binding UI to Items:**
|
|
189
|
+
Combine the general array path and the item ID.
|
|
149
190
|
|
|
150
|
-
|
|
191
|
+
```tsx
|
|
192
|
+
// ✅ Correct: Binds perfectly regardless of list index changes
|
|
193
|
+
on.select("users.role", userId);
|
|
194
|
+
|
|
195
|
+
// ❌ Warning (Unless primitives array): Prevents index-shifting stability
|
|
196
|
+
on.select("users", 0);
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Using the `helpers` Library:**
|
|
200
|
+
Extract `helpers` out of `useForm(...)` to manipulate array state securely.
|
|
151
201
|
|
|
152
202
|
```tsx
|
|
153
|
-
|
|
154
|
-
|
|
203
|
+
const { helpers } = useForm(mySchema);
|
|
204
|
+
|
|
205
|
+
// Add an item (Optionally provide index as a 3rd argument to insert)
|
|
206
|
+
helpers.addItem("users", { id: Date.now(), role: "guest" });
|
|
207
|
+
|
|
208
|
+
// Remove item by ID
|
|
209
|
+
helpers.removeById("users", 12345);
|
|
155
210
|
|
|
156
|
-
//
|
|
157
|
-
|
|
211
|
+
// Reorder items by ID
|
|
212
|
+
helpers.moveById("users", fromId, toId);
|
|
158
213
|
```
|
|
159
214
|
|
|
160
|
-
|
|
215
|
+
### Form Submission
|
|
161
216
|
|
|
162
|
-
|
|
217
|
+
There are two primary ways to submit, validate, and handle your logic, both fully type-safe.
|
|
163
218
|
|
|
164
|
-
|
|
165
|
-
// Add
|
|
166
|
-
helpers.addItem("users", { id: "new-id", name: "" });
|
|
219
|
+
**1. The `ControlledForm` Wrapper (Recommended)**
|
|
167
220
|
|
|
168
|
-
|
|
169
|
-
helpers.removeById("users", "user-id-123");
|
|
221
|
+
`ControlledForm` behaves exactly like a HeroUI `Form` component. It automatically intercepts submit events, validates all bindings through your schema, and invokes `onSubmit` with the validated dataset.
|
|
170
222
|
|
|
171
|
-
|
|
172
|
-
|
|
223
|
+
```tsx
|
|
224
|
+
const { ControlledForm } = useForm(mySchema);
|
|
225
|
+
|
|
226
|
+
return (
|
|
227
|
+
<ControlledForm onSubmit={(data, event) => console.log(data.fullName)}>
|
|
228
|
+
<Input {...on.input("fullName")} />
|
|
229
|
+
<Button type='submit'>Submit</Button>
|
|
230
|
+
</ControlledForm>
|
|
231
|
+
);
|
|
173
232
|
```
|
|
174
233
|
|
|
175
|
-
|
|
234
|
+
**2. The `onFormSubmit` Handler Wrapper**
|
|
176
235
|
|
|
177
|
-
|
|
236
|
+
If you prefer using native HTML `<form>` tags, you can pass your callback into `onFormSubmit`. The params exposed to your callback are tightly inferred from the schema.
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
const { onFormSubmit, state } = useForm(mySchema);
|
|
178
240
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
241
|
+
// Automatically infers your final structured data (data) and the React form event (e)
|
|
242
|
+
const submitHandler = onFormSubmit((data, e) => {
|
|
243
|
+
// Validation passed successfully!
|
|
244
|
+
// 'data.settings.theme' is correctly typed as string.
|
|
245
|
+
api.post("/endpoint", data);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// Used manually on form tags or button invocations
|
|
249
|
+
<form onSubmit={submitHandler}>{/* inputs */}</form>;
|
|
250
|
+
```
|
|
184
251
|
|
|
185
|
-
|
|
252
|
+
**3. External Handler Definitions**
|
|
186
253
|
|
|
187
|
-
|
|
254
|
+
If you define your schemas inline inside `useForm( { ... } )` but want to extract your `submit` handler natively without destructing variables you aren't using:
|
|
188
255
|
|
|
189
256
|
```tsx
|
|
190
|
-
const
|
|
257
|
+
export const MyForm = () => {
|
|
258
|
+
// 1. Schema is defined organically inline inside the component execution
|
|
259
|
+
const { ControlledForm } = useForm({
|
|
260
|
+
fullName: string().required(),
|
|
261
|
+
});
|
|
191
262
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
263
|
+
// 2. Type your extract handler capturing React.ComponentProps directly on the wrapper
|
|
264
|
+
const handleSubmit: React.ComponentProps<
|
|
265
|
+
typeof ControlledForm
|
|
266
|
+
>["onSubmit"] = (data, event) => {
|
|
267
|
+
// Both data.fullName and React Events are perfectly inferred natively!
|
|
268
|
+
console.log(data.fullName);
|
|
269
|
+
};
|
|
197
270
|
|
|
198
|
-
|
|
271
|
+
// 3. Destructure whatever you need right on your JSX render
|
|
272
|
+
return <ControlledForm onSubmit={handleSubmit}>...</ControlledForm>;
|
|
273
|
+
};
|
|
199
274
|
```
|
|
200
275
|
|
|
201
276
|
---
|
|
@@ -204,76 +279,81 @@ return <form onSubmit={onSubmit(handleSubmit)}>...</form>;
|
|
|
204
279
|
|
|
205
280
|
### `useForm`
|
|
206
281
|
|
|
282
|
+
Instantiates state and schema configurations.
|
|
283
|
+
|
|
207
284
|
```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?);
|
|
285
|
+
const formApi = useForm(schema, options?);
|
|
221
286
|
```
|
|
222
287
|
|
|
223
288
|
#### Arguments
|
|
224
289
|
|
|
225
|
-
|
|
|
226
|
-
|
|
|
227
|
-
| **`schema`**
|
|
228
|
-
| **`options`** | `FormOptions`
|
|
290
|
+
| Parameter | Type | Description |
|
|
291
|
+
| :------------ | :--------------------------- | :------------------------------------------------------------------------------- |
|
|
292
|
+
| **`schema`** | `Record<string, ConfigType>` | Your form shape configuration containing `Yup` schemas or primitive constraints. |
|
|
293
|
+
| **`options`** | `FormOptions` | Configuration behaviors. |
|
|
229
294
|
|
|
230
295
|
#### Options
|
|
231
296
|
|
|
232
|
-
|
|
297
|
+
| Option | Type | Description |
|
|
298
|
+
| :--------------------- | :--------- | :------------------------------------------------------------------------------ |
|
|
299
|
+
| **`arrayIdentifiers`** | `Object` | Identifier maps for objects missing `id` (e.g. `{ users: "uuid" }`). |
|
|
300
|
+
| **`resetOnSubmit`** | `boolean` | Instantly resets all values tracking arrays to initialization configurations. |
|
|
301
|
+
| **`onFormSubmit`** | `Function` | Fallback default submission pipeline. |
|
|
302
|
+
| **`keepValues`** | `string[]` | Keys in the root state to preserve during a reset (e.g. `["settings", "age"]`). |
|
|
233
303
|
|
|
234
|
-
|
|
304
|
+
---
|
|
235
305
|
|
|
236
|
-
The `on`
|
|
306
|
+
### The `on` API
|
|
237
307
|
|
|
238
|
-
|
|
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`). |
|
|
308
|
+
`on` hooks dynamically assign value tracks, validity checks, error text extractions, and update invocations back to the controller.
|
|
243
309
|
|
|
244
|
-
|
|
310
|
+
| Method | Description |
|
|
311
|
+
| :-------------------------------- | :--------------------------------------------------------------------------- |
|
|
312
|
+
| **`on.input(path, [itemId])`** | Exports `{ id, isInvalid, errorMessage, value, onValueChange, onBlur }`. |
|
|
313
|
+
| **`on.select(path, [itemId])`** | Exports properties mapped for `<Select>` components matching `selectedKeys`. |
|
|
314
|
+
| **`on.autocomplete(path, [id])`** | Exports properties mapped for `<Autocomplete>` matching `selectedKey`. |
|
|
245
315
|
|
|
246
|
-
|
|
316
|
+
---
|
|
247
317
|
|
|
248
|
-
|
|
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. |
|
|
318
|
+
### ControlledForm
|
|
257
319
|
|
|
258
|
-
|
|
320
|
+
A Drop-in `<Form />` equivalent handling submit event delegation natively linked to validation triggers internally.
|
|
259
321
|
|
|
260
|
-
|
|
|
261
|
-
|
|
|
262
|
-
| **`
|
|
263
|
-
| **`reset`** | `(options?) => void` | Resets form state and metadata to initial values. |
|
|
322
|
+
| Prop | Type | Description |
|
|
323
|
+
| :------------- | :------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
324
|
+
| **`onSubmit`** | `(data, e) => void` | Invoked strictly post-validation of `schema` variables passing criteria. Both arguments `data` (your state payload) and `e` (the React event) are correctly typed. |
|
|
264
325
|
|
|
265
|
-
|
|
326
|
+
_Notes: Spreads any traditional `<form>` properties to standard HeroUI mappings out of the box._
|
|
266
327
|
|
|
267
|
-
|
|
268
|
-
// Reset everything
|
|
269
|
-
reset();
|
|
328
|
+
---
|
|
270
329
|
|
|
271
|
-
|
|
272
|
-
reset({ keys: ["organizationId"] });
|
|
330
|
+
### Array Helpers
|
|
273
331
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
332
|
+
Array adjustments exported off the `helpers` map:
|
|
333
|
+
|
|
334
|
+
| Utility | Description |
|
|
335
|
+
| :--------------------------------- | :---------------------------------------------------------------------------- |
|
|
336
|
+
| **`addItem(path, item, index?)`** | Submits entries safely. |
|
|
337
|
+
| **`removeItem(path, index)`** | Excludes entry mapped at index map offset. |
|
|
338
|
+
| **`removeById(path, id)`** | Standard and secure ID withdrawal. |
|
|
339
|
+
| **`updateItem(path, index, val)`** | Hot swap content without re-render destruction. |
|
|
340
|
+
| **`moveItem(path, current, to)`** | Re-order index slots. |
|
|
341
|
+
| **`moveById(path, fromId, toId)`** | Shift lists seamlessly referencing fixed ID targets. |
|
|
342
|
+
| **`getItem(path, id)`** | Read items immediately via O(1) indexed lookups without array mapping cycles. |
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
### Form Controls
|
|
347
|
+
|
|
348
|
+
Additional utilities available directly out of `useForm`:
|
|
349
|
+
|
|
350
|
+
| Method | Signatures / Types | Info |
|
|
351
|
+
| :---------------- | :---------------------------------- | :------------------------------------------------------------------ |
|
|
352
|
+
| **`state`** | `InferState<S>` | Evaluated state values matching object signatures defined. |
|
|
353
|
+
| **`setState`** | `Dispatch<SetStateAction>` | The fundamental state mutation. |
|
|
354
|
+
| **`onFormReset`** | `(opts?: { keepValues: string[] })` | Discards invalidity layers and remounts variables back to defaults. |
|
|
355
|
+
| **`isDirty`** | `boolean` | Truthy flag reflecting if state parameters altered. |
|
|
356
|
+
| **`metadata`** | `Map<string, FieldMetadata>` | Touched and Error metadata instances tracked. |
|
|
277
357
|
|
|
278
358
|
---
|
|
279
359
|
|
package/dist/index.d.mts
CHANGED
|
@@ -61,6 +61,11 @@ type FieldMetadata = {
|
|
|
61
61
|
};
|
|
62
62
|
type MetadataType = Map<string, FieldMetadata>;
|
|
63
63
|
type FormSubmitHandler<O extends StateType> = (data: O, e: React.FormEvent) => void;
|
|
64
|
+
/**
|
|
65
|
+
* A utility type for inferring the submit handler's signature directly from a Yup schema object.
|
|
66
|
+
* This saves developers from manually mapping `InferType` back to `FormSubmitHandler` when extracting sumbits.
|
|
67
|
+
*/
|
|
68
|
+
type InferSubmitHandler<S extends Record<string, ConfigType>> = (data: InferState<S>, e: React.FormEvent) => void;
|
|
64
69
|
interface FormResetOptions<O> {
|
|
65
70
|
keepValues?: (keyof O)[];
|
|
66
71
|
}
|
|
@@ -205,4 +210,4 @@ interface UseFormResponse<O extends StateType> {
|
|
|
205
210
|
|
|
206
211
|
declare function useForm<S extends Record<string, ConfigType>>(schema: S, { arrayIdentifiers, onFormSubmit: onFormSubmitProp, resetOnSubmit, keepValues: keepValuesProp, }?: FormOptions<InferState<S>>): UseFormResponse<InferState<S>>;
|
|
207
212
|
|
|
208
|
-
export { type BlurFunc, type ConfigType, type FieldMetadata, type FormOptions, type FormSubmitHandler, type HelpersFunc, type InferState, type MetadataType, type NestedChangeProps, NextUIError, type OnMethods, type StateType, type UseFormResponse, type ValueChangeFunc, useForm };
|
|
213
|
+
export { type BlurFunc, type ConfigType, type FieldMetadata, type FormOptions, type FormSubmitHandler, type HelpersFunc, type InferState, type InferSubmitHandler, type MetadataType, type NestedChangeProps, NextUIError, type OnMethods, type StateType, type UseFormResponse, type ValueChangeFunc, useForm };
|
package/dist/index.d.ts
CHANGED
|
@@ -61,6 +61,11 @@ type FieldMetadata = {
|
|
|
61
61
|
};
|
|
62
62
|
type MetadataType = Map<string, FieldMetadata>;
|
|
63
63
|
type FormSubmitHandler<O extends StateType> = (data: O, e: React.FormEvent) => void;
|
|
64
|
+
/**
|
|
65
|
+
* A utility type for inferring the submit handler's signature directly from a Yup schema object.
|
|
66
|
+
* This saves developers from manually mapping `InferType` back to `FormSubmitHandler` when extracting sumbits.
|
|
67
|
+
*/
|
|
68
|
+
type InferSubmitHandler<S extends Record<string, ConfigType>> = (data: InferState<S>, e: React.FormEvent) => void;
|
|
64
69
|
interface FormResetOptions<O> {
|
|
65
70
|
keepValues?: (keyof O)[];
|
|
66
71
|
}
|
|
@@ -205,4 +210,4 @@ interface UseFormResponse<O extends StateType> {
|
|
|
205
210
|
|
|
206
211
|
declare function useForm<S extends Record<string, ConfigType>>(schema: S, { arrayIdentifiers, onFormSubmit: onFormSubmitProp, resetOnSubmit, keepValues: keepValuesProp, }?: FormOptions<InferState<S>>): UseFormResponse<InferState<S>>;
|
|
207
212
|
|
|
208
|
-
export { type BlurFunc, type ConfigType, type FieldMetadata, type FormOptions, type FormSubmitHandler, type HelpersFunc, type InferState, type MetadataType, type NestedChangeProps, NextUIError, type OnMethods, type StateType, type UseFormResponse, type ValueChangeFunc, useForm };
|
|
213
|
+
export { type BlurFunc, type ConfigType, type FieldMetadata, type FormOptions, type FormSubmitHandler, type HelpersFunc, type InferState, type InferSubmitHandler, type MetadataType, type NestedChangeProps, NextUIError, type OnMethods, type StateType, type UseFormResponse, type ValueChangeFunc, useForm };
|
package/dist/index.js
CHANGED
|
@@ -127,8 +127,7 @@ var translations = {
|
|
|
127
127
|
uuid: "Enter a valid UUID",
|
|
128
128
|
trim: "Remove leading/trailing spaces",
|
|
129
129
|
lowercase: "Must be in lowercase",
|
|
130
|
-
uppercase: "Must be in uppercase"
|
|
131
|
-
password: "Your password doesn't meet the security criteria."
|
|
130
|
+
uppercase: "Must be in uppercase"
|
|
132
131
|
},
|
|
133
132
|
number: {
|
|
134
133
|
min: "Value must be ${min} or greater",
|
|
@@ -174,8 +173,7 @@ var translations = {
|
|
|
174
173
|
uuid: "Ingresa un UUID v\xE1lido",
|
|
175
174
|
trim: "No debe contener espacios al inicio o final",
|
|
176
175
|
lowercase: "Debe estar en min\xFAsculas",
|
|
177
|
-
uppercase: "Debe estar en may\xFAsculas"
|
|
178
|
-
password: "Tu contrase\xF1a no cumple con los requisitos de seguridad."
|
|
176
|
+
uppercase: "Debe estar en may\xFAsculas"
|
|
179
177
|
},
|
|
180
178
|
number: {
|
|
181
179
|
min: "Debe ser mayor o igual a ${min}",
|
|
@@ -207,15 +205,16 @@ var translations = {
|
|
|
207
205
|
// src/hooks/useComponentLang.tsx
|
|
208
206
|
var cookieName = "LOCALE";
|
|
209
207
|
var getClientCookie = () => {
|
|
208
|
+
if (typeof document === "undefined") return "en";
|
|
210
209
|
const value = "; " + document.cookie, decodedValue = decodeURIComponent(value), parts = decodedValue.split("; " + cookieName + "=");
|
|
211
210
|
if (parts.length === 2) return parts.pop()?.split(";").shift();
|
|
212
211
|
};
|
|
212
|
+
var initialLocale = getClientCookie() || "en";
|
|
213
|
+
(0, import_yup.setLocale)(translations[initialLocale] || translations.en);
|
|
213
214
|
function useComponentLanguage() {
|
|
214
215
|
(0, import_react.useEffect)(() => {
|
|
215
216
|
const locale = getClientCookie() || "en";
|
|
216
|
-
|
|
217
|
-
(0, import_yup.setLocale)(translations[locale]);
|
|
218
|
-
}
|
|
217
|
+
(0, import_yup.setLocale)(translations[locale] || translations.en);
|
|
219
218
|
}, []);
|
|
220
219
|
}
|
|
221
220
|
|
package/dist/index.mjs
CHANGED
|
@@ -101,8 +101,7 @@ var translations = {
|
|
|
101
101
|
uuid: "Enter a valid UUID",
|
|
102
102
|
trim: "Remove leading/trailing spaces",
|
|
103
103
|
lowercase: "Must be in lowercase",
|
|
104
|
-
uppercase: "Must be in uppercase"
|
|
105
|
-
password: "Your password doesn't meet the security criteria."
|
|
104
|
+
uppercase: "Must be in uppercase"
|
|
106
105
|
},
|
|
107
106
|
number: {
|
|
108
107
|
min: "Value must be ${min} or greater",
|
|
@@ -148,8 +147,7 @@ var translations = {
|
|
|
148
147
|
uuid: "Ingresa un UUID v\xE1lido",
|
|
149
148
|
trim: "No debe contener espacios al inicio o final",
|
|
150
149
|
lowercase: "Debe estar en min\xFAsculas",
|
|
151
|
-
uppercase: "Debe estar en may\xFAsculas"
|
|
152
|
-
password: "Tu contrase\xF1a no cumple con los requisitos de seguridad."
|
|
150
|
+
uppercase: "Debe estar en may\xFAsculas"
|
|
153
151
|
},
|
|
154
152
|
number: {
|
|
155
153
|
min: "Debe ser mayor o igual a ${min}",
|
|
@@ -181,15 +179,16 @@ var translations = {
|
|
|
181
179
|
// src/hooks/useComponentLang.tsx
|
|
182
180
|
var cookieName = "LOCALE";
|
|
183
181
|
var getClientCookie = () => {
|
|
182
|
+
if (typeof document === "undefined") return "en";
|
|
184
183
|
const value = "; " + document.cookie, decodedValue = decodeURIComponent(value), parts = decodedValue.split("; " + cookieName + "=");
|
|
185
184
|
if (parts.length === 2) return parts.pop()?.split(";").shift();
|
|
186
185
|
};
|
|
186
|
+
var initialLocale = getClientCookie() || "en";
|
|
187
|
+
setLocale(translations[initialLocale] || translations.en);
|
|
187
188
|
function useComponentLanguage() {
|
|
188
189
|
useEffect(() => {
|
|
189
190
|
const locale = getClientCookie() || "en";
|
|
190
|
-
|
|
191
|
-
setLocale(translations[locale]);
|
|
192
|
-
}
|
|
191
|
+
setLocale(translations[locale] || translations.en);
|
|
193
192
|
}, []);
|
|
194
193
|
}
|
|
195
194
|
|