"use strict";
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
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 (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        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 __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Menu = void 0;
/* eslint jsx-a11y/no-static-element-interactions: 0 */
var react_1 = __importDefault(require("react"));
var bem_react_classname_1 = require("bem-react-classname");
var icons_classic_1 = require("@alfalab/icons-classic");
var cn_1 = require("../cn");
var menu_item_1 = __importDefault(require("../menu-item/menu-item"));
var window_1 = require("../lib/window");
var keyboard_code_1 = __importDefault(require("../lib/keyboard-code"));
var performance_1 = __importDefault(require("../performance"));
/**
 * Компонент меню.
 */
var Menu = /** @class */ (function (_super) {
    __extends(Menu, _super);
    function Menu() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.cn = bem_react_classname_1.createCn('menu');
        _this.state = {
            highlightedItem: null,
            checkedItems: [],
            hovered: false,
        };
        _this.menuItemList = [];
        _this.blurTimeoutId = null;
        _this.handleMenuItemClick = function (item, event) {
            _this.setNewCheckedItems(item, event);
            if (_this.props.onItemClick) {
                _this.props.onItemClick(item, event);
            }
        };
        _this.handleMouseEnter = function (event) {
            _this.setState({ hovered: true });
            if (_this.props.onMouseEnter) {
                _this.props.onMouseEnter(event);
            }
        };
        _this.handleMouseLeave = function (event) {
            _this.setState({ hovered: false });
            if (_this.props.onMouseLeave) {
                _this.props.onMouseLeave(event);
            }
        };
        _this.handleKeyUp = function (event) {
            if (_this.props.onKeyUp) {
                _this.props.onKeyUp(event);
            }
        };
        _this.handleKeyDown = function (event) {
            var highlightedItem = null;
            var highlightedMenuItem = null;
            var menuIteListLength = _this.menuItemList.length;
            switch (event.which) {
                case keyboard_code_1.default.DOWN_ARROW: {
                    event.preventDefault();
                    if (_this.state.highlightedItem) {
                        _this.menuItemList.forEach(function (item, index, menuItemList) {
                            if (item.ref === _this.state.highlightedItem.ref) {
                                if (index + 1 === menuIteListLength) {
                                    highlightedItem = menuItemList[0];
                                }
                                else {
                                    highlightedItem = menuItemList[index + 1];
                                }
                            }
                        });
                    }
                    else {
                        highlightedItem = _this.menuItemList[0];
                    }
                    _this.setState({
                        highlightedItem: highlightedItem,
                    });
                    if (_this.props.onHighlightItem) {
                        _this.props.onHighlightItem(highlightedItem);
                    }
                    break;
                }
                case keyboard_code_1.default.UP_ARROW: {
                    event.preventDefault();
                    if (_this.state.highlightedItem) {
                        _this.menuItemList.forEach(function (item, index, menuItemList) {
                            if (item.ref === _this.state.highlightedItem.ref) {
                                if (index - 1 < 0) {
                                    highlightedItem = menuItemList[menuIteListLength - 1];
                                }
                                else {
                                    highlightedItem = menuItemList[index - 1];
                                }
                            }
                        });
                    }
                    else {
                        highlightedItem = _this.menuItemList[menuIteListLength - 1];
                    }
                    _this.setState({
                        highlightedItem: highlightedItem,
                    });
                    if (_this.props.onHighlightItem) {
                        _this.props.onHighlightItem(highlightedItem);
                    }
                    break;
                }
                case keyboard_code_1.default.ENTER:
                case keyboard_code_1.default.SPACE: {
                    event.preventDefault();
                    highlightedItem = _this.props.highlightedItem === undefined
                        ? _this.state.highlightedItem
                        : _this.props.highlightedItem;
                    if (highlightedItem) {
                        _this.setNewCheckedItems(highlightedItem.item, event);
                    }
                    break;
                }
            }
            if (highlightedItem) {
                highlightedMenuItem = highlightedItem.instance;
            }
            if (_this.props.onKeyDown) {
                _this.props.onKeyDown(event, highlightedMenuItem);
            }
        };
        _this.handleFocus = function (event) {
            if (_this.blurTimeoutId) {
                clearTimeout(_this.blurTimeoutId);
                _this.blurTimeoutId = null;
            }
            if (_this.props.onFocus) {
                _this.props.onFocus(event);
            }
        };
        _this.handleBlur = function (event) {
            event.persist();
            if (_this.blurTimeoutId) {
                clearTimeout(_this.blurTimeoutId);
            }
            _this.blurTimeoutId = setTimeout(function () {
                if (window_1.isNodeOutsideElement(document.activeElement, _this.root) && _this.props.onBlur) {
                    _this.props.onBlur(event);
                }
                _this.blurTimeoutId = null;
            }, 0);
        };
        _this.handleMenuItemMouseLeave = function () {
            _this.setState({
                highlightedItem: null,
            });
            if (_this.props.onHighlightItem) {
                _this.props.onHighlightItem(null);
            }
        };
        _this.getIndexInCheckedItemsList = function (value) {
            var checkedItems = _this.props.checkedItems ? _this.props.checkedItems : _this.state.checkedItems;
            return checkedItems.indexOf(value);
        };
        return _this;
    }
    Menu.prototype.componentDidMount = function () {
        if (!!this.props.content && this.props.content.length > 0
            && (!this.props.checkedItems || this.props.checkedItems.length === 0)
            && this.props.mode === 'radio') {
            var firstItem = this.getFirstItem(this.props.content);
            this.changeCheckedItems([firstItem.value], null);
        }
    };
    // eslint-disable-next-line camelcase
    Menu.prototype.UNSAFE_componentWillReceiveProps = function (nextProps) {
        if (this.props.mode !== 'check' && this.state.checkedItems[0]
            && nextProps.checkedItems[0] !== this.state.checkedItems[0]) {
            var highlightedItem_1;
            this.menuItemList.forEach(function (item, index, menuItemList) {
                if (item.ref === nextProps.checkedItems[0]) {
                    highlightedItem_1 = menuItemList[index].instance;
                }
            });
            if (this.props.onHighlightItem) {
                this.props.onHighlightItem(highlightedItem_1);
            }
        }
    };
    // eslint-disable-next-line camelcase
    Menu.prototype.UNSAFE_componentWillUpdate = function () {
        this.menuItemList = [];
    };
    Menu.prototype.componentWillUnmount = function () {
        if (this.blurTimeoutId) {
            clearTimeout(this.blurTimeoutId);
            this.blurTimeoutId = null;
        }
    };
    Menu.prototype.render = function () {
        var _this = this;
        /* eslint-disable jsx-a11y/no-noninteractive-tabindex */
        return (react_1.default.createElement("div", { ref: function (root) {
                _this.root = root;
            }, style: this.props.style, className: this.cn({
                size: this.props.size,
                view: this.props.view,
                'group-view': this.props.groupView,
                hovered: this.state.hovered,
                disabled: this.props.disabled,
                mode: this.props.mode,
            }), id: this.props.id, tabIndex: 0, onMouseEnter: this.handleMouseEnter, onMouseLeave: this.handleMouseLeave, onKeyDown: this.handleKeyDown, onKeyUp: this.handleKeyUp, onFocus: this.handleFocus, onBlur: this.handleBlur, "data-test-id": this.props['data-test-id'] }, !!this.props.content && this.renderMenuItemList(this.props.content)));
        /* eslint-enable jsx-a11y/no-noninteractive-tabindex */
    };
    Menu.prototype.renderMenuItemList = function (content) {
        var _this = this;
        var result = [];
        var groupKey = 0;
        content.forEach(function (item) {
            if (item.type === 'group') {
                result.push(react_1.default.createElement("div", { className: _this.cn('group'), key: "group_" + groupKey },
                    !!item.title
                        && (react_1.default.createElement("div", { className: _this.cn('group-title') }, item.title)),
                    _this.renderMenuItemList(item.content)));
                groupKey += 1;
            }
            else {
                result.push(_this.renderMenuItem(item));
            }
        });
        return result;
    };
    Menu.prototype.renderMenuItem = function (item) {
        var _this = this;
        var itemProps = item.props || {};
        var isItemChecked = this.getIndexInCheckedItemsList(item.value) !== -1;
        var isItemDisabled = this.props.disabled || itemProps.disabled;
        var clickHandler = this.props.mode === 'basic' ? itemProps.onClick : function (event) { return _this.handleMenuItemClick(item, event); };
        var menuItem = {
            item: item,
            ref: item.value,
        };
        var menuItemProps = __assign(__assign({}, itemProps), { disabled: isItemDisabled, value: item.value, size: this.props.size || itemProps.size, onClick: isItemDisabled ? undefined : clickHandler });
        var highlightedItem = this.props.highlightedItem === undefined
            ? this.state.highlightedItem
            : this.props.highlightedItem;
        var IconTick;
        switch (this.props.size) {
            case 's':
            case 'm':
                IconTick = icons_classic_1.TickSIcon;
                break;
            case 'l':
            case 'xl':
                IconTick = icons_classic_1.TickMIcon;
                break;
        }
        this.menuItemList.push(menuItem);
        return (react_1.default.createElement(menu_item_1.default, __assign({}, menuItemProps, { ref: function (instance) {
                menuItem.instance = instance;
            }, key: item.key || item.value, checked: isItemChecked, type: this.props.mode === 'basic' ? itemProps.type : 'block', onMouseEnter: function () { return _this.handleMenuItemMouseEnter(menuItem); }, onMouseLeave: this.handleMenuItemMouseLeave, hovered: highlightedItem && highlightedItem.ref === menuItem.ref }),
            this.props.mode === 'check' && isItemChecked
                && (react_1.default.createElement("div", { className: "icon" },
                    react_1.default.createElement(IconTick, null))),
            item.content));
    };
    Menu.prototype.handleMenuItemMouseEnter = function (menuItem) {
        this.setState({
            highlightedItem: menuItem,
        });
        if (this.props.onHighlightItem) {
            this.props.onHighlightItem(menuItem);
        }
    };
    /**
     * Возвращает корневой `HTMLElement` компонента.
     */
    Menu.prototype.getNode = function () {
        return this.root;
    };
    /**
     * Устанавливает фокус на меню.
     */
    Menu.prototype.focus = function () {
        this.root.focus();
        if (this.props.autoFocusFirstItem) {
            var highlightedItem = this.menuItemList[0];
            this.setState({
                highlightedItem: highlightedItem,
            });
            if (this.props.onHighlightItem) {
                this.props.onHighlightItem(highlightedItem);
            }
        }
    };
    /**
     * Убирает фокус с меню.
     */
    // eslint-disable-next-line class-methods-use-this
    Menu.prototype.blur = function () {
        if (document.activeElement) {
            document.activeElement.blur();
        }
    };
    Menu.prototype.setNewCheckedItems = function (item, event) {
        var value = item.value;
        var checkedItems = this.props.checkedItems === undefined
            ? Array.from(this.state.checkedItems)
            : Array.from(this.props.checkedItems);
        var indexInCheckedItemsList = this.getIndexInCheckedItemsList(value);
        switch (this.props.mode) {
            case 'check':
                if (indexInCheckedItemsList === -1) {
                    checkedItems.push(value);
                }
                else {
                    checkedItems.splice(indexInCheckedItemsList, 1);
                }
                break;
            case 'radio':
                if (indexInCheckedItemsList === -1) {
                    checkedItems = [value];
                }
                break;
            case 'radio-check':
                if (indexInCheckedItemsList === -1) {
                    checkedItems = [value];
                }
                else {
                    checkedItems = [];
                }
                break;
            default:
                break;
        }
        this.changeCheckedItems(checkedItems, event);
        this.focus();
    };
    /**
     * Изменяет выбранные значения.
     *
     * @param checkedItems Список выбранных значений
     * @param event
     */
    Menu.prototype.changeCheckedItems = function (checkedItems, event) {
        this.setState({
            checkedItems: checkedItems,
        });
        if (this.props.onItemCheck) {
            this.props.onItemCheck(checkedItems, event);
        }
    };
    Menu.prototype.getFirstItem = function (content) {
        var firstItem = content[0];
        return firstItem.type === 'group' ? this.getFirstItem(firstItem.content) : firstItem;
    };
    Menu.defaultProps = {
        size: 'm',
        mode: 'basic',
        groupView: 'default',
        autoFocusFirstItem: false,
    };
    Menu = __decorate([
        performance_1.default(true)
    ], Menu);
    return Menu;
}(react_1.default.Component));
exports.Menu = Menu;
exports.default = cn_1.withTheme(Menu);

//# sourceMappingURL=menu.js.map
