@instructure/ui-tabs 9.0.2-snapshot-11 → 9.0.2-snapshot-15
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 +7 -1
- package/es/Tabs/Panel/index.js +33 -22
- package/es/Tabs/Panel/props.js +3 -2
- package/es/Tabs/Panel/styles.js +5 -1
- package/es/Tabs/index.js +10 -6
- package/lib/Tabs/Panel/index.js +33 -22
- package/lib/Tabs/Panel/props.js +3 -2
- package/lib/Tabs/Panel/styles.js +5 -1
- package/lib/Tabs/index.js +9 -5
- package/package.json +20 -20
- package/src/Tabs/Panel/index.tsx +13 -7
- package/src/Tabs/Panel/props.ts +8 -2
- package/src/Tabs/Panel/styles.ts +6 -1
- package/src/Tabs/README.md +73 -0
- package/src/Tabs/index.tsx +24 -21
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/Tabs/Panel/index.d.ts +4 -0
- package/types/Tabs/Panel/index.d.ts.map +1 -1
- package/types/Tabs/Panel/props.d.ts +4 -0
- package/types/Tabs/Panel/props.d.ts.map +1 -1
- package/types/Tabs/Panel/styles.d.ts +3 -1
- package/types/Tabs/Panel/styles.d.ts.map +1 -1
- package/types/Tabs/index.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,14 +3,20 @@
|
|
|
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-
|
|
6
|
+
## [9.0.2-snapshot-15](https://github.com/instructure/instructure-ui/compare/v9.0.1...v9.0.2-snapshot-15) (2024-06-13)
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
### Bug Fixes
|
|
10
10
|
|
|
11
|
+
* **ui-tabs:** fix horizontal scrolling with keyboard navigation ([a25c7db](https://github.com/instructure/instructure-ui/commit/a25c7db1ebede622f489dd65872ed8fc5a1b9651))
|
|
11
12
|
* **ui-tabs:** fix id generation when null is present as children ([85765ae](https://github.com/instructure/instructure-ui/commit/85765ae3183ac121714cd814a322dcc012ed2f72))
|
|
12
13
|
|
|
13
14
|
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* **ui-tabs:** add option for persisting tabpanels ([6fe73a3](https://github.com/instructure/instructure-ui/commit/6fe73a3ec76c88fcc7baf2f587276de595316dbc))
|
|
18
|
+
|
|
19
|
+
|
|
14
20
|
|
|
15
21
|
|
|
16
22
|
|
package/es/Tabs/Panel/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const
|
|
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:
|
|
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 };
|
package/es/Tabs/Panel/props.js
CHANGED
|
@@ -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 };
|
package/es/Tabs/Panel/styles.js
CHANGED
|
@@ -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
|
|
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';
|
|
@@ -252,22 +252,26 @@ let Tabs = (_dec = withStyle(generateStyle, generateComponentTheme), _dec2 = tes
|
|
|
252
252
|
id
|
|
253
253
|
});
|
|
254
254
|
}
|
|
255
|
-
|
|
255
|
+
|
|
256
|
+
// this is needed because keypress cancels scrolling. So we have to trigger the scrolling
|
|
257
|
+
// one "tick" later than the keypress
|
|
258
|
+
setTimeout(() => {
|
|
259
|
+
this.state.withTabListOverflow && this.showActiveTabIfOverlayed(this._tabList.querySelector(`#tab-${id}`));
|
|
260
|
+
}, 0);
|
|
256
261
|
}
|
|
257
262
|
createTab(index, generatedId, selected, panel) {
|
|
258
263
|
const id = panel.props.id || generatedId;
|
|
259
|
-
return
|
|
264
|
+
return jsx(Tab, {
|
|
260
265
|
variant: this.props.variant,
|
|
261
266
|
key: `tab-${index}`,
|
|
262
267
|
id: `tab-${id}`,
|
|
263
268
|
controls: panel.props.id || `panel-${id}`,
|
|
264
|
-
index,
|
|
269
|
+
index: index,
|
|
265
270
|
isSelected: selected,
|
|
266
271
|
isDisabled: panel.props.isDisabled,
|
|
267
|
-
children: panel.props.renderTitle,
|
|
268
272
|
onClick: this.handleTabClick,
|
|
269
273
|
onKeyDown: this.handleTabKeyDown
|
|
270
|
-
});
|
|
274
|
+
}, panel.props.renderTitle);
|
|
271
275
|
}
|
|
272
276
|
clonePanel(index, generatedId, selected, panel, activePanel) {
|
|
273
277
|
const id = panel.props.id || generatedId;
|
package/lib/Tabs/Panel/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const
|
|
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:
|
|
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;
|
package/lib/Tabs/Panel/props.js
CHANGED
|
@@ -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'];
|
package/lib/Tabs/Panel/styles.js
CHANGED
|
@@ -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
|
@@ -267,22 +267,26 @@ let Tabs = exports.Tabs = (_dec = (0, _emotion.withStyle)(_styles.default, _them
|
|
|
267
267
|
id
|
|
268
268
|
});
|
|
269
269
|
}
|
|
270
|
-
|
|
270
|
+
|
|
271
|
+
// this is needed because keypress cancels scrolling. So we have to trigger the scrolling
|
|
272
|
+
// one "tick" later than the keypress
|
|
273
|
+
setTimeout(() => {
|
|
274
|
+
this.state.withTabListOverflow && this.showActiveTabIfOverlayed(this._tabList.querySelector(`#tab-${id}`));
|
|
275
|
+
}, 0);
|
|
271
276
|
}
|
|
272
277
|
createTab(index, generatedId, selected, panel) {
|
|
273
278
|
const id = panel.props.id || generatedId;
|
|
274
|
-
return
|
|
279
|
+
return (0, _emotion.jsx)(_Tab.Tab, {
|
|
275
280
|
variant: this.props.variant,
|
|
276
281
|
key: `tab-${index}`,
|
|
277
282
|
id: `tab-${id}`,
|
|
278
283
|
controls: panel.props.id || `panel-${id}`,
|
|
279
|
-
index,
|
|
284
|
+
index: index,
|
|
280
285
|
isSelected: selected,
|
|
281
286
|
isDisabled: panel.props.isDisabled,
|
|
282
|
-
children: panel.props.renderTitle,
|
|
283
287
|
onClick: this.handleTabClick,
|
|
284
288
|
onKeyDown: this.handleTabKeyDown
|
|
285
|
-
});
|
|
289
|
+
}, panel.props.renderTitle);
|
|
286
290
|
}
|
|
287
291
|
clonePanel(index, generatedId, selected, panel, activePanel) {
|
|
288
292
|
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-
|
|
3
|
+
"version": "9.0.2-snapshot-15",
|
|
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-
|
|
27
|
-
"@instructure/ui-color-utils": "9.0.2-snapshot-
|
|
28
|
-
"@instructure/ui-test-locator": "9.0.2-snapshot-
|
|
29
|
-
"@instructure/ui-test-utils": "9.0.2-snapshot-
|
|
30
|
-
"@instructure/ui-themes": "9.0.2-snapshot-
|
|
26
|
+
"@instructure/ui-babel-preset": "9.0.2-snapshot-15",
|
|
27
|
+
"@instructure/ui-color-utils": "9.0.2-snapshot-15",
|
|
28
|
+
"@instructure/ui-test-locator": "9.0.2-snapshot-15",
|
|
29
|
+
"@instructure/ui-test-utils": "9.0.2-snapshot-15",
|
|
30
|
+
"@instructure/ui-themes": "9.0.2-snapshot-15",
|
|
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-
|
|
37
|
-
"@instructure/debounce": "9.0.2-snapshot-
|
|
38
|
-
"@instructure/emotion": "9.0.2-snapshot-
|
|
39
|
-
"@instructure/shared-types": "9.0.2-snapshot-
|
|
40
|
-
"@instructure/ui-dom-utils": "9.0.2-snapshot-
|
|
41
|
-
"@instructure/ui-focusable": "9.0.2-snapshot-
|
|
42
|
-
"@instructure/ui-i18n": "9.0.2-snapshot-
|
|
43
|
-
"@instructure/ui-motion": "9.0.2-snapshot-
|
|
44
|
-
"@instructure/ui-prop-types": "9.0.2-snapshot-
|
|
45
|
-
"@instructure/ui-react-utils": "9.0.2-snapshot-
|
|
46
|
-
"@instructure/ui-testable": "9.0.2-snapshot-
|
|
47
|
-
"@instructure/ui-utils": "9.0.2-snapshot-
|
|
48
|
-
"@instructure/ui-view": "9.0.2-snapshot-
|
|
49
|
-
"@instructure/uid": "9.0.2-snapshot-
|
|
36
|
+
"@instructure/console": "9.0.2-snapshot-15",
|
|
37
|
+
"@instructure/debounce": "9.0.2-snapshot-15",
|
|
38
|
+
"@instructure/emotion": "9.0.2-snapshot-15",
|
|
39
|
+
"@instructure/shared-types": "9.0.2-snapshot-15",
|
|
40
|
+
"@instructure/ui-dom-utils": "9.0.2-snapshot-15",
|
|
41
|
+
"@instructure/ui-focusable": "9.0.2-snapshot-15",
|
|
42
|
+
"@instructure/ui-i18n": "9.0.2-snapshot-15",
|
|
43
|
+
"@instructure/ui-motion": "9.0.2-snapshot-15",
|
|
44
|
+
"@instructure/ui-prop-types": "9.0.2-snapshot-15",
|
|
45
|
+
"@instructure/ui-react-utils": "9.0.2-snapshot-15",
|
|
46
|
+
"@instructure/ui-testable": "9.0.2-snapshot-15",
|
|
47
|
+
"@instructure/ui-utils": "9.0.2-snapshot-15",
|
|
48
|
+
"@instructure/ui-view": "9.0.2-snapshot-15",
|
|
49
|
+
"@instructure/uid": "9.0.2-snapshot-15",
|
|
50
50
|
"keycode": "^2.2.1",
|
|
51
51
|
"prop-types": "^15.8.1"
|
|
52
52
|
},
|
package/src/Tabs/Panel/index.tsx
CHANGED
|
@@ -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
|
package/src/Tabs/Panel/props.ts
CHANGED
|
@@ -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 }
|
package/src/Tabs/Panel/styles.ts
CHANGED
|
@@ -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: {
|
package/src/Tabs/README.md
CHANGED
|
@@ -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
|
package/src/Tabs/index.tsx
CHANGED
|
@@ -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
|
|
|
@@ -329,8 +323,14 @@ class Tabs extends Component<TabsProps, TabsState> {
|
|
|
329
323
|
this.props.onRequestTabChange(event, { index, id })
|
|
330
324
|
}
|
|
331
325
|
|
|
332
|
-
this.
|
|
333
|
-
|
|
326
|
+
// this is needed because keypress cancels scrolling. So we have to trigger the scrolling
|
|
327
|
+
// one "tick" later than the keypress
|
|
328
|
+
setTimeout(() => {
|
|
329
|
+
this.state.withTabListOverflow &&
|
|
330
|
+
this.showActiveTabIfOverlayed(
|
|
331
|
+
this._tabList!.querySelector(`#tab-${id}`)
|
|
332
|
+
)
|
|
333
|
+
}, 0)
|
|
334
334
|
}
|
|
335
335
|
|
|
336
336
|
createTab(
|
|
@@ -341,18 +341,21 @@ class Tabs extends Component<TabsProps, TabsState> {
|
|
|
341
341
|
): TabChild {
|
|
342
342
|
const id = panel.props.id || generatedId
|
|
343
343
|
|
|
344
|
-
return
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
344
|
+
return (
|
|
345
|
+
<Tab
|
|
346
|
+
variant={this.props.variant}
|
|
347
|
+
key={`tab-${index}`}
|
|
348
|
+
id={`tab-${id}`}
|
|
349
|
+
controls={panel.props.id || `panel-${id}`}
|
|
350
|
+
index={index}
|
|
351
|
+
isSelected={selected}
|
|
352
|
+
isDisabled={panel.props.isDisabled}
|
|
353
|
+
onClick={this.handleTabClick}
|
|
354
|
+
onKeyDown={this.handleTabKeyDown}
|
|
355
|
+
>
|
|
356
|
+
{panel.props.renderTitle}
|
|
357
|
+
</Tab>
|
|
358
|
+
)
|
|
356
359
|
}
|
|
357
360
|
|
|
358
361
|
clonePanel(
|