react-hook-form 7.80.0 → 7.82.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -602,301 +602,77 @@ function useController(props) {
602
602
  */
603
603
  const Controller = (props) => props.render(useController(props));
604
604
 
605
- const flatten = (obj) => {
606
- const output = {};
607
- for (const key of Object.keys(obj)) {
608
- if (isObjectType(obj[key]) && obj[key] !== null) {
609
- const nested = flatten(obj[key]);
610
- for (const nestedKey of Object.keys(nested)) {
611
- output[`${key}.${nestedKey}`] = nested[nestedKey];
612
- }
613
- }
614
- else {
615
- output[key] = obj[key];
616
- }
605
+ var generateId = () => {
606
+ if (typeof crypto !== 'undefined' && crypto.randomUUID) {
607
+ return crypto.randomUUID();
617
608
  }
618
- return output;
609
+ const d = typeof performance === 'undefined' ? Date.now() : performance.now() * 1000;
610
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
611
+ const r = ((Math.random() * 16 + d) % 16) | 0;
612
+ return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16);
613
+ });
619
614
  };
620
615
 
621
- const HookFormContext = React.createContext(null);
622
- HookFormContext.displayName = 'HookFormContext';
623
- /**
624
- * This custom hook allows you to access the form context. useFormContext is intended to be used in deeply nested structures, where it would become inconvenient to pass the context as a prop. To be used with {@link FormProvider}.
625
- *
626
- * @remarks
627
- * [API](https://react-hook-form.com/docs/useformcontext) [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
628
- *
629
- * @returns return all useForm methods
630
- *
631
- * @example
632
- * ```tsx
633
- * function App() {
634
- * const methods = useForm();
635
- * const onSubmit = data => console.log(data);
636
- *
637
- * return (
638
- * <FormProvider {...methods} >
639
- * <form onSubmit={methods.handleSubmit(onSubmit)}>
640
- * <NestedInput />
641
- * <input type="submit" />
642
- * </form>
643
- * </FormProvider>
644
- * );
645
- * }
646
- *
647
- * function NestedInput() {
648
- * const { register } = useFormContext(); // retrieve all hook methods
649
- * return <input {...register("test")} />;
650
- * }
651
- * ```
652
- */
653
- const useFormContext = () => React.useContext(HookFormContext);
654
- /**
655
- * A provider component that propagates the `useForm` methods to all children components via [React Context](https://react.dev/reference/react/useContext) API. To be used with {@link useFormContext}.
656
- *
657
- * @remarks
658
- * [API](https://react-hook-form.com/docs/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
659
- *
660
- * @param props - all useForm methods
661
- *
662
- * @example
663
- * ```tsx
664
- * function App() {
665
- * const methods = useForm();
666
- * const onSubmit = data => console.log(data);
667
- *
668
- * return (
669
- * <FormProvider {...methods} >
670
- * <form onSubmit={methods.handleSubmit(onSubmit)}>
671
- * <NestedInput />
672
- * <input type="submit" />
673
- * </form>
674
- * </FormProvider>
675
- * );
676
- * }
677
- *
678
- * function NestedInput() {
679
- * const { register } = useFormContext(); // retrieve all hook methods
680
- * return <input {...register("test")} />;
681
- * }
682
- * ```
683
- */
684
- const FormProvider = ({ children, watch, getValues, getFieldState, setError, clearErrors, setValue, setValues, trigger, formState, resetField, reset, handleSubmit, unregister, control, register, setFocus, subscribe, }) => {
685
- const memoizedValue = React.useMemo(() => ({
686
- watch,
687
- getValues,
688
- getFieldState,
689
- setError,
690
- clearErrors,
691
- setValue,
692
- setValues,
693
- trigger,
694
- formState,
695
- resetField,
696
- reset,
697
- handleSubmit,
698
- unregister,
699
- control,
700
- register,
701
- setFocus,
702
- subscribe,
703
- }), [
704
- clearErrors,
705
- control,
706
- formState,
707
- getFieldState,
708
- getValues,
709
- handleSubmit,
710
- register,
711
- reset,
712
- resetField,
713
- setError,
714
- setFocus,
715
- setValue,
716
- setValues,
717
- subscribe,
718
- trigger,
719
- unregister,
720
- watch,
721
- ]);
722
- return (React.createElement(HookFormContext.Provider, { value: memoizedValue },
723
- React.createElement(HookFormControlContext.Provider, { value: memoizedValue.control }, children)));
616
+ var getFocusFieldName = (name, index, options = {}) => options.shouldFocus || isUndefined(options.shouldFocus)
617
+ ? options.focusName ||
618
+ `${name}.${isUndefined(options.focusIndex) ? index : options.focusIndex}.`
619
+ : '';
620
+
621
+ var getValidationModes = (mode) => ({
622
+ isOnSubmit: !mode || mode === VALIDATION_MODE.onSubmit,
623
+ isOnBlur: mode === VALIDATION_MODE.onBlur,
624
+ isOnChange: mode === VALIDATION_MODE.onChange,
625
+ isOnAll: mode === VALIDATION_MODE.all,
626
+ isOnTouch: mode === VALIDATION_MODE.onTouched,
627
+ });
628
+
629
+ var isWatched = (name, _names, isBlurEvent) => {
630
+ if (isBlurEvent)
631
+ return false;
632
+ if (_names.watchAll || _names.watch.has(name))
633
+ return true;
634
+ for (const watchName of _names.watch) {
635
+ if (name.startsWith(watchName) && name.charAt(watchName.length) === '.')
636
+ return true;
637
+ }
638
+ return false;
724
639
  };
725
640
 
726
- const POST_REQUEST = 'post';
727
- /**
728
- * Form component to manage submission.
729
- *
730
- * @param props - to setup submission detail. {@link FormProps}
731
- *
732
- * @returns form component or headless render prop.
733
- *
734
- * @example
735
- * ```tsx
736
- * function App() {
737
- * const { control, formState: { errors } } = useForm();
738
- *
739
- * return (
740
- * <Form action="/api" control={control}>
741
- * <input {...register("name")} />
742
- * <p>{errors?.root?.server && 'Server error'}</p>
743
- * <button>Submit</button>
744
- * </Form>
745
- * );
746
- * }
747
- * ```
748
- */
749
- function Form(props) {
750
- const methods = useFormContext();
751
- const [mounted, setMounted] = React.useState(false);
752
- const { control = methods.control, onSubmit, children, action, method = POST_REQUEST, headers, encType, onError, render, onSuccess, validateStatus, ...rest } = props;
753
- const submit = React.useCallback(async (event) => {
754
- let hasError = false;
755
- let type = '';
756
- await control.handleSubmit(async (data) => {
757
- const formData = new FormData();
758
- let formDataJson = '';
759
- try {
760
- formDataJson = JSON.stringify(data);
761
- }
762
- catch (_a) { }
763
- const flattenFormValues = flatten(data);
764
- for (const key in flattenFormValues) {
765
- formData.append(key, flattenFormValues[key]);
766
- }
767
- if (onSubmit) {
768
- await onSubmit({
769
- data,
770
- event,
771
- method,
772
- formData,
773
- formDataJson,
774
- });
775
- }
776
- if (action) {
777
- try {
778
- const shouldStringifySubmissionData = [
779
- headers && headers['Content-Type'],
780
- encType,
781
- ].some((value) => value && value.includes('json'));
782
- const response = await fetch(String(action), {
783
- method,
784
- headers: {
785
- ...headers,
786
- ...(encType && encType !== 'multipart/form-data'
787
- ? { 'Content-Type': encType }
788
- : {}),
789
- },
790
- body: shouldStringifySubmissionData ? formDataJson : formData,
791
- });
792
- if (response &&
793
- (validateStatus
794
- ? !validateStatus(response.status)
795
- : response.status < 200 || response.status >= 300)) {
796
- hasError = true;
797
- onError && onError({ response });
798
- type = String(response.status);
799
- }
800
- else {
801
- onSuccess && onSuccess({ response });
641
+ const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
642
+ for (const key of fieldsNames || Object.keys(fields)) {
643
+ const field = get(fields, key);
644
+ if (field) {
645
+ const { _f, ...currentField } = field;
646
+ if (_f) {
647
+ if (_f.refs && _f.refs[0] && action(_f.refs[0], key) && !abortEarly) {
648
+ return true;
649
+ }
650
+ else if (_f.ref && action(_f.ref, _f.name) && !abortEarly) {
651
+ return true;
652
+ }
653
+ else {
654
+ if (iterateFieldsByAction(currentField, action)) {
655
+ break;
802
656
  }
803
657
  }
804
- catch (error) {
805
- hasError = true;
806
- onError && onError({ error });
658
+ }
659
+ else if (isObject(currentField)) {
660
+ if (iterateFieldsByAction(currentField, action)) {
661
+ break;
807
662
  }
808
663
  }
809
- })(event);
810
- if (hasError && control) {
811
- control._subjects.state.next({
812
- isSubmitSuccessful: false,
813
- });
814
- control.setError('root.server', {
815
- type,
816
- });
817
664
  }
818
- }, [
819
- control,
820
- onSubmit,
821
- method,
822
- action,
823
- headers,
824
- encType,
825
- validateStatus,
826
- onError,
827
- onSuccess,
828
- ]);
829
- React.useEffect(() => {
830
- setMounted(true);
831
- }, []);
832
- return render ? (React.createElement(React.Fragment, null, render({
833
- submit,
834
- }))) : (React.createElement("form", { noValidate: mounted, action: action, method: method, encType: encType, onSubmit: submit, ...rest }, children));
835
- }
836
-
837
- const FormStateSubscribe = ({ control, disabled, exact, name, render, }) => render(useFormState({ control, name, disabled, exact }));
838
-
839
- var appendErrors = (name, validateAllFieldCriteria, errors, type, message) => validateAllFieldCriteria
840
- ? {
841
- ...errors[name],
842
- types: {
843
- ...(errors[name] && errors[name].types ? errors[name].types : {}),
844
- [type]: message || true,
845
- },
846
665
  }
847
- : {};
848
-
849
- var compact = (value) => Array.isArray(value) ? value.filter(Boolean) : [];
850
-
851
- var convertToArrayPayload = (value) => (Array.isArray(value) ? value : [value]);
852
-
853
- var createSubject = () => {
854
- let _observers = [];
855
- const next = (value) => {
856
- for (const observer of _observers) {
857
- observer.next && observer.next(value);
858
- }
859
- };
860
- const subscribe = (observer) => {
861
- _observers.push(observer);
862
- return {
863
- unsubscribe: () => {
864
- _observers = _observers.filter((o) => o !== observer);
865
- },
866
- };
867
- };
868
- const unsubscribe = () => {
869
- _observers = [];
870
- };
871
- return {
872
- get observers() {
873
- return _observers;
874
- },
875
- next,
876
- subscribe,
877
- unsubscribe,
878
- };
666
+ return;
879
667
  };
880
668
 
881
- function extractFormValues(fieldsState, formValues) {
882
- const values = {};
883
- for (const key in fieldsState) {
884
- if (fieldsState.hasOwnProperty(key)) {
885
- const fieldState = fieldsState[key];
886
- const fieldValue = formValues[key];
887
- if (fieldState && isObject(fieldState) && fieldValue) {
888
- const nestedFieldsState = extractFormValues(fieldState, fieldValue);
889
- if (isObject(nestedFieldsState)) {
890
- values[key] = nestedFieldsState;
891
- }
892
- }
893
- else if (fieldsState[key]) {
894
- values[key] = fieldValue;
895
- }
896
- }
897
- }
898
- return values;
899
- }
669
+ var updateFieldArrayRootError = (errors, error, name) => {
670
+ const existingErrors = get(errors, name);
671
+ const fieldArrayErrors = Array.isArray(existingErrors) ? existingErrors : [];
672
+ set(fieldArrayErrors, ROOT_ERROR_TYPE, error[name]);
673
+ set(errors, name, fieldArrayErrors);
674
+ return errors;
675
+ };
900
676
 
901
677
  var isEmptyObject = (value) => isObject(value) && !Object.keys(value).length;
902
678
 
@@ -911,128 +687,19 @@ var isHTMLElement = (value) => {
911
687
  (owner && owner.defaultView ? owner.defaultView.HTMLElement : HTMLElement));
912
688
  };
913
689
 
914
- var isMultipleSelect = (element) => element.type === `select-multiple`;
915
-
916
690
  var isRadioInput = (element) => element.type === 'radio';
917
691
 
918
- var isRadioOrCheckbox = (ref) => isRadioInput(ref) || isCheckBoxInput(ref);
919
-
920
- var live = (ref) => isHTMLElement(ref) && ref.isConnected;
921
-
922
- function baseGet(object, updatePath) {
923
- const length = updatePath.slice(0, -1).length;
924
- let index = 0;
925
- while (index < length) {
926
- if (isNullOrUndefined(object)) {
927
- object = undefined;
928
- break;
929
- }
930
- object = object[updatePath[index]];
931
- index++;
932
- }
933
- return object;
934
- }
935
- function isEmptyArray(obj) {
936
- for (const key in obj) {
937
- if (obj.hasOwnProperty(key) && !isUndefined(obj[key])) {
938
- return false;
939
- }
940
- }
941
- return true;
942
- }
943
- function unset(object, path) {
944
- if (isString(path) && Object.prototype.hasOwnProperty.call(object, path)) {
945
- delete object[path];
946
- return object;
947
- }
948
- const paths = Array.isArray(path)
949
- ? path
950
- : isKey(path)
951
- ? [path]
952
- : stringToPath(path);
953
- const childObject = paths.length === 1 ? object : baseGet(object, paths);
954
- const index = paths.length - 1;
955
- const key = paths[index];
956
- if (childObject) {
957
- delete childObject[key];
958
- }
959
- if (index !== 0 &&
960
- ((isObject(childObject) && isEmptyObject(childObject)) ||
961
- (Array.isArray(childObject) && isEmptyArray(childObject)))) {
962
- unset(object, paths.slice(0, -1));
963
- }
964
- return object;
965
- }
966
-
967
- var objectHasFunction = (data) => {
968
- for (const key in data) {
969
- if (isFunction(data[key])) {
970
- return true;
971
- }
972
- }
973
- return false;
974
- };
692
+ var isRegex = (value) => value instanceof RegExp;
975
693
 
976
- function isTraversable(value) {
977
- return Array.isArray(value) || (isObject(value) && !objectHasFunction(value));
978
- }
979
- function markFieldsDirty(data, fields = {}) {
980
- for (const key in data) {
981
- const value = data[key];
982
- if (isTraversable(value)) {
983
- fields[key] = Array.isArray(value) ? [] : {};
984
- markFieldsDirty(value, fields[key]);
985
- }
986
- else if (!isUndefined(value)) {
987
- fields[key] = true;
988
- }
989
- }
990
- return fields;
991
- }
992
- function pruneDirtyFields(value) {
993
- if (value === false) {
994
- return undefined;
995
- }
996
- if (value === true) {
997
- return true;
998
- }
999
- if (Array.isArray(value)) {
1000
- const result = value.map((value) => pruneDirtyFields(value));
1001
- return (result.some((value) => value !== undefined) ? result : undefined);
1002
- }
1003
- if (isObject(value)) {
1004
- const result = {};
1005
- for (const key in value) {
1006
- const pruned = pruneDirtyFields(value[key]);
1007
- if (!isUndefined(pruned)) {
1008
- result[key] = pruned;
1009
- }
1010
- }
1011
- return (Object.keys(result).length ? result : undefined);
1012
- }
1013
- return undefined;
1014
- }
1015
- function getDirtyFields(data, formValues, dirtyFieldsFromValues) {
1016
- if (!dirtyFieldsFromValues) {
1017
- dirtyFieldsFromValues = markFieldsDirty(formValues);
1018
- }
1019
- for (const key in data) {
1020
- const value = data[key];
1021
- if (isTraversable(value)) {
1022
- if (isUndefined(formValues) || isPrimitive(dirtyFieldsFromValues[key])) {
1023
- dirtyFieldsFromValues[key] = markFieldsDirty(value, Array.isArray(value) ? [] : {});
1024
- }
1025
- else {
1026
- getDirtyFields(value, isNullOrUndefined(formValues) ? {} : formValues[key], dirtyFieldsFromValues[key]);
1027
- }
1028
- }
1029
- else {
1030
- const formValue = formValues[key];
1031
- dirtyFieldsFromValues[key] = !deepEqual(value, formValue);
1032
- }
694
+ var appendErrors = (name, validateAllFieldCriteria, errors, type, message) => validateAllFieldCriteria
695
+ ? {
696
+ ...errors[name],
697
+ types: {
698
+ ...(errors[name] && errors[name].types ? errors[name].types : {}),
699
+ [type]: message || true,
700
+ },
1033
701
  }
1034
- return pruneDirtyFields(dirtyFieldsFromValues) || {};
1035
- }
702
+ : {};
1036
703
 
1037
704
  const defaultResult = {
1038
705
  value: false,
@@ -1059,20 +726,6 @@ var getCheckboxValue = (options) => {
1059
726
  return defaultResult;
1060
727
  };
1061
728
 
1062
- var getFieldValueAs = (value, { valueAsNumber, valueAsDate, setValueAs }) => isUndefined(value)
1063
- ? value
1064
- : valueAsNumber
1065
- ? value === ''
1066
- ? NaN
1067
- : value
1068
- ? +value
1069
- : value
1070
- : valueAsDate && isString(value)
1071
- ? new Date(value)
1072
- : setValueAs
1073
- ? setValueAs(value)
1074
- : value;
1075
-
1076
729
  const defaultReturn = {
1077
730
  isValid: false,
1078
731
  value: null,
@@ -1086,221 +739,23 @@ var getRadioValue = (options) => Array.isArray(options)
1086
739
  : previous, defaultReturn)
1087
740
  : defaultReturn;
1088
741
 
1089
- function getFieldValue(_f) {
1090
- const ref = _f.ref;
1091
- if (isFileInput(ref)) {
1092
- return ref.files;
1093
- }
1094
- if (isRadioInput(ref)) {
1095
- return getRadioValue(_f.refs).value;
1096
- }
1097
- if (isMultipleSelect(ref)) {
1098
- return [...ref.selectedOptions].map(({ value }) => value);
1099
- }
1100
- if (isCheckBoxInput(ref)) {
1101
- return getCheckboxValue(_f.refs).value;
742
+ function getValidateError(result, ref, type = 'validate') {
743
+ if (isString(result) ||
744
+ (Array.isArray(result) && result.every(isString)) ||
745
+ (isBoolean(result) && !result)) {
746
+ return {
747
+ type,
748
+ message: isString(result) ? result : '',
749
+ ref,
750
+ };
1102
751
  }
1103
- return getFieldValueAs(isUndefined(ref.value) ? _f.ref.value : ref.value, _f);
1104
752
  }
1105
753
 
1106
- var getResolverOptions = (fieldsNames, _fields, criteriaMode, shouldUseNativeValidation) => {
1107
- const fields = {};
1108
- for (const name of fieldsNames) {
1109
- const field = get(_fields, name);
1110
- field && set(fields, name, field._f);
1111
- }
1112
- return {
1113
- criteriaMode,
1114
- names: [...fieldsNames],
1115
- fields,
1116
- shouldUseNativeValidation,
1117
- };
1118
- };
1119
-
1120
- var isRegex = (value) => value instanceof RegExp;
1121
-
1122
- var getRuleValue = (rule) => isUndefined(rule)
1123
- ? rule
1124
- : isRegex(rule)
1125
- ? rule.source
1126
- : isObject(rule)
1127
- ? isRegex(rule.value)
1128
- ? rule.value.source
1129
- : rule.value
1130
- : rule;
1131
-
1132
- var getValidationModes = (mode) => ({
1133
- isOnSubmit: !mode || mode === VALIDATION_MODE.onSubmit,
1134
- isOnBlur: mode === VALIDATION_MODE.onBlur,
1135
- isOnChange: mode === VALIDATION_MODE.onChange,
1136
- isOnAll: mode === VALIDATION_MODE.all,
1137
- isOnTouch: mode === VALIDATION_MODE.onTouched,
1138
- });
1139
-
1140
- const ASYNC_FUNCTION = 'AsyncFunction';
1141
- var hasPromiseValidation = (fieldReference) => {
1142
- if (!fieldReference || !fieldReference.validate)
1143
- return false;
1144
- if (isFunction(fieldReference.validate)) {
1145
- return fieldReference.validate.constructor.name === ASYNC_FUNCTION;
1146
- }
1147
- if (isObject(fieldReference.validate)) {
1148
- for (const key in fieldReference.validate) {
1149
- if (fieldReference.validate[key].constructor
1150
- .name === ASYNC_FUNCTION) {
1151
- return true;
1152
- }
1153
- }
1154
- }
1155
- return false;
1156
- };
1157
-
1158
- var hasValidation = (options) => options.mount &&
1159
- (options.required ||
1160
- options.min ||
1161
- options.max ||
1162
- options.maxLength ||
1163
- options.minLength ||
1164
- options.pattern ||
1165
- options.validate);
1166
-
1167
- var isWatched = (name, _names, isBlurEvent) => {
1168
- if (isBlurEvent)
1169
- return false;
1170
- if (_names.watchAll || _names.watch.has(name))
1171
- return true;
1172
- for (const watchName of _names.watch) {
1173
- if (name.startsWith(watchName) && name.charAt(watchName.length) === '.')
1174
- return true;
1175
- }
1176
- return false;
1177
- };
1178
-
1179
- const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
1180
- for (const key of fieldsNames || Object.keys(fields)) {
1181
- const field = get(fields, key);
1182
- if (field) {
1183
- const { _f, ...currentField } = field;
1184
- if (_f) {
1185
- if (_f.refs && _f.refs[0] && action(_f.refs[0], key) && !abortEarly) {
1186
- return true;
1187
- }
1188
- else if (_f.ref && action(_f.ref, _f.name) && !abortEarly) {
1189
- return true;
1190
- }
1191
- else {
1192
- if (iterateFieldsByAction(currentField, action)) {
1193
- break;
1194
- }
1195
- }
1196
- }
1197
- else if (isObject(currentField)) {
1198
- if (iterateFieldsByAction(currentField, action)) {
1199
- break;
1200
- }
1201
- }
1202
- }
1203
- }
1204
- return;
1205
- };
1206
-
1207
- function schemaErrorLookup(errors, _fields, name) {
1208
- const error = get(errors, name);
1209
- if (error || isKey(name)) {
1210
- return {
1211
- error,
1212
- name,
1213
- };
1214
- }
1215
- const names = name.split('.');
1216
- while (names.length) {
1217
- const fieldName = names.join('.');
1218
- const field = get(_fields, fieldName);
1219
- const foundError = get(errors, fieldName);
1220
- if (field && !Array.isArray(field) && name !== fieldName) {
1221
- return { name };
1222
- }
1223
- if (foundError && foundError.type) {
1224
- return {
1225
- name: fieldName,
1226
- error: foundError,
1227
- };
1228
- }
1229
- if (foundError && foundError.root && foundError.root.type) {
1230
- return {
1231
- name: `${fieldName}.root`,
1232
- error: foundError.root,
1233
- };
1234
- }
1235
- names.pop();
1236
- }
1237
- return {
1238
- name,
1239
- };
1240
- }
1241
-
1242
- var shouldRenderFormState = (formStateData, _proxyFormState, updateFormState, isRoot) => {
1243
- updateFormState(formStateData);
1244
- const { name, ...formState } = formStateData;
1245
- const keys = Object.keys(formState);
1246
- return (!keys.length ||
1247
- (isRoot && keys.length >= Object.keys(_proxyFormState).length) ||
1248
- keys.find((key) => _proxyFormState[key] ===
1249
- (!isRoot || VALIDATION_MODE.all)));
1250
- };
1251
-
1252
- var shouldSubscribeByName = (name, signalName, exact) => !name ||
1253
- !signalName ||
1254
- name === signalName ||
1255
- convertToArrayPayload(name).some((currentName) => currentName &&
1256
- (exact
1257
- ? currentName === signalName
1258
- : currentName.startsWith(signalName) ||
1259
- signalName.startsWith(currentName)));
1260
-
1261
- var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode) => {
1262
- if (mode.isOnAll) {
1263
- return false;
1264
- }
1265
- else if (!isSubmitted && mode.isOnTouch) {
1266
- return !(isTouched || isBlurEvent);
1267
- }
1268
- else if (isSubmitted ? reValidateMode.isOnBlur : mode.isOnBlur) {
1269
- return !isBlurEvent;
1270
- }
1271
- else if (isSubmitted ? reValidateMode.isOnChange : mode.isOnChange) {
1272
- return isBlurEvent;
1273
- }
1274
- return true;
1275
- };
1276
-
1277
- var unsetEmptyArray = (ref, name) => !compact(get(ref, name)).length && unset(ref, name);
1278
-
1279
- var updateFieldArrayRootError = (errors, error, name) => {
1280
- const existingErrors = get(errors, name);
1281
- const fieldArrayErrors = Array.isArray(existingErrors) ? existingErrors : [];
1282
- set(fieldArrayErrors, ROOT_ERROR_TYPE, error[name]);
1283
- set(errors, name, fieldArrayErrors);
1284
- return errors;
1285
- };
1286
-
1287
- function getValidateError(result, ref, type = 'validate') {
1288
- if (isString(result) ||
1289
- (Array.isArray(result) && result.every(isString)) ||
1290
- (isBoolean(result) && !result)) {
1291
- return {
1292
- type,
1293
- message: isString(result) ? result : '',
1294
- ref,
1295
- };
1296
- }
1297
- }
1298
-
1299
- var getValueAndMessage = (validationData) => isObject(validationData) && !isRegex(validationData)
1300
- ? validationData
1301
- : {
1302
- value: validationData,
1303
- message: '',
754
+ var getValueAndMessage = (validationData) => isObject(validationData) && !isRegex(validationData)
755
+ ? validationData
756
+ : {
757
+ value: validationData,
758
+ message: '',
1304
759
  };
1305
760
 
1306
761
  var validateField = async (field, disabledFieldNames, formValues, validateAllFieldCriteria, shouldUseNativeValidation, isFieldArray) => {
@@ -1488,1735 +943,2371 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
1488
943
  return error;
1489
944
  };
1490
945
 
1491
- const defaultOptions = {
1492
- mode: VALIDATION_MODE.onSubmit,
1493
- reValidateMode: VALIDATION_MODE.onChange,
1494
- shouldFocusError: true,
946
+ var convertToArrayPayload = (value) => (Array.isArray(value) ? value : [value]);
947
+
948
+ var appendAt = (data, value) => [
949
+ ...data,
950
+ ...convertToArrayPayload(value),
951
+ ];
952
+
953
+ var fillEmptyArray = (value) => Array.isArray(value) ? value.map(() => undefined) : undefined;
954
+
955
+ function insert(data, index, value) {
956
+ return [
957
+ ...data.slice(0, index),
958
+ ...convertToArrayPayload(value),
959
+ ...data.slice(index),
960
+ ];
961
+ }
962
+
963
+ var moveArrayAt = (data, from, to) => {
964
+ if (!Array.isArray(data)) {
965
+ return [];
966
+ }
967
+ if (isUndefined(data[to])) {
968
+ data[to] = undefined;
969
+ }
970
+ data.splice(to, 0, data.splice(from, 1)[0]);
971
+ return data;
1495
972
  };
1496
- const FORM_ERROR_TYPE = 'form';
1497
- const DEFAULT_FORM_STATE = {
1498
- submitCount: 0,
1499
- isDirty: false,
1500
- isReady: false,
1501
- isValidating: false,
1502
- isSubmitted: false,
1503
- isSubmitting: false,
1504
- isSubmitSuccessful: false,
1505
- isValid: false,
1506
- touchedFields: {},
1507
- dirtyFields: {},
1508
- validatingFields: {},
973
+
974
+ var prependAt = (data, value) => [
975
+ ...convertToArrayPayload(value),
976
+ ...convertToArrayPayload(data),
977
+ ];
978
+
979
+ var compact = (value) => Array.isArray(value) ? value.filter(Boolean) : [];
980
+
981
+ function removeAtIndexes(data, indexes) {
982
+ let i = 0;
983
+ const temp = [...data];
984
+ for (const index of indexes) {
985
+ temp.splice(index - i, 1);
986
+ i++;
987
+ }
988
+ return compact(temp).length ? temp : [];
989
+ }
990
+ var removeArrayAt = (data, index) => isUndefined(index)
991
+ ? []
992
+ : removeAtIndexes(data, convertToArrayPayload(index).sort((a, b) => a - b));
993
+
994
+ var swapArrayAt = (data, indexA, indexB) => {
995
+ [data[indexA], data[indexB]] = [data[indexB], data[indexA]];
1509
996
  };
1510
- function createFormControl(props = {}) {
1511
- let _options = {
1512
- ...defaultOptions,
1513
- ...props,
1514
- };
1515
- let _formState = {
1516
- ...cloneObject(DEFAULT_FORM_STATE),
1517
- isLoading: isFunction(_options.defaultValues),
1518
- errors: _options.errors || {},
1519
- disabled: _options.disabled || false,
1520
- };
1521
- let _fields = {};
1522
- let _defaultValues = isObject(_options.defaultValues) || isObject(_options.values)
1523
- ? cloneObject(_options.defaultValues || _options.values) || {}
1524
- : {};
1525
- let _formValues = _options.shouldUnregister
1526
- ? {}
1527
- : cloneObject(_defaultValues);
1528
- let _state = {
1529
- action: false,
1530
- mount: false,
1531
- watch: false,
1532
- keepIsValid: false,
1533
- };
1534
- let _names = {
1535
- mount: new Set(),
1536
- disabled: new Set(),
1537
- unMount: new Set(),
1538
- array: new Set(),
1539
- watch: new Set(),
1540
- registerName: new Set(),
1541
- };
1542
- let delayErrorCallback;
1543
- let timer = 0;
1544
- let _valuesSubscriberCount = 0;
1545
- let _validationModeBeforeSubmit = getValidationModes(_options.mode);
1546
- let _validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
1547
- const defaultProxyFormState = {
1548
- isDirty: false,
1549
- dirtyFields: false,
1550
- validatingFields: false,
1551
- touchedFields: false,
1552
- isValidating: false,
1553
- isValid: false,
1554
- errors: false,
1555
- };
1556
- const _proxyFormState = {
1557
- ...defaultProxyFormState,
997
+
998
+ function baseGet(object, updatePath) {
999
+ const length = updatePath.slice(0, -1).length;
1000
+ let index = 0;
1001
+ while (index < length) {
1002
+ if (isNullOrUndefined(object)) {
1003
+ object = undefined;
1004
+ break;
1005
+ }
1006
+ object = object[updatePath[index]];
1007
+ index++;
1008
+ }
1009
+ return object;
1010
+ }
1011
+ function isEmptyArray(obj) {
1012
+ for (const key in obj) {
1013
+ if (obj.hasOwnProperty(key) && !isUndefined(obj[key])) {
1014
+ return false;
1015
+ }
1016
+ }
1017
+ return true;
1018
+ }
1019
+ function unset(object, path) {
1020
+ if (isString(path) && Object.prototype.hasOwnProperty.call(object, path)) {
1021
+ delete object[path];
1022
+ return object;
1023
+ }
1024
+ const paths = Array.isArray(path)
1025
+ ? path
1026
+ : isKey(path)
1027
+ ? [path]
1028
+ : stringToPath(path);
1029
+ if (paths.some((segment) => PROTOTYPE_KEYWORDS.includes(String(segment)))) {
1030
+ return object;
1031
+ }
1032
+ const childObject = paths.length === 1 ? object : baseGet(object, paths);
1033
+ const index = paths.length - 1;
1034
+ const key = paths[index];
1035
+ if (childObject) {
1036
+ delete childObject[key];
1037
+ }
1038
+ if (index !== 0 &&
1039
+ ((isObject(childObject) && isEmptyObject(childObject)) ||
1040
+ (Array.isArray(childObject) && isEmptyArray(childObject)))) {
1041
+ unset(object, paths.slice(0, -1));
1042
+ }
1043
+ return object;
1044
+ }
1045
+
1046
+ var updateAt = (fieldValues, index, value) => {
1047
+ fieldValues[index] = value;
1048
+ return fieldValues;
1049
+ };
1050
+
1051
+ /**
1052
+ * 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)
1053
+ *
1054
+ * @remarks
1055
+ * [API](https://react-hook-form.com/docs/usefieldarray) • [Demo](https://codesandbox.io/s/react-hook-form-usefieldarray-ssugn)
1056
+ *
1057
+ * @param props - useFieldArray props
1058
+ *
1059
+ * @returns methods - functions to manipulate with the Field Arrays (dynamic inputs) {@link UseFieldArrayReturn}
1060
+ *
1061
+ * @example
1062
+ * ```tsx
1063
+ * function App() {
1064
+ * const { register, control, handleSubmit, reset, trigger, setError } = useForm({
1065
+ * defaultValues: {
1066
+ * test: []
1067
+ * }
1068
+ * });
1069
+ * const { fields, append } = useFieldArray({
1070
+ * control,
1071
+ * name: "test"
1072
+ * });
1073
+ *
1074
+ * return (
1075
+ * <form onSubmit={handleSubmit(data => console.log(data))}>
1076
+ * {fields.map((item, index) => (
1077
+ * <input key={item.id} {...register(`test.${index}.firstName`)} />
1078
+ * ))}
1079
+ * <button type="button" onClick={() => append({ firstName: "bill" })}>
1080
+ * append
1081
+ * </button>
1082
+ * <input type="submit" />
1083
+ * </form>
1084
+ * );
1085
+ * }
1086
+ * ```
1087
+ */
1088
+ function useFieldArray(props) {
1089
+ const formControl = useFormControlContext();
1090
+ const { control = formControl, name, keyName = 'id', disabled, shouldUnregister, rules, } = props;
1091
+ const [fields, setFields] = React.useState(control._getFieldArray(name));
1092
+ const ids = React.useRef(control._getFieldArray(name).map(generateId));
1093
+ const _actioned = React.useRef(false);
1094
+ if (!disabled) {
1095
+ control._names.array.add(name);
1096
+ }
1097
+ React.useMemo(() => !disabled &&
1098
+ rules &&
1099
+ fields.length >= 0 &&
1100
+ control.register(name, rules), [control, name, fields.length, rules, disabled]);
1101
+ useIsomorphicLayoutEffect(() => {
1102
+ if (disabled) {
1103
+ return;
1104
+ }
1105
+ return control._subjects.array.subscribe({
1106
+ next: ({ values, name: fieldArrayName, }) => {
1107
+ if (fieldArrayName === name || !fieldArrayName) {
1108
+ const fieldValues = get(values, name);
1109
+ if (Array.isArray(fieldValues)) {
1110
+ setFields(fieldValues);
1111
+ ids.current = fieldValues.map(generateId);
1112
+ }
1113
+ else if (!fieldArrayName) {
1114
+ setFields([]);
1115
+ ids.current = [];
1116
+ }
1117
+ }
1118
+ },
1119
+ }).unsubscribe;
1120
+ }, [control, name, disabled]);
1121
+ const updateValues = React.useCallback((updatedFieldArrayValues) => {
1122
+ _actioned.current = true;
1123
+ control._setFieldArray(name, updatedFieldArrayValues);
1124
+ }, [control, name]);
1125
+ const append = (value, options) => {
1126
+ if (disabled) {
1127
+ return;
1128
+ }
1129
+ const appendValue = convertToArrayPayload(cloneObject(value));
1130
+ const updatedFieldArrayValues = appendAt(control._getFieldArray(name), appendValue);
1131
+ control._names.focus = getFocusFieldName(name, updatedFieldArrayValues.length - 1, options);
1132
+ ids.current = appendAt(ids.current, appendValue.map(generateId));
1133
+ updateValues(updatedFieldArrayValues);
1134
+ setFields(updatedFieldArrayValues);
1135
+ control._setFieldArray(name, updatedFieldArrayValues, appendAt, {
1136
+ argA: fillEmptyArray(value),
1137
+ });
1558
1138
  };
1559
- let _proxySubscribeFormState = {
1560
- ..._proxyFormState,
1139
+ const prepend = (value, options) => {
1140
+ if (disabled) {
1141
+ return;
1142
+ }
1143
+ const prependValue = convertToArrayPayload(cloneObject(value));
1144
+ const updatedFieldArrayValues = prependAt(control._getFieldArray(name), prependValue);
1145
+ control._names.focus = getFocusFieldName(name, 0, options);
1146
+ ids.current = prependAt(ids.current, prependValue.map(generateId));
1147
+ updateValues(updatedFieldArrayValues);
1148
+ setFields(updatedFieldArrayValues);
1149
+ control._setFieldArray(name, updatedFieldArrayValues, prependAt, {
1150
+ argA: fillEmptyArray(value),
1151
+ });
1561
1152
  };
1562
- const _subjects = {
1563
- array: createSubject(),
1564
- state: createSubject(),
1153
+ const remove = (index) => {
1154
+ if (disabled) {
1155
+ return;
1156
+ }
1157
+ const updatedFieldArrayValues = removeArrayAt(control._getFieldArray(name), index);
1158
+ ids.current = removeArrayAt(ids.current, index);
1159
+ updateValues(updatedFieldArrayValues);
1160
+ setFields(updatedFieldArrayValues);
1161
+ !Array.isArray(get(control._fields, name)) &&
1162
+ set(control._fields, name, undefined);
1163
+ control._setFieldArray(name, updatedFieldArrayValues, removeArrayAt, {
1164
+ argA: index,
1165
+ });
1565
1166
  };
1566
- const shouldDisplayAllAssociatedErrors = _options.criteriaMode === VALIDATION_MODE.all;
1567
- const debounce = (callback) => (wait) => {
1568
- clearTimeout(timer);
1569
- timer = setTimeout(callback, wait);
1167
+ const insert$1 = (index, value, options) => {
1168
+ if (disabled) {
1169
+ return;
1170
+ }
1171
+ const insertValue = convertToArrayPayload(cloneObject(value));
1172
+ const updatedFieldArrayValues = insert(control._getFieldArray(name), index, insertValue);
1173
+ control._names.focus = getFocusFieldName(name, index, options);
1174
+ ids.current = insert(ids.current, index, insertValue.map(generateId));
1175
+ updateValues(updatedFieldArrayValues);
1176
+ setFields(updatedFieldArrayValues);
1177
+ control._setFieldArray(name, updatedFieldArrayValues, insert, {
1178
+ argA: index,
1179
+ argB: fillEmptyArray(value),
1180
+ });
1570
1181
  };
1571
- const _setValid = async (shouldUpdateValid) => {
1572
- if (_state.keepIsValid) {
1182
+ const swap = (indexA, indexB) => {
1183
+ if (disabled) {
1573
1184
  return;
1574
1185
  }
1575
- if (!_options.disabled &&
1576
- (_proxyFormState.isValid ||
1577
- _proxySubscribeFormState.isValid ||
1578
- shouldUpdateValid)) {
1579
- let isValid;
1580
- if (_options.resolver) {
1581
- isValid = isEmptyObject((await _runSchema()).errors);
1582
- _updateIsValidating();
1583
- }
1584
- else {
1585
- isValid = await executeBuiltInValidation({
1586
- fields: _fields,
1587
- onlyCheckValid: true,
1588
- eventType: EVENTS.VALID,
1589
- });
1590
- }
1591
- if (isValid !== _formState.isValid) {
1592
- _subjects.state.next({
1593
- isValid,
1594
- });
1595
- }
1186
+ const updatedFieldArrayValues = control._getFieldArray(name);
1187
+ swapArrayAt(updatedFieldArrayValues, indexA, indexB);
1188
+ swapArrayAt(ids.current, indexA, indexB);
1189
+ updateValues(updatedFieldArrayValues);
1190
+ setFields(updatedFieldArrayValues);
1191
+ control._setFieldArray(name, updatedFieldArrayValues, swapArrayAt, {
1192
+ argA: indexA,
1193
+ argB: indexB,
1194
+ }, false);
1195
+ };
1196
+ const move = (from, to) => {
1197
+ if (disabled) {
1198
+ return;
1596
1199
  }
1200
+ const updatedFieldArrayValues = control._getFieldArray(name);
1201
+ moveArrayAt(updatedFieldArrayValues, from, to);
1202
+ moveArrayAt(ids.current, from, to);
1203
+ updateValues(updatedFieldArrayValues);
1204
+ setFields(updatedFieldArrayValues);
1205
+ control._setFieldArray(name, updatedFieldArrayValues, moveArrayAt, {
1206
+ argA: from,
1207
+ argB: to,
1208
+ }, false);
1597
1209
  };
1598
- const _updateIsValidating = (names, isValidating) => {
1599
- if (!_options.disabled &&
1600
- (_proxyFormState.isValidating ||
1601
- _proxyFormState.validatingFields ||
1602
- _proxySubscribeFormState.isValidating ||
1603
- _proxySubscribeFormState.validatingFields)) {
1604
- (names || Array.from(_names.mount)).forEach((name) => {
1605
- if (name) {
1606
- isValidating
1607
- ? set(_formState.validatingFields, name, isValidating)
1608
- : unset(_formState.validatingFields, name);
1609
- }
1610
- });
1611
- _subjects.state.next({
1612
- validatingFields: _formState.validatingFields,
1613
- isValidating: !isEmptyObject(_formState.validatingFields),
1614
- });
1210
+ const update = (index, value) => {
1211
+ if (disabled) {
1212
+ return;
1615
1213
  }
1214
+ const updateValue = cloneObject(value);
1215
+ const updatedFieldArrayValues = updateAt(control._getFieldArray(name), index, updateValue);
1216
+ ids.current = [...updatedFieldArrayValues].map((item, i) => !item || i === index ? generateId() : ids.current[i]);
1217
+ updateValues(updatedFieldArrayValues);
1218
+ setFields([...updatedFieldArrayValues]);
1219
+ control._setFieldArray(name, updatedFieldArrayValues, updateAt, {
1220
+ argA: index,
1221
+ argB: updateValue,
1222
+ }, true, false);
1616
1223
  };
1617
- const _updateDirtyFields = () => {
1618
- _formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
1619
- };
1620
- const _setFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndState = true) => {
1621
- if (args && method && !_options.disabled) {
1622
- _state.action = true;
1623
- if (shouldUpdateFieldsAndState && Array.isArray(get(_fields, name))) {
1624
- const fieldValues = method(get(_fields, name), args.argA, args.argB);
1625
- shouldSetValues && set(_fields, name, fieldValues);
1626
- }
1627
- if (shouldUpdateFieldsAndState &&
1628
- Array.isArray(get(_formState.errors, name))) {
1629
- const errors = method(get(_formState.errors, name), args.argA, args.argB);
1630
- shouldSetValues && set(_formState.errors, name, errors);
1631
- unsetEmptyArray(_formState.errors, name);
1632
- }
1633
- if ((_proxyFormState.touchedFields ||
1634
- _proxySubscribeFormState.touchedFields) &&
1635
- shouldUpdateFieldsAndState &&
1636
- Array.isArray(get(_formState.touchedFields, name))) {
1637
- const touchedFields = method(get(_formState.touchedFields, name), args.argA, args.argB);
1638
- shouldSetValues && set(_formState.touchedFields, name, touchedFields);
1639
- }
1640
- if (_proxyFormState.dirtyFields || _proxySubscribeFormState.dirtyFields) {
1641
- _updateDirtyFields();
1642
- }
1643
- _subjects.state.next({
1644
- name,
1645
- isDirty: _getDirty(name, values),
1646
- dirtyFields: _formState.dirtyFields,
1647
- errors: _formState.errors,
1648
- isValid: _formState.isValid,
1649
- });
1650
- }
1651
- else {
1652
- set(_formValues, name, values);
1224
+ const replace = (value) => {
1225
+ if (disabled) {
1226
+ return;
1653
1227
  }
1228
+ const updatedFieldArrayValues = convertToArrayPayload(cloneObject(value));
1229
+ ids.current = updatedFieldArrayValues.map(generateId);
1230
+ updateValues([...updatedFieldArrayValues]);
1231
+ setFields([...updatedFieldArrayValues]);
1232
+ control._setFieldArray(name, [...updatedFieldArrayValues], (data) => data, {}, true, false);
1654
1233
  };
1655
- const updateErrors = (name, error) => {
1656
- set(_formState.errors, name, error);
1657
- _formState.errors = { ..._formState.errors };
1658
- _subjects.state.next({
1659
- errors: _formState.errors,
1660
- });
1661
- };
1662
- const _setErrors = (errors) => {
1663
- _formState.errors = errors;
1664
- _subjects.state.next({
1665
- errors: _formState.errors,
1666
- isValid: false,
1667
- });
1668
- };
1669
- const hasExplicitNullIntermediate = (name) => {
1670
- const segments = isKey(name) ? [name] : stringToPath(name);
1671
- let formValues = _formValues;
1672
- let defaultValues = _defaultValues;
1673
- for (let i = 0; i < segments.length - 1; i++) {
1674
- const key = segments[i];
1675
- formValues = isNullOrUndefined(formValues) ? formValues : formValues[key];
1676
- defaultValues = isNullOrUndefined(defaultValues)
1677
- ? defaultValues
1678
- : defaultValues[key];
1679
- if (formValues === null && defaultValues !== null) {
1680
- return true;
1681
- }
1234
+ React.useEffect(() => {
1235
+ if (disabled) {
1236
+ return;
1682
1237
  }
1683
- return false;
1684
- };
1685
- const updateValidAndValue = (name, shouldSkipSetValueAs, value, ref) => {
1686
- const field = get(_fields, name);
1687
- if (field) {
1688
- if (hasExplicitNullIntermediate(name)) {
1689
- return;
1690
- }
1691
- const wasUnsetInFormValues = isUndefined(get(_formValues, name));
1692
- const defaultValue = get(_formValues, name, isUndefined(value) ? get(_defaultValues, name) : value);
1693
- isUndefined(defaultValue) ||
1694
- (ref && ref.defaultChecked) ||
1695
- shouldSkipSetValueAs
1696
- ? set(_formValues, name, shouldSkipSetValueAs ? defaultValue : getFieldValue(field._f))
1697
- : setFieldValue(name, defaultValue);
1698
- if (_state.mount && !_state.action) {
1699
- _setValid();
1700
- if (wasUnsetInFormValues &&
1701
- _formState.isDirty &&
1702
- (_proxyFormState.isDirty || _proxySubscribeFormState.isDirty)) {
1703
- const isDirty = _getDirty();
1704
- if (!isDirty) {
1705
- _formState.isDirty = false;
1706
- _subjects.state.next({ ..._formState });
1238
+ control._state.action = false;
1239
+ isWatched(name, control._names) &&
1240
+ control._subjects.state.next({
1241
+ ...control._formState,
1242
+ });
1243
+ const validationModes = getValidationModes(control._options.mode);
1244
+ if (_actioned.current &&
1245
+ (!validationModes.isOnSubmit || control._formState.isSubmitted) &&
1246
+ !getValidationModes(control._options.reValidateMode).isOnSubmit &&
1247
+ !validationModes.isOnBlur) {
1248
+ if (control._options.resolver) {
1249
+ control._runSchema([name]).then((result) => {
1250
+ var _a, _b;
1251
+ control._updateIsValidating([name]);
1252
+ const error = get(result.errors, name);
1253
+ const existingError = get(control._formState.errors, name);
1254
+ const existingErrorType = existingError && (existingError.type || ((_a = existingError.root) === null || _a === void 0 ? void 0 : _a.type));
1255
+ const existingErrorMessage = existingError &&
1256
+ (existingError.message || ((_b = existingError.root) === null || _b === void 0 ? void 0 : _b.message));
1257
+ if (existingError
1258
+ ? (!error && existingErrorType) ||
1259
+ (error &&
1260
+ (existingErrorType !== error.type ||
1261
+ existingErrorMessage !== error.message))
1262
+ : error && error.type) {
1263
+ if (error) {
1264
+ isObject(error) &&
1265
+ !Object.keys(error).some((key) => !Number.isNaN(+key))
1266
+ ? updateFieldArrayRootError(control._formState.errors, { [name]: error }, name)
1267
+ : set(control._formState.errors, name, error);
1268
+ }
1269
+ else {
1270
+ unset(control._formState.errors, name);
1271
+ }
1272
+ control._subjects.state.next({
1273
+ errors: control._formState.errors,
1274
+ });
1707
1275
  }
1708
- }
1709
- if (props.shouldUnregister &&
1710
- wasUnsetInFormValues &&
1711
- !isUndefined(get(_formValues, name)) &&
1712
- isWatched(name, _names)) {
1713
- _state.watch = true;
1276
+ });
1277
+ }
1278
+ else {
1279
+ const field = get(control._fields, name);
1280
+ if (field &&
1281
+ field._f &&
1282
+ !(getValidationModes(control._options.reValidateMode).isOnSubmit &&
1283
+ getValidationModes(control._options.mode).isOnSubmit)) {
1284
+ validateField(field, control._names.disabled, control._formValues, control._options.criteriaMode === VALIDATION_MODE.all, control._options.shouldUseNativeValidation, true).then((error) => !isEmptyObject(error) &&
1285
+ control._subjects.state.next({
1286
+ errors: updateFieldArrayRootError(control._formState.errors, error, name),
1287
+ }));
1714
1288
  }
1715
1289
  }
1716
1290
  }
1717
- };
1718
- const updateTouchAndDirty = (name, fieldValue, isBlurEvent, shouldDirty, shouldRender) => {
1719
- let shouldUpdateField = false;
1720
- let isPreviousDirty = false;
1721
- const output = {
1722
- name,
1723
- };
1724
- if (!_options.disabled) {
1725
- if (!isBlurEvent || shouldDirty) {
1726
- const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
1727
- if (_proxyFormState.isDirty || _proxySubscribeFormState.isDirty) {
1728
- isPreviousDirty = _formState.isDirty;
1729
- _formState.isDirty = output.isDirty =
1730
- !isCurrentFieldPristine || _getDirty();
1731
- shouldUpdateField = isPreviousDirty !== output.isDirty;
1732
- }
1733
- isPreviousDirty = !!get(_formState.dirtyFields, name);
1734
- if (isCurrentFieldPristine !== _formState.isDirty) {
1735
- _formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
1736
- }
1737
- else {
1738
- isCurrentFieldPristine
1739
- ? unset(_formState.dirtyFields, name)
1740
- : set(_formState.dirtyFields, name, true);
1291
+ // External updates that change `fields` (e.g. reset() or setValue() on
1292
+ // the array) already notify subscribers with the up-to-date values
1293
+ // themselves, so only re-broadcast here for genuine array method calls.
1294
+ _actioned.current &&
1295
+ control._subjects.state.next({
1296
+ name,
1297
+ values: cloneObject(control._formValues),
1298
+ });
1299
+ control._names.focus &&
1300
+ iterateFieldsByAction(control._fields, (ref, key) => {
1301
+ if (control._names.focus &&
1302
+ key.startsWith(control._names.focus) &&
1303
+ ref.focus) {
1304
+ ref.focus();
1305
+ return 1;
1741
1306
  }
1742
- output.dirtyFields = _formState.dirtyFields;
1743
- shouldUpdateField =
1744
- shouldUpdateField ||
1745
- ((_proxyFormState.dirtyFields ||
1746
- _proxySubscribeFormState.dirtyFields) &&
1747
- isPreviousDirty !== !isCurrentFieldPristine);
1307
+ return;
1308
+ });
1309
+ control._names.focus = '';
1310
+ control._setValid();
1311
+ _actioned.current = false;
1312
+ }, [fields, name, control, disabled]);
1313
+ React.useEffect(() => {
1314
+ if (!disabled) {
1315
+ !get(control._formValues, name) && control._setFieldArray(name);
1316
+ }
1317
+ return () => {
1318
+ if (disabled) {
1319
+ return;
1748
1320
  }
1749
- if (isBlurEvent) {
1750
- const isPreviousFieldTouched = get(_formState.touchedFields, name);
1751
- if (!isPreviousFieldTouched) {
1752
- set(_formState.touchedFields, name, isBlurEvent);
1753
- output.touchedFields = _formState.touchedFields;
1754
- shouldUpdateField =
1755
- shouldUpdateField ||
1756
- ((_proxyFormState.touchedFields ||
1757
- _proxySubscribeFormState.touchedFields) &&
1758
- isPreviousFieldTouched !== isBlurEvent);
1321
+ const shouldKeepFieldArrayValues = !(control._options.shouldUnregister || shouldUnregister);
1322
+ const updateMounted = (name, value) => {
1323
+ const field = get(control._fields, name);
1324
+ if (field && field._f) {
1325
+ field._f.mount = value;
1759
1326
  }
1760
- }
1761
- shouldUpdateField && shouldRender && _subjects.state.next(output);
1762
- }
1763
- return shouldUpdateField ? output : {};
1764
- };
1765
- const shouldRenderByError = (name, isValid, error, fieldState) => {
1766
- const previousFieldError = get(_formState.errors, name);
1767
- const shouldUpdateValid = (_proxyFormState.isValid || _proxySubscribeFormState.isValid) &&
1768
- isBoolean(isValid) &&
1769
- _formState.isValid !== isValid;
1770
- if (_options.delayError && error) {
1771
- delayErrorCallback = debounce(() => updateErrors(name, error));
1772
- delayErrorCallback(_options.delayError);
1773
- }
1774
- else {
1775
- clearTimeout(timer);
1776
- delayErrorCallback = null;
1777
- error
1778
- ? set(_formState.errors, name, error)
1779
- : unset(_formState.errors, name);
1780
- _formState.errors = { ..._formState.errors };
1781
- }
1782
- if ((error ? !deepEqual(previousFieldError, error) : previousFieldError) ||
1783
- !isEmptyObject(fieldState) ||
1784
- shouldUpdateValid) {
1785
- const updatedFormState = {
1786
- ...fieldState,
1787
- ...(shouldUpdateValid && isBoolean(isValid) ? { isValid } : {}),
1788
- errors: _formState.errors,
1789
- name,
1790
1327
  };
1791
- _formState = {
1792
- ..._formState,
1793
- ...updatedFormState,
1328
+ if (_actioned.current && shouldKeepFieldArrayValues) {
1329
+ control._subjects.state.next({
1330
+ name,
1331
+ values: cloneObject(control._formValues),
1332
+ });
1333
+ }
1334
+ shouldKeepFieldArrayValues
1335
+ ? updateMounted(name, false)
1336
+ : control.unregister(name);
1337
+ };
1338
+ }, [name, control, keyName, shouldUnregister, disabled]);
1339
+ return {
1340
+ swap: React.useCallback(swap, [updateValues, name, control, disabled]),
1341
+ move: React.useCallback(move, [updateValues, name, control, disabled]),
1342
+ prepend: React.useCallback(prepend, [
1343
+ updateValues,
1344
+ name,
1345
+ control,
1346
+ disabled,
1347
+ ]),
1348
+ append: React.useCallback(append, [updateValues, name, control, disabled]),
1349
+ remove: React.useCallback(remove, [updateValues, name, control, disabled]),
1350
+ insert: React.useCallback(insert$1, [updateValues, name, control, disabled]),
1351
+ update: React.useCallback(update, [updateValues, name, control, disabled]),
1352
+ replace: React.useCallback(replace, [
1353
+ updateValues,
1354
+ name,
1355
+ control,
1356
+ disabled,
1357
+ ]),
1358
+ fields: React.useMemo(() => fields.map((field, index) => ({
1359
+ ...field,
1360
+ ...(isBoolean(disabled) ? { disabled } : {}),
1361
+ [keyName]: ids.current[index] || generateId(),
1362
+ })), [fields, keyName, disabled]),
1363
+ };
1364
+ }
1365
+
1366
+ /**
1367
+ * Component based on `useFieldArray` hook to work with controlled component.
1368
+ *
1369
+ * @example
1370
+ * ```tsx
1371
+ * function App() {
1372
+ * const { control, register } = useForm<FormValues>({
1373
+ * defaultValues: {
1374
+ * test: [
1375
+ * {
1376
+ * value: '',
1377
+ * },
1378
+ * ],
1379
+ * },
1380
+ * });
1381
+ *
1382
+ * return (
1383
+ * <form>
1384
+ * <FieldArray
1385
+ * control={control}
1386
+ * name="test"
1387
+ * render={({ fields }) =>
1388
+ * fields.map((field, index) => (
1389
+ * <input key={field.id} {...register(`test.${index}.value`)} />
1390
+ * ))
1391
+ * }
1392
+ * />
1393
+ * </form>
1394
+ * );
1395
+ * }
1396
+ * ```
1397
+ */
1398
+ const FieldArray = (props) => props.render(useFieldArray(props));
1399
+
1400
+ const flatten = (obj) => {
1401
+ const output = {};
1402
+ for (const key of Object.keys(obj)) {
1403
+ if (isObjectType(obj[key]) &&
1404
+ obj[key] !== null &&
1405
+ !isDateObject(obj[key])) {
1406
+ const nested = flatten(obj[key]);
1407
+ for (const nestedKey of Object.keys(nested)) {
1408
+ output[`${key}.${nestedKey}`] = nested[nestedKey];
1409
+ }
1410
+ }
1411
+ else {
1412
+ output[key] = obj[key];
1413
+ }
1414
+ }
1415
+ return output;
1416
+ };
1417
+
1418
+ const HookFormContext = React.createContext(null);
1419
+ HookFormContext.displayName = 'HookFormContext';
1420
+ /**
1421
+ * This custom hook allows you to access the form context. useFormContext is intended to be used in deeply nested structures, where it would become inconvenient to pass the context as a prop. To be used with {@link FormProvider}.
1422
+ *
1423
+ * @remarks
1424
+ * [API](https://react-hook-form.com/docs/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
1425
+ *
1426
+ * @returns return all useForm methods
1427
+ *
1428
+ * @example
1429
+ * ```tsx
1430
+ * function App() {
1431
+ * const methods = useForm();
1432
+ * const onSubmit = data => console.log(data);
1433
+ *
1434
+ * return (
1435
+ * <FormProvider {...methods} >
1436
+ * <form onSubmit={methods.handleSubmit(onSubmit)}>
1437
+ * <NestedInput />
1438
+ * <input type="submit" />
1439
+ * </form>
1440
+ * </FormProvider>
1441
+ * );
1442
+ * }
1443
+ *
1444
+ * function NestedInput() {
1445
+ * const { register } = useFormContext(); // retrieve all hook methods
1446
+ * return <input {...register("test")} />;
1447
+ * }
1448
+ * ```
1449
+ */
1450
+ const useFormContext = () => React.useContext(HookFormContext);
1451
+ /**
1452
+ * A provider component that propagates the `useForm` methods to all children components via [React Context](https://react.dev/reference/react/useContext) API. To be used with {@link useFormContext}.
1453
+ *
1454
+ * @remarks
1455
+ * [API](https://react-hook-form.com/docs/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
1456
+ *
1457
+ * @param props - all useForm methods
1458
+ *
1459
+ * @example
1460
+ * ```tsx
1461
+ * function App() {
1462
+ * const methods = useForm();
1463
+ * const onSubmit = data => console.log(data);
1464
+ *
1465
+ * return (
1466
+ * <FormProvider {...methods} >
1467
+ * <form onSubmit={methods.handleSubmit(onSubmit)}>
1468
+ * <NestedInput />
1469
+ * <input type="submit" />
1470
+ * </form>
1471
+ * </FormProvider>
1472
+ * );
1473
+ * }
1474
+ *
1475
+ * function NestedInput() {
1476
+ * const { register } = useFormContext(); // retrieve all hook methods
1477
+ * return <input {...register("test")} />;
1478
+ * }
1479
+ * ```
1480
+ */
1481
+ const FormProvider = ({ children, watch, getValues, getFieldState, setError, clearErrors, setValue, setValues, trigger, formState, resetField, reset, resetDefaultValues, handleSubmit, unregister, control, register, setFocus, subscribe, }) => {
1482
+ const memoizedValue = React.useMemo(() => ({
1483
+ watch,
1484
+ getValues,
1485
+ getFieldState,
1486
+ setError,
1487
+ clearErrors,
1488
+ setValue,
1489
+ setValues,
1490
+ trigger,
1491
+ formState,
1492
+ resetField,
1493
+ reset,
1494
+ resetDefaultValues,
1495
+ handleSubmit,
1496
+ unregister,
1497
+ control,
1498
+ register,
1499
+ setFocus,
1500
+ subscribe,
1501
+ }), [
1502
+ clearErrors,
1503
+ control,
1504
+ formState,
1505
+ getFieldState,
1506
+ getValues,
1507
+ handleSubmit,
1508
+ register,
1509
+ reset,
1510
+ resetDefaultValues,
1511
+ resetField,
1512
+ setError,
1513
+ setFocus,
1514
+ setValue,
1515
+ setValues,
1516
+ subscribe,
1517
+ trigger,
1518
+ unregister,
1519
+ watch,
1520
+ ]);
1521
+ return (React.createElement(HookFormContext.Provider, { value: memoizedValue },
1522
+ React.createElement(HookFormControlContext.Provider, { value: memoizedValue.control }, children)));
1523
+ };
1524
+
1525
+ const POST_REQUEST = 'post';
1526
+ /**
1527
+ * Form component to manage submission.
1528
+ *
1529
+ * @param props - to setup submission detail. {@link FormProps}
1530
+ *
1531
+ * @returns form component or headless render prop.
1532
+ *
1533
+ * @example
1534
+ * ```tsx
1535
+ * function App() {
1536
+ * const { control, formState: { errors } } = useForm();
1537
+ *
1538
+ * return (
1539
+ * <Form action="/api" control={control}>
1540
+ * <input {...register("name")} />
1541
+ * <p>{errors?.root?.server && 'Server error'}</p>
1542
+ * <button>Submit</button>
1543
+ * </Form>
1544
+ * );
1545
+ * }
1546
+ * ```
1547
+ */
1548
+ function Form(props) {
1549
+ const methods = useFormContext();
1550
+ const [mounted, setMounted] = React.useState(false);
1551
+ const { control = methods.control, onSubmit, children, action, method = POST_REQUEST, headers, encType, onError, render, onSuccess, validateStatus, ...rest } = props;
1552
+ const submit = React.useCallback(async (event) => {
1553
+ let hasError = false;
1554
+ let type = '';
1555
+ await control.handleSubmit(async (data) => {
1556
+ const formData = new FormData();
1557
+ let formDataJson = '';
1558
+ try {
1559
+ formDataJson = JSON.stringify(data);
1560
+ }
1561
+ catch (_a) { }
1562
+ const flattenFormValues = flatten(data);
1563
+ for (const key in flattenFormValues) {
1564
+ formData.append(key, flattenFormValues[key]);
1565
+ }
1566
+ if (onSubmit) {
1567
+ await onSubmit({
1568
+ data,
1569
+ event,
1570
+ method,
1571
+ formData,
1572
+ formDataJson,
1573
+ });
1574
+ }
1575
+ if (action) {
1576
+ try {
1577
+ const shouldStringifySubmissionData = [
1578
+ headers && headers['Content-Type'],
1579
+ encType,
1580
+ ].some((value) => value && value.includes('json'));
1581
+ const response = await fetch(String(action), {
1582
+ method,
1583
+ headers: {
1584
+ ...headers,
1585
+ ...(encType && encType !== 'multipart/form-data'
1586
+ ? { 'Content-Type': encType }
1587
+ : {}),
1588
+ },
1589
+ body: shouldStringifySubmissionData ? formDataJson : formData,
1590
+ });
1591
+ if (response &&
1592
+ (validateStatus
1593
+ ? !validateStatus(response.status)
1594
+ : response.status < 200 || response.status >= 300)) {
1595
+ hasError = true;
1596
+ onError && onError({ response });
1597
+ type = String(response.status);
1598
+ }
1599
+ else {
1600
+ onSuccess && onSuccess({ response });
1601
+ }
1602
+ }
1603
+ catch (error) {
1604
+ hasError = true;
1605
+ onError && onError({ error });
1606
+ }
1607
+ }
1608
+ })(event);
1609
+ if (hasError && control) {
1610
+ control._subjects.state.next({
1611
+ isSubmitSuccessful: false,
1612
+ });
1613
+ control.setError('root.server', {
1614
+ type,
1615
+ });
1616
+ }
1617
+ }, [
1618
+ control,
1619
+ onSubmit,
1620
+ method,
1621
+ action,
1622
+ headers,
1623
+ encType,
1624
+ validateStatus,
1625
+ onError,
1626
+ onSuccess,
1627
+ ]);
1628
+ React.useEffect(() => {
1629
+ setMounted(true);
1630
+ }, []);
1631
+ return render ? (React.createElement(React.Fragment, null, render({
1632
+ submit,
1633
+ }))) : (React.createElement("form", { noValidate: mounted, action: action, method: method, encType: encType, onSubmit: submit, ...rest }, children));
1634
+ }
1635
+
1636
+ const FormStateSubscribe = ({ control, disabled, exact, name, render, }) => render(useFormState({ control, name, disabled, exact }));
1637
+
1638
+ var createSubject = () => {
1639
+ let _observers = [];
1640
+ const next = (value) => {
1641
+ for (const observer of _observers) {
1642
+ observer.next && observer.next(value);
1643
+ }
1644
+ };
1645
+ const subscribe = (observer) => {
1646
+ _observers.push(observer);
1647
+ return {
1648
+ unsubscribe: () => {
1649
+ _observers = _observers.filter((o) => o !== observer);
1650
+ },
1651
+ };
1652
+ };
1653
+ const unsubscribe = () => {
1654
+ _observers = [];
1655
+ };
1656
+ return {
1657
+ get observers() {
1658
+ return _observers;
1659
+ },
1660
+ next,
1661
+ subscribe,
1662
+ unsubscribe,
1663
+ };
1664
+ };
1665
+
1666
+ function extractFormValues(fieldsState, formValues) {
1667
+ const values = {};
1668
+ for (const key in fieldsState) {
1669
+ if (fieldsState.hasOwnProperty(key)) {
1670
+ const fieldState = fieldsState[key];
1671
+ const fieldValue = formValues[key];
1672
+ if (fieldState && isObject(fieldState) && fieldValue) {
1673
+ const nestedFieldsState = extractFormValues(fieldState, fieldValue);
1674
+ if (isObject(nestedFieldsState)) {
1675
+ values[key] = nestedFieldsState;
1676
+ }
1677
+ }
1678
+ else if (fieldsState[key]) {
1679
+ values[key] = fieldValue;
1680
+ }
1681
+ }
1682
+ }
1683
+ return values;
1684
+ }
1685
+
1686
+ var isMultipleSelect = (element) => element.type === `select-multiple`;
1687
+
1688
+ var isRadioOrCheckbox = (ref) => isRadioInput(ref) || isCheckBoxInput(ref);
1689
+
1690
+ var live = (ref) => isHTMLElement(ref) && ref.isConnected;
1691
+
1692
+ var objectHasFunction = (data) => {
1693
+ for (const key in data) {
1694
+ if (isFunction(data[key])) {
1695
+ return true;
1696
+ }
1697
+ }
1698
+ return false;
1699
+ };
1700
+
1701
+ function isTraversable(value) {
1702
+ return Array.isArray(value) || (isObject(value) && !objectHasFunction(value));
1703
+ }
1704
+ function isRegisteredLeaf(fieldRef) {
1705
+ return !!(fieldRef && '_f' in fieldRef);
1706
+ }
1707
+ function isEmptyDirtyContainer(value) {
1708
+ return Array.isArray(value)
1709
+ ? !value.some((item) => !isUndefined(item))
1710
+ : !Object.keys(value).length;
1711
+ }
1712
+ function clearDirtyField(container, key) {
1713
+ if (Array.isArray(container)) {
1714
+ container[key] = undefined;
1715
+ }
1716
+ else {
1717
+ delete container[key];
1718
+ }
1719
+ }
1720
+ function markFieldsDirty(data, fields = {}, fieldRefs) {
1721
+ for (const key in data) {
1722
+ const value = data[key];
1723
+ const fieldRef = fieldRefs && fieldRefs[key];
1724
+ if (isTraversable(value) &&
1725
+ (!Array.isArray(value) || !isRegisteredLeaf(fieldRef))) {
1726
+ fields[key] = Array.isArray(value) ? [] : {};
1727
+ markFieldsDirty(value, fields[key], fieldRef);
1728
+ if (isEmptyDirtyContainer(fields[key])) {
1729
+ clearDirtyField(fields, key);
1730
+ }
1731
+ }
1732
+ else if (!isUndefined(value)) {
1733
+ fields[key] = true;
1734
+ }
1735
+ }
1736
+ return fields;
1737
+ }
1738
+ function getDirtyFields(data, formValues, dirtyFieldsFromValues, fieldRefs) {
1739
+ if (!dirtyFieldsFromValues) {
1740
+ dirtyFieldsFromValues = markFieldsDirty(formValues, {}, fieldRefs);
1741
+ }
1742
+ for (const key in data) {
1743
+ const value = data[key];
1744
+ const fieldRef = fieldRefs && fieldRefs[key];
1745
+ if (isTraversable(value) &&
1746
+ (!Array.isArray(value) || !isRegisteredLeaf(fieldRef))) {
1747
+ if (isUndefined(formValues) || isPrimitive(dirtyFieldsFromValues[key])) {
1748
+ dirtyFieldsFromValues[key] = markFieldsDirty(value, Array.isArray(value) ? [] : {}, fieldRef);
1749
+ }
1750
+ else {
1751
+ getDirtyFields(value, isNullOrUndefined(formValues) ? {} : formValues[key], dirtyFieldsFromValues[key], fieldRef);
1752
+ }
1753
+ if (isEmptyDirtyContainer(dirtyFieldsFromValues[key])) {
1754
+ clearDirtyField(dirtyFieldsFromValues, key);
1755
+ }
1756
+ }
1757
+ else if (deepEqual(value, formValues[key])) {
1758
+ clearDirtyField(dirtyFieldsFromValues, key);
1759
+ }
1760
+ else {
1761
+ dirtyFieldsFromValues[key] = true;
1762
+ }
1763
+ }
1764
+ return dirtyFieldsFromValues;
1765
+ }
1766
+
1767
+ var getFieldValueAs = (value, { valueAsNumber, valueAsDate, setValueAs }) => isUndefined(value)
1768
+ ? value
1769
+ : valueAsNumber
1770
+ ? value === ''
1771
+ ? NaN
1772
+ : value
1773
+ ? +value
1774
+ : value
1775
+ : valueAsDate && isString(value)
1776
+ ? new Date(value)
1777
+ : setValueAs
1778
+ ? setValueAs(value)
1779
+ : value;
1780
+
1781
+ function getFieldValue(_f) {
1782
+ const ref = _f.ref;
1783
+ if (isFileInput(ref)) {
1784
+ return ref.files;
1785
+ }
1786
+ if (isRadioInput(ref)) {
1787
+ return getRadioValue(_f.refs).value;
1788
+ }
1789
+ if (isMultipleSelect(ref)) {
1790
+ return [...ref.selectedOptions].map(({ value }) => value);
1791
+ }
1792
+ if (isCheckBoxInput(ref)) {
1793
+ return getCheckboxValue(_f.refs).value;
1794
+ }
1795
+ return getFieldValueAs(isUndefined(ref.value) ? _f.ref.value : ref.value, _f);
1796
+ }
1797
+
1798
+ var getResolverOptions = (fieldsNames, _fields, criteriaMode, shouldUseNativeValidation) => {
1799
+ const fields = {};
1800
+ for (const name of fieldsNames) {
1801
+ const field = get(_fields, name);
1802
+ field && set(fields, name, field._f);
1803
+ }
1804
+ return {
1805
+ criteriaMode,
1806
+ names: [...fieldsNames],
1807
+ fields,
1808
+ shouldUseNativeValidation,
1809
+ };
1810
+ };
1811
+
1812
+ var getRuleValue = (rule) => isUndefined(rule)
1813
+ ? rule
1814
+ : isRegex(rule)
1815
+ ? rule.source
1816
+ : isObject(rule)
1817
+ ? isRegex(rule.value)
1818
+ ? rule.value.source
1819
+ : rule.value
1820
+ : rule;
1821
+
1822
+ const ASYNC_FUNCTION = 'AsyncFunction';
1823
+ var hasPromiseValidation = (fieldReference) => {
1824
+ if (!fieldReference || !fieldReference.validate)
1825
+ return false;
1826
+ if (isFunction(fieldReference.validate)) {
1827
+ return fieldReference.validate.constructor.name === ASYNC_FUNCTION;
1828
+ }
1829
+ if (isObject(fieldReference.validate)) {
1830
+ for (const key in fieldReference.validate) {
1831
+ if (fieldReference.validate[key].constructor
1832
+ .name === ASYNC_FUNCTION) {
1833
+ return true;
1834
+ }
1835
+ }
1836
+ }
1837
+ return false;
1838
+ };
1839
+
1840
+ var hasValidation = (options) => options.mount &&
1841
+ (options.required ||
1842
+ options.min ||
1843
+ options.max ||
1844
+ options.maxLength ||
1845
+ options.minLength ||
1846
+ options.pattern ||
1847
+ options.validate);
1848
+
1849
+ function schemaErrorLookup(errors, _fields, name) {
1850
+ const error = get(errors, name);
1851
+ if (error || isKey(name)) {
1852
+ return {
1853
+ error,
1854
+ name,
1855
+ };
1856
+ }
1857
+ const names = name.split('.');
1858
+ while (names.length) {
1859
+ const fieldName = names.join('.');
1860
+ const field = get(_fields, fieldName);
1861
+ const foundError = get(errors, fieldName);
1862
+ if (field && !Array.isArray(field) && name !== fieldName) {
1863
+ return { name };
1864
+ }
1865
+ if (foundError && foundError.type) {
1866
+ return {
1867
+ name: fieldName,
1868
+ error: foundError,
1869
+ };
1870
+ }
1871
+ if (foundError && foundError.root && foundError.root.type) {
1872
+ return {
1873
+ name: `${fieldName}.root`,
1874
+ error: foundError.root,
1794
1875
  };
1795
- _subjects.state.next(updatedFormState);
1796
1876
  }
1877
+ names.pop();
1878
+ }
1879
+ return {
1880
+ name,
1797
1881
  };
1798
- const _runSchema = async (name) => {
1799
- _updateIsValidating(name, true);
1800
- return await _options.resolver(_formValues, _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation));
1882
+ }
1883
+
1884
+ var shouldRenderFormState = (formStateData, _proxyFormState, updateFormState, isRoot) => {
1885
+ updateFormState(formStateData);
1886
+ const { name, ...formState } = formStateData;
1887
+ const keys = Object.keys(formState);
1888
+ return (!keys.length ||
1889
+ (isRoot && keys.length >= Object.keys(_proxyFormState).length) ||
1890
+ keys.find((key) => _proxyFormState[key] ===
1891
+ (!isRoot || VALIDATION_MODE.all)));
1892
+ };
1893
+
1894
+ var shouldSubscribeByName = (name, signalName, exact) => !name ||
1895
+ !signalName ||
1896
+ name === signalName ||
1897
+ convertToArrayPayload(name).some((currentName) => currentName &&
1898
+ (exact
1899
+ ? currentName === signalName || currentName.startsWith(signalName + '.')
1900
+ : currentName.startsWith(signalName) ||
1901
+ signalName.startsWith(currentName)));
1902
+
1903
+ var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode) => {
1904
+ if (mode.isOnAll) {
1905
+ return false;
1906
+ }
1907
+ else if (!isSubmitted && mode.isOnTouch) {
1908
+ return !(isTouched || isBlurEvent);
1909
+ }
1910
+ else if (isSubmitted ? reValidateMode.isOnBlur : mode.isOnBlur) {
1911
+ return !isBlurEvent;
1912
+ }
1913
+ else if (isSubmitted ? reValidateMode.isOnChange : mode.isOnChange) {
1914
+ return isBlurEvent;
1915
+ }
1916
+ return true;
1917
+ };
1918
+
1919
+ var unsetEmptyArray = (ref, name) => !compact(get(ref, name)).length && unset(ref, name);
1920
+
1921
+ const defaultOptions = {
1922
+ mode: VALIDATION_MODE.onSubmit,
1923
+ reValidateMode: VALIDATION_MODE.onChange,
1924
+ shouldFocusError: true,
1925
+ };
1926
+ const FORM_ERROR_TYPE = 'form';
1927
+ const DEFAULT_FORM_STATE = {
1928
+ submitCount: 0,
1929
+ isDirty: false,
1930
+ isReady: false,
1931
+ isValidating: false,
1932
+ isSubmitted: false,
1933
+ isSubmitting: false,
1934
+ isSubmitSuccessful: false,
1935
+ isValid: false,
1936
+ touchedFields: {},
1937
+ dirtyFields: {},
1938
+ validatingFields: {},
1939
+ };
1940
+ function createFormControl(props = {}) {
1941
+ let _options = {
1942
+ ...defaultOptions,
1943
+ ...props,
1801
1944
  };
1802
- const executeSchemaAndUpdateState = async (names) => {
1803
- const { errors } = await _runSchema(names);
1804
- _updateIsValidating(names);
1805
- if (names) {
1806
- for (const name of names) {
1807
- const error = get(errors, name);
1808
- error
1809
- ? _names.array.has(name) &&
1810
- isObject(error) &&
1811
- !Object.keys(error).some((key) => !Number.isNaN(Number(key)))
1812
- ? updateFieldArrayRootError(_formState.errors, { [name]: error }, name)
1813
- : set(_formState.errors, name, error)
1814
- : unset(_formState.errors, name);
1815
- }
1816
- _formState.errors = { ..._formState.errors };
1817
- }
1818
- else {
1819
- _formState.errors = errors;
1820
- }
1821
- return errors;
1945
+ let _formState = {
1946
+ ...cloneObject(DEFAULT_FORM_STATE),
1947
+ isLoading: isFunction(_options.defaultValues),
1948
+ errors: _options.errors || {},
1949
+ disabled: _options.disabled || false,
1822
1950
  };
1823
- const validateForm = async ({ name, eventType, }) => {
1824
- if (props.validate) {
1825
- const result = await props.validate({
1826
- formValues: _formValues,
1827
- formState: _formState,
1828
- name,
1829
- eventType,
1830
- });
1831
- if (isObject(result)) {
1832
- for (const key in result) {
1833
- const error = result[key];
1834
- if (error) {
1835
- setError(`${FORM_ERROR_TYPE}.${key}`, {
1836
- message: isString(error.message) ? error.message : '',
1837
- type: error.type || INPUT_VALIDATION_RULES.validate,
1838
- });
1839
- }
1840
- }
1841
- }
1842
- else if (isString(result) || !result) {
1843
- setError(FORM_ERROR_TYPE, {
1844
- message: result || '',
1845
- type: INPUT_VALIDATION_RULES.validate,
1846
- });
1847
- }
1848
- else {
1849
- clearErrors(FORM_ERROR_TYPE);
1850
- }
1851
- return result;
1852
- }
1853
- return true;
1951
+ let _fields = {};
1952
+ let _defaultValues = isObject(_options.defaultValues) || isObject(_options.values)
1953
+ ? cloneObject(_options.defaultValues || _options.values) || {}
1954
+ : {};
1955
+ let _formValues = _options.shouldUnregister
1956
+ ? {}
1957
+ : cloneObject(_defaultValues);
1958
+ let _state = {
1959
+ action: false,
1960
+ mount: false,
1961
+ watch: false,
1962
+ keepIsValid: false,
1854
1963
  };
1855
- const executeBuiltInValidation = async ({ fields, onlyCheckValid, name, eventType, context = {
1856
- valid: true,
1857
- runRootValidation: false,
1858
- }, }) => {
1859
- if (props.validate) {
1860
- context.runRootValidation = true;
1861
- const result = await validateForm({
1862
- name,
1863
- eventType,
1864
- });
1865
- if (!result) {
1866
- context.valid = false;
1867
- if (onlyCheckValid) {
1868
- return context.valid;
1869
- }
1870
- }
1871
- }
1872
- for (const name in fields) {
1873
- const field = fields[name];
1874
- if (field) {
1875
- const { _f, ...fieldValue } = field;
1876
- if (_f) {
1877
- const isFieldArrayRoot = _names.array.has(_f.name);
1878
- const isPromiseFunction = field._f && hasPromiseValidation(field._f);
1879
- const shouldTrackIsValidatingState = _proxyFormState.validatingFields ||
1880
- _proxyFormState.isValidating ||
1881
- _proxySubscribeFormState.validatingFields ||
1882
- _proxySubscribeFormState.isValidating;
1883
- if (isPromiseFunction && shouldTrackIsValidatingState) {
1884
- _updateIsValidating([_f.name], true);
1885
- }
1886
- const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !onlyCheckValid, isFieldArrayRoot);
1887
- if (isPromiseFunction && shouldTrackIsValidatingState) {
1888
- _updateIsValidating([_f.name]);
1889
- }
1890
- if (fieldError[_f.name]) {
1891
- context.valid = false;
1892
- if (onlyCheckValid) {
1893
- break;
1894
- }
1895
- }
1896
- !onlyCheckValid &&
1897
- (get(fieldError, _f.name)
1898
- ? isFieldArrayRoot
1899
- ? updateFieldArrayRootError(_formState.errors, fieldError, _f.name)
1900
- : set(_formState.errors, _f.name, fieldError[_f.name])
1901
- : unset(_formState.errors, _f.name));
1902
- if (props.shouldUseNativeValidation && fieldError[_f.name]) {
1903
- break;
1904
- }
1905
- }
1906
- !isEmptyObject(fieldValue) &&
1907
- (await executeBuiltInValidation({
1908
- context,
1909
- onlyCheckValid,
1910
- fields: fieldValue,
1911
- name: name,
1912
- eventType,
1913
- }));
1914
- }
1915
- }
1916
- return context.valid;
1964
+ let _names = {
1965
+ mount: new Set(),
1966
+ disabled: new Set(),
1967
+ unMount: new Set(),
1968
+ array: new Set(),
1969
+ watch: new Set(),
1970
+ registerName: new Set(),
1971
+ };
1972
+ const delayErrorCallbacks = {};
1973
+ const timers = {};
1974
+ let _valuesSubscriberCount = 0;
1975
+ let _validationModeBeforeSubmit = getValidationModes(_options.mode);
1976
+ let _validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
1977
+ const defaultProxyFormState = {
1978
+ isDirty: false,
1979
+ dirtyFields: false,
1980
+ validatingFields: false,
1981
+ touchedFields: false,
1982
+ isValidating: false,
1983
+ isValid: false,
1984
+ errors: false,
1917
1985
  };
1918
- const _removeUnmounted = () => {
1919
- for (const name of _names.unMount) {
1920
- const field = get(_fields, name);
1921
- field &&
1922
- (field._f.refs
1923
- ? field._f.refs.every((ref) => !live(ref))
1924
- : !live(field._f.ref)) &&
1925
- unregister(name);
1926
- }
1927
- _names.unMount = new Set();
1986
+ const _proxyFormState = {
1987
+ ...defaultProxyFormState,
1928
1988
  };
1929
- const _getDirty = (name, data) => !_options.disabled &&
1930
- (name && data && set(_formValues, name, data),
1931
- !deepEqual(_state.mount ? _formValues : _defaultValues, _defaultValues));
1932
- const _getWatch = (names, defaultValue, isGlobal) => generateWatchOutput(names, _names, {
1933
- ...(_state.mount
1934
- ? _formValues
1935
- : isUndefined(defaultValue)
1936
- ? _defaultValues
1937
- : isString(names)
1938
- ? { [names]: defaultValue }
1939
- : defaultValue),
1940
- }, isGlobal, defaultValue);
1941
- const _getFieldArray = (name) => compact(get(_state.mount ? _formValues : _defaultValues, name, _options.shouldUnregister ? get(_defaultValues, name, []) : []));
1942
- const setFieldValue = (name, value, options = {}, skipClone = false, skipRender = false) => {
1943
- const field = get(_fields, name);
1944
- let fieldValue = value;
1945
- if (field) {
1946
- const fieldReference = field._f;
1947
- if (fieldReference) {
1948
- !fieldReference.disabled &&
1949
- set(_formValues, name, getFieldValueAs(value, fieldReference));
1950
- fieldValue =
1951
- isHTMLElement(fieldReference.ref) && isNullOrUndefined(value)
1952
- ? ''
1953
- : value;
1954
- if (isMultipleSelect(fieldReference.ref)) {
1955
- [...fieldReference.ref.options].forEach((optionRef) => (optionRef.selected = fieldValue.includes(optionRef.value)));
1956
- }
1957
- else if (fieldReference.refs) {
1958
- if (isCheckBoxInput(fieldReference.ref)) {
1959
- fieldReference.refs.forEach((checkboxRef) => {
1960
- if (!checkboxRef.defaultChecked || !checkboxRef.disabled) {
1961
- if (Array.isArray(fieldValue)) {
1962
- checkboxRef.checked = !!fieldValue.find((data) => data === checkboxRef.value);
1963
- }
1964
- else {
1965
- checkboxRef.checked =
1966
- fieldValue === checkboxRef.value || !!fieldValue;
1967
- }
1968
- }
1969
- });
1970
- }
1971
- else {
1972
- fieldReference.refs.forEach((radioRef) => (radioRef.checked = radioRef.value === fieldValue));
1973
- }
1974
- }
1975
- else if (isFileInput(fieldReference.ref)) {
1976
- fieldReference.ref.value = '';
1977
- }
1978
- else {
1979
- fieldReference.ref.value = fieldValue;
1980
- if (!fieldReference.ref.type && !skipRender) {
1981
- _subjects.state.next({
1982
- name,
1983
- values: skipClone ? _formValues : cloneObject(_formValues),
1984
- });
1985
- }
1986
- }
1987
- }
1988
- }
1989
- (options.shouldDirty || options.shouldTouch) &&
1990
- updateTouchAndDirty(name, fieldValue, options.shouldTouch, options.shouldDirty, !skipRender);
1991
- options.shouldValidate && trigger(name);
1989
+ let _proxySubscribeFormState = {
1990
+ ..._proxyFormState,
1992
1991
  };
1993
- const setFieldValues = (name, value, options, skipClone = false, skipRender = false) => {
1994
- for (const fieldKey in value) {
1995
- if (!value.hasOwnProperty(fieldKey)) {
1996
- return;
1997
- }
1998
- const fieldValue = value[fieldKey];
1999
- const fieldName = name + '.' + fieldKey;
2000
- const field = get(_fields, fieldName);
2001
- (_names.array.has(name) ||
2002
- isObject(fieldValue) ||
2003
- (field && !field._f)) &&
2004
- !isDateObject(fieldValue)
2005
- ? setFieldValues(fieldName, fieldValue, options, skipClone, skipRender)
2006
- : setFieldValue(fieldName, fieldValue, options, skipClone, skipRender);
2007
- }
1992
+ const _subjects = {
1993
+ array: createSubject(),
1994
+ state: createSubject(),
2008
1995
  };
2009
- const _setValue = (name, value, options, skipClone, skipStateEmit = false) => {
2010
- const field = get(_fields, name);
2011
- const isFieldArray = _names.array.has(name);
2012
- const cloneValue = skipClone ? value : cloneObject(value);
2013
- const previousValue = get(_formValues, name);
2014
- const isValueUnchanged = deepEqual(previousValue, cloneValue);
2015
- if (!isValueUnchanged) {
2016
- set(_formValues, name, cloneValue);
2017
- }
2018
- if (isFieldArray) {
2019
- _subjects.array.next({
2020
- name,
2021
- values: skipClone ? _formValues : cloneObject(_formValues),
2022
- });
2023
- if ((_proxyFormState.isDirty ||
2024
- _proxyFormState.dirtyFields ||
2025
- _proxySubscribeFormState.isDirty ||
2026
- _proxySubscribeFormState.dirtyFields) &&
2027
- options.shouldDirty) {
2028
- _updateDirtyFields();
2029
- if (!skipStateEmit) {
2030
- _subjects.state.next({
2031
- name,
2032
- dirtyFields: _formState.dirtyFields,
2033
- isDirty: _getDirty(name, cloneValue),
2034
- });
2035
- }
2036
- }
1996
+ let _setValidCallId = 0;
1997
+ const shouldDisplayAllAssociatedErrors = _options.criteriaMode === VALIDATION_MODE.all;
1998
+ const debounce = (name, callback) => (wait) => {
1999
+ clearTimeout(timers[name]);
2000
+ timers[name] = setTimeout(callback, wait);
2001
+ };
2002
+ const _setValid = async (shouldUpdateValid) => {
2003
+ if (_state.keepIsValid) {
2004
+ return;
2037
2005
  }
2038
- else {
2039
- const isEmpty = (Array.isArray(cloneValue) && !cloneValue.length) ||
2040
- isEmptyObject(cloneValue);
2041
- if (!field || field._f || isNullOrUndefined(cloneValue) || isEmpty) {
2042
- setFieldValue(name, cloneValue, options, skipClone, skipStateEmit);
2006
+ if (!_options.disabled &&
2007
+ (_proxyFormState.isValid ||
2008
+ _proxySubscribeFormState.isValid ||
2009
+ shouldUpdateValid)) {
2010
+ const callId = ++_setValidCallId;
2011
+ let isValid;
2012
+ if (_options.resolver) {
2013
+ isValid = isEmptyObject((await _runSchema()).errors);
2014
+ callId === _setValidCallId && _updateIsValidating();
2043
2015
  }
2044
2016
  else {
2045
- setFieldValues(name, cloneValue, options, skipClone, skipStateEmit);
2017
+ isValid = await executeBuiltInValidation({
2018
+ fields: _fields,
2019
+ onlyCheckValid: true,
2020
+ eventType: EVENTS.VALID,
2021
+ });
2022
+ }
2023
+ if (callId === _setValidCallId && isValid !== _formState.isValid) {
2024
+ _subjects.state.next({
2025
+ isValid,
2026
+ });
2046
2027
  }
2047
2028
  }
2048
- if (!isValueUnchanged && !skipStateEmit) {
2049
- const watched = isWatched(name, _names);
2050
- const values = skipClone ? _formValues : cloneObject(_formValues);
2029
+ };
2030
+ const _updateIsValidating = (names, isValidating) => {
2031
+ if (!_options.disabled &&
2032
+ (_proxyFormState.isValidating ||
2033
+ _proxyFormState.validatingFields ||
2034
+ _proxySubscribeFormState.isValidating ||
2035
+ _proxySubscribeFormState.validatingFields)) {
2036
+ (names || Array.from(_names.mount)).forEach((name) => {
2037
+ if (name) {
2038
+ isValidating
2039
+ ? set(_formState.validatingFields, name, isValidating)
2040
+ : unset(_formState.validatingFields, name);
2041
+ }
2042
+ });
2051
2043
  _subjects.state.next({
2052
- ...(watched && _formState),
2053
- name: _state.mount || watched ? name : undefined,
2054
- values,
2044
+ validatingFields: _formState.validatingFields,
2045
+ isValidating: !isEmptyObject(_formState.validatingFields),
2055
2046
  });
2056
2047
  }
2057
2048
  };
2058
- const setValue = (name, value, options = {}) => _setValue(name, value, options, false);
2059
- const setValues = (formValues, options = {}) => {
2060
- const updatedFormValues = isFunction(formValues)
2061
- ? formValues(_formValues)
2062
- : formValues;
2063
- if (!deepEqual(_formValues, updatedFormValues)) {
2064
- _formValues = {
2065
- ..._formValues,
2066
- ...updatedFormValues,
2067
- };
2068
- for (const fieldName of _names.mount) {
2069
- _setValue(fieldName, get(updatedFormValues, fieldName), options, true, true);
2049
+ const _updateDirtyFields = () => {
2050
+ _formState.dirtyFields = getDirtyFields(_defaultValues, _formValues, undefined, _fields);
2051
+ };
2052
+ const _setFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndState = true) => {
2053
+ if (args && method && !_options.disabled) {
2054
+ _state.action = true;
2055
+ if (shouldUpdateFieldsAndState && Array.isArray(get(_fields, name))) {
2056
+ const fieldValues = method(get(_fields, name), args.argA, args.argB);
2057
+ shouldSetValues && set(_fields, name, fieldValues);
2058
+ }
2059
+ if (shouldUpdateFieldsAndState &&
2060
+ Array.isArray(get(_formState.errors, name))) {
2061
+ const errors = method(get(_formState.errors, name), args.argA, args.argB);
2062
+ shouldSetValues && set(_formState.errors, name, errors);
2063
+ unsetEmptyArray(_formState.errors, name);
2064
+ }
2065
+ if ((_proxyFormState.touchedFields ||
2066
+ _proxySubscribeFormState.touchedFields) &&
2067
+ shouldUpdateFieldsAndState &&
2068
+ Array.isArray(get(_formState.touchedFields, name))) {
2069
+ const touchedFields = method(get(_formState.touchedFields, name), args.argA, args.argB);
2070
+ shouldSetValues && set(_formState.touchedFields, name, touchedFields);
2071
+ }
2072
+ if (_proxyFormState.dirtyFields || _proxySubscribeFormState.dirtyFields) {
2073
+ _updateDirtyFields();
2070
2074
  }
2071
2075
  _subjects.state.next({
2072
- ..._formState,
2073
- name: undefined,
2074
- type: undefined,
2075
- ...(_valuesSubscriberCount ? { values: _formValues } : {}),
2076
+ name,
2077
+ isDirty: _getDirty(name, values),
2078
+ dirtyFields: _formState.dirtyFields,
2079
+ errors: _formState.errors,
2080
+ isValid: _formState.isValid,
2076
2081
  });
2077
- if (options.shouldValidate) {
2082
+ }
2083
+ else {
2084
+ set(_formValues, name, values);
2085
+ }
2086
+ };
2087
+ const updateErrors = (name, error) => {
2088
+ set(_formState.errors, name, error);
2089
+ _formState.errors = { ..._formState.errors };
2090
+ _subjects.state.next({
2091
+ errors: _formState.errors,
2092
+ });
2093
+ };
2094
+ const _setErrors = (errors) => {
2095
+ _formState.errors = errors;
2096
+ _subjects.state.next({
2097
+ errors: _formState.errors,
2098
+ isValid: false,
2099
+ });
2100
+ };
2101
+ const hasExplicitNullIntermediate = (name) => {
2102
+ const segments = isKey(name) ? [name] : stringToPath(name);
2103
+ let formValues = _formValues;
2104
+ let defaultValues = _defaultValues;
2105
+ for (let i = 0; i < segments.length - 1; i++) {
2106
+ const key = segments[i];
2107
+ formValues = isNullOrUndefined(formValues) ? formValues : formValues[key];
2108
+ defaultValues = isNullOrUndefined(defaultValues)
2109
+ ? defaultValues
2110
+ : defaultValues[key];
2111
+ if (formValues === null && defaultValues !== null) {
2112
+ return true;
2113
+ }
2114
+ }
2115
+ return false;
2116
+ };
2117
+ const updateValidAndValue = (name, shouldSkipSetValueAs, value, ref) => {
2118
+ const field = get(_fields, name);
2119
+ if (field) {
2120
+ if (hasExplicitNullIntermediate(name)) {
2121
+ return;
2122
+ }
2123
+ const wasUnsetInFormValues = isUndefined(get(_formValues, name));
2124
+ const defaultValue = get(_formValues, name, isUndefined(value) ? get(_defaultValues, name) : value);
2125
+ isUndefined(defaultValue) ||
2126
+ (ref && ref.defaultChecked) ||
2127
+ shouldSkipSetValueAs
2128
+ ? set(_formValues, name, shouldSkipSetValueAs ? defaultValue : getFieldValue(field._f))
2129
+ : setFieldValue(name, defaultValue);
2130
+ if (_state.mount && !_state.action) {
2078
2131
  _setValid();
2132
+ if (wasUnsetInFormValues &&
2133
+ _formState.isDirty &&
2134
+ (_proxyFormState.isDirty || _proxySubscribeFormState.isDirty)) {
2135
+ const isDirty = _getDirty();
2136
+ if (!isDirty) {
2137
+ _formState.isDirty = false;
2138
+ _subjects.state.next({ ..._formState });
2139
+ }
2140
+ }
2141
+ if (props.shouldUnregister &&
2142
+ wasUnsetInFormValues &&
2143
+ !isUndefined(get(_formValues, name)) &&
2144
+ isWatched(name, _names)) {
2145
+ _state.watch = true;
2146
+ }
2079
2147
  }
2080
2148
  }
2081
2149
  };
2082
- const onChange = async (event) => {
2083
- _state.mount = true;
2084
- const target = event.target;
2085
- let name = target.name;
2086
- let isFieldValueUpdated = true;
2087
- const field = get(_fields, name);
2088
- const _updateIsFieldValueUpdated = (fieldValue) => {
2089
- isFieldValueUpdated =
2090
- Number.isNaN(fieldValue) ||
2091
- (isDateObject(fieldValue) && isNaN(fieldValue.getTime())) ||
2092
- deepEqual(fieldValue, get(_formValues, name, fieldValue));
2150
+ const updateTouchAndDirty = (name, fieldValue, isBlurEvent, shouldDirty, shouldRender) => {
2151
+ let shouldUpdateField = false;
2152
+ let isPreviousDirty = false;
2153
+ const output = {
2154
+ name,
2093
2155
  };
2094
- if (field) {
2095
- let error;
2096
- let isValid;
2097
- const fieldValue = target.type
2098
- ? getFieldValue(field._f)
2099
- : getEventValue(event);
2100
- const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
2101
- const hasNoValidationEffect = !hasValidation(field._f) &&
2102
- !props.validate &&
2103
- !_options.resolver &&
2104
- !get(_formState.errors, name) &&
2105
- !field._f.deps;
2106
- const shouldSkipValidation = hasNoValidationEffect ||
2107
- skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, _validationModeAfterSubmit, _validationModeBeforeSubmit);
2108
- const watched = isWatched(name, _names, isBlurEvent);
2109
- set(_formValues, name, fieldValue);
2110
- if (isBlurEvent) {
2111
- if (!target || !target.readOnly) {
2112
- field._f.onBlur && field._f.onBlur(event);
2113
- delayErrorCallback && delayErrorCallback(0);
2156
+ // an explicit programmatic update (e.g. setValue with shouldDirty: true)
2157
+ // opts into dirty tracking even when the form is disabled
2158
+ if (!_options.disabled || shouldDirty === true) {
2159
+ if (!isBlurEvent || shouldDirty) {
2160
+ const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
2161
+ if (_proxyFormState.isDirty || _proxySubscribeFormState.isDirty) {
2162
+ isPreviousDirty = _formState.isDirty;
2163
+ _formState.isDirty = output.isDirty =
2164
+ !isCurrentFieldPristine || _getDirty();
2165
+ shouldUpdateField = isPreviousDirty !== output.isDirty;
2114
2166
  }
2115
- }
2116
- else if (field._f.onChange) {
2117
- field._f.onChange(event);
2118
- }
2119
- const fieldState = updateTouchAndDirty(name, fieldValue, isBlurEvent);
2120
- const shouldRender = !isEmptyObject(fieldState) || watched;
2121
- !isBlurEvent &&
2122
- _subjects.state.next({
2123
- name,
2124
- type: event.type,
2125
- ...(_valuesSubscriberCount
2126
- ? { values: cloneObject(_formValues) }
2127
- : {}),
2128
- });
2129
- if (shouldSkipValidation) {
2130
- if ((!hasNoValidationEffect || !_formState.isValid) &&
2131
- (_proxyFormState.isValid || _proxySubscribeFormState.isValid)) {
2132
- if (_options.mode === 'onBlur') {
2133
- if (isBlurEvent) {
2134
- _setValid();
2135
- }
2136
- }
2137
- else if (!isBlurEvent) {
2138
- _setValid();
2139
- }
2167
+ isPreviousDirty = !!get(_formState.dirtyFields, name);
2168
+ if (isCurrentFieldPristine !== _formState.isDirty) {
2169
+ _formState.dirtyFields = getDirtyFields(_defaultValues, _formValues, undefined, _fields);
2140
2170
  }
2141
- return (shouldRender &&
2142
- _subjects.state.next({ name, ...(watched ? {} : fieldState) }));
2143
- }
2144
- if (!_options.resolver && props.validate) {
2145
- await validateForm({
2146
- name: name,
2147
- eventType: event.type,
2148
- });
2149
- }
2150
- !isBlurEvent && watched && _subjects.state.next({ ..._formState });
2151
- if (_options.resolver) {
2152
- const { errors } = await _runSchema([name]);
2153
- _updateIsValidating([name]);
2154
- _updateIsFieldValueUpdated(fieldValue);
2155
- if (!isFieldValueUpdated) {
2156
- !isEmptyObject(fieldState) && _subjects.state.next(fieldState);
2157
- return;
2171
+ else {
2172
+ isCurrentFieldPristine
2173
+ ? unset(_formState.dirtyFields, name)
2174
+ : set(_formState.dirtyFields, name, true);
2158
2175
  }
2159
- const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name);
2160
- const errorLookupResult = schemaErrorLookup(errors, _fields, previousErrorLookupResult.name || name);
2161
- error = errorLookupResult.error;
2162
- name = errorLookupResult.name;
2163
- isValid = isEmptyObject(errors);
2176
+ output.dirtyFields = _formState.dirtyFields;
2177
+ shouldUpdateField =
2178
+ shouldUpdateField ||
2179
+ ((_proxyFormState.dirtyFields ||
2180
+ _proxySubscribeFormState.dirtyFields) &&
2181
+ isPreviousDirty !== !isCurrentFieldPristine);
2164
2182
  }
2165
- else {
2166
- _updateIsValidating([name], true);
2167
- error = (await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation))[name];
2168
- _updateIsValidating([name]);
2169
- _updateIsFieldValueUpdated(fieldValue);
2170
- if (isFieldValueUpdated) {
2171
- if (error) {
2172
- isValid = false;
2173
- }
2174
- else if (_proxyFormState.isValid ||
2175
- _proxySubscribeFormState.isValid) {
2176
- isValid = await executeBuiltInValidation({
2177
- fields: _fields,
2178
- onlyCheckValid: true,
2179
- name: name,
2180
- eventType: event.type,
2181
- });
2182
- }
2183
+ if (isBlurEvent) {
2184
+ const isPreviousFieldTouched = get(_formState.touchedFields, name);
2185
+ if (!isPreviousFieldTouched) {
2186
+ set(_formState.touchedFields, name, isBlurEvent);
2187
+ output.touchedFields = _formState.touchedFields;
2188
+ shouldUpdateField =
2189
+ shouldUpdateField ||
2190
+ ((_proxyFormState.touchedFields ||
2191
+ _proxySubscribeFormState.touchedFields) &&
2192
+ isPreviousFieldTouched !== isBlurEvent);
2183
2193
  }
2184
2194
  }
2185
- if (isFieldValueUpdated) {
2186
- field._f.deps &&
2187
- (!Array.isArray(field._f.deps) || field._f.deps.length > 0) &&
2188
- trigger(field._f.deps);
2189
- shouldRenderByError(name, isValid, error, fieldState);
2190
- }
2191
- }
2192
- };
2193
- const _focusInput = (ref, key) => {
2194
- if (get(_formState.errors, key) && ref.focus) {
2195
- ref.focus();
2196
- return 1;
2195
+ shouldUpdateField && shouldRender && _subjects.state.next(output);
2197
2196
  }
2198
- return;
2197
+ return shouldUpdateField ? output : {};
2199
2198
  };
2200
- const trigger = async (name, options = {}) => {
2201
- let isValid;
2202
- let validationResult;
2203
- const fieldNames = convertToArrayPayload(name);
2204
- if (_options.resolver) {
2205
- const errors = await executeSchemaAndUpdateState(isUndefined(name) ? name : fieldNames);
2206
- isValid = isEmptyObject(errors);
2207
- validationResult = name
2208
- ? !fieldNames.some((name) => get(errors, name))
2209
- : isValid;
2210
- }
2211
- else if (name) {
2212
- validationResult = (await Promise.all(fieldNames.map(async (fieldName) => {
2213
- const field = get(_fields, fieldName);
2214
- return await executeBuiltInValidation({
2215
- fields: field && field._f ? { [fieldName]: field } : field,
2216
- eventType: EVENTS.TRIGGER,
2217
- });
2218
- }))).every(Boolean);
2219
- !(!validationResult && !_formState.isValid) && _setValid();
2199
+ const shouldRenderByError = (name, isValid, error, fieldState) => {
2200
+ const previousFieldError = get(_formState.errors, name);
2201
+ const shouldUpdateValid = (_proxyFormState.isValid || _proxySubscribeFormState.isValid) &&
2202
+ isBoolean(isValid) &&
2203
+ _formState.isValid !== isValid;
2204
+ if (_options.delayError && error) {
2205
+ delayErrorCallbacks[name] = debounce(name, () => updateErrors(name, error));
2206
+ delayErrorCallbacks[name](_options.delayError);
2220
2207
  }
2221
2208
  else {
2222
- validationResult = isValid = await executeBuiltInValidation({
2223
- fields: _fields,
2209
+ clearTimeout(timers[name]);
2210
+ delete delayErrorCallbacks[name];
2211
+ error
2212
+ ? set(_formState.errors, name, error)
2213
+ : unset(_formState.errors, name);
2214
+ _formState.errors = { ..._formState.errors };
2215
+ }
2216
+ if ((error ? !deepEqual(previousFieldError, error) : previousFieldError) ||
2217
+ !isEmptyObject(fieldState) ||
2218
+ shouldUpdateValid) {
2219
+ const updatedFormState = {
2220
+ ...fieldState,
2221
+ ...(shouldUpdateValid && isBoolean(isValid) ? { isValid } : {}),
2222
+ errors: _formState.errors,
2224
2223
  name,
2225
- eventType: EVENTS.TRIGGER,
2226
- });
2224
+ };
2225
+ _formState = {
2226
+ ..._formState,
2227
+ ...updatedFormState,
2228
+ };
2229
+ _subjects.state.next(updatedFormState);
2227
2230
  }
2228
- _subjects.state.next({
2229
- ...(!isString(name) ||
2230
- ((_proxyFormState.isValid || _proxySubscribeFormState.isValid) &&
2231
- isValid !== _formState.isValid)
2232
- ? {}
2233
- : { name }),
2234
- ...(_options.resolver || !name ? { isValid } : {}),
2235
- errors: _formState.errors,
2236
- });
2237
- options.shouldFocus &&
2238
- !validationResult &&
2239
- iterateFieldsByAction(_fields, _focusInput, name ? fieldNames : _names.mount);
2240
- return validationResult;
2241
2231
  };
2242
- const getValues = (fieldNames, config) => {
2243
- let values = {
2244
- ...(_state.mount ? _formValues : _defaultValues),
2245
- };
2246
- if (config) {
2247
- values = extractFormValues(config.dirtyFields ? _formState.dirtyFields : _formState.touchedFields, values);
2248
- }
2249
- return isUndefined(fieldNames)
2250
- ? values
2251
- : isString(fieldNames)
2252
- ? get(values, fieldNames)
2253
- : fieldNames.map((name) => get(values, name));
2232
+ const _runSchema = async (name) => {
2233
+ _updateIsValidating(name, true);
2234
+ return await _options.resolver(_formValues, _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation));
2254
2235
  };
2255
- const getFieldState = (name, formState) => ({
2256
- invalid: !!get((formState || _formState).errors, name),
2257
- isDirty: !!get((formState || _formState).dirtyFields, name),
2258
- error: get((formState || _formState).errors, name),
2259
- isValidating: !!get(_formState.validatingFields, name),
2260
- isTouched: !!get((formState || _formState).touchedFields, name),
2261
- });
2262
- const clearErrors = (name) => {
2263
- const names = name ? convertToArrayPayload(name) : undefined;
2264
- names === null || names === void 0 ? void 0 : names.forEach((inputName) => unset(_formState.errors, inputName));
2236
+ const executeSchemaAndUpdateState = async (names) => {
2237
+ const { errors } = await _runSchema(names);
2238
+ _updateIsValidating(names);
2265
2239
  if (names) {
2266
- names.forEach((inputName) => {
2267
- _subjects.state.next({
2268
- name: inputName,
2269
- errors: _formState.errors,
2270
- });
2271
- });
2240
+ for (const name of names) {
2241
+ const error = get(errors, name);
2242
+ error
2243
+ ? _names.array.has(name) &&
2244
+ isObject(error) &&
2245
+ !Object.keys(error).some((key) => !Number.isNaN(Number(key)))
2246
+ ? updateFieldArrayRootError(_formState.errors, { [name]: error }, name)
2247
+ : set(_formState.errors, name, error)
2248
+ : unset(_formState.errors, name);
2249
+ }
2250
+ _formState.errors = { ..._formState.errors };
2272
2251
  }
2273
2252
  else {
2274
- _subjects.state.next({
2275
- errors: {},
2276
- });
2253
+ _formState.errors = errors;
2277
2254
  }
2255
+ return errors;
2278
2256
  };
2279
- const setError = (name, error, options) => {
2280
- const ref = (get(_fields, name, { _f: {} })._f || {}).ref;
2281
- const currentError = get(_formState.errors, name) || {};
2282
- const { ref: currentRef, message, type, ...restOfErrorTree } = currentError;
2283
- set(_formState.errors, name, {
2284
- ...restOfErrorTree,
2285
- ...error,
2286
- ref,
2287
- });
2288
- _subjects.state.next({
2289
- name,
2290
- errors: _formState.errors,
2291
- isValid: false,
2292
- });
2293
- options && options.shouldFocus && ref && ref.focus && ref.focus();
2294
- };
2295
- const watch = (name, defaultValue) => {
2296
- if (isFunction(name)) {
2297
- _valuesSubscriberCount++;
2298
- const { unsubscribe } = _subjects.state.subscribe({
2299
- next: (payload) => 'values' in payload &&
2300
- name(payload.values || _getWatch(undefined, defaultValue), payload),
2257
+ const validateForm = async ({ name, eventType, }) => {
2258
+ if (props.validate) {
2259
+ const result = await props.validate({
2260
+ formValues: _formValues,
2261
+ formState: _formState,
2262
+ name,
2263
+ eventType,
2301
2264
  });
2302
- let called = false;
2303
- return {
2304
- unsubscribe: () => {
2305
- if (called) {
2306
- return;
2265
+ if (isObject(result)) {
2266
+ for (const key in result) {
2267
+ const error = result[key];
2268
+ if (error) {
2269
+ setError(`${FORM_ERROR_TYPE}.${key}`, {
2270
+ message: isString(error.message) ? error.message : '',
2271
+ type: error.type || INPUT_VALIDATION_RULES.validate,
2272
+ });
2307
2273
  }
2308
- called = true;
2309
- _valuesSubscriberCount--;
2310
- unsubscribe();
2311
- },
2312
- };
2313
- }
2314
- return _getWatch(name, defaultValue, true);
2315
- };
2316
- const _subscribe = (props) => {
2317
- var _a;
2318
- const needsValues = !!((_a = props.formState) === null || _a === void 0 ? void 0 : _a.values);
2319
- if (needsValues) {
2320
- _valuesSubscriberCount++;
2321
- }
2322
- const { unsubscribe } = _subjects.state.subscribe({
2323
- next: (formState) => {
2324
- if (shouldSubscribeByName(props.name, formState.name, props.exact) &&
2325
- shouldRenderFormState(formState, props.formState || _proxyFormState, _setFormState, props.reRenderRoot)) {
2326
- const snapshot = { ..._formValues };
2327
- props.callback({
2328
- values: snapshot,
2329
- ..._formState,
2330
- ...formState,
2331
- defaultValues: _defaultValues,
2332
- });
2333
2274
  }
2334
- },
2335
- });
2336
- if (!needsValues) {
2337
- return unsubscribe;
2338
- }
2339
- let called = false;
2340
- return () => {
2341
- if (called) {
2342
- return;
2343
2275
  }
2344
- called = true;
2345
- _valuesSubscriberCount--;
2346
- unsubscribe();
2347
- };
2348
- };
2349
- const subscribe = (props) => {
2350
- _state.mount = true;
2351
- _proxySubscribeFormState = {
2352
- ..._proxySubscribeFormState,
2353
- ...props.formState,
2354
- };
2355
- return _subscribe({
2356
- ...props,
2357
- formState: {
2358
- ...defaultProxyFormState,
2359
- ...props.formState,
2360
- },
2361
- });
2362
- };
2363
- const unregister = (name, options = {}) => {
2364
- for (const fieldName of name ? convertToArrayPayload(name) : _names.mount) {
2365
- _names.mount.delete(fieldName);
2366
- _names.array.delete(fieldName);
2367
- if (!options.keepValue) {
2368
- unset(_fields, fieldName);
2369
- unset(_formValues, fieldName);
2276
+ else if (isString(result) || !result) {
2277
+ setError(FORM_ERROR_TYPE, {
2278
+ message: result || '',
2279
+ type: INPUT_VALIDATION_RULES.validate,
2280
+ });
2370
2281
  }
2371
- !options.keepError && unset(_formState.errors, fieldName);
2372
- !options.keepDirty && unset(_formState.dirtyFields, fieldName);
2373
- !options.keepTouched && unset(_formState.touchedFields, fieldName);
2374
- !options.keepIsValidating &&
2375
- unset(_formState.validatingFields, fieldName);
2376
- !_options.shouldUnregister &&
2377
- !options.keepDefaultValue &&
2378
- unset(_defaultValues, fieldName);
2379
- }
2380
- _subjects.state.next({
2381
- values: cloneObject(_formValues),
2382
- });
2383
- _subjects.state.next({
2384
- ..._formState,
2385
- ...(!options.keepDirty ? {} : { isDirty: _getDirty() }),
2386
- });
2387
- !options.keepIsValid && _setValid();
2388
- };
2389
- const _setDisabledField = ({ disabled, name, }) => {
2390
- if ((isBoolean(disabled) && _state.mount) ||
2391
- !!disabled ||
2392
- _names.disabled.has(name)) {
2393
- const wasDisabled = _names.disabled.has(name);
2394
- const isDisabled = !!disabled;
2395
- const disabledStateChanged = wasDisabled !== isDisabled;
2396
- disabled ? _names.disabled.add(name) : _names.disabled.delete(name);
2397
- disabledStateChanged && _state.mount && !_state.action && _setValid();
2282
+ else {
2283
+ clearErrors(FORM_ERROR_TYPE);
2284
+ }
2285
+ return result;
2398
2286
  }
2287
+ return true;
2399
2288
  };
2400
- const register = (name, options = {}) => {
2401
- let field = get(_fields, name);
2402
- const disabledIsDefined = isBoolean(options.disabled) || isBoolean(_options.disabled);
2403
- const shouldRevalidateRemount = !_names.registerName.has(name) && field && field._f && !field._f.mount;
2404
- set(_fields, name, {
2405
- ...(field || {}),
2406
- _f: {
2407
- ...(field && field._f ? field._f : { ref: { name } }),
2408
- name,
2409
- mount: true,
2410
- ...options,
2411
- },
2412
- });
2413
- _names.mount.add(name);
2414
- if (field && !shouldRevalidateRemount) {
2415
- _setDisabledField({
2416
- disabled: isBoolean(options.disabled)
2417
- ? options.disabled
2418
- : _options.disabled,
2289
+ const executeBuiltInValidation = async ({ fields, onlyCheckValid, name, eventType, context = {
2290
+ valid: true,
2291
+ runRootValidation: false,
2292
+ }, }) => {
2293
+ if (props.validate) {
2294
+ context.runRootValidation = true;
2295
+ const result = await validateForm({
2419
2296
  name,
2297
+ eventType,
2420
2298
  });
2421
- }
2422
- else {
2423
- updateValidAndValue(name, true, options.value);
2424
- }
2425
- return {
2426
- ...(disabledIsDefined
2427
- ? { disabled: options.disabled || _options.disabled }
2428
- : {}),
2429
- ...(_options.progressive
2430
- ? {
2431
- required: !!options.required,
2432
- min: getRuleValue(options.min),
2433
- max: getRuleValue(options.max),
2434
- minLength: getRuleValue(options.minLength),
2435
- maxLength: getRuleValue(options.maxLength),
2436
- pattern: getRuleValue(options.pattern),
2299
+ if (!result) {
2300
+ context.valid = false;
2301
+ if (onlyCheckValid) {
2302
+ return context.valid;
2437
2303
  }
2438
- : {}),
2439
- name,
2440
- onChange,
2441
- onBlur: onChange,
2442
- ref: (ref) => {
2443
- if (ref) {
2444
- _names.registerName.add(name);
2445
- register(name, options);
2446
- _names.registerName.delete(name);
2447
- field = get(_fields, name);
2448
- const fieldRef = isUndefined(ref.value)
2449
- ? ref.querySelectorAll
2450
- ? ref.querySelectorAll('input,select,textarea')[0] || ref
2451
- : ref
2452
- : ref;
2453
- const radioOrCheckbox = isRadioOrCheckbox(fieldRef);
2454
- const refs = field._f.refs || [];
2455
- if (radioOrCheckbox
2456
- ? refs.find((option) => option === fieldRef)
2457
- : fieldRef === field._f.ref) {
2458
- return;
2304
+ }
2305
+ }
2306
+ for (const name in fields) {
2307
+ const field = fields[name];
2308
+ if (field) {
2309
+ const { _f, ...fieldValue } = field;
2310
+ if (_f) {
2311
+ const isFieldArrayRoot = _names.array.has(_f.name);
2312
+ const isPromiseFunction = field._f && hasPromiseValidation(field._f);
2313
+ const shouldTrackIsValidatingState = _proxyFormState.validatingFields ||
2314
+ _proxyFormState.isValidating ||
2315
+ _proxySubscribeFormState.validatingFields ||
2316
+ _proxySubscribeFormState.isValidating;
2317
+ if (isPromiseFunction && shouldTrackIsValidatingState) {
2318
+ _updateIsValidating([_f.name], true);
2319
+ }
2320
+ const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !onlyCheckValid, isFieldArrayRoot);
2321
+ if (isPromiseFunction && shouldTrackIsValidatingState) {
2322
+ _updateIsValidating([_f.name]);
2323
+ }
2324
+ if (fieldError[_f.name]) {
2325
+ context.valid = false;
2326
+ if (onlyCheckValid) {
2327
+ break;
2328
+ }
2459
2329
  }
2460
- set(_fields, name, {
2461
- _f: {
2462
- ...field._f,
2463
- ...(radioOrCheckbox
2464
- ? {
2465
- refs: [
2466
- ...refs.filter(live),
2467
- fieldRef,
2468
- ...(Array.isArray(get(_defaultValues, name)) ? [{}] : []),
2469
- ],
2470
- ref: { type: fieldRef.type, name },
2471
- }
2472
- : { ref: fieldRef }),
2473
- },
2474
- });
2475
- updateValidAndValue(name, false, undefined, fieldRef);
2476
- }
2477
- else {
2478
- field = get(_fields, name, {});
2479
- if (field._f) {
2480
- field._f.mount = false;
2330
+ !onlyCheckValid &&
2331
+ (get(fieldError, _f.name)
2332
+ ? isFieldArrayRoot
2333
+ ? updateFieldArrayRootError(_formState.errors, fieldError, _f.name)
2334
+ : set(_formState.errors, _f.name, fieldError[_f.name])
2335
+ : unset(_formState.errors, _f.name));
2336
+ if (props.shouldUseNativeValidation && fieldError[_f.name]) {
2337
+ break;
2481
2338
  }
2482
- (_options.shouldUnregister || options.shouldUnregister) &&
2483
- !(isNameInFieldArray(_names.array, name) && _state.action) &&
2484
- _names.unMount.add(name);
2485
2339
  }
2486
- },
2487
- };
2340
+ !isEmptyObject(fieldValue) &&
2341
+ (await executeBuiltInValidation({
2342
+ context,
2343
+ onlyCheckValid,
2344
+ fields: fieldValue,
2345
+ name: name,
2346
+ eventType,
2347
+ }));
2348
+ }
2349
+ }
2350
+ return context.valid;
2488
2351
  };
2489
- const _focusError = () => _options.shouldFocusError &&
2490
- !_options.shouldUseNativeValidation &&
2491
- iterateFieldsByAction(_fields, _focusInput, _names.mount);
2492
- const _disableForm = (disabled) => {
2493
- if (isBoolean(disabled)) {
2494
- _subjects.state.next({ disabled });
2495
- iterateFieldsByAction(_fields, (ref, name) => {
2496
- const currentField = get(_fields, name);
2497
- if (currentField) {
2498
- ref.disabled = currentField._f.disabled || disabled;
2499
- if (Array.isArray(currentField._f.refs)) {
2500
- currentField._f.refs.forEach((inputRef) => {
2501
- inputRef.disabled = currentField._f.disabled || disabled;
2352
+ const _removeUnmounted = () => {
2353
+ for (const name of _names.unMount) {
2354
+ const field = get(_fields, name);
2355
+ field &&
2356
+ (field._f.refs
2357
+ ? field._f.refs.every((ref) => !live(ref))
2358
+ : !live(field._f.ref)) &&
2359
+ unregister(name);
2360
+ }
2361
+ _names.unMount = new Set();
2362
+ };
2363
+ const _getDirty = (name, data) => (name && data && set(_formValues, name, data),
2364
+ !deepEqual(_state.mount ? _formValues : _defaultValues, _defaultValues));
2365
+ const _getWatch = (names, defaultValue, isGlobal) => generateWatchOutput(names, _names, {
2366
+ ...(_state.mount
2367
+ ? _formValues
2368
+ : isUndefined(defaultValue)
2369
+ ? _defaultValues
2370
+ : isString(names)
2371
+ ? { [names]: defaultValue }
2372
+ : defaultValue),
2373
+ }, isGlobal, defaultValue);
2374
+ const _getFieldArray = (name) => compact(get(_state.mount ? _formValues : _defaultValues, name, _options.shouldUnregister ? get(_defaultValues, name, []) : []));
2375
+ const setFieldValue = (name, value, options = {}, skipClone = false, skipRender = false) => {
2376
+ const field = get(_fields, name);
2377
+ let fieldValue = value;
2378
+ if (field) {
2379
+ const fieldReference = field._f;
2380
+ if (fieldReference) {
2381
+ !fieldReference.disabled &&
2382
+ set(_formValues, name, getFieldValueAs(value, fieldReference));
2383
+ fieldValue =
2384
+ isHTMLElement(fieldReference.ref) && isNullOrUndefined(value)
2385
+ ? ''
2386
+ : value;
2387
+ if (isMultipleSelect(fieldReference.ref)) {
2388
+ [...fieldReference.ref.options].forEach((optionRef) => (optionRef.selected = fieldValue.includes(optionRef.value)));
2389
+ }
2390
+ else if (fieldReference.refs) {
2391
+ if (isCheckBoxInput(fieldReference.ref)) {
2392
+ fieldReference.refs.forEach((checkboxRef) => {
2393
+ if (!checkboxRef.defaultChecked || !checkboxRef.disabled) {
2394
+ if (Array.isArray(fieldValue)) {
2395
+ checkboxRef.checked = !!fieldValue.find((data) => data === checkboxRef.value);
2396
+ }
2397
+ else {
2398
+ checkboxRef.checked =
2399
+ fieldValue === checkboxRef.value || !!fieldValue;
2400
+ }
2401
+ }
2502
2402
  });
2503
2403
  }
2404
+ else {
2405
+ fieldReference.refs.forEach((radioRef) => (radioRef.checked = radioRef.value === fieldValue));
2406
+ }
2504
2407
  }
2505
- }, 0, false);
2506
- }
2507
- };
2508
- const handleSubmit = (onValid, onInvalid) => async (e) => {
2509
- let onValidError = undefined;
2510
- if (e) {
2511
- e.preventDefault && e.preventDefault();
2512
- e.persist &&
2513
- e.persist();
2514
- }
2515
- let fieldValues = cloneObject(_formValues);
2516
- _subjects.state.next({
2517
- isSubmitting: true,
2518
- });
2519
- if (_options.resolver) {
2520
- const { errors, values } = await _runSchema();
2521
- _updateIsValidating();
2522
- _formState.errors = errors;
2523
- fieldValues = cloneObject(values);
2408
+ else if (isFileInput(fieldReference.ref)) {
2409
+ fieldReference.ref.value = '';
2410
+ }
2411
+ else {
2412
+ fieldReference.ref.value = fieldValue;
2413
+ if (!fieldReference.ref.type && !skipRender) {
2414
+ _subjects.state.next({
2415
+ name,
2416
+ values: skipClone ? _formValues : cloneObject(_formValues),
2417
+ });
2418
+ }
2419
+ }
2420
+ }
2524
2421
  }
2525
- else {
2526
- await executeBuiltInValidation({
2527
- fields: _fields,
2528
- eventType: EVENTS.SUBMIT,
2422
+ (options.shouldDirty || options.shouldTouch) &&
2423
+ updateTouchAndDirty(name, fieldValue, options.shouldTouch, options.shouldDirty, !skipRender);
2424
+ options.shouldValidate &&
2425
+ trigger(name, {
2426
+ delayError: options.delayError,
2529
2427
  });
2530
- }
2531
- if (_names.disabled.size) {
2532
- for (const name of _names.disabled) {
2533
- unset(fieldValues, name);
2428
+ };
2429
+ const setFieldValues = (name, value, options, skipClone = false, skipRender = false) => {
2430
+ for (const fieldKey in value) {
2431
+ if (!value.hasOwnProperty(fieldKey)) {
2432
+ return;
2534
2433
  }
2434
+ const fieldValue = value[fieldKey];
2435
+ const fieldName = name + '.' + fieldKey;
2436
+ const field = get(_fields, fieldName);
2437
+ (_names.array.has(name) ||
2438
+ isObject(fieldValue) ||
2439
+ (field && !field._f)) &&
2440
+ !isDateObject(fieldValue)
2441
+ ? setFieldValues(fieldName, fieldValue, options, skipClone, skipRender)
2442
+ : setFieldValue(fieldName, fieldValue, options, skipClone, skipRender);
2535
2443
  }
2536
- unset(_formState.errors, ROOT_ERROR_TYPE);
2537
- if (isEmptyObject(_formState.errors)) {
2538
- _subjects.state.next({
2539
- errors: {},
2444
+ };
2445
+ const _setValue = (name, value, options, skipClone, skipStateEmit = false) => {
2446
+ const field = get(_fields, name);
2447
+ const isFieldArray = _names.array.has(name);
2448
+ const cloneValue = skipClone ? value : cloneObject(value);
2449
+ const previousValue = get(_formValues, name);
2450
+ const isValueUnchanged = deepEqual(previousValue, cloneValue);
2451
+ if (!isValueUnchanged) {
2452
+ set(_formValues, name, cloneValue);
2453
+ }
2454
+ if (isFieldArray) {
2455
+ _subjects.array.next({
2456
+ name,
2457
+ values: skipClone ? _formValues : cloneObject(_formValues),
2540
2458
  });
2541
- try {
2542
- await onValid(fieldValues, e);
2543
- }
2544
- catch (error) {
2545
- onValidError = error;
2459
+ if ((_proxyFormState.isDirty ||
2460
+ _proxyFormState.dirtyFields ||
2461
+ _proxySubscribeFormState.isDirty ||
2462
+ _proxySubscribeFormState.dirtyFields) &&
2463
+ options.shouldDirty) {
2464
+ _updateDirtyFields();
2465
+ if (!skipStateEmit) {
2466
+ _subjects.state.next({
2467
+ name,
2468
+ dirtyFields: _formState.dirtyFields,
2469
+ isDirty: _getDirty(name, cloneValue),
2470
+ });
2471
+ }
2546
2472
  }
2547
2473
  }
2548
2474
  else {
2549
- if (onInvalid) {
2550
- await onInvalid({ ..._formState.errors }, e);
2475
+ const isEmpty = (Array.isArray(cloneValue) && !cloneValue.length) ||
2476
+ isEmptyObject(cloneValue);
2477
+ if (!field || field._f || isNullOrUndefined(cloneValue) || isEmpty) {
2478
+ setFieldValue(name, cloneValue, options, skipClone, skipStateEmit);
2479
+ }
2480
+ else {
2481
+ setFieldValues(name, cloneValue, options, skipClone, skipStateEmit);
2551
2482
  }
2552
- _focusError();
2553
- setTimeout(_focusError);
2554
2483
  }
2555
- _subjects.state.next({
2556
- isSubmitted: true,
2557
- isSubmitting: false,
2558
- isSubmitSuccessful: isEmptyObject(_formState.errors) && !onValidError,
2559
- submitCount: _formState.submitCount + 1,
2560
- errors: _formState.errors,
2561
- });
2562
- if (onValidError) {
2563
- throw onValidError;
2484
+ if (!isValueUnchanged && !skipStateEmit) {
2485
+ const watched = isWatched(name, _names);
2486
+ const values = skipClone ? _formValues : cloneObject(_formValues);
2487
+ _subjects.state.next({
2488
+ ...(watched && _formState),
2489
+ name: _state.mount || watched ? name : undefined,
2490
+ values,
2491
+ });
2564
2492
  }
2565
2493
  };
2566
- const resetField = (name, options = {}) => {
2567
- if (get(_fields, name)) {
2568
- if (isUndefined(options.defaultValue)) {
2569
- setValue(name, cloneObject(get(_defaultValues, name)));
2570
- }
2571
- else {
2572
- setValue(name, options.defaultValue);
2573
- set(_defaultValues, name, cloneObject(options.defaultValue));
2574
- }
2575
- if (!options.keepTouched) {
2576
- unset(_formState.touchedFields, name);
2577
- }
2578
- if (!options.keepDirty) {
2579
- unset(_formState.dirtyFields, name);
2580
- _formState.isDirty = options.defaultValue
2581
- ? _getDirty(name, cloneObject(get(_defaultValues, name)))
2582
- : _getDirty();
2494
+ const setValue = (name, value, options = {}) => _setValue(name, value, options, false);
2495
+ const setValues = (formValues, options = {}) => {
2496
+ const updatedFormValues = isFunction(formValues)
2497
+ ? formValues(_formValues)
2498
+ : formValues;
2499
+ if (!deepEqual(_formValues, updatedFormValues)) {
2500
+ _formValues = {
2501
+ ..._formValues,
2502
+ ...updatedFormValues,
2503
+ };
2504
+ const flattenedUpdates = flatten(updatedFormValues);
2505
+ for (const fieldName of _names.mount) {
2506
+ if (fieldName in flattenedUpdates) {
2507
+ _setValue(fieldName, flattenedUpdates[fieldName], options, true, true);
2508
+ }
2583
2509
  }
2584
- if (!options.keepError) {
2585
- unset(_formState.errors, name);
2586
- _proxyFormState.isValid && _setValid();
2510
+ _subjects.state.next({
2511
+ ..._formState,
2512
+ name: undefined,
2513
+ type: undefined,
2514
+ ...(_valuesSubscriberCount ? { values: _formValues } : {}),
2515
+ });
2516
+ if (options.shouldValidate) {
2517
+ _setValid();
2587
2518
  }
2588
- _subjects.state.next({ ..._formState });
2589
2519
  }
2590
2520
  };
2591
- const _reset = (formValues, keepStateOptions = {}) => {
2592
- const updatedValues = formValues ? cloneObject(formValues) : _defaultValues;
2593
- const cloneUpdatedValues = cloneObject(updatedValues);
2594
- const isEmptyResetValues = isEmptyObject(formValues);
2595
- const values = cloneUpdatedValues;
2596
- if (!keepStateOptions.keepDefaultValues) {
2597
- _defaultValues = updatedValues;
2598
- }
2599
- if (!keepStateOptions.keepValues) {
2600
- if (keepStateOptions.keepDirtyValues) {
2601
- const fieldsToCheck = new Set([
2602
- ..._names.mount,
2603
- ...Object.keys(getDirtyFields(_defaultValues, _formValues)),
2604
- ]);
2605
- for (const fieldName of Array.from(fieldsToCheck)) {
2606
- const isDirty = get(_formState.dirtyFields, fieldName);
2607
- const existingValue = get(_formValues, fieldName);
2608
- const newValue = get(values, fieldName);
2609
- if (isDirty && !isUndefined(existingValue)) {
2610
- set(values, fieldName, existingValue);
2611
- }
2612
- else if (!isDirty && !isUndefined(newValue)) {
2613
- setValue(fieldName, newValue);
2614
- }
2521
+ const onChange = async (event) => {
2522
+ _state.mount = true;
2523
+ const target = event.target;
2524
+ let name = target.name;
2525
+ let isFieldValueUpdated = true;
2526
+ const field = get(_fields, name);
2527
+ const _updateIsFieldValueUpdated = (fieldValue) => {
2528
+ isFieldValueUpdated =
2529
+ Number.isNaN(fieldValue) ||
2530
+ (isDateObject(fieldValue) && isNaN(fieldValue.getTime())) ||
2531
+ deepEqual(fieldValue, get(_formValues, name, fieldValue));
2532
+ };
2533
+ if (field) {
2534
+ let error;
2535
+ let isValid;
2536
+ const fieldValue = target.type
2537
+ ? getFieldValue(field._f)
2538
+ : getEventValue(event);
2539
+ const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
2540
+ const hasNoValidationEffect = !hasValidation(field._f) &&
2541
+ !props.validate &&
2542
+ !_options.resolver &&
2543
+ !get(_formState.errors, name) &&
2544
+ !field._f.deps;
2545
+ const shouldSkipValidation = hasNoValidationEffect ||
2546
+ skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, _validationModeAfterSubmit, _validationModeBeforeSubmit);
2547
+ const watched = isWatched(name, _names, isBlurEvent);
2548
+ set(_formValues, name, fieldValue);
2549
+ if (isBlurEvent) {
2550
+ if (!target || !target.readOnly) {
2551
+ field._f.onBlur && field._f.onBlur(event);
2552
+ const pendingDelayError = delayErrorCallbacks[name];
2553
+ pendingDelayError && pendingDelayError(0);
2615
2554
  }
2616
2555
  }
2617
- else {
2618
- if (isWeb && isUndefined(formValues)) {
2619
- for (const name of _names.mount) {
2620
- const field = get(_fields, name);
2621
- if (field && field._f) {
2622
- const fieldReference = Array.isArray(field._f.refs)
2623
- ? field._f.refs[0]
2624
- : field._f.ref;
2625
- if (isHTMLElement(fieldReference)) {
2626
- const form = fieldReference.closest('form');
2627
- if (form) {
2628
- form.reset();
2629
- break;
2630
- }
2631
- }
2556
+ else if (field._f.onChange) {
2557
+ field._f.onChange(event);
2558
+ }
2559
+ const fieldState = updateTouchAndDirty(name, fieldValue, isBlurEvent);
2560
+ const shouldRender = !isEmptyObject(fieldState) || watched;
2561
+ !isBlurEvent &&
2562
+ _subjects.state.next({
2563
+ name,
2564
+ type: event.type,
2565
+ ...(_valuesSubscriberCount
2566
+ ? { values: cloneObject(_formValues) }
2567
+ : {}),
2568
+ });
2569
+ if (shouldSkipValidation) {
2570
+ if ((!hasNoValidationEffect || !_formState.isValid) &&
2571
+ (_proxyFormState.isValid || _proxySubscribeFormState.isValid)) {
2572
+ if (_options.mode === 'onBlur') {
2573
+ if (isBlurEvent) {
2574
+ _setValid();
2632
2575
  }
2633
2576
  }
2634
- }
2635
- if (keepStateOptions.keepFieldsRef) {
2636
- for (const fieldName of _names.mount) {
2637
- setValue(fieldName, get(values, fieldName));
2577
+ else if (!isBlurEvent) {
2578
+ _setValid();
2638
2579
  }
2639
2580
  }
2640
- else {
2641
- _fields = {};
2581
+ return (shouldRender &&
2582
+ _subjects.state.next({ name, ...(watched ? {} : fieldState) }));
2583
+ }
2584
+ if (!_options.resolver && props.validate) {
2585
+ await validateForm({
2586
+ name: name,
2587
+ eventType: event.type,
2588
+ });
2589
+ }
2590
+ !isBlurEvent && watched && _subjects.state.next({ ..._formState });
2591
+ if (_options.resolver) {
2592
+ const { errors } = await _runSchema([name]);
2593
+ _updateIsValidating([name]);
2594
+ _updateIsFieldValueUpdated(fieldValue);
2595
+ if (!isFieldValueUpdated) {
2596
+ !isEmptyObject(fieldState) && _subjects.state.next(fieldState);
2597
+ return;
2642
2598
  }
2599
+ const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name);
2600
+ const errorLookupResult = schemaErrorLookup(errors, _fields, previousErrorLookupResult.name || name);
2601
+ error = errorLookupResult.error;
2602
+ name = errorLookupResult.name;
2603
+ isValid = isEmptyObject(errors);
2643
2604
  }
2644
- if (_options.shouldUnregister) {
2645
- _formValues = keepStateOptions.keepDefaultValues
2646
- ? cloneObject(_defaultValues)
2647
- : {};
2648
- if (keepStateOptions.keepFieldsRef) {
2649
- for (const fieldName of _names.mount) {
2650
- set(_formValues, fieldName, get(values, fieldName));
2605
+ else {
2606
+ _updateIsValidating([name], true);
2607
+ error = (await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation))[name];
2608
+ _updateIsValidating([name]);
2609
+ _updateIsFieldValueUpdated(fieldValue);
2610
+ if (isFieldValueUpdated) {
2611
+ if (error) {
2612
+ isValid = false;
2613
+ }
2614
+ else if (_proxyFormState.isValid ||
2615
+ _proxySubscribeFormState.isValid) {
2616
+ isValid = await executeBuiltInValidation({
2617
+ fields: _fields,
2618
+ onlyCheckValid: true,
2619
+ name: name,
2620
+ eventType: event.type,
2621
+ });
2651
2622
  }
2652
2623
  }
2653
2624
  }
2654
- else {
2655
- _formValues = cloneObject(values);
2625
+ if (isFieldValueUpdated) {
2626
+ field._f.deps &&
2627
+ (!Array.isArray(field._f.deps) || field._f.deps.length > 0) &&
2628
+ trigger(field._f.deps);
2629
+ shouldRenderByError(name, isValid, error, fieldState);
2656
2630
  }
2657
- _subjects.array.next({
2658
- values: { ...values },
2659
- });
2660
- _subjects.state.next({
2661
- values: { ...values },
2662
- });
2663
2631
  }
2664
- _names = {
2665
- mount: keepStateOptions.keepDirtyValues ? _names.mount : new Set(),
2666
- unMount: new Set(),
2667
- array: new Set(),
2668
- registerName: new Set(),
2669
- disabled: new Set(),
2670
- watch: new Set(),
2671
- watchAll: false,
2672
- focus: '',
2673
- };
2674
- _state.mount =
2675
- !_proxyFormState.isValid ||
2676
- !!keepStateOptions.keepIsValid ||
2677
- !!keepStateOptions.keepDirtyValues ||
2678
- (!_options.shouldUnregister && !isEmptyObject(values));
2679
- _state.watch = !!_options.shouldUnregister;
2680
- _state.keepIsValid = !!keepStateOptions.keepIsValid;
2681
- _state.action = false;
2682
- if (!keepStateOptions.keepErrors) {
2683
- _formState.errors = {};
2632
+ };
2633
+ const _focusInput = (ref, key) => {
2634
+ if (get(_formState.errors, key) && ref.focus) {
2635
+ ref.focus();
2636
+ return 1;
2684
2637
  }
2685
- _subjects.state.next({
2686
- submitCount: keepStateOptions.keepSubmitCount
2687
- ? _formState.submitCount
2688
- : 0,
2689
- isDirty: isEmptyResetValues
2690
- ? false
2691
- : keepStateOptions.keepDirty
2692
- ? _formState.isDirty
2693
- : keepStateOptions.keepValues
2694
- ? _getDirty()
2695
- : !!(keepStateOptions.keepDefaultValues &&
2696
- !deepEqual(formValues, _defaultValues)),
2697
- isSubmitted: keepStateOptions.keepIsSubmitted
2698
- ? _formState.isSubmitted
2699
- : false,
2700
- dirtyFields: isEmptyResetValues
2701
- ? {}
2702
- : keepStateOptions.keepDirtyValues
2703
- ? keepStateOptions.keepDefaultValues && _formValues
2704
- ? getDirtyFields(_defaultValues, _formValues)
2705
- : _formState.dirtyFields
2706
- : keepStateOptions.keepDefaultValues && formValues
2707
- ? getDirtyFields(_defaultValues, formValues)
2708
- : keepStateOptions.keepDirty
2709
- ? _formState.dirtyFields
2710
- : {},
2711
- touchedFields: keepStateOptions.keepTouched
2712
- ? _formState.touchedFields
2713
- : {},
2714
- errors: keepStateOptions.keepErrors ? _formState.errors : {},
2715
- isSubmitSuccessful: keepStateOptions.keepIsSubmitSuccessful
2716
- ? _formState.isSubmitSuccessful
2717
- : false,
2718
- isSubmitting: false,
2719
- defaultValues: _defaultValues,
2720
- });
2638
+ return;
2721
2639
  };
2722
- const reset = (formValues, keepStateOptions) => _reset(isFunction(formValues)
2723
- ? formValues(_formValues)
2724
- : formValues, { ..._options.resetOptions, ...keepStateOptions });
2725
- const setFocus = (name, options = {}) => {
2726
- const field = get(_fields, name);
2727
- const fieldReference = field && field._f;
2728
- if (fieldReference) {
2729
- const fieldRef = fieldReference.refs
2730
- ? fieldReference.refs[0]
2731
- : fieldReference.ref;
2732
- if (fieldRef.focus) {
2733
- setTimeout(() => {
2734
- fieldRef.focus();
2735
- options.shouldSelect &&
2736
- isFunction(fieldRef.select) &&
2737
- fieldRef.select();
2640
+ const trigger = async (name, options = {}) => {
2641
+ let isValid;
2642
+ let validationResult;
2643
+ const fieldNames = convertToArrayPayload(name);
2644
+ if (_options.resolver) {
2645
+ const errors = await executeSchemaAndUpdateState(isUndefined(name) ? name : fieldNames);
2646
+ isValid = isEmptyObject(errors);
2647
+ validationResult = name
2648
+ ? !fieldNames.some((name) => get(errors, name))
2649
+ : isValid;
2650
+ }
2651
+ else if (name) {
2652
+ validationResult = (await Promise.all(fieldNames.map(async (fieldName) => {
2653
+ const field = get(_fields, fieldName);
2654
+ return await executeBuiltInValidation({
2655
+ fields: field && field._f ? { [fieldName]: field } : field,
2656
+ eventType: EVENTS.TRIGGER,
2738
2657
  });
2658
+ }))).every(Boolean);
2659
+ !(!validationResult && !_formState.isValid) && _setValid();
2660
+ }
2661
+ else {
2662
+ validationResult = isValid = await executeBuiltInValidation({
2663
+ fields: _fields,
2664
+ name,
2665
+ eventType: EVENTS.TRIGGER,
2666
+ });
2667
+ }
2668
+ if (options.delayError && _options.delayError && isString(name)) {
2669
+ const error = get(_formState.errors, name);
2670
+ if (error) {
2671
+ unset(_formState.errors, name);
2672
+ delayErrorCallbacks[name] = debounce(name, () => updateErrors(name, error));
2673
+ delayErrorCallbacks[name](_options.delayError);
2674
+ }
2675
+ else {
2676
+ clearTimeout(timers[name]);
2677
+ delete delayErrorCallbacks[name];
2739
2678
  }
2740
2679
  }
2680
+ _subjects.state.next({
2681
+ ...(!isString(name) ||
2682
+ ((_proxyFormState.isValid || _proxySubscribeFormState.isValid) &&
2683
+ isValid !== _formState.isValid)
2684
+ ? {}
2685
+ : { name }),
2686
+ ...(_options.resolver || !name ? { isValid } : {}),
2687
+ errors: _formState.errors,
2688
+ });
2689
+ options.shouldFocus &&
2690
+ !validationResult &&
2691
+ iterateFieldsByAction(_fields, _focusInput, name ? fieldNames : _names.mount);
2692
+ return validationResult;
2741
2693
  };
2742
- const _setFormState = (updatedFormState) => {
2743
- _formState = {
2744
- ..._formState,
2745
- ...updatedFormState,
2694
+ const getValues = (fieldNames, config) => {
2695
+ let values = {
2696
+ ...(_state.mount ? _formValues : _defaultValues),
2746
2697
  };
2698
+ if (config) {
2699
+ values = extractFormValues(config.dirtyFields ? _formState.dirtyFields : _formState.touchedFields, values);
2700
+ }
2701
+ return isUndefined(fieldNames)
2702
+ ? values
2703
+ : isString(fieldNames)
2704
+ ? get(values, fieldNames)
2705
+ : fieldNames.map((name) => get(values, name));
2747
2706
  };
2748
- const _resetDefaultValues = () => isFunction(_options.defaultValues) &&
2749
- _options.defaultValues().then((values) => {
2750
- reset(values, _options.resetOptions);
2751
- _subjects.state.next({
2752
- isLoading: false,
2707
+ const getFieldState = (name, formState) => ({
2708
+ invalid: !!get((formState || _formState).errors, name),
2709
+ isDirty: !!get((formState || _formState).dirtyFields, name),
2710
+ error: get((formState || _formState).errors, name),
2711
+ isValidating: !!get(_formState.validatingFields, name),
2712
+ isTouched: !!get((formState || _formState).touchedFields, name),
2713
+ });
2714
+ const clearErrors = (name) => {
2715
+ const names = name ? convertToArrayPayload(name) : undefined;
2716
+ names === null || names === void 0 ? void 0 : names.forEach((inputName) => unset(_formState.errors, inputName));
2717
+ if (names) {
2718
+ names.forEach((inputName) => {
2719
+ _subjects.state.next({
2720
+ name: inputName,
2721
+ errors: _formState.errors,
2722
+ });
2753
2723
  });
2754
- });
2755
- const resetDefaultValues = (values, options = {}) => {
2756
- _defaultValues = cloneObject(values);
2757
- if (!options.keepDirty) {
2758
- const newDirtyFields = getDirtyFields(_defaultValues, _formValues);
2759
- _formState.dirtyFields = newDirtyFields;
2760
- _formState.isDirty = !isEmptyObject(newDirtyFields);
2761
2724
  }
2762
- if (!options.keepIsValid) {
2763
- _setValid();
2725
+ else {
2726
+ _subjects.state.next({
2727
+ errors: {},
2728
+ });
2764
2729
  }
2730
+ };
2731
+ const setError = (name, error, options) => {
2732
+ const ref = (get(_fields, name, { _f: {} })._f || {}).ref;
2733
+ const currentError = get(_formState.errors, name) || {};
2734
+ const { ref: currentRef, message, type, ...restOfErrorTree } = currentError;
2735
+ set(_formState.errors, name, {
2736
+ ...restOfErrorTree,
2737
+ ...error,
2738
+ ref,
2739
+ });
2765
2740
  _subjects.state.next({
2766
- ..._formState,
2767
- defaultValues: _defaultValues,
2741
+ name,
2742
+ errors: _formState.errors,
2743
+ isValid: false,
2768
2744
  });
2745
+ options && options.shouldFocus && ref && ref.focus && ref.focus();
2769
2746
  };
2770
- const methods = {
2771
- control: {
2772
- register,
2773
- unregister,
2774
- getFieldState,
2775
- handleSubmit,
2776
- setError,
2777
- _subscribe,
2778
- _runSchema,
2779
- _updateIsValidating,
2780
- _focusError,
2781
- _getWatch,
2782
- _getDirty,
2783
- _setValid,
2784
- _setFieldArray,
2785
- _setDisabledField,
2786
- _setErrors,
2787
- _getFieldArray,
2788
- _reset,
2789
- _resetDefaultValues,
2790
- _removeUnmounted,
2791
- _disableForm,
2792
- _subjects,
2793
- _proxyFormState,
2794
- get _fields() {
2795
- return _fields;
2796
- },
2797
- get _formValues() {
2798
- return _formValues;
2799
- },
2800
- get _state() {
2801
- return _state;
2802
- },
2803
- set _state(value) {
2804
- _state = value;
2805
- },
2806
- get _defaultValues() {
2807
- return _defaultValues;
2808
- },
2809
- get _names() {
2810
- return _names;
2811
- },
2812
- set _names(value) {
2813
- _names = value;
2814
- },
2815
- get _formState() {
2816
- return _formState;
2817
- },
2818
- get _options() {
2819
- return _options;
2747
+ const watch = (name, defaultValue) => {
2748
+ if (isFunction(name)) {
2749
+ _valuesSubscriberCount++;
2750
+ const { unsubscribe } = _subjects.state.subscribe({
2751
+ next: (payload) => 'values' in payload &&
2752
+ name(payload.values || _getWatch(undefined, defaultValue), payload),
2753
+ });
2754
+ let called = false;
2755
+ return {
2756
+ unsubscribe: () => {
2757
+ if (called) {
2758
+ return;
2759
+ }
2760
+ called = true;
2761
+ _valuesSubscriberCount--;
2762
+ unsubscribe();
2763
+ },
2764
+ };
2765
+ }
2766
+ return _getWatch(name, defaultValue, true);
2767
+ };
2768
+ const _subscribe = (props) => {
2769
+ var _a;
2770
+ const needsValues = !!((_a = props.formState) === null || _a === void 0 ? void 0 : _a.values);
2771
+ if (needsValues) {
2772
+ _valuesSubscriberCount++;
2773
+ }
2774
+ const { unsubscribe } = _subjects.state.subscribe({
2775
+ next: (formState) => {
2776
+ if (shouldSubscribeByName(props.name, formState.name, props.exact) &&
2777
+ shouldRenderFormState(formState, props.formState || _proxyFormState, _setFormState, props.reRenderRoot)) {
2778
+ const snapshot = { ..._formValues };
2779
+ props.callback({
2780
+ values: snapshot,
2781
+ ..._formState,
2782
+ ...formState,
2783
+ defaultValues: _defaultValues,
2784
+ });
2785
+ }
2820
2786
  },
2821
- set _options(value) {
2822
- _options = {
2823
- ..._options,
2824
- ...value,
2825
- };
2826
- _validationModeBeforeSubmit = getValidationModes(_options.mode);
2827
- _validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
2787
+ });
2788
+ if (!needsValues) {
2789
+ return unsubscribe;
2790
+ }
2791
+ let called = false;
2792
+ return () => {
2793
+ if (called) {
2794
+ return;
2795
+ }
2796
+ called = true;
2797
+ _valuesSubscriberCount--;
2798
+ unsubscribe();
2799
+ };
2800
+ };
2801
+ const subscribe = (props) => {
2802
+ _state.mount = true;
2803
+ _proxySubscribeFormState = {
2804
+ ..._proxySubscribeFormState,
2805
+ ...props.formState,
2806
+ };
2807
+ return _subscribe({
2808
+ ...props,
2809
+ formState: {
2810
+ ...defaultProxyFormState,
2811
+ ...props.formState,
2828
2812
  },
2829
- },
2830
- subscribe,
2831
- trigger,
2832
- register,
2833
- handleSubmit,
2834
- watch,
2835
- setValue,
2836
- setValues,
2837
- getValues,
2838
- reset,
2839
- resetField,
2840
- resetDefaultValues,
2841
- clearErrors,
2842
- unregister,
2843
- setError,
2844
- setFocus,
2845
- getFieldState,
2813
+ });
2814
+ };
2815
+ const unregister = (name, options = {}) => {
2816
+ for (const fieldName of name ? convertToArrayPayload(name) : _names.mount) {
2817
+ _names.mount.delete(fieldName);
2818
+ _names.array.delete(fieldName);
2819
+ if (!options.keepValue) {
2820
+ unset(_fields, fieldName);
2821
+ unset(_formValues, fieldName);
2822
+ }
2823
+ !options.keepError && unset(_formState.errors, fieldName);
2824
+ !options.keepDirty && unset(_formState.dirtyFields, fieldName);
2825
+ !options.keepTouched && unset(_formState.touchedFields, fieldName);
2826
+ !options.keepIsValidating &&
2827
+ unset(_formState.validatingFields, fieldName);
2828
+ !_options.shouldUnregister &&
2829
+ !options.keepDefaultValue &&
2830
+ unset(_defaultValues, fieldName);
2831
+ }
2832
+ _subjects.state.next({
2833
+ values: cloneObject(_formValues),
2834
+ });
2835
+ _subjects.state.next({
2836
+ ..._formState,
2837
+ ...(!options.keepDirty ? {} : { isDirty: _getDirty() }),
2838
+ });
2839
+ !options.keepIsValid && _setValid();
2846
2840
  };
2847
- return {
2848
- ...methods,
2849
- formControl: methods,
2841
+ const _setDisabledField = ({ disabled, name, }) => {
2842
+ if ((isBoolean(disabled) && _state.mount) ||
2843
+ !!disabled ||
2844
+ _names.disabled.has(name)) {
2845
+ const wasDisabled = _names.disabled.has(name);
2846
+ const isDisabled = !!disabled;
2847
+ const disabledStateChanged = wasDisabled !== isDisabled;
2848
+ disabled ? _names.disabled.add(name) : _names.disabled.delete(name);
2849
+ disabledStateChanged && _state.mount && !_state.action && _setValid();
2850
+ }
2850
2851
  };
2851
- }
2852
-
2853
- var generateId = () => {
2854
- if (typeof crypto !== 'undefined' && crypto.randomUUID) {
2855
- return crypto.randomUUID();
2856
- }
2857
- const d = typeof performance === 'undefined' ? Date.now() : performance.now() * 1000;
2858
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
2859
- const r = ((Math.random() * 16 + d) % 16) | 0;
2860
- return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16);
2861
- });
2862
- };
2863
-
2864
- var getFocusFieldName = (name, index, options = {}) => options.shouldFocus || isUndefined(options.shouldFocus)
2865
- ? options.focusName ||
2866
- `${name}.${isUndefined(options.focusIndex) ? index : options.focusIndex}.`
2867
- : '';
2868
-
2869
- var appendAt = (data, value) => [
2870
- ...data,
2871
- ...convertToArrayPayload(value),
2872
- ];
2873
-
2874
- var fillEmptyArray = (value) => Array.isArray(value) ? value.map(() => undefined) : undefined;
2875
-
2876
- function insert(data, index, value) {
2877
- return [
2878
- ...data.slice(0, index),
2879
- ...convertToArrayPayload(value),
2880
- ...data.slice(index),
2881
- ];
2882
- }
2883
-
2884
- var moveArrayAt = (data, from, to) => {
2885
- if (!Array.isArray(data)) {
2886
- return [];
2887
- }
2888
- if (isUndefined(data[to])) {
2889
- data[to] = undefined;
2890
- }
2891
- data.splice(to, 0, data.splice(from, 1)[0]);
2892
- return data;
2893
- };
2894
-
2895
- var prependAt = (data, value) => [
2896
- ...convertToArrayPayload(value),
2897
- ...convertToArrayPayload(data),
2898
- ];
2899
-
2900
- function removeAtIndexes(data, indexes) {
2901
- let i = 0;
2902
- const temp = [...data];
2903
- for (const index of indexes) {
2904
- temp.splice(index - i, 1);
2905
- i++;
2906
- }
2907
- return compact(temp).length ? temp : [];
2908
- }
2909
- var removeArrayAt = (data, index) => isUndefined(index)
2910
- ? []
2911
- : removeAtIndexes(data, convertToArrayPayload(index).sort((a, b) => a - b));
2912
-
2913
- var swapArrayAt = (data, indexA, indexB) => {
2914
- [data[indexA], data[indexB]] = [data[indexB], data[indexA]];
2915
- };
2916
-
2917
- var updateAt = (fieldValues, index, value) => {
2918
- fieldValues[index] = value;
2919
- return fieldValues;
2920
- };
2921
-
2922
- /**
2923
- * 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)
2924
- *
2925
- * @remarks
2926
- * [API](https://react-hook-form.com/docs/usefieldarray) • [Demo](https://codesandbox.io/s/react-hook-form-usefieldarray-ssugn)
2927
- *
2928
- * @param props - useFieldArray props
2929
- *
2930
- * @returns methods - functions to manipulate with the Field Arrays (dynamic inputs) {@link UseFieldArrayReturn}
2931
- *
2932
- * @example
2933
- * ```tsx
2934
- * function App() {
2935
- * const { register, control, handleSubmit, reset, trigger, setError } = useForm({
2936
- * defaultValues: {
2937
- * test: []
2938
- * }
2939
- * });
2940
- * const { fields, append } = useFieldArray({
2941
- * control,
2942
- * name: "test"
2943
- * });
2944
- *
2945
- * return (
2946
- * <form onSubmit={handleSubmit(data => console.log(data))}>
2947
- * {fields.map((item, index) => (
2948
- * <input key={item.id} {...register(`test.${index}.firstName`)} />
2949
- * ))}
2950
- * <button type="button" onClick={() => append({ firstName: "bill" })}>
2951
- * append
2952
- * </button>
2953
- * <input type="submit" />
2954
- * </form>
2955
- * );
2956
- * }
2957
- * ```
2958
- */
2959
- function useFieldArray(props) {
2960
- const formControl = useFormControlContext();
2961
- const { control = formControl, name, keyName = 'id', disabled, shouldUnregister, rules, } = props;
2962
- const [fields, setFields] = React.useState(control._getFieldArray(name));
2963
- const ids = React.useRef(control._getFieldArray(name).map(generateId));
2964
- const _actioned = React.useRef(false);
2965
- if (!disabled) {
2966
- control._names.array.add(name);
2967
- }
2968
- React.useMemo(() => !disabled &&
2969
- rules &&
2970
- fields.length >= 0 &&
2971
- control.register(name, rules), [control, name, fields.length, rules, disabled]);
2972
- useIsomorphicLayoutEffect(() => {
2973
- if (disabled) {
2974
- return;
2852
+ const register = (name, options = {}) => {
2853
+ let field = get(_fields, name);
2854
+ const disabledIsDefined = isBoolean(options.disabled) || isBoolean(_options.disabled);
2855
+ const shouldRevalidateRemount = !_names.registerName.has(name) && field && field._f && !field._f.mount;
2856
+ set(_fields, name, {
2857
+ ...(field || {}),
2858
+ _f: {
2859
+ ...(field && field._f ? field._f : { ref: { name } }),
2860
+ name,
2861
+ mount: true,
2862
+ ...options,
2863
+ },
2864
+ });
2865
+ _names.mount.add(name);
2866
+ if (field && !shouldRevalidateRemount) {
2867
+ _setDisabledField({
2868
+ disabled: isBoolean(options.disabled)
2869
+ ? options.disabled
2870
+ : _options.disabled,
2871
+ name,
2872
+ });
2975
2873
  }
2976
- return control._subjects.array.subscribe({
2977
- next: ({ values, name: fieldArrayName, }) => {
2978
- if (fieldArrayName === name || !fieldArrayName) {
2979
- const fieldValues = get(values, name);
2980
- if (Array.isArray(fieldValues)) {
2981
- setFields(fieldValues);
2982
- ids.current = fieldValues.map(generateId);
2874
+ else {
2875
+ updateValidAndValue(name, true, options.value);
2876
+ }
2877
+ return {
2878
+ ...(disabledIsDefined
2879
+ ? { disabled: options.disabled || _options.disabled }
2880
+ : {}),
2881
+ ...(_options.progressive
2882
+ ? {
2883
+ required: !!options.required,
2884
+ min: getRuleValue(options.min),
2885
+ max: getRuleValue(options.max),
2886
+ minLength: getRuleValue(options.minLength),
2887
+ maxLength: getRuleValue(options.maxLength),
2888
+ pattern: getRuleValue(options.pattern),
2889
+ }
2890
+ : {}),
2891
+ name,
2892
+ onChange,
2893
+ onBlur: onChange,
2894
+ ref: (ref) => {
2895
+ if (ref) {
2896
+ _names.registerName.add(name);
2897
+ register(name, options);
2898
+ _names.registerName.delete(name);
2899
+ field = get(_fields, name);
2900
+ const fieldRef = isUndefined(ref.value)
2901
+ ? ref.querySelectorAll
2902
+ ? ref.querySelectorAll('input,select,textarea')[0] || ref
2903
+ : ref
2904
+ : ref;
2905
+ const radioOrCheckbox = isRadioOrCheckbox(fieldRef);
2906
+ const refs = field._f.refs || [];
2907
+ if (radioOrCheckbox
2908
+ ? refs.find((option) => option === fieldRef)
2909
+ : fieldRef === field._f.ref) {
2910
+ return;
2983
2911
  }
2984
- else if (!fieldArrayName) {
2985
- setFields([]);
2986
- ids.current = [];
2912
+ set(_fields, name, {
2913
+ _f: {
2914
+ ...field._f,
2915
+ ...(radioOrCheckbox
2916
+ ? {
2917
+ refs: [
2918
+ ...refs.filter(live),
2919
+ fieldRef,
2920
+ ...(Array.isArray(get(_defaultValues, name)) ? [{}] : []),
2921
+ ],
2922
+ ref: { type: fieldRef.type, name },
2923
+ }
2924
+ : { ref: fieldRef }),
2925
+ },
2926
+ });
2927
+ updateValidAndValue(name, false, undefined, fieldRef);
2928
+ }
2929
+ else {
2930
+ field = get(_fields, name, {});
2931
+ if (field._f) {
2932
+ field._f.mount = false;
2987
2933
  }
2934
+ (_options.shouldUnregister || options.shouldUnregister) &&
2935
+ !(isNameInFieldArray(_names.array, name) && _state.action) &&
2936
+ _names.unMount.add(name);
2988
2937
  }
2989
2938
  },
2990
- }).unsubscribe;
2991
- }, [control, name, disabled]);
2992
- const updateValues = React.useCallback((updatedFieldArrayValues) => {
2993
- _actioned.current = true;
2994
- control._setFieldArray(name, updatedFieldArrayValues);
2995
- }, [control, name]);
2996
- const append = (value, options) => {
2997
- if (disabled) {
2998
- return;
2939
+ };
2940
+ };
2941
+ const _focusError = () => _options.shouldFocusError &&
2942
+ !_options.shouldUseNativeValidation &&
2943
+ iterateFieldsByAction(_fields, _focusInput, _names.mount);
2944
+ const _disableForm = (disabled) => {
2945
+ if (isBoolean(disabled)) {
2946
+ _subjects.state.next({ disabled });
2947
+ iterateFieldsByAction(_fields, (ref, name) => {
2948
+ const currentField = get(_fields, name);
2949
+ if (currentField) {
2950
+ ref.disabled = currentField._f.disabled || disabled;
2951
+ if (Array.isArray(currentField._f.refs)) {
2952
+ currentField._f.refs.forEach((inputRef) => {
2953
+ inputRef.disabled = currentField._f.disabled || disabled;
2954
+ });
2955
+ }
2956
+ }
2957
+ }, 0, false);
2999
2958
  }
3000
- const appendValue = convertToArrayPayload(cloneObject(value));
3001
- const updatedFieldArrayValues = appendAt(control._getFieldArray(name), appendValue);
3002
- control._names.focus = getFocusFieldName(name, updatedFieldArrayValues.length - 1, options);
3003
- ids.current = appendAt(ids.current, appendValue.map(generateId));
3004
- updateValues(updatedFieldArrayValues);
3005
- setFields(updatedFieldArrayValues);
3006
- control._setFieldArray(name, updatedFieldArrayValues, appendAt, {
3007
- argA: fillEmptyArray(value),
3008
- });
3009
2959
  };
3010
- const prepend = (value, options) => {
3011
- if (disabled) {
3012
- return;
2960
+ const handleSubmit = (onValid, onInvalid) => async (e) => {
2961
+ let onValidError = undefined;
2962
+ if (e) {
2963
+ e.preventDefault && e.preventDefault();
2964
+ e.persist &&
2965
+ e.persist();
3013
2966
  }
3014
- const prependValue = convertToArrayPayload(cloneObject(value));
3015
- const updatedFieldArrayValues = prependAt(control._getFieldArray(name), prependValue);
3016
- control._names.focus = getFocusFieldName(name, 0, options);
3017
- ids.current = prependAt(ids.current, prependValue.map(generateId));
3018
- updateValues(updatedFieldArrayValues);
3019
- setFields(updatedFieldArrayValues);
3020
- control._setFieldArray(name, updatedFieldArrayValues, prependAt, {
3021
- argA: fillEmptyArray(value),
2967
+ let fieldValues = cloneObject(_formValues);
2968
+ _subjects.state.next({
2969
+ isSubmitting: true,
3022
2970
  });
3023
- };
3024
- const remove = (index) => {
3025
- if (disabled) {
3026
- return;
2971
+ if (_options.resolver) {
2972
+ const { errors, values } = await _runSchema();
2973
+ _updateIsValidating();
2974
+ _formState.errors = errors;
2975
+ fieldValues = cloneObject(values);
3027
2976
  }
3028
- const updatedFieldArrayValues = removeArrayAt(control._getFieldArray(name), index);
3029
- ids.current = removeArrayAt(ids.current, index);
3030
- updateValues(updatedFieldArrayValues);
3031
- setFields(updatedFieldArrayValues);
3032
- !Array.isArray(get(control._fields, name)) &&
3033
- set(control._fields, name, undefined);
3034
- control._setFieldArray(name, updatedFieldArrayValues, removeArrayAt, {
3035
- argA: index,
3036
- });
3037
- };
3038
- const insert$1 = (index, value, options) => {
3039
- if (disabled) {
3040
- return;
2977
+ else {
2978
+ await executeBuiltInValidation({
2979
+ fields: _fields,
2980
+ eventType: EVENTS.SUBMIT,
2981
+ });
3041
2982
  }
3042
- const insertValue = convertToArrayPayload(cloneObject(value));
3043
- const updatedFieldArrayValues = insert(control._getFieldArray(name), index, insertValue);
3044
- control._names.focus = getFocusFieldName(name, index, options);
3045
- ids.current = insert(ids.current, index, insertValue.map(generateId));
3046
- updateValues(updatedFieldArrayValues);
3047
- setFields(updatedFieldArrayValues);
3048
- control._setFieldArray(name, updatedFieldArrayValues, insert, {
3049
- argA: index,
3050
- argB: fillEmptyArray(value),
3051
- });
3052
- };
3053
- const swap = (indexA, indexB) => {
3054
- if (disabled) {
3055
- return;
2983
+ if (_names.disabled.size) {
2984
+ for (const name of _names.disabled) {
2985
+ unset(fieldValues, name);
2986
+ }
3056
2987
  }
3057
- const updatedFieldArrayValues = control._getFieldArray(name);
3058
- swapArrayAt(updatedFieldArrayValues, indexA, indexB);
3059
- swapArrayAt(ids.current, indexA, indexB);
3060
- updateValues(updatedFieldArrayValues);
3061
- setFields(updatedFieldArrayValues);
3062
- control._setFieldArray(name, updatedFieldArrayValues, swapArrayAt, {
3063
- argA: indexA,
3064
- argB: indexB,
3065
- }, false);
3066
- };
3067
- const move = (from, to) => {
3068
- if (disabled) {
3069
- return;
2988
+ unset(_formState.errors, ROOT_ERROR_TYPE);
2989
+ if (isEmptyObject(_formState.errors)) {
2990
+ _subjects.state.next({
2991
+ errors: {},
2992
+ });
2993
+ try {
2994
+ await onValid(fieldValues, e);
2995
+ }
2996
+ catch (error) {
2997
+ onValidError = error;
2998
+ }
3070
2999
  }
3071
- const updatedFieldArrayValues = control._getFieldArray(name);
3072
- moveArrayAt(updatedFieldArrayValues, from, to);
3073
- moveArrayAt(ids.current, from, to);
3074
- updateValues(updatedFieldArrayValues);
3075
- setFields(updatedFieldArrayValues);
3076
- control._setFieldArray(name, updatedFieldArrayValues, moveArrayAt, {
3077
- argA: from,
3078
- argB: to,
3079
- }, false);
3080
- };
3081
- const update = (index, value) => {
3082
- if (disabled) {
3083
- return;
3000
+ else {
3001
+ if (onInvalid) {
3002
+ await onInvalid({ ..._formState.errors }, e);
3003
+ }
3004
+ _focusError();
3005
+ setTimeout(_focusError);
3006
+ }
3007
+ _subjects.state.next({
3008
+ isSubmitted: true,
3009
+ isSubmitting: false,
3010
+ isSubmitSuccessful: isEmptyObject(_formState.errors) && !onValidError,
3011
+ submitCount: _formState.submitCount + 1,
3012
+ errors: _formState.errors,
3013
+ });
3014
+ if (onValidError) {
3015
+ throw onValidError;
3084
3016
  }
3085
- const updateValue = cloneObject(value);
3086
- const updatedFieldArrayValues = updateAt(control._getFieldArray(name), index, updateValue);
3087
- ids.current = [...updatedFieldArrayValues].map((item, i) => !item || i === index ? generateId() : ids.current[i]);
3088
- updateValues(updatedFieldArrayValues);
3089
- setFields([...updatedFieldArrayValues]);
3090
- control._setFieldArray(name, updatedFieldArrayValues, updateAt, {
3091
- argA: index,
3092
- argB: updateValue,
3093
- }, true, false);
3094
3017
  };
3095
- const replace = (value) => {
3096
- if (disabled) {
3097
- return;
3018
+ const resetField = (name, options = {}) => {
3019
+ if (get(_fields, name)) {
3020
+ if (isUndefined(options.defaultValue)) {
3021
+ setValue(name, cloneObject(get(_defaultValues, name)));
3022
+ }
3023
+ else {
3024
+ setValue(name, options.defaultValue);
3025
+ set(_defaultValues, name, cloneObject(options.defaultValue));
3026
+ }
3027
+ if (!options.keepTouched) {
3028
+ unset(_formState.touchedFields, name);
3029
+ }
3030
+ if (!options.keepDirty) {
3031
+ unset(_formState.dirtyFields, name);
3032
+ _formState.isDirty = options.defaultValue
3033
+ ? _getDirty(name, cloneObject(get(_defaultValues, name)))
3034
+ : _getDirty();
3035
+ }
3036
+ if (!options.keepError) {
3037
+ unset(_formState.errors, name);
3038
+ _proxyFormState.isValid && _setValid();
3039
+ }
3040
+ _subjects.state.next({ ..._formState });
3098
3041
  }
3099
- const updatedFieldArrayValues = convertToArrayPayload(cloneObject(value));
3100
- ids.current = updatedFieldArrayValues.map(generateId);
3101
- updateValues([...updatedFieldArrayValues]);
3102
- setFields([...updatedFieldArrayValues]);
3103
- control._setFieldArray(name, [...updatedFieldArrayValues], (data) => data, {}, true, false);
3104
3042
  };
3105
- React.useEffect(() => {
3106
- if (disabled) {
3107
- return;
3043
+ const _reset = (formValues, keepStateOptions = {}) => {
3044
+ const updatedValues = formValues ? cloneObject(formValues) : _defaultValues;
3045
+ const cloneUpdatedValues = cloneObject(updatedValues);
3046
+ const isEmptyResetValues = isEmptyObject(formValues);
3047
+ const values = cloneUpdatedValues;
3048
+ const fieldRefs = _fields;
3049
+ if (!keepStateOptions.keepDefaultValues) {
3050
+ _defaultValues = updatedValues;
3108
3051
  }
3109
- control._state.action = false;
3110
- isWatched(name, control._names) &&
3111
- control._subjects.state.next({
3112
- ...control._formState,
3113
- });
3114
- const validationModes = getValidationModes(control._options.mode);
3115
- if (_actioned.current &&
3116
- (!validationModes.isOnSubmit || control._formState.isSubmitted) &&
3117
- !getValidationModes(control._options.reValidateMode).isOnSubmit &&
3118
- !validationModes.isOnBlur) {
3119
- if (control._options.resolver) {
3120
- control._runSchema([name]).then((result) => {
3121
- control._updateIsValidating([name]);
3122
- const error = get(result.errors, name);
3123
- const existingError = get(control._formState.errors, name);
3124
- if (existingError
3125
- ? (!error && existingError.type) ||
3126
- (error &&
3127
- (existingError.type !== error.type ||
3128
- existingError.message !== error.message))
3129
- : error && error.type) {
3130
- error
3131
- ? set(control._formState.errors, name, error)
3132
- : unset(control._formState.errors, name);
3133
- control._subjects.state.next({
3134
- errors: control._formState.errors,
3135
- });
3052
+ if (!keepStateOptions.keepValues) {
3053
+ if (keepStateOptions.keepDirtyValues) {
3054
+ const fieldsToCheck = new Set([
3055
+ ..._names.mount,
3056
+ ...Object.keys(getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs)),
3057
+ ]);
3058
+ for (const fieldName of Array.from(fieldsToCheck)) {
3059
+ const isDirty = get(_formState.dirtyFields, fieldName);
3060
+ const existingValue = get(_formValues, fieldName);
3061
+ const newValue = get(values, fieldName);
3062
+ if (isDirty && !isUndefined(existingValue)) {
3063
+ set(values, fieldName, existingValue);
3136
3064
  }
3137
- });
3065
+ else if (!isDirty && !isUndefined(newValue)) {
3066
+ setValue(fieldName, newValue);
3067
+ }
3068
+ }
3138
3069
  }
3139
3070
  else {
3140
- const field = get(control._fields, name);
3141
- if (field &&
3142
- field._f &&
3143
- !(getValidationModes(control._options.reValidateMode).isOnSubmit &&
3144
- getValidationModes(control._options.mode).isOnSubmit)) {
3145
- validateField(field, control._names.disabled, control._formValues, control._options.criteriaMode === VALIDATION_MODE.all, control._options.shouldUseNativeValidation, true).then((error) => !isEmptyObject(error) &&
3146
- control._subjects.state.next({
3147
- errors: updateFieldArrayRootError(control._formState.errors, error, name),
3148
- }));
3071
+ if (isWeb && isUndefined(formValues)) {
3072
+ for (const name of _names.mount) {
3073
+ const field = get(_fields, name);
3074
+ if (field && field._f) {
3075
+ const fieldReference = Array.isArray(field._f.refs)
3076
+ ? field._f.refs[0]
3077
+ : field._f.ref;
3078
+ if (isHTMLElement(fieldReference)) {
3079
+ const form = fieldReference.closest('form');
3080
+ if (form) {
3081
+ form.reset();
3082
+ break;
3083
+ }
3084
+ }
3085
+ }
3086
+ }
3087
+ }
3088
+ if (keepStateOptions.keepFieldsRef) {
3089
+ for (const fieldName of _names.mount) {
3090
+ setValue(fieldName, get(values, fieldName));
3091
+ }
3092
+ }
3093
+ else {
3094
+ _fields = {};
3095
+ }
3096
+ }
3097
+ if (_options.shouldUnregister) {
3098
+ _formValues = keepStateOptions.keepDefaultValues
3099
+ ? cloneObject(_defaultValues)
3100
+ : {};
3101
+ if (keepStateOptions.keepFieldsRef) {
3102
+ for (const fieldName of _names.mount) {
3103
+ set(_formValues, fieldName, get(values, fieldName));
3104
+ }
3149
3105
  }
3150
3106
  }
3151
- }
3152
- control._subjects.state.next({
3153
- name,
3154
- values: cloneObject(control._formValues),
3155
- });
3156
- control._names.focus &&
3157
- iterateFieldsByAction(control._fields, (ref, key) => {
3158
- if (control._names.focus &&
3159
- key.startsWith(control._names.focus) &&
3160
- ref.focus) {
3161
- ref.focus();
3162
- return 1;
3163
- }
3164
- return;
3107
+ else {
3108
+ _formValues = cloneObject(values);
3109
+ }
3110
+ _subjects.array.next({
3111
+ values: { ...values },
3112
+ });
3113
+ _subjects.state.next({
3114
+ name: undefined,
3115
+ type: undefined,
3116
+ values: { ...values },
3165
3117
  });
3166
- control._names.focus = '';
3167
- control._setValid();
3168
- _actioned.current = false;
3169
- }, [fields, name, control, disabled]);
3170
- React.useEffect(() => {
3171
- if (!disabled) {
3172
- !get(control._formValues, name) && control._setFieldArray(name);
3173
3118
  }
3174
- return () => {
3175
- if (disabled) {
3176
- return;
3177
- }
3178
- const shouldKeepFieldArrayValues = !(control._options.shouldUnregister || shouldUnregister);
3179
- const updateMounted = (name, value) => {
3180
- const field = get(control._fields, name);
3181
- if (field && field._f) {
3182
- field._f.mount = value;
3183
- }
3184
- };
3185
- if (_actioned.current && shouldKeepFieldArrayValues) {
3186
- control._subjects.state.next({
3187
- name,
3188
- values: cloneObject(control._formValues),
3119
+ _names = {
3120
+ mount: keepStateOptions.keepDirtyValues ? _names.mount : new Set(),
3121
+ unMount: new Set(),
3122
+ array: new Set(),
3123
+ registerName: new Set(),
3124
+ disabled: new Set(),
3125
+ watch: new Set(),
3126
+ watchAll: false,
3127
+ focus: '',
3128
+ };
3129
+ _state.mount =
3130
+ !_proxyFormState.isValid ||
3131
+ !!keepStateOptions.keepIsValid ||
3132
+ !!keepStateOptions.keepDirtyValues ||
3133
+ (!_options.shouldUnregister && !isEmptyObject(values));
3134
+ _state.watch = !!_options.shouldUnregister;
3135
+ _state.keepIsValid = !!keepStateOptions.keepIsValid;
3136
+ _state.action = false;
3137
+ if (!keepStateOptions.keepErrors) {
3138
+ _formState.errors = {};
3139
+ }
3140
+ _subjects.state.next({
3141
+ submitCount: keepStateOptions.keepSubmitCount
3142
+ ? _formState.submitCount
3143
+ : 0,
3144
+ isDirty: isEmptyResetValues
3145
+ ? false
3146
+ : keepStateOptions.keepDirty
3147
+ ? _formState.isDirty
3148
+ : keepStateOptions.keepValues
3149
+ ? _getDirty()
3150
+ : !!(keepStateOptions.keepDefaultValues &&
3151
+ !deepEqual(formValues, _defaultValues)),
3152
+ isSubmitted: keepStateOptions.keepIsSubmitted
3153
+ ? _formState.isSubmitted
3154
+ : false,
3155
+ dirtyFields: isEmptyResetValues
3156
+ ? {}
3157
+ : keepStateOptions.keepDirtyValues
3158
+ ? keepStateOptions.keepDefaultValues && _formValues
3159
+ ? getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs)
3160
+ : _formState.dirtyFields
3161
+ : keepStateOptions.keepDefaultValues && formValues
3162
+ ? getDirtyFields(_defaultValues, formValues, undefined, fieldRefs)
3163
+ : keepStateOptions.keepDirty
3164
+ ? _formState.dirtyFields
3165
+ : {},
3166
+ touchedFields: keepStateOptions.keepTouched
3167
+ ? _formState.touchedFields
3168
+ : {},
3169
+ errors: keepStateOptions.keepErrors ? _formState.errors : {},
3170
+ isSubmitSuccessful: keepStateOptions.keepIsSubmitSuccessful
3171
+ ? _formState.isSubmitSuccessful
3172
+ : false,
3173
+ isSubmitting: false,
3174
+ defaultValues: _defaultValues,
3175
+ });
3176
+ };
3177
+ const reset = (formValues, keepStateOptions) => _reset(isFunction(formValues)
3178
+ ? formValues(_formValues)
3179
+ : formValues, { ..._options.resetOptions, ...keepStateOptions });
3180
+ const setFocus = (name, options = {}) => {
3181
+ const field = get(_fields, name);
3182
+ const fieldReference = field && field._f;
3183
+ if (fieldReference) {
3184
+ const fieldRef = fieldReference.refs
3185
+ ? fieldReference.refs[0]
3186
+ : fieldReference.ref;
3187
+ if (fieldRef.focus) {
3188
+ setTimeout(() => {
3189
+ fieldRef.focus();
3190
+ options.shouldSelect &&
3191
+ isFunction(fieldRef.select) &&
3192
+ fieldRef.select();
3189
3193
  });
3190
3194
  }
3191
- shouldKeepFieldArrayValues
3192
- ? updateMounted(name, false)
3193
- : control.unregister(name);
3195
+ }
3196
+ };
3197
+ const _setFormState = (updatedFormState) => {
3198
+ // `name`, `type`, and `values` describe the event that produced this
3199
+ // update, not the form's persisted state (they aren't part of
3200
+ // `FormState`). Merging them in would leak a stale `name`/`type` from
3201
+ // one event into a later, unrelated notification that doesn't specify
3202
+ // its own.
3203
+ const { name, type, values, ...formState } = updatedFormState;
3204
+ _formState = {
3205
+ ..._formState,
3206
+ ...formState,
3194
3207
  };
3195
- }, [name, control, keyName, shouldUnregister, disabled]);
3208
+ };
3209
+ const _resetDefaultValues = () => isFunction(_options.defaultValues) &&
3210
+ _options.defaultValues().then((values) => {
3211
+ reset(values, _options.resetOptions);
3212
+ _subjects.state.next({
3213
+ isLoading: false,
3214
+ });
3215
+ });
3216
+ const resetDefaultValues = (values, options = {}) => {
3217
+ _defaultValues = cloneObject(values);
3218
+ if (!options.keepDirty) {
3219
+ const newDirtyFields = getDirtyFields(_defaultValues, _formValues, undefined, _fields);
3220
+ _formState.dirtyFields = newDirtyFields;
3221
+ _formState.isDirty = !isEmptyObject(newDirtyFields);
3222
+ }
3223
+ if (!options.keepIsValid) {
3224
+ _setValid();
3225
+ }
3226
+ _subjects.state.next({
3227
+ ..._formState,
3228
+ defaultValues: _defaultValues,
3229
+ });
3230
+ };
3231
+ const methods = {
3232
+ control: {
3233
+ register,
3234
+ unregister,
3235
+ getFieldState,
3236
+ handleSubmit,
3237
+ setError,
3238
+ _subscribe,
3239
+ _runSchema,
3240
+ _updateIsValidating,
3241
+ _focusError,
3242
+ _getWatch,
3243
+ _getDirty,
3244
+ _setValid,
3245
+ _setFieldArray,
3246
+ _setDisabledField,
3247
+ _setErrors,
3248
+ _getFieldArray,
3249
+ _reset,
3250
+ _resetDefaultValues,
3251
+ _removeUnmounted,
3252
+ _disableForm,
3253
+ _subjects,
3254
+ _proxyFormState,
3255
+ get _fields() {
3256
+ return _fields;
3257
+ },
3258
+ get _formValues() {
3259
+ return _formValues;
3260
+ },
3261
+ get _state() {
3262
+ return _state;
3263
+ },
3264
+ set _state(value) {
3265
+ _state = value;
3266
+ },
3267
+ get _defaultValues() {
3268
+ return _defaultValues;
3269
+ },
3270
+ get _names() {
3271
+ return _names;
3272
+ },
3273
+ set _names(value) {
3274
+ _names = value;
3275
+ },
3276
+ get _formState() {
3277
+ return _formState;
3278
+ },
3279
+ get _options() {
3280
+ return _options;
3281
+ },
3282
+ set _options(value) {
3283
+ _options = {
3284
+ ..._options,
3285
+ ...value,
3286
+ };
3287
+ _validationModeBeforeSubmit = getValidationModes(_options.mode);
3288
+ _validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
3289
+ },
3290
+ },
3291
+ subscribe,
3292
+ trigger,
3293
+ register,
3294
+ handleSubmit,
3295
+ watch,
3296
+ setValue,
3297
+ setValues,
3298
+ getValues,
3299
+ reset,
3300
+ resetField,
3301
+ resetDefaultValues,
3302
+ clearErrors,
3303
+ unregister,
3304
+ setError,
3305
+ setFocus,
3306
+ getFieldState,
3307
+ };
3196
3308
  return {
3197
- swap: React.useCallback(swap, [updateValues, name, control, disabled]),
3198
- move: React.useCallback(move, [updateValues, name, control, disabled]),
3199
- prepend: React.useCallback(prepend, [
3200
- updateValues,
3201
- name,
3202
- control,
3203
- disabled,
3204
- ]),
3205
- append: React.useCallback(append, [updateValues, name, control, disabled]),
3206
- remove: React.useCallback(remove, [updateValues, name, control, disabled]),
3207
- insert: React.useCallback(insert$1, [updateValues, name, control, disabled]),
3208
- update: React.useCallback(update, [updateValues, name, control, disabled]),
3209
- replace: React.useCallback(replace, [
3210
- updateValues,
3211
- name,
3212
- control,
3213
- disabled,
3214
- ]),
3215
- fields: React.useMemo(() => fields.map((field, index) => ({
3216
- ...field,
3217
- ...(isBoolean(disabled) ? { disabled } : {}),
3218
- [keyName]: ids.current[index] || generateId(),
3219
- })), [fields, keyName, disabled]),
3309
+ ...methods,
3310
+ formControl: methods,
3220
3311
  };
3221
3312
  }
3222
3313
 
@@ -3391,5 +3482,5 @@ function useForm(props = {}) {
3391
3482
  */
3392
3483
  const Watch = (props) => props.render(useWatch({ name: props.names, ...props }));
3393
3484
 
3394
- export { Controller, Form, FormProvider, FormStateSubscribe, Watch, appendErrors, createFormControl, get, set, useController, useFieldArray, useForm, useFormContext, useFormState, useWatch };
3485
+ export { Controller, FieldArray, Form, FormProvider, FormStateSubscribe, Watch, appendErrors, createFormControl, get, set, useController, useFieldArray, useForm, useFormContext, useFormState, useWatch };
3395
3486
  //# sourceMappingURL=index.esm.mjs.map