@vuehookform/core 0.2.11 → 0.3.3

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