diff --git a/components/menu/IconMenu.d.ts b/components/menu/IconMenu.d.ts index 931bcfe0..f7140965 100644 --- a/components/menu/IconMenu.d.ts +++ b/components/menu/IconMenu.d.ts @@ -13,6 +13,11 @@ export interface IconMenuTheme { } export interface IconMenuProps extends ReactToolbox.Props { + /** + * If true, the inner Menu component will be active. + * @default false + */ + active?: boolean; /** * Children to pass through the component. */ diff --git a/components/menu/IconMenu.js b/components/menu/IconMenu.js index e82e7fd4..d00fd3f5 100644 --- a/components/menu/IconMenu.js +++ b/components/menu/IconMenu.js @@ -9,6 +9,7 @@ import InjectMenu from './Menu'; const factory = (IconButton, Menu) => { class IconMenu extends Component { static propTypes = { + active: PropTypes.bool, children: PropTypes.node, className: PropTypes.string, icon: PropTypes.oneOfType([ @@ -32,6 +33,7 @@ const factory = (IconButton, Menu) => { }; static defaultProps = { + active: false, className: '', icon: 'more_vert', iconRipple: true, @@ -41,7 +43,13 @@ const factory = (IconButton, Menu) => { }; state = { - active: false, + active: this.props.active, + } + + componentWillReceiveProps(nextProps) { + if (this.state.active !== nextProps.active) { + this.setState({ active: nextProps.active }); + } } handleButtonClick = (event) => { @@ -56,7 +64,7 @@ const factory = (IconButton, Menu) => { render() { const { - children, className, icon, iconRipple, inverse, menuRipple, onHide, // eslint-disable-line + active, children, className, icon, iconRipple, inverse, menuRipple, onHide, // eslint-disable-line onSelect, onShow, position, selectable, selected, theme, ...other } = this.props; return ( diff --git a/components/menu/__test__/index.spec.js b/components/menu/__test__/index.spec.js index be98b943..59624fcf 100644 --- a/components/menu/__test__/index.spec.js +++ b/components/menu/__test__/index.spec.js @@ -1,8 +1,60 @@ import React from 'react'; -import { shallow } from 'enzyme'; +import { mount, shallow } from 'enzyme'; +import { IconMenu } from '../IconMenu'; import { Menu } from '../Menu'; import { MenuItem } from '../MenuItem'; +describe('IconMenu', () => { + describe('#on mount', () => { + describe('when \'active\' prop is not set', () => { + it('sets \'active\' Menu prop correctly', () => { + const wrapper = shallow(); + expect(wrapper.find('Menu').props().active).toBe(false); + }); + }); + + describe('when \'active\' prop is set to false', () => { + it('sets \'active\' Menu prop correctly', () => { + const wrapper = shallow(); + expect(wrapper.find('Menu').props().active).toBe(false); + }); + + it('sets \'active\' Menu prop correctly after IconButton click', () => { + const wrapper = mount(); + wrapper.find('IconButton').simulate('click'); + expect(wrapper.find('Menu').props().active).toBe(true); + }); + + it('sets \'active\' Menu prop correctly when prop is set after IconButton click', () => { + const wrapper = mount(); + wrapper.find('IconButton').simulate('click'); + wrapper.setProps({ active: false }); + expect(wrapper.find('Menu').props().active).toBe(false); + }); + }); + + describe('when \'active\' prop is set to true', () => { + it('sets \'active\' Menu prop correctly', () => { + const wrapper = shallow(); + expect(wrapper.find('Menu').props().active).toBe(true); + }); + + it('sets \'active\' Menu prop correctly after IconButton click', () => { + const wrapper = mount(); + wrapper.find('IconButton').simulate('click'); + expect(wrapper.find('Menu').props().active).toBe(false); + }); + + it('sets \'active\' Menu prop correctly when prop is set after IconButton click', () => { + const wrapper = mount(); + wrapper.find('IconButton').simulate('click'); + wrapper.setProps({ active: true }); + expect(wrapper.find('Menu').props().active).toBe(true); + }); + }); + }); +}); + describe('MenuItem', () => { describe('#onClick', () => { it('passes to listener the event', () => { diff --git a/components/menu/readme.md b/components/menu/readme.md index 8bf58b99..a897042f 100644 --- a/components/menu/readme.md +++ b/components/menu/readme.md @@ -61,6 +61,7 @@ As the most usual scenario will be to open the menu from a click in an Icon, we | Name | Type | Default | Description| |:-----|:-----|:-----|:-----| +| `active` | `Boolean` | `false` | If true, the inner `Menu` component will be active. | | `className` | `String` | `''` | Set a class to give custom styles to the icon wrapper.| | `icon` | `String` or `Element` | `more_vert` | Icon font key string or Element to display the opener icon. | | `iconRipple` | `Boolean` | `true` | If true, the icon will show a ripple when is clicked. |