carbon-react 117.2.2 → 117.4.0

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 (34) hide show
  1. package/esm/components/pager/__internal__/pager-navigation.component.d.ts +3 -1
  2. package/esm/components/pager/__internal__/pager-navigation.component.js +10 -3
  3. package/esm/components/pager/pager.component.d.ts +3 -1
  4. package/esm/components/pager/pager.component.js +3 -0
  5. package/esm/components/pager/pager.style.d.ts +2 -1
  6. package/esm/components/pager/pager.style.js +6 -1
  7. package/esm/components/tabs/__internal__/tab-title/tab-title.style.js +3 -0
  8. package/esm/components/tabs/__internal__/tabs-header/tabs-header.component.d.ts +1 -2
  9. package/esm/components/tabs/__internal__/tabs-header/tabs-header.component.js +45 -7
  10. package/esm/components/tabs/__internal__/tabs-header/tabs-header.style.d.ts +9 -2
  11. package/esm/components/tabs/__internal__/tabs-header/tabs-header.style.js +90 -17
  12. package/esm/components/tabs/tabs.component.js +2 -11
  13. package/esm/hooks/__internal__/useThrottle/index.d.ts +1 -0
  14. package/esm/hooks/__internal__/useThrottle/index.js +1 -0
  15. package/esm/hooks/__internal__/useThrottle/useThrottle.d.ts +4 -0
  16. package/esm/hooks/__internal__/useThrottle/useThrottle.js +18 -0
  17. package/lib/components/pager/__internal__/pager-navigation.component.d.ts +3 -1
  18. package/lib/components/pager/__internal__/pager-navigation.component.js +9 -2
  19. package/lib/components/pager/pager.component.d.ts +3 -1
  20. package/lib/components/pager/pager.component.js +3 -0
  21. package/lib/components/pager/pager.style.d.ts +2 -1
  22. package/lib/components/pager/pager.style.js +7 -1
  23. package/lib/components/tabs/__internal__/tab-title/tab-title.style.js +3 -0
  24. package/lib/components/tabs/__internal__/tabs-header/tabs-header.component.d.ts +1 -2
  25. package/lib/components/tabs/__internal__/tabs-header/tabs-header.component.js +49 -6
  26. package/lib/components/tabs/__internal__/tabs-header/tabs-header.style.d.ts +9 -2
  27. package/lib/components/tabs/__internal__/tabs-header/tabs-header.style.js +97 -17
  28. package/lib/components/tabs/tabs.component.js +2 -11
  29. package/lib/hooks/__internal__/useThrottle/index.d.ts +1 -0
  30. package/lib/hooks/__internal__/useThrottle/index.js +15 -0
  31. package/lib/hooks/__internal__/useThrottle/package.json +6 -0
  32. package/lib/hooks/__internal__/useThrottle/useThrottle.d.ts +4 -0
  33. package/lib/hooks/__internal__/useThrottle/useThrottle.js +29 -0
  34. package/package.json +1 -1
@@ -23,8 +23,10 @@ export interface PagerNavigationProps {
23
23
  showPreviousAndNextButtons?: boolean;
24
24
  /** Should the page count input be shown */
25
25
  showPageCount?: boolean;
26
+ /** If true, page number navigation will be changed to a non-interactive label */
27
+ interactivePageNumber?: boolean;
26
28
  /** If true, sets css property visibility: hidden on all disabled elements */
27
29
  hideDisabledElements?: boolean;
28
30
  }
29
- declare const PagerNavigation: ({ pageSize, currentPage, setCurrentPage, onNext, onPrevious, onFirst, onLast, onPagination, pageCount, showFirstAndLastButtons, showPreviousAndNextButtons, showPageCount, hideDisabledElements, }: PagerNavigationProps) => JSX.Element;
31
+ declare const PagerNavigation: ({ pageSize, currentPage, setCurrentPage, onNext, onPrevious, onFirst, onLast, onPagination, pageCount, showFirstAndLastButtons, showPreviousAndNextButtons, showPageCount, interactivePageNumber, hideDisabledElements, }: PagerNavigationProps) => JSX.Element;
30
32
  export default PagerNavigation;
