@sproutsocial/seeds-react-tabs 1.4.14 → 1.4.16
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/dist/esm/index.js +168 -49
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.mts +14 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.js +167 -48
- package/dist/index.js.map +1 -1
- package/dist/tabs.css +122 -0
- package/package.json +16 -5
- package/.eslintignore +0 -6
- package/.eslintrc.js +0 -4
- package/.turbo/turbo-build.log +0 -21
- package/CHANGELOG.md +0 -391
- package/jest.config.js +0 -9
- package/src/Tabs.stories.tsx +0 -258
- package/src/Tabs.tsx +0 -284
- package/src/TabsTypes.ts +0 -48
- package/src/__tests__/Tabs.typetest.tsx +0 -20
- package/src/__tests__/tabs.test.tsx +0 -462
- package/src/index.ts +0 -5
- package/src/styled.d.ts +0 -7
- package/src/styles.ts +0 -119
- package/tsconfig.json +0 -9
- package/tsup.config.ts +0 -12
|
@@ -1,462 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import {
|
|
3
|
-
render,
|
|
4
|
-
fireEvent,
|
|
5
|
-
screen,
|
|
6
|
-
} from "@sproutsocial/seeds-react-testing-library";
|
|
7
|
-
import { Box } from "@sproutsocial/seeds-react-box";
|
|
8
|
-
import { Tabs, type TypeTabsProps } from "../";
|
|
9
|
-
|
|
10
|
-
const leftArrowKey = {
|
|
11
|
-
key: "ArrowLeft",
|
|
12
|
-
code: 37,
|
|
13
|
-
keyCode: 37,
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const rightArrowKey = {
|
|
17
|
-
key: "ArrowRight",
|
|
18
|
-
code: 39,
|
|
19
|
-
keyCode: 39,
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
interface TypeButtonData {
|
|
23
|
-
id: string;
|
|
24
|
-
text: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const mapTabButton = (button: TypeButtonData) => (
|
|
28
|
-
<Tabs.Button key={button.id} id={button.id}>
|
|
29
|
-
{button.text}
|
|
30
|
-
</Tabs.Button>
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
interface TypeTestStatefulTabsProps {
|
|
34
|
-
children: React.ReactNode;
|
|
35
|
-
selectedId?: string;
|
|
36
|
-
onSelect?: (id: string) => void;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const TestStatefulTabs = ({
|
|
40
|
-
children,
|
|
41
|
-
selectedId = "1",
|
|
42
|
-
onSelect = jest.fn(),
|
|
43
|
-
}: TypeTestStatefulTabsProps) => {
|
|
44
|
-
const [state, setState] = React.useState({
|
|
45
|
-
selectedId,
|
|
46
|
-
});
|
|
47
|
-
return (
|
|
48
|
-
<Tabs
|
|
49
|
-
selectedId={state.selectedId}
|
|
50
|
-
onSelect={(id) => {
|
|
51
|
-
onSelect(id);
|
|
52
|
-
setState({
|
|
53
|
-
selectedId: id,
|
|
54
|
-
});
|
|
55
|
-
}}
|
|
56
|
-
>
|
|
57
|
-
{children}
|
|
58
|
-
</Tabs>
|
|
59
|
-
);
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
describe("Tabs", () => {
|
|
63
|
-
beforeEach(() => {
|
|
64
|
-
// jsdom doesn't implement Element.prototype.scrollIntoView or .scrollBy
|
|
65
|
-
Element.prototype.scrollIntoView = jest.fn();
|
|
66
|
-
Element.prototype.scrollBy = jest.fn();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
const mockScrollDimensions = (
|
|
70
|
-
el: Element,
|
|
71
|
-
{
|
|
72
|
-
scrollWidth,
|
|
73
|
-
clientWidth,
|
|
74
|
-
scrollLeft,
|
|
75
|
-
}: { scrollWidth: number; clientWidth: number; scrollLeft: number }
|
|
76
|
-
) => {
|
|
77
|
-
Object.defineProperty(el, "scrollWidth", {
|
|
78
|
-
value: scrollWidth,
|
|
79
|
-
configurable: true,
|
|
80
|
-
});
|
|
81
|
-
Object.defineProperty(el, "clientWidth", {
|
|
82
|
-
value: clientWidth,
|
|
83
|
-
configurable: true,
|
|
84
|
-
});
|
|
85
|
-
Object.defineProperty(el, "scrollLeft", {
|
|
86
|
-
value: scrollLeft,
|
|
87
|
-
configurable: true,
|
|
88
|
-
writable: true,
|
|
89
|
-
});
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
it("should render selected tab", () => {
|
|
93
|
-
render(
|
|
94
|
-
<TestStatefulTabs>
|
|
95
|
-
<Tabs.Button id="1">First</Tabs.Button>
|
|
96
|
-
<Tabs.Button id="2">Second</Tabs.Button>
|
|
97
|
-
</TestStatefulTabs>
|
|
98
|
-
);
|
|
99
|
-
const firstTab = screen.getByText(/first/i);
|
|
100
|
-
const secondTab = screen.getByText(/second/i);
|
|
101
|
-
expect(firstTab).toHaveAttribute("tabindex", "0");
|
|
102
|
-
expect(secondTab).toHaveAttribute("tabindex", "-1");
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it("should work when tab buttons aren't direct children", () => {
|
|
106
|
-
render(
|
|
107
|
-
<TestStatefulTabs>
|
|
108
|
-
<Box border="2px red solid">
|
|
109
|
-
<Tabs.Button id="1">First</Tabs.Button>
|
|
110
|
-
</Box>
|
|
111
|
-
<Box border="2px green solid">
|
|
112
|
-
<Tabs.Button id="2">Second</Tabs.Button>
|
|
113
|
-
</Box>
|
|
114
|
-
</TestStatefulTabs>
|
|
115
|
-
);
|
|
116
|
-
const tabs = screen.getByDataQaLabel({
|
|
117
|
-
tabs: "",
|
|
118
|
-
});
|
|
119
|
-
const secondTab = screen.getByText(/second/i);
|
|
120
|
-
fireEvent.keyDown(tabs, rightArrowKey);
|
|
121
|
-
expect(secondTab).toHaveFocus();
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it("should handle left arrow key", () => {
|
|
125
|
-
const onSelect = jest.fn();
|
|
126
|
-
render(
|
|
127
|
-
<TestStatefulTabs onSelect={onSelect}>
|
|
128
|
-
<Tabs.Button id="1">First</Tabs.Button>
|
|
129
|
-
<Tabs.Button id="2">Second</Tabs.Button>
|
|
130
|
-
<Tabs.Button id="3">Third</Tabs.Button>
|
|
131
|
-
</TestStatefulTabs>
|
|
132
|
-
);
|
|
133
|
-
const tabs = screen.getByDataQaLabel({
|
|
134
|
-
tabs: "",
|
|
135
|
-
});
|
|
136
|
-
const secondTab = screen.getByText(/second/i);
|
|
137
|
-
const thirdTab = screen.getByText(/third/i);
|
|
138
|
-
fireEvent.keyDown(tabs, leftArrowKey);
|
|
139
|
-
expect(onSelect).toHaveBeenCalledWith("3");
|
|
140
|
-
expect(thirdTab).toHaveFocus();
|
|
141
|
-
onSelect.mockReset();
|
|
142
|
-
fireEvent.keyDown(tabs, leftArrowKey);
|
|
143
|
-
expect(onSelect).toHaveBeenCalledWith("2");
|
|
144
|
-
expect(secondTab).toHaveFocus();
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it("should handle right arrow key", () => {
|
|
148
|
-
const onSelect = jest.fn();
|
|
149
|
-
render(
|
|
150
|
-
<TestStatefulTabs onSelect={onSelect}>
|
|
151
|
-
<Tabs.Button id="1">First</Tabs.Button>
|
|
152
|
-
<Tabs.Button id="2">Second</Tabs.Button>
|
|
153
|
-
<Tabs.Button id="3">Third</Tabs.Button>
|
|
154
|
-
</TestStatefulTabs>
|
|
155
|
-
);
|
|
156
|
-
const tabs = screen.getByDataQaLabel({
|
|
157
|
-
tabs: "",
|
|
158
|
-
});
|
|
159
|
-
const firstTab = screen.getByText(/first/i);
|
|
160
|
-
const secondTab = screen.getByText(/second/i);
|
|
161
|
-
const thirdTab = screen.getByText(/third/i);
|
|
162
|
-
fireEvent.keyDown(tabs, rightArrowKey);
|
|
163
|
-
expect(onSelect).toHaveBeenCalledWith("2");
|
|
164
|
-
expect(secondTab).toHaveFocus();
|
|
165
|
-
onSelect.mockReset();
|
|
166
|
-
fireEvent.keyDown(tabs, rightArrowKey);
|
|
167
|
-
expect(onSelect).toHaveBeenCalledWith("3");
|
|
168
|
-
expect(thirdTab).toHaveFocus();
|
|
169
|
-
onSelect.mockReset();
|
|
170
|
-
fireEvent.keyDown(tabs, rightArrowKey);
|
|
171
|
-
expect(onSelect).toHaveBeenCalledWith("1");
|
|
172
|
-
expect(firstTab).toHaveFocus();
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
it("should handle dynamically adding tabs", () => {
|
|
176
|
-
const onSelect = jest.fn();
|
|
177
|
-
const initialButtons = [
|
|
178
|
-
{
|
|
179
|
-
id: "1",
|
|
180
|
-
text: "First",
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
id: "2",
|
|
184
|
-
text: "Second",
|
|
185
|
-
},
|
|
186
|
-
];
|
|
187
|
-
const addButton = initialButtons.concat({
|
|
188
|
-
id: "3",
|
|
189
|
-
text: "Third",
|
|
190
|
-
});
|
|
191
|
-
const { rerender } = render(
|
|
192
|
-
<TestStatefulTabs onSelect={onSelect}>
|
|
193
|
-
{initialButtons.map(mapTabButton)}
|
|
194
|
-
</TestStatefulTabs>
|
|
195
|
-
);
|
|
196
|
-
const tabs = screen.getByDataQaLabel({
|
|
197
|
-
tabs: "",
|
|
198
|
-
});
|
|
199
|
-
const secondTab = screen.getByText(/second/i);
|
|
200
|
-
fireEvent.keyDown(tabs, rightArrowKey);
|
|
201
|
-
expect(onSelect).toHaveBeenCalledWith("2");
|
|
202
|
-
expect(secondTab).toHaveFocus();
|
|
203
|
-
rerender(
|
|
204
|
-
<TestStatefulTabs onSelect={onSelect}>
|
|
205
|
-
{addButton.map(mapTabButton)}
|
|
206
|
-
</TestStatefulTabs>
|
|
207
|
-
);
|
|
208
|
-
onSelect.mockReset();
|
|
209
|
-
fireEvent.keyDown(tabs, rightArrowKey);
|
|
210
|
-
const thirdTab = screen.getByText(/third/i);
|
|
211
|
-
expect(onSelect).toHaveBeenCalledWith("3");
|
|
212
|
-
expect(thirdTab).toHaveFocus();
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
it("should handle dynamically removing tabs", () => {
|
|
216
|
-
const onSelect = jest.fn();
|
|
217
|
-
const initialButtons = [
|
|
218
|
-
{
|
|
219
|
-
id: "1",
|
|
220
|
-
text: "First",
|
|
221
|
-
},
|
|
222
|
-
{
|
|
223
|
-
id: "2",
|
|
224
|
-
text: "Second",
|
|
225
|
-
},
|
|
226
|
-
{
|
|
227
|
-
id: "3",
|
|
228
|
-
text: "Third",
|
|
229
|
-
},
|
|
230
|
-
];
|
|
231
|
-
const removeButton = initialButtons.slice(1);
|
|
232
|
-
const { rerender } = render(
|
|
233
|
-
<TestStatefulTabs onSelect={onSelect}>
|
|
234
|
-
{initialButtons.map(mapTabButton)}
|
|
235
|
-
</TestStatefulTabs>
|
|
236
|
-
);
|
|
237
|
-
const tabs = screen.getByDataQaLabel({
|
|
238
|
-
tabs: "",
|
|
239
|
-
});
|
|
240
|
-
const secondTab = screen.getByText(/second/i);
|
|
241
|
-
const thirdTab = screen.getByText(/third/i);
|
|
242
|
-
fireEvent.keyDown(tabs, rightArrowKey);
|
|
243
|
-
expect(onSelect).toHaveBeenCalledWith("2");
|
|
244
|
-
expect(secondTab).toHaveFocus();
|
|
245
|
-
rerender(
|
|
246
|
-
<TestStatefulTabs onSelect={onSelect}>
|
|
247
|
-
{removeButton.map(mapTabButton)}
|
|
248
|
-
</TestStatefulTabs>
|
|
249
|
-
);
|
|
250
|
-
onSelect.mockReset();
|
|
251
|
-
fireEvent.keyDown(tabs, rightArrowKey);
|
|
252
|
-
expect(onSelect).toHaveBeenCalledWith("3");
|
|
253
|
-
expect(thirdTab).toHaveFocus();
|
|
254
|
-
onSelect.mockReset();
|
|
255
|
-
fireEvent.keyDown(tabs, rightArrowKey);
|
|
256
|
-
expect(onSelect).toHaveBeenCalledWith("2");
|
|
257
|
-
expect(secondTab).toHaveFocus();
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
it("scrolls the focused tab into view on arrow-key navigation", () => {
|
|
261
|
-
render(
|
|
262
|
-
<TestStatefulTabs>
|
|
263
|
-
<Tabs.Button id="1">First</Tabs.Button>
|
|
264
|
-
<Tabs.Button id="2">Second</Tabs.Button>
|
|
265
|
-
<Tabs.Button id="3">Third</Tabs.Button>
|
|
266
|
-
</TestStatefulTabs>
|
|
267
|
-
);
|
|
268
|
-
const tabs = screen.getByDataQaLabel({ tabs: "" });
|
|
269
|
-
const secondTab = screen.getByText(/second/i);
|
|
270
|
-
|
|
271
|
-
fireEvent.keyDown(tabs, rightArrowKey);
|
|
272
|
-
|
|
273
|
-
expect(secondTab.scrollIntoView).toHaveBeenCalledWith({
|
|
274
|
-
block: "nearest",
|
|
275
|
-
inline: "nearest",
|
|
276
|
-
});
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
it("scrolls the activated tab into view on click", () => {
|
|
280
|
-
render(
|
|
281
|
-
<TestStatefulTabs>
|
|
282
|
-
<Tabs.Button id="1">First</Tabs.Button>
|
|
283
|
-
<Tabs.Button id="2">Second</Tabs.Button>
|
|
284
|
-
</TestStatefulTabs>
|
|
285
|
-
);
|
|
286
|
-
const secondTab = screen.getByText(/second/i);
|
|
287
|
-
|
|
288
|
-
fireEvent.click(secondTab);
|
|
289
|
-
|
|
290
|
-
expect(secondTab.scrollIntoView).toHaveBeenCalledWith({
|
|
291
|
-
block: "nearest",
|
|
292
|
-
inline: "nearest",
|
|
293
|
-
});
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
it("forwards aria-label to the tablist", () => {
|
|
297
|
-
render(
|
|
298
|
-
<Tabs
|
|
299
|
-
selectedId="1"
|
|
300
|
-
onSelect={jest.fn()}
|
|
301
|
-
aria-label="Repository sections"
|
|
302
|
-
>
|
|
303
|
-
<Tabs.Button id="1">First</Tabs.Button>
|
|
304
|
-
<Tabs.Button id="2">Second</Tabs.Button>
|
|
305
|
-
</Tabs>
|
|
306
|
-
);
|
|
307
|
-
|
|
308
|
-
const tablist = screen.getByRole("tablist", {
|
|
309
|
-
name: "Repository sections",
|
|
310
|
-
});
|
|
311
|
-
expect(tablist).toBeInTheDocument();
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
it("should handle dynamically changing tab ids", () => {
|
|
315
|
-
const onSelect = jest.fn();
|
|
316
|
-
const { rerender } = render(
|
|
317
|
-
<TestStatefulTabs onSelect={onSelect}>
|
|
318
|
-
<Tabs.Button id="1">First</Tabs.Button>
|
|
319
|
-
<Tabs.Button id="2">Second</Tabs.Button>
|
|
320
|
-
<Tabs.Button id="3">Third</Tabs.Button>
|
|
321
|
-
<Tabs.Button id="4">Fourth</Tabs.Button>
|
|
322
|
-
</TestStatefulTabs>
|
|
323
|
-
);
|
|
324
|
-
|
|
325
|
-
rerender(
|
|
326
|
-
<TestStatefulTabs onSelect={onSelect}>
|
|
327
|
-
<Tabs.Button id="1">First</Tabs.Button>
|
|
328
|
-
<Tabs.Button id="6">Second</Tabs.Button>
|
|
329
|
-
<Tabs.Button id="5">Third</Tabs.Button>
|
|
330
|
-
<Tabs.Button id="4">Fourth</Tabs.Button>
|
|
331
|
-
</TestStatefulTabs>
|
|
332
|
-
);
|
|
333
|
-
|
|
334
|
-
const tabs = screen.getByDataQaLabel({
|
|
335
|
-
tabs: "",
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
const secondTab = screen.getByText(/second/i);
|
|
339
|
-
const thirdTab = screen.getByText(/third/i);
|
|
340
|
-
const fourthTab = screen.getByText(/fourth/i);
|
|
341
|
-
|
|
342
|
-
fireEvent.keyDown(tabs, rightArrowKey);
|
|
343
|
-
expect(onSelect).toHaveBeenCalledWith("6");
|
|
344
|
-
expect(secondTab).toHaveFocus();
|
|
345
|
-
onSelect.mockReset();
|
|
346
|
-
fireEvent.keyDown(tabs, rightArrowKey);
|
|
347
|
-
expect(onSelect).toHaveBeenCalledWith("5");
|
|
348
|
-
expect(thirdTab).toHaveFocus();
|
|
349
|
-
onSelect.mockReset();
|
|
350
|
-
fireEvent.keyDown(tabs, rightArrowKey);
|
|
351
|
-
expect(onSelect).toHaveBeenCalledWith("4");
|
|
352
|
-
expect(fourthTab).toHaveFocus();
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
describe("wheel redirect", () => {
|
|
356
|
-
const renderOverflowing = () => {
|
|
357
|
-
render(
|
|
358
|
-
<TestStatefulTabs>
|
|
359
|
-
<Tabs.Button id="1">First</Tabs.Button>
|
|
360
|
-
<Tabs.Button id="2">Second</Tabs.Button>
|
|
361
|
-
<Tabs.Button id="3">Third</Tabs.Button>
|
|
362
|
-
</TestStatefulTabs>
|
|
363
|
-
);
|
|
364
|
-
return screen.getByDataQaLabel({ tabs: "" });
|
|
365
|
-
};
|
|
366
|
-
|
|
367
|
-
it("redirects vertical wheel to horizontal scroll mid-list", () => {
|
|
368
|
-
const tabs = renderOverflowing();
|
|
369
|
-
mockScrollDimensions(tabs, {
|
|
370
|
-
scrollWidth: 800,
|
|
371
|
-
clientWidth: 480,
|
|
372
|
-
scrollLeft: 100,
|
|
373
|
-
});
|
|
374
|
-
const wheelEvent = new WheelEvent("wheel", {
|
|
375
|
-
deltaY: 50,
|
|
376
|
-
deltaX: 0,
|
|
377
|
-
cancelable: true,
|
|
378
|
-
bubbles: true,
|
|
379
|
-
});
|
|
380
|
-
jest.spyOn(wheelEvent, "preventDefault");
|
|
381
|
-
tabs.dispatchEvent(wheelEvent);
|
|
382
|
-
expect(wheelEvent.preventDefault).toHaveBeenCalled();
|
|
383
|
-
expect(tabs.scrollBy).toHaveBeenCalledWith({
|
|
384
|
-
left: 50,
|
|
385
|
-
behavior: "instant",
|
|
386
|
-
});
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
it("releases at the end so page scroll can take over", () => {
|
|
390
|
-
const tabs = renderOverflowing();
|
|
391
|
-
mockScrollDimensions(tabs, {
|
|
392
|
-
scrollWidth: 800,
|
|
393
|
-
clientWidth: 480,
|
|
394
|
-
scrollLeft: 320, // at end (320 + 480 = 800)
|
|
395
|
-
});
|
|
396
|
-
const wheelEvent = new WheelEvent("wheel", {
|
|
397
|
-
deltaY: 50,
|
|
398
|
-
deltaX: 0,
|
|
399
|
-
cancelable: true,
|
|
400
|
-
bubbles: true,
|
|
401
|
-
});
|
|
402
|
-
jest.spyOn(wheelEvent, "preventDefault");
|
|
403
|
-
tabs.dispatchEvent(wheelEvent);
|
|
404
|
-
expect(wheelEvent.preventDefault).not.toHaveBeenCalled();
|
|
405
|
-
expect(tabs.scrollBy).not.toHaveBeenCalled();
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
it("releases at the start when scrolling back further", () => {
|
|
409
|
-
const tabs = renderOverflowing();
|
|
410
|
-
mockScrollDimensions(tabs, {
|
|
411
|
-
scrollWidth: 800,
|
|
412
|
-
clientWidth: 480,
|
|
413
|
-
scrollLeft: 0,
|
|
414
|
-
});
|
|
415
|
-
const wheelEvent = new WheelEvent("wheel", {
|
|
416
|
-
deltaY: -50,
|
|
417
|
-
deltaX: 0,
|
|
418
|
-
cancelable: true,
|
|
419
|
-
bubbles: true,
|
|
420
|
-
});
|
|
421
|
-
jest.spyOn(wheelEvent, "preventDefault");
|
|
422
|
-
tabs.dispatchEvent(wheelEvent);
|
|
423
|
-
expect(wheelEvent.preventDefault).not.toHaveBeenCalled();
|
|
424
|
-
});
|
|
425
|
-
|
|
426
|
-
it("does not interfere when wheel input has a horizontal component", () => {
|
|
427
|
-
const tabs = renderOverflowing();
|
|
428
|
-
mockScrollDimensions(tabs, {
|
|
429
|
-
scrollWidth: 800,
|
|
430
|
-
clientWidth: 480,
|
|
431
|
-
scrollLeft: 100,
|
|
432
|
-
});
|
|
433
|
-
const wheelEvent = new WheelEvent("wheel", {
|
|
434
|
-
deltaY: 50,
|
|
435
|
-
deltaX: 30,
|
|
436
|
-
cancelable: true,
|
|
437
|
-
bubbles: true,
|
|
438
|
-
});
|
|
439
|
-
jest.spyOn(wheelEvent, "preventDefault");
|
|
440
|
-
tabs.dispatchEvent(wheelEvent);
|
|
441
|
-
expect(wheelEvent.preventDefault).not.toHaveBeenCalled();
|
|
442
|
-
});
|
|
443
|
-
|
|
444
|
-
it("does nothing when the tab list does not overflow", () => {
|
|
445
|
-
const tabs = renderOverflowing();
|
|
446
|
-
mockScrollDimensions(tabs, {
|
|
447
|
-
scrollWidth: 400,
|
|
448
|
-
clientWidth: 480,
|
|
449
|
-
scrollLeft: 0,
|
|
450
|
-
});
|
|
451
|
-
const wheelEvent = new WheelEvent("wheel", {
|
|
452
|
-
deltaY: 50,
|
|
453
|
-
deltaX: 0,
|
|
454
|
-
cancelable: true,
|
|
455
|
-
bubbles: true,
|
|
456
|
-
});
|
|
457
|
-
jest.spyOn(wheelEvent, "preventDefault");
|
|
458
|
-
tabs.dispatchEvent(wheelEvent);
|
|
459
|
-
expect(wheelEvent.preventDefault).not.toHaveBeenCalled();
|
|
460
|
-
});
|
|
461
|
-
});
|
|
462
|
-
});
|
package/src/index.ts
DELETED
package/src/styled.d.ts
DELETED
package/src/styles.ts
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import styled, { css } from "styled-components";
|
|
2
|
-
import { COMMON } from "@sproutsocial/seeds-react-system-props";
|
|
3
|
-
import { Button } from "@sproutsocial/seeds-react-button";
|
|
4
|
-
import { type TypeTabsProps } from "./TabsTypes";
|
|
5
|
-
|
|
6
|
-
interface TypeTabState {
|
|
7
|
-
isSelected: boolean;
|
|
8
|
-
}
|
|
9
|
-
type TypeFullWidth = Pick<TypeTabsProps, "fullWidth">;
|
|
10
|
-
interface TypeStyleProps extends TypeFullWidth, TypeTabState {}
|
|
11
|
-
|
|
12
|
-
const Container = styled.div<TypeTabsProps>`
|
|
13
|
-
display: ${(props) => (props.fullWidth ? "flex" : "inline-flex")};
|
|
14
|
-
margin: 0;
|
|
15
|
-
padding: 0;
|
|
16
|
-
min-width: 0;
|
|
17
|
-
max-width: 100%;
|
|
18
|
-
min-height: min-content;
|
|
19
|
-
flex-shrink: 0;
|
|
20
|
-
overflow-x: auto;
|
|
21
|
-
overflow-y: hidden;
|
|
22
|
-
scrollbar-width: none;
|
|
23
|
-
scroll-padding-inline: 48px;
|
|
24
|
-
scroll-behavior: smooth;
|
|
25
|
-
border-bottom: ${(props) => props.theme.borders[500]}
|
|
26
|
-
${(props) => props.theme.colors.container.border.base};
|
|
27
|
-
|
|
28
|
-
&::-webkit-scrollbar {
|
|
29
|
-
display: none;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
&[data-fade-right] {
|
|
33
|
-
-webkit-mask-image: linear-gradient(
|
|
34
|
-
to right,
|
|
35
|
-
black 0,
|
|
36
|
-
black calc(100% - 48px),
|
|
37
|
-
transparent
|
|
38
|
-
);
|
|
39
|
-
mask-image: linear-gradient(
|
|
40
|
-
to right,
|
|
41
|
-
black 0,
|
|
42
|
-
black calc(100% - 48px),
|
|
43
|
-
transparent
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
&[data-fade-left] {
|
|
48
|
-
-webkit-mask-image: linear-gradient(
|
|
49
|
-
to right,
|
|
50
|
-
transparent,
|
|
51
|
-
black 48px,
|
|
52
|
-
black 100%
|
|
53
|
-
);
|
|
54
|
-
mask-image: linear-gradient(to right, transparent, black 48px, black 100%);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
&[data-fade-left][data-fade-right] {
|
|
58
|
-
-webkit-mask-image: linear-gradient(
|
|
59
|
-
to right,
|
|
60
|
-
transparent,
|
|
61
|
-
black 48px,
|
|
62
|
-
black calc(100% - 48px),
|
|
63
|
-
transparent
|
|
64
|
-
);
|
|
65
|
-
mask-image: linear-gradient(
|
|
66
|
-
to right,
|
|
67
|
-
transparent,
|
|
68
|
-
black 48px,
|
|
69
|
-
black calc(100% - 48px),
|
|
70
|
-
transparent
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
${COMMON}
|
|
75
|
-
`;
|
|
76
|
-
|
|
77
|
-
export const TabButton = styled(Button)<TypeStyleProps>`
|
|
78
|
-
margin-bottom: -1px;
|
|
79
|
-
padding: ${(props) =>
|
|
80
|
-
`${props.theme.space[350]} ${
|
|
81
|
-
props.fullWidth ? 0 : props.theme.space[350]
|
|
82
|
-
}`};
|
|
83
|
-
color: ${(props) => props.theme.colors.text.headline};
|
|
84
|
-
border-radius: 0;
|
|
85
|
-
border-width: 0 0 3px;
|
|
86
|
-
width: 100%;
|
|
87
|
-
|
|
88
|
-
${(props) =>
|
|
89
|
-
props.fullWidth &&
|
|
90
|
-
css`
|
|
91
|
-
flex-grow: 1;
|
|
92
|
-
`};
|
|
93
|
-
|
|
94
|
-
${(props) =>
|
|
95
|
-
props.isSelected &&
|
|
96
|
-
css`
|
|
97
|
-
color: ${(props) => props.theme.colors.link.base};
|
|
98
|
-
border-color: transparent transparent
|
|
99
|
-
${(props) => props.theme.colors.button.primary.background.base};
|
|
100
|
-
`};
|
|
101
|
-
|
|
102
|
-
&:hover {
|
|
103
|
-
${(props) =>
|
|
104
|
-
props.isSelected &&
|
|
105
|
-
css`
|
|
106
|
-
color: ${(props) => props.theme.colors.link.hover};
|
|
107
|
-
`};
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
&:focus,
|
|
111
|
-
&:active {
|
|
112
|
-
box-shadow: none;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
&:active {
|
|
116
|
-
transform: none;
|
|
117
|
-
}
|
|
118
|
-
`;
|
|
119
|
-
export default Container;
|
package/tsconfig.json
DELETED
package/tsup.config.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "tsup";
|
|
2
|
-
|
|
3
|
-
export default defineConfig((options) => ({
|
|
4
|
-
entry: ["src/index.ts"],
|
|
5
|
-
format: ["cjs", "esm"],
|
|
6
|
-
clean: true,
|
|
7
|
-
legacyOutput: true,
|
|
8
|
-
dts: options.dts,
|
|
9
|
-
external: ["react"],
|
|
10
|
-
sourcemap: true,
|
|
11
|
-
metafile: options.metafile,
|
|
12
|
-
}));
|