@vuehookform/core 0.2.11 → 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.
@@ -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) return;
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) return;
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) return;
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) return;
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) return;
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) return;
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) return;
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) return;
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
- const formState = computed(() => {
705
- const mergedErrors = {
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.getValue(name) === void 0) form.setValue(name, defaultValue);
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.getValue(name) ?? defaultValue;
1291
+ return form.getValues(name) ?? defaultValue;
916
1292
  },
917
1293
  set: (newValue) => {
918
1294
  form.setValue(name, newValue);