UNPKG

@ant-design/pro-layout

Version:
372 lines (315 loc) 12.9 kB
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;