@@ -2,7 +2,7 @@ function _extends() { _extends = Object.assign || function (target) { for (var i
2
2
 
3
3
  import React, { useRef } from "react";
4
4
  import PropTypes from "prop-types";
5
- import { StyledPagerNavigation, StyledPagerNavInner, StyledPagerNoSelect } from "../pager.style";
5
+ import { StyledPagerNavigation, StyledPagerNavInner, StyledPagerNoSelect, StyledPagerNavLabel } from "../pager.style";
6
6
  import NumberInput from "../../number";
7
7
  import Events from "../../../__internal__/utils/helpers/events";
8
8
  import createGuid from "../../../__internal__/utils/helpers/guid";
@@ -22,11 +22,13 @@ const PagerNavigation = ({
22
22
  showFirstAndLastButtons = true,
23
23
  showPreviousAndNextButtons = true,
24
24
  showPageCount = true,
25
+ interactivePageNumber = true,
25
26
  hideDisabledElements = false
26
27
  }) => {
27
28
  const l = useLocale();
28
29
  const guid = useRef(createGuid());
29
30
  const currentPageId = `Pager_${guid.current}`;
31
+ const navLabelString = `${l.pager.pageX()} ${currentPage.toString()} ${l.pager.ofY(pageCount)}`;
30
32
  const hasOnePage = pageCount <= 1;
31
33
  const hasTwoPages = pageCount === 2;
32
34
  const pagerNavigationProps = {
@@ -86,7 +88,7 @@ const PagerNavigation = ({
86
88
  onClick: onLast
87
89
  }, pagerNavigationProps)));
88
90
 
89
- return /*#__PURE__*/React.createElement(StyledPagerNavigation, null, !hasOnePage && renderButtonsBeforeCount(), showPageCount && /*#__PURE__*/React.createElement(StyledPagerNavInner, null, /*#__PURE__*/React.createElement("label", {
91
+ return /*#__PURE__*/React.createElement(StyledPagerNavigation, null, !hasOnePage && renderButtonsBeforeCount(), showPageCount && (interactivePageNumber ? /*#__PURE__*/React.createElement(StyledPagerNavInner, null, /*#__PURE__*/React.createElement("label", {
90
92
  htmlFor: currentPageId
91
93
  }, /*#__PURE__*/React.createElement(StyledPagerNoSelect, null, l.pager.pageX())), /*#__PURE__*/React.createElement(NumberInput, {
92
94
  value: currentPage.toString(),
@@ -95,12 +97,17 @@ const PagerNavigation = ({
95
97
  onBlur: handlePageInputChange,
96
98
  id: currentPageId,
97
99
  onKeyUp: ev => Events.isEnterKey(ev) ? handlePageInputChange(ev) : false
98
- }), /*#__PURE__*/React.createElement(StyledPagerNoSelect, null, l.pager.ofY(pageCount))), !hasOnePage && renderButtonsAfterCount());
100
+ }), /*#__PURE__*/React.createElement(StyledPagerNoSelect, null, l.pager.ofY(pageCount))) : /*#__PURE__*/React.createElement(StyledPagerNavLabel, {
101
+ "data-element": "current-page-label",
102
+ id: currentPageId,
103
+ "aria-live": "polite"
104
+ }, navLabelString)), !hasOnePage && renderButtonsAfterCount());
99
105
  };
100
106
 
101
107
  PagerNavigation.propTypes = {
102
108
  "currentPage": PropTypes.number.isRequired,
103
109
  "hideDisabledElements": PropTypes.bool,
110
+ "interactivePageNumber": PropTypes.bool,
104
111
  "onFirst": PropTypes.func,
105
112
  "onLast": PropTypes.func,
106
113
  "onNext": PropTypes.func,
@@ -16,6 +16,8 @@ export interface PagerProps {
16
16
  onLast?: (ev: React.MouseEvent<HTMLButtonElement> | React.KeyboardEvent<HTMLButtonElement>) => void;
17
17
  /** Current visible page */
18
18
  currentPage?: number | string;
19
+ /** If true, page number navigation will be changed to a non-interactive label */
20
+ interactivePageNumber?: boolean;
19
21
  /** If true, sets css property visibility: hidden on all disabled elements */
20
22
  hideDisabledElements?: boolean;
21
23
  /** Total number of records */
@@ -41,5 +43,5 @@ export interface PagerProps {
41
43
  /** What variant the Pager background should be */
42
44
  variant?: "default" | "alternate";
43
45
  }
44
- export declare const Pager: ({ currentPage, hideDisabledElements, pageSizeSelectionOptions, pageSize, showPageSizeSelection, totalRecords, onPagination, onNext, onFirst, onPrevious, onLast, showPageSizeLabelBefore, showPageSizeLabelAfter, showTotalRecords, showFirstAndLastButtons, showPreviousAndNextButtons, showPageCount, variant, ...rest }: PagerProps) => JSX.Element;
46
+ export declare const Pager: ({ currentPage, hideDisabledElements, interactivePageNumber, pageSizeSelectionOptions, pageSize, showPageSizeSelection, totalRecords, onPagination, onNext, onFirst, onPrevious, onLast, showPageSizeLabelBefore, showPageSizeLabelAfter, showTotalRecords, showFirstAndLastButtons, showPreviousAndNextButtons, showPageCount, variant, ...rest }: PagerProps) => JSX.Element;
45
47
  export default Pager;
@@ -12,6 +12,7 @@ import Events from "../../__internal__/utils/helpers/events";
12
12
  const Pager = ({
13
13
  currentPage = 1,
14
14
  hideDisabledElements = false,
15
+ interactivePageNumber = true,
15
16
  pageSizeSelectionOptions = [{
16
17
  id: "10",
17
18
  name: 10
@@ -137,6 +138,7 @@ const Pager = ({
137
138
  }, rest), /*#__PURE__*/React.createElement(StyledPagerSizeOptions, null, renderPageSizeOptions()), /*#__PURE__*/React.createElement(PagerNavigation, {
138
139
  pageSize: currentPageSize,
139
140
  currentPage: page,
141
+ interactivePageNumber: interactivePageNumber,
140
142
  hideDisabledElements: hideDisabledElements,
141
143
  setCurrentPage: setPage,
142
144
  onNext: handleOnNext,
@@ -154,6 +156,7 @@ const Pager = ({
154
156
  Pager.propTypes = {
155
157
  "currentPage": PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
156
158
  "hideDisabledElements": PropTypes.bool,
159
+ "interactivePageNumber": PropTypes.bool,
157
160
  "onFirst": PropTypes.func,
158
161
  "onLast": PropTypes.func,
159
162
  "onNext": PropTypes.func,
@@ -9,7 +9,8 @@ declare const StyledPagerSizeOptions: import("styled-components").StyledComponen
9
9
  declare const StyledPagerSizeOptionsInner: import("styled-components").StyledComponent<"div", any, {}, never>;
10
10
  declare const StyledPagerNavigation: import("styled-components").StyledComponent<"div", any, {}, never>;
11
11
  declare const StyledPagerNavInner: import("styled-components").StyledComponent<"div", any, {}, never>;
12
+ declare const StyledPagerNavLabel: import("styled-components").StyledComponent<"label", any, {}, never>;
12
13
  declare const StyledPagerLink: import("styled-components").StyledComponent<import("react").ForwardRefExoticComponent<import("../link").LinkProps & import("react").RefAttributes<HTMLButtonElement | HTMLLinkElement>>, any, Pick<StyledPagerProps, "hideDisabledButtons">, never>;
13
14
  declare const StyledPagerNoSelect: import("styled-components").StyledComponent<"div", any, {}, never>;
14
15
  declare const StyledPagerSummary: import("styled-components").StyledComponent<"div", any, {}, never>;
15
- export { StyledPagerContainer, StyledPagerSizeOptions, StyledPagerSizeOptionsInner, StyledPagerNavigation, StyledPagerNavInner, StyledPagerLink, StyledPagerNoSelect, StyledPagerSummary, StyledSelectContainer, };
16
+ export { StyledPagerContainer, StyledPagerSizeOptions, StyledPagerSizeOptionsInner, StyledPagerNavigation, StyledPagerNavInner, StyledPagerNavLabel, StyledPagerLink, StyledPagerNoSelect, StyledPagerSummary, StyledSelectContainer, };
@@ -95,6 +95,11 @@ const StyledPagerNavInner = styled.div`
95
95
  margin-bottom: 0;
96
96
  }
97
97
  `;
98
+ const StyledPagerNavLabel = styled.label`
99
+ white-space: nowrap;
100
+ padding: 9px 12px;
101
+ margin: 4px 0;
102
+ `;
98
103
  const StyledPagerLink = styled(Link)`
99
104
  padding: 0 10px;
100
105
  margin-left: 7px;
@@ -118,4 +123,4 @@ const StyledPagerSummary = styled.div`
118
123
  flex: 1 1 30%;
119
124
  justify-content: flex-end;
120
125
  `;
121
- export { StyledPagerContainer, StyledPagerSizeOptions, StyledPagerSizeOptionsInner, StyledPagerNavigation, StyledPagerNavInner, StyledPagerLink, StyledPagerNoSelect, StyledPagerSummary, StyledSelectContainer };
126
+ export { StyledPagerContainer, StyledPagerSizeOptions, StyledPagerSizeOptionsInner, StyledPagerNavigation, StyledPagerNavInner, StyledPagerNavLabel, StyledPagerLink, StyledPagerNoSelect, StyledPagerSummary, StyledSelectContainer };
@@ -217,6 +217,9 @@ const tabTitleStyles = css`
217
217
  text-decoration: none;
218
218
  outline-offset: 0px;
219
219
  margin: 0;
220
+ ${({
221
+ position
222
+ }) => position === "top" && "white-space: nowrap"};
220
223
 
221
224
  a:visited {
222
225
  color: inherit;
@@ -4,10 +4,9 @@ export interface TabHeaderProps {
4
4
  position?: "top" | "left";
5
5
  extendedLine?: boolean;
6
6
  noRightBorder?: boolean;
7
- alternateStyling?: boolean;
8
7
  isInSidebar?: boolean;
9
8
  children: React.ReactNode;
10
9
  align?: "left" | "right";
11
10
  }
12
- declare const TabsHeader: ({ align, children, position, role, extendedLine, alternateStyling, noRightBorder, isInSidebar, }: TabHeaderProps) => JSX.Element;
11
+ declare const TabsHeader: ({ align, children, position, role, extendedLine, noRightBorder, isInSidebar, }: TabHeaderProps) => JSX.Element;
13
12
  export default TabsHeader;
@@ -1,6 +1,20 @@
1
- import React from "react";
1
+ import React, { useRef, useState } from "react";
2
2
  import PropTypes from "prop-types";
3
- import { StyledTabsHeaderWrapper, StyledTabsHeaderList } from "./tabs-header.style";
3
+ import { StyledTabsHeaderWrapper, StyledTabsHeaderList, StyledTabsBottomBorder, StyledTabsWrapper, StyledTabsBottomBorderWrapper } from "./tabs-header.style";
4
+ import useThrottle from "../../../../hooks/__internal__/useThrottle";
5
+ /* In the original prototype the tabs have shadows that fade out as you scroll horizontally.
6
+ * This value is the closest replication to the way that the shadow disappears.
7
+ * It is ultimately tied to the position of the scroll that will then fade the shadow in and out. */
8
+
9
+ const fullOpacityThreshold = 128;
10
+
11
+ const getOpacityRatio = value => value / fullOpacityThreshold;
12
+
13
+ const getScrollRight = ({
14
+ scrollWidth,
15
+ clientWidth,
16
+ scrollLeft
17
+ }) => scrollWidth - clientWidth - scrollLeft;
4
18
 
5
19
  const TabsHeader = ({
6
20
  align = "left",
@@ -8,10 +22,31 @@ const TabsHeader = ({
8
22
  position = "top",
9
23
  role,
10
24
  extendedLine,
11
- alternateStyling,
12
25
  noRightBorder = false,
13
26
  isInSidebar = false
14
27
  }) => {
28
+ const [leftScrollOpacity, setLeftScrollOpacity] = useState(0);
29
+ const [rightScrollOpacity, setRightScrollOpacity] = useState(1);
30
+ const ref = useRef(null);
31
+ let isScrollable = false;
32
+ const {
33
+ current
34
+ } = ref;
35
+
36
+ if (position === "top" && current) {
37
+ isScrollable = current.scrollWidth > current.clientWidth;
38
+ }
39
+
40
+ const handleScroll = e => {
41
+ const {
42
+ scrollLeft
43
+ } = e.target;
44
+ const scrollRight = getScrollRight(e.target);
45
+ setLeftScrollOpacity(Math.min(getOpacityRatio(scrollLeft), 1));
46
+ setRightScrollOpacity(Math.min(getOpacityRatio(scrollRight), 1));
47
+ };
48
+
49
+ const throttledHandleScroll = useThrottle(handleScroll, 50);
15
50
  return /*#__PURE__*/React.createElement(StyledTabsHeaderWrapper, {
16
51
  isInSidebar: isInSidebar,
17
52
  position: position
@@ -20,15 +55,18 @@ const TabsHeader = ({
20
55
  position: position,
21
56
  role: role,
22
57
  extendedLine: extendedLine,
23
- alternateStyling: alternateStyling,
24
58
  noRightBorder: noRightBorder,
25
- isInSidebar: isInSidebar
26
- }, children));
59
+ isInSidebar: isInSidebar,
60
+ onScroll: throttledHandleScroll,
61
+ leftScrollOpacity: leftScrollOpacity,
62
+ rightScrollOpacity: rightScrollOpacity,
63
+ isScrollable: isScrollable,
64
+ ref: ref
65
+ }, position === "top" ? /*#__PURE__*/React.createElement(StyledTabsWrapper, null, /*#__PURE__*/React.createElement(StyledTabsBottomBorderWrapper, null, /*#__PURE__*/React.createElement(StyledTabsBottomBorder, null)), children) : children));
27
66
  };
28
67
 
29
68
  TabsHeader.propTypes = {
30
69
  "align": PropTypes.oneOf(["left", "right"]),
31
- "alternateStyling": PropTypes.bool,
32
70
  "children": PropTypes.node,
33
71
  "extendedLine": PropTypes.bool,
34
72
  "isInSidebar": PropTypes.bool,
@@ -1,6 +1,13 @@
1
1
  import { TabHeaderProps } from "./tabs-header.component";
2
2
  declare type StyledTabsHeaderWrapperProps = Pick<TabHeaderProps, "position" | "isInSidebar">;
3
3
  declare const StyledTabsHeaderWrapper: import("styled-components").StyledComponent<"div", any, StyledTabsHeaderWrapperProps, never>;
4
- export declare type StyledTabsHeaderListProps = Pick<TabHeaderProps, "align" | "alternateStyling" | "extendedLine" | "noRightBorder" | "isInSidebar" | "position">;
4
+ export interface StyledTabsHeaderListProps extends Pick<TabHeaderProps, "align" | "extendedLine" | "noRightBorder" | "isInSidebar" | "position"> {
5
+ leftScrollOpacity?: number;
6
+ rightScrollOpacity?: number;
7
+ isScrollable?: boolean;
8
+ }
5
9
  declare const StyledTabsHeaderList: import("styled-components").StyledComponent<"div", any, StyledTabsHeaderListProps, never>;
6
- export { StyledTabsHeaderWrapper, StyledTabsHeaderList };
10
+ declare const StyledTabsWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
11
+ declare const StyledTabsBottomBorderWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
12
+ declare const StyledTabsBottomBorder: import("styled-components").StyledComponent<"div", any, {}, never>;
13
+ export { StyledTabsHeaderWrapper, StyledTabsHeaderList, StyledTabsWrapper, StyledTabsBottomBorderWrapper, StyledTabsBottomBorder, };
@@ -1,17 +1,6 @@
1
1
  import styled, { css } from "styled-components";
2
-
3
- const computeLineWidth = ({
4
- alternateStyling,
5
- isInSidebar,
6
- position
7
- }) => {
8
- if (isInSidebar && position === "left") {
9
- return "0px";
10
- }
11
-
12
- return alternateStyling ? "-1px" : "-2px";
13
- };
14
-
2
+ import BaseTheme from "../../../../style/themes/base";
3
+ const outlineWidth = "3px";
15
4
  const StyledTabsHeaderWrapper = styled.div`
16
5
  ${({
17
6
  position,
@@ -32,9 +21,21 @@ const StyledTabsHeaderWrapper = styled.div`
32
21
  `}
33
22
  `}
34
23
  `;
24
+ const commonShadowStyles = css`
25
+ pointer-events: none;
26
+ content: "";
27
+ background-repeat: no-repeat;
28
+ background-size: 16px 48px;
29
+ background-attachment: scroll;
30
+ z-index: ${({
31
+ theme
32
+ }) => theme.zIndex.overlay};
33
+ position: sticky;
34
+ min-width: 16px;
35
+ transition: opacity 0.1s ease-in-out;
36
+ `;
35
37
  const StyledTabsHeaderList = styled.div`
36
38
  display: flex;
37
- box-shadow: inset 0px ${computeLineWidth} 0px 0px var(--colorsActionMinor100);
38
39
  ${({
39
40
  extendedLine = true
40
41
  }) => !extendedLine && css`
@@ -42,8 +43,57 @@ const StyledTabsHeaderList = styled.div`
42
43
  `}
43
44
  cursor: default;
44
45
  list-style: none;
45
- margin: 0;
46
- padding: 0;
46
+ margin: -${outlineWidth};
47
+ padding: ${outlineWidth};
48
+ overflow-x: auto;
49
+ position: relative;
50
+ ${({
51
+ position
52
+ }) => position === "top" && "white-space: nowrap"};
53
+
54
+ ${({
55
+ isScrollable,
56
+ leftScrollOpacity,
57
+ rightScrollOpacity
58
+ }) => isScrollable && css`
59
+ &:before {
60
+ ${commonShadowStyles}
61
+ background: radial-gradient(
62
+ farthest-side at 0 50%,
63
+ rgba(0, 0, 0, 0.2),
64
+ rgba(0, 0, 0, 0)
65
+ );
66
+ background-position: left calc(50% - 4px);
67
+ left: -${outlineWidth};
68
+ margin-right: -16px;
69
+ opacity: ${leftScrollOpacity};
70
+ }
71
+
72
+ &:after {
73
+ ${commonShadowStyles}
74
+ background: radial-gradient(
75
+ farthest-side at 100% 50%,
76
+ rgba(0, 0, 0, 0.2),
77
+ rgba(0, 0, 0, 0)
78
+ );
79
+ background-position: right calc(50% - 4px);
80
+ right: -${outlineWidth};
81
+ margin-left: -16px;
82
+ opacity: ${rightScrollOpacity};
83
+ }
84
+ `}
85
+
86
+ &::-webkit-scrollbar {
87
+ -webkit-appearance: none;
88
+ background: var(--colorsUtilityMajor025);
89
+ height: 8px;
90
+ width: 8px;
91
+ }
92
+
93
+ &::-webkit-scrollbar-thumb {
94
+ background-color: var(--colorsUtilityMajor300);
95
+ cursor: pointer;
96
+ }
47
97
 
48
98
  ${({
49
99
  align = "left"
@@ -69,4 +119,27 @@ const StyledTabsHeaderList = styled.div`
69
119
  `}
70
120
  `}
71
121
  `;
72
- export { StyledTabsHeaderWrapper, StyledTabsHeaderList };
122
+ StyledTabsHeaderList.defaultProps = {
123
+ theme: BaseTheme
124
+ };
125
+ const StyledTabsWrapper = styled.div`
126
+ position: relative;
127
+ min-width: max-content;
128
+ width: 100%;
129
+ height: 100%;
130
+ `;
131
+ const StyledTabsBottomBorderWrapper = styled.div`
132
+ position: absolute;
133
+ width: 100%;
134
+ height: auto;
135
+ bottom: 0;
136
+ `;
137
+ const StyledTabsBottomBorder = styled.div`
138
+ position: sticky;
139
+ bottom: 2px;
140
+ left: ${outlineWidth};
141
+ right: ${outlineWidth};
142
+ height: 2px;
143
+ background-color: var(--colorsActionMinor100);
144
+ `;
145
+ export { StyledTabsHeaderWrapper, StyledTabsHeaderList, StyledTabsWrapper, StyledTabsBottomBorderWrapper, StyledTabsBottomBorder };
@@ -45,7 +45,6 @@ const Tabs = ({
45
45
  }).map(() => /*#__PURE__*/createRef()), [filteredChildren.length]);
46
46
  const previousSelectedTabId = useRef(selectedTabId);
47
47
  const [selectedTabIdState, setSelectedTabIdState] = useState(selectedTabId || filteredChildren[0].props.tabId);
48
- const [tabStopId, setTabStopId] = useState();
49
48
  const {
50
49
  isInSidebar
51
50
  } = useContext(DrawerSidebarContext);
@@ -70,7 +69,6 @@ const Tabs = ({
70
69
  /** Returns true/false for if the given tab id is selected. */
71
70
 
72
71
  const isTabSelected = useCallback(tabId => tabId === selectedTabIdState, [selectedTabIdState]);
73
- const hasTabStop = useCallback(tabId => tabId === tabStopId, [tabStopId]);
74
72
  /** Updates the currently visible tab */
75
73
 
76
74
  const updateVisibleTab = useCallback(tabid => {
@@ -78,14 +76,10 @@ const Tabs = ({
78
76
  setSelectedTabIdState(tabid);
79
77
  }
80
78
 
81
- if (!hasTabStop(tabid)) {
82
- setTabStopId(tabid);
83
- }
84
-
85
79
  if (onTabChange) {
86
80
  onTabChange(tabid);
87
81
  }
88
- }, [onTabChange, isTabSelected, hasTabStop]);
82
+ }, [onTabChange, isTabSelected]);
89
83
  const blurPreviousSelectedTab = useCallback(() => {
90
84
  const {
91
85
  current
@@ -145,9 +139,7 @@ const Tabs = ({
145
139
  newIndex = 0;
146
140
  }
147
141
 
148
- const nextTabId = tabIds[newIndex];
149
142
  const nextRef = tabRefs[newIndex];
150
- updateVisibleTab(nextTabId);
151
143
  focusTab(nextRef);
152
144
  };
153
145
  /** Handles the keyboard navigation of tabs */
@@ -223,7 +215,7 @@ const Tabs = ({
223
215
  onClick: handleTabClick,
224
216
  onKeyDown: handleKeyDown(index),
225
217
  ref: tabRefs[index],
226
- tabIndex: isTabSelected(tabId) || hasTabStop(tabId) ? 0 : -1,
218
+ tabIndex: isTabSelected(tabId) ? 0 : -1,
227
219
  title: title,
228
220
  href: href,
229
221
  isTabSelected: isTabSelected(tabId),
@@ -250,7 +242,6 @@ const Tabs = ({
250
242
  position: isInSidebar ? "left" : position,
251
243
  role: "tablist",
252
244
  extendedLine: extendedLine,
253
- alternateStyling: variant === "alternate" || isInSidebar,
254
245
  noRightBorder: ["no right side", "no sides"].includes(borders),
255
246
  isInSidebar: isInSidebar
256
247
  }, tabTitles);
@@ -0,0 +1 @@
1
+ export { default } from "./useThrottle";
@@ -0,0 +1 @@
1
+ export { default } from "./useThrottle";
@@ -0,0 +1,4 @@
1
+ import { DebouncedFunc } from "lodash";
2
+ declare type Callback = (...args: any[]) => void;
3
+ declare const useThrottle: <T extends Callback>(callback: T, delay: number) => DebouncedFunc<T>;
4
+ export default useThrottle;
@@ -0,0 +1,18 @@
1
+ import { useMemo, useEffect, useRef } from "react";
2
+ import throttle from "lodash/throttle";
3
+
4
+ const useThrottle = (callback, delay) => {
5
+ const callbackRef = useRef(callback);
6
+ useEffect(() => {
7
+ callbackRef.current = callback;
8
+ });
9
+ const throttledCallback = useMemo(() => throttle(callbackRef.current, delay), [delay]);
10
+ useEffect(() => {
11
+ return () => {
12
+ throttledCallback.cancel();
13
+ };
14
+ });
15
+ return throttledCallback;
16
+ };
17
+
18
+ export default useThrottle;
@@ -23,8 +23,10 @@ export interface PagerNavigationProps {
23
23
  showPreviousAndNextButtons?: boolean;
24
24
  /** Should the page count input be shown */
25
25
  showPageCount?: boolean;
26
+ /** If true, page number navigation will be changed to a non-interactive label */
27
+ interactivePageNumber?: boolean;
26
28
  /** If true, sets css property visibility: hidden on all disabled elements */
27
29
  hideDisabledElements?: boolean;
28
30
  }
29
- declare const PagerNavigation: ({ pageSize, currentPage, setCurrentPage, onNext, onPrevious, onFirst, onLast, onPagination, pageCount, showFirstAndLastButtons, showPreviousAndNextButtons, showPageCount, hideDisabledElements, }: PagerNavigationProps) => JSX.Element;
31
+ declare const PagerNavigation: ({ pageSize, currentPage, setCurrentPage, onNext, onPrevious, onFirst, onLast, onPagination, pageCount, showFirstAndLastButtons, showPreviousAndNextButtons, showPageCount, interactivePageNumber, hideDisabledElements, }: PagerNavigationProps) => JSX.Element;
30
32
  export default PagerNavigation;
@@ -42,11 +42,13 @@ const PagerNavigation = ({
42
42
  showFirstAndLastButtons = true,
43
43
  showPreviousAndNextButtons = true,
44
44
  showPageCount = true,
45
+ interactivePageNumber = true,
45
46
  hideDisabledElements = false
46
47
  }) => {
47
48
  const l = (0, _useLocale.default)();
48
49
  const guid = (0, _react.useRef)((0, _guid.default)());
49
50
  const currentPageId = `Pager_${guid.current}`;
51
+ const navLabelString = `${l.pager.pageX()} ${currentPage.toString()} ${l.pager.ofY(pageCount)}`;
50
52
  const hasOnePage = pageCount <= 1;
51
53
  const hasTwoPages = pageCount === 2;
52
54
  const pagerNavigationProps = {
@@ -106,7 +108,7 @@ const PagerNavigation = ({
106
108
  onClick: onLast
107
109
  }, pagerNavigationProps)));
108
110
 
109
- return /*#__PURE__*/_react.default.createElement(_pager.StyledPagerNavigation, null, !hasOnePage && renderButtonsBeforeCount(), showPageCount && /*#__PURE__*/_react.default.createElement(_pager.StyledPagerNavInner, null, /*#__PURE__*/_react.default.createElement("label", {
111
+ return /*#__PURE__*/_react.default.createElement(_pager.StyledPagerNavigation, null, !hasOnePage && renderButtonsBeforeCount(), showPageCount && (interactivePageNumber ? /*#__PURE__*/_react.default.createElement(_pager.StyledPagerNavInner, null, /*#__PURE__*/_react.default.createElement("label", {
110
112
  htmlFor: currentPageId
111
113
  }, /*#__PURE__*/_react.default.createElement(_pager.StyledPagerNoSelect, null, l.pager.pageX())), /*#__PURE__*/_react.default.createElement(_number.default, {
112
114
  value: currentPage.toString(),
@@ -115,12 +117,17 @@ const PagerNavigation = ({
115
117
  onBlur: handlePageInputChange,
116
118
  id: currentPageId,
117
119
  onKeyUp: ev => _events.default.isEnterKey(ev) ? handlePageInputChange(ev) : false
118
- }), /*#__PURE__*/_react.default.createElement(_pager.StyledPagerNoSelect, null, l.pager.ofY(pageCount))), !hasOnePage && renderButtonsAfterCount());
120
+ }), /*#__PURE__*/_react.default.createElement(_pager.StyledPagerNoSelect, null, l.pager.ofY(pageCount))) : /*#__PURE__*/_react.default.createElement(_pager.StyledPagerNavLabel, {
121
+ "data-element": "current-page-label",
122
+ id: currentPageId,
123
+ "aria-live": "polite"
124
+ }, navLabelString)), !hasOnePage && renderButtonsAfterCount());
119
125
  };
120
126
 
121
127
  PagerNavigation.propTypes = {
122
128
  "currentPage": _propTypes.default.number.isRequired,
123
129
  "hideDisabledElements": _propTypes.default.bool,
130
+ "interactivePageNumber": _propTypes.default.bool,
124
131
  "onFirst": _propTypes.default.func,
125
132
  "onLast": _propTypes.default.func,
126
133
  "onNext": _propTypes.default.func,
@@ -16,6 +16,8 @@ export interface PagerProps {
16
16
  onLast?: (ev: React.MouseEvent<HTMLButtonElement> | React.KeyboardEvent<HTMLButtonElement>) => void;
17
17
  /** Current visible page */
18
18
  currentPage?: number | string;
19
+ /** If true, page number navigation will be changed to a non-interactive label */
20
+ interactivePageNumber?: boolean;
19
21
  /** If true, sets css property visibility: hidden on all disabled elements */
20
22
  hideDisabledElements?: boolean;
21
23
  /** Total number of records */
@@ -41,5 +43,5 @@ export interface PagerProps {
41
43
  /** What variant the Pager background should be */
42
44
  variant?: "default" | "alternate";
43
45
  }
44
- export declare const Pager: ({ currentPage, hideDisabledElements, pageSizeSelectionOptions, pageSize, showPageSizeSelection, totalRecords, onPagination, onNext, onFirst, onPrevious, onLast, showPageSizeLabelBefore, showPageSizeLabelAfter, showTotalRecords, showFirstAndLastButtons, showPreviousAndNextButtons, showPageCount, variant, ...rest }: PagerProps) => JSX.Element;
46
+ export declare const Pager: ({ currentPage, hideDisabledElements, interactivePageNumber, pageSizeSelectionOptions, pageSize, showPageSizeSelection, totalRecords, onPagination, onNext, onFirst, onPrevious, onLast, showPageSizeLabelBefore, showPageSizeLabelAfter, showTotalRecords, showFirstAndLastButtons, showPreviousAndNextButtons, showPageCount, variant, ...rest }: PagerProps) => JSX.Element;
45
47
  export default Pager;
@@ -32,6 +32,7 @@ function _extends() { _extends = Object.assign || function (target) { for (var i
32
32
  const Pager = ({
33
33
  currentPage = 1,
34
34
  hideDisabledElements = false,
35
+ interactivePageNumber = true,
35
36
  pageSizeSelectionOptions = [{
36
37
  id: "10",
37
38
  name: 10
@@ -157,6 +158,7 @@ const Pager = ({
157
158
  }, rest), /*#__PURE__*/_react.default.createElement(_pager.StyledPagerSizeOptions, null, renderPageSizeOptions()), /*#__PURE__*/_react.default.createElement(_pagerNavigation.default, {
158
159
  pageSize: currentPageSize,
159
160
  currentPage: page,
161
+ interactivePageNumber: interactivePageNumber,
160
162
  hideDisabledElements: hideDisabledElements,
161
163
  setCurrentPage: setPage,
162
164
  onNext: handleOnNext,
@@ -175,6 +177,7 @@ exports.Pager = Pager;
175
177
  Pager.propTypes = {
176
178
  "currentPage": _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]),
177
179
  "hideDisabledElements": _propTypes.default.bool,
180
+ "interactivePageNumber": _propTypes.default.bool,
178
181
  "onFirst": _propTypes.default.func,
179
182
  "onLast": _propTypes.default.func,
180
183
  "onNext": _propTypes.default.func,
@@ -9,7 +9,8 @@ declare const StyledPagerSizeOptions: import("styled-components").StyledComponen
9
9
  declare const StyledPagerSizeOptionsInner: import("styled-components").StyledComponent<"div", any, {}, never>;
10
10
  declare const StyledPagerNavigation: import("styled-components").StyledComponent<"div", any, {}, never>;
11
11
  declare const StyledPagerNavInner: import("styled-components").StyledComponent<"div", any, {}, never>;
12
+ declare const StyledPagerNavLabel: import("styled-components").StyledComponent<"label", any, {}, never>;
12
13
  declare const StyledPagerLink: import("styled-components").StyledComponent<import("react").ForwardRefExoticComponent<import("../link").LinkProps & import("react").RefAttributes<HTMLButtonElement | HTMLLinkElement>>, any, Pick<StyledPagerProps, "hideDisabledButtons">, never>;
13
14
  declare const StyledPagerNoSelect: import("styled-components").StyledComponent<"div", any, {}, never>;
14
15
  declare const StyledPagerSummary: import("styled-components").StyledComponent<"div", any, {}, never>;
15
- export { StyledPagerContainer, StyledPagerSizeOptions, StyledPagerSizeOptionsInner, StyledPagerNavigation, StyledPagerNavInner, StyledPagerLink, StyledPagerNoSelect, StyledPagerSummary, StyledSelectContainer, };
16
+ export { StyledPagerContainer, StyledPagerSizeOptions, StyledPagerSizeOptionsInner, StyledPagerNavigation, StyledPagerNavInner, StyledPagerNavLabel, StyledPagerLink, StyledPagerNoSelect, StyledPagerSummary, StyledSelectContainer, };
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.StyledSelectContainer = exports.StyledPagerSummary = exports.StyledPagerNoSelect = exports.StyledPagerLink = exports.StyledPagerNavInner = exports.StyledPagerNavigation = exports.StyledPagerSizeOptionsInner = exports.StyledPagerSizeOptions = exports.StyledPagerContainer = void 0;
6
+ exports.StyledSelectContainer = exports.StyledPagerSummary = exports.StyledPagerNoSelect = exports.StyledPagerLink = exports.StyledPagerNavLabel = exports.StyledPagerNavInner = exports.StyledPagerNavigation = exports.StyledPagerSizeOptionsInner = exports.StyledPagerSizeOptions = exports.StyledPagerContainer = void 0;
7
7
 
8
8
  var _styledComponents = _interopRequireWildcard(require("styled-components"));
9
9
 
@@ -121,6 +121,12 @@ const StyledPagerNavInner = _styledComponents.default.div`
121
121
  }
122
122
  `;
123
123
  exports.StyledPagerNavInner = StyledPagerNavInner;
124
+ const StyledPagerNavLabel = _styledComponents.default.label`
125
+ white-space: nowrap;
126
+ padding: 9px 12px;
127
+ margin: 4px 0;
128
+ `;
129
+ exports.StyledPagerNavLabel = StyledPagerNavLabel;
124
130
  const StyledPagerLink = (0, _styledComponents.default)(_link.default)`
125
131
  padding: 0 10px;
126
132
  margin-left: 7px;
@@ -234,6 +234,9 @@ const tabTitleStyles = (0, _styledComponents.css)`
234
234
  text-decoration: none;
235
235
  outline-offset: 0px;
236
236
  margin: 0;
237
+ ${({
238
+ position
239
+ }) => position === "top" && "white-space: nowrap"};
237
240
 
238
241
  a:visited {
239
242
  color: inherit;
@@ -4,10 +4,9 @@ export interface TabHeaderProps {
4
4
  position?: "top" | "left";
5
5
  extendedLine?: boolean;
6
6
  noRightBorder?: boolean;
7
- alternateStyling?: boolean;
8
7
  isInSidebar?: boolean;
9
8
  children: React.ReactNode;
10
9
  align?: "left" | "right";
11
10
  }
12
- declare const TabsHeader: ({ align, children, position, role, extendedLine, alternateStyling, noRightBorder, isInSidebar, }: TabHeaderProps) => JSX.Element;
11
+ declare const TabsHeader: ({ align, children, position, role, extendedLine, noRightBorder, isInSidebar, }: TabHeaderProps) => JSX.Element;
13
12
  export default TabsHeader;
@@ -5,24 +5,64 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
 
8
- var _react = _interopRequireDefault(require("react"));
8
+ var _react = _interopRequireWildcard(require("react"));
9
9
 
10
10
  var _propTypes = _interopRequireDefault(require("prop-types"));
11
11
 
12
12
  var _tabsHeader = require("./tabs-header.style");
13
13
 
14
+ var _useThrottle = _interopRequireDefault(require("../../../../hooks/__internal__/useThrottle"));
15
+
14
16
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
17
 
18
+ function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
19
+
20
+ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (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
+ /* In the original prototype the tabs have shadows that fade out as you scroll horizontally.
23
+ * This value is the closest replication to the way that the shadow disappears.
24
+ * It is ultimately tied to the position of the scroll that will then fade the shadow in and out. */
25
+ const fullOpacityThreshold = 128;
26
+
27
+ const getOpacityRatio = value => value / fullOpacityThreshold;
28
+
29
+ const getScrollRight = ({
30
+ scrollWidth,
31
+ clientWidth,
32
+ scrollLeft
33
+ }) => scrollWidth - clientWidth - scrollLeft;
34
+
16
35
  const TabsHeader = ({
17
36
  align = "left",
18
37
  children,
19
38
  position = "top",
20
39
  role,
21
40
  extendedLine,
22
- alternateStyling,
23
41
  noRightBorder = false,
24
42
  isInSidebar = false
25
43
  }) => {
44
+ const [leftScrollOpacity, setLeftScrollOpacity] = (0, _react.useState)(0);
45
+ const [rightScrollOpacity, setRightScrollOpacity] = (0, _react.useState)(1);
46
+ const ref = (0, _react.useRef)(null);
47
+ let isScrollable = false;
48
+ const {
49
+ current
50
+ } = ref;
51
+
52
+ if (position === "top" && current) {
53
+ isScrollable = current.scrollWidth > current.clientWidth;
54
+ }
55
+
56
+ const handleScroll = e => {
57
+ const {
58
+ scrollLeft
59
+ } = e.target;
60
+ const scrollRight = getScrollRight(e.target);
61
+ setLeftScrollOpacity(Math.min(getOpacityRatio(scrollLeft), 1));
62
+ setRightScrollOpacity(Math.min(getOpacityRatio(scrollRight), 1));
63
+ };
64
+
65
+ const throttledHandleScroll = (0, _useThrottle.default)(handleScroll, 50);
26
66
  return /*#__PURE__*/_react.default.createElement(_tabsHeader.StyledTabsHeaderWrapper, {
27
67
  isInSidebar: isInSidebar,
28
68
  position: position
@@ -31,15 +71,18 @@ const TabsHeader = ({
31
71
  position: position,
32
72
  role: role,
33
73
  extendedLine: extendedLine,
34
- alternateStyling: alternateStyling,
35
74
  noRightBorder: noRightBorder,
36
- isInSidebar: isInSidebar
37
- }, children));
75
+ isInSidebar: isInSidebar,
76
+ onScroll: throttledHandleScroll,
77
+ leftScrollOpacity: leftScrollOpacity,
78
+ rightScrollOpacity: rightScrollOpacity,
79
+ isScrollable: isScrollable,
80
+ ref: ref
81
+ }, position === "top" ? /*#__PURE__*/_react.default.createElement(_tabsHeader.StyledTabsWrapper, null, /*#__PURE__*/_react.default.createElement(_tabsHeader.StyledTabsBottomBorderWrapper, null, /*#__PURE__*/_react.default.createElement(_tabsHeader.StyledTabsBottomBorder, null)), children) : children));
38
82
  };
39
83
 
40
84
  TabsHeader.propTypes = {
41
85
  "align": _propTypes.default.oneOf(["left", "right"]),
42
- "alternateStyling": _propTypes.default.bool,
43
86
  "children": _propTypes.default.node,
44
87
  "extendedLine": _propTypes.default.bool,
45
88
  "isInSidebar": _propTypes.default.bool,
@@ -1,6 +1,13 @@
1
1
  import { TabHeaderProps } from "./tabs-header.component";
2
2
  declare type StyledTabsHeaderWrapperProps = Pick<TabHeaderProps, "position" | "isInSidebar">;
3
3
  declare const StyledTabsHeaderWrapper: import("styled-components").StyledComponent<"div", any, StyledTabsHeaderWrapperProps, never>;
4
- export declare type StyledTabsHeaderListProps = Pick<TabHeaderProps, "align" | "alternateStyling" | "extendedLine" | "noRightBorder" | "isInSidebar" | "position">;
4
+ export interface StyledTabsHeaderListProps extends Pick<TabHeaderProps, "align" | "extendedLine" | "noRightBorder" | "isInSidebar" | "position"> {
5
+ leftScrollOpacity?: number;
6
+ rightScrollOpacity?: number;
7
+ isScrollable?: boolean;
8
+ }
5
9
  declare const StyledTabsHeaderList: import("styled-components").StyledComponent<"div", any, StyledTabsHeaderListProps, never>;
6
- export { StyledTabsHeaderWrapper, StyledTabsHeaderList };
10
+ declare const StyledTabsWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
11
+ declare const StyledTabsBottomBorderWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
12
+ declare const StyledTabsBottomBorder: import("styled-components").StyledComponent<"div", any, {}, never>;
13
+ export { StyledTabsHeaderWrapper, StyledTabsHeaderList, StyledTabsWrapper, StyledTabsBottomBorderWrapper, StyledTabsBottomBorder, };
@@ -3,26 +3,19 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.StyledTabsHeaderList = exports.StyledTabsHeaderWrapper = void 0;
6
+ exports.StyledTabsBottomBorder = exports.StyledTabsBottomBorderWrapper = exports.StyledTabsWrapper = exports.StyledTabsHeaderList = exports.StyledTabsHeaderWrapper = void 0;
7
7
 
8
8
  var _styledComponents = _interopRequireWildcard(require("styled-components"));
9
9
 
10
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
10
+ var _base = _interopRequireDefault(require("../../../../style/themes/base"));
11
11
 
12
- function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (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; }
12
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
13
 
14
- const computeLineWidth = ({
15
- alternateStyling,
16
- isInSidebar,
17
- position
18
- }) => {
19
- if (isInSidebar && position === "left") {
20
- return "0px";
21
- }
14
+ function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
22
15
 
23
- return alternateStyling ? "-1px" : "-2px";
24
- };
16
+ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (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; }
25
17
 
18
+ const outlineWidth = "3px";
26
19
  const StyledTabsHeaderWrapper = _styledComponents.default.div`
27
20
  ${({
28
21
  position,
@@ -44,9 +37,21 @@ const StyledTabsHeaderWrapper = _styledComponents.default.div`
44
37
  `}
45
38
  `;
46
39
  exports.StyledTabsHeaderWrapper = StyledTabsHeaderWrapper;
40
+ const commonShadowStyles = (0, _styledComponents.css)`
41
+ pointer-events: none;
42
+ content: "";
43
+ background-repeat: no-repeat;
44
+ background-size: 16px 48px;
45
+ background-attachment: scroll;
46
+ z-index: ${({
47
+ theme
48
+ }) => theme.zIndex.overlay};
49
+ position: sticky;
50
+ min-width: 16px;
51
+ transition: opacity 0.1s ease-in-out;
52
+ `;
47
53
  const StyledTabsHeaderList = _styledComponents.default.div`
48
54
  display: flex;
49
- box-shadow: inset 0px ${computeLineWidth} 0px 0px var(--colorsActionMinor100);
50
55
  ${({
51
56
  extendedLine = true
52
57
  }) => !extendedLine && (0, _styledComponents.css)`
@@ -54,8 +59,57 @@ const StyledTabsHeaderList = _styledComponents.default.div`
54
59
  `}
55
60
  cursor: default;
56
61
  list-style: none;
57
- margin: 0;
58
- padding: 0;
62
+ margin: -${outlineWidth};
63
+ padding: ${outlineWidth};
64
+ overflow-x: auto;
65
+ position: relative;
66
+ ${({
67
+ position
68
+ }) => position === "top" && "white-space: nowrap"};
69
+
70
+ ${({
71
+ isScrollable,
72
+ leftScrollOpacity,
73
+ rightScrollOpacity
74
+ }) => isScrollable && (0, _styledComponents.css)`
75
+ &:before {
76
+ ${commonShadowStyles}
77
+ background: radial-gradient(
78
+ farthest-side at 0 50%,
79
+ rgba(0, 0, 0, 0.2),
80
+ rgba(0, 0, 0, 0)
81
+ );
82
+ background-position: left calc(50% - 4px);
83
+ left: -${outlineWidth};
84
+ margin-right: -16px;
85
+ opacity: ${leftScrollOpacity};
86
+ }
87
+
88
+ &:after {
89
+ ${commonShadowStyles}
90
+ background: radial-gradient(
91
+ farthest-side at 100% 50%,
92
+ rgba(0, 0, 0, 0.2),
93
+ rgba(0, 0, 0, 0)
94
+ );
95
+ background-position: right calc(50% - 4px);
96
+ right: -${outlineWidth};
97
+ margin-left: -16px;
98
+ opacity: ${rightScrollOpacity};
99
+ }
100
+ `}
101
+
102
+ &::-webkit-scrollbar {
103
+ -webkit-appearance: none;
104
+ background: var(--colorsUtilityMajor025);
105
+ height: 8px;
106
+ width: 8px;
107
+ }
108
+
109
+ &::-webkit-scrollbar-thumb {
110
+ background-color: var(--colorsUtilityMajor300);
111
+ cursor: pointer;
112
+ }
59
113
 
60
114
  ${({
61
115
  align = "left"
@@ -81,4 +135,30 @@ const StyledTabsHeaderList = _styledComponents.default.div`
81
135
  `}
82
136
  `}
83
137
  `;
84
- exports.StyledTabsHeaderList = StyledTabsHeaderList;
138
+ exports.StyledTabsHeaderList = StyledTabsHeaderList;
139
+ StyledTabsHeaderList.defaultProps = {
140
+ theme: _base.default
141
+ };
142
+ const StyledTabsWrapper = _styledComponents.default.div`
143
+ position: relative;
144
+ min-width: max-content;
145
+ width: 100%;
146
+ height: 100%;
147
+ `;
148
+ exports.StyledTabsWrapper = StyledTabsWrapper;
149
+ const StyledTabsBottomBorderWrapper = _styledComponents.default.div`
150
+ position: absolute;
151
+ width: 100%;
152
+ height: auto;
153
+ bottom: 0;
154
+ `;
155
+ exports.StyledTabsBottomBorderWrapper = StyledTabsBottomBorderWrapper;
156
+ const StyledTabsBottomBorder = _styledComponents.default.div`
157
+ position: sticky;
158
+ bottom: 2px;
159
+ left: ${outlineWidth};
160
+ right: ${outlineWidth};
161
+ height: 2px;
162
+ background-color: var(--colorsActionMinor100);
163
+ `;
164
+ exports.StyledTabsBottomBorder = StyledTabsBottomBorder;
@@ -72,7 +72,6 @@ const Tabs = ({
72
72
  }).map(() => /*#__PURE__*/(0, _react.createRef)()), [filteredChildren.length]);
73
73
  const previousSelectedTabId = (0, _react.useRef)(selectedTabId);
74
74
  const [selectedTabIdState, setSelectedTabIdState] = (0, _react.useState)(selectedTabId || filteredChildren[0].props.tabId);
75
- const [tabStopId, setTabStopId] = (0, _react.useState)();
76
75
  const {
77
76
  isInSidebar
78
77
  } = (0, _react.useContext)(_drawer.DrawerSidebarContext);
@@ -97,7 +96,6 @@ const Tabs = ({
97
96
  /** Returns true/false for if the given tab id is selected. */
98
97
 
99
98
  const isTabSelected = (0, _react.useCallback)(tabId => tabId === selectedTabIdState, [selectedTabIdState]);
100
- const hasTabStop = (0, _react.useCallback)(tabId => tabId === tabStopId, [tabStopId]);
101
99
  /** Updates the currently visible tab */
102
100
 
103
101
  const updateVisibleTab = (0, _react.useCallback)(tabid => {
@@ -105,14 +103,10 @@ const Tabs = ({
105
103
  setSelectedTabIdState(tabid);
106
104
  }
107
105
 
108
- if (!hasTabStop(tabid)) {
109
- setTabStopId(tabid);
110
- }
111
-
112
106
  if (onTabChange) {
113
107
  onTabChange(tabid);
114
108
  }
115
- }, [onTabChange, isTabSelected, hasTabStop]);
109
+ }, [onTabChange, isTabSelected]);
116
110
  const blurPreviousSelectedTab = (0, _react.useCallback)(() => {
117
111
  const {
118
112
  current
@@ -172,9 +166,7 @@ const Tabs = ({
172
166
  newIndex = 0;
173
167
  }
174
168
 
175
- const nextTabId = tabIds[newIndex];
176
169
  const nextRef = tabRefs[newIndex];
177
- updateVisibleTab(nextTabId);
178
170
  focusTab(nextRef);
179
171
  };
180
172
  /** Handles the keyboard navigation of tabs */
@@ -254,7 +246,7 @@ const Tabs = ({
254
246
  onClick: handleTabClick,
255
247
  onKeyDown: handleKeyDown(index),
256
248
  ref: tabRefs[index],
257
- tabIndex: isTabSelected(tabId) || hasTabStop(tabId) ? 0 : -1,
249
+ tabIndex: isTabSelected(tabId) ? 0 : -1,
258
250
  title: title,
259
251
  href: href,
260
252
  isTabSelected: isTabSelected(tabId),
@@ -281,7 +273,6 @@ const Tabs = ({
281
273
  position: isInSidebar ? "left" : position,
282
274
  role: "tablist",
283
275
  extendedLine: extendedLine,
284
- alternateStyling: variant === "alternate" || isInSidebar,
285
276
  noRightBorder: ["no right side", "no sides"].includes(borders),
286
277
  isInSidebar: isInSidebar
287
278
  }, tabTitles);
@@ -0,0 +1 @@
1
+ export { default } from "./useThrottle";
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "default", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _useThrottle.default;
10
+ }
11
+ });
12
+
13
+ var _useThrottle = _interopRequireDefault(require("./useThrottle"));
14
+
15
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -0,0 +1,6 @@
1
+ {
2
+ "sideEffects": false,
3
+ "module": "../../../../esm/hooks/__internal__/useThrottle/index.js",
4
+ "main": "./index.js",
5
+ "types": "./index.d.ts"
6
+ }
@@ -0,0 +1,4 @@
1
+ import { DebouncedFunc } from "lodash";
2
+ declare type Callback = (...args: any[]) => void;
3
+ declare const useThrottle: <T extends Callback>(callback: T, delay: number) => DebouncedFunc<T>;
4
+ export default useThrottle;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _react = require("react");
9
+
10
+ var _throttle = _interopRequireDefault(require("lodash/throttle"));
11
+
12
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
+
14
+ const useThrottle = (callback, delay) => {
15
+ const callbackRef = (0, _react.useRef)(callback);
16
+ (0, _react.useEffect)(() => {
17
+ callbackRef.current = callback;
18
+ });
19
+ const throttledCallback = (0, _react.useMemo)(() => (0, _throttle.default)(callbackRef.current, delay), [delay]);
20
+ (0, _react.useEffect)(() => {
21
+ return () => {
22
+ throttledCallback.cancel();
23
+ };
24
+ });
25
+ return throttledCallback;
26
+ };
27
+
28
+ var _default = useThrottle;
29
+ exports.default = _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "carbon-react",
3
- "version": "117.2.2",
3
+ "version": "117.4.0",
4
4
  "description": "A library of reusable React components for easily building user interfaces.",
5
5
  "files": [
6
6
  "lib",