Skip to content

Commit

Permalink
feat(Navs): Add nav components
Browse files Browse the repository at this point in the history
  • Loading branch information
eddywashere committed Mar 27, 2016
1 parent d3fcd8d commit 5e2ba03
Show file tree
Hide file tree
Showing 9 changed files with 388 additions and 0 deletions.
57 changes: 57 additions & 0 deletions lib/Nav.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React, { PropTypes } from 'react';
import classNames from 'classnames';

const propTypes = {
inline: PropTypes.bool,
disabled: PropTypes.bool,
tabs: PropTypes.bool,
pills: PropTypes.bool,
stacked: PropTypes.bool,
navbar: PropTypes.bool,
tag: PropTypes.oneOfType([PropTypes.func, PropTypes.string])
};

const defaultProps = {
tag: 'ul'
};

class Nav extends React.Component {
constructor(props) {
super(props);
}

render() {
const {
className,
tabs,
pills,
inline,
stacked,
navbar,
tag: Tag,
...attributes
} = this.props;

const classes = classNames(
className,
'nav',
{
'navbar-nav': navbar,
'nav-tabs': tabs,
'nav-pills': pills,
'nav-inline': inline,
'nav-stacked': stacked,
'disabled': attributes.disabled
}
);

return (
<Tag {...attributes} className={classes}/>
);
}
}

Nav.propTypes = propTypes;
Nav.defaultProps = defaultProps;

export default Nav;
40 changes: 40 additions & 0 deletions lib/NavDropdown.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { PropTypes } from 'react';
import classNames from 'classnames';
import Dropdown from './Dropdown';

const propTypes = {
children: PropTypes.node,
tag: PropTypes.oneOfType([PropTypes.func, PropTypes.string])
};

const defaultProps = {
tag: 'li'
};

class NavDropdown extends React.Component {
constructor(props) {
super(props);
}

render() {
const {
className,
tag: Tag,
...attributes
} = this.props;

const classes = classNames(
className,
'nav-item'
);

return (
<Dropdown {...attributes} tag={Tag} className={classes} />
);
}
}

NavDropdown.propTypes = propTypes;
NavDropdown.defaultProps = defaultProps;

export default NavDropdown;
34 changes: 34 additions & 0 deletions lib/NavItem.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React, { PropTypes } from 'react';
import classNames from 'classnames';

const propTypes = {
tag: PropTypes.oneOfType([PropTypes.func, PropTypes.string])
};

const defaultProps = {
tag: 'li'
};

class NavItem extends React.Component {
render() {
const {
className,
tag: Tag,
...attributes
} = this.props;

const classes = classNames(
className,
'nav-item'
);

return (
<Tag {...attributes} className={classes}/>
);
}
}

NavItem.propTypes = propTypes;
NavItem.defaultProps = defaultProps;

export default NavItem;
61 changes: 61 additions & 0 deletions lib/NavLink.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React, { PropTypes } from 'react';
import classNames from 'classnames';

const propTypes = {
tag: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
disabled: PropTypes.bool,
active: PropTypes.bool
};

const defaultProps = {
tag: 'a'
};

class NavLink extends React.Component {
constructor(props) {
super(props);

this.onClick = this.onClick.bind(this);
}

onClick(e) {
if (this.props.disabled) {
return e.preventDefault();
}

if (this.props.href === '#') {
e.preventDefault();
}

if (this.props.onClick) {
this.props.onClick(e);
}
}

render() {
let {
className,
active,
tag: Tag,
...attributes
} = this.props;

const classes = classNames(
className,
'nav-link',
{
'disabled': attributes.disabled,
'active': active
}
);

return (
<Tag {...attributes} onClick={this.onClick} className={classes} />
);
}
}

NavLink.propTypes = propTypes;
NavLink.defaultProps = defaultProps;

export default NavLink;
8 changes: 8 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import Container from './Container';
import Row from './Row';
import Col from './Col';
import Nav from './Nav';
import NavItem from './NavItem';
import NavDropdown from './NavDropdown';
import NavLink from './NavLink';
import Button from './Button';
import ButtonDropdown from './ButtonDropdown';
import ButtonGroup from './ButtonGroup';
Expand All @@ -25,6 +29,10 @@ export {
Container,
Row,
Col,
Nav,
NavItem,
NavDropdown,
NavLink,
Button,
ButtonDropdown,
ButtonGroup,
Expand Down
31 changes: 31 additions & 0 deletions test/Nav.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* eslint react/no-multi-comp: 0, react/prop-types: 0 */
import React from 'react';
import { shallow } from 'enzyme';
import { Nav } from 'reactstrap';;

describe('Nav', () => {
it('should render .nav markup', () => {
const wrapper = shallow(<Nav/>);

expect(wrapper.html()).toBe('<ul class="nav"></ul>');
});

it('should render custom tag', () => {
const wrapper = shallow(<Nav tag="nav"/>);

expect(wrapper.html()).toBe('<nav class="nav"></nav>');
});

it('should render children', () => {
const wrapper = shallow(<Nav>Children</Nav>);

expect(wrapper.html()).toBe('<ul class="nav">Children</ul>');
});

it('should pass additional classNames', () => {
const wrapper = shallow(<Nav className="extra"/>);

expect(wrapper.hasClass('extra')).toBe(true);
expect(wrapper.hasClass('nav')).toBe(true);
});
});
39 changes: 39 additions & 0 deletions test/NavDropdown.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* eslint react/no-multi-comp: 0, react/prop-types: 0 */
import React from 'react';
import { mount } from 'enzyme';
import { NavDropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';;


describe('NavDropdown', () => {
let isOpen;
let toggle;

beforeEach(() => {
isOpen = false;
toggle = () => isOpen = !isOpen;
});

it('should render a single child', () => {
const wrapper = mount(<NavDropdown isOpen={isOpen} toggle={toggle}>Ello world</NavDropdown>);

expect(wrapper.text()).toBe('Ello world');
expect(wrapper.find('.nav-item').length).toBe(1);
});

it('should render multiple children when isOpen', () => {
isOpen = true;
const wrapper = mount(
<NavDropdown isOpen={isOpen} toggle={toggle}>
<DropdownToggle>Toggle</DropdownToggle>
<DropdownMenu>
<DropdownItem>Test</DropdownItem>
</DropdownMenu>
</NavDropdown>
);

expect(wrapper.find('.btn').text()).toBe('Toggle');
expect(wrapper.find('.nav-item').length).toBe(1);
expect(wrapper.find('.dropdown-item').length).toBe(1);
expect(wrapper.children().length).toBe(2);
});
});
31 changes: 31 additions & 0 deletions test/NavItem.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* eslint react/no-multi-comp: 0, react/prop-types: 0 */
import React from 'react';
import { shallow } from 'enzyme';
import { NavItem } from 'reactstrap';;

describe('NavItem', () => {
it('should render .nav-item markup', () => {
const wrapper = shallow(<NavItem/>);

expect(wrapper.html()).toBe('<li class="nav-item"></li>');
});

it('should render custom tag', () => {
const wrapper = shallow(<NavItem tag="div"/>);

expect(wrapper.html()).toBe('<div class="nav-item"></div>');
});

it('sholid render children', () => {
const wrapper = shallow(<NavItem>Children</NavItem>);

expect(wrapper.html()).toBe('<li class="nav-item">Children</li>');
});

it('should pass additional classNames', () => {
const wrapper = shallow(<NavItem className="extra"/>);

expect(wrapper.hasClass('extra')).toBe(true);
expect(wrapper.hasClass('nav-item')).toBe(true);
});
});
Loading

0 comments on commit 5e2ba03

Please sign in to comment.