@purpurds/accordion 5.24.3 → 5.25.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/dist/LICENSE.txt +3 -165
- package/dist/accordion-item.d.ts +9 -8
- package/dist/accordion-item.d.ts.map +1 -1
- package/dist/accordion.cjs.js +5 -5
- package/dist/accordion.cjs.js.map +1 -1
- package/dist/accordion.d.ts +10 -3
- package/dist/accordion.d.ts.map +1 -1
- package/dist/accordion.es.js +276 -907
- package/dist/accordion.es.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +5 -6
- package/src/accordion-item.module.scss +45 -56
- package/src/accordion-item.tsx +73 -56
- package/src/accordion.stories.tsx +39 -17
- package/src/accordion.test.tsx +3 -17
- package/src/accordion.tsx +25 -22
package/dist/styles.css
CHANGED
@@ -1 +1 @@
|
|
1
|
-
._purpur-accordion_u887g_1{container:accordion/inline-size}._purpur-accordion_u887g_1 ._purpur-accordion__title_u887g_4{margin-bottom:var(--purpur-spacing-300);color:var(--purpur-color-text-default)}@container accordion (min-width: 600px){._purpur-accordion_u887g_1 ._purpur-accordion__title_u887g_4{margin-bottom:var(--purpur-spacing-400)}}._purpur-accordion--negative_u887g_13{background-color:var(--purpur-color-purple-900)}._purpur-accordion--negative_u887g_13 ._purpur-accordion__title_u887g_4{color:var(--purpur-color-text-default-negative)}._purpur-accordion-
|
1
|
+
._purpur-accordion_u887g_1{container:accordion/inline-size}._purpur-accordion_u887g_1 ._purpur-accordion__title_u887g_4{margin-bottom:var(--purpur-spacing-300);color:var(--purpur-color-text-default)}@container accordion (min-width: 600px){._purpur-accordion_u887g_1 ._purpur-accordion__title_u887g_4{margin-bottom:var(--purpur-spacing-400)}}._purpur-accordion--negative_u887g_13{background-color:var(--purpur-color-purple-900)}._purpur-accordion--negative_u887g_13 ._purpur-accordion__title_u887g_4{color:var(--purpur-color-text-default-negative)}._purpur-accordion-item_29ds4_1{border-bottom:var(--purpur-border-width-xs) solid var(--purpur-color-border-weak)}._purpur-accordion-item_29ds4_1:has(button:hover){border-bottom-color:transparent}._purpur-accordion-item_29ds4_1:nth-of-type(1){border-top:var(--purpur-border-width-xs) solid var(--purpur-color-border-weak)}._purpur-accordion-item__header_29ds4_10{display:flex}._purpur-accordion-item__trigger_29ds4_13{border:none;padding:0;width:100%;text-align:left;font-family:inherit;font-size:inherit;font-weight:inherit;color:inherit;line-height:inherit;background-color:transparent;transition:background-color var(--purpur-motion-duration-150) ease;display:flex;align-items:center;justify-content:space-between;column-gap:var(--purpur-spacing-100);padding:var(--purpur-spacing-200) var(--purpur-spacing-200) var(--purpur-spacing-200) 0;cursor:pointer;outline:none}@container accordion (min-width: 600px){._purpur-accordion-item__trigger_29ds4_13{padding:var(--purpur-spacing-300) var(--purpur-spacing-300) var(--purpur-spacing-300) 0}}@container accordion (min-width: 1024px){._purpur-accordion-item__trigger_29ds4_13{padding:var(--purpur-spacing-400) var(--purpur-spacing-300) var(--purpur-spacing-400) 0}}._purpur-accordion-item__trigger_29ds4_13[data-state=open]>._purpur-accordion-item__trigger__icon_29ds4_43{transform:rotate(180deg)}._purpur-accordion-item__trigger_29ds4_13:hover{background-color:var(--purpur-color-background-interactive-transparent-hover)}._purpur-accordion-item__trigger_29ds4_13:hover ._purpur-accordion-item__title_29ds4_49,._purpur-accordion-item__trigger_29ds4_13:hover__icon{color:var(--purpur-color-text-interactive-primary-hover)}._purpur-accordion-item__trigger_29ds4_13:active{background-color:var(--purpur-color-background-interactive-transparent-active)}._purpur-accordion-item__trigger_29ds4_13:active ._purpur-accordion-item__title_29ds4_49,._purpur-accordion-item__trigger_29ds4_13:active__icon{color:var(--purpur-color-text-interactive-primary-active)}._purpur-accordion-item__trigger_29ds4_13:focus-visible{outline:none;box-shadow:0 0 0 var(--purpur-border-width-sm) var(--purpur-color-border-interactive-focus);box-sizing:content-box}._purpur-accordion-item__rotate_29ds4_63>._purpur-accordion-item__icon_29ds4_63{transform:rotate(180deg)}._purpur-accordion-item__content_29ds4_66{overflow:hidden;display:grid;grid-template-rows:1fr;padding:var(--purpur-spacing-200) 0;transition:var(--purpur-motion-duration-200) var(--purpur-motion-easing-ease-in-out);transition-property:grid-template-rows,padding}._purpur-accordion-item__content_29ds4_66[aria-hidden=true]{grid-template-rows:0fr;padding:0;visibility:hidden}._purpur-accordion-item__contentText_29ds4_79{overflow:hidden;max-width:calc(var(--purpur-spacing-1200) / .16)}._purpur-accordion-item__icon_29ds4_63{flex-shrink:0;height:var(--purpur-spacing-300);width:var(--purpur-spacing-300);transition:transform var(--purpur-motion-duration-150) ease-in-out}._purpur-accordion-item_29ds4_1 ._purpur-accordion-item__title_29ds4_49{max-width:100%}._purpur-accordion-item_29ds4_1 ._purpur-accordion-item__title_29ds4_49,._purpur-accordion-item__icon_29ds4_63{color:var(--purpur-color-text-interactive-primary)}._purpur-accordion-item__contentText_29ds4_79 p{color:var(--purpur-color-text-default)}._purpur-accordion-item--negative_29ds4_98{border-bottom:var(--purpur-border-width-xs) solid var(--purpur-color-border-weak-negative)}._purpur-accordion-item--negative_29ds4_98:nth-of-type(1){border-top:var(--purpur-border-width-xs) solid var(--purpur-color-border-weak-negative)}._purpur-accordion-item--negative_29ds4_98 ._purpur-accordion-item__title_29ds4_49,._purpur-accordion-item--negative_29ds4_98 ._purpur-accordion-item__icon_29ds4_63{color:var(--purpur-color-text-interactive-primary-negative)}._purpur-accordion-item--negative_29ds4_98 ._purpur-accordion-item__trigger_29ds4_13:hover{background-color:var(--purpur-color-background-interactive-transparent-negative-hover)}._purpur-accordion-item--negative_29ds4_98 ._purpur-accordion-item__trigger_29ds4_13:hover ._purpur-accordion-item__title_29ds4_49,._purpur-accordion-item--negative_29ds4_98 ._purpur-accordion-item__trigger_29ds4_13:hover ._purpur-accordion-item__icon_29ds4_63{color:var(--purpur-color-border-interactive-primary-negative-hover)}._purpur-accordion-item--negative_29ds4_98 ._purpur-accordion-item__trigger_29ds4_13:active{background-color:var(--purpur-color-background-interactive-transparent-negative-active)}._purpur-accordion-item--negative_29ds4_98 ._purpur-accordion-item__trigger_29ds4_13:active ._purpur-accordion-item__title_29ds4_49,._purpur-accordion-item--negative_29ds4_98 ._purpur-accordion-item__trigger_29ds4_13:active ._purpur-accordion-item__icon_29ds4_63{color:var(--purpur-color-border-interactive-primary-negative-active)}._purpur-accordion-item--negative_29ds4_98 ._purpur-accordion-item__contentText_29ds4_79 p{color:var(--purpur-color-text-default-negative)}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@purpurds/accordion",
|
3
|
-
"version": "5.
|
3
|
+
"version": "5.25.0",
|
4
4
|
"license": "AGPL-3.0-only",
|
5
5
|
"main": "./dist/accordion.cjs.js",
|
6
6
|
"types": "./dist/accordion.d.ts",
|
@@ -15,11 +15,10 @@
|
|
15
15
|
"source": "src/accordion.tsx",
|
16
16
|
"dependencies": {
|
17
17
|
"classnames": "~2.5.0",
|
18
|
-
"@
|
19
|
-
"@purpurds/
|
20
|
-
"@purpurds/
|
21
|
-
"@purpurds/paragraph": "5.
|
22
|
-
"@purpurds/icon": "5.24.3"
|
18
|
+
"@purpurds/tokens": "5.25.0",
|
19
|
+
"@purpurds/heading": "5.25.0",
|
20
|
+
"@purpurds/icon": "5.25.0",
|
21
|
+
"@purpurds/paragraph": "5.25.0"
|
23
22
|
},
|
24
23
|
"devDependencies": {
|
25
24
|
"@rushstack/eslint-patch": "~1.10.0",
|
@@ -2,9 +2,11 @@
|
|
2
2
|
|
3
3
|
.purpur-accordion-item {
|
4
4
|
$root: &;
|
5
|
-
overflow: hidden;
|
6
5
|
border-bottom: var(--purpur-border-width-xs) solid var(--purpur-color-border-weak);
|
7
6
|
|
7
|
+
&:has(button:hover) {
|
8
|
+
border-bottom-color: transparent;
|
9
|
+
}
|
8
10
|
&:nth-of-type(1) {
|
9
11
|
border-top: var(--purpur-border-width-xs) solid var(--purpur-color-border-weak);
|
10
12
|
}
|
@@ -40,22 +42,56 @@
|
|
40
42
|
@container accordion (min-width: #{$purpur-breakpoint-lg}) {
|
41
43
|
padding: var(--purpur-spacing-400) var(--purpur-spacing-300) var(--purpur-spacing-400) 0;
|
42
44
|
}
|
43
|
-
}
|
44
45
|
|
45
|
-
|
46
|
-
|
46
|
+
&[data-state="open"] > &__icon {
|
47
|
+
transform: rotate(180deg);
|
48
|
+
}
|
49
|
+
&:hover {
|
50
|
+
background-color: var(--purpur-color-background-interactive-transparent-hover);
|
51
|
+
|
52
|
+
#{$root}__title,
|
53
|
+
&__icon {
|
54
|
+
color: var(--purpur-color-text-interactive-primary-hover);
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
&:active {
|
59
|
+
background-color: var(--purpur-color-background-interactive-transparent-active);
|
60
|
+
|
61
|
+
#{$root}__title,
|
62
|
+
&__icon {
|
63
|
+
color: var(--purpur-color-text-interactive-primary-active);
|
64
|
+
}
|
65
|
+
}
|
66
|
+
&:focus-visible {
|
67
|
+
outline: none;
|
68
|
+
box-shadow: 0 0 0 var(--purpur-border-width-sm) var(--purpur-color-border-interactive-focus);
|
69
|
+
box-sizing: content-box;
|
70
|
+
}
|
47
71
|
}
|
48
72
|
|
49
|
-
&
|
50
|
-
|
73
|
+
&__rotate > &__icon {
|
74
|
+
transform: rotate(180deg);
|
51
75
|
}
|
52
76
|
|
53
|
-
&__content
|
54
|
-
|
77
|
+
&__content {
|
78
|
+
overflow: hidden;
|
79
|
+
display: grid;
|
80
|
+
grid-template-rows: 1fr;
|
81
|
+
padding: var(--purpur-spacing-200) 0;
|
82
|
+
transition: var(--purpur-motion-duration-200) var(--purpur-motion-easing-ease-in-out);
|
83
|
+
// Needs to be after transition otherwise it will overwrite it
|
84
|
+
transition-property: grid-template-rows, padding;
|
85
|
+
|
86
|
+
&[aria-hidden="true"] {
|
87
|
+
grid-template-rows: 0fr;
|
88
|
+
padding: 0;
|
89
|
+
visibility: hidden;
|
90
|
+
}
|
55
91
|
}
|
56
92
|
|
57
93
|
&__contentText {
|
58
|
-
|
94
|
+
overflow: hidden;
|
59
95
|
max-width: calc(var(--purpur-spacing-1200) / 0.16);
|
60
96
|
}
|
61
97
|
|
@@ -66,15 +102,6 @@
|
|
66
102
|
transition: transform var(--purpur-motion-duration-150) ease-in-out;
|
67
103
|
}
|
68
104
|
|
69
|
-
&__trigger[data-state="open"] > &__icon {
|
70
|
-
transform: rotate(180deg);
|
71
|
-
}
|
72
|
-
|
73
|
-
&:has(:focus-visible) {
|
74
|
-
outline: none;
|
75
|
-
box-shadow: 0 0 0 var(--purpur-border-width-sm) var(--purpur-color-border-interactive-focus);
|
76
|
-
}
|
77
|
-
|
78
105
|
#{$root}__title {
|
79
106
|
max-width: 100%;
|
80
107
|
}
|
@@ -84,24 +111,6 @@
|
|
84
111
|
color: var(--purpur-color-text-interactive-primary);
|
85
112
|
}
|
86
113
|
|
87
|
-
&__trigger:hover {
|
88
|
-
background-color: var(--purpur-color-background-interactive-transparent-hover);
|
89
|
-
|
90
|
-
#{$root}__title,
|
91
|
-
&__icon {
|
92
|
-
color: var(--purpur-color-text-interactive-primary-hover);
|
93
|
-
}
|
94
|
-
}
|
95
|
-
|
96
|
-
&__trigger:active {
|
97
|
-
background-color: var(--purpur-color-background-interactive-transparent-active);
|
98
|
-
|
99
|
-
#{$root}__title,
|
100
|
-
&__icon {
|
101
|
-
color: var(--purpur-color-text-interactive-primary-active);
|
102
|
-
}
|
103
|
-
}
|
104
|
-
|
105
114
|
&__contentText p {
|
106
115
|
color: var(--purpur-color-text-default);
|
107
116
|
}
|
@@ -141,23 +150,3 @@
|
|
141
150
|
}
|
142
151
|
}
|
143
152
|
}
|
144
|
-
|
145
|
-
@keyframes slideDown {
|
146
|
-
from {
|
147
|
-
height: 0;
|
148
|
-
}
|
149
|
-
|
150
|
-
to {
|
151
|
-
height: var(--radix-accordion-content-height);
|
152
|
-
}
|
153
|
-
}
|
154
|
-
|
155
|
-
@keyframes slideUp {
|
156
|
-
from {
|
157
|
-
height: var(--radix-accordion-content-height);
|
158
|
-
}
|
159
|
-
|
160
|
-
to {
|
161
|
-
height: 0;
|
162
|
-
}
|
163
|
-
}
|
package/src/accordion-item.tsx
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
import type {
|
2
|
-
import React, {
|
1
|
+
import type { ReactNode } from "react";
|
2
|
+
import React, { useContext, useId, useState } from "react";
|
3
3
|
import type { HeadingTagType } from "@purpurds/heading";
|
4
4
|
import { Heading } from "@purpurds/heading";
|
5
5
|
import { IconChevronDown } from "@purpurds/icon";
|
6
6
|
import { Paragraph } from "@purpurds/paragraph";
|
7
|
-
import * as RadixAccordion from "@radix-ui/react-accordion";
|
8
7
|
import c from "classnames/bind";
|
9
8
|
|
9
|
+
import { NegativeContext } from "./accordion";
|
10
10
|
import styles from "./accordion-item.module.scss";
|
11
11
|
|
12
12
|
const cx = c.bind(styles);
|
@@ -21,13 +21,10 @@ export type AccordionItemProps = {
|
|
21
21
|
["data-testid"]?: string;
|
22
22
|
children: ReactNode;
|
23
23
|
/**
|
24
|
-
*
|
25
|
-
|
24
|
+
* @deprecated
|
25
|
+
*/
|
26
26
|
negative?: boolean;
|
27
27
|
className?: string;
|
28
|
-
/**
|
29
|
-
* Title of the accordion item
|
30
|
-
* */
|
31
28
|
title: string;
|
32
29
|
/**
|
33
30
|
* This is the heading tag used for the accordion item title. Defaults to h3.
|
@@ -35,9 +32,13 @@ export type AccordionItemProps = {
|
|
35
32
|
*/
|
36
33
|
titleTag?: HeadingTagType;
|
37
34
|
/**
|
38
|
-
*
|
39
|
-
|
35
|
+
* @deprecated
|
36
|
+
*/
|
40
37
|
value?: string;
|
38
|
+
/**
|
39
|
+
* Makes it possible to set the initial state to opened.
|
40
|
+
* */
|
41
|
+
initialOpen?: boolean;
|
41
42
|
/**
|
42
43
|
* onClick is called when accordion item is expanded or collapsed
|
43
44
|
* event.currentTarget.dataset.state will be either "open" or "closed"
|
@@ -45,51 +46,67 @@ export type AccordionItemProps = {
|
|
45
46
|
onClick?: (event: AccordionItemOnClickEvent) => void;
|
46
47
|
};
|
47
48
|
|
48
|
-
export const AccordionItem =
|
49
|
-
|
49
|
+
export const AccordionItem = ({
|
50
|
+
children,
|
51
|
+
className,
|
52
|
+
title,
|
53
|
+
titleTag = "h3",
|
54
|
+
initialOpen = false,
|
55
|
+
onClick,
|
56
|
+
...props
|
57
|
+
}: AccordionItemProps) => {
|
58
|
+
const negative = useContext(NegativeContext);
|
59
|
+
const uid = useId();
|
60
|
+
const [hidden, setHidden] = useState(!initialOpen);
|
61
|
+
|
62
|
+
const classes = cx([
|
63
|
+
className,
|
64
|
+
rootClassName,
|
50
65
|
{
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
titleTag = "h3",
|
55
|
-
negative,
|
56
|
-
onClick,
|
57
|
-
...props
|
58
|
-
}: AccordionItemProps,
|
59
|
-
ref: ForwardedRef<HTMLButtonElement>
|
60
|
-
) => {
|
61
|
-
const classes = cx([
|
62
|
-
className,
|
63
|
-
rootClassName,
|
64
|
-
{
|
65
|
-
[`${rootClassName}--negative`]: negative,
|
66
|
-
},
|
67
|
-
]);
|
66
|
+
[`${rootClassName}--negative`]: negative,
|
67
|
+
},
|
68
|
+
]);
|
68
69
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
)
|
70
|
+
return (
|
71
|
+
<div className={classes} {...props}>
|
72
|
+
<Heading
|
73
|
+
tag={titleTag}
|
74
|
+
variant="title-100"
|
75
|
+
className={cx([`${rootClassName}__header`, `${rootClassName}__title`])}
|
76
|
+
>
|
77
|
+
<button
|
78
|
+
type="button"
|
79
|
+
data-state={hidden ? "open" : "close"} // The state is actually set in the onClick, so reversing the data- output state here
|
80
|
+
onClick={(e: AccordionItemOnClickEvent) => {
|
81
|
+
onClick && onClick(e);
|
82
|
+
setHidden(!hidden);
|
83
|
+
}}
|
84
|
+
className={cx(`${rootClassName}__trigger`, className, {
|
85
|
+
[`${rootClassName}__rotate`]: !hidden,
|
86
|
+
})}
|
87
|
+
aria-expanded={!hidden}
|
88
|
+
aria-controls={uid}
|
89
|
+
id={uid + "button"}
|
90
|
+
>
|
91
|
+
{title}
|
92
|
+
<IconChevronDown size="md" className={cx(`${rootClassName}__icon`)} aria-hidden />
|
93
|
+
</button>
|
94
|
+
</Heading>
|
95
|
+
<div
|
96
|
+
className={cx(`${rootClassName}__content`, className)}
|
97
|
+
aria-hidden={hidden}
|
98
|
+
id={uid}
|
99
|
+
aria-labelledby={uid + "button"}
|
100
|
+
role="region"
|
101
|
+
>
|
102
|
+
<div className={cx(`${rootClassName}__contentText`)}>
|
103
|
+
{typeof children === "string" ? (
|
104
|
+
<Paragraph variant="paragraph-200">{children}</Paragraph>
|
105
|
+
) : (
|
106
|
+
children
|
107
|
+
)}
|
108
|
+
</div>
|
109
|
+
</div>
|
110
|
+
</div>
|
111
|
+
);
|
112
|
+
};
|
@@ -44,34 +44,56 @@ const meta = {
|
|
44
44
|
},
|
45
45
|
},
|
46
46
|
},
|
47
|
+
args: {
|
48
|
+
title: "Title goes here",
|
49
|
+
titleVariant: "title-300",
|
50
|
+
defaultValue: ["1"],
|
51
|
+
negative: false,
|
52
|
+
},
|
47
53
|
} satisfies Meta<typeof Accordion>;
|
48
54
|
|
49
55
|
export default meta;
|
50
56
|
type Story = StoryObj<typeof Accordion>;
|
51
57
|
|
58
|
+
const text =
|
59
|
+
"Place body text here. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus at rutrum nulla";
|
60
|
+
|
61
|
+
const items = Array(3).fill(text);
|
62
|
+
|
52
63
|
export const Showcase: Story = {
|
53
64
|
render: (args) => (
|
54
65
|
<Accordion {...args}>
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
</Accordion.Item>
|
66
|
+
{items.map((t, i) => (
|
67
|
+
<Accordion.Item title={`Section title ${i + 1}`} key={i}>
|
68
|
+
{t}
|
69
|
+
</Accordion.Item>
|
70
|
+
))}
|
71
|
+
</Accordion>
|
72
|
+
),
|
73
|
+
};
|
64
74
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
75
|
+
export const UsingSchema: Story = {
|
76
|
+
render: (args) => (
|
77
|
+
<Accordion {...args}>
|
78
|
+
{items.map((t, i) => (
|
79
|
+
<Accordion.Item title={`Section title ${i + 1}`} key={i}>
|
80
|
+
{t}
|
81
|
+
</Accordion.Item>
|
82
|
+
))}
|
69
83
|
</Accordion>
|
70
84
|
),
|
71
85
|
args: {
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
86
|
+
schema: JSON.stringify({
|
87
|
+
"@context": "https://schema.org",
|
88
|
+
"@type": "FAQPage",
|
89
|
+
mainEntity: items.map((question) => ({
|
90
|
+
"@type": "Question",
|
91
|
+
name: question.title,
|
92
|
+
acceptedAnswer: {
|
93
|
+
"@type": "Answer",
|
94
|
+
text: question,
|
95
|
+
},
|
96
|
+
})),
|
97
|
+
}),
|
76
98
|
},
|
77
99
|
};
|
package/src/accordion.test.tsx
CHANGED
@@ -37,10 +37,10 @@ describe("Accordion", () => {
|
|
37
37
|
expect(screen.getByRole("heading", { level: 3, name: "Test heading" })).toBeDefined();
|
38
38
|
});
|
39
39
|
|
40
|
-
it("should
|
40
|
+
it("should render accordion item content when trigger is not clicked", () => {
|
41
41
|
setup();
|
42
42
|
|
43
|
-
expect(screen.queryByText("item content")).toBeNull();
|
43
|
+
expect(screen.queryByText("item content")).not.toBeNull();
|
44
44
|
});
|
45
45
|
|
46
46
|
it("should show/hide accordion item content when trigger is clicked", () => {
|
@@ -52,7 +52,7 @@ describe("Accordion", () => {
|
|
52
52
|
expect(screen.getByText("item content")).toBeDefined();
|
53
53
|
|
54
54
|
fireEvent.click(trigger);
|
55
|
-
expect(screen.queryByText("item content")).toBeNull();
|
55
|
+
expect(screen.queryByText("item content")).not.toBeNull();
|
56
56
|
});
|
57
57
|
|
58
58
|
it("should render custom accordion item content", () => {
|
@@ -69,18 +69,4 @@ describe("Accordion", () => {
|
|
69
69
|
|
70
70
|
expect(screen.getByRole("link", { name: "Test link" })).toBeDefined();
|
71
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
|
-
});
|
86
72
|
});
|
package/src/accordion.tsx
CHANGED
@@ -1,12 +1,5 @@
|
|
1
|
-
import React, {
|
2
|
-
Children,
|
3
|
-
cloneElement,
|
4
|
-
JSXElementConstructor,
|
5
|
-
ReactElement,
|
6
|
-
ReactNode,
|
7
|
-
} from "react";
|
1
|
+
import React, { createContext, ReactNode } from "react";
|
8
2
|
import { Heading, HeadingTagType, TitleVariantType } from "@purpurds/heading";
|
9
|
-
import * as RadixAccordion from "@radix-ui/react-accordion";
|
10
3
|
import c from "classnames/bind";
|
11
4
|
|
12
5
|
import styles from "./accordion.module.scss";
|
@@ -20,15 +13,23 @@ export type AccordionProps = {
|
|
20
13
|
children: ReactNode;
|
21
14
|
className?: string;
|
22
15
|
/**
|
23
|
-
*
|
16
|
+
* @deprecated
|
24
17
|
* */
|
25
18
|
defaultValue?: string[];
|
26
19
|
negative?: boolean;
|
27
20
|
title?: string;
|
28
21
|
titleTag?: HeadingTagType;
|
29
22
|
titleVariant?: TitleVariantType;
|
23
|
+
/**
|
24
|
+
* A schema enables external applications to parse the content in a structured manner.
|
25
|
+
* See more at schema.org . We use a JSON-LD based script-tag to add the schema to the DOM.
|
26
|
+
* Note that only one type of schema can be added per page
|
27
|
+
*/
|
28
|
+
schema?: string;
|
30
29
|
};
|
31
30
|
|
31
|
+
export const NegativeContext = createContext(false);
|
32
|
+
|
32
33
|
export const Accordion = ({
|
33
34
|
["data-testid"]: dataTestId,
|
34
35
|
children,
|
@@ -37,6 +38,7 @@ export const Accordion = ({
|
|
37
38
|
title,
|
38
39
|
titleTag = "h2",
|
39
40
|
titleVariant = "title-300",
|
41
|
+
schema,
|
40
42
|
...props
|
41
43
|
}: AccordionProps) => {
|
42
44
|
const classes = cx([
|
@@ -47,23 +49,24 @@ export const Accordion = ({
|
|
47
49
|
},
|
48
50
|
]);
|
49
51
|
|
50
|
-
const renderChildren = () =>
|
51
|
-
Children.map(children, (child) => {
|
52
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
53
|
-
return cloneElement(child as ReactElement<any, string | JSXElementConstructor<any>>, {
|
54
|
-
negative,
|
55
|
-
});
|
56
|
-
});
|
57
|
-
|
58
52
|
return (
|
59
|
-
<
|
60
|
-
{title
|
53
|
+
<div className={classes} data-testid={dataTestId} {...props}>
|
54
|
+
{title && (
|
61
55
|
<Heading tag={titleTag} variant={titleVariant} className={cx(`${rootClassName}__title`)}>
|
62
56
|
{title}
|
63
57
|
</Heading>
|
64
|
-
)
|
65
|
-
{
|
66
|
-
|
58
|
+
)}
|
59
|
+
<NegativeContext.Provider value={negative}>{children}</NegativeContext.Provider>
|
60
|
+
{schema && (
|
61
|
+
<script
|
62
|
+
type="application/ld+json"
|
63
|
+
// eslint-disable-next-line react/no-danger
|
64
|
+
dangerouslySetInnerHTML={{
|
65
|
+
__html: schema,
|
66
|
+
}}
|
67
|
+
/>
|
68
|
+
)}
|
69
|
+
</div>
|
67
70
|
);
|
68
71
|
};
|
69
72
|
|