@juantroconisf/lib 11.3.0 → 11.4.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 +18 -8
- package/dist/index.d.mts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +52 -0
- package/dist/index.mjs +52 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -131,6 +131,16 @@ Arrays of objects are tracked by item `id` (configurable via `arrayIdentifiers`)
|
|
|
131
131
|
</Button>;
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
+
### Deeply Nested Arrays (N-Level Depth)
|
|
135
|
+
|
|
136
|
+
If your schema contains arrays inside objects inside arrays (infinite depth), you can pass a variadic sequence of arguments alternating between structural paths and array IDs (or indexes).
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
// Schema: items[].form_response.input_values[].value
|
|
140
|
+
<Input {...on.input("items", itemId, "form_response.input_values", inputId, "value")} label="Deep Value" />
|
|
141
|
+
```
|
|
142
|
+
The library dynamically traverses your state, mapping IDs securely to their array indices natively, regardless of depth.
|
|
143
|
+
|
|
134
144
|
---
|
|
135
145
|
|
|
136
146
|
## The `on` API — Component Bindings
|
|
@@ -142,17 +152,17 @@ Each `on.*` method returns a set of props that you spread directly onto a HeroUI
|
|
|
142
152
|
- **Error display** — `isInvalid` and `errorMessage` from the schema
|
|
143
153
|
- **Required indicator** — `isRequired` derived from `.required()` in your schema
|
|
144
154
|
|
|
145
|
-
All methods support
|
|
155
|
+
All methods support **scalar/nested** paths, standard **array item** paths (composite `"array.field"` + `itemId`), and **variadic sequences** for N-level deep structures.
|
|
146
156
|
|
|
147
157
|
| Method | HeroUI Component | Key props returned |
|
|
148
158
|
| --------------------------------- | ------------------- | ----------------------------------------------- |
|
|
149
|
-
| `on.input(
|
|
150
|
-
| `on.numberInput(
|
|
151
|
-
| `on.select(
|
|
152
|
-
| `on.autocomplete(
|
|
153
|
-
| `on.checkbox(
|
|
154
|
-
| `on.switch(
|
|
155
|
-
| `on.radio(
|
|
159
|
+
| `on.input(...args)` | `Input`, `Textarea` | `value: string`, `onValueChange(string)` |
|
|
160
|
+
| `on.numberInput(...args)` | `NumberInput` | `value: number`, `onValueChange(number)` |
|
|
161
|
+
| `on.select(...args)` | `Select` | `selectedKeys`, `onSelectionChange` |
|
|
162
|
+
| `on.autocomplete(...args)` | `Autocomplete` | `selectedKey`, `onSelectionChange` |
|
|
163
|
+
| `on.checkbox(...args)` | `Checkbox` | `isSelected: boolean`, `onValueChange(boolean)` |
|
|
164
|
+
| `on.switch(...args)` | `Switch` | `isSelected: boolean`, `onValueChange(boolean)` |
|
|
165
|
+
| `on.radio(...args)` | `RadioGroup` | `value: string`, `onValueChange(string)` |
|
|
156
166
|
|
|
157
167
|
> **Why separate methods?** Each HeroUI component has a different prop contract (e.g. `isSelected` vs `value`, `onSelectionChange` vs `onValueChange`). Separate methods give accurate intellisense for each component.
|
|
158
168
|
|
package/dist/index.d.mts
CHANGED
|
@@ -133,10 +133,14 @@ interface OnMethods<O extends StateType> {
|
|
|
133
133
|
input<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemInputProps<any>;
|
|
134
134
|
/** Registers a primitive array element by index. */
|
|
135
135
|
input<K extends ArrayPaths<O>>(arrayKey: K, index: number): ItemInputProps<any>;
|
|
136
|
+
/** Registers a deeply nested field using variadic path segments. */
|
|
137
|
+
input(...args: any[]): ItemInputProps<any>;
|
|
136
138
|
/** Registers a numeric field for NumberInput. */
|
|
137
139
|
numberInput<P extends AllPaths<O>>(id: P): ItemNumberInputProps;
|
|
138
140
|
/** Registers a numeric field within an object array element. */
|
|
139
141
|
numberInput<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemNumberInputProps;
|
|
142
|
+
/** Registers a deeply nested numeric field using variadic path segments. */
|
|
143
|
+
numberInput(...args: any[]): ItemNumberInputProps;
|
|
140
144
|
/** Registers a scalar or nested object field. */
|
|
141
145
|
select<P extends AllPaths<O>>(id: P): ItemSelectProps;
|
|
142
146
|
/** Registers a complete array field for multi-selection. */
|
|
@@ -145,24 +149,34 @@ interface OnMethods<O extends StateType> {
|
|
|
145
149
|
select<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemSelectProps;
|
|
146
150
|
/** Registers a primitive array element by index. */
|
|
147
151
|
select<K extends ArrayPaths<O>>(arrayKey: K, index: number): ItemSelectProps;
|
|
152
|
+
/** Registers a deeply nested field using variadic path segments. */
|
|
153
|
+
select(...args: any[]): ItemSelectProps;
|
|
148
154
|
/** Registers a scalar or nested object field. */
|
|
149
155
|
autocomplete<P extends AllPaths<O>>(id: P): ItemAutocompleteProps;
|
|
150
156
|
/** Registers an object array element's field using composite syntax "array.field". */
|
|
151
157
|
autocomplete<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemAutocompleteProps;
|
|
152
158
|
/** Registers a primitive array element by index. */
|
|
153
159
|
autocomplete<K extends ArrayPaths<O>>(arrayKey: K, index: number): ItemAutocompleteProps;
|
|
160
|
+
/** Registers a deeply nested field using variadic path segments. */
|
|
161
|
+
autocomplete(...args: any[]): ItemAutocompleteProps;
|
|
154
162
|
/** Registers a boolean field for Checkbox. */
|
|
155
163
|
checkbox<P extends AllPaths<O>>(id: P): ItemToggleProps;
|
|
156
164
|
/** Registers a boolean field within an object array element for Checkbox. */
|
|
157
165
|
checkbox<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemToggleProps;
|
|
166
|
+
/** Registers a deeply nested boolean field using variadic path segments. */
|
|
167
|
+
checkbox(...args: any[]): ItemToggleProps;
|
|
158
168
|
/** Registers a boolean field for Switch. */
|
|
159
169
|
switch<P extends AllPaths<O>>(id: P): ItemToggleProps;
|
|
160
170
|
/** Registers a boolean field within an object array element for Switch. */
|
|
161
171
|
switch<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemToggleProps;
|
|
172
|
+
/** Registers a deeply nested boolean field using variadic path segments. */
|
|
173
|
+
switch(...args: any[]): ItemToggleProps;
|
|
162
174
|
/** Registers a string field for RadioGroup. */
|
|
163
175
|
radio<P extends AllPaths<O>>(id: P): ItemRadioGroupProps;
|
|
164
176
|
/** Registers a string field within an object array element for RadioGroup. */
|
|
165
177
|
radio<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemRadioGroupProps;
|
|
178
|
+
/** Registers a deeply nested string field using variadic path segments. */
|
|
179
|
+
radio(...args: any[]): ItemRadioGroupProps;
|
|
166
180
|
}
|
|
167
181
|
/**
|
|
168
182
|
* Recursive type to find all paths to arrays in the state.
|
package/dist/index.d.ts
CHANGED
|
@@ -133,10 +133,14 @@ interface OnMethods<O extends StateType> {
|
|
|
133
133
|
input<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemInputProps<any>;
|
|
134
134
|
/** Registers a primitive array element by index. */
|
|
135
135
|
input<K extends ArrayPaths<O>>(arrayKey: K, index: number): ItemInputProps<any>;
|
|
136
|
+
/** Registers a deeply nested field using variadic path segments. */
|
|
137
|
+
input(...args: any[]): ItemInputProps<any>;
|
|
136
138
|
/** Registers a numeric field for NumberInput. */
|
|
137
139
|
numberInput<P extends AllPaths<O>>(id: P): ItemNumberInputProps;
|
|
138
140
|
/** Registers a numeric field within an object array element. */
|
|
139
141
|
numberInput<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemNumberInputProps;
|
|
142
|
+
/** Registers a deeply nested numeric field using variadic path segments. */
|
|
143
|
+
numberInput(...args: any[]): ItemNumberInputProps;
|
|
140
144
|
/** Registers a scalar or nested object field. */
|
|
141
145
|
select<P extends AllPaths<O>>(id: P): ItemSelectProps;
|
|
142
146
|
/** Registers a complete array field for multi-selection. */
|
|
@@ -145,24 +149,34 @@ interface OnMethods<O extends StateType> {
|
|
|
145
149
|
select<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemSelectProps;
|
|
146
150
|
/** Registers a primitive array element by index. */
|
|
147
151
|
select<K extends ArrayPaths<O>>(arrayKey: K, index: number): ItemSelectProps;
|
|
152
|
+
/** Registers a deeply nested field using variadic path segments. */
|
|
153
|
+
select(...args: any[]): ItemSelectProps;
|
|
148
154
|
/** Registers a scalar or nested object field. */
|
|
149
155
|
autocomplete<P extends AllPaths<O>>(id: P): ItemAutocompleteProps;
|
|
150
156
|
/** Registers an object array element's field using composite syntax "array.field". */
|
|
151
157
|
autocomplete<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemAutocompleteProps;
|
|
152
158
|
/** Registers a primitive array element by index. */
|
|
153
159
|
autocomplete<K extends ArrayPaths<O>>(arrayKey: K, index: number): ItemAutocompleteProps;
|
|
160
|
+
/** Registers a deeply nested field using variadic path segments. */
|
|
161
|
+
autocomplete(...args: any[]): ItemAutocompleteProps;
|
|
154
162
|
/** Registers a boolean field for Checkbox. */
|
|
155
163
|
checkbox<P extends AllPaths<O>>(id: P): ItemToggleProps;
|
|
156
164
|
/** Registers a boolean field within an object array element for Checkbox. */
|
|
157
165
|
checkbox<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemToggleProps;
|
|
166
|
+
/** Registers a deeply nested boolean field using variadic path segments. */
|
|
167
|
+
checkbox(...args: any[]): ItemToggleProps;
|
|
158
168
|
/** Registers a boolean field for Switch. */
|
|
159
169
|
switch<P extends AllPaths<O>>(id: P): ItemToggleProps;
|
|
160
170
|
/** Registers a boolean field within an object array element for Switch. */
|
|
161
171
|
switch<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemToggleProps;
|
|
172
|
+
/** Registers a deeply nested boolean field using variadic path segments. */
|
|
173
|
+
switch(...args: any[]): ItemToggleProps;
|
|
162
174
|
/** Registers a string field for RadioGroup. */
|
|
163
175
|
radio<P extends AllPaths<O>>(id: P): ItemRadioGroupProps;
|
|
164
176
|
/** Registers a string field within an object array element for RadioGroup. */
|
|
165
177
|
radio<P extends ObjectArrayFieldPaths<O>>(compositePath: P, itemId: string | number): ItemRadioGroupProps;
|
|
178
|
+
/** Registers a deeply nested string field using variadic path segments. */
|
|
179
|
+
radio(...args: any[]): ItemRadioGroupProps;
|
|
166
180
|
}
|
|
167
181
|
/**
|
|
168
182
|
* Recursive type to find all paths to arrays in the state.
|
package/dist/index.js
CHANGED
|
@@ -98,6 +98,21 @@ function removeCompositeKeysByPrefix(map, prefix) {
|
|
|
98
98
|
}
|
|
99
99
|
return result;
|
|
100
100
|
}
|
|
101
|
+
function setNestedValue(state, dotPath, value) {
|
|
102
|
+
const keys = dotPath.split(".");
|
|
103
|
+
const copy = { ...state };
|
|
104
|
+
let current = copy;
|
|
105
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
106
|
+
if (Array.isArray(current[keys[i]])) {
|
|
107
|
+
current[keys[i]] = [...current[keys[i]]];
|
|
108
|
+
} else {
|
|
109
|
+
current[keys[i]] = { ...current[keys[i]] };
|
|
110
|
+
}
|
|
111
|
+
current = current[keys[i]];
|
|
112
|
+
}
|
|
113
|
+
current[keys[keys.length - 1]] = value;
|
|
114
|
+
return copy;
|
|
115
|
+
}
|
|
101
116
|
|
|
102
117
|
// src/hooks/useForm.tsx
|
|
103
118
|
var import_react3 = require("@heroui/react");
|
|
@@ -314,6 +329,41 @@ function resolveFieldData(args, state, getIndex, getNestedValue2) {
|
|
|
314
329
|
nestedField: field
|
|
315
330
|
};
|
|
316
331
|
}
|
|
332
|
+
if (argCount >= 5) {
|
|
333
|
+
let current = state;
|
|
334
|
+
const compositeKeyParts = [];
|
|
335
|
+
const fieldPathParts = [];
|
|
336
|
+
const realPathParts = [];
|
|
337
|
+
let currentPath = "";
|
|
338
|
+
const parts = args.flatMap(
|
|
339
|
+
(arg) => typeof arg === "string" ? arg.split(".") : [arg]
|
|
340
|
+
);
|
|
341
|
+
for (const part of parts) {
|
|
342
|
+
if (Array.isArray(current)) {
|
|
343
|
+
let indexNum = getIndex(currentPath, part);
|
|
344
|
+
if (indexNum === void 0 && typeof part === "number") {
|
|
345
|
+
indexNum = part;
|
|
346
|
+
}
|
|
347
|
+
if (indexNum === void 0) return null;
|
|
348
|
+
compositeKeyParts.push(String(part));
|
|
349
|
+
realPathParts.push(String(indexNum));
|
|
350
|
+
current = current[indexNum];
|
|
351
|
+
} else {
|
|
352
|
+
compositeKeyParts.push(String(part));
|
|
353
|
+
fieldPathParts.push(String(part));
|
|
354
|
+
realPathParts.push(String(part));
|
|
355
|
+
currentPath = realPathParts.join(".");
|
|
356
|
+
current = current?.[part];
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return {
|
|
360
|
+
type: "deep" /* Deep */,
|
|
361
|
+
compositeKey: compositeKeyParts.join(".").replace(/\.\./g, "."),
|
|
362
|
+
fieldPath: fieldPathParts.filter(Boolean).join("."),
|
|
363
|
+
realPath: realPathParts.join("."),
|
|
364
|
+
value: current
|
|
365
|
+
};
|
|
366
|
+
}
|
|
317
367
|
return null;
|
|
318
368
|
}
|
|
319
369
|
|
|
@@ -598,6 +648,8 @@ function useForm(schema, {
|
|
|
598
648
|
parentArr[pIndex] = pItem;
|
|
599
649
|
nextState = { ...nextState, [parentKey]: parentArr };
|
|
600
650
|
}
|
|
651
|
+
} else if (type === "deep" /* Deep */) {
|
|
652
|
+
nextState = setNestedValue(nextState, resolution.realPath, finalValue);
|
|
601
653
|
}
|
|
602
654
|
setState(nextState);
|
|
603
655
|
validateField(
|
package/dist/index.mjs
CHANGED
|
@@ -72,6 +72,21 @@ function removeCompositeKeysByPrefix(map, prefix) {
|
|
|
72
72
|
}
|
|
73
73
|
return result;
|
|
74
74
|
}
|
|
75
|
+
function setNestedValue(state, dotPath, value) {
|
|
76
|
+
const keys = dotPath.split(".");
|
|
77
|
+
const copy = { ...state };
|
|
78
|
+
let current = copy;
|
|
79
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
80
|
+
if (Array.isArray(current[keys[i]])) {
|
|
81
|
+
current[keys[i]] = [...current[keys[i]]];
|
|
82
|
+
} else {
|
|
83
|
+
current[keys[i]] = { ...current[keys[i]] };
|
|
84
|
+
}
|
|
85
|
+
current = current[keys[i]];
|
|
86
|
+
}
|
|
87
|
+
current[keys[keys.length - 1]] = value;
|
|
88
|
+
return copy;
|
|
89
|
+
}
|
|
75
90
|
|
|
76
91
|
// src/hooks/useForm.tsx
|
|
77
92
|
import { Form } from "@heroui/react";
|
|
@@ -288,6 +303,41 @@ function resolveFieldData(args, state, getIndex, getNestedValue2) {
|
|
|
288
303
|
nestedField: field
|
|
289
304
|
};
|
|
290
305
|
}
|
|
306
|
+
if (argCount >= 5) {
|
|
307
|
+
let current = state;
|
|
308
|
+
const compositeKeyParts = [];
|
|
309
|
+
const fieldPathParts = [];
|
|
310
|
+
const realPathParts = [];
|
|
311
|
+
let currentPath = "";
|
|
312
|
+
const parts = args.flatMap(
|
|
313
|
+
(arg) => typeof arg === "string" ? arg.split(".") : [arg]
|
|
314
|
+
);
|
|
315
|
+
for (const part of parts) {
|
|
316
|
+
if (Array.isArray(current)) {
|
|
317
|
+
let indexNum = getIndex(currentPath, part);
|
|
318
|
+
if (indexNum === void 0 && typeof part === "number") {
|
|
319
|
+
indexNum = part;
|
|
320
|
+
}
|
|
321
|
+
if (indexNum === void 0) return null;
|
|
322
|
+
compositeKeyParts.push(String(part));
|
|
323
|
+
realPathParts.push(String(indexNum));
|
|
324
|
+
current = current[indexNum];
|
|
325
|
+
} else {
|
|
326
|
+
compositeKeyParts.push(String(part));
|
|
327
|
+
fieldPathParts.push(String(part));
|
|
328
|
+
realPathParts.push(String(part));
|
|
329
|
+
currentPath = realPathParts.join(".");
|
|
330
|
+
current = current?.[part];
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
type: "deep" /* Deep */,
|
|
335
|
+
compositeKey: compositeKeyParts.join(".").replace(/\.\./g, "."),
|
|
336
|
+
fieldPath: fieldPathParts.filter(Boolean).join("."),
|
|
337
|
+
realPath: realPathParts.join("."),
|
|
338
|
+
value: current
|
|
339
|
+
};
|
|
340
|
+
}
|
|
291
341
|
return null;
|
|
292
342
|
}
|
|
293
343
|
|
|
@@ -572,6 +622,8 @@ function useForm(schema, {
|
|
|
572
622
|
parentArr[pIndex] = pItem;
|
|
573
623
|
nextState = { ...nextState, [parentKey]: parentArr };
|
|
574
624
|
}
|
|
625
|
+
} else if (type === "deep" /* Deep */) {
|
|
626
|
+
nextState = setNestedValue(nextState, resolution.realPath, finalValue);
|
|
575
627
|
}
|
|
576
628
|
setState(nextState);
|
|
577
629
|
validateField(
|