feat: update menu

pull/2468/head
tangjinzhou 2020-06-16 22:55:02 +08:00
parent 75e1661c16
commit 4311c15755
18 changed files with 388 additions and 460 deletions

View File

@ -29,3 +29,9 @@ v-model -> v-model:visible
## Tooltip ## Tooltip
v-model -> v-model:visible v-model -> v-model:visible
## Modal
v-model -> v-model:visible
okButtonProps、cancelButtonProps 扁平化处理

View File

@ -54,12 +54,12 @@ function animate(node, show, done) {
} }
const animation = { const animation = {
enter(node, done) { onEnter(node, done) {
nextTick(() => { nextTick(() => {
animate(node, true, done); animate(node, true, done);
}); });
}, },
leave(node, done) { onLeave(node, done) {
return animate(node, false, done); return animate(node, false, done);
}, },
}; };

View File

@ -118,6 +118,7 @@ const getOptionProps = instance => {
return res; return res;
}; };
const getComponent = (instance, prop, options = instance, execute = true) => { const getComponent = (instance, prop, options = instance, execute = true) => {
if (instance.$) {
const temp = instance[prop]; const temp = instance[prop];
if (temp !== undefined) { if (temp !== undefined) {
return typeof temp === 'function' && execute ? temp(options) : temp; return typeof temp === 'function' && execute ? temp(options) : temp;
@ -126,6 +127,17 @@ const getComponent = (instance, prop, options = instance, execute = true) => {
com = execute && com ? com(options) : com; com = execute && com ? com(options) : com;
return Array.isArray(com) && com.length === 1 ? com[0] : com; return Array.isArray(com) && com.length === 1 ? com[0] : com;
} }
} else if (isVNode(instance)) {
const temp = instance.props && instance.props[prop];
if (temp !== undefined) {
return typeof temp === 'function' && execute ? temp(options) : temp;
} else if (instance.children && instance.children[name]) {
let com = instance.children[prop];
com = execute && com ? com(options) : com;
return Array.isArray(com) && com.length === 1 ? com[0] : com;
}
}
return undefined;
}; };
const getComponentFromProp = (instance, prop, options = instance, execute = true) => { const getComponentFromProp = (instance, prop, options = instance, execute = true) => {
if (instance.$createElement) { if (instance.$createElement) {
@ -169,13 +181,13 @@ const getComponentFromProp = (instance, prop, options = instance, execute = true
}; };
const getAllProps = ele => { const getAllProps = ele => {
let data = ele.data || {}; let props = getOptionProps(ele);
let componentOptions = ele.componentOptions || {}; if (ele.$) {
if (ele.$vnode) { props = { ...props, ...this.$attrs };
data = ele.$vnode.data || {}; } else {
componentOptions = ele.$vnode.componentOptions || {}; props = { ...props, ...ele.props };
} }
return { ...data.props, ...data.attrs, ...componentOptions.propsData }; return props;
}; };
// 使用 getOptionProps 替换 ,待测试 // 使用 getOptionProps 替换 ,待测试

View File

@ -1,5 +1,6 @@
import { createVNode } from 'vue';
import PropTypes from './vue-types'; import PropTypes from './vue-types';
import { getOptionProps, getListeners } from './props-util'; import { getOptionProps } from './props-util';
function getDisplayName(WrappedComponent) { function getDisplayName(WrappedComponent) {
return WrappedComponent.name || 'Component'; return WrappedComponent.name || 'Component';
@ -15,6 +16,7 @@ export default function wrapWithConnect(WrappedComponent) {
WrappedComponent.props.children = PropTypes.array.def([]); WrappedComponent.props.children = PropTypes.array.def([]);
const ProxyWrappedComponent = { const ProxyWrappedComponent = {
props, props,
inheritAttrs: false,
model: WrappedComponent.model, model: WrappedComponent.model,
name: `Proxy_${getDisplayName(WrappedComponent)}`, name: `Proxy_${getDisplayName(WrappedComponent)}`,
methods: { methods: {
@ -23,30 +25,21 @@ export default function wrapWithConnect(WrappedComponent) {
}, },
}, },
render() { render() {
const { $slots = {}, $scopedSlots } = this; const { $slots = {} } = this;
const props = getOptionProps(this); const props = getOptionProps(this);
const wrapProps = { const wrapProps = {
props: {
...props, ...props,
__propsSymbol__: Symbol(), __propsSymbol__: Symbol(),
componentWillReceiveProps: { ...props }, componentWillReceiveProps: { ...props },
children: $slots.default || props.children || [], children: props.children || $slots?.default() || [],
}, slots: $slots,
on: getListeners(this), ref: 'wrappedInstance',
}; };
if (Object.keys($scopedSlots).length) { return createVNode(WrappedComponent, wrapProps);
wrapProps.scopedSlots = $scopedSlots; // return (
} // <WrappedComponent {...wrapProps} ref="wrappedInstance">
const slotsKey = Object.keys($slots); // </WrappedComponent>
return ( // );
<WrappedComponent {...wrapProps} ref="wrappedInstance">
{slotsKey.length
? slotsKey.map(name => {
return <template slot={name}>{$slots[name]}</template>;
})
: null}
</WrappedComponent>
);
}, },
}; };
Object.keys(methods).map(m => { Object.keys(methods).map(m => {

View File

@ -1,15 +1,15 @@
import { provide } from 'vue';
import { storeShape } from './PropTypes'; import { storeShape } from './PropTypes';
import { getSlot } from '../props-util';
export default { export default {
name: 'StoreProvider', name: 'StoreProvider',
props: { props: {
store: storeShape.isRequired, store: storeShape.isRequired,
}, },
provide() { created() {
return { provide('storeContext', this.$props);
storeContext: this.$props,
};
}, },
render() { render() {
return this.$slots.default[0]; return getSlot(this);
}, },
}; };

View File

@ -1,6 +1,7 @@
import shallowEqual from 'shallowequal'; import shallowEqual from 'shallowequal';
import { inject, createVNode } from 'vue';
import omit from 'omit.js'; import omit from 'omit.js';
import { getOptionProps, getListeners } from '../props-util'; import { getOptionProps } from '../props-util';
import PropTypes from '../vue-types'; import PropTypes from '../vue-types';
import proxyComponent from '../proxyComponent'; import proxyComponent from '../proxyComponent';
@ -22,9 +23,12 @@ export default function connect(mapStateToProps) {
}); });
const Connect = { const Connect = {
name: `Connect_${getDisplayName(WrappedComponent)}`, name: `Connect_${getDisplayName(WrappedComponent)}`,
inheritAttrs: false,
props, props,
inject: { setup() {
storeContext: { default: () => ({}) }, return {
storeContext: inject('storeContext', {}),
};
}, },
data() { data() {
this.store = this.storeContext.store; this.store = this.storeContext.store;
@ -80,25 +84,19 @@ export default function connect(mapStateToProps) {
}, },
}, },
render() { render() {
const { $slots = {}, $scopedSlots, subscribed, store } = this; const { $slots = {}, subscribed, store, $attrs } = this;
const props = getOptionProps(this); const props = getOptionProps(this);
this.preProps = { ...omit(props, ['__propsSymbol__']) }; this.preProps = { ...omit(props, ['__propsSymbol__']) };
const wrapProps = { const wrapProps = {
props: {
...props, ...props,
...subscribed, ...subscribed,
...$attrs,
store, store,
}, slots: $slots,
on: getListeners(this), ref: 'wrappedInstance',
scopedSlots: $scopedSlots,
}; };
return ( return createVNode(WrappedComponent, wrapProps);
<WrappedComponent {...wrapProps} ref="wrappedInstance"> // return <WrappedComponent {...wrapProps} ref="wrappedInstance"></WrappedComponent>;
{Object.keys($slots).map(name => {
return <template slot={name}>{$slots[name]}</template>;
})}
</WrappedComponent>
);
}, },
}; };
return proxyComponent(Connect); return proxyComponent(Connect);

View File

@ -1,16 +1,20 @@
import { inject } from 'vue';
import { Item, itemProps } from '../vc-menu'; import { Item, itemProps } from '../vc-menu';
import { getOptionProps, getListeners } from '../_util/props-util'; import { getOptionProps, getSlot } from '../_util/props-util';
import Tooltip from '../tooltip'; import Tooltip from '../tooltip';
function noop() {} function noop() {}
export default { export default {
name: 'MenuItem', name: 'MenuItem',
inheritAttrs: false, inheritAttrs: false,
props: itemProps, props: itemProps,
inject: {
getInlineCollapsed: { default: () => noop },
layoutSiderContext: { default: () => ({}) },
},
isMenuItem: true, isMenuItem: true,
setup() {
return {
getInlineCollapsed: inject('getInlineCollapsed', noop),
layoutSiderContext: inject('layoutSiderContext', {}),
};
},
methods: { methods: {
onKeyDown(e) { onKeyDown(e) {
this.$refs.menuItem.onKeyDown(e); this.$refs.menuItem.onKeyDown(e);
@ -33,24 +37,20 @@ export default {
} }
const itemProps = { const itemProps = {
props: {
...props, ...props,
title, title,
}, ...attrs,
attrs,
on: getListeners(this),
}; };
const toolTipProps = { const toolTipProps = {
props: {
...tooltipProps, ...tooltipProps,
placement: 'right', placement: 'right',
overlayClassName: `${rootPrefixCls}-inline-collapsed-tooltip`, overlayClassName: `${rootPrefixCls}-inline-collapsed-tooltip`,
},
}; };
// return <div>ddd</div>;
return ( return (
<Tooltip {...toolTipProps}> <Tooltip {...toolTipProps}>
<Item {...itemProps} ref="menuItem"> <Item {...itemProps} ref="menuItem">
{$slots.default} {getSlot(this)}
</Item> </Item>
</Tooltip> </Tooltip>
); );

View File

@ -1,13 +1,18 @@
import { inject } from 'vue';
import { SubMenu as VcSubMenu } from '../vc-menu'; import { SubMenu as VcSubMenu } from '../vc-menu';
import { getListeners } from '../_util/props-util';
import classNames from 'classnames'; import classNames from 'classnames';
import Omit from 'omit.js';
import { getSlot } from '../_util/props-util';
export default { export default {
name: 'ASubMenu', name: 'ASubMenu',
isSubMenu: true, isSubMenu: true,
inheritAttrs: false,
props: { ...VcSubMenu.props }, props: { ...VcSubMenu.props },
inject: { setup() {
menuPropsContext: { default: () => ({}) }, return {
menuPropsContext: inject('menuPropsContext', {}),
};
}, },
methods: { methods: {
onKeyDown(e) { onKeyDown(e) {
@ -16,27 +21,16 @@ export default {
}, },
render() { render() {
const { $slots, $scopedSlots } = this; const { $slots, $attrs } = this;
const { rootPrefixCls, popupClassName } = this.$props; const { rootPrefixCls, popupClassName } = this.$props;
const { theme: antdMenuTheme } = this.menuPropsContext; const { theme: antdMenuTheme } = this.menuPropsContext;
const props = { const props = {
props: {
...this.$props, ...this.$props,
popupClassName: classNames(`${rootPrefixCls}-${antdMenuTheme}`, popupClassName), popupClassName: classNames(`${rootPrefixCls}-${antdMenuTheme}`, popupClassName),
},
ref: 'subMenu', ref: 'subMenu',
on: getListeners(this), ...$attrs,
scopedSlots: $scopedSlots, ...Omit($slots, ['default']),
}; };
const slotsKey = Object.keys($slots); return <VcSubMenu {...props}>{getSlot(this)}</VcSubMenu>;
return (
<VcSubMenu {...props}>
{slotsKey.length
? slotsKey.map(name => {
return <template slot={name}>{$slots[name]}</template>;
})
: null}
</VcSubMenu>
);
}, },
}; };

View File

@ -1,3 +1,4 @@
import { inject, provide } from 'vue';
import omit from 'omit.js'; import omit from 'omit.js';
import VcMenu, { Divider, ItemGroup } from '../vc-menu'; import VcMenu, { Divider, ItemGroup } from '../vc-menu';
import SubMenu from './SubMenu'; import SubMenu from './SubMenu';
@ -5,11 +6,10 @@ 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, getOptionProps } from '../_util/props-util'; import { hasProp, getOptionProps, getSlot } 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 raf from '../_util/raf'; // import raf from '../_util/raf';
export const MenuMode = PropTypes.oneOf([ export const MenuMode = PropTypes.oneOf([
@ -41,26 +41,27 @@ export const menuProps = {
const Menu = { const Menu = {
name: 'AMenu', name: 'AMenu',
inheritAttrs: false,
props: menuProps, props: menuProps,
Divider: { ...Divider, name: 'AMenuDivider' }, Divider: { ...Divider, name: 'AMenuDivider' },
Item: { ...Item, name: 'AMenuItem' }, Item: { ...Item, name: 'AMenuItem' },
SubMenu: { ...SubMenu, name: 'ASubMenu' }, SubMenu: { ...SubMenu, name: 'ASubMenu' },
ItemGroup: { ...ItemGroup, name: 'AMenuItemGroup' }, ItemGroup: { ...ItemGroup, name: 'AMenuItemGroup' },
provide() { mixins: [BaseMixin],
created() {
provide('getInlineCollapsed', this.getInlineCollapsed);
provide('menuPropsContext', this.$props);
},
setup() {
return { return {
getInlineCollapsed: this.getInlineCollapsed, configProvider: inject('configProvider', ConfigConsumerProps),
menuPropsContext: this.$props, layoutSiderContext: inject('layoutSiderContext', {}),
}; };
}, },
mixins: [BaseMixin], // model: {
inject: { // prop: 'selectedKeys',
layoutSiderContext: { default: () => ({}) }, // event: 'selectChange',
configProvider: { default: () => ConfigConsumerProps }, // },
},
model: {
prop: 'selectedKeys',
event: 'selectChange',
},
updated() { updated() {
this.propsUpdating = false; this.propsUpdating = false;
}, },
@ -165,10 +166,12 @@ const Menu = {
}, },
handleSelect(info) { handleSelect(info) {
this.$emit('select', info); this.$emit('select', info);
this.$emit('update:selectedKeys', info.selectedKeys);
this.$emit('selectChange', info.selectedKeys); this.$emit('selectChange', info.selectedKeys);
}, },
handleDeselect(info) { handleDeselect(info) {
this.$emit('deselect', info); this.$emit('deselect', info);
this.$emit('update:selectedKeys', info.selectedKeys);
this.$emit('selectChange', info.selectedKeys); this.$emit('selectChange', info.selectedKeys);
}, },
handleOpenChange(openKeys) { handleOpenChange(openKeys) {
@ -203,7 +206,7 @@ const Menu = {
if (menuMode === 'horizontal') { if (menuMode === 'horizontal') {
menuOpenAnimation = 'slide-up'; menuOpenAnimation = 'slide-up';
} else if (menuMode === 'inline') { } else if (menuMode === 'inline') {
menuOpenAnimation = { on: animation }; menuOpenAnimation = animation;
} else { } else {
// When mode switch from inline // When mode switch from inline
// submenu should hide without animation // submenu should hide without animation
@ -219,7 +222,7 @@ const Menu = {
}, },
}, },
render() { render() {
const { layoutSiderContext, $slots } = this; const { layoutSiderContext } = this;
const { collapsedWidth } = layoutSiderContext; const { collapsedWidth } = layoutSiderContext;
const { getPopupContainer: getContextPopupContainer } = this.configProvider; const { getPopupContainer: getContextPopupContainer } = this.configProvider;
const props = getOptionProps(this); const props = getOptionProps(this);
@ -235,37 +238,32 @@ const Menu = {
}; };
const menuProps = { const menuProps = {
props: {
...omit(props, ['inlineCollapsed']), ...omit(props, ['inlineCollapsed']),
getPopupContainer: getPopupContainer || getContextPopupContainer, getPopupContainer: getPopupContainer || getContextPopupContainer,
openKeys: this.sOpenKeys, openKeys: this.sOpenKeys,
mode: menuMode, mode: menuMode,
prefixCls, prefixCls,
}, ...this.$attrs,
on: { onSelect: this.handleSelect,
...getListeners(this), onDeselect: this.handleDeselect,
select: this.handleSelect, onOpenChange: this.handleOpenChange,
deselect: this.handleDeselect, onMouseenter: this.handleMouseEnter,
openChange: this.handleOpenChange, onTransitionend: this.handleTransitionEnd,
mouseenter: this.handleMouseEnter, children: getSlot(this),
},
nativeOn: {
transitionend: this.handleTransitionEnd,
},
}; };
if (!hasProp(this, 'selectedKeys')) { if (!hasProp(this, 'selectedKeys')) {
delete menuProps.props.selectedKeys; delete menuProps.selectedKeys;
} }
if (menuMode !== 'inline') { if (menuMode !== 'inline') {
// closing vertical popup submenu after click it // closing vertical popup submenu after click it
menuProps.on.click = this.handleClick; menuProps.onClick = this.handleClick;
menuProps.props.openTransitionName = menuOpenAnimation; menuProps.openTransitionName = menuOpenAnimation;
} else { } else {
menuProps.on.click = e => { menuProps.onClick = e => {
this.$emit('click', e); this.$emit('click', e);
}; };
menuProps.props.openAnimation = menuOpenAnimation; menuProps.openAnimation = menuOpenAnimation;
} }
// https://github.com/ant-design/ant-design/issues/8587 // https://github.com/ant-design/ant-design/issues/8587
@ -273,24 +271,19 @@ const Menu = {
this.getInlineCollapsed() && this.getInlineCollapsed() &&
(collapsedWidth === 0 || collapsedWidth === '0' || collapsedWidth === '0px'); (collapsedWidth === 0 || collapsedWidth === '0' || collapsedWidth === '0px');
if (hideMenu) { if (hideMenu) {
menuProps.props.openKeys = []; menuProps.openKeys = [];
} }
return ( return <VcMenu {...menuProps} class={menuClassName} />;
<VcMenu {...menuProps} class={menuClassName}>
{$slots.default}
</VcMenu>
);
}, },
}; };
/* istanbul ignore next */ /* istanbul ignore next */
Menu.install = function(Vue) { Menu.install = function(app) {
Vue.use(Base); app.component(Menu.name, Menu);
Vue.component(Menu.name, Menu); app.component(Menu.Item.name, Menu.Item);
Vue.component(Menu.Item.name, Menu.Item); app.component(Menu.SubMenu.name, Menu.SubMenu);
Vue.component(Menu.SubMenu.name, Menu.SubMenu); app.component(Menu.Divider.name, Menu.Divider);
Vue.component(Menu.Divider.name, Menu.Divider); app.component(Menu.ItemGroup.name, Menu.ItemGroup);
Vue.component(Menu.ItemGroup.name, Menu.ItemGroup);
}; };
export default Menu; export default Menu;

View File

@ -4,7 +4,7 @@ import SubMenu from './SubMenu';
import BaseMixin from '../_util/BaseMixin'; import BaseMixin from '../_util/BaseMixin';
import { getWidth, setStyle, menuAllProps } from './util'; import { getWidth, setStyle, menuAllProps } from './util';
import { cloneElement } from '../_util/vnode'; import { cloneElement } from '../_util/vnode';
import { getClass, getPropsData, getEvents, getListeners } from '../_util/props-util'; import { getPropsData, getSlot, getAllProps } from '../_util/props-util';
const canUseDOM = !!( const canUseDOM = !!(
typeof window !== 'undefined' && typeof window !== 'undefined' &&
@ -110,9 +110,8 @@ 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 = getSlot(this)[0];
const { title, ...rest } = getPropsData(copy); // eslint-disable-line no-unused-vars const { title, ...rest } = getAllProps(copy); // eslint-disable-line no-unused-vars
const events = getEvents(copy);
let style = {}; let style = {};
let key = `${keyPrefix}-overflowed-indicator`; let key = `${keyPrefix}-overflowed-indicator`;
let eventKey = `${keyPrefix}-overflowed-indicator`; let eventKey = `${keyPrefix}-overflowed-indicator`;
@ -133,29 +132,20 @@ const DOMWrap = {
const popupClassName = theme ? `${prefixCls}-${theme}` : ''; const popupClassName = theme ? `${prefixCls}-${theme}` : '';
const props = {}; const props = {};
const on = {}; menuAllProps.forEach(k => {
menuAllProps.props.forEach(k => {
if (rest[k] !== undefined) { if (rest[k] !== undefined) {
props[k] = rest[k]; props[k] = rest[k];
} }
}); });
menuAllProps.on.forEach(k => {
if (events[k] !== undefined) {
on[k] = events[k];
}
});
const subMenuProps = { const subMenuProps = {
props: {
title: overflowedIndicator, title: overflowedIndicator,
popupClassName, popupClassName,
...props, ...props,
eventKey, eventKey,
disabled: false, disabled: false,
},
class: `${prefixCls}-overflowed-submenu`, class: `${prefixCls}-overflowed-submenu`,
key, key,
style, style,
on,
}; };
return <SubMenu {...subMenuProps}>{overflowedItems}</SubMenu>; return <SubMenu {...subMenuProps}>{overflowedItems}</SubMenu>;
@ -245,7 +235,7 @@ const DOMWrap = {
renderChildren(children) { renderChildren(children) {
// need to take care of overflowed items in horizontal mode // need to take care of overflowed items in horizontal mode
const { lastVisibleIndex } = this.$data; const { lastVisibleIndex } = this.$data;
const className = getClass(this); const className = this.$attrs.class || '';
return (children || []).reduce((acc, childNode, index) => { return (children || []).reduce((acc, childNode, index) => {
let item = childNode; let item = childNode;
const eventKey = getPropsData(childNode).eventKey; const eventKey = getPropsData(childNode).eventKey;
@ -258,7 +248,7 @@ const DOMWrap = {
// eventKey openkeys // eventKey openkeys
{ {
style: { display: 'none' }, style: { display: 'none' },
props: { eventKey: `${eventKey}-hidden` }, eventKey: `${eventKey}-hidden`,
class: MENUITEM_OVERFLOWED_CLASSNAME, class: MENUITEM_OVERFLOWED_CLASSNAME,
}, },
); );
@ -271,7 +261,7 @@ const DOMWrap = {
// we have to overwrite with the correct key explicitly // we have to overwrite with the correct key explicitly
{ {
key: getPropsData(c).eventKey, key: getPropsData(c).eventKey,
props: { mode: 'vertical-left' }, mode: 'vertical-left',
}, },
); );
}); });
@ -295,10 +285,8 @@ const DOMWrap = {
render() { render() {
const Tag = this.$props.tag; const Tag = this.$props.tag;
const tagProps = {
on: getListeners(this), return <Tag>{this.renderChildren(getSlot(this))}</Tag>;
};
return <Tag {...tagProps}>{this.renderChildren(this.$slots.default)}</Tag>;
}, },
}; };
@ -311,6 +299,7 @@ DOMWrap.props = {
visible: PropTypes.bool, visible: PropTypes.bool,
hiddenClassName: PropTypes.string, hiddenClassName: PropTypes.string,
tag: PropTypes.string.def('div'), tag: PropTypes.string.def('div'),
children: PropTypes.any,
}; };
export default DOMWrap; export default DOMWrap;

View File

@ -2,16 +2,12 @@ import PropTypes from '../_util/vue-types';
import { Provider, create } from '../_util/store'; import { Provider, create } from '../_util/store';
import { default as SubPopupMenu, getActiveKey } from './SubPopupMenu'; import { default as SubPopupMenu, getActiveKey } from './SubPopupMenu';
import BaseMixin from '../_util/BaseMixin'; import BaseMixin from '../_util/BaseMixin';
import hasProp, { import hasProp, { getOptionProps, getComponent, filterEmpty } from '../_util/props-util';
getOptionProps,
getComponentFromProp,
filterEmpty,
getListeners,
} from '../_util/props-util';
import commonPropsType from './commonPropsType'; import commonPropsType from './commonPropsType';
const Menu = { const Menu = {
name: 'Menu', name: 'Menu',
inheritAttrs: false,
props: { props: {
...commonPropsType, ...commonPropsType,
selectable: PropTypes.bool.def(true), selectable: PropTypes.bool.def(true),
@ -33,7 +29,7 @@ const Menu = {
selectedKeys, selectedKeys,
openKeys, openKeys,
activeKey: { activeKey: {
'0-menu-': getActiveKey({ ...props, children: this.$slots.default || [] }, props.activeKey), '0-menu-': getActiveKey({ ...props, children: props.children || [] }, props.activeKey),
}, },
}); });
@ -158,27 +154,20 @@ const Menu = {
}, },
render() { render() {
const props = getOptionProps(this); const props = { ...getOptionProps(this), ...this.$attrs };
props.class += ` ${props.prefixCls}-root`;
const subPopupMenuProps = { const subPopupMenuProps = {
props: {
...props, ...props,
itemIcon: getComponentFromProp(this, 'itemIcon', props), itemIcon: getComponent(this, 'itemIcon', props),
expandIcon: getComponentFromProp(this, 'expandIcon', props), expandIcon: getComponent(this, 'expandIcon', props),
overflowedIndicator: getComponentFromProp(this, 'overflowedIndicator', props) || ( overflowedIndicator: getComponent(this, 'overflowedIndicator', props) || <span>···</span>,
<span>···</span>
),
openTransitionName: this.getOpenTransitionName(), openTransitionName: this.getOpenTransitionName(),
parentMenu: this, parentMenu: this,
children: filterEmpty(this.$slots.default || []), children: filterEmpty(props.children),
}, onClick: this.onClick,
class: `${props.prefixCls}-root`, onOpenChange: this.onOpenChange,
on: { onDeselect: this.onDeselect,
...getListeners(this), onSelect: this.onSelect,
click: this.onClick,
openChange: this.onOpenChange,
deselect: this.onDeselect,
select: this.onSelect,
},
ref: 'innerMenu', ref: 'innerMenu',
}; };
return ( return (

View File

@ -4,7 +4,7 @@ import BaseMixin from '../_util/BaseMixin';
import scrollIntoView from 'dom-scroll-into-view'; import scrollIntoView from 'dom-scroll-into-view';
import { connect } from '../_util/store'; import { connect } from '../_util/store';
import { noop, menuAllProps } from './util'; import { noop, menuAllProps } from './util';
import { getComponentFromProp, getListeners } from '../_util/props-util'; import { getComponent, getSlot } from '../_util/props-util';
const props = { const props = {
attribute: PropTypes.object, attribute: PropTypes.object,
@ -36,6 +36,7 @@ const props = {
}; };
const MenuItem = { const MenuItem = {
name: 'MenuItem', name: 'MenuItem',
inheritAttrs: false,
props, props,
mixins: [BaseMixin], mixins: [BaseMixin],
isMenuItem: true, isMenuItem: true,
@ -141,8 +142,10 @@ const MenuItem = {
}, },
render() { render() {
const props = { ...this.$props }; const props = { ...this.$props, ...this.$attrs };
const className = { const className = {
[props.class]: props.class,
[this.getPrefixCls()]: true, [this.getPrefixCls()]: true,
[this.getActiveClassName()]: !props.disabled && props.active, [this.getActiveClassName()]: !props.disabled && props.active,
[this.getSelectedClassName()]: props.isSelected, [this.getSelectedClassName()]: props.isSelected,
@ -171,32 +174,27 @@ const MenuItem = {
} }
// In case that onClick/onMouseLeave/onMouseEnter is passed down from owner // In case that onClick/onMouseLeave/onMouseEnter is passed down from owner
const mouseEvent = { const mouseEvent = {
click: props.disabled ? noop : this.onClick, onClick: props.disabled ? noop : this.onClick,
mouseleave: props.disabled ? noop : this.onMouseLeave, onMouseleave: props.disabled ? noop : this.onMouseLeave,
mouseenter: props.disabled ? noop : this.onMouseEnter, onMouseenter: props.disabled ? noop : this.onMouseEnter,
}; };
const style = {}; const style = { ...(props.style || {}) };
if (props.mode === 'inline') { if (props.mode === 'inline') {
style.paddingLeft = `${props.inlineIndent * props.level}px`; style.paddingLeft = `${props.inlineIndent * props.level}px`;
} }
const listeners = { ...getListeners(this) }; [...menuAllProps, 'children', 'slots', '__propsSymbol__', 'componentWillReceiveProps'].forEach(
menuAllProps.props.forEach(key => delete props[key]); key => delete props[key],
menuAllProps.on.forEach(key => delete listeners[key]); );
const liProps = { const liProps = {
attrs: {
...props, ...props,
...attrs, ...attrs,
},
on: {
...listeners,
...mouseEvent, ...mouseEvent,
},
}; };
return ( return (
<li {...liProps} style={style} class={className}> <li {...liProps} style={style} class={className}>
{this.$slots.default} {getSlot(this)}
{getComponentFromProp(this, 'itemIcon', props)} {getComponent(this, 'itemIcon', props)}
</li> </li>
); );
}, },

View File

@ -1,11 +1,11 @@
import PropTypes from '../_util/vue-types'; import PropTypes from '../_util/vue-types';
import { getComponentFromProp, getListeners } from '../_util/props-util'; import { getComponent, getSlot } from '../_util/props-util';
// import { menuAllProps } from './util' // import { menuAllProps } from './util'
const MenuItemGroup = { const MenuItemGroup = {
name: 'MenuItemGroup', name: 'MenuItemGroup',
inheritAttrs: false,
props: { props: {
renderMenuItem: PropTypes.func, renderMenuItem: PropTypes.func,
index: PropTypes.number, index: PropTypes.number,
@ -23,22 +23,19 @@ const MenuItemGroup = {
}, },
}, },
render() { render() {
const props = { ...this.$props }; const props = { ...this.$props, ...this.$attrs };
const { rootPrefixCls, title } = props; const { class: cls = '', rootPrefixCls, title } = props;
const titleClassName = `${rootPrefixCls}-item-group-title`; const titleClassName = `${rootPrefixCls}-item-group-title`;
const listClassName = `${rootPrefixCls}-item-group-list`; const listClassName = `${rootPrefixCls}-item-group-list`;
// menuAllProps.props.forEach(key => delete props[key]) // menuAllProps.props.forEach(key => delete props[key])
const listeners = { ...getListeners(this) }; delete props.onClick;
delete listeners.click; const children = getSlot(this);
return ( return (
<li {...{ on: listeners, class: `${rootPrefixCls}-item-group` }}> <li {...props} class={`${cls} ${rootPrefixCls}-item-group`}>
<div class={titleClassName} title={typeof title === 'string' ? title : undefined}> <div class={titleClassName} title={typeof title === 'string' ? title : undefined}>
{getComponentFromProp(this, 'title')} {getComponent(this, 'title')}
</div> </div>
<ul class={listClassName}> <ul class={listClassName}>{children && children.map(this.renderInnerMenuItem)}</ul>
{this.$slots.default && this.$slots.default.map(this.renderInnerMenuItem)}
</ul>
</li> </li>
); );
}, },

View File

@ -6,7 +6,7 @@ import { connect } from '../_util/store';
import SubPopupMenu from './SubPopupMenu'; import SubPopupMenu from './SubPopupMenu';
import placements from './placements'; import placements from './placements';
import BaseMixin from '../_util/BaseMixin'; import BaseMixin from '../_util/BaseMixin';
import { getComponentFromProp, filterEmpty, getListeners } from '../_util/props-util'; import { getComponent, filterEmpty, getSlot, splitAttrs } from '../_util/props-util';
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';
@ -33,6 +33,7 @@ const updateDefaultActiveFirst = (store, eventKey, defaultActiveFirst) => {
const SubMenu = { const SubMenu = {
name: 'SubMenu', name: 'SubMenu',
inheritAttrs: false,
props: { props: {
parentMenu: PropTypes.object, parentMenu: PropTypes.object,
title: PropTypes.any, title: PropTypes.any,
@ -86,6 +87,9 @@ const SubMenu = {
} }
updateDefaultActiveFirst(store, eventKey, value); updateDefaultActiveFirst(store, eventKey, value);
this.internalMenuId = undefined;
this.haveRendered = undefined;
this.haveOpened = undefined;
return { return {
// defaultActiveFirst: false, // defaultActiveFirst: false,
}; };
@ -312,7 +316,7 @@ const SubMenu = {
isChildrenSelected() { isChildrenSelected() {
const ret = { find: false }; const ret = { find: false };
loopMenuItemRecursively(this.$slots.default, this.$props.selectedKeys, ret); loopMenuItemRecursively(getSlot(this), this.$props.selectedKeys, ret);
return ret.find; return ret.find;
}, },
// isOpen () { // isOpen () {
@ -334,10 +338,8 @@ const SubMenu = {
}, },
renderChildren(children) { renderChildren(children) {
const props = this.$props; const props = { ...this.$props, ...this.$attrs };
const { select, deselect, openChange } = getListeners(this);
const subPopupMenuProps = { const subPopupMenuProps = {
props: {
mode: props.mode === 'horizontal' ? 'vertical' : props.mode, mode: props.mode === 'horizontal' ? 'vertical' : props.mode,
visible: props.isOpen, visible: props.isOpen,
level: props.level + 1, level: props.level + 1,
@ -360,23 +362,20 @@ const SubMenu = {
multiple: props.multiple, multiple: props.multiple,
prefixCls: props.rootPrefixCls, prefixCls: props.rootPrefixCls,
manualRef: this.saveMenuInstance, manualRef: this.saveMenuInstance,
itemIcon: getComponentFromProp(this, 'itemIcon'), itemIcon: getComponent(this, 'itemIcon'),
expandIcon: getComponentFromProp(this, 'expandIcon'), expandIcon: getComponent(this, 'expandIcon'),
children, children,
},
on: {
click: this.onSubMenuClick, click: this.onSubMenuClick,
select, onSelect: props.onSelect || noop,
deselect, onDeselect: props.onDeselect || noop,
openChange, onOpenChange: props.onOpenChange || noop,
},
id: this.internalMenuId, id: this.internalMenuId,
}; };
const baseProps = subPopupMenuProps.props;
const haveRendered = this.haveRendered; const haveRendered = this.haveRendered;
this.haveRendered = true; this.haveRendered = true;
this.haveOpened = this.haveOpened || baseProps.visible || baseProps.forceSubMenuRender; this.haveOpened =
this.haveOpened || subPopupMenuProps.visible || subPopupMenuProps.forceSubMenuRender;
// never rendered not planning to, don't render // never rendered not planning to, don't render
if (!this.haveOpened) { if (!this.haveOpened) {
return <div />; return <div />;
@ -385,28 +384,24 @@ const SubMenu = {
// don't show transition on first rendering (no animation for opened menu) // don't show transition on first rendering (no animation for opened menu)
// show appear transition if it's not visible (not sure why) // show appear transition if it's not visible (not sure why)
// show appear transition if it's not inline mode // show appear transition if it's not inline mode
const transitionAppear = haveRendered || !baseProps.visible || !baseProps.mode === 'inline'; const transitionAppear =
subPopupMenuProps.class = ` ${baseProps.prefixCls}-sub`; haveRendered || !subPopupMenuProps.visible || !subPopupMenuProps.mode === 'inline';
let animProps = { appear: transitionAppear, css: false }; subPopupMenuProps.class = ` ${subPopupMenuProps.prefixCls}-sub`;
let transitionProps = { let transitionProps = { appear: transitionAppear, css: false };
props: animProps,
on: {}, if (subPopupMenuProps.openTransitionName) {
}; transitionProps = getTransitionProps(subPopupMenuProps.openTransitionName, {
if (baseProps.openTransitionName) {
transitionProps = getTransitionProps(baseProps.openTransitionName, {
appear: transitionAppear, appear: transitionAppear,
}); });
} else if (typeof baseProps.openAnimation === 'object') { } else if (typeof subPopupMenuProps.openAnimation === 'object') {
animProps = { ...animProps, ...(baseProps.openAnimation.props || {}) }; transitionProps = { ...transitionProps, ...(subPopupMenuProps.openAnimation || {}) };
if (!transitionAppear) { if (!transitionAppear) {
animProps.appear = false; transitionProps.appear = false;
} }
} else if (typeof baseProps.openAnimation === 'string') { } else if (typeof subPopupMenuProps.openAnimation === 'string') {
transitionProps = getTransitionProps(baseProps.openAnimation, { appear: transitionAppear }); transitionProps = getTransitionProps(subPopupMenuProps.openAnimation, {
} appear: transitionAppear,
});
if (typeof baseProps.openAnimation === 'object' && baseProps.openAnimation.on) {
transitionProps.on = baseProps.openAnimation.on;
} }
return ( return (
<transition {...transitionProps}> <transition {...transitionProps}>
@ -417,7 +412,8 @@ const SubMenu = {
}, },
render() { render() {
const props = this.$props; const props = { ...this.$props, ...this.$attrs };
const { onEvents } = splitAttrs(props);
const { rootPrefixCls, parentMenu } = this; const { rootPrefixCls, parentMenu } = this;
const isOpen = props.isOpen; const isOpen = props.isOpen;
const prefixCls = this.getPrefixCls(); const prefixCls = this.getPrefixCls();
@ -425,6 +421,7 @@ const SubMenu = {
const className = { const className = {
[prefixCls]: true, [prefixCls]: true,
[`${prefixCls}-${props.mode}`]: true, [`${prefixCls}-${props.mode}`]: true,
[props.className]: !!props.className,
[this.getOpenClassName()]: isOpen, [this.getOpenClassName()]: isOpen,
[this.getActiveClassName()]: props.active || (isOpen && !isInlineMode), [this.getActiveClassName()]: props.active || (isOpen && !isInlineMode),
[this.getDisabledClassName()]: props.disabled, [this.getDisabledClassName()]: props.disabled,
@ -444,17 +441,17 @@ const SubMenu = {
let titleMouseEvents = {}; let titleMouseEvents = {};
if (!props.disabled) { if (!props.disabled) {
mouseEvents = { mouseEvents = {
mouseleave: this.onMouseLeave, onMouseleave: this.onMouseLeave,
mouseenter: this.onMouseEnter, onMouseenter: this.onMouseEnter,
}; };
// only works in title, not outer li // only works in title, not outer li
titleClickEvents = { titleClickEvents = {
click: this.onTitleClick, onClick: this.onTitleClick,
}; };
titleMouseEvents = { titleMouseEvents = {
mouseenter: this.onTitleMouseEnter, onMouseenter: this.onTitleMouseEnter,
mouseleave: this.onTitleMouseLeave, onMouseleave: this.onTitleMouseLeave,
}; };
} }
@ -472,16 +469,12 @@ const SubMenu = {
}; };
} }
const titleProps = { const titleProps = {
attrs: {
'aria-expanded': isOpen, 'aria-expanded': isOpen,
...ariaOwns, ...ariaOwns,
'aria-haspopup': 'true', 'aria-haspopup': 'true',
title: typeof props.title === 'string' ? props.title : undefined, title: typeof props.title === 'string' ? props.title : undefined,
},
on: {
...titleMouseEvents, ...titleMouseEvents,
...titleClickEvents, ...titleClickEvents,
},
style, style,
class: `${prefixCls}-title`, class: `${prefixCls}-title`,
ref: 'subMenuTitle', ref: 'subMenuTitle',
@ -489,15 +482,15 @@ const SubMenu = {
// expand custom icon should NOT be displayed in menu with horizontal mode. // expand custom icon should NOT be displayed in menu with horizontal mode.
let icon = null; let icon = null;
if (props.mode !== 'horizontal') { if (props.mode !== 'horizontal') {
icon = getComponentFromProp(this, 'expandIcon', props); icon = getComponent(this, 'expandIcon', props);
} }
const title = ( const title = (
<div {...titleProps}> <div {...titleProps}>
{getComponentFromProp(this, 'title')} {getComponent(this, 'title')}
{icon || <i class={`${prefixCls}-arrow`} />} {icon || <i class={`${prefixCls}-arrow`} />}
</div> </div>
); );
const children = this.renderChildren(filterEmpty(this.$slots.default)); const children = this.renderChildren(filterEmpty(getSlot(this)));
const getPopupContainer = this.parentMenu.isRootMenu const getPopupContainer = this.parentMenu.isRootMenu
? this.parentMenu.getPopupContainer ? this.parentMenu.getPopupContainer
@ -506,7 +499,8 @@ const SubMenu = {
const popupAlign = props.popupOffset ? { offset: props.popupOffset } : {}; const popupAlign = props.popupOffset ? { offset: props.popupOffset } : {};
const popupClassName = props.mode === 'inline' ? '' : props.popupClassName; const popupClassName = props.mode === 'inline' ? '' : props.popupClassName;
const liProps = { const liProps = {
on: { ...omit(getListeners(this), ['click']), ...mouseEvents }, ...omit(onEvents, ['onClick']),
...mouseEvents,
class: className, class: className,
}; };
@ -533,8 +527,8 @@ const SubMenu = {
forceRender={props.forceSubMenuRender} forceRender={props.forceSubMenuRender}
// popupTransitionName='rc-menu-open-slide-up' // popupTransitionName='rc-menu-open-slide-up'
// popupAnimation={transitionProps} // popupAnimation={transitionProps}
popup={children}
> >
<template slot="popup">{children}</template>
{title} {title}
</Trigger> </Trigger>
)} )}

View File

@ -1,4 +1,4 @@
import omit from 'omit.js'; import { Comment } from 'vue';
import PropTypes from '../_util/vue-types'; import PropTypes from '../_util/vue-types';
import { connect } from '../_util/store'; import { connect } from '../_util/store';
import BaseMixin from '../_util/BaseMixin'; import BaseMixin from '../_util/BaseMixin';
@ -7,14 +7,7 @@ import classNames from 'classnames';
import { getKeyFromChildrenIndex, loopMenuItem, noop, isMobileDevice } from './util'; import { getKeyFromChildrenIndex, loopMenuItem, noop, isMobileDevice } from './util';
import DOMWrap from './DOMWrap'; import DOMWrap from './DOMWrap';
import { cloneElement } from '../_util/vnode'; import { cloneElement } from '../_util/vnode';
import { import { initDefaultProps, getOptionProps, getComponent, splitAttrs } from '../_util/props-util';
initDefaultProps,
getOptionProps,
getPropsData,
getEvents,
getComponentFromProp,
getListeners,
} from '../_util/props-util';
function allDisabled(arr) { function allDisabled(arr) {
if (!arr.length) { if (!arr.length) {
@ -77,6 +70,7 @@ export function getActiveKey(props, originalActiveKey) {
const SubPopupMenu = { const SubPopupMenu = {
name: 'SubPopupMenu', name: 'SubPopupMenu',
inheritAttrs: false,
props: initDefaultProps( props: initDefaultProps(
{ {
// onSelect: PropTypes.func, // onSelect: PropTypes.func,
@ -271,48 +265,23 @@ const SubPopupMenu = {
return null; return null;
}, },
getIcon(instance, name) { getIcon(instance, name) {
if (instance.$createElement) { return getComponent(instance, name);
const temp = instance[name];
if (temp !== undefined) {
return temp;
}
return instance.$slots[name] || instance.$scopedSlots[name];
} else {
const temp = getPropsData(instance)[name];
if (temp !== undefined) {
return temp;
}
const slotsProp = [];
const componentOptions = instance.componentOptions || {};
(componentOptions.children || []).forEach(child => {
if (child.data && child.data.slot === name) {
if (child.tag === 'template') {
slotsProp.push(child.children);
} else {
slotsProp.push(child);
}
}
});
return slotsProp.length ? slotsProp : undefined;
}
}, },
renderCommonMenuItem(child, i, extraProps) { renderCommonMenuItem(child, i, extraProps) {
if (child.tag === undefined) { if (child.type === Comment) {
return child; return child;
} }
const state = this.$props.store.getState(); const state = this.$props.store.getState();
const props = this.$props; const props = this.$props;
const key = getKeyFromChildrenIndex(child, props.eventKey, i); const key = getKeyFromChildrenIndex(child, props.eventKey, i);
const childProps = child.componentOptions.propsData || {}; const childProps = { ...getOptionProps(child), ...child.props }; // child.props
const isActive = key === state.activeKey[getEventKey(this.$props)]; const isActive = key === state.activeKey[getEventKey(this.$props)];
if (!childProps.disabled) { if (!childProps.disabled) {
// manualRef使keyrefthis.instanceArray // manualRef使keyrefthis.instanceArray
this.instanceArrayKeyIndexMap[key] = Object.keys(this.instanceArrayKeyIndexMap).length; this.instanceArrayKeyIndexMap[key] = Object.keys(this.instanceArrayKeyIndexMap).length;
} }
const childListeners = getEvents(child);
const newChildProps = { const newChildProps = {
props: {
mode: childProps.mode || props.mode, mode: childProps.mode || props.mode,
level: props.level, level: props.level,
inlineIndent: props.inlineIndent, inlineIndent: props.inlineIndent,
@ -334,22 +303,19 @@ const SubPopupMenu = {
itemIcon: this.getIcon(child, 'itemIcon') || this.getIcon(this, 'itemIcon'), itemIcon: this.getIcon(child, 'itemIcon') || this.getIcon(this, 'itemIcon'),
expandIcon: this.getIcon(child, 'expandIcon') || this.getIcon(this, 'expandIcon'), expandIcon: this.getIcon(child, 'expandIcon') || this.getIcon(this, 'expandIcon'),
...extraProps, ...extraProps,
}, onClick: e => {
on: { (childProps.onClick || noop)(e);
click: e => {
(childListeners.click || noop)(e);
this.onClick(e); this.onClick(e);
}, },
itemHover: this.onItemHover, onItemHover: this.onItemHover,
openChange: this.onOpenChange, onOpenChange: this.onOpenChange,
deselect: this.onDeselect, onDeselect: this.onDeselect,
// destroy: this.onDestroy, // destroy: this.onDestroy,
select: this.onSelect, onSelect: this.onSelect,
},
}; };
// ref: https://github.com/ant-design/ant-design/issues/13943 // ref: https://github.com/ant-design/ant-design/issues/13943
if (props.mode === 'inline' || isMobileDevice()) { if (props.mode === 'inline' || isMobileDevice()) {
newChildProps.props.triggerSubMenuAction = 'click'; newChildProps.triggerSubMenuAction = 'click';
} }
return cloneElement(child, newChildProps); return cloneElement(child, newChildProps);
}, },
@ -370,13 +336,16 @@ const SubPopupMenu = {
}, },
}, },
render() { render() {
const { ...props } = this.$props; const props = { ...this.$props };
const { onEvents } = splitAttrs(this.$attrs);
const { eventKey, prefixCls, visible, level, mode, theme } = props; const { eventKey, prefixCls, visible, level, mode, theme } = props;
this.instanceArray = []; this.instanceArray = [];
this.instanceArrayKeyIndexMap = {}; this.instanceArrayKeyIndexMap = {};
const className = classNames(props.prefixCls, `${props.prefixCls}-${props.mode}`); const className = classNames(props.class, props.prefixCls, `${props.prefixCls}-${props.mode}`);
// Otherwise, the propagated click event will trigger another onClick
delete onEvents.onClick;
const domWrapProps = { const domWrapProps = {
props: { ...props,
tag: 'ul', tag: 'ul',
// hiddenClassName: `${prefixCls}-hidden`, // hiddenClassName: `${prefixCls}-hidden`,
visible, visible,
@ -384,21 +353,17 @@ const SubPopupMenu = {
level, level,
mode, mode,
theme, theme,
overflowedIndicator: getComponentFromProp(this, 'overflowedIndicator'), overflowedIndicator: getComponent(this, 'overflowedIndicator'),
},
attrs: {
role: props.role || 'menu', role: props.role || 'menu',
},
class: className, class: className,
// Otherwise, the propagated click event will trigger another onClick ...onEvents,
on: omit(getListeners(this), ['click']),
}; };
// if (props.id) { // if (props.id) {
// domProps.id = props.id // domProps.id = props.id
// } // }
if (props.focusable) { if (props.focusable) {
domWrapProps.attrs.tabIndex = '0'; domWrapProps.tabIndex = '0';
domWrapProps.on.keydown = this.onKeyDown; domWrapProps.onKeydown = this.onKeyDown;
} }
return ( return (
// ESLint is not smart enough to know that the type of `children` was checked. // ESLint is not smart enough to know that the type of `children` was checked.

View File

@ -37,4 +37,5 @@ export default {
itemIcon: PropTypes.any, itemIcon: PropTypes.any,
expandIcon: PropTypes.any, expandIcon: PropTypes.any,
overflowedIndicator: PropTypes.any, overflowedIndicator: PropTypes.any,
children: PropTypes.any,
}; };

View File

@ -51,8 +51,7 @@ export function loopMenuItemRecursively(children, keys, ret) {
}); });
} }
export const menuAllProps = { export const menuAllProps = [
props: [
'defaultSelectedKeys', 'defaultSelectedKeys',
'selectedKeys', 'selectedKeys',
'defaultOpenKeys', 'defaultOpenKeys',
@ -101,18 +100,16 @@ export const menuAllProps = {
'theme', 'theme',
'itemIcon', 'itemIcon',
'expandIcon', 'expandIcon',
],
on: [ 'onSelect',
'select', 'onDeselect',
'deselect', 'onDestroy',
'destroy', 'onOpenChange',
'openChange', 'onItemHover',
'itemHover', 'onTitleMouseenter',
'titleMouseenter', 'onTitleMouseleave',
'titleMouseleave', 'onTitleClick',
'titleClick', ];
],
};
// ref: https://github.com/ant-design/ant-design/issues/14007 // ref: https://github.com/ant-design/ant-design/issues/14007
// ref: https://bugs.chromium.org/p/chromium/issues/detail?id=360889 // ref: https://bugs.chromium.org/p/chromium/issues/detail?id=360889

View File

@ -29,6 +29,7 @@ import Popover from 'ant-design-vue/popover';
import notification from 'ant-design-vue/notification'; import notification from 'ant-design-vue/notification';
import message from 'ant-design-vue/message'; import message from 'ant-design-vue/message';
import Modal from 'ant-design-vue/modal'; import Modal from 'ant-design-vue/modal';
import Menu from 'ant-design-vue/menu';
import 'ant-design-vue/style.js'; import 'ant-design-vue/style.js';
const app = createApp(App); const app = createApp(App);
@ -61,4 +62,5 @@ app
.use(Popconfirm) .use(Popconfirm)
.use(Popover) .use(Popover)
.use(Modal) .use(Modal)
.use(Menu)
.mount('#app'); .mount('#app');