react-hook-form 7.71.2 → 7.72.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.
@@ -105,6 +105,9 @@ const EVENTS = {
105
105
  BLUR: 'blur',
106
106
  FOCUS_OUT: 'focusout',
107
107
  CHANGE: 'change',
108
+ SUBMIT: 'submit',
109
+ TRIGGER: 'trigger',
110
+ VALID: 'valid',
108
111
  };
109
112
  const VALIDATION_MODE = {
110
113
  onBlur: 'onBlur',
@@ -122,6 +125,8 @@ const INPUT_VALIDATION_RULES = {
122
125
  required: 'required',
123
126
  validate: 'validate',
124
127
  };
128
+ const FORM_ERROR_TYPE = 'form';
129
+ const ROOT_ERROR_TYPE = 'root';
125
130
 
126
131
  /**
127
132
  * Separate context for `control` to prevent unnecessary rerenders.
@@ -1167,7 +1172,7 @@ var unsetEmptyArray = (ref, name) => !compact(get(ref, name)).length && unset(re
1167
1172
 
1168
1173
  var updateFieldArrayRootError = (errors, error, name) => {
1169
1174
  const fieldArrayErrors = convertToArrayPayload(get(errors, name));
1170
- set(fieldArrayErrors, 'root', error[name]);
1175
+ set(fieldArrayErrors, ROOT_ERROR_TYPE, error[name]);
1171
1176
  set(errors, name, fieldArrayErrors);
1172
1177
  return errors;
1173
1178
  };
@@ -1456,7 +1461,11 @@ function createFormControl(props = {}) {
1456
1461
  _updateIsValidating();
1457
1462
  }
1458
1463
  else {
1459
- isValid = await executeBuiltInValidation(_fields, true);
1464
+ isValid = await executeBuiltInValidation({
1465
+ fields: _fields,
1466
+ onlyCheckValid: true,
1467
+ eventType: EVENTS.VALID,
1468
+ });
1460
1469
  }
1461
1470
  if (isValid !== _formState.isValid) {
1462
1471
  _subjects.state.next({
@@ -1505,7 +1514,9 @@ function createFormControl(props = {}) {
1505
1514
  shouldSetValues && set(_formState.touchedFields, name, touchedFields);
1506
1515
  }
1507
1516
  if (_proxyFormState.dirtyFields || _proxySubscribeFormState.dirtyFields) {
1508
- _formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
1517
+ const fullDirtyFields = getDirtyFields(_defaultValues, _formValues);
1518
+ const rootName = getNodeParentName(name);
1519
+ set(_formState.dirtyFields, rootName, get(fullDirtyFields, rootName));
1509
1520
  }
1510
1521
  _subjects.state.next({
1511
1522
  name,
@@ -1619,8 +1630,7 @@ function createFormControl(props = {}) {
1619
1630
  };
1620
1631
  const _runSchema = async (name) => {
1621
1632
  _updateIsValidating(name, true);
1622
- const result = await _options.resolver(_formValues, _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation));
1623
- return result;
1633
+ return await _options.resolver(_formValues, _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation));
1624
1634
  };
1625
1635
  const executeSchemaAndUpdateState = async (names) => {
1626
1636
  const { errors } = await _runSchema(names);
@@ -1638,9 +1648,55 @@ function createFormControl(props = {}) {
1638
1648
  }
1639
1649
  return errors;
1640
1650
  };
1641
- const executeBuiltInValidation = async (fields, shouldOnlyCheckValid, context = {
1651
+ const validateForm = async ({ name, eventType, }) => {
1652
+ if (props.validate) {
1653
+ const result = await props.validate({
1654
+ formValues: _formValues,
1655
+ formState: _formState,
1656
+ name,
1657
+ eventType,
1658
+ });
1659
+ if (isObject(result)) {
1660
+ for (const key in result) {
1661
+ const error = result[key];
1662
+ if (error) {
1663
+ setError(`${FORM_ERROR_TYPE}.${key}`, {
1664
+ message: isString(result.message) ? result.message : '',
1665
+ type: INPUT_VALIDATION_RULES.validate,
1666
+ });
1667
+ }
1668
+ }
1669
+ }
1670
+ else if (isString(result) || !result) {
1671
+ setError(FORM_ERROR_TYPE, {
1672
+ message: result || '',
1673
+ type: INPUT_VALIDATION_RULES.validate,
1674
+ });
1675
+ }
1676
+ else {
1677
+ clearErrors(FORM_ERROR_TYPE);
1678
+ }
1679
+ return result;
1680
+ }
1681
+ return true;
1682
+ };
1683
+ const executeBuiltInValidation = async ({ fields, onlyCheckValid, name, eventType, context = {
1642
1684
  valid: true,
1643
- }) => {
1685
+ runRootValidation: false,
1686
+ }, }) => {
1687
+ if (props.validate) {
1688
+ context.runRootValidation = true;
1689
+ const result = await validateForm({
1690
+ name,
1691
+ eventType,
1692
+ });
1693
+ if (!result) {
1694
+ context.valid = false;
1695
+ if (onlyCheckValid) {
1696
+ return context.valid;
1697
+ }
1698
+ }
1699
+ }
1644
1700
  for (const name in fields) {
1645
1701
  const field = fields[name];
1646
1702
  if (field) {
@@ -1651,25 +1707,34 @@ function createFormControl(props = {}) {
1651
1707
  if (isPromiseFunction && _proxyFormState.validatingFields) {
1652
1708
  _updateIsValidating([_f.name], true);
1653
1709
  }
1654
- const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !shouldOnlyCheckValid, isFieldArrayRoot);
1710
+ const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !onlyCheckValid, isFieldArrayRoot);
1655
1711
  if (isPromiseFunction && _proxyFormState.validatingFields) {
1656
1712
  _updateIsValidating([_f.name]);
1657
1713
  }
1658
1714
  if (fieldError[_f.name]) {
1659
1715
  context.valid = false;
1660
- if (shouldOnlyCheckValid || props.shouldUseNativeValidation) {
1716
+ if (onlyCheckValid) {
1661
1717
  break;
1662
1718
  }
1663
1719
  }
1664
- !shouldOnlyCheckValid &&
1720
+ !onlyCheckValid &&
1665
1721
  (get(fieldError, _f.name)
1666
1722
  ? isFieldArrayRoot
1667
1723
  ? updateFieldArrayRootError(_formState.errors, fieldError, _f.name)
1668
1724
  : set(_formState.errors, _f.name, fieldError[_f.name])
1669
1725
  : unset(_formState.errors, _f.name));
1726
+ if (props.shouldUseNativeValidation && fieldError[_f.name]) {
1727
+ break;
1728
+ }
1670
1729
  }
1671
1730
  !isEmptyObject(fieldValue) &&
1672
- (await executeBuiltInValidation(fieldValue, shouldOnlyCheckValid, context));
1731
+ (await executeBuiltInValidation({
1732
+ context,
1733
+ onlyCheckValid,
1734
+ fields: fieldValue,
1735
+ name: name,
1736
+ eventType,
1737
+ }));
1673
1738
  }
1674
1739
  }
1675
1740
  return context.valid;
@@ -1828,6 +1893,7 @@ function createFormControl(props = {}) {
1828
1893
  : getEventValue(event);
1829
1894
  const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
1830
1895
  const shouldSkipValidation = (!hasValidation(field._f) &&
1896
+ !props.validate &&
1831
1897
  !_options.resolver &&
1832
1898
  !get(_formState.errors, name) &&
1833
1899
  !field._f.deps) ||
@@ -1865,6 +1931,12 @@ function createFormControl(props = {}) {
1865
1931
  return (shouldRender &&
1866
1932
  _subjects.state.next({ name, ...(watched ? {} : fieldState) }));
1867
1933
  }
1934
+ if (!_options.resolver && props.validate) {
1935
+ await validateForm({
1936
+ name: name,
1937
+ eventType: event.type,
1938
+ });
1939
+ }
1868
1940
  !isBlurEvent && watched && _subjects.state.next({ ..._formState });
1869
1941
  if (_options.resolver) {
1870
1942
  const { errors } = await _runSchema([name]);
@@ -1889,7 +1961,12 @@ function createFormControl(props = {}) {
1889
1961
  }
1890
1962
  else if (_proxyFormState.isValid ||
1891
1963
  _proxySubscribeFormState.isValid) {
1892
- isValid = await executeBuiltInValidation(_fields, true);
1964
+ isValid = await executeBuiltInValidation({
1965
+ fields: _fields,
1966
+ onlyCheckValid: true,
1967
+ name: name,
1968
+ eventType: event.type,
1969
+ });
1893
1970
  }
1894
1971
  }
1895
1972
  }
@@ -1922,12 +1999,19 @@ function createFormControl(props = {}) {
1922
1999
  else if (name) {
1923
2000
  validationResult = (await Promise.all(fieldNames.map(async (fieldName) => {
1924
2001
  const field = get(_fields, fieldName);
1925
- return await executeBuiltInValidation(field && field._f ? { [fieldName]: field } : field);
2002
+ return await executeBuiltInValidation({
2003
+ fields: field && field._f ? { [fieldName]: field } : field,
2004
+ eventType: EVENTS.TRIGGER,
2005
+ });
1926
2006
  }))).every(Boolean);
1927
2007
  !(!validationResult && !_formState.isValid) && _setValid();
1928
2008
  }
1929
2009
  else {
1930
- validationResult = isValid = await executeBuiltInValidation(_fields);
2010
+ validationResult = isValid = await executeBuiltInValidation({
2011
+ fields: _fields,
2012
+ name,
2013
+ eventType: EVENTS.TRIGGER,
2014
+ });
1931
2015
  }
1932
2016
  _subjects.state.next({
1933
2017
  ...(!isString(name) ||
@@ -2192,14 +2276,17 @@ function createFormControl(props = {}) {
2192
2276
  fieldValues = cloneObject(values);
2193
2277
  }
2194
2278
  else {
2195
- await executeBuiltInValidation(_fields);
2279
+ await executeBuiltInValidation({
2280
+ fields: _fields,
2281
+ eventType: EVENTS.SUBMIT,
2282
+ });
2196
2283
  }
2197
2284
  if (_names.disabled.size) {
2198
2285
  for (const name of _names.disabled) {
2199
2286
  unset(fieldValues, name);
2200
2287
  }
2201
2288
  }
2202
- unset(_formState.errors, 'root');
2289
+ unset(_formState.errors, ROOT_ERROR_TYPE);
2203
2290
  if (isEmptyObject(_formState.errors)) {
2204
2291
  _subjects.state.next({
2205
2292
  errors: {},