@vuehookform/core 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/core/fieldState.d.ts +21 -10
- package/dist/core/formContext.d.ts +8 -1
- package/dist/types.d.ts +18 -2
- package/dist/utils/clone.d.ts +19 -0
- package/dist/utils/devWarnings.d.ts +0 -4
- package/dist/utils/hash.d.ts +6 -0
- package/dist/utils/paths.d.ts +5 -0
- package/dist/utils/schemaExtract.d.ts +42 -0
- package/dist/vuehookform.cjs +733 -215
- package/dist/vuehookform.js +501 -197
- package/package.json +9 -17
package/dist/vuehookform.cjs
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
let vue = require("vue");
|
|
3
|
+
var pathCache = /* @__PURE__ */ new Map();
|
|
4
|
+
var PATH_CACHE_MAX_SIZE = 256;
|
|
5
|
+
function getPathSegments(path) {
|
|
6
|
+
let segments = pathCache.get(path);
|
|
7
|
+
if (segments) return segments;
|
|
8
|
+
segments = path.split(".");
|
|
9
|
+
if (pathCache.size >= PATH_CACHE_MAX_SIZE) {
|
|
10
|
+
const firstKey = pathCache.keys().next().value;
|
|
11
|
+
if (firstKey !== void 0) pathCache.delete(firstKey);
|
|
12
|
+
}
|
|
13
|
+
pathCache.set(path, segments);
|
|
14
|
+
return segments;
|
|
15
|
+
}
|
|
3
16
|
function get(obj, path) {
|
|
4
17
|
if (!path || obj === null || obj === void 0) return obj;
|
|
5
|
-
const keys = path
|
|
18
|
+
const keys = getPathSegments(path);
|
|
6
19
|
let result = obj;
|
|
7
20
|
for (const key of keys) {
|
|
8
21
|
if (result === null || result === void 0) return;
|
|
@@ -12,7 +25,7 @@ function get(obj, path) {
|
|
|
12
25
|
}
|
|
13
26
|
function set(obj, path, value) {
|
|
14
27
|
if (!path) return;
|
|
15
|
-
const keys = path.
|
|
28
|
+
const keys = getPathSegments(path).slice();
|
|
16
29
|
const UNSAFE_KEYS = [
|
|
17
30
|
"__proto__",
|
|
18
31
|
"constructor",
|
|
@@ -37,7 +50,7 @@ function set(obj, path, value) {
|
|
|
37
50
|
}
|
|
38
51
|
function unset(obj, path) {
|
|
39
52
|
if (!path) return;
|
|
40
|
-
const keys = path.
|
|
53
|
+
const keys = getPathSegments(path).slice();
|
|
41
54
|
const lastKey = keys.pop();
|
|
42
55
|
let current = obj;
|
|
43
56
|
for (const key of keys) {
|
|
@@ -53,11 +66,35 @@ function generateId() {
|
|
|
53
66
|
const random = Math.random().toString(36).substring(2, 11);
|
|
54
67
|
return `field_${Date.now()}_${idCounter++}_${random}`;
|
|
55
68
|
}
|
|
56
|
-
|
|
69
|
+
function deepClone(obj) {
|
|
70
|
+
if (obj === null || obj === void 0) return obj;
|
|
71
|
+
if (typeof obj !== "object") return obj;
|
|
72
|
+
if (obj instanceof Date) return new Date(obj.getTime());
|
|
73
|
+
if (Array.isArray(obj)) return obj.map((item) => deepClone(item));
|
|
74
|
+
const cloned = {};
|
|
75
|
+
for (const key in obj) if (Object.prototype.hasOwnProperty.call(obj, key)) cloned[key] = deepClone(obj[key]);
|
|
76
|
+
return cloned;
|
|
77
|
+
}
|
|
78
|
+
var proc = globalThis.process;
|
|
79
|
+
const __DEV__ = proc?.env?.NODE_ENV !== "production";
|
|
57
80
|
var warnedMessages = /* @__PURE__ */ new Set();
|
|
58
|
-
function warnOnce(message, key) {
|
|
59
|
-
|
|
81
|
+
function warnOnce(message, key) {
|
|
82
|
+
if (!__DEV__) return;
|
|
83
|
+
const cacheKey = key ?? message;
|
|
84
|
+
if (warnedMessages.has(cacheKey)) return;
|
|
85
|
+
warnedMessages.add(cacheKey);
|
|
86
|
+
console.warn(`[vue-hook-form] ${message}`);
|
|
87
|
+
}
|
|
88
|
+
function warn(message) {
|
|
89
|
+
if (!__DEV__) return;
|
|
90
|
+
console.warn(`[vue-hook-form] ${message}`);
|
|
91
|
+
}
|
|
60
92
|
function validatePathSyntax(path) {
|
|
93
|
+
if (!__DEV__) return null;
|
|
94
|
+
if (!path || path.trim() === "") return "Path cannot be empty";
|
|
95
|
+
if (path.startsWith(".") || path.endsWith(".") || path.includes("..")) return `Invalid path "${path}": contains empty segments`;
|
|
96
|
+
if (path.includes("[")) return `Invalid path "${path}": use dot notation (e.g., "items.0") instead of bracket notation (e.g., "items[0]")`;
|
|
97
|
+
if (/\s/.test(path)) return `Invalid path "${path}": paths cannot contain whitespace`;
|
|
61
98
|
return null;
|
|
62
99
|
}
|
|
63
100
|
function traverseSchemaPath(schema, path) {
|
|
@@ -67,7 +104,7 @@ function traverseSchemaPath(schema, path) {
|
|
|
67
104
|
const segment = segments[i];
|
|
68
105
|
if (!segment) continue;
|
|
69
106
|
currentSchema = unwrapSchema(currentSchema);
|
|
70
|
-
if (isZodObject(currentSchema)) {
|
|
107
|
+
if (isZodObject$1(currentSchema)) {
|
|
71
108
|
const shape = currentSchema.shape;
|
|
72
109
|
if (segment in shape) {
|
|
73
110
|
const nextSchema = shape[segment];
|
|
@@ -82,7 +119,7 @@ function traverseSchemaPath(schema, path) {
|
|
|
82
119
|
segmentIndex: i
|
|
83
120
|
};
|
|
84
121
|
}
|
|
85
|
-
if (isZodArray(currentSchema) && /^\d+$/.test(segment)) {
|
|
122
|
+
if (isZodArray$1(currentSchema) && /^\d+$/.test(segment)) {
|
|
86
123
|
currentSchema = currentSchema.element;
|
|
87
124
|
continue;
|
|
88
125
|
}
|
|
@@ -94,32 +131,93 @@ function traverseSchemaPath(schema, path) {
|
|
|
94
131
|
return { schema: currentSchema };
|
|
95
132
|
}
|
|
96
133
|
function validatePathAgainstSchema(schema, path) {
|
|
97
|
-
return { valid: true };
|
|
134
|
+
if (!__DEV__) return { valid: true };
|
|
135
|
+
try {
|
|
136
|
+
const result = traverseSchemaPath(schema, path);
|
|
137
|
+
if ("error" in result) return {
|
|
138
|
+
valid: false,
|
|
139
|
+
reason: result.error,
|
|
140
|
+
availableFields: result.availableFields
|
|
141
|
+
};
|
|
142
|
+
return { valid: true };
|
|
143
|
+
} catch {
|
|
144
|
+
return { valid: true };
|
|
145
|
+
}
|
|
98
146
|
}
|
|
99
147
|
function isArrayFieldInSchema(schema, path) {
|
|
100
|
-
return null;
|
|
148
|
+
if (!__DEV__) return null;
|
|
149
|
+
try {
|
|
150
|
+
const result = traverseSchemaPath(schema, path);
|
|
151
|
+
if ("error" in result) return null;
|
|
152
|
+
return isZodArray$1(unwrapSchema(result.schema));
|
|
153
|
+
} catch {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
101
156
|
}
|
|
102
|
-
function warnInvalidPath(fnName, path, reason) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
157
|
+
function warnInvalidPath(fnName, path, reason) {
|
|
158
|
+
if (!__DEV__) return;
|
|
159
|
+
let message = `${fnName}("${path}"): ${reason}`;
|
|
160
|
+
if (reason.includes("bracket notation")) {
|
|
161
|
+
const fixedPath = path.replace(/\[(\d+)\]/g, ".$1");
|
|
162
|
+
message += `\n FIX: Use dot notation for array indices`;
|
|
163
|
+
message += `\n EXAMPLE: ${fnName}("${fixedPath}")`;
|
|
164
|
+
} else if (reason.includes("empty")) {
|
|
165
|
+
message += `\n FIX: Provide a non-empty field path`;
|
|
166
|
+
message += `\n EXAMPLE: ${fnName}("email") or ${fnName}("user.address.city")`;
|
|
167
|
+
} else if (reason.includes("whitespace")) {
|
|
168
|
+
const fixedPath = path.replace(/\s/g, "");
|
|
169
|
+
message += `\n FIX: Remove spaces from the field path`;
|
|
170
|
+
message += `\n EXAMPLE: ${fnName}("${fixedPath}")`;
|
|
171
|
+
} else if (reason.includes("empty segments")) {
|
|
172
|
+
const fixedPath = path.replace(/\.{2,}/g, ".").replace(/^\./, "").replace(/\.$/, "");
|
|
173
|
+
message += `\n FIX: Remove extra dots from the path`;
|
|
174
|
+
message += `\n EXAMPLE: ${fnName}("${fixedPath}")`;
|
|
175
|
+
}
|
|
176
|
+
warnOnce(message, `invalid-path:${fnName}:${path}`);
|
|
177
|
+
}
|
|
178
|
+
function warnPathNotInSchema(fnName, path, availableFields) {
|
|
179
|
+
if (!__DEV__) return;
|
|
180
|
+
let message = `${fnName}("${path}"): Path does not exist in your Zod schema.`;
|
|
181
|
+
message += `\n FIX: Check that the path matches your schema definition exactly (case-sensitive)`;
|
|
182
|
+
if (availableFields && availableFields.length > 0) {
|
|
183
|
+
const pathLower = path.toLowerCase();
|
|
184
|
+
const suggestions = availableFields.filter((f) => f.toLowerCase().includes(pathLower) || pathLower.includes(f.toLowerCase()));
|
|
185
|
+
if (suggestions.length > 0) message += `\n DID YOU MEAN: ${suggestions.slice(0, 3).map((s) => `"${s}"`).join(", ")}`;
|
|
186
|
+
message += `\n AVAILABLE: ${availableFields.slice(0, 8).join(", ")}${availableFields.length > 8 ? "..." : ""}`;
|
|
187
|
+
}
|
|
188
|
+
warnOnce(message, `path-not-in-schema:${fnName}:${path}`);
|
|
189
|
+
}
|
|
190
|
+
function warnFieldsOnNonArray(path) {
|
|
191
|
+
if (!__DEV__) return;
|
|
192
|
+
warnOnce(`fields("${path}"): Expected an array field, but this path does not point to an array in your schema. The fields() method is only for array fields. Use register() for non-array fields.`, `fields-non-array:${path}`);
|
|
193
|
+
}
|
|
194
|
+
function warnArrayOperationRejected(operation, path, reason, details) {
|
|
195
|
+
if (!__DEV__) return;
|
|
196
|
+
warn(`${operation}() on "${path}": ${{
|
|
197
|
+
maxLength: details ? `Would exceed maxLength (current: ${details.current}, max: ${details.limit})` : "Would exceed maxLength rule",
|
|
198
|
+
minLength: details ? `Would violate minLength (current: ${details.current}, min: ${details.limit})` : "Would violate minLength rule"
|
|
199
|
+
}[reason]}. Operation was silently ignored.`);
|
|
200
|
+
}
|
|
201
|
+
function warnArrayIndexOutOfBounds(operation, path, index, length) {
|
|
202
|
+
if (!__DEV__) return;
|
|
203
|
+
warn(`${operation}() on "${path}": Index ${index} is out of bounds (array length: ${length}). Operation was silently ignored.`);
|
|
204
|
+
}
|
|
205
|
+
function getDefProp$1(schema, prop) {
|
|
108
206
|
return schema.def[prop];
|
|
109
207
|
}
|
|
110
208
|
function getTypeName(schema) {
|
|
111
|
-
return getDefProp(schema, "typeName");
|
|
209
|
+
return getDefProp$1(schema, "typeName");
|
|
112
210
|
}
|
|
113
|
-
function isZodObject(schema) {
|
|
211
|
+
function isZodObject$1(schema) {
|
|
114
212
|
return getTypeName(schema) === "ZodObject";
|
|
115
213
|
}
|
|
116
|
-
function isZodArray(schema) {
|
|
214
|
+
function isZodArray$1(schema) {
|
|
117
215
|
return getTypeName(schema) === "ZodArray";
|
|
118
216
|
}
|
|
119
217
|
function unwrapSchema(schema) {
|
|
120
218
|
const typeName = getTypeName(schema);
|
|
121
|
-
const innerType = getDefProp(schema, "innerType");
|
|
122
|
-
const schemaType = getDefProp(schema, "schema");
|
|
219
|
+
const innerType = getDefProp$1(schema, "innerType");
|
|
220
|
+
const schemaType = getDefProp$1(schema, "schema");
|
|
123
221
|
if ((typeName === "ZodOptional" || typeName === "ZodNullable" || typeName === "ZodDefault") && innerType) return unwrapSchema(innerType);
|
|
124
222
|
if (typeName === "ZodEffects" && schemaType) return unwrapSchema(schemaType);
|
|
125
223
|
return schema;
|
|
@@ -152,7 +250,7 @@ function createFormContext(options) {
|
|
|
152
250
|
const submitCount = (0, vue.ref)(0);
|
|
153
251
|
const defaultValuesError = (0, vue.ref)(null);
|
|
154
252
|
const isSubmitSuccessful = (0, vue.ref)(false);
|
|
155
|
-
const validatingFields = (0, vue.shallowRef)(
|
|
253
|
+
const validatingFields = (0, vue.shallowRef)(/* @__PURE__ */ new Set());
|
|
156
254
|
const externalErrors = (0, vue.shallowRef)({});
|
|
157
255
|
const errorDelayTimers = /* @__PURE__ */ new Map();
|
|
158
256
|
const pendingErrors = /* @__PURE__ */ new Map();
|
|
@@ -163,6 +261,10 @@ function createFormContext(options) {
|
|
|
163
261
|
const debounceTimers = /* @__PURE__ */ new Map();
|
|
164
262
|
const validationRequestIds = /* @__PURE__ */ new Map();
|
|
165
263
|
const resetGeneration = (0, vue.ref)(0);
|
|
264
|
+
const dirtyFieldCount = (0, vue.ref)(0);
|
|
265
|
+
const touchedFieldCount = (0, vue.ref)(0);
|
|
266
|
+
const validationCache = /* @__PURE__ */ new Map();
|
|
267
|
+
const schemaValidationTimers = /* @__PURE__ */ new Map();
|
|
166
268
|
const isDisabled = (0, vue.ref)(false);
|
|
167
269
|
if (options.disabled !== void 0) {
|
|
168
270
|
isDisabled.value = (0, vue.toValue)(options.disabled) ?? false;
|
|
@@ -220,24 +322,136 @@ function createFormContext(options) {
|
|
|
220
322
|
validationRequestIds,
|
|
221
323
|
resetGeneration,
|
|
222
324
|
isDisabled,
|
|
325
|
+
dirtyFieldCount,
|
|
326
|
+
touchedFieldCount,
|
|
327
|
+
validationCache,
|
|
328
|
+
schemaValidationTimers,
|
|
223
329
|
options
|
|
224
330
|
};
|
|
225
331
|
}
|
|
332
|
+
var uniqueIdCounter = 0;
|
|
333
|
+
function hashValue(value) {
|
|
334
|
+
if (value === null) return "null";
|
|
335
|
+
if (value === void 0) return "undefined";
|
|
336
|
+
const type = typeof value;
|
|
337
|
+
if (type === "string") return `s:${value}`;
|
|
338
|
+
if (type === "number") return `n:${value}`;
|
|
339
|
+
if (type === "boolean") return `b:${value}`;
|
|
340
|
+
if (type === "object") try {
|
|
341
|
+
return `o:${JSON.stringify(value)}`;
|
|
342
|
+
} catch {
|
|
343
|
+
return `o:_${++uniqueIdCounter}`;
|
|
344
|
+
}
|
|
345
|
+
return `x:_${++uniqueIdCounter}`;
|
|
346
|
+
}
|
|
347
|
+
function getDefType(schema) {
|
|
348
|
+
return schema._def?.type;
|
|
349
|
+
}
|
|
350
|
+
function getDefProp(schema, prop) {
|
|
351
|
+
return schema._def?.[prop];
|
|
352
|
+
}
|
|
353
|
+
function isZodObject(schema) {
|
|
354
|
+
return getDefType(schema) === "object";
|
|
355
|
+
}
|
|
356
|
+
function isZodArray(schema) {
|
|
357
|
+
return getDefType(schema) === "array";
|
|
358
|
+
}
|
|
359
|
+
function hasChecks(schema) {
|
|
360
|
+
const checks = getDefProp(schema, "checks");
|
|
361
|
+
return Array.isArray(checks) && checks.length > 0;
|
|
362
|
+
}
|
|
363
|
+
function unwrapNonEffects(schema) {
|
|
364
|
+
const type = getDefType(schema);
|
|
365
|
+
const innerType = getDefProp(schema, "innerType");
|
|
366
|
+
if ((type === "optional" || type === "nullable" || type === "default") && innerType) return unwrapNonEffects(innerType);
|
|
367
|
+
return schema;
|
|
368
|
+
}
|
|
369
|
+
var analysisCache = /* @__PURE__ */ new WeakMap();
|
|
370
|
+
function hasRootEffects(schema) {
|
|
371
|
+
return hasChecks(schema);
|
|
372
|
+
}
|
|
373
|
+
function extractSubSchema(schema, path) {
|
|
374
|
+
const segments = path.split(".");
|
|
375
|
+
let currentSchema = schema;
|
|
376
|
+
let hasEffects = false;
|
|
377
|
+
for (const segment of segments) {
|
|
378
|
+
if (!segment) continue;
|
|
379
|
+
if (hasChecks(currentSchema)) hasEffects = true;
|
|
380
|
+
const unwrapped = unwrapNonEffects(currentSchema);
|
|
381
|
+
if (hasChecks(unwrapped)) hasEffects = true;
|
|
382
|
+
if (isZodObject(unwrapped)) {
|
|
383
|
+
const shape = getDefProp(unwrapped, "shape");
|
|
384
|
+
if (!shape || !(segment in shape)) return null;
|
|
385
|
+
currentSchema = shape[segment];
|
|
386
|
+
} else if (isZodArray(unwrapped) && /^\d+$/.test(segment)) {
|
|
387
|
+
const element = getDefProp(unwrapped, "element");
|
|
388
|
+
if (!element) return null;
|
|
389
|
+
currentSchema = element;
|
|
390
|
+
} else return null;
|
|
391
|
+
}
|
|
392
|
+
const finalUnwrapped = unwrapNonEffects(currentSchema);
|
|
393
|
+
const finalChecks = getDefProp(finalUnwrapped, "checks");
|
|
394
|
+
if (finalChecks) {
|
|
395
|
+
for (const check of finalChecks) if (check && typeof check === "object" && "type" in check && check.type === "custom") {
|
|
396
|
+
hasEffects = true;
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return {
|
|
401
|
+
schema: finalUnwrapped,
|
|
402
|
+
hasEffects
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
function analyzeSchemaPath(schema, path) {
|
|
406
|
+
let cache = analysisCache.get(schema);
|
|
407
|
+
if (!cache) {
|
|
408
|
+
cache = /* @__PURE__ */ new Map();
|
|
409
|
+
analysisCache.set(schema, cache);
|
|
410
|
+
}
|
|
411
|
+
const cached = cache.get(path);
|
|
412
|
+
if (cached) return cached;
|
|
413
|
+
if (hasRootEffects(schema)) {
|
|
414
|
+
const result$1 = {
|
|
415
|
+
canPartialValidate: false,
|
|
416
|
+
reason: "root-checks"
|
|
417
|
+
};
|
|
418
|
+
cache.set(path, result$1);
|
|
419
|
+
return result$1;
|
|
420
|
+
}
|
|
421
|
+
const extracted = extractSubSchema(schema, path);
|
|
422
|
+
if (!extracted) {
|
|
423
|
+
const result$1 = {
|
|
424
|
+
canPartialValidate: false,
|
|
425
|
+
reason: "invalid-path"
|
|
426
|
+
};
|
|
427
|
+
cache.set(path, result$1);
|
|
428
|
+
return result$1;
|
|
429
|
+
}
|
|
430
|
+
if (extracted.hasEffects) {
|
|
431
|
+
const result$1 = {
|
|
432
|
+
canPartialValidate: false,
|
|
433
|
+
reason: "path-checks"
|
|
434
|
+
};
|
|
435
|
+
cache.set(path, result$1);
|
|
436
|
+
return result$1;
|
|
437
|
+
}
|
|
438
|
+
const result = {
|
|
439
|
+
canPartialValidate: true,
|
|
440
|
+
subSchema: extracted.schema
|
|
441
|
+
};
|
|
442
|
+
cache.set(path, result);
|
|
443
|
+
return result;
|
|
444
|
+
}
|
|
226
445
|
function clearFieldErrors$1(errors, fieldPath) {
|
|
227
446
|
const newErrors = { ...errors };
|
|
228
447
|
for (const key of Object.keys(newErrors)) if (key === fieldPath || key.startsWith(`${fieldPath}.`)) delete newErrors[key];
|
|
229
448
|
return newErrors;
|
|
230
449
|
}
|
|
231
450
|
function setValidating(ctx, fieldPath, isValidating) {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
else {
|
|
237
|
-
const newValidating = { ...ctx.validatingFields.value };
|
|
238
|
-
delete newValidating[fieldPath];
|
|
239
|
-
ctx.validatingFields.value = newValidating;
|
|
240
|
-
}
|
|
451
|
+
const newSet = new Set(ctx.validatingFields.value);
|
|
452
|
+
if (isValidating) newSet.add(fieldPath);
|
|
453
|
+
else newSet.delete(fieldPath);
|
|
454
|
+
ctx.validatingFields.value = newSet;
|
|
241
455
|
}
|
|
242
456
|
function groupErrorsByPath(issues) {
|
|
243
457
|
const grouped = /* @__PURE__ */ new Map();
|
|
@@ -279,6 +493,18 @@ function createValidation(ctx) {
|
|
|
279
493
|
if (!ctx.options.shouldUseNativeValidation) return;
|
|
280
494
|
for (const [path] of ctx.fieldRefs) applyNativeValidation(path, null);
|
|
281
495
|
}
|
|
496
|
+
function scheduleErrorsBatch(errors) {
|
|
497
|
+
if ((ctx.options.delayError || 0) <= 0) {
|
|
498
|
+
const newErrors = { ...ctx.errors.value };
|
|
499
|
+
for (const [fieldPath, error] of errors) {
|
|
500
|
+
set(newErrors, fieldPath, error);
|
|
501
|
+
applyNativeValidation(fieldPath, typeof error === "string" ? error : error.message);
|
|
502
|
+
}
|
|
503
|
+
ctx.errors.value = newErrors;
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
for (const [fieldPath, error] of errors) scheduleError(fieldPath, error);
|
|
507
|
+
}
|
|
282
508
|
function scheduleError(fieldPath, error) {
|
|
283
509
|
const delayMs = ctx.options.delayError || 0;
|
|
284
510
|
const errorMessage = typeof error === "string" ? error : error.message;
|
|
@@ -320,42 +546,108 @@ function createValidation(ctx) {
|
|
|
320
546
|
ctx.errorDelayTimers.clear();
|
|
321
547
|
ctx.pendingErrors.clear();
|
|
322
548
|
}
|
|
549
|
+
async function validateFieldPartial(fieldPath, subSchema, valueHash, criteriaMode, generationAtStart) {
|
|
550
|
+
const fieldValue = get(ctx.formData, fieldPath);
|
|
551
|
+
setValidating(ctx, fieldPath, true);
|
|
552
|
+
try {
|
|
553
|
+
const result = await subSchema.safeParseAsync(fieldValue);
|
|
554
|
+
if (ctx.resetGeneration.value !== generationAtStart) return true;
|
|
555
|
+
if (result.success) {
|
|
556
|
+
ctx.errors.value = cancelError(fieldPath);
|
|
557
|
+
if (valueHash) ctx.validationCache.set(fieldPath, {
|
|
558
|
+
hash: valueHash,
|
|
559
|
+
isValid: true
|
|
560
|
+
});
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
563
|
+
const fieldErrors = result.error.issues.map((issue) => ({
|
|
564
|
+
...issue,
|
|
565
|
+
path: fieldPath.split(".").concat(issue.path.map(String))
|
|
566
|
+
}));
|
|
567
|
+
ctx.errors.value = cancelError(fieldPath);
|
|
568
|
+
const grouped = groupErrorsByPath(fieldErrors);
|
|
569
|
+
const errorBatch = [];
|
|
570
|
+
for (const [path, errors] of grouped) errorBatch.push([path, createFieldError(errors, criteriaMode)]);
|
|
571
|
+
scheduleErrorsBatch(errorBatch);
|
|
572
|
+
if (valueHash) ctx.validationCache.set(fieldPath, {
|
|
573
|
+
hash: valueHash,
|
|
574
|
+
isValid: false
|
|
575
|
+
});
|
|
576
|
+
return false;
|
|
577
|
+
} finally {
|
|
578
|
+
setValidating(ctx, fieldPath, false);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
async function validateFieldFull(fieldPath, valueHash, criteriaMode, generationAtStart) {
|
|
582
|
+
setValidating(ctx, fieldPath, true);
|
|
583
|
+
try {
|
|
584
|
+
const result = await ctx.options.schema.safeParseAsync(ctx.formData);
|
|
585
|
+
if (ctx.resetGeneration.value !== generationAtStart) return true;
|
|
586
|
+
if (result.success) {
|
|
587
|
+
ctx.errors.value = cancelError(fieldPath);
|
|
588
|
+
if (valueHash) ctx.validationCache.set(fieldPath, {
|
|
589
|
+
hash: valueHash,
|
|
590
|
+
isValid: true
|
|
591
|
+
});
|
|
592
|
+
return true;
|
|
593
|
+
}
|
|
594
|
+
const fieldErrors = result.error.issues.filter((issue) => {
|
|
595
|
+
const path = issue.path.join(".");
|
|
596
|
+
return path === fieldPath || path.startsWith(`${fieldPath}.`);
|
|
597
|
+
});
|
|
598
|
+
if (fieldErrors.length === 0) {
|
|
599
|
+
ctx.errors.value = cancelError(fieldPath);
|
|
600
|
+
if (valueHash) ctx.validationCache.set(fieldPath, {
|
|
601
|
+
hash: valueHash,
|
|
602
|
+
isValid: true
|
|
603
|
+
});
|
|
604
|
+
return true;
|
|
605
|
+
}
|
|
606
|
+
ctx.errors.value = cancelError(fieldPath);
|
|
607
|
+
const grouped = groupErrorsByPath(fieldErrors);
|
|
608
|
+
const errorBatch = [];
|
|
609
|
+
for (const [path, errors] of grouped) errorBatch.push([path, createFieldError(errors, criteriaMode)]);
|
|
610
|
+
scheduleErrorsBatch(errorBatch);
|
|
611
|
+
if (valueHash) ctx.validationCache.set(fieldPath, {
|
|
612
|
+
hash: valueHash,
|
|
613
|
+
isValid: false
|
|
614
|
+
});
|
|
615
|
+
return false;
|
|
616
|
+
} finally {
|
|
617
|
+
setValidating(ctx, fieldPath, false);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
323
620
|
async function validate(fieldPath) {
|
|
324
621
|
const generationAtStart = ctx.resetGeneration.value;
|
|
325
622
|
const criteriaMode = ctx.options.criteriaMode || "firstError";
|
|
326
|
-
|
|
623
|
+
let valueHash;
|
|
624
|
+
if (fieldPath) {
|
|
625
|
+
valueHash = hashValue(get(ctx.formData, fieldPath));
|
|
626
|
+
const cached = ctx.validationCache.get(fieldPath);
|
|
627
|
+
if (cached && cached.hash === valueHash) return cached.isValid;
|
|
628
|
+
const analysis = analyzeSchemaPath(ctx.options.schema, fieldPath);
|
|
629
|
+
if (analysis.canPartialValidate && analysis.subSchema) return validateFieldPartial(fieldPath, analysis.subSchema, valueHash, criteriaMode, generationAtStart);
|
|
630
|
+
return validateFieldFull(fieldPath, valueHash, criteriaMode, generationAtStart);
|
|
631
|
+
}
|
|
632
|
+
const validatingKey = "_form";
|
|
327
633
|
setValidating(ctx, validatingKey, true);
|
|
328
634
|
try {
|
|
329
635
|
const result = await ctx.options.schema.safeParseAsync(ctx.formData);
|
|
330
636
|
if (ctx.resetGeneration.value !== generationAtStart) return true;
|
|
331
637
|
if (result.success) {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
clearAllNativeValidation();
|
|
337
|
-
}
|
|
638
|
+
clearAllPendingErrors();
|
|
639
|
+
ctx.errors.value = {};
|
|
640
|
+
clearAllNativeValidation();
|
|
641
|
+
ctx.validationCache.clear();
|
|
338
642
|
return true;
|
|
339
643
|
}
|
|
340
|
-
const zodErrors = result.error.issues;
|
|
341
|
-
if (fieldPath) {
|
|
342
|
-
const fieldErrors = zodErrors.filter((issue) => {
|
|
343
|
-
const path = issue.path.join(".");
|
|
344
|
-
return path === fieldPath || path.startsWith(`${fieldPath}.`);
|
|
345
|
-
});
|
|
346
|
-
if (fieldErrors.length === 0) {
|
|
347
|
-
ctx.errors.value = cancelError(fieldPath);
|
|
348
|
-
return true;
|
|
349
|
-
}
|
|
350
|
-
ctx.errors.value = cancelError(fieldPath);
|
|
351
|
-
const grouped$1 = groupErrorsByPath(fieldErrors);
|
|
352
|
-
for (const [path, errors] of grouped$1) scheduleError(path, createFieldError(errors, criteriaMode));
|
|
353
|
-
return false;
|
|
354
|
-
}
|
|
355
644
|
clearAllPendingErrors();
|
|
356
645
|
ctx.errors.value = {};
|
|
357
|
-
const grouped = groupErrorsByPath(
|
|
358
|
-
|
|
646
|
+
const grouped = groupErrorsByPath(result.error.issues);
|
|
647
|
+
const errorBatch = [];
|
|
648
|
+
for (const [path, errors] of grouped) errorBatch.push([path, createFieldError(errors, criteriaMode)]);
|
|
649
|
+
scheduleErrorsBatch(errorBatch);
|
|
650
|
+
ctx.validationCache.clear();
|
|
359
651
|
return false;
|
|
360
652
|
} finally {
|
|
361
653
|
setValidating(ctx, validatingKey, false);
|
|
@@ -366,9 +658,57 @@ function createValidation(ctx) {
|
|
|
366
658
|
clearAllPendingErrors
|
|
367
659
|
};
|
|
368
660
|
}
|
|
661
|
+
function markFieldDirty(dirtyFields, dirtyFieldCount, fieldName) {
|
|
662
|
+
if (dirtyFields.value[fieldName]) return;
|
|
663
|
+
dirtyFields.value = {
|
|
664
|
+
...dirtyFields.value,
|
|
665
|
+
[fieldName]: true
|
|
666
|
+
};
|
|
667
|
+
dirtyFieldCount.value++;
|
|
668
|
+
}
|
|
669
|
+
function markFieldTouched(touchedFields, touchedFieldCount, fieldName) {
|
|
670
|
+
if (touchedFields.value[fieldName]) return;
|
|
671
|
+
touchedFields.value = {
|
|
672
|
+
...touchedFields.value,
|
|
673
|
+
[fieldName]: true
|
|
674
|
+
};
|
|
675
|
+
touchedFieldCount.value++;
|
|
676
|
+
}
|
|
677
|
+
function clearFieldDirty(dirtyFields, dirtyFieldCount, fieldName) {
|
|
678
|
+
if (!(fieldName in dirtyFields.value)) return;
|
|
679
|
+
const newDirty = { ...dirtyFields.value };
|
|
680
|
+
delete newDirty[fieldName];
|
|
681
|
+
dirtyFields.value = newDirty;
|
|
682
|
+
dirtyFieldCount.value--;
|
|
683
|
+
}
|
|
684
|
+
function clearFieldTouched(touchedFields, touchedFieldCount, fieldName) {
|
|
685
|
+
if (!(fieldName in touchedFields.value)) return;
|
|
686
|
+
const newTouched = { ...touchedFields.value };
|
|
687
|
+
delete newTouched[fieldName];
|
|
688
|
+
touchedFields.value = newTouched;
|
|
689
|
+
touchedFieldCount.value--;
|
|
690
|
+
}
|
|
691
|
+
function clearFieldErrors(errors, fieldName) {
|
|
692
|
+
const currentErrors = errors.value;
|
|
693
|
+
const keys = Object.keys(currentErrors);
|
|
694
|
+
if (keys.length === 0) return;
|
|
695
|
+
const prefix = `${fieldName}.`;
|
|
696
|
+
const keysToDelete = [];
|
|
697
|
+
for (const key of keys) if (key === fieldName || key.startsWith(prefix)) keysToDelete.push(key);
|
|
698
|
+
if (keysToDelete.length === 0) return;
|
|
699
|
+
const newErrors = { ...currentErrors };
|
|
700
|
+
for (const key of keysToDelete) delete newErrors[key];
|
|
701
|
+
errors.value = newErrors;
|
|
702
|
+
}
|
|
369
703
|
var validationRequestCounter = 0;
|
|
370
704
|
function createFieldRegistration(ctx, validate) {
|
|
371
705
|
function register(name, registerOptions) {
|
|
706
|
+
if (__DEV__) {
|
|
707
|
+
const syntaxError = validatePathSyntax(name);
|
|
708
|
+
if (syntaxError) warnInvalidPath("register", name, syntaxError);
|
|
709
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, name);
|
|
710
|
+
if (!schemaResult.valid) warnPathNotInSchema("register", name, schemaResult.availableFields);
|
|
711
|
+
}
|
|
372
712
|
let fieldRef = ctx.fieldRefs.get(name);
|
|
373
713
|
if (!fieldRef) {
|
|
374
714
|
fieldRef = (0, vue.ref)(null);
|
|
@@ -401,16 +741,30 @@ function createFieldRegistration(ctx, validate) {
|
|
|
401
741
|
const target = e.target;
|
|
402
742
|
const value = target.type === "checkbox" ? target.checked : target.value;
|
|
403
743
|
set(ctx.formData, name, value);
|
|
404
|
-
ctx.dirtyFields.
|
|
405
|
-
|
|
406
|
-
[name]: true
|
|
407
|
-
};
|
|
744
|
+
markFieldDirty(ctx.dirtyFields, ctx.dirtyFieldCount, name);
|
|
745
|
+
const fieldOpts = ctx.fieldOptions.get(name);
|
|
408
746
|
if (ctx.options.mode === "onChange" || ctx.options.mode === "onTouched" && ctx.touchedFields.value[name] || ctx.touchedFields.value[name] && ctx.options.reValidateMode === "onChange") {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
747
|
+
const validationDebounceMs = ctx.options.validationDebounce || 0;
|
|
748
|
+
if (validationDebounceMs > 0) {
|
|
749
|
+
const existingTimer = ctx.schemaValidationTimers.get(name);
|
|
750
|
+
if (existingTimer) clearTimeout(existingTimer);
|
|
751
|
+
const timer = setTimeout(async () => {
|
|
752
|
+
ctx.schemaValidationTimers.delete(name);
|
|
753
|
+
await validate(name);
|
|
754
|
+
if (fieldOpts?.deps && fieldOpts.deps.length > 0) {
|
|
755
|
+
const uniqueDeps = [...new Set(fieldOpts.deps)];
|
|
756
|
+
await Promise.all(uniqueDeps.map((depField) => validate(depField)));
|
|
757
|
+
}
|
|
758
|
+
}, validationDebounceMs);
|
|
759
|
+
ctx.schemaValidationTimers.set(name, timer);
|
|
760
|
+
} else {
|
|
761
|
+
await validate(name);
|
|
762
|
+
if (fieldOpts?.deps && fieldOpts.deps.length > 0) {
|
|
763
|
+
const uniqueDeps = [...new Set(fieldOpts.deps)];
|
|
764
|
+
await Promise.all(uniqueDeps.map((depField) => validate(depField)));
|
|
765
|
+
}
|
|
766
|
+
}
|
|
412
767
|
}
|
|
413
|
-
const fieldOpts = ctx.fieldOptions.get(name);
|
|
414
768
|
if (fieldOpts?.validate && !fieldOpts.disabled) {
|
|
415
769
|
const requestId = ++validationRequestCounter;
|
|
416
770
|
ctx.validationRequestIds.set(name, requestId);
|
|
@@ -419,23 +773,24 @@ function createFieldRegistration(ctx, validate) {
|
|
|
419
773
|
if (debounceMs > 0) {
|
|
420
774
|
const existingTimer = ctx.debounceTimers.get(name);
|
|
421
775
|
if (existingTimer) clearTimeout(existingTimer);
|
|
422
|
-
const timer = setTimeout(() => {
|
|
776
|
+
const timer = setTimeout(async () => {
|
|
423
777
|
ctx.debounceTimers.delete(name);
|
|
424
|
-
runCustomValidation(name, value, requestId, resetGenAtStart);
|
|
778
|
+
await runCustomValidation(name, value, requestId, resetGenAtStart);
|
|
779
|
+
ctx.validationRequestIds.delete(name);
|
|
425
780
|
}, debounceMs);
|
|
426
781
|
ctx.debounceTimers.set(name, timer);
|
|
427
782
|
} else await runCustomValidation(name, value, requestId, resetGenAtStart);
|
|
428
783
|
}
|
|
429
784
|
};
|
|
430
785
|
const onBlur = async (_e) => {
|
|
431
|
-
ctx.touchedFields.
|
|
432
|
-
...ctx.touchedFields.value,
|
|
433
|
-
[name]: true
|
|
434
|
-
};
|
|
786
|
+
markFieldTouched(ctx.touchedFields, ctx.touchedFieldCount, name);
|
|
435
787
|
if (ctx.options.mode === "onBlur" || ctx.options.mode === "onTouched" || ctx.submitCount.value > 0 && ctx.options.reValidateMode === "onBlur") {
|
|
436
788
|
await validate(name);
|
|
437
789
|
const fieldOpts = ctx.fieldOptions.get(name);
|
|
438
|
-
if (fieldOpts?.deps && fieldOpts.deps.length > 0)
|
|
790
|
+
if (fieldOpts?.deps && fieldOpts.deps.length > 0) {
|
|
791
|
+
const uniqueDeps = [...new Set(fieldOpts.deps)];
|
|
792
|
+
await Promise.all(uniqueDeps.map((depField) => validate(depField)));
|
|
793
|
+
}
|
|
439
794
|
}
|
|
440
795
|
};
|
|
441
796
|
const refCallback = (el) => {
|
|
@@ -457,18 +812,17 @@ function createFieldRegistration(ctx, validate) {
|
|
|
457
812
|
clearTimeout(timer);
|
|
458
813
|
ctx.debounceTimers.delete(name);
|
|
459
814
|
}
|
|
815
|
+
const schemaTimer = ctx.schemaValidationTimers.get(name);
|
|
816
|
+
if (schemaTimer) {
|
|
817
|
+
clearTimeout(schemaTimer);
|
|
818
|
+
ctx.schemaValidationTimers.delete(name);
|
|
819
|
+
}
|
|
460
820
|
ctx.validationRequestIds.delete(name);
|
|
461
821
|
if (opts?.shouldUnregister ?? ctx.options.shouldUnregister ?? false) {
|
|
462
822
|
unset(ctx.formData, name);
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
ctx.
|
|
466
|
-
const newTouched = { ...ctx.touchedFields.value };
|
|
467
|
-
delete newTouched[name];
|
|
468
|
-
ctx.touchedFields.value = newTouched;
|
|
469
|
-
const newDirty = { ...ctx.dirtyFields.value };
|
|
470
|
-
delete newDirty[name];
|
|
471
|
-
ctx.dirtyFields.value = newDirty;
|
|
823
|
+
clearFieldErrors(ctx.errors, name);
|
|
824
|
+
clearFieldTouched(ctx.touchedFields, ctx.touchedFieldCount, name);
|
|
825
|
+
clearFieldDirty(ctx.dirtyFields, ctx.dirtyFieldCount, name);
|
|
472
826
|
ctx.fieldRefs.delete(name);
|
|
473
827
|
ctx.fieldOptions.delete(name);
|
|
474
828
|
ctx.fieldHandlers.delete(name);
|
|
@@ -492,10 +846,7 @@ function createFieldRegistration(ctx, validate) {
|
|
|
492
846
|
get: () => get(ctx.formData, name),
|
|
493
847
|
set: (val) => {
|
|
494
848
|
set(ctx.formData, name, val);
|
|
495
|
-
ctx.dirtyFields.
|
|
496
|
-
...ctx.dirtyFields.value,
|
|
497
|
-
[name]: true
|
|
498
|
-
};
|
|
849
|
+
markFieldDirty(ctx.dirtyFields, ctx.dirtyFieldCount, name);
|
|
499
850
|
}
|
|
500
851
|
}) }
|
|
501
852
|
};
|
|
@@ -503,21 +854,9 @@ function createFieldRegistration(ctx, validate) {
|
|
|
503
854
|
function unregister(name, options) {
|
|
504
855
|
const opts = options || {};
|
|
505
856
|
if (!opts.keepValue) unset(ctx.formData, name);
|
|
506
|
-
if (!opts.keepError)
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
ctx.errors.value = newErrors;
|
|
510
|
-
}
|
|
511
|
-
if (!opts.keepTouched) {
|
|
512
|
-
const newTouched = { ...ctx.touchedFields.value };
|
|
513
|
-
delete newTouched[name];
|
|
514
|
-
ctx.touchedFields.value = newTouched;
|
|
515
|
-
}
|
|
516
|
-
if (!opts.keepDirty) {
|
|
517
|
-
const newDirty = { ...ctx.dirtyFields.value };
|
|
518
|
-
delete newDirty[name];
|
|
519
|
-
ctx.dirtyFields.value = newDirty;
|
|
520
|
-
}
|
|
857
|
+
if (!opts.keepError) clearFieldErrors(ctx.errors, name);
|
|
858
|
+
if (!opts.keepTouched) clearFieldTouched(ctx.touchedFields, ctx.touchedFieldCount, name);
|
|
859
|
+
if (!opts.keepDirty) clearFieldDirty(ctx.dirtyFields, ctx.dirtyFieldCount, name);
|
|
521
860
|
ctx.fieldRefs.delete(name);
|
|
522
861
|
ctx.fieldOptions.delete(name);
|
|
523
862
|
ctx.fieldHandlers.delete(name);
|
|
@@ -526,6 +865,11 @@ function createFieldRegistration(ctx, validate) {
|
|
|
526
865
|
clearTimeout(timer);
|
|
527
866
|
ctx.debounceTimers.delete(name);
|
|
528
867
|
}
|
|
868
|
+
const schemaTimer = ctx.schemaValidationTimers.get(name);
|
|
869
|
+
if (schemaTimer) {
|
|
870
|
+
clearTimeout(schemaTimer);
|
|
871
|
+
ctx.schemaValidationTimers.delete(name);
|
|
872
|
+
}
|
|
529
873
|
ctx.validationRequestIds.delete(name);
|
|
530
874
|
}
|
|
531
875
|
return {
|
|
@@ -535,6 +879,13 @@ function createFieldRegistration(ctx, validate) {
|
|
|
535
879
|
}
|
|
536
880
|
function createFieldArrayManager(ctx, validate, setFocus) {
|
|
537
881
|
function fields(name, options) {
|
|
882
|
+
if (__DEV__) {
|
|
883
|
+
const syntaxError = validatePathSyntax(name);
|
|
884
|
+
if (syntaxError) warnInvalidPath("fields", name, syntaxError);
|
|
885
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, name);
|
|
886
|
+
if (!schemaResult.valid) warnPathNotInSchema("fields", name, schemaResult.availableFields);
|
|
887
|
+
if (isArrayFieldInSchema(ctx.options.schema, name) === false) warnFieldsOnNonArray(name);
|
|
888
|
+
}
|
|
538
889
|
let fieldArray = ctx.fieldArrays.get(name);
|
|
539
890
|
if (!fieldArray) {
|
|
540
891
|
const existingValues = get(ctx.formData, name) || [];
|
|
@@ -555,6 +906,35 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
555
906
|
indexCache.set(item.key, idx);
|
|
556
907
|
});
|
|
557
908
|
};
|
|
909
|
+
const appendToCache = (startIndex) => {
|
|
910
|
+
const items = fa.items.value;
|
|
911
|
+
for (let i = startIndex; i < items.length; i++) {
|
|
912
|
+
const item = items[i];
|
|
913
|
+
if (item) indexCache.set(item.key, i);
|
|
914
|
+
}
|
|
915
|
+
};
|
|
916
|
+
const updateCacheAfterInsert = (insertIndex, _insertCount) => {
|
|
917
|
+
const items = fa.items.value;
|
|
918
|
+
for (let i = insertIndex; i < items.length; i++) {
|
|
919
|
+
const item = items[i];
|
|
920
|
+
if (item) indexCache.set(item.key, i);
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
const swapInCache = (indexA, indexB) => {
|
|
924
|
+
const items = fa.items.value;
|
|
925
|
+
const itemA = items[indexA];
|
|
926
|
+
const itemB = items[indexB];
|
|
927
|
+
if (itemA) indexCache.set(itemA.key, indexA);
|
|
928
|
+
if (itemB) indexCache.set(itemB.key, indexB);
|
|
929
|
+
};
|
|
930
|
+
const updateCacheAfterRemove = (removedKey, startIndex) => {
|
|
931
|
+
indexCache.delete(removedKey);
|
|
932
|
+
const items = fa.items.value;
|
|
933
|
+
for (let i = startIndex; i < items.length; i++) {
|
|
934
|
+
const item = items[i];
|
|
935
|
+
if (item) indexCache.set(item.key, i);
|
|
936
|
+
}
|
|
937
|
+
};
|
|
558
938
|
const createItem = (key) => ({
|
|
559
939
|
key,
|
|
560
940
|
get index() {
|
|
@@ -586,16 +966,19 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
586
966
|
const currentValues = get(ctx.formData, name) || [];
|
|
587
967
|
const insertIndex = currentValues.length;
|
|
588
968
|
const rules = fa.rules;
|
|
589
|
-
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value)
|
|
969
|
+
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) {
|
|
970
|
+
if (__DEV__) warnArrayOperationRejected("append", name, "maxLength", {
|
|
971
|
+
current: currentValues.length,
|
|
972
|
+
limit: rules.maxLength.value
|
|
973
|
+
});
|
|
974
|
+
return false;
|
|
975
|
+
}
|
|
590
976
|
const newValues = [...currentValues, ...values];
|
|
591
977
|
set(ctx.formData, name, newValues);
|
|
592
978
|
const newItems = values.map(() => createItem(generateId()));
|
|
593
979
|
fa.items.value = [...fa.items.value, ...newItems];
|
|
594
|
-
|
|
595
|
-
ctx.dirtyFields.
|
|
596
|
-
...ctx.dirtyFields.value,
|
|
597
|
-
[name]: true
|
|
598
|
-
};
|
|
980
|
+
appendToCache(insertIndex);
|
|
981
|
+
markFieldDirty(ctx.dirtyFields, ctx.dirtyFieldCount, name);
|
|
599
982
|
if (ctx.options.mode === "onChange") validate(name);
|
|
600
983
|
handleFocus(insertIndex, values.length, focusOptions);
|
|
601
984
|
return true;
|
|
@@ -605,47 +988,56 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
605
988
|
if (values.length === 0) return true;
|
|
606
989
|
const currentValues = get(ctx.formData, name) || [];
|
|
607
990
|
const rules = fa.rules;
|
|
608
|
-
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value)
|
|
991
|
+
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) {
|
|
992
|
+
if (__DEV__) warnArrayOperationRejected("prepend", name, "maxLength", {
|
|
993
|
+
current: currentValues.length,
|
|
994
|
+
limit: rules.maxLength.value
|
|
995
|
+
});
|
|
996
|
+
return false;
|
|
997
|
+
}
|
|
609
998
|
const newValues = [...values, ...currentValues];
|
|
610
999
|
set(ctx.formData, name, newValues);
|
|
611
1000
|
const newItems = values.map(() => createItem(generateId()));
|
|
612
1001
|
fa.items.value = [...newItems, ...fa.items.value];
|
|
613
|
-
|
|
614
|
-
ctx.dirtyFields.
|
|
615
|
-
...ctx.dirtyFields.value,
|
|
616
|
-
[name]: true
|
|
617
|
-
};
|
|
1002
|
+
updateCacheAfterInsert(0, values.length);
|
|
1003
|
+
markFieldDirty(ctx.dirtyFields, ctx.dirtyFieldCount, name);
|
|
618
1004
|
if (ctx.options.mode === "onChange") validate(name);
|
|
619
1005
|
handleFocus(0, values.length, focusOptions);
|
|
620
1006
|
return true;
|
|
621
1007
|
};
|
|
622
1008
|
const update = (index, value) => {
|
|
623
1009
|
const currentValues = get(ctx.formData, name) || [];
|
|
624
|
-
if (index < 0 || index >= currentValues.length)
|
|
1010
|
+
if (index < 0 || index >= currentValues.length) {
|
|
1011
|
+
if (__DEV__) warnArrayIndexOutOfBounds("update", name, index, currentValues.length);
|
|
1012
|
+
return false;
|
|
1013
|
+
}
|
|
625
1014
|
const newValues = [...currentValues];
|
|
626
1015
|
newValues[index] = value;
|
|
627
1016
|
set(ctx.formData, name, newValues);
|
|
628
|
-
ctx.dirtyFields.
|
|
629
|
-
...ctx.dirtyFields.value,
|
|
630
|
-
[name]: true
|
|
631
|
-
};
|
|
1017
|
+
markFieldDirty(ctx.dirtyFields, ctx.dirtyFieldCount, name);
|
|
632
1018
|
if (ctx.options.mode === "onChange") validate(name);
|
|
633
1019
|
return true;
|
|
634
1020
|
};
|
|
635
1021
|
const removeAt = (index) => {
|
|
636
1022
|
const currentValues = get(ctx.formData, name) || [];
|
|
637
|
-
if (index < 0 || index >= currentValues.length)
|
|
1023
|
+
if (index < 0 || index >= currentValues.length) {
|
|
1024
|
+
if (__DEV__) warnArrayIndexOutOfBounds("remove", name, index, currentValues.length);
|
|
1025
|
+
return false;
|
|
1026
|
+
}
|
|
638
1027
|
const rules = fa.rules;
|
|
639
|
-
if (rules?.minLength && currentValues.length - 1 < rules.minLength.value)
|
|
1028
|
+
if (rules?.minLength && currentValues.length - 1 < rules.minLength.value) {
|
|
1029
|
+
if (__DEV__) warnArrayOperationRejected("remove", name, "minLength", {
|
|
1030
|
+
current: currentValues.length,
|
|
1031
|
+
limit: rules.minLength.value
|
|
1032
|
+
});
|
|
1033
|
+
return false;
|
|
1034
|
+
}
|
|
640
1035
|
const newValues = currentValues.filter((_, i) => i !== index);
|
|
641
1036
|
set(ctx.formData, name, newValues);
|
|
642
1037
|
const keyToRemove = fa.items.value[index]?.key;
|
|
643
1038
|
fa.items.value = fa.items.value.filter((item) => item.key !== keyToRemove);
|
|
644
|
-
|
|
645
|
-
ctx.dirtyFields.
|
|
646
|
-
...ctx.dirtyFields.value,
|
|
647
|
-
[name]: true
|
|
648
|
-
};
|
|
1039
|
+
if (keyToRemove) updateCacheAfterRemove(keyToRemove, index);
|
|
1040
|
+
markFieldDirty(ctx.dirtyFields, ctx.dirtyFieldCount, name);
|
|
649
1041
|
if (ctx.options.mode === "onChange") validate(name);
|
|
650
1042
|
return true;
|
|
651
1043
|
};
|
|
@@ -654,7 +1046,13 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
654
1046
|
if (values.length === 0) return true;
|
|
655
1047
|
const currentValues = get(ctx.formData, name) || [];
|
|
656
1048
|
const rules = fa.rules;
|
|
657
|
-
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value)
|
|
1049
|
+
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) {
|
|
1050
|
+
if (__DEV__) warnArrayOperationRejected("insert", name, "maxLength", {
|
|
1051
|
+
current: currentValues.length,
|
|
1052
|
+
limit: rules.maxLength.value
|
|
1053
|
+
});
|
|
1054
|
+
return false;
|
|
1055
|
+
}
|
|
658
1056
|
const clampedIndex = Math.max(0, Math.min(index, currentValues.length));
|
|
659
1057
|
const newValues = [
|
|
660
1058
|
...currentValues.slice(0, clampedIndex),
|
|
@@ -668,18 +1066,18 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
668
1066
|
...newItems,
|
|
669
1067
|
...fa.items.value.slice(clampedIndex)
|
|
670
1068
|
];
|
|
671
|
-
|
|
672
|
-
ctx.dirtyFields.
|
|
673
|
-
...ctx.dirtyFields.value,
|
|
674
|
-
[name]: true
|
|
675
|
-
};
|
|
1069
|
+
updateCacheAfterInsert(clampedIndex, values.length);
|
|
1070
|
+
markFieldDirty(ctx.dirtyFields, ctx.dirtyFieldCount, name);
|
|
676
1071
|
if (ctx.options.mode === "onChange") validate(name);
|
|
677
1072
|
handleFocus(clampedIndex, values.length, focusOptions);
|
|
678
1073
|
return true;
|
|
679
1074
|
};
|
|
680
1075
|
const swap = (indexA, indexB) => {
|
|
681
1076
|
const currentValues = get(ctx.formData, name) || [];
|
|
682
|
-
if (indexA < 0 || indexB < 0 || indexA >= currentValues.length || indexB >= currentValues.length)
|
|
1077
|
+
if (indexA < 0 || indexB < 0 || indexA >= currentValues.length || indexB >= currentValues.length) {
|
|
1078
|
+
if (__DEV__) warnArrayIndexOutOfBounds("swap", name, indexA < 0 || indexA >= currentValues.length ? indexA : indexB, currentValues.length);
|
|
1079
|
+
return false;
|
|
1080
|
+
}
|
|
683
1081
|
const newValues = [...currentValues];
|
|
684
1082
|
[newValues[indexA], newValues[indexB]] = [newValues[indexB], newValues[indexA]];
|
|
685
1083
|
set(ctx.formData, name, newValues);
|
|
@@ -690,18 +1088,18 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
690
1088
|
newItems[indexA] = itemB;
|
|
691
1089
|
newItems[indexB] = itemA;
|
|
692
1090
|
fa.items.value = newItems;
|
|
693
|
-
|
|
1091
|
+
swapInCache(indexA, indexB);
|
|
694
1092
|
}
|
|
695
|
-
ctx.dirtyFields.
|
|
696
|
-
...ctx.dirtyFields.value,
|
|
697
|
-
[name]: true
|
|
698
|
-
};
|
|
1093
|
+
markFieldDirty(ctx.dirtyFields, ctx.dirtyFieldCount, name);
|
|
699
1094
|
if (ctx.options.mode === "onChange") validate(name);
|
|
700
1095
|
return true;
|
|
701
1096
|
};
|
|
702
1097
|
const move = (from, to) => {
|
|
703
1098
|
const currentValues = get(ctx.formData, name) || [];
|
|
704
|
-
if (from < 0 || from >= currentValues.length || to < 0)
|
|
1099
|
+
if (from < 0 || from >= currentValues.length || to < 0) {
|
|
1100
|
+
if (__DEV__) warnArrayIndexOutOfBounds("move", name, from < 0 || from >= currentValues.length ? from : to, currentValues.length);
|
|
1101
|
+
return false;
|
|
1102
|
+
}
|
|
705
1103
|
const newValues = [...currentValues];
|
|
706
1104
|
const [removed] = newValues.splice(from, 1);
|
|
707
1105
|
if (removed !== void 0) {
|
|
@@ -715,12 +1113,15 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
715
1113
|
const clampedTo = Math.min(to, newItems.length);
|
|
716
1114
|
newItems.splice(clampedTo, 0, removedItem);
|
|
717
1115
|
fa.items.value = newItems;
|
|
718
|
-
|
|
1116
|
+
const minIdx = Math.min(from, clampedTo);
|
|
1117
|
+
const maxIdx = Math.max(from, clampedTo);
|
|
1118
|
+
const items = fa.items.value;
|
|
1119
|
+
for (let i = minIdx; i <= maxIdx; i++) {
|
|
1120
|
+
const item = items[i];
|
|
1121
|
+
if (item) indexCache.set(item.key, i);
|
|
1122
|
+
}
|
|
719
1123
|
}
|
|
720
|
-
ctx.dirtyFields.
|
|
721
|
-
...ctx.dirtyFields.value,
|
|
722
|
-
[name]: true
|
|
723
|
-
};
|
|
1124
|
+
markFieldDirty(ctx.dirtyFields, ctx.dirtyFieldCount, name);
|
|
724
1125
|
if (ctx.options.mode === "onChange") validate(name);
|
|
725
1126
|
return true;
|
|
726
1127
|
};
|
|
@@ -729,23 +1130,23 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
729
1130
|
set(ctx.formData, name, newValues);
|
|
730
1131
|
fa.items.value = newValues.map(() => createItem(generateId()));
|
|
731
1132
|
rebuildIndexCache();
|
|
732
|
-
ctx.dirtyFields.
|
|
733
|
-
...ctx.dirtyFields.value,
|
|
734
|
-
[name]: true
|
|
735
|
-
};
|
|
1133
|
+
markFieldDirty(ctx.dirtyFields, ctx.dirtyFieldCount, name);
|
|
736
1134
|
if (ctx.options.mode === "onChange") validate(name);
|
|
737
1135
|
return true;
|
|
738
1136
|
};
|
|
739
1137
|
const removeAll = () => {
|
|
740
1138
|
const rules = fa.rules;
|
|
741
|
-
if (rules?.minLength && rules.minLength.value > 0)
|
|
1139
|
+
if (rules?.minLength && rules.minLength.value > 0) {
|
|
1140
|
+
if (__DEV__) warnArrayOperationRejected("removeAll", name, "minLength", {
|
|
1141
|
+
current: fa.items.value.length,
|
|
1142
|
+
limit: rules.minLength.value
|
|
1143
|
+
});
|
|
1144
|
+
return false;
|
|
1145
|
+
}
|
|
742
1146
|
set(ctx.formData, name, []);
|
|
743
1147
|
fa.items.value = [];
|
|
744
|
-
|
|
745
|
-
ctx.dirtyFields.
|
|
746
|
-
...ctx.dirtyFields.value,
|
|
747
|
-
[name]: true
|
|
748
|
-
};
|
|
1148
|
+
indexCache.clear();
|
|
1149
|
+
markFieldDirty(ctx.dirtyFields, ctx.dirtyFieldCount, name);
|
|
749
1150
|
if (ctx.options.mode === "onChange") validate(name);
|
|
750
1151
|
return true;
|
|
751
1152
|
};
|
|
@@ -755,17 +1156,24 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
755
1156
|
if (validIndices.length === 0) return true;
|
|
756
1157
|
const rules = fa.rules;
|
|
757
1158
|
const remainingCount = currentValues.length - validIndices.length;
|
|
758
|
-
if (rules?.minLength && remainingCount < rules.minLength.value)
|
|
1159
|
+
if (rules?.minLength && remainingCount < rules.minLength.value) {
|
|
1160
|
+
if (__DEV__) warnArrayOperationRejected("removeMany", name, "minLength", {
|
|
1161
|
+
current: currentValues.length,
|
|
1162
|
+
limit: rules.minLength.value
|
|
1163
|
+
});
|
|
1164
|
+
return false;
|
|
1165
|
+
}
|
|
759
1166
|
const sortedIndices = [...new Set(validIndices)].sort((a, b) => b - a);
|
|
760
1167
|
const indicesToRemove = new Set(sortedIndices);
|
|
1168
|
+
const keysToRemove = fa.items.value.filter((_, i) => indicesToRemove.has(i)).map((item) => item.key);
|
|
761
1169
|
const newValues = currentValues.filter((_, i) => !indicesToRemove.has(i));
|
|
762
1170
|
set(ctx.formData, name, newValues);
|
|
763
1171
|
fa.items.value = fa.items.value.filter((_, i) => !indicesToRemove.has(i));
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
1172
|
+
for (const key of keysToRemove) indexCache.delete(key);
|
|
1173
|
+
fa.items.value.forEach((item, idx) => {
|
|
1174
|
+
indexCache.set(item.key, idx);
|
|
1175
|
+
});
|
|
1176
|
+
markFieldDirty(ctx.dirtyFields, ctx.dirtyFieldCount, name);
|
|
769
1177
|
if (ctx.options.mode === "onChange") validate(name);
|
|
770
1178
|
return true;
|
|
771
1179
|
};
|
|
@@ -797,38 +1205,19 @@ function updateDomElement(el, value) {
|
|
|
797
1205
|
if (el.type === "checkbox") el.checked = value;
|
|
798
1206
|
else el.value = value;
|
|
799
1207
|
}
|
|
800
|
-
function markFieldDirty(dirtyFields, fieldName) {
|
|
801
|
-
dirtyFields.value = {
|
|
802
|
-
...dirtyFields.value,
|
|
803
|
-
[fieldName]: true
|
|
804
|
-
};
|
|
805
|
-
}
|
|
806
|
-
function markFieldTouched(touchedFields, fieldName) {
|
|
807
|
-
touchedFields.value = {
|
|
808
|
-
...touchedFields.value,
|
|
809
|
-
[fieldName]: true
|
|
810
|
-
};
|
|
811
|
-
}
|
|
812
|
-
function clearFieldDirty(dirtyFields, fieldName) {
|
|
813
|
-
const newDirty = { ...dirtyFields.value };
|
|
814
|
-
delete newDirty[fieldName];
|
|
815
|
-
dirtyFields.value = newDirty;
|
|
816
|
-
}
|
|
817
|
-
function clearFieldTouched(touchedFields, fieldName) {
|
|
818
|
-
const newTouched = { ...touchedFields.value };
|
|
819
|
-
delete newTouched[fieldName];
|
|
820
|
-
touchedFields.value = newTouched;
|
|
821
|
-
}
|
|
822
|
-
function clearFieldErrors(errors, fieldName) {
|
|
823
|
-
const newErrors = { ...errors.value };
|
|
824
|
-
for (const key of Object.keys(newErrors)) if (key === fieldName || key.startsWith(`${fieldName}.`)) delete newErrors[key];
|
|
825
|
-
errors.value = newErrors;
|
|
826
|
-
}
|
|
827
1208
|
function useForm(options) {
|
|
828
1209
|
const ctx = createFormContext(options);
|
|
829
1210
|
const { validate, clearAllPendingErrors } = createValidation(ctx);
|
|
830
1211
|
const { register, unregister } = createFieldRegistration(ctx, validate);
|
|
831
1212
|
function setFocus(name, focusOptions) {
|
|
1213
|
+
if (__DEV__) {
|
|
1214
|
+
const syntaxError = validatePathSyntax(name);
|
|
1215
|
+
if (syntaxError) warnInvalidPath("setFocus", name, syntaxError);
|
|
1216
|
+
else {
|
|
1217
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, name);
|
|
1218
|
+
if (!schemaResult.valid) warnPathNotInSchema("setFocus", name, schemaResult.availableFields);
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
832
1221
|
const fieldRef = ctx.fieldRefs.get(name);
|
|
833
1222
|
if (!fieldRef?.value) return;
|
|
834
1223
|
const el = fieldRef.value;
|
|
@@ -839,32 +1228,84 @@ function useForm(options) {
|
|
|
839
1228
|
}
|
|
840
1229
|
const setFocusWrapper = (name) => setFocus(name);
|
|
841
1230
|
const { fields } = createFieldArrayManager(ctx, validate, setFocusWrapper);
|
|
1231
|
+
let lastSyncTime = 0;
|
|
1232
|
+
const SYNC_DEBOUNCE_MS = 16;
|
|
1233
|
+
function syncWithDebounce() {
|
|
1234
|
+
const now = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
1235
|
+
if (now - lastSyncTime < SYNC_DEBOUNCE_MS) return;
|
|
1236
|
+
syncUncontrolledInputs(ctx.fieldRefs, ctx.fieldOptions, ctx.formData);
|
|
1237
|
+
lastSyncTime = now;
|
|
1238
|
+
}
|
|
1239
|
+
let lastErrors = ctx.errors.value;
|
|
1240
|
+
let lastExternalErrors = ctx.externalErrors.value;
|
|
1241
|
+
let cachedMergedErrors = null;
|
|
842
1242
|
function getMergedErrors() {
|
|
843
|
-
return
|
|
1243
|
+
if (cachedMergedErrors !== null && lastErrors === ctx.errors.value && lastExternalErrors === ctx.externalErrors.value) return cachedMergedErrors;
|
|
1244
|
+
lastErrors = ctx.errors.value;
|
|
1245
|
+
lastExternalErrors = ctx.externalErrors.value;
|
|
1246
|
+
cachedMergedErrors = {
|
|
844
1247
|
...ctx.errors.value,
|
|
845
1248
|
...ctx.externalErrors.value
|
|
846
1249
|
};
|
|
1250
|
+
return cachedMergedErrors;
|
|
847
1251
|
}
|
|
848
|
-
const
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
}
|
|
1252
|
+
const isDirtyComputed = (0, vue.computed)(() => ctx.dirtyFieldCount.value > 0);
|
|
1253
|
+
const errorsComputed = (0, vue.computed)(() => getMergedErrors());
|
|
1254
|
+
const isValidComputed = (0, vue.computed)(() => {
|
|
1255
|
+
if (!(ctx.submitCount.value > 0 || ctx.touchedFieldCount.value > 0)) return false;
|
|
1256
|
+
return Object.keys(errorsComputed.value).length === 0;
|
|
1257
|
+
});
|
|
1258
|
+
const isReadyComputed = (0, vue.computed)(() => !ctx.isLoading.value);
|
|
1259
|
+
const isValidatingComputed = (0, vue.computed)(() => ctx.validatingFields.value.size > 0);
|
|
1260
|
+
const isSubmittedComputed = (0, vue.computed)(() => ctx.submitCount.value > 0);
|
|
1261
|
+
const formStateInternal = (0, vue.reactive)({
|
|
1262
|
+
get errors() {
|
|
1263
|
+
return errorsComputed.value;
|
|
1264
|
+
},
|
|
1265
|
+
get isDirty() {
|
|
1266
|
+
return isDirtyComputed.value;
|
|
1267
|
+
},
|
|
1268
|
+
get dirtyFields() {
|
|
1269
|
+
return ctx.dirtyFields.value;
|
|
1270
|
+
},
|
|
1271
|
+
get isValid() {
|
|
1272
|
+
return isValidComputed.value;
|
|
1273
|
+
},
|
|
1274
|
+
get isSubmitting() {
|
|
1275
|
+
return ctx.isSubmitting.value;
|
|
1276
|
+
},
|
|
1277
|
+
get isLoading() {
|
|
1278
|
+
return ctx.isLoading.value;
|
|
1279
|
+
},
|
|
1280
|
+
get isReady() {
|
|
1281
|
+
return isReadyComputed.value;
|
|
1282
|
+
},
|
|
1283
|
+
get isValidating() {
|
|
1284
|
+
return isValidatingComputed.value;
|
|
1285
|
+
},
|
|
1286
|
+
get validatingFields() {
|
|
1287
|
+
return ctx.validatingFields.value;
|
|
1288
|
+
},
|
|
1289
|
+
get touchedFields() {
|
|
1290
|
+
return ctx.touchedFields.value;
|
|
1291
|
+
},
|
|
1292
|
+
get submitCount() {
|
|
1293
|
+
return ctx.submitCount.value;
|
|
1294
|
+
},
|
|
1295
|
+
get defaultValuesError() {
|
|
1296
|
+
return ctx.defaultValuesError.value;
|
|
1297
|
+
},
|
|
1298
|
+
get isSubmitted() {
|
|
1299
|
+
return isSubmittedComputed.value;
|
|
1300
|
+
},
|
|
1301
|
+
get isSubmitSuccessful() {
|
|
1302
|
+
return ctx.isSubmitSuccessful.value;
|
|
1303
|
+
},
|
|
1304
|
+
get disabled() {
|
|
1305
|
+
return ctx.isDisabled.value;
|
|
1306
|
+
}
|
|
867
1307
|
});
|
|
1308
|
+
const formState = (0, vue.computed)(() => formStateInternal);
|
|
868
1309
|
function handleSubmit(onValid, onInvalid) {
|
|
869
1310
|
return async (e) => {
|
|
870
1311
|
e.preventDefault();
|
|
@@ -874,7 +1315,7 @@ function useForm(options) {
|
|
|
874
1315
|
ctx.submitCount.value++;
|
|
875
1316
|
ctx.isSubmitSuccessful.value = false;
|
|
876
1317
|
try {
|
|
877
|
-
|
|
1318
|
+
syncWithDebounce();
|
|
878
1319
|
if (await validate()) {
|
|
879
1320
|
await onValid(ctx.formData);
|
|
880
1321
|
ctx.isSubmitSuccessful.value = true;
|
|
@@ -891,9 +1332,17 @@ function useForm(options) {
|
|
|
891
1332
|
};
|
|
892
1333
|
}
|
|
893
1334
|
function setValue(name, value, setValueOptions) {
|
|
1335
|
+
if (__DEV__) {
|
|
1336
|
+
const syntaxError = validatePathSyntax(name);
|
|
1337
|
+
if (syntaxError) warnInvalidPath("setValue", name, syntaxError);
|
|
1338
|
+
else {
|
|
1339
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, name);
|
|
1340
|
+
if (!schemaResult.valid) warnPathNotInSchema("setValue", name, schemaResult.availableFields);
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
894
1343
|
set(ctx.formData, name, value);
|
|
895
|
-
if (setValueOptions?.shouldDirty !== false) markFieldDirty(ctx.dirtyFields, name);
|
|
896
|
-
if (setValueOptions?.shouldTouch) markFieldTouched(ctx.touchedFields, name);
|
|
1344
|
+
if (setValueOptions?.shouldDirty !== false) markFieldDirty(ctx.dirtyFields, ctx.dirtyFieldCount, name);
|
|
1345
|
+
if (setValueOptions?.shouldTouch) markFieldTouched(ctx.touchedFields, ctx.touchedFieldCount, name);
|
|
897
1346
|
if (!ctx.fieldOptions.get(name)?.controlled) {
|
|
898
1347
|
const fieldRef = ctx.fieldRefs.get(name);
|
|
899
1348
|
if (fieldRef?.value) updateDomElement(fieldRef.value, value);
|
|
@@ -904,15 +1353,23 @@ function useForm(options) {
|
|
|
904
1353
|
const opts = resetOptions || {};
|
|
905
1354
|
ctx.resetGeneration.value++;
|
|
906
1355
|
clearAllPendingErrors();
|
|
907
|
-
ctx.validatingFields.value =
|
|
1356
|
+
ctx.validatingFields.value = /* @__PURE__ */ new Set();
|
|
1357
|
+
ctx.validationCache.clear();
|
|
1358
|
+
for (const timer of ctx.schemaValidationTimers.values()) clearTimeout(timer);
|
|
1359
|
+
ctx.schemaValidationTimers.clear();
|
|
908
1360
|
if (!opts.keepDefaultValues && values) Object.assign(ctx.defaultValues, values);
|
|
909
1361
|
Object.keys(ctx.formData).forEach((key) => delete ctx.formData[key]);
|
|
910
|
-
const
|
|
911
|
-
const newValues = JSON.parse(JSON.stringify(sourceValues));
|
|
1362
|
+
const newValues = deepClone(values || ctx.defaultValues);
|
|
912
1363
|
Object.assign(ctx.formData, newValues);
|
|
913
1364
|
if (!opts.keepErrors) ctx.errors.value = {};
|
|
914
|
-
if (!opts.keepTouched)
|
|
915
|
-
|
|
1365
|
+
if (!opts.keepTouched) {
|
|
1366
|
+
ctx.touchedFields.value = {};
|
|
1367
|
+
ctx.touchedFieldCount.value = 0;
|
|
1368
|
+
}
|
|
1369
|
+
if (!opts.keepDirty) {
|
|
1370
|
+
ctx.dirtyFields.value = {};
|
|
1371
|
+
ctx.dirtyFieldCount.value = 0;
|
|
1372
|
+
}
|
|
916
1373
|
if (!opts.keepSubmitCount) ctx.submitCount.value = 0;
|
|
917
1374
|
if (!opts.keepIsSubmitting) ctx.isSubmitting.value = false;
|
|
918
1375
|
if (!opts.keepIsSubmitSuccessful) ctx.isSubmitSuccessful.value = false;
|
|
@@ -927,6 +1384,14 @@ function useForm(options) {
|
|
|
927
1384
|
}
|
|
928
1385
|
}
|
|
929
1386
|
function resetField(name, resetFieldOptions) {
|
|
1387
|
+
if (__DEV__) {
|
|
1388
|
+
const syntaxError = validatePathSyntax(name);
|
|
1389
|
+
if (syntaxError) warnInvalidPath("resetField", name, syntaxError);
|
|
1390
|
+
else {
|
|
1391
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, name);
|
|
1392
|
+
if (!schemaResult.valid) warnPathNotInSchema("resetField", name, schemaResult.availableFields);
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
930
1395
|
const opts = resetFieldOptions || {};
|
|
931
1396
|
ctx.resetGeneration.value++;
|
|
932
1397
|
const errorTimer = ctx.errorDelayTimers.get(name);
|
|
@@ -938,17 +1403,28 @@ function useForm(options) {
|
|
|
938
1403
|
let defaultValue = opts.defaultValue;
|
|
939
1404
|
if (defaultValue === void 0) defaultValue = get(ctx.defaultValues, name);
|
|
940
1405
|
else set(ctx.defaultValues, name, defaultValue);
|
|
941
|
-
const clonedValue = defaultValue !== void 0 ?
|
|
1406
|
+
const clonedValue = defaultValue !== void 0 ? deepClone(defaultValue) : void 0;
|
|
942
1407
|
set(ctx.formData, name, clonedValue);
|
|
943
1408
|
if (!opts.keepError) clearFieldErrors(ctx.errors, name);
|
|
944
|
-
if (!opts.keepDirty) clearFieldDirty(ctx.dirtyFields, name);
|
|
945
|
-
if (!opts.keepTouched) clearFieldTouched(ctx.touchedFields, name);
|
|
1409
|
+
if (!opts.keepDirty) clearFieldDirty(ctx.dirtyFields, ctx.dirtyFieldCount, name);
|
|
1410
|
+
if (!opts.keepTouched) clearFieldTouched(ctx.touchedFields, ctx.touchedFieldCount, name);
|
|
946
1411
|
if (!ctx.fieldOptions.get(name)?.controlled) {
|
|
947
1412
|
const fieldRef = ctx.fieldRefs.get(name);
|
|
948
1413
|
if (fieldRef?.value) updateDomElement(fieldRef.value, clonedValue ?? (fieldRef.value.type === "checkbox" ? false : ""));
|
|
949
1414
|
}
|
|
950
1415
|
}
|
|
951
1416
|
function watch$1(name) {
|
|
1417
|
+
if (__DEV__ && name) {
|
|
1418
|
+
const names = Array.isArray(name) ? name : [name];
|
|
1419
|
+
for (const n of names) {
|
|
1420
|
+
const syntaxError = validatePathSyntax(n);
|
|
1421
|
+
if (syntaxError) warnInvalidPath("watch", n, syntaxError);
|
|
1422
|
+
else {
|
|
1423
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, n);
|
|
1424
|
+
if (!schemaResult.valid) warnPathNotInSchema("watch", n, schemaResult.availableFields);
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
952
1428
|
return (0, vue.computed)(() => {
|
|
953
1429
|
if (!name) return ctx.formData;
|
|
954
1430
|
if (Array.isArray(name)) {
|
|
@@ -960,6 +1436,18 @@ function useForm(options) {
|
|
|
960
1436
|
});
|
|
961
1437
|
}
|
|
962
1438
|
function clearErrors(name) {
|
|
1439
|
+
if (__DEV__ && name && !String(name).startsWith("root")) {
|
|
1440
|
+
const names = Array.isArray(name) ? name : [name];
|
|
1441
|
+
for (const n of names) {
|
|
1442
|
+
if (String(n).startsWith("root")) continue;
|
|
1443
|
+
const syntaxError = validatePathSyntax(n);
|
|
1444
|
+
if (syntaxError) warnInvalidPath("clearErrors", n, syntaxError);
|
|
1445
|
+
else {
|
|
1446
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, n);
|
|
1447
|
+
if (!schemaResult.valid) warnPathNotInSchema("clearErrors", n, schemaResult.availableFields);
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
963
1451
|
if (name === void 0) {
|
|
964
1452
|
ctx.errors.value = {};
|
|
965
1453
|
return;
|
|
@@ -998,7 +1486,18 @@ function useForm(options) {
|
|
|
998
1486
|
return get(mergedErrors, fieldPath);
|
|
999
1487
|
}
|
|
1000
1488
|
function getValues(nameOrNames) {
|
|
1001
|
-
|
|
1489
|
+
if (__DEV__ && nameOrNames) {
|
|
1490
|
+
const names = Array.isArray(nameOrNames) ? nameOrNames : [nameOrNames];
|
|
1491
|
+
for (const n of names) {
|
|
1492
|
+
const syntaxError = validatePathSyntax(n);
|
|
1493
|
+
if (syntaxError) warnInvalidPath("getValues", n, syntaxError);
|
|
1494
|
+
else {
|
|
1495
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, n);
|
|
1496
|
+
if (!schemaResult.valid) warnPathNotInSchema("getValues", n, schemaResult.availableFields);
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
syncWithDebounce();
|
|
1002
1501
|
if (nameOrNames === void 0) return { ...ctx.formData };
|
|
1003
1502
|
if (Array.isArray(nameOrNames)) {
|
|
1004
1503
|
const result = {};
|
|
@@ -1008,6 +1507,14 @@ function useForm(options) {
|
|
|
1008
1507
|
return get(ctx.formData, nameOrNames);
|
|
1009
1508
|
}
|
|
1010
1509
|
function getFieldState(name) {
|
|
1510
|
+
if (__DEV__) {
|
|
1511
|
+
const syntaxError = validatePathSyntax(name);
|
|
1512
|
+
if (syntaxError) warnInvalidPath("getFieldState", name, syntaxError);
|
|
1513
|
+
else {
|
|
1514
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, name);
|
|
1515
|
+
if (!schemaResult.valid) warnPathNotInSchema("getFieldState", name, schemaResult.availableFields);
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1011
1518
|
const error = get(ctx.errors.value, name);
|
|
1012
1519
|
return {
|
|
1013
1520
|
isDirty: ctx.dirtyFields.value[name] === true,
|
|
@@ -1017,6 +1524,17 @@ function useForm(options) {
|
|
|
1017
1524
|
};
|
|
1018
1525
|
}
|
|
1019
1526
|
async function trigger(name) {
|
|
1527
|
+
if (__DEV__ && name) {
|
|
1528
|
+
const names = Array.isArray(name) ? name : [name];
|
|
1529
|
+
for (const n of names) {
|
|
1530
|
+
const syntaxError = validatePathSyntax(n);
|
|
1531
|
+
if (syntaxError) warnInvalidPath("trigger", n, syntaxError);
|
|
1532
|
+
else {
|
|
1533
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, n);
|
|
1534
|
+
if (!schemaResult.valid) warnPathNotInSchema("trigger", n, schemaResult.availableFields);
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1020
1538
|
if (name === void 0) return await validate();
|
|
1021
1539
|
if (Array.isArray(name)) {
|
|
1022
1540
|
let allValid = true;
|