'use strict';

var React = require('react');
var jobberHooks = require('@jobber/hooks');
var FormField = require('../FormField-cjs.js');
require('classnames');
require('../tslib.es6-cjs.js');
require('react-hook-form');
require('framer-motion');
require('@jobber/design');
require('../Button-cjs.js');
var mergeRefs = require('../mergeRefs-cjs.js');
var filterDataAttributes = require('../filterDataAttributes-cjs.js');
require('react-router-dom');
require('../Icon-cjs.js');
require('../Typography-cjs.js');
require('../Text-cjs.js');
require('../useFormFieldFocus-cjs.js');
require('../InputValidation-cjs.js');
require('../Spinner-cjs.js');

/**
 * Hook for resizing a textarea based on its content. The textarea will grow up to the max number of rows specified.
 */
function useTextAreaResize({ rows, value, inputRef, wrapperRef, }) {
    const rowRange = getRowRange(rows);
    jobberHooks.useSafeLayoutEffect(() => {
        if (inputRef &&
            inputRef.current instanceof HTMLTextAreaElement &&
            wrapperRef &&
            wrapperRef.current instanceof HTMLDivElement) {
            resize();
        }
    }, [inputRef.current, wrapperRef.current]);
    // When the consumer passes a new controlled value, we need to recheck the size.
    // The timeout ensures the DOM has a enough time to render the new text before
    // we access the height.
    jobberHooks.useSafeLayoutEffect(() => {
        setTimeout(() => {
            if (inputRef &&
                inputRef.current instanceof HTMLTextAreaElement &&
                wrapperRef &&
                wrapperRef.current instanceof HTMLDivElement) {
                resize();
            }
        }, 0);
    }, [value]);
    function resize() {
        if (inputRef &&
            inputRef.current instanceof HTMLTextAreaElement &&
            wrapperRef &&
            (wrapperRef === null || wrapperRef === void 0 ? void 0 : wrapperRef.current) instanceof HTMLDivElement) {
            if (rowRange.min === rowRange.max)
                return;
            inputRef.current.style.flexBasis = "auto";
            wrapperRef.current.style.height = "auto";
            inputRef.current.style.flexBasis =
                textAreaHeight(inputRef.current) + "px";
        }
    }
    function textAreaHeight(textArea) {
        const { lineHeight, borderBottomWidth, borderTopWidth, paddingBottom, paddingTop, } = window.getComputedStyle(textArea);
        const maxHeight = rowRange.max * parseFloat(lineHeight) +
            parseFloat(borderTopWidth) +
            parseFloat(borderBottomWidth) +
            parseFloat(paddingTop) +
            parseFloat(paddingBottom);
        const scrollHeight = textArea.scrollHeight +
            parseFloat(borderTopWidth) +
            parseFloat(borderBottomWidth);
        return Math.min(scrollHeight, maxHeight);
    }
    return { resize, rowRange };
}
function getRowRange(rows) {
    if (rows === undefined) {
        return { min: 3, max: 3 };
    }
    else if (typeof rows === "object") {
        return { min: rows.min, max: rows.max };
    }
    else {
        return { min: rows, max: rows };
    }
}

