diff --git a/src/pivotal-ui/components/tabs.scss b/src/pivotal-ui/components/tabs.scss index 83c943c36..a672aaa4b 100644 --- a/src/pivotal-ui/components/tabs.scss +++ b/src/pivotal-ui/components/tabs.scss @@ -501,8 +501,8 @@ You can use any 130px by 130px svg for the icon in the center of the tab. Please /*doc --- -title: React Simple Alt Tabs -name: react_simple_alt_tabs +title: React Simple Tabs +name: react_simple_tabs categories: - Beta --- @@ -513,13 +513,13 @@ categories: ```jsx_example React.render( - + Wow!

Neat!

So much content.
-
, + , document.getElementById('simple-alt-tabs-example') ); ``` diff --git a/src/pivotal-ui/javascripts/components.js b/src/pivotal-ui/javascripts/components.js index be86a0c45..eb20c93a4 100644 --- a/src/pivotal-ui/javascripts/components.js +++ b/src/pivotal-ui/javascripts/components.js @@ -2,33 +2,33 @@ var React = require('react'); module.exports = { TableSortable: React.createFactory(require('./table-sortable.jsx')), - + DefaultH1: require('./typography.jsx').DefaultH1, DefaultH2: require('./typography.jsx').DefaultH2, DefaultH3: require('./typography.jsx').DefaultH3, DefaultH4: require('./typography.jsx').DefaultH4, DefaultH5: require('./typography.jsx').DefaultH5, DefaultH6: require('./typography.jsx').DefaultH6, - + AlternateH1: require('./typography.jsx').AlternateH1, AlternateH2: require('./typography.jsx').AlternateH2, AlternateH3: require('./typography.jsx').AlternateH3, AlternateH4: require('./typography.jsx').AlternateH4, AlternateH5: require('./typography.jsx').AlternateH5, AlternateH6: require('./typography.jsx').AlternateH6, - + MarketingH1: require('./typography.jsx').MarketingH1, MarketingH2: require('./typography.jsx').MarketingH2, MarketingH3: require('./typography.jsx').MarketingH3, MarketingH4: require('./typography.jsx').MarketingH4, MarketingH5: require('./typography.jsx').MarketingH5, MarketingH6: require('./typography.jsx').MarketingH6, - + Heading: require('./typography.jsx').Heading, - + BasePane: require('./panes.jsx').BasePane, Pane: require('./panes.jsx').Pane, - + UIButton: require('./buttons.jsx').UIButton, DefaultButton: require('./buttons.jsx').DefaultButton, DefaultAltButton: require('./buttons.jsx').DefaultAltButton, @@ -37,20 +37,20 @@ module.exports = { DangerButton: require('./buttons.jsx').DangerButton, HighlightButton: require('./buttons.jsx').HighlightButton, HighlightAltButton: require('./buttons.jsx').HighlightAltButton, - + SearchInput: require('./inputs.jsx').SearchInput, - + Divider: require('./dividers.jsx').Divider, DividerInverse: require('./dividers.jsx').DividerInverse, - + Row: require('./grids.jsx').Row, Col: require('./grids.jsx').Col, - + Media: require('./media.jsx').Media, Flag: require('./media.jsx').Flag, - + PivnetHomepage: require('./pivnet_homepage.jsx').PivnetHomepage, - + Panel: require('./panels.jsx').Panel, SimplePanel: require('./panels.jsx').SimplePanel, ClickablePanel: require('./panels.jsx').ClickablePanel, @@ -61,6 +61,6 @@ module.exports = { Image: require('./images.jsx').Image, - SimpleAltTabs: require('./tabs.jsx').SimpleAltTabs, - Tab: require('./tabs.jsx').Tab + Tab: require('./tabs.jsx').Tab, + Tabs: require('./tabs.jsx').Tabs }; diff --git a/src/pivotal-ui/javascripts/tabs.jsx b/src/pivotal-ui/javascripts/tabs.jsx index 5fe044413..c0ba05f71 100644 --- a/src/pivotal-ui/javascripts/tabs.jsx +++ b/src/pivotal-ui/javascripts/tabs.jsx @@ -3,50 +3,71 @@ var React = require('react'); var _ = require('lodash'); -var SimpleAltTabs = React.createClass({ +var TabMenu = React.createClass({ render: function () { - var activeIndex = _.findIndex(this.props.children, function (tab) { - return tab.props.active; - }); - - if (activeIndex === -1) { - activeIndex = 0; - } - - var tabs = _.map(this.props.children, function(tab, index) { - var className = index === activeIndex ? 'active' : ''; - var tabId = '#tab-' + index; - + var tabs = _.map(this.props.tabs, function(tab, index) { + var className = (index === this.props.activeIndex) ? "active" : ""; + var key = "tab-control-" + index; return ( -
  • - {tab.props.heading} +
  • + {tab}
  • ); - }); + }, this); + + return ( + + ); + } +}); - var contents = _.map(this.props.children, function(tab, index) { - var classes = ['tab-pane', 'fade']; - var tabId = 'tab-' + index; - if (index === activeIndex) { - classes.push('in'); - classes.push('active'); - } +var TabContents = React.createClass({ + render: function () { + var panels = _.map(this.props.children, function(panel, index) { + var className = "tab-pane fade"; + className += (this.props.activeIndex === index) ? " active in" : ""; + + var key = "tab-panel-" + index; return ( -
    - {tab.props.children} +
    + {panel.props.children}
    ); - }); + }, this); return ( -
    - -
    - {contents} -
    +
    + {panels} +
    + ); + } +}); + +var Tabs = React.createClass({ + getInitialState: function () { + return { + activeIndex: 0 + }; + }, + componentWillMount: function () { + if (this.props.activeTab) { + this.setState({ activeIndex: this.props.activeTab }); + } + }, + updateTabs: function (event) { + var tabIndex = parseInt(event.target.getAttribute('data-index')); + this.setState({ activeIndex: tabIndex }); + }, + render: function () { + var tabLinks = _.pluck(_.pluck(this.props.children, 'props'), 'heading'); + + return ( +
    + + {this.props.children}
    ); } @@ -54,11 +75,15 @@ var SimpleAltTabs = React.createClass({ var Tab = React.createClass({ render: function () { - return ""; + return ( +
    + {this.props.children} +
    + ); } }); module.exports = { - SimpleAltTabs: SimpleAltTabs, + Tabs: Tabs, Tab: Tab }; diff --git a/test/spec/javascripts/tabs_spec.js b/test/spec/javascripts/tabs_spec.js index 80ce2bf07..cf6b94db8 100644 --- a/test/spec/javascripts/tabs_spec.js +++ b/test/spec/javascripts/tabs_spec.js @@ -4,10 +4,10 @@ var $ = require('jquery'); var React = require('react/addons'); var TestUtils = React.addons.TestUtils; -var SimpleAltTabs = require('../../../src/pivotal-ui/javascripts/tabs.jsx').SimpleAltTabs; +var Tabs = require('../../../src/pivotal-ui/javascripts/tabs.jsx').Tabs; var Tab = require('../../../src/pivotal-ui/javascripts/tabs.jsx').Tab; -describe('SimpleAltTabs', function() { +describe("Tabs", function() { beforeEach(function() { this.node = $('
    ').appendTo('body').get(0); }); @@ -17,42 +17,65 @@ describe('SimpleAltTabs', function() { document.body.removeChild(this.node); }); - describe("when the active flag is not set", function() { + describe("when the active tab is not set", function() { beforeEach(function() { React.render( - + Content for first tab Content for second tab - , + , this.node ); }); - it("renders the correct tabs and content", function() { - expect($('#container .tab-simple-alt ul.nav.nav-tabs li.active a')).toHaveText("My first tab"); - expect($('#container .tab-simple-alt ul.nav.nav-tabs li:not(.active) a')).toHaveText("My second tab"); + it("renders the tabs and content with first tab active", function() { + expect($('#container .tab-simple ul.nav.nav-tabs li.active a')).toHaveText("My first tab"); + expect($('#container .tab-simple ul.nav.nav-tabs li:not(.active) a')).toHaveText("My second tab"); - expect($('#container li.active a').attr('href')).toEqual('#' + $('#container .tab-pane.active').attr("id")); + expect($('#container .tab-simple .tab-content .tab-pane.in.active')).toHaveText("Content for first tab"); + expect($('#container .tab-simple .tab-content .tab-pane:not(.in.active)')).toHaveText("Content for second tab"); + }); + }); + + describe("when the active tab is set", function() { + beforeEach(function() { + React.render( + + Content for first tab + Content for second tab + , + this.node + ); + }); + + it("renders the tabs and content with specified tab active", function() { + expect($('#container .tab-simple ul.nav.nav-tabs li.active a')).toHaveText("My second tab"); + expect($('#container .tab-simple ul.nav.nav-tabs li:not(.active) a')).toHaveText("My first tab"); - expect($('#container .tab-simple-alt .tab-content .tab-pane.in.active')).toHaveText("Content for first tab"); - expect($('#container .tab-simple-alt .tab-content .tab-pane:not(.in.active)')).toHaveText("Content for second tab"); + expect($('#container .tab-simple .tab-content .tab-pane.in.active')).toHaveText("Content for second tab"); + expect($('#container .tab-simple .tab-content .tab-pane:not(.in.active)')).toHaveText("Content for first tab"); }); }); - describe("when the active flag is set on a tab", function() { + describe("clicking a non-active tab", function() { beforeEach(function() { React.render( - + Content for first tab - Content for second tab - , + Content for second tab + , this.node ); + + TestUtils.Simulate.click($('li:not(.active) a').get(0)); }); - it("sets the specified tab as active", function() { - expect($('#container .tab-simple-alt ul.nav.nav-tabs li.active a')).toHaveText("My second tab"); - expect($('#container .tab-simple-alt .tab-content .tab-pane.in.active')).toHaveText("Content for second tab"); + it("updates the active tab and content", function() { + expect($('#container .tab-simple ul.nav.nav-tabs li.active a')).toHaveText("My second tab"); + expect($('#container .tab-simple ul.nav.nav-tabs li:not(.active) a')).toHaveText("My first tab"); + + expect($('#container .tab-simple .tab-content .tab-pane.in.active')).toHaveText("Content for second tab"); + expect($('#container .tab-simple .tab-content .tab-pane:not(.in.active)')).toHaveText("Content for first tab"); }); }); });