@vuehookform/core 0.2.10 → 0.3.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 +26 -28
- package/dist/core/domSync.d.ts +0 -7
- package/dist/core/formContext.d.ts +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/types.d.ts +324 -35
- package/dist/utils/devWarnings.d.ts +59 -0
- package/dist/vuehookform.cjs +184 -21
- package/dist/vuehookform.js +397 -21
- package/package.json +19 -7
package/dist/vuehookform.js
CHANGED
|
@@ -52,6 +52,152 @@ function generateId() {
|
|
|
52
52
|
const random = Math.random().toString(36).substring(2, 11);
|
|
53
53
|
return `field_${Date.now()}_${idCounter++}_${random}`;
|
|
54
54
|
}
|
|
55
|
+
const __DEV__ = typeof import.meta !== "undefined" && false;
|
|
56
|
+
var warnedMessages = /* @__PURE__ */ new Set();
|
|
57
|
+
function warnOnce(message, key) {
|
|
58
|
+
if (!__DEV__) return;
|
|
59
|
+
const cacheKey = key ?? message;
|
|
60
|
+
if (warnedMessages.has(cacheKey)) return;
|
|
61
|
+
warnedMessages.add(cacheKey);
|
|
62
|
+
console.warn(`[vue-hook-form] ${message}`);
|
|
63
|
+
}
|
|
64
|
+
function warn(message) {
|
|
65
|
+
if (!__DEV__) return;
|
|
66
|
+
console.warn(`[vue-hook-form] ${message}`);
|
|
67
|
+
}
|
|
68
|
+
function validatePathSyntax(path) {
|
|
69
|
+
if (!__DEV__) return null;
|
|
70
|
+
if (!path || path.trim() === "") return "Path cannot be empty";
|
|
71
|
+
if (path.startsWith(".") || path.endsWith(".") || path.includes("..")) return `Invalid path "${path}": contains empty segments`;
|
|
72
|
+
if (path.includes("[")) return `Invalid path "${path}": use dot notation (e.g., "items.0") instead of bracket notation (e.g., "items[0]")`;
|
|
73
|
+
if (/\s/.test(path)) return `Invalid path "${path}": paths cannot contain whitespace`;
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
function traverseSchemaPath(schema, path) {
|
|
77
|
+
const segments = path.split(".");
|
|
78
|
+
let currentSchema = schema;
|
|
79
|
+
for (let i = 0; i < segments.length; i++) {
|
|
80
|
+
const segment = segments[i];
|
|
81
|
+
if (!segment) continue;
|
|
82
|
+
currentSchema = unwrapSchema(currentSchema);
|
|
83
|
+
if (isZodObject(currentSchema)) {
|
|
84
|
+
const shape = currentSchema.shape;
|
|
85
|
+
if (segment in shape) {
|
|
86
|
+
const nextSchema = shape[segment];
|
|
87
|
+
if (nextSchema) {
|
|
88
|
+
currentSchema = nextSchema;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
error: `Field "${segments.slice(0, i + 1).join(".")}" does not exist in schema`,
|
|
94
|
+
availableFields: Object.keys(shape),
|
|
95
|
+
segmentIndex: i
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (isZodArray(currentSchema) && /^\d+$/.test(segment)) {
|
|
99
|
+
currentSchema = currentSchema.element;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
error: `Cannot navigate path "${path}" at segment "${segment}"`,
|
|
104
|
+
segmentIndex: i
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return { schema: currentSchema };
|
|
108
|
+
}
|
|
109
|
+
function validatePathAgainstSchema(schema, path) {
|
|
110
|
+
if (!__DEV__) return { valid: true };
|
|
111
|
+
try {
|
|
112
|
+
const result = traverseSchemaPath(schema, path);
|
|
113
|
+
if ("error" in result) return {
|
|
114
|
+
valid: false,
|
|
115
|
+
reason: result.error,
|
|
116
|
+
availableFields: result.availableFields
|
|
117
|
+
};
|
|
118
|
+
return { valid: true };
|
|
119
|
+
} catch {
|
|
120
|
+
return { valid: true };
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function isArrayFieldInSchema(schema, path) {
|
|
124
|
+
if (!__DEV__) return null;
|
|
125
|
+
try {
|
|
126
|
+
const result = traverseSchemaPath(schema, path);
|
|
127
|
+
if ("error" in result) return null;
|
|
128
|
+
return isZodArray(unwrapSchema(result.schema));
|
|
129
|
+
} catch {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function warnInvalidPath(fnName, path, reason) {
|
|
134
|
+
if (!__DEV__) return;
|
|
135
|
+
let message = `${fnName}("${path}"): ${reason}`;
|
|
136
|
+
if (reason.includes("bracket notation")) {
|
|
137
|
+
const fixedPath = path.replace(/\[(\d+)\]/g, ".$1");
|
|
138
|
+
message += `\n FIX: Use dot notation for array indices`;
|
|
139
|
+
message += `\n EXAMPLE: ${fnName}("${fixedPath}")`;
|
|
140
|
+
} else if (reason.includes("empty")) {
|
|
141
|
+
message += `\n FIX: Provide a non-empty field path`;
|
|
142
|
+
message += `\n EXAMPLE: ${fnName}("email") or ${fnName}("user.address.city")`;
|
|
143
|
+
} else if (reason.includes("whitespace")) {
|
|
144
|
+
const fixedPath = path.replace(/\s/g, "");
|
|
145
|
+
message += `\n FIX: Remove spaces from the field path`;
|
|
146
|
+
message += `\n EXAMPLE: ${fnName}("${fixedPath}")`;
|
|
147
|
+
} else if (reason.includes("empty segments")) {
|
|
148
|
+
const fixedPath = path.replace(/\.{2,}/g, ".").replace(/^\./, "").replace(/\.$/, "");
|
|
149
|
+
message += `\n FIX: Remove extra dots from the path`;
|
|
150
|
+
message += `\n EXAMPLE: ${fnName}("${fixedPath}")`;
|
|
151
|
+
}
|
|
152
|
+
warnOnce(message, `invalid-path:${fnName}:${path}`);
|
|
153
|
+
}
|
|
154
|
+
function warnPathNotInSchema(fnName, path, availableFields) {
|
|
155
|
+
if (!__DEV__) return;
|
|
156
|
+
let message = `${fnName}("${path}"): Path does not exist in your Zod schema.`;
|
|
157
|
+
message += `\n FIX: Check that the path matches your schema definition exactly (case-sensitive)`;
|
|
158
|
+
if (availableFields && availableFields.length > 0) {
|
|
159
|
+
const pathLower = path.toLowerCase();
|
|
160
|
+
const suggestions = availableFields.filter((f) => f.toLowerCase().includes(pathLower) || pathLower.includes(f.toLowerCase()));
|
|
161
|
+
if (suggestions.length > 0) message += `\n DID YOU MEAN: ${suggestions.slice(0, 3).map((s) => `"${s}"`).join(", ")}`;
|
|
162
|
+
message += `\n AVAILABLE: ${availableFields.slice(0, 8).join(", ")}${availableFields.length > 8 ? "..." : ""}`;
|
|
163
|
+
}
|
|
164
|
+
warnOnce(message, `path-not-in-schema:${fnName}:${path}`);
|
|
165
|
+
}
|
|
166
|
+
function warnFieldsOnNonArray(path) {
|
|
167
|
+
if (!__DEV__) return;
|
|
168
|
+
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}`);
|
|
169
|
+
}
|
|
170
|
+
function warnArrayOperationRejected(operation, path, reason, details) {
|
|
171
|
+
if (!__DEV__) return;
|
|
172
|
+
warn(`${operation}() on "${path}": ${{
|
|
173
|
+
maxLength: details ? `Would exceed maxLength (current: ${details.current}, max: ${details.limit})` : "Would exceed maxLength rule",
|
|
174
|
+
minLength: details ? `Would violate minLength (current: ${details.current}, min: ${details.limit})` : "Would violate minLength rule"
|
|
175
|
+
}[reason]}. Operation was silently ignored.`);
|
|
176
|
+
}
|
|
177
|
+
function warnArrayIndexOutOfBounds(operation, path, index, length) {
|
|
178
|
+
if (!__DEV__) return;
|
|
179
|
+
warn(`${operation}() on "${path}": Index ${index} is out of bounds (array length: ${length}). Operation was silently ignored.`);
|
|
180
|
+
}
|
|
181
|
+
function getDefProp(schema, prop) {
|
|
182
|
+
return schema.def[prop];
|
|
183
|
+
}
|
|
184
|
+
function getTypeName(schema) {
|
|
185
|
+
return getDefProp(schema, "typeName");
|
|
186
|
+
}
|
|
187
|
+
function isZodObject(schema) {
|
|
188
|
+
return getTypeName(schema) === "ZodObject";
|
|
189
|
+
}
|
|
190
|
+
function isZodArray(schema) {
|
|
191
|
+
return getTypeName(schema) === "ZodArray";
|
|
192
|
+
}
|
|
193
|
+
function unwrapSchema(schema) {
|
|
194
|
+
const typeName = getTypeName(schema);
|
|
195
|
+
const innerType = getDefProp(schema, "innerType");
|
|
196
|
+
const schemaType = getDefProp(schema, "schema");
|
|
197
|
+
if ((typeName === "ZodOptional" || typeName === "ZodNullable" || typeName === "ZodDefault") && innerType) return unwrapSchema(innerType);
|
|
198
|
+
if (typeName === "ZodEffects" && schemaType) return unwrapSchema(schemaType);
|
|
199
|
+
return schema;
|
|
200
|
+
}
|
|
55
201
|
function createFormContext(options) {
|
|
56
202
|
const formData = reactive({});
|
|
57
203
|
const defaultValues = reactive({});
|
|
@@ -91,6 +237,13 @@ function createFormContext(options) {
|
|
|
91
237
|
const debounceTimers = /* @__PURE__ */ new Map();
|
|
92
238
|
const validationRequestIds = /* @__PURE__ */ new Map();
|
|
93
239
|
const resetGeneration = ref(0);
|
|
240
|
+
const isDisabled = ref(false);
|
|
241
|
+
if (options.disabled !== void 0) {
|
|
242
|
+
isDisabled.value = toValue(options.disabled) ?? false;
|
|
243
|
+
watch(() => toValue(options.disabled), (newDisabled) => {
|
|
244
|
+
isDisabled.value = newDisabled ?? false;
|
|
245
|
+
});
|
|
246
|
+
}
|
|
94
247
|
if (options.values !== void 0) {
|
|
95
248
|
const initialValues = toValue(options.values);
|
|
96
249
|
if (initialValues && !isAsyncDefaults) {
|
|
@@ -140,6 +293,7 @@ function createFormContext(options) {
|
|
|
140
293
|
debounceTimers,
|
|
141
294
|
validationRequestIds,
|
|
142
295
|
resetGeneration,
|
|
296
|
+
isDisabled,
|
|
143
297
|
options
|
|
144
298
|
};
|
|
145
299
|
}
|
|
@@ -190,12 +344,23 @@ function createFieldError(errors, criteriaMode = "firstError") {
|
|
|
190
344
|
};
|
|
191
345
|
}
|
|
192
346
|
function createValidation(ctx) {
|
|
347
|
+
function applyNativeValidation(fieldPath, errorMessage) {
|
|
348
|
+
if (!ctx.options.shouldUseNativeValidation) return;
|
|
349
|
+
const el = ctx.fieldRefs.get(fieldPath)?.value;
|
|
350
|
+
if (el && "setCustomValidity" in el) el.setCustomValidity(errorMessage || "");
|
|
351
|
+
}
|
|
352
|
+
function clearAllNativeValidation() {
|
|
353
|
+
if (!ctx.options.shouldUseNativeValidation) return;
|
|
354
|
+
for (const [path] of ctx.fieldRefs) applyNativeValidation(path, null);
|
|
355
|
+
}
|
|
193
356
|
function scheduleError(fieldPath, error) {
|
|
194
357
|
const delayMs = ctx.options.delayError || 0;
|
|
358
|
+
const errorMessage = typeof error === "string" ? error : error.message;
|
|
195
359
|
if (delayMs <= 0) {
|
|
196
360
|
const newErrors = { ...ctx.errors.value };
|
|
197
361
|
set(newErrors, fieldPath, error);
|
|
198
362
|
ctx.errors.value = newErrors;
|
|
363
|
+
applyNativeValidation(fieldPath, errorMessage);
|
|
199
364
|
return;
|
|
200
365
|
}
|
|
201
366
|
const existingTimer = ctx.errorDelayTimers.get(fieldPath);
|
|
@@ -209,6 +374,7 @@ function createValidation(ctx) {
|
|
|
209
374
|
const newErrors = { ...ctx.errors.value };
|
|
210
375
|
set(newErrors, fieldPath, pendingError);
|
|
211
376
|
ctx.errors.value = newErrors;
|
|
377
|
+
applyNativeValidation(fieldPath, errorMessage);
|
|
212
378
|
}
|
|
213
379
|
}, delayMs);
|
|
214
380
|
ctx.errorDelayTimers.set(fieldPath, timer);
|
|
@@ -220,6 +386,7 @@ function createValidation(ctx) {
|
|
|
220
386
|
ctx.errorDelayTimers.delete(fieldPath);
|
|
221
387
|
}
|
|
222
388
|
ctx.pendingErrors.delete(fieldPath);
|
|
389
|
+
applyNativeValidation(fieldPath, null);
|
|
223
390
|
return clearFieldErrors$1(ctx.errors.value, fieldPath);
|
|
224
391
|
}
|
|
225
392
|
function clearAllPendingErrors() {
|
|
@@ -240,6 +407,7 @@ function createValidation(ctx) {
|
|
|
240
407
|
else {
|
|
241
408
|
clearAllPendingErrors();
|
|
242
409
|
ctx.errors.value = {};
|
|
410
|
+
clearAllNativeValidation();
|
|
243
411
|
}
|
|
244
412
|
return true;
|
|
245
413
|
}
|
|
@@ -275,6 +443,12 @@ function createValidation(ctx) {
|
|
|
275
443
|
var validationRequestCounter = 0;
|
|
276
444
|
function createFieldRegistration(ctx, validate) {
|
|
277
445
|
function register(name, registerOptions) {
|
|
446
|
+
if (__DEV__) {
|
|
447
|
+
const syntaxError = validatePathSyntax(name);
|
|
448
|
+
if (syntaxError) warnInvalidPath("register", name, syntaxError);
|
|
449
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, name);
|
|
450
|
+
if (!schemaResult.valid) warnPathNotInSchema("register", name, schemaResult.availableFields);
|
|
451
|
+
}
|
|
278
452
|
let fieldRef = ctx.fieldRefs.get(name);
|
|
279
453
|
if (!fieldRef) {
|
|
280
454
|
fieldRef = ref(null);
|
|
@@ -393,6 +567,7 @@ function createFieldRegistration(ctx, validate) {
|
|
|
393
567
|
ref: handlers.refCallback,
|
|
394
568
|
onInput: handlers.onInput,
|
|
395
569
|
onBlur: handlers.onBlur,
|
|
570
|
+
...ctx.isDisabled.value && { disabled: true },
|
|
396
571
|
...registerOptions?.controlled && { value: computed({
|
|
397
572
|
get: () => get(ctx.formData, name),
|
|
398
573
|
set: (val) => {
|
|
@@ -440,6 +615,13 @@ function createFieldRegistration(ctx, validate) {
|
|
|
440
615
|
}
|
|
441
616
|
function createFieldArrayManager(ctx, validate, setFocus) {
|
|
442
617
|
function fields(name, options) {
|
|
618
|
+
if (__DEV__) {
|
|
619
|
+
const syntaxError = validatePathSyntax(name);
|
|
620
|
+
if (syntaxError) warnInvalidPath("fields", name, syntaxError);
|
|
621
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, name);
|
|
622
|
+
if (!schemaResult.valid) warnPathNotInSchema("fields", name, schemaResult.availableFields);
|
|
623
|
+
if (isArrayFieldInSchema(ctx.options.schema, name) === false) warnFieldsOnNonArray(name);
|
|
624
|
+
}
|
|
443
625
|
let fieldArray = ctx.fieldArrays.get(name);
|
|
444
626
|
if (!fieldArray) {
|
|
445
627
|
const existingValues = get(ctx.formData, name) || [];
|
|
@@ -487,11 +669,17 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
487
669
|
};
|
|
488
670
|
const append = (value, focusOptions) => {
|
|
489
671
|
const values = normalizeToArray(value);
|
|
490
|
-
if (values.length === 0) return;
|
|
672
|
+
if (values.length === 0) return true;
|
|
491
673
|
const currentValues = get(ctx.formData, name) || [];
|
|
492
674
|
const insertIndex = currentValues.length;
|
|
493
675
|
const rules = fa.rules;
|
|
494
|
-
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value)
|
|
676
|
+
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) {
|
|
677
|
+
if (__DEV__) warnArrayOperationRejected("append", name, "maxLength", {
|
|
678
|
+
current: currentValues.length,
|
|
679
|
+
limit: rules.maxLength.value
|
|
680
|
+
});
|
|
681
|
+
return false;
|
|
682
|
+
}
|
|
495
683
|
const newValues = [...currentValues, ...values];
|
|
496
684
|
set(ctx.formData, name, newValues);
|
|
497
685
|
const newItems = values.map(() => createItem(generateId()));
|
|
@@ -503,13 +691,20 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
503
691
|
};
|
|
504
692
|
if (ctx.options.mode === "onChange") validate(name);
|
|
505
693
|
handleFocus(insertIndex, values.length, focusOptions);
|
|
694
|
+
return true;
|
|
506
695
|
};
|
|
507
696
|
const prepend = (value, focusOptions) => {
|
|
508
697
|
const values = normalizeToArray(value);
|
|
509
|
-
if (values.length === 0) return;
|
|
698
|
+
if (values.length === 0) return true;
|
|
510
699
|
const currentValues = get(ctx.formData, name) || [];
|
|
511
700
|
const rules = fa.rules;
|
|
512
|
-
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value)
|
|
701
|
+
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) {
|
|
702
|
+
if (__DEV__) warnArrayOperationRejected("prepend", name, "maxLength", {
|
|
703
|
+
current: currentValues.length,
|
|
704
|
+
limit: rules.maxLength.value
|
|
705
|
+
});
|
|
706
|
+
return false;
|
|
707
|
+
}
|
|
513
708
|
const newValues = [...values, ...currentValues];
|
|
514
709
|
set(ctx.formData, name, newValues);
|
|
515
710
|
const newItems = values.map(() => createItem(generateId()));
|
|
@@ -521,10 +716,14 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
521
716
|
};
|
|
522
717
|
if (ctx.options.mode === "onChange") validate(name);
|
|
523
718
|
handleFocus(0, values.length, focusOptions);
|
|
719
|
+
return true;
|
|
524
720
|
};
|
|
525
721
|
const update = (index, value) => {
|
|
526
722
|
const currentValues = get(ctx.formData, name) || [];
|
|
527
|
-
if (index < 0 || index >= currentValues.length)
|
|
723
|
+
if (index < 0 || index >= currentValues.length) {
|
|
724
|
+
if (__DEV__) warnArrayIndexOutOfBounds("update", name, index, currentValues.length);
|
|
725
|
+
return false;
|
|
726
|
+
}
|
|
528
727
|
const newValues = [...currentValues];
|
|
529
728
|
newValues[index] = value;
|
|
530
729
|
set(ctx.formData, name, newValues);
|
|
@@ -533,12 +732,22 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
533
732
|
[name]: true
|
|
534
733
|
};
|
|
535
734
|
if (ctx.options.mode === "onChange") validate(name);
|
|
735
|
+
return true;
|
|
536
736
|
};
|
|
537
737
|
const removeAt = (index) => {
|
|
538
738
|
const currentValues = get(ctx.formData, name) || [];
|
|
539
|
-
if (index < 0 || index >= currentValues.length)
|
|
739
|
+
if (index < 0 || index >= currentValues.length) {
|
|
740
|
+
if (__DEV__) warnArrayIndexOutOfBounds("remove", name, index, currentValues.length);
|
|
741
|
+
return false;
|
|
742
|
+
}
|
|
540
743
|
const rules = fa.rules;
|
|
541
|
-
if (rules?.minLength && currentValues.length - 1 < rules.minLength.value)
|
|
744
|
+
if (rules?.minLength && currentValues.length - 1 < rules.minLength.value) {
|
|
745
|
+
if (__DEV__) warnArrayOperationRejected("remove", name, "minLength", {
|
|
746
|
+
current: currentValues.length,
|
|
747
|
+
limit: rules.minLength.value
|
|
748
|
+
});
|
|
749
|
+
return false;
|
|
750
|
+
}
|
|
542
751
|
const newValues = currentValues.filter((_, i) => i !== index);
|
|
543
752
|
set(ctx.formData, name, newValues);
|
|
544
753
|
const keyToRemove = fa.items.value[index]?.key;
|
|
@@ -549,13 +758,20 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
549
758
|
[name]: true
|
|
550
759
|
};
|
|
551
760
|
if (ctx.options.mode === "onChange") validate(name);
|
|
761
|
+
return true;
|
|
552
762
|
};
|
|
553
763
|
const insert = (index, value, focusOptions) => {
|
|
554
764
|
const values = normalizeToArray(value);
|
|
555
|
-
if (values.length === 0) return;
|
|
765
|
+
if (values.length === 0) return true;
|
|
556
766
|
const currentValues = get(ctx.formData, name) || [];
|
|
557
767
|
const rules = fa.rules;
|
|
558
|
-
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value)
|
|
768
|
+
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) {
|
|
769
|
+
if (__DEV__) warnArrayOperationRejected("insert", name, "maxLength", {
|
|
770
|
+
current: currentValues.length,
|
|
771
|
+
limit: rules.maxLength.value
|
|
772
|
+
});
|
|
773
|
+
return false;
|
|
774
|
+
}
|
|
559
775
|
const clampedIndex = Math.max(0, Math.min(index, currentValues.length));
|
|
560
776
|
const newValues = [
|
|
561
777
|
...currentValues.slice(0, clampedIndex),
|
|
@@ -576,10 +792,14 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
576
792
|
};
|
|
577
793
|
if (ctx.options.mode === "onChange") validate(name);
|
|
578
794
|
handleFocus(clampedIndex, values.length, focusOptions);
|
|
795
|
+
return true;
|
|
579
796
|
};
|
|
580
797
|
const swap = (indexA, indexB) => {
|
|
581
798
|
const currentValues = get(ctx.formData, name) || [];
|
|
582
|
-
if (indexA < 0 || indexB < 0 || indexA >= currentValues.length || indexB >= currentValues.length)
|
|
799
|
+
if (indexA < 0 || indexB < 0 || indexA >= currentValues.length || indexB >= currentValues.length) {
|
|
800
|
+
if (__DEV__) warnArrayIndexOutOfBounds("swap", name, indexA < 0 || indexA >= currentValues.length ? indexA : indexB, currentValues.length);
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
583
803
|
const newValues = [...currentValues];
|
|
584
804
|
[newValues[indexA], newValues[indexB]] = [newValues[indexB], newValues[indexA]];
|
|
585
805
|
set(ctx.formData, name, newValues);
|
|
@@ -597,10 +817,14 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
597
817
|
[name]: true
|
|
598
818
|
};
|
|
599
819
|
if (ctx.options.mode === "onChange") validate(name);
|
|
820
|
+
return true;
|
|
600
821
|
};
|
|
601
822
|
const move = (from, to) => {
|
|
602
823
|
const currentValues = get(ctx.formData, name) || [];
|
|
603
|
-
if (from < 0 || from >= currentValues.length || to < 0)
|
|
824
|
+
if (from < 0 || from >= currentValues.length || to < 0) {
|
|
825
|
+
if (__DEV__) warnArrayIndexOutOfBounds("move", name, from < 0 || from >= currentValues.length ? from : to, currentValues.length);
|
|
826
|
+
return false;
|
|
827
|
+
}
|
|
604
828
|
const newValues = [...currentValues];
|
|
605
829
|
const [removed] = newValues.splice(from, 1);
|
|
606
830
|
if (removed !== void 0) {
|
|
@@ -621,9 +845,10 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
621
845
|
[name]: true
|
|
622
846
|
};
|
|
623
847
|
if (ctx.options.mode === "onChange") validate(name);
|
|
848
|
+
return true;
|
|
624
849
|
};
|
|
625
850
|
const replace = (newValues) => {
|
|
626
|
-
if (!Array.isArray(newValues)) return;
|
|
851
|
+
if (!Array.isArray(newValues)) return false;
|
|
627
852
|
set(ctx.formData, name, newValues);
|
|
628
853
|
fa.items.value = newValues.map(() => createItem(generateId()));
|
|
629
854
|
rebuildIndexCache();
|
|
@@ -632,12 +857,60 @@ function createFieldArrayManager(ctx, validate, setFocus) {
|
|
|
632
857
|
[name]: true
|
|
633
858
|
};
|
|
634
859
|
if (ctx.options.mode === "onChange") validate(name);
|
|
860
|
+
return true;
|
|
861
|
+
};
|
|
862
|
+
const removeAll = () => {
|
|
863
|
+
const rules = fa.rules;
|
|
864
|
+
if (rules?.minLength && rules.minLength.value > 0) {
|
|
865
|
+
if (__DEV__) warnArrayOperationRejected("removeAll", name, "minLength", {
|
|
866
|
+
current: fa.items.value.length,
|
|
867
|
+
limit: rules.minLength.value
|
|
868
|
+
});
|
|
869
|
+
return false;
|
|
870
|
+
}
|
|
871
|
+
set(ctx.formData, name, []);
|
|
872
|
+
fa.items.value = [];
|
|
873
|
+
rebuildIndexCache();
|
|
874
|
+
ctx.dirtyFields.value = {
|
|
875
|
+
...ctx.dirtyFields.value,
|
|
876
|
+
[name]: true
|
|
877
|
+
};
|
|
878
|
+
if (ctx.options.mode === "onChange") validate(name);
|
|
879
|
+
return true;
|
|
880
|
+
};
|
|
881
|
+
const removeMany = (indices) => {
|
|
882
|
+
const currentValues = get(ctx.formData, name) || [];
|
|
883
|
+
const validIndices = indices.filter((i) => i >= 0 && i < currentValues.length);
|
|
884
|
+
if (validIndices.length === 0) return true;
|
|
885
|
+
const rules = fa.rules;
|
|
886
|
+
const remainingCount = currentValues.length - validIndices.length;
|
|
887
|
+
if (rules?.minLength && remainingCount < rules.minLength.value) {
|
|
888
|
+
if (__DEV__) warnArrayOperationRejected("removeMany", name, "minLength", {
|
|
889
|
+
current: currentValues.length,
|
|
890
|
+
limit: rules.minLength.value
|
|
891
|
+
});
|
|
892
|
+
return false;
|
|
893
|
+
}
|
|
894
|
+
const sortedIndices = [...new Set(validIndices)].sort((a, b) => b - a);
|
|
895
|
+
const indicesToRemove = new Set(sortedIndices);
|
|
896
|
+
const newValues = currentValues.filter((_, i) => !indicesToRemove.has(i));
|
|
897
|
+
set(ctx.formData, name, newValues);
|
|
898
|
+
fa.items.value = fa.items.value.filter((_, i) => !indicesToRemove.has(i));
|
|
899
|
+
rebuildIndexCache();
|
|
900
|
+
ctx.dirtyFields.value = {
|
|
901
|
+
...ctx.dirtyFields.value,
|
|
902
|
+
[name]: true
|
|
903
|
+
};
|
|
904
|
+
if (ctx.options.mode === "onChange") validate(name);
|
|
905
|
+
return true;
|
|
635
906
|
};
|
|
636
907
|
return {
|
|
637
908
|
value: fa.items.value,
|
|
638
909
|
append,
|
|
639
910
|
prepend,
|
|
640
911
|
remove: removeAt,
|
|
912
|
+
removeAll,
|
|
913
|
+
removeMany,
|
|
641
914
|
insert,
|
|
642
915
|
swap,
|
|
643
916
|
move,
|
|
@@ -691,6 +964,14 @@ function useForm(options) {
|
|
|
691
964
|
const { validate, clearAllPendingErrors } = createValidation(ctx);
|
|
692
965
|
const { register, unregister } = createFieldRegistration(ctx, validate);
|
|
693
966
|
function setFocus(name, focusOptions) {
|
|
967
|
+
if (__DEV__) {
|
|
968
|
+
const syntaxError = validatePathSyntax(name);
|
|
969
|
+
if (syntaxError) warnInvalidPath("setFocus", name, syntaxError);
|
|
970
|
+
else {
|
|
971
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, name);
|
|
972
|
+
if (!schemaResult.valid) warnPathNotInSchema("setFocus", name, schemaResult.availableFields);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
694
975
|
const fieldRef = ctx.fieldRefs.get(name);
|
|
695
976
|
if (!fieldRef?.value) return;
|
|
696
977
|
const el = fieldRef.value;
|
|
@@ -701,11 +982,14 @@ function useForm(options) {
|
|
|
701
982
|
}
|
|
702
983
|
const setFocusWrapper = (name) => setFocus(name);
|
|
703
984
|
const { fields } = createFieldArrayManager(ctx, validate, setFocusWrapper);
|
|
704
|
-
|
|
705
|
-
|
|
985
|
+
function getMergedErrors() {
|
|
986
|
+
return {
|
|
706
987
|
...ctx.errors.value,
|
|
707
988
|
...ctx.externalErrors.value
|
|
708
989
|
};
|
|
990
|
+
}
|
|
991
|
+
const formState = computed(() => {
|
|
992
|
+
const mergedErrors = getMergedErrors();
|
|
709
993
|
return {
|
|
710
994
|
errors: mergedErrors,
|
|
711
995
|
isDirty: Object.keys(ctx.dirtyFields.value).some((k) => ctx.dirtyFields.value[k]),
|
|
@@ -720,12 +1004,14 @@ function useForm(options) {
|
|
|
720
1004
|
submitCount: ctx.submitCount.value,
|
|
721
1005
|
defaultValuesError: ctx.defaultValuesError.value,
|
|
722
1006
|
isSubmitted: ctx.submitCount.value > 0,
|
|
723
|
-
isSubmitSuccessful: ctx.isSubmitSuccessful.value
|
|
1007
|
+
isSubmitSuccessful: ctx.isSubmitSuccessful.value,
|
|
1008
|
+
disabled: ctx.isDisabled.value
|
|
724
1009
|
};
|
|
725
1010
|
});
|
|
726
1011
|
function handleSubmit(onValid, onInvalid) {
|
|
727
1012
|
return async (e) => {
|
|
728
1013
|
e.preventDefault();
|
|
1014
|
+
if (ctx.isDisabled.value) return;
|
|
729
1015
|
if (ctx.isSubmitting.value) return;
|
|
730
1016
|
ctx.isSubmitting.value = true;
|
|
731
1017
|
ctx.submitCount.value++;
|
|
@@ -748,6 +1034,14 @@ function useForm(options) {
|
|
|
748
1034
|
};
|
|
749
1035
|
}
|
|
750
1036
|
function setValue(name, value, setValueOptions) {
|
|
1037
|
+
if (__DEV__) {
|
|
1038
|
+
const syntaxError = validatePathSyntax(name);
|
|
1039
|
+
if (syntaxError) warnInvalidPath("setValue", name, syntaxError);
|
|
1040
|
+
else {
|
|
1041
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, name);
|
|
1042
|
+
if (!schemaResult.valid) warnPathNotInSchema("setValue", name, schemaResult.availableFields);
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
751
1045
|
set(ctx.formData, name, value);
|
|
752
1046
|
if (setValueOptions?.shouldDirty !== false) markFieldDirty(ctx.dirtyFields, name);
|
|
753
1047
|
if (setValueOptions?.shouldTouch) markFieldTouched(ctx.touchedFields, name);
|
|
@@ -757,9 +1051,6 @@ function useForm(options) {
|
|
|
757
1051
|
}
|
|
758
1052
|
if (setValueOptions?.shouldValidate) validate(name);
|
|
759
1053
|
}
|
|
760
|
-
function getValue(name) {
|
|
761
|
-
return get(ctx.formData, name);
|
|
762
|
-
}
|
|
763
1054
|
function reset(values, resetOptions) {
|
|
764
1055
|
const opts = resetOptions || {};
|
|
765
1056
|
ctx.resetGeneration.value++;
|
|
@@ -787,6 +1078,14 @@ function useForm(options) {
|
|
|
787
1078
|
}
|
|
788
1079
|
}
|
|
789
1080
|
function resetField(name, resetFieldOptions) {
|
|
1081
|
+
if (__DEV__) {
|
|
1082
|
+
const syntaxError = validatePathSyntax(name);
|
|
1083
|
+
if (syntaxError) warnInvalidPath("resetField", name, syntaxError);
|
|
1084
|
+
else {
|
|
1085
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, name);
|
|
1086
|
+
if (!schemaResult.valid) warnPathNotInSchema("resetField", name, schemaResult.availableFields);
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
790
1089
|
const opts = resetFieldOptions || {};
|
|
791
1090
|
ctx.resetGeneration.value++;
|
|
792
1091
|
const errorTimer = ctx.errorDelayTimers.get(name);
|
|
@@ -809,6 +1108,17 @@ function useForm(options) {
|
|
|
809
1108
|
}
|
|
810
1109
|
}
|
|
811
1110
|
function watch$1(name) {
|
|
1111
|
+
if (__DEV__ && name) {
|
|
1112
|
+
const names = Array.isArray(name) ? name : [name];
|
|
1113
|
+
for (const n of names) {
|
|
1114
|
+
const syntaxError = validatePathSyntax(n);
|
|
1115
|
+
if (syntaxError) warnInvalidPath("watch", n, syntaxError);
|
|
1116
|
+
else {
|
|
1117
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, n);
|
|
1118
|
+
if (!schemaResult.valid) warnPathNotInSchema("watch", n, schemaResult.availableFields);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
812
1122
|
return computed(() => {
|
|
813
1123
|
if (!name) return ctx.formData;
|
|
814
1124
|
if (Array.isArray(name)) {
|
|
@@ -820,6 +1130,18 @@ function useForm(options) {
|
|
|
820
1130
|
});
|
|
821
1131
|
}
|
|
822
1132
|
function clearErrors(name) {
|
|
1133
|
+
if (__DEV__ && name && !String(name).startsWith("root")) {
|
|
1134
|
+
const names = Array.isArray(name) ? name : [name];
|
|
1135
|
+
for (const n of names) {
|
|
1136
|
+
if (String(n).startsWith("root")) continue;
|
|
1137
|
+
const syntaxError = validatePathSyntax(n);
|
|
1138
|
+
if (syntaxError) warnInvalidPath("clearErrors", n, syntaxError);
|
|
1139
|
+
else {
|
|
1140
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, n);
|
|
1141
|
+
if (!schemaResult.valid) warnPathNotInSchema("clearErrors", n, schemaResult.availableFields);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
823
1145
|
if (name === void 0) {
|
|
824
1146
|
ctx.errors.value = {};
|
|
825
1147
|
return;
|
|
@@ -835,7 +1157,40 @@ function useForm(options) {
|
|
|
835
1157
|
} : error.message);
|
|
836
1158
|
ctx.errors.value = newErrors;
|
|
837
1159
|
}
|
|
1160
|
+
function setErrors(errors, options$1) {
|
|
1161
|
+
const newErrors = options$1?.shouldReplace ? {} : { ...ctx.errors.value };
|
|
1162
|
+
for (const [name, error] of Object.entries(errors)) {
|
|
1163
|
+
if (error === void 0) continue;
|
|
1164
|
+
set(newErrors, name, typeof error === "string" ? error : error.type ? {
|
|
1165
|
+
type: error.type,
|
|
1166
|
+
message: error.message
|
|
1167
|
+
} : error.message);
|
|
1168
|
+
}
|
|
1169
|
+
ctx.errors.value = newErrors;
|
|
1170
|
+
}
|
|
1171
|
+
function hasErrors(fieldPath) {
|
|
1172
|
+
const mergedErrors = getMergedErrors();
|
|
1173
|
+
if (fieldPath === void 0) return Object.keys(mergedErrors).length > 0;
|
|
1174
|
+
const error = get(mergedErrors, fieldPath);
|
|
1175
|
+
return error !== void 0 && error !== null;
|
|
1176
|
+
}
|
|
1177
|
+
function getErrors(fieldPath) {
|
|
1178
|
+
const mergedErrors = getMergedErrors();
|
|
1179
|
+
if (fieldPath === void 0) return mergedErrors;
|
|
1180
|
+
return get(mergedErrors, fieldPath);
|
|
1181
|
+
}
|
|
838
1182
|
function getValues(nameOrNames) {
|
|
1183
|
+
if (__DEV__ && nameOrNames) {
|
|
1184
|
+
const names = Array.isArray(nameOrNames) ? nameOrNames : [nameOrNames];
|
|
1185
|
+
for (const n of names) {
|
|
1186
|
+
const syntaxError = validatePathSyntax(n);
|
|
1187
|
+
if (syntaxError) warnInvalidPath("getValues", n, syntaxError);
|
|
1188
|
+
else {
|
|
1189
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, n);
|
|
1190
|
+
if (!schemaResult.valid) warnPathNotInSchema("getValues", n, schemaResult.availableFields);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
839
1194
|
syncUncontrolledInputs(ctx.fieldRefs, ctx.fieldOptions, ctx.formData);
|
|
840
1195
|
if (nameOrNames === void 0) return { ...ctx.formData };
|
|
841
1196
|
if (Array.isArray(nameOrNames)) {
|
|
@@ -846,6 +1201,14 @@ function useForm(options) {
|
|
|
846
1201
|
return get(ctx.formData, nameOrNames);
|
|
847
1202
|
}
|
|
848
1203
|
function getFieldState(name) {
|
|
1204
|
+
if (__DEV__) {
|
|
1205
|
+
const syntaxError = validatePathSyntax(name);
|
|
1206
|
+
if (syntaxError) warnInvalidPath("getFieldState", name, syntaxError);
|
|
1207
|
+
else {
|
|
1208
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, name);
|
|
1209
|
+
if (!schemaResult.valid) warnPathNotInSchema("getFieldState", name, schemaResult.availableFields);
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
849
1212
|
const error = get(ctx.errors.value, name);
|
|
850
1213
|
return {
|
|
851
1214
|
isDirty: ctx.dirtyFields.value[name] === true,
|
|
@@ -855,6 +1218,17 @@ function useForm(options) {
|
|
|
855
1218
|
};
|
|
856
1219
|
}
|
|
857
1220
|
async function trigger(name) {
|
|
1221
|
+
if (__DEV__ && name) {
|
|
1222
|
+
const names = Array.isArray(name) ? name : [name];
|
|
1223
|
+
for (const n of names) {
|
|
1224
|
+
const syntaxError = validatePathSyntax(n);
|
|
1225
|
+
if (syntaxError) warnInvalidPath("trigger", n, syntaxError);
|
|
1226
|
+
else {
|
|
1227
|
+
const schemaResult = validatePathAgainstSchema(ctx.options.schema, n);
|
|
1228
|
+
if (!schemaResult.valid) warnPathNotInSchema("trigger", n, schemaResult.availableFields);
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
858
1232
|
if (name === void 0) return await validate();
|
|
859
1233
|
if (Array.isArray(name)) {
|
|
860
1234
|
let allValid = true;
|
|
@@ -870,13 +1244,15 @@ function useForm(options) {
|
|
|
870
1244
|
formState,
|
|
871
1245
|
fields,
|
|
872
1246
|
setValue,
|
|
873
|
-
getValue,
|
|
874
1247
|
reset,
|
|
875
1248
|
resetField,
|
|
876
1249
|
watch: watch$1,
|
|
877
1250
|
validate,
|
|
878
1251
|
clearErrors,
|
|
879
1252
|
setError,
|
|
1253
|
+
setErrors,
|
|
1254
|
+
hasErrors,
|
|
1255
|
+
getErrors,
|
|
880
1256
|
getValues,
|
|
881
1257
|
getFieldState,
|
|
882
1258
|
trigger,
|
|
@@ -909,10 +1285,10 @@ function useController(options) {
|
|
|
909
1285
|
const { name, control, defaultValue } = options;
|
|
910
1286
|
const form = control ?? useFormContext();
|
|
911
1287
|
const elementRef = ref(null);
|
|
912
|
-
if (defaultValue !== void 0 && form.
|
|
1288
|
+
if (defaultValue !== void 0 && form.getValues(name) === void 0) form.setValue(name, defaultValue);
|
|
913
1289
|
const value = computed({
|
|
914
1290
|
get: () => {
|
|
915
|
-
return form.
|
|
1291
|
+
return form.getValues(name) ?? defaultValue;
|
|
916
1292
|
},
|
|
917
1293
|
set: (newValue) => {
|
|
918
1294
|
form.setValue(name, newValue);
|