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