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

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.
@@ -81,6 +81,21 @@ var get = (object, path, defaultValue) => {
81
81
 
82
82
  var isBoolean = (value) => typeof value === 'boolean';
83
83
 
84
+ function mergeMissingKeysAsUndefined(oldObject, newObject) {
85
+ if (!newObject) {
86
+ return newObject;
87
+ }
88
+ const result = { ...newObject };
89
+ if (oldObject) {
90
+ for (const key in oldObject) {
91
+ if (!(key in result)) {
92
+ result[key] = undefined;
93
+ }
94
+ }
95
+ }
96
+ return result;
97
+ }
98
+
84
99
  var set = (object, path, value) => {
85
100
  let index = -1;
86
101
  const tempPath = isKey(path) ? [path] : stringToPath(path);
@@ -109,6 +124,8 @@ var set = (object, path, value) => {
109
124
  const EVENTS = {
110
125
  BLUR: 'blur',
111
126
  FOCUS_OUT: 'focusout',
127
+ FOCUS: 'focus',
128
+ FOCUS_IN: 'focusin',
112
129
  CHANGE: 'change',
113
130
  };
114
131
  const VALIDATION_MODE = {
@@ -256,6 +273,7 @@ function useFormState(props) {
256
273
  isLoading: false,
257
274
  dirtyFields: false,
258
275
  touchedFields: false,
276
+ focusedField: false,
259
277
  validatingFields: false,
260
278
  isValidating: false,
261
279
  isValid: false,
@@ -427,11 +445,22 @@ function useController(props) {
427
445
  exact: true,
428
446
  });
429
447
  const _props = React.useRef(props);
448
+ const _previousRules = React.useRef(props.rules);
430
449
  const _registerProps = React.useRef(control.register(name, {
431
450
  ...props.rules,
432
451
  value,
433
452
  ...(isBoolean(props.disabled) ? { disabled: props.disabled } : {}),
434
453
  }));
454
+ const mergedRules = React.useMemo(() => mergeMissingKeysAsUndefined(_previousRules.current, props.rules), [props.rules]);
455
+ // Update register props when rules change
456
+ React.useEffect(() => {
457
+ _registerProps.current = control.register(name, {
458
+ ...mergedRules,
459
+ value,
460
+ ...(isBoolean(props.disabled) ? { disabled: props.disabled } : {}),
461
+ });
462
+ _previousRules.current = props.rules;
463
+ }, [mergedRules, props.rules, value, props.disabled, control, name]);
435
464
  _props.current = props;
436
465
  const fieldState = React.useMemo(() => Object.defineProperties({}, {
437
466
  invalid: {
@@ -446,6 +475,10 @@ function useController(props) {
446
475
  enumerable: true,
447
476
  get: () => !!get(formState.touchedFields, name),
448
477
  },
478
+ isFocused: {
479
+ enumerable: true,
480
+ get: () => formState.focusedField === name,
481
+ },
449
482
  isValidating: {
450
483
  enumerable: true,
451
484
  get: () => !!get(formState.validatingFields, name),
@@ -469,6 +502,13 @@ function useController(props) {
469
502
  },
470
503
  type: EVENTS.BLUR,
471
504
  }), [name, control._formValues]);
505
+ const onFocus = React.useCallback(() => _registerProps.current.onFocus({
506
+ target: {
507
+ value: get(control._formValues, name),
508
+ name: name,
509
+ },
510
+ type: EVENTS.FOCUS,
511
+ }), [name, control._formValues]);
472
512
  const elementRef = React.useRef(null);
473
513
  const ref = React.useCallback((elm) => {
474
514
  elementRef.current = elm;
@@ -510,9 +550,19 @@ function useController(props) {
510
550
  ...(isBoolean(isFieldDisabled) ? { disabled: isFieldDisabled } : {}),
511
551
  onChange,
512
552
  onBlur,
553
+ onFocus,
513
554
  ref,
514
555
  };
515
- }, [name, disabled, control._options.disabled, onChange, onBlur, ref, value]);
556
+ }, [
557
+ name,
558
+ disabled,
559
+ control._options.disabled,
560
+ onChange,
561
+ onBlur,
562
+ onFocus,
563
+ ref,
564
+ value,
565
+ ]);
516
566
  React.useEffect(() => {
517
567
  const _shouldUnregisterField = control._options.shouldUnregister || shouldUnregister;
518
568
  control.register(name, {
@@ -1120,7 +1170,15 @@ var shouldSubscribeByName = (name, signalName, exact) => !name ||
1120
1170
  : currentName.startsWith(signalName) ||
1121
1171
  signalName.startsWith(currentName)));
1122
1172
 
1123
- var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode) => {
1173
+ var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode,
1174
+ /**
1175
+ * Need to keep this order of parameters for backward compatibility
1176
+ */
1177
+ isFocusEvent) => {
1178
+ // Focus events should always skip validation
1179
+ if (isFocusEvent) {
1180
+ return true;
1181
+ }
1124
1182
  if (mode.isOnAll) {
1125
1183
  return false;
1126
1184
  }
@@ -1387,6 +1445,7 @@ function createFormControl(props = {}) {
1387
1445
  isValid: false,
1388
1446
  touchedFields: {},
1389
1447
  dirtyFields: {},
1448
+ focusedField: undefined,
1390
1449
  validatingFields: {},
1391
1450
  errors: _options.errors || {},
1392
1451
  disabled: Array.isArray(_options.disabled)
@@ -1420,6 +1479,7 @@ function createFormControl(props = {}) {
1420
1479
  dirtyFields: false,
1421
1480
  validatingFields: false,
1422
1481
  touchedFields: false,
1482
+ focusedField: false,
1423
1483
  isValidating: false,
1424
1484
  isValid: false,
1425
1485
  errors: false,
@@ -1531,7 +1591,7 @@ function createFormControl(props = {}) {
1531
1591
  _state.mount && _setValid();
1532
1592
  }
1533
1593
  };
1534
- const updateTouchAndDirty = (name, fieldValue, isBlurEvent, shouldDirty, shouldRender) => {
1594
+ const updateTouchAndDirty = (name, fieldValue, isBlurEvent, isFocusEvent, shouldDirty, shouldRender) => {
1535
1595
  let shouldUpdateField = false;
1536
1596
  let isPreviousDirty = false;
1537
1597
  const output = {
@@ -1568,6 +1628,25 @@ function createFormControl(props = {}) {
1568
1628
  isPreviousFieldTouched !== isBlurEvent);
1569
1629
  }
1570
1630
  }
1631
+ // Handle focus state
1632
+ if (isFocusEvent || isBlurEvent) {
1633
+ const wasPreviouslyFocused = _formState.focusedField === name;
1634
+ const shouldBeFocused = isFocusEvent && !isBlurEvent;
1635
+ if (wasPreviouslyFocused !== shouldBeFocused) {
1636
+ if (shouldBeFocused) {
1637
+ _formState.focusedField = name;
1638
+ }
1639
+ else {
1640
+ _formState.focusedField = undefined;
1641
+ }
1642
+ output.focusedField = _formState.focusedField;
1643
+ shouldUpdateField =
1644
+ shouldUpdateField ||
1645
+ ((_proxyFormState.focusedField ||
1646
+ _proxySubscribeFormState.focusedField) &&
1647
+ wasPreviouslyFocused !== shouldBeFocused);
1648
+ }
1649
+ }
1571
1650
  shouldUpdateField && shouldRender && _subjects.state.next(output);
1572
1651
  }
1573
1652
  return shouldUpdateField ? output : {};
@@ -1733,7 +1812,8 @@ function createFormControl(props = {}) {
1733
1812
  }
1734
1813
  }
1735
1814
  (options.shouldDirty || options.shouldTouch) &&
1736
- updateTouchAndDirty(name, fieldValue, options.shouldTouch, options.shouldDirty, true);
1815
+ updateTouchAndDirty(name, fieldValue, options.shouldTouch, false, // isFocusEvent - not applicable for setValue
1816
+ options.shouldDirty, true);
1737
1817
  options.shouldValidate && trigger(name);
1738
1818
  };
1739
1819
  const setValues = (name, value, options) => {
@@ -1822,12 +1902,13 @@ function createFormControl(props = {}) {
1822
1902
  ? getFieldValue(field._f)
1823
1903
  : getEventValue(event);
1824
1904
  const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
1905
+ const isFocusEvent = event.type === EVENTS.FOCUS || event.type === EVENTS.FOCUS_IN;
1825
1906
  const shouldSkipValidation = (!hasValidation(field._f) &&
1826
1907
  !_options.resolver &&
1827
1908
  !get(_formState.errors, name) &&
1828
1909
  !field._f.deps) ||
1829
- skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, validationModeAfterSubmit, validationModeBeforeSubmit);
1830
- const watched = isWatched(name, _names, isBlurEvent);
1910
+ skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, validationModeAfterSubmit, validationModeBeforeSubmit, isFocusEvent);
1911
+ const watched = isWatched(name, _names, isBlurEvent || isFocusEvent);
1831
1912
  set(_formValues, name, fieldValue);
1832
1913
  if (isBlurEvent) {
1833
1914
  if (!target || !target.readOnly) {
@@ -1838,7 +1919,7 @@ function createFormControl(props = {}) {
1838
1919
  else if (field._f.onChange) {
1839
1920
  field._f.onChange(event);
1840
1921
  }
1841
- const fieldState = updateTouchAndDirty(name, fieldValue, isBlurEvent);
1922
+ const fieldState = updateTouchAndDirty(name, fieldValue, isBlurEvent, isFocusEvent);
1842
1923
  const shouldRender = !isEmptyObject(fieldState) || watched;
1843
1924
  !isBlurEvent &&
1844
1925
  _subjects.state.next({
@@ -1952,6 +2033,7 @@ function createFormControl(props = {}) {
1952
2033
  error: get((formState || _formState).errors, name),
1953
2034
  isValidating: !!get(_formState.validatingFields, name),
1954
2035
  isTouched: !!get((formState || _formState).touchedFields, name),
2036
+ isFocused: (formState || _formState).focusedField === name,
1955
2037
  });
1956
2038
  const clearErrors = (name) => {
1957
2039
  name &&
@@ -2091,6 +2173,7 @@ function createFormControl(props = {}) {
2091
2173
  name,
2092
2174
  onChange,
2093
2175
  onBlur: onChange,
2176
+ onFocus: onChange,
2094
2177
  ref: (ref) => {
2095
2178
  if (ref) {
2096
2179
  register(name, options);
@@ -2356,6 +2439,7 @@ function createFormControl(props = {}) {
2356
2439
  touchedFields: keepStateOptions.keepTouched
2357
2440
  ? _formState.touchedFields
2358
2441
  : {},
2442
+ focusedField: undefined, // Always reset focused field on form reset
2359
2443
  errors: keepStateOptions.keepErrors ? _formState.errors : {},
2360
2444
  isSubmitSuccessful: keepStateOptions.keepIsSubmitSuccessful
2361
2445
  ? _formState.isSubmitSuccessful
@@ -2872,6 +2956,7 @@ function useForm(props = {}) {
2872
2956
  submitCount: 0,
2873
2957
  dirtyFields: {},
2874
2958
  touchedFields: {},
2959
+ focusedField: undefined,
2875
2960
  validatingFields: {},
2876
2961
  errors: props.errors || {},
2877
2962
  // If it's an array, set formState.disabled to false because when using array mode,