@orangesk/orange-design-system 2.0.0-beta.45 → 2.0.0-beta.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/components/Breadcrumbs/style.css +1 -1
- package/build/components/Breadcrumbs/style.css.map +1 -1
- package/build/components/Carousel/style.css +1 -1
- package/build/components/Carousel/style.css.map +1 -1
- package/build/components/Footer/style.css +1 -1
- package/build/components/Footer/style.css.map +1 -1
- package/build/components/Grid/style.css +1 -1
- package/build/components/Grid/style.css.map +1 -1
- package/build/components/Link/style.css +1 -1
- package/build/components/Link/style.css.map +1 -1
- package/build/components/Megamenu/style.css +1 -1
- package/build/components/Megamenu/style.css.map +1 -1
- package/build/components/Stepbar/style.css +1 -1
- package/build/components/Stepbar/style.css.map +1 -1
- package/build/components/Tabs/style.css +1 -1
- package/build/components/Tabs/style.css.map +1 -1
- package/build/components/index.js +1 -1
- package/build/components/index.js.map +1 -1
- package/build/components/tsconfig.tsbuildinfo +1 -1
- package/build/components/types/index.d.ts +1 -4
- package/build/components/types/src/components/CarouselHero/CarouselHero.d.ts +1 -0
- package/build/components/types/src/components/Preview/CodeExample.d.ts +1 -0
- package/build/components/types/src/components/Preview/PreviewGenerator.d.ts +1 -0
- package/build/components/types/src/components/Preview/getElementDisplayName.d.ts +1 -0
- package/build/components/types/src/components/Tabs/Tabs.d.ts +0 -4
- package/build/components/types/src/components/Tabs/Tabs.static.d.ts +12 -0
- package/build/lib/base.css +1 -1
- package/build/lib/base.css.map +1 -1
- package/build/lib/components.css +1 -1
- package/build/lib/components.css.map +1 -1
- package/build/lib/footer.css +1 -1
- package/build/lib/footer.css.map +1 -1
- package/build/lib/megamenu.css +1 -1
- package/build/lib/megamenu.css.map +1 -1
- package/build/lib/scripts.js +1 -1
- package/build/lib/scripts.js.map +1 -1
- package/build/lib/style.css +1 -1
- package/build/lib/style.css.map +1 -1
- package/build/lib/utilities.css +1 -1
- package/build/lib/utilities.css.map +1 -1
- package/build/search-index.json +5 -5
- package/package.json +18 -18
- package/src/components/Breadcrumbs/styles/mixins.scss +14 -3
- package/src/components/Carousel/styles/mixins.scss +22 -2
- package/src/components/CarouselHero/CarouselHero.tsx +20 -6
- package/src/components/CarouselHero/tests/CarouselHero.conformance.test.jsx +2 -0
- package/src/components/CarouselHero/tests/CarouselHero.unit.test.jsx +78 -9
- package/src/components/Footer/styles/mixins.scss +2 -1
- package/src/components/Forms/Checkbox/styles/style.scss +13 -6
- package/src/components/Forms/InputStepper/InputStepper.tsx +2 -0
- package/src/components/Forms/InputStepper/styles/style.scss +25 -8
- package/src/components/Forms/InputStepper/tests/InputStepper.unit.test.jsx +8 -0
- package/src/components/Link/styles/mixins.scss +0 -1
- package/src/components/Megamenu/Megamenu.tsx +2 -2
- package/src/components/Megamenu/MegamenuBlog.tsx +2 -2
- package/src/components/Megamenu/styles/mixins.scss +20 -12
- package/src/components/Preview/CodeExample.tsx +66 -25
- package/src/components/Preview/Preview.tsx +26 -13
- package/src/components/Preview/PreviewGenerator.tsx +57 -32
- package/src/components/Preview/getElementDisplayName.ts +25 -0
- package/src/components/Stepbar/styles/config.scss +34 -17
- package/src/components/Stepbar/styles/mixins.scss +5 -3
- package/src/components/Tabs/Tabs.static.ts +157 -30
- package/src/components/Tabs/Tabs.tsx +62 -67
- package/src/components/Tabs/styles/config.scss +18 -25
- package/src/components/Tabs/styles/mixins.scss +93 -28
- package/src/components/Tabs/styles/style.scss +4 -15
- package/src/components/Tabs/tests/Tabs.unit.test.jsx +111 -0
- package/src/styles/base/globals.scss +2 -0
- package/src/styles/shame.scss +16 -3
- package/src/styles/tools/convert.scss +8 -0
- package/src/styles/utilities/horizontal-scroll.scss +7 -2
- package/src/styles/utilities/text.scss +0 -1
|
@@ -8,10 +8,6 @@ import { Tab } from "./Tab";
|
|
|
8
8
|
import type { TabPanelProps } from "./TabPanel";
|
|
9
9
|
import TabsStatic from "./Tabs.static";
|
|
10
10
|
|
|
11
|
-
export const variants = ["standard", "light"] as const;
|
|
12
|
-
|
|
13
|
-
export type TabsVariant = (typeof variants)[number];
|
|
14
|
-
|
|
15
11
|
interface TabsProps extends React.HTMLAttributes<HTMLUListElement> {
|
|
16
12
|
/** Active Tab index */
|
|
17
13
|
activeTabIndex?: number;
|
|
@@ -23,8 +19,6 @@ interface TabsProps extends React.HTMLAttributes<HTMLUListElement> {
|
|
|
23
19
|
isFullWidth?: boolean;
|
|
24
20
|
/** Tabs behave as links rather than tabs */
|
|
25
21
|
isLink?: boolean;
|
|
26
|
-
/** Visual variant of the tabs */
|
|
27
|
-
variant?: TabsVariant;
|
|
28
22
|
/** Tab panels as children */
|
|
29
23
|
children: React.ReactElement<TabPanelProps>[];
|
|
30
24
|
}
|
|
@@ -36,7 +30,6 @@ const Tabs: React.FC<TabsProps> = ({
|
|
|
36
30
|
isFullWidth,
|
|
37
31
|
isLink,
|
|
38
32
|
hasEqualTabWidth,
|
|
39
|
-
variant = "standard",
|
|
40
33
|
children,
|
|
41
34
|
...other
|
|
42
35
|
}) => {
|
|
@@ -46,80 +39,82 @@ const Tabs: React.FC<TabsProps> = ({
|
|
|
46
39
|
CLASS_TABNAV,
|
|
47
40
|
{ [`${CLASS_TABNAV}--equal`]: hasEqualTabWidth },
|
|
48
41
|
{ [`${CLASS_TABNAV}--fullwidth`]: isFullWidth },
|
|
49
|
-
{ [`${CLASS_TABNAV}--light`]: variant === "light" },
|
|
50
42
|
classesTabNav,
|
|
51
43
|
className,
|
|
52
44
|
);
|
|
53
45
|
|
|
54
46
|
const [tabListRef] = useStatic(TabsStatic);
|
|
55
47
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const isActive = i === activeTabIndex;
|
|
61
|
-
const props = tabPanel.props || {};
|
|
62
|
-
const {
|
|
63
|
-
renderTab = undefined,
|
|
64
|
-
id,
|
|
65
|
-
isDisabled,
|
|
66
|
-
tab,
|
|
67
|
-
href,
|
|
68
|
-
} = props as TabPanelProps;
|
|
69
|
-
|
|
70
|
-
// Generate ID if not provided
|
|
71
|
-
const tabId = id || `tab-${i}`;
|
|
72
|
-
|
|
73
|
-
if (!renderTab) {
|
|
74
|
-
return (
|
|
75
|
-
<Tab
|
|
76
|
-
key={tabId}
|
|
77
|
-
controls={!href ? tabId : ""}
|
|
78
|
-
href={href}
|
|
79
|
-
isDisabled={isDisabled}
|
|
80
|
-
isActive={isActive}
|
|
81
|
-
>
|
|
82
|
-
{tab}
|
|
83
|
-
</Tab>
|
|
84
|
-
);
|
|
85
|
-
}
|
|
48
|
+
const tabPanels = React.Children.toArray(children).filter(
|
|
49
|
+
(tabPanel): tabPanel is React.ReactElement<TabPanelProps> =>
|
|
50
|
+
React.isValidElement(tabPanel),
|
|
51
|
+
);
|
|
86
52
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
53
|
+
function getTabs() {
|
|
54
|
+
return tabPanels.map((tabPanel, i) => {
|
|
55
|
+
const isActive = i === activeTabIndex;
|
|
56
|
+
const props = tabPanel.props || {};
|
|
57
|
+
const {
|
|
58
|
+
renderTab = undefined,
|
|
59
|
+
id,
|
|
60
|
+
isDisabled,
|
|
61
|
+
tab,
|
|
62
|
+
href,
|
|
63
|
+
} = props as TabPanelProps;
|
|
64
|
+
|
|
65
|
+
// Generate ID if not provided
|
|
66
|
+
const tabId = id || `tab-${i}`;
|
|
67
|
+
|
|
68
|
+
if (!renderTab) {
|
|
69
|
+
return (
|
|
70
|
+
<Tab
|
|
71
|
+
key={tabId}
|
|
72
|
+
controls={!href ? tabId : ""}
|
|
73
|
+
href={href}
|
|
74
|
+
isDisabled={isDisabled}
|
|
75
|
+
isActive={isActive}
|
|
76
|
+
>
|
|
77
|
+
{tab}
|
|
78
|
+
</Tab>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const renderedTab = renderTab(props as TabPanelProps);
|
|
83
|
+
return React.cloneElement(renderedTab, {
|
|
84
|
+
key: tabId,
|
|
85
|
+
isActive,
|
|
86
|
+
} as React.HTMLAttributes<HTMLElement>);
|
|
87
|
+
});
|
|
93
88
|
}
|
|
94
89
|
|
|
95
90
|
function getPanels() {
|
|
96
|
-
return
|
|
97
|
-
|
|
98
|
-
.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
} as Partial<TabPanelProps>);
|
|
108
|
-
});
|
|
91
|
+
return tabPanels.map((tabPanel, i) => {
|
|
92
|
+
const isActive = i === activeTabIndex;
|
|
93
|
+
const props = tabPanel.props || {};
|
|
94
|
+
const { id } = props;
|
|
95
|
+
const tabId = id || `tab-${i}`;
|
|
96
|
+
return React.cloneElement(tabPanel, {
|
|
97
|
+
key: tabId,
|
|
98
|
+
isActive,
|
|
99
|
+
tab: undefined,
|
|
100
|
+
} as Partial<TabPanelProps>);
|
|
101
|
+
});
|
|
109
102
|
}
|
|
110
103
|
|
|
111
104
|
return (
|
|
112
105
|
<>
|
|
113
|
-
<
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
106
|
+
<div className="tab-list__viewport">
|
|
107
|
+
<ul
|
|
108
|
+
className={tabNavClasses}
|
|
109
|
+
role={isLink ? "navigation" : "tablist"}
|
|
110
|
+
ref={tabListRef}
|
|
111
|
+
data-tabs={isLink ? undefined : "true"}
|
|
112
|
+
{...other}
|
|
113
|
+
>
|
|
114
|
+
{getTabs()}
|
|
115
|
+
{isFullWidth && <li role="presentation" className="tab-list__hr" />}
|
|
116
|
+
</ul>
|
|
117
|
+
</div>
|
|
123
118
|
{!isLink ? getPanels() : null}
|
|
124
119
|
</>
|
|
125
120
|
);
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
@use "../../../styles/tokens/base";
|
|
1
2
|
@use "../../../styles/tokens/space";
|
|
2
3
|
@use "../../../styles/tools/convert";
|
|
3
4
|
|
|
4
5
|
$outline-width: convert.to-rem(2px);
|
|
5
|
-
$
|
|
6
|
+
$focusring-space: convert.to-rem(
|
|
7
|
+
base.$focusring-width + base.$focusring-offset
|
|
8
|
+
);
|
|
9
|
+
$negative-outline-width: $focusring-space * -1;
|
|
6
10
|
|
|
7
11
|
$tablist-spacing: (
|
|
8
12
|
margin: $negative-outline-width $negative-outline-width
|
|
@@ -10,50 +14,39 @@ $tablist-spacing: (
|
|
|
10
14
|
space.get() + $negative-outline-width,
|
|
11
15
|
)
|
|
12
16
|
$negative-outline-width,
|
|
13
|
-
padding: $
|
|
17
|
+
padding: $focusring-space,
|
|
14
18
|
);
|
|
15
19
|
|
|
16
20
|
$tab: (
|
|
17
21
|
default: (
|
|
18
22
|
color: var(--color-text-default),
|
|
19
|
-
|
|
23
|
+
background-color: transparent,
|
|
24
|
+
box-shadow: inset 0 -1px 0 0 var(--color-surface-moderate),
|
|
20
25
|
),
|
|
21
26
|
active: (
|
|
22
|
-
color: var(--color-text-
|
|
27
|
+
color: var(--color-text-default),
|
|
28
|
+
background-color: var(--color-fill-moderate),
|
|
23
29
|
box-shadow: (
|
|
24
|
-
inset
|
|
25
|
-
inset 0
|
|
26
|
-
inset 2px 0 0 0 var(--color-border-contrast),
|
|
30
|
+
inset 0 4px 0 0 var(--color-border-accent),
|
|
31
|
+
inset 0 -1px 0 0 var(--color-fill-moderate),
|
|
27
32
|
),
|
|
28
33
|
),
|
|
29
34
|
hover: (
|
|
30
35
|
color: var(--color-text-accent),
|
|
36
|
+
background-color: transparent,
|
|
37
|
+
box-shadow: inset 0 -1px 0 0 var(--color-surface-moderate),
|
|
31
38
|
),
|
|
32
39
|
disabled: (
|
|
33
|
-
color: var(--color-
|
|
34
|
-
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
$tab-light: (
|
|
38
|
-
default: (
|
|
39
|
-
box-shadow: none "!important",
|
|
40
|
-
),
|
|
41
|
-
active: (
|
|
42
|
-
box-shadow: inset 0 -4px 0 0 var(--color-border-accent) "!important",
|
|
43
|
-
),
|
|
44
|
-
hover: (
|
|
45
|
-
box-shadow: none "!important",
|
|
46
|
-
),
|
|
47
|
-
disabled: (
|
|
48
|
-
box-shadow: none "!important",
|
|
40
|
+
color: var(--color-text-disabled),
|
|
41
|
+
background-color: transparent,
|
|
49
42
|
),
|
|
50
43
|
);
|
|
51
44
|
|
|
52
45
|
$tab-sizes: (
|
|
53
46
|
default: (
|
|
54
|
-
padding:
|
|
47
|
+
padding: convert.to-rem(15px) convert.to-rem(20px),
|
|
55
48
|
),
|
|
56
49
|
large: (
|
|
57
|
-
padding:
|
|
50
|
+
padding: convert.to-rem(20px),
|
|
58
51
|
),
|
|
59
52
|
);
|
|
@@ -1,10 +1,61 @@
|
|
|
1
1
|
@use "./config";
|
|
2
2
|
@use "../../../styles/tokens/base";
|
|
3
3
|
@use "../../../styles/tokens/space";
|
|
4
|
+
@use "../../../styles/tools/convert";
|
|
4
5
|
@use "../../../styles/tools/generate";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
$tab-focus-radius: convert.to-rem(5px);
|
|
8
|
+
$tab-focusring-space: convert.to-rem(
|
|
9
|
+
base.$focusring-width + base.$focusring-offset
|
|
10
|
+
);
|
|
11
|
+
$tab-overflow-fade-width: convert.to-rem(72px);
|
|
12
|
+
|
|
13
|
+
@mixin list-viewport {
|
|
7
14
|
position: relative;
|
|
15
|
+
overflow: hidden;
|
|
16
|
+
padding: $tab-focusring-space $tab-focusring-space 0;
|
|
17
|
+
|
|
18
|
+
&::before,
|
|
19
|
+
&::after {
|
|
20
|
+
z-index: 2;
|
|
21
|
+
width: $tab-overflow-fade-width;
|
|
22
|
+
content: "";
|
|
23
|
+
position: absolute;
|
|
24
|
+
top: 0;
|
|
25
|
+
height: 100%;
|
|
26
|
+
pointer-events: none;
|
|
27
|
+
opacity: 0;
|
|
28
|
+
transition: opacity 0.2s ease;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
&::before {
|
|
32
|
+
left: 0;
|
|
33
|
+
background: linear-gradient(
|
|
34
|
+
to left,
|
|
35
|
+
transparent 0%,
|
|
36
|
+
var(--color-background-primary) 100%
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&::after {
|
|
41
|
+
right: 0;
|
|
42
|
+
background: linear-gradient(
|
|
43
|
+
to right,
|
|
44
|
+
transparent 0%,
|
|
45
|
+
var(--color-background-primary) 100%
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
&.has-left-overflow::before {
|
|
50
|
+
opacity: 1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
&.has-right-overflow::after {
|
|
54
|
+
opacity: 1;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@mixin list-base($spacing: config.$tablist-spacing) {
|
|
8
59
|
display: flex;
|
|
9
60
|
overflow-x: auto;
|
|
10
61
|
overflow-y: visible;
|
|
@@ -16,6 +67,10 @@
|
|
|
16
67
|
|
|
17
68
|
@mixin list-equal {
|
|
18
69
|
flex-grow: 1;
|
|
70
|
+
|
|
71
|
+
.tab-list__tab {
|
|
72
|
+
text-align: center;
|
|
73
|
+
}
|
|
19
74
|
}
|
|
20
75
|
|
|
21
76
|
@mixin list-item {
|
|
@@ -28,54 +83,68 @@
|
|
|
28
83
|
flex: 1 1 auto;
|
|
29
84
|
display: flex;
|
|
30
85
|
flex-flow: column;
|
|
86
|
+
justify-content: center;
|
|
31
87
|
height: initial;
|
|
32
88
|
position: relative;
|
|
33
|
-
font-weight:
|
|
89
|
+
font-weight: 700;
|
|
34
90
|
background: transparent;
|
|
35
91
|
border-width: 0;
|
|
36
92
|
text-align: left;
|
|
93
|
+
white-space: nowrap;
|
|
94
|
+
cursor: pointer;
|
|
95
|
+
|
|
96
|
+
&::after {
|
|
97
|
+
content: "";
|
|
98
|
+
position: absolute;
|
|
99
|
+
inset: $tab-focusring-space * -1;
|
|
100
|
+
border: base.$focus-outline;
|
|
101
|
+
border-radius: calc(#{$tab-focus-radius} + #{$tab-focusring-space});
|
|
102
|
+
opacity: 0;
|
|
103
|
+
pointer-events: none;
|
|
104
|
+
}
|
|
37
105
|
|
|
38
106
|
&:focus {
|
|
39
107
|
z-index: 1;
|
|
108
|
+
outline-width: 0;
|
|
109
|
+
outline-color: transparent;
|
|
40
110
|
}
|
|
41
111
|
|
|
42
|
-
|
|
43
|
-
|
|
112
|
+
&:focus::after {
|
|
113
|
+
opacity: 1;
|
|
114
|
+
}
|
|
44
115
|
|
|
45
|
-
|
|
46
|
-
|
|
116
|
+
&:focus-visible {
|
|
117
|
+
outline-width: 0;
|
|
118
|
+
outline-color: transparent;
|
|
119
|
+
}
|
|
47
120
|
|
|
48
|
-
|
|
49
|
-
|
|
121
|
+
&:focus-visible::after {
|
|
122
|
+
opacity: 1;
|
|
50
123
|
}
|
|
51
124
|
|
|
52
|
-
&:
|
|
53
|
-
|
|
125
|
+
&:focus:not(:focus-visible)::after {
|
|
126
|
+
opacity: 0;
|
|
54
127
|
}
|
|
55
128
|
|
|
56
|
-
&[aria-
|
|
57
|
-
|
|
129
|
+
&[aria-selected="true"] {
|
|
130
|
+
z-index: 1;
|
|
58
131
|
}
|
|
59
132
|
}
|
|
60
133
|
|
|
61
|
-
@mixin
|
|
62
|
-
@include generate.css-map(config
|
|
63
|
-
|
|
64
|
-
&:hover {
|
|
65
|
-
@include generate.css-map(config.$tab-light, "hover");
|
|
66
|
-
}
|
|
134
|
+
@mixin color-variant($config: config.$tab) {
|
|
135
|
+
@include generate.css-map($config, "default");
|
|
67
136
|
|
|
68
137
|
&[aria-selected="true"] {
|
|
69
|
-
@include generate.css-map(config
|
|
138
|
+
@include generate.css-map($config, "active");
|
|
70
139
|
}
|
|
71
140
|
|
|
72
|
-
|
|
73
|
-
@include generate.css-map(config.$tab
|
|
141
|
+
&:hover:not([aria-selected="true"]):not([aria-disabled="true"]) {
|
|
142
|
+
@include generate.css-map(config.$tab, "hover");
|
|
74
143
|
}
|
|
75
|
-
}
|
|
76
144
|
|
|
77
|
-
|
|
78
|
-
|
|
145
|
+
&[aria-disabled="true"]:not([aria-selected="true"]) {
|
|
146
|
+
@include generate.css-map(config.$tab, "disabled");
|
|
147
|
+
}
|
|
79
148
|
}
|
|
80
149
|
|
|
81
150
|
@mixin tab-size($size, $config: config.$tab-sizes) {
|
|
@@ -85,10 +154,6 @@
|
|
|
85
154
|
@mixin underline {
|
|
86
155
|
flex: 1 1 auto;
|
|
87
156
|
max-width: none;
|
|
88
|
-
box-shadow: inset 0 -2px 0 0 var(--color-border-contrast);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
@mixin underline-light {
|
|
92
157
|
box-shadow: inset 0 -1px 0 0 var(--color-surface-moderate);
|
|
93
158
|
}
|
|
94
159
|
|
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
@use "../../../styles/typography/mixins" as typography;
|
|
6
6
|
|
|
7
7
|
@layer components {
|
|
8
|
+
.tab-list__viewport {
|
|
9
|
+
@include mixins.list-viewport;
|
|
10
|
+
}
|
|
11
|
+
|
|
8
12
|
.tab-list {
|
|
9
13
|
$this: &;
|
|
10
14
|
|
|
@@ -21,10 +25,6 @@
|
|
|
21
25
|
#{$this}--equal & {
|
|
22
26
|
@include mixins.list-equal-item;
|
|
23
27
|
}
|
|
24
|
-
|
|
25
|
-
#{$this}--light & {
|
|
26
|
-
@include mixins.underline-light;
|
|
27
|
-
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
&__tab {
|
|
@@ -36,21 +36,10 @@
|
|
|
36
36
|
@include mixins.tab-size($size);
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
#{$this}--light & {
|
|
40
|
-
@include mixins.tab-light;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
#{$this}--light#{$this}--equal & {
|
|
44
|
-
@include mixins.tab-centered;
|
|
45
|
-
}
|
|
46
39
|
}
|
|
47
40
|
|
|
48
41
|
&__hr {
|
|
49
42
|
@include mixins.underline;
|
|
50
|
-
|
|
51
|
-
#{$this}--light & {
|
|
52
|
-
@include mixins.underline-light;
|
|
53
|
-
}
|
|
54
43
|
}
|
|
55
44
|
}
|
|
56
45
|
}
|
|
@@ -2,6 +2,7 @@ import { fireEvent, render, screen } from "@testing-library/react";
|
|
|
2
2
|
import userEvent from "@testing-library/user-event";
|
|
3
3
|
import { TabPanel } from "../TabPanel";
|
|
4
4
|
import { Tabs } from "../Tabs";
|
|
5
|
+
import TabsStatic from "../Tabs.static";
|
|
5
6
|
|
|
6
7
|
const arr = [1, 2, 3, 4];
|
|
7
8
|
|
|
@@ -98,6 +99,116 @@ describe("rendering Tabs", () => {
|
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
101
|
});
|
|
102
|
+
|
|
103
|
+
it("toggles left and right overflow classes based on scroll position", () => {
|
|
104
|
+
const { getByTestId } = render(<TabsExample />);
|
|
105
|
+
const tabList = getByTestId("test-id");
|
|
106
|
+
const viewport = tabList.parentElement;
|
|
107
|
+
const tabsStatic = TabsStatic.getInstance(tabList);
|
|
108
|
+
|
|
109
|
+
let scrollLeft = 0;
|
|
110
|
+
Object.defineProperty(tabList, "clientWidth", {
|
|
111
|
+
configurable: true,
|
|
112
|
+
value: 200,
|
|
113
|
+
});
|
|
114
|
+
Object.defineProperty(tabList, "scrollWidth", {
|
|
115
|
+
configurable: true,
|
|
116
|
+
value: 500,
|
|
117
|
+
});
|
|
118
|
+
Object.defineProperty(tabList, "scrollLeft", {
|
|
119
|
+
configurable: true,
|
|
120
|
+
get: () => scrollLeft,
|
|
121
|
+
set: (value) => {
|
|
122
|
+
scrollLeft = value;
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
tabsStatic?.update();
|
|
127
|
+
|
|
128
|
+
expect(viewport).not.toHaveClass("has-left-overflow");
|
|
129
|
+
expect(viewport).toHaveClass("has-right-overflow");
|
|
130
|
+
|
|
131
|
+
scrollLeft = 300;
|
|
132
|
+
fireEvent.scroll(tabList);
|
|
133
|
+
|
|
134
|
+
expect(viewport).toHaveClass("has-left-overflow");
|
|
135
|
+
expect(viewport).not.toHaveClass("has-right-overflow");
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("centers clicked active tab inside the scroll container", () => {
|
|
139
|
+
const { getByTestId, container } = render(<TabsExample />);
|
|
140
|
+
const tabList = getByTestId("test-id");
|
|
141
|
+
const secondTab = container.querySelector(
|
|
142
|
+
'button[aria-controls="tabpanel-2"]',
|
|
143
|
+
);
|
|
144
|
+
const scrollToSpy = vi.fn();
|
|
145
|
+
|
|
146
|
+
Object.defineProperty(tabList, "clientWidth", {
|
|
147
|
+
configurable: true,
|
|
148
|
+
value: 200,
|
|
149
|
+
});
|
|
150
|
+
Object.defineProperty(tabList, "scrollWidth", {
|
|
151
|
+
configurable: true,
|
|
152
|
+
value: 600,
|
|
153
|
+
});
|
|
154
|
+
Object.defineProperty(tabList, "scrollLeft", {
|
|
155
|
+
configurable: true,
|
|
156
|
+
value: 180,
|
|
157
|
+
writable: true,
|
|
158
|
+
});
|
|
159
|
+
Object.defineProperty(tabList, "getBoundingClientRect", {
|
|
160
|
+
configurable: true,
|
|
161
|
+
value: () => ({
|
|
162
|
+
top: 0,
|
|
163
|
+
bottom: 0,
|
|
164
|
+
left: 0,
|
|
165
|
+
right: 200,
|
|
166
|
+
width: 200,
|
|
167
|
+
height: 0,
|
|
168
|
+
x: 0,
|
|
169
|
+
y: 0,
|
|
170
|
+
toJSON: () => ({}),
|
|
171
|
+
}),
|
|
172
|
+
});
|
|
173
|
+
Object.defineProperty(secondTab, "getBoundingClientRect", {
|
|
174
|
+
configurable: true,
|
|
175
|
+
value: () => ({
|
|
176
|
+
top: 0,
|
|
177
|
+
bottom: 0,
|
|
178
|
+
left: 40,
|
|
179
|
+
right: 120,
|
|
180
|
+
width: 80,
|
|
181
|
+
height: 0,
|
|
182
|
+
x: 40,
|
|
183
|
+
y: 0,
|
|
184
|
+
toJSON: () => ({}),
|
|
185
|
+
}),
|
|
186
|
+
});
|
|
187
|
+
tabList.scrollTo = scrollToSpy;
|
|
188
|
+
|
|
189
|
+
fireEvent.click(secondTab);
|
|
190
|
+
|
|
191
|
+
expect(scrollToSpy).toHaveBeenCalledWith({
|
|
192
|
+
left: 160,
|
|
193
|
+
behavior: "smooth",
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("does not center on pointer-style focus before click activation", () => {
|
|
198
|
+
const { getByTestId, container } = render(<TabsExample />);
|
|
199
|
+
const tabList = getByTestId("test-id");
|
|
200
|
+
const secondTab = container.querySelector(
|
|
201
|
+
'button[aria-controls="tabpanel-2"]',
|
|
202
|
+
);
|
|
203
|
+
const scrollToSpy = vi.fn();
|
|
204
|
+
|
|
205
|
+
secondTab.matches = vi.fn((selector) => selector !== ":focus-visible");
|
|
206
|
+
tabList.scrollTo = scrollToSpy;
|
|
207
|
+
|
|
208
|
+
fireEvent.focus(secondTab);
|
|
209
|
+
|
|
210
|
+
expect(scrollToSpy).not.toHaveBeenCalled();
|
|
211
|
+
});
|
|
101
212
|
});
|
|
102
213
|
describe("checking fireEvents", () => {
|
|
103
214
|
it("click in disabled tab button doesnt cause change", () => {
|
package/src/styles/shame.scss
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
@layer utilities {
|
|
2
2
|
/**
|
|
3
|
-
* Resets for megamenu and footer
|
|
4
|
-
* This reset is required due to default list spacing in ods 1 and will be removed once megamenu and footer components are migrated to 1.
|
|
5
|
-
**/
|
|
3
|
+
* Resets for megamenu and footer
|
|
4
|
+
* This reset is required due to default list spacing in ods 1 and will be removed once megamenu and footer components are migrated to 1.
|
|
5
|
+
**/
|
|
6
6
|
.osk-footer-menu,
|
|
7
7
|
.mm-header ul,
|
|
8
8
|
.megamenu-header ul {
|
|
@@ -14,4 +14,17 @@
|
|
|
14
14
|
margin-bottom: 0;
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Fixes for header and megamenu when modal is open
|
|
20
|
+
* This is required to prevent the header and megamenu from shifting when a modal is open due to scrollbar disappearance.
|
|
21
|
+
* This is a temporary fix and will be removed once the header and megamenu components are migrated to ods2
|
|
22
|
+
**/
|
|
23
|
+
body.has-modal {
|
|
24
|
+
.mm-header.is-sticky,
|
|
25
|
+
.megamenu-header.is-sticky,
|
|
26
|
+
[data-megamenu].is-sticky:not(.megamenu) {
|
|
27
|
+
padding-right: var(--ods-modal-scrollbar-width, 0px);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
17
30
|
}
|
|
@@ -3,10 +3,18 @@
|
|
|
3
3
|
@use "../tokens/base";
|
|
4
4
|
|
|
5
5
|
@function to-em($size, $font-size: base.$font-size) {
|
|
6
|
+
@if $size == 0 {
|
|
7
|
+
@return 0;
|
|
8
|
+
}
|
|
9
|
+
|
|
6
10
|
@return math.div($size, $font-size) * 1em;
|
|
7
11
|
}
|
|
8
12
|
|
|
9
13
|
@function to-rem($size, $base: base.$font-size) {
|
|
14
|
+
@if $size == 0 {
|
|
15
|
+
@return 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
10
18
|
@return math.div($size, $base) * 1rem;
|
|
11
19
|
}
|
|
12
20
|
|
|
@@ -15,14 +15,16 @@
|
|
|
15
15
|
|
|
16
16
|
@supports selector(::-webkit-scrollbar) {
|
|
17
17
|
&::-webkit-scrollbar {
|
|
18
|
-
height: convert.to-rem(
|
|
18
|
+
height: convert.to-rem(8px);
|
|
19
19
|
appearance: none;
|
|
20
|
-
background-color:
|
|
20
|
+
background-color: transparent;
|
|
21
21
|
border-radius: 99px;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
&::-webkit-scrollbar-track {
|
|
25
|
+
border: convert.to-rem(1px) solid transparent;
|
|
25
26
|
background-color: var(--color-surface-moderate);
|
|
27
|
+
background-clip: content-box;
|
|
26
28
|
border-radius: 99px;
|
|
27
29
|
}
|
|
28
30
|
|
|
@@ -30,12 +32,15 @@
|
|
|
30
32
|
opacity: 1;
|
|
31
33
|
background-color: var(--color-fill-contrast);
|
|
32
34
|
border-radius: 99px;
|
|
35
|
+
border: convert.to-rem(1px) solid transparent;
|
|
36
|
+
background-clip: content-box;
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
&:hover::-webkit-scrollbar-thumb,
|
|
36
40
|
&:active::-webkit-scrollbar-thumb,
|
|
37
41
|
&::-webkit-scrollbar-thumb:hover,
|
|
38
42
|
&::-webkit-scrollbar-thumb:active {
|
|
43
|
+
border-width: 0;
|
|
39
44
|
background-color: var(--color-fill-secondary) !important;
|
|
40
45
|
}
|
|
41
46
|
}
|