@vuehookform/core 0.4.1 → 0.4.3
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/LICENSE +1 -1
- package/README.md +46 -6
- package/dist/core/domSync.d.ts +29 -3
- package/dist/core/fieldState.d.ts +19 -13
- package/dist/core/formContext.d.ts +65 -8
- package/dist/index.d.ts +2 -1
- package/dist/types.d.ts +30 -5
- package/dist/useForm.d.ts +6 -0
- package/dist/utils/clone.d.ts +2 -2
- package/dist/utils/hash.d.ts +3 -0
- package/dist/utils/modeChecks.d.ts +22 -0
- package/dist/utils/paths.d.ts +15 -3
- package/dist/vuehookform.cjs +426 -227
- package/dist/vuehookform.js +423 -229
- package/package.json +7 -1
package/dist/vuehookform.cjs
CHANGED
|
@@ -2,6 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
let vue = require("vue");
|
|
3
3
|
var pathCache = /* @__PURE__ */ new Map();
|
|
4
4
|
var PATH_CACHE_MAX_SIZE = 256;
|
|
5
|
+
var MAX_ARRAY_INDEX = 1e4;
|
|
5
6
|
function getPathSegments(path) {
|
|
6
7
|
let segments = pathCache.get(path);
|
|
7
8
|
if (segments) return segments;
|
|
@@ -13,6 +14,9 @@ function getPathSegments(path) {
|
|
|
13
14
|
pathCache.set(path, segments);
|
|
14
15
|
return segments;
|
|
15
16
|
}
|
|
17
|
+
function clearPathCache() {
|
|
18
|
+
pathCache.clear();
|
|
19
|
+
}
|
|
16
20
|
function get(obj, path) {
|
|
17
21
|
if (!path || obj === null || obj === void 0) return obj;
|
|
18
22
|
const keys = getPathSegments(path);
|
|
@@ -32,6 +36,13 @@ function set(obj, path, value) {
|
|
|
32
36
|
"prototype"
|
|
33
37
|
];
|
|
34
38
|
if (keys.some((k) => UNSAFE_KEYS.includes(k))) return;
|
|
39
|
+
for (const key of keys) if (/^\d+$/.test(key)) {
|
|
40
|
+
const index = parseInt(key, 10);
|
|
41
|
+
if (index > MAX_ARRAY_INDEX) {
|
|
42
|
+
if (typeof console !== "undefined" && console.warn) console.warn(`[vue-hook-form] set(): Array index ${index} exceeds maximum allowed (${MAX_ARRAY_INDEX}). Path "${path}" was not set to prevent memory exhaustion.`);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
35
46
|
const lastKey = keys.pop();
|
|
36
47
|
let current = obj;
|
|
37
48
|
for (let i = 0; i < keys.length; i++) {
|
|
@@ -66,13 +77,22 @@ function generateId() {
|
|
|
66
77
|
const random = Math.random().toString(36).substring(2, 11);
|
|
67
78
|
return `field_${Date.now()}_${idCounter++}_${random}`;
|
|
68
79
|
}
|
|
69
|
-
function deepClone(obj) {
|
|
80
|
+
function deepClone(obj, seen) {
|
|
70
81
|
if (obj === null || obj === void 0) return obj;
|
|
71
82
|
if (typeof obj !== "object") return obj;
|
|
72
83
|
if (obj instanceof Date) return new Date(obj.getTime());
|
|
73
|
-
if (
|
|
84
|
+
if (!seen) seen = /* @__PURE__ */ new Map();
|
|
85
|
+
const existingClone = seen.get(obj);
|
|
86
|
+
if (existingClone !== void 0) return existingClone;
|
|
87
|
+
if (Array.isArray(obj)) {
|
|
88
|
+
const clonedArray = [];
|
|
89
|
+
seen.set(obj, clonedArray);
|
|
90
|
+
for (const item of obj) clonedArray.push(deepClone(item, seen));
|
|
91
|
+
return clonedArray;
|
|
92
|
+
}
|
|
74
93
|
const cloned = {};
|
|
75
|
-
|
|
94
|
+
seen.set(obj, cloned);
|
|
95
|
+
for (const key in obj) if (Object.prototype.hasOwnProperty.call(obj, key)) cloned[key] = deepClone(obj[key], seen);
|
|
76
96
|
return cloned;
|
|
77
97
|
}
|
|
78
98
|
var proc = globalThis.process;
|
|
@@ -202,26 +222,68 @@ function warnArrayIndexOutOfBounds(operation, path, index, length) {
|
|
|
202
222
|
if (!__DEV__) return;
|
|
203
223
|
warn(`${operation}() on "${path}": Index ${index} is out of bounds (array length: ${length}). Operation was silently ignored.`);
|
|
204
224
|
}
|
|
205
|
-
function
|
|
206
|
-
return schema.
|
|
207
|
-
}
|
|
208
|
-
function getTypeName(schema) {
|
|
209
|
-
return getDefProp$1(schema, "typeName");
|
|
225
|
+
function getSchemaType(schema) {
|
|
226
|
+
return schema.type;
|
|
210
227
|
}
|
|
211
228
|
function isZodObject$1(schema) {
|
|
212
|
-
return
|
|
229
|
+
return getSchemaType(schema) === "object";
|
|
213
230
|
}
|
|
214
231
|
function isZodArray$1(schema) {
|
|
215
|
-
return
|
|
232
|
+
return getSchemaType(schema) === "array";
|
|
216
233
|
}
|
|
217
234
|
function unwrapSchema(schema) {
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
235
|
+
const schemaType = getSchemaType(schema);
|
|
236
|
+
if (schemaType === "optional" || schemaType === "nullable" || schemaType === "default") {
|
|
237
|
+
const schemaWithUnwrap = schema;
|
|
238
|
+
if (typeof schemaWithUnwrap.unwrap === "function") return unwrapSchema(schemaWithUnwrap.unwrap());
|
|
239
|
+
}
|
|
223
240
|
return schema;
|
|
224
241
|
}
|
|
242
|
+
function getInputElement(refValue) {
|
|
243
|
+
if (!refValue) return null;
|
|
244
|
+
if (refValue instanceof HTMLInputElement) return refValue;
|
|
245
|
+
if (refValue instanceof HTMLSelectElement || refValue instanceof HTMLTextAreaElement) return refValue;
|
|
246
|
+
if (typeof refValue === "object" && "$el" in refValue) {
|
|
247
|
+
const el = refValue.$el;
|
|
248
|
+
if (el instanceof HTMLInputElement) return el;
|
|
249
|
+
if (el instanceof HTMLSelectElement || el instanceof HTMLTextAreaElement) return el;
|
|
250
|
+
if (el instanceof Element) {
|
|
251
|
+
const input = el.querySelector("input, select, textarea");
|
|
252
|
+
if (input instanceof HTMLInputElement || input instanceof HTMLSelectElement || input instanceof HTMLTextAreaElement) return input;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
function getFocusableElement(refValue) {
|
|
258
|
+
const input = getInputElement(refValue);
|
|
259
|
+
if (input) return input;
|
|
260
|
+
if (typeof refValue === "object" && refValue && "$el" in refValue) {
|
|
261
|
+
const el = refValue.$el;
|
|
262
|
+
if (el instanceof HTMLElement && typeof el.focus === "function") return el;
|
|
263
|
+
}
|
|
264
|
+
if (refValue instanceof HTMLElement && typeof refValue.focus === "function") return refValue;
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
function syncUncontrolledInputs(fieldRefs, fieldOptions, formData) {
|
|
268
|
+
for (const [name, fieldRef] of Array.from(fieldRefs.entries())) {
|
|
269
|
+
const el = getInputElement(fieldRef.value);
|
|
270
|
+
if (el) {
|
|
271
|
+
if (!fieldOptions.get(name)?.controlled) {
|
|
272
|
+
let value;
|
|
273
|
+
if (el.type === "checkbox") value = el.checked;
|
|
274
|
+
else if (el.type === "number" || el.type === "range") value = el.valueAsNumber;
|
|
275
|
+
else value = el.value;
|
|
276
|
+
set(formData, name, value);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
function updateDomElement(refValue, value) {
|
|
282
|
+
const el = getInputElement(refValue);
|
|
283
|
+
if (!el) return;
|
|
284
|
+
if (el.type === "checkbox") el.checked = value;
|
|
285
|
+
else el.value = value;
|
|
286
|
+
}
|
|
225
287
|
function createFormContext(options) {
|
|
226
288
|
const formData = (0, vue.reactive)({});
|
|
227
289
|
const defaultValues = (0, vue.reactive)({});
|
|
@@ -230,8 +292,8 @@ function createFormContext(options) {
|
|
|
230
292
|
if (isAsyncDefaults) {
|
|
231
293
|
const asyncFn = options.defaultValues;
|
|
232
294
|
asyncFn().then((values) => {
|
|
233
|
-
Object.assign(defaultValues, values);
|
|
234
|
-
Object.assign(formData, values);
|
|
295
|
+
Object.assign(defaultValues, deepClone(values));
|
|
296
|
+
Object.assign(formData, deepClone(values));
|
|
235
297
|
isLoading.value = false;
|
|
236
298
|
}).catch((error) => {
|
|
237
299
|
console.error("Failed to load async default values:", error);
|
|
@@ -240,8 +302,8 @@ function createFormContext(options) {
|
|
|
240
302
|
options.onDefaultValuesError?.(error);
|
|
241
303
|
});
|
|
242
304
|
} else if (options.defaultValues) {
|
|
243
|
-
Object.assign(defaultValues, options.defaultValues);
|
|
244
|
-
Object.assign(formData, defaultValues);
|
|
305
|
+
Object.assign(defaultValues, deepClone(options.defaultValues));
|
|
306
|
+
Object.assign(formData, deepClone(options.defaultValues));
|
|
245
307
|
}
|
|
246
308
|
const errors = (0, vue.shallowRef)({});
|
|
247
309
|
const touchedFields = (0, vue.shallowRef)({});
|
|
@@ -261,43 +323,44 @@ function createFormContext(options) {
|
|
|
261
323
|
const debounceTimers = /* @__PURE__ */ new Map();
|
|
262
324
|
const validationRequestIds = /* @__PURE__ */ new Map();
|
|
263
325
|
const resetGeneration = (0, vue.ref)(0);
|
|
264
|
-
const dirtyFieldCount = (0, vue.ref)(0);
|
|
265
|
-
const touchedFieldCount = (0, vue.ref)(0);
|
|
266
326
|
const validationCache = /* @__PURE__ */ new Map();
|
|
267
327
|
const schemaValidationTimers = /* @__PURE__ */ new Map();
|
|
328
|
+
const persistentErrorFields = /* @__PURE__ */ new Set();
|
|
329
|
+
const defaultValueHashes = /* @__PURE__ */ new Map();
|
|
268
330
|
const isDisabled = (0, vue.ref)(false);
|
|
331
|
+
const watchStopHandles = [];
|
|
269
332
|
if (options.disabled !== void 0) {
|
|
270
333
|
isDisabled.value = (0, vue.toValue)(options.disabled) ?? false;
|
|
271
|
-
(0, vue.watch)(() => (0, vue.toValue)(options.disabled), (newDisabled) => {
|
|
334
|
+
watchStopHandles.push((0, vue.watch)(() => (0, vue.toValue)(options.disabled), (newDisabled) => {
|
|
272
335
|
isDisabled.value = newDisabled ?? false;
|
|
273
|
-
});
|
|
336
|
+
}));
|
|
274
337
|
}
|
|
275
338
|
if (options.values !== void 0) {
|
|
276
339
|
const initialValues = (0, vue.toValue)(options.values);
|
|
277
340
|
if (initialValues && !isAsyncDefaults) {
|
|
278
341
|
for (const [key, value] of Object.entries(initialValues)) if (value !== void 0) set(formData, key, value);
|
|
279
342
|
}
|
|
280
|
-
(0, vue.watch)(() => (0, vue.toValue)(options.values), (newValues) => {
|
|
343
|
+
watchStopHandles.push((0, vue.watch)(() => (0, vue.toValue)(options.values), (newValues) => {
|
|
281
344
|
if (newValues) {
|
|
282
345
|
for (const [key, value] of Object.entries(newValues)) if (value !== void 0) {
|
|
283
346
|
set(formData, key, value);
|
|
284
347
|
const fieldRef = fieldRefs.get(key);
|
|
285
348
|
const opts = fieldOptions.get(key);
|
|
286
349
|
if (fieldRef?.value && !opts?.controlled) {
|
|
287
|
-
const el = fieldRef.value;
|
|
288
|
-
if (el.type === "checkbox") el.checked = value;
|
|
350
|
+
const el = getInputElement(fieldRef.value);
|
|
351
|
+
if (el) if (el.type === "checkbox") el.checked = value;
|
|
289
352
|
else el.value = value;
|
|
290
353
|
}
|
|
291
354
|
}
|
|
292
355
|
}
|
|
293
|
-
}, { deep: true });
|
|
356
|
+
}, { deep: true }));
|
|
294
357
|
}
|
|
295
358
|
if (options.errors !== void 0) {
|
|
296
359
|
const initialErrors = (0, vue.toValue)(options.errors);
|
|
297
360
|
if (initialErrors) externalErrors.value = initialErrors;
|
|
298
|
-
(0, vue.watch)(() => (0, vue.toValue)(options.errors), (newErrors) => {
|
|
361
|
+
watchStopHandles.push((0, vue.watch)(() => (0, vue.toValue)(options.errors), (newErrors) => {
|
|
299
362
|
externalErrors.value = newErrors || {};
|
|
300
|
-
}, { deep: true });
|
|
363
|
+
}, { deep: true }));
|
|
301
364
|
}
|
|
302
365
|
return {
|
|
303
366
|
formData,
|
|
@@ -322,25 +385,40 @@ function createFormContext(options) {
|
|
|
322
385
|
validationRequestIds,
|
|
323
386
|
resetGeneration,
|
|
324
387
|
isDisabled,
|
|
325
|
-
dirtyFieldCount,
|
|
326
|
-
touchedFieldCount,
|
|
327
388
|
validationCache,
|
|
328
389
|
schemaValidationTimers,
|
|
329
|
-
|
|
390
|
+
persistentErrorFields,
|
|
391
|
+
defaultValueHashes,
|
|
392
|
+
options,
|
|
393
|
+
cleanup: () => {
|
|
394
|
+
for (const stop of watchStopHandles) stop();
|
|
395
|
+
}
|
|
330
396
|
};
|
|
331
397
|
}
|
|
332
398
|
var uniqueIdCounter = 0;
|
|
399
|
+
var circularRefMap = /* @__PURE__ */ new WeakMap();
|
|
333
400
|
function hashValue(value) {
|
|
334
401
|
if (value === null) return "null";
|
|
335
402
|
if (value === void 0) return "undefined";
|
|
336
403
|
const type = typeof value;
|
|
337
404
|
if (type === "string") return `s:${value}`;
|
|
338
|
-
if (type === "number")
|
|
405
|
+
if (type === "number") {
|
|
406
|
+
const num = value;
|
|
407
|
+
if (Number.isNaN(num)) return "n:NaN";
|
|
408
|
+
if (num === 0) return "n:0";
|
|
409
|
+
if (!Number.isFinite(num)) return `n:${num > 0 ? "Infinity" : "-Infinity"}`;
|
|
410
|
+
return `n:${num}`;
|
|
411
|
+
}
|
|
339
412
|
if (type === "boolean") return `b:${value}`;
|
|
340
413
|
if (type === "object") try {
|
|
341
414
|
return `o:${JSON.stringify(value)}`;
|
|
342
415
|
} catch {
|
|
343
|
-
|
|
416
|
+
let id = circularRefMap.get(value);
|
|
417
|
+
if (!id) {
|
|
418
|
+
id = String(++uniqueIdCounter);
|
|
419
|
+
circularRefMap.set(value, id);
|
|
420
|
+
}
|
|
421
|
+
return `o:_${id}`;
|
|
344
422
|
}
|
|
345
423
|
return `x:_${++uniqueIdCounter}`;
|
|
346
424
|
}
|
|
@@ -375,7 +453,7 @@ function extractSubSchema(schema, path) {
|
|
|
375
453
|
let currentSchema = schema;
|
|
376
454
|
let hasEffects = false;
|
|
377
455
|
for (const segment of segments) {
|
|
378
|
-
if (!segment)
|
|
456
|
+
if (!segment) return null;
|
|
379
457
|
if (hasChecks(currentSchema)) hasEffects = true;
|
|
380
458
|
const unwrapped = unwrapNonEffects(currentSchema);
|
|
381
459
|
if (hasChecks(unwrapped)) hasEffects = true;
|
|
@@ -442,10 +520,54 @@ function analyzeSchemaPath(schema, path) {
|
|
|
442
520
|
cache.set(path, result);
|
|
443
521
|
return result;
|
|
444
522
|
}
|
|
445
|
-
function
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
523
|
+
function markFieldTouched(touchedFields, fieldName) {
|
|
524
|
+
if (touchedFields.value[fieldName]) return;
|
|
525
|
+
touchedFields.value = {
|
|
526
|
+
...touchedFields.value,
|
|
527
|
+
[fieldName]: true
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
function clearFieldDirty(dirtyFields, fieldName) {
|
|
531
|
+
if (!(fieldName in dirtyFields.value)) return;
|
|
532
|
+
const newDirty = { ...dirtyFields.value };
|
|
533
|
+
delete newDirty[fieldName];
|
|
534
|
+
dirtyFields.value = newDirty;
|
|
535
|
+
}
|
|
536
|
+
function clearFieldTouched(touchedFields, fieldName) {
|
|
537
|
+
if (!(fieldName in touchedFields.value)) return;
|
|
538
|
+
const newTouched = { ...touchedFields.value };
|
|
539
|
+
delete newTouched[fieldName];
|
|
540
|
+
touchedFields.value = newTouched;
|
|
541
|
+
}
|
|
542
|
+
function clearFieldErrors(errors, fieldName) {
|
|
543
|
+
const currentErrors = errors.value;
|
|
544
|
+
const keys = Object.keys(currentErrors);
|
|
545
|
+
if (keys.length === 0) return;
|
|
546
|
+
const prefix = `${fieldName}.`;
|
|
547
|
+
const keysToDelete = [];
|
|
548
|
+
for (const key of keys) if (key === fieldName || key.startsWith(prefix)) keysToDelete.push(key);
|
|
549
|
+
if (keysToDelete.length === 0) return;
|
|
550
|
+
const newErrors = { ...currentErrors };
|
|
551
|
+
for (const key of keysToDelete) delete newErrors[key];
|
|
552
|
+
errors.value = newErrors;
|
|
553
|
+
}
|
|
554
|
+
function updateFieldDirtyState(dirtyFields, defaultValues, defaultValueHashes, fieldName, currentValue) {
|
|
555
|
+
let defaultHash = defaultValueHashes.get(fieldName);
|
|
556
|
+
if (defaultHash === void 0) {
|
|
557
|
+
defaultHash = hashValue(get(defaultValues, fieldName));
|
|
558
|
+
defaultValueHashes.set(fieldName, defaultHash);
|
|
559
|
+
}
|
|
560
|
+
const isDirty = hashValue(currentValue) !== defaultHash;
|
|
561
|
+
const wasDirty = dirtyFields.value[fieldName] === true;
|
|
562
|
+
if (isDirty && !wasDirty) dirtyFields.value = {
|
|
563
|
+
...dirtyFields.value,
|
|
564
|
+
[fieldName]: true
|
|
565
|
+
};
|
|
566
|
+
else if (!isDirty && wasDirty) {
|
|
567
|
+
const newDirty = { ...dirtyFields.value };
|
|
568
|
+
delete newDirty[fieldName];
|
|
569
|
+
dirtyFields.value = newDirty;
|
|
570
|
+
}
|
|
449
571
|
}
|
|
450
572
|
function setValidating(ctx, fieldPath, isValidating) {
|
|
451
573
|
const newSet = new Set(ctx.validatingFields.value);
|
|
@@ -486,7 +608,7 @@ function createFieldError(errors, criteriaMode = "firstError") {
|
|
|
486
608
|
function createValidation(ctx) {
|
|
487
609
|
function applyNativeValidation(fieldPath, errorMessage) {
|
|
488
610
|
if (!ctx.options.shouldUseNativeValidation) return;
|
|
489
|
-
const el = ctx.fieldRefs.get(fieldPath)?.value;
|
|
611
|
+
const el = getInputElement(ctx.fieldRefs.get(fieldPath)?.value);
|
|
490
612
|
if (el && "setCustomValidity" in el) el.setCustomValidity(errorMessage || "");
|
|
491
613
|
}
|
|
492
614
|
function clearAllNativeValidation() {
|
|
@@ -539,37 +661,43 @@ function createValidation(ctx) {
|
|
|
539
661
|
}
|
|
540
662
|
ctx.pendingErrors.delete(fieldPath);
|
|
541
663
|
applyNativeValidation(fieldPath, null);
|
|
542
|
-
|
|
664
|
+
if (ctx.persistentErrorFields.has(fieldPath)) return;
|
|
665
|
+
clearFieldErrors(ctx.errors, fieldPath);
|
|
543
666
|
}
|
|
544
667
|
function clearAllPendingErrors() {
|
|
545
668
|
for (const timer of ctx.errorDelayTimers.values()) clearTimeout(timer);
|
|
546
669
|
ctx.errorDelayTimers.clear();
|
|
547
670
|
ctx.pendingErrors.clear();
|
|
548
671
|
}
|
|
549
|
-
async function validateFieldPartial(fieldPath, subSchema, valueHash, criteriaMode, generationAtStart) {
|
|
672
|
+
async function validateFieldPartial(fieldPath, subSchema, valueHash, cacheKey, criteriaMode, generationAtStart) {
|
|
550
673
|
const fieldValue = get(ctx.formData, fieldPath);
|
|
551
674
|
setValidating(ctx, fieldPath, true);
|
|
552
675
|
try {
|
|
553
676
|
const result = await subSchema.safeParseAsync(fieldValue);
|
|
554
677
|
if (ctx.resetGeneration.value !== generationAtStart) return true;
|
|
555
678
|
if (result.success) {
|
|
556
|
-
|
|
557
|
-
if (valueHash) ctx.validationCache.set(
|
|
679
|
+
cancelError(fieldPath);
|
|
680
|
+
if (valueHash) ctx.validationCache.set(cacheKey, {
|
|
558
681
|
hash: valueHash,
|
|
559
682
|
isValid: true
|
|
560
683
|
});
|
|
561
684
|
return true;
|
|
562
685
|
}
|
|
563
|
-
const
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
686
|
+
const fieldSegments = fieldPath.split(".");
|
|
687
|
+
const fieldErrors = result.error.issues.map((issue) => {
|
|
688
|
+
const issuePath = issue.path.map(String);
|
|
689
|
+
const alreadyPrefixed = issuePath.length >= fieldSegments.length && fieldSegments.every((seg, i) => issuePath[i] === seg);
|
|
690
|
+
return {
|
|
691
|
+
...issue,
|
|
692
|
+
path: alreadyPrefixed ? issuePath : fieldSegments.concat(issuePath)
|
|
693
|
+
};
|
|
694
|
+
});
|
|
695
|
+
cancelError(fieldPath);
|
|
568
696
|
const grouped = groupErrorsByPath(fieldErrors);
|
|
569
697
|
const errorBatch = [];
|
|
570
698
|
for (const [path, errors] of grouped) errorBatch.push([path, createFieldError(errors, criteriaMode)]);
|
|
571
699
|
scheduleErrorsBatch(errorBatch);
|
|
572
|
-
if (valueHash) ctx.validationCache.set(
|
|
700
|
+
if (valueHash) ctx.validationCache.set(cacheKey, {
|
|
573
701
|
hash: valueHash,
|
|
574
702
|
isValid: false
|
|
575
703
|
});
|
|
@@ -578,14 +706,14 @@ function createValidation(ctx) {
|
|
|
578
706
|
setValidating(ctx, fieldPath, false);
|
|
579
707
|
}
|
|
580
708
|
}
|
|
581
|
-
async function validateFieldFull(fieldPath, valueHash, criteriaMode, generationAtStart) {
|
|
709
|
+
async function validateFieldFull(fieldPath, valueHash, cacheKey, criteriaMode, generationAtStart) {
|
|
582
710
|
setValidating(ctx, fieldPath, true);
|
|
583
711
|
try {
|
|
584
712
|
const result = await ctx.options.schema.safeParseAsync(ctx.formData);
|
|
585
713
|
if (ctx.resetGeneration.value !== generationAtStart) return true;
|
|
586
714
|
if (result.success) {
|
|
587
|
-
|
|
588
|
-
if (valueHash) ctx.validationCache.set(
|
|
715
|
+
cancelError(fieldPath);
|
|
716
|
+
if (valueHash) ctx.validationCache.set(cacheKey, {
|
|
589
717
|
hash: valueHash,
|
|
590
718
|
isValid: true
|
|
591
719
|
});
|
|
@@ -596,19 +724,19 @@ function createValidation(ctx) {
|
|
|
596
724
|
return path === fieldPath || path.startsWith(`${fieldPath}.`);
|
|
597
725
|
});
|
|
598
726
|
if (fieldErrors.length === 0) {
|
|
599
|
-
|
|
600
|
-
if (valueHash) ctx.validationCache.set(
|
|
727
|
+
cancelError(fieldPath);
|
|
728
|
+
if (valueHash) ctx.validationCache.set(cacheKey, {
|
|
601
729
|
hash: valueHash,
|
|
602
730
|
isValid: true
|
|
603
731
|
});
|
|
604
732
|
return true;
|
|
605
733
|
}
|
|
606
|
-
|
|
734
|
+
cancelError(fieldPath);
|
|
607
735
|
const grouped = groupErrorsByPath(fieldErrors);
|
|
608
736
|
const errorBatch = [];
|
|
609
737
|
for (const [path, errors] of grouped) errorBatch.push([path, createFieldError(errors, criteriaMode)]);
|
|
610
738
|
scheduleErrorsBatch(errorBatch);
|
|
611
|
-
if (valueHash) ctx.validationCache.set(
|
|
739
|
+
if (valueHash) ctx.validationCache.set(cacheKey, {
|
|
612
740
|
hash: valueHash,
|
|
613
741
|
isValid: false
|
|
614
742
|
});
|
|
@@ -623,14 +751,16 @@ function createValidation(ctx) {
|
|
|
623
751
|
let valueHash;
|
|
624
752
|
if (fieldPath) {
|
|
625
753
|
valueHash = hashValue(get(ctx.formData, fieldPath));
|
|
626
|
-
const cached = ctx.validationCache.get(fieldPath);
|
|
627
|
-
if (cached && cached.hash === valueHash) {
|
|
628
|
-
if (cached.isValid) ctx.errors.value = cancelError(fieldPath);
|
|
629
|
-
return cached.isValid;
|
|
630
|
-
}
|
|
631
754
|
const analysis = analyzeSchemaPath(ctx.options.schema, fieldPath);
|
|
632
|
-
|
|
633
|
-
|
|
755
|
+
const usePartial = analysis.canPartialValidate && analysis.subSchema;
|
|
756
|
+
const cacheKey = `${fieldPath}:${usePartial ? "partial" : "full"}`;
|
|
757
|
+
const cached = ctx.validationCache.get(cacheKey);
|
|
758
|
+
if (cached && cached.hash === valueHash && cached.isValid) {
|
|
759
|
+
cancelError(fieldPath);
|
|
760
|
+
return true;
|
|
761
|
+
}
|
|
762
|
+
if (usePartial) return validateFieldPartial(fieldPath, analysis.subSchema, valueHash, cacheKey, criteriaMode, generationAtStart);
|
|
763
|
+
return validateFieldFull(fieldPath, valueHash, cacheKey, criteriaMode, generationAtStart);
|
|
634
764
|
}
|
|
635
765
|
const validatingKey = "_form";
|
|
636
766
|
setValidating(ctx, validatingKey, true);
|
|
@@ -661,47 +791,31 @@ function createValidation(ctx) {
|
|
|
661
791
|
clearAllPendingErrors
|
|
662
792
|
};
|
|
663
793
|
}
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
794
|
+
var VALID_MODES = [
|
|
795
|
+
"onSubmit",
|
|
796
|
+
"onBlur",
|
|
797
|
+
"onChange",
|
|
798
|
+
"onTouched"
|
|
799
|
+
];
|
|
800
|
+
function validateMode(mode, paramName) {
|
|
801
|
+
if (__DEV__ && !VALID_MODES.includes(mode)) warnOnce(`Invalid ${paramName}: "${mode}". Expected one of: ${VALID_MODES.join(", ")}`, `invalid-mode-${mode}`);
|
|
671
802
|
}
|
|
672
|
-
function
|
|
673
|
-
if (
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
if (!(fieldName in dirtyFields.value)) return;
|
|
682
|
-
const newDirty = { ...dirtyFields.value };
|
|
683
|
-
delete newDirty[fieldName];
|
|
684
|
-
dirtyFields.value = newDirty;
|
|
685
|
-
dirtyFieldCount.value--;
|
|
686
|
-
}
|
|
687
|
-
function clearFieldTouched(touchedFields, touchedFieldCount, fieldName) {
|
|
688
|
-
if (!(fieldName in touchedFields.value)) return;
|
|
689
|
-
const newTouched = { ...touchedFields.value };
|
|
690
|
-
delete newTouched[fieldName];
|
|
691
|
-
touchedFields.value = newTouched;
|
|
692
|
-
touchedFieldCount.value--;
|
|
803
|
+
function shouldValidateOnChange(mode, isTouched, reValidateMode, hasSubmitted) {
|
|
804
|
+
if (__DEV__) {
|
|
805
|
+
validateMode(mode, "validation mode");
|
|
806
|
+
if (reValidateMode) validateMode(reValidateMode, "reValidateMode");
|
|
807
|
+
}
|
|
808
|
+
if (mode === "onChange") return true;
|
|
809
|
+
if (mode === "onTouched" && isTouched) return true;
|
|
810
|
+
if (hasSubmitted === true && reValidateMode === "onChange") return true;
|
|
811
|
+
return false;
|
|
693
812
|
}
|
|
694
|
-
function
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
for (const key of keys) if (key === fieldName || key.startsWith(prefix)) keysToDelete.push(key);
|
|
701
|
-
if (keysToDelete.length === 0) return;
|
|
702
|
-
const newErrors = { ...currentErrors };
|
|
703
|
-
for (const key of keysToDelete) delete newErrors[key];
|
|
704
|
-
errors.value = newErrors;
|
|
813
|
+
function shouldValidateOnBlur(mode, hasSubmitted, reValidateMode) {
|
|
814
|
+
if (__DEV__) {
|
|
815
|
+
validateMode(mode, "validation mode");
|
|
816
|
+
if (reValidateMode) validateMode(reValidateMode, "reValidateMode");
|
|
817
|
+
}
|
|
818
|
+
return mode === "onBlur" || mode === "onTouched" || hasSubmitted && (reValidateMode === "onBlur" || reValidateMode === "onTouched");
|
|
705
819
|
}
|
|
706
820
|
var validationRequestCounter = 0;
|
|
707
821
|
function createFieldRegistration(ctx, validate) {
|
|
@@ -742,11 +856,14 @@ function createFieldRegistration(ctx, validate) {
|
|
|
742
856
|
};
|
|
743
857
|
const onInput = async (e) => {
|
|
744
858
|
const target = e.target;
|
|
745
|
-
|
|
859
|
+
let value;
|
|
860
|
+
if (target.type === "checkbox") value = target.checked;
|
|
861
|
+
else if (target.type === "number" || target.type === "range") value = target.valueAsNumber;
|
|
862
|
+
else value = target.value;
|
|
746
863
|
set(ctx.formData, name, value);
|
|
747
|
-
|
|
864
|
+
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, value);
|
|
748
865
|
const fieldOpts = ctx.fieldOptions.get(name);
|
|
749
|
-
if (ctx.options.mode
|
|
866
|
+
if (shouldValidateOnChange(ctx.options.mode ?? "onSubmit", ctx.touchedFields.value[name] === true, ctx.options.reValidateMode, ctx.submitCount.value > 0)) {
|
|
750
867
|
const validationDebounceMs = ctx.options.validationDebounce || 0;
|
|
751
868
|
if (validationDebounceMs > 0) {
|
|
752
869
|
const existingTimer = ctx.schemaValidationTimers.get(name);
|
|
@@ -779,15 +896,18 @@ function createFieldRegistration(ctx, validate) {
|
|
|
779
896
|
const timer = setTimeout(async () => {
|
|
780
897
|
ctx.debounceTimers.delete(name);
|
|
781
898
|
await runCustomValidation(name, value, requestId, resetGenAtStart);
|
|
782
|
-
ctx.validationRequestIds.delete(name);
|
|
899
|
+
if (ctx.validationRequestIds.get(name) === requestId) ctx.validationRequestIds.delete(name);
|
|
783
900
|
}, debounceMs);
|
|
784
901
|
ctx.debounceTimers.set(name, timer);
|
|
785
|
-
} else
|
|
902
|
+
} else {
|
|
903
|
+
await runCustomValidation(name, value, requestId, resetGenAtStart);
|
|
904
|
+
if (ctx.validationRequestIds.get(name) === requestId) ctx.validationRequestIds.delete(name);
|
|
905
|
+
}
|
|
786
906
|
}
|
|
787
907
|
};
|
|
788
|
-
const onBlur = async (
|
|
789
|
-
markFieldTouched(ctx.touchedFields,
|
|
790
|
-
if (ctx.options.mode
|
|
908
|
+
const onBlur = async () => {
|
|
909
|
+
markFieldTouched(ctx.touchedFields, name);
|
|
910
|
+
if (shouldValidateOnBlur(ctx.options.mode ?? "onSubmit", ctx.submitCount.value > 0, ctx.options.reValidateMode)) {
|
|
791
911
|
await validate(name);
|
|
792
912
|
const fieldOpts = ctx.fieldOptions.get(name);
|
|
793
913
|
if (fieldOpts?.deps && fieldOpts.deps.length > 0) {
|
|
@@ -804,10 +924,11 @@ function createFieldRegistration(ctx, validate) {
|
|
|
804
924
|
if (previousEl && el) return;
|
|
805
925
|
currentFieldRef.value = el;
|
|
806
926
|
const opts = ctx.fieldOptions.get(name);
|
|
807
|
-
|
|
927
|
+
const inputEl = getInputElement(el);
|
|
928
|
+
if (inputEl && !opts?.controlled) {
|
|
808
929
|
const value = get(ctx.formData, name);
|
|
809
|
-
if (value !== void 0) if (
|
|
810
|
-
else
|
|
930
|
+
if (value !== void 0) if (inputEl.type === "checkbox") inputEl.checked = value;
|
|
931
|
+
else inputEl.value = value;
|
|
811
932
|
}
|
|
812
933
|
if (previousEl && !el) {
|
|
813
934
|
const timer = ctx.debounceTimers.get(name);
|
|
@@ -820,15 +941,21 @@ function createFieldRegistration(ctx, validate) {
|
|
|
820
941
|
clearTimeout(schemaTimer);
|
|
821
942
|
ctx.schemaValidationTimers.delete(name);
|
|
822
943
|
}
|
|
944
|
+
const errorTimer = ctx.errorDelayTimers.get(name);
|
|
945
|
+
if (errorTimer) {
|
|
946
|
+
clearTimeout(errorTimer);
|
|
947
|
+
ctx.errorDelayTimers.delete(name);
|
|
948
|
+
}
|
|
949
|
+
ctx.pendingErrors.delete(name);
|
|
823
950
|
ctx.validationRequestIds.delete(name);
|
|
951
|
+
ctx.fieldRefs.delete(name);
|
|
952
|
+
ctx.fieldOptions.delete(name);
|
|
953
|
+
ctx.fieldHandlers.delete(name);
|
|
824
954
|
if (opts?.shouldUnregister ?? ctx.options.shouldUnregister ?? false) {
|
|
825
955
|
unset(ctx.formData, name);
|
|
826
956
|
clearFieldErrors(ctx.errors, name);
|
|
827
|
-
clearFieldTouched(ctx.touchedFields,
|
|
828
|
-
clearFieldDirty(ctx.dirtyFields,
|
|
829
|
-
ctx.fieldRefs.delete(name);
|
|
830
|
-
ctx.fieldOptions.delete(name);
|
|
831
|
-
ctx.fieldHandlers.delete(name);
|
|
957
|
+
clearFieldTouched(ctx.touchedFields, name);
|
|
958
|
+
clearFieldDirty(ctx.dirtyFields, name);
|
|
832
959
|
}
|
|
833
960
|
}
|
|
834
961
|
};
|
|
@@ -849,7 +976,7 @@ function createFieldRegistration(ctx, validate) {
|
|
|
849
976
|
get: () => get(ctx.formData, name),
|
|
850
977
|
set: (val) => {
|
|
851
978
|
set(ctx.formData, name, val);
|
|
852
|
-
|
|
979
|
+
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, val);
|
|
853
980
|
}
|
|
854
981
|
}) }
|
|
855
982
|
};
|
|
@@ -858,8 +985,8 @@ function createFieldRegistration(ctx, validate) {
|
|
|
858
985
|
const opts = options || {};
|
|
859
986
|
if (!opts.keepValue) unset(ctx.formData, name);
|
|
860
987
|
if (!opts.keepError) clearFieldErrors(ctx.errors, name);
|
|
861
|
-
if (!opts.keepTouched) clearFieldTouched(ctx.touchedFields,
|
|
862
|
-
if (!opts.keepDirty) clearFieldDirty(ctx.dirtyFields,
|
|
988
|
+
if (!opts.keepTouched) clearFieldTouched(ctx.touchedFields, name);
|
|
989
|
+
if (!opts.keepDirty) clearFieldDirty(ctx.dirtyFields, name);
|
|
863
990
|
ctx.fieldRefs.delete(name);
|
|
864
991
|
ctx.fieldOptions.delete(name);
|
|
865
992
|
ctx.fieldHandlers.delete(name);
|
|
@@ -874,6 +1001,8 @@ function createFieldRegistration(ctx, validate) {
|
|
|
874
1001
|
ctx.schemaValidationTimers.delete(name);
|
|
875
1002
|
}
|
|
876
1003
|
ctx.validationRequestIds.delete(name);
|
|
1004
|
+
ctx.validationCache.delete(`${name}:partial`);
|
|
1005
|
+
ctx.validationCache.delete(`${name}:full`);
|
|
877
1006
|
}
|
|
878
1007
|
return {
|
|
879
1008
|
register,
|
|
@@ -909,20 +1038,6 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
909
1038
|
indexCache.set(item.key, idx);
|
|
910
1039
|
});
|
|
911
1040
|
};
|
|
912
|
-
const appendToCache = (startIndex) => {
|
|
913
|
-
const items = fa.items.value;
|
|
914
|
-
for (let i = startIndex; i < items.length; i++) {
|
|
915
|
-
const item = items[i];
|
|
916
|
-
if (item) indexCache.set(item.key, i);
|
|
917
|
-
}
|
|
918
|
-
};
|
|
919
|
-
const updateCacheAfterInsert = (insertIndex, _insertCount) => {
|
|
920
|
-
const items = fa.items.value;
|
|
921
|
-
for (let i = insertIndex; i < items.length; i++) {
|
|
922
|
-
const item = items[i];
|
|
923
|
-
if (item) indexCache.set(item.key, i);
|
|
924
|
-
}
|
|
925
|
-
};
|
|
926
1041
|
const swapInCache = (indexA, indexB) => {
|
|
927
1042
|
const items = fa.items.value;
|
|
928
1043
|
const itemA = items[indexA];
|
|
@@ -963,10 +1078,32 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
963
1078
|
const normalizeToArray = (value) => {
|
|
964
1079
|
return Array.isArray(value) ? value : [value];
|
|
965
1080
|
};
|
|
1081
|
+
const clearValidationCache = () => {
|
|
1082
|
+
for (const key of ctx.validationCache.keys()) {
|
|
1083
|
+
const colonIndex = key.lastIndexOf(":");
|
|
1084
|
+
const fieldPath = colonIndex > 0 ? key.slice(0, colonIndex) : key;
|
|
1085
|
+
if (fieldPath === name || fieldPath.startsWith(`${name}.`)) ctx.validationCache.delete(key);
|
|
1086
|
+
}
|
|
1087
|
+
};
|
|
1088
|
+
const validateIfNeeded = () => {
|
|
1089
|
+
const isTouched = ctx.touchedFields.value[name] === true;
|
|
1090
|
+
const hasSubmitted = ctx.submitCount.value > 0;
|
|
1091
|
+
if (shouldValidateOnChange(ctx.options.mode ?? "onSubmit", isTouched, ctx.options.reValidateMode, hasSubmitted)) validate(name);
|
|
1092
|
+
};
|
|
1093
|
+
const ensureSync = () => {
|
|
1094
|
+
const currentValues = get(ctx.formData, name) || [];
|
|
1095
|
+
if (fa.items.value.length !== currentValues.length) {
|
|
1096
|
+
if (__DEV__) console.warn(`[vue-hook-form] Field array out of sync with formData. Rebuilding items array (items: ${fa.items.value.length}, formData: ${currentValues.length})`);
|
|
1097
|
+
fa.items.value = currentValues.map(() => createItem(generateId()));
|
|
1098
|
+
rebuildIndexCache();
|
|
1099
|
+
}
|
|
1100
|
+
return currentValues;
|
|
1101
|
+
};
|
|
966
1102
|
const append = (value, focusOptions) => {
|
|
1103
|
+
clearValidationCache();
|
|
967
1104
|
const values = normalizeToArray(value);
|
|
968
1105
|
if (values.length === 0) return true;
|
|
969
|
-
const currentValues =
|
|
1106
|
+
const currentValues = ensureSync();
|
|
970
1107
|
const insertIndex = currentValues.length;
|
|
971
1108
|
const rules = fa.rules;
|
|
972
1109
|
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) {
|
|
@@ -979,17 +1116,22 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
979
1116
|
const newValues = [...currentValues, ...values];
|
|
980
1117
|
set(ctx.formData, name, newValues);
|
|
981
1118
|
const newItems = values.map(() => createItem(generateId()));
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1119
|
+
const newItemsArray = [...fa.items.value, ...newItems];
|
|
1120
|
+
for (let i = insertIndex; i < newItemsArray.length; i++) {
|
|
1121
|
+
const item = newItemsArray[i];
|
|
1122
|
+
if (item) indexCache.set(item.key, i);
|
|
1123
|
+
}
|
|
1124
|
+
fa.items.value = newItemsArray;
|
|
1125
|
+
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1126
|
+
validateIfNeeded();
|
|
986
1127
|
handleFocus(insertIndex, values.length, focusOptions);
|
|
987
1128
|
return true;
|
|
988
1129
|
};
|
|
989
1130
|
const prepend = (value, focusOptions) => {
|
|
1131
|
+
clearValidationCache();
|
|
990
1132
|
const values = normalizeToArray(value);
|
|
991
1133
|
if (values.length === 0) return true;
|
|
992
|
-
const currentValues =
|
|
1134
|
+
const currentValues = ensureSync();
|
|
993
1135
|
const rules = fa.rules;
|
|
994
1136
|
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) {
|
|
995
1137
|
if (__DEV__) warnArrayOperationRejected("prepend", name, "maxLength", {
|
|
@@ -1000,16 +1142,20 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
1000
1142
|
}
|
|
1001
1143
|
const newValues = [...values, ...currentValues];
|
|
1002
1144
|
set(ctx.formData, name, newValues);
|
|
1003
|
-
const
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1145
|
+
const newItemsArray = [...values.map(() => createItem(generateId())), ...fa.items.value];
|
|
1146
|
+
for (let i = 0; i < newItemsArray.length; i++) {
|
|
1147
|
+
const item = newItemsArray[i];
|
|
1148
|
+
if (item) indexCache.set(item.key, i);
|
|
1149
|
+
}
|
|
1150
|
+
fa.items.value = newItemsArray;
|
|
1151
|
+
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1152
|
+
validateIfNeeded();
|
|
1008
1153
|
handleFocus(0, values.length, focusOptions);
|
|
1009
1154
|
return true;
|
|
1010
1155
|
};
|
|
1011
1156
|
const update = (index, value) => {
|
|
1012
|
-
|
|
1157
|
+
clearValidationCache();
|
|
1158
|
+
const currentValues = ensureSync();
|
|
1013
1159
|
if (index < 0 || index >= currentValues.length) {
|
|
1014
1160
|
if (__DEV__) warnArrayIndexOutOfBounds("update", name, index, currentValues.length);
|
|
1015
1161
|
return false;
|
|
@@ -1017,12 +1163,13 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
1017
1163
|
const newValues = [...currentValues];
|
|
1018
1164
|
newValues[index] = value;
|
|
1019
1165
|
set(ctx.formData, name, newValues);
|
|
1020
|
-
|
|
1021
|
-
|
|
1166
|
+
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1167
|
+
validateIfNeeded();
|
|
1022
1168
|
return true;
|
|
1023
1169
|
};
|
|
1024
1170
|
const removeAt = (index) => {
|
|
1025
|
-
|
|
1171
|
+
clearValidationCache();
|
|
1172
|
+
const currentValues = ensureSync();
|
|
1026
1173
|
if (index < 0 || index >= currentValues.length) {
|
|
1027
1174
|
if (__DEV__) warnArrayIndexOutOfBounds("remove", name, index, currentValues.length);
|
|
1028
1175
|
return false;
|
|
@@ -1040,14 +1187,15 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
1040
1187
|
const keyToRemove = fa.items.value[index]?.key;
|
|
1041
1188
|
fa.items.value = fa.items.value.filter((item) => item.key !== keyToRemove);
|
|
1042
1189
|
if (keyToRemove) updateCacheAfterRemove(keyToRemove, index);
|
|
1043
|
-
|
|
1044
|
-
|
|
1190
|
+
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1191
|
+
validateIfNeeded();
|
|
1045
1192
|
return true;
|
|
1046
1193
|
};
|
|
1047
1194
|
const insert = (index, value, focusOptions) => {
|
|
1195
|
+
clearValidationCache();
|
|
1048
1196
|
const values = normalizeToArray(value);
|
|
1049
1197
|
if (values.length === 0) return true;
|
|
1050
|
-
const currentValues =
|
|
1198
|
+
const currentValues = ensureSync();
|
|
1051
1199
|
const rules = fa.rules;
|
|
1052
1200
|
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) {
|
|
1053
1201
|
if (__DEV__) warnArrayOperationRejected("insert", name, "maxLength", {
|
|
@@ -1056,27 +1204,35 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
1056
1204
|
});
|
|
1057
1205
|
return false;
|
|
1058
1206
|
}
|
|
1059
|
-
|
|
1207
|
+
if (index < 0 || index > currentValues.length) {
|
|
1208
|
+
if (__DEV__) warnArrayIndexOutOfBounds("insert", name, index, currentValues.length);
|
|
1209
|
+
return false;
|
|
1210
|
+
}
|
|
1060
1211
|
const newValues = [
|
|
1061
|
-
...currentValues.slice(0,
|
|
1212
|
+
...currentValues.slice(0, index),
|
|
1062
1213
|
...values,
|
|
1063
|
-
...currentValues.slice(
|
|
1214
|
+
...currentValues.slice(index)
|
|
1064
1215
|
];
|
|
1065
1216
|
set(ctx.formData, name, newValues);
|
|
1066
1217
|
const newItems = values.map(() => createItem(generateId()));
|
|
1067
|
-
|
|
1068
|
-
...fa.items.value.slice(0,
|
|
1218
|
+
const newItemsArray = [
|
|
1219
|
+
...fa.items.value.slice(0, index),
|
|
1069
1220
|
...newItems,
|
|
1070
|
-
...fa.items.value.slice(
|
|
1221
|
+
...fa.items.value.slice(index)
|
|
1071
1222
|
];
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1223
|
+
for (let i = index; i < newItemsArray.length; i++) {
|
|
1224
|
+
const item = newItemsArray[i];
|
|
1225
|
+
if (item) indexCache.set(item.key, i);
|
|
1226
|
+
}
|
|
1227
|
+
fa.items.value = newItemsArray;
|
|
1228
|
+
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1229
|
+
validateIfNeeded();
|
|
1230
|
+
handleFocus(index, values.length, focusOptions);
|
|
1076
1231
|
return true;
|
|
1077
1232
|
};
|
|
1078
1233
|
const swap = (indexA, indexB) => {
|
|
1079
|
-
|
|
1234
|
+
clearValidationCache();
|
|
1235
|
+
const currentValues = ensureSync();
|
|
1080
1236
|
if (indexA < 0 || indexB < 0 || indexA >= currentValues.length || indexB >= currentValues.length) {
|
|
1081
1237
|
if (__DEV__) warnArrayIndexOutOfBounds("swap", name, indexA < 0 || indexA >= currentValues.length ? indexA : indexB, currentValues.length);
|
|
1082
1238
|
return false;
|
|
@@ -1093,51 +1249,52 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
1093
1249
|
fa.items.value = newItems;
|
|
1094
1250
|
swapInCache(indexA, indexB);
|
|
1095
1251
|
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1252
|
+
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1253
|
+
validateIfNeeded();
|
|
1098
1254
|
return true;
|
|
1099
1255
|
};
|
|
1100
1256
|
const move = (from, to) => {
|
|
1101
|
-
|
|
1102
|
-
|
|
1257
|
+
clearValidationCache();
|
|
1258
|
+
const currentValues = ensureSync();
|
|
1259
|
+
if (from < 0 || from >= currentValues.length || to < 0 || to >= currentValues.length) {
|
|
1103
1260
|
if (__DEV__) warnArrayIndexOutOfBounds("move", name, from < 0 || from >= currentValues.length ? from : to, currentValues.length);
|
|
1104
1261
|
return false;
|
|
1105
1262
|
}
|
|
1106
1263
|
const newValues = [...currentValues];
|
|
1107
1264
|
const [removed] = newValues.splice(from, 1);
|
|
1108
1265
|
if (removed !== void 0) {
|
|
1109
|
-
|
|
1110
|
-
newValues.splice(clampedTo, 0, removed);
|
|
1266
|
+
newValues.splice(to, 0, removed);
|
|
1111
1267
|
set(ctx.formData, name, newValues);
|
|
1112
1268
|
}
|
|
1113
1269
|
const newItems = [...fa.items.value];
|
|
1114
1270
|
const [removedItem] = newItems.splice(from, 1);
|
|
1115
1271
|
if (removedItem) {
|
|
1116
|
-
|
|
1117
|
-
newItems.splice(clampedTo, 0, removedItem);
|
|
1272
|
+
newItems.splice(to, 0, removedItem);
|
|
1118
1273
|
fa.items.value = newItems;
|
|
1119
|
-
const minIdx = Math.min(from,
|
|
1120
|
-
const maxIdx = Math.max(from,
|
|
1274
|
+
const minIdx = Math.min(from, to);
|
|
1275
|
+
const maxIdx = Math.max(from, to);
|
|
1121
1276
|
const items = fa.items.value;
|
|
1122
1277
|
for (let i = minIdx; i <= maxIdx; i++) {
|
|
1123
1278
|
const item = items[i];
|
|
1124
1279
|
if (item) indexCache.set(item.key, i);
|
|
1125
1280
|
}
|
|
1126
1281
|
}
|
|
1127
|
-
|
|
1128
|
-
|
|
1282
|
+
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1283
|
+
validateIfNeeded();
|
|
1129
1284
|
return true;
|
|
1130
1285
|
};
|
|
1131
1286
|
const replace = (newValues) => {
|
|
1287
|
+
clearValidationCache();
|
|
1132
1288
|
if (!Array.isArray(newValues)) return false;
|
|
1133
1289
|
set(ctx.formData, name, newValues);
|
|
1134
1290
|
fa.items.value = newValues.map(() => createItem(generateId()));
|
|
1135
1291
|
rebuildIndexCache();
|
|
1136
|
-
|
|
1137
|
-
|
|
1292
|
+
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1293
|
+
validateIfNeeded();
|
|
1138
1294
|
return true;
|
|
1139
1295
|
};
|
|
1140
1296
|
const removeAll = () => {
|
|
1297
|
+
clearValidationCache();
|
|
1141
1298
|
const rules = fa.rules;
|
|
1142
1299
|
if (rules?.minLength && rules.minLength.value > 0) {
|
|
1143
1300
|
if (__DEV__) warnArrayOperationRejected("removeAll", name, "minLength", {
|
|
@@ -1149,12 +1306,13 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
1149
1306
|
set(ctx.formData, name, []);
|
|
1150
1307
|
fa.items.value = [];
|
|
1151
1308
|
indexCache.clear();
|
|
1152
|
-
|
|
1153
|
-
|
|
1309
|
+
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1310
|
+
validateIfNeeded();
|
|
1154
1311
|
return true;
|
|
1155
1312
|
};
|
|
1156
1313
|
const removeMany = (indices) => {
|
|
1157
|
-
|
|
1314
|
+
clearValidationCache();
|
|
1315
|
+
const currentValues = ensureSync();
|
|
1158
1316
|
const validIndices = indices.filter((i) => i >= 0 && i < currentValues.length);
|
|
1159
1317
|
if (validIndices.length === 0) return true;
|
|
1160
1318
|
const rules = fa.rules;
|
|
@@ -1176,12 +1334,14 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
1176
1334
|
fa.items.value.forEach((item, idx) => {
|
|
1177
1335
|
indexCache.set(item.key, idx);
|
|
1178
1336
|
});
|
|
1179
|
-
|
|
1180
|
-
|
|
1337
|
+
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1338
|
+
validateIfNeeded();
|
|
1181
1339
|
return true;
|
|
1182
1340
|
};
|
|
1183
1341
|
return {
|
|
1184
|
-
value
|
|
1342
|
+
get value() {
|
|
1343
|
+
return fa.items.value;
|
|
1344
|
+
},
|
|
1185
1345
|
append,
|
|
1186
1346
|
prepend,
|
|
1187
1347
|
remove: removeAt,
|
|
@@ -1196,20 +1356,16 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
1196
1356
|
}
|
|
1197
1357
|
return { fields };
|
|
1198
1358
|
}
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
if (el) {
|
|
1203
|
-
if (!fieldOptions.get(name)?.controlled) set(formData, name, el.type === "checkbox" ? el.checked : el.value);
|
|
1204
|
-
}
|
|
1205
|
-
}
|
|
1206
|
-
}
|
|
1207
|
-
function updateDomElement(el, value) {
|
|
1208
|
-
if (el.type === "checkbox") el.checked = value;
|
|
1209
|
-
else el.value = value;
|
|
1359
|
+
var isCalledFromController = false;
|
|
1360
|
+
function setCalledFromController(value) {
|
|
1361
|
+
isCalledFromController = value;
|
|
1210
1362
|
}
|
|
1211
1363
|
function useForm(options) {
|
|
1212
1364
|
const ctx = createFormContext(options);
|
|
1365
|
+
let isSubmissionLocked = false;
|
|
1366
|
+
(0, vue.onScopeDispose)(() => {
|
|
1367
|
+
ctx.cleanup();
|
|
1368
|
+
});
|
|
1213
1369
|
const { validate, clearAllPendingErrors } = createValidation(ctx);
|
|
1214
1370
|
const { register, unregister } = createFieldRegistration(ctx, validate);
|
|
1215
1371
|
function setFocus(name, focusOptions) {
|
|
@@ -1223,11 +1379,10 @@ function useForm(options) {
|
|
|
1223
1379
|
}
|
|
1224
1380
|
const fieldRef = ctx.fieldRefs.get(name);
|
|
1225
1381
|
if (!fieldRef?.value) return;
|
|
1226
|
-
const el = fieldRef.value;
|
|
1227
|
-
if (
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
}
|
|
1382
|
+
const el = getFocusableElement(fieldRef.value);
|
|
1383
|
+
if (!el) return;
|
|
1384
|
+
el.focus();
|
|
1385
|
+
if (focusOptions?.shouldSelect && el instanceof HTMLInputElement && typeof el.select === "function") el.select();
|
|
1231
1386
|
}
|
|
1232
1387
|
const setFocusWrapper = (name) => setFocus(name);
|
|
1233
1388
|
const { fields } = createFieldArrayManager(ctx, validate, setFocusWrapper);
|
|
@@ -1252,10 +1407,10 @@ function useForm(options) {
|
|
|
1252
1407
|
};
|
|
1253
1408
|
return cachedMergedErrors;
|
|
1254
1409
|
}
|
|
1255
|
-
const isDirtyComputed = (0, vue.computed)(() => ctx.
|
|
1410
|
+
const isDirtyComputed = (0, vue.computed)(() => Object.keys(ctx.dirtyFields.value).length > 0);
|
|
1256
1411
|
const errorsComputed = (0, vue.computed)(() => getMergedErrors());
|
|
1257
1412
|
const isValidComputed = (0, vue.computed)(() => {
|
|
1258
|
-
if (!(ctx.submitCount.value > 0 || ctx.
|
|
1413
|
+
if (!(ctx.submitCount.value > 0 || Object.keys(ctx.touchedFields.value).length > 0)) return false;
|
|
1259
1414
|
return Object.keys(errorsComputed.value).length === 0;
|
|
1260
1415
|
});
|
|
1261
1416
|
const isReadyComputed = (0, vue.computed)(() => !ctx.isLoading.value);
|
|
@@ -1313,7 +1468,8 @@ function useForm(options) {
|
|
|
1313
1468
|
return async (e) => {
|
|
1314
1469
|
e.preventDefault();
|
|
1315
1470
|
if (ctx.isDisabled.value) return;
|
|
1316
|
-
if (
|
|
1471
|
+
if (isSubmissionLocked) return;
|
|
1472
|
+
isSubmissionLocked = true;
|
|
1317
1473
|
ctx.isSubmitting.value = true;
|
|
1318
1474
|
ctx.submitCount.value++;
|
|
1319
1475
|
ctx.isSubmitSuccessful.value = false;
|
|
@@ -1331,6 +1487,7 @@ function useForm(options) {
|
|
|
1331
1487
|
}
|
|
1332
1488
|
} finally {
|
|
1333
1489
|
ctx.isSubmitting.value = false;
|
|
1490
|
+
isSubmissionLocked = false;
|
|
1334
1491
|
}
|
|
1335
1492
|
};
|
|
1336
1493
|
}
|
|
@@ -1344,8 +1501,9 @@ function useForm(options) {
|
|
|
1344
1501
|
}
|
|
1345
1502
|
}
|
|
1346
1503
|
set(ctx.formData, name, value);
|
|
1347
|
-
if (setValueOptions?.shouldDirty
|
|
1348
|
-
|
|
1504
|
+
if (setValueOptions?.shouldDirty === false) clearFieldDirty(ctx.dirtyFields, name);
|
|
1505
|
+
else updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, value);
|
|
1506
|
+
if (setValueOptions?.shouldTouch) markFieldTouched(ctx.touchedFields, name);
|
|
1349
1507
|
if (!ctx.fieldOptions.get(name)?.controlled) {
|
|
1350
1508
|
const fieldRef = ctx.fieldRefs.get(name);
|
|
1351
1509
|
if (fieldRef?.value) updateDomElement(fieldRef.value, value);
|
|
@@ -1354,31 +1512,34 @@ function useForm(options) {
|
|
|
1354
1512
|
}
|
|
1355
1513
|
function reset(values, resetOptions) {
|
|
1356
1514
|
const opts = resetOptions || {};
|
|
1515
|
+
ctx.validationCache.clear();
|
|
1357
1516
|
ctx.resetGeneration.value++;
|
|
1358
1517
|
clearAllPendingErrors();
|
|
1359
1518
|
ctx.validatingFields.value = /* @__PURE__ */ new Set();
|
|
1360
|
-
ctx.validationCache.clear();
|
|
1361
1519
|
for (const timer of ctx.schemaValidationTimers.values()) clearTimeout(timer);
|
|
1362
1520
|
ctx.schemaValidationTimers.clear();
|
|
1363
|
-
|
|
1521
|
+
for (const timer of ctx.debounceTimers.values()) clearTimeout(timer);
|
|
1522
|
+
ctx.debounceTimers.clear();
|
|
1523
|
+
ctx.validationRequestIds.clear();
|
|
1524
|
+
if (!opts.keepDefaultValues && values) {
|
|
1525
|
+
Object.assign(ctx.defaultValues, values);
|
|
1526
|
+
ctx.defaultValueHashes.clear();
|
|
1527
|
+
}
|
|
1364
1528
|
Object.keys(ctx.formData).forEach((key) => delete ctx.formData[key]);
|
|
1365
1529
|
const newValues = deepClone(values || ctx.defaultValues);
|
|
1366
1530
|
Object.assign(ctx.formData, newValues);
|
|
1367
|
-
if (!opts.keepErrors)
|
|
1368
|
-
|
|
1369
|
-
ctx.
|
|
1370
|
-
ctx.touchedFieldCount.value = 0;
|
|
1371
|
-
}
|
|
1372
|
-
if (!opts.keepDirty) {
|
|
1373
|
-
ctx.dirtyFields.value = {};
|
|
1374
|
-
ctx.dirtyFieldCount.value = 0;
|
|
1531
|
+
if (!opts.keepErrors) {
|
|
1532
|
+
ctx.errors.value = {};
|
|
1533
|
+
ctx.persistentErrorFields.clear();
|
|
1375
1534
|
}
|
|
1535
|
+
if (!opts.keepTouched) ctx.touchedFields.value = {};
|
|
1536
|
+
if (!opts.keepDirty) ctx.dirtyFields.value = {};
|
|
1376
1537
|
if (!opts.keepSubmitCount) ctx.submitCount.value = 0;
|
|
1377
1538
|
if (!opts.keepIsSubmitting) ctx.isSubmitting.value = false;
|
|
1378
1539
|
if (!opts.keepIsSubmitSuccessful) ctx.isSubmitSuccessful.value = false;
|
|
1379
1540
|
ctx.fieldArrays.clear();
|
|
1380
1541
|
for (const [name, fieldRef] of Array.from(ctx.fieldRefs.entries())) {
|
|
1381
|
-
const el = fieldRef.value;
|
|
1542
|
+
const el = getInputElement(fieldRef.value);
|
|
1382
1543
|
if (el) {
|
|
1383
1544
|
const value = get(newValues, name);
|
|
1384
1545
|
if (value !== void 0) if (el.type === "checkbox") el.checked = value;
|
|
@@ -1397,6 +1558,8 @@ function useForm(options) {
|
|
|
1397
1558
|
}
|
|
1398
1559
|
const opts = resetFieldOptions || {};
|
|
1399
1560
|
ctx.resetGeneration.value++;
|
|
1561
|
+
ctx.validationCache.delete(`${name}:partial`);
|
|
1562
|
+
ctx.validationCache.delete(`${name}:full`);
|
|
1400
1563
|
const errorTimer = ctx.errorDelayTimers.get(name);
|
|
1401
1564
|
if (errorTimer) {
|
|
1402
1565
|
clearTimeout(errorTimer);
|
|
@@ -1405,15 +1568,21 @@ function useForm(options) {
|
|
|
1405
1568
|
ctx.pendingErrors.delete(name);
|
|
1406
1569
|
let defaultValue = opts.defaultValue;
|
|
1407
1570
|
if (defaultValue === void 0) defaultValue = get(ctx.defaultValues, name);
|
|
1408
|
-
else
|
|
1571
|
+
else {
|
|
1572
|
+
set(ctx.defaultValues, name, defaultValue);
|
|
1573
|
+
ctx.defaultValueHashes.set(name, hashValue(defaultValue));
|
|
1574
|
+
}
|
|
1409
1575
|
const clonedValue = defaultValue !== void 0 ? deepClone(defaultValue) : void 0;
|
|
1410
1576
|
set(ctx.formData, name, clonedValue);
|
|
1411
1577
|
if (!opts.keepError) clearFieldErrors(ctx.errors, name);
|
|
1412
|
-
if (!opts.keepDirty) clearFieldDirty(ctx.dirtyFields,
|
|
1413
|
-
if (!opts.keepTouched) clearFieldTouched(ctx.touchedFields,
|
|
1578
|
+
if (!opts.keepDirty) clearFieldDirty(ctx.dirtyFields, name);
|
|
1579
|
+
if (!opts.keepTouched) clearFieldTouched(ctx.touchedFields, name);
|
|
1414
1580
|
if (!ctx.fieldOptions.get(name)?.controlled) {
|
|
1415
1581
|
const fieldRef = ctx.fieldRefs.get(name);
|
|
1416
|
-
if (fieldRef?.value)
|
|
1582
|
+
if (fieldRef?.value) {
|
|
1583
|
+
const el = getInputElement(fieldRef.value);
|
|
1584
|
+
updateDomElement(fieldRef.value, clonedValue ?? (el?.type === "checkbox" ? false : ""));
|
|
1585
|
+
}
|
|
1417
1586
|
}
|
|
1418
1587
|
}
|
|
1419
1588
|
function watch$1(name) {
|
|
@@ -1453,10 +1622,16 @@ function useForm(options) {
|
|
|
1453
1622
|
}
|
|
1454
1623
|
if (name === void 0) {
|
|
1455
1624
|
ctx.errors.value = {};
|
|
1625
|
+
ctx.externalErrors.value = {};
|
|
1626
|
+
ctx.persistentErrorFields.clear();
|
|
1456
1627
|
return;
|
|
1457
1628
|
}
|
|
1458
1629
|
const fieldsToClean = Array.isArray(name) ? name : [name];
|
|
1459
|
-
for (const field of fieldsToClean)
|
|
1630
|
+
for (const field of fieldsToClean) {
|
|
1631
|
+
clearFieldErrors(ctx.errors, field);
|
|
1632
|
+
clearFieldErrors(ctx.externalErrors, field);
|
|
1633
|
+
ctx.persistentErrorFields.delete(field);
|
|
1634
|
+
}
|
|
1460
1635
|
}
|
|
1461
1636
|
function setError(name, error) {
|
|
1462
1637
|
const newErrors = { ...ctx.errors.value };
|
|
@@ -1465,6 +1640,7 @@ function useForm(options) {
|
|
|
1465
1640
|
message: error.message
|
|
1466
1641
|
} : error.message);
|
|
1467
1642
|
ctx.errors.value = newErrors;
|
|
1643
|
+
if (error.persistent) ctx.persistentErrorFields.add(name);
|
|
1468
1644
|
}
|
|
1469
1645
|
function setErrors(errors, options$1) {
|
|
1470
1646
|
const newErrors = options$1?.shouldReplace ? {} : { ...ctx.errors.value };
|
|
@@ -1517,6 +1693,7 @@ function useForm(options) {
|
|
|
1517
1693
|
const schemaResult = validatePathAgainstSchema(ctx.options.schema, name);
|
|
1518
1694
|
if (!schemaResult.valid) warnPathNotInSchema("getFieldState", name, schemaResult.availableFields);
|
|
1519
1695
|
}
|
|
1696
|
+
if ((0, vue.getCurrentInstance)() && !isCalledFromController) console.warn(`[vue-hook-form] getFieldState('${name}') returns a snapshot, not reactive refs.\nFor reactive error display, use one of these alternatives:\n • formState.value.errors.${name}\n • const { fieldState } = useController({ name: '${name}', control })\n • const ${name}Error = computed(() => formState.value.errors.${name})\n\nSee docs: https://github.com/vuehookform/core#common-mistakes`);
|
|
1520
1697
|
}
|
|
1521
1698
|
const error = get(ctx.errors.value, name);
|
|
1522
1699
|
return {
|
|
@@ -1526,7 +1703,7 @@ function useForm(options) {
|
|
|
1526
1703
|
error
|
|
1527
1704
|
};
|
|
1528
1705
|
}
|
|
1529
|
-
async function trigger(name) {
|
|
1706
|
+
async function trigger(name, options$1) {
|
|
1530
1707
|
if (__DEV__ && name) {
|
|
1531
1708
|
const names = Array.isArray(name) ? name : [name];
|
|
1532
1709
|
for (const n of names) {
|
|
@@ -1538,6 +1715,7 @@ function useForm(options) {
|
|
|
1538
1715
|
}
|
|
1539
1716
|
}
|
|
1540
1717
|
}
|
|
1718
|
+
if (options$1?.markAsSubmitted) ctx.submitCount.value++;
|
|
1541
1719
|
if (name === void 0) return await validate();
|
|
1542
1720
|
if (Array.isArray(name)) {
|
|
1543
1721
|
let allValid = true;
|
|
@@ -1565,7 +1743,11 @@ function useForm(options) {
|
|
|
1565
1743
|
getValues,
|
|
1566
1744
|
getFieldState,
|
|
1567
1745
|
trigger,
|
|
1568
|
-
setFocus
|
|
1746
|
+
setFocus,
|
|
1747
|
+
options: {
|
|
1748
|
+
mode: ctx.options.mode ?? "onSubmit",
|
|
1749
|
+
reValidateMode: ctx.options.reValidateMode
|
|
1750
|
+
}
|
|
1569
1751
|
};
|
|
1570
1752
|
}
|
|
1571
1753
|
const FormContextKey = Symbol("FormContext");
|
|
@@ -1604,13 +1786,22 @@ function useController(options) {
|
|
|
1604
1786
|
}
|
|
1605
1787
|
});
|
|
1606
1788
|
const onChange = (newValue) => {
|
|
1607
|
-
form.
|
|
1789
|
+
const isTouched = form.formState.value.touchedFields[name] === true;
|
|
1790
|
+
const hasSubmitted = form.formState.value.submitCount > 0;
|
|
1791
|
+
const mode = form.options.mode ?? "onSubmit";
|
|
1792
|
+
const reValidateMode = form.options.reValidateMode;
|
|
1793
|
+
const shouldValidate = shouldValidateOnChange(mode, isTouched, reValidateMode, hasSubmitted);
|
|
1794
|
+
form.setValue(name, newValue, { shouldValidate });
|
|
1608
1795
|
};
|
|
1609
1796
|
const onBlur = () => {
|
|
1797
|
+
const hasSubmitted = form.formState.value.submitCount > 0;
|
|
1798
|
+
const mode = form.options.mode ?? "onSubmit";
|
|
1799
|
+
const reValidateMode = form.options.reValidateMode;
|
|
1800
|
+
const shouldValidate = shouldValidateOnBlur(mode, hasSubmitted, reValidateMode);
|
|
1610
1801
|
const currentValue = form.getValues(name);
|
|
1611
1802
|
form.setValue(name, currentValue, {
|
|
1612
1803
|
shouldTouch: true,
|
|
1613
|
-
shouldValidate
|
|
1804
|
+
shouldValidate,
|
|
1614
1805
|
shouldDirty: false
|
|
1615
1806
|
});
|
|
1616
1807
|
};
|
|
@@ -1618,7 +1809,10 @@ function useController(options) {
|
|
|
1618
1809
|
elementRef.value = el;
|
|
1619
1810
|
};
|
|
1620
1811
|
const fieldState = (0, vue.computed)(() => {
|
|
1621
|
-
|
|
1812
|
+
setCalledFromController(true);
|
|
1813
|
+
const state = form.getFieldState(name);
|
|
1814
|
+
setCalledFromController(false);
|
|
1815
|
+
return state;
|
|
1622
1816
|
});
|
|
1623
1817
|
return {
|
|
1624
1818
|
field: {
|
|
@@ -1649,8 +1843,13 @@ function isFieldError(error) {
|
|
|
1649
1843
|
return typeof error === "object" && error !== null && "type" in error && "message" in error && typeof error.type === "string" && typeof error.message === "string";
|
|
1650
1844
|
}
|
|
1651
1845
|
exports.FormContextKey = FormContextKey;
|
|
1846
|
+
exports.clearPathCache = clearPathCache;
|
|
1847
|
+
exports.generateId = generateId;
|
|
1848
|
+
exports.get = get;
|
|
1652
1849
|
exports.isFieldError = isFieldError;
|
|
1653
1850
|
exports.provideForm = provideForm;
|
|
1851
|
+
exports.set = set;
|
|
1852
|
+
exports.unset = unset;
|
|
1654
1853
|
exports.useController = useController;
|
|
1655
1854
|
exports.useForm = useForm;
|
|
1656
1855
|
exports.useFormContext = useFormContext;
|