@elliemae/ds-tabs 2.0.3 → 2.0.7

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.
@@ -1,6 +1,6 @@
1
1
  import _jsx from '@babel/runtime/helpers/esm/jsx';
2
2
  import { useContext } from 'react';
3
- import { DSIconSizes, DSIconColors } from '@elliemae/ds-icon';
3
+ import { DSIconSizes } from '@elliemae/ds-icon';
4
4
  import { BUTTON_TYPES } from '@elliemae/ds-button';
5
5
  import { ChevronLeft, ChevronRight } from '@elliemae/ds-icons';
6
6
  import { StyledCarouselWrapper, StyledCarouselButtonWrapper, StyledCarouselBtn, StyledChildrenWrap } from './styles.js';
@@ -38,8 +38,7 @@ const Carousel = _ref => {
38
38
  "data-testid": DSTabsDatatestid.CAROUSEL.BUTTON_LEFT,
39
39
  buttonType: BUTTON_TYPES.ICON
40
40
  }, void 0, /*#__PURE__*/_jsx(ChevronLeft, {
41
- size: DSIconSizes.S,
42
- color: DSIconColors.PRIMARY
41
+ size: DSIconSizes.S
43
42
  }))), showChevrons.right && /*#__PURE__*/_jsx(StyledCarouselButtonWrapper, {
44
43
  tabType: type,
45
44
  right: showChevrons.right
@@ -50,8 +49,7 @@ const Carousel = _ref => {
50
49
  "data-testid": DSTabsDatatestid.CAROUSEL.BUTTON_RIGHT,
51
50
  buttonType: BUTTON_TYPES.ICON
52
51
  }, void 0, /*#__PURE__*/_jsx(ChevronRight, {
53
- size: DSIconSizes.S,
54
- color: DSIconColors.PRIMARY
52
+ size: DSIconSizes.S
55
53
  }))), /*#__PURE__*/jsx(StyledChildrenWrap, {
56
54
  ref: carouselOnlyListRef,
57
55
  onClick: handleOnClick,
@@ -4,7 +4,7 @@ import { TabTypes } from '../../utils/constants.js';
4
4
 
5
5
  const StyledCarouselBtn = /*#__PURE__*/styled(DSButtonV2).withConfig({
6
6
  componentId: "sc-prv5a7-0"
7
- })(["margin:0;min-width:", ";width:", ";&:hover:not(:disabled){background-color:transparent;}background-color:transparent;border-radius:0px;"], _ref => {
7
+ })(["margin:0;min-width:", ";width:", ";&:hover:not(:disabled){background-color:transparent;}background-color:transparent;border-radius:0px;& .em-ds-icon svg{fill:", ";}"], _ref => {
8
8
  let {
9
9
  theme
10
10
  } = _ref;
@@ -14,6 +14,11 @@ const StyledCarouselBtn = /*#__PURE__*/styled(DSButtonV2).withConfig({
14
14
  theme
15
15
  } = _ref2;
16
16
  return theme.space.xs;
17
+ }, _ref3 => {
18
+ let {
19
+ theme
20
+ } = _ref3;
21
+ return theme.colors.brand[600];
17
22
  });
18
23
  const StyledCarouselWrapper = /*#__PURE__*/styled.span.withConfig({
19
24
  componentId: "sc-prv5a7-1"
@@ -23,27 +28,27 @@ const StyledChildrenWrap = /*#__PURE__*/styled.div.withConfig({
23
28
  })(["display:flex;flex-wrap:nowrap;flex:1;overflow-x:hidden;"]);
24
29
  const StyledCarouselButtonWrapper = /*#__PURE__*/styled.div.withConfig({
25
30
  componentId: "sc-prv5a7-3"
26
- })(["max-width:16px;position:absolute;z-index:200;", " width:16px;height:", ";padding-top:", ";background-color:white;", ";"], _ref3 => {
31
+ })(["max-width:16px;position:absolute;z-index:200;", " width:16px;height:", ";padding-top:", ";background:white;", ";"], _ref4 => {
27
32
  let {
28
33
  right
29
- } = _ref3;
34
+ } = _ref4;
30
35
  return right ? 'right: 0;' : "left: 0;";
31
- }, _ref4 => {
36
+ }, _ref5 => {
32
37
  let {
33
38
  tabType
34
- } = _ref4;
39
+ } = _ref5;
35
40
  return tabType === TabTypes.NORMAL ? '32px' : '22px';
36
- }, _ref5 => {
41
+ }, _ref6 => {
37
42
  let {
38
43
  tabType
39
- } = _ref5;
44
+ } = _ref6;
40
45
  return tabType === TabTypes.NORMAL ? '5px' : '0px';
41
- }, _ref6 => {
46
+ }, _ref7 => {
42
47
  let {
43
48
  theme,
44
49
  tabType
45
- } = _ref6;
46
- return tabType === TabTypes.NORMAL ? "\n border-bottom: 1px solid ".concat(theme.colors.neutral[200], ";") : "";
50
+ } = _ref7;
51
+ return tabType === TabTypes.NORMAL ? "\n background: linear-gradient(to bottom, white 0px, white 30px, ".concat(theme.colors.neutral[400], " 30px, ").concat(theme.colors.neutral[400], " 31px, white 31px , white 32px );\n ") : "";
47
52
  });
48
53
 
49
54
  export { StyledCarouselBtn, StyledCarouselButtonWrapper, StyledCarouselWrapper, StyledChildrenWrap };
@@ -7,6 +7,7 @@ import { useTabBar } from './useTabBar.js';
7
7
  import { StyledTabButton, StyledRequiredMark, StyledSubTabsList, StyledTabList, StyledTabWrapper, StyledSelectionIndicator } from './styles.js';
8
8
  import { DSTabsContext, DSTabsCrossRefContext } from '../../DSTabsCTX.js';
9
9
  import { useKeyboardNavigation } from '../../utils/hooks/useKeyboardNavigation.js';
10
+ import { centerTab } from '../../utils/helpers.js';
10
11
  import { TabTypes } from '../../utils/constants.js';
11
12
  import { useTabsCallbacks } from '../../utils/hooks/useTabsCallbacks.js';
12
13
  import { DSTabsDatatestid } from '../../DSTabsDatatestid.js';
@@ -19,6 +20,7 @@ const TabBar = () => {
19
20
  focusableTabsRef,
20
21
  tabsListRef,
21
22
  tabsRefAsArray,
23
+ carouselOnlyListRef,
22
24
  actualActiveTab,
23
25
  props: {
24
26
  type,
@@ -61,21 +63,21 @@ const TabBar = () => {
61
63
  if (!disabled) availableTabIndexes.push(index);
62
64
  return /*#__PURE__*/jsxs(StyledTabButton, {
63
65
  role: "tab",
64
- ref: t => {
65
- if (tabsRefAsArray.current && focusableTabsRef.current && tabsRef.current) {
66
- tabsRefAsArray.current[index] = t;
67
- if (!disabled && !focusableTabsRef.current.includes(t)) focusableTabsRef.current.push(t);
68
- tabsRef.current[index] = t;
66
+ ref: tabButtonRef => {
67
+ if (tabButtonRef && tabsRefAsArray.current && focusableTabsRef.current && tabsRef.current) {
68
+ tabsRefAsArray.current[index] = tabButtonRef;
69
+ if (!disabled && !focusableTabsRef.current.includes(tabButtonRef)) focusableTabsRef.current.push(tabButtonRef);
70
+ tabsRef.current[index] = tabButtonRef;
69
71
 
70
72
  if (type === TabTypes.SUBTABS && firstSubtabInternalRef && index === availableTabIndexes[0]) {
71
- firstSubtabInternalRef.current = t;
73
+ firstSubtabInternalRef.current = tabButtonRef;
72
74
  }
73
75
 
74
76
  if (type !== TabTypes.SUBTABS && index === availableTabIndexes[availableTabIndexes.length - 1]) {
75
- lastTabInternalRef.current = t;
77
+ lastTabInternalRef.current = tabButtonRef;
76
78
  }
77
79
 
78
- if (ref) ref.current = t;
80
+ if (ref) ref.current = tabButtonRef;
79
81
  }
80
82
  },
81
83
  type: "button",
@@ -104,6 +106,12 @@ const TabBar = () => {
104
106
 
105
107
  if (onClick && !disabled) onClick(tabId, e);
106
108
  },
109
+ onFocus: e => {
110
+ if (withCarousel) centerTab({
111
+ e,
112
+ listRef: carouselOnlyListRef
113
+ });
114
+ },
107
115
  onKeyDown: e => {
108
116
  if (e.key === 'Enter') e.stopPropagation();
109
117
  if (!disabled) handleOnKeyDown(e);
@@ -113,7 +121,7 @@ const TabBar = () => {
113
121
  children: [title, required && (_StyledRequiredMark || (_StyledRequiredMark = /*#__PURE__*/_jsx(StyledRequiredMark, {}, void 0, "\u25CF")))]
114
122
  }, tabId);
115
123
  });
116
- }, [tabs, actualActiveTab, isDSMobile, fixedTabsHeaders, type, withCarousel, showSeparator, tabsRefAsArray, focusableTabsRef, tabsRef, firstSubtabInternalRef, lastTabInternalRef, handleOnTabChange, updateIndicatorStyle, handleOnKeyDown]);
124
+ }, [tabs, actualActiveTab, isDSMobile, fixedTabsHeaders, type, withCarousel, showSeparator, tabsRefAsArray, focusableTabsRef, tabsRef, firstSubtabInternalRef, lastTabInternalRef, handleOnTabChange, updateIndicatorStyle, carouselOnlyListRef, handleOnKeyDown]);
117
125
 
118
126
  if (type === TabTypes.SUBTABS && !isDSMobile) {
119
127
  return /*#__PURE__*/jsx(StyledSubTabsList, {
@@ -11,7 +11,7 @@ const StyledSelectionIndicator = /*#__PURE__*/styled.div.withConfig({
11
11
  tabType,
12
12
  isDSMobile
13
13
  } = _ref;
14
- if (isDSMobile) return "34px";
14
+ if (isDSMobile) return "35px";
15
15
  if (tabType === TabTypes.NORMAL_SMALL) return "15px";
16
16
  return "25px";
17
17
  }, _ref2 => {
@@ -43,135 +43,136 @@ const mobileGradientsSettings = css(_templateObject || (_templateObject = _tagge
43
43
  });
44
44
  const StyledTabWrapper = /*#__PURE__*/styled.div.withConfig({
45
45
  componentId: "sc-3hla56-1"
46
- })(["display:flex;flex:1;flex-wrap:nowrap;", ""], _ref5 => {
46
+ })(["display:flex;flex:1;flex-wrap:nowrap;", " ", ""], _ref5 => {
47
47
  let {
48
48
  fixedTabsHeaders,
49
49
  isDSMobile
50
50
  } = _ref5;
51
51
  return !fixedTabsHeaders && isDSMobile ? '' : 'overflow-x: hidden;';
52
+ }, _ref6 => {
53
+ let {
54
+ theme,
55
+ isDSMobile
56
+ } = _ref6;
57
+ return isDSMobile ? "border-bottom: 1px solid ".concat(theme.colors.brand[300], ";") : "";
52
58
  });
53
59
  const StyledTabButton = /*#__PURE__*/styled.button.withConfig({
54
60
  componentId: "sc-3hla56-2"
55
- })(["position:relative;background-color:transparent;border:none;cursor:pointer;transition:100ms cubic-bezier(0,0,0.42,1);text-transform:", ";letter-spacing:0px;white-space:nowrap;padding:2px 0;margin-right:", ";margin-left:", ";color:", ";", " ", " ", " ", " ", " ", " ", ""], _ref6 => {
61
+ })(["position:relative;background-color:transparent;border:none;cursor:pointer;transition:100ms cubic-bezier(0,0,0.42,1);text-transform:", ";letter-spacing:0px;white-space:nowrap;padding:2px 0;margin-right:", ";margin-left:", ";color:", ";", " ", " ", " ", " ", " ", " ", ""], _ref7 => {
56
62
  let {
57
63
  tabType
58
- } = _ref6;
64
+ } = _ref7;
59
65
  return tabType === TabTypes.SUBTABS ? "capitalize" : "uppercase";
60
- }, _ref7 => {
66
+ }, _ref8 => {
61
67
  let {
62
68
  fixedTabsHeaders,
63
69
  isDSMobile
64
- } = _ref7;
70
+ } = _ref8;
65
71
  if (fixedTabsHeaders) return '0px';
66
72
  if (!fixedTabsHeaders && isDSMobile) return '14px';
67
73
  return '16px';
68
- }, _ref8 => {
74
+ }, _ref9 => {
69
75
  let {
70
76
  fixedTabsHeaders,
71
77
  isDSMobile
72
- } = _ref8;
78
+ } = _ref9;
73
79
  if (fixedTabsHeaders) return '0px';
74
80
  if (!fixedTabsHeaders && isDSMobile) return '14px';
75
81
  return '16px';
76
- }, _ref9 => {
82
+ }, _ref10 => {
77
83
  let {
78
84
  theme
79
- } = _ref9;
85
+ } = _ref10;
80
86
  return theme.colors.neutral[700];
81
- }, onlySafariAndFirefox('-webkit-text-stroke: 0.4px transparent;'), _ref10 => {
87
+ }, onlySafariAndFirefox('-webkit-text-stroke: 0.4px transparent;'), _ref11 => {
82
88
  let {
83
89
  tabType
84
- } = _ref10;
85
- return tabType === TabTypes.NORMAL ? "height: 32px;" : "height: 22px;";
86
- }, _ref11 => {
87
- let {
88
- theme,
89
- isActive,
90
- disabled
91
90
  } = _ref11;
92
- return isActive && !disabled ? "\n font-weight: ".concat(theme.fontWeights.semibold, ";\n ").concat(safariAndFirefoxBold("#353C46"), "\n\n &:hover {\n ").concat(safariAndFirefoxBold("#1E79C2"), "\n }\n \n ") : "\n \n ";
91
+ return tabType === TabTypes.NORMAL ? "height: 32px;" : "height: 22px;";
93
92
  }, _ref12 => {
94
93
  let {
95
94
  theme,
95
+ isActive,
96
96
  disabled
97
97
  } = _ref12;
98
- return disabled ? "\n color: ".concat(theme.colors.neutral[500], ";\n cursor: not-allowed;\n ") : "\n &:hover {\n color: ".concat(theme.colors.brand[600], ";\n }\n ");
98
+ return isActive && !disabled ? "\n font-weight: ".concat(theme.fontWeights.semibold, ";\n ").concat(safariAndFirefoxBold("#353C46"), "\n\n &:hover {\n ").concat(safariAndFirefoxBold("#1E79C2"), "\n }\n \n ") : "\n \n ";
99
99
  }, _ref13 => {
100
100
  let {
101
101
  theme,
102
- isDSMobile
102
+ disabled
103
103
  } = _ref13;
104
- return !isDSMobile ? "\n &:focus {\n outline: none;\n &:after {\n position: absolute;\n content: '';\n top: 0;\n left: -16px;\n width: calc(100% + 32px);\n height: 100%;\n z-index: 5;\n border-radius: 2px;\n border: 2px solid ".concat(theme.colors.brand[600], ";\n }\n }\n \n ") : "";
104
+ return disabled ? "\n color: ".concat(theme.colors.neutral[500], ";\n cursor: not-allowed;\n ") : "\n &:hover {\n color: ".concat(theme.colors.brand[600], ";\n }\n ");
105
105
  }, _ref14 => {
106
106
  let {
107
107
  theme,
108
108
  showSeparator,
109
109
  tabType
110
110
  } = _ref14;
111
- return showSeparator ? "\n &:not(:last-of-type):before\n {\n content: \"\";\n position: absolute;\n width: 1px;\n right: -17px;\n top: 50%;\n transform: translateY(-50%);\n height: ".concat(tabType === TabTypes.NORMAL_SMALL ? "10px" : "16px", ";\n background-color: ").concat(theme.colors.neutral[400], ";\n }") : "";
111
+ return showSeparator ? "\n &:not(:last-of-type):before\n {\n content: \"\";\n position: absolute;\n width: 1px;\n right: -16px;\n top: 50%;\n transform: translateY(-50%);\n height: ".concat(tabType === TabTypes.SUBTABS ? "10px" : "16px", ";\n background: ").concat(theme.colors.neutral[400], ";\n }") : "";
112
112
  }, _ref15 => {
113
+ let {
114
+ theme,
115
+ isDSMobile,
116
+ tabType,
117
+ isActive
118
+ } = _ref15;
119
+ return !isDSMobile ? "\n &:focus {\n outline: none;\n &:after {\n position: absolute;\n content: '';\n top: 0;\n left: -16px;\n width: calc(100% + 32px);\n height: 100%;\n z-index: 5;\n border-radius: 2px;\n border: 2px solid ".concat(theme.colors.brand[700], ";\n }\n\n ").concat(tabType !== TabTypes.SUBTABS && isActive ? "\n &:before {\n position: absolute;\n content: '';\n left: -16px;\n right: 0;\n top: calc(100% - 2px);\n transform: none;\n width: calc(100% + 32px);\n height: 2px;\n z-index: 10;\n background: linear-gradient(to right, transparent 0px, transparent 12px, white 12px, white 16px, transparent 16px,transparent calc(100% - 16px), white calc(100% - 16px), white calc(100% - 12px), transparent calc(100% - 12px), transparent 100%);\n }\n " : "", "\n }\n \n ") : "";
120
+ }, _ref16 => {
113
121
  let {
114
122
  theme,
115
123
  isActive,
116
124
  disabled,
117
125
  isDSMobile
118
- } = _ref15;
126
+ } = _ref16;
119
127
  return isDSMobile ? "\n height: 40px;\n color: ".concat(theme.colors.brand[600], ";\n font-weight: ").concat(theme.fontWeights.regular, ";\n padding: 0;\n font-size: 13px;\n line-height: 1.3;\n ").concat(onlySafariAndFirefox('-webkit-text-stroke: 0.4px transparent;'), " \n\n &:focus {\n font-weight: ").concat(theme.fontWeights.regular, ";\n font-size: 13px;\n ").concat(safariAndFirefoxBold('#006AA9'), "\n }\n\n ").concat(isActive ? "\n font-weight: ".concat(theme.fontWeights.regular, ";\n font-size: 13px;\n ").concat(safariAndFirefoxBold('#006AA9'), "\n ") : "", "\n\n ").concat(isActive && !disabled ? "\n font-size: 13px;\n color: ".concat(theme.colors.brand[700], ";\n line-height: 1.3;\n font-weight: ").concat(theme.fontWeights.regular, ";\n -webkit-font-smoothing: subpixel-antialiased; \n -webkit-text-stroke: 0.4px ").concat(theme.colors.brand[700], ";") : "", "\n\n ").concat(!disabled ? "\n &:hover,\n &:focus {\n outline: none;\n color: ".concat(theme.colors.brand[700], ";\n ").concat(safariAndFirefoxBold('#006AA9'), "\n }") : "", "\n\n ") : "";
120
128
  });
121
129
  const StyledSubTabsList = /*#__PURE__*/styled.div.withConfig({
122
130
  componentId: "sc-3hla56-3"
123
- })(["position:relative;display:flex;flex-wrap:nowrap;flex:1;width:100%;", ""], _ref16 => {
131
+ })(["position:relative;display:flex;flex-wrap:nowrap;flex:1;width:100%;", ""], _ref17 => {
124
132
  let {
125
133
  withCarousel
126
- } = _ref16;
134
+ } = _ref17;
127
135
  return withCarousel ? 'max-width: 100%;' : '';
128
136
  });
