From a951e0bdc96e8b4c8e4bd5813cebd96e38d701e0 Mon Sep 17 00:00:00 2001 From: Alf Eaton <eaton.alf@gmail.com> Date: Thu, 24 Aug 2017 12:44:48 +0100 Subject: [PATCH] Improve Menu implementation and add initial test --- src/atoms/Menu.js | 75 ++++++++++++++++++++++++++++++++++++++++ src/atoms/Menu.local.css | 1 + src/index.js | 1 + test/Menu.test.js | 29 ++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 src/atoms/Menu.js create mode 100644 test/Menu.test.js diff --git a/src/atoms/Menu.js b/src/atoms/Menu.js new file mode 100644 index 000000000..c7a34a0b4 --- /dev/null +++ b/src/atoms/Menu.js @@ -0,0 +1,75 @@ +import React from 'react' +import classnames from 'classnames' +import classes from './Menu.local.css' + +class Menu extends React.Component { + constructor (props) { + super(props) + + this.state = { + open: false, + selected: props.value + } + } + + toggleMenu = () => { + this.setState({ + open: !this.state.open + }) + } + + handleSelect = selected => { + this.setState({ + selected, + open: false + }) + + // TODO: fire "change" event + } + + optionLabel = value => { + const { options } = this.props + + return options.find(option => option.value === value).label + } + + render () { + const { options, placeholder = 'Choose in the list' } = this.props + const { open, selected } = this.state + + return ( + <div className={classes.root}> + <div> + <button + className={classes.opener} + onClick={this.toggleMenu}> + {selected ? ( + <span>{this.optionLabel(selected)}</span> + ) : ( + <span className={classes.placeholder}>{placeholder}</span> + )} + <span className={classes.arrow}>{ open ? 'â–²' : 'â–¼' }</span> + </button> + </div> + + <div className={classes.menuContainer}> + {open && ( + <div className={classes.menu}> + {options.map(option => ( + <div + key={option.value} + className={classnames(classes.option, { + [classes.active]: option.value === selected + })} + onClick={() => this.handleSelect(option.value)} + >{option.label || option.value}</div> + ))} + </div> + )} + </div> + </div> + ) + } +} + +export default Menu diff --git a/src/atoms/Menu.local.css b/src/atoms/Menu.local.css index 8f3d39ad1..ac7343c2f 100644 --- a/src/atoms/Menu.local.css +++ b/src/atoms/Menu.local.css @@ -41,6 +41,7 @@ .option { cursor: pointer; padding: 10px; + white-space: nowrap; } .option:hover { diff --git a/src/index.js b/src/index.js index b506e2384..370bfa72d 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,4 @@ +export { default as Menu } from './atoms/Menu' export { default as Tags } from './atoms/Tags' export { default as AppBar } from './molecules/AppBar' export { default as YesOrNo } from './molecules/YesOrNo' diff --git a/test/Menu.test.js b/test/Menu.test.js new file mode 100644 index 000000000..e575fef6a --- /dev/null +++ b/test/Menu.test.js @@ -0,0 +1,29 @@ +import React from 'react' +import { shallow } from 'enzyme' +// import renderer from 'react-test-renderer' + +import Menu from '../src/atoms/Menu' + +const props = { + options: [ + { value: 'foo', label: 'Foo' }, + { value: 'bar', label: 'Bar' }, + ], + value: 'foo' +} + +const wrapper = shallow(<Menu {...props} />) + +describe('Menu', () => { + /*test('Snapshot', () => { + const tree = renderer.create( + <Menu {...props} /> + ).toJSON() + expect(tree).toMatchSnapshot() + })*/ + + test('Renders a Menu', () => { + expect(wrapper.is('div')).toBeTruthy() + expect(wrapper).toHaveLength(1) + }) +}) -- GitLab