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