var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __rest = (this && this.__rest) || function (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;
};
import React, { useContext, useEffect, useImperativeHandle, useRef, useCallback, useState } from 'react';
import debounce from 'lodash.debounce';
import { useGlobal, useEmotion, useStyles } from '../../../lib/renderEnvironment/index.js';
import { isBrowser } from '../../../lib/globalObject.js';
import { ThemeContext } from '../../../lib/theming/ThemeContext.js';
import { forwardRefAndName } from '../../../lib/forwardRefAndName.js';
import { globalClasses, getStyles } from './ColorableInputElement.styles.js';
// Возможно придётся включить.
// Иногда, на тяжёлых страницах, текст рендерится итеративно.
// Из-за этого могут оставаться артефакты при покраске компонента, которые пропадут только после фокуса.
// setInterval(() => window.requestAnimationFrame(() => dictionary.forEach((paint) => paint())), 1000);
export var ColorableInputElement = forwardRefAndName('ColorableInputElement', function ColorableInputElement(props, ref) {
    var _a;
    var _b;
    var inputRef = useRef(null);
    var spanRef = useRef(null);
    var focused = useRef(false);
    var updateActiveTimer = useRef(undefined);
    var globalObject = useGlobal();
    var emotion = useEmotion();
    var cx = emotion.cx;
    var styles = useStyles(getStyles);
    var theme = useContext(ThemeContext);
    var _c = useState(Boolean(props.alwaysShowMask || (!props.placeholder && (props.value || props.defaultValue)))), active = _c[0], setActive = _c[1];
    var children = props.children, onInput = props.onInput, onFocus = props.onFocus, onBlur = props.onBlur, showOnFocus = props.showOnFocus, alwaysShowMask = props.alwaysShowMask, inputProps = __rest(props, ["children", "onInput", "onFocus", "onBlur", "showOnFocus", "alwaysShowMask"]);
    var stopUpdateActive = useCallback(function () {
        clearTimeout(updateActiveTimer.current);
    }, []);
    var updateActive = useCallback(function () {
        stopUpdateActive();
        updateActiveTimer.current = setTimeout(function () {
            var _a, _b;
            var nextActive = true;
            if (inputRef.current) {
                var _c = inputRef.current, clientWidth = _c.clientWidth, scrollWidth = _c.scrollWidth;
                var scrollable = scrollWidth > clientWidth;
                var placeholderShown = (_b = (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0 ? void 0 : _b.querySelector(':placeholder-shown');
                nextActive = !(scrollable || placeholderShown);
            }
            setActive(nextActive);
        }, 0);
    }, [stopUpdateActive]);
    var paintText = useCallback(function () {
        var _a, _b, _c, _d;
        if (!isBrowser(globalObject) || !spanRef.current || !inputRef.current || !active) {
            inputRef.current && (inputRef.current.style.backgroundImage = '');
            (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.classList.remove(globalClasses.input);
            return;
        }
        (_b = inputRef.current) === null || _b === void 0 ? void 0 : _b.classList.add(globalClasses.input);
        var shadow = spanRef.current.shadowRoot;
        var typedValueElement = shadow === null || shadow === void 0 ? void 0 : shadow.getElementById('typed-value');
        var fullValueElement = shadow === null || shadow === void 0 ? void 0 : shadow.getElementById('full-value');
        if (!typedValueElement || !fullValueElement) {
            shadow = spanRef.current.attachShadow({ mode: 'open' });
            typedValueElement = globalObject.document.createElement('span');
            fullValueElement = globalObject.document.createElement('span');
            typedValueElement.setAttribute('id', 'typed-value');
            fullValueElement.setAttribute('id', 'full-value');
            shadow.append(typedValueElement, fullValueElement);
        }
        var style = getComputedStyle(inputRef.current);
        typedValueElement.textContent =
            ((inputRef.current.getAttribute('data-unmasked-value') || focused.current) &&
                inputRef.current.getAttribute('data-typed-value')) ||
                '';
        fullValueElement.textContent = inputRef.current.value || inputRef.current.defaultValue || '';
        var inputRect = inputRef.current.getBoundingClientRect();
        var typedValueRect = typedValueElement.getBoundingClientRect();
        var fullValueRect = fullValueElement.getBoundingClientRect();
        var threshold = typedValueRect.width / (inputRect.width / 100);
        var degree = style.fontStyle === 'italic' ? 100 : 90;
        var restValueWidth = 1 - Math.min(fullValueRect.width / inputRect.width, 1);
        var typedValueColor = theme.inputTextColor;
        var maskColor = theme.inputPlaceholderColor;
        var indent = 0;
        if (props.disabled) {
            typedValueColor = theme.inputTextColorDisabled;
            maskColor = theme.inputTextColorDisabled;
        }
        if (props.showOnFocus) {
            maskColor = focused.current ? maskColor : 'transparent';
        }
        if (((_c = props.style) === null || _c === void 0 ? void 0 : _c.textAlign) === 'right') {
            indent = 100 * restValueWidth;
        }
        if (((_d = props.style) === null || _d === void 0 ? void 0 : _d.textAlign) === 'center') {
            indent = 50 * restValueWidth;
        }
        inputRef.current.style.backgroundImage = "\n      linear-gradient(\n          ".concat(degree, "deg,\n          ").concat(typedValueColor, " ").concat(threshold + indent, "%,\n          ").concat(maskColor, " ").concat(threshold + indent, "%\n      )");
    }, [
        active,
        props.showOnFocus,
        props.disabled,
        theme.inputTextColor,
        theme.inputPlaceholderColor,
        theme.inputTextColorDisabled,
        globalObject,
        (_b = props.style) === null || _b === void 0 ? void 0 : _b.textAlign,
    ]);
    var debouncedPaintText = useCallback(function () { return debounce(paintText); }, [paintText])();
    var handleInput = useCallback(function (e) {
        debouncedPaintText();
        onInput === null || onInput === void 0 ? void 0 : onInput(e);
    }, [debouncedPaintText, onInput]);
    var handleFocus = useCallback(function (e) {
        updateActive();
        focused.current = true;
        onFocus === null || onFocus === void 0 ? void 0 : onFocus(e);
    }, [onFocus, updateActive]);
    var handleBlur = useCallback(function (e) {
        updateActive();
        focused.current = false;
        onBlur === null || onBlur === void 0 ? void 0 : onBlur(e);
    }, [onBlur, updateActive]);
    useImperativeHandle(ref, function () { return ({
        input: inputRef.current,
        getRootNode: function () { return inputRef.current; },
    }); }, []);
    useEffect(function () {
        debouncedPaintText();
        updateActive();
        return stopUpdateActive;
    }, [updateActive, props.value, props.defaultValue, theme, debouncedPaintText, stopUpdateActive]);
    return (React.createElement(React.Fragment, null,
        React.cloneElement(children, __assign(__assign({}, inputProps), { onInput: handleInput, onFocus: handleFocus, onBlur: handleBlur, inputRef: inputRef, className: cx(props.className, styles.root(), (_a = {},
                _a[globalClasses.input] = active,
                _a)) })),
        active && React.createElement("span", { style: { visibility: 'hidden', position: 'absolute', whiteSpace: 'pre' }, ref: spanRef })));
});
//# sourceMappingURL=ColorableInputElement.js.map