@bombillazo/rhf-plus 7.62.0-plus.4 → 7.62.0-plus.6

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.
@@ -270,6 +270,8 @@ function useFormState(props) {
270
270
  const [formState, updateFormState] = React.useState(control._formState);
271
271
  const _localProxyFormState = React.useRef({
272
272
  isDirty: false,
273
+ isDirtySinceSubmit: false,
274
+ hasBeenSubmitted: false,
273
275
  isLoading: false,
274
276
  dirtyFields: false,
275
277
  touchedFields: false,
@@ -1436,6 +1438,8 @@ function createFormControl(props = {}) {
1436
1438
  let _formState = {
1437
1439
  submitCount: 0,
1438
1440
  isDirty: false,
1441
+ isDirtySinceSubmit: false,
1442
+ hasBeenSubmitted: false,
1439
1443
  isReady: false,
1440
1444
  isLoading: _internalLoading,
1441
1445
  isValidating: false,
@@ -1476,6 +1480,8 @@ function createFormControl(props = {}) {
1476
1480
  let timer = 0;
1477
1481
  const _proxyFormState = {
1478
1482
  isDirty: false,
1483
+ isDirtySinceSubmit: false,
1484
+ hasBeenSubmitted: false,
1479
1485
  dirtyFields: false,
1480
1486
  validatingFields: false,
1481
1487
  touchedFields: false,
@@ -1493,6 +1499,8 @@ function createFormControl(props = {}) {
1493
1499
  };
1494
1500
  const shouldDisplayAllAssociatedErrors = _options.criteriaMode === VALIDATION_MODE.all;
1495
1501
  const id = createId(props.id);
1502
+ // Track if form was ever submitted (persists through resets)
1503
+ let _hasBeenSubmitted = false;
1496
1504
  const debounce = (callback) => (wait) => {
1497
1505
  clearTimeout(timer);
1498
1506
  timer = setTimeout(callback, wait);
@@ -1616,6 +1624,20 @@ function createFormControl(props = {}) {
1616
1624
  _proxySubscribeFormState.dirtyFields) &&
1617
1625
  isPreviousDirty !== !isCurrentFieldPristine);
1618
1626
  }
1627
+ // Set isDirtySinceSubmit to true if form was ever submitted and a field value is being changed
1628
+ // For change events (not blur/focus), always set if form was ever submitted
1629
+ // shouldDirty is true for onChange events, false for blur
1630
+ if ((_formState.isSubmitted || _hasBeenSubmitted) &&
1631
+ !_formState.isDirtySinceSubmit &&
1632
+ !isBlurEvent &&
1633
+ !isFocusEvent &&
1634
+ shouldDirty) {
1635
+ _formState.isDirtySinceSubmit = output.isDirtySinceSubmit = true;
1636
+ shouldUpdateField =
1637
+ shouldUpdateField ||
1638
+ !!(_proxyFormState.isDirtySinceSubmit ||
1639
+ _proxySubscribeFormState.isDirtySinceSubmit);
1640
+ }
1619
1641
  if (isBlurEvent) {
1620
1642
  const isPreviousFieldTouched = get(_formState.touchedFields, name);
1621
1643
  if (!isPreviousFieldTouched) {
@@ -1811,9 +1833,15 @@ function createFormControl(props = {}) {
1811
1833
  }
1812
1834
  }
1813
1835
  }
1814
- (options.shouldDirty || options.shouldTouch) &&
1836
+ const isSubmittedAndDirty = (_formState.isSubmitted || _hasBeenSubmitted) &&
1837
+ !deepEqual(get(_defaultValues, name), fieldValue);
1838
+ // If the form was submitted, track value changes for isDirtySinceSubmit
1839
+ // only when the value actually differs from the default value,
1840
+ // even if shouldDirty is not explicitly set
1841
+ const shouldTrackChange = options.shouldDirty || options.shouldTouch || isSubmittedAndDirty;
1842
+ shouldTrackChange &&
1815
1843
  updateTouchAndDirty(name, fieldValue, options.shouldTouch, false, // isFocusEvent - not applicable for setValue
1816
- options.shouldDirty, true);
1844
+ options.shouldDirty || isSubmittedAndDirty, true);
1817
1845
  options.shouldValidate && trigger(name);
1818
1846
  };
1819
1847
  const setValues = (name, value, options) => {
@@ -1845,12 +1873,25 @@ function createFormControl(props = {}) {
1845
1873
  if ((_proxyFormState.isDirty ||
1846
1874
  _proxyFormState.dirtyFields ||
1847
1875
  _proxySubscribeFormState.isDirty ||
1848
- _proxySubscribeFormState.dirtyFields) &&
1876
+ _proxySubscribeFormState.dirtyFields ||
1877
+ _proxyFormState.isDirtySinceSubmit ||
1878
+ _proxySubscribeFormState.isDirtySinceSubmit) &&
1849
1879
  options.shouldDirty) {
1850
1880
  _subjects.state.next({
1851
1881
  name,
1852
1882
  dirtyFields: getDirtyFields(_defaultValues, _formValues),
1853
1883
  isDirty: _getDirty(name, cloneValue),
1884
+ ...((_formState.isSubmitted || _hasBeenSubmitted) &&
1885
+ !_formState.isDirtySinceSubmit
1886
+ ? { isDirtySinceSubmit: true }
1887
+ : {}),
1888
+ });
1889
+ }
1890
+ else if ((_formState.isSubmitted || _hasBeenSubmitted) &&
1891
+ !_formState.isDirtySinceSubmit) {
1892
+ _subjects.state.next({
1893
+ name,
1894
+ isDirtySinceSubmit: true,
1854
1895
  });
1855
1896
  }
1856
1897
  }
@@ -1864,6 +1905,14 @@ function createFormControl(props = {}) {
1864
1905
  name: _state.mount ? name : undefined,
1865
1906
  values: cloneObject(_formValues),
1866
1907
  });
1908
+ // Trigger validation when shouldValidate is true
1909
+ // This ensures validation happens for all cases including:
1910
+ // - Field arrays
1911
+ // - Empty arrays
1912
+ // - Nested fields with array values
1913
+ if (options.shouldValidate) {
1914
+ trigger(name);
1915
+ }
1867
1916
  };
1868
1917
  const onChange = async (event) => {
1869
1918
  _state.mount = true;
@@ -1919,7 +1968,7 @@ function createFormControl(props = {}) {
1919
1968
  else if (field._f.onChange) {
1920
1969
  field._f.onChange(event);
1921
1970
  }
1922
- const fieldState = updateTouchAndDirty(name, fieldValue, isBlurEvent, isFocusEvent);
1971
+ const fieldState = updateTouchAndDirty(name, fieldValue, isBlurEvent, isFocusEvent, !isBlurEvent);
1923
1972
  const shouldRender = !isEmptyObject(fieldState) || watched;
1924
1973
  !isBlurEvent &&
1925
1974
  _subjects.state.next({
@@ -2303,11 +2352,14 @@ function createFormControl(props = {}) {
2303
2352
  _focusError();
2304
2353
  setTimeout(_focusError);
2305
2354
  }
2355
+ _hasBeenSubmitted = true; // Mark that form was submitted at least once
2306
2356
  _subjects.state.next({
2307
2357
  isSubmitted: true,
2308
2358
  isSubmitting: false,
2309
2359
  isSubmitSuccessful: isEmptyObject(_formState.errors) && !onValidError,
2310
2360
  submitCount: _formState.submitCount + 1,
2361
+ isDirtySinceSubmit: false,
2362
+ hasBeenSubmitted: _hasBeenSubmitted,
2311
2363
  errors: _formState.errors,
2312
2364
  });
2313
2365
  if (onValidError) {
@@ -2370,7 +2422,7 @@ function createFormControl(props = {}) {
2370
2422
  if (isHTMLElement(fieldReference)) {
2371
2423
  const form = fieldReference.closest('form');
2372
2424
  if (form) {
2373
- form.reset();
2425
+ HTMLFormElement.prototype.reset.call(form);
2374
2426
  break;
2375
2427
  }
2376
2428
  }
@@ -2422,6 +2474,8 @@ function createFormControl(props = {}) {
2422
2474
  ? _formState.isDirty
2423
2475
  : !!(keepStateOptions.keepDefaultValues &&
2424
2476
  !deepEqual(formValues, _defaultValues)),
2477
+ isDirtySinceSubmit: false,
2478
+ hasBeenSubmitted: _hasBeenSubmitted, // Persist the hasBeenSubmitted flag
2425
2479
  isSubmitted: keepStateOptions.keepIsSubmitted
2426
2480
  ? _formState.isSubmitted
2427
2481
  : false,
@@ -2947,6 +3001,8 @@ function useForm(props = {}) {
2947
3001
  const _values = React.useRef(undefined);
2948
3002
  const [formState, updateFormState] = React.useState({
2949
3003
  isDirty: false,
3004
+ isDirtySinceSubmit: false,
3005
+ hasBeenSubmitted: false,
2950
3006
  isValidating: false,
2951
3007
  isLoading: props.isLoading || isFunction(props.defaultValues),
2952
3008
  isSubmitted: false,