'use strict';

var React = require('react');
var jobberHooks = require('@jobber/hooks');
var framerMotion = require('framer-motion');
var design = require('@jobber/design');
var classnames = require('classnames');
var Button = require('./Button-cjs.js');
var Icon = require('./Icon-cjs.js');
var Text = require('./Text-cjs.js');
var useFormFieldFocus = require('./useFormFieldFocus-cjs.js');
var InputValidation = require('./InputValidation-cjs.js');
var Spinner = require('./Spinner-cjs.js');

var formFieldStyles = {"container":"YL-mNv-Bl6g-","wrapper":"_8lhbGTQ-hhg-","disabled":"Tz9LK9ABKMk-","horizontalWrapper":"b5mv1x1H7YE-","textarea":"hGr6YW4AeLM-","safari":"QBCWi9GBgMs-","timeInputLabel":"_0pmqVa2zSE4-","miniLabel":"F1t76G6bDKo-","large":"_9tjyT9QUtP8-","text":"QmMiyoAWp-g-","invalid":"XWDSfe6weSY-","small":"Sw5O4I0lMJg-","inline":"SaORbL7SYWY-","center":"ozy2UoT2vsg-","right":"_3TJdT91YD3c-","maxLength":"W6GrMqLy2qk-","inputWrapper":"-LmjnYRU0r0-","childrenWrapper":"yVXYv6hkuOA-","input":"vtSDcuzNr9Q-","emptyPhoneNumber":"MVhuQuzUBUs-","label":"Dgk00tzlODA-","select":"NwQGiWBWIsc-","externalLabel":"Qb8zQ8n-8vc-","postfix":"yTDzs9h1otI-","affixIcon":"m0YpdssD2dY-","suffix":"_-3mMnjSh6ok-","affixLabel":"-Wzcb0pBh5I-","description":"DHX5ijY3xIw-","toolbar":"AL-2brNI7dk-","spinning":"_8Rzv7CcDW80-"};

/**
 * @internal Reach out to UX Foundations if using this component since it is possible it might change
 */
function AffixLabel({ label, variation = "prefix", labelRef, }) {
    const affixLabelClass = classnames(formFieldStyles.affixLabel, {
        [formFieldStyles.suffix]: variation === "suffix",
    });
    if (!label)
        return null;
    return (React.createElement("div", { ref: labelRef, className: affixLabelClass }, label));
}
function AffixIcon({ icon, onClick, ariaLabel, variation = "prefix", size, }) {
    const affixIconClass = classnames(formFieldStyles.affixIcon, {
        [formFieldStyles.suffix]: variation === "suffix",
    });
    const iconSize = size === "small" ? "small" : "base";
    if (!icon)
        return null;
    return (React.createElement("div", { className: affixIconClass }, onClick ? (React.createElement(Button.Button
    /**
     * We can cast the ariaLabel here as a `Suffix`
     * requires an ariaLabel if there is an action
     */
    , { 
        /**
         * We can cast the ariaLabel here as a `Suffix`
         * requires an ariaLabel if there is an action
         */
        ariaLabel: ariaLabel, icon: icon, onClick: onClick, variation: "subtle", type: "tertiary", size: iconSize })) : (React.createElement(Icon.Icon, { name: icon, size: iconSize, color: "greyBlue" }))));
}

function FormFieldDescription({ id, description, visible = true, }) {
    if (!visible)
        return null;
    const useStringFormat = !description || typeof description === "string";
    return (React.createElement("div", { id: id, className: formFieldStyles.description }, useStringFormat ? (React.createElement(Text.Text, { size: "small", variation: "subdued" }, description)) : (description)));
}

var styles = {"clearInput":"YmRTd-KeXv4-","spinning":"B25z9B8I3gs-"};

function ClearAction({ onClick, visible, }) {
    if (!visible)
        return null;
    return (React.createElement("button", { className: styles.clearInput, onClick: onClick, type: "button", "aria-label": "Clear input", "data-testid": "ATL-FormField-clearButton" },
        React.createElement(Icon.Icon, { name: "remove", size: "small" })));
}

function useToolbar(props) {
    const isToolbarVisible = props.toolbar !== undefined &&
        (props.toolbarVisibility === "always" || props.focused);
    const toolbarAnimationEnd = { opacity: 0, height: 0 };
    const toolbarAnimationStart = { opacity: 1, height: "auto" };
    return {
        isToolbarVisible,
        toolbarAnimationEnd,
        toolbarAnimationStart,
    };
}

function useIsSafari() {
    return (globalThis === null || globalThis === void 0 ? void 0 : globalThis.navigator)
        ? /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
        : false;
}

/**
 * Hook for getting the correct styles for the FormField and its children
 */
