import React, { useContext, useRef, useCallback, useImperativeHandle, forwardRef, useEffect, } from 'react';
import { st, classes } from './Input.st.css.js';
import { InputContext } from './InputContext';
import { STATUS } from '../StatusIndicator/StatusIndicator.constants';
import { DATA_ATTR } from './Input.constants';
import Ticker from './components/Ticker';
import IconAffix from './components/IconAffix';
import Affix from './components/Affix';
import Group from './components/Group';
import { WixStyleReactMaskingContext } from '../WixStyleReactMaskingProvider/context';
import { WixStyleReactDefaultsOverrideContext } from '../WixStyleReactDefaultsOverrideProvider';
import { StatusContext, getAriaAttributesFromContext, getStatusFromContext, } from '../FormField/StatusContext';
import { useAutoFocusAndSelect } from './hooks/useAutoFocusAndSelect';
import { transformAriaKebabCase } from './utils/transformAriaKebabCase';
import { Suffix } from './components/Suffix/Suffix';
export const Input = forwardRef((props, ref) => {
    const { input: inputPropsDefaults } = useContext(WixStyleReactDefaultsOverrideContext);
    const { role, autoSelect = true, textOverflow = 'clip', size = inputPropsDefaults.size, hideStatusSuffix = false, clearButton = false, focusOnClearClick = true, border = 'standard', maxLength = 524288, autoFocus, onFocus, onBlur, value, customInput, min, max, step, inputRef, id, name, disabled, defaultValue, onChange, type, onKeyDown, onEnterPressed, onEscapePressed, onPaste, onCopy, placeholder, tabIndex, onInputClicked, onKeyUp, readOnly, disableEditing, required, autocomplete, onCompositionChange, pattern, prefix, suffix, className, status, statusMessage, onClear, menuArrow, rtl, dataHook, forceFocus, noRightBorderRadius, noLeftBorderRadius, forceHover, tooltipPlacement, clearButtonTooltipContent, clearButtonTooltipProps, clearButtonAriaLabel, statusMessageTooltipProps, ...rest } = props;
    const isComposing = useRef(false);
    const localInputRef = useRef(null);
    const { maskingClassNames } = useContext(WixStyleReactMaskingContext);
    const statusContext = useContext(StatusContext);
    const { _onFocus, _onBlur, isFocused } = useAutoFocusAndSelect({
        localInputRef,
        onFocus,
        onBlur,
        autoFocus,
        autoSelect,
        value,
    });
    useImperativeHandle(ref, () => ({
        /**
         * Sets focus on the input element
         */
        focus: (options = {}) => localInputRef.current?.focus(options),
        /**
         * Removes focus from the input element
         */
        blur: () => localInputRef.current?.blur(),
        /**
         * Selects the text in the input element
         */
        select: () => localInputRef.current?.select(),
        /**
         * Sets the start and end positions of the current text selection in the input element
         */
        setSelectionRange: (start, end) => localInputRef.current?.setSelectionRange(start, end),
        /**
         * Clears the input value
         */
        clear: (event) => {
            // If the value is undefined, we are dealing with an uncontrolled input
            if (value === undefined && localInputRef.current) {
                localInputRef.current.value = '';
            }
            onClear?.(event);
        },
        /**
         * Gets the input DOM element.
         */
        input: localInputRef.current,
    }));
    /**
     * Legacy reason to still support inputRef prop as prop.
     */
    useEffect(() => {
        if (inputRef && localInputRef.current) {
            inputRef(localInputRef.current);
        }
    }, [inputRef]);
    const isValid = useCallback((val) => {
        if (type === 'number') {
            /*
             * Limit our number input to contain only:
             * - \d - digits
             * - .  - a dot
             * - ,  - a comma
             * - \- - a hyphen minus
             * - +  - a plus sign
             */
            return /^[\d.,\-+]*$/.test(val);
        }
        return true;
    }, [type]);
    const _onChange = useCallback((event) => {
        if (isValid(event.target.value)) {
            onChange?.(event);
        }
    }, [isValid, onChange]);
    const _onKeyPress = useCallback((event) => {
        if (!isValid(event.currentTarget.value + event.key)) {
            event.preventDefault();
        }
    }, [isValid]);
    const _onWheel = useCallback(() => {
        if (type === 'number') {
            localInputRef.current?.blur();
        }
    }, [type]);
    const _onKeyDown = useCallback((event) => {
        if (isComposing.current) {
            return;
        }
        // On key event
        onKeyDown?.(event);
        // Enter
        if (event.key === 'Enter' || event.keyCode === 13) {
            onEnterPressed?.(event);
        }
        // Escape
        if (event.key === 'Escape' || event.keyCode === 27) {
            onEscapePressed?.(event);
        }
    }, [isComposing, onEnterPressed, onEscapePressed, onKeyDown]);
    const _onClick = useCallback((event) => onInputClicked?.(event), [onInputClicked]);
    const _onCompositionChange = useCallback((composing) => {
        isComposing.current = composing;
        onCompositionChange?.(composing);
    }, [onCompositionChange]);
    const commonProps = {
        role,
        id,
        min,
        max,
        step,
        'data-mask': !!maskingClassNames,
        className: st(classes.input, {}, maskingClassNames),
        style: { textOverflow },
        name,
        disabled,
        defaultValue,
        value,
        onFocus: _onFocus,
        onBlur: _onBlur,
        onChange: _onChange,
        onKeyPress: _onKeyPress,
        onWheel: _onWheel,
        onKeyDown: _onKeyDown,
        onClick: _onClick,
        onPaste,
        onCopy,
        placeholder,
        tabIndex,
        onKeyUp,
        readOnly: readOnly || disableEditing,
        type,
        required,
        autoComplete: autocomplete,
        onCompositionStart: () => _onCompositionChange(true),
        onCompositionEnd: () => _onCompositionChange(false),
        pattern,
        maxLength,
        ...getAriaAttributesFromContext(statusContext),
        ...transformAriaKebabCase(rest),
    };
    const CustomInputComponent = customInput;
    const inputElement = customInput ? (React.createElement(CustomInputComponent, { "data-hook": "wsr-custom-input", ref: localInputRef, ...commonProps })) : (React.createElement("input", { "data-hook": "wsr-input", ref: localInputRef, ...commonProps }));
    const dataAttributes = {
        [DATA_ATTR.ROOT]: true,
        [DATA_ATTR.SIZE]: size,
        [DATA_ATTR.STATUS]: getStatusFromContext(statusContext, status),
        [DATA_ATTR.PREFIX]: !!prefix,
        [DATA_ATTR.DISABLED]: disabled,
        [DATA_ATTR.HOVER]: forceHover,
        [DATA_ATTR.FOCUS]: forceFocus || isFocused,
        [DATA_ATTR.LEFTBORDERRADIUS]: noLeftBorderRadius,
        [DATA_ATTR.RIGHTBORDERRADIUS]: noRightBorderRadius,
    };
    return (React.createElement("div", { className: st(classes.root, {
            size,
            hasFocus: forceFocus || isFocused,
            status: getStatusFromContext(statusContext, status),
            forceHover,
            readOnly,
            disabled,
            border,
            noRightBorderRadius,
            noLeftBorderRadius,
        }, className), dir: rtl ? 'rtl' : undefined, "data-hook": dataHook, ...dataAttributes },
        React.createElement("div", { className: classes.wrapper },
            prefix && (React.createElement(InputContext.Provider, { value: { ...props, size, inPrefix: true } }, prefix)),
            inputElement,
            React.createElement(InputContext.Provider, { value: { ...props, size, inSuffix: true } },
                React.createElement(Suffix, { statusMessage: statusMessage, status: status, disabled: disabled, menuArrow: menuArrow, suffix: suffix, tooltipPlacement: tooltipPlacement, clearButtonTooltipContent: clearButtonTooltipContent, clearButtonTooltipProps: clearButtonTooltipProps, clearButtonAriaLabel: clearButtonAriaLabel, statusMessageTooltipProps: statusMessageTooltipProps, hideStatusSuffix: hideStatusSuffix, onClear: onClear, clearButton: clearButton, value: value, size: size, onInputClicked: onInputClicked, focusOnClearClick: focusOnClearClick, inputElementRef: localInputRef })))));
});
Input.displayName = 'Input';
export default Object.assign(Input, {
    Ticker,
    IconAffix,
    Affix,
    Group,
    StatusError: STATUS.ERROR,
    StatusWarning: STATUS.WARNING,
    StatusLoading: STATUS.LOADING,
});
//# sourceMappingURL=Input.js.map