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