@vuehookform/core 0.5.0 → 0.7.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.
@@ -539,14 +539,15 @@ function clearFieldTouched(touchedFields, fieldName) {
539
539
  }
540
540
  function clearFieldErrors(errors, fieldName) {
541
541
  const currentErrors = errors.value;
542
- const keys = Object.keys(currentErrors);
543
- if (keys.length === 0) return;
542
+ if (Object.keys(currentErrors).length === 0) return;
543
+ const nestedError = get(currentErrors, fieldName);
544
544
  const prefix = `${fieldName}.`;
545
- const keysToDelete = [];
546
- for (const key of keys) if (key === fieldName || key.startsWith(prefix)) keysToDelete.push(key);
547
- if (keysToDelete.length === 0) return;
545
+ const flatKeysToDelete = [];
546
+ for (const key of Object.keys(currentErrors)) if (key === fieldName || key.startsWith(prefix)) flatKeysToDelete.push(key);
547
+ if (nestedError === void 0 && flatKeysToDelete.length === 0) return;
548
548
  const newErrors = { ...currentErrors };
549
- for (const key of keysToDelete) delete newErrors[key];
549
+ for (const key of flatKeysToDelete) delete newErrors[key];
550
+ if (nestedError !== void 0) unset(newErrors, fieldName);
550
551
  errors.value = newErrors;
551
552
  }
