@dhis2-ui/tab 9.11.0 → 9.11.1-beta.1
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/build/cjs/index.js +0 -2
- package/build/cjs/tab/features/accepts_children/index.js +0 -1
- package/build/cjs/tab/features/accepts_icon/index.js +0 -1
- package/build/cjs/tab/features/is_clickable/index.js +2 -3
- package/build/cjs/tab/index.js +0 -1
- package/build/cjs/tab/tab.e2e.stories.js +28 -0
- package/build/cjs/tab/tab.js +8 -25
- package/build/cjs/tab-bar/animated-side-scroll.js +0 -7
- package/build/cjs/tab-bar/detect-horizontal-scrollbar-height.js +12 -3
- package/build/cjs/tab-bar/features/accepts_children/index.js +0 -1
- package/build/cjs/tab-bar/features/auto_hides_scroll_buttons/index.js +0 -1
- package/build/cjs/tab-bar/index.js +0 -1
- package/build/cjs/tab-bar/scroll-bar.js +7 -44
- package/build/cjs/tab-bar/scroll-button.js +2 -10
- package/build/cjs/tab-bar/tab-bar.e2e.stories.js +31 -0
- package/build/cjs/tab-bar/tab-bar.js +4 -15
- package/build/cjs/tab-bar/{tab-bar.stories.js → tab-bar.prod.stories.js} +23 -29
- package/build/cjs/tab-bar/tabs.js +6 -25
- package/build/es/tab/features/is_clickable/index.js +2 -2
- package/build/es/tab/tab.e2e.stories.js +17 -0
- package/build/es/tab/tab.js +4 -9
- package/build/es/tab-bar/animated-side-scroll.js +0 -6
- package/build/es/tab-bar/detect-horizontal-scrollbar-height.js +12 -2
- package/build/es/tab-bar/scroll-bar.js +4 -31
- package/build/es/tab-bar/scroll-button.js +1 -1
- package/build/es/tab-bar/{tab-bar.stories.e2e.js → tab-bar.e2e.stories.js} +8 -5
- package/build/es/tab-bar/tab-bar.js +3 -9
- package/build/es/tab-bar/{tab-bar.stories.js → tab-bar.prod.stories.js} +21 -6
- package/build/es/tab-bar/tabs.js +3 -14
- package/package.json +7 -7
- package/build/cjs/tab/tab.stories.e2e.js +0 -19
- package/build/cjs/tab-bar/tab-bar.stories.e2e.js +0 -26
- package/build/es/tab/tab.stories.e2e.js +0 -12
|
@@ -4,19 +4,12 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = exports.TabsWithScroller = exports.TabsWithHiddenScrollButtons = exports.TabStatesWithIcon = exports.TabStates = exports.RTL = exports.FixedTabsFillContent = exports.DefaultFluid = void 0;
|
|
7
|
-
|
|
8
7
|
var _style = _interopRequireDefault(require("styled-jsx/style"));
|
|
9
|
-
|
|
10
8
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
11
|
-
|
|
12
9
|
var _react = _interopRequireDefault(require("react"));
|
|
13
|
-
|
|
14
10
|
var _index = require("../tab/index.js");
|
|
15
|
-
|
|
16
11
|
var _index2 = require("./index.js");
|
|
17
|
-
|
|
18
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
|
-
|
|
12
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
20
13
|
function AttachFile(_ref) {
|
|
21
14
|
let {
|
|
22
15
|
className
|
|
@@ -32,29 +25,45 @@ function AttachFile(_ref) {
|
|
|
32
25
|
id: "4098137027"
|
|
33
26
|
}, ["svg.jsx-4098137027{fill:inherit;height:24px;width:24px;vertical-align:middle;pointer-events:none;}"]));
|
|
34
27
|
}
|
|
35
|
-
|
|
36
28
|
AttachFile.propTypes = {
|
|
37
29
|
className: _propTypes.default.string
|
|
38
30
|
};
|
|
39
31
|
const subtitle = 'Ssed to divide content into categories and/or sections';
|
|
40
|
-
const description =
|
|
32
|
+
const description = `
|
|
33
|
+
Use tabs to split related content into separate sections.
|
|
41
34
|
|
|
35
|
+
- Each tab should contain content that relates to one another, but the content should not overlap.
|
|
36
|
+
- Tabs are especially useful for splitting up content that may be relevant to different user groups, instead of displaying overwhelming amounts of information on a single page.
|
|
37
|
+
- Do not use tabs to compare content.
|
|
38
|
+
- Do not use tabs for sequential content that needs to be done in order.
|
|
39
|
+
- Do not use tabs for content that needs to be viewed at the same time.
|
|
40
|
+
- The number of tabs is less important than splitting content into understandable, predictable groups. Do not group together unrelated content in order to reduce tab count. Users struggle more with unpredictable tabs than too many tabs.
|
|
41
|
+
|
|
42
|
+
#### Naming
|
|
43
|
+
|
|
44
|
+
Give tabs short, understandable names. Try to find a word or very short phrase that summarizes the content. If you cannot find a suitable word this may mean you are trying to fit too much content under a single tab. The content of a tab should be obvious from its name.
|
|
45
|
+
|
|
46
|
+
For example: Do use "Legends" instead of "Set up legends", Do use "Data analysis" instead of "Options for analysis of data",
|
|
47
|
+
|
|
48
|
+
Do not repeat a term across tabs. If tabs are used inside a 'Options' modal, it is enough to use tab names "Data", "Legend", "Style". Do not repeat 'options' for all, e.g. "Data options", "Legend options" etc.
|
|
49
|
+
|
|
50
|
+
\`\`\`js
|
|
51
|
+
import { TabBar, Tab } from '@dhis2/ui'
|
|
52
|
+
\`\`\`
|
|
53
|
+
`;
|
|
42
54
|
const Wrapper = fn => /*#__PURE__*/_react.default.createElement("div", {
|
|
43
55
|
style: {
|
|
44
56
|
maxWidth: 700
|
|
45
57
|
}
|
|
46
58
|
}, fn(), /*#__PURE__*/_react.default.createElement("p", null, "Max-width of this container is 700 px"));
|
|
47
|
-
|
|
48
59
|
window.onClick = (payload, event) => {
|
|
49
60
|
console.log('onClick payload', payload);
|
|
50
61
|
console.log('onClick event', event);
|
|
51
62
|
};
|
|
52
|
-
|
|
53
63
|
const onClick = function () {
|
|
54
64
|
return window.onClick(...arguments);
|
|
55
65
|
};
|
|
56
|
-
|
|
57
|
-
var _default = {
|
|
66
|
+
var _default = exports.default = {
|
|
58
67
|
title: 'Tab Bar',
|
|
59
68
|
component: _index2.TabBar,
|
|
60
69
|
subcomponents: {
|
|
@@ -70,8 +79,6 @@ var _default = {
|
|
|
70
79
|
},
|
|
71
80
|
decorators: [Wrapper]
|
|
72
81
|
};
|
|
73
|
-
exports.default = _default;
|
|
74
|
-
|
|
75
82
|
const DefaultFluid = args => /*#__PURE__*/_react.default.createElement(_index2.TabBar, args, /*#__PURE__*/_react.default.createElement(_index.Tab, {
|
|
76
83
|
onClick: onClick
|
|
77
84
|
}, "Tab A"), /*#__PURE__*/_react.default.createElement(_index.Tab, {
|
|
@@ -88,10 +95,8 @@ const DefaultFluid = args => /*#__PURE__*/_react.default.createElement(_index2.T
|
|
|
88
95
|
}, "Tab F"), /*#__PURE__*/_react.default.createElement(_index.Tab, {
|
|
89
96
|
onClick: onClick
|
|
90
97
|
}, "Tab G"));
|
|
91
|
-
|
|
92
98
|
exports.DefaultFluid = DefaultFluid;
|
|
93
99
|
DefaultFluid.storyName = 'Default (fluid)';
|
|
94
|
-
|
|
95
100
|
const FixedTabsFillContent = args => /*#__PURE__*/_react.default.createElement(_index2.TabBar, args, /*#__PURE__*/_react.default.createElement(_index.Tab, {
|
|
96
101
|
onClick: onClick
|
|
97
102
|
}, "Tab A"), /*#__PURE__*/_react.default.createElement(_index.Tab, {
|
|
@@ -108,13 +113,11 @@ const FixedTabsFillContent = args => /*#__PURE__*/_react.default.createElement(_
|
|
|
108
113
|
}, "Tab F"), /*#__PURE__*/_react.default.createElement(_index.Tab, {
|
|
109
114
|
onClick: onClick
|
|
110
115
|
}, "Tab G"));
|
|
111
|
-
|
|
112
116
|
exports.FixedTabsFillContent = FixedTabsFillContent;
|
|
113
117
|
FixedTabsFillContent.args = {
|
|
114
118
|
fixed: true
|
|
115
119
|
};
|
|
116
120
|
FixedTabsFillContent.storyName = 'Fixed - tabs fill content';
|
|
117
|
-
|
|
118
121
|
const TabsWithScroller = args => /*#__PURE__*/_react.default.createElement(_index2.TabBar, args, /*#__PURE__*/_react.default.createElement(_index.Tab, {
|
|
119
122
|
onClick: onClick
|
|
120
123
|
}, "Tab A"), /*#__PURE__*/_react.default.createElement(_index.Tab, {
|
|
@@ -153,13 +156,11 @@ const TabsWithScroller = args => /*#__PURE__*/_react.default.createElement(_inde
|
|
|
153
156
|
}, "Tab Q"), /*#__PURE__*/_react.default.createElement(_index.Tab, {
|
|
154
157
|
onClick: onClick
|
|
155
158
|
}, "Tab R"));
|
|
156
|
-
|
|
157
159
|
exports.TabsWithScroller = TabsWithScroller;
|
|
158
160
|
TabsWithScroller.args = {
|
|
159
161
|
scrollable: true
|
|
160
162
|
};
|
|
161
163
|
TabsWithScroller.storyName = 'Tabs with scroller';
|
|
162
|
-
|
|
163
164
|
const TabsWithHiddenScrollButtons = args => /*#__PURE__*/_react.default.createElement(_index2.TabBar, args, /*#__PURE__*/_react.default.createElement(_index.Tab, {
|
|
164
165
|
onClick: onClick
|
|
165
166
|
}, "Tab A"), /*#__PURE__*/_react.default.createElement(_index.Tab, {
|
|
@@ -167,13 +168,11 @@ const TabsWithHiddenScrollButtons = args => /*#__PURE__*/_react.default.createEl
|
|
|
167
168
|
}, "Tab B"), /*#__PURE__*/_react.default.createElement(_index.Tab, {
|
|
168
169
|
onClick: onClick
|
|
169
170
|
}, "Tab C"));
|
|
170
|
-
|
|
171
171
|
exports.TabsWithHiddenScrollButtons = TabsWithHiddenScrollButtons;
|
|
172
172
|
TabsWithHiddenScrollButtons.args = {
|
|
173
173
|
scrollable: true
|
|
174
174
|
};
|
|
175
175
|
TabsWithHiddenScrollButtons.storyName = 'Tabs with hidden scroll buttons';
|
|
176
|
-
|
|
177
176
|
const TabStates = args => /*#__PURE__*/_react.default.createElement(_index2.TabBar, args, /*#__PURE__*/_react.default.createElement(_index.Tab, {
|
|
178
177
|
onClick: onClick
|
|
179
178
|
}, "Default"), /*#__PURE__*/_react.default.createElement(_index.Tab, {
|
|
@@ -184,10 +183,8 @@ const TabStates = args => /*#__PURE__*/_react.default.createElement(_index2.TabB
|
|
|
184
183
|
}, "Disabled"), /*#__PURE__*/_react.default.createElement(_index.Tab, {
|
|
185
184
|
onClick: onClick
|
|
186
185
|
}, "Text overflow - This tab has a very long text and it exceeds the maximum width of 320px"));
|
|
187
|
-
|
|
188
186
|
exports.TabStates = TabStates;
|
|
189
187
|
TabStates.storyName = 'Tab states';
|
|
190
|
-
|
|
191
188
|
const TabStatesWithIcon = args => /*#__PURE__*/_react.default.createElement(_index2.TabBar, args, /*#__PURE__*/_react.default.createElement(_index.Tab, {
|
|
192
189
|
onClick: onClick,
|
|
193
190
|
icon: /*#__PURE__*/_react.default.createElement(AttachFile, null)
|
|
@@ -202,12 +199,9 @@ const TabStatesWithIcon = args => /*#__PURE__*/_react.default.createElement(_ind
|
|
|
202
199
|
onClick: onClick,
|
|
203
200
|
icon: /*#__PURE__*/_react.default.createElement(AttachFile, null)
|
|
204
201
|
}, "Text overflow - This tab has a very long text and it exceeds the maximum width of 320px"));
|
|
205
|
-
|
|
206
202
|
exports.TabStatesWithIcon = TabStatesWithIcon;
|
|
207
203
|
TabStatesWithIcon.storyName = 'Tab states - with icon';
|
|
208
|
-
|
|
209
204
|
const RTL = args => /*#__PURE__*/_react.default.createElement("div", {
|
|
210
205
|
dir: "rtl"
|
|
211
206
|
}, /*#__PURE__*/_react.default.createElement(TabStatesWithIcon, args));
|
|
212
|
-
|
|
213
207
|
exports.RTL = RTL;
|
|
@@ -4,23 +4,14 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.Tabs = void 0;
|
|
7
|
-
|
|
8
7
|
var _style = _interopRequireDefault(require("styled-jsx/style"));
|
|
9
|
-
|
|
10
8
|
var _uiConstants = require("@dhis2/ui-constants");
|
|
11
|
-
|
|
12
9
|
var _classnames = _interopRequireDefault(require("classnames"));
|
|
13
|
-
|
|
14
10
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
15
|
-
|
|
16
11
|
var _react = _interopRequireWildcard(require("react"));
|
|
17
|
-
|
|
18
|
-
function
|
|
19
|
-
|
|
20
|
-
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
21
|
-
|
|
22
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
23
|
-
|
|
12
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
13
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
14
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
24
15
|
const Tabs = _ref => {
|
|
25
16
|
let {
|
|
26
17
|
children,
|
|
@@ -29,37 +20,29 @@ const Tabs = _ref => {
|
|
|
29
20
|
} = _ref;
|
|
30
21
|
const tabContainer = (0, _react.useRef)(null);
|
|
31
22
|
const childrenRefs = (0, _react.useMemo)(() => _react.default.Children.map(children, () => /*#__PURE__*/_react.default.createRef()), [children]);
|
|
32
|
-
|
|
33
23
|
const handleKeyDown = event => {
|
|
34
24
|
const currentFocus = document.activeElement;
|
|
35
|
-
|
|
36
25
|
if (tabContainer.current && tabContainer.current === currentFocus) {
|
|
37
26
|
if (childrenRefs.length > 0 && childrenRefs[0].current) {
|
|
38
27
|
childrenRefs[0].current.focus();
|
|
39
28
|
}
|
|
40
|
-
|
|
41
29
|
return;
|
|
42
30
|
}
|
|
43
|
-
|
|
44
31
|
const currentIndex = childrenRefs.findIndex(ref => ref.current === currentFocus);
|
|
45
|
-
|
|
46
32
|
if (currentIndex === -1) {
|
|
47
33
|
return;
|
|
48
34
|
}
|
|
49
|
-
|
|
50
35
|
if (event.key === 'ArrowRight') {
|
|
51
36
|
event.preventDefault();
|
|
52
37
|
const nextIndex = (currentIndex + 1) % childrenRefs.length;
|
|
53
38
|
childrenRefs[nextIndex].current.focus();
|
|
54
39
|
}
|
|
55
|
-
|
|
56
40
|
if (event.key === 'ArrowLeft') {
|
|
57
41
|
event.preventDefault();
|
|
58
42
|
const prevIndex = (currentIndex - 1 + childrenRefs.length) % childrenRefs.length;
|
|
59
43
|
childrenRefs[prevIndex].current.focus();
|
|
60
44
|
}
|
|
61
45
|
};
|
|
62
|
-
|
|
63
46
|
return /*#__PURE__*/_react.default.createElement("div", {
|
|
64
47
|
ref: tabContainer,
|
|
65
48
|
"data-test": dataTest,
|
|
@@ -74,9 +57,8 @@ const Tabs = _ref => {
|
|
|
74
57
|
return /*#__PURE__*/_react.default.cloneElement(child, {
|
|
75
58
|
ref: childrenRefs[index]
|
|
76
59
|
});
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
60
|
+
}
|
|
61
|
+
// Wrap non-element children e.g string in a <span>
|
|
80
62
|
return /*#__PURE__*/_react.default.createElement("span", {
|
|
81
63
|
ref: childrenRefs[index],
|
|
82
64
|
tabIndex: -1,
|
|
@@ -85,9 +67,8 @@ const Tabs = _ref => {
|
|
|
85
67
|
}), /*#__PURE__*/_react.default.createElement(_style.default, {
|
|
86
68
|
id: "771129571",
|
|
87
69
|
dynamic: [_uiConstants.colors.grey400, _uiConstants.colors.white]
|
|
88
|
-
}, [
|
|
70
|
+
}, [`div.__jsx-style-dynamic-selector{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:flex-start;-webkit-box-align:flex-start;-ms-flex-align:flex-start;align-items:flex-start;position:relative;overflow:hidden;box-shadow:inset 0 -1px 0 0 ${_uiConstants.colors.grey400};-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;background:${_uiConstants.colors.white};}`]));
|
|
89
71
|
};
|
|
90
|
-
|
|
91
72
|
exports.Tabs = Tabs;
|
|
92
73
|
Tabs.propTypes = {
|
|
93
74
|
dataTest: _propTypes.default.string.isRequired,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor';
|
|
2
2
|
Given('a Tab with onClick handler is rendered', () => {
|
|
3
|
-
cy.visitStory('Tab', 'With
|
|
3
|
+
cy.visitStory('Tab', 'With on click');
|
|
4
4
|
});
|
|
5
5
|
Given('a disabled Tab with onClick handler is rendered', () => {
|
|
6
|
-
cy.visitStory('Tab', 'With
|
|
6
|
+
cy.visitStory('Tab', 'With on click and disabled');
|
|
7
7
|
});
|
|
8
8
|
When('the Tab is clicked', () => {
|
|
9
9
|
cy.get('[data-test="dhis2-uicore-tab"]').click();
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Tab } from './tab.js';
|
|
3
|
+
window.onClick = window.Cypress && window.Cypress.cy.stub();
|
|
4
|
+
export default {
|
|
5
|
+
title: 'Tab'
|
|
6
|
+
};
|
|
7
|
+
export const WithOnClick = () => /*#__PURE__*/React.createElement(Tab, {
|
|
8
|
+
onClick: window.onClick
|
|
9
|
+
}, "Tab A");
|
|
10
|
+
export const WithChildren = () => /*#__PURE__*/React.createElement(Tab, null, "I am a child");
|
|
11
|
+
export const WithIcon = () => /*#__PURE__*/React.createElement(Tab, {
|
|
12
|
+
icon: /*#__PURE__*/React.createElement("div", null, "Icon")
|
|
13
|
+
}, "Children");
|
|
14
|
+
export const WithOnClickAndDisabled = () => /*#__PURE__*/React.createElement(Tab, {
|
|
15
|
+
onClick: window.onClick,
|
|
16
|
+
disabled: true
|
|
17
|
+
}, "Tab A");
|
package/build/es/tab/tab.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _JSXStyle from "styled-jsx/style";
|
|
2
|
-
import { Tooltip } from '@dhis2-ui/tooltip';
|
|
3
2
|
import { colors, theme } from '@dhis2/ui-constants';
|
|
3
|
+
import { Tooltip } from '@dhis2-ui/tooltip';
|
|
4
4
|
import cx from 'classnames';
|
|
5
5
|
import PropTypes from 'prop-types';
|
|
6
6
|
import React, { useState, useEffect, useRef } from 'react';
|
|
@@ -15,18 +15,15 @@ export const Tab = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
15
15
|
dataTest
|
|
16
16
|
} = _ref;
|
|
17
17
|
let tabRef = useRef(null);
|
|
18
|
-
|
|
19
18
|
if (ref) {
|
|
20
19
|
tabRef = ref;
|
|
21
20
|
}
|
|
22
|
-
|
|
23
21
|
const [isOverflowing, setIsOverflowing] = useState(false);
|
|
24
22
|
useEffect(() => {
|
|
25
23
|
const checkOverflow = () => {
|
|
26
24
|
const isOverflow = tabRef.current.scrollWidth > tabRef.current.clientWidth;
|
|
27
25
|
setIsOverflowing(isOverflow);
|
|
28
26
|
};
|
|
29
|
-
|
|
30
27
|
checkOverflow();
|
|
31
28
|
}, []);
|
|
32
29
|
return /*#__PURE__*/React.createElement("button", {
|
|
@@ -38,10 +35,10 @@ export const Tab = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
38
35
|
"aria-disabled": disabled ? 'true' : 'false',
|
|
39
36
|
onFocus: disabled ? undefined : event => onClick({}, event),
|
|
40
37
|
tabIndex: -1,
|
|
41
|
-
className: _JSXStyle.dynamic([["2433456263", [colors.grey400, colors.grey600, theme.focus, colors.grey600, colors.grey900, colors.grey600, colors.grey800, theme.primary800, theme.primary700, theme.primary700, theme.primary700, colors.grey500, colors.grey500]]]) + " " +
|
|
38
|
+
className: _JSXStyle.dynamic([["2433456263", [colors.grey400, colors.grey600, theme.focus, colors.grey600, colors.grey900, colors.grey600, colors.grey800, theme.primary800, theme.primary700, theme.primary700, theme.primary700, colors.grey500, colors.grey500]]]) + " " + `${cx('tab', className, {
|
|
42
39
|
selected,
|
|
43
40
|
disabled
|
|
44
|
-
})
|
|
41
|
+
})}`
|
|
45
42
|
}, icon, isOverflowing ? /*#__PURE__*/React.createElement(Tooltip, {
|
|
46
43
|
content: children,
|
|
47
44
|
maxWidth: '100%'
|
|
@@ -54,7 +51,7 @@ export const Tab = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
54
51
|
}, children), /*#__PURE__*/React.createElement(_JSXStyle, {
|
|
55
52
|
id: "2433456263",
|
|
56
53
|
dynamic: [colors.grey400, colors.grey600, theme.focus, colors.grey600, colors.grey900, colors.grey600, colors.grey800, theme.primary800, theme.primary700, theme.primary700, theme.primary700, colors.grey500, colors.grey500]
|
|
57
|
-
}, [
|
|
54
|
+
}, [`button.__jsx-style-dynamic-selector{-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;position:relative;display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;vertical-align:bottom;height:100%;padding:16px 16px 11px;background-color:transparent;outline:none;border:none;border-bottom:1px solid ${colors.grey400};color:${colors.grey600};font-size:14px;line-height:20px;cursor:pointer;}`, ".fixed>button.__jsx-style-dynamic-selector{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;}", "button.__jsx-style-dynamic-selector::after{content:' ';display:block;position:absolute;bottom:-1px;inset-inline-start:0;height:4px;width:100%;background-color:transparent;}", "span.__jsx-style-dynamic-selector{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;max-width:320px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;-webkit-transition:fill 150ms ease-in-out;transition:fill 150ms ease-in-out;}", `button.__jsx-style-dynamic-selector:focus{outline:3px solid ${theme.focus};outline-offset:-3px;}`, "button.__jsx-style-dynamic-selector:focus.__jsx-style-dynamic-selector:not(:focus-visible){outline:none;}", `button.__jsx-style-dynamic-selector>svg{fill:${colors.grey600};width:14px;height:14px;margin:0 4px 0 0;}`, `button.__jsx-style-dynamic-selector:hover{color:${colors.grey900};}`, `button.__jsx-style-dynamic-selector:hover.__jsx-style-dynamic-selector::after{background-color:${colors.grey600};height:2px;}`, `button.__jsx-style-dynamic-selector:active.__jsx-style-dynamic-selector::after{background-color:${colors.grey800};}`, `button.selected.__jsx-style-dynamic-selector{color:${theme.primary800};}`, `button.selected.__jsx-style-dynamic-selector::after{background-color:${theme.primary700};-webkit-transition:background-color 150ms ease-in-out;transition:background-color 150ms ease-in-out;}`, `button.selected.__jsx-style-dynamic-selector:hover.__jsx-style-dynamic-selector::after{background-color:${theme.primary700};height:4px;}`, `button.selected.__jsx-style-dynamic-selector>svg{fill:${theme.primary700};}`, `button.disabled.__jsx-style-dynamic-selector{color:${colors.grey500};cursor:not-allowed;}`, "button.disabled.__jsx-style-dynamic-selector:hover,button.selected.__jsx-style-dynamic-selector:hover{background-color:transparent;}", `button.disabled.__jsx-style-dynamic-selector>svg{fill:${colors.grey500};}`]));
|
|
58
55
|
});
|
|
59
56
|
Tab.defaultProps = {
|
|
60
57
|
dataTest: 'dhis2-uicore-tab'
|
|
@@ -65,10 +62,8 @@ Tab.propTypes = {
|
|
|
65
62
|
dataTest: PropTypes.string,
|
|
66
63
|
disabled: PropTypes.bool,
|
|
67
64
|
icon: PropTypes.element,
|
|
68
|
-
|
|
69
65
|
/** Indicates this tab is selected */
|
|
70
66
|
selected: PropTypes.bool,
|
|
71
|
-
|
|
72
67
|
/** Called with the signature `({}, event)` */
|
|
73
68
|
onClick: PropTypes.func
|
|
74
69
|
};
|
|
@@ -14,13 +14,11 @@ export function animatedSideScroll(scrollBox, callback) {
|
|
|
14
14
|
});
|
|
15
15
|
window.requestAnimationFrame(step);
|
|
16
16
|
}
|
|
17
|
-
|
|
18
17
|
function getEndValue(scrollBox, startValue, goBackwards) {
|
|
19
18
|
const scrollDistance = scrollBox.clientWidth * SCROLL_STEP;
|
|
20
19
|
const inverter = goBackwards ? -1 : 1;
|
|
21
20
|
return Math.floor(startValue + scrollDistance * inverter);
|
|
22
21
|
}
|
|
23
|
-
|
|
24
22
|
function createFrameStepper(_ref) {
|
|
25
23
|
let {
|
|
26
24
|
scrollBox,
|
|
@@ -34,7 +32,6 @@ function createFrameStepper(_ref) {
|
|
|
34
32
|
if (!startTimestamp) {
|
|
35
33
|
startTimestamp = timestamp;
|
|
36
34
|
}
|
|
37
|
-
|
|
38
35
|
elapsedTime = timestamp - startTimestamp;
|
|
39
36
|
scrollValue = easeInOutQuad({
|
|
40
37
|
currentTime: elapsedTime,
|
|
@@ -42,12 +39,10 @@ function createFrameStepper(_ref) {
|
|
|
42
39
|
startValue,
|
|
43
40
|
change
|
|
44
41
|
});
|
|
45
|
-
|
|
46
42
|
if (elapsedTime >= DURATION) {
|
|
47
43
|
if (scrollValue !== endValue) {
|
|
48
44
|
scrollBox.scrollLeft = endValue;
|
|
49
45
|
}
|
|
50
|
-
|
|
51
46
|
callback && callback();
|
|
52
47
|
} else {
|
|
53
48
|
scrollBox.scrollLeft = scrollValue;
|
|
@@ -55,7 +50,6 @@ function createFrameStepper(_ref) {
|
|
|
55
50
|
}
|
|
56
51
|
};
|
|
57
52
|
}
|
|
58
|
-
|
|
59
53
|
function easeInOutQuad(_ref2) {
|
|
60
54
|
let {
|
|
61
55
|
currentTime,
|
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
let horizontalScrollbarHeight;
|
|
2
2
|
const className = '__vertical-scrollbar-height-test__';
|
|
3
|
-
const styles =
|
|
3
|
+
const styles = `
|
|
4
|
+
.${className} {
|
|
5
|
+
position: absolute;
|
|
6
|
+
top: -9999px;
|
|
7
|
+
width: 100px;
|
|
8
|
+
height: 100px;
|
|
9
|
+
overflow-x: scroll;
|
|
10
|
+
}
|
|
11
|
+
.${className}::-webkit-scrollbar {
|
|
12
|
+
display: none;
|
|
13
|
+
}
|
|
14
|
+
`;
|
|
4
15
|
export function detectHorizontalScrollbarHeight() {
|
|
5
16
|
if (horizontalScrollbarHeight) {
|
|
6
17
|
return horizontalScrollbarHeight;
|
|
7
18
|
}
|
|
8
|
-
|
|
9
19
|
const style = document.createElement('style');
|
|
10
20
|
style.innerHTML = styles;
|
|
11
21
|
const el = document.createElement('div');
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import _JSXStyle from "styled-jsx/style";
|
|
2
|
-
|
|
3
|
-
function
|
|
4
|
-
|
|
2
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
3
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
4
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
5
5
|
import { IconChevronRight16, IconChevronLeft16 } from '@dhis2/ui-icons';
|
|
6
6
|
import cx from 'classnames';
|
|
7
7
|
import PropTypes from 'prop-types';
|
|
@@ -9,19 +9,13 @@ import React, { Component, createRef } from 'react';
|
|
|
9
9
|
import { animatedSideScroll } from './animated-side-scroll.js';
|
|
10
10
|
import { detectHorizontalScrollbarHeight } from './detect-horizontal-scrollbar-height.js';
|
|
11
11
|
import { ScrollButton } from './scroll-button.js';
|
|
12
|
-
|
|
13
12
|
class ScrollBar extends Component {
|
|
14
13
|
constructor(props) {
|
|
15
14
|
super(props);
|
|
16
|
-
|
|
17
15
|
_defineProperty(this, "scrollBox", /*#__PURE__*/createRef());
|
|
18
|
-
|
|
19
16
|
_defineProperty(this, "scrollArea", /*#__PURE__*/createRef());
|
|
20
|
-
|
|
21
17
|
_defineProperty(this, "horizontalScrollBarHeight", detectHorizontalScrollbarHeight());
|
|
22
|
-
|
|
23
18
|
_defineProperty(this, "scrollBoxResizeObserver", null);
|
|
24
|
-
|
|
25
19
|
_defineProperty(this, "calculateShouldHideButtons", () => {
|
|
26
20
|
this.setState({
|
|
27
21
|
hideScrollButtonsInitialized: false
|
|
@@ -38,31 +32,24 @@ class ScrollBar extends Component {
|
|
|
38
32
|
this.setState({
|
|
39
33
|
hideScrollButtons
|
|
40
34
|
});
|
|
41
|
-
|
|
42
35
|
if (!hideScrollButtons) {
|
|
43
36
|
if (this.state.scrolledToStart) {
|
|
44
37
|
this.scrollLeft();
|
|
45
38
|
}
|
|
46
|
-
|
|
47
39
|
if (this.state.scrolledToEnd) {
|
|
48
40
|
this.scrollRight();
|
|
49
41
|
}
|
|
50
42
|
}
|
|
51
|
-
|
|
52
43
|
this.setState({
|
|
53
44
|
hideScrollButtonsInitialized: true
|
|
54
45
|
});
|
|
55
46
|
});
|
|
56
|
-
|
|
57
47
|
_defineProperty(this, "scrollRight", () => this.scroll());
|
|
58
|
-
|
|
59
48
|
_defineProperty(this, "scrollLeft", () => this.scroll(true));
|
|
60
|
-
|
|
61
49
|
_defineProperty(this, "animatedScrollCallback", () => {
|
|
62
50
|
this.updateScrolledToStates();
|
|
63
51
|
this.attachSideScrollListener();
|
|
64
52
|
});
|
|
65
|
-
|
|
66
53
|
_defineProperty(this, "updateScrolledToStates", () => {
|
|
67
54
|
const {
|
|
68
55
|
scrollLeft,
|
|
@@ -73,7 +60,6 @@ class ScrollBar extends Component {
|
|
|
73
60
|
} = this.scrollArea.current;
|
|
74
61
|
const scrolledToStart = scrollLeft <= 0;
|
|
75
62
|
const scrolledToEnd = scrollLeft + offsetWidth >= areaOffsetWidth;
|
|
76
|
-
|
|
77
63
|
if (this.state.scrolledToStart !== scrolledToStart || this.state.scrolledToEnd !== scrolledToEnd) {
|
|
78
64
|
this.setState({
|
|
79
65
|
scrolledToStart,
|
|
@@ -81,7 +67,6 @@ class ScrollBar extends Component {
|
|
|
81
67
|
});
|
|
82
68
|
}
|
|
83
69
|
});
|
|
84
|
-
|
|
85
70
|
this.state = {
|
|
86
71
|
scrolledToStart: true,
|
|
87
72
|
scrolledToEnd: false,
|
|
@@ -92,18 +77,15 @@ class ScrollBar extends Component {
|
|
|
92
77
|
};
|
|
93
78
|
this.scrollBoxResizeObserver = new ResizeObserver(this.calculateShouldHideButtons);
|
|
94
79
|
}
|
|
95
|
-
|
|
96
80
|
componentDidMount() {
|
|
97
81
|
this.scrollSelectedTabIntoView();
|
|
98
82
|
this.attachSideScrollListener();
|
|
99
83
|
this.manageShouldHideButtons();
|
|
100
84
|
}
|
|
101
|
-
|
|
102
85
|
componentWillUnmount() {
|
|
103
86
|
this.removeSideScrollListener();
|
|
104
87
|
this.scrollBoxResizeObserver.disconnect();
|
|
105
88
|
}
|
|
106
|
-
|
|
107
89
|
manageShouldHideButtons() {
|
|
108
90
|
const {
|
|
109
91
|
current: scrollBox
|
|
@@ -111,33 +93,26 @@ class ScrollBar extends Component {
|
|
|
111
93
|
this.scrollBoxResizeObserver.observe(scrollBox);
|
|
112
94
|
this.calculateShouldHideButtons();
|
|
113
95
|
}
|
|
114
|
-
|
|
115
96
|
scroll(goBackwards) {
|
|
116
97
|
this.removeSideScrollListener();
|
|
117
98
|
animatedSideScroll(this.scrollBox.current, this.animatedScrollCallback, goBackwards);
|
|
118
99
|
}
|
|
119
|
-
|
|
120
100
|
scrollSelectedTabIntoView() {
|
|
121
101
|
const scrollBoxEl = this.scrollBox.current;
|
|
122
102
|
const tab = scrollBoxEl.querySelector('.tab.selected');
|
|
123
|
-
|
|
124
103
|
if (tab) {
|
|
125
104
|
const tabEnd = tab.offsetLeft + tab.offsetWidth;
|
|
126
|
-
|
|
127
105
|
if (tabEnd > scrollBoxEl.offsetWidth) {
|
|
128
106
|
scrollBoxEl.scrollLeft = tabEnd - scrollBoxEl.offsetWidth;
|
|
129
107
|
}
|
|
130
108
|
}
|
|
131
109
|
}
|
|
132
|
-
|
|
133
110
|
attachSideScrollListener() {
|
|
134
111
|
this.scrollBox.current.addEventListener('scroll', this.updateScrolledToStates);
|
|
135
112
|
}
|
|
136
|
-
|
|
137
113
|
removeSideScrollListener() {
|
|
138
114
|
this.scrollBox.current.removeEventListener('scroll', this.updateScrolledToStates);
|
|
139
115
|
}
|
|
140
|
-
|
|
141
116
|
render() {
|
|
142
117
|
const {
|
|
143
118
|
scrolledToStart,
|
|
@@ -173,13 +148,11 @@ class ScrollBar extends Component {
|
|
|
173
148
|
}, /*#__PURE__*/React.createElement(IconChevronRight16, null)), /*#__PURE__*/React.createElement(_JSXStyle, {
|
|
174
149
|
id: "4174900658",
|
|
175
150
|
dynamic: [-this.horizontalScrollBarHeight]
|
|
176
|
-
}, [
|
|
151
|
+
}, [`.scroll-box.__jsx-style-dynamic-selector{margin-bottom:${-this.horizontalScrollBarHeight}px;}`]), /*#__PURE__*/React.createElement(_JSXStyle, {
|
|
177
152
|
id: "191575146"
|
|
178
153
|
}, [".scroll-bar.jsx-191575146{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;}", ".scroll-box-clipper.jsx-191575146{overflow-y:hidden;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;}", ".scroll-box.jsx-191575146{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;overflow-x:scroll;-webkit-overflow-scrolling:touch;display:-ms-flexbox;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}", ".scroll-box.jsx-191575146::-webkit-scrollbar{display:none;}", ".scroll-area.jsx-191575146{position:relative;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex:1 0 auto;-ms-flex:1 0 auto;flex:1 0 auto;overflow-x:hidden;}"]));
|
|
179
154
|
}
|
|
180
|
-
|
|
181
155
|
}
|
|
182
|
-
|
|
183
156
|
ScrollBar.propTypes = {
|
|
184
157
|
children: PropTypes.node.isRequired,
|
|
185
158
|
dataTest: PropTypes.string.isRequired,
|
|
@@ -19,7 +19,7 @@ export const ScrollButton = _ref => {
|
|
|
19
19
|
}, children, /*#__PURE__*/React.createElement(_JSXStyle, {
|
|
20
20
|
id: "2701682090",
|
|
21
21
|
dynamic: [colors.white, colors.grey400, colors.grey600, colors.grey100, colors.grey200, colors.grey500]
|
|
22
|
-
}, [
|
|
22
|
+
}, [`.scroll-button.__jsx-style-dynamic-selector{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:inherit;background-color:${colors.white};border:none;border-bottom:1px solid ${colors.grey400};outline:none;padding:16px 16px 11px 16px;cursor:pointer;}`, ".scroll-button.hidden.__jsx-style-dynamic-selector{display:none;}", `.scroll-button.__jsx-style-dynamic-selector svg{width:20px;height:20px;fill:${colors.grey600};-webkit-transition:opacity 150ms ease-in-out;transition:opacity 150ms ease-in-out;opacity:1;}`, `.scroll-button.__jsx-style-dynamic-selector:hover{background-color:${colors.grey100};}`, `.scroll-button.__jsx-style-dynamic-selector:active{background-color:${colors.grey200};}`, ".scroll-button.disabled.__jsx-style-dynamic-selector{cursor:not-allowed;}", ".scroll-button.disabled.__jsx-style-dynamic-selector:hover{background-color:transparent;}", `.scroll-button.disabled.__jsx-style-dynamic-selector svg{fill:${colors.grey500};}`]));
|
|
23
23
|
};
|
|
24
24
|
ScrollButton.displayName = 'ScrollButton';
|
|
25
25
|
ScrollButton.propTypes = {
|
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
import { storiesOf } from '@storybook/react';
|
|
2
1
|
import React from 'react';
|
|
3
2
|
import { Tab } from '../tab/index.js';
|
|
4
3
|
import { TabBar } from './index.js';
|
|
5
|
-
|
|
4
|
+
export default {
|
|
5
|
+
title: 'TabBar'
|
|
6
|
+
};
|
|
7
|
+
export const WithChildren = () => /*#__PURE__*/React.createElement(TabBar, null, "I am a child");
|
|
8
|
+
export const ScrollableWithChildren = () => /*#__PURE__*/React.createElement(TabBar, {
|
|
6
9
|
scrollable: true
|
|
7
|
-
}, "I am a child")
|
|
10
|
+
}, "I am a child");
|
|
11
|
+
export const ScrollableWithSomeTabs = () => {
|
|
8
12
|
const TabStaticWidth = () => /*#__PURE__*/React.createElement(Tab, null, /*#__PURE__*/React.createElement("div", {
|
|
9
13
|
style: {
|
|
10
14
|
width: 100,
|
|
11
15
|
border: '1px solid black'
|
|
12
16
|
}
|
|
13
17
|
}, "Foo"));
|
|
14
|
-
|
|
15
18
|
return /*#__PURE__*/React.createElement(TabBar, {
|
|
16
19
|
scrollable: true
|
|
17
20
|
}, /*#__PURE__*/React.createElement(TabStaticWidth, null), /*#__PURE__*/React.createElement(TabStaticWidth, null), /*#__PURE__*/React.createElement(TabStaticWidth, null));
|
|
18
|
-
}
|
|
21
|
+
};
|
|
@@ -2,7 +2,6 @@ import PropTypes from 'prop-types';
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { ScrollBar } from './scroll-bar.js';
|
|
4
4
|
import { Tabs } from './tabs.js';
|
|
5
|
-
|
|
6
5
|
const TabBar = _ref => {
|
|
7
6
|
let {
|
|
8
7
|
fixed,
|
|
@@ -11,28 +10,25 @@ const TabBar = _ref => {
|
|
|
11
10
|
scrollable,
|
|
12
11
|
dataTest
|
|
13
12
|
} = _ref;
|
|
14
|
-
|
|
15
13
|
if (scrollable) {
|
|
16
14
|
return /*#__PURE__*/React.createElement("div", {
|
|
17
15
|
className: className,
|
|
18
16
|
"data-test": dataTest
|
|
19
17
|
}, /*#__PURE__*/React.createElement(ScrollBar, {
|
|
20
|
-
dataTest:
|
|
18
|
+
dataTest: `${dataTest}-scrollbar`
|
|
21
19
|
}, /*#__PURE__*/React.createElement(Tabs, {
|
|
22
20
|
fixed: fixed,
|
|
23
|
-
dataTest:
|
|
21
|
+
dataTest: `${dataTest}-tabs`
|
|
24
22
|
}, children)));
|
|
25
23
|
}
|
|
26
|
-
|
|
27
24
|
return /*#__PURE__*/React.createElement("div", {
|
|
28
25
|
className: className,
|
|
29
26
|
"data-test": dataTest
|
|
30
27
|
}, /*#__PURE__*/React.createElement(Tabs, {
|
|
31
28
|
fixed: fixed,
|
|
32
|
-
dataTest:
|
|
29
|
+
dataTest: `${dataTest}-tabs`
|
|
33
30
|
}, children));
|
|
34
31
|
};
|
|
35
|
-
|
|
36
32
|
TabBar.defaultProps = {
|
|
37
33
|
dataTest: 'dhis2-uicore-tabbar'
|
|
38
34
|
};
|
|
@@ -40,10 +36,8 @@ TabBar.propTypes = {
|
|
|
40
36
|
children: PropTypes.node,
|
|
41
37
|
className: PropTypes.string,
|
|
42
38
|
dataTest: PropTypes.string,
|
|
43
|
-
|
|
44
39
|
/** Fixed tabs fill the width of their container. If false (i.e. fluid), tabs take up an amount of space defined by the tab name. Fluid tabs should be used most of the time. */
|
|
45
40
|
fixed: PropTypes.bool,
|
|
46
|
-
|
|
47
41
|
/** Enables horizontal scrolling for many tabs that don't fit the width of the container */
|
|
48
42
|
scrollable: PropTypes.bool
|
|
49
43
|
};
|