var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
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 __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
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;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
import React from 'react';
import warning from 'warning';
import { isKonturIcon } from '../../lib/utils.js';
import { isSafari } from '../../lib/client.js';
import { KeyListener } from '../../lib/events/keyListener.js';
import { ThemeContext } from '../../lib/theming/ThemeContext.js';
import { CommonWrapper } from '../../internal/CommonWrapper/index.js';
import { rootNode } from '../../lib/rootNode/index.js';
import { ThemeFactory } from '../../lib/theming/ThemeFactory.js';
import { createPropsGetter } from '../../lib/createPropsGetter.js';
import { Link } from '../Link/index.js';
import { withSize } from '../../lib/size/SizeDecorator.js';
import { withRenderEnvironment } from '../../lib/renderEnvironment/index.js';
import { getStyles, getActiveStyles, globalClasses } from './Button.styles.js';
import { ButtonIcon, getButtonIconSizes } from './ButtonIcon.js';
import { useButtonArrow } from './ButtonArrow.js';
import { getInnerLinkTheme } from './getInnerLinkTheme.js';
import { LoadingButtonIcon } from './LoadingButtonIcon.js';
export var BUTTON_DEFAULT_COMPONENT = 'button';
export var ButtonDataTids = {
    rootElement: 'Button__rootElement',
    root: 'Button__root',
    spinner: 'Button__spinner',
};
var SpanComponent = function (_a) {
    var children = _a.children, rest = __rest(_a, ["children"]);
    return React.createElement("span", __assign({}, rest), children);
};
/** Кнопка запускает действие, сценарий или позволяет перейти на другую страницу. */
var Button = /** @class */ (function (_super) {
    __extends(Button, _super);
    function Button() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.getProps = createPropsGetter(Button_1.defaultProps);
        _this.state = {
            focusedByTab: false,
        };
        _this.node = null;
        _this.renderMain = function (props) {
            var _a, _b, _c, _d, _e;
            var corners = props.corners, active = props.active, disabled = props.disabled, borderless = props.borderless, checked = props.checked, error = props.error, warning = props.warning, loading = props.loading, narrow = props.narrow, arrow = props.arrow, icon = props.icon, rightIcon = props.rightIcon, _noPadding = props._noPadding, _noRightPadding = props._noRightPadding, visuallyFocused = props.visuallyFocused, align = props.align, disableFocus = props.disableFocus, width = props.width, tabIndex = props.tabIndex, _component = props.component, useProp = props.use, theme = props.theme, rest = __rest(props, ["corners", "active", "disabled", "borderless", "checked", "error", "warning", "loading", "narrow", "arrow", "icon", "rightIcon", "_noPadding", "_noRightPadding", "visuallyFocused", "align", "disableFocus", "width", "tabIndex", "component", "use", "theme"]);
            var _f = _this.getProps(), use = _f.use, component = _f.component, children = _f.children;
            var sizeClass = _this.getSizeClassName();
            var isFocused = _this.state.focusedByTab || visuallyFocused;
            var isLink = use === 'link';
            var _g = useButtonArrow(__assign(__assign({}, _this.props), { isFocused: Boolean(isFocused), size: _this.size }), _this.theme, _this.styles, _this.cx), rootClassNameWithArrow = _g[0], arrowNode = _g[1];
            var isUseStateWithoutOutlineInDisabledState = !['default', 'backless', 'outline'].includes(use);
            var nonInteractive = disabled || loading;
            var _h = _this.getUseStyle(), style = _h.style, styleActive = _h.styleActive;
            var rootClassName = _this.cx.apply(_this, __spreadArray([_this.styles.root(_this.theme),
                style,
                sizeClass,
                narrow && _this.styles.narrow(),
                _noPadding && _this.styles.noPadding(),
                _noRightPadding && _this.styles.noRightPadding(),
                rootClassNameWithArrow], (nonInteractive
                ? [
                    _this.styles.disabled(_this.theme),
                    isUseStateWithoutOutlineInDisabledState && _this.styles.disabledWithoutOutline(_this.theme),
                    checked && _this.styles.checkedDisabled(_this.theme),
                    borderless && _this.styles.borderless(),
                    (use === 'backless' || use === 'outline') && _this.styles.backlessDisabled(_this.theme),
                    use === 'text' && _this.styles.textDisabled(),
                    globalClasses.disabled,
                ]
                : [
                    active && !checked && styleActive,
                    isFocused && _this.styles.focus(_this.theme),
                    checked && _this.styles.checked(_this.theme),
                    checked && isFocused && _this.styles.checkedFocused(_this.theme),
                    borderless && !checked && !isFocused && _this.styles.borderless(),
                ]), false));
            var rootProps = __assign(__assign({}, rest), { className: rootClassName, style: __assign({ textAlign: align }, corners), onFocus: _this.handleFocus, onBlur: _this.handleBlur, tabIndex: _this.getTabIndex({ disableFocus: disableFocus, disabled: nonInteractive, tabIndex: tabIndex }) });
            var wrapProps = {
                className: _this.cx(globalClasses.root, (_a = {},
                    _a[_this.styles.wrap(_this.theme)] = true,
                    _a[_this.getSizeWrapClassName()] = true,
                    _a)),
                style: {
                    width: width,
                },
            };
            var buttonOnlyProps = component === 'button' ? { disabled: nonInteractive } : {};
            var innerShadowNode = null;
            var outlineNode = null;
            if ((!isFocused || isLink) && !nonInteractive) {
                outlineNode = (React.createElement("div", { className: _this.cx(_this.styles.outlineDefault(), (_b = {},
                        _b[_this.styles.outlineWarning(_this.theme)] = warning,
                        _b[_this.styles.outlineError(_this.theme)] = error,
                        _b[_this.styles.outlineLink()] = isLink,
                        _b[_this.styles.outlineLinkWarning(_this.theme)] = isLink && warning,
                        _b[_this.styles.outlineLinkError(_this.theme)] = isLink && error,
                        _b)) }));
            }
            var iconProps = {
                use: use,
                size: _this.size,
                hasChildren: !!children,
                loading: loading || false,
            };
            var leftIconNode = icon && React.createElement(ButtonIcon, __assign({}, iconProps, { position: "left", icon: icon }));
            var rightIconNode = rightIcon && (React.createElement(ButtonIcon, __assign({}, iconProps, { hasBothIcons: !!icon && !!rightIcon, position: "right", icon: rightIcon })));
            // Force disable all props and features, that cannot be use with Link
            if (isLink) {
                rootProps.className = _this.cx((_c = {},
                    _c[_this.styles.root(_this.theme)] = true,
                    _c[sizeClass] = true,
                    _c[_this.styles.link(_this.theme)] = true,
                    _c[_this.styles.linkLineHeight()] = !isSafari,
                    _c[_this.styles.linkLineHeightSafariFallback()] = isSafari,
                    _c[_this.styles.linkFocus(_this.theme)] = isFocused,
                    _c[_this.styles.linkDisabled(_this.theme)] = nonInteractive,
                    _c));
                Object.assign(wrapProps, {
                    className: _this.cx(_this.styles.wrap(_this.theme), _this.styles.wrapLink()),
                    style: { width: wrapProps.style.width },
                });
                rootProps.style.textAlign = undefined;
            }
            var hasLoadingNode = loading && !icon && !rightIcon;
            var loadingNode = hasLoadingNode && React.createElement(LoadingButtonIcon, { size: _this.size });
            var captionNode = (React.createElement("div", { className: _this.cx(_this.styles.caption(), globalClasses.caption, (_d = {},
                    _d[_this.styles.captionLink()] = isLink,
                    _d[_this.styles.captionDisabled()] = !checked && disabled,
                    _d)) },
                loadingNode,
                leftIconNode,
                React.createElement("span", { className: _this.cx(globalClasses.text, (_e = {},
                        _e[_this.styles.visibilityHidden()] = hasLoadingNode,
                        _e)) }, children),
                rightIconNode));
            if (isLink && !loading) {
                captionNode = (React.createElement(ThemeContext.Provider, { value: getInnerLinkTheme(_this.theme) }, React.createElement(Link, { focused: isFocused, disabled: disabled, icon: _this.renderIcon2022(icon), rightIcon: _this.renderIcon2022(rightIcon), tabIndex: -1, component: SpanComponent }, children)));
            }
            var Root = component;
            return (React.createElement("span", __assign({}, wrapProps, { "data-tid": ButtonDataTids.root }),
                React.createElement(Root, __assign({ "data-tid": ButtonDataTids.rootElement, ref: _this._ref }, rootProps, buttonOnlyProps),
                    innerShadowNode,
                    outlineNode,
                    arrowNode,
                    captionNode)));
        };
        _this.handleFocus = function (e) {
            var _a, _b, _c, _d;
            if (!_this.props.disabled && !_this.props.disableFocus) {
                // focus event fires before keyDown eventlistener
                // so we should check tabPressed in async way
                (_b = (_a = _this.globalObject).requestAnimationFrame) === null || _b === void 0 ? void 0 : _b.call(_a, function () {
                    if (_this.keyListener.isTabPressed) {
                        _this.setState({ focusedByTab: true });
                    }
                });
                (_d = (_c = _this.props).onFocus) === null || _d === void 0 ? void 0 : _d.call(_c, e);
            }
        };
        _this.handleBlur = function (e) {
            var _a, _b;
            _this.setState({ focusedByTab: false });
            if (!_this.props.disabled && !_this.props.disableFocus) {
                (_b = (_a = _this.props).onBlur) === null || _b === void 0 ? void 0 : _b.call(_a, e);
            }
        };
        _this._ref = function (node) {
            _this.node = node;
        };
        return _this;
    }
    Button_1 = Button;
    Button.prototype.componentDidMount = function () {
        this.keyListener = new KeyListener(this.globalObject);
        if (this.props.autoFocus) {
            this.keyListener.isTabPressed = true;
            this.focus();
        }
        warning(this.props.use !== 'link', '[Button]: `use="link"` has been deprecated. Please, use `<Link component="button" />` instead.');
        warning(this.props.use !== 'primary', '[Button]: `use="primary"` has been deprecated. Please, use `use="accent"` instead.');
        warning(this.props.use !== 'backless', '[Button]: `use="backless"` has been deprecated. Please, use `use="outline"` instead.');
    };
    Button.getDerivedStateFromProps = function (props) {
        if (props.loading || props.disabled) {
            return { focusedByTab: false };
        }
        return null;
    };
    /** Программно устанавливает фокус на кнопке. Появляется фокусная рамка, элемент получает клавиатурные события и воспринимается как текущий элемент для чтения скринридерами.
     * @public
     */
    Button.prototype.focus = function () {
        var _a;
        (_a = this.node) === null || _a === void 0 ? void 0 : _a.focus();
    };
    /** Программно снимает фокус с кнопки.
     * @public
     */
    Button.prototype.blur = function () {
        var _a;
        (_a = this.node) === null || _a === void 0 ? void 0 : _a.blur();
    };
    Button.prototype.render = function () {
        var _this = this;
        this.styles = getStyles(this.emotion);
        this.activeStyles = getActiveStyles(this.emotion);
        return (React.createElement(ThemeContext.Consumer, null, function (theme) {
            _this.theme = _this.props.theme ? ThemeFactory.create(_this.props.theme, theme) : theme;
            return (React.createElement(CommonWrapper, __assign({ rootNodeRef: _this.setRootNode }, _this.props), _this.renderMain));
        }));
    };
    Button.prototype.getTabIndex = function (_a) {
        var disableFocus = _a.disableFocus, disabled = _a.disabled, _b = _a.tabIndex, tabIndex = _b === void 0 ? 0 : _b;
        if (disableFocus || disabled) {
            return -1;
        }
        return tabIndex;
    };
    Button.prototype.renderIcon2022 = function (icon) {
        var _a;
        if ((icon === null || icon === void 0 ? void 0 : icon.props) && isKonturIcon(icon)) {
            var iconProps = icon.props;
            var sizes = getButtonIconSizes(this.theme);
            return React.cloneElement(icon, { size: (_a = iconProps.size) !== null && _a !== void 0 ? _a : sizes[this.size] });
        }
        return icon;
    };
    Button.prototype.getUseStyle = function () {
        var style;
        var styleActive;
        var _a = this, styles = _a.styles, activeStyles = _a.activeStyles;
        switch (this.props.use) {
            case 'primary':
            case 'accent':
                style = styles.accent(this.theme);
                styleActive = activeStyles.accent(this.theme);
                break;
            case 'backless':
            case 'outline':
                style = styles.outline(this.theme);
                styleActive = activeStyles.outline(this.theme);
                break;
            case 'fill':
                style = styles.fill(this.theme);
                styleActive = activeStyles.fill(this.theme);
                break;
            case 'success':
                style = styles.success(this.theme);
                styleActive = activeStyles.success(this.theme);
                break;
            case 'danger':
                style = styles.danger(this.theme);
                styleActive = activeStyles.danger(this.theme);
                break;
            case 'pay':
                style = styles.pay(this.theme);
                styleActive = activeStyles.pay(this.theme);
                break;
            case 'text':
                style = styles.text(this.theme);
                styleActive = activeStyles.text(this.theme);
                break;
            default:
                style = styles.default(this.theme);
                styleActive = activeStyles.default(this.theme);
        }
        return { style: style, styleActive: styleActive };
    };
    Button.prototype.getSizeClassName = function () {
        var _a, _b, _c;
        var _d = this.getProps(), icon = _d.icon, rightIcon = _d.rightIcon, children = _d.children;
        switch (this.size) {
            case 'large': {
                var commonClasses = (_a = {},
                    _a[this.styles.sizeLargeWithIcon(this.theme)] = !!icon,
                    _a[this.styles.sizeLargeWithRightIcon(this.theme)] = !!rightIcon,
                    _a[this.styles.sizeLargeWithIconWithoutText(this.theme)] = (!!icon || !!rightIcon) && !children,
                    _a);
                return this.cx(this.styles.sizeLarge(this.theme), commonClasses);
            }
            case 'medium': {
                var commonClasses = (_b = {},
                    _b[this.styles.sizeMediumWithIcon(this.theme)] = !!icon,
                    _b[this.styles.sizeMediumWithRightIcon(this.theme)] = !!rightIcon,
                    _b[this.styles.sizeMediumWithIconWithoutText(this.theme)] = (!!icon || !!rightIcon) && !children,
                    _b);
                return this.cx(this.styles.sizeMedium(this.theme), commonClasses);
            }
            case 'small':
            default: {
                var commonClasses = (_c = {},
                    _c[this.styles.sizeSmallWithIcon(this.theme)] = !!icon,
                    _c[this.styles.sizeSmallWithRightIcon(this.theme)] = !!rightIcon,
                    _c[this.styles.sizeSmallWithIconWithoutText(this.theme)] = (!!icon || !!rightIcon) && !children,
                    _c);
                return this.cx(this.styles.sizeSmall(this.theme), commonClasses);
            }
        }
    };
    Button.prototype.getSizeWrapClassName = function () {
        switch (this.size) {
            case 'large':
                return this.styles.wrapLarge(this.theme);
            case 'medium':
                return this.styles.wrapMedium(this.theme);
            case 'small':
            default:
                return this.styles.wrapSmall(this.theme);
        }
    };
    var Button_1;
    Button.__KONTUR_REACT_UI__ = 'Button';
    Button.displayName = 'Button';
    Button.__BUTTON__ = true;
    Button.defaultProps = {
        use: 'default',
        // By default, the type attribute is 'submit'. IE8 will fire a click event
        // on this button if somewhere on the page user presses Enter while some
        // input is focused. So we set type to 'button' by default.
        type: 'button',
        component: BUTTON_DEFAULT_COMPONENT,
    };
    Button = Button_1 = __decorate([
        withRenderEnvironment,
        withSize,
        rootNode
    ], Button);
    return Button;
}(React.Component));
export { Button };
//# sourceMappingURL=Button.js.map