129
137
  const StyledTabList = /*#__PURE__*/styled.div.withConfig({
130
138
  componentId: "sc-3hla56-4"
131
- })(["position:relative;display:flex;flex-wrap:nowrap;flex:1;width:100%;", " ", " ", "{padding-bottom:0;padding-top:0;}", " ", " ", " ", "{", "}&:not(:focus-within){", "{background:", ";}}&:focus-within{", "{background:", "}"], _ref17 => {
139
+ })(["position:relative;display:flex;flex-wrap:nowrap;flex:1;width:100%;", " ", " ", "{padding-bottom:0;padding-top:0;}", " ", " ", " ", "{", "}", "{background:", ";}"], _ref18 => {
132
140
  let {
133
141
  withCarousel,
134
142
  isDSMobile
135
- } = _ref17;
143
+ } = _ref18;
136
144
  return withCarousel && !isDSMobile ? "max-width: 100%;" : '';
137
- }, _ref18 => {
145
+ }, _ref19 => {
138
146
  let {
139
147
  theme,
140
148
  isDSMobile,
141
149
  tabType
142
- } = _ref18;
143
- return tabType !== TabTypes.NORMAL_SMALL ? "\n &:after {\n content: '';\n position: absolute;\n width: 100%;\n height: 100%;\n border-bottom-width: 1px;\n border-bottom-style: solid;\n border-bottom-color: ".concat(isDSMobile ? theme.colors.brand[200] : theme.colors.neutral[200], ";\n pointer-events: none;\n }\n ") : "";
144
- }, StyledTabButton, _ref19 => {
150
+ } = _ref19;
151
+ return tabType !== TabTypes.NORMAL_SMALL && !isDSMobile ? "\n &:after {\n content: '';\n position: absolute;\n width: 100%;\n height: 1px;\n box-shadow: 0px 0px 0px 1px ".concat(theme.colors.neutral[400], ";\n pointer-events: none;\n bottom: 0px;\n }\n ") : "";
152
+ }, StyledTabButton, _ref20 => {
145
153
  let {
146
154
  theme,
147
155
  isDSMobile
148
- } = _ref19;
149
- return isDSMobile ? "border-bottom: 1px solid ".concat(theme.colors.brand[300], ";\n background: ").concat(theme.colors.brand[200], ";") : "";
150
- }, mobileGradientsSettings, _ref20 => {
156
+ } = _ref20;
157
+ return isDSMobile ? "\n \n background: ".concat(theme.colors.brand[200], ";") : "";
158
+ }, mobileGradientsSettings, _ref21 => {
151
159
  let {
152
160
  isDSMobile,
153
161
  fixedTabsHeaders
154
- } = _ref20;
155
- return isDSMobile ? "\n ".concat(!fixedTabsHeaders ? "\n z-index: 0;\n overflow-x: auto;\n overflow-y: hidden;\n scrollbar-width: thin;\n &::-webkit-scrollbar {\n display: none;\n }" : "\n display: flex;\n ".concat(StyledTabButton, " {\n flex: 1;\n overflow-x: hidden;\n }")) : "";
156
- }, StyledSelectionIndicator, _ref21 => {
157
- let {
158
- indicatorStyle
159
162
  } = _ref21;
160
- return "\n width: ".concat(indicatorStyle.width, ";\n left: ").concat(indicatorStyle.left, ";\n ");
163
+ return isDSMobile ? "\n ".concat(!fixedTabsHeaders ? "\n z-index: 0;\n overflow-x: auto;\n overflow-y: hidden;\n scrollbar-width: thin;\n &::-webkit-scrollbar {\n display: none;\n }" : "\n display: flex;\n ".concat(StyledTabButton, " {\n flex: 1;\n overflow-x: hidden;\n }")) : "";
161
164
  }, StyledSelectionIndicator, _ref22 => {
162
165
  let {
163
- theme,
164
- indicatorStyle,
165
- isDSMobile
166
+ indicatorStyle
166
167
  } = _ref22;
167
- return !isDSMobile ? indicatorStyle.backgroundWithTransparent : theme.colors.brand[600];
168
+ return "\n width: ".concat(indicatorStyle.width, ";\n left: ").concat(indicatorStyle.left, ";\n ");
168
169
  }, StyledSelectionIndicator, _ref23 => {
169
170
  let {
170
171
  theme,
171
172
  indicatorStyle,
172
173
  isDSMobile
173
174
  } = _ref23;
174
- return !isDSMobile ? indicatorStyle.backgroundWithTransparentAndWhite : theme.colors.brand[600];
175
+ return !isDSMobile ? indicatorStyle.backgroundWithTransparent : theme.colors.brand[600];
175
176
  });
