Skip to content

Commit

Permalink
Add unmountOnExit prop
Browse files Browse the repository at this point in the history
  • Loading branch information
maslianok committed Jun 5, 2020
1 parent 2d42277 commit 0b6e862
Show file tree
Hide file tree
Showing 10 changed files with 256 additions and 97 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) => ({
Expand Down Expand Up @@ -86,6 +89,7 @@ render(<App />, 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 |
Expand Down
36 changes: 19 additions & 17 deletions examples/src/Basic/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => ({
Expand All @@ -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 (
<div className="basic__wrapper">
<div className="basic__props">
<div className="basic__prop">
<label>
<input type="checkbox" onChange={this.onChangeProp('showMore')} checked={showMore} />
{' '}
showMore
<input type="checkbox" onChange={this.onChangeProp('showMore')} checked={showMore} />{' '}
<span>showMore</span>
</label>
</div>
<div className="basic__prop">
<label>
<input type="checkbox" onChange={this.onChangeProp('transform')} checked={transform} />{' '}
<span>transform to accordion when width {'<'} 800px</span>
</label>
</div>
<div className="basic__prop">
<label>
<input type="checkbox" onChange={this.onChangeProp('transform')} checked={transform} />
{' '}
{'transform to accordion when width < 800px'}
<input type="checkbox" onChange={this.onChangeProp('showInkBar')} checked={showInkBar} />{' '}
<span>showInkBar</span>
</label>
</div>
<div className="basic__prop">
<label>
<input type="checkbox" onChange={this.onChangeProp('showInkBar')} checked={showInkBar} />
{' '}
showInkBar
<input type="checkbox" onChange={this.onChangeProp('unmountOnExit')} checked={unmountOnExit} />{' '}
<span>unmount inactive tabs</span>
</label>
</div>
<div className="basic__prop">
Expand All @@ -64,9 +67,8 @@ export class Basic extends PureComponent {
onChange={this.onChangeProp('selectedTabKey')}
className="basic__input"
value={selectedTabKey}
/>
{' '}
selected tab
/>{' '}
<span>selected tab</span>
</label>
</div>
</div>
Expand Down
32 changes: 16 additions & 16 deletions examples/src/Basic/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
.basic__tabs {
padding: 10px;
flex-grow: 1;
}
34 changes: 26 additions & 8 deletions lib/components/TabPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -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, [{
Expand All @@ -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",
Expand All @@ -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
};
}
}]);

Expand All @@ -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
};
34 changes: 26 additions & 8 deletions lib/esm/components/TabPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -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, [{
Expand All @@ -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",
Expand All @@ -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
};
}
}]);

Expand All @@ -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
};
49 changes: 40 additions & 9 deletions lib/esm/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
};
});

Expand All @@ -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;
Expand All @@ -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 '';
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -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(),
Expand All @@ -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;
Expand All @@ -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
}));
Expand Down Expand Up @@ -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,
Expand All @@ -528,6 +558,7 @@ Tabs.defaultProps = {
tabClass: undefined,
panelClass: undefined,
showMoreLabel: '...',
unmountOnExit: true,
onChange: function onChange() {
return null;
},
Expand Down
Loading

0 comments on commit 0b6e862

Please sign in to comment.