/**
 * amis-ui v6.12.0-beta.0
 * Copyright 2018-2025 fex
 */

import { __extends, __assign, __values, __read, __spreadArray, __awaiter, __generator, __decorate, __metadata } from 'tslib';
import React__default from 'react';
import uniq from 'lodash/uniq';
import isEqual from 'lodash/isEqual';
import RcMenu, { ItemGroup, Divider } from 'rc-menu';
import { findTree, getTreeAncestors, mapTree, filterTree, autobind, themeable } from 'amis-core';
import { Icon } from '../icons.js';
import MenuItem from './MenuItem.js';
import SubMenu from './SubMenu.js';
import PanelMenu from './PanelMenu.js';
import { MenuContext } from './MenuContext.js';

/**
 * @file Menu
 * @description 导航菜单，基于rc-menu实现：https://github.com/react-component/menu
 * @author fex
 */
var INVALIDATE = 'invalidate';
var RESPONSIVE = 'responsive';
var Menu = /** @class */ (function (_super) {
    __extends(Menu, _super);
    function Menu(props) {
        var _this = this;
        var _a;
        _this = _super.call(this, props) || this;
        var _b = _this.normalizeNavigations(__assign({}, props)), transformedNav = _b.transformedNav, activeKey = _b.activeKey, defaultOpenKeys = _b.defaultOpenKeys, openKeys = _b.openKeys, activeItems = _b.activeItems;
        _this.state = {
            navigations: transformedNav,
            activeKey: activeKey,
            defaultOpenKeys: defaultOpenKeys,
            openKeys: openKeys
        };
        if (activeKey.length) {
            (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, activeItems);
        }
        return _this;
    }
    Menu.prototype.componentDidUpdate = function (prevProps, prevState) {
        var e_1, _a;
        var _b;
        var props = this.props;
        var isOpen = prevProps.isOpen;
        var isNavDiff = prevProps.navigations.length !== props.navigations.length;
        if (!isNavDiff) {
            try {
                // 顺序也要保持一致
                for (var _c = __values(props.navigations.entries()), _d = _c.next(); !_d.done; _d = _c.next()) {
                    var _e = __read(_d.value, 2), index = _e[0], item = _e[1];
                    // 对比navigations中的link属性 否则item中包含很多处理过的属性 甚至包含react组件 对比会引发性能问题
                    // 如果作为组件使用时 可以通过配置link 配置关键对比属性 如果没有 那直接跳过
                    // 如果没有link 就先不对比了
                    if (!item.link ||
                        (item.link && !isEqual(item.link, prevProps.navigations[index].link))) {
                        isNavDiff = true;
                        break;
                    }
                }
            }
            catch (e_1_1) { e_1 = { error: e_1_1 }; }
            finally {
                try {
                    if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
                }
                finally { if (e_1) throw e_1.error; }
            }
        }
        if (isNavDiff || !isEqual(prevProps.location, props.location)) {
            var _f = this.normalizeNavigations(__assign(__assign({}, props), { isOpen: isOpen })), transformedNav = _f.transformedNav, activeKey = _f.activeKey, defaultOpenKeys = _f.defaultOpenKeys, openKeys = _f.openKeys, activeItems = _f.activeItems;
            this.setState({
                navigations: transformedNav,
                activeKey: activeKey,
                defaultOpenKeys: defaultOpenKeys,
                openKeys: openKeys,
                activeItems: activeItems
            });
        }
        if (!isEqual(prevState.activeKey, this.state.activeKey)) {
            (_b = props.onChange) === null || _b === void 0 ? void 0 : _b.call(props, this.state.activeItems);
        }
    };
    Menu.prototype.getKeyPaths = function (navigations, key) {
        var activeItem = findTree(navigations, function (item) { return item.id === key; });
        if (!activeItem) {
            return [];
        }
        var ancestors = getTreeAncestors(navigations, activeItem);
        return ancestors ? ancestors.map(function (item) { return item.id || ''; }) : [];
    };
    Menu.prototype.normalizeNavigations = function (props) {
        var _this = this;
        var navigations = props.navigations, prefix = props.prefix, isActive = props.isActive, isOpen = props.isOpen, stacked = props.stacked;
        var id = 1;
        var activeKeys = [];
        var openKeys = [];
        var activeItems = [];
        var transformedNav = mapTree(filterTree(navigations, function (item, key, level) {
            // 水平导航不需要分割线
            if (!stacked && item.mode === 'divider') {
                return false;
            }
            return true;
        }), function (item, key, level, paths) {
            // 如果没有传入key，则为导航加一个自增key
            var navId = (item.id || item.key || id++).toString();
            if (!activeKeys.find(function (key) { return key === navId; }) && isActive(item, prefix)) {
                activeKeys === null || activeKeys === void 0 ? void 0 : activeKeys.push(navId);
                activeItems === null || activeItems === void 0 ? void 0 : activeItems.push(item.link || item);
            }
            var open = isOpen(item);
            if (!openKeys.find(function (key) { return key === navId; }) && open) {
                openKeys.push(navId);
            }
            return __assign(__assign({}, item), { id: navId, active: isActive, depth: level, children: item.children });
        }, 1, false);
        var activeKeyPaths = [];
        activeKeys.forEach(function (key) {
            activeKeyPaths = __spreadArray(__spreadArray(__spreadArray([], __read(activeKeyPaths), false), __read(_this.getKeyPaths(transformedNav, key)), false), [
                key
            ], false);
        });
        return {
            transformedNav: transformedNav,
            activeKey: activeKeys,
            defaultOpenKeys: activeKeyPaths,
            openKeys: openKeys,
            activeItems: activeItems
        };
    };
    Menu.prototype.handleItemClick = function (_a) {
        var key = _a.key, domEvent = _a.domEvent, keyPath = _a.keyPath;
        return __awaiter(this, void 0, void 0, function () {
            var onSelect, currentItem, result, _b;
            return __generator(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        // 菜单项里面可能会有按钮
                        // 如果里面事件执行了e.preventDefault() 则不执行后面的
                        // model:panel RcMenu收集itemClick key为空的情况
                        if ((domEvent && domEvent.defaultPrevented) || !key) {
                            return [2 /*return*/];
                        }
                        onSelect = this.props.onSelect;
                        currentItem = findTree(this.state.navigations, function (item) { return item.id === key; });
                        _b = onSelect;
                        if (!_b) return [3 /*break*/, 2];
                        return [4 /*yield*/, onSelect((currentItem === null || currentItem === void 0 ? void 0 : currentItem.link) || currentItem, keyPath.length)];
                    case 1:
                        _b = (_c.sent());
                        _c.label = 2;
                    case 2:
                        result = _b;
                        if (result === false) {
                            return [2 /*return*/];
                        }
                        this.setState({ activeKey: [key] });
                        return [2 /*return*/];
                }
            });
        });
    };
    Menu.prototype.handleSubMenuTitleClick = function (_a) {
        var key = _a.key, domEvent = _a.domEvent, props = _a.props;
        if (domEvent && domEvent.defaultPrevented) {
            return;
        }
        this.selectSubItem({ key: key, domEvent: domEvent, props: props });
    };
    Menu.prototype.handlePanelMenuClick = function (_a) {
        var key = _a.key, domEvent = _a.domEvent, keyPath = _a.keyPath;
        this.handleItemClick({ key: key, domEvent: domEvent, keyPath: keyPath });
    };
    Menu.prototype.selectSubItem = function (_a) {
        var key = _a.key; _a.domEvent; _a.props;
        var navigations = this.state.navigations;
        var _b = this.props, stacked = _b.stacked, mode = _b.mode, collapsed = _b.collapsed, accordion = _b.accordion, onToggle = _b.onToggle, onToggleExpand = _b.onToggleExpand, onSelect = _b.onSelect;
        var isVericalInline = stacked && mode === 'inline' && !collapsed;
        var openKeys = this.state.openKeys.concat();
        var isOpen = openKeys.includes(key);
        var keyPaths = this.getKeyPaths(navigations, key);
        if (isOpen) {
            openKeys = openKeys.filter(function (item) { return item !== key; });
        }
        else {
            if (isVericalInline && accordion) {
                openKeys = __spreadArray(__spreadArray([], __read(keyPaths), false), [key], false);
            }
            else {
                openKeys = __spreadArray(__spreadArray([], __read(openKeys), false), [key], false);
            }
        }
        var currentItem = findTree(navigations, function (item) { return item.id === key; });
        if (currentItem === null || currentItem === void 0 ? void 0 : currentItem.path) {
            onSelect === null || onSelect === void 0 ? void 0 : onSelect((currentItem === null || currentItem === void 0 ? void 0 : currentItem.link) || currentItem, keyPaths.length);
        }
        else {
            // 因为Nav里只处理当前菜单项 因此新增一个onToggle事件
            onToggle === null || onToggle === void 0 ? void 0 : onToggle(currentItem === null || currentItem === void 0 ? void 0 : currentItem.link, keyPaths.length, isOpen);
            onToggleExpand === null || onToggleExpand === void 0 ? void 0 : onToggleExpand(uniq(openKeys));
        }
    };
    Menu.prototype.handleToggleExpand = function (ctx) {
        var navigations = this.state.navigations;
        var _a = this.props, onToggleExpand = _a.onToggleExpand, stacked = _a.stacked, mode = _a.mode, collapsed = _a.collapsed, accordion = _a.accordion, onToggle = _a.onToggle;
        var disabled = ctx.disabled, eventKey = ctx.eventKey, isOpen = ctx.isOpen, isSubMenu = ctx.isSubMenu;
        var openKeys = this.state.openKeys.concat();
        var isVericalInline = stacked && mode === 'inline' && !collapsed;
        var keyPaths = this.getKeyPaths(navigations, eventKey);
        if (isSubMenu && !disabled) {
            // isOpen是当前菜单的展开状态
            if (isOpen) {
                openKeys = openKeys.filter(function (key) { return key !== eventKey; });
            }
            else {
                // 手风琴模式 仅展开
                if (isVericalInline && accordion) {
                    openKeys = __spreadArray(__spreadArray([], __read(keyPaths), false), [eventKey], false);
                }
                else {
                    openKeys.push(eventKey);
                }
            }
            var currentItem = findTree(navigations, function (item) { return item.id === eventKey; });
            // 因为Nav里只处理当前菜单项 因此新增一个onToggle事件
            onToggle === null || onToggle === void 0 ? void 0 : onToggle((currentItem === null || currentItem === void 0 ? void 0 : currentItem.link) || currentItem, keyPaths.length, isOpen);
            onToggleExpand === null || onToggleExpand === void 0 ? void 0 : onToggleExpand(uniq(openKeys));
        }
    };
    Menu.prototype.renderExpandIcon = function (ctx) {
        var _this = this;
        var _a;
        var navigations = this.state.navigations;
        var _b = this.props, cx = _b.classnames, expandIcon = _b.expandIcon, testIdBuilder = _b.testIdBuilder;
        var link = findTree(navigations, function (item) { return item.id === ctx.eventKey; });
        return (React__default.createElement("span", __assign({ key: "expand-toggle", className: cx('Nav-Menu-submenu-arrow'), onClick: function (e) {
                _this.handleToggleExpand(ctx);
                e.preventDefault();
            } }, testIdBuilder === null || testIdBuilder === void 0 ? void 0 : testIdBuilder.getChild(((_a = link === null || link === void 0 ? void 0 : link.link) === null || _a === void 0 ? void 0 : _a.testid) || ctx.eventKey).getChild('expand-toggle').getTestId()), !React__default.isValidElement(expandIcon) ? (React__default.createElement(Icon, { icon: typeof expandIcon === 'string' ? expandIcon : 'right-arrow-bold', className: "icon" })) : (expandIcon)));
    };
    Menu.prototype.renderMenuContent = function (list, level, mode) {
        var _this = this;
        var _a = this.props, renderLink = _a.renderLink, cx = _a.classnames, themeColor = _a.themeColor, disabled = _a.disabled, badge = _a.badge, data = _a.data, isActive = _a.isActive, collapsed = _a.collapsed, overflowedIndicator = _a.overflowedIndicator, overflowMaxCount = _a.overflowMaxCount, popupClassName = _a.popupClassName, testIdBuilder = _a.testIdBuilder;
        return list.map(function (item, index) {
            var _a;
            // 如果这一级是分组标题 那么level不递增
            // 如果这一层第一个就是分组标题 那么收起状态下 不展示分割线
            if (item.mode && item.mode === 'group') {
                return (React__default.createElement(ItemGroup, { key: item.id, title: collapsed ? '' : item.label, className: item.className },
                    collapsed && index > 0 ? (React__default.createElement(Divider, { key: 'group-divider' + item.id })) : null,
                    _this.renderMenuContent(item.children || [], item.depth)));
            }
            var itemDisabled = disabled || item.disabled;
            var link = item.link;
            if ((link && link.defer && !link.loaded) ||
                (item.children && item.children.length)) {
                return (React__default.createElement(SubMenu, __assign({}, item, { key: item.id, disabled: itemDisabled || link.loading, active: isActive(item), badge: badge, renderLink: renderLink, depth: level || 1, testIdBuilder: testIdBuilder === null || testIdBuilder === void 0 ? void 0 : testIdBuilder.getChild(link.testid || index), popupClassName: popupClassName }), mode === 'panel' ? (React__default.createElement(PanelMenu, __assign({}, item, { data: data }))) : (_this.renderMenuContent(item.children || [], item.depth + 1))));
            }
            return item.mode === 'divider' ? (React__default.createElement(Divider, { key: item.id, className: cx("Nav-Menu-item-divider", (_a = {},
                    _a['Nav-Menu-item-divider-dark'] = themeColor === 'dark',
                    _a)) })) : (React__default.createElement(MenuItem, __assign({}, item, { key: item.id, disabled: itemDisabled, renderLink: renderLink, badge: badge, data: data, testIdBuilder: testIdBuilder === null || testIdBuilder === void 0 ? void 0 : testIdBuilder.getChild(link.testid || index), depth: level || 1, order: index, overflowedIndicator: overflowedIndicator, overflowMaxCount: overflowMaxCount })));
        });
    };
    Menu.prototype.render = function () {
        var _a;
        var _b;
        var _c = this.props, classPrefix = _c.classPrefix, cx = _c.classnames, collapsed = _c.collapsed, themeColor = _c.themeColor, stacked = _c.stacked, mode = _c.mode, accordion = _c.accordion, prefix = _c.prefix, disabled = _c.disabled, draggable = _c.draggable, className = _c.className, triggerSubMenuAction = _c.triggerSubMenuAction, direction = _c.direction, overflowedIndicator = _c.overflowedIndicator, disabledOverflow = _c.disabledOverflow, overflowMaxCount = _c.overflowMaxCount, overflowComponent = _c.overflowComponent, overflowedIndicatorPopupClassName = _c.overflowedIndicatorPopupClassName, overflowSuffix = _c.overflowSuffix, overflowItemWidth = _c.overflowItemWidth, overflowStyle = _c.overflowStyle, popOverContainer = _c.popOverContainer, inlineIndent = _c.inlineIndent, expandBefore = _c.expandBefore, onDragStart = _c.onDragStart;
        var _d = this.state, navigations = _d.navigations, activeKey = _d.activeKey, defaultOpenKeys = _d.defaultOpenKeys, openKeys = _d.openKeys;
        var isDarkTheme = themeColor === 'dark';
        var rcMode = stacked
            ? mode === 'float' || mode === 'panel'
                ? 'vertical-left'
                : 'vertical'
            : 'horizontal';
        var disableOpen = collapsed ||
            !stacked ||
            (stacked && (mode === 'float' || mode === 'panel'));
        return (React__default.createElement(MenuContext.Provider, { value: {
                themeColor: themeColor,
                stacked: stacked,
                mode: mode,
                collapsed: collapsed,
                direction: direction,
                prefix: prefix,
                inlineIndent: inlineIndent,
                accordion: accordion,
                draggable: draggable,
                onDragStart: onDragStart,
                onSubmenuClick: this.handleSubMenuTitleClick,
                onPanelMenuClick: this.handlePanelMenuClick
            } },
            React__default.createElement(RcMenu, { key: "menu", prefixCls: "".concat(classPrefix, "Nav-Menu"), className: cx("Nav-Menu-".concat(direction), className, (_a = {},
                    _a['Nav-Menu-collapsed'] = stacked && collapsed,
                    _a['Nav-Menu-dark'] = isDarkTheme,
                    _a['Nav-Menu-light'] = !isDarkTheme,
                    _a['Nav-Menu-disabled'] = disabled,
                    _a['Nav-Menu-expand-before'] = stacked && mode === 'inline' && !collapsed && expandBefore,
                    _a)), direction: direction, 
                // @ts-ignore
                // horizontal inline vertical-right
                mode: stacked && mode === 'inline' && !collapsed ? 'inline' : rcMode, inlineIndent: inlineIndent, triggerSubMenuAction: triggerSubMenuAction, expandIcon: this.renderExpandIcon, getPopupContainer: popOverContainer, overflowedIndicator: React__default.isValidElement(overflowedIndicator) ? (React__default.cloneElement(overflowedIndicator, {
                    className: cx('Nav-Menu-item-icon Nav-Menu-overflowedIcon', (_b = overflowedIndicator.props) === null || _b === void 0 ? void 0 : _b.className)
                })) : (React__default.createElement("i", { className: cx('Nav-Menu-item-icon Nav-Menu-overflowedIcon', 'fa fa-ellipsis-h') })), 
                // RcMenu没有暴露这个属性 但实际可以覆盖
                // @ts-ignore
                maxCount: stacked || disabledOverflow
                    ? INVALIDATE
                    : overflowMaxCount || RESPONSIVE, component: overflowComponent || 'ul', style: overflowStyle, overflowedIndicatorPopupClassName: overflowedIndicatorPopupClassName, suffix: overflowSuffix ? overflowSuffix : null, itemWidth: overflowItemWidth ? overflowItemWidth : null, selectedKeys: activeKey != null ? activeKey : [], defaultOpenKeys: disableOpen ? undefined : defaultOpenKeys, openKeys: disableOpen ? undefined : openKeys, onClick: this.handleItemClick }, this.renderMenuContent(navigations, 0, mode))));
    };
    Menu.defaultProps = {
        collapsed: false,
        themeColor: 'light',
        stacked: true,
        mode: 'inline',
        direction: 'ltr',
        prefix: '',
        triggerSubMenuAction: 'hover',
        inlineIndent: 15,
        popOverContainer: function () { return document.body; },
        renderLink: function (link) {
            return { pathname: link.path };
        },
        isActive: function (link, prefix) {
            var path = link.path;
            var ret = location.pathname === path;
            return !!ret;
        },
        isOpen: function (item) {
            return item.children ? item.children.some(function (item) { return item.open; }) : false;
        }
    };
    __decorate([
        autobind,
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [Object]),
        __metadata("design:returntype", Promise)
    ], Menu.prototype, "handleItemClick", null);
    __decorate([
        autobind,
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [Object]),
        __metadata("design:returntype", void 0)
    ], Menu.prototype, "handleSubMenuTitleClick", null);
    __decorate([
        autobind,
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [Object]),
        __metadata("design:returntype", void 0)
    ], Menu.prototype, "handlePanelMenuClick", null);
    __decorate([
        autobind,
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [Object]),
        __metadata("design:returntype", void 0)
    ], Menu.prototype, "handleToggleExpand", null);
    __decorate([
        autobind,
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [Object]),
        __metadata("design:returntype", void 0)
    ], Menu.prototype, "renderExpandIcon", null);
    return Menu;
}(React__default.Component));
var Menu$1 = themeable(Menu);

export { Menu, Menu$1 as default };
