import _extends from 'babel-runtime/helpers/extends'; import _defineProperty from 'babel-runtime/helpers/defineProperty'; import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties'; import _classCallCheck from 'babel-runtime/helpers/classCallCheck'; import _createClass from 'babel-runtime/helpers/createClass'; import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn'; import _inherits from 'babel-runtime/helpers/inherits'; import React from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import raf from 'raf'; import { polyfill } from 'react-lifecycles-compat'; import KeyCode from './KeyCode'; import TabPane from './TabPane'; import { getDataAttr } from './utils'; import Sentinel, { SentinelProvider } from './Sentinel'; function noop() {} function getDefaultActiveKey(props) { var activeKey = void 0; React.Children.forEach(props.children, function (child) { if (child && !activeKey && !child.props.disabled) { activeKey = child.key; } }); return activeKey; } function activeKeyIsValid(props, key) { var keys = React.Children.map(props.children, function (child) { return child && child.key; }); return keys.indexOf(key) >= 0; } var Tabs = function (_React$Component) { _inherits(Tabs, _React$Component); function Tabs(props) { _classCallCheck(this, Tabs); var _this = _possibleConstructorReturn(this, (Tabs.__proto__ || Object.getPrototypeOf(Tabs)).call(this, props)); _initialiseProps.call(_this); var activeKey = void 0; if ('activeKey' in props) { activeKey = props.activeKey; } else if ('defaultActiveKey' in props) { activeKey = props.defaultActiveKey; } else { activeKey = getDefaultActiveKey(props); } _this.state = { activeKey: activeKey }; return _this; } _createClass(Tabs, [{ key: 'componentWillUnmount', value: function componentWillUnmount() { this.destroy = true; raf.cancel(this.sentinelId); } // Sentinel for tab index }, { key: 'updateSentinelContext', value: function updateSentinelContext() { var _this2 = this; if (this.destroy) return; raf.cancel(this.sentinelId); this.sentinelId = raf(function () { if (_this2.destroy) return; _this2.forceUpdate(); }); } }, { key: 'render', value: function render() { var _classnames; var props = this.props; var prefixCls = props.prefixCls, navWrapper = props.navWrapper, tabBarPosition = props.tabBarPosition, className = props.className, renderTabContent = props.renderTabContent, renderTabBar = props.renderTabBar, destroyInactiveTabPane = props.destroyInactiveTabPane, direction = props.direction, restProps = _objectWithoutProperties(props, ['prefixCls', 'navWrapper', 'tabBarPosition', 'className', 'renderTabContent', 'renderTabBar', 'destroyInactiveTabPane', 'direction']); var cls = classnames((_classnames = {}, _defineProperty(_classnames, prefixCls, 1), _defineProperty(_classnames, prefixCls + '-' + tabBarPosition, 1), _defineProperty(_classnames, className, !!className), _defineProperty(_classnames, prefixCls + '-rtl', direction === 'rtl'), _classnames)); this.tabBar = renderTabBar(); var tabBar = React.cloneElement(this.tabBar, { prefixCls: prefixCls, navWrapper: navWrapper, key: 'tabBar', onKeyDown: this.onNavKeyDown, tabBarPosition: tabBarPosition, onTabClick: this.onTabClick, panels: props.children, activeKey: this.state.activeKey, direction: this.props.direction }); var tabContent = React.cloneElement(renderTabContent(), { prefixCls: prefixCls, tabBarPosition: tabBarPosition, activeKey: this.state.activeKey, destroyInactiveTabPane: destroyInactiveTabPane, children: props.children, onChange: this.setActiveKey, key: 'tabContent', direction: this.props.direction }); var sentinelStart = React.createElement(Sentinel, { key: 'sentinelStart', setRef: this.setSentinelStart, nextElement: this.panelSentinelStart }); var sentinelEnd = React.createElement(Sentinel, { key: 'sentinelEnd', setRef: this.setSentinelEnd, prevElement: this.panelSentinelEnd }); var contents = []; if (tabBarPosition === 'bottom') { contents.push(sentinelStart, tabContent, sentinelEnd, tabBar); } else { contents.push(tabBar, sentinelStart, tabContent, sentinelEnd); } return React.createElement( SentinelProvider, { value: { sentinelStart: this.sentinelStart, sentinelEnd: this.sentinelEnd, setPanelSentinelStart: this.setPanelSentinelStart, setPanelSentinelEnd: this.setPanelSentinelEnd } }, React.createElement( 'div', _extends({ className: cls, style: props.style }, getDataAttr(restProps), { onScroll: this.onScroll }), contents ) ); } }], [{ key: 'getDerivedStateFromProps', value: function getDerivedStateFromProps(props, state) { var newState = {}; if ('activeKey' in props) { newState.activeKey = props.activeKey; } else if (!activeKeyIsValid(props, state.activeKey)) { newState.activeKey = getDefaultActiveKey(props); } if (Object.keys(newState).length > 0) { return newState; } return null; } }]); return Tabs; }(React.Component); var _initialiseProps = function _initialiseProps() { var _this3 = this; this.onTabClick = function (activeKey, e) { if (_this3.tabBar.props.onTabClick) { _this3.tabBar.props.onTabClick(activeKey, e); } _this3.setActiveKey(activeKey); }; this.onNavKeyDown = function (e) { var eventKeyCode = e.keyCode; if (eventKeyCode === KeyCode.RIGHT || eventKeyCode === KeyCode.DOWN) { e.preventDefault(); var nextKey = _this3.getNextActiveKey(true); _this3.onTabClick(nextKey); } else if (eventKeyCode === KeyCode.LEFT || eventKeyCode === KeyCode.UP) { e.preventDefault(); var previousKey = _this3.getNextActiveKey(false); _this3.onTabClick(previousKey); } }; this.onScroll = function (_ref) { var target = _ref.target, currentTarget = _ref.currentTarget; if (target === currentTarget && target.scrollLeft > 0) { target.scrollLeft = 0; } }; this.setSentinelStart = function (node) { _this3.sentinelStart = node; }; this.setSentinelEnd = function (node) { _this3.sentinelEnd = node; }; this.setPanelSentinelStart = function (node) { if (node !== _this3.panelSentinelStart) { _this3.updateSentinelContext(); } _this3.panelSentinelStart = node; }; this.setPanelSentinelEnd = function (node) { if (node !== _this3.panelSentinelEnd) { _this3.updateSentinelContext(); } _this3.panelSentinelEnd = node; }; this.setActiveKey = function (activeKey) { if (_this3.state.activeKey !== activeKey) { if (!('activeKey' in _this3.props)) { _this3.setState({ activeKey: activeKey }); } _this3.props.onChange(activeKey); } }; this.getNextActiveKey = function (next) { var activeKey = _this3.state.activeKey; var children = []; React.Children.forEach(_this3.props.children, function (c) { if (c && !c.props.disabled) { if (next) { children.push(c); } else { children.unshift(c); } } }); var length = children.length; var ret = length && children[0].key; children.forEach(function (child, i) { if (child.key === activeKey) { if (i === length - 1) { ret = children[0].key; } else { ret = children[i + 1].key; } } }); return ret; }; }; Tabs.propTypes = { destroyInactiveTabPane: PropTypes.bool, renderTabBar: PropTypes.func.isRequired, renderTabContent: PropTypes.func.isRequired, navWrapper: PropTypes.func, onChange: PropTypes.func, children: PropTypes.node, prefixCls: PropTypes.string, className: PropTypes.string, tabBarPosition: PropTypes.string, style: PropTypes.object, activeKey: PropTypes.string, defaultActiveKey: PropTypes.string, direction: PropTypes.string }; Tabs.defaultProps = { prefixCls: 'rc-tabs', destroyInactiveTabPane: false, onChange: noop, navWrapper: function navWrapper(arg) { return arg; }, tabBarPosition: 'top', children: null, style: {}, direction: 'ltr' }; Tabs.TabPane = TabPane; polyfill(Tabs); export default Tabs;