);
}
- _onActive(tab){
+ _handleButtonClick() {
+ this.setState({tabsValue: 'c'});
+ }
+
+ _handleTabActive(tab){
this.context.router.transitionTo(tab.props.route);
}
+
+ _handleTabsChange(e, tab){
+ this.setState({tabsValue: tab.props.value});
+ }
}
TabsPage.contextTypes = {
diff --git a/src/tabs/tab.jsx b/src/tabs/tab.jsx
index 4185492c3efe18..bc5b9c13ca61c6 100644
--- a/src/tabs/tab.jsx
+++ b/src/tabs/tab.jsx
@@ -13,15 +13,27 @@ let Tab = React.createClass({
propTypes: {
handleTouchTap: React.PropTypes.func,
+ onActive: React.PropTypes.func,
selected: React.PropTypes.bool,
width: React.PropTypes.string,
+ value: React.PropTypes.string,
},
- handleTouchTap() {
- this.props.handleTouchTap(this.props.tabIndex, this);
+ getDefaultProps(){
+ return {
+ onActive: () => {},
+ };
},
render() {
+ let {
+ label,
+ selected,
+ style,
+ value,
+ width,
+ ...other,
+ } = this.props;
let styles = this.mergeAndPrefix({
display: 'table-cell',
cursor: 'pointer',
@@ -29,24 +41,30 @@ let Tab = React.createClass({
verticalAlign: 'middle',
height: 48,
color: Colors.white,
- opacity: 0.6,
+ opacity: selected ? 1 : 0.6,
+ outline: 'none',
fontSize: 14,
- fontWeight: '500',
+ fontWeight: 500,
whiteSpace: 'initial',
fontFamily: this.context.muiTheme.contentFontFamily,
boxSizing: 'border-box',
- width: this.props.width,
- }, this.props.style);
-
- if (this.props.selected) styles.opacity = '1';
+ width: width,
+ }, style);
return (
-
- {this.props.label}
+
+ {label}
);
},
+ _handleTouchTap(e) {
+ this.props.handleTouchTap(e, this);
+ },
+
});
module.exports = Tab;
diff --git a/src/tabs/tabs.jsx b/src/tabs/tabs.jsx
index 399de9549caebc..74bc11a6ea71c8 100644
--- a/src/tabs/tabs.jsx
+++ b/src/tabs/tabs.jsx
@@ -2,33 +2,40 @@ let React = require('react/addons');
let TabTemplate = require('./tabTemplate');
let InkBar = require('../ink-bar');
let StylePropable = require('../mixins/style-propable');
-let Events = require('../utils/events');
+let Controllable = require('../mixins/controllable');
let Tabs = React.createClass({
- mixins: [StylePropable],
+ mixins: [StylePropable, Controllable],
contextTypes: {
muiTheme: React.PropTypes.object,
},
propTypes: {
- initialSelectedIndex: React.PropTypes.number,
- onActive: React.PropTypes.func,
- tabWidth: React.PropTypes.number,
- tabItemContainerStyle: React.PropTypes.object,
contentContainerStyle: React.PropTypes.object,
+ initialSelectedIndex: React.PropTypes.number,
inkBarStyle: React.PropTypes.object,
+ tabItemContainerStyle: React.PropTypes.object,
+ },
+
+ getDefaultProps() {
+ return {
+ initialSelectedIndex : 0,
+ };
},
getInitialState(){
- let selectedIndex = 0;
- if (this.props.initialSelectedIndex && this.props.initialSelectedIndex < this.getTabCount()) {
- selectedIndex = this.props.initialSelectedIndex;
- }
+ let valueLink = this.getValueLink(this.props);
+ let initialIndex = this.props.initialSelectedIndex;
+
return {
- selectedIndex: selectedIndex,
+ selectedIndex: valueLink.value ?
+ this._getSelectedIndex(this.props) :
+ initialIndex < this.getTabCount() ?
+ initialIndex :
+ 0,
};
},
@@ -44,116 +51,136 @@ let Tabs = React.createClass({
return React.Children.count(this.props.children);
},
- componentDidMount() {
- this._updateTabWidth();
- Events.on(window, 'resize', this._updateTabWidth);
- },
-
- componentWillUnmount() {
- Events.off(window, 'resize', this._updateTabWidth);
- },
-
componentWillReceiveProps(newProps) {
- if (newProps.hasOwnProperty('style')) this._updateTabWidth();
- },
+ let valueLink = this.getValueLink(newProps);
- handleTouchTap(tabIndex, tab){
- if (this.props.onChange && this.state.selectedIndex !== tabIndex) {
- this.props.onChange(tabIndex, tab);
+ if (valueLink.value){
+ this.setState({selectedIndex: this._getSelectedIndex(newProps)});
}
-
- this.setState({selectedIndex: tabIndex});
- //default CB is _onActive. Can be updated in tab.jsx
- if (tab.props.onActive) tab.props.onActive(tab);
},
- getStyles() {
- let themeVariables = this.context.muiTheme.component.tabs;
+ render() {
+ let {
+ children,
+ contentContainerStyle,
+ initialSelectedIndex,
+ inkBarStyle,
+ style,
+ tabWidth,
+ tabItemContainerStyle,
+ ...other,
+ } = this.props;
- return {
+ let themeVariables = this.context.muiTheme.component.tabs;
+ let styles = {
tabItemContainer: {
- margin: '0',
- padding: '0',
+ margin: 0,
+ padding: 0,
width: '100%',
- height: '48px',
+ height: 48,
backgroundColor: themeVariables.backgroundColor,
whiteSpace: 'nowrap',
display: 'table',
},
};
- },
-
- render() {
- let styles = this.getStyles();
+ let valueLink = this.getValueLink(this.props);
+ let tabValue = valueLink.value;
let tabContent = [];
- let width = this.state.fixedWidth ?
- 100 / this.getTabCount() +'%' :
- this.props.tabWidth + 'px';
+
+ let width = 100 / this.getTabCount() +'%';
let left = 'calc(' + width + '*' + this.state.selectedIndex + ')';
- let tabs = React.Children.map(this.props.children, (tab, index) => {
+ let tabs = React.Children.map(children, (tab, index) => {
if (tab.type.displayName === "Tab") {
- if (tab.props.children) {
- tabContent.push(React.createElement(TabTemplate, {
- key: index,
- selected: this.state.selectedIndex === index,
- }, tab.props.children));
- }
- else {
- tabContent.push(undefined);
+ if (!tab.props.value && tabValue && process.env.NODE_ENV !== 'production') {
+ console.error('Tabs value prop has been passed, but Tab ' + index +
+ ' does not have a value prop. Needs value if Tabs is going' +
+ ' to be a controlled component.');
}
- return React.addons.cloneWithProps(tab, {
+ tabContent.push(tab.props.children ?
+ React.createElement(TabTemplate, {
+ key: index,
+ selected: this._getSelected(tab, index),
+ }, tab.props.children) : undefined);
+
+ return React.cloneElement(tab, {
key: index,
- selected: this.state.selectedIndex === index,
+ selected: this._getSelected(tab, index),
tabIndex: index,
width: width,
- handleTouchTap: this.handleTouchTap,
+ handleTouchTap: this._handleTouchTap,
});
}
else {
let type = tab.type.displayName || tab.type;
- throw 'Tabs only accepts Tab Components as children. Found ' +
- type + ' as child number ' + (index + 1) + ' of Tabs';
+ console.error('Tabs only accepts Tab Components as children. Found ' +
+ type + ' as child number ' + (index + 1) + ' of Tabs');
}
}, this);
+ let inkBar = this.state.selectedIndex !== -1 ? (
+
+ ) : null;
+
+ let inkBarContainerWidth = tabItemContainerStyle ?
+ tabItemContainerStyle.width : '100%';
+
return (
-
-
+
+
{tabs}
-
-
+
+ {inkBar}
+
+
{tabContent}
);
},
- _tabWidthPropIsValid() {
- return this.props.tabWidth &&
- (this.props.tabWidth * this.getTabCount() <= this.getEvenWidth());
+ _getSelectedIndex(props) {
+ let valueLink = this.getValueLink(props);
+ let selectedIndex = -1;
+
+ React.Children.forEach(props.children, (tab, index) => {
+ if (valueLink.value === tab.props.value) {
+ selectedIndex = index;
+ }
+ });
+
+ return selectedIndex;
},
- // Validates that the tabWidth can fit all tabs on the tab bar. If not, the
- // tabWidth is recalculated and fixed.
- _updateTabWidth() {
- if (this._tabWidthPropIsValid()) {
- this.setState({
- fixedWidth: false,
- });
- }
- else {
- this.setState({
- fixedWidth: true,
- });
+ _handleTouchTap(e, tab){
+ let valueLink = this.getValueLink(this.props);
+ let tabIndex = tab.props.tabIndex;
+ let value = tab.props.value;
+
+ if ((valueLink.value && valueLink.value !== value) ||
+ this.state.selectedIndex !== tabIndex) {
+ valueLink.requestChange(e, tab);
}
+
+ this.setState({selectedIndex: tabIndex});
+ tab.props.onActive(tab);
+ },
+
+ _getSelected(tab, index) {
+ let valueLink = this.getValueLink(this.props);
+ return valueLink.value ? valueLink.value === tab.props.value :
+ this.state.selectedIndex === index;
},
});
module.exports = Tabs;
-