Skip to content
Merged
6 changes: 4 additions & 2 deletions src/MenuItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import KeyCode from 'rc-util/lib/KeyCode';
import classNames from 'classnames';
import scrollIntoView from 'dom-scroll-into-view';
import { connect } from 'mini-store';
import { noop } from './util';
import { noop, menuAllProps } from './util';

/* eslint react/no-is-mounted:0 */

Expand Down Expand Up @@ -139,7 +139,7 @@ export class MenuItem extends React.Component {
}

render() {
const props = this.props;
const props = { ...this.props };
const className = classNames(this.getPrefixCls(), props.className, {
[this.getActiveClassName()]: !props.disabled && props.active,
[this.getSelectedClassName()]: props.isSelected,
Expand Down Expand Up @@ -167,8 +167,10 @@ export class MenuItem extends React.Component {
if (props.mode === 'inline') {
style.paddingLeft = props.inlineIndent * props.level;
}
menuAllProps.forEach(key => delete props[key]);
Copy link
Member

@afc163 afc163 Apr 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这样 MenuItem 上的 onClick、onMouseEnter、onMouseLeave 就没了,这几个可以有的。

MenuItemGroup 和 SubMenu 同理。

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不对啊,,,这些事件不是在内部重写了吗???那还带上干啥???
有 { ...mouseEvent } 啊...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好像只有 group 上有用,,加着吧。。。

return (
<li
{...props}
{...attrs}
{...mouseEvent}
style={style}
Expand Down
13 changes: 8 additions & 5 deletions src/MenuItemGroup.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { menuAllProps } from './util';

class MenuItemGroup extends React.Component {
static propTypes = {
Expand All @@ -20,20 +21,22 @@ class MenuItemGroup extends React.Component {
}

render() {
const props = this.props;
const { ...props } = this.props;
const { className = '', rootPrefixCls } = props;
const titleClassName = `${rootPrefixCls}-item-group-title`;
const listClassName = `${rootPrefixCls}-item-group-list`;
const { title, children } = props;
menuAllProps.forEach(key => delete props[key]);
return (
<li className={`${className} ${rootPrefixCls}-item-group`}>
<li {...props} className={`${className} ${rootPrefixCls}-item-group`}>
<div
className={titleClassName}
title={typeof props.title === 'string' ? props.title : undefined}
title={typeof title === 'string' ? title : undefined}
>
{props.title}
{title}
</div>
<ul className={listClassName}>
{React.Children.map(props.children, this.renderInnerMenuItem)}
{React.Children.map(children, this.renderInnerMenuItem)}
</ul>
</li>
);
Expand Down
22 changes: 15 additions & 7 deletions src/SubMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
noop,
loopMenuItemRecursively,
getMenuIdFromSubMenuEventKey,
menuAllProps,
} from './util';

let guid = 0;
Expand Down Expand Up @@ -404,7 +405,7 @@ export class SubMenu extends React.Component {
}

render() {
const props = this.props;
const props = { ...this.props };
const isOpen = props.isOpen;
const prefixCls = this.getPrefixCls();
const isInlineMode = props.mode === 'inline';
Expand Down Expand Up @@ -469,9 +470,16 @@ export class SubMenu extends React.Component {
props.parentMenu.props.getPopupContainer : triggerNode => triggerNode.parentNode;
const popupPlacement = popupPlacementMap[props.mode];
const popupClassName = props.mode === 'inline' ? '' : props.popupClassName;

const {
disabled,
triggerSubMenuAction,
subMenuOpenDelay,
forceSubMenuRender,
subMenuCloseDelay,
} = props;
menuAllProps.forEach(key => delete props[key]);
return (
<li {...mouseEvents} className={className} style={props.style}>
<li {...props} {...mouseEvents} className={className}>
{isInlineMode && title}
{isInlineMode && children}
{!isInlineMode && (
Expand All @@ -483,11 +491,11 @@ export class SubMenu extends React.Component {
popupPlacement={popupPlacement}
popupVisible={isOpen}
popup={children}
action={props.disabled ? [] : [props.triggerSubMenuAction]}
mouseEnterDelay={props.subMenuOpenDelay}
mouseLeaveDelay={props.subMenuCloseDelay}
action={disabled ? [] : [triggerSubMenuAction]}
mouseEnterDelay={subMenuOpenDelay}
mouseLeaveDelay={subMenuCloseDelay}
onPopupVisibleChange={this.onPopupVisibleChange}
forceRender={props.forceSubMenuRender}
forceRender={forceSubMenuRender}
>
{title}
</Trigger>
Expand Down
21 changes: 13 additions & 8 deletions src/SubPopupMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { connect } from 'mini-store';
import KeyCode from 'rc-util/lib/KeyCode';
import createChainedFunction from 'rc-util/lib/createChainedFunction';
import classNames from 'classnames';
import { getKeyFromChildrenIndex, loopMenuItem, noop } from './util';
import { getKeyFromChildrenIndex, loopMenuItem, noop, menuAllProps } from './util';
import DOMWrap from './DOMWrap';

function allDisabled(arr) {
Expand Down Expand Up @@ -87,7 +87,7 @@ export class SubPopupMenu extends React.Component {
level: PropTypes.number,
mode: PropTypes.oneOf(['horizontal', 'vertical', 'vertical-left', 'vertical-right', 'inline']),
triggerSubMenuAction: PropTypes.oneOf(['click', 'hover']),
inlineIndent: PropTypes.oneOfType(PropTypes.number, PropTypes.string),
inlineIndent: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
manualRef: PropTypes.func,
};

Expand Down Expand Up @@ -270,7 +270,10 @@ export class SubPopupMenu extends React.Component {
eventKey: key,
active: !childProps.disabled && isActive,
multiple: props.multiple,
onClick: this.onClick,
onClick: (e) => {
(childProps.onClick || noop)(e);
this.onClick(e);
},
onItemHover: this.onItemHover,
openTransitionName: this.getOpenTransitionName(),
openAnimation: props.openAnimation,
Expand Down Expand Up @@ -304,7 +307,7 @@ export class SubPopupMenu extends React.Component {
};

render() {
const props = this.props;
const { ...props } = this.props;
this.instanceArray = [];
const className = classNames(
props.prefixCls,
Expand All @@ -323,19 +326,21 @@ export class SubPopupMenu extends React.Component {
domProps.tabIndex = '0';
domProps.onKeyDown = this.onKeyDown;
}
const { prefixCls, eventKey, visible } = props;
menuAllProps.forEach(key => delete props[key]);
return (
// ESLint is not smart enough to know that the type of `children` was checked.
/* eslint-disable */
<DOMWrap
style={props.style}
{...props}
tag="ul"
hiddenClassName={`${props.prefixCls}-hidden`}
visible={props.visible}
hiddenClassName={`${prefixCls}-hidden`}
visible={visible}
{...domProps}
>
{React.Children.map(
props.children,
(c, i) => this.renderMenuItem(c, i, props.eventKey || '0-menu-'),
(c, i) => this.renderMenuItem(c, i, eventKey || '0-menu-'),
)}
</DOMWrap>
/*eslint-enable */
Expand Down
49 changes: 47 additions & 2 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ export function loopMenuItemRecursively(children, keys, ret) {
if (c) {
const construct = c.type;
if (!construct
||
!(construct.isSubMenu || construct.isMenuItem || construct.isMenuItemGroup)
||
!(construct.isSubMenu || construct.isMenuItem || construct.isMenuItemGroup)
) {
return;
}
Expand All @@ -49,3 +49,48 @@ export function loopMenuItemRecursively(children, keys, ret) {
}
});
}

export const menuAllProps = [
'defaultSelectedKeys',
'selectedKeys',
'defaultOpenKeys',
'openKeys',
'mode',
'getPopupContainer',
'onSelect',
'onDeselect',
'onDestroy',
'openTransitionName',
'openAnimation',
'subMenuOpenDelay',
'subMenuCloseDelay',
'forceSubMenuRender',
'triggerSubMenuAction',
'level',
'selectable',
'multiple',
'onOpenChange',
'visible',
'focusable',
'defaultActiveFirst',
'prefixCls',
'inlineIndent',
'parentMenu',
'title',
'rootPrefixCls',
'eventKey',
'active',
'onItemHover',
'onTitleMouseEnter',
'onTitleMouseLeave',
'onTitleClick',
'isOpen',
'renderMenuItem',
'manualRef',
'subMenuKey',
'disabled',
'index',
'isSelected',
'store',
'activeKey',
];
33 changes: 32 additions & 1 deletion tests/MenuItem.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import React from 'react';
import { mount, shallow } from 'enzyme';
import KeyCode from 'rc-util/lib/KeyCode';
import Menu, { MenuItem } from '../src';
import Menu, { MenuItem, MenuItemGroup, SubMenu } from '../src';

import { MenuItem as NakedMenuItem } from '../src/MenuItem';

Expand Down Expand Up @@ -81,4 +81,35 @@ describe('MenuItem', () => {
expect(onMouseLeave).toHaveBeenCalledWith({ key, domEvent });
});
});

describe('rest props', () => {
it('can render all props to sub component', () => {
const onClick = jest.fn();
const restProps = {
onClick,
'data-whatever': 'whatever',
title: 'title',
className: 'className',
style: { fontSize: 20 },
};
const wrapper = mount(
<Menu mode="inline" activeKey="1">
<MenuItem key="1" {...restProps}>1</MenuItem>
<SubMenu {...restProps}>
<MenuItem key="2" {...restProps}>3</MenuItem>
</SubMenu>
<MenuItemGroup {...restProps}>
<MenuItem key="3" {...restProps}>4</MenuItem>
</MenuItemGroup>
</Menu>
);
expect(wrapper.render()).toMatchSnapshot();
wrapper.find('MenuItem').at(0).simulate('click');
expect(onClick).toHaveBeenCalledTimes(1);
wrapper.find('SubMenu').at(0).simulate('click');
expect(onClick).toHaveBeenCalledTimes(2);
wrapper.find('MenuItemGroup').at(0).simulate('click');
expect(onClick).toHaveBeenCalledTimes(3);
});
});
});
67 changes: 67 additions & 0 deletions tests/__snapshots__/MenuItem.spec.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`MenuItem rest props can render all props to sub component 1`] = `
<ul
aria-activedescendant=""
class="rc-menu rc-menu-root rc-menu-inline"
role="menu"
tabindex="0"
>
<li
aria-selected="false"
class="rc-menu-item className rc-menu-item-active"
data-whatever="whatever"
role="menuitem"
style="font-size: 20px; padding-left: 24px;"
title="title"
>
1
</li>
<li
class="rc-menu-submenu rc-menu-submenu-inline className"
data-whatever="whatever"
style="font-size: 20px;"
>
<div
aria-expanded="false"
aria-haspopup="true"
aria-owns="item_1$Menu"
class="rc-menu-submenu-title"
style="padding-left: 24px;"
title="title"
>
title
<i
class="rc-menu-submenu-arrow"
/>
</div>
<div />
</li>
<li
class="className rc-menu-item-group"
data-whatever="whatever"
style="font-size: 20px;"
>
<div
class="rc-menu-item-group-title"
title="title"
>
title
</div>
<ul
class="rc-menu-item-group-list"
>
<li
aria-selected="false"
class="rc-menu-item className"
data-whatever="whatever"
role="menuitem"
style="font-size: 20px; padding-left: 24px;"
title="title"
>
4
</li>
</ul>
</li>
</ul>
`;