function InputTextInternal(
// eslint-disable-next-line import/no-deprecated
props, ref) {
    const inputRef = React.useRef(null);
    const actionsRef = React.useRef(null);
    const wrapperRef = React.useRef(null);
    const { resize, rowRange } = useTextAreaResize({
        rows: props.rows,
        value: props.value,
        inputRef,
        wrapperRef,
    });
    React.useImperativeHandle(ref, () => ({
        insert: (text) => {
            insertText(text);
        },
        blur: () => {
            const input = inputRef.current;
            if (input) {
                input.blur();
            }
        },
        focus: () => {
            const input = inputRef.current;
            if (input) {
                input.focus();
            }
        },
        scrollIntoView: arg => {
            const input = inputRef.current;
            if (input) {
                input.scrollIntoView(arg);
            }
        },
    }));
    return (React.createElement(FormField.FormField, Object.assign({}, props, { type: props.multiline ? "textarea" : "text", inputRef: inputRef, actionsRef: actionsRef, wrapperRef: wrapperRef, onChange: handleChange, rows: rowRange.min })));
    function handleChange(newValue) {
        props.onChange && props.onChange(newValue);
        resize();
    }
    function insertText(text) {
        var _a;
        const input = inputRef.current;
        if (input) {
            insertAtCursor(input, text);
            const newValue = input.value;
            (_a = actionsRef.current) === null || _a === void 0 ? void 0 : _a.setValue(newValue);
            props.onChange && props.onChange(newValue);
        }
    }
}
const InputText$1 = React.forwardRef(InputTextInternal);
function insertAtCursor(input, newText) {
    const start = input.selectionStart || 0;
    const end = input.selectionEnd || 0;
    const text = input.value;
    const before = text.substring(0, start);
    const after = text.substring(end, text.length);
    input.value = before + newText + after;
    input.selectionStart = input.selectionEnd = start + newText.length;
    input.focus();
}

/**
 * Combines the actions on the InputText such as onChange, onEnter, onFocus, onBlur, and onClear to forward information to the consumers of the InputText.
 * DO not repeat this pattern. We are doing this as a proof of concept relating to the refactoring of Form inputs to see what can be removed.
 */
function useInputTextActions({ onChange, inputRef, onEnter, onFocus, onBlur, onKeyDown, onKeyUp, onMouseDown, onMouseUp, onPointerDown, onPointerUp, onClick, }) {
    function handleClear() {
        var _a;
        onChange && onChange("");
        (_a = inputRef === null || inputRef === void 0 ? void 0 : inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
    }
    function handleChange(event) {
        const newValue = event.currentTarget.value;
        onChange === null || onChange === void 0 ? void 0 : onChange(newValue, event);
    }
    function handleKeyDown(event) {
        onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event);
        if (!onEnter)
            return;
        if (event.key !== "Enter")
            return;
        if (event.shiftKey || event.ctrlKey)
            return;
        event.preventDefault();
        onEnter && onEnter(event);
    }
    function handleKeyUp(event) {
        onKeyUp === null || onKeyUp === void 0 ? void 0 : onKeyUp(event);
    }
    function handleFocus(event) {
        onFocus === null || onFocus === void 0 ? void 0 : onFocus(event);
    }
    function handleBlur(event) {
        onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
    }
    function handleMouseDown(event) {
        onMouseDown === null || onMouseDown === void 0 ? void 0 : onMouseDown(event);
    }
    function handleMouseUp(event) {
        onMouseUp === null || onMouseUp === void 0 ? void 0 : onMouseUp(event);
    }
    function handlePointerDown(event) {
        onPointerDown === null || onPointerDown === void 0 ? void 0 : onPointerDown(event);
    }
    function handlePointerUp(event) {
        onPointerUp === null || onPointerUp === void 0 ? void 0 : onPointerUp(event);
    }
    function handleClick(event) {
        onClick === null || onClick === void 0 ? void 0 : onClick(event);
    }
    return {
        handleClear,
        handleChange,
        handleKeyDown,
        handleKeyUp,
        handleFocus,
        handleBlur,
        handleMouseDown,
        handleMouseUp,
        handlePointerDown,
        handlePointerUp,
        handleClick,
    };
}

