@sproutsocial/seeds-react-accordion 0.4.32 → 0.4.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,536 +0,0 @@
1
- import React from "react";
2
- import {
3
- render,
4
- screen,
5
- fireEvent,
6
- } from "@sproutsocial/seeds-react-testing-library";
7
- import { Accordion } from "../Accordion";
8
- import { AccordionItem } from "../AccordionItem";
9
- import { AccordionTrigger } from "../AccordionTrigger";
10
- import { AccordionContent } from "../AccordionContent";
11
-
12
- describe("Accordion", () => {
13
- it("renders accordion with title", () => {
14
- render(
15
- <Accordion defaultValue={["item-1"]}>
16
- <AccordionItem value="item-1">
17
- <AccordionTrigger title="Test Title" />
18
- <AccordionContent>Content</AccordionContent>
19
- </AccordionItem>
20
- </Accordion>
21
- );
22
-
23
- expect(screen.getByText("Test Title")).toBeInTheDocument();
24
- });
25
-
26
- describe("relatedActions", () => {
27
- it("renders action buttons with proper aria-labels", () => {
28
- render(
29
- <Accordion defaultValue={["item-1"]}>
30
- <AccordionItem value="item-1">
31
- <AccordionTrigger
32
- title="Test"
33
- relatedActions={[
34
- {
35
- iconName: "alarm-clock",
36
- onClick: jest.fn(),
37
- "aria-label": "Set alarm",
38
- },
39
- {
40
- iconName: "ellipsis-horizontal-outline",
41
- onClick: jest.fn(),
42
- "aria-label": "More options",
43
- },
44
- ]}
45
- />
46
- <AccordionContent>Content</AccordionContent>
47
- </AccordionItem>
48
- </Accordion>
49
- );
50
-
51
- expect(screen.getByLabelText("Set alarm")).toBeInTheDocument();
52
- expect(screen.getByLabelText("More options")).toBeInTheDocument();
53
- });
54
-
55
- it("limits related actions to maximum of 2", () => {
56
- render(
57
- <Accordion defaultValue={["item-1"]}>
58
- <AccordionItem value="item-1">
59
- <AccordionTrigger
60
- title="Test"
61
- relatedActions={[
62
- {
63
- iconName: "alarm-clock",
64
- onClick: jest.fn(),
65
- "aria-label": "Action 1",
66
- },
67
- {
68
- iconName: "ellipsis-horizontal-outline",
69
- onClick: jest.fn(),
70
- "aria-label": "Action 2",
71
- },
72
- {
73
- iconName: "alarm-clock",
74
- onClick: jest.fn(),
75
- "aria-label": "Action 3",
76
- },
77
- {
78
- iconName: "ellipsis-horizontal-outline",
79
- onClick: jest.fn(),
80
- "aria-label": "Action 4",
81
- },
82
- ]}
83
- />
84
- <AccordionContent>Content</AccordionContent>
85
- </AccordionItem>
86
- </Accordion>
87
- );
88
-
89
- expect(screen.getByLabelText("Action 1")).toBeInTheDocument();
90
- expect(screen.getByLabelText("Action 2")).toBeInTheDocument();
91
- expect(screen.queryByLabelText("Action 3")).not.toBeInTheDocument();
92
- expect(screen.queryByLabelText("Action 4")).not.toBeInTheDocument();
93
- });
94
-
95
- it("renders icons with aria-hidden for accessibility", () => {
96
- render(
97
- <Accordion defaultValue={["item-1"]}>
98
- <AccordionItem value="item-1">
99
- <AccordionTrigger
100
- title="Test"
101
- relatedActions={[
102
- {
103
- iconName: "alarm-clock",
104
- onClick: jest.fn(),
105
- "aria-label": "Set alarm",
106
- },
107
- ]}
108
- />
109
- <AccordionContent>Content</AccordionContent>
110
- </AccordionItem>
111
- </Accordion>
112
- );
113
-
114
- const button = screen.getByLabelText("Set alarm");
115
- const icon = button.querySelector('[aria-hidden="true"]');
116
- expect(icon).toBeInTheDocument();
117
- });
118
-
119
- it("calls onClick handler when action button is clicked", () => {
120
- const mockOnClick = jest.fn();
121
- render(
122
- <Accordion defaultValue={["item-1"]}>
123
- <AccordionItem value="item-1">
124
- <AccordionTrigger
125
- title="Test"
126
- relatedActions={[
127
- {
128
- iconName: "alarm-clock",
129
- onClick: mockOnClick,
130
- "aria-label": "Set alarm",
131
- },
132
- ]}
133
- />
134
- <AccordionContent>Content</AccordionContent>
135
- </AccordionItem>
136
- </Accordion>
137
- );
138
-
139
- const actionButton = screen.getByLabelText("Set alarm");
140
- fireEvent.click(actionButton);
141
-
142
- expect(mockOnClick).toHaveBeenCalledTimes(1);
143
- });
144
-
145
- it("does not toggle accordion when clicking action button", () => {
146
- const mockOnClick = jest.fn();
147
- render(
148
- <Accordion defaultValue={["item-1"]}>
149
- <AccordionItem value="item-1">
150
- <AccordionTrigger
151
- title="Test"
152
- relatedActions={[
153
- {
154
- iconName: "alarm-clock",
155
- onClick: mockOnClick,
156
- "aria-label": "Set alarm",
157
- },
158
- ]}
159
- />
160
- <AccordionContent>Content</AccordionContent>
161
- </AccordionItem>
162
- </Accordion>
163
- );
164
-
165
- // Verify accordion is open initially
166
- expect(screen.getByText("Content")).toBeInTheDocument();
167
-
168
- // Click the action button
169
- const actionButton = screen.getByLabelText("Set alarm");
170
- fireEvent.click(actionButton);
171
-
172
- // Accordion should still be open
173
- expect(screen.getByText("Content")).toBeInTheDocument();
174
- expect(mockOnClick).toHaveBeenCalled();
175
- });
176
-
177
- it("handles multiple onClick handlers correctly", () => {
178
- const mockOnClick1 = jest.fn();
179
- const mockOnClick2 = jest.fn();
180
- render(
181
- <Accordion defaultValue={["item-1"]}>
182
- <AccordionItem value="item-1">
183
- <AccordionTrigger
184
- title="Test"
185
- relatedActions={[
186
- {
187
- iconName: "alarm-clock",
188
- onClick: mockOnClick1,
189
- "aria-label": "Action 1",
190
- },
191
- {
192
- iconName: "ellipsis-horizontal-outline",
193
- onClick: mockOnClick2,
194
- "aria-label": "Action 2",
195
- },
196
- ]}
197
- />
198
- <AccordionContent>Content</AccordionContent>
199
- </AccordionItem>
200
- </Accordion>
201
- );
202
-
203
- fireEvent.click(screen.getByLabelText("Action 1"));
204
- expect(mockOnClick1).toHaveBeenCalledTimes(1);
205
- expect(mockOnClick2).not.toHaveBeenCalled();
206
-
207
- fireEvent.click(screen.getByLabelText("Action 2"));
208
- expect(mockOnClick1).toHaveBeenCalledTimes(1);
209
- expect(mockOnClick2).toHaveBeenCalledTimes(1);
210
- });
211
- });
212
-
213
- describe("trigger icon", () => {
214
- it("renders default chevron-down icon", () => {
215
- const { container } = render(
216
- <Accordion defaultValue={["item-1"]}>
217
- <AccordionItem value="item-1">
218
- <AccordionTrigger title="Test Title" />
219
- <AccordionContent>Content</AccordionContent>
220
- </AccordionItem>
221
- </Accordion>
222
- );
223
-
224
- const icon = container.querySelector(".triggerIcon");
225
- expect(icon).toBeInTheDocument();
226
- });
227
-
228
- it("renders custom trigger icon", () => {
229
- const CustomIcon = () => <div data-testid="custom-icon">Custom Icon</div>;
230
-
231
- render(
232
- <Accordion defaultValue={["item-1"]} triggerIcon={<CustomIcon />}>
233
- <AccordionItem value="item-1">
234
- <AccordionTrigger title="Test Title" />
235
- <AccordionContent>Content</AccordionContent>
236
- </AccordionItem>
237
- </Accordion>
238
- );
239
-
240
- expect(screen.getByTestId("custom-icon")).toBeInTheDocument();
241
- });
242
-
243
- it("positions trigger icon on the right by default", () => {
244
- const { container } = render(
245
- <Accordion defaultValue={["item-1"]}>
246
- <AccordionItem value="item-1">
247
- <AccordionTrigger title="Test Title" />
248
- <AccordionContent>Content</AccordionContent>
249
- </AccordionItem>
250
- </Accordion>
251
- );
252
-
253
- const icon = container.querySelector(".triggerIcon");
254
- expect(icon).toBeInTheDocument();
255
- // Icon should be rendered after title (right position)
256
- const trigger = screen.getByText("Test Title").closest("button");
257
- const iconParent = icon?.parentElement ?? null;
258
- expect(trigger).toContainElement(iconParent);
259
- });
260
-
261
- it("positions trigger icon on the left when triggerPosition is 'left'", () => {
262
- const { container } = render(
263
- <Accordion defaultValue={["item-1"]} triggerPosition="left">
264
- <AccordionItem value="item-1">
265
- <AccordionTrigger title="Test Title" />
266
- <AccordionContent>Content</AccordionContent>
267
- </AccordionItem>
268
- </Accordion>
269
- );
270
-
271
- const icon = container.querySelector(".triggerIcon");
272
- expect(icon).toBeInTheDocument();
273
- const trigger = screen.getByText("Test Title").closest("button");
274
- const iconParent = icon?.parentElement ?? null;
275
- expect(trigger).toContainElement(iconParent);
276
- });
277
-
278
- it("positions trigger icon on the right when triggerPosition is 'right'", () => {
279
- const { container } = render(
280
- <Accordion defaultValue={["item-1"]} triggerPosition="right">
281
- <AccordionItem value="item-1">
282
- <AccordionTrigger title="Test Title" />
283
- <AccordionContent>Content</AccordionContent>
284
- </AccordionItem>
285
- </Accordion>
286
- );
287
-
288
- const icon = container.querySelector(".triggerIcon");
289
- expect(icon).toBeInTheDocument();
290
- });
291
- });
292
-
293
- describe("slots", () => {
294
- it("renders leftSlot content", () => {
295
- render(
296
- <Accordion defaultValue={["item-1"]}>
297
- <AccordionItem value="item-1">
298
- <AccordionTrigger
299
- title="Test Title"
300
- leftSlot={<div data-testid="left-content">Left Content</div>}
301
- />
302
- <AccordionContent>Content</AccordionContent>
303
- </AccordionItem>
304
- </Accordion>
305
- );
306
-
307
- expect(screen.getByTestId("left-content")).toBeInTheDocument();
308
- expect(screen.getByText("Left Content")).toBeInTheDocument();
309
- });
310
-
311
- it("renders rightSlot content", () => {
312
- render(
313
- <Accordion defaultValue={["item-1"]}>
314
- <AccordionItem value="item-1">
315
- <AccordionTrigger
316
- title="Test Title"
317
- rightSlot={<div data-testid="right-content">Right Content</div>}
318
- />
319
- <AccordionContent>Content</AccordionContent>
320
- </AccordionItem>
321
- </Accordion>
322
- );
323
-
324
- expect(screen.getByTestId("right-content")).toBeInTheDocument();
325
- expect(screen.getByText("Right Content")).toBeInTheDocument();
326
- });
327
-
328
- it("renders both leftSlot and rightSlot together", () => {
329
- render(
330
- <Accordion defaultValue={["item-1"]}>
331
- <AccordionItem value="item-1">
332
- <AccordionTrigger
333
- title="Test Title"
334
- leftSlot={<div data-testid="left-content">Left Content</div>}
335
- rightSlot={<div data-testid="right-content">Right Content</div>}
336
- />
337
- <AccordionContent>Content</AccordionContent>
338
- </AccordionItem>
339
- </Accordion>
340
- );
341
-
342
- expect(screen.getByTestId("left-content")).toBeInTheDocument();
343
- expect(screen.getByTestId("right-content")).toBeInTheDocument();
344
- expect(screen.getByText("Test Title")).toBeInTheDocument();
345
- });
346
-
347
- it("renders slots with complex components", () => {
348
- const LeftComponent = () => (
349
- <div data-testid="left-complex">
350
- <span>Icon</span>
351
- <span>Badge</span>
352
- </div>
353
- );
354
- const RightComponent = () => (
355
- <div data-testid="right-complex">
356
- <button>Action</button>
357
- </div>
358
- );
359
-
360
- render(
361
- <Accordion defaultValue={["item-1"]}>
362
- <AccordionItem value="item-1">
363
- <AccordionTrigger
364
- title="Test Title"
365
- leftSlot={<LeftComponent />}
366
- rightSlot={<RightComponent />}
367
- />
368
- <AccordionContent>Content</AccordionContent>
369
- </AccordionItem>
370
- </Accordion>
371
- );
372
-
373
- expect(screen.getByTestId("left-complex")).toBeInTheDocument();
374
- expect(screen.getByTestId("right-complex")).toBeInTheDocument();
375
- expect(screen.getByText("Icon")).toBeInTheDocument();
376
- expect(screen.getByText("Badge")).toBeInTheDocument();
377
- expect(screen.getByText("Action")).toBeInTheDocument();
378
- });
379
-
380
- it("positions leftSlot before title and rightSlot after title when triggerPosition is right", () => {
381
- render(
382
- <Accordion defaultValue={["item-1"]} triggerPosition="right">
383
- <AccordionItem value="item-1">
384
- <AccordionTrigger
385
- title="Test Title"
386
- leftSlot={<span data-testid="left">Left</span>}
387
- rightSlot={<span data-testid="right">Right</span>}
388
- />
389
- <AccordionContent>Content</AccordionContent>
390
- </AccordionItem>
391
- </Accordion>
392
- );
393
-
394
- const trigger = screen.getByText("Test Title").closest("button");
395
- expect(trigger).toBeInTheDocument();
396
- expect(screen.getByTestId("left")).toBeInTheDocument();
397
- expect(screen.getByTestId("right")).toBeInTheDocument();
398
- });
399
-
400
- it("renders slots correctly when triggerPosition is left", () => {
401
- render(
402
- <Accordion defaultValue={["item-1"]} triggerPosition="left">
403
- <AccordionItem value="item-1">
404
- <AccordionTrigger
405
- title="Test Title"
406
- leftSlot={<span data-testid="left">Left</span>}
407
- rightSlot={<span data-testid="right">Right</span>}
408
- />
409
- <AccordionContent>Content</AccordionContent>
410
- </AccordionItem>
411
- </Accordion>
412
- );
413
-
414
- expect(screen.getByTestId("left")).toBeInTheDocument();
415
- expect(screen.getByTestId("right")).toBeInTheDocument();
416
- expect(screen.getByText("Test Title")).toBeInTheDocument();
417
- });
418
- });
419
-
420
- describe("fontSize customization", () => {
421
- it("applies fontSize prop to AccordionTrigger", () => {
422
- render(
423
- <Accordion defaultValue={["item-1"]} styled={false}>
424
- <AccordionItem value="item-1">
425
- <AccordionTrigger title="Custom Font Size" fontSize={400} />
426
- <AccordionContent>Content</AccordionContent>
427
- </AccordionItem>
428
- </Accordion>
429
- );
430
-
431
- const title = screen.getByText("Custom Font Size");
432
- expect(title).toBeInTheDocument();
433
- // Verify component renders without errors when fontSize prop is provided
434
- });
435
-
436
- it("applies typeScale prop to AccordionContent", () => {
437
- render(
438
- <Accordion defaultValue={["item-1"]} styled={false}>
439
- <AccordionItem value="item-1">
440
- <AccordionTrigger title="Test" />
441
- <AccordionContent typeScale={300}>Custom Content</AccordionContent>
442
- </AccordionItem>
443
- </Accordion>
444
- );
445
-
446
- const content = screen.getByText("Custom Content");
447
- expect(content).toBeInTheDocument();
448
- // Verify component renders without errors when typeScale prop is provided
449
- });
450
- });
451
-
452
- describe("headingLevel", () => {
453
- it("renders h4 heading by default", () => {
454
- const { container } = render(
455
- <Accordion defaultValue={["item-1"]}>
456
- <AccordionItem value="item-1">
457
- <AccordionTrigger title="Test Title" />
458
- <AccordionContent>Content</AccordionContent>
459
- </AccordionItem>
460
- </Accordion>
461
- );
462
-
463
- const heading = container.querySelector("h4");
464
- expect(heading).toBeInTheDocument();
465
- expect(heading).toHaveTextContent("Test Title");
466
- });
467
-
468
- it("renders h2 heading when headingLevel is h2", () => {
469
- const { container } = render(
470
- <Accordion defaultValue={["item-1"]}>
471
- <AccordionItem value="item-1">
472
- <AccordionTrigger title="Test Title" headingLevel="h2" />
473
- <AccordionContent>Content</AccordionContent>
474
- </AccordionItem>
475
- </Accordion>
476
- );
477
-
478
- const heading = container.querySelector("h2");
479
- expect(heading).toBeInTheDocument();
480
- expect(heading).toHaveTextContent("Test Title");
481
- });
482
-
483
- it("renders h3 heading when headingLevel is h3", () => {
484
- const { container } = render(
485
- <Accordion defaultValue={["item-1"]}>
486
- <AccordionItem value="item-1">
487
- <AccordionTrigger title="Test Title" headingLevel="h3" />
488
- <AccordionContent>Content</AccordionContent>
489
- </AccordionItem>
490
- </Accordion>
491
- );
492
-
493
- const heading = container.querySelector("h3");
494
- expect(heading).toBeInTheDocument();
495
- expect(heading).toHaveTextContent("Test Title");
496
- });
497
-
498
- it("renders h1 heading when headingLevel is h1", () => {
499
- const { container } = render(
500
- <Accordion defaultValue={["item-1"]}>
501
- <AccordionItem value="item-1">
502
- <AccordionTrigger title="Test Title" headingLevel="h1" />
503
- <AccordionContent>Content</AccordionContent>
504
- </AccordionItem>
505
- </Accordion>
506
- );
507
-
508
- const heading = container.querySelector("h1");
509
- expect(heading).toBeInTheDocument();
510
- expect(heading).toHaveTextContent("Test Title");
511
- });
512
-
513
- it("renders correct heading level for multiple accordion items", () => {
514
- const { container } = render(
515
- <Accordion defaultValue={["item-1", "item-2"]}>
516
- <AccordionItem value="item-1">
517
- <AccordionTrigger title="First Item" headingLevel="h2" />
518
- <AccordionContent>Content 1</AccordionContent>
519
- </AccordionItem>
520
- <AccordionItem value="item-2">
521
- <AccordionTrigger title="Second Item" headingLevel="h3" />
522
- <AccordionContent>Content 2</AccordionContent>
523
- </AccordionItem>
524
- </Accordion>
525
- );
526
-
527
- const h2Heading = container.querySelector("h2");
528
- const h3Heading = container.querySelector("h3");
529
-
530
- expect(h2Heading).toBeInTheDocument();
531
- expect(h2Heading).toHaveTextContent("First Item");
532
- expect(h3Heading).toBeInTheDocument();
533
- expect(h3Heading).toHaveTextContent("Second Item");
534
- });
535
- });
536
- });
package/src/index.ts DELETED
@@ -1,7 +0,0 @@
1
- import { Accordion } from "./Accordion";
2
- import { AccordionItem } from "./AccordionItem";
3
- import { AccordionContent } from "./AccordionContent";
4
- import { AccordionTrigger } from "./AccordionTrigger";
5
-
6
- export { Accordion, AccordionItem, AccordionContent, AccordionTrigger };
7
- export * from "./AccordionTypes";
package/src/styled.d.ts DELETED
@@ -1,7 +0,0 @@
1
- import "styled-components";
2
- import { TypeTheme } from "@sproutsocial/seeds-react-theme";
3
-
4
- declare module "styled-components" {
5
- // eslint-disable-next-line @typescript-eslint/no-empty-interface
6
- export interface DefaultTheme extends TypeTheme {}
7
- }