@purpurds/accordion 5.2.0 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@purpurds/accordion",
3
- "version": "5.2.0",
3
+ "version": "5.4.0",
4
4
  "license": "AGPL-3.0-only",
5
5
  "main": "./dist/accordion.cjs.js",
6
6
  "types": "./dist/accordion.d.ts",
@@ -16,10 +16,10 @@
16
16
  "dependencies": {
17
17
  "classnames": "~2.5.0",
18
18
  "@radix-ui/react-accordion": "~1.1.2",
19
- "@purpurds/tokens": "5.2.0",
20
- "@purpurds/icon": "5.2.0",
21
- "@purpurds/heading": "5.2.0",
22
- "@purpurds/paragraph": "5.2.0"
19
+ "@purpurds/tokens": "5.4.0",
20
+ "@purpurds/icon": "5.4.0",
21
+ "@purpurds/paragraph": "5.4.0",
22
+ "@purpurds/heading": "5.4.0"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@rushstack/eslint-patch": "~1.10.0",
@@ -30,7 +30,7 @@
30
30
  "@testing-library/dom": "~9.3.3",
31
31
  "@testing-library/jest-dom": "~6.4.0",
32
32
  "@testing-library/react": "~14.3.0",
33
- "@types/node": "18",
33
+ "@types/node": "20.12.12",
34
34
  "@types/react-dom": "~18.3.0",
35
35
  "@types/react": "~18.3.0",
36
36
  "eslint-plugin-testing-library": "~6.2.0",
package/readme.mdx CHANGED
@@ -34,20 +34,20 @@ In MyComponent.tsx
34
34
  #### Default
35
35
 
36
36
  ```tsx
37
- import { Accordion, AccordionItem } from "@purpurds/purpur";
37
+ import { Accordion } from "@purpurds/purpur";
38
38
 
39
39
  export const MyComponent = () => {
40
40
  return (
41
41
  <Accordion title="Accordion title" titleVariant="title-100">
42
- <AccordionItem title="Section title" value="1">
42
+ <Accordion.Item title="Section title" value="1">
43
43
  Place body text here. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus at
44
44
  rutrum nulla.
45
- </AccordionItem>
45
+ </Accordion.Item>
46
46
 
47
- <AccordionItem title="Section title" value="2">
47
+ <Accordion.Item title="Section title" value="2">
48
48
  Place body text here. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus at
49
49
  rutrum nulla.
50
- </AccordionItem>
50
+ </Accordion.Item>
51
51
  </Accordion>
52
52
  );
53
53
  };
@@ -59,17 +59,17 @@ export const MyComponent = () => {
59
59
  export const MyComponent = () => {
60
60
  return (
61
61
  <Accordion negative title="Accordion title">
62
- <AccordionItem title="Section title1">
62
+ <Accordion.Item title="Section title1">
63
63
  Place body text here. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus at
64
64
  rutrum nulla.
65
65
  <a href="https://telia.se">Link1</a>
66
- </AccordionItem>
66
+ </Accordion.Item>
67
67
 
68
- <AccordionItem title="Section title2">
68
+ <Accordion.Item title="Section title2">
69
69
  Place body text here. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus at
70
70
  rutrum nulla.
71
71
  <a href="https://telia.se">Link2</a>
72
- </AccordionItem>
72
+ </Accordion.Item>
73
73
  </Accordion>
74
74
  );
75
75
  };
@@ -2,7 +2,6 @@ import React from "react";
2
2
  import type { Meta, StoryObj } from "@storybook/react";
3
3
 
4
4
  import { Accordion } from "./accordion";
5
- import { AccordionItem as AccordionItemComponent } from "./accordion-item";
6
5
 
7
6
  const meta: Meta<typeof Accordion> = {
8
7
  title: "Components/Accordion",
@@ -19,12 +18,12 @@ const meta: Meta<typeof Accordion> = {
19
18
  };
20
19
 
21
20
  export default meta;
22
- type Story = StoryObj<typeof AccordionItemComponent>;
21
+ type Story = StoryObj<typeof Accordion.Item>;
23
22
 
24
23
  export const AccordionItem: Story = {
25
24
  render: (args) => (
26
25
  <Accordion negative={args.negative}>
27
- <AccordionItemComponent {...args} />
26
+ <Accordion.Item {...args} />
28
27
  </Accordion>
29
28
  ),
30
29
  args: {
@@ -27,6 +27,11 @@ export type AccordionItemProps = {
27
27
  * Value is used to identify the accordion. By default title is used for that purpose. If there are identical titles in the accordion, then value should be defined.
28
28
  * */
29
29
  value?: string;
30
+ /**
31
+ * onClick is called when accordion item is expanded or collapsed
32
+ * event.target.dataset.state will be either "open" or "closed"
33
+ */
34
+ onClick?: () => void;
30
35
  };
31
36
 
32
37
  export const AccordionItem = ({
@@ -34,6 +39,7 @@ export const AccordionItem = ({
34
39
  className,
35
40
  title,
36
41
  negative,
42
+ onClick,
37
43
  ...props
38
44
  }: AccordionItemProps) => {
39
45
  const classes = cx([
@@ -47,7 +53,10 @@ export const AccordionItem = ({
47
53
  return (
48
54
  <RadixAccordion.Item className={classes} value={title} {...props}>
49
55
  <RadixAccordion.Header className={cx(`${rootClassName}__header`)} asChild>
50
- <RadixAccordion.Trigger className={cx(`${rootClassName}__trigger`, className)}>
56
+ <RadixAccordion.Trigger
57
+ onClick={onClick}
58
+ className={cx(`${rootClassName}__trigger`, className)}
59
+ >
51
60
  <Heading tag="h3" variant="title-100" className={cx(`${rootClassName}__title`)}>
52
61
  {title}
53
62
  </Heading>
@@ -2,7 +2,6 @@ import React from "react";
2
2
  import type { Meta, StoryObj } from "@storybook/react";
3
3
 
4
4
  import { Accordion } from "./accordion";
5
- import { AccordionItem } from "./accordion-item";
6
5
 
7
6
  const meta: Meta<typeof Accordion> = {
8
7
  title: "Components/Accordion",
@@ -24,20 +23,20 @@ type Story = StoryObj<typeof Accordion>;
24
23
  export const Showcase: Story = {
25
24
  render: (args) => (
26
25
  <Accordion {...args}>
27
- <AccordionItem title="Section title" value="1">
26
+ <Accordion.Item title="Section title" value="1">
28
27
  Place body text here. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus at
29
28
  rutrum nulla.
30
- </AccordionItem>
29
+ </Accordion.Item>
31
30
 
32
- <AccordionItem title="Section title" value="2">
31
+ <Accordion.Item title="Section title" value="2">
33
32
  Place body text here. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus at
34
33
  rutrum nulla.
35
- </AccordionItem>
34
+ </Accordion.Item>
36
35
 
37
- <AccordionItem title="Section title" value="3">
36
+ <Accordion.Item title="Section title" value="3">
38
37
  Place body text here. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus at
39
38
  rutrum nulla.
40
- </AccordionItem>
39
+ </Accordion.Item>
41
40
  </Accordion>
42
41
  ),
43
42
  args: {
@@ -1,21 +1,28 @@
1
1
  import React from "react";
2
2
  import * as matchers from "@testing-library/jest-dom/matchers";
3
3
  import { cleanup, fireEvent, render, screen } from "@testing-library/react";
4
- import { afterEach, describe, expect, it } from "vitest";
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
5
5
 
6
6
  import { Accordion } from "./accordion";
7
- import { AccordionItem } from "./accordion-item";
8
7
 
9
8
  expect.extend(matchers);
10
9
 
10
+ const onClickFunction = vi.fn();
11
+
11
12
  const setup = () =>
12
13
  render(
13
14
  <Accordion title="accordion heading">
14
- <AccordionItem title="Test heading">item content</AccordionItem>
15
+ <Accordion.Item title="Test heading" onClick={onClickFunction}>
16
+ item content
17
+ </Accordion.Item>
15
18
  </Accordion>
16
19
  );
17
20
 
18
21
  describe("Accordion", () => {
22
+ beforeEach(() => {
23
+ vi.clearAllMocks();
24
+ });
25
+
19
26
  afterEach(cleanup);
20
27
 
21
28
  it("should render accordion heading", () => {
@@ -51,9 +58,9 @@ describe("Accordion", () => {
51
58
  it("should render custom accordion item content", () => {
52
59
  render(
53
60
  <Accordion title="accordion heading">
54
- <AccordionItem title="Test heading">
61
+ <Accordion.Item title="Test heading">
55
62
  <a href="/test">Test link</a>
56
- </AccordionItem>
63
+ </Accordion.Item>
57
64
  </Accordion>
58
65
  );
59
66
 
@@ -62,4 +69,18 @@ describe("Accordion", () => {
62
69
 
63
70
  expect(screen.getByRole("link", { name: "Test link" })).toBeDefined();
64
71
  });
72
+
73
+ it("should send onClick event when trigger is clicked", () => {
74
+ setup();
75
+
76
+ const trigger = screen.getByRole("button");
77
+
78
+ fireEvent.click(trigger);
79
+ expect(onClickFunction).toHaveBeenCalled();
80
+ expect(onClickFunction.mock.calls[0][0].target.dataset.state).toBe("open");
81
+
82
+ fireEvent.click(trigger);
83
+ expect(onClickFunction).toHaveBeenCalled();
84
+ expect(onClickFunction.mock.calls[0][0].target.dataset.state).toBe("closed");
85
+ });
65
86
  });
package/src/accordion.tsx CHANGED
@@ -4,7 +4,7 @@ import * as RadixAccordion from "@radix-ui/react-accordion";
4
4
  import c from "classnames/bind";
5
5
 
6
6
  import styles from "./accordion.module.scss";
7
- import { isAccordionItem } from "./accordion-item";
7
+ import { AccordionItem, isAccordionItem } from "./accordion-item";
8
8
 
9
9
  const cx = c.bind(styles);
10
10
 
@@ -64,4 +64,6 @@ export const Accordion = ({
64
64
  );
65
65
  };
66
66
 
67
+ Accordion.Item = AccordionItem;
68
+
67
69
  Accordion.displayName = "Accordion";