const InputTextSPAR = React.forwardRef(function InputTextInternal(props, inputRef) {
    var _a, _b, _c;
    const inputTextRef = React.useRef(null), wrapperRef = React.useRef(null);
    const id = useInputTextId(props);
    const { rowRange } = useTextAreaResize({
        rows: props.rows,
        value: props.value,
        inputRef: inputTextRef,
        wrapperRef: wrapperRef,
    });
    const { name } = mergeRefs.useAtlantisFormFieldName({
        nameProp: props.name,
        id: id,
    });
    const { handleChange, handleBlur, handleFocus, handleKeyDown, handleKeyUp, handleClear, handleMouseDown, handleMouseUp, handlePointerDown, handlePointerUp, handleClick, } = useInputTextActions({
        onChange: props.onChange,
        onBlur: props.onBlur,
        onFocus: props.onFocus,
        onMouseDown: props.onMouseDown,
        onMouseUp: props.onMouseUp,
        onPointerDown: props.onPointerDown,
        onPointerUp: props.onPointerUp,
        onClick: props.onClick,
        onKeyDown: props.onKeyDown,
        onKeyUp: props.onKeyUp,
        onEnter: props.onEnter,
        inputRef: inputTextRef,
    });
    const descriptionIdentifier = `descriptionUUID--${id}`;
    const descriptionVisible = props.description && !props.inline;
    const isInvalid = Boolean(props.error || props.invalid);
    const dataAttrs = filterDataAttributes.filterDataAttributes(props);
    const mergedRef = React.useMemo(() => mergeRefs.mergeRefs([inputRef, inputTextRef]), []);
    // Shared props for both TextArea and TextInput
    const commonInputProps = Object.assign({ id,
        name, className: mergeRefs.formFieldStyles.input, value: props.value, disabled: props.disabled, readOnly: props.readOnly, autoFocus: props.autoFocus, autoComplete: props.autoComplete, inputMode: props.inputMode, tabIndex: props.tabIndex, maxLength: props.maxLength, required: props.required, role: props.role, "aria-label": props["aria-label"], "aria-describedby": descriptionVisible
            ? descriptionIdentifier
            : props["aria-describedby"], "aria-invalid": isInvalid ? true : undefined, "aria-controls": props["aria-controls"], "aria-expanded": props["aria-expanded"], "aria-activedescendant": props["aria-activedescendant"], "aria-autocomplete": props["aria-autocomplete"], "aria-required": props["aria-required"], onChange: handleChange, onBlur: handleBlur, onFocus: handleFocus, onKeyDown: handleKeyDown, onKeyUp: handleKeyUp, onMouseDown: handleMouseDown, onMouseUp: handleMouseUp, onPointerDown: handlePointerDown, onPointerUp: handlePointerUp, onClick: handleClick, ref: mergedRef }, dataAttrs);
    return (React.createElement(mergeRefs.FormFieldWrapper, { disabled: props.disabled, size: props.size, align: props.align, inline: props.inline, name: name, wrapperRef: wrapperRef, error: (_a = props.error) !== null && _a !== void 0 ? _a : "", invalid: Boolean(props.error || props.invalid), identifier: id, descriptionIdentifier: descriptionIdentifier, description: props.description, clearable: (_b = props.clearable) !== null && _b !== void 0 ? _b : "never", onClear: handleClear, type: props.multiline ? "textarea" : "text", placeholder: props.placeholder, value: props.value, prefix: props.prefix, suffix: props.suffix, readonly: props.readOnly, rows: rowRange.min, toolbar: props.toolbar, toolbarVisibility: props.toolbarVisibility, showMiniLabel: props.showMiniLabel },
        React.createElement(React.Fragment, null,
            props.multiline ? (React.createElement(TextArea, Object.assign({}, commonInputProps, { rows: rowRange.min }))) : (React.createElement(TextInput, Object.assign({}, commonInputProps, { pattern: props.pattern }))),
            React.createElement(mergeRefs.FormFieldPostFix, { variation: "spinner", visible: (_c = props.loading) !== null && _c !== void 0 ? _c : false }))));
});
function useInputTextId(props) {
    const generatedId = React.useId();
    return props.id || generatedId;
}
const TextArea = React.forwardRef(function TextArea(props, ref) {
    return React.createElement("textarea", Object.assign({}, props, { ref: ref }));
});
const TextInput = React.forwardRef(function TextInput(props, ref) {
    return React.createElement("input", Object.assign({}, props, { ref: ref }));
});

function isNewInputTextProps(props) {
    return props.version === 2;
}
const InputText = React.forwardRef(function InputTextShim(props, ref) {
    if (isNewInputTextProps(props)) {
        return (React.createElement(InputTextSPAR, Object.assign({}, props, { ref: ref })));
    }
    else {
        return (React.createElement(InputText$1, Object.assign({}, props, { ref: ref })));
    }
});

exports.InputText = InputText;
