@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.
@@ -53,6 +53,77 @@ function generateId() {
53
53
  const random = Math.random().toString(36).substring(2, 11);
54
54
  return `field_${Date.now()}_${idCounter++}_${random}`;
55
55
  }
56
+ const __DEV__ = false;
57
+ var warnedMessages = /* @__PURE__ */ new Set();
58
+ function warnOnce(message, key) {}
59
+ function warn(message) {}
60
+ function validatePathSyntax(path) {
61
+ return null;
62
+ }
63
+ function traverseSchemaPath(schema, path) {
64
+ const segments = path.split(".");
65
+ let currentSchema = schema;
66
+ for (let i = 0; i < segments.length; i++) {
67
+ const segment = segments[i];
68
+ if (!segment) continue;
69
+ currentSchema = unwrapSchema(currentSchema);
70
+ if (isZodObject(currentSchema)) {
71
+ const shape = currentSchema.shape;
72
+ if (segment in shape) {
73
+ const nextSchema = shape[segment];
74
+ if (nextSchema) {
75
+ currentSchema = nextSchema;
76
+ continue;
77
+ }
78
+ }
79
+ return {
80
+ error: `Field "${segments.slice(0, i + 1).join(".")}" does not exist in schema`,
81
+ availableFields: Object.keys(shape),
82
+ segmentIndex: i
83
+ };
84
+ }
85
+ if (isZodArray(currentSchema) && /^\d+$/.test(segment)) {
86
+ currentSchema = currentSchema.element;
87
+ continue;
88
+ }
89
+ return {
90
+ error: `Cannot navigate path "${path}" at segment "${segment}"`,
91
+ segmentIndex: i
92
+ };
93
+ }
94
+ return { schema: currentSchema };
95
+ }
96
+ function validatePathAgainstSchema(schema, path) {
97
+ return { valid: true };
98
+ }
99
+ function isArrayFieldInSchema(schema, path) {
100
+ return null;
101
+ }
102
+ function warnInvalidPath(fnName, path, reason) {}
103
+ function warnPathNotInSchema(fnName, path, availableFields) {}
104
+ function warnFieldsOnNonArray(path) {}
105
+ function warnArrayOperationRejected(operation, path, reason, details) {}
106
+ function warnArrayIndexOutOfBounds(operation, path, index, length) {}
107
+ function getDefProp(schema, prop) {
108
+ return schema.def[prop];
109
+ }
110
+ function getTypeName(schema) {
111
+ return getDefProp(schema, "typeName");
112
+ }
113
+ function isZodObject(schema) {
114
+ return getTypeName(schema) === "ZodObject";
115
+ }
116
+ function isZodArray(schema) {
117
+ return getTypeName(schema) === "ZodArray";
118
+ }
119
+ function unwrapSchema(schema) {
120
+ const typeName = getTypeName(schema);
121
+ const innerType = getDefProp(schema, "innerType");
122
+ const schemaType = getDefProp(schema, "schema");
123
+ if ((typeName === "ZodOptional" || typeName === "ZodNullable" || typeName === "ZodDefault") && innerType) return unwrapSchema(innerType);
124
+ if (typeName === "ZodEffects" && schemaType) return unwrapSchema(schemaType);
125
+ return schema;
126
+ }
56
127
  function createFormContext(options) {
57
128
  const formData = (0, vue.reactive)({});
58
129
  const defaultValues = (0, vue.reactive)({});
@@ -92,6 +163,13 @@ function createFormContext(options) {
92
163
  const debounceTimers = /* @__PURE__ */ new Map();
93
164
  const validationRequestIds = /* @__PURE__ */ new Map();
94
165
  const resetGeneration = (0, vue.ref)(0);
166
+ const isDisabled = (0, vue.ref)(false);
167
+ if (options.disabled !== void 0) {
168
+ isDisabled.value = (0, vue.toValue)(options.disabled) ?? false;
169
+ (0, vue.watch)(() => (0, vue.toValue)(options.disabled), (newDisabled) => {
170
+ isDisabled.value = newDisabled ?? false;
171
+ });
172
+ }
95
173
  if (options.values !== void 0) {
96
174
  const initialValues = (0, vue.toValue)(options.values);
97
175
  if (initialValues && !isAsyncDefaults) {
@@ -141,6 +219,7 @@ function createFormContext(options) {
141
219
  debounceTimers,
142
220
  validationRequestIds,
143
221
  resetGeneration,
222
+ isDisabled,
144
223
  options
145
224
  };
146
225
  }
@@ -191,12 +270,23 @@ function createFieldError(errors, criteriaMode = "firstError") {
191
270
  };
192
271
  }
193
272
  function createValidation(ctx) {
273
+ function applyNativeValidation(fieldPath, errorMessage) {
274
+ if (!ctx.options.shouldUseNativeValidation) return;
275
+ const el = ctx.fieldRefs.get(fieldPath)?.value;
276
+ if (el && "setCustomValidity" in el) el.setCustomValidity(errorMessage || "");
277
+ }
278
+ function clearAllNativeValidation() {
279
+ if (!ctx.options.shouldUseNativeValidation) return;
280
+ for (const [path] of ctx.fieldRefs) applyNativeValidation(path, null);
281
+ }
194
282
  function scheduleError(fieldPath, error) {
195
283
  const delayMs = ctx.options.delayError || 0;
284
+ const errorMessage = typeof error === "string" ? error : error.message;
196
285
  if (delayMs <= 0) {
197
286
  const newErrors = { ...ctx.errors.value };
198
287
  set(newErrors, fieldPath, error);
199
288
  ctx.errors.value = newErrors;
289
+ applyNativeValidation(fieldPath, errorMessage);
200
290
  return;
201
291
  }
202
292
  const existingTimer = ctx.errorDelayTimers.get(fieldPath);
@@ -210,6 +300,7 @@ function createValidation(ctx) {
210
300
  const newErrors = { ...ctx.errors.value };
211
301
  set(newErrors, fieldPath, pendingError);
212
302
  ctx.errors.value = newErrors;
303
+ applyNativeValidation(fieldPath, errorMessage);
213
304
  }
214
305
  }, delayMs);
215
306
  ctx.errorDelayTimers.set(fieldPath, timer);
@@ -221,6 +312,7 @@ function createValidation(ctx) {
221
312
  ctx.errorDelayTimers.delete(fieldPath);
222
313
  }
223
314
  ctx.pendingErrors.delete(fieldPath);
315
+ applyNativeValidation(fieldPath, null);
224
316
  return clearFieldErrors$1(ctx.errors.value, fieldPath);
225
317
  }
226
318
  function clearAllPendingErrors() {
@@ -241,6 +333,7 @@ function createValidation(ctx) {
241
333
  else {
242
334
  clearAllPendingErrors();
243
335
  ctx.errors.value = {};
336
+ clearAllNativeValidation();
244
337
  }
245
338
  return true;
246
339
  }
@@ -394,6 +487,7 @@ function createFieldRegistration(ctx, validate) {
394
487
  ref: handlers.refCallback,
395
488
  onInput: handlers.onInput,
396
489
  onBlur: handlers.onBlur,
490
+ ...ctx.isDisabled.value && { disabled: true },
397
491
  ...registerOptions?.controlled && { value: (0, vue.computed)({
398
492
  get: () => get(ctx.formData, name),
399
493
  set: (val) => {
@@ -488,11 +582,11 @@ function createFieldArrayManager(ctx, validate, setFocus) {
488
582
  };
489
583
  const append = (value, focusOptions) => {
490
584
  const values = normalizeToArray(value);
491
- if (values.length === 0) return;
585
+ if (values.length === 0) return true;
492
586
  const currentValues = get(ctx.formData, name) || [];
493
587
  const insertIndex = currentValues.length;
494
588
  const rules = fa.rules;
495
- if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) return;
589
+ if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) return false;
496
590
  const newValues = [...currentValues, ...values];
497
591
  set(ctx.formData, name, newValues);
498
592
  const newItems = values.map(() => createItem(generateId()));
@@ -504,13 +598,14 @@ function createFieldArrayManager(ctx, validate, setFocus) {
504
598
  };
505
599
  if (ctx.options.mode === "onChange") validate(name);
506
600
  handleFocus(insertIndex, values.length, focusOptions);
601
+ return true;
507
602
  };
508
603
  const prepend = (value, focusOptions) => {
509
604
  const values = normalizeToArray(value);
510
- if (values.length === 0) return;
605
+ if (values.length === 0) return true;
511
606
  const currentValues = get(ctx.formData, name) || [];
512
607
  const rules = fa.rules;
513
- if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) return;
608
+ if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) return false;
514
609
  const newValues = [...values, ...currentValues];
515
610
  set(ctx.formData, name, newValues);
516
611
  const newItems = values.map(() => createItem(generateId()));
@@ -522,10 +617,11 @@ function createFieldArrayManager(ctx, validate, setFocus) {
522
617
  };
523
618
  if (ctx.options.mode === "onChange") validate(name);
524
619
  handleFocus(0, values.length, focusOptions);
620
+ return true;
525
621
  };
526
622
  const update = (index, value) => {
527
623
  const currentValues = get(ctx.formData, name) || [];
528
- if (index < 0 || index >= currentValues.length) return;
624
+ if (index < 0 || index >= currentValues.length) return false;
529
625
  const newValues = [...currentValues];
530
626
  newValues[index] = value;
531
627
  set(ctx.formData, name, newValues);
@@ -534,12 +630,13 @@ function createFieldArrayManager(ctx, validate, setFocus) {
534
630
  [name]: true
535
631
  };
536
632
  if (ctx.options.mode === "onChange") validate(name);
633
+ return true;
537
634
  };
538
635
  const removeAt = (index) => {
539
636
  const currentValues = get(ctx.formData, name) || [];
540
- if (index < 0 || index >= currentValues.length) return;
637
+ if (index < 0 || index >= currentValues.length) return false;
541
638
  const rules = fa.rules;
542
- if (rules?.minLength && currentValues.length - 1 < rules.minLength.value) return;
639
+ if (rules?.minLength && currentValues.length - 1 < rules.minLength.value) return false;
543
640
  const newValues = currentValues.filter((_, i) => i !== index);
544
641
  set(ctx.formData, name, newValues);
545
642
  const keyToRemove = fa.items.value[index]?.key;
@@ -550,13 +647,14 @@ function createFieldArrayManager(ctx, validate, setFocus) {
550
647
  [name]: true
551
648
  };
552
649
  if (ctx.options.mode === "onChange") validate(name);
650
+ return true;
553
651
  };
554
652
  const insert = (index, value, focusOptions) => {
555
653
  const values = normalizeToArray(value);
556
- if (values.length === 0) return;
654
+ if (values.length === 0) return true;
557
655
  const currentValues = get(ctx.formData, name) || [];
558
656
  const rules = fa.rules;
559
- if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) return;
657
+ if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) return false;
560
658
  const clampedIndex = Math.max(0, Math.min(index, currentValues.length));
561
659
  const newValues = [
562
660
  ...currentValues.slice(0, clampedIndex),
@@ -577,10 +675,11 @@ function createFieldArrayManager(ctx, validate, setFocus) {
577
675
  };
578
676
  if (ctx.options.mode === "onChange") validate(name);
579
677
  handleFocus(clampedIndex, values.length, focusOptions);
678
+ return true;
580
679
  };
581
680
  const swap = (indexA, indexB) => {
582
681
  const currentValues = get(ctx.formData, name) || [];
583
- if (indexA < 0 || indexB < 0 || indexA >= currentValues.length || indexB >= currentValues.length) return;
682
+ if (indexA < 0 || indexB < 0 || indexA >= currentValues.length || indexB >= currentValues.length) return false;
584
683
  const newValues = [...currentValues];
585
684
  [newValues[indexA], newValues[indexB]] = [newValues[indexB], newValues[indexA]];
586
685
  set(ctx.formData, name, newValues);
@@ -598,10 +697,11 @@ function createFieldArrayManager(ctx, validate, setFocus) {
598
697
  [name]: true
599
698
  };
600
699
  if (ctx.options.mode === "onChange") validate(name);
700
+ return true;
601
701
  };
602
702
  const move = (from, to) => {
603
703
  const currentValues = get(ctx.formData, name) || [];
604
- if (from < 0 || from >= currentValues.length || to < 0) return;
704
+ if (from < 0 || from >= currentValues.length || to < 0) return false;
605
705
  const newValues = [...currentValues];
606
706
  const [removed] = newValues.splice(from, 1);
607
707
  if (removed !== void 0) {
@@ -622,9 +722,10 @@ function createFieldArrayManager(ctx, validate, setFocus) {
622
722
  [name]: true
623
723
  };
624
724
  if (ctx.options.mode === "onChange") validate(name);
725
+ return true;
625
726
  };
626
727
  const replace = (newValues) => {
627
- if (!Array.isArray(newValues)) return;
728
+ if (!Array.isArray(newValues)) return false;
628
729
  set(ctx.formData, name, newValues);
629
730
  fa.items.value = newValues.map(() => createItem(generateId()));
630
731
  rebuildIndexCache();
@@ -633,12 +734,48 @@ function createFieldArrayManager(ctx, validate, setFocus) {
633
734
  [name]: true
634
735
  };
635
736
  if (ctx.options.mode === "onChange") validate(name);
737
+ return true;
738
+ };
739
+ const removeAll = () => {
740
+ const rules = fa.rules;
741
+ if (rules?.minLength && rules.minLength.value > 0) return false;
742
+ set(ctx.formData, name, []);
743
+ fa.items.value = [];
744
+ rebuildIndexCache();
745
+ ctx.dirtyFields.value = {
746
+ ...ctx.dirtyFields.value,
747
+ [name]: true
748
+ };
749
+ if (ctx.options.mode === "onChange") validate(name);
750
+ return true;
751
+ };
752
+ const removeMany = (indices) => {
753
+ const currentValues = get(ctx.formData, name) || [];
754
+ const validIndices = indices.filter((i) => i >= 0 && i < currentValues.length);
755
+ if (validIndices.length === 0) return true;
756
+ const rules = fa.rules;
757
+ const remainingCount = currentValues.length - validIndices.length;
758
+ if (rules?.minLength && remainingCount < rules.minLength.value) return false;
759
+ const sortedIndices = [...new Set(validIndices)].sort((a, b) => b - a);
760
+ const indicesToRemove = new Set(sortedIndices);
761
+ const newValues = currentValues.filter((_, i) => !indicesToRemove.has(i));
762
+ set(ctx.formData, name, newValues);
763
+ fa.items.value = fa.items.value.filter((_, i) => !indicesToRemove.has(i));
764
+ rebuildIndexCache();
765
+ ctx.dirtyFields.value = {
766
+ ...ctx.dirtyFields.value,
767
+ [name]: true
768
+ };
769
+ if (ctx.options.mode === "onChange") validate(name);
770
+ return true;
636
771
  };
637
772
  return {
638
773
  value: fa.items.value,
639
774
  append,
640
775
  prepend,
641
776
  remove: removeAt,
777
+ removeAll,
778
+ removeMany,
642
779
  insert,
643
780
  swap,
644
781
  move,
@@ -702,11 +839,14 @@ function useForm(options) {
702
839
  }
703
840
  const setFocusWrapper = (name) => setFocus(name);
704
841
  const { fields } = createFieldArrayManager(ctx, validate, setFocusWrapper);
705
- const formState = (0, vue.computed)(() => {
706
- const mergedErrors = {
842
+ function getMergedErrors() {
843
+ return {
707
844
  ...ctx.errors.value,
708
845
  ...ctx.externalErrors.value
709
846
  };
847
+ }
848
+ const formState = (0, vue.computed)(() => {
849
+ const mergedErrors = getMergedErrors();
710
850
  return {
711
851
  errors: mergedErrors,
712
852
  isDirty: Object.keys(ctx.dirtyFields.value).some((k) => ctx.dirtyFields.value[k]),
@@ -721,12 +861,14 @@ function useForm(options) {
721
861
  submitCount: ctx.submitCount.value,
722
862
  defaultValuesError: ctx.defaultValuesError.value,
723
863
  isSubmitted: ctx.submitCount.value > 0,
724
- isSubmitSuccessful: ctx.isSubmitSuccessful.value
864
+ isSubmitSuccessful: ctx.isSubmitSuccessful.value,
865
+ disabled: ctx.isDisabled.value
725
866
  };
726
867
  });
727
868
  function handleSubmit(onValid, onInvalid) {
728
869
  return async (e) => {
729
870
  e.preventDefault();
871
+ if (ctx.isDisabled.value) return;
730
872
  if (ctx.isSubmitting.value) return;
731
873
  ctx.isSubmitting.value = true;
732
874
  ctx.submitCount.value++;
@@ -758,9 +900,6 @@ function useForm(options) {
758
900
  }
759
901
  if (setValueOptions?.shouldValidate) validate(name);
760
902
  }
761
- function getValue(name) {
762
- return get(ctx.formData, name);
763
- }
764
903
  function reset(values, resetOptions) {
765
904
  const opts = resetOptions || {};
766
905
  ctx.resetGeneration.value++;
@@ -836,6 +975,28 @@ function useForm(options) {
836
975
  } : error.message);
837
976
  ctx.errors.value = newErrors;
838
977
  }
978
+ function setErrors(errors, options$1) {
979
+ const newErrors = options$1?.shouldReplace ? {} : { ...ctx.errors.value };
980
+ for (const [name, error] of Object.entries(errors)) {
981
+ if (error === void 0) continue;
982
+ set(newErrors, name, typeof error === "string" ? error : error.type ? {
983
+ type: error.type,
984
+ message: error.message
985
+ } : error.message);
986
+ }
987
+ ctx.errors.value = newErrors;
988
+ }
989
+ function hasErrors(fieldPath) {
990
+ const mergedErrors = getMergedErrors();
991
+ if (fieldPath === void 0) return Object.keys(mergedErrors).length > 0;
992
+ const error = get(mergedErrors, fieldPath);
993
+ return error !== void 0 && error !== null;
994
+ }
995
+ function getErrors(fieldPath) {
996
+ const mergedErrors = getMergedErrors();
997
+ if (fieldPath === void 0) return mergedErrors;
998
+ return get(mergedErrors, fieldPath);
999
+ }
839
1000
  function getValues(nameOrNames) {
840
1001
  syncUncontrolledInputs(ctx.fieldRefs, ctx.fieldOptions, ctx.formData);
841
1002
  if (nameOrNames === void 0) return { ...ctx.formData };
@@ -871,13 +1032,15 @@ function useForm(options) {
871
1032
  formState,
872
1033
  fields,
873
1034
  setValue,
874
- getValue,
875
1035
  reset,
876
1036
  resetField,
877
1037
  watch: watch$1,
878
1038
  validate,
879
1039
  clearErrors,
880
1040
  setError,
1041
+ setErrors,
1042
+ hasErrors,
1043
+ getErrors,
881
1044
  getValues,
882
1045
  getFieldState,
883
1046
  trigger,
@@ -910,10 +1073,10 @@ function useController(options) {
910
1073
  const { name, control, defaultValue } = options;
911
1074
  const form = control ?? useFormContext();
912
1075
  const elementRef = (0, vue.ref)(null);
913
- if (defaultValue !== void 0 && form.getValue(name) === void 0) form.setValue(name, defaultValue);
1076
+ if (defaultValue !== void 0 && form.getValues(name) === void 0) form.setValue(name, defaultValue);
914
1077
  const value = (0, vue.computed)({
915
1078
  get: () => {
916
- return form.getValue(name) ?? defaultValue;
1079
+ return form.getValues(name) ?? defaultValue;
917
1080
  },
918
1081
  set: (newValue) => {
919
1082
  form.setValue(name, newValue);