Skip to content

Commit

Permalink
Add Menu component
Browse files Browse the repository at this point in the history
  • Loading branch information
John Benavides committed Dec 27, 2017
1 parent 56e6432 commit e39abbf
Show file tree
Hide file tree
Showing 12 changed files with 437 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/))
Expand Down
1 change: 1 addition & 0 deletions src/__test__/__snapshots__/index.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Object {
"Level": [Function],
"Loader": [Function],
"Media": [Function],
"Menu": [Function],
"Modal": [Function],
"Navbar": [Function],
"Notification": [Function],
Expand Down
148 changes: 148 additions & 0 deletions src/components/menu/__test__/__snapshots__/menu.test.js.snap
Original file line number Diff line number Diff line change
@@ -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`] = `
<aside
className="menu"
>
<p
className="menu-label"
>
General
</p>
<ul
className="menu-list"
>
<li>
<span
className=""
>
Custom
Dashboard
</span>
</li>
<li>
<span
className=""
>
Custom
Customer
</span>
</li>
</ul>
</aside>
`;

exports[`Menu component Should concat Menu.List to display as submenus 1`] = `
<aside
className="menu"
>
<p
className="menu-label"
>
General
</p>
<ul
className="menu-list"
>
<li>
<a
className=""
>
Dashboard
</a>
</li>
<li>
<li>
<a
className="is-active"
>
Manage Your Team
</a>
<ul
className="menu-list"
>
<li>
<a
className=""
>
Members
</a>
</li>
<li>
<a
className="is-active"
>
Plugins
</a>
</li>
<li>
<a
className=""
>
Add a member
</a>
</li>
</ul>
</li>
</li>
</ul>
</aside>
`;

exports[`Menu component Should have menu classnames 1`] = `
<aside
className="menu"
>
<p
className="menu-label"
>
General
</p>
<ul
className="menu-list"
>
<li>
<a
className=""
>
Dashboard
</a>
</li>
<li>
<a
className=""
>
Customer
</a>
</li>
</ul>
</aside>
`;

exports[`Menu component Should render custom item child 1`] = `
<aside
className="menu"
>
<p
className="menu-label"
>
General
</p>
<ul
className="menu-list"
>
<li>
<p>
Custom children 1
</p>
</li>
<li>
<a>
Custom children 2
</a>
</li>
</ul>
</aside>
`;
84 changes: 84 additions & 0 deletions src/components/menu/__test__/menu.test.js
Original file line number Diff line number Diff line change
@@ -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(
<Menu>
<Menu.List title="General">
<Menu.List.Item>
Dashboard
</Menu.List.Item>
<Menu.List.Item>
Customer
</Menu.List.Item>
</Menu.List>
</Menu>,
);
expect(component.toJSON()).toMatchSnapshot();
});
it('Should concat Menu.List to display as submenus', () => {
const component = renderer.create(
<Menu>
<Menu.List title="General">
<Menu.List.Item>
Dashboard
</Menu.List.Item>
<Menu.List.Item>
<Menu.List.Item active>
<Menu.List title="Manage Your Team">
<Menu.List.Item>
Members
</Menu.List.Item>
<Menu.List.Item active>
Plugins
</Menu.List.Item>
<Menu.List.Item>
Add a member
</Menu.List.Item>
</Menu.List>
</Menu.List.Item>
</Menu.List.Item>
</Menu.List>
</Menu>,
);
expect(component.toJSON()).toMatchSnapshot();
});
it('Should accept a react Element as renderAs prop', () => {
// eslint-disable-next-line react/prop-types
const Custom = props => (<span {...props}>Custom {props.children}</span>);
const component = renderer.create(
<Menu>
<Menu.List title="General">
<Menu.List.Item renderAs={Custom}>
Dashboard
</Menu.List.Item>
<Menu.List.Item renderAs={Custom}>
Customer
</Menu.List.Item>
</Menu.List>
</Menu>,
);
expect(component.toJSON()).toMatchSnapshot();
});
it('Should render custom item child', () => {
// eslint-disable-next-line react/prop-types
const component = renderer.create(
<Menu>
<Menu.List title="General">
<Menu.List.Item>
<p>Custom children 1</p>
</Menu.List.Item>
<Menu.List.Item>
<a>Custom children 2</a>
</Menu.List.Item>
</Menu.List>
</Menu>,
);
expect(component.toJSON()).toMatchSnapshot();
});
});
57 changes: 57 additions & 0 deletions src/components/menu/components/list/components/item.js
Original file line number Diff line number Diff line change
@@ -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 (
<li>
<Element className={classnames(className, { 'is-active': active })} {...props}>{children}</Element>
</li>
);
}

if (React.Children.only(children).type === List) {
const child = React.Children.only(children);
return (
<li>
<Element className={classnames(className, { 'is-active': active })} {...props}>{child.props.title}</Element>
{React.cloneElement(child, { title: null })}
</li>
);
}

return <li>{children}</li>;
}
}
1 change: 1 addition & 0 deletions src/components/menu/components/list/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './list';
39 changes: 39 additions & 0 deletions src/components/menu/components/list/list.js
Original file line number Diff line number Diff line change
@@ -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 (
<React.Fragment>
{
title &&
<p className="menu-label">
{title}
</p>
}
<ul className={classnames('menu-list', className)} {...props} />
</React.Fragment>
);
}
}
3 changes: 3 additions & 0 deletions src/components/menu/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import './menu.sass';

export { default } from './menu';
36 changes: 36 additions & 0 deletions src/components/menu/menu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import MenuList from './components/list';

export default class Menu extends PureComponent {
static propTypes = {
className: PropTypes.string,
renderAs: PropTypes.oneOfType([
PropTypes.string,
PropTypes.func,
]),
}

static defaultProps = {
className: '',
renderAs: 'aside',
}

static List = MenuList;

render() {
const {
className,
renderAs,
...props
} = this.props;
const Element = renderAs;
return (
<Element
{...props}
className={classnames('menu', className)}
/>
);
}
}
2 changes: 2 additions & 0 deletions src/components/menu/menu.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@import '../utils.sass';
@import '~bulma/sass/components/menu.sass';
Loading

0 comments on commit e39abbf

Please sign in to comment.