'use strict';

var React = require('react');
var mergeRefs = require('./mergeRefs-cjs.js');
var classnames = require('classnames');
var tslib_es6 = require('./tslib.es6-cjs.js');
var reactHookForm = require('react-hook-form');

/**
 * Combines the actions from the props of the FormField with the actions from react-hook-form. This is used to
 * manage the form state of a field through react-hook-form while providing support for additional callbacks
 */
function useAtlantisFormFieldActions({ name, onChange, inputRef, onControllerChange, onControllerBlur, onEnter, readonly, type, setValue, onFocus, onBlur, onValidation, }) {
    function handleClear() {
        var _a;
        handleBlur();
        setValue(name, "", { shouldValidate: true });
        onChange && onChange("");
        (_a = inputRef === null || inputRef === void 0 ? void 0 : inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
    }
    function handleChange(event) {
        let newValue;
        newValue = event.currentTarget.value;
        if (type === "number" && newValue.length > 0) {
            newValue = parseFloat(newValue);
        }
        onChange && onChange(newValue, event);
        onControllerChange(event);
    }
    function handleKeyDown(event) {
        if (!onEnter)
            return;
        if (event.key !== "Enter")
            return;
        if (event.shiftKey || event.ctrlKey)
            return;
        event.preventDefault();
        onEnter && onEnter(event);
    }
    function handleFocus(event) {
        const target = event.currentTarget;
        if (target.select) {
            setTimeout(() => readonly && target.select());
        }
        onFocus && onFocus();
    }
    function handleBlur() {
        onBlur && onBlur();
        onControllerBlur();
    }
    function handleValidation(message) {
        onValidation && onValidation(message);
    }
    return {
        handleClear,
        handleChange,
        handleKeyDown,
        handleFocus,
        handleBlur,
        handleValidation,
    };
}

/**
 * Provides the props for the html fields rendered by the FormField component
 */
function useAtlantisFormField({ id, nameProp, name, useControllerField: useControllerField, description, disabled, readonly, keyboard, autofocus, pattern, type, value, handleChange, handleBlur, handleFocus, inline, validations, handleKeyDown, handleValidation, errorMessage, }) {
    const descriptionIdentifier = `descriptionUUID--${id}`;
    const fieldProps = Object.assign(Object.assign(Object.assign({}, useControllerField), { id, className: classnames(mergeRefs.formFieldStyles.input, {
            [mergeRefs.formFieldStyles.emptyPhoneNumber]: shouldAddPhoneNumberClass(type, value, pattern),
        }), name: (validations || nameProp) && name, disabled: disabled, readOnly: readonly, inputMode: keyboard, onChange: handleChange, onBlur: handleBlur, onFocus: handleFocus, autoFocus: autofocus }), (description &&
        !inline && { "aria-describedby": descriptionIdentifier }));
    const textFieldProps = Object.assign(Object.assign({}, fieldProps), { autoFocus: autofocus, onKeyDown: handleKeyDown });
    React.useEffect(() => handleValidation(errorMessage), [errorMessage]);
    return { textFieldProps, fieldProps, descriptionIdentifier };
}
function shouldAddPhoneNumberClass(type, value, pattern) {
    return type === "tel" && !value && pattern && pattern[0] === "(";
}

/**
 * Hook used to manage the form state of a field through react-hook-form
 */
function useAtlantisReactHookForm({ actionsRef, name, defaultValue, value, validations, inputRef, }) {
    var _a;
    const formContext = reactHookForm.useFormContext();
    // If there isn't a Form Context being provided, get a form for this field.
    const { control, setValue, watch } = formContext !== null && formContext !== void 0 ? formContext : reactHookForm.useForm({ mode: "onTouched" });
    React.useImperativeHandle(actionsRef, () => ({
        setValue: newValue => {
            setValue(name, newValue, { shouldValidate: true });
        },
    }));
    const { field, fieldState: { error }, } = reactHookForm.useController({
        name,
        control,
        rules: validations,
        defaultValue: (_a = value !== null && value !== void 0 ? value : defaultValue) !== null && _a !== void 0 ? _a : "",
    });
    const { onChange, onBlur, ref: fieldRef } = field, useControllerField = tslib_es6.__rest(field, ["onChange", "onBlur", "ref"]);
    React.useEffect(() => {
        if (value != undefined) {
            setValue(name, value);
        }
    }, [value, watch(name)]);
    const inputRefs = mergeRefs.mergeRefs([inputRef, fieldRef]);
    return {
        inputRefs,
        useControllerField,
        setValue,
        errorMessage: (error === null || error === void 0 ? void 0 : error.message) || "",
        onControllerChange: onChange,
        onControllerBlur: onBlur,
    };
}

function FormField(props) {
    // Warning: do not move useId into FormFieldInternal. This must be here to avoid
    // a problem where useId isn't stable across multiple StrictMode renders.
    // https://github.com/facebook/react/issues/27103
    const generatedId = React.useId();
    const id = props.id || generatedId;
    return React.createElement(FormFieldInternal, Object.assign({}, props, { id: id }));
}
function FormFieldInternal(props) {
    var _a;
    const { actionsRef, autocomplete = true, children, defaultValue, description, disabled, id, inputRef, inline, keyboard, max, maxLength, min, name: nameProp, pattern, readonly, rows, loading, type = "text", validations, value, onChange, onEnter, onFocus, onBlur, onValidation, onKeyUp, clearable = "never", autofocus, } = props;
    const { name } = mergeRefs.useAtlantisFormFieldName({ id, nameProp });
    const { errorMessage, inputRefs, useControllerField, setValue, onControllerBlur, onControllerChange, } = useAtlantisReactHookForm({
        actionsRef,
        name,
        defaultValue,
        value,
        validations,
        inputRef,
    });
    const { handleValidation, handleBlur, handleChange, handleClear, handleFocus, handleKeyDown, } = useAtlantisFormFieldActions({
        inputRef,
        onChange,
        onEnter,
        readonly,
        type,
        onFocus,
        setValue,
        onBlur,
        onValidation,
        onControllerBlur,
        onControllerChange,
        name,
    });
    const { textFieldProps, fieldProps, descriptionIdentifier } = useAtlantisFormField({
        id,
        useControllerField,
        name,
        nameProp,
        description,
        validations: !!validations,
        disabled,
        readonly,
        keyboard,
        autofocus,
        value,
        type,
        pattern,
        handleChange,
        handleBlur,
        handleFocus,
        inline,
        errorMessage,
        handleValidation,
        handleKeyDown,
    });
    // Ensure focus tracking works by providing a wrapperRef when none is passed
    const internalWrapperRef = React.useRef(null);
    const wrapperRef = (_a = props.wrapperRef) !== null && _a !== void 0 ? _a : internalWrapperRef;
    return (React.createElement(mergeRefs.FormFieldWrapper, Object.assign({}, props, { value: useControllerField.value, error: errorMessage, identifier: id, descriptionIdentifier: descriptionIdentifier, clearable: clearable, onClear: handleClear, wrapperRef: wrapperRef }), renderField()));
    function renderField() {
        switch (type) {
            case "select":
                return (React.createElement(React.Fragment, null,
                    React.createElement("select", Object.assign({}, fieldProps), children),
                    React.createElement(mergeRefs.FormFieldPostFix, { variation: "select" })));
            case "textarea":
                return React.createElement("textarea", Object.assign({}, textFieldProps, { rows: rows, ref: inputRefs }));
            default:
                return (React.createElement(React.Fragment, null,
                    React.createElement("input", Object.assign({}, textFieldProps, { autoComplete: setAutocomplete(autocomplete), type: type, maxLength: maxLength, max: max, min: min, ref: inputRefs, onKeyUp: onKeyUp })),
                    loading && React.createElement(mergeRefs.FormFieldPostFix, { variation: "spinner" }),
                    children));
        }
    }
}
function setAutocomplete(autocompleteSetting) {
    if (autocompleteSetting === true) {
        return undefined;
    }
    else if (autocompleteSetting === false) {
        return "off";
    }
    return autocompleteSetting;
}

exports.FormField = FormField;
exports.useAtlantisFormField = useAtlantisFormField;
exports.useAtlantisFormFieldActions = useAtlantisFormFieldActions;
exports.useAtlantisReactHookForm = useAtlantisReactHookForm;
