Skip to content

Commit

Permalink
[changed] New Tabs API
Browse files Browse the repository at this point in the history
* Deprecates TabbedArea and TabPane
* Adds Tabs (formerly TabbedArea) and Tab (formerly TabPane)
* `tab` attribute is renamed to `title`
* Removes tests for TabbedArea and TabPane (because the deprecation
warning fails them all)
* Update docs to use Tabs and Tab examples

Signed-off-by: Kenny Wang <kwang@pivotal.io>
Signed-off-by: Caroline Taymor <ctaymor@pivotal.io>
Signed-off-by: Dominick Reinhold <dreinhold@pivotal.io>
  • Loading branch information
Caroline Taymor committed Aug 12, 2015
1 parent df1db7b commit e7cf455
Show file tree
Hide file tree
Showing 17 changed files with 462 additions and 407 deletions.
2 changes: 2 additions & 0 deletions docs/examples/.eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@
"ProgressBar",
"Row",
"SplitButton",
"Tab",
"TabbedArea",
"Table",
"TabPane",
"Tabs",
"Tooltip",
"Well",
"Thumbnail",
Expand Down
24 changes: 0 additions & 24 deletions docs/examples/TabbedAreaControlled.js

This file was deleted.

9 changes: 0 additions & 9 deletions docs/examples/TabbedAreaNoAnimation.js

This file was deleted.

9 changes: 0 additions & 9 deletions docs/examples/TabbedAreaUncontrolled.js

This file was deleted.

24 changes: 24 additions & 0 deletions docs/examples/TabsControlled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const ControlledTabs = React.createClass({
getInitialState() {
return {
key: 1
};
},

handleSelect(key) {
alert('selected ' + key);
this.setState({key});
},

render() {
return (
<Tabs activeKey={this.state.key} onSelect={this.handleSelect}>
<Tab eventKey={1} title='Tab 1'>Tab 1 content</Tab>
<Tab eventKey={2} title='Tab 2'>Tab 2 content</Tab>
<Tab eventKey={3} title='Tab 3' disabled>Tab 3 content</Tab>
</Tabs>
);
}
});

React.render(<ControlledTabs />, mountNode);
9 changes: 9 additions & 0 deletions docs/examples/TabsNoAnimation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const tabsInstance = (
<Tabs defaultActiveKey={1} animation={false}>
<Tab eventKey={1} title='Tab 1'>Tab 1 content</Tab>
<Tab eventKey={2} title='Tab 2'>Tab 2 content</Tab>
<Tab eventKey={3} title='Tab 3' disabled>Tab 3 content</Tab>
</Tabs>
);

React.render(tabsInstance, mountNode);
9 changes: 9 additions & 0 deletions docs/examples/TabsUncontrolled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const tabsInstance = (
<Tabs defaultActiveKey={2}>
<Tab eventKey={1} title='Tab 1'>Tab 1 content</Tab>
<Tab eventKey={2} title='Tab 2'>Tab 2 content</Tab>
<Tab eventKey={3} title='Tab 3' disabled>Tab 3 content</Tab>
</Tabs>
);

