UNPKG

d2-ui

Version:
265 lines (219 loc) 6.71 kB
import React from 'react'; import ReactDOM from 'react-dom'; import TabTemplate from './tabTemplate'; import InkBar from '../ink-bar'; import StylePropable from '../mixins/style-propable'; import getMuiTheme from '../styles/getMuiTheme'; import warning from 'warning'; const Tabs = React.createClass({ propTypes: { /** * Should be used to pass `Tab` components. */ children: React.PropTypes.node, /** * The css class name of the root element. */ className: React.PropTypes.string, /** * The css class name of the content's container. */ contentContainerClassName: React.PropTypes.string, /** * Override the inline-styles of the content's container. */ contentContainerStyle: React.PropTypes.object, /** * Specify initial visible tab index. * Initial selected index is set by default to 0. * If initialSelectedIndex is set but larger than the total amount of specified tabs, * initialSelectedIndex will revert back to default. */ initialSelectedIndex: React.PropTypes.number, /** * Override the inline-styles of the InkBar. */ inkBarStyle: React.PropTypes.object, /** * Called when the selected value change. */ onChange: React.PropTypes.func, /** * Override the inline-styles of the root element. */ style: React.PropTypes.object, /** * Override the inline-styles of the tab-labels container. */ tabItemContainerStyle: React.PropTypes.object, /** * Override the default tab template used to wrap the content of each tab element. */ tabTemplate: React.PropTypes.func, /** * Makes Tabs controllable and selects the tab whose value prop matches this prop. */ value: React.PropTypes.any, }, contextTypes: { muiTheme: React.PropTypes.object, }, childContextTypes: { muiTheme: React.PropTypes.object, }, mixins: [ StylePropable, ], getDefaultProps() { return { initialSelectedIndex: 0, onChange: () => {}, }; }, getInitialState() { let valueLink = this.getValueLink(this.props); let initialIndex = this.props.initialSelectedIndex; return { selectedIndex: valueLink.value !== undefined ? this._getSelectedIndex(this.props) : initialIndex < this.getTabCount() ? initialIndex : 0, muiTheme: this.context.muiTheme || getMuiTheme(), }; }, getChildContext() { return { muiTheme: this.state.muiTheme, }; }, componentWillReceiveProps(newProps, nextContext) { const valueLink = this.getValueLink(newProps); const newMuiTheme = nextContext.muiTheme ? nextContext.muiTheme : this.state.muiTheme; if (valueLink.value !== undefined) { this.setState({selectedIndex: this._getSelectedIndex(newProps)}); } this.setState({muiTheme: newMuiTheme}); }, getEvenWidth() { return ( parseInt(window .getComputedStyle(ReactDOM.findDOMNode(this)) .getPropertyValue('width'), 10) ); }, getTabCount() { return React.Children.count(this.props.children); }, // Do not use outside of this component, it will be removed once valueLink is deprecated getValueLink(props) { return props.valueLink || { value: props.value, requestChange: props.onChange, }; }, _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; }, _handleTabTouchTap(value, e, tab) { let valueLink = this.getValueLink(this.props); let tabIndex = tab.props.tabIndex; if ((valueLink.value && valueLink.value !== value) || this.state.selectedIndex !== tabIndex) { valueLink.requestChange(value, e, tab); } this.setState({selectedIndex: tabIndex}); if (tab.props.onActive) { 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; }, render() { let { children, contentContainerClassName, contentContainerStyle, initialSelectedIndex, inkBarStyle, style, tabItemContainerStyle, tabTemplate, ...other, } = this.props; let themeVariables = this.state.muiTheme.tabs; let styles = { tabItemContainer: { margin: 0, padding: 0, width: '100%', backgroundColor: themeVariables.backgroundColor, whiteSpace: 'nowrap', }, }; let valueLink = this.getValueLink(this.props); let tabValue = valueLink.value; let tabContent = []; const width = 100 / this.getTabCount(); let tabs = React.Children.map(children, (tab, index) => { warning(tab.type && tab.type.displayName === 'Tab', `Tabs only accepts Tab Components as children. Found ${tab.type.displayName || tab.type} as child number ${index + 1} of Tabs`); warning(!tabValue || tab.props.value !== undefined, `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.`); tabContent.push(tab.props.children ? React.createElement(tabTemplate || TabTemplate, { key: index, selected: this._getSelected(tab, index), }, tab.props.children) : undefined); return React.cloneElement(tab, { key: index, selected: this._getSelected(tab, index), tabIndex: index, width: width + '%', onTouchTap: this._handleTabTouchTap, }); }); const inkBar = this.state.selectedIndex !== -1 ? ( <InkBar left={width * this.state.selectedIndex + '%'} width={width + '%'} style={inkBarStyle} /> ) : null; const inkBarContainerWidth = tabItemContainerStyle ? tabItemContainerStyle.width : '100%'; return ( <div {...other} style={this.prepareStyles(style)} > <div style={this.prepareStyles(styles.tabItemContainer, tabItemContainerStyle)}> {tabs} </div> <div style={{width: inkBarContainerWidth}}> {inkBar} </div> <div style={this.prepareStyles(contentContainerStyle)} className={contentContainerClassName} > {tabContent} </div> </div> ); }, }); export default Tabs;