@juantroconisf/lib 11.8.0 → 11.10.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 +31 -0
- package/dist/index.d.mts +23 -3
- package/dist/index.d.ts +23 -3
- package/dist/index.js +541 -354
- package/dist/index.mjs +534 -347
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -35,74 +35,8 @@ var NextUIError = class {
|
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
// src/hooks/useForm.tsx
|
|
38
|
-
var
|
|
39
|
-
|
|
40
|
-
// src/utils/utils.ts
|
|
41
|
-
function handleNestedChange({
|
|
42
|
-
state,
|
|
43
|
-
id,
|
|
44
|
-
value,
|
|
45
|
-
hasNestedValues = false
|
|
46
|
-
}) {
|
|
47
|
-
const isNested = hasNestedValues || String(id).includes(".");
|
|
48
|
-
if (!isNested) return { ...state, [id]: value };
|
|
49
|
-
const keys = String(id).split(".");
|
|
50
|
-
const newState = { ...state };
|
|
51
|
-
let current = newState;
|
|
52
|
-
for (let i = 0; i < keys.length - 1; i++) {
|
|
53
|
-
const key = keys[i];
|
|
54
|
-
if (Array.isArray(current[key])) {
|
|
55
|
-
current[key] = [...current[key]];
|
|
56
|
-
} else {
|
|
57
|
-
current[key] = { ...current[key] };
|
|
58
|
-
}
|
|
59
|
-
current = current[key];
|
|
60
|
-
}
|
|
61
|
-
current[keys[keys.length - 1]] = value;
|
|
62
|
-
return newState;
|
|
63
|
-
}
|
|
64
|
-
function handleArrayItemChange({
|
|
65
|
-
state,
|
|
66
|
-
arrayKey,
|
|
67
|
-
index,
|
|
68
|
-
field,
|
|
69
|
-
value
|
|
70
|
-
}) {
|
|
71
|
-
const arr = [...state[arrayKey]];
|
|
72
|
-
const item = { ...arr[index] };
|
|
73
|
-
const fieldDepth = field.split(".");
|
|
74
|
-
if (fieldDepth.length === 1) {
|
|
75
|
-
item[field] = value;
|
|
76
|
-
} else {
|
|
77
|
-
let current = item;
|
|
78
|
-
for (let i = 0; i < fieldDepth.length - 1; i++) {
|
|
79
|
-
if (Array.isArray(current[fieldDepth[i]])) {
|
|
80
|
-
current[fieldDepth[i]] = [...current[fieldDepth[i]]];
|
|
81
|
-
} else {
|
|
82
|
-
current[fieldDepth[i]] = { ...current[fieldDepth[i]] };
|
|
83
|
-
}
|
|
84
|
-
current = current[fieldDepth[i]];
|
|
85
|
-
}
|
|
86
|
-
current[fieldDepth[fieldDepth.length - 1]] = value;
|
|
87
|
-
}
|
|
88
|
-
arr[index] = item;
|
|
89
|
-
return { ...state, [arrayKey]: arr };
|
|
90
|
-
}
|
|
91
|
-
function getNestedValue(obj, path) {
|
|
92
|
-
return path.split(".").reduce((acc, key) => acc?.[key], obj);
|
|
93
|
-
}
|
|
94
|
-
function removeCompositeKeysByPrefix(map, prefix) {
|
|
95
|
-
const result = new Map(map);
|
|
96
|
-
for (const key of map.keys()) {
|
|
97
|
-
if (key.startsWith(prefix)) {
|
|
98
|
-
result.delete(key);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
return result;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// src/hooks/useForm.tsx
|
|
105
|
-
var import_react3 = require("@heroui/react");
|
|
38
|
+
var import_react6 = require("react");
|
|
39
|
+
var import_react7 = require("@heroui/react");
|
|
106
40
|
|
|
107
41
|
// src/hooks/useComponentLang.tsx
|
|
108
42
|
var import_yup = require("yup");
|
|
@@ -220,8 +154,64 @@ function useComponentLanguage() {
|
|
|
220
154
|
}, []);
|
|
221
155
|
}
|
|
222
156
|
|
|
223
|
-
// src/hooks/useForm
|
|
224
|
-
|
|
157
|
+
// src/hooks/useForm/utils.ts
|
|
158
|
+
var import_yup2 = require("yup");
|
|
159
|
+
function resolveLabel(id) {
|
|
160
|
+
const fallback = () => {
|
|
161
|
+
const lastPart = id.split(".").pop() || id;
|
|
162
|
+
return lastPart.charAt(0).toUpperCase() + lastPart.slice(1);
|
|
163
|
+
};
|
|
164
|
+
if (typeof document === "undefined") return fallback();
|
|
165
|
+
const el = document.getElementById(id);
|
|
166
|
+
if (!el) return fallback();
|
|
167
|
+
if (el.ariaLabelledByElements?.[0]) {
|
|
168
|
+
const text = el.ariaLabelledByElements[0].innerText || el.ariaLabelledByElements[0].textContent;
|
|
169
|
+
if (text) return text.trim();
|
|
170
|
+
}
|
|
171
|
+
const labelledBy = el.getAttribute("aria-labelledby");
|
|
172
|
+
if (labelledBy) {
|
|
173
|
+
const labelEl = document.getElementById(labelledBy);
|
|
174
|
+
const text = labelEl?.innerText || labelEl?.textContent;
|
|
175
|
+
if (text) return text.trim();
|
|
176
|
+
}
|
|
177
|
+
if (el.labels?.[0]) {
|
|
178
|
+
const text = el.labels[0].innerText || el.labels[0].textContent;
|
|
179
|
+
if (text) return text.trim();
|
|
180
|
+
}
|
|
181
|
+
return fallback();
|
|
182
|
+
}
|
|
183
|
+
function getRule(path, schema, ruleCache) {
|
|
184
|
+
if (ruleCache.has(path)) {
|
|
185
|
+
return ruleCache.get(path);
|
|
186
|
+
}
|
|
187
|
+
let rule;
|
|
188
|
+
try {
|
|
189
|
+
rule = (0, import_yup2.reach)(schema, path);
|
|
190
|
+
} catch {
|
|
191
|
+
const genericPath = path.replace(/\.\d+\./g, ".").replace(/\.\d+$/, "");
|
|
192
|
+
try {
|
|
193
|
+
rule = (0, import_yup2.reach)(schema, genericPath);
|
|
194
|
+
} catch {
|
|
195
|
+
rule = void 0;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
ruleCache.set(path, rule);
|
|
199
|
+
return rule;
|
|
200
|
+
}
|
|
201
|
+
function getIndex(arrayKey, itemId, indexMap) {
|
|
202
|
+
const map = indexMap.get(arrayKey);
|
|
203
|
+
if (!map) return void 0;
|
|
204
|
+
const index = map.get(itemId);
|
|
205
|
+
if (index !== void 0) return index;
|
|
206
|
+
if (typeof itemId === "string") {
|
|
207
|
+
const num = Number(itemId);
|
|
208
|
+
if (!isNaN(num)) return map.get(num);
|
|
209
|
+
} else if (typeof itemId === "number") {
|
|
210
|
+
return map.get(String(itemId));
|
|
211
|
+
}
|
|
212
|
+
return void 0;
|
|
213
|
+
}
|
|
214
|
+
function resolveFieldData(args, state, getIndexFn, getNestedValue2, getRuleFn, validationSchema) {
|
|
225
215
|
const argCount = args.length;
|
|
226
216
|
if (argCount === 1) {
|
|
227
217
|
const id = args[0];
|
|
@@ -242,7 +232,7 @@ function resolveFieldData(args, state, getIndex, getNestedValue2, getRule, valid
|
|
|
242
232
|
if (Array.isArray(state[arrayKey2])) {
|
|
243
233
|
const field = parts.slice(1).join(".");
|
|
244
234
|
const itemId = arg1;
|
|
245
|
-
const index2 =
|
|
235
|
+
const index2 = getIndexFn(arrayKey2, itemId);
|
|
246
236
|
if (index2 === void 0) return null;
|
|
247
237
|
const arr2 = state[arrayKey2];
|
|
248
238
|
const item = arr2[index2];
|
|
@@ -251,7 +241,6 @@ function resolveFieldData(args, state, getIndex, getNestedValue2, getRule, valid
|
|
|
251
241
|
type: "objectArray" /* ObjectArray */,
|
|
252
242
|
compositeKey: `${arrayKey2}.${itemId}.${field}`,
|
|
253
243
|
fieldPath: arg0,
|
|
254
|
-
// "array.field"
|
|
255
244
|
realPath: `${arrayKey2}.${index2}.${field}`,
|
|
256
245
|
value,
|
|
257
246
|
arrayKey: arrayKey2,
|
|
@@ -276,7 +265,7 @@ function resolveFieldData(args, state, getIndex, getNestedValue2, getRule, valid
|
|
|
276
265
|
}
|
|
277
266
|
if (argCount === 3) {
|
|
278
267
|
const [arrayKey, itemId, field] = args;
|
|
279
|
-
const index =
|
|
268
|
+
const index = getIndexFn(arrayKey, itemId);
|
|
280
269
|
if (index === void 0) return null;
|
|
281
270
|
const arr = state[arrayKey];
|
|
282
271
|
const item = arr[index];
|
|
@@ -285,7 +274,6 @@ function resolveFieldData(args, state, getIndex, getNestedValue2, getRule, valid
|
|
|
285
274
|
type: "objectArray" /* ObjectArray */,
|
|
286
275
|
compositeKey: `${arrayKey}.${itemId}.${field}`,
|
|
287
276
|
fieldPath: `${arrayKey}.${field}`,
|
|
288
|
-
// Normalized path for rules
|
|
289
277
|
realPath: `${arrayKey}.${index}.${field}`,
|
|
290
278
|
value,
|
|
291
279
|
arrayKey,
|
|
@@ -296,7 +284,7 @@ function resolveFieldData(args, state, getIndex, getNestedValue2, getRule, valid
|
|
|
296
284
|
}
|
|
297
285
|
if (argCount === 4) {
|
|
298
286
|
const [parentKey, parentId, field, index] = args;
|
|
299
|
-
const parentIndex =
|
|
287
|
+
const parentIndex = getIndexFn(parentKey, parentId);
|
|
300
288
|
if (parentIndex === void 0) return null;
|
|
301
289
|
const arr = state[parentKey];
|
|
302
290
|
const item = arr[parentIndex];
|
|
@@ -306,7 +294,6 @@ function resolveFieldData(args, state, getIndex, getNestedValue2, getRule, valid
|
|
|
306
294
|
type: "nestedPrimitiveArray" /* NestedPrimitiveArray */,
|
|
307
295
|
compositeKey: `${parentKey}.${parentId}.${field}.@${index}`,
|
|
308
296
|
fieldPath: `${parentKey}.${field}`,
|
|
309
|
-
// Roughly?
|
|
310
297
|
realPath: `${parentKey}.${parentIndex}.${field}.${index}`,
|
|
311
298
|
value,
|
|
312
299
|
parentKey,
|
|
@@ -327,15 +314,15 @@ function resolveFieldData(args, state, getIndex, getNestedValue2, getRule, valid
|
|
|
327
314
|
);
|
|
328
315
|
for (const part of parts) {
|
|
329
316
|
let isArrayContext = Array.isArray(current);
|
|
330
|
-
if (!isArrayContext &&
|
|
317
|
+
if (!isArrayContext && getRuleFn && validationSchema) {
|
|
331
318
|
const currentFieldPath = fieldPathParts.filter(Boolean).join(".");
|
|
332
|
-
const rule =
|
|
319
|
+
const rule = getRuleFn(currentFieldPath, validationSchema);
|
|
333
320
|
if (rule && rule.type === "array") {
|
|
334
321
|
isArrayContext = true;
|
|
335
322
|
}
|
|
336
323
|
}
|
|
337
324
|
if (isArrayContext) {
|
|
338
|
-
let indexNum =
|
|
325
|
+
let indexNum = getIndexFn(currentPath, part);
|
|
339
326
|
if (indexNum === void 0 && typeof part === "number") {
|
|
340
327
|
indexNum = part;
|
|
341
328
|
}
|
|
@@ -362,21 +349,18 @@ function resolveFieldData(args, state, getIndex, getNestedValue2, getRule, valid
|
|
|
362
349
|
return null;
|
|
363
350
|
}
|
|
364
351
|
|
|
365
|
-
// src/hooks/useForm.
|
|
366
|
-
var import_yup2 = require("yup");
|
|
367
|
-
var import_jsx_runtime = require("react/jsx-runtime");
|
|
352
|
+
// src/hooks/useForm/constants.ts
|
|
368
353
|
var DEFAULT_OPTIONS = {};
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
} = DEFAULT_OPTIONS) {
|
|
354
|
+
|
|
355
|
+
// src/hooks/useForm/useFormState.ts
|
|
356
|
+
var import_react2 = require("react");
|
|
357
|
+
var import_yup3 = require("yup");
|
|
358
|
+
function useFormState(schema, arrayIdentifiers) {
|
|
375
359
|
const { initialState, validationSchema } = (0, import_react2.useMemo)(() => {
|
|
376
360
|
const state2 = {};
|
|
377
361
|
const extractedRules = {};
|
|
378
362
|
Object.entries(schema).forEach(([key, value]) => {
|
|
379
|
-
if ((0,
|
|
363
|
+
if ((0, import_yup3.isSchema)(value)) {
|
|
380
364
|
try {
|
|
381
365
|
state2[key] = value.cast(void 0);
|
|
382
366
|
} catch {
|
|
@@ -389,12 +373,14 @@ function useForm(schema, {
|
|
|
389
373
|
});
|
|
390
374
|
return {
|
|
391
375
|
initialState: state2,
|
|
392
|
-
validationSchema: (0,
|
|
376
|
+
validationSchema: (0, import_yup3.object)().shape(extractedRules)
|
|
393
377
|
};
|
|
394
378
|
}, [schema]);
|
|
395
|
-
const [state, setState] = (0, import_react2.useState)(initialState)
|
|
396
|
-
|
|
397
|
-
const stateRef = (0, import_react2.useRef)(state)
|
|
379
|
+
const [state, setState] = (0, import_react2.useState)(initialState);
|
|
380
|
+
const [metadata, setMetadata] = (0, import_react2.useState)(/* @__PURE__ */ new Map());
|
|
381
|
+
const stateRef = (0, import_react2.useRef)(state);
|
|
382
|
+
const metadataRef = (0, import_react2.useRef)(metadata);
|
|
383
|
+
const propsCache = (0, import_react2.useRef)(/* @__PURE__ */ new Map());
|
|
398
384
|
stateRef.current = state;
|
|
399
385
|
metadataRef.current = metadata;
|
|
400
386
|
const indexMap = (0, import_react2.useMemo)(() => {
|
|
@@ -427,44 +413,28 @@ function useForm(schema, {
|
|
|
427
413
|
}, [state, arrayIdentifiers]);
|
|
428
414
|
const indexMapRef = (0, import_react2.useRef)(indexMap);
|
|
429
415
|
indexMapRef.current = indexMap;
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
}
|
|
451
|
-
let rule;
|
|
452
|
-
try {
|
|
453
|
-
rule = (0, import_yup2.reach)(schema2, path);
|
|
454
|
-
} catch {
|
|
455
|
-
const genericPath = path.replace(/\.\d+\./g, ".").replace(/\.\d+$/, "");
|
|
456
|
-
try {
|
|
457
|
-
rule = (0, import_yup2.reach)(schema2, genericPath);
|
|
458
|
-
} catch {
|
|
459
|
-
rule = void 0;
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
ruleCache.current.set(path, rule);
|
|
463
|
-
return rule;
|
|
464
|
-
}, []);
|
|
465
|
-
const runValidation = (0, import_react2.useCallback)(
|
|
416
|
+
return {
|
|
417
|
+
state,
|
|
418
|
+
setState,
|
|
419
|
+
metadata,
|
|
420
|
+
setMetadata,
|
|
421
|
+
stateRef,
|
|
422
|
+
metadataRef,
|
|
423
|
+
propsCache,
|
|
424
|
+
indexMap,
|
|
425
|
+
indexMapRef,
|
|
426
|
+
initialState,
|
|
427
|
+
validationSchema
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// src/hooks/useForm/useValidation.ts
|
|
432
|
+
var import_react3 = require("react");
|
|
433
|
+
var import_yup4 = require("yup");
|
|
434
|
+
function useValidation(validationSchema, stateRef, metadataRef, setMetadata, arrayIdentifiers, ruleCache) {
|
|
435
|
+
const runValidation = (0, import_react3.useCallback)(
|
|
466
436
|
(ruleDef, value, compositeKey, realPath, fullState) => {
|
|
467
|
-
if ((0,
|
|
437
|
+
if ((0, import_yup4.isSchema)(ruleDef)) {
|
|
468
438
|
const updateMetadata = (err) => {
|
|
469
439
|
const error = {
|
|
470
440
|
isInvalid: true,
|
|
@@ -510,11 +480,11 @@ function useForm(schema, {
|
|
|
510
480
|
}
|
|
511
481
|
return false;
|
|
512
482
|
},
|
|
513
|
-
[validationSchema]
|
|
483
|
+
[validationSchema, setMetadata]
|
|
514
484
|
);
|
|
515
|
-
const validateField = (0,
|
|
485
|
+
const validateField = (0, import_react3.useCallback)(
|
|
516
486
|
(compositeKey, fieldPath, realPath, value, fullState) => {
|
|
517
|
-
let schemaRule = getRule(fieldPath, validationSchema);
|
|
487
|
+
let schemaRule = getRule(fieldPath, validationSchema, ruleCache.current);
|
|
518
488
|
if (schemaRule) {
|
|
519
489
|
const result = runValidation(
|
|
520
490
|
schemaRule,
|
|
@@ -550,24 +520,73 @@ function useForm(schema, {
|
|
|
550
520
|
clearError();
|
|
551
521
|
return false;
|
|
552
522
|
},
|
|
553
|
-
[
|
|
523
|
+
[validationSchema, ruleCache, runValidation, setMetadata]
|
|
524
|
+
);
|
|
525
|
+
const validateFields = (0, import_react3.useCallback)(
|
|
526
|
+
async (paths) => {
|
|
527
|
+
if (!validationSchema) return { isValid: true, errors: [], results: [] };
|
|
528
|
+
const errors = [];
|
|
529
|
+
const results = [];
|
|
530
|
+
const newMetadata = new Map(metadataRef.current);
|
|
531
|
+
for (const path of paths) {
|
|
532
|
+
const compositeKey = String(path);
|
|
533
|
+
try {
|
|
534
|
+
await validationSchema.validateAt(compositeKey, stateRef.current);
|
|
535
|
+
const currentMeta = newMetadata.get(compositeKey);
|
|
536
|
+
if (currentMeta?.isInvalid) {
|
|
537
|
+
newMetadata.set(compositeKey, {
|
|
538
|
+
...currentMeta,
|
|
539
|
+
isInvalid: false,
|
|
540
|
+
errorMessage: ""
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
} catch (err) {
|
|
544
|
+
if (err.name === "ValidationError") {
|
|
545
|
+
errors.push(compositeKey);
|
|
546
|
+
const currentMeta = newMetadata.get(compositeKey) || {
|
|
547
|
+
isTouched: false,
|
|
548
|
+
isInvalid: false,
|
|
549
|
+
errorMessage: ""
|
|
550
|
+
};
|
|
551
|
+
const label = currentMeta.label || resolveLabel(compositeKey);
|
|
552
|
+
results.push({ id: compositeKey, label, message: err.message });
|
|
553
|
+
newMetadata.set(compositeKey, {
|
|
554
|
+
...currentMeta,
|
|
555
|
+
isTouched: true,
|
|
556
|
+
isInvalid: true,
|
|
557
|
+
errorMessage: err.message,
|
|
558
|
+
label
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
setMetadata(newMetadata);
|
|
564
|
+
return { isValid: errors.length === 0, errors, results };
|
|
565
|
+
},
|
|
566
|
+
[validationSchema, metadataRef, stateRef, setMetadata]
|
|
554
567
|
);
|
|
555
|
-
const validateAll = (0,
|
|
556
|
-
if (!validationSchema)
|
|
568
|
+
const validateAll = (0, import_react3.useCallback)(() => {
|
|
569
|
+
if (!validationSchema)
|
|
570
|
+
return Promise.resolve({ isValid: true, errors: [], results: [] });
|
|
557
571
|
const cleanMetadata = new Map(metadataRef.current);
|
|
558
572
|
cleanMetadata.forEach((value, key) => {
|
|
559
573
|
if (value.isInvalid) {
|
|
560
|
-
cleanMetadata.set(key, {
|
|
574
|
+
cleanMetadata.set(key, {
|
|
575
|
+
...value,
|
|
576
|
+
isInvalid: false,
|
|
577
|
+
errorMessage: ""
|
|
578
|
+
});
|
|
561
579
|
}
|
|
562
580
|
});
|
|
563
581
|
const handleErrors = (err) => {
|
|
564
582
|
const newMetadata = new Map(cleanMetadata);
|
|
583
|
+
const errors = [];
|
|
584
|
+
const results = [];
|
|
565
585
|
if (err.inner) {
|
|
566
586
|
err.inner.forEach((validationError) => {
|
|
567
|
-
const
|
|
568
|
-
const
|
|
569
|
-
|
|
570
|
-
let current = state;
|
|
587
|
+
const cleanPath = validationError.path.replace(/\["([^"]+)"\]/g, ".$1").replace(/\['([^']+)'\]/g, ".$1").replace(/\[(\d+)\]/g, ".$1").replace(/^\./, "");
|
|
588
|
+
const parts = cleanPath.split(".");
|
|
589
|
+
let current = stateRef.current;
|
|
571
590
|
const compositeParts = [];
|
|
572
591
|
for (let i = 0; i < parts.length; i++) {
|
|
573
592
|
const part = parts[i];
|
|
@@ -589,42 +608,128 @@ function useForm(schema, {
|
|
|
589
608
|
}
|
|
590
609
|
}
|
|
591
610
|
const compositeKey = compositeParts.join(".");
|
|
611
|
+
errors.push(compositeKey);
|
|
592
612
|
const currentMeta = newMetadata.get(compositeKey) || {
|
|
593
613
|
isTouched: false,
|
|
594
614
|
isInvalid: false,
|
|
595
615
|
errorMessage: ""
|
|
596
616
|
};
|
|
617
|
+
const label = currentMeta.label || resolveLabel(compositeKey);
|
|
618
|
+
const errorResult = {
|
|
619
|
+
id: compositeKey,
|
|
620
|
+
label,
|
|
621
|
+
message: validationError.message
|
|
622
|
+
};
|
|
623
|
+
results.push(errorResult);
|
|
597
624
|
newMetadata.set(compositeKey, {
|
|
598
625
|
...currentMeta,
|
|
599
626
|
isTouched: true,
|
|
600
627
|
isInvalid: true,
|
|
601
|
-
errorMessage: validationError.message
|
|
628
|
+
errorMessage: validationError.message,
|
|
629
|
+
label
|
|
602
630
|
});
|
|
603
631
|
});
|
|
604
632
|
}
|
|
605
633
|
setMetadata(newMetadata);
|
|
606
|
-
return
|
|
634
|
+
return { isValid: false, errors, results };
|
|
607
635
|
};
|
|
608
636
|
try {
|
|
609
|
-
validationSchema.validateSync(
|
|
637
|
+
validationSchema.validateSync(stateRef.current, { abortEarly: false });
|
|
610
638
|
} catch (err) {
|
|
611
639
|
if (err.name === "ValidationError") {
|
|
612
|
-
return handleErrors(err);
|
|
640
|
+
return Promise.resolve(handleErrors(err));
|
|
613
641
|
}
|
|
614
642
|
return (async () => {
|
|
615
643
|
try {
|
|
616
|
-
await validationSchema.validate(
|
|
644
|
+
await validationSchema.validate(stateRef.current, { abortEarly: false });
|
|
617
645
|
setMetadata(cleanMetadata);
|
|
618
|
-
return
|
|
646
|
+
return { isValid: true, errors: [], results: [] };
|
|
619
647
|
} catch (asyncErr) {
|
|
620
648
|
return handleErrors(asyncErr);
|
|
621
649
|
}
|
|
622
650
|
})();
|
|
623
651
|
}
|
|
624
652
|
setMetadata(cleanMetadata);
|
|
625
|
-
return
|
|
626
|
-
}, [validationSchema,
|
|
627
|
-
|
|
653
|
+
return Promise.resolve({ isValid: true, errors: [], results: [] });
|
|
654
|
+
}, [validationSchema, metadataRef, stateRef, arrayIdentifiers, setMetadata]);
|
|
655
|
+
return {
|
|
656
|
+
validateField,
|
|
657
|
+
validateFields,
|
|
658
|
+
validateAll,
|
|
659
|
+
runValidation
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// src/hooks/useForm/useHandlers.ts
|
|
664
|
+
var import_react4 = require("react");
|
|
665
|
+
|
|
666
|
+
// src/utils/utils.ts
|
|
667
|
+
function handleNestedChange({
|
|
668
|
+
state,
|
|
669
|
+
id,
|
|
670
|
+
value,
|
|
671
|
+
hasNestedValues = false
|
|
672
|
+
}) {
|
|
673
|
+
const isNested = hasNestedValues || String(id).includes(".");
|
|
674
|
+
if (!isNested) return { ...state, [id]: value };
|
|
675
|
+
const keys = String(id).split(".");
|
|
676
|
+
const newState = { ...state };
|
|
677
|
+
let current = newState;
|
|
678
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
679
|
+
const key = keys[i];
|
|
680
|
+
if (Array.isArray(current[key])) {
|
|
681
|
+
current[key] = [...current[key]];
|
|
682
|
+
} else {
|
|
683
|
+
current[key] = { ...current[key] };
|
|
684
|
+
}
|
|
685
|
+
current = current[key];
|
|
686
|
+
}
|
|
687
|
+
current[keys[keys.length - 1]] = value;
|
|
688
|
+
return newState;
|
|
689
|
+
}
|
|
690
|
+
function handleArrayItemChange({
|
|
691
|
+
state,
|
|
692
|
+
arrayKey,
|
|
693
|
+
index,
|
|
694
|
+
field,
|
|
695
|
+
value
|
|
696
|
+
}) {
|
|
697
|
+
const arr = [...state[arrayKey]];
|
|
698
|
+
const item = { ...arr[index] };
|
|
699
|
+
const fieldDepth = field.split(".");
|
|
700
|
+
if (fieldDepth.length === 1) {
|
|
701
|
+
item[field] = value;
|
|
702
|
+
} else {
|
|
703
|
+
let current = item;
|
|
704
|
+
for (let i = 0; i < fieldDepth.length - 1; i++) {
|
|
705
|
+
if (Array.isArray(current[fieldDepth[i]])) {
|
|
706
|
+
current[fieldDepth[i]] = [...current[fieldDepth[i]]];
|
|
707
|
+
} else {
|
|
708
|
+
current[fieldDepth[i]] = { ...current[fieldDepth[i]] };
|
|
709
|
+
}
|
|
710
|
+
current = current[fieldDepth[i]];
|
|
711
|
+
}
|
|
712
|
+
current[fieldDepth[fieldDepth.length - 1]] = value;
|
|
713
|
+
}
|
|
714
|
+
arr[index] = item;
|
|
715
|
+
return { ...state, [arrayKey]: arr };
|
|
716
|
+
}
|
|
717
|
+
function getNestedValue(obj, path) {
|
|
718
|
+
return path.split(".").reduce((acc, key) => acc?.[key], obj);
|
|
719
|
+
}
|
|
720
|
+
function removeCompositeKeysByPrefix(map, prefix) {
|
|
721
|
+
const result = new Map(map);
|
|
722
|
+
for (const key of map.keys()) {
|
|
723
|
+
if (key.startsWith(prefix)) {
|
|
724
|
+
result.delete(key);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
return result;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
// src/hooks/useForm/useHandlers.ts
|
|
731
|
+
function useHandlers(stateRef, setState, metadataRef, setMetadata, validationSchema, ruleCache, propsCache, getIndex3, validateField) {
|
|
732
|
+
const handleFieldChange = (0, import_react4.useCallback)(
|
|
628
733
|
(resolution, newValue) => {
|
|
629
734
|
if (!resolution) return;
|
|
630
735
|
const {
|
|
@@ -638,7 +743,7 @@ function useForm(schema, {
|
|
|
638
743
|
nestedField
|
|
639
744
|
} = resolution;
|
|
640
745
|
let finalValue = newValue;
|
|
641
|
-
let rule = getRule(fieldPath, validationSchema);
|
|
746
|
+
let rule = getRule(fieldPath, validationSchema, ruleCache.current);
|
|
642
747
|
if (rule && rule.type === "array" && type === "primitiveArray" /* PrimitiveArray */ && rule.innerType) {
|
|
643
748
|
rule = rule.innerType;
|
|
644
749
|
}
|
|
@@ -696,7 +801,7 @@ function useForm(schema, {
|
|
|
696
801
|
value: finalValue
|
|
697
802
|
});
|
|
698
803
|
} else if (type === "nestedPrimitiveArray" /* NestedPrimitiveArray */) {
|
|
699
|
-
const pIndex =
|
|
804
|
+
const pIndex = getIndex3(parentKey, parentId);
|
|
700
805
|
if (pIndex !== void 0) {
|
|
701
806
|
const parentArr = [...nextState[parentKey]];
|
|
702
807
|
const pItem = { ...parentArr[pIndex] };
|
|
@@ -723,9 +828,9 @@ function useForm(schema, {
|
|
|
723
828
|
nextState
|
|
724
829
|
);
|
|
725
830
|
},
|
|
726
|
-
[
|
|
831
|
+
[stateRef, setState, validationSchema, ruleCache, getIndex3, validateField]
|
|
727
832
|
);
|
|
728
|
-
const createHandlers = (0,
|
|
833
|
+
const createHandlers = (0, import_react4.useCallback)(
|
|
729
834
|
(resolution) => {
|
|
730
835
|
if (!resolution) return {};
|
|
731
836
|
const { compositeKey, fieldPath, realPath, value } = resolution;
|
|
@@ -733,7 +838,7 @@ function useForm(schema, {
|
|
|
733
838
|
const isTouched = meta?.isTouched;
|
|
734
839
|
let isRequired = false;
|
|
735
840
|
try {
|
|
736
|
-
const rule = getRule(fieldPath, validationSchema);
|
|
841
|
+
const rule = getRule(fieldPath, validationSchema, ruleCache.current);
|
|
737
842
|
if (rule) isRequired = rule.describe().optional === false;
|
|
738
843
|
} catch {
|
|
739
844
|
}
|
|
@@ -759,100 +864,113 @@ function useForm(schema, {
|
|
|
759
864
|
isInvalid: false,
|
|
760
865
|
errorMessage: ""
|
|
761
866
|
};
|
|
762
|
-
|
|
867
|
+
const label = current.label || resolveLabel(compositeKey);
|
|
868
|
+
newMap.set(compositeKey, {
|
|
869
|
+
...current,
|
|
870
|
+
isTouched: true,
|
|
871
|
+
label
|
|
872
|
+
});
|
|
763
873
|
return newMap;
|
|
764
874
|
});
|
|
765
875
|
}
|
|
766
876
|
};
|
|
767
877
|
},
|
|
768
|
-
[
|
|
878
|
+
[validationSchema, ruleCache, metadataRef, setMetadata, validateField, stateRef]
|
|
769
879
|
);
|
|
770
|
-
const on = (0,
|
|
771
|
-
() => {
|
|
772
|
-
const
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
return {
|
|
807
|
-
...createHandlers(data),
|
|
808
|
-
selectedKeys: data.value === null || data.value === void 0 ? [] : isArray ? data.value.map(String) : [String(data.value)],
|
|
809
|
-
onSelectionChange: (v) => {
|
|
810
|
-
const fixed = typeof v === "string" || v === null ? v : isArray ? Array.from(v) : Array.from(v)[0] ?? null;
|
|
811
|
-
handleFieldChange(data, fixed);
|
|
812
|
-
}
|
|
813
|
-
};
|
|
814
|
-
}),
|
|
815
|
-
autocomplete: (...args) => getCachedProps("autocomplete", args, (data) => ({
|
|
880
|
+
const on = (0, import_react4.useMemo)(() => {
|
|
881
|
+
const getCachedProps = (method, args, factory) => {
|
|
882
|
+
const data = resolveFieldData(
|
|
883
|
+
args,
|
|
884
|
+
stateRef.current,
|
|
885
|
+
getIndex3,
|
|
886
|
+
getNestedValue,
|
|
887
|
+
(p, s) => getRule(p, s, ruleCache.current),
|
|
888
|
+
validationSchema
|
|
889
|
+
);
|
|
890
|
+
if (!data) return {};
|
|
891
|
+
const meta = metadataRef.current.get(data.compositeKey);
|
|
892
|
+
const deps = JSON.stringify([
|
|
893
|
+
data.value,
|
|
894
|
+
meta?.isInvalid,
|
|
895
|
+
meta?.errorMessage,
|
|
896
|
+
meta?.isTouched
|
|
897
|
+
]);
|
|
898
|
+
const cacheKey = `${method}:${JSON.stringify(args)}`;
|
|
899
|
+
const cached = propsCache.current.get(cacheKey);
|
|
900
|
+
if (cached && cached.deps === deps) {
|
|
901
|
+
return cached.props;
|
|
902
|
+
}
|
|
903
|
+
const props = factory(data);
|
|
904
|
+
propsCache.current.set(cacheKey, { props, deps });
|
|
905
|
+
return props;
|
|
906
|
+
};
|
|
907
|
+
return {
|
|
908
|
+
input: (...args) => getCachedProps("input", args, (data) => ({
|
|
909
|
+
...createHandlers(data),
|
|
910
|
+
value: data.value === null || data.value === void 0 ? "" : typeof data.value === "boolean" ? data.value : String(data.value),
|
|
911
|
+
onValueChange: (v) => handleFieldChange(data, v)
|
|
912
|
+
})),
|
|
913
|
+
select: (...args) => getCachedProps("select", args, (data) => {
|
|
914
|
+
const isArray = Array.isArray(data.value);
|
|
915
|
+
return {
|
|
816
916
|
...createHandlers(data),
|
|
817
|
-
|
|
917
|
+
selectedKeys: data.value === null || data.value === void 0 ? [] : isArray ? data.value.map(String) : [String(data.value)],
|
|
818
918
|
onSelectionChange: (v) => {
|
|
819
|
-
const fixed = typeof v === "string" || v === null
|
|
919
|
+
const fixed = typeof v === "string" || v === null ? v : isArray ? Array.from(v) : Array.from(v)[0] ?? null;
|
|
820
920
|
handleFieldChange(data, fixed);
|
|
821
921
|
}
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
922
|
+
};
|
|
923
|
+
}),
|
|
924
|
+
autocomplete: (...args) => getCachedProps("autocomplete", args, (data) => ({
|
|
925
|
+
...createHandlers(data),
|
|
926
|
+
selectedKey: data.value === null || data.value === void 0 ? null : String(data.value),
|
|
927
|
+
onSelectionChange: (v) => {
|
|
928
|
+
const fixed = typeof v === "string" || v === null || v === void 0 ? v : String(v);
|
|
929
|
+
handleFieldChange(data, fixed);
|
|
930
|
+
}
|
|
931
|
+
})),
|
|
932
|
+
numberInput: (...args) => getCachedProps("numberInput", args, (data) => ({
|
|
933
|
+
...createHandlers(data),
|
|
934
|
+
value: data.value === null || data.value === void 0 ? "" : String(data.value),
|
|
935
|
+
onValueChange: (v) => handleFieldChange(data, v)
|
|
936
|
+
})),
|
|
937
|
+
checkbox: (...args) => getCachedProps("checkbox", args, (data) => ({
|
|
938
|
+
...createHandlers(data),
|
|
939
|
+
isSelected: Boolean(data.value),
|
|
940
|
+
onValueChange: (v) => handleFieldChange(data, v)
|
|
941
|
+
})),
|
|
942
|
+
switch: (...args) => getCachedProps("switch", args, (data) => ({
|
|
943
|
+
...createHandlers(data),
|
|
944
|
+
isSelected: Boolean(data.value),
|
|
945
|
+
onValueChange: (v) => handleFieldChange(data, v)
|
|
946
|
+
})),
|
|
947
|
+
radio: (...args) => getCachedProps("radio", args, (data) => ({
|
|
948
|
+
...createHandlers(data),
|
|
949
|
+
value: data.value === null || data.value === void 0 ? "" : String(data.value),
|
|
950
|
+
onValueChange: (v) => handleFieldChange(data, v)
|
|
951
|
+
}))
|
|
952
|
+
};
|
|
953
|
+
}, [
|
|
954
|
+
createHandlers,
|
|
955
|
+
getIndex3,
|
|
956
|
+
handleFieldChange,
|
|
957
|
+
ruleCache,
|
|
958
|
+
validationSchema,
|
|
959
|
+
stateRef,
|
|
960
|
+
metadataRef,
|
|
961
|
+
propsCache
|
|
962
|
+
]);
|
|
963
|
+
return {
|
|
964
|
+
on,
|
|
965
|
+
handleFieldChange,
|
|
966
|
+
createHandlers
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// src/hooks/useForm/useFormHelpers.ts
|
|
971
|
+
var import_react5 = require("react");
|
|
972
|
+
function useFormHelpers(stateRef, setState, setMetadata, metadataRef, arrayIdentifiers, validationSchema, getIndex3, validateAll, validateFields, ruleCache) {
|
|
973
|
+
const helpers = (0, import_react5.useMemo)(
|
|
856
974
|
() => ({
|
|
857
975
|
addItem: (arrayKey, item, index) => {
|
|
858
976
|
setState((prev) => {
|
|
@@ -888,7 +1006,7 @@ function useForm(schema, {
|
|
|
888
1006
|
}
|
|
889
1007
|
},
|
|
890
1008
|
removeById: (arrayKey, itemId) => {
|
|
891
|
-
const index =
|
|
1009
|
+
const index = getIndex3(arrayKey, itemId);
|
|
892
1010
|
if (index !== void 0) {
|
|
893
1011
|
setState((prev) => {
|
|
894
1012
|
const arr = [...getNestedValue(prev, arrayKey) || []];
|
|
@@ -917,7 +1035,7 @@ function useForm(schema, {
|
|
|
917
1035
|
});
|
|
918
1036
|
},
|
|
919
1037
|
updateById: (arrayKey, itemId, value) => {
|
|
920
|
-
const index =
|
|
1038
|
+
const index = getIndex3(arrayKey, itemId);
|
|
921
1039
|
if (index !== void 0) {
|
|
922
1040
|
setState((prev) => {
|
|
923
1041
|
const arr = [...getNestedValue(prev, arrayKey) || []];
|
|
@@ -945,8 +1063,8 @@ function useForm(schema, {
|
|
|
945
1063
|
});
|
|
946
1064
|
},
|
|
947
1065
|
moveById: (arrayKey, fromId, toId) => {
|
|
948
|
-
const fromIndex =
|
|
949
|
-
const toIndex =
|
|
1066
|
+
const fromIndex = getIndex3(arrayKey, fromId);
|
|
1067
|
+
const toIndex = getIndex3(arrayKey, toId);
|
|
950
1068
|
if (fromIndex !== void 0 && toIndex !== void 0) {
|
|
951
1069
|
setState((prev) => {
|
|
952
1070
|
const arr = [...getNestedValue(prev, arrayKey) || []];
|
|
@@ -962,125 +1080,188 @@ function useForm(schema, {
|
|
|
962
1080
|
}
|
|
963
1081
|
},
|
|
964
1082
|
getItemById: (arrayKey, itemId) => {
|
|
965
|
-
const index =
|
|
1083
|
+
const index = getIndex3(arrayKey, itemId);
|
|
966
1084
|
if (index === void 0) return void 0;
|
|
967
|
-
return getNestedValue(stateRef.current, arrayKey)[index];
|
|
1085
|
+
return (getNestedValue(stateRef.current, arrayKey) || [])[index];
|
|
968
1086
|
},
|
|
969
1087
|
validateItem: async (arrayKey, itemId) => {
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
const
|
|
974
|
-
const
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1088
|
+
const index = getIndex3(arrayKey, itemId);
|
|
1089
|
+
if (index === void 0)
|
|
1090
|
+
return { isValid: true, errors: [], results: [] };
|
|
1091
|
+
const item = (getNestedValue(stateRef.current, arrayKey) || [])[index];
|
|
1092
|
+
const itemSchema = getRule(String(arrayKey), validationSchema, ruleCache.current)?.innerType;
|
|
1093
|
+
if (!itemSchema) return { isValid: true, errors: [], results: [] };
|
|
1094
|
+
try {
|
|
1095
|
+
await itemSchema.validate(item, { abortEarly: false });
|
|
1096
|
+
const prefix = `${String(arrayKey)}.${itemId}.`;
|
|
1097
|
+
setMetadata((prev) => {
|
|
1098
|
+
const newMap = new Map(prev);
|
|
1099
|
+
let changed = false;
|
|
1100
|
+
for (const [key, meta] of newMap.entries()) {
|
|
1101
|
+
if (key.startsWith(prefix) && meta.isInvalid) {
|
|
1102
|
+
newMap.set(key, { ...meta, isInvalid: false, errorMessage: "" });
|
|
1103
|
+
changed = true;
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
return changed ? newMap : prev;
|
|
1107
|
+
});
|
|
1108
|
+
return { isValid: true, errors: [], results: [] };
|
|
1109
|
+
} catch (err) {
|
|
1110
|
+
const errors = [];
|
|
1111
|
+
const results = [];
|
|
1112
|
+
const newMetadata = new Map(metadataRef.current);
|
|
988
1113
|
if (err.inner) {
|
|
989
1114
|
err.inner.forEach((validationError) => {
|
|
990
|
-
const
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
);
|
|
994
|
-
const parts = localDotPath.split(".");
|
|
995
|
-
let current = stateRef.current;
|
|
996
|
-
const compositeParts = [];
|
|
997
|
-
for (let i = 0; i < parts.length; i++) {
|
|
998
|
-
const part = parts[i];
|
|
999
|
-
if (Array.isArray(current)) {
|
|
1000
|
-
const idx = parseInt(part, 10);
|
|
1001
|
-
const item = current[idx];
|
|
1002
|
-
if (item && typeof item === "object") {
|
|
1003
|
-
const genericPath = compositeParts.join(".").replace(/\.\d+/g, "");
|
|
1004
|
-
const idKey = arrayIdentifiers?.[genericPath] || "id";
|
|
1005
|
-
const id = item[idKey];
|
|
1006
|
-
compositeParts.push(String(id !== void 0 ? id : idx));
|
|
1007
|
-
} else {
|
|
1008
|
-
compositeParts.push(part);
|
|
1009
|
-
}
|
|
1010
|
-
current = item;
|
|
1011
|
-
} else {
|
|
1012
|
-
compositeParts.push(part);
|
|
1013
|
-
current = current?.[part];
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
const compositeKey = compositeParts.join(".");
|
|
1115
|
+
const field = validationError.path;
|
|
1116
|
+
const compositeKey = `${String(arrayKey)}.${itemId}.${field}`;
|
|
1117
|
+
errors.push(compositeKey);
|
|
1017
1118
|
const currentMeta = newMetadata.get(compositeKey) || {
|
|
1018
1119
|
isTouched: false,
|
|
1019
1120
|
isInvalid: false,
|
|
1020
1121
|
errorMessage: ""
|
|
1021
1122
|
};
|
|
1123
|
+
const label = currentMeta.label || resolveLabel(compositeKey);
|
|
1124
|
+
const errorResult = {
|
|
1125
|
+
id: compositeKey,
|
|
1126
|
+
label,
|
|
1127
|
+
message: validationError.message
|
|
1128
|
+
};
|
|
1129
|
+
results.push(errorResult);
|
|
1022
1130
|
newMetadata.set(compositeKey, {
|
|
1023
1131
|
...currentMeta,
|
|
1024
1132
|
isTouched: true,
|
|
1025
1133
|
isInvalid: true,
|
|
1026
|
-
errorMessage: validationError.message
|
|
1134
|
+
errorMessage: validationError.message,
|
|
1135
|
+
label
|
|
1027
1136
|
});
|
|
1028
1137
|
});
|
|
1029
1138
|
}
|
|
1030
1139
|
setMetadata(newMetadata);
|
|
1031
|
-
return
|
|
1032
|
-
};
|
|
1033
|
-
try {
|
|
1034
|
-
await validationSchema.validateAt(yupPath, stateRef.current, {
|
|
1035
|
-
abortEarly: false
|
|
1036
|
-
});
|
|
1037
|
-
setMetadata(cleanMetadata);
|
|
1038
|
-
return false;
|
|
1039
|
-
} catch (err) {
|
|
1040
|
-
if (err.name === "ValidationError") {
|
|
1041
|
-
return handleErrors(err);
|
|
1042
|
-
}
|
|
1043
|
-
return false;
|
|
1140
|
+
return { isValid: false, errors, results };
|
|
1044
1141
|
}
|
|
1045
|
-
}
|
|
1142
|
+
},
|
|
1143
|
+
validateAll,
|
|
1144
|
+
validateFields
|
|
1046
1145
|
}),
|
|
1047
|
-
[
|
|
1146
|
+
[
|
|
1147
|
+
stateRef,
|
|
1148
|
+
setState,
|
|
1149
|
+
setMetadata,
|
|
1150
|
+
metadataRef,
|
|
1151
|
+
arrayIdentifiers,
|
|
1152
|
+
validationSchema,
|
|
1153
|
+
getIndex3,
|
|
1154
|
+
validateAll,
|
|
1155
|
+
validateFields,
|
|
1156
|
+
ruleCache
|
|
1157
|
+
]
|
|
1158
|
+
);
|
|
1159
|
+
return helpers;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
// src/hooks/useForm.tsx
|
|
1163
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1164
|
+
function useForm(schema, {
|
|
1165
|
+
arrayIdentifiers,
|
|
1166
|
+
onFormSubmit: onFormSubmitProp,
|
|
1167
|
+
resetOnSubmit = false,
|
|
1168
|
+
keepValues: keepValuesProp
|
|
1169
|
+
} = DEFAULT_OPTIONS) {
|
|
1170
|
+
const {
|
|
1171
|
+
state,
|
|
1172
|
+
setState,
|
|
1173
|
+
metadata,
|
|
1174
|
+
setMetadata,
|
|
1175
|
+
stateRef,
|
|
1176
|
+
metadataRef,
|
|
1177
|
+
propsCache,
|
|
1178
|
+
indexMapRef,
|
|
1179
|
+
initialState,
|
|
1180
|
+
validationSchema
|
|
1181
|
+
} = useFormState(schema, arrayIdentifiers);
|
|
1182
|
+
useComponentLanguage();
|
|
1183
|
+
const ruleCache = (0, import_react6.useRef)(/* @__PURE__ */ new Map());
|
|
1184
|
+
(0, import_react6.useMemo)(() => {
|
|
1185
|
+
ruleCache.current.clear();
|
|
1186
|
+
}, [validationSchema]);
|
|
1187
|
+
const getIndexFn = (0, import_react6.useCallback)(
|
|
1188
|
+
(arrayKey, itemId) => getIndex(arrayKey, itemId, indexMapRef.current),
|
|
1189
|
+
[indexMapRef]
|
|
1190
|
+
);
|
|
1191
|
+
const { validateField, validateFields, validateAll } = useValidation(
|
|
1192
|
+
validationSchema,
|
|
1193
|
+
stateRef,
|
|
1194
|
+
metadataRef,
|
|
1195
|
+
setMetadata,
|
|
1196
|
+
arrayIdentifiers,
|
|
1197
|
+
ruleCache
|
|
1198
|
+
);
|
|
1199
|
+
const { on, handleFieldChange } = useHandlers(
|
|
1200
|
+
stateRef,
|
|
1201
|
+
setState,
|
|
1202
|
+
metadataRef,
|
|
1203
|
+
setMetadata,
|
|
1204
|
+
validationSchema,
|
|
1205
|
+
ruleCache,
|
|
1206
|
+
propsCache,
|
|
1207
|
+
getIndexFn,
|
|
1208
|
+
validateField
|
|
1048
1209
|
);
|
|
1049
|
-
const
|
|
1210
|
+
const helpers = useFormHelpers(
|
|
1211
|
+
stateRef,
|
|
1212
|
+
setState,
|
|
1213
|
+
setMetadata,
|
|
1214
|
+
metadataRef,
|
|
1215
|
+
arrayIdentifiers,
|
|
1216
|
+
validationSchema,
|
|
1217
|
+
getIndexFn,
|
|
1218
|
+
validateAll,
|
|
1219
|
+
validateFields,
|
|
1220
|
+
ruleCache
|
|
1221
|
+
);
|
|
1222
|
+
const onBlur = (0, import_react6.useCallback)(
|
|
1050
1223
|
(id) => {
|
|
1224
|
+
const compositeKey = String(id);
|
|
1051
1225
|
validateField(
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1226
|
+
compositeKey,
|
|
1227
|
+
compositeKey,
|
|
1228
|
+
compositeKey,
|
|
1055
1229
|
stateRef.current[id],
|
|
1056
1230
|
stateRef.current
|
|
1057
1231
|
);
|
|
1058
1232
|
setMetadata((prev) => {
|
|
1059
1233
|
const newMap = new Map(prev);
|
|
1060
|
-
const current = newMap.get(
|
|
1234
|
+
const current = newMap.get(compositeKey) || {
|
|
1061
1235
|
isTouched: false,
|
|
1062
1236
|
isInvalid: false,
|
|
1063
1237
|
errorMessage: ""
|
|
1064
1238
|
};
|
|
1065
|
-
|
|
1239
|
+
const label = current.label || resolveLabel(compositeKey);
|
|
1240
|
+
newMap.set(compositeKey, {
|
|
1241
|
+
...current,
|
|
1242
|
+
isTouched: true,
|
|
1243
|
+
label
|
|
1244
|
+
});
|
|
1066
1245
|
return newMap;
|
|
1067
1246
|
});
|
|
1068
1247
|
},
|
|
1069
|
-
[validateField]
|
|
1248
|
+
[validateField, stateRef, setMetadata]
|
|
1070
1249
|
);
|
|
1071
|
-
const scalarOnFieldChange = (0,
|
|
1250
|
+
const scalarOnFieldChange = (0, import_react6.useCallback)(
|
|
1072
1251
|
(id, value) => {
|
|
1073
1252
|
const data = resolveFieldData(
|
|
1074
1253
|
[id],
|
|
1075
1254
|
stateRef.current,
|
|
1076
|
-
|
|
1077
|
-
getNestedValue
|
|
1255
|
+
getIndexFn,
|
|
1256
|
+
getNestedValue,
|
|
1257
|
+
(p, s) => getRule(p, s, ruleCache.current),
|
|
1258
|
+
validationSchema
|
|
1078
1259
|
);
|
|
1079
1260
|
if (data) handleFieldChange(data, value);
|
|
1080
1261
|
},
|
|
1081
|
-
[
|
|
1262
|
+
[stateRef, getIndexFn, validationSchema, ruleCache, handleFieldChange]
|
|
1082
1263
|
);
|
|
1083
|
-
const arrayItemChange = (0,
|
|
1264
|
+
const arrayItemChange = (0, import_react6.useCallback)(
|
|
1084
1265
|
({
|
|
1085
1266
|
at: compositePath,
|
|
1086
1267
|
id: itemId,
|
|
@@ -1089,28 +1270,31 @@ function useForm(schema, {
|
|
|
1089
1270
|
const data = resolveFieldData(
|
|
1090
1271
|
[compositePath, itemId],
|
|
1091
1272
|
stateRef.current,
|
|
1092
|
-
|
|
1093
|
-
getNestedValue
|
|
1273
|
+
getIndexFn,
|
|
1274
|
+
getNestedValue,
|
|
1275
|
+
(p, s) => getRule(p, s, ruleCache.current),
|
|
1276
|
+
validationSchema
|
|
1094
1277
|
);
|
|
1095
1278
|
if (data) handleFieldChange(data, value);
|
|
1096
1279
|
},
|
|
1097
|
-
[
|
|
1280
|
+
[stateRef, getIndexFn, validationSchema, ruleCache, handleFieldChange]
|
|
1098
1281
|
);
|
|
1099
|
-
const scalarOnSelectionChange = (0,
|
|
1282
|
+
const scalarOnSelectionChange = (0, import_react6.useCallback)(
|
|
1100
1283
|
(id, val) => {
|
|
1284
|
+
const compositeKey = String(id);
|
|
1101
1285
|
const fixed = typeof val === "string" || val === null ? val : Array.from(val);
|
|
1102
|
-
|
|
1286
|
+
const nextState = handleNestedChange({
|
|
1103
1287
|
state: stateRef.current,
|
|
1104
|
-
id,
|
|
1288
|
+
id: compositeKey,
|
|
1105
1289
|
value: fixed,
|
|
1106
|
-
hasNestedValues:
|
|
1290
|
+
hasNestedValues: compositeKey.includes(".")
|
|
1107
1291
|
});
|
|
1108
1292
|
setState(nextState);
|
|
1109
|
-
validateField(
|
|
1293
|
+
validateField(compositeKey, compositeKey, compositeKey, fixed, nextState);
|
|
1110
1294
|
},
|
|
1111
|
-
[validateField]
|
|
1295
|
+
[stateRef, setState, validateField]
|
|
1112
1296
|
);
|
|
1113
|
-
const arraySelectionChange = (0,
|
|
1297
|
+
const arraySelectionChange = (0, import_react6.useCallback)(
|
|
1114
1298
|
({
|
|
1115
1299
|
at: compositePath,
|
|
1116
1300
|
id: itemId,
|
|
@@ -1120,28 +1304,25 @@ function useForm(schema, {
|
|
|
1120
1304
|
const data = resolveFieldData(
|
|
1121
1305
|
[compositePath, itemId],
|
|
1122
1306
|
stateRef.current,
|
|
1123
|
-
|
|
1124
|
-
getNestedValue
|
|
1307
|
+
getIndexFn,
|
|
1308
|
+
getNestedValue,
|
|
1309
|
+
(p, s) => getRule(p, s, ruleCache.current),
|
|
1310
|
+
validationSchema
|
|
1125
1311
|
);
|
|
1126
1312
|
if (data) handleFieldChange(data, fixed);
|
|
1127
1313
|
},
|
|
1128
|
-
[
|
|
1314
|
+
[stateRef, getIndexFn, validationSchema, ruleCache, handleFieldChange]
|
|
1129
1315
|
);
|
|
1130
|
-
const onFormSubmit = (0,
|
|
1316
|
+
const onFormSubmit = (0, import_react6.useCallback)(
|
|
1131
1317
|
(fn) => async (e) => {
|
|
1132
1318
|
e.preventDefault();
|
|
1133
|
-
|
|
1319
|
+
const { isValid } = await validateAll();
|
|
1320
|
+
if (!isValid) return;
|
|
1134
1321
|
fn(stateRef.current, e);
|
|
1135
1322
|
},
|
|
1136
|
-
[validateAll]
|
|
1323
|
+
[validateAll, stateRef]
|
|
1137
1324
|
);
|
|
1138
|
-
const
|
|
1139
|
-
onFormSubmitPropRef.current = onFormSubmitProp;
|
|
1140
|
-
const resetOnSubmitRef = (0, import_react2.useRef)(resetOnSubmit);
|
|
1141
|
-
resetOnSubmitRef.current = resetOnSubmit;
|
|
1142
|
-
const keepValuesPropRef = (0, import_react2.useRef)(keepValuesProp);
|
|
1143
|
-
keepValuesPropRef.current = keepValuesProp;
|
|
1144
|
-
const handleReset = (0, import_react2.useCallback)(
|
|
1325
|
+
const handleReset = (0, import_react6.useCallback)(
|
|
1145
1326
|
(options) => {
|
|
1146
1327
|
const { keepValues } = options || {};
|
|
1147
1328
|
if (keepValues && keepValues.length > 0) {
|
|
@@ -1156,18 +1337,23 @@ function useForm(schema, {
|
|
|
1156
1337
|
}
|
|
1157
1338
|
setMetadata(/* @__PURE__ */ new Map());
|
|
1158
1339
|
},
|
|
1159
|
-
[initialState]
|
|
1340
|
+
[initialState, stateRef, setState, setMetadata]
|
|
1160
1341
|
);
|
|
1161
|
-
const
|
|
1342
|
+
const onFormSubmitPropRef = (0, import_react6.useRef)(onFormSubmitProp);
|
|
1343
|
+
onFormSubmitPropRef.current = onFormSubmitProp;
|
|
1344
|
+
const resetOnSubmitRef = (0, import_react6.useRef)(resetOnSubmit);
|
|
1345
|
+
resetOnSubmitRef.current = resetOnSubmit;
|
|
1346
|
+
const keepValuesPropRef = (0, import_react6.useRef)(keepValuesProp);
|
|
1347
|
+
keepValuesPropRef.current = keepValuesProp;
|
|
1348
|
+
const validateAllRef = (0, import_react6.useRef)(validateAll);
|
|
1162
1349
|
validateAllRef.current = validateAll;
|
|
1163
|
-
const ControlledForm = (0,
|
|
1350
|
+
const ControlledForm = (0, import_react6.useMemo)(() => {
|
|
1164
1351
|
return (props) => {
|
|
1165
1352
|
const { onSubmit, ...rest } = props;
|
|
1166
1353
|
const handleSubmit = async (e) => {
|
|
1167
1354
|
e.preventDefault();
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
}
|
|
1355
|
+
const { isValid } = await validateAllRef.current();
|
|
1356
|
+
if (!isValid) return;
|
|
1171
1357
|
onFormSubmitPropRef.current?.(stateRef.current, e);
|
|
1172
1358
|
if (resetOnSubmitRef.current) {
|
|
1173
1359
|
handleReset({ keepValues: keepValuesPropRef.current });
|
|
@@ -1175,18 +1361,16 @@ function useForm(schema, {
|
|
|
1175
1361
|
onSubmit?.(stateRef.current, e);
|
|
1176
1362
|
};
|
|
1177
1363
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1178
|
-
|
|
1364
|
+
import_react7.Form,
|
|
1179
1365
|
{
|
|
1180
|
-
style: {
|
|
1181
|
-
display: "contents"
|
|
1182
|
-
},
|
|
1366
|
+
style: { display: "contents" },
|
|
1183
1367
|
onSubmit: handleSubmit,
|
|
1184
1368
|
...rest
|
|
1185
1369
|
}
|
|
1186
1370
|
);
|
|
1187
1371
|
};
|
|
1188
|
-
}, []);
|
|
1189
|
-
return (0,
|
|
1372
|
+
}, [handleReset, stateRef]);
|
|
1373
|
+
return (0, import_react6.useMemo)(
|
|
1190
1374
|
() => ({
|
|
1191
1375
|
state,
|
|
1192
1376
|
setState,
|
|
@@ -1201,6 +1385,8 @@ function useForm(schema, {
|
|
|
1201
1385
|
isDirty: Array.from(metadata.values()).some((m) => m.isTouched),
|
|
1202
1386
|
onFormReset: handleReset,
|
|
1203
1387
|
onFormSubmit,
|
|
1388
|
+
validateAll,
|
|
1389
|
+
validateFields,
|
|
1204
1390
|
ControlledForm
|
|
1205
1391
|
}),
|
|
1206
1392
|
[
|
|
@@ -1215,9 +1401,10 @@ function useForm(schema, {
|
|
|
1215
1401
|
scalarOnSelectionChange,
|
|
1216
1402
|
arraySelectionChange,
|
|
1217
1403
|
validateAll,
|
|
1404
|
+
validateFields,
|
|
1218
1405
|
onFormSubmit,
|
|
1219
1406
|
ControlledForm,
|
|
1220
|
-
|
|
1407
|
+
handleReset
|
|
1221
1408
|
]
|
|
1222
1409
|
);
|
|
1223
1410
|
}
|