react-hook-form 7.54.2 → 7.55.0-next.1

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.
@@ -217,43 +217,6 @@ var getProxyFormState = (formState, control, localProxyFormState, isRoot = true)
217
217
  return result;
218
218
  };
219
219
 
220
- var isEmptyObject = (value) => isObject(value) && !Object.keys(value).length;
221
-
222
- var shouldRenderFormState = (formStateData, _proxyFormState, updateFormState, isRoot) => {
223
- updateFormState(formStateData);
224
- const { name, ...formState } = formStateData;
225
- return (isEmptyObject(formState) ||
226
- Object.keys(formState).length >= Object.keys(_proxyFormState).length ||
227
- Object.keys(formState).find((key) => _proxyFormState[key] ===
228
- (!isRoot || VALIDATION_MODE.all)));
229
- };
230
-
231
- var convertToArrayPayload = (value) => (Array.isArray(value) ? value : [value]);
232
-
233
- var shouldSubscribeByName = (name, signalName, exact) => !name ||
234
- !signalName ||
235
- name === signalName ||
236
- convertToArrayPayload(name).some((currentName) => currentName &&
237
- (exact
238
- ? currentName === signalName
239
- : currentName.startsWith(signalName) ||
240
- signalName.startsWith(currentName)));
241
-
242
- function useSubscribe(props) {
243
- const _props = React.useRef(props);
244
- _props.current = props;
245
- React.useEffect(() => {
246
- const subscription = !props.disabled &&
247
- _props.current.subject &&
248
- _props.current.subject.subscribe({
249
- next: _props.current.next,
250
- });
251
- return () => {
252
- subscription && subscription.unsubscribe();
253
- };
254
- }, [props.disabled]);
255
- }
256
-
257
220
  /**
258
221
  * This custom hook allows you to subscribe to each form state, and isolate the re-render at the custom hook level. It has its scope in terms of form state subscription, so it would not affect other useFormState and useForm. Using this hook can reduce the re-render impact on large and complex form application.
259
222
  *
@@ -288,7 +251,6 @@ function useFormState(props) {
288
251
  const methods = useFormContext();
289
252
  const { control = methods.control, disabled, name, exact } = props || {};
290
253
  const [formState, updateFormState] = React.useState(control._formState);
291
- const _mounted = React.useRef(true);
292
254
  const _localProxyFormState = React.useRef({
293
255
  isDirty: false,
294
256
  isLoading: false,
@@ -301,23 +263,20 @@ function useFormState(props) {
301
263
  });
302
264
  const _name = React.useRef(name);
303
265
  _name.current = name;
304
- useSubscribe({
305
- disabled,
306
- next: (value) => _mounted.current &&
307
- shouldSubscribeByName(_name.current, value.name, exact) &&
308
- shouldRenderFormState(value, _localProxyFormState.current, control._updateFormState) &&
309
- updateFormState({
310
- ...control._formState,
311
- ...value,
312
- }),
313
- subject: control._subjects.state,
314
- });
266
+ React.useEffect(() => control._subscribe({
267
+ name: _name.current,
268
+ formState: _localProxyFormState.current,
269
+ exact,
270
+ callback: (formState) => {
271
+ !disabled &&
272
+ updateFormState({
273
+ ...control._formState,
274
+ ...formState,
275
+ });
276
+ },
277
+ }), [control, disabled, exact]);
315
278
  React.useEffect(() => {
316
- _mounted.current = true;
317
- _localProxyFormState.current.isValid && control._updateValid(true);
318
- return () => {
319
- _mounted.current = false;
320
- };
279
+ _localProxyFormState.current.isValid && control._setValid(true);
321
280
  }, [control]);
322
281
  return React.useMemo(() => getProxyFormState(formState, control, _localProxyFormState.current, false), [formState, control]);
323
282
  }
@@ -357,15 +316,15 @@ function useWatch(props) {
357
316
  const { control = methods.control, name, defaultValue, disabled, exact, } = props || {};
358
317
  const _name = React.useRef(name);
359
318
  _name.current = name;
360
- useSubscribe({
361
- disabled,
362
- subject: control._subjects.values,
363
- next: (formState) => {
364
- if (shouldSubscribeByName(_name.current, formState.name, exact)) {
365
- updateValue(cloneObject(generateWatchOutput(_name.current, control._names, formState.values || control._formValues, false, defaultValue)));
366
- }
319
+ React.useEffect(() => control._subscribe({
320
+ name: _name.current,
321
+ formState: {
322
+ values: true,
367
323
  },
368
- });
324
+ exact,
325
+ callback: (formState) => !disabled &&
326
+ updateValue(cloneObject(generateWatchOutput(_name.current, control._names, formState.values || control._formValues, false, defaultValue))),
327
+ }), [control, defaultValue, disabled, exact]);
369
328
  const [value, updateValue] = React.useState(control._getWatch(name, defaultValue));
370
329
  React.useEffect(() => control._removeUnmounted());
371
330
  return value;
@@ -502,7 +461,7 @@ function useController(props) {
502
461
  };
503
462
  }, [name, control, isArrayField, shouldUnregister]);
504
463
  React.useEffect(() => {
505
- control._updateDisabledField({
464
+ control._setDisabledField({
506
465
  disabled,
507
466
  fields: control._fields,
508
467
  name,
@@ -684,67 +643,70 @@ var appendErrors = (name, validateAllFieldCriteria, errors, type, message) => va
684
643
  }
685
644
  : {};
686
645
 
687
- var generateId = () => {
688
- const d = typeof performance === 'undefined' ? Date.now() : performance.now() * 1000;
689
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
690
- const r = (Math.random() * 16 + d) % 16 | 0;
691
- return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16);
692
- });
693
- };
694
-
695
- var getFocusFieldName = (name, index, options = {}) => options.shouldFocus || isUndefined(options.shouldFocus)
696
- ? options.focusName ||
697
- `${name}.${isUndefined(options.focusIndex) ? index : options.focusIndex}.`
698
- : '';
646
+ var convertToArrayPayload = (value) => (Array.isArray(value) ? value : [value]);
699
647
 
700
- var getValidationModes = (mode) => ({
701
- isOnSubmit: !mode || mode === VALIDATION_MODE.onSubmit,
702
- isOnBlur: mode === VALIDATION_MODE.onBlur,
703
- isOnChange: mode === VALIDATION_MODE.onChange,
704
- isOnAll: mode === VALIDATION_MODE.all,
705
- isOnTouch: mode === VALIDATION_MODE.onTouched,
706
- });
648
+ var createSubject = () => {
649
+ let _observers = [];
650
+ const next = (value) => {
651
+ for (const observer of _observers) {
652
+ observer.next && observer.next(value);
653
+ }
654
+ };
655
+ const subscribe = (observer) => {
656
+ _observers.push(observer);
657
+ return {
658
+ unsubscribe: () => {
659
+ _observers = _observers.filter((o) => o !== observer);
660
+ },
661
+ };
662
+ };
663
+ const unsubscribe = () => {
664
+ _observers = [];
665
+ };
666
+ return {
667
+ get observers() {
668
+ return _observers;
669
+ },
670
+ next,
671
+ subscribe,
672
+ unsubscribe,
673
+ };
674
+ };
707
675
 
708
- var isWatched = (name, _names, isBlurEvent) => !isBlurEvent &&
709
- (_names.watchAll ||
710
- _names.watch.has(name) ||
711
- [..._names.watch].some((watchName) => name.startsWith(watchName) &&
712
- /^\.\w+/.test(name.slice(watchName.length))));
676
+ var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
713
677
 
714
- const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
715
- for (const key of fieldsNames || Object.keys(fields)) {
716
- const field = get(fields, key);
717
- if (field) {
718
- const { _f, ...currentField } = field;
719
- if (_f) {
720
- if (_f.refs && _f.refs[0] && action(_f.refs[0], key) && !abortEarly) {
721
- return true;
722
- }
723
- else if (_f.ref && action(_f.ref, _f.name) && !abortEarly) {
724
- return true;
725
- }
726
- else {
727
- if (iterateFieldsByAction(currentField, action)) {
728
- break;
729
- }
730
- }
731
- }
732
- else if (isObject(currentField)) {
733
- if (iterateFieldsByAction(currentField, action)) {
734
- break;
735
- }
678
+ function deepEqual(object1, object2) {
679
+ if (isPrimitive(object1) || isPrimitive(object2)) {
680
+ return object1 === object2;
681
+ }
682
+ if (isDateObject(object1) && isDateObject(object2)) {
683
+ return object1.getTime() === object2.getTime();
684
+ }
685
+ const keys1 = Object.keys(object1);
686
+ const keys2 = Object.keys(object2);
687
+ if (keys1.length !== keys2.length) {
688
+ return false;
689
+ }
690
+ for (const key of keys1) {
691
+ const val1 = object1[key];
692
+ if (!keys2.includes(key)) {
693
+ return false;
694
+ }
695
+ if (key !== 'ref') {
696
+ const val2 = object2[key];
697
+ if ((isDateObject(val1) && isDateObject(val2)) ||
698
+ (isObject(val1) && isObject(val2)) ||
699
+ (Array.isArray(val1) && Array.isArray(val2))
700
+ ? !deepEqual(val1, val2)
701
+ : val1 !== val2) {
702
+ return false;
736
703
  }
737
704
  }
738
705
  }
739
- return;
740
- };
706
+ return true;
707
+ }
741
708
 
742
- var updateFieldArrayRootError = (errors, error, name) => {
743
- const fieldArrayErrors = convertToArrayPayload(get(errors, name));
744
- set(fieldArrayErrors, 'root', error[name]);
745
- set(errors, name, fieldArrayErrors);
746
- return errors;
747
- };
709
+ var isEmptyObject = (value) => isObject(value) && !Object.keys(value).length;
748
710
 
749
711
  var isFileInput = (element) => element.type === 'file';
750
712
 
@@ -759,11 +721,99 @@ var isHTMLElement = (value) => {
759
721
  (owner && owner.defaultView ? owner.defaultView.HTMLElement : HTMLElement));
760
722
  };
761
723
 
762
- var isMessage = (value) => isString(value);
724
+ var isMultipleSelect = (element) => element.type === `select-multiple`;
763
725
 
764
726
  var isRadioInput = (element) => element.type === 'radio';
765
727
 
766
- var isRegex = (value) => value instanceof RegExp;
728
+ var isRadioOrCheckbox = (ref) => isRadioInput(ref) || isCheckBoxInput(ref);
729
+
730
+ var live = (ref) => isHTMLElement(ref) && ref.isConnected;
731
+
732
+ function baseGet(object, updatePath) {
733
+ const length = updatePath.slice(0, -1).length;
734
+ let index = 0;
735
+ while (index < length) {
736
+ object = isUndefined(object) ? index++ : object[updatePath[index++]];
737
+ }
738
+ return object;
739
+ }
740
+ function isEmptyArray(obj) {
741
+ for (const key in obj) {
742
+ if (obj.hasOwnProperty(key) && !isUndefined(obj[key])) {
743
+ return false;
744
+ }
745
+ }
746
+ return true;
747
+ }
748
+ function unset(object, path) {
749
+ const paths = Array.isArray(path)
750
+ ? path
751
+ : isKey(path)
752
+ ? [path]
753
+ : stringToPath(path);
754
+ const childObject = paths.length === 1 ? object : baseGet(object, paths);
755
+ const index = paths.length - 1;
756
+ const key = paths[index];
757
+ if (childObject) {
758
+ delete childObject[key];
759
+ }
760
+ if (index !== 0 &&
761
+ ((isObject(childObject) && isEmptyObject(childObject)) ||
762
+ (Array.isArray(childObject) && isEmptyArray(childObject)))) {
763
+ unset(object, paths.slice(0, -1));
764
+ }
765
+ return object;
766
+ }
767
+
768
+ var objectHasFunction = (data) => {
769
+ for (const key in data) {
770
+ if (isFunction(data[key])) {
771
+ return true;
772
+ }
773
+ }
774
+ return false;
775
+ };
776
+
777
+ function markFieldsDirty(data, fields = {}) {
778
+ const isParentNodeArray = Array.isArray(data);
779
+ if (isObject(data) || isParentNodeArray) {
780
+ for (const key in data) {
781
+ if (Array.isArray(data[key]) ||
782
+ (isObject(data[key]) && !objectHasFunction(data[key]))) {
783
+ fields[key] = Array.isArray(data[key]) ? [] : {};
784
+ markFieldsDirty(data[key], fields[key]);
785
+ }
786
+ else if (!isNullOrUndefined(data[key])) {
787
+ fields[key] = true;
788
+ }
789
+ }
790
+ }
791
+ return fields;
792
+ }
793
+ function getDirtyFieldsFromDefaultValues(data, formValues, dirtyFieldsFromValues) {
794
+ const isParentNodeArray = Array.isArray(data);
795
+ if (isObject(data) || isParentNodeArray) {
796
+ for (const key in data) {
797
+ if (Array.isArray(data[key]) ||
798
+ (isObject(data[key]) && !objectHasFunction(data[key]))) {
799
+ if (isUndefined(formValues) ||
800
+ isPrimitive(dirtyFieldsFromValues[key])) {
801
+ dirtyFieldsFromValues[key] = Array.isArray(data[key])
802
+ ? markFieldsDirty(data[key], [])
803
+ : { ...markFieldsDirty(data[key]) };
804
+ }
805
+ else {
806
+ getDirtyFieldsFromDefaultValues(data[key], isNullOrUndefined(formValues) ? {} : formValues[key], dirtyFieldsFromValues[key]);
807
+ }
808
+ }
809
+ else {
810
+ dirtyFieldsFromValues[key] = !deepEqual(data[key], formValues[key]);
811
+ }
812
+ }
813
+ }
814
+ return dirtyFieldsFromValues;
815
+ }
816
+ var getDirtyFields = (defaultValues, formValues) => getDirtyFieldsFromDefaultValues(defaultValues, formValues, markFieldsDirty(formValues));
767
817
 
768
818
  const defaultResult = {
769
819
  value: false,
@@ -790,6 +840,20 @@ var getCheckboxValue = (options) => {
790
840
  return defaultResult;
791
841
  };
792
842
 
843
+ var getFieldValueAs = (value, { valueAsNumber, valueAsDate, setValueAs }) => isUndefined(value)
844
+ ? value
845
+ : valueAsNumber
846
+ ? value === ''
847
+ ? NaN
848
+ : value
849
+ ? +value
850
+ : value
851
+ : valueAsDate && isString(value)
852
+ ? new Date(value)
853
+ : setValueAs
854
+ ? setValueAs(value)
855
+ : value;
856
+
793
857
  const defaultReturn = {
794
858
  isValid: false,
795
859
  value: null,
@@ -803,6 +867,182 @@ var getRadioValue = (options) => Array.isArray(options)
803
867
  : previous, defaultReturn)
804
868
  : defaultReturn;
805
869
 
870
+ function getFieldValue(_f) {
871
+ const ref = _f.ref;
872
+ if (isFileInput(ref)) {
873
+ return ref.files;
874
+ }
875
+ if (isRadioInput(ref)) {
876
+ return getRadioValue(_f.refs).value;
877
+ }
878
+ if (isMultipleSelect(ref)) {
879
+ return [...ref.selectedOptions].map(({ value }) => value);
880
+ }
881
+ if (isCheckBoxInput(ref)) {
882
+ return getCheckboxValue(_f.refs).value;
883
+ }
884
+ return getFieldValueAs(isUndefined(ref.value) ? _f.ref.value : ref.value, _f);
885
+ }
886
+
887
+ var getResolverOptions = (fieldsNames, _fields, criteriaMode, shouldUseNativeValidation) => {
888
+ const fields = {};
889
+ for (const name of fieldsNames) {
890
+ const field = get(_fields, name);
891
+ field && set(fields, name, field._f);
892
+ }
893
+ return {
894
+ criteriaMode,
895
+ names: [...fieldsNames],
896
+ fields,
897
+ shouldUseNativeValidation,
898
+ };
899
+ };
900
+
901
+ var isRegex = (value) => value instanceof RegExp;
902
+
903
+ var getRuleValue = (rule) => isUndefined(rule)
904
+ ? rule
905
+ : isRegex(rule)
906
+ ? rule.source
907
+ : isObject(rule)
908
+ ? isRegex(rule.value)
909
+ ? rule.value.source
910
+ : rule.value
911
+ : rule;
912
+
913
+ var getValidationModes = (mode) => ({
914
+ isOnSubmit: !mode || mode === VALIDATION_MODE.onSubmit,
915
+ isOnBlur: mode === VALIDATION_MODE.onBlur,
916
+ isOnChange: mode === VALIDATION_MODE.onChange,
917
+ isOnAll: mode === VALIDATION_MODE.all,
918
+ isOnTouch: mode === VALIDATION_MODE.onTouched,
919
+ });
920
+
921
+ const ASYNC_FUNCTION = 'AsyncFunction';
922
+ var hasPromiseValidation = (fieldReference) => !!fieldReference &&
923
+ !!fieldReference.validate &&
924
+ !!((isFunction(fieldReference.validate) &&
925
+ fieldReference.validate.constructor.name === ASYNC_FUNCTION) ||
926
+ (isObject(fieldReference.validate) &&
927
+ Object.values(fieldReference.validate).find((validateFunction) => validateFunction.constructor.name === ASYNC_FUNCTION)));
928
+
929
+ var hasValidation = (options) => options.mount &&
930
+ (options.required ||
931
+ options.min ||
932
+ options.max ||
933
+ options.maxLength ||
934
+ options.minLength ||
935
+ options.pattern ||
936
+ options.validate);
937
+
938
+ var isWatched = (name, _names, isBlurEvent) => !isBlurEvent &&
939
+ (_names.watchAll ||
940
+ _names.watch.has(name) ||
941
+ [..._names.watch].some((watchName) => name.startsWith(watchName) &&
942
+ /^\.\w+/.test(name.slice(watchName.length))));
943
+
944
+ const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
945
+ for (const key of fieldsNames || Object.keys(fields)) {
946
+ const field = get(fields, key);
947
+ if (field) {
948
+ const { _f, ...currentField } = field;
949
+ if (_f) {
950
+ if (_f.refs && _f.refs[0] && action(_f.refs[0], key) && !abortEarly) {
951
+ return true;
952
+ }
953
+ else if (_f.ref && action(_f.ref, _f.name) && !abortEarly) {
954
+ return true;
955
+ }
956
+ else {
957
+ if (iterateFieldsByAction(currentField, action)) {
958
+ break;
959
+ }
960
+ }
961
+ }
962
+ else if (isObject(currentField)) {
963
+ if (iterateFieldsByAction(currentField, action)) {
964
+ break;
965
+ }
966
+ }
967
+ }
968
+ }
969
+ return;
970
+ };
971
+
972
+ function schemaErrorLookup(errors, _fields, name) {
973
+ const error = get(errors, name);
974
+ if (error || isKey(name)) {
975
+ return {
976
+ error,
977
+ name,
978
+ };
979
+ }
980
+ const names = name.split('.');
981
+ while (names.length) {
982
+ const fieldName = names.join('.');
983
+ const field = get(_fields, fieldName);
984
+ const foundError = get(errors, fieldName);
985
+ if (field && !Array.isArray(field) && name !== fieldName) {
986
+ return { name };
987
+ }
988
+ if (foundError && foundError.type) {
989
+ return {
990
+ name: fieldName,
991
+ error: foundError,
992
+ };
993
+ }
994
+ names.pop();
995
+ }
996
+ return {
997
+ name,
998
+ };
999
+ }
1000
+
1001
+ var shouldRenderFormState = (formStateData, _proxyFormState, updateFormState, isRoot) => {
1002
+ updateFormState(formStateData);
1003
+ const { name, ...formState } = formStateData;
1004
+ return (isEmptyObject(formState) ||
1005
+ Object.keys(formState).length >= Object.keys(_proxyFormState).length ||
1006
+ Object.keys(formState).find((key) => _proxyFormState[key] ===
1007
+ (!isRoot || VALIDATION_MODE.all)));
1008
+ };
1009
+
1010
+ var shouldSubscribeByName = (name, signalName, exact) => !name ||
1011
+ !signalName ||
1012
+ name === signalName ||
1013
+ convertToArrayPayload(name).some((currentName) => currentName &&
1014
+ (exact
1015
+ ? currentName === signalName
1016
+ : currentName.startsWith(signalName) ||
1017
+ signalName.startsWith(currentName)));
1018
+
1019
+ var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode) => {
1020
+ if (mode.isOnAll) {
1021
+ return false;
1022
+ }
1023
+ else if (!isSubmitted && mode.isOnTouch) {
1024
+ return !(isTouched || isBlurEvent);
1025
+ }
1026
+ else if (isSubmitted ? reValidateMode.isOnBlur : mode.isOnBlur) {
1027
+ return !isBlurEvent;
1028
+ }
1029
+ else if (isSubmitted ? reValidateMode.isOnChange : mode.isOnChange) {
1030
+ return isBlurEvent;
1031
+ }
1032
+ return true;
1033
+ };
1034
+
1035
+ var unsetEmptyArray = (ref, name) => !compact(get(ref, name)).length && unset(ref, name);
1036
+
1037
+ var updateFieldArrayRootError = (errors, error, name) => {
1038
+ const fieldArrayErrors = convertToArrayPayload(get(errors, name));
1039
+ set(fieldArrayErrors, 'root', error[name]);
1040
+ set(errors, name, fieldArrayErrors);
1041
+ return errors;
1042
+ };
1043
+
1044
+ var isMessage = (value) => isString(value);
1045
+
806
1046
  function getValidateError(result, ref, type = 'validate') {
807
1047
  if (isMessage(result) ||
808
1048
  (Array.isArray(result) && result.every(isMessage)) ||
@@ -1001,848 +1241,301 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
1001
1241
  return error;
1002
1242
  };
1003
1243
 
1004
- var appendAt = (data, value) => [
1005
- ...data,
1006
- ...convertToArrayPayload(value),
1007
- ];
1008
-
1009
- var fillEmptyArray = (value) => Array.isArray(value) ? value.map(() => undefined) : undefined;
1010
-
1011
- function insert(data, index, value) {
1012
- return [
1013
- ...data.slice(0, index),
1014
- ...convertToArrayPayload(value),
1015
- ...data.slice(index),
1016
- ];
1017
- }
1018
-
1019
- var moveArrayAt = (data, from, to) => {
1020
- if (!Array.isArray(data)) {
1021
- return [];
1022
- }
1023
- if (isUndefined(data[to])) {
1024
- data[to] = undefined;
1025
- }
1026
- data.splice(to, 0, data.splice(from, 1)[0]);
1027
- return data;
1028
- };
1029
-
1030
- var prependAt = (data, value) => [
1031
- ...convertToArrayPayload(value),
1032
- ...convertToArrayPayload(data),
1033
- ];
1034
-
1035
- function removeAtIndexes(data, indexes) {
1036
- let i = 0;
1037
- const temp = [...data];
1038
- for (const index of indexes) {
1039
- temp.splice(index - i, 1);
1040
- i++;
1041
- }
1042
- return compact(temp).length ? temp : [];
1043
- }
1044
- var removeArrayAt = (data, index) => isUndefined(index)
1045
- ? []
1046
- : removeAtIndexes(data, convertToArrayPayload(index).sort((a, b) => a - b));
1047
-
1048
- var swapArrayAt = (data, indexA, indexB) => {
1049
- [data[indexA], data[indexB]] = [data[indexB], data[indexA]];
1244
+ const defaultOptions = {
1245
+ mode: VALIDATION_MODE.onSubmit,
1246
+ reValidateMode: VALIDATION_MODE.onChange,
1247
+ shouldFocusError: true,
1050
1248
  };
1051
-
1052
- function baseGet(object, updatePath) {
1053
- const length = updatePath.slice(0, -1).length;
1054
- let index = 0;
1055
- while (index < length) {
1056
- object = isUndefined(object) ? index++ : object[updatePath[index++]];
1057
- }
1058
- return object;
1059
- }
1060
- function isEmptyArray(obj) {
1061
- for (const key in obj) {
1062
- if (obj.hasOwnProperty(key) && !isUndefined(obj[key])) {
1063
- return false;
1064
- }
1065
- }
1066
- return true;
1067
- }
1068
- function unset(object, path) {
1069
- const paths = Array.isArray(path)
1070
- ? path
1071
- : isKey(path)
1072
- ? [path]
1073
- : stringToPath(path);
1074
- const childObject = paths.length === 1 ? object : baseGet(object, paths);
1075
- const index = paths.length - 1;
1076
- const key = paths[index];
1077
- if (childObject) {
1078
- delete childObject[key];
1079
- }
1080
- if (index !== 0 &&
1081
- ((isObject(childObject) && isEmptyObject(childObject)) ||
1082
- (Array.isArray(childObject) && isEmptyArray(childObject)))) {
1083
- unset(object, paths.slice(0, -1));
1084
- }
1085
- return object;
1086
- }
1087
-
1088
- var updateAt = (fieldValues, index, value) => {
1089
- fieldValues[index] = value;
1090
- return fieldValues;
1091
- };
1092
-
1093
- /**
1094
- * A custom hook that exposes convenient methods to perform operations with a list of dynamic inputs that need to be appended, updated, removed etc. • [Demo](https://codesandbox.io/s/react-hook-form-usefieldarray-ssugn) • [Video](https://youtu.be/4MrbfGSFY2A)
1095
- *
1096
- * @remarks
1097
- * [API](https://react-hook-form.com/docs/usefieldarray) • [Demo](https://codesandbox.io/s/react-hook-form-usefieldarray-ssugn)
1098
- *
1099
- * @param props - useFieldArray props
1100
- *
1101
- * @returns methods - functions to manipulate with the Field Arrays (dynamic inputs) {@link UseFieldArrayReturn}
1102
- *
1103
- * @example
1104
- * ```tsx
1105
- * function App() {
1106
- * const { register, control, handleSubmit, reset, trigger, setError } = useForm({
1107
- * defaultValues: {
1108
- * test: []
1109
- * }
1110
- * });
1111
- * const { fields, append } = useFieldArray({
1112
- * control,
1113
- * name: "test"
1114
- * });
1115
- *
1116
- * return (
1117
- * <form onSubmit={handleSubmit(data => console.log(data))}>
1118
- * {fields.map((item, index) => (
1119
- * <input key={item.id} {...register(`test.${index}.firstName`)} />
1120
- * ))}
1121
- * <button type="button" onClick={() => append({ firstName: "bill" })}>
1122
- * append
1123
- * </button>
1124
- * <input type="submit" />
1125
- * </form>
1126
- * );
1127
- * }
1128
- * ```
1129
- */
1130
- function useFieldArray(props) {
1131
- const methods = useFormContext();
1132
- const { control = methods.control, name, keyName = 'id', shouldUnregister, rules, } = props;
1133
- const [fields, setFields] = React.useState(control._getFieldArray(name));
1134
- const ids = React.useRef(control._getFieldArray(name).map(generateId));
1135
- const _fieldIds = React.useRef(fields);
1136
- const _name = React.useRef(name);
1137
- const _actioned = React.useRef(false);
1138
- _name.current = name;
1139
- _fieldIds.current = fields;
1140
- control._names.array.add(name);
1141
- rules &&
1142
- control.register(name, rules);
1143
- useSubscribe({
1144
- next: ({ values, name: fieldArrayName, }) => {
1145
- if (fieldArrayName === _name.current || !fieldArrayName) {
1146
- const fieldValues = get(values, _name.current);
1147
- if (Array.isArray(fieldValues)) {
1148
- setFields(fieldValues);
1149
- ids.current = fieldValues.map(generateId);
1150
- }
1151
- }
1152
- },
1153
- subject: control._subjects.array,
1154
- });
1155
- const updateValues = React.useCallback((updatedFieldArrayValues) => {
1156
- _actioned.current = true;
1157
- control._updateFieldArray(name, updatedFieldArrayValues);
1158
- }, [control, name]);
1159
- const append = (value, options) => {
1160
- const appendValue = convertToArrayPayload(cloneObject(value));
1161
- const updatedFieldArrayValues = appendAt(control._getFieldArray(name), appendValue);
1162
- control._names.focus = getFocusFieldName(name, updatedFieldArrayValues.length - 1, options);
1163
- ids.current = appendAt(ids.current, appendValue.map(generateId));
1164
- updateValues(updatedFieldArrayValues);
1165
- setFields(updatedFieldArrayValues);
1166
- control._updateFieldArray(name, updatedFieldArrayValues, appendAt, {
1167
- argA: fillEmptyArray(value),
1168
- });
1249
+ function createFormControl(props = {}) {
1250
+ let _options = {
1251
+ ...defaultOptions,
1252
+ ...props,
1169
1253
  };
1170
- const prepend = (value, options) => {
1171
- const prependValue = convertToArrayPayload(cloneObject(value));
1172
- const updatedFieldArrayValues = prependAt(control._getFieldArray(name), prependValue);
1173
- control._names.focus = getFocusFieldName(name, 0, options);
1174
- ids.current = prependAt(ids.current, prependValue.map(generateId));
1175
- updateValues(updatedFieldArrayValues);
1176
- setFields(updatedFieldArrayValues);
1177
- control._updateFieldArray(name, updatedFieldArrayValues, prependAt, {
1178
- argA: fillEmptyArray(value),
1179
- });
1254
+ let _formState = {
1255
+ submitCount: 0,
1256
+ isDirty: false,
1257
+ isLoading: isFunction(_options.defaultValues),
1258
+ isValidating: false,
1259
+ isSubmitted: false,
1260
+ isSubmitting: false,
1261
+ isSubmitSuccessful: false,
1262
+ isValid: false,
1263
+ touchedFields: {},
1264
+ dirtyFields: {},
1265
+ validatingFields: {},
1266
+ errors: _options.errors || {},
1267
+ disabled: _options.disabled || false,
1180
1268
  };
1181
- const remove = (index) => {
1182
- const updatedFieldArrayValues = removeArrayAt(control._getFieldArray(name), index);
1183
- ids.current = removeArrayAt(ids.current, index);
1184
- updateValues(updatedFieldArrayValues);
1185
- setFields(updatedFieldArrayValues);
1186
- !Array.isArray(get(control._fields, name)) &&
1187
- set(control._fields, name, undefined);
1188
- control._updateFieldArray(name, updatedFieldArrayValues, removeArrayAt, {
1189
- argA: index,
1190
- });
1269
+ let _fields = {};
1270
+ let _defaultValues = isObject(_options.defaultValues) || isObject(_options.values)
1271
+ ? cloneObject(_options.defaultValues || _options.values) || {}
1272
+ : {};
1273
+ let _formValues = _options.shouldUnregister
1274
+ ? {}
1275
+ : cloneObject(_defaultValues);
1276
+ let _state = {
1277
+ action: false,
1278
+ mount: false,
1279
+ watch: false,
1191
1280
  };
1192
- const insert$1 = (index, value, options) => {
1193
- const insertValue = convertToArrayPayload(cloneObject(value));
1194
- const updatedFieldArrayValues = insert(control._getFieldArray(name), index, insertValue);
1195
- control._names.focus = getFocusFieldName(name, index, options);
1196
- ids.current = insert(ids.current, index, insertValue.map(generateId));
1197
- updateValues(updatedFieldArrayValues);
1198
- setFields(updatedFieldArrayValues);
1199
- control._updateFieldArray(name, updatedFieldArrayValues, insert, {
1200
- argA: index,
1201
- argB: fillEmptyArray(value),
1202
- });
1281
+ let _names = {
1282
+ mount: new Set(),
1283
+ disabled: new Set(),
1284
+ unMount: new Set(),
1285
+ array: new Set(),
1286
+ watch: new Set(),
1203
1287
  };
1204
- const swap = (indexA, indexB) => {
1205
- const updatedFieldArrayValues = control._getFieldArray(name);
1206
- swapArrayAt(updatedFieldArrayValues, indexA, indexB);
1207
- swapArrayAt(ids.current, indexA, indexB);
1208
- updateValues(updatedFieldArrayValues);
1209
- setFields(updatedFieldArrayValues);
1210
- control._updateFieldArray(name, updatedFieldArrayValues, swapArrayAt, {
1211
- argA: indexA,
1212
- argB: indexB,
1213
- }, false);
1288
+ let delayErrorCallback;
1289
+ let timer = 0;
1290
+ const _proxyFormState = {
1291
+ isDirty: false,
1292
+ dirtyFields: false,
1293
+ validatingFields: false,
1294
+ touchedFields: false,
1295
+ isValidating: false,
1296
+ isValid: false,
1297
+ errors: false,
1214
1298
  };
1215
- const move = (from, to) => {
1216
- const updatedFieldArrayValues = control._getFieldArray(name);
1217
- moveArrayAt(updatedFieldArrayValues, from, to);
1218
- moveArrayAt(ids.current, from, to);
1219
- updateValues(updatedFieldArrayValues);
1220
- setFields(updatedFieldArrayValues);
1221
- control._updateFieldArray(name, updatedFieldArrayValues, moveArrayAt, {
1222
- argA: from,
1223
- argB: to,
1224
- }, false);
1299
+ let _proxySubscribeFormState = {
1300
+ ..._proxyFormState,
1225
1301
  };
1226
- const update = (index, value) => {
1227
- const updateValue = cloneObject(value);
1228
- const updatedFieldArrayValues = updateAt(control._getFieldArray(name), index, updateValue);
1229
- ids.current = [...updatedFieldArrayValues].map((item, i) => !item || i === index ? generateId() : ids.current[i]);
1230
- updateValues(updatedFieldArrayValues);
1231
- setFields([...updatedFieldArrayValues]);
1232
- control._updateFieldArray(name, updatedFieldArrayValues, updateAt, {
1233
- argA: index,
1234
- argB: updateValue,
1235
- }, true, false);
1302
+ const _subjects = {
1303
+ array: createSubject(),
1304
+ state: createSubject(),
1236
1305
  };
1237
- const replace = (value) => {
1238
- const updatedFieldArrayValues = convertToArrayPayload(cloneObject(value));
1239
- ids.current = updatedFieldArrayValues.map(generateId);
1240
- updateValues([...updatedFieldArrayValues]);
1241
- setFields([...updatedFieldArrayValues]);
1242
- control._updateFieldArray(name, [...updatedFieldArrayValues], (data) => data, {}, true, false);
1306
+ const validationModeBeforeSubmit = getValidationModes(_options.mode);
1307
+ const validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
1308
+ const shouldDisplayAllAssociatedErrors = _options.criteriaMode === VALIDATION_MODE.all;
1309
+ const debounce = (callback) => (wait) => {
1310
+ clearTimeout(timer);
1311
+ timer = setTimeout(callback, wait);
1243
1312
  };
1244
- React.useEffect(() => {
1245
- control._state.action = false;
1246
- isWatched(name, control._names) &&
1247
- control._subjects.state.next({
1248
- ...control._formState,
1249
- });
1250
- if (_actioned.current &&
1251
- (!getValidationModes(control._options.mode).isOnSubmit ||
1252
- control._formState.isSubmitted)) {
1253
- if (control._options.resolver) {
1254
- control._executeSchema([name]).then((result) => {
1255
- const error = get(result.errors, name);
1256
- const existingError = get(control._formState.errors, name);
1257
- if (existingError
1258
- ? (!error && existingError.type) ||
1259
- (error &&
1260
- (existingError.type !== error.type ||
1261
- existingError.message !== error.message))
1262
- : error && error.type) {
1263
- error
1264
- ? set(control._formState.errors, name, error)
1265
- : unset(control._formState.errors, name);
1266
- control._subjects.state.next({
1267
- errors: control._formState.errors,
1268
- });
1269
- }
1313
+ const _setValid = async (shouldUpdateValid) => {
1314
+ if (!_options.disabled &&
1315
+ (_proxyFormState.isValid ||
1316
+ _proxySubscribeFormState.isValid ||
1317
+ shouldUpdateValid)) {
1318
+ const isValid = _options.resolver
1319
+ ? isEmptyObject((await _runSchema()).errors)
1320
+ : await executeBuiltInValidation(_fields, true);
1321
+ if (isValid !== _formState.isValid) {
1322
+ _subjects.state.next({
1323
+ isValid,
1270
1324
  });
1271
1325
  }
1272
- else {
1273
- const field = get(control._fields, name);
1274
- if (field &&
1275
- field._f &&
1276
- !(getValidationModes(control._options.reValidateMode).isOnSubmit &&
1277
- getValidationModes(control._options.mode).isOnSubmit)) {
1278
- validateField(field, control._names.disabled, control._formValues, control._options.criteriaMode === VALIDATION_MODE.all, control._options.shouldUseNativeValidation, true).then((error) => !isEmptyObject(error) &&
1279
- control._subjects.state.next({
1280
- errors: updateFieldArrayRootError(control._formState.errors, error, name),
1281
- }));
1326
+ }
1327
+ };
1328
+ const _updateIsValidating = (names, isValidating) => {
1329
+ if (!_options.disabled &&
1330
+ (_proxyFormState.isValidating ||
1331
+ _proxyFormState.validatingFields ||
1332
+ _proxySubscribeFormState.isValidating ||
1333
+ _proxySubscribeFormState.validatingFields)) {
1334
+ (names || Array.from(_names.mount)).forEach((name) => {
1335
+ if (name) {
1336
+ isValidating
1337
+ ? set(_formState.validatingFields, name, isValidating)
1338
+ : unset(_formState.validatingFields, name);
1282
1339
  }
1283
- }
1340
+ });
1341
+ _subjects.state.next({
1342
+ validatingFields: _formState.validatingFields,
1343
+ isValidating: !isEmptyObject(_formState.validatingFields),
1344
+ });
1284
1345
  }
1285
- control._subjects.values.next({
1286
- name,
1287
- values: { ...control._formValues },
1288
- });
1289
- control._names.focus &&
1290
- iterateFieldsByAction(control._fields, (ref, key) => {
1291
- if (control._names.focus &&
1292
- key.startsWith(control._names.focus) &&
1293
- ref.focus) {
1294
- ref.focus();
1295
- return 1;
1296
- }
1297
- return;
1298
- });
1299
- control._names.focus = '';
1300
- control._updateValid();
1301
- _actioned.current = false;
1302
- }, [fields, name, control]);
1303
- React.useEffect(() => {
1304
- !get(control._formValues, name) && control._updateFieldArray(name);
1305
- return () => {
1306
- (control._options.shouldUnregister || shouldUnregister) &&
1307
- control.unregister(name);
1308
- };
1309
- }, [name, control, keyName, shouldUnregister]);
1310
- return {
1311
- swap: React.useCallback(swap, [updateValues, name, control]),
1312
- move: React.useCallback(move, [updateValues, name, control]),
1313
- prepend: React.useCallback(prepend, [updateValues, name, control]),
1314
- append: React.useCallback(append, [updateValues, name, control]),
1315
- remove: React.useCallback(remove, [updateValues, name, control]),
1316
- insert: React.useCallback(insert$1, [updateValues, name, control]),
1317
- update: React.useCallback(update, [updateValues, name, control]),
1318
- replace: React.useCallback(replace, [updateValues, name, control]),
1319
- fields: React.useMemo(() => fields.map((field, index) => ({
1320
- ...field,
1321
- [keyName]: ids.current[index] || generateId(),
1322
- })), [fields, keyName]),
1323
1346
  };
1324
- }
1325
-
1326
- var createSubject = () => {
1327
- let _observers = [];
1328
- const next = (value) => {
1329
- for (const observer of _observers) {
1330
- observer.next && observer.next(value);
1347
+ const _setFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndState = true) => {
1348
+ if (args && method && !_options.disabled) {
1349
+ _state.action = true;
1350
+ if (shouldUpdateFieldsAndState && Array.isArray(get(_fields, name))) {
1351
+ const fieldValues = method(get(_fields, name), args.argA, args.argB);
1352
+ shouldSetValues && set(_fields, name, fieldValues);
1353
+ }
1354
+ if (shouldUpdateFieldsAndState &&
1355
+ Array.isArray(get(_formState.errors, name))) {
1356
+ const errors = method(get(_formState.errors, name), args.argA, args.argB);
1357
+ shouldSetValues && set(_formState.errors, name, errors);
1358
+ unsetEmptyArray(_formState.errors, name);
1359
+ }
1360
+ if ((_proxyFormState.touchedFields ||
1361
+ _proxySubscribeFormState.touchedFields) &&
1362
+ shouldUpdateFieldsAndState &&
1363
+ Array.isArray(get(_formState.touchedFields, name))) {
1364
+ const touchedFields = method(get(_formState.touchedFields, name), args.argA, args.argB);
1365
+ shouldSetValues && set(_formState.touchedFields, name, touchedFields);
1366
+ }
1367
+ if (_proxyFormState.dirtyFields || _proxySubscribeFormState.dirtyFields) {
1368
+ _formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
1369
+ }
1370
+ _subjects.state.next({
1371
+ name,
1372
+ isDirty: _getDirty(name, values),
1373
+ dirtyFields: _formState.dirtyFields,
1374
+ errors: _formState.errors,
1375
+ isValid: _formState.isValid,
1376
+ });
1377
+ }
1378
+ else {
1379
+ set(_formValues, name, values);
1331
1380
  }
1332
1381
  };
1333
- const subscribe = (observer) => {
1334
- _observers.push(observer);
1335
- return {
1336
- unsubscribe: () => {
1337
- _observers = _observers.filter((o) => o !== observer);
1338
- },
1339
- };
1340
- };
1341
- const unsubscribe = () => {
1342
- _observers = [];
1382
+ const updateErrors = (name, error) => {
1383
+ set(_formState.errors, name, error);
1384
+ _subjects.state.next({
1385
+ errors: _formState.errors,
1386
+ });
1343
1387
  };
1344
- return {
1345
- get observers() {
1346
- return _observers;
1347
- },
1348
- next,
1349
- subscribe,
1350
- unsubscribe,
1388
+ const _setErrors = (errors) => {
1389
+ _formState.errors = errors;
1390
+ _subjects.state.next({
1391
+ errors: _formState.errors,
1392
+ isValid: false,
1393
+ });
1351
1394
  };
1352
- };
1353
-
1354
- var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
1355
-
1356
- function deepEqual(object1, object2) {
1357
- if (isPrimitive(object1) || isPrimitive(object2)) {
1358
- return object1 === object2;
1359
- }
1360
- if (isDateObject(object1) && isDateObject(object2)) {
1361
- return object1.getTime() === object2.getTime();
1362
- }
1363
- const keys1 = Object.keys(object1);
1364
- const keys2 = Object.keys(object2);
1365
- if (keys1.length !== keys2.length) {
1366
- return false;
1367
- }
1368
- for (const key of keys1) {
1369
- const val1 = object1[key];
1370
- if (!keys2.includes(key)) {
1371
- return false;
1395
+ const updateValidAndValue = (name, shouldSkipSetValueAs, value, ref) => {
1396
+ const field = get(_fields, name);
1397
+ if (field) {
1398
+ const defaultValue = get(_formValues, name, isUndefined(value) ? get(_defaultValues, name) : value);
1399
+ isUndefined(defaultValue) ||
1400
+ (ref && ref.defaultChecked) ||
1401
+ shouldSkipSetValueAs
1402
+ ? set(_formValues, name, shouldSkipSetValueAs ? defaultValue : getFieldValue(field._f))
1403
+ : setFieldValue(name, defaultValue);
1404
+ _state.mount && _setValid();
1372
1405
  }
1373
- if (key !== 'ref') {
1374
- const val2 = object2[key];
1375
- if ((isDateObject(val1) && isDateObject(val2)) ||
1376
- (isObject(val1) && isObject(val2)) ||
1377
- (Array.isArray(val1) && Array.isArray(val2))
1378
- ? !deepEqual(val1, val2)
1379
- : val1 !== val2) {
1380
- return false;
1406
+ };
1407
+ const updateTouchAndDirty = (name, fieldValue, isBlurEvent, shouldDirty, shouldRender) => {
1408
+ let shouldUpdateField = false;
1409
+ let isPreviousDirty = false;
1410
+ const output = {
1411
+ name,
1412
+ };
1413
+ if (!_options.disabled) {
1414
+ const disabledField = !!(get(_fields, name) &&
1415
+ get(_fields, name)._f &&
1416
+ get(_fields, name)._f.disabled);
1417
+ if (!isBlurEvent || shouldDirty) {
1418
+ if (_proxyFormState.isDirty || _proxySubscribeFormState.isDirty) {
1419
+ isPreviousDirty = _formState.isDirty;
1420
+ _formState.isDirty = output.isDirty = _getDirty();
1421
+ shouldUpdateField = isPreviousDirty !== output.isDirty;
1422
+ }
1423
+ const isCurrentFieldPristine = disabledField || deepEqual(get(_defaultValues, name), fieldValue);
1424
+ isPreviousDirty = !!(!disabledField && get(_formState.dirtyFields, name));
1425
+ isCurrentFieldPristine || disabledField
1426
+ ? unset(_formState.dirtyFields, name)
1427
+ : set(_formState.dirtyFields, name, true);
1428
+ output.dirtyFields = _formState.dirtyFields;
1429
+ shouldUpdateField =
1430
+ shouldUpdateField ||
1431
+ ((_proxyFormState.dirtyFields ||
1432
+ _proxySubscribeFormState.dirtyFields) &&
1433
+ isPreviousDirty !== !isCurrentFieldPristine);
1434
+ }
1435
+ if (isBlurEvent) {
1436
+ const isPreviousFieldTouched = get(_formState.touchedFields, name);
1437
+ if (!isPreviousFieldTouched) {
1438
+ set(_formState.touchedFields, name, isBlurEvent);
1439
+ output.touchedFields = _formState.touchedFields;
1440
+ shouldUpdateField =
1441
+ shouldUpdateField ||
1442
+ ((_proxyFormState.touchedFields ||
1443
+ _proxySubscribeFormState.touchedFields) &&
1444
+ isPreviousFieldTouched !== isBlurEvent);
1445
+ }
1381
1446
  }
1447
+ shouldUpdateField && shouldRender && _subjects.state.next(output);
1382
1448
  }
1383
- }
1384
- return true;
1385
- }
1386
-
1387
- var isMultipleSelect = (element) => element.type === `select-multiple`;
1388
-
1389
- var isRadioOrCheckbox = (ref) => isRadioInput(ref) || isCheckBoxInput(ref);
1390
-
1391
- var live = (ref) => isHTMLElement(ref) && ref.isConnected;
1392
-
1393
- var objectHasFunction = (data) => {
1394
- for (const key in data) {
1395
- if (isFunction(data[key])) {
1396
- return true;
1449
+ return shouldUpdateField ? output : {};
1450
+ };
1451
+ const shouldRenderByError = (name, isValid, error, fieldState) => {
1452
+ const previousFieldError = get(_formState.errors, name);
1453
+ const shouldUpdateValid = (_proxyFormState.isValid || _proxySubscribeFormState.isValid) &&
1454
+ isBoolean(isValid) &&
1455
+ _formState.isValid !== isValid;
1456
+ if (_options.delayError && error) {
1457
+ delayErrorCallback = debounce(() => updateErrors(name, error));
1458
+ delayErrorCallback(_options.delayError);
1397
1459
  }
1398
- }
1399
- return false;
1400
- };
1401
-
1402
- function markFieldsDirty(data, fields = {}) {
1403
- const isParentNodeArray = Array.isArray(data);
1404
- if (isObject(data) || isParentNodeArray) {
1405
- for (const key in data) {
1406
- if (Array.isArray(data[key]) ||
1407
- (isObject(data[key]) && !objectHasFunction(data[key]))) {
1408
- fields[key] = Array.isArray(data[key]) ? [] : {};
1409
- markFieldsDirty(data[key], fields[key]);
1410
- }
1411
- else if (!isNullOrUndefined(data[key])) {
1412
- fields[key] = true;
1413
- }
1460
+ else {
1461
+ clearTimeout(timer);
1462
+ delayErrorCallback = null;
1463
+ error
1464
+ ? set(_formState.errors, name, error)
1465
+ : unset(_formState.errors, name);
1414
1466
  }
1415
- }
1416
- return fields;
1417
- }
1418
- function getDirtyFieldsFromDefaultValues(data, formValues, dirtyFieldsFromValues) {
1419
- const isParentNodeArray = Array.isArray(data);
1420
- if (isObject(data) || isParentNodeArray) {
1421
- for (const key in data) {
1422
- if (Array.isArray(data[key]) ||
1423
- (isObject(data[key]) && !objectHasFunction(data[key]))) {
1424
- if (isUndefined(formValues) ||
1425
- isPrimitive(dirtyFieldsFromValues[key])) {
1426
- dirtyFieldsFromValues[key] = Array.isArray(data[key])
1427
- ? markFieldsDirty(data[key], [])
1428
- : { ...markFieldsDirty(data[key]) };
1429
- }
1430
- else {
1431
- getDirtyFieldsFromDefaultValues(data[key], isNullOrUndefined(formValues) ? {} : formValues[key], dirtyFieldsFromValues[key]);
1432
- }
1433
- }
1434
- else {
1435
- dirtyFieldsFromValues[key] = !deepEqual(data[key], formValues[key]);
1436
- }
1467
+ if ((error ? !deepEqual(previousFieldError, error) : previousFieldError) ||
1468
+ !isEmptyObject(fieldState) ||
1469
+ shouldUpdateValid) {
1470
+ const updatedFormState = {
1471
+ ...fieldState,
1472
+ ...(shouldUpdateValid && isBoolean(isValid) ? { isValid } : {}),
1473
+ errors: _formState.errors,
1474
+ name,
1475
+ };
1476
+ _formState = {
1477
+ ..._formState,
1478
+ ...updatedFormState,
1479
+ };
1480
+ _subjects.state.next(updatedFormState);
1437
1481
  }
1438
- }
1439
- return dirtyFieldsFromValues;
1440
- }
1441
- var getDirtyFields = (defaultValues, formValues) => getDirtyFieldsFromDefaultValues(defaultValues, formValues, markFieldsDirty(formValues));
1442
-
1443
- var getFieldValueAs = (value, { valueAsNumber, valueAsDate, setValueAs }) => isUndefined(value)
1444
- ? value
1445
- : valueAsNumber
1446
- ? value === ''
1447
- ? NaN
1448
- : value
1449
- ? +value
1450
- : value
1451
- : valueAsDate && isString(value)
1452
- ? new Date(value)
1453
- : setValueAs
1454
- ? setValueAs(value)
1455
- : value;
1456
-
1457
- function getFieldValue(_f) {
1458
- const ref = _f.ref;
1459
- if (isFileInput(ref)) {
1460
- return ref.files;
1461
- }
1462
- if (isRadioInput(ref)) {
1463
- return getRadioValue(_f.refs).value;
1464
- }
1465
- if (isMultipleSelect(ref)) {
1466
- return [...ref.selectedOptions].map(({ value }) => value);
1467
- }
1468
- if (isCheckBoxInput(ref)) {
1469
- return getCheckboxValue(_f.refs).value;
1470
- }
1471
- return getFieldValueAs(isUndefined(ref.value) ? _f.ref.value : ref.value, _f);
1472
- }
1473
-
1474
- var getResolverOptions = (fieldsNames, _fields, criteriaMode, shouldUseNativeValidation) => {
1475
- const fields = {};
1476
- for (const name of fieldsNames) {
1477
- const field = get(_fields, name);
1478
- field && set(fields, name, field._f);
1479
- }
1480
- return {
1481
- criteriaMode,
1482
- names: [...fieldsNames],
1483
- fields,
1484
- shouldUseNativeValidation,
1485
- };
1486
- };
1487
-
1488
- var getRuleValue = (rule) => isUndefined(rule)
1489
- ? rule
1490
- : isRegex(rule)
1491
- ? rule.source
1492
- : isObject(rule)
1493
- ? isRegex(rule.value)
1494
- ? rule.value.source
1495
- : rule.value
1496
- : rule;
1497
-
1498
- const ASYNC_FUNCTION = 'AsyncFunction';
1499
- var hasPromiseValidation = (fieldReference) => !!fieldReference &&
1500
- !!fieldReference.validate &&
1501
- !!((isFunction(fieldReference.validate) &&
1502
- fieldReference.validate.constructor.name === ASYNC_FUNCTION) ||
1503
- (isObject(fieldReference.validate) &&
1504
- Object.values(fieldReference.validate).find((validateFunction) => validateFunction.constructor.name === ASYNC_FUNCTION)));
1505
-
1506
- var hasValidation = (options) => options.mount &&
1507
- (options.required ||
1508
- options.min ||
1509
- options.max ||
1510
- options.maxLength ||
1511
- options.minLength ||
1512
- options.pattern ||
1513
- options.validate);
1514
-
1515
- function schemaErrorLookup(errors, _fields, name) {
1516
- const error = get(errors, name);
1517
- if (error || isKey(name)) {
1518
- return {
1519
- error,
1520
- name,
1521
- };
1522
- }
1523
- const names = name.split('.');
1524
- while (names.length) {
1525
- const fieldName = names.join('.');
1526
- const field = get(_fields, fieldName);
1527
- const foundError = get(errors, fieldName);
1528
- if (field && !Array.isArray(field) && name !== fieldName) {
1529
- return { name };
1530
- }
1531
- if (foundError && foundError.type) {
1532
- return {
1533
- name: fieldName,
1534
- error: foundError,
1535
- };
1536
- }
1537
- names.pop();
1538
- }
1539
- return {
1540
- name,
1541
- };
1542
- }
1543
-
1544
- var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode) => {
1545
- if (mode.isOnAll) {
1546
- return false;
1547
- }
1548
- else if (!isSubmitted && mode.isOnTouch) {
1549
- return !(isTouched || isBlurEvent);
1550
- }
1551
- else if (isSubmitted ? reValidateMode.isOnBlur : mode.isOnBlur) {
1552
- return !isBlurEvent;
1553
- }
1554
- else if (isSubmitted ? reValidateMode.isOnChange : mode.isOnChange) {
1555
- return isBlurEvent;
1556
- }
1557
- return true;
1558
- };
1559
-
1560
- var unsetEmptyArray = (ref, name) => !compact(get(ref, name)).length && unset(ref, name);
1561
-
1562
- const defaultOptions = {
1563
- mode: VALIDATION_MODE.onSubmit,
1564
- reValidateMode: VALIDATION_MODE.onChange,
1565
- shouldFocusError: true,
1566
- };
1567
- function createFormControl(props = {}) {
1568
- let _options = {
1569
- ...defaultOptions,
1570
- ...props,
1571
1482
  };
1572
- let _formState = {
1573
- submitCount: 0,
1574
- isDirty: false,
1575
- isLoading: isFunction(_options.defaultValues),
1576
- isValidating: false,
1577
- isSubmitted: false,
1578
- isSubmitting: false,
1579
- isSubmitSuccessful: false,
1580
- isValid: false,
1581
- touchedFields: {},
1582
- dirtyFields: {},
1583
- validatingFields: {},
1584
- errors: _options.errors || {},
1585
- disabled: _options.disabled || false,
1586
- };
1587
- let _fields = {};
1588
- let _defaultValues = isObject(_options.defaultValues) || isObject(_options.values)
1589
- ? cloneObject(_options.defaultValues || _options.values) || {}
1590
- : {};
1591
- let _formValues = _options.shouldUnregister
1592
- ? {}
1593
- : cloneObject(_defaultValues);
1594
- let _state = {
1595
- action: false,
1596
- mount: false,
1597
- watch: false,
1598
- };
1599
- let _names = {
1600
- mount: new Set(),
1601
- disabled: new Set(),
1602
- unMount: new Set(),
1603
- array: new Set(),
1604
- watch: new Set(),
1605
- };
1606
- let delayErrorCallback;
1607
- let timer = 0;
1608
- const _proxyFormState = {
1609
- isDirty: false,
1610
- dirtyFields: false,
1611
- validatingFields: false,
1612
- touchedFields: false,
1613
- isValidating: false,
1614
- isValid: false,
1615
- errors: false,
1616
- };
1617
- const _subjects = {
1618
- values: createSubject(),
1619
- array: createSubject(),
1620
- state: createSubject(),
1621
- };
1622
- const validationModeBeforeSubmit = getValidationModes(_options.mode);
1623
- const validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
1624
- const shouldDisplayAllAssociatedErrors = _options.criteriaMode === VALIDATION_MODE.all;
1625
- const debounce = (callback) => (wait) => {
1626
- clearTimeout(timer);
1627
- timer = setTimeout(callback, wait);
1483
+ const _runSchema = async (name) => {
1484
+ _updateIsValidating(name, true);
1485
+ const result = await _options.resolver(_formValues, _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation));
1486
+ _updateIsValidating(name);
1487
+ return result;
1628
1488
  };
1629
- const _updateValid = async (shouldUpdateValid) => {
1630
- if (!_options.disabled && (_proxyFormState.isValid || shouldUpdateValid)) {
1631
- const isValid = _options.resolver
1632
- ? isEmptyObject((await _executeSchema()).errors)
1633
- : await executeBuiltInValidation(_fields, true);
1634
- if (isValid !== _formState.isValid) {
1635
- _subjects.state.next({
1636
- isValid,
1637
- });
1489
+ const executeSchemaAndUpdateState = async (names) => {
1490
+ const { errors } = await _runSchema(names);
1491
+ if (names) {
1492
+ for (const name of names) {
1493
+ const error = get(errors, name);
1494
+ error
1495
+ ? set(_formState.errors, name, error)
1496
+ : unset(_formState.errors, name);
1638
1497
  }
1639
1498
  }
1499
+ else {
1500
+ _formState.errors = errors;
1501
+ }
1502
+ return errors;
1640
1503
  };
1641
- const _updateIsValidating = (names, isValidating) => {
1642
- if (!_options.disabled &&
1643
- (_proxyFormState.isValidating || _proxyFormState.validatingFields)) {
1644
- (names || Array.from(_names.mount)).forEach((name) => {
1645
- if (name) {
1646
- isValidating
1647
- ? set(_formState.validatingFields, name, isValidating)
1648
- : unset(_formState.validatingFields, name);
1504
+ const executeBuiltInValidation = async (fields, shouldOnlyCheckValid, context = {
1505
+ valid: true,
1506
+ }) => {
1507
+ for (const name in fields) {
1508
+ const field = fields[name];
1509
+ if (field) {
1510
+ const { _f, ...fieldValue } = field;
1511
+ if (_f) {
1512
+ const isFieldArrayRoot = _names.array.has(_f.name);
1513
+ const isPromiseFunction = field._f && hasPromiseValidation(field._f);
1514
+ if (isPromiseFunction && _proxyFormState.validatingFields) {
1515
+ _updateIsValidating([name], true);
1516
+ }
1517
+ const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !shouldOnlyCheckValid, isFieldArrayRoot);
1518
+ if (isPromiseFunction && _proxyFormState.validatingFields) {
1519
+ _updateIsValidating([name]);
1520
+ }
1521
+ if (fieldError[_f.name]) {
1522
+ context.valid = false;
1523
+ if (shouldOnlyCheckValid) {
1524
+ break;
1525
+ }
1526
+ }
1527
+ !shouldOnlyCheckValid &&
1528
+ (get(fieldError, _f.name)
1529
+ ? isFieldArrayRoot
1530
+ ? updateFieldArrayRootError(_formState.errors, fieldError, _f.name)
1531
+ : set(_formState.errors, _f.name, fieldError[_f.name])
1532
+ : unset(_formState.errors, _f.name));
1649
1533
  }
1650
- });
1651
- _subjects.state.next({
1652
- validatingFields: _formState.validatingFields,
1653
- isValidating: !isEmptyObject(_formState.validatingFields),
1654
- });
1534
+ !isEmptyObject(fieldValue) &&
1535
+ (await executeBuiltInValidation(fieldValue, shouldOnlyCheckValid, context));
1536
+ }
1655
1537
  }
1656
- };
1657
- const _updateFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndState = true) => {
1658
- if (args && method && !_options.disabled) {
1659
- _state.action = true;
1660
- if (shouldUpdateFieldsAndState && Array.isArray(get(_fields, name))) {
1661
- const fieldValues = method(get(_fields, name), args.argA, args.argB);
1662
- shouldSetValues && set(_fields, name, fieldValues);
1663
- }
1664
- if (shouldUpdateFieldsAndState &&
1665
- Array.isArray(get(_formState.errors, name))) {
1666
- const errors = method(get(_formState.errors, name), args.argA, args.argB);
1667
- shouldSetValues && set(_formState.errors, name, errors);
1668
- unsetEmptyArray(_formState.errors, name);
1669
- }
1670
- if (_proxyFormState.touchedFields &&
1671
- shouldUpdateFieldsAndState &&
1672
- Array.isArray(get(_formState.touchedFields, name))) {
1673
- const touchedFields = method(get(_formState.touchedFields, name), args.argA, args.argB);
1674
- shouldSetValues && set(_formState.touchedFields, name, touchedFields);
1675
- }
1676
- if (_proxyFormState.dirtyFields) {
1677
- _formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
1678
- }
1679
- _subjects.state.next({
1680
- name,
1681
- isDirty: _getDirty(name, values),
1682
- dirtyFields: _formState.dirtyFields,
1683
- errors: _formState.errors,
1684
- isValid: _formState.isValid,
1685
- });
1686
- }
1687
- else {
1688
- set(_formValues, name, values);
1689
- }
1690
- };
1691
- const updateErrors = (name, error) => {
1692
- set(_formState.errors, name, error);
1693
- _subjects.state.next({
1694
- errors: _formState.errors,
1695
- });
1696
- };
1697
- const _setErrors = (errors) => {
1698
- _formState.errors = errors;
1699
- _subjects.state.next({
1700
- errors: _formState.errors,
1701
- isValid: false,
1702
- });
1703
- };
1704
- const updateValidAndValue = (name, shouldSkipSetValueAs, value, ref) => {
1705
- const field = get(_fields, name);
1706
- if (field) {
1707
- const defaultValue = get(_formValues, name, isUndefined(value) ? get(_defaultValues, name) : value);
1708
- isUndefined(defaultValue) ||
1709
- (ref && ref.defaultChecked) ||
1710
- shouldSkipSetValueAs
1711
- ? set(_formValues, name, shouldSkipSetValueAs ? defaultValue : getFieldValue(field._f))
1712
- : setFieldValue(name, defaultValue);
1713
- _state.mount && _updateValid();
1714
- }
1715
- };
1716
- const updateTouchAndDirty = (name, fieldValue, isBlurEvent, shouldDirty, shouldRender) => {
1717
- let shouldUpdateField = false;
1718
- let isPreviousDirty = false;
1719
- const output = {
1720
- name,
1721
- };
1722
- if (!_options.disabled) {
1723
- const disabledField = !!(get(_fields, name) &&
1724
- get(_fields, name)._f &&
1725
- get(_fields, name)._f.disabled);
1726
- if (!isBlurEvent || shouldDirty) {
1727
- if (_proxyFormState.isDirty) {
1728
- isPreviousDirty = _formState.isDirty;
1729
- _formState.isDirty = output.isDirty = _getDirty();
1730
- shouldUpdateField = isPreviousDirty !== output.isDirty;
1731
- }
1732
- const isCurrentFieldPristine = disabledField || deepEqual(get(_defaultValues, name), fieldValue);
1733
- isPreviousDirty = !!(!disabledField && get(_formState.dirtyFields, name));
1734
- isCurrentFieldPristine || disabledField
1735
- ? unset(_formState.dirtyFields, name)
1736
- : set(_formState.dirtyFields, name, true);
1737
- output.dirtyFields = _formState.dirtyFields;
1738
- shouldUpdateField =
1739
- shouldUpdateField ||
1740
- (_proxyFormState.dirtyFields &&
1741
- isPreviousDirty !== !isCurrentFieldPristine);
1742
- }
1743
- if (isBlurEvent) {
1744
- const isPreviousFieldTouched = get(_formState.touchedFields, name);
1745
- if (!isPreviousFieldTouched) {
1746
- set(_formState.touchedFields, name, isBlurEvent);
1747
- output.touchedFields = _formState.touchedFields;
1748
- shouldUpdateField =
1749
- shouldUpdateField ||
1750
- (_proxyFormState.touchedFields &&
1751
- isPreviousFieldTouched !== isBlurEvent);
1752
- }
1753
- }
1754
- shouldUpdateField && shouldRender && _subjects.state.next(output);
1755
- }
1756
- return shouldUpdateField ? output : {};
1757
- };
1758
- const shouldRenderByError = (name, isValid, error, fieldState) => {
1759
- const previousFieldError = get(_formState.errors, name);
1760
- const shouldUpdateValid = _proxyFormState.isValid &&
1761
- isBoolean(isValid) &&
1762
- _formState.isValid !== isValid;
1763
- if (_options.delayError && error) {
1764
- delayErrorCallback = debounce(() => updateErrors(name, error));
1765
- delayErrorCallback(_options.delayError);
1766
- }
1767
- else {
1768
- clearTimeout(timer);
1769
- delayErrorCallback = null;
1770
- error
1771
- ? set(_formState.errors, name, error)
1772
- : unset(_formState.errors, name);
1773
- }
1774
- if ((error ? !deepEqual(previousFieldError, error) : previousFieldError) ||
1775
- !isEmptyObject(fieldState) ||
1776
- shouldUpdateValid) {
1777
- const updatedFormState = {
1778
- ...fieldState,
1779
- ...(shouldUpdateValid && isBoolean(isValid) ? { isValid } : {}),
1780
- errors: _formState.errors,
1781
- name,
1782
- };
1783
- _formState = {
1784
- ..._formState,
1785
- ...updatedFormState,
1786
- };
1787
- _subjects.state.next(updatedFormState);
1788
- }
1789
- };
1790
- const _executeSchema = async (name) => {
1791
- _updateIsValidating(name, true);
1792
- const result = await _options.resolver(_formValues, _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation));
1793
- _updateIsValidating(name);
1794
- return result;
1795
- };
1796
- const executeSchemaAndUpdateState = async (names) => {
1797
- const { errors } = await _executeSchema(names);
1798
- if (names) {
1799
- for (const name of names) {
1800
- const error = get(errors, name);
1801
- error
1802
- ? set(_formState.errors, name, error)
1803
- : unset(_formState.errors, name);
1804
- }
1805
- }
1806
- else {
1807
- _formState.errors = errors;
1808
- }
1809
- return errors;
1810
- };
1811
- const executeBuiltInValidation = async (fields, shouldOnlyCheckValid, context = {
1812
- valid: true,
1813
- }) => {
1814
- for (const name in fields) {
1815
- const field = fields[name];
1816
- if (field) {
1817
- const { _f, ...fieldValue } = field;
1818
- if (_f) {
1819
- const isFieldArrayRoot = _names.array.has(_f.name);
1820
- const isPromiseFunction = field._f && hasPromiseValidation(field._f);
1821
- if (isPromiseFunction && _proxyFormState.validatingFields) {
1822
- _updateIsValidating([name], true);
1823
- }
1824
- const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !shouldOnlyCheckValid, isFieldArrayRoot);
1825
- if (isPromiseFunction && _proxyFormState.validatingFields) {
1826
- _updateIsValidating([name]);
1827
- }
1828
- if (fieldError[_f.name]) {
1829
- context.valid = false;
1830
- if (shouldOnlyCheckValid) {
1831
- break;
1832
- }
1833
- }
1834
- !shouldOnlyCheckValid &&
1835
- (get(fieldError, _f.name)
1836
- ? isFieldArrayRoot
1837
- ? updateFieldArrayRootError(_formState.errors, fieldError, _f.name)
1838
- : set(_formState.errors, _f.name, fieldError[_f.name])
1839
- : unset(_formState.errors, _f.name));
1840
- }
1841
- !isEmptyObject(fieldValue) &&
1842
- (await executeBuiltInValidation(fieldValue, shouldOnlyCheckValid, context));
1843
- }
1844
- }
1845
- return context.valid;
1538
+ return context.valid;
1846
1539
  };
1847
1540
  const _removeUnmounted = () => {
1848
1541
  for (const name of _names.unMount) {
@@ -1903,7 +1596,7 @@ function createFormControl(props = {}) {
1903
1596
  else {
1904
1597
  fieldReference.ref.value = fieldValue;
1905
1598
  if (!fieldReference.ref.type) {
1906
- _subjects.values.next({
1599
+ _subjects.state.next({
1907
1600
  name,
1908
1601
  values: { ..._formValues },
1909
1602
  });
@@ -1938,7 +1631,10 @@ function createFormControl(props = {}) {
1938
1631
  name,
1939
1632
  values: { ..._formValues },
1940
1633
  });
1941
- if ((_proxyFormState.isDirty || _proxyFormState.dirtyFields) &&
1634
+ if ((_proxyFormState.isDirty ||
1635
+ _proxyFormState.dirtyFields ||
1636
+ _proxySubscribeFormState.isDirty ||
1637
+ _proxySubscribeFormState.dirtyFields) &&
1942
1638
  options.shouldDirty) {
1943
1639
  _subjects.state.next({
1944
1640
  name,
@@ -1953,7 +1649,7 @@ function createFormControl(props = {}) {
1953
1649
  : setFieldValue(name, cloneValue, options);
1954
1650
  }
1955
1651
  isWatched(name, _names) && _subjects.state.next({ ..._formState });
1956
- _subjects.values.next({
1652
+ _subjects.state.next({
1957
1653
  name: _state.mount ? name : undefined,
1958
1654
  values: { ..._formValues },
1959
1655
  });
@@ -1964,7 +1660,6 @@ function createFormControl(props = {}) {
1964
1660
  let name = target.name;
1965
1661
  let isFieldValueUpdated = true;
1966
1662
  const field = get(_fields, name);
1967
- const getCurrentFieldValue = () => target.type ? getFieldValue(field._f) : getEventValue(event);
1968
1663
  const _updateIsFieldValueUpdated = (fieldValue) => {
1969
1664
  isFieldValueUpdated =
1970
1665
  Number.isNaN(fieldValue) ||
@@ -1974,7 +1669,9 @@ function createFormControl(props = {}) {
1974
1669
  if (field) {
1975
1670
  let error;
1976
1671
  let isValid;
1977
- const fieldValue = getCurrentFieldValue();
1672
+ const fieldValue = target.type
1673
+ ? getFieldValue(field._f)
1674
+ : getEventValue(event);
1978
1675
  const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
1979
1676
  const shouldSkipValidation = (!hasValidation(field._f) &&
1980
1677
  !_options.resolver &&
@@ -1990,21 +1687,21 @@ function createFormControl(props = {}) {
1990
1687
  else if (field._f.onChange) {
1991
1688
  field._f.onChange(event);
1992
1689
  }
1993
- const fieldState = updateTouchAndDirty(name, fieldValue, isBlurEvent, false);
1690
+ const fieldState = updateTouchAndDirty(name, fieldValue, isBlurEvent);
1994
1691
  const shouldRender = !isEmptyObject(fieldState) || watched;
1995
1692
  !isBlurEvent &&
1996
- _subjects.values.next({
1693
+ _subjects.state.next({
1997
1694
  name,
1998
1695
  type: event.type,
1999
1696
  values: { ..._formValues },
2000
1697
  });
2001
1698
  if (shouldSkipValidation) {
2002
- if (_proxyFormState.isValid) {
1699
+ if (_proxyFormState.isValid || _proxySubscribeFormState.isValid) {
2003
1700
  if (_options.mode === 'onBlur' && isBlurEvent) {
2004
- _updateValid();
1701
+ _setValid();
2005
1702
  }
2006
1703
  else if (!isBlurEvent) {
2007
- _updateValid();
1704
+ _setValid();
2008
1705
  }
2009
1706
  }
2010
1707
  return (shouldRender &&
@@ -2012,7 +1709,7 @@ function createFormControl(props = {}) {
2012
1709
  }
2013
1710
  !isBlurEvent && watched && _subjects.state.next({ ..._formState });
2014
1711
  if (_options.resolver) {
2015
- const { errors } = await _executeSchema([name]);
1712
+ const { errors } = await _runSchema([name]);
2016
1713
  _updateIsFieldValueUpdated(fieldValue);
2017
1714
  if (isFieldValueUpdated) {
2018
1715
  const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name);
@@ -2031,7 +1728,8 @@ function createFormControl(props = {}) {
2031
1728
  if (error) {
2032
1729
  isValid = false;
2033
1730
  }
2034
- else if (_proxyFormState.isValid) {
1731
+ else if (_proxyFormState.isValid ||
1732
+ _proxySubscribeFormState.isValid) {
2035
1733
  isValid = await executeBuiltInValidation(_fields, true);
2036
1734
  }
2037
1735
  }
@@ -2066,14 +1764,15 @@ function createFormControl(props = {}) {
2066
1764
  const field = get(_fields, fieldName);
2067
1765
  return await executeBuiltInValidation(field && field._f ? { [fieldName]: field } : field);
2068
1766
  }))).every(Boolean);
2069
- !(!validationResult && !_formState.isValid) && _updateValid();
1767
+ !(!validationResult && !_formState.isValid) && _setValid();
2070
1768
  }
2071
1769
  else {
2072
1770
  validationResult = isValid = await executeBuiltInValidation(_fields);
2073
1771
  }
2074
1772
  _subjects.state.next({
2075
1773
  ...(!isString(name) ||
2076
- (_proxyFormState.isValid && isValid !== _formState.isValid)
1774
+ ((_proxyFormState.isValid || _proxySubscribeFormState.isValid) &&
1775
+ isValid !== _formState.isValid)
2077
1776
  ? {}
2078
1777
  : { name }),
2079
1778
  ...(_options.resolver || !name ? { isValid } : {}),
@@ -2126,10 +1825,33 @@ function createFormControl(props = {}) {
2126
1825
  options && options.shouldFocus && ref && ref.focus && ref.focus();
2127
1826
  };
2128
1827
  const watch = (name, defaultValue) => isFunction(name)
2129
- ? _subjects.values.subscribe({
1828
+ ? _subjects.state.subscribe({
2130
1829
  next: (payload) => name(_getWatch(undefined, defaultValue), payload),
2131
1830
  })
2132
1831
  : _getWatch(name, defaultValue, true);
1832
+ const _subscribe = (props) => _subjects.state.subscribe({
1833
+ next: (formState) => {
1834
+ if (shouldSubscribeByName(props.name, formState.name, props.exact) &&
1835
+ shouldRenderFormState(formState, props.formState || _proxyFormState, _setFormState, props.reRenderRoot)) {
1836
+ props.callback({
1837
+ values: _formValues,
1838
+ ..._formState,
1839
+ ...formState,
1840
+ });
1841
+ }
1842
+ },
1843
+ }).unsubscribe;
1844
+ const subscribe = (props) => {
1845
+ _state.mount = true;
1846
+ _proxySubscribeFormState = {
1847
+ ..._proxySubscribeFormState,
1848
+ ...props.formState,
1849
+ };
1850
+ return _subscribe({
1851
+ ...props,
1852
+ formState: _proxySubscribeFormState,
1853
+ });
1854
+ };
2133
1855
  const unregister = (name, options = {}) => {
2134
1856
  for (const fieldName of name ? convertToArrayPayload(name) : _names.mount) {
2135
1857
  _names.mount.delete(fieldName);
@@ -2147,409 +1869,709 @@ function createFormControl(props = {}) {
2147
1869
  !options.keepDefaultValue &&
2148
1870
  unset(_defaultValues, fieldName);
2149
1871
  }
2150
- _subjects.values.next({
1872
+ _subjects.state.next({
2151
1873
  values: { ..._formValues },
2152
1874
  });
2153
1875
  _subjects.state.next({
2154
1876
  ..._formState,
2155
1877
  ...(!options.keepDirty ? {} : { isDirty: _getDirty() }),
2156
1878
  });
2157
- !options.keepIsValid && _updateValid();
2158
- };
2159
- const _updateDisabledField = ({ disabled, name, field, fields, }) => {
2160
- if ((isBoolean(disabled) && _state.mount) ||
2161
- !!disabled ||
2162
- _names.disabled.has(name)) {
2163
- disabled ? _names.disabled.add(name) : _names.disabled.delete(name);
2164
- updateTouchAndDirty(name, getFieldValue(field ? field._f : get(fields, name)._f), false, false, true);
2165
- }
1879
+ !options.keepIsValid && _setValid();
1880
+ };
1881
+ const _setDisabledField = ({ disabled, name, field, fields, }) => {
1882
+ if ((isBoolean(disabled) && _state.mount) ||
1883
+ !!disabled ||
1884
+ _names.disabled.has(name)) {
1885
+ disabled ? _names.disabled.add(name) : _names.disabled.delete(name);
1886
+ updateTouchAndDirty(name, getFieldValue(field ? field._f : get(fields, name)._f), false, false, true);
1887
+ }
1888
+ };
1889
+ const register = (name, options = {}) => {
1890
+ let field = get(_fields, name);
1891
+ const disabledIsDefined = isBoolean(options.disabled) || isBoolean(_options.disabled);
1892
+ set(_fields, name, {
1893
+ ...(field || {}),
1894
+ _f: {
1895
+ ...(field && field._f ? field._f : { ref: { name } }),
1896
+ name,
1897
+ mount: true,
1898
+ ...options,
1899
+ },
1900
+ });
1901
+ _names.mount.add(name);
1902
+ if (field) {
1903
+ _setDisabledField({
1904
+ field,
1905
+ disabled: isBoolean(options.disabled)
1906
+ ? options.disabled
1907
+ : _options.disabled,
1908
+ name,
1909
+ });
1910
+ }
1911
+ else {
1912
+ updateValidAndValue(name, true, options.value);
1913
+ }
1914
+ return {
1915
+ ...(disabledIsDefined
1916
+ ? { disabled: options.disabled || _options.disabled }
1917
+ : {}),
1918
+ ...(_options.progressive
1919
+ ? {
1920
+ required: !!options.required,
1921
+ min: getRuleValue(options.min),
1922
+ max: getRuleValue(options.max),
1923
+ minLength: getRuleValue(options.minLength),
1924
+ maxLength: getRuleValue(options.maxLength),
1925
+ pattern: getRuleValue(options.pattern),
1926
+ }
1927
+ : {}),
1928
+ name,
1929
+ onChange,
1930
+ onBlur: onChange,
1931
+ ref: (ref) => {
1932
+ if (ref) {
1933
+ register(name, options);
1934
+ field = get(_fields, name);
1935
+ const fieldRef = isUndefined(ref.value)
1936
+ ? ref.querySelectorAll
1937
+ ? ref.querySelectorAll('input,select,textarea')[0] || ref
1938
+ : ref
1939
+ : ref;
1940
+ const radioOrCheckbox = isRadioOrCheckbox(fieldRef);
1941
+ const refs = field._f.refs || [];
1942
+ if (radioOrCheckbox
1943
+ ? refs.find((option) => option === fieldRef)
1944
+ : fieldRef === field._f.ref) {
1945
+ return;
1946
+ }
1947
+ set(_fields, name, {
1948
+ _f: {
1949
+ ...field._f,
1950
+ ...(radioOrCheckbox
1951
+ ? {
1952
+ refs: [
1953
+ ...refs.filter(live),
1954
+ fieldRef,
1955
+ ...(Array.isArray(get(_defaultValues, name)) ? [{}] : []),
1956
+ ],
1957
+ ref: { type: fieldRef.type, name },
1958
+ }
1959
+ : { ref: fieldRef }),
1960
+ },
1961
+ });
1962
+ updateValidAndValue(name, false, undefined, fieldRef);
1963
+ }
1964
+ else {
1965
+ field = get(_fields, name, {});
1966
+ if (field._f) {
1967
+ field._f.mount = false;
1968
+ }
1969
+ (_options.shouldUnregister || options.shouldUnregister) &&
1970
+ !(isNameInFieldArray(_names.array, name) && _state.action) &&
1971
+ _names.unMount.add(name);
1972
+ }
1973
+ },
1974
+ };
1975
+ };
1976
+ const _focusError = () => _options.shouldFocusError &&
1977
+ iterateFieldsByAction(_fields, _focusInput, _names.mount);
1978
+ const _disableForm = (disabled) => {
1979
+ if (isBoolean(disabled)) {
1980
+ _subjects.state.next({ disabled });
1981
+ iterateFieldsByAction(_fields, (ref, name) => {
1982
+ const currentField = get(_fields, name);
1983
+ if (currentField) {
1984
+ ref.disabled = currentField._f.disabled || disabled;
1985
+ if (Array.isArray(currentField._f.refs)) {
1986
+ currentField._f.refs.forEach((inputRef) => {
1987
+ inputRef.disabled = currentField._f.disabled || disabled;
1988
+ });
1989
+ }
1990
+ }
1991
+ }, 0, false);
1992
+ }
1993
+ };
1994
+ const handleSubmit = (onValid, onInvalid) => async (e) => {
1995
+ let onValidError = undefined;
1996
+ if (e) {
1997
+ e.preventDefault && e.preventDefault();
1998
+ e.persist && e.persist();
1999
+ }
2000
+ let fieldValues = cloneObject(_formValues);
2001
+ if (_names.disabled.size) {
2002
+ for (const name of _names.disabled) {
2003
+ set(fieldValues, name, undefined);
2004
+ }
2005
+ }
2006
+ _subjects.state.next({
2007
+ isSubmitting: true,
2008
+ });
2009
+ if (_options.resolver) {
2010
+ const { errors, values } = await _runSchema();
2011
+ _formState.errors = errors;
2012
+ fieldValues = values;
2013
+ }
2014
+ else {
2015
+ await executeBuiltInValidation(_fields);
2016
+ }
2017
+ unset(_formState.errors, 'root');
2018
+ if (isEmptyObject(_formState.errors)) {
2019
+ _subjects.state.next({
2020
+ errors: {},
2021
+ });
2022
+ try {
2023
+ await onValid(fieldValues, e);
2024
+ }
2025
+ catch (error) {
2026
+ onValidError = error;
2027
+ }
2028
+ }
2029
+ else {
2030
+ if (onInvalid) {
2031
+ await onInvalid({ ..._formState.errors }, e);
2032
+ }
2033
+ _focusError();
2034
+ setTimeout(_focusError);
2035
+ }
2036
+ _subjects.state.next({
2037
+ isSubmitted: true,
2038
+ isSubmitting: false,
2039
+ isSubmitSuccessful: isEmptyObject(_formState.errors) && !onValidError,
2040
+ submitCount: _formState.submitCount + 1,
2041
+ errors: _formState.errors,
2042
+ });
2043
+ if (onValidError) {
2044
+ throw onValidError;
2045
+ }
2046
+ };
2047
+ const resetField = (name, options = {}) => {
2048
+ if (get(_fields, name)) {
2049
+ if (isUndefined(options.defaultValue)) {
2050
+ setValue(name, cloneObject(get(_defaultValues, name)));
2051
+ }
2052
+ else {
2053
+ setValue(name, options.defaultValue);
2054
+ set(_defaultValues, name, cloneObject(options.defaultValue));
2055
+ }
2056
+ if (!options.keepTouched) {
2057
+ unset(_formState.touchedFields, name);
2058
+ }
2059
+ if (!options.keepDirty) {
2060
+ unset(_formState.dirtyFields, name);
2061
+ _formState.isDirty = options.defaultValue
2062
+ ? _getDirty(name, cloneObject(get(_defaultValues, name)))
2063
+ : _getDirty();
2064
+ }
2065
+ if (!options.keepError) {
2066
+ unset(_formState.errors, name);
2067
+ _proxyFormState.isValid && _setValid();
2068
+ }
2069
+ _subjects.state.next({ ..._formState });
2070
+ }
2071
+ };
2072
+ const _reset = (formValues, keepStateOptions = {}) => {
2073
+ const updatedValues = formValues ? cloneObject(formValues) : _defaultValues;
2074
+ const cloneUpdatedValues = cloneObject(updatedValues);
2075
+ const isEmptyResetValues = isEmptyObject(formValues);
2076
+ const values = isEmptyResetValues ? _defaultValues : cloneUpdatedValues;
2077
+ if (!keepStateOptions.keepDefaultValues) {
2078
+ _defaultValues = updatedValues;
2079
+ }
2080
+ if (!keepStateOptions.keepValues) {
2081
+ if (keepStateOptions.keepDirtyValues) {
2082
+ const fieldsToCheck = new Set([
2083
+ ..._names.mount,
2084
+ ...Object.keys(getDirtyFields(_defaultValues, _formValues)),
2085
+ ]);
2086
+ for (const fieldName of Array.from(fieldsToCheck)) {
2087
+ get(_formState.dirtyFields, fieldName)
2088
+ ? set(values, fieldName, get(_formValues, fieldName))
2089
+ : setValue(fieldName, get(values, fieldName));
2090
+ }
2091
+ }
2092
+ else {
2093
+ if (isWeb && isUndefined(formValues)) {
2094
+ for (const name of _names.mount) {
2095
+ const field = get(_fields, name);
2096
+ if (field && field._f) {
2097
+ const fieldReference = Array.isArray(field._f.refs)
2098
+ ? field._f.refs[0]
2099
+ : field._f.ref;
2100
+ if (isHTMLElement(fieldReference)) {
2101
+ const form = fieldReference.closest('form');
2102
+ if (form) {
2103
+ form.reset();
2104
+ break;
2105
+ }
2106
+ }
2107
+ }
2108
+ }
2109
+ }
2110
+ _fields = {};
2111
+ }
2112
+ _formValues = _options.shouldUnregister
2113
+ ? keepStateOptions.keepDefaultValues
2114
+ ? cloneObject(_defaultValues)
2115
+ : {}
2116
+ : cloneObject(values);
2117
+ _subjects.array.next({
2118
+ values: { ...values },
2119
+ });
2120
+ _subjects.state.next({
2121
+ values: { ...values },
2122
+ });
2123
+ }
2124
+ _names = {
2125
+ mount: keepStateOptions.keepDirtyValues ? _names.mount : new Set(),
2126
+ unMount: new Set(),
2127
+ array: new Set(),
2128
+ disabled: new Set(),
2129
+ watch: new Set(),
2130
+ watchAll: false,
2131
+ focus: '',
2132
+ };
2133
+ _state.mount =
2134
+ !_proxyFormState.isValid ||
2135
+ !!keepStateOptions.keepIsValid ||
2136
+ !!keepStateOptions.keepDirtyValues;
2137
+ _state.watch = !!_options.shouldUnregister;
2138
+ _subjects.state.next({
2139
+ submitCount: keepStateOptions.keepSubmitCount
2140
+ ? _formState.submitCount
2141
+ : 0,
2142
+ isDirty: isEmptyResetValues
2143
+ ? false
2144
+ : keepStateOptions.keepDirty
2145
+ ? _formState.isDirty
2146
+ : !!(keepStateOptions.keepDefaultValues &&
2147
+ !deepEqual(formValues, _defaultValues)),
2148
+ isSubmitted: keepStateOptions.keepIsSubmitted
2149
+ ? _formState.isSubmitted
2150
+ : false,
2151
+ dirtyFields: isEmptyResetValues
2152
+ ? {}
2153
+ : keepStateOptions.keepDirtyValues
2154
+ ? keepStateOptions.keepDefaultValues && _formValues
2155
+ ? getDirtyFields(_defaultValues, _formValues)
2156
+ : _formState.dirtyFields
2157
+ : keepStateOptions.keepDefaultValues && formValues
2158
+ ? getDirtyFields(_defaultValues, formValues)
2159
+ : keepStateOptions.keepDirty
2160
+ ? _formState.dirtyFields
2161
+ : {},
2162
+ touchedFields: keepStateOptions.keepTouched
2163
+ ? _formState.touchedFields
2164
+ : {},
2165
+ errors: keepStateOptions.keepErrors ? _formState.errors : {},
2166
+ isSubmitSuccessful: keepStateOptions.keepIsSubmitSuccessful
2167
+ ? _formState.isSubmitSuccessful
2168
+ : false,
2169
+ isSubmitting: false,
2170
+ });
2171
+ };
2172
+ const reset = (formValues, keepStateOptions) => _reset(isFunction(formValues)
2173
+ ? formValues(_formValues)
2174
+ : formValues, keepStateOptions);
2175
+ const setFocus = (name, options = {}) => {
2176
+ const field = get(_fields, name);
2177
+ const fieldReference = field && field._f;
2178
+ if (fieldReference) {
2179
+ const fieldRef = fieldReference.refs
2180
+ ? fieldReference.refs[0]
2181
+ : fieldReference.ref;
2182
+ if (fieldRef.focus) {
2183
+ fieldRef.focus();
2184
+ options.shouldSelect &&
2185
+ isFunction(fieldRef.select) &&
2186
+ fieldRef.select();
2187
+ }
2188
+ }
2189
+ };
2190
+ const _setFormState = (updatedFormState) => {
2191
+ _formState = {
2192
+ ..._formState,
2193
+ ...updatedFormState,
2194
+ };
2195
+ };
2196
+ const _resetDefaultValues = () => isFunction(_options.defaultValues) &&
2197
+ _options.defaultValues().then((values) => {
2198
+ reset(values, _options.resetOptions);
2199
+ _subjects.state.next({
2200
+ isLoading: false,
2201
+ });
2202
+ });
2203
+ const methods = {
2204
+ control: {
2205
+ register,
2206
+ unregister,
2207
+ getFieldState,
2208
+ handleSubmit,
2209
+ setError,
2210
+ _subscribe,
2211
+ _runSchema,
2212
+ _getWatch,
2213
+ _getDirty,
2214
+ _setValid,
2215
+ _setFieldArray,
2216
+ _setDisabledField,
2217
+ _setErrors,
2218
+ _getFieldArray,
2219
+ _reset,
2220
+ _resetDefaultValues,
2221
+ _removeUnmounted,
2222
+ _disableForm,
2223
+ _subjects,
2224
+ _proxyFormState,
2225
+ get _fields() {
2226
+ return _fields;
2227
+ },
2228
+ get _formValues() {
2229
+ return _formValues;
2230
+ },
2231
+ get _state() {
2232
+ return _state;
2233
+ },
2234
+ set _state(value) {
2235
+ _state = value;
2236
+ },
2237
+ get _defaultValues() {
2238
+ return _defaultValues;
2239
+ },
2240
+ get _names() {
2241
+ return _names;
2242
+ },
2243
+ set _names(value) {
2244
+ _names = value;
2245
+ },
2246
+ get _formState() {
2247
+ return _formState;
2248
+ },
2249
+ get _options() {
2250
+ return _options;
2251
+ },
2252
+ set _options(value) {
2253
+ _options = {
2254
+ ..._options,
2255
+ ...value,
2256
+ };
2257
+ },
2258
+ },
2259
+ subscribe,
2260
+ trigger,
2261
+ register,
2262
+ handleSubmit,
2263
+ watch,
2264
+ setValue,
2265
+ getValues,
2266
+ reset,
2267
+ resetField,
2268
+ clearErrors,
2269
+ unregister,
2270
+ setError,
2271
+ setFocus,
2272
+ getFieldState,
2273
+ };
2274
+ return {
2275
+ ...methods,
2276
+ formControl: methods,
2277
+ };
2278
+ }
2279
+
2280
+ var generateId = () => {
2281
+ const d = typeof performance === 'undefined' ? Date.now() : performance.now() * 1000;
2282
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
2283
+ const r = (Math.random() * 16 + d) % 16 | 0;
2284
+ return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16);
2285
+ });
2286
+ };
2287
+
2288
+ var getFocusFieldName = (name, index, options = {}) => options.shouldFocus || isUndefined(options.shouldFocus)
2289
+ ? options.focusName ||
2290
+ `${name}.${isUndefined(options.focusIndex) ? index : options.focusIndex}.`
2291
+ : '';
2292
+
2293
+ var appendAt = (data, value) => [
2294
+ ...data,
2295
+ ...convertToArrayPayload(value),
2296
+ ];
2297
+
2298
+ var fillEmptyArray = (value) => Array.isArray(value) ? value.map(() => undefined) : undefined;
2299
+
2300
+ function insert(data, index, value) {
2301
+ return [
2302
+ ...data.slice(0, index),
2303
+ ...convertToArrayPayload(value),
2304
+ ...data.slice(index),
2305
+ ];
2306
+ }
2307
+
2308
+ var moveArrayAt = (data, from, to) => {
2309
+ if (!Array.isArray(data)) {
2310
+ return [];
2311
+ }
2312
+ if (isUndefined(data[to])) {
2313
+ data[to] = undefined;
2314
+ }
2315
+ data.splice(to, 0, data.splice(from, 1)[0]);
2316
+ return data;
2317
+ };
2318
+
2319
+ var prependAt = (data, value) => [
2320
+ ...convertToArrayPayload(value),
2321
+ ...convertToArrayPayload(data),
2322
+ ];
2323
+
2324
+ function removeAtIndexes(data, indexes) {
2325
+ let i = 0;
2326
+ const temp = [...data];
2327
+ for (const index of indexes) {
2328
+ temp.splice(index - i, 1);
2329
+ i++;
2330
+ }
2331
+ return compact(temp).length ? temp : [];
2332
+ }
2333
+ var removeArrayAt = (data, index) => isUndefined(index)
2334
+ ? []
2335
+ : removeAtIndexes(data, convertToArrayPayload(index).sort((a, b) => a - b));
2336
+
2337
+ var swapArrayAt = (data, indexA, indexB) => {
2338
+ [data[indexA], data[indexB]] = [data[indexB], data[indexA]];
2339
+ };
2340
+
2341
+ var updateAt = (fieldValues, index, value) => {
2342
+ fieldValues[index] = value;
2343
+ return fieldValues;
2344
+ };
2345
+
2346
+ /**
2347
+ * A custom hook that exposes convenient methods to perform operations with a list of dynamic inputs that need to be appended, updated, removed etc. • [Demo](https://codesandbox.io/s/react-hook-form-usefieldarray-ssugn) • [Video](https://youtu.be/4MrbfGSFY2A)
2348
+ *
2349
+ * @remarks
2350
+ * [API](https://react-hook-form.com/docs/usefieldarray) • [Demo](https://codesandbox.io/s/react-hook-form-usefieldarray-ssugn)
2351
+ *
2352
+ * @param props - useFieldArray props
2353
+ *
2354
+ * @returns methods - functions to manipulate with the Field Arrays (dynamic inputs) {@link UseFieldArrayReturn}
2355
+ *
2356
+ * @example
2357
+ * ```tsx
2358
+ * function App() {
2359
+ * const { register, control, handleSubmit, reset, trigger, setError } = useForm({
2360
+ * defaultValues: {
2361
+ * test: []
2362
+ * }
2363
+ * });
2364
+ * const { fields, append } = useFieldArray({
2365
+ * control,
2366
+ * name: "test"
2367
+ * });
2368
+ *
2369
+ * return (
2370
+ * <form onSubmit={handleSubmit(data => console.log(data))}>
2371
+ * {fields.map((item, index) => (
2372
+ * <input key={item.id} {...register(`test.${index}.firstName`)} />
2373
+ * ))}
2374
+ * <button type="button" onClick={() => append({ firstName: "bill" })}>
2375
+ * append
2376
+ * </button>
2377
+ * <input type="submit" />
2378
+ * </form>
2379
+ * );
2380
+ * }
2381
+ * ```
2382
+ */
2383
+ function useFieldArray(props) {
2384
+ const methods = useFormContext();
2385
+ const { control = methods.control, name, keyName = 'id', shouldUnregister, rules, } = props;
2386
+ const [fields, setFields] = React.useState(control._getFieldArray(name));
2387
+ const ids = React.useRef(control._getFieldArray(name).map(generateId));
2388
+ const _fieldIds = React.useRef(fields);
2389
+ const _name = React.useRef(name);
2390
+ const _actioned = React.useRef(false);
2391
+ _name.current = name;
2392
+ _fieldIds.current = fields;
2393
+ control._names.array.add(name);
2394
+ rules &&
2395
+ control.register(name, rules);
2396
+ React.useEffect(() => control._subjects.array.subscribe({
2397
+ next: ({ values, name: fieldArrayName, }) => {
2398
+ if (fieldArrayName === _name.current || !fieldArrayName) {
2399
+ const fieldValues = get(values, _name.current);
2400
+ if (Array.isArray(fieldValues)) {
2401
+ setFields(fieldValues);
2402
+ ids.current = fieldValues.map(generateId);
2403
+ }
2404
+ }
2405
+ },
2406
+ }).unsubscribe, [control]);
2407
+ const updateValues = React.useCallback((updatedFieldArrayValues) => {
2408
+ _actioned.current = true;
2409
+ control._setFieldArray(name, updatedFieldArrayValues);
2410
+ }, [control, name]);
2411
+ const append = (value, options) => {
2412
+ const appendValue = convertToArrayPayload(cloneObject(value));
2413
+ const updatedFieldArrayValues = appendAt(control._getFieldArray(name), appendValue);
2414
+ control._names.focus = getFocusFieldName(name, updatedFieldArrayValues.length - 1, options);
2415
+ ids.current = appendAt(ids.current, appendValue.map(generateId));
2416
+ updateValues(updatedFieldArrayValues);
2417
+ setFields(updatedFieldArrayValues);
2418
+ control._setFieldArray(name, updatedFieldArrayValues, appendAt, {
2419
+ argA: fillEmptyArray(value),
2420
+ });
2166
2421
  };
2167
- const register = (name, options = {}) => {
2168
- let field = get(_fields, name);
2169
- const disabledIsDefined = isBoolean(options.disabled) || isBoolean(_options.disabled);
2170
- set(_fields, name, {
2171
- ...(field || {}),
2172
- _f: {
2173
- ...(field && field._f ? field._f : { ref: { name } }),
2174
- name,
2175
- mount: true,
2176
- ...options,
2177
- },
2422
+ const prepend = (value, options) => {
2423
+ const prependValue = convertToArrayPayload(cloneObject(value));
2424
+ const updatedFieldArrayValues = prependAt(control._getFieldArray(name), prependValue);
2425
+ control._names.focus = getFocusFieldName(name, 0, options);
2426
+ ids.current = prependAt(ids.current, prependValue.map(generateId));
2427
+ updateValues(updatedFieldArrayValues);
2428
+ setFields(updatedFieldArrayValues);
2429
+ control._setFieldArray(name, updatedFieldArrayValues, prependAt, {
2430
+ argA: fillEmptyArray(value),
2178
2431
  });
2179
- _names.mount.add(name);
2180
- if (field) {
2181
- _updateDisabledField({
2182
- field,
2183
- disabled: isBoolean(options.disabled)
2184
- ? options.disabled
2185
- : _options.disabled,
2186
- name,
2187
- });
2188
- }
2189
- else {
2190
- updateValidAndValue(name, true, options.value);
2191
- }
2192
- return {
2193
- ...(disabledIsDefined
2194
- ? { disabled: options.disabled || _options.disabled }
2195
- : {}),
2196
- ...(_options.progressive
2197
- ? {
2198
- required: !!options.required,
2199
- min: getRuleValue(options.min),
2200
- max: getRuleValue(options.max),
2201
- minLength: getRuleValue(options.minLength),
2202
- maxLength: getRuleValue(options.maxLength),
2203
- pattern: getRuleValue(options.pattern),
2204
- }
2205
- : {}),
2206
- name,
2207
- onChange,
2208
- onBlur: onChange,
2209
- ref: (ref) => {
2210
- if (ref) {
2211
- register(name, options);
2212
- field = get(_fields, name);
2213
- const fieldRef = isUndefined(ref.value)
2214
- ? ref.querySelectorAll
2215
- ? ref.querySelectorAll('input,select,textarea')[0] || ref
2216
- : ref
2217
- : ref;
2218
- const radioOrCheckbox = isRadioOrCheckbox(fieldRef);
2219
- const refs = field._f.refs || [];
2220
- if (radioOrCheckbox
2221
- ? refs.find((option) => option === fieldRef)
2222
- : fieldRef === field._f.ref) {
2223
- return;
2224
- }
2225
- set(_fields, name, {
2226
- _f: {
2227
- ...field._f,
2228
- ...(radioOrCheckbox
2229
- ? {
2230
- refs: [
2231
- ...refs.filter(live),
2232
- fieldRef,
2233
- ...(Array.isArray(get(_defaultValues, name)) ? [{}] : []),
2234
- ],
2235
- ref: { type: fieldRef.type, name },
2236
- }
2237
- : { ref: fieldRef }),
2238
- },
2239
- });
2240
- updateValidAndValue(name, false, undefined, fieldRef);
2241
- }
2242
- else {
2243
- field = get(_fields, name, {});
2244
- if (field._f) {
2245
- field._f.mount = false;
2246
- }
2247
- (_options.shouldUnregister || options.shouldUnregister) &&
2248
- !(isNameInFieldArray(_names.array, name) && _state.action) &&
2249
- _names.unMount.add(name);
2250
- }
2251
- },
2252
- };
2253
- };
2254
- const _focusError = () => _options.shouldFocusError &&
2255
- iterateFieldsByAction(_fields, _focusInput, _names.mount);
2256
- const _disableForm = (disabled) => {
2257
- if (isBoolean(disabled)) {
2258
- _subjects.state.next({ disabled });
2259
- iterateFieldsByAction(_fields, (ref, name) => {
2260
- const currentField = get(_fields, name);
2261
- if (currentField) {
2262
- ref.disabled = currentField._f.disabled || disabled;
2263
- if (Array.isArray(currentField._f.refs)) {
2264
- currentField._f.refs.forEach((inputRef) => {
2265
- inputRef.disabled = currentField._f.disabled || disabled;
2266
- });
2267
- }
2268
- }
2269
- }, 0, false);
2270
- }
2271
2432
  };
2272
- const handleSubmit = (onValid, onInvalid) => async (e) => {
2273
- let onValidError = undefined;
2274
- if (e) {
2275
- e.preventDefault && e.preventDefault();
2276
- e.persist && e.persist();
2277
- }
2278
- let fieldValues = cloneObject(_formValues);
2279
- if (_names.disabled.size) {
2280
- for (const name of _names.disabled) {
2281
- set(fieldValues, name, undefined);
2282
- }
2283
- }
2284
- _subjects.state.next({
2285
- isSubmitting: true,
2433
+ const remove = (index) => {
2434
+ const updatedFieldArrayValues = removeArrayAt(control._getFieldArray(name), index);
2435
+ ids.current = removeArrayAt(ids.current, index);
2436
+ updateValues(updatedFieldArrayValues);
2437
+ setFields(updatedFieldArrayValues);
2438
+ !Array.isArray(get(control._fields, name)) &&
2439
+ set(control._fields, name, undefined);
2440
+ control._setFieldArray(name, updatedFieldArrayValues, removeArrayAt, {
2441
+ argA: index,
2286
2442
  });
2287
- if (_options.resolver) {
2288
- const { errors, values } = await _executeSchema();
2289
- _formState.errors = errors;
2290
- fieldValues = values;
2291
- }
2292
- else {
2293
- await executeBuiltInValidation(_fields);
2294
- }
2295
- unset(_formState.errors, 'root');
2296
- if (isEmptyObject(_formState.errors)) {
2297
- _subjects.state.next({
2298
- errors: {},
2299
- });
2300
- try {
2301
- await onValid(fieldValues, e);
2302
- }
2303
- catch (error) {
2304
- onValidError = error;
2305
- }
2306
- }
2307
- else {
2308
- if (onInvalid) {
2309
- await onInvalid({ ..._formState.errors }, e);
2310
- }
2311
- _focusError();
2312
- setTimeout(_focusError);
2313
- }
2314
- _subjects.state.next({
2315
- isSubmitted: true,
2316
- isSubmitting: false,
2317
- isSubmitSuccessful: isEmptyObject(_formState.errors) && !onValidError,
2318
- submitCount: _formState.submitCount + 1,
2319
- errors: _formState.errors,
2443
+ };
2444
+ const insert$1 = (index, value, options) => {
2445
+ const insertValue = convertToArrayPayload(cloneObject(value));
2446
+ const updatedFieldArrayValues = insert(control._getFieldArray(name), index, insertValue);
2447
+ control._names.focus = getFocusFieldName(name, index, options);
2448
+ ids.current = insert(ids.current, index, insertValue.map(generateId));
2449
+ updateValues(updatedFieldArrayValues);
2450
+ setFields(updatedFieldArrayValues);
2451
+ control._setFieldArray(name, updatedFieldArrayValues, insert, {
2452
+ argA: index,
2453
+ argB: fillEmptyArray(value),
2320
2454
  });
2321
- if (onValidError) {
2322
- throw onValidError;
2323
- }
2324
2455
  };
2325
- const resetField = (name, options = {}) => {
2326
- if (get(_fields, name)) {
2327
- if (isUndefined(options.defaultValue)) {
2328
- setValue(name, cloneObject(get(_defaultValues, name)));
2329
- }
2330
- else {
2331
- setValue(name, options.defaultValue);
2332
- set(_defaultValues, name, cloneObject(options.defaultValue));
2333
- }
2334
- if (!options.keepTouched) {
2335
- unset(_formState.touchedFields, name);
2336
- }
2337
- if (!options.keepDirty) {
2338
- unset(_formState.dirtyFields, name);
2339
- _formState.isDirty = options.defaultValue
2340
- ? _getDirty(name, cloneObject(get(_defaultValues, name)))
2341
- : _getDirty();
2342
- }
2343
- if (!options.keepError) {
2344
- unset(_formState.errors, name);
2345
- _proxyFormState.isValid && _updateValid();
2346
- }
2347
- _subjects.state.next({ ..._formState });
2348
- }
2456
+ const swap = (indexA, indexB) => {
2457
+ const updatedFieldArrayValues = control._getFieldArray(name);
2458
+ swapArrayAt(updatedFieldArrayValues, indexA, indexB);
2459
+ swapArrayAt(ids.current, indexA, indexB);
2460
+ updateValues(updatedFieldArrayValues);
2461
+ setFields(updatedFieldArrayValues);
2462
+ control._setFieldArray(name, updatedFieldArrayValues, swapArrayAt, {
2463
+ argA: indexA,
2464
+ argB: indexB,
2465
+ }, false);
2349
2466
  };
2350
- const _reset = (formValues, keepStateOptions = {}) => {
2351
- const updatedValues = formValues ? cloneObject(formValues) : _defaultValues;
2352
- const cloneUpdatedValues = cloneObject(updatedValues);
2353
- const isEmptyResetValues = isEmptyObject(formValues);
2354
- const values = isEmptyResetValues ? _defaultValues : cloneUpdatedValues;
2355
- if (!keepStateOptions.keepDefaultValues) {
2356
- _defaultValues = updatedValues;
2357
- }
2358
- if (!keepStateOptions.keepValues) {
2359
- if (keepStateOptions.keepDirtyValues) {
2360
- const fieldsToCheck = new Set([
2361
- ..._names.mount,
2362
- ...Object.keys(getDirtyFields(_defaultValues, _formValues)),
2363
- ]);
2364
- for (const fieldName of Array.from(fieldsToCheck)) {
2365
- get(_formState.dirtyFields, fieldName)
2366
- ? set(values, fieldName, get(_formValues, fieldName))
2367
- : setValue(fieldName, get(values, fieldName));
2368
- }
2467
+ const move = (from, to) => {
2468
+ const updatedFieldArrayValues = control._getFieldArray(name);
2469
+ moveArrayAt(updatedFieldArrayValues, from, to);
2470
+ moveArrayAt(ids.current, from, to);
2471
+ updateValues(updatedFieldArrayValues);
2472
+ setFields(updatedFieldArrayValues);
2473
+ control._setFieldArray(name, updatedFieldArrayValues, moveArrayAt, {
2474
+ argA: from,
2475
+ argB: to,
2476
+ }, false);
2477
+ };
2478
+ const update = (index, value) => {
2479
+ const updateValue = cloneObject(value);
2480
+ const updatedFieldArrayValues = updateAt(control._getFieldArray(name), index, updateValue);
2481
+ ids.current = [...updatedFieldArrayValues].map((item, i) => !item || i === index ? generateId() : ids.current[i]);
2482
+ updateValues(updatedFieldArrayValues);
2483
+ setFields([...updatedFieldArrayValues]);
2484
+ control._setFieldArray(name, updatedFieldArrayValues, updateAt, {
2485
+ argA: index,
2486
+ argB: updateValue,
2487
+ }, true, false);
2488
+ };
2489
+ const replace = (value) => {
2490
+ const updatedFieldArrayValues = convertToArrayPayload(cloneObject(value));
2491
+ ids.current = updatedFieldArrayValues.map(generateId);
2492
+ updateValues([...updatedFieldArrayValues]);
2493
+ setFields([...updatedFieldArrayValues]);
2494
+ control._setFieldArray(name, [...updatedFieldArrayValues], (data) => data, {}, true, false);
2495
+ };
2496
+ React.useEffect(() => {
2497
+ control._state.action = false;
2498
+ isWatched(name, control._names) &&
2499
+ control._subjects.state.next({
2500
+ ...control._formState,
2501
+ });
2502
+ if (_actioned.current &&
2503
+ (!getValidationModes(control._options.mode).isOnSubmit ||
2504
+ control._formState.isSubmitted)) {
2505
+ if (control._options.resolver) {
2506
+ control._runSchema([name]).then((result) => {
2507
+ const error = get(result.errors, name);
2508
+ const existingError = get(control._formState.errors, name);
2509
+ if (existingError
2510
+ ? (!error && existingError.type) ||
2511
+ (error &&
2512
+ (existingError.type !== error.type ||
2513
+ existingError.message !== error.message))
2514
+ : error && error.type) {
2515
+ error
2516
+ ? set(control._formState.errors, name, error)
2517
+ : unset(control._formState.errors, name);
2518
+ control._subjects.state.next({
2519
+ errors: control._formState.errors,
2520
+ });
2521
+ }
2522
+ });
2369
2523
  }
2370
2524
  else {
2371
- if (isWeb && isUndefined(formValues)) {
2372
- for (const name of _names.mount) {
2373
- const field = get(_fields, name);
2374
- if (field && field._f) {
2375
- const fieldReference = Array.isArray(field._f.refs)
2376
- ? field._f.refs[0]
2377
- : field._f.ref;
2378
- if (isHTMLElement(fieldReference)) {
2379
- const form = fieldReference.closest('form');
2380
- if (form) {
2381
- form.reset();
2382
- break;
2383
- }
2384
- }
2385
- }
2386
- }
2525
+ const field = get(control._fields, name);
2526
+ if (field &&
2527
+ field._f &&
2528
+ !(getValidationModes(control._options.reValidateMode).isOnSubmit &&
2529
+ getValidationModes(control._options.mode).isOnSubmit)) {
2530
+ validateField(field, control._names.disabled, control._formValues, control._options.criteriaMode === VALIDATION_MODE.all, control._options.shouldUseNativeValidation, true).then((error) => !isEmptyObject(error) &&
2531
+ control._subjects.state.next({
2532
+ errors: updateFieldArrayRootError(control._formState.errors, error, name),
2533
+ }));
2387
2534
  }
2388
- _fields = {};
2389
2535
  }
2390
- _formValues = _options.shouldUnregister
2391
- ? keepStateOptions.keepDefaultValues
2392
- ? cloneObject(_defaultValues)
2393
- : {}
2394
- : cloneObject(values);
2395
- _subjects.array.next({
2396
- values: { ...values },
2397
- });
2398
- _subjects.values.next({
2399
- values: { ...values },
2400
- });
2401
2536
  }
2402
- _names = {
2403
- mount: keepStateOptions.keepDirtyValues ? _names.mount : new Set(),
2404
- unMount: new Set(),
2405
- array: new Set(),
2406
- disabled: new Set(),
2407
- watch: new Set(),
2408
- watchAll: false,
2409
- focus: '',
2410
- };
2411
- _state.mount =
2412
- !_proxyFormState.isValid ||
2413
- !!keepStateOptions.keepIsValid ||
2414
- !!keepStateOptions.keepDirtyValues;
2415
- _state.watch = !!_options.shouldUnregister;
2416
- _subjects.state.next({
2417
- submitCount: keepStateOptions.keepSubmitCount
2418
- ? _formState.submitCount
2419
- : 0,
2420
- isDirty: isEmptyResetValues
2421
- ? false
2422
- : keepStateOptions.keepDirty
2423
- ? _formState.isDirty
2424
- : !!(keepStateOptions.keepDefaultValues &&
2425
- !deepEqual(formValues, _defaultValues)),
2426
- isSubmitted: keepStateOptions.keepIsSubmitted
2427
- ? _formState.isSubmitted
2428
- : false,
2429
- dirtyFields: isEmptyResetValues
2430
- ? {}
2431
- : keepStateOptions.keepDirtyValues
2432
- ? keepStateOptions.keepDefaultValues && _formValues
2433
- ? getDirtyFields(_defaultValues, _formValues)
2434
- : _formState.dirtyFields
2435
- : keepStateOptions.keepDefaultValues && formValues
2436
- ? getDirtyFields(_defaultValues, formValues)
2437
- : keepStateOptions.keepDirty
2438
- ? _formState.dirtyFields
2439
- : {},
2440
- touchedFields: keepStateOptions.keepTouched
2441
- ? _formState.touchedFields
2442
- : {},
2443
- errors: keepStateOptions.keepErrors ? _formState.errors : {},
2444
- isSubmitSuccessful: keepStateOptions.keepIsSubmitSuccessful
2445
- ? _formState.isSubmitSuccessful
2446
- : false,
2447
- isSubmitting: false,
2537
+ control._subjects.state.next({
2538
+ name,
2539
+ values: { ...control._formValues },
2448
2540
  });
2449
- };
2450
- const reset = (formValues, keepStateOptions) => _reset(isFunction(formValues)
2451
- ? formValues(_formValues)
2452
- : formValues, keepStateOptions);
2453
- const setFocus = (name, options = {}) => {
2454
- const field = get(_fields, name);
2455
- const fieldReference = field && field._f;
2456
- if (fieldReference) {
2457
- const fieldRef = fieldReference.refs
2458
- ? fieldReference.refs[0]
2459
- : fieldReference.ref;
2460
- if (fieldRef.focus) {
2461
- fieldRef.focus();
2462
- options.shouldSelect &&
2463
- isFunction(fieldRef.select) &&
2464
- fieldRef.select();
2465
- }
2466
- }
2467
- };
2468
- const _updateFormState = (updatedFormState) => {
2469
- _formState = {
2470
- ..._formState,
2471
- ...updatedFormState,
2472
- };
2473
- };
2474
- const _resetDefaultValues = () => isFunction(_options.defaultValues) &&
2475
- _options.defaultValues().then((values) => {
2476
- reset(values, _options.resetOptions);
2477
- _subjects.state.next({
2478
- isLoading: false,
2541
+ control._names.focus &&
2542
+ iterateFieldsByAction(control._fields, (ref, key) => {
2543
+ if (control._names.focus &&
2544
+ key.startsWith(control._names.focus) &&
2545
+ ref.focus) {
2546
+ ref.focus();
2547
+ return 1;
2548
+ }
2549
+ return;
2479
2550
  });
2480
- });
2551
+ control._names.focus = '';
2552
+ control._setValid();
2553
+ _actioned.current = false;
2554
+ }, [fields, name, control]);
2555
+ React.useEffect(() => {
2556
+ !get(control._formValues, name) && control._setFieldArray(name);
2557
+ return () => {
2558
+ (control._options.shouldUnregister || shouldUnregister) &&
2559
+ control.unregister(name);
2560
+ };
2561
+ }, [name, control, keyName, shouldUnregister]);
2481
2562
  return {
2482
- control: {
2483
- register,
2484
- unregister,
2485
- getFieldState,
2486
- handleSubmit,
2487
- setError,
2488
- _executeSchema,
2489
- _getWatch,
2490
- _getDirty,
2491
- _updateValid,
2492
- _removeUnmounted,
2493
- _updateFieldArray,
2494
- _updateDisabledField,
2495
- _getFieldArray,
2496
- _reset,
2497
- _resetDefaultValues,
2498
- _updateFormState,
2499
- _disableForm,
2500
- _subjects,
2501
- _proxyFormState,
2502
- _setErrors,
2503
- get _fields() {
2504
- return _fields;
2505
- },
2506
- get _formValues() {
2507
- return _formValues;
2508
- },
2509
- get _state() {
2510
- return _state;
2511
- },
2512
- set _state(value) {
2513
- _state = value;
2514
- },
2515
- get _defaultValues() {
2516
- return _defaultValues;
2517
- },
2518
- get _names() {
2519
- return _names;
2520
- },
2521
- set _names(value) {
2522
- _names = value;
2523
- },
2524
- get _formState() {
2525
- return _formState;
2526
- },
2527
- set _formState(value) {
2528
- _formState = value;
2529
- },
2530
- get _options() {
2531
- return _options;
2532
- },
2533
- set _options(value) {
2534
- _options = {
2535
- ..._options,
2536
- ...value,
2537
- };
2538
- },
2539
- },
2540
- trigger,
2541
- register,
2542
- handleSubmit,
2543
- watch,
2544
- setValue,
2545
- getValues,
2546
- reset,
2547
- resetField,
2548
- clearErrors,
2549
- unregister,
2550
- setError,
2551
- setFocus,
2552
- getFieldState,
2563
+ swap: React.useCallback(swap, [updateValues, name, control]),
2564
+ move: React.useCallback(move, [updateValues, name, control]),
2565
+ prepend: React.useCallback(prepend, [updateValues, name, control]),
2566
+ append: React.useCallback(append, [updateValues, name, control]),
2567
+ remove: React.useCallback(remove, [updateValues, name, control]),
2568
+ insert: React.useCallback(insert$1, [updateValues, name, control]),
2569
+ update: React.useCallback(update, [updateValues, name, control]),
2570
+ replace: React.useCallback(replace, [updateValues, name, control]),
2571
+ fields: React.useMemo(() => fields.map((field, index) => ({
2572
+ ...field,
2573
+ [keyName]: ids.current[index] || generateId(),
2574
+ })), [fields, keyName]),
2553
2575
  };
2554
2576
  }
2555
2577
 
@@ -2605,20 +2627,17 @@ function useForm(props = {}) {
2605
2627
  });
2606
2628
  if (!_formControl.current) {
2607
2629
  _formControl.current = {
2608
- ...createFormControl(props),
2630
+ ...(props.formControl ? props.formControl : createFormControl(props)),
2609
2631
  formState,
2610
2632
  };
2611
2633
  }
2612
2634
  const control = _formControl.current.control;
2613
2635
  control._options = props;
2614
- useSubscribe({
2615
- subject: control._subjects.state,
2616
- next: (value) => {
2617
- if (shouldRenderFormState(value, control._proxyFormState, control._updateFormState, true)) {
2618
- updateFormState({ ...control._formState });
2619
- }
2620
- },
2621
- });
2636
+ React.useEffect(() => control._subscribe({
2637
+ formState: control._proxyFormState,
2638
+ callback: () => updateFormState({ ...control._formState }),
2639
+ reRenderRoot: true,
2640
+ }), [control]);
2622
2641
  React.useEffect(() => control._disableForm(props.disabled), [control, props.disabled]);
2623
2642
  React.useEffect(() => {
2624
2643
  if (control._proxyFormState.isDirty) {
@@ -2647,7 +2666,7 @@ function useForm(props = {}) {
2647
2666
  }, [props.errors, control]);
2648
2667
  React.useEffect(() => {
2649
2668
  if (!control._state.mount) {
2650
- control._updateValid();
2669
+ control._setValid();
2651
2670
  control._state.mount = true;
2652
2671
  }
2653
2672
  if (control._state.watch) {
@@ -2658,7 +2677,7 @@ function useForm(props = {}) {
2658
2677
  });
2659
2678
  React.useEffect(() => {
2660
2679
  props.shouldUnregister &&
2661
- control._subjects.values.next({
2680
+ control._subjects.state.next({
2662
2681
  values: control._getWatch(),
2663
2682
  });
2664
2683
  }, [props.shouldUnregister, control]);
@@ -2666,5 +2685,5 @@ function useForm(props = {}) {
2666
2685
  return _formControl.current;
2667
2686
  }
2668
2687
 
2669
- export { Controller, Form, FormProvider, appendErrors, get, set, useController, useFieldArray, useForm, useFormContext, useFormState, useWatch };
2688
+ export { Controller, Form, FormProvider, appendErrors, createFormControl, get, set, useController, useFieldArray, useForm, useFormContext, useFormState, useWatch };
2670
2689
  //# sourceMappingURL=index.esm.mjs.map