176
177
  const StyledRequiredMark = /*#__PURE__*/styled.span.withConfig({
177
178
  componentId: "sc-3hla56-5"
@@ -1,5 +1,5 @@
1
1
  import 'core-js/modules/web.dom-collections.iterator.js';
2
- import { useContext, useState, useCallback, useEffect, useLayoutEffect } from 'react';
2
+ import { useContext, useState, useCallback, useLayoutEffect } from 'react';
3
3
  import useResizeObserver from '@react-hook/resize-observer';
4
4
  import { isElementVisible, shouldHaveLeftGradient, shouldHaveRightGradient } from '../../utils/helpers.js';
5
5
  import { DSTabsContext } from '../../DSTabsCTX.js';
@@ -33,12 +33,10 @@ const useTabBar = () => {
33
33
  // behavior that adds scroll to the tabList
34
34
 
35
35
  const position = isDSMobile && !fixedTabsHeaders ? activeTabButton.getBoundingClientRect().left - tabList.getBoundingClientRect().left + tabList.scrollLeft : activeTabButton.getBoundingClientRect().left - tabList.getBoundingClientRect().left - missingMargins;
36
- const backgroundWithTransparentAndWhite = "linear-gradient(to right, transparent 0px, transparent 12px, white 12px, white 16px, #1E79C2 16px, #1E79C2 ".concat(tabClientWidth - 16, "px,white ").concat(tabClientWidth - 16, "px,white ").concat(tabClientWidth - 12, "px,transparent ").concat(tabClientWidth - 12, "px,transparent ").concat(tabClientWidth, "px )");
37
36
  const backgroundWithTransparent = "linear-gradient(to right, transparent 0px, transparent 16px, #1E79C2 16px, #1E79C2 ".concat(tabClientWidth - 16, "px,transparent ").concat(tabClientWidth - 16, "px,transparent ").concat(tabClientWidth, "px )");
38
37
  return {
39
38
  left: "".concat(position, "px"),
40
39
  width: "".concat(tabClientWidth, "px"),
41
- backgroundWithTransparentAndWhite,
42
40
  backgroundWithTransparent
43
41
  };
44
42
  }
@@ -60,15 +58,6 @@ const useTabBar = () => {
60
58
  });
61
59
  }
