@instructure/ui-tabs 9.0.2-snapshot-11 → 9.0.2-snapshot-13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,7 +3,7 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
- ## [9.0.2-snapshot-11](https://github.com/instructure/instructure-ui/compare/v9.0.1...v9.0.2-snapshot-11) (2024-06-12)
6
+ ## [9.0.2-snapshot-13](https://github.com/instructure/instructure-ui/compare/v9.0.1...v9.0.2-snapshot-13) (2024-06-13)
7
7
 
8
8
 
9
9
  ### Bug Fixes
@@ -11,6 +11,11 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
11
11
  * **ui-tabs:** fix id generation when null is present as children ([85765ae](https://github.com/instructure/instructure-ui/commit/85765ae3183ac121714cd814a322dcc012ed2f72))
12
12
 
13
13
 
14
+ ### Features
15
+
16
+ * **ui-tabs:** add option for persisting tabpanels ([6fe73a3](https://github.com/instructure/instructure-ui/commit/6fe73a3ec76c88fcc7baf2f587276de595316dbc))
17
+
18
+
14
19
 
15
20
 
16
21
 
@@ -1,5 +1,5 @@
1
1
  import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
2
- const _excluded = ["labelledBy", "variant", "id", "maxHeight", "minHeight", "padding", "textAlign", "children", "elementRef", "isDisabled", "isSelected", "styles", "active"];
2
+ const _excluded = ["labelledBy", "variant", "id", "maxHeight", "minHeight", "padding", "textAlign", "children", "elementRef", "isDisabled", "isSelected", "styles", "active", "unmountOnExit"];
3
3
  var _dec, _class, _Panel;
4
4
  /*
5
5
  * The MIT License (MIT)
@@ -55,40 +55,50 @@ let Panel = (_dec = withStyle(generateStyle, generateComponentTheme), _dec(_clas
55
55
  }
56
56
  componentDidMount() {
57
57
  var _this$props$makeStyle, _this$props;
58
- (_this$props$makeStyle = (_this$props = this.props).makeStyles) === null || _this$props$makeStyle === void 0 ? void 0 : _this$props$makeStyle.call(_this$props);
58
+ (_this$props$makeStyle = (_this$props = this.props).makeStyles) === null || _this$props$makeStyle === void 0 ? void 0 : _this$props$makeStyle.call(_this$props, {
59
+ isHidden: this.isHidden
60
+ });
59
61
  }
60
62
  componentDidUpdate() {
61
63
  var _this$props$makeStyle2, _this$props2;
62
- (_this$props$makeStyle2 = (_this$props2 = this.props).makeStyles) === null || _this$props$makeStyle2 === void 0 ? void 0 : _this$props$makeStyle2.call(_this$props2);
64
+ (_this$props$makeStyle2 = (_this$props2 = this.props).makeStyles) === null || _this$props$makeStyle2 === void 0 ? void 0 : _this$props$makeStyle2.call(_this$props2, {
65
+ isHidden: this.isHidden
66
+ });
63
67
  }
64
- render() {
68
+ get isHidden() {
65
69
  const _this$props3 = this.props,
66
- labelledBy = _this$props3.labelledBy,
67
- variant = _this$props3.variant,
68
- id = _this$props3.id,
69
- maxHeight = _this$props3.maxHeight,
70
- minHeight = _this$props3.minHeight,
71
- padding = _this$props3.padding,
72
- textAlign = _this$props3.textAlign,
73
- children = _this$props3.children,
74
- elementRef = _this$props3.elementRef,
75
70
  isDisabled = _this$props3.isDisabled,
76
- isSelected = _this$props3.isSelected,
77
- styles = _this$props3.styles,
78
- active = _this$props3.active,
79
- props = _objectWithoutProperties(_this$props3, _excluded);
80
- const isHidden = !isSelected || !!isDisabled;
71
+ isSelected = _this$props3.isSelected;
72
+ return !isSelected || !!isDisabled;
73
+ }
74
+ render() {
75
+ const _this$props4 = this.props,
76
+ labelledBy = _this$props4.labelledBy,
77
+ variant = _this$props4.variant,
78
+ id = _this$props4.id,
79
+ maxHeight = _this$props4.maxHeight,
80
+ minHeight = _this$props4.minHeight,
81
+ padding = _this$props4.padding,
82
+ textAlign = _this$props4.textAlign,
83
+ children = _this$props4.children,
84
+ elementRef = _this$props4.elementRef,
85
+ isDisabled = _this$props4.isDisabled,
86
+ isSelected = _this$props4.isSelected,
87
+ styles = _this$props4.styles,
88
+ active = _this$props4.active,
89
+ unmountOnExit = _this$props4.unmountOnExit,
90
+ props = _objectWithoutProperties(_this$props4, _excluded);
81
91
  return jsx("div", Object.assign({}, passthroughProps(props), {
82
92
  css: styles === null || styles === void 0 ? void 0 : styles.panel,
83
93
  role: "tabpanel",
84
94
  id: id,
85
95
  "aria-labelledby": labelledBy,
86
- "aria-hidden": isHidden ? 'true' : void 0,
96
+ "aria-hidden": this.isHidden ? 'true' : void 0,
87
97
  ref: this.handleRef
88
98
  }), jsx(Transition, {
89
99
  type: "fade",
90
- in: !isHidden,
91
- unmountOnExit: true,
100
+ in: !this.isHidden,
101
+ unmountOnExit: unmountOnExit,
92
102
  transitionExit: false
93
103
  }, jsx(View, {
94
104
  css: styles === null || styles === void 0 ? void 0 : styles.content,
@@ -105,7 +115,8 @@ let Panel = (_dec = withStyle(generateStyle, generateComponentTheme), _dec(_clas
105
115
  variant: 'default',
106
116
  isSelected: false,
107
117
  padding: 'small',
108
- active: false
118
+ active: false,
119
+ unmountOnExit: true
109
120
  }, _Panel)) || _class);
110
121
  export default Panel;
111
122
  export { Panel };
@@ -37,7 +37,8 @@ const propTypes = {
37
37
  padding: ThemeablePropTypes.spacing,
38
38
  textAlign: PropTypes.oneOf(['start', 'center', 'end']),
39
39
  elementRef: PropTypes.func,
40
- active: PropTypes.bool
40
+ active: PropTypes.bool,
41
+ unmountOnExit: PropTypes.bool
41
42
  };
42
- const allowedProps = ['renderTitle', 'children', 'variant', 'isSelected', 'isDisabled', 'maxHeight', 'minHeight', 'id', 'labelledBy', 'padding', 'textAlign', 'elementRef', 'active'];
43
+ const allowedProps = ['renderTitle', 'children', 'variant', 'isSelected', 'isDisabled', 'maxHeight', 'minHeight', 'id', 'labelledBy', 'padding', 'textAlign', 'elementRef', 'active', 'unmountOnExit'];
43
44
  export { propTypes, allowedProps };
@@ -32,9 +32,10 @@
32
32
  * @param {Object} state the state of the component, the style is applied to
33
33
  * @return {Object} The final style object, which will be used in the component
34
34
  */
35
- const generateStyle = (componentTheme, props) => {
35
+ const generateStyle = (componentTheme, props, state) => {
36
36
  const maxHeight = props.maxHeight,
37
37
  isSelected = props.isSelected;
38
+ const isHidden = state.isHidden;
38
39
  return {
39
40
  panel: {
40
41
  label: 'panel',
@@ -48,6 +49,9 @@ const generateStyle = (componentTheme, props) => {
48
49
  ...(isSelected && {
49
50
  flexGrow: 1,
50
51
  height: '100%'
52
+ }),
53
+ ...(isHidden && {
54
+ display: 'none'
51
55
  })
52
56
  },
53
57
  content: {
package/es/Tabs/index.js CHANGED
@@ -26,7 +26,7 @@ var _dec, _dec2, _class, _Tabs;
26
26
  */
27
27
 
28
28
  /** @jsx jsx */
29
- import React, { Component, createElement } from 'react';
29
+ import React, { Component } from 'react';
30
30
  import keycode from 'keycode';
31
31
  import { View } from '@instructure/ui-view';
32
32
  import { matchComponentTypes, safeCloneElement, passthroughProps } from '@instructure/ui-react-utils';
@@ -256,18 +256,17 @@ let Tabs = (_dec = withStyle(generateStyle, generateComponentTheme), _dec2 = tes
256
256
  }
257
257
  createTab(index, generatedId, selected, panel) {
258
258
  const id = panel.props.id || generatedId;
259
- return /*#__PURE__*/createElement(Tab, {
259
+ return jsx(Tab, {
260
260
  variant: this.props.variant,
261
261
  key: `tab-${index}`,
262
262
  id: `tab-${id}`,
263
263
  controls: panel.props.id || `panel-${id}`,
264
- index,
264
+ index: index,
265
265
  isSelected: selected,
266
266
  isDisabled: panel.props.isDisabled,
267
- children: panel.props.renderTitle,
268
267
  onClick: this.handleTabClick,
269
268
  onKeyDown: this.handleTabKeyDown
270
- });
269
+ }, panel.props.renderTitle);
271
270
  }
272
271
  clonePanel(index, generatedId, selected, panel, activePanel) {
273
272
  const id = panel.props.id || generatedId;
@@ -14,7 +14,7 @@ var _emotion = require("@instructure/emotion");
14
14
  var _styles = _interopRequireDefault(require("./styles"));
15
15
  var _theme = _interopRequireDefault(require("./theme"));
16
16
  var _props = require("./props");
17
- const _excluded = ["labelledBy", "variant", "id", "maxHeight", "minHeight", "padding", "textAlign", "children", "elementRef", "isDisabled", "isSelected", "styles", "active"];
17
+ const _excluded = ["labelledBy", "variant", "id", "maxHeight", "minHeight", "padding", "textAlign", "children", "elementRef", "isDisabled", "isSelected", "styles", "active", "unmountOnExit"];
18
18
  var _dec, _class, _Panel;
19
19
  /*
20
20
  * The MIT License (MIT)
@@ -60,40 +60,50 @@ let Panel = exports.Panel = (_dec = (0, _emotion.withStyle)(_styles.default, _th
60
60
  }
61
61
  componentDidMount() {
62
62
  var _this$props$makeStyle, _this$props;
63
- (_this$props$makeStyle = (_this$props = this.props).makeStyles) === null || _this$props$makeStyle === void 0 ? void 0 : _this$props$makeStyle.call(_this$props);
63
+ (_this$props$makeStyle = (_this$props = this.props).makeStyles) === null || _this$props$makeStyle === void 0 ? void 0 : _this$props$makeStyle.call(_this$props, {
64
+ isHidden: this.isHidden
65
+ });
64
66
  }
65
67
  componentDidUpdate() {
66
68
  var _this$props$makeStyle2, _this$props2;
67
- (_this$props$makeStyle2 = (_this$props2 = this.props).makeStyles) === null || _this$props$makeStyle2 === void 0 ? void 0 : _this$props$makeStyle2.call(_this$props2);
69
+ (_this$props$makeStyle2 = (_this$props2 = this.props).makeStyles) === null || _this$props$makeStyle2 === void 0 ? void 0 : _this$props$makeStyle2.call(_this$props2, {
70
+ isHidden: this.isHidden
71
+ });
68
72
  }
69
- render() {
73
+ get isHidden() {
70
74
  const _this$props3 = this.props,
71
- labelledBy = _this$props3.labelledBy,
72
- variant = _this$props3.variant,
73
- id = _this$props3.id,
74
- maxHeight = _this$props3.maxHeight,
75
- minHeight = _this$props3.minHeight,
76
- padding = _this$props3.padding,
77
- textAlign = _this$props3.textAlign,
78
- children = _this$props3.children,
79
- elementRef = _this$props3.elementRef,
80
75
  isDisabled = _this$props3.isDisabled,
81
- isSelected = _this$props3.isSelected,
82
- styles = _this$props3.styles,
83
- active = _this$props3.active,
84
- props = (0, _objectWithoutProperties2.default)(_this$props3, _excluded);
85
- const isHidden = !isSelected || !!isDisabled;
76
+ isSelected = _this$props3.isSelected;
77
+ return !isSelected || !!isDisabled;
78
+ }
79
+ render() {
80
+ const _this$props4 = this.props,
81
+ labelledBy = _this$props4.labelledBy,
82
+ variant = _this$props4.variant,
83
+ id = _this$props4.id,
84
+ maxHeight = _this$props4.maxHeight,
85
+ minHeight = _this$props4.minHeight,
86
+ padding = _this$props4.padding,
87
+ textAlign = _this$props4.textAlign,
88
+ children = _this$props4.children,
89
+ elementRef = _this$props4.elementRef,
90
+ isDisabled = _this$props4.isDisabled,
91
+ isSelected = _this$props4.isSelected,
92
+ styles = _this$props4.styles,
93
+ active = _this$props4.active,
94
+ unmountOnExit = _this$props4.unmountOnExit,
95
+ props = (0, _objectWithoutProperties2.default)(_this$props4, _excluded);
86
96
  return (0, _emotion.jsx)("div", Object.assign({}, (0, _passthroughProps.passthroughProps)(props), {
87
97
  css: styles === null || styles === void 0 ? void 0 : styles.panel,
88
98
  role: "tabpanel",
89
99
  id: id,
90
100
  "aria-labelledby": labelledBy,
91
- "aria-hidden": isHidden ? 'true' : void 0,
101
+ "aria-hidden": this.isHidden ? 'true' : void 0,
92
102
  ref: this.handleRef
93
103
  }), (0, _emotion.jsx)(_Transition.Transition, {
94
104
  type: "fade",
95
- in: !isHidden,
96
- unmountOnExit: true,
105
+ in: !this.isHidden,
106
+ unmountOnExit: unmountOnExit,
97
107
  transitionExit: false
98
108
  }, (0, _emotion.jsx)(_View.View, {
99
109
  css: styles === null || styles === void 0 ? void 0 : styles.content,
@@ -110,6 +120,7 @@ let Panel = exports.Panel = (_dec = (0, _emotion.withStyle)(_styles.default, _th
110
120
  variant: 'default',
111
121
  isSelected: false,
112
122
  padding: 'small',
113
- active: false
123
+ active: false,
124
+ unmountOnExit: true
114
125
  }, _Panel)) || _class);
115
126
  var _default = exports.default = Panel;
@@ -44,6 +44,7 @@ const propTypes = exports.propTypes = {
44
44
  padding: _emotion.ThemeablePropTypes.spacing,
45
45
  textAlign: _propTypes.default.oneOf(['start', 'center', 'end']),
46
46
  elementRef: _propTypes.default.func,
47
- active: _propTypes.default.bool
47
+ active: _propTypes.default.bool,
48
+ unmountOnExit: _propTypes.default.bool
48
49
  };
49
- const allowedProps = exports.allowedProps = ['renderTitle', 'children', 'variant', 'isSelected', 'isDisabled', 'maxHeight', 'minHeight', 'id', 'labelledBy', 'padding', 'textAlign', 'elementRef', 'active'];
50
+ const allowedProps = exports.allowedProps = ['renderTitle', 'children', 'variant', 'isSelected', 'isDisabled', 'maxHeight', 'minHeight', 'id', 'labelledBy', 'padding', 'textAlign', 'elementRef', 'active', 'unmountOnExit'];
@@ -38,9 +38,10 @@ exports.default = void 0;
38
38
  * @param {Object} state the state of the component, the style is applied to
39
39
  * @return {Object} The final style object, which will be used in the component
40
40
  */
41
- const generateStyle = (componentTheme, props) => {
41
+ const generateStyle = (componentTheme, props, state) => {
42
42
  const maxHeight = props.maxHeight,
43
43
  isSelected = props.isSelected;
44
+ const isHidden = state.isHidden;
44
45
  return {
45
46
  panel: {
46
47
  label: 'panel',
@@ -54,6 +55,9 @@ const generateStyle = (componentTheme, props) => {
54
55
  ...(isSelected && {
55
56
  flexGrow: 1,
56
57
  height: '100%'
58
+ }),
59
+ ...(isHidden && {
60
+ display: 'none'
57
61
  })
58
62
  },
59
63
  content: {
package/lib/Tabs/index.js CHANGED
@@ -271,18 +271,17 @@ let Tabs = exports.Tabs = (_dec = (0, _emotion.withStyle)(_styles.default, _them
271
271
  }
272
272
  createTab(index, generatedId, selected, panel) {
273
273
  const id = panel.props.id || generatedId;
274
- return /*#__PURE__*/(0, _react.createElement)(_Tab.Tab, {
274
+ return (0, _emotion.jsx)(_Tab.Tab, {
275
275
  variant: this.props.variant,
276
276
  key: `tab-${index}`,
277
277
  id: `tab-${id}`,
278
278
  controls: panel.props.id || `panel-${id}`,
279
- index,
279
+ index: index,
280
280
  isSelected: selected,
281
281
  isDisabled: panel.props.isDisabled,
282
- children: panel.props.renderTitle,
283
282
  onClick: this.handleTabClick,
284
283
  onKeyDown: this.handleTabKeyDown
285
- });
284
+ }, panel.props.renderTitle);
286
285
  }
287
286
  clonePanel(index, generatedId, selected, panel, activePanel) {
288
287
  const id = panel.props.id || generatedId;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instructure/ui-tabs",
3
- "version": "9.0.2-snapshot-11",
3
+ "version": "9.0.2-snapshot-13",
4
4
  "description": "A UI component library made by Instructure Inc.",
5
5
  "author": "Instructure, Inc. Engineering and Product Design",
6
6
  "module": "./es/index.js",
@@ -23,30 +23,30 @@
23
23
  },
24
24
  "license": "MIT",
25
25
  "devDependencies": {
26
- "@instructure/ui-babel-preset": "9.0.2-snapshot-11",
27
- "@instructure/ui-color-utils": "9.0.2-snapshot-11",
28
- "@instructure/ui-test-locator": "9.0.2-snapshot-11",
29
- "@instructure/ui-test-utils": "9.0.2-snapshot-11",
30
- "@instructure/ui-themes": "9.0.2-snapshot-11",
26
+ "@instructure/ui-babel-preset": "9.0.2-snapshot-13",
27
+ "@instructure/ui-color-utils": "9.0.2-snapshot-13",
28
+ "@instructure/ui-test-locator": "9.0.2-snapshot-13",
29
+ "@instructure/ui-test-utils": "9.0.2-snapshot-13",
30
+ "@instructure/ui-themes": "9.0.2-snapshot-13",
31
31
  "@testing-library/jest-dom": "^6.4.5",
32
32
  "@testing-library/react": "^15.0.7"
33
33
  },
34
34
  "dependencies": {
35
35
  "@babel/runtime": "^7.24.5",
36
- "@instructure/console": "9.0.2-snapshot-11",
37
- "@instructure/debounce": "9.0.2-snapshot-11",
38
- "@instructure/emotion": "9.0.2-snapshot-11",
39
- "@instructure/shared-types": "9.0.2-snapshot-11",
40
- "@instructure/ui-dom-utils": "9.0.2-snapshot-11",
41
- "@instructure/ui-focusable": "9.0.2-snapshot-11",
42
- "@instructure/ui-i18n": "9.0.2-snapshot-11",
43
- "@instructure/ui-motion": "9.0.2-snapshot-11",
44
- "@instructure/ui-prop-types": "9.0.2-snapshot-11",
45
- "@instructure/ui-react-utils": "9.0.2-snapshot-11",
46
- "@instructure/ui-testable": "9.0.2-snapshot-11",
47
- "@instructure/ui-utils": "9.0.2-snapshot-11",
48
- "@instructure/ui-view": "9.0.2-snapshot-11",
49
- "@instructure/uid": "9.0.2-snapshot-11",
36
+ "@instructure/console": "9.0.2-snapshot-13",
37
+ "@instructure/debounce": "9.0.2-snapshot-13",
38
+ "@instructure/emotion": "9.0.2-snapshot-13",
39
+ "@instructure/shared-types": "9.0.2-snapshot-13",
40
+ "@instructure/ui-dom-utils": "9.0.2-snapshot-13",
41
+ "@instructure/ui-focusable": "9.0.2-snapshot-13",
42
+ "@instructure/ui-i18n": "9.0.2-snapshot-13",
43
+ "@instructure/ui-motion": "9.0.2-snapshot-13",
44
+ "@instructure/ui-prop-types": "9.0.2-snapshot-13",
45
+ "@instructure/ui-react-utils": "9.0.2-snapshot-13",
46
+ "@instructure/ui-testable": "9.0.2-snapshot-13",
47
+ "@instructure/ui-utils": "9.0.2-snapshot-13",
48
+ "@instructure/ui-view": "9.0.2-snapshot-13",
49
+ "@instructure/uid": "9.0.2-snapshot-13",
50
50
  "keycode": "^2.2.1",
51
51
  "prop-types": "^15.8.1"
52
52
  },
@@ -55,19 +55,25 @@ class Panel extends Component<TabsPanelProps> {
55
55
  variant: 'default',
56
56
  isSelected: false,
57
57
  padding: 'small',
58
- active: false
58
+ active: false,
59
+ unmountOnExit: true
59
60
  }
60
61
 
61
62
  componentDidMount() {
62
- this.props.makeStyles?.()
63
+ this.props.makeStyles?.({ isHidden: this.isHidden })
63
64
  }
64
65
 
65
66
  componentDidUpdate() {
66
- this.props.makeStyles?.()
67
+ this.props.makeStyles?.({ isHidden: this.isHidden })
67
68
  }
68
69
 
69
70
  ref: HTMLDivElement | null = null
70
71
 
72
+ get isHidden() {
73
+ const { isDisabled, isSelected } = this.props
74
+ return !isSelected || !!isDisabled
75
+ }
76
+
71
77
  handleRef = (el: HTMLDivElement | null) => {
72
78
  const { elementRef } = this.props
73
79
 
@@ -93,9 +99,9 @@ class Panel extends Component<TabsPanelProps> {
93
99
  isSelected,
94
100
  styles,
95
101
  active,
102
+ unmountOnExit,
96
103
  ...props
97
104
  } = this.props
98
- const isHidden = !isSelected || !!isDisabled
99
105
 
100
106
  return (
101
107
  <div
@@ -104,13 +110,13 @@ class Panel extends Component<TabsPanelProps> {
104
110
  role="tabpanel"
105
111
  id={id}
106
112
  aria-labelledby={labelledBy}
107
- aria-hidden={isHidden ? 'true' : undefined}
113
+ aria-hidden={this.isHidden ? 'true' : undefined}
108
114
  ref={this.handleRef}
109
115
  >
110
116
  <Transition
111
117
  type="fade"
112
- in={!isHidden}
113
- unmountOnExit
118
+ in={!this.isHidden}
119
+ unmountOnExit={unmountOnExit}
114
120
  transitionExit={false}
115
121
  >
116
122
  <View
@@ -63,6 +63,10 @@ type TabsPanelOwnProps = {
63
63
  * for all the `<Tabs.Panel />`s.
64
64
  */
65
65
  active?: boolean
66
+ /**
67
+ * When set to false, the tabPanel only will be hidden, but not dismounted when not active
68
+ */
69
+ unmountOnExit?: boolean
66
70
  }
67
71
 
68
72
  type PropKeys = keyof TabsPanelOwnProps
@@ -88,7 +92,8 @@ const propTypes: PropValidators<PropKeys> = {
88
92
  padding: ThemeablePropTypes.spacing,
89
93
  textAlign: PropTypes.oneOf(['start', 'center', 'end']),
90
94
  elementRef: PropTypes.func,
91
- active: PropTypes.bool
95
+ active: PropTypes.bool,
96
+ unmountOnExit: PropTypes.bool
92
97
  }
93
98
 
94
99
  const allowedProps: AllowedPropKeys = [
@@ -104,7 +109,8 @@ const allowedProps: AllowedPropKeys = [
104
109
  'padding',
105
110
  'textAlign',
106
111
  'elementRef',
107
- 'active'
112
+ 'active',
113
+ 'unmountOnExit'
108
114
  ]
109
115
 
110
116
  export type { TabsPanelProps, TabsPanelStyle }
@@ -37,9 +37,11 @@ import type { TabsPanelProps, TabsPanelStyle } from './props'
37
37
  */
38
38
  const generateStyle = (
39
39
  componentTheme: TabsPanelTheme,
40
- props: TabsPanelProps
40
+ props: TabsPanelProps,
41
+ state: { isHidden: boolean }
41
42
  ): TabsPanelStyle => {
42
43
  const { maxHeight, isSelected } = props
44
+ const { isHidden } = state
43
45
 
44
46
  return {
45
47
  panel: {
@@ -54,6 +56,9 @@ const generateStyle = (
54
56
  ...(isSelected && {
55
57
  flexGrow: 1,
56
58
  height: '100%'
59
+ }),
60
+ ...(isHidden && {
61
+ display: 'none'
57
62
  })
58
63
  },
59
64
  content: {
@@ -322,6 +322,79 @@ class Example extends React.Component {
322
322
  render(<Example />)
323
323
  ```
324
324
 
325
+ ### Persisting the selected tab
326
+
327
+ If you need to persist the rendered content of the tabpanels between tabbing, you can set the `unmountOnExit` prop to `false` on the `<Tabs.Panel>` component. It works case by case, so you can set it to `false` only on the tabpanels you want to persist.
328
+
329
+ ```js
330
+ ---
331
+ type: example
332
+ ---
333
+ class Counter extends React.Component{
334
+ state = {
335
+ counter: 0
336
+ }
337
+ handleIncrement = () => {
338
+ this.setState({
339
+ counter: this.state.counter + 1
340
+ })
341
+ }
342
+
343
+ render () {
344
+ return (
345
+ <div>
346
+ <Button onClick={this.handleIncrement}>Increment</Button>
347
+ <hr/>
348
+ <Text>{this.state.counter}</Text>
349
+ </div>
350
+ )
351
+ }
352
+ }
353
+ class Example extends React.Component {
354
+ state = {
355
+ selectedIndex: 0
356
+ }
357
+ handleTabChange = (event, { index, id }) => {
358
+ this.setState({
359
+ selectedIndex: index
360
+ })
361
+ }
362
+ render () {
363
+ const { selectedIndex } = this.state
364
+ return (
365
+ <Tabs
366
+ margin="large auto"
367
+ padding="medium"
368
+ onRequestTabChange={this.handleTabChange}
369
+ >
370
+ <Tabs.Panel
371
+ id="tabA"
372
+ renderTitle="I will persist"
373
+ textAlign="center"
374
+ padding="large"
375
+ isSelected={selectedIndex === 0}
376
+ unmountOnExit={false}
377
+ >
378
+ <Counter/>
379
+ </Tabs.Panel>
380
+ <Tabs.Panel id="tabB" renderTitle="I will unmount" isSelected={selectedIndex === 1} textAlign="center"
381
+ padding="large">
382
+ <Counter/>
383
+ </Tabs.Panel>
384
+ <Tabs.Panel id="tabC" renderTitle="Tab C" isSelected={selectedIndex === 2}>
385
+ Tab C
386
+ </Tabs.Panel>
387
+ <Tabs.Panel id="tabD" renderTitle="Tab D" isSelected={selectedIndex === 3}>
388
+ Tab D
389
+ </Tabs.Panel>
390
+ </Tabs>
391
+ )
392
+ }
393
+ }
394
+
395
+ render(<Example />)
396
+ ```
397
+
325
398
  ### Guidelines
326
399
 
327
400
  ```js
@@ -23,13 +23,7 @@
23
23
  */
24
24
 
25
25
  /** @jsx jsx */
26
- import React, {
27
- Component,
28
- ComponentClass,
29
- ComponentElement,
30
- createElement,
31
- ReactElement
32
- } from 'react'
26
+ import React, { Component, ComponentElement, ReactElement } from 'react'
33
27
 
34
28
  import keycode from 'keycode'
35
29
 
@@ -341,18 +335,21 @@ class Tabs extends Component<TabsProps, TabsState> {
341
335
  ): TabChild {
342
336
  const id = panel.props.id || generatedId
343
337
 
344
- return createElement(Tab as ComponentClass<TabsTabProps>, {
345
- variant: this.props.variant,
346
- key: `tab-${index}`,
347
- id: `tab-${id}`,
348
- controls: panel.props.id || `panel-${id}`,
349
- index,
350
- isSelected: selected,
351
- isDisabled: panel.props.isDisabled,
352
- children: panel.props.renderTitle,
353
- onClick: this.handleTabClick,
354
- onKeyDown: this.handleTabKeyDown
355
- })
338
+ return (
339
+ <Tab
340
+ variant={this.props.variant}
341
+ key={`tab-${index}`}
342
+ id={`tab-${id}`}
343
+ controls={panel.props.id || `panel-${id}`}
344
+ index={index}
345
+ isSelected={selected}
346
+ isDisabled={panel.props.isDisabled}
347
+ onClick={this.handleTabClick}
348
+ onKeyDown={this.handleTabKeyDown}
349
+ >
350
+ {panel.props.renderTitle}
351
+ </Tab>
352
+ )
356
353
  }
357
354
 
358
355
  clonePanel(