diff --git a/src/MenuItem.jsx b/src/MenuItem.jsx
index 3920b7b5..19e483a6 100644
--- a/src/MenuItem.jsx
+++ b/src/MenuItem.jsx
@@ -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 */
@@ -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,
@@ -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]);
return (
delete props[key]);
return (
-
+
- {props.title}
+ {title}
- {React.Children.map(props.children, this.renderInnerMenuItem)}
+ {React.Children.map(children, this.renderInnerMenuItem)}
);
diff --git a/src/SubMenu.jsx b/src/SubMenu.jsx
index 9c9c6bae..951fe578 100644
--- a/src/SubMenu.jsx
+++ b/src/SubMenu.jsx
@@ -12,6 +12,7 @@ import {
noop,
loopMenuItemRecursively,
getMenuIdFromSubMenuEventKey,
+ menuAllProps,
} from './util';
let guid = 0;
@@ -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';
@@ -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 (
-
+
{isInlineMode && title}
{isInlineMode && children}
{!isInlineMode && (
@@ -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}
diff --git a/src/SubPopupMenu.js b/src/SubPopupMenu.js
index 7bcecb5b..cd3c71f1 100644
--- a/src/SubPopupMenu.js
+++ b/src/SubPopupMenu.js
@@ -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) {
@@ -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,
};
@@ -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,
@@ -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,
@@ -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 */
{React.Children.map(
props.children,
- (c, i) => this.renderMenuItem(c, i, props.eventKey || '0-menu-'),
+ (c, i) => this.renderMenuItem(c, i, eventKey || '0-menu-'),
)}
/*eslint-enable */
diff --git a/src/util.js b/src/util.js
index 82c07f4f..d4556ed6 100644
--- a/src/util.js
+++ b/src/util.js
@@ -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;
}
@@ -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',
+];
diff --git a/tests/MenuItem.spec.js b/tests/MenuItem.spec.js
index b87064c7..1e65bc5c 100644
--- a/tests/MenuItem.spec.js
+++ b/tests/MenuItem.spec.js
@@ -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';
@@ -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(
+
+ );
+ 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);
+ });
+ });
});
diff --git a/tests/__snapshots__/MenuItem.spec.js.snap b/tests/__snapshots__/MenuItem.spec.js.snap
new file mode 100644
index 00000000..3fb01614
--- /dev/null
+++ b/tests/__snapshots__/MenuItem.spec.js.snap
@@ -0,0 +1,67 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`MenuItem rest props can render all props to sub component 1`] = `
+
+`;