@vuehookform/core 0.4.2 → 0.4.4
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 +53 -9
- package/package.json +7 -1
- package/dist/context.d.ts +0 -37
- package/dist/core/domSync.d.ts +0 -27
- package/dist/core/fieldState.d.ts +0 -53
- package/dist/core/formContext.d.ts +0 -117
- package/dist/core/useFieldArray.d.ts +0 -8
- package/dist/core/useFieldRegistration.d.ts +0 -9
- package/dist/core/useValidation.d.ts +0 -8
- package/dist/index.d.ts +0 -24
- package/dist/types.d.ts +0 -889
- package/dist/useController.d.ts +0 -63
- package/dist/useForm.d.ts +0 -20
- package/dist/useFormState.d.ts +0 -39
- package/dist/useWatch.d.ts +0 -46
- package/dist/utils/clone.d.ts +0 -19
- package/dist/utils/devWarnings.d.ts +0 -55
- package/dist/utils/hash.d.ts +0 -9
- package/dist/utils/modeChecks.d.ts +0 -22
- package/dist/utils/paths.d.ts +0 -53
- package/dist/utils/schemaExtract.d.ts +0 -42
- package/dist/vuehookform.cjs +0 -1823
- package/dist/vuehookform.js +0 -1809
package/dist/vuehookform.cjs
DELETED
|
@@ -1,1823 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
let vue = require("vue");
|
|
3
|
-
var pathCache = /* @__PURE__ */ new Map();
|
|
4
|
-
var PATH_CACHE_MAX_SIZE = 256;
|
|
5
|
-
var MAX_ARRAY_INDEX = 1e4;
|
|
6
|
-
function getPathSegments(path) {
|
|
7
|
-
let segments = pathCache.get(path);
|
|
8
|
-
if (segments) return segments;
|
|
9
|
-
segments = path.split(".");
|
|
10
|
-
if (pathCache.size >= PATH_CACHE_MAX_SIZE) {
|
|
11
|
-
const firstKey = pathCache.keys().next().value;
|
|
12
|
-
if (firstKey !== void 0) pathCache.delete(firstKey);
|
|
13
|
-
}
|
|
14
|
-
pathCache.set(path, segments);
|
|
15
|
-
return segments;
|
|
16
|
-
}
|
|
17
|
-
function clearPathCache() {
|
|
18
|
-
pathCache.clear();
|
|
19
|
-
}
|
|
20
|
-
function get(obj, path) {
|
|
21
|
-
if (!path || obj === null || obj === void 0) return obj;
|
|
22
|
-
const keys = getPathSegments(path);
|
|
23
|
-
let result = obj;
|
|
24
|
-
for (const key of keys) {
|
|
25
|
-
if (result === null || result === void 0) return;
|
|
26
|
-
result = result[key];
|
|
27
|
-
}
|
|
28
|
-
return result;
|
|
29
|
-
}
|
|
30
|
-
function set(obj, path, value) {
|
|
31
|
-
if (!path) return;
|
|
32
|
-
const keys = getPathSegments(path).slice();
|
|
33
|
-
const UNSAFE_KEYS = [
|
|
34
|
-
"__proto__",
|
|
35
|
-
"constructor",
|
|
36
|
-
"prototype"
|
|
37
|
-
];
|
|
38
|
-
if (keys.some((k) => UNSAFE_KEYS.includes(k))) return;
|
|
39
|
-
for (const key of keys) if (/^\d+$/.test(key)) {
|
|
40
|
-
const index = parseInt(key, 10);
|
|
41
|
-
if (index > MAX_ARRAY_INDEX) {
|
|
42
|
-
if (typeof console !== "undefined" && console.warn) console.warn(`[vue-hook-form] set(): Array index ${index} exceeds maximum allowed (${MAX_ARRAY_INDEX}). Path "${path}" was not set to prevent memory exhaustion.`);
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
const lastKey = keys.pop();
|
|
47
|
-
let current = obj;
|
|
48
|
-
for (let i = 0; i < keys.length; i++) {
|
|
49
|
-
const key = keys[i];
|
|
50
|
-
const existing = current[key];
|
|
51
|
-
if (existing !== void 0 && existing !== null && typeof existing !== "object") try {
|
|
52
|
-
if (globalThis.process?.env?.NODE_ENV !== "production") console.warn(`[vue-hook-form] set(): Overwriting primitive value at path "${keys.slice(0, i + 1).join(".")}" with an object. Previous value: ${JSON.stringify(existing)}`);
|
|
53
|
-
} catch {}
|
|
54
|
-
if (!(key in current) || typeof current[key] !== "object" || current[key] === null) {
|
|
55
|
-
const nextKey = keys[i + 1];
|
|
56
|
-
current[key] = nextKey && /^\d+$/.test(nextKey) ? [] : {};
|
|
57
|
-
}
|
|
58
|
-
current = current[key];
|
|
59
|
-
}
|
|
60
|
-
current[lastKey] = value;
|
|
61
|
-
}
|
|
62
|
-
function unset(obj, path) {
|
|
63
|
-
if (!path) return;
|
|
64
|
-
const keys = getPathSegments(path).slice();
|
|
65
|
-
const lastKey = keys.pop();
|
|
66
|
-
let current = obj;
|
|
67
|
-
for (const key of keys) {
|
|
68
|
-
if (!(key in current)) return;
|
|
69
|
-
const next = current[key];
|
|
70
|
-
if (next === null || typeof next !== "object") return;
|
|
71
|
-
current = next;
|
|
72
|
-
}
|
|
73
|
-
delete current[lastKey];
|
|
74
|
-
}
|
|
75
|
-
var idCounter = 0;
|
|
76
|
-
function generateId() {
|
|
77
|
-
const random = Math.random().toString(36).substring(2, 11);
|
|
78
|
-
return `field_${Date.now()}_${idCounter++}_${random}`;
|
|
79
|
-
}
|
|
80
|
-
function deepClone(obj, seen) {
|
|
81
|
-
if (obj === null || obj === void 0) return obj;
|
|
82
|
-
if (typeof obj !== "object") return obj;
|
|
83
|
-
if (obj instanceof Date) return new Date(obj.getTime());
|
|
84
|
-
if (!seen) seen = /* @__PURE__ */ new Map();
|
|
85
|
-
const existingClone = seen.get(obj);
|
|
86
|
-
if (existingClone !== void 0) return existingClone;
|
|
87
|
-
if (Array.isArray(obj)) {
|
|
88
|
-
const clonedArray = [];
|
|
89
|
-
seen.set(obj, clonedArray);
|
|
90
|
-
for (const item of obj) clonedArray.push(deepClone(item, seen));
|
|
91
|
-
return clonedArray;
|
|
92
|
-
}
|
|
93
|
-
const cloned = {};
|
|
94
|
-
seen.set(obj, cloned);
|
|
95
|
-
for (const key in obj) if (Object.prototype.hasOwnProperty.call(obj, key)) cloned[key] = deepClone(obj[key], seen);
|
|
96
|
-
return cloned;
|
|
97
|
-
}
|
|
98
|
-
var proc = globalThis.process;
|
|
99
|
-
const __DEV__ = proc?.env?.NODE_ENV !== "production";
|
|
100
|
-
var warnedMessages = /* @__PURE__ */ new Set();
|
|
101
|
-
function warnOnce(message, key) {
|
|
102
|
-
if (!__DEV__) return;
|
|
103
|
-
const cacheKey = key ?? message;
|
|
104
|
-
if (warnedMessages.has(cacheKey)) return;
|
|
105
|
-
warnedMessages.add(cacheKey);
|
|
106
|
-
console.warn(`[vue-hook-form] ${message}`);
|
|
107
|
-
}
|
|
108
|
-
function warn(message) {
|
|
109
|
-
if (!__DEV__) return;
|
|
110
|
-
console.warn(`[vue-hook-form] ${message}`);
|
|
111
|
-
}
|
|
112
|
-
function validatePathSyntax(path) {
|
|
113
|
-
if (!__DEV__) return null;
|
|
114
|
-
if (!path || path.trim() === "") return "Path cannot be empty";
|
|
115
|
-
if (path.startsWith(".") || path.endsWith(".") || path.includes("..")) return `Invalid path "${path}": contains empty segments`;
|
|
116
|
-
if (path.includes("[")) return `Invalid path "${path}": use dot notation (e.g., "items.0") instead of bracket notation (e.g., "items[0]")`;
|
|
117
|
-
if (/\s/.test(path)) return `Invalid path "${path}": paths cannot contain whitespace`;
|
|
118
|
-
return null;
|
|
119
|
-
}
|
|
120
|
-
function traverseSchemaPath(schema, path) {
|
|
121
|
-
const segments = path.split(".");
|
|
122
|
-
let currentSchema = schema;
|
|
123
|
-
for (let i = 0; i < segments.length; i++) {
|
|
124
|
-
const segment = segments[i];
|
|
125
|
-
if (!segment) continue;
|
|
126
|
-
currentSchema = unwrapSchema(currentSchema);
|
|
127
|
-
if (isZodObject$1(currentSchema)) {
|
|
128
|
-
const shape = currentSchema.shape;
|
|
129
|
-
if (segment in shape) {
|
|
130
|
-
const nextSchema = shape[segment];
|
|
131
|
-
if (nextSchema) {
|
|
132
|
-
currentSchema = nextSchema;
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
return {
|
|
137
|
-
error: `Field "${segments.slice(0, i + 1).join(".")}" does not exist in schema`,
|
|
138
|
-
availableFields: Object.keys(shape),
|
|
139
|
-
segmentIndex: i
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
if (isZodArray$1(currentSchema) && /^\d+$/.test(segment)) {
|
|
143
|
-
currentSchema = currentSchema.element;
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
return {
|
|
147
|
-
error: `Cannot navigate path "${path}" at segment "${segment}"`,
|
|
148
|
-
segmentIndex: i
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
return { schema: currentSchema };
|
|
152
|
-
}
|
|
153
|
-
function validatePathAgainstSchema(schema, path) {
|
|
154
|
-
if (!__DEV__) return { valid: true };
|
|
155
|
-
try {
|
|
156
|
-
const result = traverseSchemaPath(schema, path);
|
|
157
|
-
if ("error" in result) return {
|
|
158
|
-
valid: false,
|
|
159
|
-
reason: result.error,
|
|
160
|
-
availableFields: result.availableFields
|
|
161
|
-
};
|
|
162
|
-
return { valid: true };
|
|
163
|
-
} catch {
|
|
164
|
-
return { valid: true };
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
function isArrayFieldInSchema(schema, path) {
|
|
168
|
-
if (!__DEV__) return null;
|
|
169
|
-
try {
|
|
170
|
-
const result = traverseSchemaPath(schema, path);
|
|
171
|
-
if ("error" in result) return null;
|
|
172
|
-
return isZodArray$1(unwrapSchema(result.schema));
|
|
173
|
-
} catch {
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
function warnInvalidPath(fnName, path, reason) {
|
|
178
|
-
if (!__DEV__) return;
|
|
179
|
-
let message = `${fnName}("${path}"): ${reason}`;
|
|
180
|
-
if (reason.includes("bracket notation")) {
|
|
181
|
-
const fixedPath = path.replace(/\[(\d+)\]/g, ".$1");
|
|
182
|
-
message += `\n FIX: Use dot notation for array indices`;
|
|
183
|
-
message += `\n EXAMPLE: ${fnName}("${fixedPath}")`;
|
|
184
|
-
} else if (reason.includes("empty")) {
|
|
185
|
-
message += `\n FIX: Provide a non-empty field path`;
|
|
186
|
-
message += `\n EXAMPLE: ${fnName}("email") or ${fnName}("user.address.city")`;
|
|
187
|
-
} else if (reason.includes("whitespace")) {
|
|
188
|
-
const fixedPath = path.replace(/\s/g, "");
|
|
189
|
-
message += `\n FIX: Remove spaces from the field path`;
|
|
190
|
-
message += `\n EXAMPLE: ${fnName}("${fixedPath}")`;
|
|
191
|
-
} else if (reason.includes("empty segments")) {
|
|
192
|
-
const fixedPath = path.replace(/\.{2,}/g, ".").replace(/^\./, "").replace(/\.$/, "");
|
|
193
|
-
message += `\n FIX: Remove extra dots from the path`;
|
|
194
|
-
message += `\n EXAMPLE: ${fnName}("${fixedPath}")`;
|
|
195
|
-
}
|
|
196
|
-
warnOnce(message, `invalid-path:${fnName}:${path}`);
|
|
197
|
-
}
|
|
198
|
-
function warnPathNotInSchema(fnName, path, availableFields) {
|
|
199
|
-
if (!__DEV__) return;
|
|
200
|
-
let message = `${fnName}("${path}"): Path does not exist in your Zod schema.`;
|
|
201
|
-
message += `\n FIX: Check that the path matches your schema definition exactly (case-sensitive)`;
|
|
202
|
-
if (availableFields && availableFields.length > 0) {
|
|
203
|
-
const pathLower = path.toLowerCase();
|
|
204
|
-
const suggestions = availableFields.filter((f) => f.toLowerCase().includes(pathLower) || pathLower.includes(f.toLowerCase()));
|
|
205
|
-
if (suggestions.length > 0) message += `\n DID YOU MEAN: ${suggestions.slice(0, 3).map((s) => `"${s}"`).join(", ")}`;
|
|
206
|
-
message += `\n AVAILABLE: ${availableFields.slice(0, 8).join(", ")}${availableFields.length > 8 ? "..." : ""}`;
|
|
207
|
-
}
|
|
208
|
-
warnOnce(message, `path-not-in-schema:${fnName}:${path}`);
|
|
209
|
-
}
|
|
210
|
-
function warnFieldsOnNonArray(path) {
|
|
211
|
-
if (!__DEV__) return;
|
|
212
|
-
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}`);
|
|
213
|
-
}
|
|
214
|
-
function warnArrayOperationRejected(operation, path, reason, details) {
|
|
215
|
-
if (!__DEV__) return;
|
|
216
|
-
warn(`${operation}() on "${path}": ${{
|
|
217
|
-
maxLength: details ? `Would exceed maxLength (current: ${details.current}, max: ${details.limit})` : "Would exceed maxLength rule",
|
|
218
|
-
minLength: details ? `Would violate minLength (current: ${details.current}, min: ${details.limit})` : "Would violate minLength rule"
|
|
219
|
-
}[reason]}. Operation was silently ignored.`);
|
|
220
|
-
}
|
|
221
|
-
function warnArrayIndexOutOfBounds(operation, path, index, length) {
|
|
222
|
-
if (!__DEV__) return;
|
|
223
|
-
warn(`${operation}() on "${path}": Index ${index} is out of bounds (array length: ${length}). Operation was silently ignored.`);
|
|
224
|
-
}
|
|
225
|
-
function getDefProp$1(schema, prop) {
|
|
226
|
-
return schema.def[prop];
|
|
227
|
-
}
|
|
228
|
-
function getTypeName(schema) {
|
|
229
|
-
return getDefProp$1(schema, "typeName");
|
|
230
|
-
}
|
|
231
|
-
function isZodObject$1(schema) {
|
|
232
|
-
return getTypeName(schema) === "ZodObject";
|
|
233
|
-
}
|
|
234
|
-
function isZodArray$1(schema) {
|
|
235
|
-
return getTypeName(schema) === "ZodArray";
|
|
236
|
-
}
|
|
237
|
-
function unwrapSchema(schema) {
|
|
238
|
-
const typeName = getTypeName(schema);
|
|
239
|
-
const innerType = getDefProp$1(schema, "innerType");
|
|
240
|
-
const schemaType = getDefProp$1(schema, "schema");
|
|
241
|
-
if ((typeName === "ZodOptional" || typeName === "ZodNullable" || typeName === "ZodDefault") && innerType) return unwrapSchema(innerType);
|
|
242
|
-
if (typeName === "ZodEffects" && schemaType) return unwrapSchema(schemaType);
|
|
243
|
-
return schema;
|
|
244
|
-
}
|
|
245
|
-
function createFormContext(options) {
|
|
246
|
-
const formData = (0, vue.reactive)({});
|
|
247
|
-
const defaultValues = (0, vue.reactive)({});
|
|
248
|
-
const isAsyncDefaults = typeof options.defaultValues === "function";
|
|
249
|
-
const isLoading = (0, vue.ref)(isAsyncDefaults);
|
|
250
|
-
if (isAsyncDefaults) {
|
|
251
|
-
const asyncFn = options.defaultValues;
|
|
252
|
-
asyncFn().then((values) => {
|
|
253
|
-
Object.assign(defaultValues, deepClone(values));
|
|
254
|
-
Object.assign(formData, deepClone(values));
|
|
255
|
-
isLoading.value = false;
|
|
256
|
-
}).catch((error) => {
|
|
257
|
-
console.error("Failed to load async default values:", error);
|
|
258
|
-
defaultValuesError.value = error;
|
|
259
|
-
isLoading.value = false;
|
|
260
|
-
options.onDefaultValuesError?.(error);
|
|
261
|
-
});
|
|
262
|
-
} else if (options.defaultValues) {
|
|
263
|
-
Object.assign(defaultValues, deepClone(options.defaultValues));
|
|
264
|
-
Object.assign(formData, deepClone(options.defaultValues));
|
|
265
|
-
}
|
|
266
|
-
const errors = (0, vue.shallowRef)({});
|
|
267
|
-
const touchedFields = (0, vue.shallowRef)({});
|
|
268
|
-
const dirtyFields = (0, vue.shallowRef)({});
|
|
269
|
-
const isSubmitting = (0, vue.ref)(false);
|
|
270
|
-
const submitCount = (0, vue.ref)(0);
|
|
271
|
-
const defaultValuesError = (0, vue.ref)(null);
|
|
272
|
-
const isSubmitSuccessful = (0, vue.ref)(false);
|
|
273
|
-
const validatingFields = (0, vue.shallowRef)(/* @__PURE__ */ new Set());
|
|
274
|
-
const externalErrors = (0, vue.shallowRef)({});
|
|
275
|
-
const errorDelayTimers = /* @__PURE__ */ new Map();
|
|
276
|
-
const pendingErrors = /* @__PURE__ */ new Map();
|
|
277
|
-
const fieldRefs = /* @__PURE__ */ new Map();
|
|
278
|
-
const fieldOptions = /* @__PURE__ */ new Map();
|
|
279
|
-
const fieldArrays = /* @__PURE__ */ new Map();
|
|
280
|
-
const fieldHandlers = /* @__PURE__ */ new Map();
|
|
281
|
-
const debounceTimers = /* @__PURE__ */ new Map();
|
|
282
|
-
const validationRequestIds = /* @__PURE__ */ new Map();
|
|
283
|
-
const resetGeneration = (0, vue.ref)(0);
|
|
284
|
-
const validationCache = /* @__PURE__ */ new Map();
|
|
285
|
-
const schemaValidationTimers = /* @__PURE__ */ new Map();
|
|
286
|
-
const persistentErrorFields = /* @__PURE__ */ new Set();
|
|
287
|
-
const defaultValueHashes = /* @__PURE__ */ new Map();
|
|
288
|
-
const isDisabled = (0, vue.ref)(false);
|
|
289
|
-
const watchStopHandles = [];
|
|
290
|
-
if (options.disabled !== void 0) {
|
|
291
|
-
isDisabled.value = (0, vue.toValue)(options.disabled) ?? false;
|
|
292
|
-
watchStopHandles.push((0, vue.watch)(() => (0, vue.toValue)(options.disabled), (newDisabled) => {
|
|
293
|
-
isDisabled.value = newDisabled ?? false;
|
|
294
|
-
}));
|
|
295
|
-
}
|
|
296
|
-
if (options.values !== void 0) {
|
|
297
|
-
const initialValues = (0, vue.toValue)(options.values);
|
|
298
|
-
if (initialValues && !isAsyncDefaults) {
|
|
299
|
-
for (const [key, value] of Object.entries(initialValues)) if (value !== void 0) set(formData, key, value);
|
|
300
|
-
}
|
|
301
|
-
watchStopHandles.push((0, vue.watch)(() => (0, vue.toValue)(options.values), (newValues) => {
|
|
302
|
-
if (newValues) {
|
|
303
|
-
for (const [key, value] of Object.entries(newValues)) if (value !== void 0) {
|
|
304
|
-
set(formData, key, value);
|
|
305
|
-
const fieldRef = fieldRefs.get(key);
|
|
306
|
-
const opts = fieldOptions.get(key);
|
|
307
|
-
if (fieldRef?.value && !opts?.controlled) {
|
|
308
|
-
const el = fieldRef.value;
|
|
309
|
-
if (el.type === "checkbox") el.checked = value;
|
|
310
|
-
else el.value = value;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
}, { deep: true }));
|
|
315
|
-
}
|
|
316
|
-
if (options.errors !== void 0) {
|
|
317
|
-
const initialErrors = (0, vue.toValue)(options.errors);
|
|
318
|
-
if (initialErrors) externalErrors.value = initialErrors;
|
|
319
|
-
watchStopHandles.push((0, vue.watch)(() => (0, vue.toValue)(options.errors), (newErrors) => {
|
|
320
|
-
externalErrors.value = newErrors || {};
|
|
321
|
-
}, { deep: true }));
|
|
322
|
-
}
|
|
323
|
-
return {
|
|
324
|
-
formData,
|
|
325
|
-
defaultValues,
|
|
326
|
-
errors,
|
|
327
|
-
touchedFields,
|
|
328
|
-
dirtyFields,
|
|
329
|
-
isSubmitting,
|
|
330
|
-
isLoading,
|
|
331
|
-
submitCount,
|
|
332
|
-
defaultValuesError,
|
|
333
|
-
isSubmitSuccessful,
|
|
334
|
-
validatingFields,
|
|
335
|
-
externalErrors,
|
|
336
|
-
errorDelayTimers,
|
|
337
|
-
pendingErrors,
|
|
338
|
-
fieldRefs,
|
|
339
|
-
fieldOptions,
|
|
340
|
-
fieldArrays,
|
|
341
|
-
fieldHandlers,
|
|
342
|
-
debounceTimers,
|
|
343
|
-
validationRequestIds,
|
|
344
|
-
resetGeneration,
|
|
345
|
-
isDisabled,
|
|
346
|
-
validationCache,
|
|
347
|
-
schemaValidationTimers,
|
|
348
|
-
persistentErrorFields,
|
|
349
|
-
defaultValueHashes,
|
|
350
|
-
options,
|
|
351
|
-
cleanup: () => {
|
|
352
|
-
for (const stop of watchStopHandles) stop();
|
|
353
|
-
}
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
|
-
var uniqueIdCounter = 0;
|
|
357
|
-
var circularRefMap = /* @__PURE__ */ new WeakMap();
|
|
358
|
-
function hashValue(value) {
|
|
359
|
-
if (value === null) return "null";
|
|
360
|
-
if (value === void 0) return "undefined";
|
|
361
|
-
const type = typeof value;
|
|
362
|
-
if (type === "string") return `s:${value}`;
|
|
363
|
-
if (type === "number") {
|
|
364
|
-
const num = value;
|
|
365
|
-
if (Number.isNaN(num)) return "n:NaN";
|
|
366
|
-
if (num === 0) return "n:0";
|
|
367
|
-
if (!Number.isFinite(num)) return `n:${num > 0 ? "Infinity" : "-Infinity"}`;
|
|
368
|
-
return `n:${num}`;
|
|
369
|
-
}
|
|
370
|
-
if (type === "boolean") return `b:${value}`;
|
|
371
|
-
if (type === "object") try {
|
|
372
|
-
return `o:${JSON.stringify(value)}`;
|
|
373
|
-
} catch {
|
|
374
|
-
let id = circularRefMap.get(value);
|
|
375
|
-
if (!id) {
|
|
376
|
-
id = String(++uniqueIdCounter);
|
|
377
|
-
circularRefMap.set(value, id);
|
|
378
|
-
}
|
|
379
|
-
return `o:_${id}`;
|
|
380
|
-
}
|
|
381
|
-
return `x:_${++uniqueIdCounter}`;
|
|
382
|
-
}
|
|
383
|
-
function getDefType(schema) {
|
|
384
|
-
return schema._def?.type;
|
|
385
|
-
}
|
|
386
|
-
function getDefProp(schema, prop) {
|
|
387
|
-
return schema._def?.[prop];
|
|
388
|
-
}
|
|
389
|
-
function isZodObject(schema) {
|
|
390
|
-
return getDefType(schema) === "object";
|
|
391
|
-
}
|
|
392
|
-
function isZodArray(schema) {
|
|
393
|
-
return getDefType(schema) === "array";
|
|
394
|
-
}
|
|
395
|
-
function hasChecks(schema) {
|
|
396
|
-
const checks = getDefProp(schema, "checks");
|
|
397
|
-
return Array.isArray(checks) && checks.length > 0;
|
|
398
|
-
}
|
|
399
|
-
function unwrapNonEffects(schema) {
|
|
400
|
-
const type = getDefType(schema);
|
|
401
|
-
const innerType = getDefProp(schema, "innerType");
|
|
402
|
-
if ((type === "optional" || type === "nullable" || type === "default") && innerType) return unwrapNonEffects(innerType);
|
|
403
|
-
return schema;
|
|
404
|
-
}
|
|
405
|
-
var analysisCache = /* @__PURE__ */ new WeakMap();
|
|
406
|
-
function hasRootEffects(schema) {
|
|
407
|
-
return hasChecks(schema);
|
|
408
|
-
}
|
|
409
|
-
function extractSubSchema(schema, path) {
|
|
410
|
-
const segments = path.split(".");
|
|
411
|
-
let currentSchema = schema;
|
|
412
|
-
let hasEffects = false;
|
|
413
|
-
for (const segment of segments) {
|
|
414
|
-
if (!segment) return null;
|
|
415
|
-
if (hasChecks(currentSchema)) hasEffects = true;
|
|
416
|
-
const unwrapped = unwrapNonEffects(currentSchema);
|
|
417
|
-
if (hasChecks(unwrapped)) hasEffects = true;
|
|
418
|
-
if (isZodObject(unwrapped)) {
|
|
419
|
-
const shape = getDefProp(unwrapped, "shape");
|
|
420
|
-
if (!shape || !(segment in shape)) return null;
|
|
421
|
-
currentSchema = shape[segment];
|
|
422
|
-
} else if (isZodArray(unwrapped) && /^\d+$/.test(segment)) {
|
|
423
|
-
const element = getDefProp(unwrapped, "element");
|
|
424
|
-
if (!element) return null;
|
|
425
|
-
currentSchema = element;
|
|
426
|
-
} else return null;
|
|
427
|
-
}
|
|
428
|
-
const finalUnwrapped = unwrapNonEffects(currentSchema);
|
|
429
|
-
const finalChecks = getDefProp(finalUnwrapped, "checks");
|
|
430
|
-
if (finalChecks) {
|
|
431
|
-
for (const check of finalChecks) if (check && typeof check === "object" && "type" in check && check.type === "custom") {
|
|
432
|
-
hasEffects = true;
|
|
433
|
-
break;
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
return {
|
|
437
|
-
schema: finalUnwrapped,
|
|
438
|
-
hasEffects
|
|
439
|
-
};
|
|
440
|
-
}
|
|
441
|
-
function analyzeSchemaPath(schema, path) {
|
|
442
|
-
let cache = analysisCache.get(schema);
|
|
443
|
-
if (!cache) {
|
|
444
|
-
cache = /* @__PURE__ */ new Map();
|
|
445
|
-
analysisCache.set(schema, cache);
|
|
446
|
-
}
|
|
447
|
-
const cached = cache.get(path);
|
|
448
|
-
if (cached) return cached;
|
|
449
|
-
if (hasRootEffects(schema)) {
|
|
450
|
-
const result$1 = {
|
|
451
|
-
canPartialValidate: false,
|
|
452
|
-
reason: "root-checks"
|
|
453
|
-
};
|
|
454
|
-
cache.set(path, result$1);
|
|
455
|
-
return result$1;
|
|
456
|
-
}
|
|
457
|
-
const extracted = extractSubSchema(schema, path);
|
|
458
|
-
if (!extracted) {
|
|
459
|
-
const result$1 = {
|
|
460
|
-
canPartialValidate: false,
|
|
461
|
-
reason: "invalid-path"
|
|
462
|
-
};
|
|
463
|
-
cache.set(path, result$1);
|
|
464
|
-
return result$1;
|
|
465
|
-
}
|
|
466
|
-
if (extracted.hasEffects) {
|
|
467
|
-
const result$1 = {
|
|
468
|
-
canPartialValidate: false,
|
|
469
|
-
reason: "path-checks"
|
|
470
|
-
};
|
|
471
|
-
cache.set(path, result$1);
|
|
472
|
-
return result$1;
|
|
473
|
-
}
|
|
474
|
-
const result = {
|
|
475
|
-
canPartialValidate: true,
|
|
476
|
-
subSchema: extracted.schema
|
|
477
|
-
};
|
|
478
|
-
cache.set(path, result);
|
|
479
|
-
return result;
|
|
480
|
-
}
|
|
481
|
-
function markFieldTouched(touchedFields, fieldName) {
|
|
482
|
-
if (touchedFields.value[fieldName]) return;
|
|
483
|
-
touchedFields.value = {
|
|
484
|
-
...touchedFields.value,
|
|
485
|
-
[fieldName]: true
|
|
486
|
-
};
|
|
487
|
-
}
|
|
488
|
-
function clearFieldDirty(dirtyFields, fieldName) {
|
|
489
|
-
if (!(fieldName in dirtyFields.value)) return;
|
|
490
|
-
const newDirty = { ...dirtyFields.value };
|
|
491
|
-
delete newDirty[fieldName];
|
|
492
|
-
dirtyFields.value = newDirty;
|
|
493
|
-
}
|
|
494
|
-
function clearFieldTouched(touchedFields, fieldName) {
|
|
495
|
-
if (!(fieldName in touchedFields.value)) return;
|
|
496
|
-
const newTouched = { ...touchedFields.value };
|
|
497
|
-
delete newTouched[fieldName];
|
|
498
|
-
touchedFields.value = newTouched;
|
|
499
|
-
}
|
|
500
|
-
function clearFieldErrors(errors, fieldName) {
|
|
501
|
-
const currentErrors = errors.value;
|
|
502
|
-
const keys = Object.keys(currentErrors);
|
|
503
|
-
if (keys.length === 0) return;
|
|
504
|
-
const prefix = `${fieldName}.`;
|
|
505
|
-
const keysToDelete = [];
|
|
506
|
-
for (const key of keys) if (key === fieldName || key.startsWith(prefix)) keysToDelete.push(key);
|
|
507
|
-
if (keysToDelete.length === 0) return;
|
|
508
|
-
const newErrors = { ...currentErrors };
|
|
509
|
-
for (const key of keysToDelete) delete newErrors[key];
|
|
510
|
-
errors.value = newErrors;
|
|
511
|
-
}
|
|
512
|
-
function updateFieldDirtyState(dirtyFields, defaultValues, defaultValueHashes, fieldName, currentValue) {
|
|
513
|
-
let defaultHash = defaultValueHashes.get(fieldName);
|
|
514
|
-
if (defaultHash === void 0) {
|
|
515
|
-
defaultHash = hashValue(get(defaultValues, fieldName));
|
|
516
|
-
defaultValueHashes.set(fieldName, defaultHash);
|
|
517
|
-
}
|
|
518
|
-
const isDirty = hashValue(currentValue) !== defaultHash;
|
|
519
|
-
const wasDirty = dirtyFields.value[fieldName] === true;
|
|
520
|
-
if (isDirty && !wasDirty) dirtyFields.value = {
|
|
521
|
-
...dirtyFields.value,
|
|
522
|
-
[fieldName]: true
|
|
523
|
-
};
|
|
524
|
-
else if (!isDirty && wasDirty) {
|
|
525
|
-
const newDirty = { ...dirtyFields.value };
|
|
526
|
-
delete newDirty[fieldName];
|
|
527
|
-
dirtyFields.value = newDirty;
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
function setValidating(ctx, fieldPath, isValidating) {
|
|
531
|
-
const newSet = new Set(ctx.validatingFields.value);
|
|
532
|
-
if (isValidating) newSet.add(fieldPath);
|
|
533
|
-
else newSet.delete(fieldPath);
|
|
534
|
-
ctx.validatingFields.value = newSet;
|
|
535
|
-
}
|
|
536
|
-
function groupErrorsByPath(issues) {
|
|
537
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
538
|
-
for (const issue of issues) {
|
|
539
|
-
const path = issue.path.join(".");
|
|
540
|
-
const existing = grouped.get(path) || [];
|
|
541
|
-
existing.push({
|
|
542
|
-
type: issue.code,
|
|
543
|
-
message: issue.message
|
|
544
|
-
});
|
|
545
|
-
grouped.set(path, existing);
|
|
546
|
-
}
|
|
547
|
-
return grouped;
|
|
548
|
-
}
|
|
549
|
-
function createFieldError(errors, criteriaMode = "firstError") {
|
|
550
|
-
const firstError = errors[0];
|
|
551
|
-
if (!firstError) return "";
|
|
552
|
-
if (criteriaMode === "firstError") return firstError.message;
|
|
553
|
-
if (errors.length === 1) return firstError.message;
|
|
554
|
-
const types = {};
|
|
555
|
-
for (const err of errors) {
|
|
556
|
-
const existing = types[err.type];
|
|
557
|
-
if (existing) types[err.type] = Array.isArray(existing) ? [...existing, err.message] : [existing, err.message];
|
|
558
|
-
else types[err.type] = err.message;
|
|
559
|
-
}
|
|
560
|
-
return {
|
|
561
|
-
type: firstError.type,
|
|
562
|
-
message: firstError.message,
|
|
563
|
-
types
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
function createValidation(ctx) {
|
|
567
|
-
function applyNativeValidation(fieldPath, errorMessage) {
|
|
568
|
-
if (!ctx.options.shouldUseNativeValidation) return;
|
|
569
|
-
const el = ctx.fieldRefs.get(fieldPath)?.value;
|
|
570
|
-
if (el && "setCustomValidity" in el) el.setCustomValidity(errorMessage || "");
|
|
571
|
-
}
|
|
572
|
-
function clearAllNativeValidation() {
|
|
573
|
-
if (!ctx.options.shouldUseNativeValidation) return;
|
|
574
|
-
for (const [path] of ctx.fieldRefs) applyNativeValidation(path, null);
|
|
575
|
-
}
|
|
576
|
-
function scheduleErrorsBatch(errors) {
|
|
577
|
-
if ((ctx.options.delayError || 0) <= 0) {
|
|
578
|
-
const newErrors = { ...ctx.errors.value };
|
|
579
|
-
for (const [fieldPath, error] of errors) {
|
|
580
|
-
set(newErrors, fieldPath, error);
|
|
581
|
-
applyNativeValidation(fieldPath, typeof error === "string" ? error : error.message);
|
|
582
|
-
}
|
|
583
|
-
ctx.errors.value = newErrors;
|
|
584
|
-
return;
|
|
585
|
-
}
|
|
586
|
-
for (const [fieldPath, error] of errors) scheduleError(fieldPath, error);
|
|
587
|
-
}
|
|
588
|
-
function scheduleError(fieldPath, error) {
|
|
589
|
-
const delayMs = ctx.options.delayError || 0;
|
|
590
|
-
const errorMessage = typeof error === "string" ? error : error.message;
|
|
591
|
-
if (delayMs <= 0) {
|
|
592
|
-
const newErrors = { ...ctx.errors.value };
|
|
593
|
-
set(newErrors, fieldPath, error);
|
|
594
|
-
ctx.errors.value = newErrors;
|
|
595
|
-
applyNativeValidation(fieldPath, errorMessage);
|
|
596
|
-
return;
|
|
597
|
-
}
|
|
598
|
-
const existingTimer = ctx.errorDelayTimers.get(fieldPath);
|
|
599
|
-
if (existingTimer) clearTimeout(existingTimer);
|
|
600
|
-
ctx.pendingErrors.set(fieldPath, error);
|
|
601
|
-
const timer = setTimeout(() => {
|
|
602
|
-
ctx.errorDelayTimers.delete(fieldPath);
|
|
603
|
-
const pendingError = ctx.pendingErrors.get(fieldPath);
|
|
604
|
-
if (pendingError !== void 0) {
|
|
605
|
-
ctx.pendingErrors.delete(fieldPath);
|
|
606
|
-
const newErrors = { ...ctx.errors.value };
|
|
607
|
-
set(newErrors, fieldPath, pendingError);
|
|
608
|
-
ctx.errors.value = newErrors;
|
|
609
|
-
applyNativeValidation(fieldPath, errorMessage);
|
|
610
|
-
}
|
|
611
|
-
}, delayMs);
|
|
612
|
-
ctx.errorDelayTimers.set(fieldPath, timer);
|
|
613
|
-
}
|
|
614
|
-
function cancelError(fieldPath) {
|
|
615
|
-
const timer = ctx.errorDelayTimers.get(fieldPath);
|
|
616
|
-
if (timer) {
|
|
617
|
-
clearTimeout(timer);
|
|
618
|
-
ctx.errorDelayTimers.delete(fieldPath);
|
|
619
|
-
}
|
|
620
|
-
ctx.pendingErrors.delete(fieldPath);
|
|
621
|
-
applyNativeValidation(fieldPath, null);
|
|
622
|
-
if (ctx.persistentErrorFields.has(fieldPath)) return;
|
|
623
|
-
clearFieldErrors(ctx.errors, fieldPath);
|
|
624
|
-
}
|
|
625
|
-
function clearAllPendingErrors() {
|
|
626
|
-
for (const timer of ctx.errorDelayTimers.values()) clearTimeout(timer);
|
|
627
|
-
ctx.errorDelayTimers.clear();
|
|
628
|
-
ctx.pendingErrors.clear();
|
|
629
|
-
}
|
|
630
|
-
async function validateFieldPartial(fieldPath, subSchema, valueHash, cacheKey, criteriaMode, generationAtStart) {
|
|
631
|
-
const fieldValue = get(ctx.formData, fieldPath);
|
|
632
|
-
setValidating(ctx, fieldPath, true);
|
|
633
|
-
try {
|
|
634
|
-
const result = await subSchema.safeParseAsync(fieldValue);
|
|
635
|
-
if (ctx.resetGeneration.value !== generationAtStart) return true;
|
|
636
|
-
if (result.success) {
|
|
637
|
-
cancelError(fieldPath);
|
|
638
|
-
if (valueHash) ctx.validationCache.set(cacheKey, {
|
|
639
|
-
hash: valueHash,
|
|
640
|
-
isValid: true
|
|
641
|
-
});
|
|
642
|
-
return true;
|
|
643
|
-
}
|
|
644
|
-
const fieldSegments = fieldPath.split(".");
|
|
645
|
-
const fieldErrors = result.error.issues.map((issue) => {
|
|
646
|
-
const issuePath = issue.path.map(String);
|
|
647
|
-
const alreadyPrefixed = issuePath.length >= fieldSegments.length && fieldSegments.every((seg, i) => issuePath[i] === seg);
|
|
648
|
-
return {
|
|
649
|
-
...issue,
|
|
650
|
-
path: alreadyPrefixed ? issuePath : fieldSegments.concat(issuePath)
|
|
651
|
-
};
|
|
652
|
-
});
|
|
653
|
-
cancelError(fieldPath);
|
|
654
|
-
const grouped = groupErrorsByPath(fieldErrors);
|
|
655
|
-
const errorBatch = [];
|
|
656
|
-
for (const [path, errors] of grouped) errorBatch.push([path, createFieldError(errors, criteriaMode)]);
|
|
657
|
-
scheduleErrorsBatch(errorBatch);
|
|
658
|
-
if (valueHash) ctx.validationCache.set(cacheKey, {
|
|
659
|
-
hash: valueHash,
|
|
660
|
-
isValid: false
|
|
661
|
-
});
|
|
662
|
-
return false;
|
|
663
|
-
} finally {
|
|
664
|
-
setValidating(ctx, fieldPath, false);
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
async function validateFieldFull(fieldPath, valueHash, cacheKey, criteriaMode, generationAtStart) {
|
|
668
|
-
setValidating(ctx, fieldPath, true);
|
|
669
|
-
try {
|
|
670
|
-
const result = await ctx.options.schema.safeParseAsync(ctx.formData);
|
|
671
|
-
if (ctx.resetGeneration.value !== generationAtStart) return true;
|
|
672
|
-
if (result.success) {
|
|
673
|
-
cancelError(fieldPath);
|
|
674
|
-
if (valueHash) ctx.validationCache.set(cacheKey, {
|
|
675
|
-
hash: valueHash,
|
|
676
|
-
isValid: true
|
|
677
|
-
});
|
|
678
|
-
return true;
|
|
679
|
-
}
|
|
680
|
-
const fieldErrors = result.error.issues.filter((issue) => {
|
|
681
|
-
const path = issue.path.join(".");
|
|
682
|
-
return path === fieldPath || path.startsWith(`${fieldPath}.`);
|
|
683
|
-
});
|
|
684
|
-
if (fieldErrors.length === 0) {
|
|
685
|
-
cancelError(fieldPath);
|
|
686
|
-
if (valueHash) ctx.validationCache.set(cacheKey, {
|
|
687
|
-
hash: valueHash,
|
|
688
|
-
isValid: true
|
|
689
|
-
});
|
|
690
|
-
return true;
|
|
691
|
-
}
|
|
692
|
-
cancelError(fieldPath);
|
|
693
|
-
const grouped = groupErrorsByPath(fieldErrors);
|
|
694
|
-
const errorBatch = [];
|
|
695
|
-
for (const [path, errors] of grouped) errorBatch.push([path, createFieldError(errors, criteriaMode)]);
|
|
696
|
-
scheduleErrorsBatch(errorBatch);
|
|
697
|
-
if (valueHash) ctx.validationCache.set(cacheKey, {
|
|
698
|
-
hash: valueHash,
|
|
699
|
-
isValid: false
|
|
700
|
-
});
|
|
701
|
-
return false;
|
|
702
|
-
} finally {
|
|
703
|
-
setValidating(ctx, fieldPath, false);
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
async function validate(fieldPath) {
|
|
707
|
-
const generationAtStart = ctx.resetGeneration.value;
|
|
708
|
-
const criteriaMode = ctx.options.criteriaMode || "firstError";
|
|
709
|
-
let valueHash;
|
|
710
|
-
if (fieldPath) {
|
|
711
|
-
valueHash = hashValue(get(ctx.formData, fieldPath));
|
|
712
|
-
const analysis = analyzeSchemaPath(ctx.options.schema, fieldPath);
|
|
713
|
-
const usePartial = analysis.canPartialValidate && analysis.subSchema;
|
|
714
|
-
const cacheKey = `${fieldPath}:${usePartial ? "partial" : "full"}`;
|
|
715
|
-
const cached = ctx.validationCache.get(cacheKey);
|
|
716
|
-
if (cached && cached.hash === valueHash && cached.isValid) {
|
|
717
|
-
cancelError(fieldPath);
|
|
718
|
-
return true;
|
|
719
|
-
}
|
|
720
|
-
if (usePartial) return validateFieldPartial(fieldPath, analysis.subSchema, valueHash, cacheKey, criteriaMode, generationAtStart);
|
|
721
|
-
return validateFieldFull(fieldPath, valueHash, cacheKey, criteriaMode, generationAtStart);
|
|
722
|
-
}
|
|
723
|
-
const validatingKey = "_form";
|
|
724
|
-
setValidating(ctx, validatingKey, true);
|
|
725
|
-
try {
|
|
726
|
-
const result = await ctx.options.schema.safeParseAsync(ctx.formData);
|
|
727
|
-
if (ctx.resetGeneration.value !== generationAtStart) return true;
|
|
728
|
-
if (result.success) {
|
|
729
|
-
clearAllPendingErrors();
|
|
730
|
-
ctx.errors.value = {};
|
|
731
|
-
clearAllNativeValidation();
|
|
732
|
-
ctx.validationCache.clear();
|
|
733
|
-
return true;
|
|
734
|
-
}
|
|
735
|
-
clearAllPendingErrors();
|
|
736
|
-
ctx.errors.value = {};
|
|
737
|
-
const grouped = groupErrorsByPath(result.error.issues);
|
|
738
|
-
const errorBatch = [];
|
|
739
|
-
for (const [path, errors] of grouped) errorBatch.push([path, createFieldError(errors, criteriaMode)]);
|
|
740
|
-
scheduleErrorsBatch(errorBatch);
|
|
741
|
-
ctx.validationCache.clear();
|
|
742
|
-
return false;
|
|
743
|
-
} finally {
|
|
744
|
-
setValidating(ctx, validatingKey, false);
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
return {
|
|
748
|
-
validate,
|
|
749
|
-
clearAllPendingErrors
|
|
750
|
-
};
|
|
751
|
-
}
|
|
752
|
-
var VALID_MODES = [
|
|
753
|
-
"onSubmit",
|
|
754
|
-
"onBlur",
|
|
755
|
-
"onChange",
|
|
756
|
-
"onTouched"
|
|
757
|
-
];
|
|
758
|
-
function validateMode(mode, paramName) {
|
|
759
|
-
if (__DEV__ && !VALID_MODES.includes(mode)) warnOnce(`Invalid ${paramName}: "${mode}". Expected one of: ${VALID_MODES.join(", ")}`, `invalid-mode-${mode}`);
|
|
760
|
-
}
|
|
761
|
-
function shouldValidateOnChange(mode, isTouched, reValidateMode, hasSubmitted) {
|
|
762
|
-
if (__DEV__) {
|
|
763
|
-
validateMode(mode, "validation mode");
|
|
764
|
-
if (reValidateMode) validateMode(reValidateMode, "reValidateMode");
|
|
765
|
-
}
|
|
766
|
-
if (mode === "onChange") return true;
|
|
767
|
-
if (mode === "onTouched" && isTouched) return true;
|
|
768
|
-
if (hasSubmitted === true && reValidateMode === "onChange") return true;
|
|
769
|
-
return false;
|
|
770
|
-
}
|
|
771
|
-
function shouldValidateOnBlur(mode, hasSubmitted, reValidateMode) {
|
|
772
|
-
if (__DEV__) {
|
|
773
|
-
validateMode(mode, "validation mode");
|
|
774
|
-
if (reValidateMode) validateMode(reValidateMode, "reValidateMode");
|
|
775
|
-
}
|
|
776
|
-
return mode === "onBlur" || mode === "onTouched" || hasSubmitted && (reValidateMode === "onBlur" || reValidateMode === "onTouched");
|
|
777
|
-
}
|
|
778
|
-
var validationRequestCounter = 0;
|
|
779
|
-
function createFieldRegistration(ctx, validate) {
|
|
780
|
-
function register(name, registerOptions) {
|
|
781
|
-
if (__DEV__) {
|
|
782
|
-
const syntaxError = validatePathSyntax(name);
|
|
783
|
-
if (syntaxError) warnInvalidPath("register", name, syntaxError);
|
|
784
|
-
const schemaResult = validatePathAgainstSchema(ctx.options.schema, name);
|
|
785
|
-
if (!schemaResult.valid) warnPathNotInSchema("register", name, schemaResult.availableFields);
|
|
786
|
-
}
|
|
787
|
-
let fieldRef = ctx.fieldRefs.get(name);
|
|
788
|
-
if (!fieldRef) {
|
|
789
|
-
fieldRef = (0, vue.ref)(null);
|
|
790
|
-
ctx.fieldRefs.set(name, fieldRef);
|
|
791
|
-
if (get(ctx.formData, name) === void 0) {
|
|
792
|
-
const defaultValue = get(ctx.defaultValues, name);
|
|
793
|
-
if (defaultValue !== void 0) set(ctx.formData, name, defaultValue);
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
if (registerOptions) ctx.fieldOptions.set(name, registerOptions);
|
|
797
|
-
let handlers = ctx.fieldHandlers.get(name);
|
|
798
|
-
if (!handlers) {
|
|
799
|
-
const runCustomValidation = async (fieldName, value, requestId, resetGenAtStart) => {
|
|
800
|
-
const fieldOpts = ctx.fieldOptions.get(fieldName);
|
|
801
|
-
if (!fieldOpts?.validate || fieldOpts.disabled) return;
|
|
802
|
-
const error = await fieldOpts.validate(value);
|
|
803
|
-
if (requestId !== ctx.validationRequestIds.get(fieldName)) return;
|
|
804
|
-
if (ctx.resetGeneration.value !== resetGenAtStart) return;
|
|
805
|
-
if (error) ctx.errors.value = {
|
|
806
|
-
...ctx.errors.value,
|
|
807
|
-
[fieldName]: error
|
|
808
|
-
};
|
|
809
|
-
else {
|
|
810
|
-
const newErrors = { ...ctx.errors.value };
|
|
811
|
-
delete newErrors[fieldName];
|
|
812
|
-
ctx.errors.value = newErrors;
|
|
813
|
-
}
|
|
814
|
-
};
|
|
815
|
-
const onInput = async (e) => {
|
|
816
|
-
const target = e.target;
|
|
817
|
-
let value;
|
|
818
|
-
if (target.type === "checkbox") value = target.checked;
|
|
819
|
-
else if (target.type === "number" || target.type === "range") value = target.valueAsNumber;
|
|
820
|
-
else value = target.value;
|
|
821
|
-
set(ctx.formData, name, value);
|
|
822
|
-
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, value);
|
|
823
|
-
const fieldOpts = ctx.fieldOptions.get(name);
|
|
824
|
-
if (shouldValidateOnChange(ctx.options.mode ?? "onSubmit", ctx.touchedFields.value[name] === true, ctx.options.reValidateMode, ctx.submitCount.value > 0)) {
|
|
825
|
-
const validationDebounceMs = ctx.options.validationDebounce || 0;
|
|
826
|
-
if (validationDebounceMs > 0) {
|
|
827
|
-
const existingTimer = ctx.schemaValidationTimers.get(name);
|
|
828
|
-
if (existingTimer) clearTimeout(existingTimer);
|
|
829
|
-
const timer = setTimeout(async () => {
|
|
830
|
-
ctx.schemaValidationTimers.delete(name);
|
|
831
|
-
await validate(name);
|
|
832
|
-
if (fieldOpts?.deps && fieldOpts.deps.length > 0) {
|
|
833
|
-
const uniqueDeps = [...new Set(fieldOpts.deps)];
|
|
834
|
-
await Promise.all(uniqueDeps.map((depField) => validate(depField)));
|
|
835
|
-
}
|
|
836
|
-
}, validationDebounceMs);
|
|
837
|
-
ctx.schemaValidationTimers.set(name, timer);
|
|
838
|
-
} else {
|
|
839
|
-
await validate(name);
|
|
840
|
-
if (fieldOpts?.deps && fieldOpts.deps.length > 0) {
|
|
841
|
-
const uniqueDeps = [...new Set(fieldOpts.deps)];
|
|
842
|
-
await Promise.all(uniqueDeps.map((depField) => validate(depField)));
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
if (fieldOpts?.validate && !fieldOpts.disabled) {
|
|
847
|
-
const requestId = ++validationRequestCounter;
|
|
848
|
-
ctx.validationRequestIds.set(name, requestId);
|
|
849
|
-
const resetGenAtStart = ctx.resetGeneration.value;
|
|
850
|
-
const debounceMs = fieldOpts.validateDebounce || 0;
|
|
851
|
-
if (debounceMs > 0) {
|
|
852
|
-
const existingTimer = ctx.debounceTimers.get(name);
|
|
853
|
-
if (existingTimer) clearTimeout(existingTimer);
|
|
854
|
-
const timer = setTimeout(async () => {
|
|
855
|
-
ctx.debounceTimers.delete(name);
|
|
856
|
-
await runCustomValidation(name, value, requestId, resetGenAtStart);
|
|
857
|
-
if (ctx.validationRequestIds.get(name) === requestId) ctx.validationRequestIds.delete(name);
|
|
858
|
-
}, debounceMs);
|
|
859
|
-
ctx.debounceTimers.set(name, timer);
|
|
860
|
-
} else {
|
|
861
|
-
await runCustomValidation(name, value, requestId, resetGenAtStart);
|
|
862
|
-
if (ctx.validationRequestIds.get(name) === requestId) ctx.validationRequestIds.delete(name);
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
};
|
|
866
|
-
const onBlur = async (_e) => {
|
|
867
|
-
markFieldTouched(ctx.touchedFields, name);
|
|
868
|
-
if (shouldValidateOnBlur(ctx.options.mode ?? "onSubmit", ctx.submitCount.value > 0, ctx.options.reValidateMode)) {
|
|
869
|
-
await validate(name);
|
|
870
|
-
const fieldOpts = ctx.fieldOptions.get(name);
|
|
871
|
-
if (fieldOpts?.deps && fieldOpts.deps.length > 0) {
|
|
872
|
-
const uniqueDeps = [...new Set(fieldOpts.deps)];
|
|
873
|
-
await Promise.all(uniqueDeps.map((depField) => validate(depField)));
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
};
|
|
877
|
-
const refCallback = (el) => {
|
|
878
|
-
const currentFieldRef = ctx.fieldRefs.get(name);
|
|
879
|
-
if (!currentFieldRef) return;
|
|
880
|
-
const previousEl = currentFieldRef.value;
|
|
881
|
-
if (previousEl === el) return;
|
|
882
|
-
if (previousEl && el) return;
|
|
883
|
-
currentFieldRef.value = el;
|
|
884
|
-
const opts = ctx.fieldOptions.get(name);
|
|
885
|
-
if (el && !opts?.controlled && el instanceof HTMLInputElement) {
|
|
886
|
-
const value = get(ctx.formData, name);
|
|
887
|
-
if (value !== void 0) if (el.type === "checkbox") el.checked = value;
|
|
888
|
-
else el.value = value;
|
|
889
|
-
}
|
|
890
|
-
if (previousEl && !el) {
|
|
891
|
-
const timer = ctx.debounceTimers.get(name);
|
|
892
|
-
if (timer) {
|
|
893
|
-
clearTimeout(timer);
|
|
894
|
-
ctx.debounceTimers.delete(name);
|
|
895
|
-
}
|
|
896
|
-
const schemaTimer = ctx.schemaValidationTimers.get(name);
|
|
897
|
-
if (schemaTimer) {
|
|
898
|
-
clearTimeout(schemaTimer);
|
|
899
|
-
ctx.schemaValidationTimers.delete(name);
|
|
900
|
-
}
|
|
901
|
-
const errorTimer = ctx.errorDelayTimers.get(name);
|
|
902
|
-
if (errorTimer) {
|
|
903
|
-
clearTimeout(errorTimer);
|
|
904
|
-
ctx.errorDelayTimers.delete(name);
|
|
905
|
-
}
|
|
906
|
-
ctx.pendingErrors.delete(name);
|
|
907
|
-
ctx.validationRequestIds.delete(name);
|
|
908
|
-
ctx.fieldRefs.delete(name);
|
|
909
|
-
ctx.fieldOptions.delete(name);
|
|
910
|
-
ctx.fieldHandlers.delete(name);
|
|
911
|
-
if (opts?.shouldUnregister ?? ctx.options.shouldUnregister ?? false) {
|
|
912
|
-
unset(ctx.formData, name);
|
|
913
|
-
clearFieldErrors(ctx.errors, name);
|
|
914
|
-
clearFieldTouched(ctx.touchedFields, name);
|
|
915
|
-
clearFieldDirty(ctx.dirtyFields, name);
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
};
|
|
919
|
-
handlers = {
|
|
920
|
-
onInput,
|
|
921
|
-
onBlur,
|
|
922
|
-
refCallback
|
|
923
|
-
};
|
|
924
|
-
ctx.fieldHandlers.set(name, handlers);
|
|
925
|
-
}
|
|
926
|
-
return {
|
|
927
|
-
name,
|
|
928
|
-
ref: handlers.refCallback,
|
|
929
|
-
onInput: handlers.onInput,
|
|
930
|
-
onBlur: handlers.onBlur,
|
|
931
|
-
...ctx.isDisabled.value && { disabled: true },
|
|
932
|
-
...registerOptions?.controlled && { value: (0, vue.computed)({
|
|
933
|
-
get: () => get(ctx.formData, name),
|
|
934
|
-
set: (val) => {
|
|
935
|
-
set(ctx.formData, name, val);
|
|
936
|
-
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, val);
|
|
937
|
-
}
|
|
938
|
-
}) }
|
|
939
|
-
};
|
|
940
|
-
}
|
|
941
|
-
function unregister(name, options) {
|
|
942
|
-
const opts = options || {};
|
|
943
|
-
if (!opts.keepValue) unset(ctx.formData, name);
|
|
944
|
-
if (!opts.keepError) clearFieldErrors(ctx.errors, name);
|
|
945
|
-
if (!opts.keepTouched) clearFieldTouched(ctx.touchedFields, name);
|
|
946
|
-
if (!opts.keepDirty) clearFieldDirty(ctx.dirtyFields, name);
|
|
947
|
-
ctx.fieldRefs.delete(name);
|
|
948
|
-
ctx.fieldOptions.delete(name);
|
|
949
|
-
ctx.fieldHandlers.delete(name);
|
|
950
|
-
const timer = ctx.debounceTimers.get(name);
|
|
951
|
-
if (timer) {
|
|
952
|
-
clearTimeout(timer);
|
|
953
|
-
ctx.debounceTimers.delete(name);
|
|
954
|
-
}
|
|
955
|
-
const schemaTimer = ctx.schemaValidationTimers.get(name);
|
|
956
|
-
if (schemaTimer) {
|
|
957
|
-
clearTimeout(schemaTimer);
|
|
958
|
-
ctx.schemaValidationTimers.delete(name);
|
|
959
|
-
}
|
|
960
|
-
ctx.validationRequestIds.delete(name);
|
|
961
|
-
ctx.validationCache.delete(`${name}:partial`);
|
|
962
|
-
ctx.validationCache.delete(`${name}:full`);
|
|
963
|
-
}
|
|
964
|
-
return {
|
|
965
|
-
register,
|
|
966
|
-
unregister
|
|
967
|
-
};
|
|
968
|
-
}
|
|
969
|
-
function createFieldArrayManager(ctx, validate, setFocus) {
|
|
970
|
-
function fields(name, options) {
|
|
971
|
-
if (__DEV__) {
|
|
972
|
-
const syntaxError = validatePathSyntax(name);
|
|
973
|
-
if (syntaxError) warnInvalidPath("fields", name, syntaxError);
|
|
974
|
-
const schemaResult = validatePathAgainstSchema(ctx.options.schema, name);
|
|
975
|
-
if (!schemaResult.valid) warnPathNotInSchema("fields", name, schemaResult.availableFields);
|
|
976
|
-
if (isArrayFieldInSchema(ctx.options.schema, name) === false) warnFieldsOnNonArray(name);
|
|
977
|
-
}
|
|
978
|
-
let fieldArray = ctx.fieldArrays.get(name);
|
|
979
|
-
if (!fieldArray) {
|
|
980
|
-
const existingValues = get(ctx.formData, name) || [];
|
|
981
|
-
fieldArray = {
|
|
982
|
-
items: (0, vue.ref)([]),
|
|
983
|
-
values: existingValues,
|
|
984
|
-
indexCache: /* @__PURE__ */ new Map(),
|
|
985
|
-
rules: options?.rules
|
|
986
|
-
};
|
|
987
|
-
ctx.fieldArrays.set(name, fieldArray);
|
|
988
|
-
if (!get(ctx.formData, name)) set(ctx.formData, name, []);
|
|
989
|
-
} else if (options?.rules) fieldArray.rules = options.rules;
|
|
990
|
-
const fa = fieldArray;
|
|
991
|
-
const indexCache = fa.indexCache;
|
|
992
|
-
const rebuildIndexCache = () => {
|
|
993
|
-
indexCache.clear();
|
|
994
|
-
fa.items.value.forEach((item, idx) => {
|
|
995
|
-
indexCache.set(item.key, idx);
|
|
996
|
-
});
|
|
997
|
-
};
|
|
998
|
-
const appendToCache = (startIndex) => {
|
|
999
|
-
const items = fa.items.value;
|
|
1000
|
-
for (let i = startIndex; i < items.length; i++) {
|
|
1001
|
-
const item = items[i];
|
|
1002
|
-
if (item) indexCache.set(item.key, i);
|
|
1003
|
-
}
|
|
1004
|
-
};
|
|
1005
|
-
const updateCacheAfterInsert = (insertIndex, _insertCount) => {
|
|
1006
|
-
const items = fa.items.value;
|
|
1007
|
-
for (let i = insertIndex; i < items.length; i++) {
|
|
1008
|
-
const item = items[i];
|
|
1009
|
-
if (item) indexCache.set(item.key, i);
|
|
1010
|
-
}
|
|
1011
|
-
};
|
|
1012
|
-
const swapInCache = (indexA, indexB) => {
|
|
1013
|
-
const items = fa.items.value;
|
|
1014
|
-
const itemA = items[indexA];
|
|
1015
|
-
const itemB = items[indexB];
|
|
1016
|
-
if (itemA) indexCache.set(itemA.key, indexA);
|
|
1017
|
-
if (itemB) indexCache.set(itemB.key, indexB);
|
|
1018
|
-
};
|
|
1019
|
-
const updateCacheAfterRemove = (removedKey, startIndex) => {
|
|
1020
|
-
indexCache.delete(removedKey);
|
|
1021
|
-
const items = fa.items.value;
|
|
1022
|
-
for (let i = startIndex; i < items.length; i++) {
|
|
1023
|
-
const item = items[i];
|
|
1024
|
-
if (item) indexCache.set(item.key, i);
|
|
1025
|
-
}
|
|
1026
|
-
};
|
|
1027
|
-
const createItem = (key) => ({
|
|
1028
|
-
key,
|
|
1029
|
-
get index() {
|
|
1030
|
-
return indexCache.get(key) ?? -1;
|
|
1031
|
-
},
|
|
1032
|
-
remove() {
|
|
1033
|
-
const currentIndex = indexCache.get(key) ?? -1;
|
|
1034
|
-
if (currentIndex !== -1) removeAt(currentIndex);
|
|
1035
|
-
}
|
|
1036
|
-
});
|
|
1037
|
-
if (fa.items.value.length === 0 && fa.values.length > 0) {
|
|
1038
|
-
fa.items.value = fa.values.map(() => createItem(generateId()));
|
|
1039
|
-
rebuildIndexCache();
|
|
1040
|
-
}
|
|
1041
|
-
const handleFocus = async (baseIndex, addedCount, focusOptions) => {
|
|
1042
|
-
if (!focusOptions?.shouldFocus) return;
|
|
1043
|
-
await (0, vue.nextTick)();
|
|
1044
|
-
const focusItemOffset = focusOptions?.focusIndex ?? 0;
|
|
1045
|
-
let fieldPath = `${name}.${baseIndex + Math.min(focusItemOffset, addedCount - 1)}`;
|
|
1046
|
-
if (focusOptions?.focusName) fieldPath = `${fieldPath}.${focusOptions.focusName}`;
|
|
1047
|
-
setFocus(fieldPath);
|
|
1048
|
-
};
|
|
1049
|
-
const normalizeToArray = (value) => {
|
|
1050
|
-
return Array.isArray(value) ? value : [value];
|
|
1051
|
-
};
|
|
1052
|
-
const clearValidationCache = () => {
|
|
1053
|
-
for (const key of ctx.validationCache.keys()) {
|
|
1054
|
-
const colonIndex = key.lastIndexOf(":");
|
|
1055
|
-
const fieldPath = colonIndex > 0 ? key.slice(0, colonIndex) : key;
|
|
1056
|
-
if (fieldPath === name || fieldPath.startsWith(`${name}.`)) ctx.validationCache.delete(key);
|
|
1057
|
-
}
|
|
1058
|
-
};
|
|
1059
|
-
const validateIfNeeded = () => {
|
|
1060
|
-
const isTouched = ctx.touchedFields.value[name] === true;
|
|
1061
|
-
const hasSubmitted = ctx.submitCount.value > 0;
|
|
1062
|
-
if (shouldValidateOnChange(ctx.options.mode ?? "onSubmit", isTouched, ctx.options.reValidateMode, hasSubmitted)) validate(name);
|
|
1063
|
-
};
|
|
1064
|
-
const ensureSync = () => {
|
|
1065
|
-
const currentValues = get(ctx.formData, name) || [];
|
|
1066
|
-
if (fa.items.value.length !== currentValues.length) {
|
|
1067
|
-
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})`);
|
|
1068
|
-
fa.items.value = currentValues.map(() => createItem(generateId()));
|
|
1069
|
-
rebuildIndexCache();
|
|
1070
|
-
}
|
|
1071
|
-
return currentValues;
|
|
1072
|
-
};
|
|
1073
|
-
const append = (value, focusOptions) => {
|
|
1074
|
-
clearValidationCache();
|
|
1075
|
-
const values = normalizeToArray(value);
|
|
1076
|
-
if (values.length === 0) return true;
|
|
1077
|
-
const currentValues = ensureSync();
|
|
1078
|
-
const insertIndex = currentValues.length;
|
|
1079
|
-
const rules = fa.rules;
|
|
1080
|
-
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) {
|
|
1081
|
-
if (__DEV__) warnArrayOperationRejected("append", name, "maxLength", {
|
|
1082
|
-
current: currentValues.length,
|
|
1083
|
-
limit: rules.maxLength.value
|
|
1084
|
-
});
|
|
1085
|
-
return false;
|
|
1086
|
-
}
|
|
1087
|
-
const newValues = [...currentValues, ...values];
|
|
1088
|
-
set(ctx.formData, name, newValues);
|
|
1089
|
-
const newItems = values.map(() => createItem(generateId()));
|
|
1090
|
-
fa.items.value = [...fa.items.value, ...newItems];
|
|
1091
|
-
appendToCache(insertIndex);
|
|
1092
|
-
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1093
|
-
validateIfNeeded();
|
|
1094
|
-
handleFocus(insertIndex, values.length, focusOptions);
|
|
1095
|
-
return true;
|
|
1096
|
-
};
|
|
1097
|
-
const prepend = (value, focusOptions) => {
|
|
1098
|
-
clearValidationCache();
|
|
1099
|
-
const values = normalizeToArray(value);
|
|
1100
|
-
if (values.length === 0) return true;
|
|
1101
|
-
const currentValues = ensureSync();
|
|
1102
|
-
const rules = fa.rules;
|
|
1103
|
-
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) {
|
|
1104
|
-
if (__DEV__) warnArrayOperationRejected("prepend", name, "maxLength", {
|
|
1105
|
-
current: currentValues.length,
|
|
1106
|
-
limit: rules.maxLength.value
|
|
1107
|
-
});
|
|
1108
|
-
return false;
|
|
1109
|
-
}
|
|
1110
|
-
const newValues = [...values, ...currentValues];
|
|
1111
|
-
set(ctx.formData, name, newValues);
|
|
1112
|
-
const newItems = values.map(() => createItem(generateId()));
|
|
1113
|
-
fa.items.value = [...newItems, ...fa.items.value];
|
|
1114
|
-
updateCacheAfterInsert(0, values.length);
|
|
1115
|
-
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1116
|
-
validateIfNeeded();
|
|
1117
|
-
handleFocus(0, values.length, focusOptions);
|
|
1118
|
-
return true;
|
|
1119
|
-
};
|
|
1120
|
-
const update = (index, value) => {
|
|
1121
|
-
clearValidationCache();
|
|
1122
|
-
const currentValues = ensureSync();
|
|
1123
|
-
if (index < 0 || index >= currentValues.length) {
|
|
1124
|
-
if (__DEV__) warnArrayIndexOutOfBounds("update", name, index, currentValues.length);
|
|
1125
|
-
return false;
|
|
1126
|
-
}
|
|
1127
|
-
const newValues = [...currentValues];
|
|
1128
|
-
newValues[index] = value;
|
|
1129
|
-
set(ctx.formData, name, newValues);
|
|
1130
|
-
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1131
|
-
validateIfNeeded();
|
|
1132
|
-
return true;
|
|
1133
|
-
};
|
|
1134
|
-
const removeAt = (index) => {
|
|
1135
|
-
clearValidationCache();
|
|
1136
|
-
const currentValues = ensureSync();
|
|
1137
|
-
if (index < 0 || index >= currentValues.length) {
|
|
1138
|
-
if (__DEV__) warnArrayIndexOutOfBounds("remove", name, index, currentValues.length);
|
|
1139
|
-
return false;
|
|
1140
|
-
}
|
|
1141
|
-
const rules = fa.rules;
|
|
1142
|
-
if (rules?.minLength && currentValues.length - 1 < rules.minLength.value) {
|
|
1143
|
-
if (__DEV__) warnArrayOperationRejected("remove", name, "minLength", {
|
|
1144
|
-
current: currentValues.length,
|
|
1145
|
-
limit: rules.minLength.value
|
|
1146
|
-
});
|
|
1147
|
-
return false;
|
|
1148
|
-
}
|
|
1149
|
-
const newValues = currentValues.filter((_, i) => i !== index);
|
|
1150
|
-
set(ctx.formData, name, newValues);
|
|
1151
|
-
const keyToRemove = fa.items.value[index]?.key;
|
|
1152
|
-
fa.items.value = fa.items.value.filter((item) => item.key !== keyToRemove);
|
|
1153
|
-
if (keyToRemove) updateCacheAfterRemove(keyToRemove, index);
|
|
1154
|
-
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1155
|
-
validateIfNeeded();
|
|
1156
|
-
return true;
|
|
1157
|
-
};
|
|
1158
|
-
const insert = (index, value, focusOptions) => {
|
|
1159
|
-
clearValidationCache();
|
|
1160
|
-
const values = normalizeToArray(value);
|
|
1161
|
-
if (values.length === 0) return true;
|
|
1162
|
-
const currentValues = ensureSync();
|
|
1163
|
-
const rules = fa.rules;
|
|
1164
|
-
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) {
|
|
1165
|
-
if (__DEV__) warnArrayOperationRejected("insert", name, "maxLength", {
|
|
1166
|
-
current: currentValues.length,
|
|
1167
|
-
limit: rules.maxLength.value
|
|
1168
|
-
});
|
|
1169
|
-
return false;
|
|
1170
|
-
}
|
|
1171
|
-
if (index < 0 || index > currentValues.length) {
|
|
1172
|
-
if (__DEV__) warnArrayIndexOutOfBounds("insert", name, index, currentValues.length);
|
|
1173
|
-
return false;
|
|
1174
|
-
}
|
|
1175
|
-
const newValues = [
|
|
1176
|
-
...currentValues.slice(0, index),
|
|
1177
|
-
...values,
|
|
1178
|
-
...currentValues.slice(index)
|
|
1179
|
-
];
|
|
1180
|
-
set(ctx.formData, name, newValues);
|
|
1181
|
-
const newItems = values.map(() => createItem(generateId()));
|
|
1182
|
-
fa.items.value = [
|
|
1183
|
-
...fa.items.value.slice(0, index),
|
|
1184
|
-
...newItems,
|
|
1185
|
-
...fa.items.value.slice(index)
|
|
1186
|
-
];
|
|
1187
|
-
updateCacheAfterInsert(index, values.length);
|
|
1188
|
-
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1189
|
-
validateIfNeeded();
|
|
1190
|
-
handleFocus(index, values.length, focusOptions);
|
|
1191
|
-
return true;
|
|
1192
|
-
};
|
|
1193
|
-
const swap = (indexA, indexB) => {
|
|
1194
|
-
clearValidationCache();
|
|
1195
|
-
const currentValues = ensureSync();
|
|
1196
|
-
if (indexA < 0 || indexB < 0 || indexA >= currentValues.length || indexB >= currentValues.length) {
|
|
1197
|
-
if (__DEV__) warnArrayIndexOutOfBounds("swap", name, indexA < 0 || indexA >= currentValues.length ? indexA : indexB, currentValues.length);
|
|
1198
|
-
return false;
|
|
1199
|
-
}
|
|
1200
|
-
const newValues = [...currentValues];
|
|
1201
|
-
[newValues[indexA], newValues[indexB]] = [newValues[indexB], newValues[indexA]];
|
|
1202
|
-
set(ctx.formData, name, newValues);
|
|
1203
|
-
const newItems = [...fa.items.value];
|
|
1204
|
-
const itemA = newItems[indexA];
|
|
1205
|
-
const itemB = newItems[indexB];
|
|
1206
|
-
if (itemA && itemB) {
|
|
1207
|
-
newItems[indexA] = itemB;
|
|
1208
|
-
newItems[indexB] = itemA;
|
|
1209
|
-
fa.items.value = newItems;
|
|
1210
|
-
swapInCache(indexA, indexB);
|
|
1211
|
-
}
|
|
1212
|
-
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1213
|
-
validateIfNeeded();
|
|
1214
|
-
return true;
|
|
1215
|
-
};
|
|
1216
|
-
const move = (from, to) => {
|
|
1217
|
-
clearValidationCache();
|
|
1218
|
-
const currentValues = ensureSync();
|
|
1219
|
-
if (from < 0 || from >= currentValues.length || to < 0 || to >= currentValues.length) {
|
|
1220
|
-
if (__DEV__) warnArrayIndexOutOfBounds("move", name, from < 0 || from >= currentValues.length ? from : to, currentValues.length);
|
|
1221
|
-
return false;
|
|
1222
|
-
}
|
|
1223
|
-
const newValues = [...currentValues];
|
|
1224
|
-
const [removed] = newValues.splice(from, 1);
|
|
1225
|
-
if (removed !== void 0) {
|
|
1226
|
-
newValues.splice(to, 0, removed);
|
|
1227
|
-
set(ctx.formData, name, newValues);
|
|
1228
|
-
}
|
|
1229
|
-
const newItems = [...fa.items.value];
|
|
1230
|
-
const [removedItem] = newItems.splice(from, 1);
|
|
1231
|
-
if (removedItem) {
|
|
1232
|
-
newItems.splice(to, 0, removedItem);
|
|
1233
|
-
fa.items.value = newItems;
|
|
1234
|
-
const minIdx = Math.min(from, to);
|
|
1235
|
-
const maxIdx = Math.max(from, to);
|
|
1236
|
-
const items = fa.items.value;
|
|
1237
|
-
for (let i = minIdx; i <= maxIdx; i++) {
|
|
1238
|
-
const item = items[i];
|
|
1239
|
-
if (item) indexCache.set(item.key, i);
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1243
|
-
validateIfNeeded();
|
|
1244
|
-
return true;
|
|
1245
|
-
};
|
|
1246
|
-
const replace = (newValues) => {
|
|
1247
|
-
clearValidationCache();
|
|
1248
|
-
if (!Array.isArray(newValues)) return false;
|
|
1249
|
-
set(ctx.formData, name, newValues);
|
|
1250
|
-
fa.items.value = newValues.map(() => createItem(generateId()));
|
|
1251
|
-
rebuildIndexCache();
|
|
1252
|
-
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1253
|
-
validateIfNeeded();
|
|
1254
|
-
return true;
|
|
1255
|
-
};
|
|
1256
|
-
const removeAll = () => {
|
|
1257
|
-
clearValidationCache();
|
|
1258
|
-
const rules = fa.rules;
|
|
1259
|
-
if (rules?.minLength && rules.minLength.value > 0) {
|
|
1260
|
-
if (__DEV__) warnArrayOperationRejected("removeAll", name, "minLength", {
|
|
1261
|
-
current: fa.items.value.length,
|
|
1262
|
-
limit: rules.minLength.value
|
|
1263
|
-
});
|
|
1264
|
-
return false;
|
|
1265
|
-
}
|
|
1266
|
-
set(ctx.formData, name, []);
|
|
1267
|
-
fa.items.value = [];
|
|
1268
|
-
indexCache.clear();
|
|
1269
|
-
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1270
|
-
validateIfNeeded();
|
|
1271
|
-
return true;
|
|
1272
|
-
};
|
|
1273
|
-
const removeMany = (indices) => {
|
|
1274
|
-
clearValidationCache();
|
|
1275
|
-
const currentValues = ensureSync();
|
|
1276
|
-
const validIndices = indices.filter((i) => i >= 0 && i < currentValues.length);
|
|
1277
|
-
if (validIndices.length === 0) return true;
|
|
1278
|
-
const rules = fa.rules;
|
|
1279
|
-
const remainingCount = currentValues.length - validIndices.length;
|
|
1280
|
-
if (rules?.minLength && remainingCount < rules.minLength.value) {
|
|
1281
|
-
if (__DEV__) warnArrayOperationRejected("removeMany", name, "minLength", {
|
|
1282
|
-
current: currentValues.length,
|
|
1283
|
-
limit: rules.minLength.value
|
|
1284
|
-
});
|
|
1285
|
-
return false;
|
|
1286
|
-
}
|
|
1287
|
-
const sortedIndices = [...new Set(validIndices)].sort((a, b) => b - a);
|
|
1288
|
-
const indicesToRemove = new Set(sortedIndices);
|
|
1289
|
-
const keysToRemove = fa.items.value.filter((_, i) => indicesToRemove.has(i)).map((item) => item.key);
|
|
1290
|
-
const newValues = currentValues.filter((_, i) => !indicesToRemove.has(i));
|
|
1291
|
-
set(ctx.formData, name, newValues);
|
|
1292
|
-
fa.items.value = fa.items.value.filter((_, i) => !indicesToRemove.has(i));
|
|
1293
|
-
for (const key of keysToRemove) indexCache.delete(key);
|
|
1294
|
-
fa.items.value.forEach((item, idx) => {
|
|
1295
|
-
indexCache.set(item.key, idx);
|
|
1296
|
-
});
|
|
1297
|
-
updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, get(ctx.formData, name));
|
|
1298
|
-
validateIfNeeded();
|
|
1299
|
-
return true;
|
|
1300
|
-
};
|
|
1301
|
-
return {
|
|
1302
|
-
value: fa.items.value,
|
|
1303
|
-
append,
|
|
1304
|
-
prepend,
|
|
1305
|
-
remove: removeAt,
|
|
1306
|
-
removeAll,
|
|
1307
|
-
removeMany,
|
|
1308
|
-
insert,
|
|
1309
|
-
swap,
|
|
1310
|
-
move,
|
|
1311
|
-
update,
|
|
1312
|
-
replace
|
|
1313
|
-
};
|
|
1314
|
-
}
|
|
1315
|
-
return { fields };
|
|
1316
|
-
}
|
|
1317
|
-
function syncUncontrolledInputs(fieldRefs, fieldOptions, formData) {
|
|
1318
|
-
for (const [name, fieldRef] of Array.from(fieldRefs.entries())) {
|
|
1319
|
-
const el = fieldRef.value;
|
|
1320
|
-
if (el) {
|
|
1321
|
-
if (!fieldOptions.get(name)?.controlled) {
|
|
1322
|
-
let value;
|
|
1323
|
-
if (el.type === "checkbox") value = el.checked;
|
|
1324
|
-
else if (el.type === "number" || el.type === "range") value = el.valueAsNumber;
|
|
1325
|
-
else value = el.value;
|
|
1326
|
-
set(formData, name, value);
|
|
1327
|
-
}
|
|
1328
|
-
}
|
|
1329
|
-
}
|
|
1330
|
-
}
|
|
1331
|
-
function updateDomElement(el, value) {
|
|
1332
|
-
if (el.type === "checkbox") el.checked = value;
|
|
1333
|
-
else el.value = value;
|
|
1334
|
-
}
|
|
1335
|
-
function useForm(options) {
|
|
1336
|
-
const ctx = createFormContext(options);
|
|
1337
|
-
let isSubmissionLocked = false;
|
|
1338
|
-
(0, vue.onUnmounted)(() => {
|
|
1339
|
-
ctx.cleanup();
|
|
1340
|
-
});
|
|
1341
|
-
const { validate, clearAllPendingErrors } = createValidation(ctx);
|
|
1342
|
-
const { register, unregister } = createFieldRegistration(ctx, validate);
|
|
1343
|
-
function setFocus(name, focusOptions) {
|
|
1344
|
-
if (__DEV__) {
|
|
1345
|
-
const syntaxError = validatePathSyntax(name);
|
|
1346
|
-
if (syntaxError) warnInvalidPath("setFocus", name, syntaxError);
|
|
1347
|
-
else {
|
|
1348
|
-
const schemaResult = validatePathAgainstSchema(ctx.options.schema, name);
|
|
1349
|
-
if (!schemaResult.valid) warnPathNotInSchema("setFocus", name, schemaResult.availableFields);
|
|
1350
|
-
}
|
|
1351
|
-
}
|
|
1352
|
-
const fieldRef = ctx.fieldRefs.get(name);
|
|
1353
|
-
if (!fieldRef?.value) return;
|
|
1354
|
-
const el = fieldRef.value;
|
|
1355
|
-
if (typeof el.focus === "function") {
|
|
1356
|
-
el.focus();
|
|
1357
|
-
if (focusOptions?.shouldSelect && el instanceof HTMLInputElement && typeof el.select === "function") el.select();
|
|
1358
|
-
}
|
|
1359
|
-
}
|
|
1360
|
-
const setFocusWrapper = (name) => setFocus(name);
|
|
1361
|
-
const { fields } = createFieldArrayManager(ctx, validate, setFocusWrapper);
|
|
1362
|
-
let lastSyncTime = 0;
|
|
1363
|
-
const SYNC_DEBOUNCE_MS = 16;
|
|
1364
|
-
function syncWithDebounce() {
|
|
1365
|
-
const now = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
1366
|
-
if (now - lastSyncTime < SYNC_DEBOUNCE_MS) return;
|
|
1367
|
-
syncUncontrolledInputs(ctx.fieldRefs, ctx.fieldOptions, ctx.formData);
|
|
1368
|
-
lastSyncTime = now;
|
|
1369
|
-
}
|
|
1370
|
-
let lastErrors = ctx.errors.value;
|
|
1371
|
-
let lastExternalErrors = ctx.externalErrors.value;
|
|
1372
|
-
let cachedMergedErrors = null;
|
|
1373
|
-
function getMergedErrors() {
|
|
1374
|
-
if (cachedMergedErrors !== null && lastErrors === ctx.errors.value && lastExternalErrors === ctx.externalErrors.value) return cachedMergedErrors;
|
|
1375
|
-
lastErrors = ctx.errors.value;
|
|
1376
|
-
lastExternalErrors = ctx.externalErrors.value;
|
|
1377
|
-
cachedMergedErrors = {
|
|
1378
|
-
...ctx.errors.value,
|
|
1379
|
-
...ctx.externalErrors.value
|
|
1380
|
-
};
|
|
1381
|
-
return cachedMergedErrors;
|
|
1382
|
-
}
|
|
1383
|
-
const isDirtyComputed = (0, vue.computed)(() => Object.keys(ctx.dirtyFields.value).length > 0);
|
|
1384
|
-
const errorsComputed = (0, vue.computed)(() => getMergedErrors());
|
|
1385
|
-
const isValidComputed = (0, vue.computed)(() => {
|
|
1386
|
-
if (!(ctx.submitCount.value > 0 || Object.keys(ctx.touchedFields.value).length > 0)) return false;
|
|
1387
|
-
return Object.keys(errorsComputed.value).length === 0;
|
|
1388
|
-
});
|
|
1389
|
-
const isReadyComputed = (0, vue.computed)(() => !ctx.isLoading.value);
|
|
1390
|
-
const isValidatingComputed = (0, vue.computed)(() => ctx.validatingFields.value.size > 0);
|
|
1391
|
-
const isSubmittedComputed = (0, vue.computed)(() => ctx.submitCount.value > 0);
|
|
1392
|
-
const formStateInternal = (0, vue.reactive)({
|
|
1393
|
-
get errors() {
|
|
1394
|
-
return errorsComputed.value;
|
|
1395
|
-
},
|
|
1396
|
-
get isDirty() {
|
|
1397
|
-
return isDirtyComputed.value;
|
|
1398
|
-
},
|
|
1399
|
-
get dirtyFields() {
|
|
1400
|
-
return ctx.dirtyFields.value;
|
|
1401
|
-
},
|
|
1402
|
-
get isValid() {
|
|
1403
|
-
return isValidComputed.value;
|
|
1404
|
-
},
|
|
1405
|
-
get isSubmitting() {
|
|
1406
|
-
return ctx.isSubmitting.value;
|
|
1407
|
-
},
|
|
1408
|
-
get isLoading() {
|
|
1409
|
-
return ctx.isLoading.value;
|
|
1410
|
-
},
|
|
1411
|
-
get isReady() {
|
|
1412
|
-
return isReadyComputed.value;
|
|
1413
|
-
},
|
|
1414
|
-
get isValidating() {
|
|
1415
|
-
return isValidatingComputed.value;
|
|
1416
|
-
},
|
|
1417
|
-
get validatingFields() {
|
|
1418
|
-
return ctx.validatingFields.value;
|
|
1419
|
-
},
|
|
1420
|
-
get touchedFields() {
|
|
1421
|
-
return ctx.touchedFields.value;
|
|
1422
|
-
},
|
|
1423
|
-
get submitCount() {
|
|
1424
|
-
return ctx.submitCount.value;
|
|
1425
|
-
},
|
|
1426
|
-
get defaultValuesError() {
|
|
1427
|
-
return ctx.defaultValuesError.value;
|
|
1428
|
-
},
|
|
1429
|
-
get isSubmitted() {
|
|
1430
|
-
return isSubmittedComputed.value;
|
|
1431
|
-
},
|
|
1432
|
-
get isSubmitSuccessful() {
|
|
1433
|
-
return ctx.isSubmitSuccessful.value;
|
|
1434
|
-
},
|
|
1435
|
-
get disabled() {
|
|
1436
|
-
return ctx.isDisabled.value;
|
|
1437
|
-
}
|
|
1438
|
-
});
|
|
1439
|
-
const formState = (0, vue.computed)(() => formStateInternal);
|
|
1440
|
-
function handleSubmit(onValid, onInvalid) {
|
|
1441
|
-
return async (e) => {
|
|
1442
|
-
e.preventDefault();
|
|
1443
|
-
if (ctx.isDisabled.value) return;
|
|
1444
|
-
if (isSubmissionLocked) return;
|
|
1445
|
-
isSubmissionLocked = true;
|
|
1446
|
-
ctx.isSubmitting.value = true;
|
|
1447
|
-
ctx.submitCount.value++;
|
|
1448
|
-
ctx.isSubmitSuccessful.value = false;
|
|
1449
|
-
try {
|
|
1450
|
-
syncWithDebounce();
|
|
1451
|
-
if (await validate()) {
|
|
1452
|
-
await onValid(ctx.formData);
|
|
1453
|
-
ctx.isSubmitSuccessful.value = true;
|
|
1454
|
-
} else {
|
|
1455
|
-
onInvalid?.(formState.value.errors);
|
|
1456
|
-
if (options.shouldFocusError !== false) {
|
|
1457
|
-
const firstErrorField = Object.keys(formState.value.errors)[0];
|
|
1458
|
-
if (firstErrorField) setFocus(firstErrorField);
|
|
1459
|
-
}
|
|
1460
|
-
}
|
|
1461
|
-
} finally {
|
|
1462
|
-
ctx.isSubmitting.value = false;
|
|
1463
|
-
isSubmissionLocked = false;
|
|
1464
|
-
}
|
|
1465
|
-
};
|
|
1466
|
-
}
|
|
1467
|
-
function setValue(name, value, setValueOptions) {
|
|
1468
|
-
if (__DEV__) {
|
|
1469
|
-
const syntaxError = validatePathSyntax(name);
|
|
1470
|
-
if (syntaxError) warnInvalidPath("setValue", name, syntaxError);
|
|
1471
|
-
else {
|
|
1472
|
-
const schemaResult = validatePathAgainstSchema(ctx.options.schema, name);
|
|
1473
|
-
if (!schemaResult.valid) warnPathNotInSchema("setValue", name, schemaResult.availableFields);
|
|
1474
|
-
}
|
|
1475
|
-
}
|
|
1476
|
-
set(ctx.formData, name, value);
|
|
1477
|
-
if (setValueOptions?.shouldDirty === false) clearFieldDirty(ctx.dirtyFields, name);
|
|
1478
|
-
else updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, value);
|
|
1479
|
-
if (setValueOptions?.shouldTouch) markFieldTouched(ctx.touchedFields, name);
|
|
1480
|
-
if (!ctx.fieldOptions.get(name)?.controlled) {
|
|
1481
|
-
const fieldRef = ctx.fieldRefs.get(name);
|
|
1482
|
-
if (fieldRef?.value) updateDomElement(fieldRef.value, value);
|
|
1483
|
-
}
|
|
1484
|
-
if (setValueOptions?.shouldValidate) validate(name);
|
|
1485
|
-
}
|
|
1486
|
-
function reset(values, resetOptions) {
|
|
1487
|
-
const opts = resetOptions || {};
|
|
1488
|
-
ctx.validationCache.clear();
|
|
1489
|
-
ctx.resetGeneration.value++;
|
|
1490
|
-
clearAllPendingErrors();
|
|
1491
|
-
ctx.validatingFields.value = /* @__PURE__ */ new Set();
|
|
1492
|
-
for (const timer of ctx.schemaValidationTimers.values()) clearTimeout(timer);
|
|
1493
|
-
ctx.schemaValidationTimers.clear();
|
|
1494
|
-
for (const timer of ctx.debounceTimers.values()) clearTimeout(timer);
|
|
1495
|
-
ctx.debounceTimers.clear();
|
|
1496
|
-
ctx.validationRequestIds.clear();
|
|
1497
|
-
if (!opts.keepDefaultValues && values) {
|
|
1498
|
-
Object.assign(ctx.defaultValues, values);
|
|
1499
|
-
ctx.defaultValueHashes.clear();
|
|
1500
|
-
}
|
|
1501
|
-
Object.keys(ctx.formData).forEach((key) => delete ctx.formData[key]);
|
|
1502
|
-
const newValues = deepClone(values || ctx.defaultValues);
|
|
1503
|
-
Object.assign(ctx.formData, newValues);
|
|
1504
|
-
if (!opts.keepErrors) {
|
|
1505
|
-
ctx.errors.value = {};
|
|
1506
|
-
ctx.persistentErrorFields.clear();
|
|
1507
|
-
}
|
|
1508
|
-
if (!opts.keepTouched) ctx.touchedFields.value = {};
|
|
1509
|
-
if (!opts.keepDirty) ctx.dirtyFields.value = {};
|
|
1510
|
-
if (!opts.keepSubmitCount) ctx.submitCount.value = 0;
|
|
1511
|
-
if (!opts.keepIsSubmitting) ctx.isSubmitting.value = false;
|
|
1512
|
-
if (!opts.keepIsSubmitSuccessful) ctx.isSubmitSuccessful.value = false;
|
|
1513
|
-
ctx.fieldArrays.clear();
|
|
1514
|
-
for (const [name, fieldRef] of Array.from(ctx.fieldRefs.entries())) {
|
|
1515
|
-
const el = fieldRef.value;
|
|
1516
|
-
if (el) {
|
|
1517
|
-
const value = get(newValues, name);
|
|
1518
|
-
if (value !== void 0) if (el.type === "checkbox") el.checked = value;
|
|
1519
|
-
else el.value = value;
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
}
|
|
1523
|
-
function resetField(name, resetFieldOptions) {
|
|
1524
|
-
if (__DEV__) {
|
|
1525
|
-
const syntaxError = validatePathSyntax(name);
|
|
1526
|
-
if (syntaxError) warnInvalidPath("resetField", name, syntaxError);
|
|
1527
|
-
else {
|
|
1528
|
-
const schemaResult = validatePathAgainstSchema(ctx.options.schema, name);
|
|
1529
|
-
if (!schemaResult.valid) warnPathNotInSchema("resetField", name, schemaResult.availableFields);
|
|
1530
|
-
}
|
|
1531
|
-
}
|
|
1532
|
-
const opts = resetFieldOptions || {};
|
|
1533
|
-
ctx.resetGeneration.value++;
|
|
1534
|
-
ctx.validationCache.delete(`${name}:partial`);
|
|
1535
|
-
ctx.validationCache.delete(`${name}:full`);
|
|
1536
|
-
const errorTimer = ctx.errorDelayTimers.get(name);
|
|
1537
|
-
if (errorTimer) {
|
|
1538
|
-
clearTimeout(errorTimer);
|
|
1539
|
-
ctx.errorDelayTimers.delete(name);
|
|
1540
|
-
}
|
|
1541
|
-
ctx.pendingErrors.delete(name);
|
|
1542
|
-
let defaultValue = opts.defaultValue;
|
|
1543
|
-
if (defaultValue === void 0) defaultValue = get(ctx.defaultValues, name);
|
|
1544
|
-
else {
|
|
1545
|
-
set(ctx.defaultValues, name, defaultValue);
|
|
1546
|
-
ctx.defaultValueHashes.set(name, hashValue(defaultValue));
|
|
1547
|
-
}
|
|
1548
|
-
const clonedValue = defaultValue !== void 0 ? deepClone(defaultValue) : void 0;
|
|
1549
|
-
set(ctx.formData, name, clonedValue);
|
|
1550
|
-
if (!opts.keepError) clearFieldErrors(ctx.errors, name);
|
|
1551
|
-
if (!opts.keepDirty) clearFieldDirty(ctx.dirtyFields, name);
|
|
1552
|
-
if (!opts.keepTouched) clearFieldTouched(ctx.touchedFields, name);
|
|
1553
|
-
if (!ctx.fieldOptions.get(name)?.controlled) {
|
|
1554
|
-
const fieldRef = ctx.fieldRefs.get(name);
|
|
1555
|
-
if (fieldRef?.value) updateDomElement(fieldRef.value, clonedValue ?? (fieldRef.value.type === "checkbox" ? false : ""));
|
|
1556
|
-
}
|
|
1557
|
-
}
|
|
1558
|
-
function watch$1(name) {
|
|
1559
|
-
if (__DEV__ && name) {
|
|
1560
|
-
const names = Array.isArray(name) ? name : [name];
|
|
1561
|
-
for (const n of names) {
|
|
1562
|
-
const syntaxError = validatePathSyntax(n);
|
|
1563
|
-
if (syntaxError) warnInvalidPath("watch", n, syntaxError);
|
|
1564
|
-
else {
|
|
1565
|
-
const schemaResult = validatePathAgainstSchema(ctx.options.schema, n);
|
|
1566
|
-
if (!schemaResult.valid) warnPathNotInSchema("watch", n, schemaResult.availableFields);
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
1569
|
-
}
|
|
1570
|
-
return (0, vue.computed)(() => {
|
|
1571
|
-
if (!name) return ctx.formData;
|
|
1572
|
-
if (Array.isArray(name)) {
|
|
1573
|
-
const result = {};
|
|
1574
|
-
for (const n of name) result[n] = get(ctx.formData, n);
|
|
1575
|
-
return result;
|
|
1576
|
-
}
|
|
1577
|
-
return get(ctx.formData, name);
|
|
1578
|
-
});
|
|
1579
|
-
}
|
|
1580
|
-
function clearErrors(name) {
|
|
1581
|
-
if (__DEV__ && name && !String(name).startsWith("root")) {
|
|
1582
|
-
const names = Array.isArray(name) ? name : [name];
|
|
1583
|
-
for (const n of names) {
|
|
1584
|
-
if (String(n).startsWith("root")) continue;
|
|
1585
|
-
const syntaxError = validatePathSyntax(n);
|
|
1586
|
-
if (syntaxError) warnInvalidPath("clearErrors", n, syntaxError);
|
|
1587
|
-
else {
|
|
1588
|
-
const schemaResult = validatePathAgainstSchema(ctx.options.schema, n);
|
|
1589
|
-
if (!schemaResult.valid) warnPathNotInSchema("clearErrors", n, schemaResult.availableFields);
|
|
1590
|
-
}
|
|
1591
|
-
}
|
|
1592
|
-
}
|
|
1593
|
-
if (name === void 0) {
|
|
1594
|
-
ctx.errors.value = {};
|
|
1595
|
-
ctx.externalErrors.value = {};
|
|
1596
|
-
ctx.persistentErrorFields.clear();
|
|
1597
|
-
return;
|
|
1598
|
-
}
|
|
1599
|
-
const fieldsToClean = Array.isArray(name) ? name : [name];
|
|
1600
|
-
for (const field of fieldsToClean) {
|
|
1601
|
-
clearFieldErrors(ctx.errors, field);
|
|
1602
|
-
clearFieldErrors(ctx.externalErrors, field);
|
|
1603
|
-
ctx.persistentErrorFields.delete(field);
|
|
1604
|
-
}
|
|
1605
|
-
}
|
|
1606
|
-
function setError(name, error) {
|
|
1607
|
-
const newErrors = { ...ctx.errors.value };
|
|
1608
|
-
set(newErrors, name, error.type ? {
|
|
1609
|
-
type: error.type,
|
|
1610
|
-
message: error.message
|
|
1611
|
-
} : error.message);
|
|
1612
|
-
ctx.errors.value = newErrors;
|
|
1613
|
-
if (error.persistent) ctx.persistentErrorFields.add(name);
|
|
1614
|
-
}
|
|
1615
|
-
function setErrors(errors, options$1) {
|
|
1616
|
-
const newErrors = options$1?.shouldReplace ? {} : { ...ctx.errors.value };
|
|
1617
|
-
for (const [name, error] of Object.entries(errors)) {
|
|
1618
|
-
if (error === void 0) continue;
|
|
1619
|
-
set(newErrors, name, typeof error === "string" ? error : error.type ? {
|
|
1620
|
-
type: error.type,
|
|
1621
|
-
message: error.message
|
|
1622
|
-
} : error.message);
|
|
1623
|
-
}
|
|
1624
|
-
ctx.errors.value = newErrors;
|
|
1625
|
-
}
|
|
1626
|
-
function hasErrors(fieldPath) {
|
|
1627
|
-
const mergedErrors = getMergedErrors();
|
|
1628
|
-
if (fieldPath === void 0) return Object.keys(mergedErrors).length > 0;
|
|
1629
|
-
const error = get(mergedErrors, fieldPath);
|
|
1630
|
-
return error !== void 0 && error !== null;
|
|
1631
|
-
}
|
|
1632
|
-
function getErrors(fieldPath) {
|
|
1633
|
-
const mergedErrors = getMergedErrors();
|
|
1634
|
-
if (fieldPath === void 0) return mergedErrors;
|
|
1635
|
-
return get(mergedErrors, fieldPath);
|
|
1636
|
-
}
|
|
1637
|
-
function getValues(nameOrNames) {
|
|
1638
|
-
if (__DEV__ && nameOrNames) {
|
|
1639
|
-
const names = Array.isArray(nameOrNames) ? nameOrNames : [nameOrNames];
|
|
1640
|
-
for (const n of names) {
|
|
1641
|
-
const syntaxError = validatePathSyntax(n);
|
|
1642
|
-
if (syntaxError) warnInvalidPath("getValues", n, syntaxError);
|
|
1643
|
-
else {
|
|
1644
|
-
const schemaResult = validatePathAgainstSchema(ctx.options.schema, n);
|
|
1645
|
-
if (!schemaResult.valid) warnPathNotInSchema("getValues", n, schemaResult.availableFields);
|
|
1646
|
-
}
|
|
1647
|
-
}
|
|
1648
|
-
}
|
|
1649
|
-
syncWithDebounce();
|
|
1650
|
-
if (nameOrNames === void 0) return { ...ctx.formData };
|
|
1651
|
-
if (Array.isArray(nameOrNames)) {
|
|
1652
|
-
const result = {};
|
|
1653
|
-
for (const fieldName of nameOrNames) result[fieldName] = get(ctx.formData, fieldName);
|
|
1654
|
-
return result;
|
|
1655
|
-
}
|
|
1656
|
-
return get(ctx.formData, nameOrNames);
|
|
1657
|
-
}
|
|
1658
|
-
function getFieldState(name) {
|
|
1659
|
-
if (__DEV__) {
|
|
1660
|
-
const syntaxError = validatePathSyntax(name);
|
|
1661
|
-
if (syntaxError) warnInvalidPath("getFieldState", name, syntaxError);
|
|
1662
|
-
else {
|
|
1663
|
-
const schemaResult = validatePathAgainstSchema(ctx.options.schema, name);
|
|
1664
|
-
if (!schemaResult.valid) warnPathNotInSchema("getFieldState", name, schemaResult.availableFields);
|
|
1665
|
-
}
|
|
1666
|
-
}
|
|
1667
|
-
const error = get(ctx.errors.value, name);
|
|
1668
|
-
return {
|
|
1669
|
-
isDirty: ctx.dirtyFields.value[name] === true,
|
|
1670
|
-
isTouched: ctx.touchedFields.value[name] === true,
|
|
1671
|
-
invalid: error !== void 0 && error !== null,
|
|
1672
|
-
error
|
|
1673
|
-
};
|
|
1674
|
-
}
|
|
1675
|
-
async function trigger(name, options$1) {
|
|
1676
|
-
if (__DEV__ && name) {
|
|
1677
|
-
const names = Array.isArray(name) ? name : [name];
|
|
1678
|
-
for (const n of names) {
|
|
1679
|
-
const syntaxError = validatePathSyntax(n);
|
|
1680
|
-
if (syntaxError) warnInvalidPath("trigger", n, syntaxError);
|
|
1681
|
-
else {
|
|
1682
|
-
const schemaResult = validatePathAgainstSchema(ctx.options.schema, n);
|
|
1683
|
-
if (!schemaResult.valid) warnPathNotInSchema("trigger", n, schemaResult.availableFields);
|
|
1684
|
-
}
|
|
1685
|
-
}
|
|
1686
|
-
}
|
|
1687
|
-
if (options$1?.markAsSubmitted) ctx.submitCount.value++;
|
|
1688
|
-
if (name === void 0) return await validate();
|
|
1689
|
-
if (Array.isArray(name)) {
|
|
1690
|
-
let allValid = true;
|
|
1691
|
-
for (const fieldName of name) if (!await validate(fieldName)) allValid = false;
|
|
1692
|
-
return allValid;
|
|
1693
|
-
}
|
|
1694
|
-
return await validate(name);
|
|
1695
|
-
}
|
|
1696
|
-
return {
|
|
1697
|
-
register,
|
|
1698
|
-
unregister,
|
|
1699
|
-
handleSubmit,
|
|
1700
|
-
formState,
|
|
1701
|
-
fields,
|
|
1702
|
-
setValue,
|
|
1703
|
-
reset,
|
|
1704
|
-
resetField,
|
|
1705
|
-
watch: watch$1,
|
|
1706
|
-
validate,
|
|
1707
|
-
clearErrors,
|
|
1708
|
-
setError,
|
|
1709
|
-
setErrors,
|
|
1710
|
-
hasErrors,
|
|
1711
|
-
getErrors,
|
|
1712
|
-
getValues,
|
|
1713
|
-
getFieldState,
|
|
1714
|
-
trigger,
|
|
1715
|
-
setFocus,
|
|
1716
|
-
options: {
|
|
1717
|
-
mode: ctx.options.mode ?? "onSubmit",
|
|
1718
|
-
reValidateMode: ctx.options.reValidateMode
|
|
1719
|
-
}
|
|
1720
|
-
};
|
|
1721
|
-
}
|
|
1722
|
-
const FormContextKey = Symbol("FormContext");
|
|
1723
|
-
function provideForm(methods) {
|
|
1724
|
-
(0, vue.provide)(FormContextKey, methods);
|
|
1725
|
-
}
|
|
1726
|
-
function useFormContext() {
|
|
1727
|
-
const context = (0, vue.inject)(FormContextKey);
|
|
1728
|
-
if (!context) throw new Error("useFormContext must be used within a component tree where provideForm() has been called. Make sure to call provideForm(useForm({ schema })) in a parent component.");
|
|
1729
|
-
return context;
|
|
1730
|
-
}
|
|
1731
|
-
function useWatch(options = {}) {
|
|
1732
|
-
const { control, name, defaultValue } = options;
|
|
1733
|
-
const form = control ?? useFormContext();
|
|
1734
|
-
return (0, vue.computed)(() => {
|
|
1735
|
-
if (name === void 0) return form.getValues();
|
|
1736
|
-
if (Array.isArray(name)) {
|
|
1737
|
-
const result = {};
|
|
1738
|
-
for (const fieldName of name) result[fieldName] = get(form.getValues(), fieldName) ?? defaultValue;
|
|
1739
|
-
return result;
|
|
1740
|
-
}
|
|
1741
|
-
return get(form.getValues(), name) ?? defaultValue;
|
|
1742
|
-
});
|
|
1743
|
-
}
|
|
1744
|
-
function useController(options) {
|
|
1745
|
-
const { name, control, defaultValue } = options;
|
|
1746
|
-
const form = control ?? useFormContext();
|
|
1747
|
-
const elementRef = (0, vue.ref)(null);
|
|
1748
|
-
if (defaultValue !== void 0 && form.getValues(name) === void 0) form.setValue(name, defaultValue);
|
|
1749
|
-
const value = (0, vue.computed)({
|
|
1750
|
-
get: () => {
|
|
1751
|
-
return form.getValues(name) ?? defaultValue;
|
|
1752
|
-
},
|
|
1753
|
-
set: (newValue) => {
|
|
1754
|
-
form.setValue(name, newValue);
|
|
1755
|
-
}
|
|
1756
|
-
});
|
|
1757
|
-
const onChange = (newValue) => {
|
|
1758
|
-
const isTouched = form.formState.value.touchedFields[name] === true;
|
|
1759
|
-
const hasSubmitted = form.formState.value.submitCount > 0;
|
|
1760
|
-
const mode = form.options.mode ?? "onSubmit";
|
|
1761
|
-
const reValidateMode = form.options.reValidateMode;
|
|
1762
|
-
const shouldValidate = shouldValidateOnChange(mode, isTouched, reValidateMode, hasSubmitted);
|
|
1763
|
-
form.setValue(name, newValue, { shouldValidate });
|
|
1764
|
-
};
|
|
1765
|
-
const onBlur = () => {
|
|
1766
|
-
const hasSubmitted = form.formState.value.submitCount > 0;
|
|
1767
|
-
const mode = form.options.mode ?? "onSubmit";
|
|
1768
|
-
const reValidateMode = form.options.reValidateMode;
|
|
1769
|
-
const shouldValidate = shouldValidateOnBlur(mode, hasSubmitted, reValidateMode);
|
|
1770
|
-
const currentValue = form.getValues(name);
|
|
1771
|
-
form.setValue(name, currentValue, {
|
|
1772
|
-
shouldTouch: true,
|
|
1773
|
-
shouldValidate,
|
|
1774
|
-
shouldDirty: false
|
|
1775
|
-
});
|
|
1776
|
-
};
|
|
1777
|
-
const refCallback = (el) => {
|
|
1778
|
-
elementRef.value = el;
|
|
1779
|
-
};
|
|
1780
|
-
const fieldState = (0, vue.computed)(() => {
|
|
1781
|
-
return form.getFieldState(name);
|
|
1782
|
-
});
|
|
1783
|
-
return {
|
|
1784
|
-
field: {
|
|
1785
|
-
value,
|
|
1786
|
-
name,
|
|
1787
|
-
onChange,
|
|
1788
|
-
onBlur,
|
|
1789
|
-
ref: refCallback
|
|
1790
|
-
},
|
|
1791
|
-
fieldState
|
|
1792
|
-
};
|
|
1793
|
-
}
|
|
1794
|
-
function useFormState(options = {}) {
|
|
1795
|
-
const { control, name } = options;
|
|
1796
|
-
const form = control ?? useFormContext();
|
|
1797
|
-
return (0, vue.computed)(() => {
|
|
1798
|
-
const fullState = form.formState.value;
|
|
1799
|
-
if (name === void 0) return { ...fullState };
|
|
1800
|
-
if (Array.isArray(name)) {
|
|
1801
|
-
const result = {};
|
|
1802
|
-
for (const key of name) result[key] = fullState[key];
|
|
1803
|
-
return result;
|
|
1804
|
-
}
|
|
1805
|
-
return { [name]: fullState[name] };
|
|
1806
|
-
});
|
|
1807
|
-
}
|
|
1808
|
-
function isFieldError(error) {
|
|
1809
|
-
return typeof error === "object" && error !== null && "type" in error && "message" in error && typeof error.type === "string" && typeof error.message === "string";
|
|
1810
|
-
}
|
|
1811
|
-
exports.FormContextKey = FormContextKey;
|
|
1812
|
-
exports.clearPathCache = clearPathCache;
|
|
1813
|
-
exports.generateId = generateId;
|
|
1814
|
-
exports.get = get;
|
|
1815
|
-
exports.isFieldError = isFieldError;
|
|
1816
|
-
exports.provideForm = provideForm;
|
|
1817
|
-
exports.set = set;
|
|
1818
|
-
exports.unset = unset;
|
|
1819
|
-
exports.useController = useController;
|
|
1820
|
-
exports.useForm = useForm;
|
|
1821
|
-
exports.useFormContext = useFormContext;
|
|
1822
|
-
exports.useFormState = useFormState;
|
|
1823
|
-
exports.useWatch = useWatch;
|