text: (function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) :
    typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) :
    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ReactHookForm = {}, global.React));
  }(this, (function (exports, React) { 'use strict';
  
    var isHTMLElement = (value) => value instanceof HTMLElement;
  
    const EVENTS = {
        BLUR: 'blur',
        CHANGE: 'change',
        INPUT: 'input',
    };
    const VALIDATION_MODE = {
        onBlur: 'onBlur',
        onChange: 'onChange',
        onSubmit: 'onSubmit',
        onTouched: 'onTouched',
        all: 'all',
    };
    const VALUE = 'value';
    const SELECT = 'select';
    const UNDEFINED = 'undefined';
    const INPUT_VALIDATION_RULES = {
        max: 'max',
        min: 'min',
        maxLength: 'maxLength',
        minLength: 'minLength',
        pattern: 'pattern',
        required: 'required',
        validate: 'validate',
    };
  
    function attachEventListeners({ ref }, shouldAttachChangeEvent, handleChange) {
        if (isHTMLElement(ref) && handleChange) {
            ref.addEventListener(shouldAttachChangeEvent ? EVENTS.CHANGE : EVENTS.INPUT, handleChange);
            ref.addEventListener(EVENTS.BLUR, handleChange);
        }
    }
  
    var isNullOrUndefined = (value) => value == null;
  
    const isObjectType = (value) => typeof value === 'object';
    var isObject = (value) => !isNullOrUndefined(value) &&
        !Array.isArray(value) &&
        isObjectType(value) &&
        !(value instanceof Date);
  
    var isKey = (value) => !Array.isArray(value) &&
        (/^\w*$/.test(value) ||
            !/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/.test(value));
  
    var compact = (value) => value.filter(Boolean);
  
    var stringToPath = (input) => compact(input
        .replace(/["|']/g, '')
        .replace(/\[/g, '.')
        .replace(/\]/g, '')
        .split('.'));
  
    function set(object, path, value) {
        let index = -1;
        const tempPath = isKey(path) ? [path] : stringToPath(path);
        const length = tempPath.length;
        const lastIndex = length - 1;
        while (++index < length) {
            const key = tempPath[index];
            let newValue = value;
            if (index !== lastIndex) {
                const objValue = object[key];
                newValue =
                    isObject(objValue) || Array.isArray(objValue)
                        ? objValue
                        : !isNaN(+tempPath[index + 1])
                            ? []
                            : {};
            }
            object[key] = newValue;
            object = object[key];
        }
        return object;
    }
  
    var transformToNestObject = (data, value = {}) => {
        for (const key in data) {
            !isKey(key) ? set(value, key, data[key]) : (value[key] = data[key]);
        }
        return value;
    };
  
    var isUndefined = (val) => val === undefined;
  
    var get = (obj, path, defaultValue) => {
        const result = compact(path.split(/[,[\].]+?/)).reduce((result, key) => (isNullOrUndefined(result) ? result : result[key]), obj);
        return isUndefined(result) || result === obj
            ? isUndefined(obj[path])
                ? defaultValue
                : obj[path]
            : result;
    };
  
    var focusOnErrorField = (fields, fieldErrors) => {
        for (const key in fields) {
            if (get(fieldErrors, key)) {
                const field = fields[key];
                if (field) {
                    if (field.ref.focus) {
                        if (isUndefined(field.ref.focus())) {
                            break;
                        }
                    }
                    else if (field.options) {
                        field.options[0].ref.focus();
                        break;
                    }
                }
            }
        }
    };
  
    var removeAllEventListeners = (ref, validateWithStateUpdate) => {
        if (isHTMLElement(ref) && ref.removeEventListener) {
            ref.removeEventListener(EVENTS.INPUT, validateWithStateUpdate);
            ref.removeEventListener(EVENTS.CHANGE, validateWithStateUpdate);
            ref.removeEventListener(EVENTS.BLUR, validateWithStateUpdate);
        }
    };
  
    const defaultReturn = {
        isValid: false,
        value: '',
    };
    var getRadioValue = (options) => Array.isArray(options)
        ? options.reduce((previous, option) => option && option.ref.checked
            ? {
                isValid: true,
                value: option.ref.value,
            }
            : previous, defaultReturn)
        : defaultReturn;
  
    var getMultipleSelectValue = (options) => [...options]
        .filter(({ selected }) => selected)
        .map(({ value }) => value);
  
    var isRadioInput = (element) => element.type === 'radio';
  
    var isFileInput = (element) => element.type === 'file';
  
    var isCheckBoxInput = (element) => element.type === 'checkbox';
  
    var isMultipleSelect = (element) => element.type === `${SELECT}-multiple`;
  
    const defaultResult = {
        value: false,
        isValid: false,
    };
    const validResult = { value: true, isValid: true };
    var getCheckboxValue = (options) => {
        if (Array.isArray(options)) {
            if (options.length > 1) {
                const values = options
                    .filter((option) => option && option.ref.checked)
                    .map(({ ref: { value } }) => value);
                return { value: values, isValid: !!values.length };
            }
            const { checked, value, attributes } = options[0].ref;
            return checked
                ? attributes && !isUndefined(attributes.value)
                    ? isUndefined(value) || value === ''
                        ? validResult
                        : { value: value, isValid: true }
                    : validResult
                : defaultResult;
        }
        return defaultResult;
    };
  
    function getFieldValue(fieldsRef, name, shallowFieldsStateRef, excludeDisabled) {
        const field = fieldsRef.current[name];
        if (field) {
            const { ref: { value, disabled }, ref, } = field;
            if (disabled && excludeDisabled) {
                return;
            }
            if (isFileInput(ref)) {
                return ref.files;
            }
            if (isRadioInput(ref)) {
                return getRadioValue(field.options).value;
            }
            if (isMultipleSelect(ref)) {
                return getMultipleSelectValue(ref.options);
            }
            if (isCheckBoxInput(ref)) {
                return getCheckboxValue(field.options).value;
            }
            return value;
        }
        if (shallowFieldsStateRef) {
            return get(shallowFieldsStateRef.current, name);
        }
    }
  
    function isDetached(element) {
        if (!element) {
            return true;
        }
        if (!(element instanceof HTMLElement) ||
            element.nodeType === Node.DOCUMENT_NODE) {
            return false;
        }
        return isDetached(element.parentNode);
    }
  
    var isEmptyObject = (value) => isObject(value) && !Object.keys(value).length;
  
    var isBoolean = (value) => typeof value === 'boolean';
  
    function baseGet(object, updatePath) {
        const path = updatePath.slice(0, -1);
        const length = path.length;
        let index = 0;
        while (index < length) {
            object = isUndefined(object) ? index++ : object[updatePath[index++]];
        }
        return object;
    }
    function unset(object, path) {
        const updatePath = isKey(path) ? [path] : stringToPath(path);
        const childObject = updatePath.length == 1 ? object : baseGet(object, updatePath);
        const key = updatePath[updatePath.length - 1];
        let previousObjRef = undefined;
        if (childObject) {
            delete childObject[key];
        }
        for (let k = 0; k < updatePath.slice(0, -1).length; k++) {
            let index = -1;
            let objectRef = undefined;
            const currentPaths = updatePath.slice(0, -(k + 1));
            const currentPathsLength = currentPaths.length - 1;
            if (k > 0) {
                previousObjRef = object;
            }
            while (++index < currentPaths.length) {
                const item = currentPaths[index];
                objectRef = objectRef ? objectRef[item] : object[item];
                if (currentPathsLength === index &&
                    ((isObject(objectRef) && isEmptyObject(objectRef)) ||
                        (Array.isArray(objectRef) &&
                            !objectRef.filter((data) => (isObject(data) && !isEmptyObject(data)) || isBoolean(data)).length))) {
                    previousObjRef ? delete previousObjRef[item] : delete object[item];
                }
                previousObjRef = objectRef;
            }
        }
        return object;
    }
  
    const isSameRef = (fieldValue, ref) => fieldValue && fieldValue.ref === ref;
    function findRemovedFieldAndRemoveListener(fieldsRef, handleChange, field, shallowFieldsStateRef, shouldUnregister, forceDelete) {
        const { ref, ref: { name, type }, } = field;
        const fieldRef = fieldsRef.current[name];
        if (!shouldUnregister) {
            const value = getFieldValue(fieldsRef, name, shallowFieldsStateRef);
            if (!isUndefined(value)) {
                set(shallowFieldsStateRef.current, name, value);
            }
        }
        if (!type) {
            delete fieldsRef.current[name];
            return;
        }
        if ((isRadioInput(ref) || isCheckBoxInput(ref)) && fieldRef) {
            const { options } = fieldRef;
            if (Array.isArray(options) && options.length) {
                compact(options).forEach((option, index) => {
                    const { ref } = option;
                    if ((ref && isDetached(ref) && isSameRef(option, ref)) || forceDelete) {
                        removeAllEventListeners(ref, handleChange);
                        unset(options, `[${index}]`);
                    }
                });
                if (options && !compact(options).length) {
                    delete fieldsRef.current[name];
                }
            }
            else {
                delete fieldsRef.current[name];
            }
        }
        else if ((isDetached(ref) && isSameRef(fieldRef, ref)) || forceDelete) {
            removeAllEventListeners(ref, handleChange);
            delete fieldsRef.current[name];
        }
    }
  
    function setFieldArrayDirtyFields(values, defaultValues, dirtyFields, parentNode, parentName) {
        let index = -1;
        while (++index < values.length) {
            for (const key in values[index]) {
                if (Array.isArray(values[index][key])) {
                    !dirtyFields[index] && (dirtyFields[index] = {});
                    dirtyFields[index][key] = [];
                    setFieldArrayDirtyFields(values[index][key], get(defaultValues[index] || {}, key, []), dirtyFields[index][key], dirtyFields[index], key);
                }
                else {
                    get(defaultValues[index] || {}, key) === values[index][key]
                        ? set(dirtyFields[index] || {}, key)
                        : (dirtyFields[index] = Object.assign(Object.assign({}, dirtyFields[index]), { [key]: true }));
                }
            }
            !dirtyFields.length &&
                parentNode &&
                delete parentNode[parentName];
        }
        return dirtyFields.length ? dirtyFields : undefined;
    }
  
    var isString = (value) => typeof value === 'string';
  
    var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
  
    function deepMerge(target, source) {
        if (isPrimitive(target) || isPrimitive(source)) {
            return source;
        }
        for (const key in source) {
            const targetValue = target[key];
            const sourceValue = source[key];
            try {
                target[key] =
                    (isObject(targetValue) && isObject(sourceValue)) ||
                        (Array.isArray(targetValue) && Array.isArray(sourceValue))
                        ? deepMerge(targetValue, sourceValue)
                        : sourceValue;
            }
            catch (_a) { }
        }
        return target;
    }
  
    var getFieldsValues = (fieldsRef, shallowFieldsStateRef, excludeDisabled, search) => {
        const output = {};
        for (const name in fieldsRef.current) {
            if (isUndefined(search) ||
                (isString(search)
                    ? name.startsWith(search)
                    : Array.isArray(search) && search.find((data) => name.startsWith(data)))) {
                output[name] = getFieldValue(fieldsRef, name, undefined, excludeDisabled);
            }
        }
        return deepMerge(transformToNestObject(Object.assign({}, ((shallowFieldsStateRef || {}).current || {}))), transformToNestObject(output));
    };
  
    function deepEqual(object1, object2, isErrorObject) {
        if (isPrimitive(object1) || isPrimitive(object2)) {
            return object1 === object2;
        }
        const keys1 = Object.keys(object1);
        const keys2 = Object.keys(object2);
        if (keys1.length !== keys2.length) {
            return false;
        }
        for (const key of keys1) {
            if (!(isErrorObject && ['ref', 'context'].includes(key))) {
                const val1 = object1[key];
                const val2 = object2[key];
                if ((isObject(val1) || Array.isArray(val1)) &&
                    (isObject(val2) || Array.isArray(val2))
                    ? !deepEqual(val1, val2, isErrorObject)
                    : val1 !== val2) {
                    return false;
                }
            }
        }
        return true;
    }
  
    function isErrorStateChanged({ errors, name, error, validFields, fieldsWithValidation, }) {
        const isValid = isUndefined(error);
        const previousError = get(errors, name);
        return ((isValid && !!previousError) ||
            (!isValid && !deepEqual(previousError, error, true)) ||
            (isValid && get(fieldsWithValidation, name) && !get(validFields, name)));
    }
  
    var isRegex = (value) => value instanceof RegExp;
  
    const isValueMessage = (value) => isObject(value) && !isRegex(value);
    var getValueAndMessage = (validationData) => isValueMessage(validationData)
        ? validationData
        : {
            value: validationData,
            message: '',
        };
  
    var isFunction = (value) => typeof value === 'function';
  
    var isMessage = (value) => isString(value) || (isObject(value) && React.isValidElement(value));
  
    function getValidateError(result, ref, type = 'validate') {
        if (isMessage(result) || (isBoolean(result) && !result)) {
            return {
                type,
                message: isMessage(result) ? result : '',
                ref,
            };
        }
    }
  
    var appendErrors = (name, validateAllFieldCriteria, errors, type, message) => {
        if (validateAllFieldCriteria) {
            const error = errors[name];
            return Object.assign(Object.assign({}, error), { types: Object.assign(Object.assign({}, (error && error.types ? error.types : {})), { [type]: message || true }) });
        }
        return {};
    };
  
    var validateField = async (fieldsRef, validateAllFieldCriteria, { ref, ref: { type, value }, options, required, maxLength, minLength, min, max, pattern, validate, }, shallowFieldsStateRef) => {
        const fields = fieldsRef.current;
        const name = ref.name;
        const error = {};
        const isRadio = isRadioInput(ref);
        const isCheckBox = isCheckBoxInput(ref);
        const isRadioOrCheckbox = isRadio || isCheckBox;
        const isEmpty = value === '';
        const appendErrorsCurry = appendErrors.bind(null, name, validateAllFieldCriteria, error);
        const getMinMaxMessage = (exceedMax, maxLengthMessage, minLengthMessage, maxType = INPUT_VALIDATION_RULES.maxLength, minType = INPUT_VALIDATION_RULES.minLength) => {
            const message = exceedMax ? maxLengthMessage : minLengthMessage;
            error[name] = Object.assign({ type: exceedMax ? maxType : minType, message,
                ref }, (exceedMax
                ? appendErrorsCurry(maxType, message)
                : appendErrorsCurry(minType, message)));
        };
        if (required &&
            ((!isRadio && !isCheckBox && (isEmpty || isNullOrUndefined(value))) ||
                (isBoolean(value) && !value) ||
                (isCheckBox && !getCheckboxValue(options).isValid) ||
                (isRadio && !getRadioValue(options).isValid))) {
            const { value: requiredValue, message: requiredMessage } = isMessage(required)
                ? { value: !!required, message: required }
                : getValueAndMessage(required);
            if (requiredValue) {
                error[name] = Object.assign({ type: INPUT_VALIDATION_RULES.required, message: requiredMessage, ref: isRadioOrCheckbox
                        ? ((fields[name].options || [])[0] || {}).ref
                        : ref }, appendErrorsCurry(INPUT_VALIDATION_RULES.required, requiredMessage));
                if (!validateAllFieldCriteria) {
                    return error;
                }
            }
        }
        if (!isNullOrUndefined(min) || !isNullOrUndefined(max)) {
            let exceedMax;
            let exceedMin;
            const { value: maxValue, message: maxMessage } = getValueAndMessage(max);
            const { value: minValue, message: minMessage } = getValueAndMessage(min);
            if (type === 'number' || (!type && !isNaN(value))) {
                const valueNumber = ref.valueAsNumber || parseFloat(value);
                if (!isNullOrUndefined(maxValue)) {
                    exceedMax = valueNumber > maxValue;
                }
                if (!isNullOrUndefined(minValue)) {
                    exceedMin = valueNumber < minValue;
                }
            }
            else {
                const valueDate = ref.valueAsDate || new Date(value);
                if (isString(maxValue)) {
                    exceedMax = valueDate > new Date(maxValue);
                }
                if (isString(minValue)) {
                    exceedMin = valueDate < new Date(minValue);
                }
            }
            if (exceedMax || exceedMin) {
                getMinMaxMessage(!!exceedMax, maxMessage, minMessage, INPUT_VALIDATION_RULES.max, INPUT_VALIDATION_RULES.min);
                if (!validateAllFieldCriteria) {
                    return error;
                }
            }
        }
        if (isString(value) && !isEmpty && (maxLength || minLength)) {
            const { value: maxLengthValue, message: maxLengthMessage, } = getValueAndMessage(maxLength);
            const { value: minLengthValue, message: minLengthMessage, } = getValueAndMessage(minLength);
            const inputLength = value.toString().length;
            const exceedMax = !isNullOrUndefined(maxLengthValue) && inputLength > maxLengthValue;
            const exceedMin = !isNullOrUndefined(minLengthValue) && inputLength < minLengthValue;
            if (exceedMax || exceedMin) {
                getMinMaxMessage(!!exceedMax, maxLengthMessage, minLengthMessage);
                if (!validateAllFieldCriteria) {
                    return error;
                }
            }
        }
        if (pattern && !isEmpty) {
            const { value: patternValue, message: patternMessage } = getValueAndMessage(pattern);
            if (isRegex(patternValue) && !patternValue.test(value)) {
                error[name] = Object.assign({ type: INPUT_VALIDATION_RULES.pattern, message: patternMessage, ref }, appendErrorsCurry(INPUT_VALIDATION_RULES.pattern, patternMessage));
                if (!validateAllFieldCriteria) {
                    return error;
                }
            }
        }
        if (validate) {
            const fieldValue = getFieldValue(fieldsRef, name, shallowFieldsStateRef);
            const validateRef = isRadioOrCheckbox && options ? options[0].ref : ref;
            if (isFunction(validate)) {
                const result = await validate(fieldValue);
                const validateError = getValidateError(result, validateRef);
                if (validateError) {
                    error[name] = Object.assign(Object.assign({}, validateError), appendErrorsCurry(INPUT_VALIDATION_RULES.validate, validateError.message));
                    if (!validateAllFieldCriteria) {
                        return error;
                    }
                }
            }
            else if (isObject(validate)) {
                let validationResult = {};
                for (const [key, validateFunction] of Object.entries(validate)) {
                    if (!isEmptyObject(validationResult) && !validateAllFieldCriteria) {
                        break;
                    }
                    const validateResult = await validateFunction(fieldValue);
                    const validateError = getValidateError(validateResult, validateRef, key);
                    if (validateError) {
                        validationResult = Object.assign(Object.assign({}, validateError), appendErrorsCurry(key, validateError.message));
                        if (validateAllFieldCriteria) {
                            error[name] = validationResult;
                        }
                    }
                }
                if (!isEmptyObject(validationResult)) {
                    error[name] = Object.assign({ ref: validateRef }, validationResult);
                    if (!validateAllFieldCriteria) {
                        return error;
                    }
                }
            }
        }
        return error;
    };
  
    const getPath = (path, values) => {
        const getInnerPath = (key, value, isObject) => {
            const pathWithIndex = isObject ? `${path}.${key}` : `${path}[${key}]`;
            return isPrimitive(value) ? pathWithIndex : getPath(pathWithIndex, value);
        };
        return Object.entries(values)
            .map(([key, value]) => getInnerPath(key, value, isObject(values)))
            .flat(Infinity);
    };
  
    var assignWatchFields = (fieldValues, fieldName, watchFields, inputValue, isSingleField) => {
        let value;
        watchFields.add(fieldName);
        if (isEmptyObject(fieldValues)) {
            value = undefined;
        }
        else {
            value = get(fieldValues, fieldName);
            if (isObject(value) || Array.isArray(value)) {
                getPath(fieldName, value).forEach((name) => watchFields.add(name));
            }
        }
        return isUndefined(value)
            ? isSingleField
                ? inputValue
                : get(inputValue, fieldName)
            : value;
    };
  
    var skipValidation = ({ isOnBlur, isOnChange, isOnTouch, isTouched, isReValidateOnBlur, isReValidateOnChange, isBlurEvent, isSubmitted, isOnAll, }) => {
        if (isOnAll) {
            return false;
        }
        else if (!isSubmitted && isOnTouch) {
            return !(isTouched || isBlurEvent);
        }
        else if (isSubmitted ? isReValidateOnBlur : isOnBlur) {
            return !isBlurEvent;
        }
        else if (isSubmitted ? isReValidateOnChange : isOnChange) {
            return isBlurEvent;
        }
        return true;
    };
  
    var getFieldArrayParentName = (name) => name.substring(0, name.indexOf('['));
  
    const isMatchFieldArrayName = (name, searchName) => RegExp(`^${searchName}[\\d+]`.replace(/\[/g, '\\[').replace(/\]/g, '\\]')).test(name);
    var isNameInFieldArray = (names, name) => [...names].some((current) => isMatchFieldArrayName(name, current));
  
    var isSelectInput = (element) => element.type === `${SELECT}-one`;
  
    function onDomRemove(fieldsRef, removeFieldEventListenerAndRef) {
        const observer = new MutationObserver(() => {
            for (const field of Object.values(fieldsRef.current)) {
                if (field && field.options) {
                    for (const option of field.options) {
                        if (option && option.ref && isDetached(option.ref)) {
                            removeFieldEventListenerAndRef(field);
                        }
                    }
                }
                else if (field && isDetached(field.ref)) {
                    removeFieldEventListenerAndRef(field);
                }
            }
        });
        observer.observe(window.document, {
            childList: true,
            subtree: true,
        });
        return observer;
    }
  
    function cloneObject(data, isWeb) {
        let copy;
        if (isPrimitive(data) || (isWeb && data instanceof File)) {
            return data;
        }
        if (data instanceof Date) {
            copy = new Date(data.getTime());
            return copy;
        }
        if (data instanceof Set) {
            copy = new Set();
            for (const item of data) {
                copy.add(item);
            }
            return copy;
        }
        if (data instanceof Map) {
            copy = new Map();
            for (const key of data.keys()) {
                copy.set(key, cloneObject(data.get(key), isWeb));
            }
            return copy;
        }
        copy = Array.isArray(data) ? [] : {};
        for (const key in data) {
            copy[key] = cloneObject(data[key], isWeb);
        }
        return copy;
    }
  
    var modeChecker = (mode) => ({
        isOnSubmit: !mode || mode === VALIDATION_MODE.onSubmit,
        isOnBlur: mode === VALIDATION_MODE.onBlur,
        isOnChange: mode === VALIDATION_MODE.onChange,
        isOnAll: mode === VALIDATION_MODE.all,
        isOnTouch: mode === VALIDATION_MODE.onTouched,
    });
  
    var isRadioOrCheckboxFunction = (ref) => isRadioInput(ref) || isCheckBoxInput(ref);
  
    const isWindowUndefined = typeof window === UNDEFINED;
    const isWeb = typeof document !== UNDEFINED &&
        !isWindowUndefined &&
        !isUndefined(window.HTMLElement);
    const isProxyEnabled = isWeb ? 'Proxy' in window : typeof Proxy !== UNDEFINED;
    function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_MODE.onChange, resolver, context, defaultValues = {}, shouldFocusError = true, shouldUnregister = true, criteriaMode, } = {}) {
        const fieldsRef = React.useRef({});
        const fieldArrayDefaultValuesRef = React.useRef({});
        const watchFieldsRef = React.useRef(new Set());
        const useWatchFieldsRef = React.useRef({});
        const useWatchRenderFunctionsRef = React.useRef({});
        const fieldsWithValidationRef = React.useRef({});
        const validFieldsRef = React.useRef({});
        const defaultValuesRef = React.useRef(defaultValues);
        const defaultValuesAtRenderRef = React.useRef({});
        const isUnMount = React.useRef(false);
        const isWatchAllRef = React.useRef(false);
        const handleChangeRef = React.useRef();
        const shallowFieldsStateRef = React.useRef(shouldUnregister ? {} : cloneObject(defaultValues, isWeb));
        const resetFieldArrayFunctionRef = React.useRef({});
        const contextRef = React.useRef(context);
        const resolverRef = React.useRef(resolver);
        const fieldArrayNamesRef = React.useRef(new Set());
        const modeRef = React.useRef(modeChecker(mode));
        const { isOnSubmit, isOnTouch } = modeRef.current;
        const isValidateAllFieldCriteria = criteriaMode === VALIDATION_MODE.all;
        const [formState, setFormState] = React.useState({
            isDirty: false,
            dirtyFields: {},
            isSubmitted: false,
            submitCount: 0,
            touched: {},
            isSubmitting: false,
            isSubmitSuccessful: false,
            isValid: !isOnSubmit,
            errors: {},
        });
        const readFormStateRef = React.useRef({
            isDirty: !isProxyEnabled,
            dirtyFields: !isProxyEnabled,
            touched: !isProxyEnabled || isOnTouch,
            isSubmitting: !isProxyEnabled,
            isValid: !isProxyEnabled,
        });
        const formStateRef = React.useRef(formState);
        const observerRef = React.useRef();
        const { isOnBlur: isReValidateOnBlur, isOnChange: isReValidateOnChange, } = React.useRef(modeChecker(reValidateMode)).current;
        contextRef.current = context;
        resolverRef.current = resolver;
        formStateRef.current = formState;
        const updateFormState = React.useCallback((state = {}) => !isUnMount.current &&
            setFormState(Object.assign(Object.assign({}, formStateRef.current), state)), []);
        const shouldRenderBaseOnError = React.useCallback((name, error, shouldRender = false, state = {}, isValid) => {
            let shouldReRender = shouldRender ||
                isErrorStateChanged({
                    errors: formStateRef.current.errors,
                    error,
                    name,
                    validFields: validFieldsRef.current,
                    fieldsWithValidation: fieldsWithValidationRef.current,
                });
            const previousError = get(formStateRef.current.errors, name);
            if (error) {
                unset(validFieldsRef.current, name);
                shouldReRender =
                    shouldReRender ||
                        !previousError ||
                        !deepEqual(previousError, error, true);
                set(formStateRef.current.errors, name, error);
            }
            else {
                if (get(fieldsWithValidationRef.current, name) || resolverRef.current) {
                    set(validFieldsRef.current, name, true);
                    shouldReRender = shouldReRender || previousError;
                }
                unset(formStateRef.current.errors, name);
            }
            if ((shouldReRender && !isNullOrUndefined(shouldRender)) ||
                !isEmptyObject(state)) {
                updateFormState(Object.assign(Object.assign(Object.assign({}, state), { errors: formStateRef.current.errors }), (resolverRef.current ? { isValid: !!isValid } : {})));
            }
        }, []);
        const setFieldValue = React.useCallback((name, rawValue) => {
            const { ref, options } = fieldsRef.current[name];
            const value = isWeb && isHTMLElement(ref) && isNullOrUndefined(rawValue)
                ? ''
                : rawValue;
            if (isRadioInput(ref) && options) {
                options.forEach(({ ref: radioRef }) => (radioRef.checked = radioRef.value === value));
            }
            else if (isFileInput(ref) && !isString(value)) {
                ref.files = value;
            }
            else if (isMultipleSelect(ref)) {
                [...ref.options].forEach((selectRef) => (selectRef.selected = value.includes(selectRef.value)));
            }
            else if (isCheckBoxInput(ref) && options) {
                options.length > 1
                    ? options.forEach(({ ref: checkboxRef }) => (checkboxRef.checked = Array.isArray(value)
                        ? !!value.find((data) => data === checkboxRef.value)
                        : value === checkboxRef.value))
                    : (options[0].ref.checked = !!value);
            }
            else {
                ref.value = value;
            }
        }, []);
        const isFormDirty = () => !deepEqual(getValues(), isEmptyObject(defaultValuesRef.current)
            ? defaultValuesAtRenderRef.current
            : defaultValuesRef.current) || !isEmptyObject(formStateRef.current.dirtyFields);
        const updateAndGetDirtyState = React.useCallback((name, shouldRender = true) => {
            if (readFormStateRef.current.isDirty ||
                readFormStateRef.current.dirtyFields) {
                const isFieldDirty = !deepEqual(get(defaultValuesAtRenderRef.current, name), getFieldValue(fieldsRef, name, shallowFieldsStateRef));
                const isDirtyFieldExist = get(formStateRef.current.dirtyFields, name);
                const previousIsDirty = formStateRef.current.isDirty;
                isFieldDirty
                    ? set(formStateRef.current.dirtyFields, name, true)
                    : unset(formStateRef.current.dirtyFields, name);
                const state = {
                    isDirty: isFormDirty(),
                    dirtyFields: formStateRef.current.dirtyFields,
                };
                const isChanged = (readFormStateRef.current.isDirty &&
                    previousIsDirty !== state.isDirty) ||
                    (readFormStateRef.current.dirtyFields &&
                        isDirtyFieldExist !== get(formStateRef.current.dirtyFields, name));
                if (isChanged && shouldRender) {
                    formStateRef.current = Object.assign(Object.assign({}, formStateRef.current), state);
                    updateFormState(Object.assign({}, state));
                }
                return isChanged ? state : {};
            }
            return {};
        }, []);
        const executeValidation = React.useCallback(async (name, skipReRender) => {
            if (fieldsRef.current[name]) {
                const error = (await validateField(fieldsRef, isValidateAllFieldCriteria, fieldsRef.current[name], shallowFieldsStateRef))[name];
                shouldRenderBaseOnError(name, error, skipReRender);
                return isUndefined(error);
            }
            return false;
        }, [shouldRenderBaseOnError, isValidateAllFieldCriteria]);
        const executeSchemaOrResolverValidation = React.useCallback(async (names) => {
            const { errors } = await resolverRef.current(getValues(), contextRef.current, isValidateAllFieldCriteria);
            const previousFormIsValid = formStateRef.current.isValid;
            if (Array.isArray(names)) {
                const isInputsValid = names
                    .map((name) => {
                    const error = get(errors, name);
                    error
                        ? set(formStateRef.current.errors, name, error)
                        : unset(formStateRef.current.errors, name);
                    return !error;
                })
                    .every(Boolean);
                updateFormState({
                    isValid: isEmptyObject(errors),
                    errors: formStateRef.current.errors,
                });
                return isInputsValid;
            }
            else {
                const error = get(errors, names);
                shouldRenderBaseOnError(names, error, previousFormIsValid !== isEmptyObject(errors), {}, isEmptyObject(errors));
                return !error;
            }
        }, [shouldRenderBaseOnError, isValidateAllFieldCriteria]);
        const trigger = React.useCallback(async (name) => {
            const fields = name || Object.keys(fieldsRef.current);
            if (resolverRef.current) {
                return executeSchemaOrResolverValidation(fields);
            }
            if (Array.isArray(fields)) {
                !name && (formStateRef.current.errors = {});
                const result = await Promise.all(fields.map(async (data) => await executeValidation(data, null)));
                updateFormState();
                return result.every(Boolean);
            }
            return await executeValidation(fields, readFormStateRef.current.isValid);
        }, [executeSchemaOrResolverValidation, executeValidation]);
        const setInternalValues = React.useCallback((name, value, { shouldDirty, shouldValidate }) => {
            const data = {};
            set(data, name, value);
            for (const fieldName of getPath(name, value)) {
                if (fieldsRef.current[fieldName]) {
                    setFieldValue(fieldName, get(data, fieldName));
                    shouldDirty && updateAndGetDirtyState(fieldName);
                    shouldValidate && trigger(fieldName);
                }
            }
        }, [trigger, setFieldValue, updateAndGetDirtyState]);
        const setInternalValue = React.useCallback((name, value, config = {}) => {
            if (fieldsRef.current[name]) {
                setFieldValue(name, value);
                config.shouldDirty && updateAndGetDirtyState(name);
            }
            else if (!isPrimitive(value)) {
                setInternalValues(name, value, config);
                if (fieldArrayNamesRef.current.has(name)) {
                    fieldArrayDefaultValuesRef.current[name] = value;
                    resetFieldArrayFunctionRef.current[name]({
                        [name]: value,
                    });
                    if ((readFormStateRef.current.isDirty ||
                        readFormStateRef.current.dirtyFields) &&
                        config.shouldDirty) {
                        set(formStateRef.current.dirtyFields, name, setFieldArrayDirtyFields(value, get(defaultValuesRef.current, name, []), get(formStateRef.current.dirtyFields, name, [])));
                        updateFormState({
                            isDirty: !deepEqual(Object.assign(Object.assign({}, getValues()), { [name]: value }), defaultValuesRef.current),
                            dirtyFields: formStateRef.current.dirtyFields,
                        });
                    }
                }
            }
            !shouldUnregister && set(shallowFieldsStateRef.current, name, value);
        }, [updateAndGetDirtyState, setFieldValue, setInternalValues]);
        const isFieldWatched = (name) => isWatchAllRef.current ||
            watchFieldsRef.current.has(name) ||
            watchFieldsRef.current.has((name.match(/\w+/) || [])[0]);
        const renderWatchedInputs = (name, found = true) => {
            if (!isEmptyObject(useWatchFieldsRef.current)) {
                for (const key in useWatchFieldsRef.current) {
                    if (!name ||
                        !useWatchFieldsRef.current[key].size ||
                        useWatchFieldsRef.current[key].has(name) ||
                        useWatchFieldsRef.current[key].has(getFieldArrayParentName(name))) {
                        useWatchRenderFunctionsRef.current[key]();
                        found = false;
                    }
                }
            }
            return found;
        };
        function setValue(name, value, config) {
            setInternalValue(name, value, config);
            isFieldWatched(name) && updateFormState();
            renderWatchedInputs(name);
            (config || {}).shouldValidate && trigger(name);
        }
        handleChangeRef.current = handleChangeRef.current
            ? handleChangeRef.current
            : async ({ type, target }) => {
                let name = target.name;
                const field = fieldsRef.current[name];
                let error;
                let isValid;
                if (field) {
                    const isBlurEvent = type === EVENTS.BLUR;
                    const shouldSkipValidation = skipValidation(Object.assign({ isBlurEvent,
                        isReValidateOnChange,
                        isReValidateOnBlur, isTouched: !!get(formStateRef.current.touched, name), isSubmitted: formStateRef.current.isSubmitted }, modeRef.current));
                    let state = updateAndGetDirtyState(name, false);
                    let shouldRender = !isEmptyObject(state) || isFieldWatched(name);
                    if (isBlurEvent &&
                        !get(formStateRef.current.touched, name) &&
                        readFormStateRef.current.touched) {
                        set(formStateRef.current.touched, name, true);
                        state = Object.assign(Object.assign({}, state), { touched: formStateRef.current.touched });
                    }
                    if (shouldSkipValidation) {
                        renderWatchedInputs(name);
                        return ((!isEmptyObject(state) ||
                            (shouldRender && isEmptyObject(state))) &&
                            updateFormState(state));
                    }
                    if (resolverRef.current) {
                        const { errors } = await resolverRef.current(getValues(), contextRef.current, isValidateAllFieldCriteria);
                        const previousFormIsValid = formStateRef.current.isValid;
                        error = get(errors, name);
                        if (!error && resolverRef.current) {
                            const parentNodeName = name.substring(0, name.lastIndexOf('.') > name.lastIndexOf('[')
                                ? name.lastIndexOf('.')
                                : name.lastIndexOf('['));
                            const currentError = get(errors, parentNodeName, {});
                            currentError.type &&
                                currentError.message &&
                                (error = currentError);
                            if (parentNodeName &&
                                (currentError ||
                                    get(formStateRef.current.errors, parentNodeName))) {
                                name = parentNodeName;
                            }
                        }
                        isValid = isEmptyObject(errors);
                        if (previousFormIsValid !== isValid) {
                            shouldRender = true;
                        }
                    }
                    else {
                        error = (await validateField(fieldsRef, isValidateAllFieldCriteria, field, shallowFieldsStateRef))[name];
                    }
                    renderWatchedInputs(name);
                    shouldRenderBaseOnError(name, error, shouldRender, state, isValid);
                }
            };
        function setFieldArrayDefaultValues(data) {
            if (!shouldUnregister) {
                let copy = cloneObject(data, isWeb);
                for (const value of fieldArrayNamesRef.current) {
                    if (isKey(value) && !copy[value]) {
                        copy = Object.assign(Object.assign({}, copy), { [value]: [] });
                    }
                }
                return copy;
            }
            return data;
        }
        function getValues(payload) {
            if (isString(payload)) {
                return getFieldValue(fieldsRef, payload, shallowFieldsStateRef);
            }
            if (Array.isArray(payload)) {
                const data = {};
                for (const name of payload) {
                    set(data, name, getFieldValue(fieldsRef, name, shallowFieldsStateRef));
                }
                return data;
            }
            return setFieldArrayDefaultValues(getFieldsValues(fieldsRef, shallowFieldsStateRef));
        }
        const validateResolver = React.useCallback(async (values = {}) => {
            const { errors } = await resolverRef.current(Object.assign(Object.assign(Object.assign({}, defaultValuesRef.current), getValues()), values), contextRef.current, isValidateAllFieldCriteria);
            const isValid = isEmptyObject(errors);
            formStateRef.current.isValid !== isValid &&
                updateFormState({
                    isValid,
                });
        }, [isValidateAllFieldCriteria]);
        const removeFieldEventListener = React.useCallback((field, forceDelete) => findRemovedFieldAndRemoveListener(fieldsRef, handleChangeRef.current, field, shallowFieldsStateRef, shouldUnregister, forceDelete), [shouldUnregister]);
        const updateWatchedValue = (name) => {
            if (isWatchAllRef.current) {
                updateFormState();
            }
            else if (watchFieldsRef) {
                let shouldRenderUseWatch = true;
                for (const watchField of watchFieldsRef.current) {
                    if (watchField.startsWith(name)) {
                        updateFormState();
                        shouldRenderUseWatch = false;
                        break;
                    }
                }
                shouldRenderUseWatch && renderWatchedInputs(name);
            }
        };
        const removeFieldEventListenerAndRef = React.useCallback((field, forceDelete) => {
            if (field) {
                removeFieldEventListener(field, forceDelete);
                if (shouldUnregister && !compact(field.options || []).length) {
                    unset(defaultValuesAtRenderRef.current, field.ref.name);
                    unset(validFieldsRef.current, field.ref.name);
                    unset(fieldsWithValidationRef.current, field.ref.name);
                    unset(formStateRef.current.errors, field.ref.name);
                    set(formStateRef.current.dirtyFields, field.ref.name, true);
                    updateFormState({
                        errors: formStateRef.current.errors,
                        isDirty: isFormDirty(),
                        dirtyFields: formStateRef.current.dirtyFields,
                    });
                    readFormStateRef.current.isValid &&
                        resolverRef.current &&
                        validateResolver();
                    updateWatchedValue(field.ref.name);
                }
            }
        }, [validateResolver, removeFieldEventListener]);
        function clearErrors(name) {
            name &&
                (Array.isArray(name) ? name : [name]).forEach((inputName) => fieldsRef.current[inputName]
                    ? isKey(inputName)
                        ? delete formStateRef.current.errors[inputName]
                        : set(formStateRef.current.errors, inputName, undefined)
                    : unset(formStateRef.current.errors, inputName));
            updateFormState({
                errors: name ? formStateRef.current.errors : {},
            });
        }
        function setError(name, error) {
            const ref = (fieldsRef.current[name] || {}).ref;
            set(formStateRef.current.errors, name, Object.assign(Object.assign({}, error), { ref }));
            updateFormState({
                isValid: false,
                errors: formStateRef.current.errors,
            });
            error.shouldFocus && ref && ref.focus && ref.focus();
        }
        const watchInternal = React.useCallback((fieldNames, defaultValue, watchId) => {
            const watchFields = watchId
                ? useWatchFieldsRef.current[watchId]
                : watchFieldsRef.current;
            const combinedDefaultValues = isUndefined(defaultValue)
                ? defaultValuesRef.current
                : defaultValue;
            const fieldValues = getFieldsValues(fieldsRef, shallowFieldsStateRef, false, fieldNames);
            if (isString(fieldNames)) {
                return assignWatchFields(fieldValues, fieldNames, watchFields, isUndefined(defaultValue)
                    ? get(combinedDefaultValues, fieldNames)
                    : defaultValue, true);
            }
            if (Array.isArray(fieldNames)) {
                return fieldNames.reduce((previous, name) => (Object.assign(Object.assign({}, previous), { [name]: assignWatchFields(fieldValues, name, watchFields, combinedDefaultValues) })), {});
            }
            isWatchAllRef.current = isUndefined(watchId);
            return transformToNestObject((!isEmptyObject(fieldValues) && fieldValues) ||
                combinedDefaultValues);
        }, []);
        function watch(fieldNames, defaultValue) {
            return watchInternal(fieldNames, defaultValue);
        }
        function unregister(name) {
            for (const fieldName of Array.isArray(name) ? name : [name]) {
                removeFieldEventListenerAndRef(fieldsRef.current[fieldName], true);
            }
        }
        function registerFieldRef(ref, validateOptions = {}) {
            {
                if (!ref.name) {
                    return console.warn('📋 Field is missing `name` attribute', ref, `https://react-hook-form.com/api#useForm`);
                }
                if (fieldArrayNamesRef.current.has(ref.name.split(/\[\d+\]$/)[0]) &&
                    !RegExp(`^${ref.name.split(/\[\d+\]$/)[0]}[\\d+].\\w+`
                        .replace(/\[/g, '\\[')
                        .replace(/\]/g, '\\]')).test(ref.name)) {
                    return console.warn('📋 `name` prop should be in object shape: name="test[index].name"', ref, 'https://react-hook-form.com/api#useFieldArray');
                }
            }
            const { name, type, value } = ref;
            const fieldRefAndValidationOptions = Object.assign({ ref }, validateOptions);
            const fields = fieldsRef.current;
            const isRadioOrCheckbox = isRadioOrCheckboxFunction(ref);
            const isFieldArray = isNameInFieldArray(fieldArrayNamesRef.current, name);
            const compareRef = (currentRef) => isWeb && (!isHTMLElement(ref) || currentRef === ref);
            let field = fields[name];
            let isEmptyDefaultValue = true;
            let defaultValue;
            if (field &&
                (isRadioOrCheckbox
                    ? Array.isArray(field.options) &&
                        compact(field.options).find((option) => {
                            return value === option.ref.value && compareRef(option.ref);
                        })
                    : compareRef(field.ref))) {
                fields[name] = Object.assign(Object.assign({}, field), validateOptions);
                return;
            }
            if (type) {
                field = isRadioOrCheckbox
                    ? Object.assign({ options: [
                            ...compact((field && field.options) || []),
                            {
                                ref,
                            },
                        ], ref: { type, name } }, validateOptions) : Object.assign({}, fieldRefAndValidationOptions);
            }
            else {
                field = fieldRefAndValidationOptions;
            }
            fields[name] = field;
            const isEmptyUnmountFields = isUndefined(get(shallowFieldsStateRef.current, name));
            if (!isEmptyObject(defaultValuesRef.current) || !isEmptyUnmountFields) {
                defaultValue = get(isEmptyUnmountFields
                    ? defaultValuesRef.current
                    : shallowFieldsStateRef.current, name);
                isEmptyDefaultValue = isUndefined(defaultValue);
                if (!isEmptyDefaultValue && !isFieldArray) {
                    setFieldValue(name, defaultValue);
                }
            }
            if (!isEmptyObject(validateOptions)) {
                set(fieldsWithValidationRef.current, name, true);
                if (!isOnSubmit && readFormStateRef.current.isValid) {
                    validateField(fieldsRef, isValidateAllFieldCriteria, field, shallowFieldsStateRef).then((error) => {
                        const previousFormIsValid = formStateRef.current.isValid;
                        isEmptyObject(error)
                            ? set(validFieldsRef.current, name, true)
                            : unset(validFieldsRef.current, name);
                        if (previousFormIsValid !== isEmptyObject(error)) {
                            updateFormState();
                        }
                    });
                }
            }
            if (!defaultValuesAtRenderRef.current[name] &&
                !(isFieldArray && isEmptyDefaultValue)) {
                const fieldValue = getFieldValue(fieldsRef, name, shallowFieldsStateRef);
                set(defaultValuesAtRenderRef.current, name, isEmptyDefaultValue
                    ? isObject(fieldValue)
                        ? Object.assign({}, fieldValue) : fieldValue
                    : defaultValue);
                !isFieldArray && unset(formStateRef.current.dirtyFields, name);
            }
            if (type) {
                attachEventListeners(isRadioOrCheckbox && field.options
                    ? field.options[field.options.length - 1]
                    : field, isRadioOrCheckbox || isSelectInput(ref), handleChangeRef.current);
            }
        }
        function register(refOrValidationOptions, rules) {
            if (!isWindowUndefined) {
                if (isString(refOrValidationOptions)) {
                    registerFieldRef({ name: refOrValidationOptions }, rules);
                }
                else if (isObject(refOrValidationOptions) &&
                    'name' in refOrValidationOptions) {
                    registerFieldRef(refOrValidationOptions, rules);
                }
                else {
                    return (ref) => ref && registerFieldRef(ref, refOrValidationOptions);
                }
            }
        }
        const handleSubmit = React.useCallback((onValid, onInvalid) => async (e) => {
            if (e && e.preventDefault) {
                e.preventDefault();
                e.persist();
            }
            let fieldErrors = {};
            let fieldValues = setFieldArrayDefaultValues(getFieldsValues(fieldsRef, shallowFieldsStateRef, true));
            readFormStateRef.current.isSubmitting &&
                updateFormState({
                    isSubmitting: true,
                });
            try {
                if (resolverRef.current) {
                    const { errors, values } = await resolverRef.current(fieldValues, contextRef.current, isValidateAllFieldCriteria);
                    formStateRef.current.errors = fieldErrors = errors;
                    fieldValues = values;
                }
                else {
                    for (const field of Object.values(fieldsRef.current)) {
                        if (field) {
                            const { ref: { name }, } = field;
                            const fieldError = await validateField(fieldsRef, isValidateAllFieldCriteria, field, shallowFieldsStateRef);
                            if (fieldError[name]) {
                                set(fieldErrors, name, fieldError[name]);
                                unset(validFieldsRef.current, name);
                            }
                            else if (get(fieldsWithValidationRef.current, name)) {
                                unset(formStateRef.current.errors, name);
                                set(validFieldsRef.current, name, true);
                            }
                        }
                    }
                }
                if (isEmptyObject(fieldErrors) &&
                    Object.keys(formStateRef.current.errors).every((name) => name in fieldsRef.current)) {
                    updateFormState({
                        errors: {},
                        isSubmitting: true,
                    });
                    await onValid(fieldValues, e);
                }
                else {
                    formStateRef.current.errors = Object.assign(Object.assign({}, formStateRef.current.errors), fieldErrors);
                    onInvalid && (await onInvalid(formStateRef.current.errors, e));
                    shouldFocusError &&
                        focusOnErrorField(fieldsRef.current, formStateRef.current.errors);
                }
            }
            finally {
                updateFormState({
                    isSubmitted: true,
                    isSubmitting: false,
                    isSubmitSuccessful: isEmptyObject(formStateRef.current.errors),
                    errors: formStateRef.current.errors,
                    submitCount: formStateRef.current.submitCount + 1,
                });
            }
        }, [shouldFocusError, isValidateAllFieldCriteria]);
        const resetRefs = ({ errors, isDirty, isSubmitted, touched, isValid, submitCount, dirtyFields, }) => {
            if (!isValid) {
                validFieldsRef.current = {};
                fieldsWithValidationRef.current = {};
            }
            defaultValuesAtRenderRef.current = {};
            fieldArrayDefaultValuesRef.current = {};
            watchFieldsRef.current = new Set();
            isWatchAllRef.current = false;
            updateFormState({
                submitCount: submitCount ? formStateRef.current.submitCount : 0,
                isDirty: isDirty ? formStateRef.current.isDirty : false,
                isSubmitted: isSubmitted ? formStateRef.current.isSubmitted : false,
                isValid: isValid ? formStateRef.current.isValid : false,
                dirtyFields: dirtyFields ? formStateRef.current.dirtyFields : {},
                touched: touched ? formStateRef.current.touched : {},
                errors: errors ? formStateRef.current.errors : {},
                isSubmitting: false,
                isSubmitSuccessful: false,
            });
        };
        const reset = (values, omitResetState = {}) => {
            if (isWeb) {
                for (const field of Object.values(fieldsRef.current)) {
                    if (field) {
                        const { ref, options } = field;
                        const inputRef = isRadioOrCheckboxFunction(ref) && Array.isArray(options)
                            ? options[0].ref
                            : ref;
                        if (isHTMLElement(inputRef)) {
                            try {
                                inputRef.closest('form').reset();
                                break;
                            }
                            catch (_a) { }
                        }
                    }
                }
            }
            fieldsRef.current = {};
            defaultValuesRef.current = cloneObject(values || defaultValuesRef.current, isWeb);
            values && renderWatchedInputs('');
            Object.values(resetFieldArrayFunctionRef.current).forEach((resetFieldArray) => isFunction(resetFieldArray) && resetFieldArray());
            shallowFieldsStateRef.current = shouldUnregister
                ? {}
                : cloneObject(values, isWeb) || {};
            resetRefs(omitResetState);
        };
        React.useEffect(() => {
            isUnMount.current = false;
            resolver && readFormStateRef.current.isValid && validateResolver();
            observerRef.current =
                observerRef.current || !isWeb
                    ? observerRef.current
                    : onDomRemove(fieldsRef, removeFieldEventListenerAndRef);
            return () => {
                isUnMount.current = true;
                observerRef.current && observerRef.current.disconnect();
                shallowFieldsStateRef.current = {};
                {
                    return;
                }
            };
        }, [removeFieldEventListenerAndRef]);
        if (!resolver && readFormStateRef.current.isValid) {
            formState.isValid =
                deepEqual(validFieldsRef.current, fieldsWithValidationRef.current) &&
                    isEmptyObject(formStateRef.current.errors);
        }
        const commonProps = {
            trigger,
            setValue: React.useCallback(setValue, [setInternalValue, trigger]),
            getValues: React.useCallback(getValues, []),
            register: React.useCallback(register, [defaultValuesRef.current]),
            unregister: React.useCallback(unregister, []),
        };
        const control = Object.assign({ updateWatchedValue,
            shouldUnregister,
            removeFieldEventListener,
            watchInternal, mode: modeRef.current, reValidateMode: {
                isReValidateOnBlur,
                isReValidateOnChange,
            }, fieldsRef,
            resetFieldArrayFunctionRef,
            useWatchFieldsRef,
            useWatchRenderFunctionsRef,
            fieldArrayDefaultValuesRef,
            validFieldsRef,
            fieldsWithValidationRef,
            fieldArrayNamesRef,
            readFormStateRef,
            formStateRef,
            defaultValuesRef,
            shallowFieldsStateRef,
            updateFormState, validateResolver: resolver ? validateResolver : undefined }, commonProps);
        return Object.assign({ watch,
            control, formState: isProxyEnabled
                ? new Proxy(formState, {
                    get: (obj, prop) => {
                        {
                            if (prop === 'isValid' && isOnSubmit) {
                                console.warn('📋 `formState.isValid` is applicable with `onTouched`, `onChange` or `onBlur` mode. https://react-hook-form.com/api#formState');
                            }
                        }
                        if (prop in obj) {
                            readFormStateRef.current[prop] = true;
                            return obj[prop];
                        }
                        return undefined;
                    },
                })
                : formState, handleSubmit, reset: React.useCallback(reset, []), clearErrors: React.useCallback(clearErrors, []), setError: React.useCallback(setError, []), errors: formState.errors }, commonProps);
    }
  
    /*! *****************************************************************************
    Copyright (c) Microsoft Corporation.
  
    Permission to use, copy, modify, and/or distribute this software for any
    purpose with or without fee is hereby granted.
  
    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
    REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
    AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
    INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
    LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
    OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
    PERFORMANCE OF THIS SOFTWARE.
    ***************************************************************************** */
  
    function __rest(s, e) {
        var t = {};
        for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
            t[p] = s[p];
        if (s != null && typeof Object.getOwnPropertySymbols === "function")
            for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
                if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                    t[p[i]] = s[p[i]];
            }
        return t;
    }
  
    const FormContext = React.createContext(null);
    FormContext.displayName = 'RHFContext';
    const useFormContext = () => React.useContext(FormContext);
    const FormProvider = (_a) => {
        var { children } = _a, props = __rest(_a, ["children"]);
        return (React.createElement(FormContext.Provider, { value: Object.assign({}, props) }, children));
    };
  
    var generateId = () => {
        const d = typeof performance === UNDEFINED ? Date.now() : performance.now() * 1000;
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            const r = (Math.random() * 16 + d) % 16 | 0;
            return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16);
        });
    };
  
    const removeAt = (data, index) => [
        ...data.slice(0, index),
        ...data.slice(index + 1),
    ];
    function removeAtIndexes(data, index) {
        let k = -1;
        while (++k < data.length) {
            if (index.indexOf(k) >= 0) {
                delete data[k];
            }
        }
        return compact(data);
    }
    var removeArrayAt = (data, index) => isUndefined(index)
        ? []
        : Array.isArray(index)
            ? removeAtIndexes(data, index)
            : removeAt(data, index);
  
    var moveArrayAt = (data, from, to) => {
        if (Array.isArray(data)) {
            if (isUndefined(data[to])) {
                data[to] = undefined;
            }
            data.splice(to, 0, data.splice(from, 1)[0]);
            return data;
        }
        return [];
    };
  
    var swapArrayAt = (data, indexA, indexB) => {
        const temp = [data[indexB], data[indexA]];
        data[indexA] = temp[0];
        data[indexB] = temp[1];
    };
  
    function prepend(data, value) {
        return [...(Array.isArray(value) ? value : [value || undefined]), ...data];
    }
  
    function insert(data, index, value) {
        return [
            ...data.slice(0, index),
            ...(Array.isArray(value) ? value : [value || undefined]),
            ...data.slice(index),
        ];
    }
  
    var fillEmptyArray = (value) => Array.isArray(value) ? Array(value.length).fill(undefined) : undefined;
  
    function mapValueToBoolean(value) {
        if (isObject(value)) {
            const object = {};
            for (const key in value) {
                object[key] = true;
            }
            return [object];
        }
        return [true];
    }
    var fillBooleanArray = (value) => (Array.isArray(value) ? value : [value])
        .map(mapValueToBoolean)
        .flat();
  
    const mapIds = (values = [], keyName) => {
        {
            for (const value of values) {
                if (keyName in value) {
                    console.warn(`📋 useFieldArray fieldValues contain the keyName \`${keyName}\` which is reserved for use by useFieldArray. https://react-hook-form.com/api#useFieldArray`);
                    break;
                }
            }
        }
        return values.map((value) => (Object.assign({ [keyName]: generateId() }, value)));
    };
    const useFieldArray = ({ control, name, keyName = 'id', }) => {
        const methods = useFormContext();
        {
            if (!control && !methods) {
                throw new Error('📋 useFieldArray is missing `control` prop. https://react-hook-form.com/api#useFieldArray');
            }
        }
        const focusIndexRef = React.useRef(-1);
        const { updateWatchedValue, resetFieldArrayFunctionRef, fieldArrayNamesRef, fieldsRef, defaultValuesRef, removeFieldEventListener, formStateRef, shallowFieldsStateRef, updateFormState, readFormStateRef, validFieldsRef, fieldsWithValidationRef, fieldArrayDefaultValuesRef, validateResolver, getValues, shouldUnregister, } = control || methods.control;
        const fieldArrayParentName = getFieldArrayParentName(name);
        const memoizedDefaultValues = React.useRef([
            ...(get(fieldArrayDefaultValuesRef.current, fieldArrayParentName)
                ? get(fieldArrayDefaultValuesRef.current, name, [])
                : get(shouldUnregister
                    ? defaultValuesRef.current
                    : shallowFieldsStateRef.current, name, [])),
        ]);
        const [fields, setFields] = React.useState(mapIds(memoizedDefaultValues.current, keyName));
        const allFields = React.useRef(fields);
        const getCurrentFieldsValues = () => get(getValues(), name, allFields.current).map((item, index) => (Object.assign(Object.assign({}, allFields.current[index]), item)));
        allFields.current = fields;
        fieldArrayNamesRef.current.add(name);
        if (!get(fieldArrayDefaultValuesRef.current, fieldArrayParentName)) {
            set(fieldArrayDefaultValuesRef.current, fieldArrayParentName, get(defaultValuesRef.current, fieldArrayParentName));
        }
        const setFieldAndValidState = (fieldsValues) => {
            setFields(fieldsValues);
            if (readFormStateRef.current.isValid && validateResolver) {
                const values = getValues();
                set(values, name, fieldsValues);
                validateResolver(values);
            }
        };
        const getIsDirtyState = (flagOrFields) => (readFormStateRef.current.isDirty ||
            readFormStateRef.current.dirtyFields) &&
            (isUndefined(flagOrFields) ||
                !deepEqual(flagOrFields.map((_a = {}) => {
                    var _b = keyName, omitted = _a[_b], rest = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]);
                    return rest;
                }), get(defaultValuesRef.current, name, [])));
        const resetFields = () => {
            for (const key in fieldsRef.current) {
                isMatchFieldArrayName(key, name) &&
                    removeFieldEventListener(fieldsRef.current[key], true);
            }
        };
        const cleanup = (ref) => !compact(get(ref, name, [])).length && unset(ref, name);
        const updateDirtyFieldsWithDefaultValues = (updatedFieldArrayValues) => {
            const defaultFieldArrayValues = get(defaultValuesRef.current, name, []);
            const updateDirtyFieldsBaseOnDefaultValues = (base, target) => {
                for (const key in base) {
                    for (const innerKey in base[key]) {
                        if (innerKey !== keyName &&
                            (!target[key] ||
                                !base[key] ||
                                base[key][innerKey] !== target[key][innerKey])) {
                            set(formStateRef.current.dirtyFields, `${name}[${key}]`, Object.assign(Object.assign({}, get(formStateRef.current.dirtyFields, `${name}[${key}]`, {})), { [innerKey]: true }));
                        }
                    }
                }
            };
            if (updatedFieldArrayValues) {
                updateDirtyFieldsBaseOnDefaultValues(defaultFieldArrayValues, updatedFieldArrayValues);
                updateDirtyFieldsBaseOnDefaultValues(updatedFieldArrayValues, defaultFieldArrayValues);
            }
        };
        const batchStateUpdate = (method, args, updatedFieldValues, isDirty = true, shouldSet = true, shouldUpdateValid = false) => {
            if (get(shallowFieldsStateRef.current, name)) {
                const output = method(get(shallowFieldsStateRef.current, name), args.argA, args.argB);
                shouldSet && set(shallowFieldsStateRef.current, name, output);
            }
            if (get(fieldArrayDefaultValuesRef.current, name)) {
                const output = method(get(fieldArrayDefaultValuesRef.current, name), args.argA, args.argB);
                shouldSet && set(fieldArrayDefaultValuesRef.current, name, output);
                cleanup(fieldArrayDefaultValuesRef.current);
            }
            if (Array.isArray(get(formStateRef.current.errors, name))) {
                const output = method(get(formStateRef.current.errors, name), args.argA, args.argB);
                shouldSet && set(formStateRef.current.errors, name, output);
                cleanup(formStateRef.current.errors);
            }
            if (readFormStateRef.current.touched &&
                get(formStateRef.current.touched, name)) {
                const output = method(get(formStateRef.current.touched, name), args.argA, args.argB);
                shouldSet && set(formStateRef.current.touched, name, output);
                cleanup(formStateRef.current.touched);
            }
            if (readFormStateRef.current.dirtyFields ||
                readFormStateRef.current.isDirty) {
                const output = method(get(formStateRef.current.dirtyFields, name, []), args.argC, args.argD);
                shouldSet && set(formStateRef.current.dirtyFields, name, output);
                updateDirtyFieldsWithDefaultValues(updatedFieldValues);
                cleanup(formStateRef.current.dirtyFields);
            }
            if (shouldUpdateValid &&
                readFormStateRef.current.isValid &&
                !validateResolver) {
                set(validFieldsRef.current, name, method(get(validFieldsRef.current, name, []), args.argA));
                cleanup(validFieldsRef.current);
                set(fieldsWithValidationRef.current, name, method(get(fieldsWithValidationRef.current, name, []), args.argA));
                cleanup(fieldsWithValidationRef.current);
            }
            updateFormState({
                errors: formStateRef.current.errors,
                dirtyFields: formStateRef.current.dirtyFields,
                isDirty,
                touched: formStateRef.current.touched,
            });
        };
        const append = (value, shouldFocus = true) => {
            const updateFormValues = [
                ...allFields.current,
                ...mapIds(Array.isArray(value) ? value : [value], keyName),
            ];
            setFieldAndValidState(updateFormValues);
            if (readFormStateRef.current.dirtyFields ||
                readFormStateRef.current.isDirty) {
                updateDirtyFieldsWithDefaultValues(updateFormValues);
                updateFormState({
                    isDirty: true,
                    dirtyFields: formStateRef.current.dirtyFields,
                });
            }
            !shouldUnregister &&
                set(shallowFieldsStateRef.current, name, [
                    ...(shallowFieldsStateRef.current[name] || []),
                    value,
                ]);
            focusIndexRef.current = shouldFocus ? allFields.current.length : -1;
        };
        const prepend$1 = (value, shouldFocus = true) => {
            const emptyArray = fillEmptyArray(value);
            const updatedFieldArrayValues = prepend(getCurrentFieldsValues(), mapIds(Array.isArray(value) ? value : [value], keyName));
            setFieldAndValidState(updatedFieldArrayValues);
            resetFields();
            batchStateUpdate(prepend, {
                argA: emptyArray,
                argC: fillBooleanArray(value),
            }, updatedFieldArrayValues);
            focusIndexRef.current = shouldFocus ? 0 : -1;
        };
        const remove = (index) => {
            const fieldValues = getCurrentFieldsValues();
            const updatedFieldValues = removeArrayAt(fieldValues, index);
            setFieldAndValidState(updatedFieldValues);
            resetFields();
            batchStateUpdate(removeArrayAt, {
                argA: index,
                argC: index,
            }, updatedFieldValues, getIsDirtyState(removeArrayAt(fieldValues, index)), true, true);
        };
        const insert$1 = (index, value, shouldFocus = true) => {
            const emptyArray = fillEmptyArray(value);
            const fieldValues = getCurrentFieldsValues();
            const updatedFieldArrayValues = insert(fieldValues, index, mapIds(Array.isArray(value) ? value : [value], keyName));
            setFieldAndValidState(updatedFieldArrayValues);
            resetFields();
            batchStateUpdate(insert, {
                argA: index,
                argB: emptyArray,
                argC: index,
                argD: fillBooleanArray(value),
            }, updatedFieldArrayValues, getIsDirtyState(insert(fieldValues, index)));
            focusIndexRef.current = shouldFocus ? index : -1;
        };
        const swap = (indexA, indexB) => {
            const fieldValues = getCurrentFieldsValues();
            swapArrayAt(fieldValues, indexA, indexB);
            resetFields();
            setFieldAndValidState([...fieldValues]);
            batchStateUpdate(swapArrayAt, {
                argA: indexA,
                argB: indexB,
                argC: indexA,
                argD: indexB,
            }, undefined, getIsDirtyState(fieldValues), false);
        };
        const move = (from, to) => {
            const fieldValues = getCurrentFieldsValues();
            moveArrayAt(fieldValues, from, to);
            resetFields();
            setFieldAndValidState([...fieldValues]);
            batchStateUpdate(moveArrayAt, {
                argA: from,
                argB: to,
                argC: from,
                argD: to,
            }, undefined, getIsDirtyState(fieldValues), false);
        };
        const reset = (data) => {
            resetFields();
            !data && unset(fieldArrayDefaultValuesRef.current, name);
            unset(shallowFieldsStateRef.current, name);
            memoizedDefaultValues.current = get(data || defaultValuesRef.current, name);
            setFields(mapIds(memoizedDefaultValues.current, keyName));
        };
        React.useEffect(() => {
            {
                if (!name) {
                    console.warn('📋 useFieldArray is missing `name` attribute. https://react-hook-form.com/api#useFieldArray');
                }
            }
            const defaultValues = get(fieldArrayDefaultValuesRef.current, name);
            if (defaultValues && fields.length < defaultValues.length) {
                defaultValues.pop();
                set(fieldArrayDefaultValuesRef.current, name, defaultValues);
            }
            updateWatchedValue(name);
            if (focusIndexRef.current > -1) {
                for (const key in fieldsRef.current) {
                    const field = fieldsRef.current[key];
                    if (key.startsWith(`${name}[${focusIndexRef.current}]`) &&
                        field.ref.focus) {
                        field.ref.focus();
                        break;
                    }
                }
            }
            focusIndexRef.current = -1;
        }, [fields, name]);
        React.useEffect(() => {
            const resetFunctions = resetFieldArrayFunctionRef.current;
            const fieldArrayNames = fieldArrayNamesRef.current;
            if (!getFieldArrayParentName(name)) {
                resetFunctions[name] = reset;
            }
            return () => {
                resetFields();
                delete resetFunctions[name];
                fieldArrayNames.delete(name);
            };
        }, []);
        return {
            swap: React.useCallback(swap, [name]),
            move: React.useCallback(move, [name]),
            prepend: React.useCallback(prepend$1, [name]),
            append: React.useCallback(append, [name]),
            remove: React.useCallback(remove, [name]),
            insert: React.useCallback(insert$1, [name]),
            fields,
        };
    };
  
    function useWatch({ control, name, defaultValue, }) {
        const methods = useFormContext();
        {
            if (!control && !methods) {
                throw new Error('📋 useWatch is missing `control` prop. https://react-hook-form.com/api#useWatch');
            }
        }
        const { useWatchFieldsRef, useWatchRenderFunctionsRef, watchInternal, defaultValuesRef, } = control || methods.control;
        const [value, setValue] = React.useState(isUndefined(defaultValue)
            ? isString(name)
                ? get(defaultValuesRef.current, name)
                : Array.isArray(name)
                    ? name.reduce((previous, inputName) => (Object.assign(Object.assign({}, previous), { [inputName]: get(defaultValuesRef.current, inputName) })), {})
                    : defaultValuesRef.current
            : defaultValue);
        const idRef = React.useRef();
        const defaultValueRef = React.useRef(defaultValue);
        const updateWatchValue = React.useCallback(() => {
            const value = watchInternal(name, defaultValueRef.current, idRef.current);
            setValue(isObject(value)
                ? Object.assign({}, value) : Array.isArray(value)
                ? [...value]
                : value);
        }, [setValue, watchInternal, defaultValueRef, name, idRef]);
        React.useEffect(() => {
            {
                if (name === '') {
                    console.warn('📋 useWatch is missing `name` attribute. https://react-hook-form.com/api#useWatch');
                }
            }
            const id = (idRef.current = generateId());
            const watchFieldsHookRender = useWatchRenderFunctionsRef.current;
            const watchFieldsHook = useWatchFieldsRef.current;
            watchFieldsHook[id] = new Set();
            watchFieldsHookRender[id] = updateWatchValue;
            watchInternal(name, defaultValueRef.current, id);
            return () => {
                delete watchFieldsHook[id];
                delete watchFieldsHookRender[id];
            };
        }, [
            name,
            updateWatchValue,
            useWatchRenderFunctionsRef,
            useWatchFieldsRef,
            watchInternal,
            defaultValueRef,
        ]);
        return (isUndefined(value) ? defaultValue : value);
    }
  
    var getInputValue = (event) => isPrimitive(event) ||
        !isObject(event.target) ||
        (isObject(event.target) && !event.type)
        ? event
        : isUndefined(event.target.value)
            ? event.target.checked
            : event.target.value;
  
    const Controller = (_a) => {
        var { name, rules, as, render, defaultValue, control, onFocus } = _a, rest = __rest(_a, ["name", "rules", "as", "render", "defaultValue", "control", "onFocus"]);
        const methods = useFormContext();
        {
            if (!control && !methods) {
                throw new Error('📋 Controller is missing `control` prop. https://react-hook-form.com/api#Controller');
            }
        }
        const { defaultValuesRef, setValue, register, unregister, trigger, mode, reValidateMode: { isReValidateOnBlur, isReValidateOnChange }, formStateRef: { current: { isSubmitted, touched }, }, updateFormState, readFormStateRef, fieldsRef, fieldArrayNamesRef, shallowFieldsStateRef, } = control || methods.control;
        const isNotFieldArray = !isNameInFieldArray(fieldArrayNamesRef.current, name);
        const getInitialValue = () => !isUndefined(get(shallowFieldsStateRef.current, name)) && isNotFieldArray
            ? get(shallowFieldsStateRef.current, name)
            : isUndefined(defaultValue)
                ? get(defaultValuesRef.current, name)
                : defaultValue;
        const [value, setInputStateValue] = React.useState(getInitialValue());
        const valueRef = React.useRef(value);
        const ref = React.useRef({
            focus: () => null,
        });
        const onFocusRef = React.useRef(onFocus || (() => ref.current.focus()));
        const shouldValidate = (isBlurEvent) => !skipValidation(Object.assign({ isBlurEvent,
            isReValidateOnBlur,
            isReValidateOnChange,
            isSubmitted, isTouched: !!get(touched, name) }, mode));
        const commonTask = ([event]) => {
            const data = getInputValue(event);
            setInputStateValue(data);
            valueRef.current = data;
            return data;
        };
        const registerField = React.useCallback(() => {
            if ( !name) {
                return console.warn('📋 Field is missing `name` prop. https://react-hook-form.com/api#Controller');
            }
            if (fieldsRef.current[name]) {
                fieldsRef.current[name] = Object.assign({ ref: fieldsRef.current[name].ref }, rules);
            }
            else {
                register(Object.defineProperty({
                    name,
                    focus: onFocusRef.current,
                }, VALUE, {
                    set(data) {
                        setInputStateValue(data);
                        valueRef.current = data;
                    },
                    get() {
                        return valueRef.current;
                    },
                }), rules);
                if (isNotFieldArray && !get(defaultValuesRef.current, name)) {
                    setInputStateValue(getInitialValue());
                }
            }
        }, [rules, name, register]);
        React.useEffect(() => () => unregister(name), [unregister, name]);
        React.useEffect(() => {
            {
                if (isUndefined(value)) {
                    console.warn(`📋 ${name} is missing in the 'defaultValue' prop of either its Controller (https://react-hook-form.com/api#Controller) or useForm (https://react-hook-form.com/api#useForm)`);
                }
                if ((!as && !render) || (as && render)) {
                    console.warn(`📋 ${name} Controller should use either the 'as' or 'render' prop, not both. https://react-hook-form.com/api#Controller`);
                }
                if (!isNotFieldArray && isUndefined(defaultValue)) {
                    console.warn('📋 Controller is missing `defaultValue` prop when using `useFieldArray`. https://react-hook-form.com/api#Controller');
                }
            }
            registerField();
        }, [registerField]);
        React.useEffect(() => {
            if (!fieldsRef.current[name]) {
                registerField();
                if (isNotFieldArray) {
                    setInputStateValue(getInitialValue());
                }
            }
        });
        const onBlur = () => {
            if (readFormStateRef.current.touched && !get(touched, name)) {
                set(touched, name, true);
                updateFormState({
                    touched,
                });
            }
            if (shouldValidate(true)) {
                trigger(name);
            }
        };
        const onChange = (...event) => setValue(name, commonTask(event), {
            shouldValidate: shouldValidate(),
            shouldDirty: true,
        });
        const commonProps = {
            onChange,
            onBlur,
            name,
            value,
            ref,
        };
        const props = Object.assign(Object.assign({}, rest), commonProps);
        return as
            ? React.isValidElement(as)
                ? React.cloneElement(as, props)
                : React.createElement(as, props)
            : render
                ? render(commonProps)
                : null;
    };
  
    exports.Controller = Controller;
    exports.FormProvider = FormProvider;
    exports.appendErrors = appendErrors;
    exports.get = get;
    exports.transformToNestObject = transformToNestObject;
    exports.useFieldArray = useFieldArray;
    exports.useForm = useForm;
    exports.useFormContext = useFormContext;
    exports.useWatch = useWatch;
  
    Object.defineProperty(exports, '__esModule', { value: true });
  
  })));
  //# sourceMappingURL=index.umd.development.js.map
  