feat: update menu

pull/1845/head
tangjinzhou 2020-02-21 20:59:02 +08:00
parent c7b0cb0732
commit b85bc0e738
17 changed files with 256 additions and 51 deletions

View File

@ -1,5 +1,5 @@
module.exports = { module.exports = {
dev: { dev: {
componentName: 'list', // dev components componentName: 'menu', // dev components
}, },
}; };

View File

@ -8,8 +8,9 @@ export default {
props: itemProps, props: itemProps,
inject: { inject: {
getInlineCollapsed: { default: () => noop }, getInlineCollapsed: { default: () => noop },
layoutSiderContext: { default: () => ({}) },
}, },
isMenuItem: 1, isMenuItem: true,
methods: { methods: {
onKeyDown(e) { onKeyDown(e) {
this.$refs.menuItem.onKeyDown(e); this.$refs.menuItem.onKeyDown(e);
@ -20,22 +21,28 @@ export default {
const { level, title, rootPrefixCls } = props; const { level, title, rootPrefixCls } = props;
const { getInlineCollapsed, $slots, $attrs: attrs } = this; const { getInlineCollapsed, $slots, $attrs: attrs } = this;
const inlineCollapsed = getInlineCollapsed(); const inlineCollapsed = getInlineCollapsed();
let titleNode; const tooltipProps = {
if (inlineCollapsed) { title: title || (level === 1 ? $slots.default : ''),
titleNode = title || (level === 1 ? $slots.default : ''); };
const siderCollapsed = this.layoutSiderContext.sCollapsed;
if (!siderCollapsed && !inlineCollapsed) {
tooltipProps.title = null;
// Reset `visible` to fix control mode tooltip display not correct
// ref: https://github.com/ant-design/ant-design/issues/16742
tooltipProps.visible = false;
} }
const itemProps = { const itemProps = {
props: { props: {
...props, ...props,
title: inlineCollapsed ? null : title, title,
}, },
attrs, attrs,
on: getListeners(this), on: getListeners(this),
}; };
const toolTipProps = { const toolTipProps = {
props: { props: {
title: titleNode, ...tooltipProps,
placement: 'right', placement: 'right',
overlayClassName: `${rootPrefixCls}-inline-collapsed-tooltip`, overlayClassName: `${rootPrefixCls}-inline-collapsed-tooltip`,
}, },

View File

@ -0,0 +1,42 @@
import { SubMenu as VcSubMenu } from '../vc-menu';
import { getListeners } from '../_util/props-util';
import classNames from 'classnames';
export default {
name: 'ASubMenu',
isSubMenu: true,
props: { ...VcSubMenu.props },
inject: {
menuPropsContext: { default: () => ({}) },
},
methods: {
onKeyDown(e) {
this.$refs.subMenu.onKeyDown(e);
},
},
render() {
const { $slots, $scopedSlots } = this;
const { rootPrefixCls, popupClassName } = this.$props;
const { theme: antdMenuTheme } = this.menuPropsContext;
const props = {
props: {
...this.$props,
popupClassName: classNames(`${rootPrefixCls}-${antdMenuTheme}`, popupClassName),
},
ref: 'subMenu',
on: getListeners(this),
scopedSlots: $scopedSlots,
};
const slotsKey = Object.keys($slots);
return (
<VcSubMenu {...props}>
{slotsKey.length
? slotsKey.map(name => {
return <template slot={name}>{$slots[name]}</template>;
})
: null}
</VcSubMenu>
);
},
};

View File

@ -2,6 +2,7 @@ import { mount } from '@vue/test-utils';
import { asyncExpect } from '@/tests/utils'; import { asyncExpect } from '@/tests/utils';
import Menu from '..'; import Menu from '..';
import Icon from '../../icon'; import Icon from '../../icon';
import mountTest from '../../../tests/shared/mountTest';
jest.mock('mutationobserver-shim', () => { jest.mock('mutationobserver-shim', () => {
global.MutationObserver = function MutationObserver() { global.MutationObserver = function MutationObserver() {
@ -15,6 +16,17 @@ function $$(className) {
return document.body.querySelectorAll(className); return document.body.querySelectorAll(className);
} }
describe('Menu', () => { describe('Menu', () => {
mountTest({
render() {
return (
<Menu>
<Menu.Item />
<Menu.ItemGroup />
<Menu.SubMenu />
</Menu>
);
},
});
beforeEach(() => { beforeEach(() => {
document.body.innerHTML = ''; document.body.innerHTML = '';
// jest.useFakeTimers() // jest.useFakeTimers()

View File

@ -16,9 +16,13 @@ const md = {
导航菜单是一个网站的灵魂用户依赖导航在各个页面中进行跳转一般分为顶部导航和侧边导航顶部导航提供全局性的类目和功能侧边导航提供多级结构来收纳和排列网站架构 导航菜单是一个网站的灵魂用户依赖导航在各个页面中进行跳转一般分为顶部导航和侧边导航顶部导航提供全局性的类目和功能侧边导航提供多级结构来收纳和排列网站架构
## 代码演示`, ## 代码演示`,
us: `# Menu us: `# Menu
Menu list of Navigation. A versatile menu for navigation.
## When To Use ## When To Use
Navigation menu is important for a website, it helps users jump from one site section to another quickly. Mostly, it includes top navigation and side navigation. Top navigation provides all the category and functions of the website. Side navigation provides the Multi-level structure of the website.
Navigation is an important part of any website, as a good navigation setup allows users to move around the site quickly and efficiently. Ant Design offers top and side navigation options. Top navigation provides all the categories and functions of the website. Side navigation provides the multi-level structure of the website.
More layouts with navigation: [Layout](/components/layout).
## Examples`, ## Examples`,
}; };
export default { export default {

View File

@ -50,11 +50,12 @@
### Menu.SubMenu ### Menu.SubMenu
| Param | Description | Type | Default value | | Param | Description | Type | Default value | Version |
| -------- | ----------------------------------- | ------------ | ------------- | | -------------- | ----------------------------------- | ------------ | ------------- | ------- |
| disabled | whether sub menu is disabled or not | boolean | false | | popupClassName | Sub-menu class name | string | | 1.5.0 |
| key | unique id of the sub menu | string | | | disabled | whether sub menu is disabled or not | boolean | false | |
| title | title of the sub menu | string\|slot | | | key | Unique ID of the sub menu | string | | |
| title | title of the sub menu | string\|slot | | |
The children of Menu.SubMenu must be `MenuItem` or `SubMenu`. The children of Menu.SubMenu must be `MenuItem` or `SubMenu`.
@ -68,7 +69,7 @@ The children of Menu.SubMenu must be `MenuItem` or `SubMenu`.
| Param | Description | Type | Default value | | Param | Description | Type | Default value |
| -------- | ------------------ | ------------ | ------------- | | -------- | ------------------ | ------------ | ------------- |
| children | sub menu items | MenuItem\[] | | | children | sub-menu items | MenuItem\[] | |
| title | title of the group | string\|slot | | | title | title of the group | string\|slot | |
The children of Menu.ItemGroup must be `MenuItem`. The children of Menu.ItemGroup must be `MenuItem`.

View File

@ -1,14 +1,16 @@
import omit from 'omit.js'; import omit from 'omit.js';
import VcMenu, { Divider, ItemGroup, SubMenu } from '../vc-menu'; import VcMenu, { Divider, ItemGroup } from '../vc-menu';
import SubMenu from './SubMenu';
import PropTypes from '../_util/vue-types'; import PropTypes from '../_util/vue-types';
import animation from '../_util/openAnimation'; import animation from '../_util/openAnimation';
import warning from '../_util/warning'; import warning from '../_util/warning';
import Item from './MenuItem'; import Item from './MenuItem';
import { hasProp, getListeners } from '../_util/props-util'; import { hasProp, getListeners, getOptionProps } from '../_util/props-util';
import BaseMixin from '../_util/BaseMixin'; import BaseMixin from '../_util/BaseMixin';
import commonPropsType from '../vc-menu/commonPropsType'; import commonPropsType from '../vc-menu/commonPropsType';
import { ConfigConsumerProps } from '../config-provider'; import { ConfigConsumerProps } from '../config-provider';
import Base from '../base'; import Base from '../base';
// import raf from '../_util/raf';
export const MenuMode = PropTypes.oneOf([ export const MenuMode = PropTypes.oneOf([
'vertical', 'vertical',
@ -47,6 +49,7 @@ const Menu = {
provide() { provide() {
return { return {
getInlineCollapsed: this.getInlineCollapsed, getInlineCollapsed: this.getInlineCollapsed,
menuPropsContext: this.$props,
}; };
}, },
mixins: [BaseMixin], mixins: [BaseMixin],
@ -58,12 +61,12 @@ const Menu = {
prop: 'selectedKeys', prop: 'selectedKeys',
event: 'selectChange', event: 'selectChange',
}, },
created() {
this.preProps = { ...this.$props };
},
updated() { updated() {
this.propsUpdating = false; this.propsUpdating = false;
}, },
// beforeDestroy() {
// raf.cancel(this.mountRafId);
// },
watch: { watch: {
mode(val, oldVal) { mode(val, oldVal) {
if (oldVal === 'inline' && val !== 'inline') { if (oldVal === 'inline' && val !== 'inline') {
@ -81,9 +84,10 @@ const Menu = {
}, },
}, },
data() { data() {
const props = this.$props; const props = getOptionProps(this);
warning( warning(
!(hasProp(this, 'inlineCollapsed') && props.mode !== 'inline'), !('inlineCollapsed' in props && props.mode !== 'inline'),
'Menu',
"`inlineCollapsed` should only be used when Menu's `mode` is inline.", "`inlineCollapsed` should only be used when Menu's `mode` is inline.",
); );
this.switchingModeFromInline = false; this.switchingModeFromInline = false;
@ -91,9 +95,9 @@ const Menu = {
this.inlineOpenKeys = []; this.inlineOpenKeys = [];
let sOpenKeys; let sOpenKeys;
if (hasProp(this, 'openKeys')) { if ('openKeys' in props) {
sOpenKeys = props.openKeys; sOpenKeys = props.openKeys;
} else if (hasProp(this, 'defaultOpenKeys')) { } else if ('defaultOpenKeys' in props) {
sOpenKeys = props.defaultOpenKeys; sOpenKeys = props.defaultOpenKeys;
} }
return { return {
@ -137,10 +141,20 @@ const Menu = {
// when inlineCollapsed menu width animation finished // when inlineCollapsed menu width animation finished
// https://github.com/ant-design/ant-design/issues/12864 // https://github.com/ant-design/ant-design/issues/12864
const widthCollapsed = e.propertyName === 'width' && e.target === e.currentTarget; const widthCollapsed = e.propertyName === 'width' && e.target === e.currentTarget;
// Fix SVGElement e.target.className.indexOf is not a function
// https://github.com/ant-design/ant-design/issues/15699
const { className } = e.target;
// SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during an animation.
const classNameValue =
Object.prototype.toString.call(className) === '[object SVGAnimatedString]'
? className.animVal
: className;
// Fix for <Menu style={{ width: '100%' }} />, the width transition won't trigger when menu is collapsed // Fix for <Menu style={{ width: '100%' }} />, the width transition won't trigger when menu is collapsed
// https://github.com/ant-design/ant-design-pro/issues/2783 // https://github.com/ant-design/ant-design-pro/issues/2783
const iconScaled = const iconScaled = e.propertyName === 'font-size' && classNameValue.indexOf('anticon') >= 0;
e.propertyName === 'font-size' && e.target.className.indexOf('anticon') >= 0;
if (widthCollapsed || iconScaled) { if (widthCollapsed || iconScaled) {
this.restoreModeVerticalFromInline(); this.restoreModeVerticalFromInline();
} }
@ -254,11 +268,11 @@ const Menu = {
} }
// https://github.com/ant-design/ant-design/issues/8587 // https://github.com/ant-design/ant-design/issues/8587
if ( const hideMenu =
this.getInlineCollapsed() && this.getInlineCollapsed() &&
(collapsedWidth === 0 || collapsedWidth === '0' || collapsedWidth === '0px') (collapsedWidth === 0 || collapsedWidth === '0' || collapsedWidth === '0px');
) { if (hideMenu) {
return null; menuProps.props.openKeys = [];
} }
return ( return (

View File

@ -49,11 +49,12 @@
### Menu.SubMenu ### Menu.SubMenu
| 参数 | 说明 | 类型 | 默认值 | | 参数 | 说明 | 类型 | 默认值 | 版本 |
| -------- | ---------- | ------------ | ------ | | -------------- | ---------- | ------------ | ------ | ----- |
| disabled | 是否禁用 | boolean | false | | popupClassName | 子菜单样式 | string | | 1.5.0 |
| key | 唯一标志 | string | | | disabled | 是否禁用 | boolean | false | |
| title | 子菜单项值 | string\|slot | | | key | 唯一标志 | string | | |
| title | 子菜单项值 | string\|slot | | |
Menu.SubMenu 的子元素必须是 `MenuItem` 或者 `SubMenu`. Menu.SubMenu 的子元素必须是 `MenuItem` 或者 `SubMenu`.

View File

@ -85,7 +85,7 @@ const DOMWrap = {
this.resizeObserver.disconnect(); this.resizeObserver.disconnect();
} }
if (this.mutationObserver) { if (this.mutationObserver) {
this.resizeObserver.disconnect(); this.mutationObserver.disconnect();
} }
}, },
methods: { methods: {
@ -98,9 +98,9 @@ const DOMWrap = {
} }
// filter out all overflowed indicator placeholder // filter out all overflowed indicator placeholder
return [].slice.call(ul.children).filter(node => { return [].slice
return node.className.split(' ').indexOf(`${prefixCls}-overflowed-submenu`) < 0; .call(ul.children)
}); .filter(node => node.className.split(' ').indexOf(`${prefixCls}-overflowed-submenu`) < 0);
}, },
getOverflowedSubMenuItem(keyPrefix, overflowedItems, renderPlaceholder) { getOverflowedSubMenuItem(keyPrefix, overflowedItems, renderPlaceholder) {
@ -111,10 +111,11 @@ const DOMWrap = {
// put all the overflowed item inside a submenu // put all the overflowed item inside a submenu
// with a title of overflow indicator ('...') // with a title of overflow indicator ('...')
const copy = this.$slots.default[0]; const copy = this.$slots.default[0];
const { title, eventKey, ...rest } = getPropsData(copy); // eslint-disable-line no-unused-vars const { title, ...rest } = getPropsData(copy); // eslint-disable-line no-unused-vars
let style = {}; let style = {};
let key = `${keyPrefix}-overflowed-indicator`; let key = `${keyPrefix}-overflowed-indicator`;
let eventKey = `${keyPrefix}-overflowed-indicator`;
if (overflowedItems.length === 0 && renderPlaceholder !== true) { if (overflowedItems.length === 0 && renderPlaceholder !== true) {
style = { style = {
@ -127,6 +128,7 @@ const DOMWrap = {
position: 'absolute', position: 'absolute',
}; };
key = `${key}-placeholder`; key = `${key}-placeholder`;
eventKey = `${eventKey}-placeholder`;
} }
const popupClassName = theme ? `${prefixCls}-${theme}` : ''; const popupClassName = theme ? `${prefixCls}-${theme}` : '';
@ -141,7 +143,7 @@ const DOMWrap = {
title: overflowedIndicator, title: overflowedIndicator,
popupClassName, popupClassName,
...props, ...props,
eventKey: `${keyPrefix}-overflowed-indicator`, eventKey,
disabled: false, disabled: false,
}, },
class: `${prefixCls}-overflowed-submenu`, class: `${prefixCls}-overflowed-submenu`,
@ -226,7 +228,7 @@ const DOMWrap = {
this.menuItemSizes.forEach(liWidth => { this.menuItemSizes.forEach(liWidth => {
currentSumWidth += liWidth; currentSumWidth += liWidth;
if (currentSumWidth + this.overflowedIndicatorWidth <= width) { if (currentSumWidth + this.overflowedIndicatorWidth <= width) {
lastVisibleIndex++; lastVisibleIndex += 1;
} }
}); });
} }
@ -251,7 +253,7 @@ const DOMWrap = {
{ {
style: { display: 'none' }, style: { display: 'none' },
props: { eventKey: `${eventKey}-hidden` }, props: { eventKey: `${eventKey}-hidden` },
class: { ...getClass(childNode), [MENUITEM_OVERFLOWED_CLASSNAME]: true }, class: MENUITEM_OVERFLOWED_CLASSNAME,
}, },
); );
} }

View File

@ -40,16 +40,22 @@ const MenuItem = {
mixins: [BaseMixin], mixins: [BaseMixin],
isMenuItem: true, isMenuItem: true,
created() { created() {
this.prevActive = this.active;
// invoke customized ref to expose component to mixin // invoke customized ref to expose component to mixin
this.callRef(); this.callRef();
}, },
updated() { updated() {
this.$nextTick(() => { this.$nextTick(() => {
if (this.active) { const { active, parentMenu, eventKey } = this.$props;
if (!this.prevActive && active && (!parentMenu || !parentMenu[`scrolled-${eventKey}`])) {
scrollIntoView(this.$el, this.parentMenu.$el, { scrollIntoView(this.$el, this.parentMenu.$el, {
onlyScrollIfNeeded: true, onlyScrollIfNeeded: true,
}); });
parentMenu[`scrolled-${eventKey}`] = true;
} else if (parentMenu && parentMenu[`scrolled-${eventKey}`]) {
delete parentMenu[`scrolled-${eventKey}`];
} }
this.prevActive = active;
}); });
this.callRef(); this.callRef();
}, },

View File

@ -1,5 +1,6 @@
import PropTypes from '../_util/vue-types'; import PropTypes from '../_util/vue-types';
import { getComponentFromProp, getListeners } from '../_util/props-util'; import { getComponentFromProp, getListeners } from '../_util/props-util';
// import { menuAllProps } from './util' // import { menuAllProps } from './util'
const MenuItemGroup = { const MenuItemGroup = {

View File

@ -10,6 +10,7 @@ import { getComponentFromProp, filterEmpty, getListeners } from '../_util/props-
import { requestAnimationTimeout, cancelAnimationTimeout } from '../_util/requestAnimationTimeout'; import { requestAnimationTimeout, cancelAnimationTimeout } from '../_util/requestAnimationTimeout';
import { noop, loopMenuItemRecursively, getMenuIdFromSubMenuEventKey } from './util'; import { noop, loopMenuItemRecursively, getMenuIdFromSubMenuEventKey } from './util';
import getTransitionProps from '../_util/getTransitionProps'; import getTransitionProps from '../_util/getTransitionProps';
import { MenuItem } from './MenuItem';
let guid = 0; let guid = 0;
@ -171,6 +172,7 @@ const SubMenu = {
if (isOpen && (keyCode === KeyCode.UP || keyCode === KeyCode.DOWN)) { if (isOpen && (keyCode === KeyCode.UP || keyCode === KeyCode.DOWN)) {
return menu.onKeyDown(e); return menu.onKeyDown(e);
} }
return undefined;
}, },
onPopupVisibleChange(visible) { onPopupVisibleChange(visible) {
@ -368,7 +370,7 @@ const SubMenu = {
deselect, deselect,
openChange, openChange,
}, },
id: this._menuId, id: this.internalMenuId,
}; };
const baseProps = subPopupMenuProps.props; const baseProps = subPopupMenuProps.props;
const haveRendered = this.haveRendered; const haveRendered = this.haveRendered;
@ -429,11 +431,11 @@ const SubMenu = {
[this.getSelectedClassName()]: this.isChildrenSelected(), [this.getSelectedClassName()]: this.isChildrenSelected(),
}; };
if (!this._menuId) { if (!this.internalMenuId) {
if (props.eventKey) { if (props.eventKey) {
this._menuId = `${props.eventKey}$Menu`; this.internalMenuId = `${props.eventKey}$Menu`;
} else { } else {
this._menuId = `$__$${++guid}$Menu`; this.internalMenuId = `$__$${++guid}$Menu`;
} }
} }
@ -466,7 +468,7 @@ const SubMenu = {
// since corresponding node cannot be found // since corresponding node cannot be found
if (isOpen) { if (isOpen) {
ariaOwns = { ariaOwns = {
'aria-owns': this._menuId, 'aria-owns': this.internalMenuId,
}; };
} }
const titleProps = { const titleProps = {

View File

@ -193,6 +193,7 @@ const SubPopupMenu = {
return 1; return 1;
} }
return undefined;
}, },
onItemHover(e) { onItemHover(e) {

View File

@ -1,4 +1,4 @@
// based on rc-menu 7.4.21 // based on rc-menu 7.5.5
import Menu from './Menu'; import Menu from './Menu';
import SubMenu from './SubMenu'; import SubMenu from './SubMenu';
import MenuItem, { menuItemProps } from './MenuItem'; import MenuItem, { menuItemProps } from './MenuItem';

View File

@ -1,4 +1,4 @@
const isMobile = require('ismobilejs'); import isMobile from './utils/isMobile';
export function noop() {} export function noop() {}

View File

@ -0,0 +1,110 @@
// MIT License from https://github.com/kaimallea/isMobile
const applePhone = /iPhone/i;
const appleIpod = /iPod/i;
const appleTablet = /iPad/i;
const androidPhone = /\bAndroid(?:.+)Mobile\b/i; // Match 'Android' AND 'Mobile'
const androidTablet = /Android/i;
const amazonPhone = /\bAndroid(?:.+)SD4930UR\b/i;
const amazonTablet = /\bAndroid(?:.+)(?:KF[A-Z]{2,4})\b/i;
const windowsPhone = /Windows Phone/i;
const windowsTablet = /\bWindows(?:.+)ARM\b/i; // Match 'Windows' AND 'ARM'
const otherBlackberry = /BlackBerry/i;
const otherBlackberry10 = /BB10/i;
const otherOpera = /Opera Mini/i;
const otherChrome = /\b(CriOS|Chrome)(?:.+)Mobile/i;
const otherFirefox = /Mobile(?:.+)Firefox\b/i; // Match 'Mobile' AND 'Firefox'
function match(regex, userAgent) {
return regex.test(userAgent);
}
function isMobile(userAgent) {
let ua = userAgent || (typeof navigator !== 'undefined' ? navigator.userAgent : '');
// Facebook mobile app's integrated browser adds a bunch of strings that
// match everything. Strip it out if it exists.
let tmp = ua.split('[FBAN');
if (typeof tmp[1] !== 'undefined') {
[ua] = tmp;
}
// Twitter mobile app's integrated browser on iPad adds a "Twitter for
// iPhone" string. Same probably happens on other tablet platforms.
// This will confuse detection so strip it out if it exists.
tmp = ua.split('Twitter');
if (typeof tmp[1] !== 'undefined') {
[ua] = tmp;
}
const result = {
apple: {
phone: match(applePhone, ua) && !match(windowsPhone, ua),
ipod: match(appleIpod, ua),
tablet: !match(applePhone, ua) && match(appleTablet, ua) && !match(windowsPhone, ua),
device:
(match(applePhone, ua) || match(appleIpod, ua) || match(appleTablet, ua)) &&
!match(windowsPhone, ua),
},
amazon: {
phone: match(amazonPhone, ua),
tablet: !match(amazonPhone, ua) && match(amazonTablet, ua),
device: match(amazonPhone, ua) || match(amazonTablet, ua),
},
android: {
phone:
(!match(windowsPhone, ua) && match(amazonPhone, ua)) ||
(!match(windowsPhone, ua) && match(androidPhone, ua)),
tablet:
!match(windowsPhone, ua) &&
!match(amazonPhone, ua) &&
!match(androidPhone, ua) &&
(match(amazonTablet, ua) || match(androidTablet, ua)),
device:
(!match(windowsPhone, ua) &&
(match(amazonPhone, ua) ||
match(amazonTablet, ua) ||
match(androidPhone, ua) ||
match(androidTablet, ua))) ||
match(/\bokhttp\b/i, ua),
},
windows: {
phone: match(windowsPhone, ua),
tablet: match(windowsTablet, ua),
device: match(windowsPhone, ua) || match(windowsTablet, ua),
},
other: {
blackberry: match(otherBlackberry, ua),
blackberry10: match(otherBlackberry10, ua),
opera: match(otherOpera, ua),
firefox: match(otherFirefox, ua),
chrome: match(otherChrome, ua),
device:
match(otherBlackberry, ua) ||
match(otherBlackberry10, ua) ||
match(otherOpera, ua) ||
match(otherFirefox, ua) ||
match(otherChrome, ua),
},
// Additional
any: null,
phone: null,
tablet: null,
};
result.any =
result.apple.device || result.android.device || result.windows.device || result.other.device;
// excludes 'other' devices and ipods, targeting touchscreen phones
result.phone = result.apple.phone || result.android.phone || result.windows.phone;
result.tablet = result.apple.tablet || result.android.tablet || result.windows.tablet;
return result;
}
const defaultResult = {
...isMobile(),
isMobile,
};
export default defaultResult;

View File

@ -24,4 +24,6 @@ export declare class SubMenu extends AntdComponent {
* @type string | slot * @type string | slot
*/ */
title: any; title: any;
popupClassName: string;
} }