Skip to content

Commit cba188c

Browse files
committed
2 parents 3f4e420 + 7189289 commit cba188c

File tree

6 files changed

+72
-111
lines changed

6 files changed

+72
-111
lines changed

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@
128128
"./Header": "./dist/Header.js",
129129
"./DarkModeSwitch": "./dist/DarkModeSwitch.js",
130130
"./Alert": "./dist/Alert.js",
131-
"./AccordionGroup": "./dist/AccordionGroup.js",
132131
"./Accordion": "./dist/Accordion.js"
133132
}
134133
}

src/Accordion.tsx

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
import React, { forwardRef, memo, ReactNode, useId } from "react";
1+
import React, { forwardRef, memo, ReactNode, useId, useState } from "react";
22
import { assert } from "tsafe";
33
import type { Equals } from "tsafe";
44
import { fr } from "./lib";
55
import { cx } from "./lib/tools/cx";
66
import "@gouvfr/dsfr/dist/component/accordion/accordion.css";
77
import { symToStr } from "tsafe/symToStr";
8+
import { useConstCallback } from "./lib/tools/powerhooks/useConstCallback";
89

9-
export type AccordionProps = AccordionProps.Controlled;
10+
export type AccordionProps = AccordionProps.Controlled | AccordionProps.Uncontrolled;
1011

1112
//TODO Controlled mode (callback onClick, expended etc ...)
1213
export namespace AccordionProps {
@@ -18,7 +19,23 @@ export namespace AccordionProps {
1819
content: NonNullable<ReactNode>;
1920
};
2021

21-
export type Controlled = Common & {};
22+
export type Uncontrolled = Common & {
23+
defaultExpanded?: boolean;
24+
expanded?: undefined;
25+
onExpandedChange?: (
26+
expanded: boolean,
27+
e: React.MouseEvent<HTMLButtonElement, MouseEvent>
28+
) => void;
29+
};
30+
31+
export type Controlled = Common & {
32+
defaultExpanded?: undefined;
33+
expanded: boolean;
34+
onExpandedChange: (
35+
expanded: boolean,
36+
e: React.MouseEvent<HTMLButtonElement, MouseEvent>
37+
) => void;
38+
};
2239
}
2340

2441
/** @see <https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/accordeon> */
@@ -30,20 +47,37 @@ export const Accordion = memo(
3047
label,
3148
classes = {},
3249
content,
50+
expanded: expandedProp,
51+
defaultExpanded = false,
52+
onExpandedChange,
3353
...rest
3454
} = props;
3555

3656
assert<Equals<keyof typeof rest, never>>();
3757

3858
const id = useId();
3959

60+
const [expandedState, setExpandedState] = useState(defaultExpanded);
61+
62+
const value = expandedProp ? expandedProp : expandedState;
63+
64+
const onExtendButtonClick = useConstCallback(
65+
(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
66+
setExpandedState(!value);
67+
if (onExpandedChange) {
68+
onExpandedChange(!value, event);
69+
}
70+
}
71+
);
72+
4073
return (
4174
<section className={cx(fr.cx("fr-accordion"), className)} ref={ref} {...rest}>
4275
<HtmlTitleTag className={cx(fr.cx("fr-accordion__title"), classes.title)}>
4376
<button
4477
className={fr.cx("fr-accordion__btn")}
45-
aria-expanded="true"
78+
aria-expanded={value}
4679
aria-controls={`accordion-${id}`}
80+
onClick={onExtendButtonClick}
4781
>
4882
{label}
4983
</button>

src/AccordionGroup.tsx

Lines changed: 0 additions & 46 deletions
This file was deleted.

stories/Accordion.stories.tsx

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,34 @@
11
import { Accordion } from "../dist/Accordion";
2-
import { getStoryFactory } from "./getStory";
3-
//import { sectionName } from "./sectionName";
2+
import { getStoryFactory, logCallbacks } from "./getStory";
3+
import { sectionName } from "./sectionName";
44

55
const { meta, getStory } = getStoryFactory({
6-
"sectionName": "wip",
6+
"sectionName": sectionName,
77
"wrappedComponent": { Accordion },
88
"description": `- [See DSFR documentation](https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/accordeon)
99
- [See source code](https://github.com/codegouvfr/react-dsfr/blob/main/src/Accordion.tsx)
1010
11-
## Controlled
11+
## Accordion group
12+
13+
If you want to use a group of accordion, you juste have to wrap your acordions in a div with a class \`fr-accordions-group\` as bellow :
14+
15+
\`\`\`tsx
16+
<div className={fr.cx("fr-accordions-group")}>
17+
<Accordion label="Name of the Accordion 1" content="Content of the Accordion 1" />
18+
<Accordion label="Name of the Accordion 2" content="Content of the Accordion 2" />
19+
</div>
20+
\`\`\`
21+
22+
## Controlled
1223
1324
In this mode you are in charge of the behavior of the Accordion.
1425
_NOTE: In controlled mode there is no animation transition when expanding or colapsing the accordion._
1526
1627
\`\`\`tsx
1728
function ControlledAccordion() {
18-
29+
const [expanded,setExpanded] = useState(false)
1930
return (
20-
<Accordion label="Name of the Accordion" content="Content of the Accordion"/>
31+
<Accordion label="Name of the Accordion" content="Content of the Accordion" onChange={(value,) => setExpanded(!value)} expanded={expanded}/>
2132
);
2233
2334
}
@@ -29,5 +40,7 @@ export default meta;
2940

3041
export const Default = getStory({
3142
"label": "Name of the Accordion",
32-
"content": "Content of the Accordion"
43+
"content": "Content of the Accordion",
44+
"defaultExpanded": false,
45+
...logCallbacks(["onExpandedChange"])
3346
});

stories/AccordionGroup.stories.tsx

Lines changed: 0 additions & 53 deletions
This file was deleted.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import React, { useState } from "react"
2+
import { Accordion } from "@codegouvfr/react-dsfr/Accordion";
3+
import { fr } from "@codegouvfr/react-dsfr";
4+
5+
6+
export default function Test() {
7+
const [expanded, setExpanded] = useState<boolean>(true);
8+
return (
9+
<div className={fr.cx("fr-accordions-group")}>
10+
<Accordion label="Accordion Uncontrolled" content="Content of the Uncontrolled Accordion" />
11+
<Accordion label="Accordion Controlled" content="Content of the controlled Accordion" expanded={expanded} onChange={(expanded, e) => { console.log("event", e); setExpanded(!expanded); }} />
12+
</div>
13+
)
14+
}

0 commit comments

Comments
 (0)