@elliemae/ds-tabs 2.0.0-alpha.1 → 2.0.0-alpha.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.
Files changed (106) hide show
  1. package/cjs/DSTabs.js +29 -107
  2. package/cjs/DSTabsCTX.js +30 -0
  3. package/cjs/DSTabsDatatestid.js +18 -0
  4. package/cjs/DSTabsTypes.js +2 -0
  5. package/cjs/config/useCrossRef.js +17 -0
  6. package/cjs/config/useTabs.js +51 -0
  7. package/cjs/defaultProps.js +27 -0
  8. package/cjs/{PanelContainer.js → exportsRelated/DSTab.js} +19 -28
  9. package/cjs/index.js +5 -5
  10. package/cjs/parts/carousel/Carousel.js +71 -0
  11. package/cjs/parts/carousel/styles.js +60 -0
  12. package/cjs/parts/carousel/useCarousel.js +78 -0
  13. package/cjs/parts/carousel/useCarouselCallbacks.js +72 -0
  14. package/cjs/parts/tabBar/TabBar.js +160 -0
  15. package/cjs/parts/tabBar/styles.js +199 -0
  16. package/cjs/parts/tabBar/useTabBar.js +98 -0
  17. package/cjs/parts/tabsContent/TabsContent.js +49 -0
  18. package/cjs/parts/tabsContent/styles.js +15 -0
  19. package/cjs/parts/tabsPanel/TabsPanels.js +77 -0
  20. package/cjs/parts/tabsPanel/styles.js +25 -0
  21. package/cjs/propTypes.js +33 -0
  22. package/cjs/utils/constants.js +29 -0
  23. package/cjs/utils/helpers.js +47 -0
  24. package/cjs/utils/hooks/useKeyboardNavigation.js +61 -0
  25. package/cjs/utils/hooks/useTabsCallbacks.js +59 -0
  26. package/esm/DSTabs.js +30 -108
  27. package/esm/DSTabsCTX.js +25 -0
  28. package/esm/DSTabsDatatestid.js +14 -0
  29. package/esm/DSTabsTypes.js +1 -0
  30. package/esm/config/useCrossRef.js +13 -0
  31. package/esm/config/useTabs.js +47 -0
  32. package/esm/defaultProps.js +23 -0
  33. package/esm/{PanelContainer.js → exportsRelated/DSTab.js} +11 -23
  34. package/esm/index.js +4 -3
  35. package/esm/parts/carousel/Carousel.js +63 -0
  36. package/esm/parts/carousel/styles.js +49 -0
  37. package/esm/parts/carousel/useCarousel.js +70 -0
  38. package/esm/parts/carousel/useCarouselCallbacks.js +68 -0
  39. package/esm/parts/tabBar/TabBar.js +151 -0
  40. package/esm/parts/tabBar/styles.js +185 -0
  41. package/esm/parts/tabBar/useTabBar.js +90 -0
  42. package/esm/parts/tabsContent/TabsContent.js +40 -0
  43. package/esm/parts/tabsContent/styles.js +7 -0
  44. package/esm/parts/tabsPanel/TabsPanels.js +67 -0
  45. package/esm/parts/tabsPanel/styles.js +17 -0
  46. package/esm/propTypes.js +28 -0
  47. package/esm/utils/constants.js +21 -0
  48. package/esm/utils/helpers.js +37 -0
  49. package/esm/utils/hooks/useKeyboardNavigation.js +57 -0
  50. package/esm/utils/hooks/useTabsCallbacks.js +55 -0
  51. package/package.json +100 -37
  52. package/types/DSTabs.d.ts +10 -60
  53. package/types/DSTabsCTX.d.ts +4 -0
  54. package/types/DSTabsDatatestid.d.ts +12 -0
  55. package/types/DSTabsTypes.d.ts +202 -0
  56. package/types/config/useCrossRef.d.ts +2 -0
  57. package/types/config/useTabs.d.ts +2 -0
  58. package/types/defaultProps.d.ts +2 -0
  59. package/types/exportsRelated/DSTab.d.ts +14 -0
  60. package/types/index.d.ts +4 -3
  61. package/types/parts/carousel/Carousel.d.ts +3 -0
  62. package/types/parts/carousel/styles.d.ts +9 -0
  63. package/types/parts/carousel/useCarousel.d.ts +2 -0
  64. package/types/parts/carousel/useCarouselCallbacks.d.ts +2 -0
  65. package/types/parts/tabBar/TabBar.d.ts +2 -0
  66. package/types/parts/tabBar/styles.d.ts +7 -0
  67. package/types/parts/tabBar/useTabBar.d.ts +2 -0
  68. package/types/parts/tabsContent/TabsContent.d.ts +2 -0
  69. package/types/parts/tabsContent/styles.d.ts +1 -0
  70. package/types/parts/tabsPanel/TabsPanels.d.ts +2 -0
  71. package/types/parts/tabsPanel/styles.d.ts +2 -0
  72. package/types/propTypes.d.ts +54 -0
  73. package/types/tests/{DSTabs.events.test.d.ts → DSTabs.callbacks.test.d.ts} +0 -0
  74. package/types/tests/DSTabs.func.test.d.ts +1 -0
  75. package/types/tests/DSTabs.keyboard.test.d.ts +1 -0
  76. package/types/utils/constants.d.ts +19 -0
  77. package/types/utils/helpers.d.ts +8 -0
  78. package/types/utils/hooks/useKeyboardNavigation.d.ts +2 -0
  79. package/types/utils/hooks/useTabsCallbacks.d.ts +2 -0
  80. package/cjs/Carousel.js +0 -197
  81. package/cjs/DSTab.js +0 -43
  82. package/cjs/SubTabBar.js +0 -45
  83. package/cjs/TabBar.js +0 -410
  84. package/cjs/TabTypes.js +0 -12
  85. package/cjs/TabsImpl.js +0 -114
  86. package/cjs/TabsPanels.js +0 -82
  87. package/cjs/package.json +0 -7
  88. package/cjs/useResize.js +0 -24
  89. package/esm/Carousel.js +0 -186
  90. package/esm/DSTab.js +0 -33
  91. package/esm/SubTabBar.js +0 -39
  92. package/esm/TabBar.js +0 -399
  93. package/esm/TabTypes.js +0 -7
  94. package/esm/TabsImpl.js +0 -107
  95. package/esm/TabsPanels.js +0 -72
  96. package/esm/package.json +0 -7
  97. package/esm/useResize.js +0 -20
  98. package/types/Carousel.d.ts +0 -16
  99. package/types/DSTab.d.ts +0 -22
  100. package/types/PanelContainer.d.ts +0 -20
  101. package/types/SubTabBar.d.ts +0 -23
  102. package/types/TabBar.d.ts +0 -30
  103. package/types/TabTypes.d.ts +0 -5
  104. package/types/TabsImpl.d.ts +0 -37
  105. package/types/TabsPanels.d.ts +0 -5
  106. package/types/useResize.d.ts +0 -1
