@sproutsocial/seeds-react-tabs 1.3.10 → 1.4.11
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/.turbo/turbo-build.log +10 -10
- package/CHANGELOG.md +105 -0
- package/dist/esm/index.js +169 -31
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.mts +18 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.js +168 -30
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/Tabs.stories.tsx +56 -0
- package/src/Tabs.tsx +110 -10
- package/src/TabsTypes.ts +9 -0
- package/src/__tests__/tabs.test.tsx +205 -14
- package/src/styles.ts +59 -10
package/.turbo/turbo-build.log
CHANGED
|
@@ -8,14 +8,14 @@ $ tsup --dts
|
|
|
8
8
|
[34mCLI[39m Cleaning output folder
|
|
9
9
|
[34mCJS[39m Build start
|
|
10
10
|
[34mESM[39m Build start
|
|
11
|
-
[32mCJS[39m [1mdist/index.js [22m[
|
|
12
|
-
[32mCJS[39m [1mdist/index.js.map [22m[
|
|
13
|
-
[32mCJS[39m ⚡️ Build success in
|
|
14
|
-
[32mESM[39m [1mdist/esm/index.js [22m[
|
|
15
|
-
[32mESM[39m [1mdist/esm/index.js.map [22m[
|
|
16
|
-
[32mESM[39m ⚡️ Build success in
|
|
11
|
+
[32mCJS[39m [1mdist/index.js [22m[32m11.88 KB[39m
|
|
12
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m19.36 KB[39m
|
|
13
|
+
[32mCJS[39m ⚡️ Build success in 75ms
|
|
14
|
+
[32mESM[39m [1mdist/esm/index.js [22m[32m9.89 KB[39m
|
|
15
|
+
[32mESM[39m [1mdist/esm/index.js.map [22m[32m19.31 KB[39m
|
|
16
|
+
[32mESM[39m ⚡️ Build success in 75ms
|
|
17
17
|
[34mDTS[39m Build start
|
|
18
|
-
[32mDTS[39m ⚡️ Build success in
|
|
19
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[
|
|
20
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[
|
|
21
|
-
Done in
|
|
18
|
+
[32mDTS[39m ⚡️ Build success in 4933ms
|
|
19
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m3.38 KB[39m
|
|
20
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m3.38 KB[39m
|
|
21
|
+
Done in 7.10s.
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,110 @@
|
|
|
1
1
|
# @sproutsocial/seeds-react-tabs
|
|
2
2
|
|
|
3
|
+
## 1.4.11
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- @sproutsocial/seeds-react-button@2.2.1
|
|
8
|
+
|
|
9
|
+
## 1.4.10
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [456a20f]
|
|
14
|
+
- Updated dependencies [5892f44]
|
|
15
|
+
- @sproutsocial/seeds-react-button@2.2.0
|
|
16
|
+
- @sproutsocial/seeds-react-system-props@3.1.1
|
|
17
|
+
|
|
18
|
+
## 1.4.9
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- Updated dependencies [5114a32]
|
|
23
|
+
- Updated dependencies [a0fe3d3]
|
|
24
|
+
- @sproutsocial/seeds-react-theme@4.1.0
|
|
25
|
+
- @sproutsocial/seeds-react-button@2.1.3
|
|
26
|
+
|
|
27
|
+
## 1.4.8
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- Updated dependencies [cb27f07]
|
|
32
|
+
- @sproutsocial/seeds-react-button@2.1.2
|
|
33
|
+
|
|
34
|
+
## 1.4.7
|
|
35
|
+
|
|
36
|
+
### Patch Changes
|
|
37
|
+
|
|
38
|
+
- Updated dependencies [40d2dfe]
|
|
39
|
+
- @sproutsocial/seeds-react-button@2.1.1
|
|
40
|
+
|
|
41
|
+
## 1.4.6
|
|
42
|
+
|
|
43
|
+
### Patch Changes
|
|
44
|
+
|
|
45
|
+
- Updated dependencies [132ef9d]
|
|
46
|
+
- Updated dependencies [132ef9d]
|
|
47
|
+
- Updated dependencies [132ef9d]
|
|
48
|
+
- @sproutsocial/seeds-react-button@2.1.0
|
|
49
|
+
- @sproutsocial/seeds-react-theme@4.0.0
|
|
50
|
+
- @sproutsocial/seeds-react-system-props@3.1.0
|
|
51
|
+
|
|
52
|
+
## 1.4.5
|
|
53
|
+
|
|
54
|
+
### Patch Changes
|
|
55
|
+
|
|
56
|
+
- @sproutsocial/seeds-react-button@2.0.8
|
|
57
|
+
|
|
58
|
+
## 1.4.4
|
|
59
|
+
|
|
60
|
+
### Patch Changes
|
|
61
|
+
|
|
62
|
+
- Updated dependencies [47c62b3]
|
|
63
|
+
- @sproutsocial/seeds-react-theme@3.7.1
|
|
64
|
+
- @sproutsocial/seeds-react-button@2.0.7
|
|
65
|
+
|
|
66
|
+
## 1.4.3
|
|
67
|
+
|
|
68
|
+
### Patch Changes
|
|
69
|
+
|
|
70
|
+
- Updated dependencies [06da9c2]
|
|
71
|
+
- @sproutsocial/seeds-react-theme@3.7.0
|
|
72
|
+
- @sproutsocial/seeds-react-button@2.0.6
|
|
73
|
+
|
|
74
|
+
## 1.4.2
|
|
75
|
+
|
|
76
|
+
### Patch Changes
|
|
77
|
+
|
|
78
|
+
- 9c60744: Fix Safari-only tab collapse not addressed by 1.4.1:
|
|
79
|
+
|
|
80
|
+
Inside a flex parent with `overflow: auto/hidden`, Safari resolves the Container's `min-height: min-content` to `0` when the same element also has `overflow-x: auto; overflow-y: hidden`. Tabs would paint once, then collapse to their `border-bottom` (1px). Adds `flex-shrink: 0` on the Container so the tablist preserves its intrinsic height regardless of how Safari handles `min-content` in that combination. Chrome behavior is unchanged.
|
|
81
|
+
|
|
82
|
+
Reported in [BUGS-28687](https://sprout.atlassian.net/browse/BUGS-28687) across every Profiles-by-Network report.
|
|
83
|
+
|
|
84
|
+
## 1.4.1
|
|
85
|
+
|
|
86
|
+
### Patch Changes
|
|
87
|
+
|
|
88
|
+
- 679806a: Fix layout regression introduced in 1.4.0:
|
|
89
|
+
|
|
90
|
+
- **Tabs no longer collapse to a 1px-tall row inside flex-column parents.** Container's `overflow-x: auto; overflow-y: hidden` was triggering the flex `min-height: auto → 0` override, allowing an ancestor `display: flex; flex-direction: column` with a bounded height (e.g. `ContentWithDrillDown`'s `Content.Body`) to shrink the tablist to its border-bottom. Container now sets `min-height: min-content`, restoring the pre-1.4.0 minimum-size behavior without changing scroll semantics.
|
|
91
|
+
|
|
92
|
+
No API changes.
|
|
93
|
+
|
|
94
|
+
## 1.4.0
|
|
95
|
+
|
|
96
|
+
### Minor Changes
|
|
97
|
+
|
|
98
|
+
- 412cc1e: Tabs now scrolls horizontally when the tab list overflows its container, with a fade indicator at each edge that auto-adapts to the parent's background via CSS `mask-image`. Vertical mouse-wheel input is redirected to horizontal scroll (with release-at-ends behavior so page scrolling isn't trapped), and arrow-key and click activation auto-scroll the selected tab into view. Adds an optional `aria-label` prop that's forwarded to the `role="tablist"` element per the WAI-ARIA Authoring Practices Tabs pattern.
|
|
99
|
+
|
|
100
|
+
Spacing change for non-`fullWidth` Tabs: the inter-tab `margin-right` between adjacent tab buttons has been removed in favor of horizontal padding on each tab button. Visual spacing is preserved (each tab now contributes its own breathing room via padding rather than the previous tab pushing it via margin), and clickable hit-areas are slightly larger. The `fullWidth` case is unchanged. Consumers depending on the exact pixel values of the old margin should re-check their layouts.
|
|
101
|
+
|
|
102
|
+
## 1.3.11
|
|
103
|
+
|
|
104
|
+
### Patch Changes
|
|
105
|
+
|
|
106
|
+
- @sproutsocial/seeds-react-button@2.0.5
|
|
107
|
+
|
|
3
108
|
## 1.3.10
|
|
4
109
|
|
|
5
110
|
### Patch Changes
|
package/dist/esm/index.js
CHANGED
|
@@ -12,17 +12,71 @@ import "react";
|
|
|
12
12
|
// src/styles.ts
|
|
13
13
|
var Container = styled.div`
|
|
14
14
|
display: ${(props) => props.fullWidth ? "flex" : "inline-flex"};
|
|
15
|
-
justify-content: space-between;
|
|
16
15
|
margin: 0;
|
|
17
16
|
padding: 0;
|
|
17
|
+
min-width: 0;
|
|
18
|
+
max-width: 100%;
|
|
19
|
+
min-height: min-content;
|
|
20
|
+
flex-shrink: 0;
|
|
21
|
+
overflow-x: auto;
|
|
22
|
+
overflow-y: hidden;
|
|
23
|
+
scrollbar-width: none;
|
|
24
|
+
scroll-padding-inline: 48px;
|
|
25
|
+
scroll-behavior: smooth;
|
|
18
26
|
border-bottom: ${(props) => props.theme.borders[500]}
|
|
19
27
|
${(props) => props.theme.colors.container.border.base};
|
|
20
28
|
|
|
29
|
+
&::-webkit-scrollbar {
|
|
30
|
+
display: none;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&[data-fade-right] {
|
|
34
|
+
-webkit-mask-image: linear-gradient(
|
|
35
|
+
to right,
|
|
36
|
+
black 0,
|
|
37
|
+
black calc(100% - 48px),
|
|
38
|
+
transparent
|
|
39
|
+
);
|
|
40
|
+
mask-image: linear-gradient(
|
|
41
|
+
to right,
|
|
42
|
+
black 0,
|
|
43
|
+
black calc(100% - 48px),
|
|
44
|
+
transparent
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&[data-fade-left] {
|
|
49
|
+
-webkit-mask-image: linear-gradient(
|
|
50
|
+
to right,
|
|
51
|
+
transparent,
|
|
52
|
+
black 48px,
|
|
53
|
+
black 100%
|
|
54
|
+
);
|
|
55
|
+
mask-image: linear-gradient(to right, transparent, black 48px, black 100%);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
&[data-fade-left][data-fade-right] {
|
|
59
|
+
-webkit-mask-image: linear-gradient(
|
|
60
|
+
to right,
|
|
61
|
+
transparent,
|
|
62
|
+
black 48px,
|
|
63
|
+
black calc(100% - 48px),
|
|
64
|
+
transparent
|
|
65
|
+
);
|
|
66
|
+
mask-image: linear-gradient(
|
|
67
|
+
to right,
|
|
68
|
+
transparent,
|
|
69
|
+
black 48px,
|
|
70
|
+
black calc(100% - 48px),
|
|
71
|
+
transparent
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
21
75
|
${COMMON}
|
|
22
76
|
`;
|
|
23
77
|
var TabButton = styled(Button)`
|
|
24
78
|
margin-bottom: -1px;
|
|
25
|
-
padding: ${(props) => `${props.theme.space[350]} 0`};
|
|
79
|
+
padding: ${(props) => `${props.theme.space[350]} ${props.fullWidth ? 0 : props.theme.space[350]}`};
|
|
26
80
|
color: ${(props) => props.theme.colors.text.headline};
|
|
27
81
|
border-radius: 0;
|
|
28
82
|
border-width: 0 0 3px;
|
|
@@ -32,12 +86,6 @@ var TabButton = styled(Button)`
|
|
|
32
86
|
flex-grow: 1;
|
|
33
87
|
`};
|
|
34
88
|
|
|
35
|
-
&:not(:last-child) {
|
|
36
|
-
${(props) => !props.fullWidth && css`
|
|
37
|
-
margin-right: ${(props2) => props2.theme.space[350]};
|
|
38
|
-
`};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
89
|
${(props) => props.isSelected && css`
|
|
42
90
|
color: ${(props2) => props2.theme.colors.link.base};
|
|
43
91
|
border-color: transparent transparent
|
|
@@ -62,7 +110,7 @@ var TabButton = styled(Button)`
|
|
|
62
110
|
var styles_default = Container;
|
|
63
111
|
|
|
64
112
|
// src/Tabs.tsx
|
|
65
|
-
import { jsx } from "react/jsx-runtime";
|
|
113
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
66
114
|
var TabButtonContext = React2.createContext({});
|
|
67
115
|
var TabItemButton = class extends React2.Component {
|
|
68
116
|
static contextType = TabButtonContext;
|
|
@@ -116,8 +164,70 @@ var Tabs = class extends React2.Component {
|
|
|
116
164
|
static Panel = TabPanel;
|
|
117
165
|
buttonRefs = {};
|
|
118
166
|
tabList = [];
|
|
167
|
+
containerRef = React2.createRef();
|
|
168
|
+
startSentinelRef = React2.createRef();
|
|
169
|
+
endSentinelRef = React2.createRef();
|
|
170
|
+
startObserver = null;
|
|
171
|
+
endObserver = null;
|
|
172
|
+
componentDidMount() {
|
|
173
|
+
const container = this.containerRef.current;
|
|
174
|
+
if (!container) return;
|
|
175
|
+
container.addEventListener("wheel", this.handleWheel, { passive: false });
|
|
176
|
+
const startSentinel = this.startSentinelRef.current;
|
|
177
|
+
const endSentinel = this.endSentinelRef.current;
|
|
178
|
+
if (!startSentinel || !endSentinel) return;
|
|
179
|
+
if (typeof IntersectionObserver === "undefined") return;
|
|
180
|
+
this.startObserver = new IntersectionObserver(
|
|
181
|
+
([entry]) => {
|
|
182
|
+
container.toggleAttribute("data-fade-left", !entry?.isIntersecting);
|
|
183
|
+
},
|
|
184
|
+
{ root: container, threshold: 1, rootMargin: "0px 0px 0px 1px" }
|
|
185
|
+
);
|
|
186
|
+
this.endObserver = new IntersectionObserver(
|
|
187
|
+
([entry]) => {
|
|
188
|
+
container.toggleAttribute("data-fade-right", !entry?.isIntersecting);
|
|
189
|
+
},
|
|
190
|
+
{ root: container, threshold: 1, rootMargin: "0px 1px 0px 0px" }
|
|
191
|
+
);
|
|
192
|
+
this.startObserver.observe(startSentinel);
|
|
193
|
+
this.endObserver.observe(endSentinel);
|
|
194
|
+
}
|
|
195
|
+
componentWillUnmount() {
|
|
196
|
+
this.containerRef.current?.removeEventListener("wheel", this.handleWheel);
|
|
197
|
+
this.startObserver?.disconnect();
|
|
198
|
+
this.endObserver?.disconnect();
|
|
199
|
+
this.startObserver = null;
|
|
200
|
+
this.endObserver = null;
|
|
201
|
+
}
|
|
202
|
+
handleWheel = (e) => {
|
|
203
|
+
const container = this.containerRef.current;
|
|
204
|
+
if (!container) return;
|
|
205
|
+
if (e.deltaY === 0 || e.deltaX !== 0) return;
|
|
206
|
+
if (container.scrollWidth <= container.clientWidth) return;
|
|
207
|
+
const atStart = container.scrollLeft <= 0;
|
|
208
|
+
const atEnd = container.scrollLeft + container.clientWidth >= container.scrollWidth;
|
|
209
|
+
if (atEnd && e.deltaY > 0 || atStart && e.deltaY < 0) return;
|
|
210
|
+
e.preventDefault();
|
|
211
|
+
const lineHeight = 16;
|
|
212
|
+
const pixelDelta = e.deltaMode === 1 ? e.deltaY * lineHeight : e.deltaMode === 2 ? e.deltaY * container.clientHeight : e.deltaY;
|
|
213
|
+
container.scrollBy({ left: pixelDelta, behavior: "instant" });
|
|
214
|
+
};
|
|
119
215
|
getSelectedId = () => this.props.selectedId;
|
|
120
|
-
onActivate = (id) =>
|
|
216
|
+
onActivate = (id) => {
|
|
217
|
+
this.props.onSelect(id);
|
|
218
|
+
this.scrollTabIntoView(id);
|
|
219
|
+
};
|
|
220
|
+
scrollTabIntoView = (id) => {
|
|
221
|
+
const button = this.buttonRefs[id]?.current;
|
|
222
|
+
const container = this.containerRef.current;
|
|
223
|
+
if (!button || !container) return;
|
|
224
|
+
const buttonRect = button.getBoundingClientRect();
|
|
225
|
+
const containerRect = container.getBoundingClientRect();
|
|
226
|
+
const fadePadding = 48;
|
|
227
|
+
const isFullyVisible = buttonRect.left >= containerRect.left + fadePadding && buttonRect.right <= containerRect.right - fadePadding;
|
|
228
|
+
if (isFullyVisible) return;
|
|
229
|
+
button.scrollIntoView?.({ block: "nearest", inline: "nearest" });
|
|
230
|
+
};
|
|
121
231
|
onTabMount = (id, ref) => {
|
|
122
232
|
if (!this.tabList.includes(id)) {
|
|
123
233
|
this.tabList.push(id);
|
|
@@ -138,15 +248,16 @@ var Tabs = class extends React2.Component {
|
|
|
138
248
|
}
|
|
139
249
|
};
|
|
140
250
|
selectNextTab = (id) => {
|
|
141
|
-
const buttonRef = this.buttonRefs[id];
|
|
142
251
|
this.props.onSelect(id);
|
|
143
|
-
|
|
252
|
+
this.buttonRefs[id]?.current?.focus?.({ preventScroll: true });
|
|
253
|
+
this.scrollTabIntoView(id);
|
|
144
254
|
};
|
|
145
|
-
keyHandler = (
|
|
146
|
-
switch (keyCode) {
|
|
255
|
+
keyHandler = (e) => {
|
|
256
|
+
switch (e.keyCode) {
|
|
147
257
|
// left arrow
|
|
148
258
|
case 37:
|
|
149
259
|
this.tabList.forEach((id, index) => {
|
|
260
|
+
e.preventDefault();
|
|
150
261
|
if (id === this.getSelectedId()) {
|
|
151
262
|
const count = this.tabList.length;
|
|
152
263
|
const nextIndex = index - 1 >= 0 ? index - 1 : count - 1;
|
|
@@ -158,6 +269,7 @@ var Tabs = class extends React2.Component {
|
|
|
158
269
|
// right arrow
|
|
159
270
|
case 39:
|
|
160
271
|
this.tabList.forEach((id, index) => {
|
|
272
|
+
e.preventDefault();
|
|
161
273
|
if (id === this.getSelectedId()) {
|
|
162
274
|
const count = this.tabList.length;
|
|
163
275
|
const nextIndex = index + 1 < count ? index + 1 : 0;
|
|
@@ -171,30 +283,56 @@ var Tabs = class extends React2.Component {
|
|
|
171
283
|
}
|
|
172
284
|
};
|
|
173
285
|
render() {
|
|
174
|
-
const {
|
|
175
|
-
|
|
286
|
+
const {
|
|
287
|
+
children,
|
|
288
|
+
qa,
|
|
289
|
+
onSelect,
|
|
290
|
+
"aria-label": ariaLabel,
|
|
291
|
+
...rest
|
|
292
|
+
} = this.props;
|
|
293
|
+
return /* @__PURE__ */ jsxs(
|
|
176
294
|
styles_default,
|
|
177
295
|
{
|
|
296
|
+
ref: this.containerRef,
|
|
178
297
|
"data-qa-tabs": "",
|
|
179
|
-
|
|
298
|
+
onKeyDown: this.keyHandler,
|
|
180
299
|
onSelect,
|
|
181
300
|
role: "tablist",
|
|
301
|
+
"aria-label": ariaLabel,
|
|
182
302
|
...qa,
|
|
183
303
|
...rest,
|
|
184
|
-
children:
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
304
|
+
children: [
|
|
305
|
+
/* @__PURE__ */ jsx(
|
|
306
|
+
"div",
|
|
307
|
+
{
|
|
308
|
+
ref: this.startSentinelRef,
|
|
309
|
+
"aria-hidden": "true",
|
|
310
|
+
style: { flexShrink: 0, width: 1 }
|
|
311
|
+
}
|
|
312
|
+
),
|
|
313
|
+
/* @__PURE__ */ jsx(
|
|
314
|
+
TabButtonContext.Provider,
|
|
315
|
+
{
|
|
316
|
+
value: {
|
|
317
|
+
selectedId: this.getSelectedId(),
|
|
318
|
+
fullWidth: this.props.fullWidth,
|
|
319
|
+
onActivate: this.onActivate,
|
|
320
|
+
onTabMount: this.onTabMount,
|
|
321
|
+
onTabUpdate: this.onTabUpdate,
|
|
322
|
+
onTabUnmount: this.onTabUnmount
|
|
323
|
+
},
|
|
324
|
+
children
|
|
325
|
+
}
|
|
326
|
+
),
|
|
327
|
+
/* @__PURE__ */ jsx(
|
|
328
|
+
"div",
|
|
329
|
+
{
|
|
330
|
+
ref: this.endSentinelRef,
|
|
331
|
+
"aria-hidden": "true",
|
|
332
|
+
style: { flexShrink: 0, width: 1 }
|
|
333
|
+
}
|
|
334
|
+
)
|
|
335
|
+
]
|
|
198
336
|
}
|
|
199
337
|
);
|
|
200
338
|
}
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/Tabs.tsx","../../src/styles.ts","../../src/TabsTypes.ts","../../src/index.ts"],"sourcesContent":["import * as React from \"react\";\nimport Container, { TabButton } from \"./styles\";\nimport type {\n TypeTabButtonsProps,\n TypeTabsProps,\n TypeTabPanelProps,\n} from \"./TabsTypes\";\n\ninterface TypeTabButtonRef {\n current: null | React.ElementRef<\"button\">;\n}\ninterface TypeTabButtonContext {\n onActivate: (arg0: string) => void;\n onTabMount: (id: string, ref: TypeTabButtonRef) => void;\n onTabUpdate: (previousId: string, nextId: string) => void;\n onTabUnmount: (id: string) => void;\n selectedId: string;\n fullWidth?: boolean;\n}\n\nconst TabButtonContext = React.createContext<Partial<TypeTabButtonContext>>({});\n\nclass TabItemButton extends React.Component<TypeTabButtonsProps> {\n static override contextType = TabButtonContext;\n // @ts-notes - using the legacy syntax here because `declare` does not play well with babel\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n //@ts-ignore\n context!: React.ContextType<typeof TabButtonContext>;\n\n buttonRef: TypeTabButtonRef = React.createRef<React.ElementRef<\"button\">>();\n\n override componentDidMount() {\n this.context.onTabMount?.(this.props.id, this.buttonRef);\n }\n\n override componentDidUpdate(prevProps: TypeTabButtonsProps) {\n if (prevProps.id !== this.props.id) {\n this.context.onTabUpdate?.(prevProps.id, this.props.id);\n }\n }\n\n override componentWillUnmount() {\n this.context.onTabUnmount?.(this.props.id);\n }\n\n override render() {\n const { children, id, ...rest } = this.props;\n const { selectedId, onActivate, fullWidth } = this.context;\n const isSelected = selectedId === id;\n\n return (\n <TabButton\n key={id}\n innerRef={this.buttonRef}\n id={id}\n onClick={() => onActivate?.(id)}\n isSelected={isSelected}\n tabIndex={isSelected ? 0 : -1}\n fullWidth={fullWidth}\n data-qa-tab-button={id}\n data-qa-tab-button-state={isSelected}\n aria-selected={isSelected}\n role=\"tab\"\n aria-controls={`${id}-panel`}\n {...rest}\n >\n {children}\n </TabButton>\n );\n }\n}\n\nconst TabPanel: React.FC<TypeTabPanelProps> = ({ children, id, ...rest }) => {\n const panelId = `${id}-panel`;\n\n return (\n <div id={panelId} role=\"tabpanel\" aria-labelledby={id} {...rest}>\n {children}\n </div>\n );\n};\n\n/**\n * Render a group of buttons in a tab-heading style\n */\nclass Tabs extends React.Component<TypeTabsProps> {\n static Button = TabItemButton;\n static Panel = TabPanel;\n buttonRefs: Record<string, TypeTabButtonRef | null | undefined> = {};\n tabList: string[] = [];\n\n getSelectedId = () => this.props.selectedId;\n onActivate = (id: string) => this.props.onSelect(id);\n onTabMount = (id: string, ref: TypeTabButtonRef) => {\n if (!this.tabList.includes(id)) {\n this.tabList.push(id);\n this.buttonRefs[id] = ref;\n }\n };\n\n onTabUpdate = (previousId: string, newId: string) => {\n if (this.tabList.includes(previousId)) {\n this.tabList = this.tabList.map((id) => (id === previousId ? newId : id));\n this.buttonRefs[newId] = this.buttonRefs[previousId];\n this.buttonRefs[previousId] = undefined;\n }\n };\n\n onTabUnmount = (id: string) => {\n if (this.tabList.includes(id)) {\n this.tabList = this.tabList.filter((currentId) => currentId !== id);\n this.buttonRefs[id] = undefined;\n }\n };\n\n selectNextTab = (id: string) => {\n const buttonRef = this.buttonRefs[id];\n this.props.onSelect(id);\n buttonRef &&\n buttonRef.current &&\n buttonRef.current.focus &&\n buttonRef.current.focus();\n };\n\n keyHandler = ({ keyCode }: React.KeyboardEvent<HTMLDivElement>) => {\n switch (keyCode) {\n // left arrow\n case 37:\n this.tabList.forEach((id, index) => {\n if (id === this.getSelectedId()) {\n const count = this.tabList.length;\n const nextIndex = index - 1 >= 0 ? index - 1 : count - 1;\n const nextId = this.tabList[nextIndex];\n this.selectNextTab(nextId ? nextId : \"\");\n }\n });\n break;\n\n // right arrow\n case 39:\n this.tabList.forEach((id, index) => {\n if (id === this.getSelectedId()) {\n const count = this.tabList.length;\n const nextIndex = index + 1 < count ? index + 1 : 0;\n const nextId = this.tabList[nextIndex];\n this.selectNextTab(nextId ? nextId : \"\");\n }\n });\n break;\n\n default:\n break;\n }\n };\n\n override render() {\n const { children, qa, onSelect, ...rest } = this.props;\n return (\n <Container\n data-qa-tabs=\"\"\n onKeyUp={this.keyHandler}\n onSelect={onSelect}\n role=\"tablist\"\n {...qa}\n {...rest}\n >\n <TabButtonContext.Provider\n value={{\n selectedId: this.getSelectedId(),\n fullWidth: this.props.fullWidth,\n onActivate: this.onActivate,\n onTabMount: this.onTabMount,\n onTabUpdate: this.onTabUpdate,\n onTabUnmount: this.onTabUnmount,\n }}\n >\n {children}\n </TabButtonContext.Provider>\n </Container>\n );\n }\n}\n\nexport default Tabs;\n","import styled, { css } from \"styled-components\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport { Button } from \"@sproutsocial/seeds-react-button\";\nimport { type TypeTabsProps } from \"./TabsTypes\";\n\ninterface TypeTabState {\n isSelected: boolean;\n}\ntype TypeFullWidth = Pick<TypeTabsProps, \"fullWidth\">;\ninterface TypeStyleProps extends TypeFullWidth, TypeTabState {}\n\nconst Container = styled.div<TypeTabsProps>`\n display: ${(props) => (props.fullWidth ? \"flex\" : \"inline-flex\")};\n justify-content: space-between;\n margin: 0;\n padding: 0;\n border-bottom: ${(props) => props.theme.borders[500]}\n ${(props) => props.theme.colors.container.border.base};\n\n ${COMMON}\n`;\n\nexport const TabButton = styled(Button)<TypeStyleProps>`\n margin-bottom: -1px;\n padding: ${(props) => `${props.theme.space[350]} 0`};\n color: ${(props) => props.theme.colors.text.headline};\n border-radius: 0;\n border-width: 0 0 3px;\n width: 100%;\n\n ${(props) =>\n props.fullWidth &&\n css`\n flex-grow: 1;\n `};\n\n &:not(:last-child) {\n ${(props) =>\n !props.fullWidth &&\n css`\n margin-right: ${(props) => props.theme.space[350]};\n `};\n }\n\n ${(props) =>\n props.isSelected &&\n css`\n color: ${(props) => props.theme.colors.link.base};\n border-color: transparent transparent\n ${(props) => props.theme.colors.button.primary.background.base};\n `};\n\n &:hover {\n ${(props) =>\n props.isSelected &&\n css`\n color: ${(props) => props.theme.colors.link.hover};\n `};\n }\n\n &:focus,\n &:active {\n box-shadow: none;\n }\n\n &:active {\n transform: none;\n }\n`;\nexport default Container;\n","import * as React from \"react\";\nimport type {\n TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n} from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeButtonProps } from \"@sproutsocial/seeds-react-button\";\n\nexport interface TypeTabButtonsProps extends TypeButtonProps {\n children: React.ReactNode;\n\n /** Should be unique among sibling elements */\n id: string;\n}\n\nexport interface TypeTabPanelProps\n extends React.ComponentPropsWithoutRef<\"div\"> {\n children: React.ReactNode;\n\n /** Should match the corresponding tab button id */\n id: string;\n}\n\nexport interface TypeTabsProps\n extends TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n Omit<\n React.ComponentPropsWithoutRef<\"ul\">,\n keyof TypeSystemCommonProps | \"onSelect\"\n > {\n children: React.ReactNode;\n onSelect: (arg0: string) => void;\n\n /** Whether or not the tabs should stretch to fill the width of their container */\n fullWidth?: boolean;\n qa?: object;\n\n /** ID of the selected tab */\n selectedId: string;\n}\n","import Tabs from \"./Tabs\";\n\nexport default Tabs;\nexport { Tabs };\nexport * from \"./TabsTypes\";\n"],"mappings":"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","names":["React","props"]}
|
|
1
|
+
{"version":3,"sources":["../../src/Tabs.tsx","../../src/styles.ts","../../src/TabsTypes.ts","../../src/index.ts"],"sourcesContent":["import * as React from \"react\";\nimport Container, { TabButton } from \"./styles\";\nimport type {\n TypeTabButtonsProps,\n TypeTabsProps,\n TypeTabPanelProps,\n} from \"./TabsTypes\";\n\ninterface TypeTabButtonRef {\n current: null | React.ElementRef<\"button\">;\n}\ninterface TypeTabButtonContext {\n onActivate: (arg0: string) => void;\n onTabMount: (id: string, ref: TypeTabButtonRef) => void;\n onTabUpdate: (previousId: string, nextId: string) => void;\n onTabUnmount: (id: string) => void;\n selectedId: string;\n fullWidth?: boolean;\n}\n\nconst TabButtonContext = React.createContext<Partial<TypeTabButtonContext>>({});\n\nclass TabItemButton extends React.Component<TypeTabButtonsProps> {\n static override contextType = TabButtonContext;\n // @ts-notes - using the legacy syntax here because `declare` does not play well with babel\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n //@ts-ignore\n context!: React.ContextType<typeof TabButtonContext>;\n\n buttonRef: TypeTabButtonRef = React.createRef<React.ElementRef<\"button\">>();\n\n override componentDidMount() {\n this.context.onTabMount?.(this.props.id, this.buttonRef);\n }\n\n override componentDidUpdate(prevProps: TypeTabButtonsProps) {\n if (prevProps.id !== this.props.id) {\n this.context.onTabUpdate?.(prevProps.id, this.props.id);\n }\n }\n\n override componentWillUnmount() {\n this.context.onTabUnmount?.(this.props.id);\n }\n\n override render() {\n const { children, id, ...rest } = this.props;\n const { selectedId, onActivate, fullWidth } = this.context;\n const isSelected = selectedId === id;\n\n return (\n <TabButton\n key={id}\n innerRef={this.buttonRef}\n id={id}\n onClick={() => onActivate?.(id)}\n isSelected={isSelected}\n tabIndex={isSelected ? 0 : -1}\n fullWidth={fullWidth}\n data-qa-tab-button={id}\n data-qa-tab-button-state={isSelected}\n aria-selected={isSelected}\n role=\"tab\"\n aria-controls={`${id}-panel`}\n {...rest}\n >\n {children}\n </TabButton>\n );\n }\n}\n\nconst TabPanel: React.FC<TypeTabPanelProps> = ({ children, id, ...rest }) => {\n const panelId = `${id}-panel`;\n\n return (\n <div id={panelId} role=\"tabpanel\" aria-labelledby={id} {...rest}>\n {children}\n </div>\n );\n};\n\n/**\n * Render a group of buttons in a tab-heading style\n */\nclass Tabs extends React.Component<TypeTabsProps> {\n static Button = TabItemButton;\n static Panel = TabPanel;\n buttonRefs: Record<string, TypeTabButtonRef | null | undefined> = {};\n tabList: string[] = [];\n\n containerRef = React.createRef<HTMLDivElement>();\n startSentinelRef = React.createRef<HTMLDivElement>();\n endSentinelRef = React.createRef<HTMLDivElement>();\n startObserver: IntersectionObserver | null = null;\n endObserver: IntersectionObserver | null = null;\n\n override componentDidMount() {\n const container = this.containerRef.current;\n if (!container) return;\n container.addEventListener(\"wheel\", this.handleWheel, { passive: false });\n\n const startSentinel = this.startSentinelRef.current;\n const endSentinel = this.endSentinelRef.current;\n if (!startSentinel || !endSentinel) return;\n if (typeof IntersectionObserver === \"undefined\") return;\n this.startObserver = new IntersectionObserver(\n ([entry]) => {\n container.toggleAttribute(\"data-fade-left\", !entry?.isIntersecting);\n },\n { root: container, threshold: 1.0, rootMargin: \"0px 0px 0px 1px\" }\n );\n this.endObserver = new IntersectionObserver(\n ([entry]) => {\n container.toggleAttribute(\"data-fade-right\", !entry?.isIntersecting);\n },\n { root: container, threshold: 1.0, rootMargin: \"0px 1px 0px 0px\" }\n );\n this.startObserver.observe(startSentinel);\n this.endObserver.observe(endSentinel);\n }\n\n override componentWillUnmount() {\n this.containerRef.current?.removeEventListener(\"wheel\", this.handleWheel);\n this.startObserver?.disconnect();\n this.endObserver?.disconnect();\n this.startObserver = null;\n this.endObserver = null;\n }\n\n handleWheel = (e: WheelEvent) => {\n const container = this.containerRef.current;\n if (!container) return;\n // Only redirect pure-vertical wheel input. Trackpad horizontal swipes\n // (deltaX !== 0) already scroll natively — don't fight them.\n if (e.deltaY === 0 || e.deltaX !== 0) return;\n // No horizontal overflow means there's nothing to scroll.\n if (container.scrollWidth <= container.clientWidth) return;\n // Release at ends so the page can scroll past the tab bar instead of\n // trapping the user. WCAG 2.1.1 / 2.1.2 spirit.\n const atStart = container.scrollLeft <= 0;\n const atEnd =\n container.scrollLeft + container.clientWidth >= container.scrollWidth;\n if ((atEnd && e.deltaY > 0) || (atStart && e.deltaY < 0)) return;\n\n e.preventDefault();\n // Normalize deltaY across deltaMode units (Firefox can emit LINE/PAGE).\n const lineHeight = 16;\n const pixelDelta =\n e.deltaMode === 1\n ? e.deltaY * lineHeight\n : e.deltaMode === 2\n ? e.deltaY * container.clientHeight\n : e.deltaY;\n container.scrollBy({ left: pixelDelta, behavior: \"instant\" });\n };\n\n getSelectedId = () => this.props.selectedId;\n onActivate = (id: string) => {\n this.props.onSelect(id);\n this.scrollTabIntoView(id);\n };\n\n scrollTabIntoView = (id: string) => {\n const button = this.buttonRefs[id]?.current;\n const container = this.containerRef.current;\n if (!button || !container) return;\n const buttonRect = button.getBoundingClientRect();\n const containerRect = container.getBoundingClientRect();\n const fadePadding = 48;\n const isFullyVisible =\n buttonRect.left >= containerRect.left + fadePadding &&\n buttonRect.right <= containerRect.right - fadePadding;\n if (isFullyVisible) return;\n button.scrollIntoView?.({ block: \"nearest\", inline: \"nearest\" });\n };\n onTabMount = (id: string, ref: TypeTabButtonRef) => {\n if (!this.tabList.includes(id)) {\n this.tabList.push(id);\n this.buttonRefs[id] = ref;\n }\n };\n\n onTabUpdate = (previousId: string, newId: string) => {\n if (this.tabList.includes(previousId)) {\n this.tabList = this.tabList.map((id) => (id === previousId ? newId : id));\n this.buttonRefs[newId] = this.buttonRefs[previousId];\n this.buttonRefs[previousId] = undefined;\n }\n };\n\n onTabUnmount = (id: string) => {\n if (this.tabList.includes(id)) {\n this.tabList = this.tabList.filter((currentId) => currentId !== id);\n this.buttonRefs[id] = undefined;\n }\n };\n\n selectNextTab = (id: string) => {\n this.props.onSelect(id);\n this.buttonRefs[id]?.current?.focus?.({ preventScroll: true });\n this.scrollTabIntoView(id);\n };\n\n keyHandler = (e: React.KeyboardEvent<HTMLDivElement>) => {\n switch (e.keyCode) {\n // left arrow\n case 37:\n this.tabList.forEach((id, index) => {\n e.preventDefault();\n if (id === this.getSelectedId()) {\n const count = this.tabList.length;\n const nextIndex = index - 1 >= 0 ? index - 1 : count - 1;\n const nextId = this.tabList[nextIndex];\n this.selectNextTab(nextId ? nextId : \"\");\n }\n });\n break;\n\n // right arrow\n case 39:\n this.tabList.forEach((id, index) => {\n e.preventDefault();\n if (id === this.getSelectedId()) {\n const count = this.tabList.length;\n const nextIndex = index + 1 < count ? index + 1 : 0;\n const nextId = this.tabList[nextIndex];\n this.selectNextTab(nextId ? nextId : \"\");\n }\n });\n break;\n\n default:\n break;\n }\n };\n\n override render() {\n const {\n children,\n qa,\n onSelect,\n \"aria-label\": ariaLabel,\n ...rest\n } = this.props;\n return (\n <Container\n ref={this.containerRef}\n data-qa-tabs=\"\"\n onKeyDown={this.keyHandler}\n onSelect={onSelect}\n role=\"tablist\"\n aria-label={ariaLabel}\n {...qa}\n {...rest}\n >\n <div\n ref={this.startSentinelRef}\n aria-hidden=\"true\"\n style={{ flexShrink: 0, width: 1 }}\n />\n <TabButtonContext.Provider\n value={{\n selectedId: this.getSelectedId(),\n fullWidth: this.props.fullWidth,\n onActivate: this.onActivate,\n onTabMount: this.onTabMount,\n onTabUpdate: this.onTabUpdate,\n onTabUnmount: this.onTabUnmount,\n }}\n >\n {children}\n </TabButtonContext.Provider>\n <div\n ref={this.endSentinelRef}\n aria-hidden=\"true\"\n style={{ flexShrink: 0, width: 1 }}\n />\n </Container>\n );\n }\n}\n\nexport default Tabs;\n","import styled, { css } from \"styled-components\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport { Button } from \"@sproutsocial/seeds-react-button\";\nimport { type TypeTabsProps } from \"./TabsTypes\";\n\ninterface TypeTabState {\n isSelected: boolean;\n}\ntype TypeFullWidth = Pick<TypeTabsProps, \"fullWidth\">;\ninterface TypeStyleProps extends TypeFullWidth, TypeTabState {}\n\nconst Container = styled.div<TypeTabsProps>`\n display: ${(props) => (props.fullWidth ? \"flex\" : \"inline-flex\")};\n margin: 0;\n padding: 0;\n min-width: 0;\n max-width: 100%;\n min-height: min-content;\n flex-shrink: 0;\n overflow-x: auto;\n overflow-y: hidden;\n scrollbar-width: none;\n scroll-padding-inline: 48px;\n scroll-behavior: smooth;\n border-bottom: ${(props) => props.theme.borders[500]}\n ${(props) => props.theme.colors.container.border.base};\n\n &::-webkit-scrollbar {\n display: none;\n }\n\n &[data-fade-right] {\n -webkit-mask-image: linear-gradient(\n to right,\n black 0,\n black calc(100% - 48px),\n transparent\n );\n mask-image: linear-gradient(\n to right,\n black 0,\n black calc(100% - 48px),\n transparent\n );\n }\n\n &[data-fade-left] {\n -webkit-mask-image: linear-gradient(\n to right,\n transparent,\n black 48px,\n black 100%\n );\n mask-image: linear-gradient(to right, transparent, black 48px, black 100%);\n }\n\n &[data-fade-left][data-fade-right] {\n -webkit-mask-image: linear-gradient(\n to right,\n transparent,\n black 48px,\n black calc(100% - 48px),\n transparent\n );\n mask-image: linear-gradient(\n to right,\n transparent,\n black 48px,\n black calc(100% - 48px),\n transparent\n );\n }\n\n ${COMMON}\n`;\n\nexport const TabButton = styled(Button)<TypeStyleProps>`\n margin-bottom: -1px;\n padding: ${(props) =>\n `${props.theme.space[350]} ${\n props.fullWidth ? 0 : props.theme.space[350]\n }`};\n color: ${(props) => props.theme.colors.text.headline};\n border-radius: 0;\n border-width: 0 0 3px;\n width: 100%;\n\n ${(props) =>\n props.fullWidth &&\n css`\n flex-grow: 1;\n `};\n\n ${(props) =>\n props.isSelected &&\n css`\n color: ${(props) => props.theme.colors.link.base};\n border-color: transparent transparent\n ${(props) => props.theme.colors.button.primary.background.base};\n `};\n\n &:hover {\n ${(props) =>\n props.isSelected &&\n css`\n color: ${(props) => props.theme.colors.link.hover};\n `};\n }\n\n &:focus,\n &:active {\n box-shadow: none;\n }\n\n &:active {\n transform: none;\n }\n`;\nexport default Container;\n","import * as React from \"react\";\nimport type {\n TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n} from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeButtonProps } from \"@sproutsocial/seeds-react-button\";\n\nexport interface TypeTabButtonsProps extends TypeButtonProps {\n children: React.ReactNode;\n\n /** Should be unique among sibling elements */\n id: string;\n}\n\nexport interface TypeTabPanelProps\n extends React.ComponentPropsWithoutRef<\"div\"> {\n children: React.ReactNode;\n\n /** Should match the corresponding tab button id */\n id: string;\n}\n\nexport interface TypeTabsProps\n extends TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n Omit<\n React.ComponentPropsWithoutRef<\"ul\">,\n keyof TypeSystemCommonProps | \"onSelect\"\n > {\n children: React.ReactNode;\n onSelect: (arg0: string) => void;\n\n /** Whether or not the tabs should stretch to fill the width of their container */\n fullWidth?: boolean;\n qa?: object;\n\n /** ID of the selected tab */\n selectedId: string;\n\n /**\n * Accessible label for the tab list. Forwarded to the `role=\"tablist\"`\n * element. Recommended by the WAI-ARIA Tabs pattern so screen readers\n * can announce what the tabs represent (e.g. \"Report sections\").\n * Use `aria-labelledby` instead via `{...rest}` if you have a visible\n * heading to reference.\n */\n \"aria-label\"?: string;\n}\n","import Tabs from \"./Tabs\";\n\nexport default Tabs;\nexport { Tabs };\nexport * from \"./TabsTypes\";\n"],"mappings":"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","names":["React","props"]}
|
package/dist/index.d.mts
CHANGED
|
@@ -21,6 +21,14 @@ interface TypeTabsProps extends TypeStyledComponentsCommonProps, TypeSystemCommo
|
|
|
21
21
|
qa?: object;
|
|
22
22
|
/** ID of the selected tab */
|
|
23
23
|
selectedId: string;
|
|
24
|
+
/**
|
|
25
|
+
* Accessible label for the tab list. Forwarded to the `role="tablist"`
|
|
26
|
+
* element. Recommended by the WAI-ARIA Tabs pattern so screen readers
|
|
27
|
+
* can announce what the tabs represent (e.g. "Report sections").
|
|
28
|
+
* Use `aria-labelledby` instead via `{...rest}` if you have a visible
|
|
29
|
+
* heading to reference.
|
|
30
|
+
*/
|
|
31
|
+
"aria-label"?: string;
|
|
24
32
|
}
|
|
25
33
|
|
|
26
34
|
interface TypeTabButtonRef {
|
|
@@ -52,13 +60,22 @@ declare class Tabs extends React.Component<TypeTabsProps> {
|
|
|
52
60
|
static Panel: React.FC<TypeTabPanelProps>;
|
|
53
61
|
buttonRefs: Record<string, TypeTabButtonRef | null | undefined>;
|
|
54
62
|
tabList: string[];
|
|
63
|
+
containerRef: React.RefObject<HTMLDivElement>;
|
|
64
|
+
startSentinelRef: React.RefObject<HTMLDivElement>;
|
|
65
|
+
endSentinelRef: React.RefObject<HTMLDivElement>;
|
|
66
|
+
startObserver: IntersectionObserver | null;
|
|
67
|
+
endObserver: IntersectionObserver | null;
|
|
68
|
+
componentDidMount(): void;
|
|
69
|
+
componentWillUnmount(): void;
|
|
70
|
+
handleWheel: (e: WheelEvent) => void;
|
|
55
71
|
getSelectedId: () => string;
|
|
56
72
|
onActivate: (id: string) => void;
|
|
73
|
+
scrollTabIntoView: (id: string) => void;
|
|
57
74
|
onTabMount: (id: string, ref: TypeTabButtonRef) => void;
|
|
58
75
|
onTabUpdate: (previousId: string, newId: string) => void;
|
|
59
76
|
onTabUnmount: (id: string) => void;
|
|
60
77
|
selectNextTab: (id: string) => void;
|
|
61
|
-
keyHandler: (
|
|
78
|
+
keyHandler: (e: React.KeyboardEvent<HTMLDivElement>) => void;
|
|
62
79
|
render(): react_jsx_runtime.JSX.Element;
|
|
63
80
|
}
|
|
64
81
|
|
package/dist/index.d.ts
CHANGED
|
@@ -21,6 +21,14 @@ interface TypeTabsProps extends TypeStyledComponentsCommonProps, TypeSystemCommo
|
|
|
21
21
|
qa?: object;
|
|
22
22
|
/** ID of the selected tab */
|
|
23
23
|
selectedId: string;
|
|
24
|
+
/**
|
|
25
|
+
* Accessible label for the tab list. Forwarded to the `role="tablist"`
|
|
26
|
+
* element. Recommended by the WAI-ARIA Tabs pattern so screen readers
|
|
27
|
+
* can announce what the tabs represent (e.g. "Report sections").
|
|
28
|
+
* Use `aria-labelledby` instead via `{...rest}` if you have a visible
|
|
29
|
+
* heading to reference.
|
|
30
|
+
*/
|
|
31
|
+
"aria-label"?: string;
|
|
24
32
|
}
|
|
25
33
|
|
|
26
34
|
interface TypeTabButtonRef {
|
|
@@ -52,13 +60,22 @@ declare class Tabs extends React.Component<TypeTabsProps> {
|
|
|
52
60
|
static Panel: React.FC<TypeTabPanelProps>;
|
|
53
61
|
buttonRefs: Record<string, TypeTabButtonRef | null | undefined>;
|
|
54
62
|
tabList: string[];
|
|
63
|
+
containerRef: React.RefObject<HTMLDivElement>;
|
|
64
|
+
startSentinelRef: React.RefObject<HTMLDivElement>;
|
|
65
|
+
endSentinelRef: React.RefObject<HTMLDivElement>;
|
|
66
|
+
startObserver: IntersectionObserver | null;
|
|
67
|
+
endObserver: IntersectionObserver | null;
|
|
68
|
+
componentDidMount(): void;
|
|
69
|
+
componentWillUnmount(): void;
|
|
70
|
+
handleWheel: (e: WheelEvent) => void;
|
|
55
71
|
getSelectedId: () => string;
|
|
56
72
|
onActivate: (id: string) => void;
|
|
73
|
+
scrollTabIntoView: (id: string) => void;
|
|
57
74
|
onTabMount: (id: string, ref: TypeTabButtonRef) => void;
|
|
58
75
|
onTabUpdate: (previousId: string, newId: string) => void;
|
|
59
76
|
onTabUnmount: (id: string) => void;
|
|
60
77
|
selectNextTab: (id: string) => void;
|
|
61
|
-
keyHandler: (
|
|
78
|
+
keyHandler: (e: React.KeyboardEvent<HTMLDivElement>) => void;
|
|
62
79
|
render(): react_jsx_runtime.JSX.Element;
|
|
63
80
|
}
|
|
64
81
|
|