From 0b6e862a9b684696ae552a210d1e54d4f65e2f65 Mon Sep 17 00:00:00 2001 From: Vitalii Maslianok Date: Fri, 5 Jun 2020 13:35:24 +0300 Subject: [PATCH] Add unmountOnExit prop --- README.md | 6 ++- examples/src/Basic/index.js | 36 +++++++++-------- examples/src/Basic/styles.css | 32 +++++++-------- lib/components/TabPanel.js | 34 ++++++++++++---- lib/esm/components/TabPanel.js | 34 ++++++++++++---- lib/esm/index.js | 49 ++++++++++++++++++----- lib/index.js | 49 ++++++++++++++++++----- src/components/TabPanel.js | 33 ++++++++++++---- src/index.js | 71 +++++++++++++++++++++++++--------- styles.css | 9 +++-- 10 files changed, 256 insertions(+), 97 deletions(-) diff --git a/README.md b/README.md index 23bb3ea..6bb2ce6 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,10 @@ import Tabs from 'react-responsive-tabs'; // IMPORTANT you need to include the default styles import 'react-responsive-tabs/styles.css'; -const presidents = [{ name: 'George Washington', biography: '...' }, { name: 'Theodore Roosevelt', biography: '...' }]; +const presidents = [ + { name: 'George Washington', biography: '...' }, + { name: 'Theodore Roosevelt', biography: '...' }, +]; function getTabs() { return presidents.map((president, index) => ({ @@ -86,6 +89,7 @@ render(, document.getElementById('root')); | showMoreLabel | String/Node | `Show more` tab name | `...` | | transform | Bool | Transform to accordion when the wrapper width is less than `transformWidth`. | `true` | | transformWidth | Number | Transform width. | 800 | +| unmountOnExit | Bool | Whether to unmount inactive tabs from DOM tree or not | `true` | | tabsWrapperClass | String | Wrapper class | undefined | | tabClassName | String | Tab class | undefined | | panelClassName | String | Tab panel class | undefined | diff --git a/examples/src/Basic/index.js b/examples/src/Basic/index.js index 2d5e373..f2f9061 100644 --- a/examples/src/Basic/index.js +++ b/examples/src/Basic/index.js @@ -15,13 +15,13 @@ export class Basic extends PureComponent { showInkBar: false, items: this.getSimpleTabs(), selectedTabKey: 0, + unmountOnExit: true, }; } - onChangeProp = propsName => - evt => { - this.setState({ [propsName]: evt.target.type === 'checkbox' ? evt.target.checked : +evt.target.value }); - }; + onChangeProp = propsName => evt => { + this.setState({ [propsName]: evt.target.type === 'checkbox' ? evt.target.checked : +evt.target.value }); + }; getSimpleTabs = () => dummyData.map(({ name, biography }, index) => ({ @@ -31,29 +31,32 @@ export class Basic extends PureComponent { })); render() { - const { showMore, transform, showInkBar, selectedTabKey } = this.state; + const { showMore, transform, showInkBar, selectedTabKey, unmountOnExit } = this.state; return (
+
+
+
@@ -64,9 +67,8 @@ export class Basic extends PureComponent { onChange={this.onChangeProp('selectedTabKey')} className="basic__input" value={selectedTabKey} - /> - {' '} - selected tab + />{' '} + selected tab
diff --git a/examples/src/Basic/styles.css b/examples/src/Basic/styles.css index 07b7601..675afae 100644 --- a/examples/src/Basic/styles.css +++ b/examples/src/Basic/styles.css @@ -4,22 +4,22 @@ flex-grow: 1; } - .basic__props { - width: 200px; - flex-shrink: 0; - padding: 10px; - border-right: 1px solid #f0f0f0; - } +.basic__props { + width: 260px; + flex-shrink: 0; + padding: 10px; + border-right: 1px solid #f0f0f0; +} - .basic__prop { - margin: 10px 0; - } +.basic__prop { + margin: 10px 0; +} - .basic__input { - width: 40px; - } +.basic__input { + width: 40px; +} - .basic__tabs { - padding: 10px; - flex-grow: 1; - } \ No newline at end of file +.basic__tabs { + padding: 10px; + flex-grow: 1; +} diff --git a/lib/components/TabPanel.js b/lib/components/TabPanel.js index 7d91e56..c1c0480 100644 --- a/lib/components/TabPanel.js +++ b/lib/components/TabPanel.js @@ -42,10 +42,16 @@ var TabPanel = /*#__PURE__*/function (_Component) { var _super = _createSuper(TabPanel); - function TabPanel() { + function TabPanel(props) { + var _this; + _classCallCheck(this, TabPanel); - return _super.apply(this, arguments); + _this = _super.call(this, props); + _this.state = { + renderedAtLeastOnce: !props.isHidden + }; + return _this; } _createClass(TabPanel, [{ @@ -54,8 +60,9 @@ var TabPanel = /*#__PURE__*/function (_Component) { var _this$props = this.props, children = _this$props.children, getContent = _this$props.getContent, - classNames = _this$props.classNames; - return getContent !== nextProps.getContent || children !== nextProps.children || classNames !== nextProps.classNames; + classNames = _this$props.classNames, + isHidden = _this$props.isHidden; + return getContent !== nextProps.getContent || children !== nextProps.children || classNames !== nextProps.classNames || isHidden !== nextProps.isHidden; } }, { key: "render", @@ -65,14 +72,23 @@ var TabPanel = /*#__PURE__*/function (_Component) { id = _this$props2.id, tabId = _this$props2.tabId, children = _this$props2.children, - getContent = _this$props2.getContent; + getContent = _this$props2.getContent, + isHidden = _this$props2.isHidden; + var renderedAtLeastOnce = this.state.renderedAtLeastOnce; return /*#__PURE__*/_react["default"].createElement("div", { className: classNames, role: "tabpanel", id: id, "aria-labelledby": tabId, - "aria-hidden": "false" - }, getContent && getContent(), !getContent && children); + "aria-hidden": isHidden + }, getContent && renderedAtLeastOnce && getContent(), !getContent && children); + } + }], [{ + key: "getDerivedStateFromProps", + value: function getDerivedStateFromProps(props, state) { + return { + renderedAtLeastOnce: state.renderedAtLeastOnce || !props.isHidden + }; } }]); @@ -84,11 +100,13 @@ TabPanel.propTypes = { getContent: _propTypes["default"].func, children: _propTypes["default"].oneOfType([_propTypes["default"].array, _propTypes["default"].object, _propTypes["default"].string]), id: _propTypes["default"].string.isRequired, + isHidden: _propTypes["default"].bool, // generic props classNames: _propTypes["default"].string.isRequired, tabId: _propTypes["default"].string.isRequired }; TabPanel.defaultProps = { getContent: undefined, - children: undefined + children: undefined, + isHidden: false }; \ No newline at end of file diff --git a/lib/esm/components/TabPanel.js b/lib/esm/components/TabPanel.js index 365dcef..e154ce2 100644 --- a/lib/esm/components/TabPanel.js +++ b/lib/esm/components/TabPanel.js @@ -28,10 +28,16 @@ var TabPanel = /*#__PURE__*/function (_Component) { var _super = _createSuper(TabPanel); - function TabPanel() { + function TabPanel(props) { + var _this; + _classCallCheck(this, TabPanel); - return _super.apply(this, arguments); + _this = _super.call(this, props); + _this.state = { + renderedAtLeastOnce: !props.isHidden + }; + return _this; } _createClass(TabPanel, [{ @@ -40,8 +46,9 @@ var TabPanel = /*#__PURE__*/function (_Component) { var _this$props = this.props, children = _this$props.children, getContent = _this$props.getContent, - classNames = _this$props.classNames; - return getContent !== nextProps.getContent || children !== nextProps.children || classNames !== nextProps.classNames; + classNames = _this$props.classNames, + isHidden = _this$props.isHidden; + return getContent !== nextProps.getContent || children !== nextProps.children || classNames !== nextProps.classNames || isHidden !== nextProps.isHidden; } }, { key: "render", @@ -51,14 +58,23 @@ var TabPanel = /*#__PURE__*/function (_Component) { id = _this$props2.id, tabId = _this$props2.tabId, children = _this$props2.children, - getContent = _this$props2.getContent; + getContent = _this$props2.getContent, + isHidden = _this$props2.isHidden; + var renderedAtLeastOnce = this.state.renderedAtLeastOnce; return /*#__PURE__*/React.createElement("div", { className: classNames, role: "tabpanel", id: id, "aria-labelledby": tabId, - "aria-hidden": "false" - }, getContent && getContent(), !getContent && children); + "aria-hidden": isHidden + }, getContent && renderedAtLeastOnce && getContent(), !getContent && children); + } + }], [{ + key: "getDerivedStateFromProps", + value: function getDerivedStateFromProps(props, state) { + return { + renderedAtLeastOnce: state.renderedAtLeastOnce || !props.isHidden + }; } }]); @@ -70,11 +86,13 @@ TabPanel.propTypes = { getContent: PropTypes.func, children: PropTypes.oneOfType([PropTypes.array, PropTypes.object, PropTypes.string]), id: PropTypes.string.isRequired, + isHidden: PropTypes.bool, // generic props classNames: PropTypes.string.isRequired, tabId: PropTypes.string.isRequired }; TabPanel.defaultProps = { getContent: undefined, - children: undefined + children: undefined, + isHidden: false }; \ No newline at end of file diff --git a/lib/esm/index.js b/lib/esm/index.js index 39d0700..bdabe36 100644 --- a/lib/esm/index.js +++ b/lib/esm/index.js @@ -269,7 +269,7 @@ var Tabs = /*#__PURE__*/function (_Component) { }; }); - _defineProperty(_assertThisInitialized(_this), "getPanelProps", function (_ref2) { + _defineProperty(_assertThisInitialized(_this), "getPanelProps", function (_ref2, isHidden) { var key = _ref2.key, content = _ref2.content, getContent = _ref2.getContent, @@ -281,8 +281,10 @@ var Tabs = /*#__PURE__*/function (_Component) { id: panelPrefix + key, tabId: tabPrefix + key, classNames: _this.getClassNamesFor('panel', { - className: className - }) + className: className, + isHidden: isHidden + }), + isHidden: isHidden }; }); @@ -301,7 +303,8 @@ var Tabs = /*#__PURE__*/function (_Component) { tabIndex = _ref3.tabIndex, disabled = _ref3.disabled, _ref3$className = _ref3.className, - className = _ref3$className === void 0 ? '' : _ref3$className; + className = _ref3$className === void 0 ? '' : _ref3$className, + isHidden = _ref3.isHidden; var _this$props2 = _this.props, tabClass = _this$props2.tabClass, panelClass = _this$props2.panelClass; @@ -316,7 +319,9 @@ var Tabs = /*#__PURE__*/function (_Component) { }); case 'panel': - return cs('RRT__panel', className, panelClass); + return cs('RRT__panel', className, panelClass, { + 'RRT__panel--hidden': isHidden + }); default: return ''; @@ -363,6 +368,28 @@ var Tabs = /*#__PURE__*/function (_Component) { }); }); + _defineProperty(_assertThisInitialized(_this), "getExpandedTabs", function (panels, selectedTabKey, isCollapsed) { + var unmountOnExit = _this.props.unmountOnExit; + + if (isCollapsed) { + return undefined; + } + + if (!unmountOnExit) { + // render all tabs if unmountOnExit === false (inactive are hidden) + return Object.keys(panels).map(function (key) { + return /*#__PURE__*/React.createElement(TabPanel, _this.getPanelProps(panels[key], "".concat(selectedTabKey) !== "".concat(key))); + }); + } + + if (panels[selectedTabKey]) { + // render only active tab if unmountOnExit === true + return /*#__PURE__*/React.createElement(TabPanel, _this.getPanelProps(panels[selectedTabKey])); + } + + return undefined; + }); + _this.tabRefs = {}; _this.selectedTabKeyProp = props.selectedTabKey; _this.state = { @@ -431,7 +458,8 @@ var Tabs = /*#__PURE__*/function (_Component) { tabsWrapperClass = _this$props6.tabsWrapperClass, showMore = _this$props6.showMore, transform = _this$props6.transform, - showMoreLabel = _this$props6.showMoreLabel; + showMoreLabel = _this$props6.showMoreLabel, + unmountOnExit = _this$props6.unmountOnExit; var tabDimensions = this.state.tabDimensions; var _this$getTabs = this.getTabs(), @@ -458,8 +486,8 @@ var Tabs = /*#__PURE__*/function (_Component) { }, tabsVisible.reduce(function (result, tab) { result.push( /*#__PURE__*/React.createElement(Tab, _this2.getTabProps(tab))); - if (isCollapsed && selectedTabKey === tab.key) { - result.push( /*#__PURE__*/React.createElement(TabPanel, _this2.getPanelProps(panels[tab.key]))); + if (isCollapsed && (!unmountOnExit || selectedTabKey === tab.key)) { + result.push( /*#__PURE__*/React.createElement(TabPanel, _this2.getPanelProps(panels[tab.key], selectedTabKey !== tab.key))); } return result; @@ -468,7 +496,7 @@ var Tabs = /*#__PURE__*/function (_Component) { }))), showInkBar && !isCollapsed && !isSelectedTabHidden && /*#__PURE__*/React.createElement(InkBar, { left: selectedTabDimensions.offset || 0, width: selectedTabDimensions.width || 0 - }), !isCollapsed && panels[selectedTabKey] && /*#__PURE__*/React.createElement(TabPanel, this.getPanelProps(panels[selectedTabKey])), (showMore || transform) && /*#__PURE__*/React.createElement(ResizeDetector, { + }), this.getExpandedTabs(panels, selectedTabKey, isCollapsed), (showMore || transform) && /*#__PURE__*/React.createElement(ResizeDetector, { handleWidth: true, onResize: this.onResizeThrottled })); @@ -505,6 +533,8 @@ Tabs.propTypes = { onRemove: PropTypes.func, // frequency of onResize recalculation fires resizeThrottle: PropTypes.number, + // unmounts the tab when it gets inactive (unselected) + unmountOnExit: PropTypes.bool, // classnames containerClass: PropTypes.string, tabsWrapperClass: PropTypes.string, @@ -528,6 +558,7 @@ Tabs.defaultProps = { tabClass: undefined, panelClass: undefined, showMoreLabel: '...', + unmountOnExit: true, onChange: function onChange() { return null; }, diff --git a/lib/index.js b/lib/index.js index 2e2a5e6..03b0ff2 100644 --- a/lib/index.js +++ b/lib/index.js @@ -291,7 +291,7 @@ var Tabs = /*#__PURE__*/function (_Component) { }; }); - _defineProperty(_assertThisInitialized(_this), "getPanelProps", function (_ref2) { + _defineProperty(_assertThisInitialized(_this), "getPanelProps", function (_ref2, isHidden) { var key = _ref2.key, content = _ref2.content, getContent = _ref2.getContent, @@ -303,8 +303,10 @@ var Tabs = /*#__PURE__*/function (_Component) { id: panelPrefix + key, tabId: tabPrefix + key, classNames: _this.getClassNamesFor('panel', { - className: className - }) + className: className, + isHidden: isHidden + }), + isHidden: isHidden }; }); @@ -323,7 +325,8 @@ var Tabs = /*#__PURE__*/function (_Component) { tabIndex = _ref3.tabIndex, disabled = _ref3.disabled, _ref3$className = _ref3.className, - className = _ref3$className === void 0 ? '' : _ref3$className; + className = _ref3$className === void 0 ? '' : _ref3$className, + isHidden = _ref3.isHidden; var _this$props2 = _this.props, tabClass = _this$props2.tabClass, panelClass = _this$props2.panelClass; @@ -338,7 +341,9 @@ var Tabs = /*#__PURE__*/function (_Component) { }); case 'panel': - return (0, _classnames["default"])('RRT__panel', className, panelClass); + return (0, _classnames["default"])('RRT__panel', className, panelClass, { + 'RRT__panel--hidden': isHidden + }); default: return ''; @@ -385,6 +390,28 @@ var Tabs = /*#__PURE__*/function (_Component) { }); }); + _defineProperty(_assertThisInitialized(_this), "getExpandedTabs", function (panels, selectedTabKey, isCollapsed) { + var unmountOnExit = _this.props.unmountOnExit; + + if (isCollapsed) { + return undefined; + } + + if (!unmountOnExit) { + // render all tabs if unmountOnExit === false (inactive are hidden) + return Object.keys(panels).map(function (key) { + return /*#__PURE__*/_react["default"].createElement(_TabPanel["default"], _this.getPanelProps(panels[key], "".concat(selectedTabKey) !== "".concat(key))); + }); + } + + if (panels[selectedTabKey]) { + // render only active tab if unmountOnExit === true + return /*#__PURE__*/_react["default"].createElement(_TabPanel["default"], _this.getPanelProps(panels[selectedTabKey])); + } + + return undefined; + }); + _this.tabRefs = {}; _this.selectedTabKeyProp = props.selectedTabKey; _this.state = { @@ -453,7 +480,8 @@ var Tabs = /*#__PURE__*/function (_Component) { tabsWrapperClass = _this$props6.tabsWrapperClass, showMore = _this$props6.showMore, transform = _this$props6.transform, - showMoreLabel = _this$props6.showMoreLabel; + showMoreLabel = _this$props6.showMoreLabel, + unmountOnExit = _this$props6.unmountOnExit; var tabDimensions = this.state.tabDimensions; var _this$getTabs = this.getTabs(), @@ -480,8 +508,8 @@ var Tabs = /*#__PURE__*/function (_Component) { }, tabsVisible.reduce(function (result, tab) { result.push( /*#__PURE__*/_react["default"].createElement(_Tab["default"], _this2.getTabProps(tab))); - if (isCollapsed && selectedTabKey === tab.key) { - result.push( /*#__PURE__*/_react["default"].createElement(_TabPanel["default"], _this2.getPanelProps(panels[tab.key]))); + if (isCollapsed && (!unmountOnExit || selectedTabKey === tab.key)) { + result.push( /*#__PURE__*/_react["default"].createElement(_TabPanel["default"], _this2.getPanelProps(panels[tab.key], selectedTabKey !== tab.key))); } return result; @@ -490,7 +518,7 @@ var Tabs = /*#__PURE__*/function (_Component) { }))), showInkBar && !isCollapsed && !isSelectedTabHidden && /*#__PURE__*/_react["default"].createElement(_InkBar["default"], { left: selectedTabDimensions.offset || 0, width: selectedTabDimensions.width || 0 - }), !isCollapsed && panels[selectedTabKey] && /*#__PURE__*/_react["default"].createElement(_TabPanel["default"], this.getPanelProps(panels[selectedTabKey])), (showMore || transform) && /*#__PURE__*/_react["default"].createElement(_reactResizeDetector["default"], { + }), this.getExpandedTabs(panels, selectedTabKey, isCollapsed), (showMore || transform) && /*#__PURE__*/_react["default"].createElement(_reactResizeDetector["default"], { handleWidth: true, onResize: this.onResizeThrottled })); @@ -527,6 +555,8 @@ Tabs.propTypes = { onRemove: _propTypes["default"].func, // frequency of onResize recalculation fires resizeThrottle: _propTypes["default"].number, + // unmounts the tab when it gets inactive (unselected) + unmountOnExit: _propTypes["default"].bool, // classnames containerClass: _propTypes["default"].string, tabsWrapperClass: _propTypes["default"].string, @@ -550,6 +580,7 @@ Tabs.defaultProps = { tabClass: undefined, panelClass: undefined, showMoreLabel: '...', + unmountOnExit: true, onChange: function onChange() { return null; }, diff --git a/src/components/TabPanel.js b/src/components/TabPanel.js index f16f42d..f4edf50 100644 --- a/src/components/TabPanel.js +++ b/src/components/TabPanel.js @@ -2,19 +2,36 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; export default class TabPanel extends Component { + constructor(props) { + super(props); + this.state = { + renderedAtLeastOnce: !props.isHidden, + }; + } + + static getDerivedStateFromProps(props, state) { + return { + renderedAtLeastOnce: state.renderedAtLeastOnce || !props.isHidden, + }; + } + shouldComponentUpdate(nextProps) { - const { children, getContent, classNames } = this.props; + const { children, getContent, classNames, isHidden } = this.props; return ( - getContent !== nextProps.getContent || children !== nextProps.children || classNames !== nextProps.classNames + getContent !== nextProps.getContent || + children !== nextProps.children || + classNames !== nextProps.classNames || + isHidden !== nextProps.isHidden ); } render() { - const { classNames, id, tabId, children, getContent } = this.props; + const { classNames, id, tabId, children, getContent, isHidden } = this.props; + const { renderedAtLeastOnce } = this.state; return ( -
- {getContent && getContent()} +
+ {getContent && renderedAtLeastOnce && getContent()} {!getContent && children}
); @@ -25,13 +42,15 @@ TabPanel.propTypes = { getContent: PropTypes.func, children: PropTypes.oneOfType([PropTypes.array, PropTypes.object, PropTypes.string]), id: PropTypes.string.isRequired, + isHidden: PropTypes.bool, // generic props classNames: PropTypes.string.isRequired, - tabId: PropTypes.string.isRequired + tabId: PropTypes.string.isRequired, }; TabPanel.defaultProps = { getContent: undefined, - children: undefined + children: undefined, + isHidden: false, }; diff --git a/src/index.js b/src/index.js index bdde56c..78422ab 100644 --- a/src/index.js +++ b/src/index.js @@ -24,7 +24,7 @@ export default class Tabs extends Component { tabsTotalWidth: 0, showMoreWidth: 40, selectedTabKey: props.selectedTabKey, - focusedTabKey: null + focusedTabKey: null, }; this.onResizeThrottled = throttle(this.onResize, props.resizeThrottle, { trailing: true }); @@ -157,14 +157,14 @@ export default class Tabs extends Component { } }, allowRemove: allowRemove && (!removeActiveOnly || selected), - className: tabClassName + className: tabClassName, }; const panelPayload = { ...payload, content, getContent, - className: panelClassName + className: panelClassName, }; const tabWidth = tabDimensions[key] ? tabDimensions[key].width : 0; @@ -196,7 +196,7 @@ export default class Tabs extends Component { return result; }, - { tabsVisible: [], tabsHidden: [], panels: {}, isSelectedTabHidden: false } + { tabsVisible: [], tabsHidden: [], panels: {}, isSelectedTabHidden: false }, ); }; @@ -218,27 +218,28 @@ export default class Tabs extends Component { collapsed, tabIndex, disabled, - className - }) + className, + }), }); - getPanelProps = ({ key, content, getContent, className }) => ({ + getPanelProps = ({ key, content, getContent, className }, isHidden) => ({ getContent, children: content, key: panelPrefix + key, id: panelPrefix + key, tabId: tabPrefix + key, - classNames: this.getClassNamesFor('panel', { className }) + classNames: this.getClassNamesFor('panel', { className, isHidden }), + isHidden, }); getShowMoreProps = (isShown, isSelectedTabHidden, showMoreLabel) => ({ onShowMoreChanged: this.showMoreChanged, isShown, label: showMoreLabel, - hasChildSelected: isSelectedTabHidden + hasChildSelected: isSelectedTabHidden, }); - getClassNamesFor = (type, { selected, collapsed, tabIndex, disabled, className = '' }) => { + getClassNamesFor = (type, { selected, collapsed, tabIndex, disabled, className = '', isHidden }) => { const { tabClass, panelClass } = this.props; switch (type) { case 'tab': @@ -246,10 +247,10 @@ export default class Tabs extends Component { 'RRT__tab--first': !tabIndex, 'RRT__tab--selected': selected, 'RRT__tab--disabled': disabled, - 'RRT__tab--collapsed': collapsed + 'RRT__tab--collapsed': collapsed, }); case 'panel': - return cs('RRT__panel', className, panelClass); + return cs('RRT__panel', className, panelClass, { 'RRT__panel--hidden': isHidden }); default: return ''; } @@ -288,12 +289,41 @@ export default class Tabs extends Component { } this.setState({ - showMoreWidth: offsetWidth + showMoreWidth: offsetWidth, }); }; + getExpandedTabs = (panels, selectedTabKey, isCollapsed) => { + const { unmountOnExit } = this.props; + if (isCollapsed) { + return undefined; + } + + if (!unmountOnExit) { + // render all tabs if unmountOnExit === false (inactive are hidden) + return Object.keys(panels).map(key => ( + + )); + } + + if (panels[selectedTabKey]) { + // render only active tab if unmountOnExit === true + return ; + } + + return undefined; + }; + render() { - const { showInkBar, containerClass, tabsWrapperClass, showMore, transform, showMoreLabel } = this.props; + const { + showInkBar, + containerClass, + tabsWrapperClass, + showMore, + transform, + showMoreLabel, + unmountOnExit, + } = this.props; const { tabDimensions } = this.state; const { tabsVisible, tabsHidden, panels, isSelectedTabHidden } = this.getTabs(); const isCollapsed = this.getIsCollapsed(); @@ -309,8 +339,8 @@ export default class Tabs extends Component { {tabsVisible.reduce((result, tab) => { result.push(); - if (isCollapsed && selectedTabKey === tab.key) { - result.push(); + if (isCollapsed && (!unmountOnExit || selectedTabKey === tab.key)) { + result.push(); } return result; }, [])} @@ -328,7 +358,7 @@ export default class Tabs extends Component { )} - {!isCollapsed && panels[selectedTabKey] && } + {this.getExpandedTabs(panels, selectedTabKey, isCollapsed)} {(showMore || transform) && }
@@ -361,13 +391,15 @@ Tabs.propTypes = { onRemove: PropTypes.func, // frequency of onResize recalculation fires resizeThrottle: PropTypes.number, + // unmounts the tab when it gets inactive (unselected) + unmountOnExit: PropTypes.bool, // classnames containerClass: PropTypes.string, tabsWrapperClass: PropTypes.string, tabClass: PropTypes.string, panelClass: PropTypes.string, // labels - showMoreLabel: PropTypes.oneOfType([PropTypes.string, PropTypes.node]) + showMoreLabel: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), }; Tabs.defaultProps = { @@ -385,6 +417,7 @@ Tabs.defaultProps = { tabClass: undefined, panelClass: undefined, showMoreLabel: '...', + unmountOnExit: true, onChange: () => null, - onRemove: () => null + onRemove: () => null, }; diff --git a/styles.css b/styles.css index 60f9b8f..8e8b983 100644 --- a/styles.css +++ b/styles.css @@ -22,7 +22,7 @@ cursor: pointer; z-index: 1; white-space: nowrap; - padding: .7em 1em; + padding: 0.7em 1em; } .RRT__tab:focus { @@ -71,7 +71,6 @@ top: 0.2em; } - /****************************/ /********* panel styles *****/ /****************************/ @@ -81,6 +80,10 @@ border: 1px solid #ddd; } +.RRT__panel--hidden { + display: none; +} + .RRT__accordion .RRT__panel { margin-top: 0; } @@ -104,7 +107,7 @@ } .RRT__showmore-label { - padding: .7em 1em; + padding: 0.7em 1em; position: relative; bottom: -1px; z-index: 1;