From e7cf4557e4ef5499fdba6a5538040efbb7b18b7a Mon Sep 17 00:00:00 2001 From: Caroline Taymor Date: Tue, 4 Aug 2015 15:30:15 -0700 Subject: [PATCH] [changed] New Tabs API * 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 Signed-off-by: Caroline Taymor Signed-off-by: Dominick Reinhold --- docs/examples/.eslintrc | 2 + docs/examples/TabbedAreaControlled.js | 24 --- docs/examples/TabbedAreaNoAnimation.js | 9 - docs/examples/TabbedAreaUncontrolled.js | 9 - docs/examples/TabsControlled.js | 24 +++ docs/examples/TabsNoAnimation.js | 9 + docs/examples/TabsUncontrolled.js | 9 + docs/src/ComponentsPage.js | 14 +- docs/src/ReactPlayground.js | 4 +- docs/src/Samples.js | 6 +- src/Tab.js | 93 ++++++++++ src/TabPane.js | 86 +-------- src/TabbedArea.js | 168 ++--------------- src/Tabs.js | 167 +++++++++++++++++ src/index.js | 2 + test/{TabPaneSpec.js => TabSpec.js} | 12 +- test/{TabbedAreaSpec.js => TabsSpec.js} | 231 ++++++++++++------------ 17 files changed, 462 insertions(+), 407 deletions(-) delete mode 100644 docs/examples/TabbedAreaControlled.js delete mode 100644 docs/examples/TabbedAreaNoAnimation.js delete mode 100644 docs/examples/TabbedAreaUncontrolled.js create mode 100644 docs/examples/TabsControlled.js create mode 100644 docs/examples/TabsNoAnimation.js create mode 100644 docs/examples/TabsUncontrolled.js create mode 100644 src/Tab.js create mode 100644 src/Tabs.js rename test/{TabPaneSpec.js => TabSpec.js} (78%) rename test/{TabbedAreaSpec.js => TabsSpec.js} (52%) diff --git a/docs/examples/.eslintrc b/docs/examples/.eslintrc index 00c22821a7..1511bd45e2 100644 --- a/docs/examples/.eslintrc +++ b/docs/examples/.eslintrc @@ -47,9 +47,11 @@ "ProgressBar", "Row", "SplitButton", + "Tab", "TabbedArea", "Table", "TabPane", + "Tabs", "Tooltip", "Well", "Thumbnail", diff --git a/docs/examples/TabbedAreaControlled.js b/docs/examples/TabbedAreaControlled.js deleted file mode 100644 index 9e197e496f..0000000000 --- a/docs/examples/TabbedAreaControlled.js +++ /dev/null @@ -1,24 +0,0 @@ -const ControlledTabArea = React.createClass({ - getInitialState() { - return { - key: 1 - }; - }, - - handleSelect(key) { - alert('selected ' + key); - this.setState({key}); - }, - - render() { - return ( - - TabPane 1 content - TabPane 2 content - TabPane 3 content - - ); - } -}); - -React.render(, mountNode); diff --git a/docs/examples/TabbedAreaNoAnimation.js b/docs/examples/TabbedAreaNoAnimation.js deleted file mode 100644 index be5d2b4ab2..0000000000 --- a/docs/examples/TabbedAreaNoAnimation.js +++ /dev/null @@ -1,9 +0,0 @@ -const tabbedAreaInstance = ( - - TabPane 1 content - TabPane 2 content - TabPane 3 content - -); - -React.render(tabbedAreaInstance, mountNode); diff --git a/docs/examples/TabbedAreaUncontrolled.js b/docs/examples/TabbedAreaUncontrolled.js deleted file mode 100644 index 4b4a7dffcf..0000000000 --- a/docs/examples/TabbedAreaUncontrolled.js +++ /dev/null @@ -1,9 +0,0 @@ -const tabbedAreaInstance = ( - - TabPane 1 content - TabPane 2 content - TabPane 3 content - -); - -React.render(tabbedAreaInstance, mountNode); diff --git a/docs/examples/TabsControlled.js b/docs/examples/TabsControlled.js new file mode 100644 index 0000000000..e68414ab3f --- /dev/null +++ b/docs/examples/TabsControlled.js @@ -0,0 +1,24 @@ +const ControlledTabs = React.createClass({ + getInitialState() { + return { + key: 1 + }; + }, + + handleSelect(key) { + alert('selected ' + key); + this.setState({key}); + }, + + render() { + return ( + + Tab 1 content + Tab 2 content + Tab 3 content + + ); + } +}); + +React.render(, mountNode); diff --git a/docs/examples/TabsNoAnimation.js b/docs/examples/TabsNoAnimation.js new file mode 100644 index 0000000000..fe33845f6a --- /dev/null +++ b/docs/examples/TabsNoAnimation.js @@ -0,0 +1,9 @@ +const tabsInstance = ( + + Tab 1 content + Tab 2 content + Tab 3 content + +); + +React.render(tabsInstance, mountNode); diff --git a/docs/examples/TabsUncontrolled.js b/docs/examples/TabsUncontrolled.js new file mode 100644 index 0000000000..e922101ecd --- /dev/null +++ b/docs/examples/TabsUncontrolled.js @@ -0,0 +1,9 @@ +const tabsInstance = ( + + Tab 1 content + Tab 2 content + Tab 3 content + +); + +React.render(tabsInstance, mountNode); diff --git a/docs/src/ComponentsPage.js b/docs/src/ComponentsPage.js index 667fa7d37b..bf995285e4 100644 --- a/docs/src/ComponentsPage.js +++ b/docs/src/ComponentsPage.js @@ -519,15 +519,15 @@ const ComponentsPage = React.createClass({

Uncontrolled

Allow the component to control its own state.

- +

Controlled

Pass down the active state on render via props.

- +

No animation

Set the animation prop to false

- +

Extends tabbed navigation

@@ -536,11 +536,11 @@ const ComponentsPage = React.createClass({

Props

-

TabbedArea

- +

Tabs

+ -

TabPane

- +

Tab

+
{/* Pager */} diff --git a/docs/src/ReactPlayground.js b/docs/src/ReactPlayground.js index 1b9901c0b1..70e379d1d4 100644 --- a/docs/src/ReactPlayground.js +++ b/docs/src/ReactPlayground.js @@ -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'); diff --git a/docs/src/Samples.js b/docs/src/Samples.js index fc58d7ed58..14ed90a163 100644 --- a/docs/src/Samples.js +++ b/docs/src/Samples.js @@ -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'), diff --git a/src/Tab.js b/src/Tab.js new file mode 100644 index 0000000000..942c3bb725 --- /dev/null +++ b/src/Tab.js @@ -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 ( +
+ {this.props.children} +
+ ); + } +}); + +export default Tab; diff --git a/src/TabPane.js b/src/TabPane.js index 3e36db3542..aa5fce8868 100644 --- a/src/TabPane.js +++ b/src/TabPane.js @@ -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 ( -
- {this.props.children} -
+ ); } }); diff --git a/src/TabbedArea.js b/src/TabbedArea.js index 89021be333..b898f01d8a 100644 --- a/src/TabbedArea.js +++ b/src/TabbedArea.js @@ -1,167 +1,25 @@ -import React, { cloneElement } from 'react'; -import BootstrapMixin from './BootstrapMixin'; - +import React from 'react'; +import Tabs from './Tabs'; +import TabPane from './TabPane'; import ValidComponentChildren from './utils/ValidComponentChildren'; -import Nav from './Nav'; -import NavItem from './NavItem'; - -let panelId = (props, child) => child.props.id ? child.props.id : props.id && (props.id + '___panel___' + child.props.eventKey); -let tabId = (props, child) => child.props.id ? child.props.id + '___tab' : props.id && (props.id + '___tab___' + child.props.eventKey); - -function getDefaultActiveKeyFromChildren(children) { - let defaultActiveKey; - - ValidComponentChildren.forEach(children, function(child) { - if (defaultActiveKey == null) { - defaultActiveKey = child.props.eventKey; - } - }); - - return defaultActiveKey; -} +import deprecationWarning from './utils/deprecationWarning'; const TabbedArea = React.createClass({ - mixins: [BootstrapMixin], - - propTypes: { - activeKey: React.PropTypes.any, - defaultActiveKey: React.PropTypes.any, - bsStyle: React.PropTypes.oneOf(['tabs', 'pills']), - animation: React.PropTypes.bool, - id: React.PropTypes.string, - onSelect: React.PropTypes.func - }, - - getDefaultProps() { - return { - bsStyle: 'tabs', - animation: true - }; + componentDidMount() { + deprecationWarning('TabbedArea', 'Tabs', 'https://github.com/react-bootstrap/react-bootstrap/pull/1091'); }, - - getInitialState() { - let defaultActiveKey = this.props.defaultActiveKey != null ? - this.props.defaultActiveKey : getDefaultActiveKeyFromChildren(this.props.children); - - return { - activeKey: defaultActiveKey, - previousActiveKey: null - }; - }, - - componentWillReceiveProps(nextProps) { - if (nextProps.activeKey != null && nextProps.activeKey !== this.props.activeKey) { - // check if the 'previousActiveKey' child still exists - let previousActiveKey = this.props.activeKey; - React.Children.forEach(nextProps.children, (child) => { - if (React.isValidElement(child)) { - if (child.props.eventKey === previousActiveKey) { - this.setState({ - previousActiveKey - }); - return; - } - } - }); - - // if the 'previousActiveKey' child does not exist anymore - this.setState({ - previousActiveKey: null - }); - } - }, - - handlePaneAnimateOutEnd() { - this.setState({ - previousActiveKey: null - }); - }, - render() { - let { id, ...props } = this.props; - - function renderTabIfSet(child) { - return child.props.tab != null ? this.renderTab(child) : null; - } + let {children, ...props} = this.props; + let tabTitles = []; - let nav = ( - - ); - - return ( -
- {nav} -
- {ValidComponentChildren.map(this.props.children, this.renderPane)} -
-
- ); - }, - - getActiveKey() { - return this.props.activeKey != null ? this.props.activeKey : this.state.activeKey; - }, - - renderPane(child, index) { - let previousActiveKey = this.state.previousActiveKey; - - let shouldPaneBeSetActive = child.props.eventKey === this.getActiveKey(); - let thereIsNoActivePane = previousActiveKey == null; - - let paneIsAlreadyActive = previousActiveKey != null && child.props.eventKey === previousActiveKey; - - return cloneElement( - child, - { - active: shouldPaneBeSetActive && (thereIsNoActivePane || !this.props.animation), - id: panelId(this.props, child), - 'aria-labelledby': tabId(this.props, child), - key: child.key ? child.key : index, - animation: this.props.animation, - onAnimateOutEnd: paneIsAlreadyActive ? this.handlePaneAnimateOutEnd : null - } - ); - }, - - renderTab(child) { - let {eventKey, className, tab, disabled } = child.props; + tabTitles = ValidComponentChildren.map(function(child) { + let {tab, ...others} = child.props; + tabTitles.push(); + }); return ( - - {tab} - + {tabTitles} ); - }, - - shouldComponentUpdate() { - // Defer any updates to this component during the `onSelect` handler. - return !this._isChanging; - }, - - handleSelect(selectedKey) { - if (this.props.onSelect) { - this._isChanging = true; - this.props.onSelect(selectedKey); - this._isChanging = false; - return; - } - - // if there is no external handler, then use embedded one - let previousActiveKey = this.getActiveKey(); - if (selectedKey !== previousActiveKey) { - this.setState({ - activeKey: selectedKey, - previousActiveKey - }); - } } }); diff --git a/src/Tabs.js b/src/Tabs.js new file mode 100644 index 0000000000..3b28bd081f --- /dev/null +++ b/src/Tabs.js @@ -0,0 +1,167 @@ +import React, { cloneElement } from 'react'; +import ValidComponentChildren from './utils/ValidComponentChildren'; +import Nav from './Nav'; +import NavItem from './NavItem'; + +let panelId = (props, child) => child.props.id ? child.props.id : props.id && (props.id + '___panel___' + child.props.eventKey); +let tabId = (props, child) => child.props.id ? child.props.id + '___tab' : props.id && (props.id + '___tab___' + child.props.eventKey); + +function getDefaultActiveKeyFromChildren(children) { + let defaultActiveKey; + + ValidComponentChildren.forEach(children, function(child) { + if (defaultActiveKey == null) { + defaultActiveKey = child.props.eventKey; + } + }); + + return defaultActiveKey; +} + +const Tabs = React.createClass({ + propTypes: { + activeKey: React.PropTypes.any, + defaultActiveKey: React.PropTypes.any, + bsStyle: React.PropTypes.oneOf(['tabs', 'pills']), + animation: React.PropTypes.bool, + id: React.PropTypes.string, + onSelect: React.PropTypes.func + }, + + getDefaultProps() { + return { + bsStyle: 'tabs', + animation: true + }; + }, + + getInitialState() { + let defaultActiveKey = this.props.defaultActiveKey != null ? + this.props.defaultActiveKey : getDefaultActiveKeyFromChildren(this.props.children); + + return { + activeKey: defaultActiveKey, + previousActiveKey: null + }; + }, + + componentWillReceiveProps(nextProps) { + if (nextProps.activeKey != null && nextProps.activeKey !== this.props.activeKey) { + // check if the 'previousActiveKey' child still exists + let previousActiveKey = this.props.activeKey; + React.Children.forEach(nextProps.children, (child) => { + if (React.isValidElement(child)) { + if (child.props.eventKey === previousActiveKey) { + this.setState({ + previousActiveKey + }); + return; + } + } + }); + + // if the 'previousActiveKey' child does not exist anymore + this.setState({ + previousActiveKey: null + }); + } + }, + + handlePaneAnimateOutEnd() { + this.setState({ + previousActiveKey: null + }); + }, + + render() { + let { + id, + className, + style, // eslint-disable-line react/prop-types + ...props } = this.props; + + function renderTabIfSet(child) { + return child.props.title != null ? this.renderTab(child) : null; + } + + let nav = ( + + ); + + return ( +
+ {nav} +
+ {ValidComponentChildren.map(this.props.children, this.renderPane)} +
+
+ ); + }, + + getActiveKey() { + return this.props.activeKey != null ? this.props.activeKey : this.state.activeKey; + }, + + renderPane(child, index) { + let previousActiveKey = this.state.previousActiveKey; + + let shouldPaneBeSetActive = child.props.eventKey === this.getActiveKey(); + let thereIsNoActivePane = previousActiveKey == null; + + let paneIsAlreadyActive = previousActiveKey != null && child.props.eventKey === previousActiveKey; + + return cloneElement( + child, + { + active: shouldPaneBeSetActive && (thereIsNoActivePane || !this.props.animation), + id: panelId(this.props, child), + 'aria-labelledby': tabId(this.props, child), + key: child.key ? child.key : index, + animation: this.props.animation, + onAnimateOutEnd: paneIsAlreadyActive ? this.handlePaneAnimateOutEnd : null + } + ); + }, + + renderTab(child) { + let {eventKey, title, disabled } = child.props; + + return ( + + {title} + + ); + }, + + shouldComponentUpdate() { + // Defer any updates to this component during the `onSelect` handler. + return !this._isChanging; + }, + + handleSelect(selectedKey) { + if (this.props.onSelect) { + this._isChanging = true; + this.props.onSelect(selectedKey); + this._isChanging = false; + return; + } + + // if there is no external handler, then use embedded one + let previousActiveKey = this.getActiveKey(); + if (selectedKey !== previousActiveKey) { + this.setState({ + activeKey: selectedKey, + previousActiveKey + }); + } + } +}); + +export default Tabs; diff --git a/src/index.js b/src/index.js index 4ac89226c2..085bc9e392 100644 --- a/src/index.js +++ b/src/index.js @@ -53,9 +53,11 @@ export SafeAnchor from './SafeAnchor'; export SplitButton from './SplitButton'; export styleMaps from './styleMaps'; export SubNav from './SubNav'; +export Tab from './Tab'; export TabbedArea from './TabbedArea'; export Table from './Table'; export TabPane from './TabPane'; +export Tabs from './Tabs'; export Thumbnail from './Thumbnail'; export Tooltip from './Tooltip'; export Well from './Well'; diff --git a/test/TabPaneSpec.js b/test/TabSpec.js similarity index 78% rename from test/TabPaneSpec.js rename to test/TabSpec.js index ecc704da91..6babd9db32 100644 --- a/test/TabPaneSpec.js +++ b/test/TabSpec.js @@ -1,18 +1,18 @@ import React from 'react'; import ReactTestUtils from 'react/lib/ReactTestUtils'; -import TabPane from '../src/TabPane'; +import Tab from '../src/Tab'; -describe('TabPane', function () { +describe('Tab', function () { it('Should have class', function () { let instance = ReactTestUtils.renderIntoDocument( - Item content + Item content ); assert.ok(ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'tab-pane')); }); it('Should add active class', function () { let instance = ReactTestUtils.renderIntoDocument( - Item content + Item content ); assert.ok(ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'active')); }); @@ -21,7 +21,7 @@ describe('TabPane', function () { it('Should have aria-hidden', function () { let instance = ReactTestUtils.renderIntoDocument( - Item content + Item content ); assert.equal(React.findDOMNode(instance).getAttribute('aria-hidden'), 'false'); @@ -29,7 +29,7 @@ describe('TabPane', function () { it('Should have role', function () { let instance = ReactTestUtils.renderIntoDocument( - Item content + Item content ); assert.equal(React.findDOMNode(instance).getAttribute('role'), 'tabpanel'); diff --git a/test/TabbedAreaSpec.js b/test/TabsSpec.js similarity index 52% rename from test/TabbedAreaSpec.js rename to test/TabsSpec.js index 876b09dcb8..08cb82c1f9 100644 --- a/test/TabbedAreaSpec.js +++ b/test/TabsSpec.js @@ -1,43 +1,43 @@ import React from 'react'; import ReactTestUtils from 'react/lib/ReactTestUtils'; -import TabbedArea from '../src/TabbedArea'; +import Tabs from '../src/Tabs'; +import Tab from '../src/Tab'; import NavItem from '../src/NavItem'; -import TabPane from '../src/TabPane'; import ValidComponentChildren from '../src/utils/ValidComponentChildren'; import { render } from './helpers'; -describe('TabbedArea', function () { +describe('Tabs', function () { it('Should show the correct tab', function () { let instance = ReactTestUtils.renderIntoDocument( - - Tab 1 content - Tab 2 content - + + Tab 1 content + Tab 2 content + ); - let panes = ReactTestUtils.scryRenderedComponentsWithType(instance, TabPane); + let panes = ReactTestUtils.scryRenderedComponentsWithType(instance, Tab); assert.equal(panes[0].props.active, true); assert.equal(panes[1].props.active, false); - let tabbedArea = ReactTestUtils.findRenderedComponentWithType(instance, TabbedArea); + let tabs = ReactTestUtils.findRenderedComponentWithType(instance, Tabs); - assert.equal(tabbedArea.refs.tabs.props.activeKey, 1); + assert.equal(tabs.refs.tabs.props.activeKey, 1); }); - it('Should only show the tabs with `TabPane.props.tab` set', function () { + it('Should only show the tabs with `Tab.props.tab` set', function () { let instance = ReactTestUtils.renderIntoDocument( - - Tab 1 content - Tab 2 content - Tab 3 content - + + Tab 1 content + Tab 2 content + Tab 3 content + ); - let tabbedArea = ReactTestUtils.findRenderedComponentWithType(instance, TabbedArea); + let tabs = ReactTestUtils.findRenderedComponentWithType(instance, Tabs); assert.equal(ValidComponentChildren.numberOf(instance.refs.tabs.props.children), 2); - assert.equal(tabbedArea.refs.tabs.props.activeKey, 3); + assert.equal(tabs.refs.tabs.props.activeKey, 3); }); it('Should allow tab to have React components', function () { @@ -45,10 +45,10 @@ describe('TabbedArea', function () { Tab 2 ); let instance = ReactTestUtils.renderIntoDocument( - - Tab 1 content - Tab 2 content - + + Tab 1 content + Tab 2 content + ); assert.ok(ReactTestUtils.findRenderedDOMComponentWithClass(instance.refs.tabs, 'special-tab')); @@ -62,10 +62,10 @@ describe('TabbedArea', function () { let tab2 = Tab2; let instance = ReactTestUtils.renderIntoDocument( - - Tab 1 content - Tab 2 content - + + Tab 1 content + Tab 2 content + ); @@ -76,13 +76,13 @@ describe('TabbedArea', function () { it('Should have children with the correct DOM properties', function () { let instance = ReactTestUtils.renderIntoDocument( - - Tab 1 content - Tab 2 content - + + Tab 1 content + Tab 2 content + ); - let panes = ReactTestUtils.scryRenderedComponentsWithType(instance, TabPane); + let panes = ReactTestUtils.scryRenderedComponentsWithType(instance, Tab); assert.ok(React.findDOMNode(panes[0]).className.match(/\bcustom\b/)); assert.equal(React.findDOMNode(panes[0]).id, 'pane0id'); @@ -90,37 +90,37 @@ describe('TabbedArea', function () { it('Should show the correct initial pane', function () { let instance = ReactTestUtils.renderIntoDocument( - - Tab 1 content - Tab 2 content - + + Tab 1 content + Tab 2 content + ); - let tabbedArea = ReactTestUtils.findRenderedComponentWithType(instance, TabbedArea); + let tabs = ReactTestUtils.findRenderedComponentWithType(instance, Tabs); - let panes = ReactTestUtils.scryRenderedComponentsWithType(instance, TabPane); + let panes = ReactTestUtils.scryRenderedComponentsWithType(instance, Tab); assert.equal(panes[0].props.active, false); assert.equal(panes[1].props.active, true); - assert.equal(tabbedArea.refs.tabs.props.activeKey, 2); + assert.equal(tabs.refs.tabs.props.activeKey, 2); }); it('Should show the correct first tab with no active key value', function () { let instance = ReactTestUtils.renderIntoDocument( - - Tab 1 content - Tab 2 content - + + Tab 1 content + Tab 2 content + ); - let tabbedArea = ReactTestUtils.findRenderedComponentWithType(instance, TabbedArea); - let panes = ReactTestUtils.scryRenderedComponentsWithType(instance, TabPane); + let tabs = ReactTestUtils.findRenderedComponentWithType(instance, Tabs); + let panes = ReactTestUtils.scryRenderedComponentsWithType(instance, Tab); assert.equal(panes[0].props.active, true); assert.equal(panes[1].props.active, false); - assert.equal(tabbedArea.refs.tabs.props.activeKey, 1); + assert.equal(tabs.refs.tabs.props.activeKey, 1); }); it('Should show the correct first tab with `React.Children.map` children values', function () { @@ -129,14 +129,14 @@ describe('TabbedArea', function () {
Tab 2 content
]; let paneComponents = React.Children.map(panes, function(child, index) { - return {child}; + return {child}; }); let instance = ReactTestUtils.renderIntoDocument( - + {paneComponents} {null} - + ); assert.equal(instance.refs.tabs.props.activeKey, 0); @@ -145,14 +145,14 @@ describe('TabbedArea', function () { it('Should show the correct tab when selected', function () { let tab1 = Tab 1; let instance = ReactTestUtils.renderIntoDocument( - - Tab 1 content - Tab 2 content - + + Tab 1 content + Tab 2 content + ); - let tabbedArea = ReactTestUtils.findRenderedComponentWithType(instance, TabbedArea); - let panes = ReactTestUtils.scryRenderedComponentsWithType(instance, TabPane); + let tabs = ReactTestUtils.findRenderedComponentWithType(instance, Tabs); + let panes = ReactTestUtils.scryRenderedComponentsWithType(instance, Tab); ReactTestUtils.Simulate.click( ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'tab1') @@ -160,15 +160,15 @@ describe('TabbedArea', function () { assert.equal(panes[0].props.active, true); assert.equal(panes[1].props.active, false); - assert.equal(tabbedArea.refs.tabs.props.activeKey, 1); + assert.equal(tabs.refs.tabs.props.activeKey, 1); }); it('Should pass default bsStyle (of "tabs") to Nav', function () { let instance = ReactTestUtils.renderIntoDocument( - - Tab 1 content - Tab 2 content - + + Tab 1 content + Tab 2 content + ); assert.ok(ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'nav-tabs')); @@ -176,35 +176,21 @@ describe('TabbedArea', function () { it('Should pass bsStyle to Nav', function () { let instance = ReactTestUtils.renderIntoDocument( - - Tab 1 content - Tab 2 content - + + Tab 1 content + Tab 2 content + ); assert.ok(ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'nav-pills')); }); - it('Should pass className to rendered Tab NavItem', function () { + it('Should pass disabled to Nav', function () { let instance = ReactTestUtils.renderIntoDocument( - - Tab 1 content - Tab 3 content - - ); - - let tabPane = ReactTestUtils.scryRenderedComponentsWithType(instance, TabPane); - - assert.equal(tabPane.length, 2); - assert.equal(React.findDOMNode(tabPane[1]).getAttribute('class').match(/pull-right/)[0], 'pull-right'); - }); - - it('Should pass disabled to NavItem', function () { - let instance = ReactTestUtils.renderIntoDocument( - - Tab 1 content - Tab 2 content - + + Tab 1 content + Tab 2 content + ); assert.ok(ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'disabled')); @@ -213,14 +199,14 @@ describe('TabbedArea', function () { it('Should not show content when clicking disabled tab', function () { let tab1 = Tab 1; let instance = ReactTestUtils.renderIntoDocument( - - Tab 1 content - Tab 2 content - + + Tab 1 content + Tab 2 content + ); - let tabbedArea = ReactTestUtils.findRenderedComponentWithType(instance, TabbedArea); - let panes = ReactTestUtils.scryRenderedComponentsWithType(instance, TabPane); + let tabs = ReactTestUtils.findRenderedComponentWithType(instance, Tabs); + let panes = ReactTestUtils.scryRenderedComponentsWithType(instance, Tab); ReactTestUtils.Simulate.click( ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'tab1') @@ -228,7 +214,7 @@ describe('TabbedArea', function () { assert.equal(panes[0].props.active, false); assert.equal(panes[1].props.active, true); - assert.equal(tabbedArea.refs.tabs.props.activeKey, 2); + assert.equal(tabs.refs.tabs.props.activeKey, 2); }); describe('animation', function () { @@ -245,24 +231,24 @@ describe('TabbedArea', function () { }); function checkTabRemovingWithAnimation(animation) { - it(`should correctly set "active" after tabPane is removed with "animation=${animation}"`, function() { + it(`should correctly set "active" after Tab is removed with "animation=${animation}"`, function() { let instance = render( - - Tab 1 content - Tab 2 content - + + Tab 1 content + Tab 2 content + , mountPoint); - let panes = ReactTestUtils.scryRenderedComponentsWithType(instance, TabPane); + let panes = ReactTestUtils.scryRenderedComponentsWithType(instance, Tab); assert.equal(panes[0].props.active, false); assert.equal(panes[1].props.active, true); // second tab has been removed render( - - Tab 1 content - + + Tab 1 content + , mountPoint); assert.equal(panes[0].props.active, true); @@ -277,10 +263,10 @@ describe('TabbedArea', function () { it('Should generate ids from parent id', function () { let instance = ReactTestUtils.renderIntoDocument( - - Tab 1 content - Tab 2 content - + + Tab 1 content + Tab 2 content + ); let tabs = ReactTestUtils.scryRenderedComponentsWithType(instance, NavItem); @@ -291,13 +277,13 @@ describe('TabbedArea', function () { it('Should add aria-controls', function () { let instance = ReactTestUtils.renderIntoDocument( - - Tab 1 content - Tab 2 content - + + Tab 1 content + Tab 2 content + ); - let panes = ReactTestUtils.scryRenderedComponentsWithType(instance, TabPane); + let panes = ReactTestUtils.scryRenderedComponentsWithType(instance, Tab); assert.equal(panes[0].props['aria-labelledby'], 'pane-1___tab'); assert.equal(panes[1].props['aria-labelledby'], 'pane-2___tab'); @@ -305,10 +291,10 @@ describe('TabbedArea', function () { it('Should add aria-controls', function () { let instance = ReactTestUtils.renderIntoDocument( - - Tab 1 content - Tab 2 content - + + Tab 1 content + Tab 2 content + ); let tabs = ReactTestUtils.scryRenderedComponentsWithType(instance, NavItem); @@ -318,4 +304,27 @@ describe('TabbedArea', function () { }); }); + + it('Should not pass className to Nav', function () { + let instance = ReactTestUtils.renderIntoDocument( + + Tab 1 content + Tab 2 content + + ); + let myTabClass = ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'my-tab-class'); + let myNavItem = ReactTestUtils.scryRenderedDOMComponentsWithClass(instance, 'nav-pills')[0]; + assert.notDeepEqual(myTabClass, myNavItem); + }); + + it('Should pass className, Id, and style to Tabs', function () { + let instance = ReactTestUtils.renderIntoDocument( + + ); + assert.equal(React.findDOMNode(instance).getAttribute('class'), 'my-tabs-class'); + assert.equal(React.findDOMNode(instance).getAttribute('id'), 'my-tabs-id'); + assert.deepEqual(React.findDOMNode(instance).getAttribute('style'), 'opacity:0.5;'); + + }); });