Skip to content

Commit 82f0de6

Browse files
Julien Bouquillongarronej
andcommitted
feat: add Summary component (#35)
* feat: add Summary Component * fix * Update src/Summary.tsx Co-authored-by: Joseph Garrone <joseph.garrone.gj@gmail.com> Signed-off-by: Julien Bouquillon <contact@revolunet.com> * Update src/Summary.tsx Co-authored-by: Joseph Garrone <joseph.garrone.gj@gmail.com> Signed-off-by: Julien Bouquillon <contact@revolunet.com> * Update src/Summary.tsx Co-authored-by: Joseph Garrone <joseph.garrone.gj@gmail.com> Signed-off-by: Julien Bouquillon <contact@revolunet.com> * Update src/Summary.tsx Co-authored-by: Joseph Garrone <joseph.garrone.gj@gmail.com> Signed-off-by: Julien Bouquillon <contact@revolunet.com> * fixes Signed-off-by: Julien Bouquillon <contact@revolunet.com> Co-authored-by: Joseph Garrone <joseph.garrone.gj@gmail.com>
1 parent a868d75 commit 82f0de6

File tree

4 files changed

+175
-1
lines changed

4 files changed

+175
-1
lines changed

COMPONENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
- [ ] Share
3636
- [x] Footer
3737
- [ ] Translate
38-
- [ ] Summary
38+
- [x] Summary
3939
- [ ] Table
4040
- [ ] Tag
4141
- [ ] Download

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
"./mui": "./dist/mui.js",
125125
"./lib": "./dist/lib/index.js",
126126
"./Tabs": "./dist/Tabs.js",
127+
"./Summary": "./dist/Summary.js",
127128
"./Stepper": "./dist/Stepper.js",
128129
"./SkipLinks": "./dist/SkipLinks.js",
129130
"./Quote": "./dist/Quote.js",

src/Summary.tsx

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import React, { memo, forwardRef, useId } from "react";
2+
import { symToStr } from "tsafe/symToStr";
3+
import { assert } from "tsafe/assert";
4+
import type { Equals } from "tsafe";
5+
6+
import { createComponentI18nApi } from "./lib/i18n";
7+
import { cx } from "./lib/tools/cx";
8+
import { fr, RegisteredLinkProps } from "./lib";
9+
import { getLink } from "./lib/routing";
10+
11+
import "./dsfr/component/summary/summary.css";
12+
13+
type SummaryLink = {
14+
text: string;
15+
linkProps: RegisteredLinkProps;
16+
};
17+
18+
export type SummaryProps = {
19+
className?: string;
20+
links: SummaryLink[];
21+
title?: string;
22+
/** Default: "p" */
23+
as?: "p" | "h2" | "h3" | "h4" | "h5" | "h6";
24+
classes?: Partial<Record<"root" | "title" | "link", string>>;
25+
};
26+
27+
/** @see <https://react-dsfr-components.etalab.studio/?path=/docs/components-summary> */
28+
export const Summary = memo(
29+
forwardRef<HTMLDivElement, SummaryProps>((props, ref) => {
30+
const { className, links, as = "p", title, classes = {}, ...rest } = props;
31+
32+
const { t } = useTranslation();
33+
34+
const titleId = useId();
35+
const summaryTitle = title ?? t("title");
36+
37+
const { Link } = getLink();
38+
39+
assert<Equals<keyof typeof rest, never>>();
40+
41+
return (
42+
<nav
43+
className={cx(fr.cx("fr-summary"), classes.root, className)}
44+
role="navigation"
45+
aria-labelledby={titleId}
46+
ref={ref}
47+
>
48+
{React.createElement(
49+
as,
50+
{
51+
className: cx(fr.cx("fr-summary__title"), classes.title),
52+
id: titleId
53+
},
54+
<>{summaryTitle}</>
55+
)}
56+
<ol>
57+
{links.map(
58+
(link, idx) =>
59+
link.linkProps.href !== undefined && (
60+
<li key={idx}>
61+
<Link
62+
{...link.linkProps}
63+
className={cx(
64+
fr.cx("fr-summary__link"),
65+
classes.link,
66+
link.linkProps.className
67+
)}
68+
>
69+
{link.text}
70+
</Link>
71+
</li>
72+
)
73+
)}
74+
</ol>
75+
</nav>
76+
);
77+
})
78+
);
79+
80+
Summary.displayName = symToStr({ Summary });
81+
82+
const { useTranslation, addSummaryTranslations } = createComponentI18nApi({
83+
"componentName": symToStr({ Summary }),
84+
"frMessages": {
85+
/* spell-checker: disable */
86+
"title": "Sommaire"
87+
/* spell-checker: enable */
88+
}
89+
});
90+
91+
addSummaryTranslations({
92+
"lang": "en",
93+
"messages": {
94+
"title": "Summary"
95+
}
96+
});
97+
98+
export { addSummaryTranslations };
99+
100+
export default Summary;

stories/Summary.stories.tsx

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { Summary } from "../dist/Summary";
2+
import { sectionName } from "./sectionName";
3+
import { getStoryFactory } from "./getStory";
4+
5+
const { meta, getStory } = getStoryFactory({
6+
sectionName,
7+
"wrappedComponent": { Summary },
8+
"description": `
9+
- [See DSFR documentation](//www.systeme-de-design.gouv.fr/elements-d-interface/composants/sommaire)
10+
- [See source code](//github.com/codegouvfr/react-dsfr/blob/main/src/Summary.tsx)`,
11+
"disabledProps": ["lang"]
12+
});
13+
14+
export default meta;
15+
16+
export const Default = getStory({
17+
links: [
18+
{
19+
linkProps: { href: "#" },
20+
text: "Titre de l’ancre"
21+
},
22+
{
23+
linkProps: { href: "#" },
24+
25+
text: "Titre de l’ancre"
26+
},
27+
{
28+
linkProps: { href: "#" },
29+
30+
text: "Titre de l’ancre"
31+
},
32+
{
33+
linkProps: { href: "#" },
34+
35+
text: "Titre de l’ancre"
36+
},
37+
{
38+
linkProps: { href: "#" },
39+
40+
text: "Titre de l’ancre"
41+
}
42+
]
43+
});
44+
45+
export const SummaryWithCustomTitle = getStory({
46+
title: "Sommaire personnalisé",
47+
links: [
48+
{
49+
linkProps: { href: "#" },
50+
text: "Titre de l’ancre"
51+
},
52+
{
53+
linkProps: { href: "#" },
54+
55+
text: "Titre de l’ancre"
56+
},
57+
{
58+
linkProps: { href: "#" },
59+
60+
text: "Titre de l’ancre"
61+
},
62+
{
63+
linkProps: { href: "#" },
64+
65+
text: "Titre de l’ancre"
66+
},
67+
{
68+
linkProps: { href: "#" },
69+
70+
text: "Titre de l’ancre"
71+
}
72+
]
73+
});

0 commit comments

Comments
 (0)