-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Tabs): add TabContent & TabPane components (#131)
* feat(tabs): Adds TabContent and TabPane components #72 * feat(Tab): Adds docs for Tab (TabContent and TabPane) component * feat(Tab): Adds test for Tab component * feat(Tab): Adds \/tabs route to webpack.dev.config.js * Fixes TabContent and TabPane to use contextTypes for communicating active Tab * Updates Tabs.spec.js based on changes made to TabContent and TabPane + pushes code coverage to 100% * Adds extra check in TabContent while setting activeTab + moves classnames out to const variables from jsx
- Loading branch information
1 parent
af874bc
commit 2957ede
Showing
9 changed files
with
245 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* eslint react/no-multi-comp: 0, react/prop-types: 0 */ | ||
import React from 'react'; | ||
import { PrismCode } from 'react-prism'; | ||
import Helmet from 'react-helmet'; | ||
|
||
import TabsExample from '../examples/Tabs'; | ||
const TabsExampleSource = require('!!raw!../examples/Tabs'); | ||
|
||
export default function TabsPage() { | ||
return ( | ||
<div> | ||
<Helmet title="Tabs" /> | ||
<h3>Tabs</h3> | ||
<hr /> | ||
<div className="docs-example"> | ||
<TabsExample /> | ||
</div> | ||
<pre> | ||
<PrismCode className="language-jsx"> | ||
{TabsExampleSource} | ||
</PrismCode> | ||
</pre> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import React from 'react'; | ||
import { TabContent, TabPane, Nav, NavItem, NavLink, Card, Button, CardTitle, CardText, Row, Col } from 'reactstrap'; | ||
import classnames from 'classnames'; | ||
|
||
export default class Example extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.toggle = this.toggle.bind(this); | ||
this.state = { | ||
activeTab: '1' | ||
}; | ||
} | ||
|
||
toggle(tab) { | ||
if (this.state.activeTab !== tab) { | ||
this.setState({ | ||
activeTab: tab | ||
}); | ||
} | ||
} | ||
render() { | ||
return ( | ||
<div> | ||
<Nav tabs> | ||
<NavItem> | ||
<NavLink | ||
className={classnames({ active: this.state.activeTab === '1' })} | ||
onClick={() => { this.toggle('1'); }} | ||
> | ||
Tab1 | ||
</NavLink> | ||
</NavItem> | ||
<NavItem> | ||
<NavLink | ||
className={classnames({ active: this.state.activeTab === '2' })} | ||
onClick={() => { this.toggle('2'); }} | ||
> | ||
Moar Tabs | ||
</NavLink> | ||
</NavItem> | ||
</Nav> | ||
<TabContent activeTab={this.state.activeTab}> | ||
<TabPane tabId="1"> | ||
<Row> | ||
<Col sm="12"> | ||
<h4>Tab 1 Contents</h4> | ||
</Col> | ||
</Row> | ||
</TabPane> | ||
<TabPane tabId="2"> | ||
<Row> | ||
<Col sm="6"> | ||
<Card block> | ||
<CardTitle>Special Title Treatment</CardTitle> | ||
<CardText>With supporting text below as a natural lead-in to additional content.</CardText> | ||
<Button>Go somewhere</Button> | ||
</Card> | ||
</Col> | ||
<Col sm="6"> | ||
<Card block> | ||
<CardTitle>Special Title Treatment</CardTitle> | ||
<CardText>With supporting text below as a natural lead-in to additional content.</CardText> | ||
<Button>Go somewhere</Button> | ||
</Card> | ||
</Col> | ||
</Row> | ||
</TabPane> | ||
</TabContent> | ||
</div> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import React, { PropTypes, Component } from 'react'; | ||
import classnames from 'classnames'; | ||
|
||
const propTypes = { | ||
children: PropTypes.node, | ||
activeTab: PropTypes.any, | ||
className: PropTypes.string | ||
}; | ||
|
||
const childContextTypes = { | ||
activeTabId: PropTypes.any | ||
}; | ||
|
||
export default class TabContent extends Component { | ||
constructor(props) { | ||
super(props); | ||
this.state = { | ||
activeTab: this.props.activeTab | ||
}; | ||
} | ||
getChildContext() { | ||
return { | ||
activeTabId: this.state.activeTab | ||
}; | ||
} | ||
componentWillReceiveProps(nextProps) { | ||
if (this.state.activeTab !== nextProps.activeTab) { | ||
this.setState({ | ||
activeTab: nextProps.activeTab | ||
}); | ||
} | ||
} | ||
render() { | ||
const classes = classnames('tab-content', this.props.className); | ||
return ( | ||
<div className={classes}> | ||
{ this.props.children } | ||
</div> | ||
); | ||
} | ||
} | ||
TabContent.propTypes = propTypes; | ||
TabContent.childContextTypes = childContextTypes; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
|
||
import React, { PropTypes } from 'react'; | ||
import classnames from 'classnames'; | ||
|
||
const propTypes = { | ||
children: PropTypes.node, | ||
className: PropTypes.string, | ||
tabId: PropTypes.any | ||
}; | ||
const contextTypes = { | ||
activeTabId: PropTypes.any | ||
}; | ||
|
||
export default function TabPane(props, context) { | ||
const { | ||
className, | ||
tabId, | ||
children, | ||
...attributes | ||
} = props; | ||
const classes = classnames('tab-pane', className, { active: tabId === context.activeTabId }); | ||
return ( | ||
<div {...attributes} className={classes}> | ||
{children} | ||
</div> | ||
); | ||
} | ||
TabPane.propTypes = propTypes; | ||
TabPane.contextTypes = contextTypes; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/* eslint react/no-multi-comp: 0, react/prop-types: 0 */ | ||
import React from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
|
||
import { mount } from 'enzyme'; | ||
import { Nav, NavItem, NavLink, TabContent, TabPane } from 'reactstrap'; | ||
import classnames from 'classnames'; | ||
// Not sure if this is correct but didn't want to repeat a whole bunch of code. | ||
import TabsExample from '../docs/lib/examples/Tabs'; | ||
|
||
describe('Tabs', () => { | ||
it('should render', () => { | ||
let tab1 = mount(<TabsExample />); | ||
expect(tab1.find('.nav .nav-tabs').length).toBe(1); | ||
expect(tab1.find('.nav .nav-item').length).toBe(2); | ||
expect(tab1.find('.tab-content').length).toBe(1); | ||
expect(tab1.find('.tab-pane').length).toBe(2); | ||
}); | ||
it('should have tab1 as active', () => { | ||
let tab1 = mount(<TabsExample />); | ||
expect(tab1.find('.nav .nav-item .nav-link').at(0).hasClass('active')).toBe(true); | ||
expect(tab1.find('.nav .nav-item .nav-link').at(1).hasClass('active')).toBe(false); | ||
expect(tab1.find('.tab-content .tab-pane').at(0).hasClass('active')).toBe(true); | ||
}); | ||
it('should switch to tab2 as active when clicked', () => { | ||
let tab1 = mount(<TabsExample />); | ||
expect(tab1.find('.nav .nav-item .nav-link').at(0).hasClass('active')).toBe(true); | ||
expect(tab1.find('.nav .nav-item .nav-link').at(1).hasClass('active')).toBe(false); | ||
expect(tab1.find('.tab-content .tab-pane').at(0).hasClass('active')).toBe(true); | ||
tab1.find('.nav .nav-item .nav-link').at(1).simulate('click'); | ||
expect(tab1.find('.nav .nav-item .nav-link').at(0).hasClass('active')).toBe(false); | ||
expect(tab1.find('.nav .nav-item .nav-link').at(1).hasClass('active')).toBe(true); | ||
expect(tab1.find('.tab-content .tab-pane').at(1).hasClass('active')).toBe(true); | ||
tab1.find('.nav .nav-item .nav-link').at(0).simulate('click'); | ||
}); | ||
it('should show no active tabs if active tab id is unknown', () => { | ||
let tab1 = mount(<TabsExample />); | ||
const instance = tab1.instance(); | ||
expect(instance instanceof TabsExample).toBe(true); | ||
instance.toggle('3'); | ||
/* Not sure if this is what we want. Toggling to an unknown tab id should | ||
render all tabs as inactive and should show no content. | ||
This could be a warning during development that the user is not having a proper tab ids. | ||
NOTE: Should this be different? | ||
*/ | ||
expect(tab1.find('.nav .nav-item .nav-link').at(0).hasClass('active')).toBe(false); | ||
expect(tab1.find('.nav .nav-item .nav-link').at(1).hasClass('active')).toBe(false); | ||
expect(tab1.find('.tab-content .tab-pane').at(0).hasClass('active')).toBe(false); | ||
}); | ||
it('should do nothing clicking on the same tab', () => { | ||
let tab1 = mount(<TabsExample />); | ||
expect(tab1.find('.nav .nav-item .nav-link').at(0).hasClass('active')).toBe(true); | ||
expect(tab1.find('.nav .nav-item .nav-link').at(1).hasClass('active')).toBe(false); | ||
expect(tab1.find('.tab-content .tab-pane').at(0).hasClass('active')).toBe(true); | ||
tab1.find('.nav .nav-item .nav-link').at(0).simulate('click'); | ||
expect(tab1.find('.nav .nav-item .nav-link').at(0).hasClass('active')).toBe(true); | ||
expect(tab1.find('.nav .nav-item .nav-link').at(1).hasClass('active')).toBe(false); | ||
expect(tab1.find('.tab-content .tab-pane').at(0).hasClass('active')).toBe(true); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters