diff --git a/README.md b/README.md index 90f15d39..b4174abe 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ The Following componets were ported: - Level ([Storybook](https://couds.github.io/react-bulma-components/?selectedKind=Level)) ([Docs](http://bulma.io/documentation/layout/level/)) - Loader ([Storybook](https://couds.github.io/react-bulma-components/?selectedKind=Loader)) - Media ([Storybook](https://couds.github.io/react-bulma-components/?selectedKind=Media)) ([Docs](http://bulma.io/documentation/layout/media-object/)) +- Menu ([Storybook](https://couds.github.io/react-bulma-components/?selectedKind=Menu)) ([Docs](http://bulma.io/documentation/components/menu/)) - Modal ([Storybook](https://couds.github.io/react-bulma-components/?selectedKind=Modal)) ([Docs](http://bulma.io/documentation/components/modal/)) - Navbar ([Storybook](https://couds.github.io/react-bulma-components/?selectedKind=Navbar)) ([Docs](https://bulma.io/documentation/components/navbar/)) - Notification ([Storybook](https://couds.github.io/react-bulma-components/?selectedKind=Notification)) ([Docs](http://bulma.io/documentation/elements/notification/)) diff --git a/src/__test__/__snapshots__/index.test.js.snap b/src/__test__/__snapshots__/index.test.js.snap index 50a0a714..17ee4806 100644 --- a/src/__test__/__snapshots__/index.test.js.snap +++ b/src/__test__/__snapshots__/index.test.js.snap @@ -28,6 +28,7 @@ Object { "Level": [Function], "Loader": [Function], "Media": [Function], + "Menu": [Function], "Modal": [Function], "Navbar": [Function], "Notification": [Function], diff --git a/src/components/menu/__test__/__snapshots__/menu.test.js.snap b/src/components/menu/__test__/__snapshots__/menu.test.js.snap new file mode 100644 index 00000000..4d99b14d --- /dev/null +++ b/src/components/menu/__test__/__snapshots__/menu.test.js.snap @@ -0,0 +1,148 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Menu component Should Exist 1`] = `[Function]`; + +exports[`Menu component Should accept a react Element as renderAs prop 1`] = ` + +`; + +exports[`Menu component Should concat Menu.List to display as submenus 1`] = ` + +`; + +exports[`Menu component Should have menu classnames 1`] = ` + +`; + +exports[`Menu component Should render custom item child 1`] = ` + +`; diff --git a/src/components/menu/__test__/menu.test.js b/src/components/menu/__test__/menu.test.js new file mode 100644 index 00000000..1a5f645c --- /dev/null +++ b/src/components/menu/__test__/menu.test.js @@ -0,0 +1,84 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import Menu from '..'; + +describe('Menu component', () => { + it('Should Exist', () => { + expect(Menu).toMatchSnapshot(); + }); + it('Should have menu classnames', () => { + const component = renderer.create( + + + + Dashboard + + + Customer + + + , + ); + expect(component.toJSON()).toMatchSnapshot(); + }); + it('Should concat Menu.List to display as submenus', () => { + const component = renderer.create( + + + + Dashboard + + + + + + Members + + + Plugins + + + Add a member + + + + + + , + ); + expect(component.toJSON()).toMatchSnapshot(); + }); + it('Should accept a react Element as renderAs prop', () => { + // eslint-disable-next-line react/prop-types + const Custom = props => (Custom {props.children}); + const component = renderer.create( + + + + Dashboard + + + Customer + + + , + ); + expect(component.toJSON()).toMatchSnapshot(); + }); + it('Should render custom item child', () => { + // eslint-disable-next-line react/prop-types + const component = renderer.create( + + + +

Custom children 1

+
+ + Custom children 2 + +
+
, + ); + expect(component.toJSON()).toMatchSnapshot(); + }); +}); diff --git a/src/components/menu/components/list/components/item.js b/src/components/menu/components/list/components/item.js new file mode 100644 index 00000000..081f33e7 --- /dev/null +++ b/src/components/menu/components/list/components/item.js @@ -0,0 +1,57 @@ +import React, { PureComponent } from 'react'; +import PropTypes from 'prop-types'; +import classnames from 'classnames'; +import List from '../list'; + +export default class MenuListItem extends PureComponent { + static displayName = 'Menu.List.Item' + + static propTypes = { + className: PropTypes.string, + children: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.element, + ]), + active: PropTypes.bool, + renderAs: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.func, + ]), + } + + static defaultProps = { + className: '', + children: null, + active: false, + renderAs: 'a', + } + render() { + const { + children, + active, + className, + renderAs, + ...props + } = this.props; + const Element = renderAs; + if (typeof children === 'string') { + return ( +
  • + {children} +
  • + ); + } + + if (React.Children.only(children).type === List) { + const child = React.Children.only(children); + return ( +
  • + {child.props.title} + {React.cloneElement(child, { title: null })} +
  • + ); + } + + return
  • {children}
  • ; + } +} diff --git a/src/components/menu/components/list/index.js b/src/components/menu/components/list/index.js new file mode 100644 index 00000000..ea1fedd0 --- /dev/null +++ b/src/components/menu/components/list/index.js @@ -0,0 +1 @@ +export { default } from './list'; diff --git a/src/components/menu/components/list/list.js b/src/components/menu/components/list/list.js new file mode 100644 index 00000000..fb23785c --- /dev/null +++ b/src/components/menu/components/list/list.js @@ -0,0 +1,39 @@ +import React, { PureComponent } from 'react'; +import PropTypes from 'prop-types'; +import classnames from 'classnames'; +import MenuListItem from './components/item'; + +export default class MenuList extends PureComponent { + static displayName = 'Menu.List' + + static propTypes = { + className: PropTypes.string, + title: PropTypes.node, + } + + static defaultProps = { + className: '', + title: null, + } + + static Item = MenuListItem; + + render() { + const { + className, + title, + ...props + } = this.props; + return ( + + { + title && +

    + {title} +

    + } +