552
553
  function updateFieldDirtyState(dirtyFields, defaultValues, defaultValueHashes, fieldName, currentValue) {
@@ -590,7 +591,6 @@ function createFieldError(errors, criteriaMode = "firstError") {
590
591
  const firstError = errors[0];
591
592
  if (!firstError) return "";
592
593
  if (criteriaMode === "firstError") return firstError.message;
593
- if (errors.length === 1) return firstError.message;
594
594
  const types = {};
595
595
  for (const err of errors) {
596
596
  const existing = types[err.type];
@@ -816,7 +816,7 @@ function shouldValidateOnBlur(mode, hasSubmitted, reValidateMode) {
816
816
  return mode === "onBlur" || mode === "onTouched" || hasSubmitted && (reValidateMode === "onBlur" || reValidateMode === "onTouched");
817
817
  }
818
818
  var validationRequestCounter = 0;
819
- function createFieldRegistration(ctx, validate) {
819
+ function createFieldRegistration(ctx, validate, onChangeHelpers) {
820
820
  function register(name, registerOptions) {
821
821
  if (__DEV__) {
822
822
  const syntaxError = validatePathSyntax(name);
@@ -843,13 +843,13 @@ function createFieldRegistration(ctx, validate) {
843
843
  const error = await fieldOpts.validate(value);
844
844
  if (requestId !== ctx.validationRequestIds.get(fieldName)) return;
845
845
  if (ctx.resetGeneration.value !== resetGenAtStart) return;
846
- if (error) ctx.errors.value = {
847
- ...ctx.errors.value,
848
- [fieldName]: error
849
- };
850
- else {
846
+ if (error) {
847
+ const newErrors = { ...ctx.errors.value };
848
+ set(newErrors, fieldName, error);
849
+ ctx.errors.value = newErrors;
850
+ } else {
851
851
  const newErrors = { ...ctx.errors.value };
852
- delete newErrors[fieldName];
852
+ unset(newErrors, fieldName);
853
853
  ctx.errors.value = newErrors;
854
854
  }
855
855
  };
@@ -862,6 +862,11 @@ function createFieldRegistration(ctx, validate) {
862
862
  set(ctx.formData, name, value);
863
863
  updateFieldDirtyState(ctx.dirtyFields, ctx.defaultValues, ctx.defaultValueHashes, name, value);
864
864
  const fieldOpts = ctx.fieldOptions.get(name);
865
+ if (fieldOpts?.onChange && onChangeHelpers?.setValue) try {
866
+ fieldOpts.onChange(value, { setValue: onChangeHelpers.setValue });
867
+ } catch (err) {
868
+ if (__DEV__) console.error(`[vue-hook-form] Error in onChange callback for field '${name}':`, err);
869
+ }
865
870
  if (shouldValidateOnChange(ctx.options.mode ?? "onSubmit", ctx.touchedFields.value[name] === true, ctx.submitCount.value > 0, ctx.options.reValidateMode)) {
866
871
  const validationDebounceMs = ctx.options.validationDebounce || 0;
867
872
  if (validationDebounceMs > 0) {
@@ -1421,7 +1426,8 @@ function useForm(options) {
1421
1426
  ctx.cleanup();
1422
1427
  });
1423
1428
  const { validate, clearAllPendingErrors } = createValidation(ctx);
1424
- const { register, unregister } = createFieldRegistration(ctx, validate);
1429
+ const onChangeHelpers = { setValue: null };
1430
+ const { register, unregister } = createFieldRegistration(ctx, validate, onChangeHelpers);
1425
1431
  function setFocus(name, focusOptions) {
1426
1432
  if (__DEV__) {
1427
1433
  const syntaxError = validatePathSyntax(name);
@@ -1512,6 +1518,12 @@ function useForm(options) {
1512
1518
  },
1513
1519
  get disabled() {
1514
1520
  return ctx.isDisabled.value;
1521
+ },
1522
+ get isPristine() {
1523
+ return !isDirtyComputed.value;
1524
+ },
1525
+ get canSubmit() {
1526
+ return isValidComputed.value && !ctx.isSubmitting.value && !ctx.isLoading.value && !ctx.isDisabled.value;
1515
1527
  }
1516
1528
  });
1517
1529
  const formState = computed(() => formStateInternal);
@@ -1527,7 +1539,7 @@ function useForm(options) {
1527
1539
  try {
1528
1540
  syncWithDebounce();
1529
1541
  if (await validate()) {
1530
- await onValid(ctx.formData);
1542
+ await onValid(deepClone(ctx.formData));
1531
1543
  ctx.isSubmitSuccessful.value = true;
1532
1544
  } else {
1533
1545
  onInvalid?.(formState.value.errors);
@@ -1561,6 +1573,7 @@ function useForm(options) {
1561
1573
  }
1562
1574
  if (setValueOptions?.shouldValidate) validate(name);
1563
1575
  }
1576
+ onChangeHelpers.setValue = setValue;
1564
1577
  function reset(values, resetOptions) {
1565
1578
  const opts = resetOptions || {};
1566
1579
  ctx.validationCache.clear();
@@ -1609,7 +1622,6 @@ function useForm(options) {
1609
1622
  }
1610
1623
  }
1611
1624
  const opts = resetFieldOptions || {};
1612
- ctx.resetGeneration.value++;
1613
1625
  ctx.validationCache.delete(`${name}:partial`);
1614
1626
  ctx.validationCache.delete(`${name}:full`);
1615
1627
  const errorTimer = ctx.errorDelayTimers.get(name);
@@ -1618,6 +1630,11 @@ function useForm(options) {
1618
1630
  ctx.errorDelayTimers.delete(name);
1619
1631
  }
1620
1632
  ctx.pendingErrors.delete(name);
1633
+ const schemaTimer = ctx.schemaValidationTimers.get(name);
1634
+ if (schemaTimer) {
1635
+ clearTimeout(schemaTimer);
1636
+ ctx.schemaValidationTimers.delete(name);
1637
+ }
1621
1638
  let defaultValue = opts.defaultValue;
1622
1639
  if (defaultValue === void 0) defaultValue = get(ctx.defaultValues, name);
1623
1640
  else {
@@ -1730,13 +1747,13 @@ function useForm(options) {
1730
1747
  }
1731
1748
  }
1732
1749
  syncWithDebounce();
1733
- if (nameOrNames === void 0) return { ...ctx.formData };
1750
+ if (nameOrNames === void 0) return deepClone(ctx.formData);
1734
1751
  if (Array.isArray(nameOrNames)) {
1735
1752
  const result = {};
1736
- for (const fieldName of nameOrNames) result[fieldName] = get(ctx.formData, fieldName);
1753
+ for (const fieldName of nameOrNames) result[fieldName] = deepClone(get(ctx.formData, fieldName));
1737
1754
  return result;
1738
1755
  }
1739
- return get(ctx.formData, nameOrNames);
1756
+ return deepClone(get(ctx.formData, nameOrNames));
1740
1757
  }
1741
1758
  function getFieldState(name) {
1742
1759
  if (__DEV__) {
@@ -1770,11 +1787,7 @@ function useForm(options) {
1770
1787
  }
1771
1788
  if (options$1?.markAsSubmitted) ctx.submitCount.value++;
1772
1789
  if (name === void 0) return await validate();
1773
- if (Array.isArray(name)) {
1774
- let allValid = true;
1775
- for (const fieldName of name) if (!await validate(fieldName)) allValid = false;
1776
- return allValid;
1777
- }
1790
+ if (Array.isArray(name)) return (await Promise.all(name.map((fieldName) => validate(fieldName)))).every((isValid) => isValid);
1778
1791
  return await validate(name);
1779
1792
  }
1780
1793
  const setFocusWrapper = (name) => setFocus(name);
@@ -1826,25 +1839,28 @@ function useFormContext() {
1826
1839
  function useWatch(options = {}) {
1827
1840
  const { control, name, defaultValue } = options;
1828
1841
  const form = control ?? useFormContext();
1829
- return computed(() => {
1830
- if (name === void 0) return form.getValues();
1831
- if (Array.isArray(name)) {
1832
- const result = {};
1833
- for (const fieldName of name) result[fieldName] = get(form.getValues(), fieldName) ?? defaultValue;
1842
+ if (name === void 0) return form.watch();
1843
+ if (Array.isArray(name)) {
1844
+ const watched$1 = form.watch(name);
1845
+ if (defaultValue === void 0) return watched$1;
1846
+ return computed(() => {
1847
+ const result = { ...watched$1.value };
1848
+ for (const fieldName of name) if (result[fieldName] === void 0) result[fieldName] = defaultValue;
1834
1849
  return result;
1835
- }
1836
- return get(form.getValues(), name) ?? defaultValue;
1837
- });
1850
+ });
1851
+ }
1852
+ const watched = form.watch(name);
1853
+ if (defaultValue === void 0) return watched;
1854
+ return computed(() => watched.value ?? defaultValue);
1838
1855
  }
1839
1856
  function useController(options) {
1840
1857
  const { name, control, defaultValue } = options;
1841
1858
  const form = control ?? useFormContext();
1842
1859
  const elementRef = ref(null);
1843
1860
  if (defaultValue !== void 0 && form.getValues(name) === void 0) form.setValue(name, defaultValue);
1861
+ const watchedValue = form.watch(name);
1844
1862
  const value = computed({
1845
- get: () => {
1846
- return form.getValues(name) ?? defaultValue;
1847
- },
1863
+ get: () => watchedValue.value ?? defaultValue,
1848
1864
  set: (newValue) => {
1849
1865
  form.setValue(name, newValue);
1850
1866
  }
@@ -1903,7 +1919,22 @@ function useFormState(options = {}) {
1903
1919
  return { [name]: fullState[name] };
1904
1920
  });
1905
1921
  }
1922
+ function useFieldError(options) {
1923
+ const form = options.control ?? useFormContext();
1924
+ return computed(() => {
1925
+ const error = get(form.formState.value.errors, options.name);
1926
+ if (!error) return void 0;
1927
+ if (typeof error === "string") return error;
1928
+ if (Array.isArray(error)) {
1929
+ if (__DEV__) console.warn(`[vue-hook-form] useFieldError('${options.name}') resolved to an array of per-item errors.\nuseFieldError only returns scalar error messages. Use formState.value.errors['${options.name}'] directly for item-level errors.`);
1930
+ return;
1931
+ }
1932
+ if (typeof error === "object" && "message" in error) return error.message;
1933
+ });
1934
+ }
1906
1935
  function isFieldError(error) {
1907
1936
  return typeof error === "object" && error !== null && "type" in error && "message" in error && typeof error.type === "string" && typeof error.message === "string";
1908
1937
  }
1909
- export { FormContextKey, clearPathCache, get, isFieldError, provideForm, set, unset, useController, useForm, useFormContext, useFormState, useWatch };
1938
+ export { FormContextKey, clearPathCache, get, isFieldError, provideForm, set, unset, useController, useFieldError, useForm, useFormContext, useFormState, useWatch };
1939
+
1940
+ //# sourceMappingURL=vuehookform.js.map