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