React.render(tabsInstance, mountNode);
14 changes: 7 additions & 7 deletions docs/src/ComponentsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -519,15 +519,15 @@ const ComponentsPage = React.createClass({

<h3><Anchor id='tabs-uncontrolled'>Uncontrolled</Anchor></h3>
<p>Allow the component to control its own state.</p>
<ReactPlayground codeText={Samples.TabbedAreaUncontrolled} exampleClassName='bs-example-tabs' />
<ReactPlayground codeText={Samples.TabsUncontrolled} exampleClassName='bs-example-tabs' />

<h3><Anchor id='tabs-controlled'>Controlled</Anchor></h3>
<p>Pass down the active state on render via props.</p>
<ReactPlayground codeText={Samples.TabbedAreaControlled} exampleClassName='bs-example-tabs' />
<ReactPlayground codeText={Samples.TabsControlled} exampleClassName='bs-example-tabs' />

<h3><Anchor id='tabs-no-animation'>No animation</Anchor></h3>
<p>Set the <code>animation</code> prop to <code>false</code></p>
<ReactPlayground codeText={Samples.TabbedAreaNoAnimation} exampleClassName='bs-example-tabs' />
<ReactPlayground codeText={Samples.TabsNoAnimation} exampleClassName='bs-example-tabs' />

<div className='bs-callout bs-callout-info'>
<h4>Extends tabbed navigation</h4>
Expand All @@ -536,11 +536,11 @@ const ComponentsPage = React.createClass({

<h3><Anchor id='tabs-props'>Props</Anchor></h3>

<h4><Anchor id='tabs-props-area'>TabbedArea</Anchor></h4>
<PropTable component='TabbedArea'/>
<h4><Anchor id='tabs-props-area'>Tabs</Anchor></h4>
<PropTable component='Tabs'/>

<h4><Anchor id='tabs-props-pane'>TabPane</Anchor></h4>
<PropTable component='TabPane'/>
<h4><Anchor id='tabs-props-pane'>Tab</Anchor></h4>
<PropTable component='Tab'/>
</div>

{/* Pager */}
Expand Down
4 changes: 2 additions & 2 deletions docs/src/ReactPlayground.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ const Portal = require('../../src/Portal');
const ProgressBar = require('../../src/ProgressBar');
const Row = require('../../src/Row');
const SplitButton = require('../../src/SplitButton');
const TabbedArea = require('../../src/TabbedArea');
const Tab = require('../../src/Tab');
const Table = require('../../src/Table');
const TabPane = require('../../src/TabPane');
const Tabs = require('../../src/Tabs');
const Thumbnail = require('../../src/Thumbnail');
const Tooltip = require('../../src/Tooltip');
const Well = require('../../src/Well');
Expand Down
6 changes: 3 additions & 3 deletions docs/src/Samples.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ export default {
NavbarBrand: require('fs').readFileSync(__dirname + '/../examples/NavbarBrand.js', 'utf8'),
NavbarCollapsible: require('fs').readFileSync(__dirname + '/../examples/NavbarCollapsible.js', 'utf8'),
CollapsibleNav: require('fs').readFileSync(__dirname + '/../examples/CollapsibleNav.js', 'utf8'),
TabbedAreaUncontrolled: require('fs').readFileSync(__dirname + '/../examples/TabbedAreaUncontrolled.js', 'utf8'),
TabbedAreaControlled: require('fs').readFileSync(__dirname + '/../examples/TabbedAreaControlled.js', 'utf8'),
TabbedAreaNoAnimation: require('fs').readFileSync(__dirname + '/../examples/TabbedAreaNoAnimation.js', 'utf8'),
TabsUncontrolled: require('fs').readFileSync(__dirname + '/../examples/TabsUncontrolled.js', 'utf8'),
TabsControlled: require('fs').readFileSync(__dirname + '/../examples/TabsControlled.js', 'utf8'),
TabsNoAnimation: require('fs').readFileSync(__dirname + '/../examples/TabsNoAnimation.js', 'utf8'),
PagerDefault: require('fs').readFileSync(__dirname + '/../examples/PagerDefault.js', 'utf8'),
PagerAligned: require('fs').readFileSync(__dirname + '/../examples/PagerAligned.js', 'utf8'),
PagerDisabled: require('fs').readFileSync(__dirname + '/../examples/PagerDisabled.js', 'utf8'),
Expand Down
93 changes: 93 additions & 0 deletions src/Tab.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React from 'react';
import classNames from 'classnames';
import TransitionEvents from './utils/TransitionEvents';

const Tab = React.createClass({
propTypes: {
active: React.PropTypes.bool,
animation: React.PropTypes.bool,
onAnimateOutEnd: React.PropTypes.func,
disabled: React.PropTypes.bool,
title: React.PropTypes.node
},

getDefaultProps() {
return {
animation: true
};
},

getInitialState() {
return {
animateIn: false,
animateOut: false
};
},

componentWillReceiveProps(nextProps) {
if (this.props.animation) {
if (!this.state.animateIn && nextProps.active && !this.props.active) {
this.setState({
animateIn: true
});
} else if (!this.state.animateOut && !nextProps.active && this.props.active) {
this.setState({
animateOut: true
});
}
}
},

componentDidUpdate() {
if (this.state.animateIn) {
setTimeout(this.startAnimateIn, 0);
}
if (this.state.animateOut) {
TransitionEvents.addEndEventListener(
React.findDOMNode(this),
this.stopAnimateOut
);
}
},

startAnimateIn() {
if (this.isMounted()) {
this.setState({
animateIn: false
});
}
},

stopAnimateOut() {
if (this.isMounted()) {
this.setState({
animateOut: false
});

if (this.props.onAnimateOutEnd) {
this.props.onAnimateOutEnd();
}
}
},

render() {
let classes = {
'tab-pane': true,
'fade': true,
'active': this.props.active || this.state.animateOut,
'in': this.props.active && !this.state.animateIn
};

return (
<div {...this.props}
role='tabpanel'
aria-hidden={!this.props.active}
className={classNames(this.props.className, classes)}
>
{this.props.children}
</div>
);
}
});

export default Tab;
86 changes: 5 additions & 81 deletions src/TabPane.js
Original file line number Diff line number Diff line change
@@ -1,90 +1,14 @@
import React from 'react';
import classNames from 'classnames';
import TransitionEvents from './utils/TransitionEvents';
import deprecationWarning from './utils/deprecationWarning';
import Tab from './Tab';

const TabPane = React.createClass({
propTypes: {
active: React.PropTypes.bool,
animation: React.PropTypes.bool,
onAnimateOutEnd: React.PropTypes.func,
disabled: React.PropTypes.bool
componentDidMount() {
deprecationWarning('TabPane', 'Tab', 'https://github.com/react-bootstrap/react-bootstrap/pull/1091');
},

getDefaultProps() {
return {
animation: true
};
},

getInitialState() {
return {
animateIn: false,
animateOut: false
};
},

componentWillReceiveProps(nextProps) {
if (this.props.animation) {
if (!this.state.animateIn && nextProps.active && !this.props.active) {
this.setState({
animateIn: true
});
} else if (!this.state.animateOut && !nextProps.active && this.props.active) {
this.setState({
animateOut: true
});
}
}
},

componentDidUpdate() {
if (this.state.animateIn) {
setTimeout(this.startAnimateIn, 0);
}
if (this.state.animateOut) {
TransitionEvents.addEndEventListener(
React.findDOMNode(this),
this.stopAnimateOut
);
}
},

startAnimateIn() {
if (this.isMounted()) {
this.setState({
animateIn: false
});
}
},

stopAnimateOut() {
if (this.isMounted()) {
this.setState({
animateOut: false
});

if (this.props.onAnimateOutEnd) {
this.props.onAnimateOutEnd();
}
}
},

render() {
let classes = {
'tab-pane': true,
'fade': true,
'active': this.props.active || this.state.animateOut,
'in': this.props.active && !this.state.animateIn
};

return (
<div {...this.props}
role='tabpanel'
aria-hidden={!this.props.active}
className={classNames(this.props.className, classes)}
>
{this.props.children}
</div>
<Tab {...this.props} />
);
}
});
Expand Down

0 comments on commit e7cf455

Please sign in to comment.