@ant-design/pro-layout
Version:
468 lines (459 loc) • 21.8 kB
JavaScript
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
import _createClass from "@babel/runtime/helpers/esm/createClass";
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import { createFromIconfontCN } from '@ant-design/icons';
import { ProProvider } from '@ant-design/pro-provider';
import { isImg, isUrl, useMountMergeState } from '@ant-design/pro-utils';
import { Menu, Skeleton, Tooltip } from 'antd';
import classNames from 'classnames';
import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
import { defaultSettings } from "../../defaultSettings";
import { getOpenKeysFromMenuData } from "../../utils/utils";
import { useStyle } from "./style/menu";
// todo
import { jsx as _jsx } from "react/jsx-runtime";
import { jsxs as _jsxs } from "react/jsx-runtime";
import { createElement as _createElement } from "react";
var MenuItemTooltip = function MenuItemTooltip(props) {
var _useState = useState(props.collapsed),
_useState2 = _slicedToArray(_useState, 2),
collapsed = _useState2[0],
setCollapsed = _useState2[1];
var _useState3 = useState(false),
_useState4 = _slicedToArray(_useState3, 2),
open = _useState4[0],
setOpen = _useState4[1];
useEffect(function () {
setOpen(false);
setTimeout(function () {
setCollapsed(props.collapsed);
}, 400);
}, [props.collapsed]);
if (props.disable) {
return props.children;
}
return /*#__PURE__*/_jsx(Tooltip, {
title: props.title,
open: collapsed && props.collapsed ? open : false,
placement: "right",
onOpenChange: setOpen,
children: props.children
});
};
var IconFont = createFromIconfontCN({
scriptUrl: defaultSettings.iconfontUrl
});
// Allow menu.js config icon as string or ReactNode
// icon: 'setting',
// icon: 'icon-geren' #For Iconfont ,
// icon: 'http://demo.com/icon.png',
// icon: '/favicon.png',
// icon: <Icon type="setting" />,
var getIcon = function getIcon(icon) {
var iconPrefixes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'icon-';
var className = arguments.length > 2 ? arguments[2] : undefined;
if (typeof icon === 'string' && icon !== '') {
if (isUrl(icon) || isImg(icon)) {
return /*#__PURE__*/_jsx("img", {
width: 16,
src: icon,
alt: "icon",
className: className
}, icon);
}
if (icon.startsWith(iconPrefixes)) {
return /*#__PURE__*/_jsx(IconFont, {
type: icon
});
}
}
return icon;
};
var getMenuTitleSymbol = function getMenuTitleSymbol(title) {
if (title && typeof title === 'string') {
var symbol = title.substring(0, 1).toUpperCase();
return symbol;
}
return null;
};
var MenuUtil = /*#__PURE__*/_createClass(function MenuUtil(props) {
var _this = this;
_classCallCheck(this, MenuUtil);
_defineProperty(this, "props", void 0);
_defineProperty(this, "getNavMenuItems", function () {
var menusData = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var level = arguments.length > 1 ? arguments[1] : undefined;
var noGroupLevel = arguments.length > 2 ? arguments[2] : undefined;
return menusData.map(function (item) {
return _this.getSubMenuOrItem(item, level, noGroupLevel);
}).filter(function (item) {
return item;
}).flat(1);
});
/** Get SubMenu or Item */
_defineProperty(this, "getSubMenuOrItem", function (item, level, noGroupLevel) {
var _this$props = _this.props,
subMenuItemRender = _this$props.subMenuItemRender,
baseClassName = _this$props.baseClassName,
prefixCls = _this$props.prefixCls,
collapsed = _this$props.collapsed,
menu = _this$props.menu,
iconPrefixes = _this$props.iconPrefixes,
layout = _this$props.layout;
var isGroup = (menu === null || menu === void 0 ? void 0 : menu.type) === 'group' && layout !== 'top';
var designToken = _this.props.token;
var name = _this.getIntlName(item);
var children = (item === null || item === void 0 ? void 0 : item.children) || (item === null || item === void 0 ? void 0 : item.routes);
var menuType = isGroup && level === 0 ? 'group' : undefined;
if (Array.isArray(children) && children.length > 0) {
var _this$props2, _this$props3, _this$props4, _this$props5, _designToken$layout;
/** Menu 第一级可以有icon,或者 isGroup 时第二级别也要有 */
var shouldHasIcon = level === 0 || isGroup && level === 1;
// get defaultTitle by menuItemRender
var iconDom = getIcon(item.icon, iconPrefixes, "".concat(baseClassName, "-icon ").concat((_this$props2 = _this.props) === null || _this$props2 === void 0 ? void 0 : _this$props2.hashId));
/**
* 如果没有icon在收起的时候用首字母代替
*/
var defaultIcon = collapsed && shouldHasIcon ? getMenuTitleSymbol(name) : null;
var defaultTitle = /*#__PURE__*/_jsxs("div", {
className: classNames("".concat(baseClassName, "-item-title"), (_this$props3 = _this.props) === null || _this$props3 === void 0 ? void 0 : _this$props3.hashId, _defineProperty(_defineProperty(_defineProperty(_defineProperty({}, "".concat(baseClassName, "-item-title-collapsed"), collapsed), "".concat(baseClassName, "-item-title-collapsed-level-").concat(noGroupLevel), collapsed), "".concat(baseClassName, "-group-item-title"), menuType === 'group'), "".concat(baseClassName, "-item-collapsed-show-title"), (menu === null || menu === void 0 ? void 0 : menu.collapsedShowTitle) && collapsed)),
children: [menuType === 'group' && collapsed ? null : shouldHasIcon && iconDom ? /*#__PURE__*/_jsx("span", {
className: "".concat(baseClassName, "-item-icon ").concat((_this$props4 = _this.props) === null || _this$props4 === void 0 ? void 0 : _this$props4.hashId).trim(),
children: iconDom
}) : defaultIcon, /*#__PURE__*/_jsx("span", {
className: classNames("".concat(baseClassName, "-item-text"), (_this$props5 = _this.props) === null || _this$props5 === void 0 ? void 0 : _this$props5.hashId, _defineProperty({}, "".concat(baseClassName, "-item-text-has-icon"), menuType !== 'group' && shouldHasIcon && (iconDom || defaultIcon))),
children: name
})]
});
// subMenu only title render
var title = subMenuItemRender ? subMenuItemRender(_objectSpread(_objectSpread({}, item), {}, {
isUrl: false
}), defaultTitle, _this.props) : defaultTitle;
// 如果收起来,没有子菜单了,就不需要展示 group,所以 level 不增加
if (isGroup && level === 0 && _this.props.collapsed && !menu.collapsedShowGroupTitle) {
return _this.getNavMenuItems(children, level + 1, level);
}
var childrenList = _this.getNavMenuItems(children, level + 1, isGroup && level === 0 && _this.props.collapsed ? level : level + 1);
return [{
type: menuType,
key: item.key || item.path,
label: title,
onClick: isGroup ? undefined : item.onTitleClick,
children: childrenList,
className: classNames(_defineProperty(_defineProperty(_defineProperty({}, "".concat(baseClassName, "-group"), menuType === 'group'), "".concat(baseClassName, "-submenu"), menuType !== 'group'), "".concat(baseClassName, "-submenu-has-icon"), menuType !== 'group' && shouldHasIcon && iconDom))
}, isGroup && level === 0 ? {
type: 'divider',
prefixCls: prefixCls,
className: "".concat(baseClassName, "-divider"),
key: (item.key || item.path) + '-group-divider',
style: {
padding: 0,
borderBlockEnd: 0,
margin: _this.props.collapsed ? '4px' : '6px 16px',
marginBlockStart: _this.props.collapsed ? 4 : 8,
borderColor: designToken === null || designToken === void 0 || (_designToken$layout = designToken.layout) === null || _designToken$layout === void 0 || (_designToken$layout = _designToken$layout.sider) === null || _designToken$layout === void 0 ? void 0 : _designToken$layout.colorMenuItemDivider
}
} : undefined].filter(Boolean);
}
return {
className: "".concat(baseClassName, "-menu-item"),
disabled: item.disabled,
key: item.key || item.path,
onClick: item.onTitleClick,
// eslint-disable-next-line react/no-is-mounted
label: _this.getMenuItemPath(item, level, noGroupLevel)
};
});
_defineProperty(this, "getIntlName", function (item) {
var name = item.name,
locale = item.locale;
var _this$props6 = _this.props,
menu = _this$props6.menu,
formatMessage = _this$props6.formatMessage;
var finalName = name;
if (locale && (menu === null || menu === void 0 ? void 0 : menu.locale) !== false) {
finalName = formatMessage === null || formatMessage === void 0 ? void 0 : formatMessage({
id: locale,
defaultMessage: name
});
}
if (_this.props.menuTextRender) {
return _this.props.menuTextRender(item, finalName, _this.props);
}
return finalName;
});
/**
* 判断是否是http链接.返回 Link 或 a Judge whether it is http link.return a or Link
*
* @memberof SiderMenu
*/
_defineProperty(this, "getMenuItemPath", function (item, level, noGroupLevel) {
var _this$props9, _this$props10, _this$props11, _this$props12;
var itemPath = _this.conversionPath(item.path || '/');
var _this$props7 = _this.props,
_this$props7$location = _this$props7.location,
location = _this$props7$location === void 0 ? {
pathname: '/'
} : _this$props7$location,
isMobile = _this$props7.isMobile,
onCollapse = _this$props7.onCollapse,
menuItemRender = _this$props7.menuItemRender,
iconPrefixes = _this$props7.iconPrefixes;
// if local is true formatMessage all name。
var menuItemTitle = _this.getIntlName(item);
var _this$props8 = _this.props,
baseClassName = _this$props8.baseClassName,
menu = _this$props8.menu,
collapsed = _this$props8.collapsed;
var isGroup = (menu === null || menu === void 0 ? void 0 : menu.type) === 'group';
/** Menu 第一级可以有icon,或者 isGroup 时第二级别也要有 */
var hasIcon = level === 0 || isGroup && level === 1;
var icon = !hasIcon ? null : getIcon(item.icon, iconPrefixes, "".concat(baseClassName, "-icon ").concat((_this$props9 = _this.props) === null || _this$props9 === void 0 ? void 0 : _this$props9.hashId));
// 如果没有 icon 在收起的时候用首字母代替
var defaultIcon = collapsed && hasIcon ? getMenuTitleSymbol(menuItemTitle) : null;
var defaultItem = /*#__PURE__*/_jsxs("div", {
className: classNames("".concat(baseClassName, "-item-title"), (_this$props10 = _this.props) === null || _this$props10 === void 0 ? void 0 : _this$props10.hashId, _defineProperty(_defineProperty(_defineProperty({}, "".concat(baseClassName, "-item-title-collapsed"), collapsed), "".concat(baseClassName, "-item-title-collapsed-level-").concat(noGroupLevel), collapsed), "".concat(baseClassName, "-item-collapsed-show-title"), (menu === null || menu === void 0 ? void 0 : menu.collapsedShowTitle) && collapsed)),
children: [/*#__PURE__*/_jsx("span", {
className: "".concat(baseClassName, "-item-icon ").concat((_this$props11 = _this.props) === null || _this$props11 === void 0 ? void 0 : _this$props11.hashId).trim(),
style: {
display: defaultIcon === null && !icon ? 'none' : ''
},
children: icon || /*#__PURE__*/_jsx("span", {
className: "anticon",
children: defaultIcon
})
}), /*#__PURE__*/_jsx("span", {
className: classNames("".concat(baseClassName, "-item-text"), (_this$props12 = _this.props) === null || _this$props12 === void 0 ? void 0 : _this$props12.hashId, _defineProperty({}, "".concat(baseClassName, "-item-text-has-icon"), hasIcon && (icon || defaultIcon))),
children: menuItemTitle
})]
}, itemPath);
var isHttpUrl = isUrl(itemPath);
// Is it a http link
if (isHttpUrl) {
var _this$props13, _this$props14, _this$props15;
defaultItem = /*#__PURE__*/_jsxs("span", {
onClick: function onClick() {
var _window, _window$open;
(_window = window) === null || _window === void 0 || (_window$open = _window.open) === null || _window$open === void 0 || _window$open.call(_window, itemPath, '_blank');
},
className: classNames("".concat(baseClassName, "-item-title"), (_this$props13 = _this.props) === null || _this$props13 === void 0 ? void 0 : _this$props13.hashId, _defineProperty(_defineProperty(_defineProperty(_defineProperty({}, "".concat(baseClassName, "-item-title-collapsed"), collapsed), "".concat(baseClassName, "-item-title-collapsed-level-").concat(noGroupLevel), collapsed), "".concat(baseClassName, "-item-link"), true), "".concat(baseClassName, "-item-collapsed-show-title"), (menu === null || menu === void 0 ? void 0 : menu.collapsedShowTitle) && collapsed)),
children: [/*#__PURE__*/_jsx("span", {
className: "".concat(baseClassName, "-item-icon ").concat((_this$props14 = _this.props) === null || _this$props14 === void 0 ? void 0 : _this$props14.hashId).trim(),
style: {
display: defaultIcon === null && !icon ? 'none' : ''
},
children: icon || /*#__PURE__*/_jsx("span", {
className: "anticon",
children: defaultIcon
})
}), /*#__PURE__*/_jsx("span", {
className: classNames("".concat(baseClassName, "-item-text"), (_this$props15 = _this.props) === null || _this$props15 === void 0 ? void 0 : _this$props15.hashId, _defineProperty({}, "".concat(baseClassName, "-item-text-has-icon"), hasIcon && (icon || defaultIcon))),
children: menuItemTitle
})]
}, itemPath);
}
if (menuItemRender) {
var renderItemProps = _objectSpread(_objectSpread({}, item), {}, {
isUrl: isHttpUrl,
itemPath: itemPath,
isMobile: isMobile,
replace: itemPath === location.pathname,
onClick: function onClick() {
return onCollapse && onCollapse(true);
},
children: undefined
});
return level === 0 ? /*#__PURE__*/_jsx(MenuItemTooltip, {
collapsed: collapsed,
title: menuItemTitle,
disable: item.disabledTooltip,
children: menuItemRender(renderItemProps, defaultItem, _this.props)
}) : menuItemRender(renderItemProps, defaultItem, _this.props);
}
return level === 0 ? /*#__PURE__*/_jsx(MenuItemTooltip, {
collapsed: collapsed,
title: menuItemTitle,
disable: item.disabledTooltip,
children: defaultItem
}) : defaultItem;
});
_defineProperty(this, "conversionPath", function (path) {
if (path && path.indexOf('http') === 0) {
return path;
}
return "/".concat(path || '').replace(/\/+/g, '/');
});
this.props = props;
});
/**
* 生成openKeys 的对象,因为设置了openKeys 就会变成受控,所以需要一个空对象
*
* @param BaseMenuProps
*/
var getOpenKeysProps = function getOpenKeysProps(openKeys, _ref) {
var layout = _ref.layout,
collapsed = _ref.collapsed;
var openKeysProps = {};
if (openKeys && !collapsed && ['side', 'mix'].includes(layout || 'mix')) {
openKeysProps = {
openKeys: openKeys
};
}
return openKeysProps;
};
var BaseMenu = function BaseMenu(props) {
var mode = props.mode,
className = props.className,
handleOpenChange = props.handleOpenChange,
style = props.style,
menuData = props.menuData,
prefixCls = props.prefixCls,
menu = props.menu,
matchMenuKeys = props.matchMenuKeys,
iconfontUrl = props.iconfontUrl,
propsSelectedKeys = props.selectedKeys,
onSelect = props.onSelect,
menuRenderType = props.menuRenderType,
propsOpenKeys = props.openKeys;
var _useContext = useContext(ProProvider),
dark = _useContext.dark,
designToken = _useContext.token;
var baseClassName = "".concat(prefixCls, "-base-menu-").concat(mode);
// 用于减少 defaultOpenKeys 计算的组件
var defaultOpenKeysRef = useRef([]);
var _useMountMergeState = useMountMergeState(menu === null || menu === void 0 ? void 0 : menu.defaultOpenAll),
_useMountMergeState2 = _slicedToArray(_useMountMergeState, 2),
defaultOpenAll = _useMountMergeState2[0],
setDefaultOpenAll = _useMountMergeState2[1];
var _useMountMergeState3 = useMountMergeState(function () {
if (menu !== null && menu !== void 0 && menu.defaultOpenAll) {
return getOpenKeysFromMenuData(menuData) || [];
}
if (propsOpenKeys === false) {
return false;
}
return [];
}, {
value: propsOpenKeys === false ? undefined : propsOpenKeys,
onChange: handleOpenChange
}),
_useMountMergeState4 = _slicedToArray(_useMountMergeState3, 2),
openKeys = _useMountMergeState4[0],
setOpenKeys = _useMountMergeState4[1];
var _useMountMergeState5 = useMountMergeState([], {
value: propsSelectedKeys,
onChange: onSelect ? function (keys) {
if (onSelect && keys) {
onSelect(keys);
}
} : undefined
}),
_useMountMergeState6 = _slicedToArray(_useMountMergeState5, 2),
selectedKeys = _useMountMergeState6[0],
setSelectedKeys = _useMountMergeState6[1];
useEffect(function () {
if (menu !== null && menu !== void 0 && menu.defaultOpenAll || propsOpenKeys === false) {
return;
}
if (matchMenuKeys) {
setOpenKeys(matchMenuKeys);
setSelectedKeys(matchMenuKeys);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [matchMenuKeys.join('-')]);
useEffect(function () {
// reset IconFont
if (iconfontUrl) {
IconFont = createFromIconfontCN({
scriptUrl: iconfontUrl
});
}
}, [iconfontUrl]);
useEffect(function () {
// if pathname can't match, use the nearest parent's key
if (matchMenuKeys.join('-') !== (selectedKeys || []).join('-')) {
setSelectedKeys(matchMenuKeys);
}
if (!defaultOpenAll && propsOpenKeys !== false && matchMenuKeys.join('-') !== (openKeys || []).join('-')) {
var newKeys = matchMenuKeys;
// 如果不自动关闭,我需要把 openKeys 放进去
if ((menu === null || menu === void 0 ? void 0 : menu.autoClose) === false) {
newKeys = Array.from(new Set([].concat(_toConsumableArray(matchMenuKeys), _toConsumableArray(openKeys || []))));
}
setOpenKeys(newKeys);
} else if (menu !== null && menu !== void 0 && menu.ignoreFlatMenu && defaultOpenAll) {
// 忽略用户手动折叠过的菜单状态,折叠按钮切换之后也可实现默认展开所有菜单
setOpenKeys(getOpenKeysFromMenuData(menuData));
} else {
setDefaultOpenAll(false);
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[matchMenuKeys.join('-')]);
var openKeysProps = useMemo(function () {
return getOpenKeysProps(openKeys, props);
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[openKeys && openKeys.join(','), props.layout, props.collapsed]);
var _useStyle = useStyle(baseClassName, mode),
wrapSSR = _useStyle.wrapSSR,
hashId = _useStyle.hashId;
var menuUtils = useMemo(function () {
return new MenuUtil(_objectSpread(_objectSpread({}, props), {}, {
token: designToken,
menuRenderType: menuRenderType,
baseClassName: baseClassName,
hashId: hashId
}));
}, [props, designToken, menuRenderType, baseClassName, hashId]);
if (menu !== null && menu !== void 0 && menu.loading) {
return /*#__PURE__*/_jsx("div", {
style: mode !== null && mode !== void 0 && mode.includes('inline') ? {
padding: 24
} : {
marginBlockStart: 16
},
children: /*#__PURE__*/_jsx(Skeleton, {
active: true,
title: false,
paragraph: {
rows: mode !== null && mode !== void 0 && mode.includes('inline') ? 6 : 1
}
})
});
}
// 这次 openKeys === false 的时候的情况,这种情况下帮用户选中一次
// 第二此不会使用,所以用了 defaultOpenKeys
// 这里返回 null,是为了让 defaultOpenKeys 生效
if (props.openKeys === false && !props.handleOpenChange) {
defaultOpenKeysRef.current = matchMenuKeys;
}
var finallyData = props.postMenuData ? props.postMenuData(menuData) : menuData;
if (finallyData && (finallyData === null || finallyData === void 0 ? void 0 : finallyData.length) < 1) {
return null;
}
return wrapSSR( /*#__PURE__*/_createElement(Menu, _objectSpread(_objectSpread({}, openKeysProps), {}, {
_internalDisableMenuItemTitleTooltip: true,
key: "Menu",
mode: mode,
inlineIndent: 16,
defaultOpenKeys: defaultOpenKeysRef.current,
theme: dark ? 'dark' : 'light',
selectedKeys: selectedKeys,
style: _objectSpread({
backgroundColor: 'transparent',
border: 'none'
}, style),
className: classNames(className, hashId, baseClassName, _defineProperty(_defineProperty({}, "".concat(baseClassName, "-horizontal"), mode === 'horizontal'), "".concat(baseClassName, "-collapsed"), props.collapsed)),
items: menuUtils.getNavMenuItems(finallyData, 0, 0),
onOpenChange: function onOpenChange(_openKeys) {
if (!props.collapsed) {
setOpenKeys(_openKeys);
}
}
}, props.menuProps)));
};
export { BaseMenu };