function useFormFieldWrapperStyles({ size, align, placeholder, value, invalid, error, max, prefixRef, suffixRef, maxLength, type, disabled, inline, showMiniLabel = true, }) {
    const isSafari = useIsSafari();
    const wrapperClasses = classnames(formFieldStyles.wrapper, size && formFieldStyles[size], align && formFieldStyles[align], {
        [formFieldStyles.miniLabel]: (showMiniLabel && placeholder && value !== "") ||
            (placeholder && type === "select") ||
            // Naively assume that if the the type is tel, it is the InputPhoneNumber
            (placeholder && type === "tel"),
        [formFieldStyles.text]: type === "textarea" || type === "text",
        [formFieldStyles.textarea]: type === "textarea",
        [formFieldStyles.safari]: isSafari && type === "textarea",
        [formFieldStyles.select]: type === "select",
        [formFieldStyles.invalid]: invalid !== null && invalid !== void 0 ? invalid : error,
        [formFieldStyles.disabled]: disabled,
        [formFieldStyles.maxLength]: maxLength,
        [formFieldStyles.timeInputLabel]: placeholder && type === "time" && placeholder && value === "",
    });
    const containerClasses = classnames(formFieldStyles.container, {
        [formFieldStyles.inline]: inline,
    });
    const wrapperInlineStyle = {
        ["--formField-maxLength"]: maxLength || max,
    };
    const [labelStyle, setLabelStyle] = React.useState({
        paddingLeft: undefined,
        paddingRight: undefined,
    });
    React.useEffect(() => {
        var _a, _b;
        setLabelStyle(getAffixPaddding({
            value,
            type,
            prefixWidth: ((_a = prefixRef === null || prefixRef === void 0 ? void 0 : prefixRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 0,
            suffixWidth: ((_b = suffixRef === null || suffixRef === void 0 ? void 0 : suffixRef.current) === null || _b === void 0 ? void 0 : _b.offsetWidth) || 0,
        }));
    }, [value]);
    return {
        inputStyle: formFieldStyles.input,
        wrapperClasses,
        containerClasses,
        wrapperInlineStyle,
        labelStyle,
        setLabelStyle,
    };
}
function getAffixPaddding({ value, type, prefixWidth, suffixWidth, }) {
    const hasValue = value !== "";
    const newPadding = {
        paddingLeft: undefined,
        paddingRight: undefined,
    };
    // Naively assume that if the the type is tel, it is the InputPhoneNumber
    if (type === "tel")
        return newPadding;
    if (prefixWidth && !hasValue) {
        newPadding.paddingLeft = offset(prefixWidth);
    }
    if (suffixWidth && !hasValue) {
        newPadding.paddingRight = offset(suffixWidth);
    }
    function offset(width) {
        return `calc(${width}px + var(--space-smallest)`;
    }
    return newPadding;
}

function FormFieldWrapper({ align, description, descriptionIdentifier, placeholder, value, children, invalid, error, size, prefix, suffix, max, maxLength, type, disabled, inline, identifier, clearable, onClear, readonly, toolbar, toolbarVisibility = "while-editing", showMiniLabel = true, wrapperRef, }) {
    const prefixRef = React.useRef(null);
    const suffixRef = React.useRef(null);
    const { wrapperClasses, containerClasses, wrapperInlineStyle, labelStyle } = useFormFieldWrapperStyles({
        align,
        max,
        maxLength,
        prefixRef,
        suffixRef,
        placeholder,
        value,
        invalid,
        error,
        type,
        disabled,
        inline,
        size,
        showMiniLabel,
    });
    const { focused } = useFormFieldFocus.useFormFieldFocus({ wrapperRef });
    const showClear = jobberHooks.useShowClear({
        clearable,
        multiline: type === "textarea",
        focused,
        hasValue: Boolean(value),
        disabled,
        readonly,
    });
    const { isToolbarVisible, toolbarAnimationEnd, toolbarAnimationStart } = useToolbar({
        focused,
        toolbar,
        toolbarVisibility,
    });
    return (React.createElement("div", { className: containerClasses },
        React.createElement("div", { className: wrapperClasses, style: wrapperInlineStyle, "data-testid": "Form-Field-Wrapper", ref: wrapperRef },
            React.createElement(FormFieldInputHorizontalWrapper, null,
                React.createElement(AffixIcon, Object.assign({}, prefix, { size: size })),
                React.createElement(FormFieldInputWrapperStyles, null,
                    (showMiniLabel || !value) && (React.createElement(FormFieldLabel, { htmlFor: identifier, style: (prefixRef === null || prefixRef === void 0 ? void 0 : prefixRef.current) || (suffixRef === null || suffixRef === void 0 ? void 0 : suffixRef.current)
                            ? labelStyle
                            : undefined }, placeholder)),
                    React.createElement(AffixLabel, Object.assign({}, prefix, { labelRef: prefixRef })),
                    React.createElement(FormFieldWrapperMain, null, children),
                    React.createElement(AffixLabel, Object.assign({}, suffix, { labelRef: suffixRef, variation: "suffix" }))),
                React.createElement(ClearAction, { onClick: onClear, visible: showClear }),
                React.createElement(AffixIcon, Object.assign({}, suffix, { variation: "suffix", size: size }))),
            React.createElement(FormFieldWrapperToolbar, { toolbarVisibility: toolbarVisibility, isToolbarVisible: isToolbarVisible, toolbarAnimationEnd: toolbarAnimationEnd, toolbarAnimationStart: toolbarAnimationStart, toolbar: toolbar })),
        React.createElement(FormFieldDescription, { visible: !!description && !inline, id: descriptionIdentifier, description: description }),
        React.createElement(InputValidation.InputValidation, { message: error, visible: !!error && !inline })));
}
/**
 * @internal Reach out to UX Foundations if using this component since it is possible it might change
 */
function FormFieldInputHorizontalWrapper({ children, }) {
    return React.createElement("div", { className: formFieldStyles.horizontalWrapper }, children);
}
/**
 * @internal Reach out to UX Foundations if using this component since it is possible it might change
 */
function FormFieldInputWrapperStyles({ children, }) {
    return React.createElement("div", { className: formFieldStyles.inputWrapper }, children);
}
/**
 * @internal Reach out to UX Foundations if using this component since it is possible it might change
 */
function FormFieldWrapperMain({ children, tabIndex = -1, }) {
    return (React.createElement("div", { className: formFieldStyles.childrenWrapper, tabIndex: tabIndex }, children));
}
function FormFieldLabel({ children, htmlFor, style, external = false, }) {
    if (!children)
        return null;
    return (React.createElement("label", { className: external ? formFieldStyles.externalLabel : formFieldStyles.label, htmlFor: htmlFor, style: style }, children));
}
/**
 * @internal Reach out to UX Foundations if using this component since it is possible it might change
 */
function FormFieldWrapperToolbar({ toolbar, isToolbarVisible, toolbarAnimationEnd, toolbarAnimationStart, toolbarVisibility, }) {
    return (React.createElement(framerMotion.AnimatePresence, { initial: toolbarVisibility === "always" ? false : true }, isToolbarVisible && (React.createElement(framerMotion.motion.div, { key: "toolbar", initial: toolbarAnimationEnd, animate: toolbarAnimationStart, exit: toolbarAnimationEnd, transition: {
            duration: design.tokens["timing-base"] / 1000,
            ease: "easeInOut",
        }, tabIndex: -1 },
        React.createElement("div", { className: formFieldStyles.toolbar, "data-testid": "ATL-InputText-Toolbar" }, toolbar)))));
}

function FormFieldPostFix({ variation, visible = true, className, }) {
    if (!visible)
        return null;
    return (React.createElement("span", { className: classnames(formFieldStyles.postfix, className) }, variation === "select" ? (React.createElement(Icon.Icon, { name: "arrowDown" })) : (React.createElement(Spinner.Spinner, { size: "small" }))));
}

function useAtlantisFormFieldName({ id, nameProp, }) {
    /**
     * Generate a name if one is not supplied, this is the name
     * that will be used for react-hook-form and not neccessarily
     * attached to the DOM
     */
    const name = nameProp ? nameProp : `generatedName--${id}`;
    return { name };
}

/**
 * Given an array of refs, merge them into a single ref callback.
 * This is useful for cases where you need to pass a multiple refs to a component.
 */
function mergeRefs(refs) {
    return value => {
        refs.forEach(ref => {
            if (typeof ref === "function") {
                ref(value);
            }
            else if (ref != null) {
                ref.current = value;
            }
        });
    };
}

exports.AffixIcon = AffixIcon;
exports.AffixLabel = AffixLabel;
exports.FormFieldInputHorizontalWrapper = FormFieldInputHorizontalWrapper;
exports.FormFieldInputWrapperStyles = FormFieldInputWrapperStyles;
exports.FormFieldLabel = FormFieldLabel;
exports.FormFieldPostFix = FormFieldPostFix;
exports.FormFieldWrapper = FormFieldWrapper;
exports.FormFieldWrapperMain = FormFieldWrapperMain;
exports.FormFieldWrapperToolbar = FormFieldWrapperToolbar;
exports.formFieldStyles = formFieldStyles;
exports.mergeRefs = mergeRefs;
exports.useAtlantisFormFieldName = useAtlantisFormFieldName;
exports.useFormFieldWrapperStyles = useFormFieldWrapperStyles;