62
60
  }, [fixedTabsHeaders, isDSMobile, tabsListRef]);
63
- useEffect(() => {
64
- if (showSelectionIndicator) {
65
- updateIndicatorStyle();
66
- }
67
-
68
- if (isDSMobile && !fixedTabsHeaders) {
69
- updateMobileGradients();
70
- }
71
- }, [updateIndicatorStyle, showSelectionIndicator, actualActiveTab, updateMobileGradients, isDSMobile, fixedTabsHeaders]);
72
61
  useLayoutEffect(() => {
73
62
  if (showSelectionIndicator) {
74
63
  updateIndicatorStyle();
@@ -77,7 +66,7 @@ const useTabBar = () => {
77
66
  if (isDSMobile && !fixedTabsHeaders) {
78
67
  updateMobileGradients();
79
68
  }
80
- }, [updateMobileGradients, showSelectionIndicator, updateIndicatorStyle, isDSMobile, fixedTabsHeaders]);
69
+ }, [updateMobileGradients, showSelectionIndicator, updateIndicatorStyle, isDSMobile, fixedTabsHeaders, actualActiveTab]);
81
70
  return {
82
71
  updateIndicatorStyle,
83
72
  setIndicatorStyle,
@@ -1,9 +1,14 @@
1
1
  import _jsx from '@babel/runtime/helpers/esm/jsx';
2
+ import 'core-js/modules/esnext.async-iterator.constructor.js';
3
+ import 'core-js/modules/esnext.async-iterator.to-array.js';
4
+ import 'core-js/modules/esnext.iterator.constructor.js';
5
+ import 'core-js/modules/esnext.iterator.to-array.js';
6
+ import 'core-js/modules/esnext.async-iterator.filter.js';
7
+ import 'core-js/modules/esnext.iterator.filter.js';
2
8
  import 'core-js/modules/esnext.async-iterator.map.js';
3
9
  import 'core-js/modules/esnext.iterator.map.js';
4
10
  import React, { useContext, useCallback, useMemo } from 'react';
5
11
  import SwipeableViews from 'react-swipeable-views';
6
- import { getIdByIndex, getIndexById } from '../../utils/helpers.js';
7
12
  import { StyledPanelContainer } from './styles.js';
8
13
  import { DSTabsContext } from '../../DSTabsCTX.js';
9
14
  import { useTabsCallbacks } from '../../utils/hooks/useTabsCallbacks.js';
@@ -25,18 +30,38 @@ const TabsPanels = () => {
25
30
  handleOnTabChange,
26
31
  handleOnMouseDown
27
32
  } = useTabsCallbacks();
28
- const handleOnChangeIndex = useCallback(index => {
29
- handleOnTabChange(getIdByIndex(tabs, index));
30
- if (focusableTabsRef.current) focusableTabsRef.current[index].click();
31
- }, [focusableTabsRef, handleOnTabChange, tabs]);
33
+ const handleOnChangeIndex = useCallback((index, indexLatest) => {
34
+ if (!focusableTabsRef.current) return;
35
+ const offset = index - indexLatest;
36
+
37
+ if (focusableTabsRef.current) {
38
+ var _focusableTabsRef$cur, _focusableTabsRef$cur2, _focusableTabsRef$cur3, _focusableTabsRef$cur4;
39
+
40
+ const currentIndexFocusable = (_focusableTabsRef$cur = focusableTabsRef.current) === null || _focusableTabsRef$cur === void 0 ? void 0 : _focusableTabsRef$cur.findIndex(el => el.dataset.tabId === actualActiveTab);
41
+ const newFocusableIndex = currentIndexFocusable >= 0 ? currentIndexFocusable + offset : -1;
42
+ if (newFocusableIndex < 0 || newFocusableIndex > ((_focusableTabsRef$cur2 = focusableTabsRef.current) === null || _focusableTabsRef$cur2 === void 0 ? void 0 : _focusableTabsRef$cur2.length) || !((_focusableTabsRef$cur3 = focusableTabsRef.current) !== null && _focusableTabsRef$cur3 !== void 0 && _focusableTabsRef$cur3[newFocusableIndex])) return;
43
+ handleOnTabChange((_focusableTabsRef$cur4 = focusableTabsRef.current[newFocusableIndex].dataset) === null || _focusableTabsRef$cur4 === void 0 ? void 0 : _focusableTabsRef$cur4.tabId); // swiping does not trigger centerTab function inside handleOnTabChange because there is no event
44
+ // by clicking we are manually forcing to center the tab
45
+
46
+ focusableTabsRef.current[newFocusableIndex].click();
47
+ }
48
+ }, [actualActiveTab, focusableTabsRef, handleOnTabChange]);
49
+ const firstSlideToShow = useMemo(() => {
50
+ const childrenArray = React.Children.toArray(tabs);
51
+ const index = childrenArray.filter(tab => tab.props.disabled !== true).findIndex(tab => tab.props.tabId === actualActiveTab);
52
+ if (index === -1) return 0;
53
+ return index;
54
+ }, [actualActiveTab, tabs]);
32
55
  const panels = useMemo(() => React.Children.map(tabs, tab => {
33
56
  const {
34
57
  tabId: panelId = '',
35
58
  style,
36
- children: content
59
+ children: content,
60
+ disabled
37
61
  } = tab.props;
38
62
  const isActive = actualActiveTab === panelId;
39
63
  const shouldRender = !onlyRenderActiveTab || isActive;
64
+ if (disabled) return null;
40
65
  return shouldRender && /*#__PURE__*/_jsx(StyledPanelContainer, {
41
66
  id: panelId,
42
67
  "aria-labelledby": "".concat(panelId, "-label"),
@@ -54,7 +79,7 @@ const TabsPanels = () => {
54
79
  if (animated) {
55
80
  return /*#__PURE__*/_jsx(SwipeableViews, {
56
81
  enableMouseEvents: enableMouseEvents,
57
- index: getIndexById(tabs, actualActiveTab),
82
+ index: firstSlideToShow,
58
83
  onChangeIndex: handleOnChangeIndex
59
84
  }, void 0, panels);
60
85
  }
@@ -8,7 +8,6 @@ const MOBILE_GRADIENT_WIDTH = 24;
8
8
  const defaultIndicatorStyles = {
9
9
  left: '0px',
10
10
  width: '0px',
11
- backgroundWithTransparentAndWhite: '',
12
11
  backgroundWithTransparent: ''
13
12
  };
14
13
  const gradientOffsetsAccordingType = {
@@ -21,6 +21,33 @@ const isElementVisibleCarousel = function (tab, tabContainer) {
21
21
 
22
22
  return false;
23
23
  };
24
+ const centerTab = _ref => {
25
+ let {
26
+ e,
27
+ listRef
28
+ } = _ref;
29
+
30
+ if (listRef.current) {
31
+ const {
32
+ offsetLeft
33
+ } = e === null || e === void 0 ? void 0 : e.target;
34
+ const {
35
+ width: tabWidth
36
+ } = (e === null || e === void 0 ? void 0 : e.target).getBoundingClientRect();
37
+ const {
38
+ width: listWidth
39
+ } = listRef.current.getBoundingClientRect();
40
+ const extraSideSpace = listWidth - tabWidth;
41
+ const leftOffsetToCenter = extraSideSpace > 0 ? extraSideSpace / 2 : 0;
42
+ const centeredLeftOffset = offsetLeft > leftOffsetToCenter ? offsetLeft - leftOffsetToCenter : 0;
43
+ listRef.current.scrollTo({
44
+ top: 0,
45
+ left: centeredLeftOffset,
46
+ behavior: 'smooth'
47
+ });
48
+ e === null || e === void 0 ? void 0 : e.preventDefault();
49
+ }
50
+ };
24
51
  const getVisibleDimensions = (node, referenceNode) => {
25
52
  const nodeDimensions = node.getBoundingClientRect();
26
53
  const referenceNodeDimensions = referenceNode.getBoundingClientRect();
@@ -29,9 +56,7 @@ const getVisibleDimensions = (node, referenceNode) => {
29
56
  height: Math.min(node.clientHeight, referenceNodeDimensions.top + referenceNode.clientHeight - nodeDimensions.top, node.clientHeight - (referenceNodeDimensions.top - nodeDimensions.top))
30
57
  };
31
58
  };
32
- const getIndexById = (children, activeId) => children && children.findIndex(item => item.props.tabId === activeId);
33
- const getIdByIndex = (children, index) => children && children[index].props.tabId || '';
34
59
  const shouldHaveLeftGradient = scrollLeft => Math.abs(scrollLeft) > MOBILE_GRADIENT_WIDTH;
35
60
  const shouldHaveRightGradient = (scrollLeft, clientWidth, scrollWidth) => Math.abs(scrollLeft) <= scrollWidth - (clientWidth + MOBILE_GRADIENT_WIDTH);
36
61
 
37
- export { getIdByIndex, getIndexById, getVisibleDimensions, isElementVisible, isElementVisibleCarousel, shouldHaveLeftGradient, shouldHaveRightGradient };
62
+ export { centerTab, getVisibleDimensions, isElementVisible, isElementVisibleCarousel, shouldHaveLeftGradient, shouldHaveRightGradient };
@@ -1,4 +1,5 @@
1
1
  import { useContext, useCallback } from 'react';
2
+ import { centerTab } from '../helpers.js';
2
3
  import { DSTabsContext } from '../../DSTabsCTX.js';
3
4
 
4
5
  const useTabsCallbacks = () => {
@@ -12,36 +13,17 @@ const useTabsCallbacks = () => {
12
13
  fixedTabsHeaders
13
14
  }
14
15
  } = useContext(DSTabsContext);
15
- const centerTabWhenTabChangeMobile = useCallback(e => {
16
- if (tabsListRef.current) {
17
- const {
18
- offsetLeft
19
- } = e === null || e === void 0 ? void 0 : e.target;
20
- const {
21
- width: tabWidth
22
- } = (e === null || e === void 0 ? void 0 : e.target).getBoundingClientRect();
23
- const {
24
- width: listWidth
25
- } = tabsListRef.current.getBoundingClientRect();
26
- const extraSideSpace = listWidth - tabWidth;
27
- const leftOffsetToCenter = extraSideSpace > 0 ? extraSideSpace / 2 : 0;
28
- const centeredLeftOffset = offsetLeft > leftOffsetToCenter ? offsetLeft - leftOffsetToCenter : 0;
29
- tabsListRef.current.scrollTo({
30
- top: 0,
31
- left: centeredLeftOffset,
32
- behavior: 'smooth'
33
- });
34
- e === null || e === void 0 ? void 0 : e.preventDefault();
35
- }
36
- }, [tabsListRef]);
37
16
  const handleOnTabChange = useCallback((tabId, e) => {
38
17
  setInternalActiveTab(tabId);
39
18
  onTabChange(tabId, e);
40
19
 
41
20
  if (isDSMobile && !fixedTabsHeaders && e) {
42
- centerTabWhenTabChangeMobile(e);
21
+ centerTab({
22
+ e,
23
+ listRef: tabsListRef
24
+ });
43
25
  }
44
- }, [centerTabWhenTabChangeMobile, fixedTabsHeaders, isDSMobile, onTabChange, setInternalActiveTab]);
26
+ }, [fixedTabsHeaders, isDSMobile, onTabChange, setInternalActiveTab, tabsListRef]);
45
27
  const handleOnMouseDown = useCallback(e => {
46
28
  const role = e.target.getAttribute('role');
47
29
  if (role !== 'tabpanel' && allowTextSelection) e.stopPropagation();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elliemae/ds-tabs",
3
- "version": "2.0.3",
3
+ "version": "2.0.7",
4
4
  "license": "MIT",
5
5
  "description": "ICE MT - Dimsum - Tabs",
6
6
  "module": "./esm/index.js",
@@ -128,11 +128,11 @@
128
128
  "build": "node ../../scripts/build/build.js"
129
129
  },
130
130
  "dependencies": {
131
- "@elliemae/ds-button": "2.0.3",
132
- "@elliemae/ds-icon": "2.0.3",
133
- "@elliemae/ds-icons": "2.0.3",
134
- "@elliemae/ds-props-helpers": "2.0.3",
135
- "@elliemae/ds-system": "2.0.3",
131
+ "@elliemae/ds-button": "2.0.7",
132
+ "@elliemae/ds-icon": "2.0.7",
133
+ "@elliemae/ds-icons": "2.0.7",
134
+ "@elliemae/ds-props-helpers": "2.0.7",
135
+ "@elliemae/ds-system": "2.0.7",
136
136
  "@react-hook/resize-observer": "~1.2.5",
137
137
  "prop-types": "~15.7.2",
138
138
  "react-desc": "~4.1.3",
@@ -124,7 +124,6 @@ export interface MobileGradientsT {
124
124
  export interface IndicatorStyleT {
125
125
  left: string;
126
126
  width: string;
127
- backgroundWithTransparentAndWhite: string;
128
127
  backgroundWithTransparent: string;
129
128
  }
130
129
  export interface UseCarouselReturnTypeT {
@@ -163,6 +162,10 @@ export interface VisibleDimensionsT {
163
162
  width: number;
164
163
  height: number;
165
164
  }
165
+ export interface CenterTabPropsT {
166
+ e?: React.MouseEvent | React.FocusEvent;
167
+ listRef: React.MutableRefObject<HTMLDivElement | null>;
168
+ }
166
169
  export interface StyledTabWrapperPropsT {
167
170
  isDSMobile: boolean;
168
171
  fixedTabsHeaders: boolean;
@@ -8,7 +8,6 @@ export declare const MOBILE_GRADIENT_WIDTH = 24;
8
8
  export declare const defaultIndicatorStyles: {
9
9
  left: string;
10
10
  width: string;
11
- backgroundWithTransparentAndWhite: string;
12
11
  backgroundWithTransparent: string;
13
12
  };
14
13
  export declare const gradientOffsetsAccordingType: {
@@ -1,8 +1,7 @@
1
- import type { DSTabPropsWithDefaultT, VisibleDimensionsT } from '../DSTabsTypes';
1
+ import type { CenterTabPropsT, VisibleDimensionsT } from '../DSTabsTypes';
2
2
  export declare const isElementVisible: (tab: HTMLElement, tabList: HTMLElement) => boolean;
3
3
  export declare const isElementVisibleCarousel: (tab: HTMLElement | null, tabContainer: HTMLDivElement | null, firstOrLastItem?: boolean) => boolean;
4
+ export declare const centerTab: ({ e, listRef }: CenterTabPropsT) => void;
4
5
  export declare const getVisibleDimensions: (node: HTMLElement, referenceNode: HTMLElement) => VisibleDimensionsT;
5
- export declare const getIndexById: (children: React.ReactElement<DSTabPropsWithDefaultT>[], activeId?: string | undefined) => number;
6
- export declare const getIdByIndex: (children: React.ReactElement<DSTabPropsWithDefaultT>[], index: number) => string;
7
6
  export declare const shouldHaveLeftGradient: (scrollLeft: number) => boolean;
8
7
  export declare const shouldHaveRightGradient: (scrollLeft: number, clientWidth: number, scrollWidth: number) => boolean;