@bombillazo/rhf-plus 7.64.0-plus.2 → 7.67.0-plus.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.
package/dist/index.d.ts CHANGED
@@ -9,4 +9,5 @@ export * from './useFormContext';
9
9
  export * from './useFormState';
10
10
  export * from './useWatch';
11
11
  export * from './utils';
12
+ export * from './watch';
12
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC"}
@@ -179,7 +179,7 @@ HookFormContext.displayName = 'HookFormContext';
179
179
  */
180
180
  const useFormContext = () => React.useContext(HookFormContext);
181
181
  /**
182
- * A provider component that propagates the `useForm` methods to all children components via [React Context](https://reactjs.org/docs/context.html) API. To be used with {@link useFormContext}.
182
+ * A provider component that propagates the `useForm` methods to all children components via [React Context](https://react.dev/reference/react/useContext) API. To be used with {@link useFormContext}.
183
183
  *
184
184
  * @remarks
185
185
  * [API](https://react-hook-form.com/docs/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
@@ -318,7 +318,7 @@ var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
318
318
 
319
319
  function deepEqual(object1, object2, _internal_visited = new WeakSet()) {
320
320
  if (isPrimitive(object1) || isPrimitive(object2)) {
321
- return object1 === object2;
321
+ return Object.is(object1, object2);
322
322
  }
323
323
  if (isDateObject(object1) && isDateObject(object2)) {
324
324
  return object1.getTime() === object2.getTime();
@@ -344,7 +344,7 @@ function deepEqual(object1, object2, _internal_visited = new WeakSet()) {
344
344
  (isObject(val1) && isObject(val2)) ||
345
345
  (Array.isArray(val1) && Array.isArray(val2))
346
346
  ? !deepEqual(val1, val2, _internal_visited)
347
- : val1 !== val2) {
347
+ : !Object.is(val1, val2)) {
348
348
  return false;
349
349
  }
350
350
  }
@@ -374,33 +374,68 @@ function useWatch(props) {
374
374
  const _defaultValue = React.useRef(defaultValue);
375
375
  const _compute = React.useRef(compute);
376
376
  const _computeFormValues = React.useRef(undefined);
377
+ const _prevControl = React.useRef(control);
378
+ const _prevName = React.useRef(name);
377
379
  _compute.current = compute;
378
- const defaultValueMemo = React.useMemo(() => control._getWatch(name, _defaultValue.current), [control, name]);
379
- const [value, updateValue] = React.useState(_compute.current ? _compute.current(defaultValueMemo) : defaultValueMemo);
380
- useIsomorphicLayoutEffect(() => control._subscribe({
381
- name,
382
- formState: {
383
- values: true,
384
- },
385
- exact,
386
- callback: (formState) => {
387
- if (!disabled) {
388
- const formValues = generateWatchOutput(name, control._names, formState.values || control._formValues, false, _defaultValue.current);
389
- if (_compute.current) {
390
- const computedFormValues = _compute.current(formValues);
391
- if (!deepEqual(computedFormValues, _computeFormValues.current)) {
392
- updateValue(computedFormValues);
393
- _computeFormValues.current = computedFormValues;
394
- }
395
- }
396
- else {
397
- updateValue(formValues);
380
+ const [value, updateValue] = React.useState(() => {
381
+ const defaultValue = control._getWatch(name, _defaultValue.current);
382
+ return _compute.current ? _compute.current(defaultValue) : defaultValue;
383
+ });
384
+ const getCurrentOutput = React.useCallback((values) => {
385
+ const formValues = generateWatchOutput(name, control._names, values || control._formValues, false, _defaultValue.current);
386
+ return _compute.current ? _compute.current(formValues) : formValues;
387
+ }, [control._formValues, control._names, name]);
388
+ const refreshValue = React.useCallback((values) => {
389
+ if (!disabled) {
390
+ const formValues = generateWatchOutput(name, control._names, values || control._formValues, false, _defaultValue.current);
391
+ if (_compute.current) {
392
+ const computedFormValues = _compute.current(formValues);
393
+ if (!deepEqual(computedFormValues, _computeFormValues.current)) {
394
+ updateValue(computedFormValues);
395
+ _computeFormValues.current = computedFormValues;
398
396
  }
399
397
  }
400
- },
401
- }), [control, disabled, name, exact]);
398
+ else {
399
+ updateValue(formValues);
400
+ }
401
+ }
402
+ }, [control._formValues, control._names, disabled, name]);
403
+ useIsomorphicLayoutEffect(() => {
404
+ if (_prevControl.current !== control ||
405
+ !deepEqual(_prevName.current, name)) {
406
+ _prevControl.current = control;
407
+ _prevName.current = name;
408
+ refreshValue();
409
+ }
410
+ return control._subscribe({
411
+ name,
412
+ formState: {
413
+ values: true,
414
+ },
415
+ exact,
416
+ callback: (formState) => {
417
+ refreshValue(formState.values);
418
+ },
419
+ });
420
+ }, [control, exact, name, refreshValue]);
402
421
  React.useEffect(() => control._removeUnmounted());
403
- return value;
422
+ // If name or control changed for this render, synchronously reflect the
423
+ // latest value so callers (like useController) see the correct value
424
+ // immediately on the same render.
425
+ // Optimize: Check control reference first before expensive deepEqual
426
+ const controlChanged = _prevControl.current !== control;
427
+ const prevName = _prevName.current;
428
+ // Cache the computed output to avoid duplicate calls within the same render
429
+ // We include shouldReturnImmediate in deps to ensure proper recomputation
430
+ const computedOutput = React.useMemo(() => {
431
+ if (disabled) {
432
+ return null;
433
+ }
434
+ const nameChanged = !controlChanged && !deepEqual(prevName, name);
435
+ const shouldReturnImmediate = controlChanged || nameChanged;
436
+ return shouldReturnImmediate ? getCurrentOutput() : null;
437
+ }, [disabled, controlChanged, name, prevName, getCurrentOutput]);
438
+ return computedOutput !== null ? computedOutput : value;
404
439
  }
405
440
 
406
441
  /**
@@ -972,11 +1007,12 @@ function isTraversable(value) {
972
1007
  }
973
1008
  function markFieldsDirty(data, fields = {}) {
974
1009
  for (const key in data) {
975
- if (isTraversable(data[key])) {
976
- fields[key] = Array.isArray(data[key]) ? [] : {};
977
- markFieldsDirty(data[key], fields[key]);
1010
+ const value = data[key];
1011
+ if (isTraversable(value)) {
1012
+ fields[key] = Array.isArray(value) ? [] : {};
1013
+ markFieldsDirty(value, fields[key]);
978
1014
  }
979
- else if (!isNullOrUndefined(data[key])) {
1015
+ else if (!isUndefined(value)) {
980
1016
  fields[key] = true;
981
1017
  }
982
1018
  }
@@ -987,16 +1023,18 @@ function getDirtyFields(data, formValues, dirtyFieldsFromValues) {
987
1023
  dirtyFieldsFromValues = markFieldsDirty(formValues);
988
1024
  }
989
1025
  for (const key in data) {
990
- if (isTraversable(data[key])) {
1026
+ const value = data[key];
1027
+ if (isTraversable(value)) {
991
1028
  if (isUndefined(formValues) || isPrimitive(dirtyFieldsFromValues[key])) {
992
- dirtyFieldsFromValues[key] = markFieldsDirty(data[key], Array.isArray(data[key]) ? [] : {});
1029
+ dirtyFieldsFromValues[key] = markFieldsDirty(value, Array.isArray(value) ? [] : {});
993
1030
  }
994
1031
  else {
995
- getDirtyFields(data[key], isNullOrUndefined(formValues) ? {} : formValues[key], dirtyFieldsFromValues[key]);
1032
+ getDirtyFields(value, isNullOrUndefined(formValues) ? {} : formValues[key], dirtyFieldsFromValues[key]);
996
1033
  }
997
1034
  }
998
1035
  else {
999
- dirtyFieldsFromValues[key] = !deepEqual(data[key], formValues[key]);
1036
+ const formValue = formValues[key];
1037
+ dirtyFieldsFromValues[key] = !deepEqual(value, formValue);
1000
1038
  }
1001
1039
  }
1002
1040
  return dirtyFieldsFromValues;
@@ -1630,7 +1668,7 @@ function createFormControl(props = {}) {
1630
1668
  shouldSkipSetValueAs
1631
1669
  ? set(_formValues, name, shouldSkipSetValueAs ? defaultValue : getFieldValue(field._f))
1632
1670
  : setFieldValue(name, defaultValue);
1633
- _state.mount && _setValid();
1671
+ _state.mount && !_state.action && _setValid();
1634
1672
  }
1635
1673
  };
1636
1674
  const updateTouchAndDirty = (name, fieldValue, isBlurEvent, isFocusEvent, shouldDirty, shouldRender) => {
@@ -2558,7 +2596,8 @@ function createFormControl(props = {}) {
2558
2596
  _state.mount =
2559
2597
  !_proxyFormState.isValid ||
2560
2598
  !!keepStateOptions.keepIsValid ||
2561
- !!keepStateOptions.keepDirtyValues;
2599
+ !!keepStateOptions.keepDirtyValues ||
2600
+ (!_options.shouldUnregister && !isEmptyObject(values));
2562
2601
  _state.watch = !!_options.shouldUnregister;
2563
2602
  _subjects.state.next({
2564
2603
  submitCount: keepStateOptions.keepSubmitCount
@@ -2892,7 +2931,8 @@ function useFieldArray(props) {
2892
2931
  const _actioned = React.useRef(false);
2893
2932
  control._names.array.add(name);
2894
2933
  React.useMemo(() => rules &&
2895
- control.register(name, rules), [control, rules, name]);
2934
+ fields.length >= 0 &&
2935
+ control.register(name, rules), [control, name, fields.length, rules]);
2896
2936
  useIsomorphicLayoutEffect(() => control._subjects.array.subscribe({
2897
2937
  next: ({ values, name: fieldArrayName, }) => {
2898
2938
  if (fieldArrayName === name || !fieldArrayName) {
@@ -3216,11 +3256,15 @@ function useForm(props = {}) {
3216
3256
  }
3217
3257
  }, [control, formState.isDirty]);
3218
3258
  React.useEffect(() => {
3259
+ var _a;
3219
3260
  if (props.values && !deepEqual(props.values, _values.current)) {
3220
3261
  control._reset(props.values, {
3221
3262
  keepFieldsRef: true,
3222
3263
  ...control._options.resetOptions,
3223
3264
  });
3265
+ if (!((_a = control._options.resetOptions) === null || _a === void 0 ? void 0 : _a.keepIsValid)) {
3266
+ control._setValid();
3267
+ }
3224
3268
  _values.current = props.values;
3225
3269
  updateFormState((state) => ({ ...state }));
3226
3270
  }
@@ -3255,5 +3299,29 @@ function useForm(props = {}) {
3255
3299
  return _formControl.current;
3256
3300
  }
3257
3301
 
3258
- export { Controller, Form, FormProvider, appendErrors, createFormControl, get, set, submitForm as submit, useController, useFieldArray, useForm, useFormContext, useFormState, useWatch };
3302
+ /**
3303
+ * Watch component that subscribes to form field changes and re-renders when watched fields update.
3304
+ *
3305
+ * @param control - The form control object from useForm
3306
+ * @param names - Array of field names to watch for changes
3307
+ * @param render - The function that receives watched values and returns ReactNode
3308
+ * @returns The result of calling render function with watched values
3309
+ *
3310
+ * @example
3311
+ * The `Watch` component only re-render when the values of `foo`, `bar`, and `baz.qux` change.
3312
+ * The types of `foo`, `bar`, and `baz.qux` are precisely inferred.
3313
+ *
3314
+ * ```tsx
3315
+ * const { control } = useForm();
3316
+ *
3317
+ * <Watch
3318
+ * control={control}
3319
+ * names={['foo', 'bar', 'baz.qux']}
3320
+ * render={([foo, bar, baz_qux]) => <div>{foo}{bar}{baz_qux}</div>}
3321
+ * />
3322
+ * ```
3323
+ */
3324
+ const Watch = ({ control, names, render, }) => render(useWatch({ control, name: names }));
3325
+
3326
+ export { Controller, Form, FormProvider, Watch, appendErrors, createFormControl, get, set, submitForm as submit, useController, useFieldArray, useForm, useFormContext, useFormState, useWatch };
3259
3327
  //# sourceMappingURL=index.esm.mjs.map