@ant-design/pro-layout
Version:
372 lines (315 loc) • 12.9 kB
JavaScript
import "antd/es/menu/style";
import _Menu from "antd/es/menu";
import _extends from "@babel/runtime/helpers/esm/extends";
import "antd/es/skeleton/style";
import _Skeleton from "antd/es/skeleton";
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
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 './index.less';
import Icon, { createFromIconfontCN } from '@ant-design/icons';
import React, { useEffect, useState, useRef, useMemo } from 'react';
import classNames from 'classnames';
import { isUrl, isImg, useMountMergeState } from '@ant-design/pro-utils';
import defaultSettings from '../../defaultSettings';
import { getOpenKeysFromMenuData } from '../../utils/utils';
import MenuCounter from './Counter';
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-';
if (typeof icon === 'string' && icon !== '') {
if (isUrl(icon) || isImg(icon)) {
return /*#__PURE__*/React.createElement(Icon, {
component: function component() {
return /*#__PURE__*/React.createElement("img", {
src: icon,
alt: "icon",
className: "ant-pro-sider-menu-icon"
});
}
});
}
if (icon.startsWith(iconPrefixes)) {
return /*#__PURE__*/React.createElement(IconFont, {
type: icon
});
}
}
return icon;
};
var MenuUtil = /*#__PURE__*/_createClass(function MenuUtil(props) {
var _this = this;
_classCallCheck(this, MenuUtil);
this.props = void 0;
this.getNavMenuItems = function () {
var menusData = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var isChildren = arguments.length > 1 ? arguments[1] : undefined;
return menusData.map(function (item) {
return _this.getSubMenuOrItem(item, isChildren);
}).filter(function (item) {
return item;
});
};
this.getSubMenuOrItem = function (item, isChildren) {
var children = (item === null || item === void 0 ? void 0 : item.children) || (item === null || item === void 0 ? void 0 : item.routes);
if (Array.isArray(children) && children.length > 0) {
var name = _this.getIntlName(item);
var _this$props = _this.props,
subMenuItemRender = _this$props.subMenuItemRender,
prefixCls = _this$props.prefixCls,
menu = _this$props.menu,
iconPrefixes = _this$props.iconPrefixes; // get defaultTitle by menuItemRender
var defaultTitle = item.icon ? /*#__PURE__*/React.createElement("span", {
className: "".concat(prefixCls, "-menu-item"),
title: name
}, !isChildren && getIcon(item.icon, iconPrefixes), /*#__PURE__*/React.createElement("span", {
className: "".concat(prefixCls, "-menu-item-title")
}, name)) : /*#__PURE__*/React.createElement("span", {
className: "".concat(prefixCls, "-menu-item"),
title: name
}, name); // subMenu only title render
var title = subMenuItemRender ? subMenuItemRender(_objectSpread(_objectSpread({}, item), {}, {
isUrl: false
}), defaultTitle) : defaultTitle;
return {
type: (menu === null || menu === void 0 ? void 0 : menu.type) === 'group' ? 'group' : undefined,
label: title,
children: _this.getNavMenuItems(children, true),
onTitleClick: item.onTitleClick,
key: item.key || item.path
};
}
return {
label: _this.getMenuItemPath(item, isChildren),
title: _this.getIntlName(item),
key: item.key || item.path,
disabled: item.disabled,
onClick: function onClick(e) {
var _item$onTitleClick;
if (isUrl(item === null || item === void 0 ? void 0 : item.path)) {
window.open(item.path);
}
(_item$onTitleClick = item.onTitleClick) === null || _item$onTitleClick === void 0 ? void 0 : _item$onTitleClick.call(item, e);
}
};
};
this.getIntlName = function (item) {
var name = item.name,
locale = item.locale;
var _this$props2 = _this.props,
menu = _this$props2.menu,
formatMessage = _this$props2.formatMessage;
if (locale && (menu === null || menu === void 0 ? void 0 : menu.locale) !== false) {
return formatMessage === null || formatMessage === void 0 ? void 0 : formatMessage({
id: locale,
defaultMessage: name
});
}
return name;
};
this.getMenuItemPath = function (item, isChildren) {
var itemPath = _this.conversionPath(item.path || '/');
var _this$props3 = _this.props,
_this$props3$location = _this$props3.location,
location = _this$props3$location === void 0 ? {
pathname: '/'
} : _this$props3$location,
isMobile = _this$props3.isMobile,
onCollapse = _this$props3.onCollapse,
menuItemRender = _this$props3.menuItemRender,
iconPrefixes = _this$props3.iconPrefixes; // if local is true formatMessage all name。
var name = _this.getIntlName(item);
var prefixCls = _this.props.prefixCls;
var icon = isChildren ? null : getIcon(item.icon, iconPrefixes);
var isHttpUrl = isUrl(itemPath);
var defaultItem = /*#__PURE__*/React.createElement("span", {
className: classNames("".concat(prefixCls, "-menu-item"), _defineProperty({}, "".concat(prefixCls, "-menu-item-link"), isHttpUrl))
}, icon, /*#__PURE__*/React.createElement("span", {
className: "".concat(prefixCls, "-menu-item-title")
}, name));
if (menuItemRender) {
var renderItemProps = _objectSpread(_objectSpread({}, item), {}, {
isUrl: isHttpUrl,
itemPath: itemPath,
isMobile: isMobile,
replace: itemPath === location.pathname,
onClick: function onClick() {
if (isHttpUrl) window.open(itemPath);
if (onCollapse) onCollapse(true);
},
children: undefined
});
return menuItemRender(renderItemProps, defaultItem, _this.props);
}
return defaultItem;
};
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 theme = props.theme,
mode = props.mode,
className = props.className,
handleOpenChange = props.handleOpenChange,
style = props.style,
menuData = props.menuData,
menu = props.menu,
matchMenuKeys = props.matchMenuKeys,
iconfontUrl = props.iconfontUrl,
collapsed = props.collapsed,
propsSelectedKeys = props.selectedKeys,
onSelect = props.onSelect,
propsOpenKeys = props.openKeys; // 用于减少 defaultOpenKeys 计算的组件
var defaultOpenKeysRef = useRef([]);
var _MenuCounter$useConta = MenuCounter.useContainer(),
flatMenuKeys = _MenuCounter$useConta.flatMenuKeys;
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 ? 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 ? void 0 : menu.defaultOpenAll) || propsOpenKeys === false || flatMenuKeys.length) {
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 ? void 0 : menu.ignoreFlatMenu) && defaultOpenAll) {
// 忽略用户手动折叠过的菜单状态,折叠按钮切换之后也可实现默认展开所有菜单
setOpenKeys(getOpenKeysFromMenuData(menuData));
} else if (flatMenuKeys.length > 0) setDefaultOpenAll(false); // eslint-disable-next-line react-hooks/exhaustive-deps
}, [matchMenuKeys.join('-'), collapsed]);
var openKeysProps = useMemo(function () {
return getOpenKeysProps(openKeys, props);
}, // eslint-disable-next-line react-hooks/exhaustive-deps
[openKeys && openKeys.join(','), props.layout, props.collapsed]);
var _useState = useState(function () {
return new MenuUtil(props);
}),
_useState2 = _slicedToArray(_useState, 1),
menuUtils = _useState2[0];
if (menu === null || menu === void 0 ? void 0 : menu.loading) {
return /*#__PURE__*/React.createElement("div", {
style: (mode === null || mode === void 0 ? void 0 : mode.includes('inline')) ? {
padding: 24
} : {
marginTop: 16
}
}, /*#__PURE__*/React.createElement(_Skeleton, {
active: true,
title: false,
paragraph: {
rows: (mode === null || mode === void 0 ? void 0 : mode.includes('inline')) ? 6 : 1
}
}));
}
var cls = classNames(className, {
'top-nav-menu': mode === 'horizontal'
}); // sync props
menuUtils.props = props; // 这次 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 /*#__PURE__*/React.createElement(_Menu, _extends({}, openKeysProps, {
key: "Menu",
mode: mode,
items: menuUtils.getNavMenuItems(finallyData, false),
inlineIndent: 16,
defaultOpenKeys: defaultOpenKeysRef.current,
theme: theme,
selectedKeys: selectedKeys,
style: style,
className: cls,
onOpenChange: setOpenKeys
}, props.menuProps));
};
BaseMenu.defaultProps = {
postMenuData: function postMenuData(data) {
return data || [];
}
};
export default BaseMenu;