package/esm/Carousel.js DELETED
@@ -1,186 +0,0 @@
1
- import _jsx from '@babel/runtime/helpers/esm/jsx';
2
- import React, { useRef, useState, useEffect } from 'react';
3
- import ChevronRight from '@elliemae/ds-icons/ChevronRight';
4
- import ChevronLeft from '@elliemae/ds-icons/ChevronLeft';
5
- import styled from 'styled-components';
6
- import DSButton from '@elliemae/ds-button';
7
- import { useResize } from './useResize.js';
8
- import { jsx } from 'react/jsx-runtime';
9
-
10
- const CarouselBtn = /*#__PURE__*/styled(DSButton).withConfig({
11
- componentId: "sc-1317h31-0"
12
- })(["position:absolute;z-index:1;margin:0;&:focus{& span{background-color:", ";background-size:90%;border-radius:2px;border-color:transparent;}}&&{width:16px;height:calc(100% - 2px);@media (min-width:", "){height:calc(100% - 4px);&:focus{& span{background-color:unset;}}}}", " && .em-ds-icon{height:16px;width:16px;}"], props => props.theme.colors.brand[200], ({
13
- theme
14
- }) => theme.breakpoints.medium, props => props.right ? 'right: 0;' : 'left: 0;');
15
- const CarouselWrapper = /*#__PURE__*/styled.span.withConfig({
16
- componentId: "sc-1317h31-1"
17
- })(["position:relative;padding:0 16px;width:100%;"]);
18
- const ChildrenWrap = /*#__PURE__*/styled.div.withConfig({
19
- componentId: "sc-1317h31-2"
20
- })(["display:flex;flex-wrap:nowrap;flex:1;overflow:hidden;"]);
21
-
22
- function isVisibleElement(el, container) {
23
- const rect = el.getBoundingClientRect();
24
- const cRect = container.getBoundingClientRect();
25
- const elemLeft = rect.left + 3;
26
- const elemRight = rect.right - 3; // Only completely visible elements return true:
27
-
28
- const isVisible = elemLeft >= cRect.left && elemRight <= cRect.right;
29
- return isVisible;
30
- }
31
-
32
- const Carousel = ({
33
- children,
34
- onScroll
35
- }) => {
36
- const itemsRef = useRef([]);
37
- const wrapRef = useRef(null);
38
- const leftRef = useRef(null);
39
- const rightRef = useRef(null);
40
-
41
- const shouldShowLeft = () => children && children[0] && wrapRef.current && itemsRef.current[0] && !isVisibleElement(itemsRef.current[0], wrapRef.current);
42
-
43
- const shouldShowRight = () => children && children[children.length - 1] && wrapRef.current && itemsRef.current[children.length - 1] && !isVisibleElement(itemsRef.current[children.length - 1], wrapRef.current);
44
-
45
- const [{
46
- right,
47
- left,
48
- CHEVRON_FOCUS_FLAG
49
- }, setShow] = useState({
50
- right: false,
51
- left: false,
52
- CHEVRON_FOCUS_FLAG: false // flag to replace lack of callback in useState hook
53
-
54
- });
55
-
56
- const recalcChevrons = () => setShow({
57
- right: shouldShowRight(),
58
- left: shouldShowLeft()
59
- });
60
-
61
- useEffect(() => {
62
- recalcChevrons();
63
- }, []);
64
- useEffect(() => {
65
- if (CHEVRON_FOCUS_FLAG) {
66
- // focus opposite chevron when current one hides
67
- if (!left && right && rightRef.current) {
68
- rightRef.current.focus();
69
- } else if (!right && left && leftRef.current) {
70
- leftRef.current.focus();
71
- }
72
-
73
- setShow({
74
- right,
75
- left,
76
- CHEVRON_FOCUS_FLAG: false
77
- });
78
- }
79
- }, [CHEVRON_FOCUS_FLAG]);
80
- useResize(wrapRef, recalcChevrons);
81
-
82
- const getVisibleItemsOffset = () => itemsRef.current.reduce((acc, c) => {
83
- if (isVisibleElement(c, wrapRef.current)) {
84
- const styles = window.getComputedStyle(c);
85
- const width = c.offsetWidth;
86
- const margin = parseFloat(styles.marginLeft) + parseFloat(styles.marginRight);
87
- return acc + (width + margin);
88
- }
89
-
90
- return acc;
91
- }, 0);
92
-
93
- const rightClick = () => {
94
- wrapRef.current.scrollLeft += getVisibleItemsOffset();
95
- };
96
-
97
- const leftClick = () => {
98
- wrapRef.current.scrollLeft -= getVisibleItemsOffset();
99
- };
100
-
101
- const handleScroll = e => {
102
- // forces render when element.scrollTop is changed (out of react flow)
103
- setShow({
104
- right: shouldShowRight(),
105
- left: shouldShowLeft(),
106
- // to trigger focus logic at effect above
107
- CHEVRON_FOCUS_FLAG: true
108
- });
109
- onScroll(e);
110
- };
111
-
112
- const handleClick = (e, onClick = () => {}) => {
113
- const tabListDomEl = wrapRef.current;
114
- const el = e.target;
115
- const rect = el.getBoundingClientRect();
116
- const cRect = tabListDomEl.getBoundingClientRect();
117
-
118
- if (!isVisibleElement(el, tabListDomEl)) {
119
- const containerWidth = cRect.width;
120
- const halfContainer = containerWidth / 2;
121
- const elementScrollPosition = rect.left - cRect.left;
122
- const positionInContainer = elementScrollPosition % containerWidth;
123
- const width = el.offsetWidth; // align to right
124
-
125
- if (positionInContainer > halfContainer) {
126
- wrapRef.current.scrollLeft += width + positionInContainer - containerWidth;
127
- } else {
128
- // align left
129
- wrapRef.current.scrollLeft += positionInContainer;
130
- }
131
-
132
- recalcChevrons();
133
- }
134
-
135
- onClick(e);
136
- };
137
-
138
- return /*#__PURE__*/_jsx(CarouselWrapper, {}, void 0, left && /*#__PURE__*/_jsx(CarouselBtn, {
139
- "data-testid": "chevron-left",
140
- buttonType: "link",
141
- innerRef: leftRef,
142
- size: "s",
143
- icon: /*#__PURE__*/_jsx(ChevronLeft, {
144
- size: "s",
145
- color: ['brand-primary', '600']
146
- }),
147
- onClick: leftClick,
148
- tabIndex: -1
149
- }), right && /*#__PURE__*/_jsx(CarouselBtn, {
150
- "data-testid": "chevron-right",
151
- innerRef: rightRef,
152
- right: true,
153
- size: "s",
154
- buttonType: "link",
155
- icon: /*#__PURE__*/_jsx(ChevronRight, {
156
- size: "s",
157
- color: ['brand-primary', '600']
158
- }),
159
- onClick: rightClick,
160
- tabIndex: -1
161
- }), /*#__PURE__*/jsx(ChildrenWrap, {
162
- onScroll: handleScroll,
163
- ref: wrapRef,
164
- children: React.Children.map(children, (child, idx) => /*#__PURE__*/React.cloneElement(child, {
165
- onClick: e => {
166
- var _child$props;
167
-
168
- return handleClick(e, (_child$props = child.props) === null || _child$props === void 0 ? void 0 : _child$props.onClick);
169
- },
170
- key: 'carousel'.concat(idx),
171
- ref: el => {
172
- itemsRef.current[idx] = el; // keep old refs
173
-
174
- if (typeof child.ref === 'function') {
175
- child.ref(el);
176
- }
177
- }
178
- }))
179
- }));
180
- };
181
-
182
- Carousel.defaultProps = {
183
- onScroll: () => null
184
- };
185
-
186
- export { Carousel as default };
package/esm/DSTab.js DELETED
@@ -1,33 +0,0 @@
1
- import _jsx from '@babel/runtime/helpers/esm/jsx';
2
- import 'react';
3
- import { PropTypes, describe } from 'react-desc';
4
-
5
- const DSTab = ({
6
- tabId = '',
7
- title = '',
8
- required = false
9
- }) => /*#__PURE__*/_jsx("div", {
10
- "aria-labelledby": `${tabId}-label`,
11
- tabId: tabId,
12
- title: title,
13
- required: required
14
- });
15
-
16
- DSTab.displayName = 'DSTab';
17
- const props = {
18
- /** unique id for tab */
19
- tabId: PropTypes.string.description('unique id for tab'),
20
-
21
- /** tab title */
22
- title: PropTypes.string.description('tab title'),
23
-
24
- /** Show a required mark next to the title */
25
- required: PropTypes.bool.description('Show a required mark next to the title'),
26
-
27
- /** Whether or not it's a ds-tab from DSMobile tabs */
28
- isDSMobile: PropTypes.bool.description("Whether or not it's a ds-tab from DSMobile tabs")
29
- };
30
- const DSTabWithSchema = describe(DSTab);
31
- DSTabWithSchema.propTypes = props;
32
-
33
- export { DSTab, DSTabWithSchema, DSTab as default };
package/esm/SubTabBar.js DELETED
@@ -1,39 +0,0 @@
1
- import _jsx from '@babel/runtime/helpers/esm/jsx';
2
- import 'react';
3
- import { aggregatedClasses } from '@elliemae/ds-classnames';
4
- import TabBar from './TabBar.js';
5
- import Carousel from './Carousel.js';
6
-
7
- const blockName = 'tabs-tab-bar';
8
- const SubTabList = aggregatedClasses('div')(blockName, 'subtabs-list', ({
9
- withCarousel
10
- }) => ({
11
- carousel: withCarousel
12
- }));
13
-
14
- const SubTabBar = ({
15
- withCarousel,
16
- tabs = [],
17
- activeTab = '',
18
- onTabClick = () => null,
19
- firstSubtabRef,
20
- handleUpArrow
21
- }) => /*#__PURE__*/_jsx(TabBar, {
22
- activeTab: activeTab,
23
- onTabClick: onTabClick,
24
- handleUpArrow: handleUpArrow,
25
- firstSubtabRef: firstSubtabRef,
26
- renderCustomTabBar: ({
27
- tabsComponents,
28
- innerRef
29
- }) => /*#__PURE__*/_jsx(SubTabList, {
30
- withCarousel: withCarousel,
31
- innerRef: innerRef,
32
- "data-testid": "subtabs-list"
33
- }, void 0, withCarousel ? /*#__PURE__*/_jsx(Carousel, {}, void 0, tabsComponents) : tabsComponents),
34
- showSelectionIndicator: false,
35
- showSeparator: true,
36
- tabs: tabs
37
- });
38
-
39
- export { SubTabBar as default };
package/esm/TabBar.js DELETED
@@ -1,399 +0,0 @@
1
- import _jsx from '@babel/runtime/helpers/esm/jsx';
2
- import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
3
- import React, { Component } from 'react';
4
- import { debounce } from 'lodash';
5
- import { aggregatedClasses } from '@elliemae/ds-classnames';
6
- import RequiredMark from '@elliemae/ds-form/RequiredMark';
7
- import memoizeOne from 'memoize-one';
8
- import { ResizeObserver } from 'resize-observer';
9
- import styled from 'styled-components';
10
- import Carousel from './Carousel.js';
11
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
12
-
13
- const blockName = 'tabs-tab-bar';
14
- const gradientWidth = 24;
15
- const StyledTabWrapper = /*#__PURE__*/styled.div.withConfig({
16
- componentId: "sc-7sdovg-0"
17
- })(["display:flex;flex:1;flex-wrap:nowrap;", ";"], ({
18
- flexibleTabsHeaders
19
- }) => flexibleTabsHeaders ? '' : 'overflow-x: hidden');
20
- const StyledTabList = aggregatedClasses('div')(blockName, 'list', ({
21
- withCarousel,
22
- flexibleTabsHeaders,
23
- fixedTabsHeaders,
24
- isDSMobile,
25
- withLeftGradients,
26
- withRightGradients
27
- }) => ({
28
- carousel: withCarousel,
29
- 'flexible-table-headers': isDSMobile && flexibleTabsHeaders,
30
- 'fixed-table-headers': isDSMobile && fixedTabsHeaders,
31
- 'left-gradients': isDSMobile && flexibleTabsHeaders && withLeftGradients,
32
- 'right-gradients': isDSMobile && flexibleTabsHeaders && withRightGradients
33
- }), {
34
- propsToRemoveFromFinalElement: ['withCarousel', 'flexibleTabsHeaders', 'fixedTabsHeaders', 'withLeftGradients', 'withRightGradients', 'isDSMobile']
35
- });
36
- const TabContainer = aggregatedClasses('button', {
37
- role: 'tab'
38
- })(blockName, 'tab', ({
39
- isActive,
40
- showSeparator,
41
- disabled
42
- }) => ({
43
- active: isActive,
44
- separator: showSeparator,
45
- disabled
46
- }));
47
- const SelectionIndicator = aggregatedClasses('div')(blockName, 'selection-indicator');
48
-
49
- class TabBar extends Component {
50
- constructor(_props) {
51
- super(_props);
52
-
53
- _defineProperty(this, "handleTabClick", (tabId, e) => {
54
- const {
55
- tabListRef,
56
- props
57
- } = this;
58
- const {
59
- onTabClick,
60
- flexibleTabsHeaders,
61
- isDSMobile
62
- } = props;
63
-
64
- if (isDSMobile && flexibleTabsHeaders) {
65
- const tabListDomEl = tabListRef.current;
66
- const el = e.target;
67
- const {
68
- offsetLeft
69
- } = el;
70
- const {
71
- width: elWidth
72
- } = el.getBoundingClientRect();
73
- const {
74
- width: listWidth
75
- } = tabListDomEl.getBoundingClientRect();
76
- const extraSideSpace = listWidth - elWidth;
77
- const leftOffsetToCenter = extraSideSpace > 0 ? extraSideSpace / 2 : 0;
78
- const centeredLeftOffset = offsetLeft > leftOffsetToCenter ? offsetLeft - leftOffsetToCenter : 0;
79
- tabListDomEl.scrollTo({
80
- top: 0,
81
- left: centeredLeftOffset,
82
- behavior: 'smooth'
83
- });
84
- }
85
-
86
- e.preventDefault();
87
- onTabClick(tabId);
88
- });
89
-
90
- _defineProperty(this, "handleKeyPress", (tabId, e, index) => {
91
- const {
92
- tabs,
93
- handleDownArrow,
94
- handleUpArrow // onTabClick,
95
-
96
- } = this.props;
97
-
98
- if (e.keyCode === 39) {
99
- var _this$tabsRef;
100
-
101
- const nextTab = tabs[index + 1];
102
- if (!nextTab && handleDownArrow) handleDownArrow(e);
103
- if (!nextTab) return; // const { props } = nextTab
104
- // onTabClick(props.tabId)
105
-
106
- (_this$tabsRef = this.tabsRef[index + 1]) === null || _this$tabsRef === void 0 ? void 0 : _this$tabsRef.focus();
107
- }
108
-
109
- if (e.keyCode === 37) {
110
- var _this$tabsRef2;
111
-
112
- const nextTab = tabs[index - 1];
113
- if (!nextTab && handleUpArrow) handleUpArrow(e);
114
- if (!nextTab) return; // const { props } = nextTab
115
- // onTabClick(props.tabId)
116
-
117
- (_this$tabsRef2 = this.tabsRef[index - 1]) === null || _this$tabsRef2 === void 0 ? void 0 : _this$tabsRef2.focus();
118
- }
119
-
120
- if (e.keyCode === 40 && handleDownArrow) {
121
- handleDownArrow(e);
122
- }
123
-
124
- if (e.keyCode === 38 && handleUpArrow) {
125
- handleUpArrow(e);
126
- }
127
- });
128
-
129
- _defineProperty(this, "handleTabsHeadersHorizontalScroll", debounce(() => {
130
- const {
131
- tabListRef,
132
- props
133
- } = this;
134
- const {
135
- flexibleTabsHeaders,
136
- isDSMobile
137
- } = props;
138
-
139
- if (isDSMobile && flexibleTabsHeaders) {
140
- const tabListDomEl = tabListRef.current;
141
- const {
142
- scrollLeft,
143
- scrollWidth,
144
- clientWidth
145
- } = tabListDomEl;
146
- const withLeftGradients = this.shouldHaveLeftGradient(scrollLeft, gradientWidth);
147
- const withRightGradients = this.shouldHaveRightGradient(scrollLeft, gradientWidth, clientWidth, scrollWidth);
148
- this.setState({
149
- withLeftGradients,
150
- withRightGradients
151
- });
152
- }
153
- }, 50));
154
-
155
- _defineProperty(this, "renderTabs", memoizeOne((activeTab, tabs) => {
156
- const {
157
- showSeparator
158
- } = this.props;
159
- return React.Children.map(tabs, (tab, index) => {
160
- const {
161
- tabId,
162
- title,
163
- style,
164
- required,
165
- disabled
166
- } = tab.props;
167
- const isActive = activeTab === tabId;
168
- return [/*#__PURE__*/jsxs(TabContainer, {
169
- // eslint-disable-next-line no-return-assign
170
- ref: t => {
171
- this.tabsRef[index] = t;
172
-
173
- if (index === 0 && this.props.firstSubtabRef) {
174
- this.props.firstSubtabRef.current = t;
175
- }
176
-
177
- if (index === tabs.length - 1 && this.props.lastTabRef) {
178
- this.props.lastTabRef.current = t;
179
- }
180
- },
181
- "aria-controls": tabId,
182
- "aria-selected": isActive,
183
- "aria-disabled": !!disabled,
184
- classProps: {
185
- isActive,
186
- showSeparator,
187
- disabled
188
- },
189
- "data-tab-id": tabId,
190
- id: `${tabId}-label`,
191
- onClick: e => {
192
- if (!disabled) this.handleTabClick(tabId, e, index);
193
- },
194
- onKeyDown: e => {
195
- if (!disabled) this.handleKeyPress(tabId, e, index);
196
- },
197
- style: style,
198
- tabIndex: 0,
199
- children: [title, /*#__PURE__*/_jsx(RequiredMark, {
200
- required: required
201
- })]
202
- }, tabId)];
203
- }, null);
204
- }));
205
-
206
- this.tabListRef = /*#__PURE__*/React.createRef();
207
- this.resizeObserver = new ResizeObserver(() => this.setIndicatorStyle());
208
- this.state = {
209
- indicatorStyle: null,
210
- withLeftGradients: false,
211
- withRightGradients: false
212
- };
213
- this.setIndicatorStyle = this.setIndicatorStyle.bind(this);
214
- this.getIndicatorStyles = this.getIndicatorStyles.bind(this);
215
- this.handleGradients = this.handleGradients.bind(this);
216
- this.handleTabsHeadersHorizontalScroll = this.handleTabsHeadersHorizontalScroll.bind(this);
217
- this.tabsRef = {};
218
- this.setIndicatorStyle = this.setIndicatorStyle.bind(this);
219
- }
220
-
221
- componentDidMount() {
222
- const {
223
- showSelectionIndicator
224
- } = this.props;
225
- this.resizeObserver.observe(this.tabListRef.current);
226
-
227
- if (showSelectionIndicator) {
228
- this.setIndicatorStyle();
229
- }
230
-
231
- window.addEventListener('resize', this.handleGradients);
232
- window.addEventListener('orientationchange', this.handleGradients);
233
- this.handleGradients();
234
- }
235
-
236
- componentDidUpdate(prevProps) {
237
- const {
238
- activeTab,
239
- showSelectionIndicator
240
- } = this.props;
241
-
242
- if (showSelectionIndicator && prevProps.activeTab !== activeTab) {
243
- this.setIndicatorStyle(activeTab);
244
- }
245
- }
246
-
247
- componentWillUnmount() {
248
- this.resizeObserver.unobserve(this.tabListRef.current);
249
- window.removeEventListener('resize', this.handleGradients);
250
- window.removeEventListener('orientationchange', this.handleGradients);
251
- }
252
-
253
- handleGradients() {
254
- const {
255
- scrollLeft,
256
- scrollWidth,
257
- clientWidth
258
- } = this.tabListRef.current;
259
- const withLeftGradients = this.shouldHaveLeftGradient(scrollLeft, gradientWidth);
260
- const withRightGradients = this.shouldHaveRightGradient(scrollLeft, gradientWidth, clientWidth, scrollWidth);
261
- this.setState({
262
- withLeftGradients,
263
- withRightGradients
264
- });
265
- }
266
-
267
- shouldHaveLeftGradient(scrollLeft, gWidth) {
268
- return Math.abs(scrollLeft) > gWidth;
269
- } // eslint-disable-next-line max-params
270
-
271
-
272
- shouldHaveRightGradient(scrollLeft, gWidth, clientWidth, scrollWidth) {
273
- return Math.abs(scrollLeft) <= scrollWidth - (clientWidth + gWidth);
274
- }
275
-
276
- setIndicatorStyle() {
277
- const {
278
- activeTab
279
- } = this.props;
280
- setTimeout(() => this.setState({
281
- indicatorStyle: this.getIndicatorStyles(activeTab)
282
- }), 100);
283
- }
284
-
285
- getActiveTabElement(activeTab) {
286
- const tabListEl = this.tabListRef.current;
287
- const tabSelector = `[data-tab-id="${activeTab}"]`;
288
- return tabListEl && tabListEl.querySelector(tabSelector);
289
- }
290
-
291
- isElementVisible(el, holder) {
292
- const {
293
- left,
294
- right,
295
- width
296
- } = el.getBoundingClientRect();
297
- const holderRect = holder.getBoundingClientRect();
298
- return left <= holderRect.left ? holderRect.left - left <= width : right - holderRect.right <= width;
299
- }
300
-
301
- getVisibleDimensions(node, referenceNode) {
302
- const pos = node.getBoundingClientRect();
303
- const referencePos = referenceNode.getBoundingClientRect();
304
- return {
305
- width: Math.min(node.clientWidth, referencePos.left + referenceNode.clientWidth - pos.left, node.clientWidth - (referencePos.left - pos.left)),
306
- height: Math.min(node.clientHeight, referencePos.top + referenceNode.clientHeight - pos.top, node.clientHeight - (referencePos.top - pos.top))
307
- };
308
- }
309
-
310
- getIndicatorStyles(activeTab) {
311
- const tabListEl = this.tabListRef.current;
312
- const {
313
- withCarousel
314
- } = this.props;
315
- const activeTabEl = this.getActiveTabElement(activeTab);
316
- if (!activeTabEl || !this.isElementVisible(activeTabEl, tabListEl)) return null;
317
- const {
318
- clientHeight,
319
- clientWidth,
320
- offsetTop,
321
- offsetLeft
322
- } = activeTabEl;
323
- const {
324
- left
325
- } = activeTabEl.getBoundingClientRect();
326
- const leftOff = withCarousel ? Math.max(0, left - tabListEl.getBoundingClientRect().left) : offsetLeft;
327
- const width = withCarousel ? this.getVisibleDimensions(activeTabEl, tabListEl).width : clientWidth + 2;
328
- return {
329
- height: clientHeight,
330
- left: `${Math.floor(leftOff)}px`,
331
- // using left and top for ie compatibility
332
- top: `${Math.floor(offsetTop)}px`,
333
- width
334
- };
335
- }
336
-
337
- render() {
338
- const {
339
- id,
340
- tabs,
341
- activeTab,
342
- renderCustomTabBar,
343
- withCarousel,
344
- isDSMobile,
345
- flexibleTabsHeaders,
346
- fixedTabsHeaders
347
- } = this.props;
348
- const {
349
- indicatorStyle,
350
- withLeftGradients,
351
- withRightGradients
352
- } = this.state;
353
-
354
- if (renderCustomTabBar) {
355
- return renderCustomTabBar({
356
- innerRef: this.tabListRef,
357
- withCarousel,
358
- tabsComponents: this.renderTabs(activeTab, tabs)
359
- });
360
- }
361
-
362
- const shouldUseCarousel = !isDSMobile && withCarousel;
363
- return /*#__PURE__*/jsx(Fragment, {
364
- children: /*#__PURE__*/_jsx(StyledTabList, {
365
- withCarousel: withCarousel,
366
- "aria-label": id,
367
- innerRef: this.tabListRef,
368
- role: "tablist",
369
- "data-testid": "tab-list",
370
- isDSMobile: isDSMobile,
371
- flexibleTabsHeaders: flexibleTabsHeaders,
372
- withLeftGradients: withLeftGradients,
373
- withRightGradients: withRightGradients,
374
- fixedTabsHeaders: fixedTabsHeaders,
375
- onScroll: this.handleTabsHeadersHorizontalScroll,
376
- style: {
377
- width: '100%'
378
- }
379
- }, void 0, /*#__PURE__*/_jsx(StyledTabWrapper, {
380
- isDSMobile: isDSMobile,
381
- flexibleTabsHeaders: flexibleTabsHeaders,
382
- fixedTabsHeaders: fixedTabsHeaders
383
- }, void 0, shouldUseCarousel ? /*#__PURE__*/_jsx(Carousel, {
384
- onScroll: this.setIndicatorStyle
385
- }, void 0, this.renderTabs(activeTab, tabs)) : null, !shouldUseCarousel ? this.renderTabs(activeTab, tabs) : null, /*#__PURE__*/_jsx(SelectionIndicator, {
386
- style: indicatorStyle
387
- })))
388
- });
389
- }
390
-
391
- }
392
-
393
- TabBar.defaultProps = {
394
- showSelectionIndicator: true,
395
- showSeparator: false,
396
- isDSMobile: false
397
- };
398
-
399
- export { TabBar as default };
package/esm/TabTypes.js DELETED
@@ -1,7 +0,0 @@
1
- const TabTypes = {
2
- NORMAL: 'normal',
3
- SUBTABS: 'subtabs'
4
- };
5
- const getTabTypes = () => Object.keys(TabTypes).map(key => TabTypes[key]);
6
-
7
- export { TabTypes, getTabTypes };