Skip to content

Commit f19c348

Browse files
committed
2 parents 2edc6c8 + 094fbd4 commit f19c348

File tree

5 files changed

+245
-32
lines changed

5 files changed

+245
-32
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@codegouvfr/react-dsfr",
3-
"version": "0.5.2-rc.0",
3+
"version": "0.5.3-rc.0",
44
"description": "French State Design System React integration library",
55
"repository": {
66
"type": "git",
@@ -126,6 +126,7 @@
126126
"./Tabs": "./dist/Tabs.js",
127127
"./Stepper": "./dist/Stepper.js",
128128
"./SkipLinks": "./dist/SkipLinks.js",
129+
"./Quote": "./dist/Quote.js",
129130
"./Notice": "./dist/Notice.js",
130131
"./Highlight": "./dist/Highlight.js",
131132
"./Header": "./dist/Header/index.js",

src/Breadcrumb.tsx

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,71 @@
1-
import React, { memo, forwardRef, useId } from "react";
1+
import React, { memo, forwardRef, useId, ReactNode } from "react";
22
import { symToStr } from "tsafe/symToStr";
3+
import { assert } from "tsafe/assert";
4+
import type { Equals } from "tsafe";
5+
36
import { RegisteredLinkProps, useLink } from "./lib/routing";
7+
import { createComponentI18nApi } from "./lib/i18n";
48
import { fr } from "./lib";
59
import { cx } from "./lib/tools/cx";
610

7-
// We make users import dsfr.css, so we don't need to import the scoped CSS
8-
// but in the future if we have a complete component coverage it
9-
// we could stop requiring users to import the hole CSS and only import on a
10-
// per component basis.
1111
import "./dsfr/component/breadcrumb/breadcrumb.css";
1212

1313
export type BreadcrumbProps = {
1414
className?: string;
1515
links: BreadcrumbProps.Link[];
16+
classes?: Partial<Record<"root" | "button" | "collapse" | "list" | "link" | "text", string>>;
1617
};
1718

1819
export namespace BreadcrumbProps {
1920
export type Link = {
20-
text: string;
21+
text: ReactNode;
2122
linkProps: RegisteredLinkProps;
2223
isActive?: boolean;
2324
};
2425
}
2526

26-
//Longueur et lisibilité : Afin qu’il reste lisible, évitez que le fil d’Ariane soit trop long et passe sur plusieurs lignes.
27-
// Si les titres de page de votre site sont longs, nous conseillons de n’afficher que les 4 premiers mots du nom de la page courante et d’indiquer que l’élément est tronqué par l’affichage de “…”
28-
const trimText = (label: string) => {
29-
if (label && label.split(" ").length > 4) {
30-
return label.split(" ").slice(0, 4).join(" ") + "...";
31-
}
32-
return label;
33-
};
34-
3527
/** @see <https://react-dsfr-components.etalab.studio/?path=/docs/components-breadcrumb> */
3628
export const Breadcrumb = memo(
3729
forwardRef<HTMLDivElement, BreadcrumbProps>((props, ref) => {
38-
const { links, className, ...rest } = props;
30+
const { links, className, classes = {}, ...rest } = props;
31+
32+
assert<Equals<keyof typeof rest, never>>();
33+
34+
const { t } = useTranslation();
3935

4036
const { Link } = useLink();
4137
const breadcrumbId = useId();
38+
4239
return (
4340
<nav
4441
ref={ref}
4542
role="navigation"
46-
className={cx(fr.cx("fr-breadcrumb"), className)}
47-
aria-label="vous êtes ici :"
43+
className={cx(fr.cx("fr-breadcrumb"), classes.root, className)}
44+
aria-label={`${t("navigation label")} :`}
4845
{...rest}
4946
>
5047
<button
51-
className="fr-breadcrumb__button"
48+
className={cx(fr.cx("fr-breadcrumb__button"), classes.button)}
5249
aria-expanded="false"
5350
aria-controls={breadcrumbId}
5451
>
55-
Voir le fil d’Ariane
52+
{t("show breadcrumb")}
5653
</button>
57-
<div className="fr-collapse" id={breadcrumbId}>
58-
<ol className="fr-breadcrumb__list">
54+
<div className={cx(fr.cx("fr-collapse"), classes.collapse)} id={breadcrumbId}>
55+
<ol className={cx(fr.cx("fr-breadcrumb__list"), classes.list)}>
5956
<>
6057
{links.map(link => (
6158
<li key={link.linkProps.href}>
6259
<Link
6360
{...link.linkProps}
6461
className={cx(
6562
fr.cx("fr-breadcrumb__link"),
63+
classes.link,
6664
link.linkProps.className
6765
)}
6866
aria-current={link.isActive ? "page" : undefined}
6967
>
70-
{trimText(link.text)}
68+
{link.text}
7169
</Link>
7270
</li>
7371
))}
@@ -81,4 +79,22 @@ export const Breadcrumb = memo(
8179

8280
Breadcrumb.displayName = symToStr({ Breadcrumb });
8381

82+
const { useTranslation, addBreadcrumbTranslations } = createComponentI18nApi({
83+
"componentName": symToStr({ Breadcrumb }),
84+
"frMessages": {
85+
"show breadcrumb": "Voir le fil d’Ariane",
86+
"navigation label": "vous êtes ici"
87+
}
88+
});
89+
90+
addBreadcrumbTranslations({
91+
"lang": "en",
92+
"messages": {
93+
"show breadcrumb": "Show navigation",
94+
"navigation label": "you are here"
95+
}
96+
});
97+
98+
export { addBreadcrumbTranslations };
99+
84100
export default Breadcrumb;

src/Quote.tsx

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import React, { memo, forwardRef, ReactNode } from "react";
2+
import { symToStr } from "tsafe/symToStr";
3+
import { assert } from "tsafe/assert";
4+
import type { Equals } from "tsafe";
5+
6+
import { FrClassName } from "./lib/generatedFromCss/classNames";
7+
import { cx } from "./lib/tools/cx";
8+
import { fr } from "./lib";
9+
10+
import "./dsfr/component/quote/quote.css";
11+
12+
export type QuoteProps = {
13+
className?: string;
14+
text: ReactNode;
15+
author?: ReactNode;
16+
source?: ReactNode;
17+
sourceUrl?: string;
18+
imageUrl?: string;
19+
size?: "medium" | "large" | "xlarge";
20+
accentColor?: QuoteProps.AccentColor;
21+
classes?: Partial<Record<"root" | "author" | "source" | "image" | "imageTag" | "text", string>>;
22+
};
23+
24+
export namespace QuoteProps {
25+
type ExtractAccentColor<FrClassName> = FrClassName extends `fr-quote--${infer AccentColor}`
26+
? AccentColor
27+
: never;
28+
29+
export type AccentColor = ExtractAccentColor<FrClassName>;
30+
}
31+
32+
/** @see <https://react-dsfr-components.etalab.studio/?path=/docs/components-quote> */
33+
export const Quote = memo(
34+
forwardRef<HTMLDivElement, QuoteProps>((props, ref) => {
35+
const {
36+
className,
37+
text,
38+
author,
39+
source,
40+
sourceUrl,
41+
imageUrl,
42+
size = "xlarge",
43+
accentColor,
44+
classes = {},
45+
...rest
46+
} = props;
47+
48+
assert<Equals<keyof typeof rest, never>>();
49+
50+
return (
51+
<figure
52+
className={cx(
53+
fr.cx("fr-quote"),
54+
imageUrl && fr.cx("fr-quote--column"),
55+
accentColor && `fr-quote--${accentColor}`,
56+
classes.root,
57+
className
58+
)}
59+
ref={ref}
60+
>
61+
<blockquote cite={sourceUrl}>
62+
<p
63+
className={cx(
64+
size === "large" && fr.cx("fr-text--lg"),
65+
size === "medium" && fr.cx("fr-text--md"),
66+
classes.text
67+
)}
68+
>
69+
« {text} »
70+
</p>
71+
</blockquote>
72+
<figcaption>
73+
{author !== undefined && (
74+
<p className={cx(fr.cx("fr-quote__author"), classes.author)}>{author}</p>
75+
)}
76+
{source !== undefined && (
77+
<ul className={cx(fr.cx("fr-quote__source"), classes.source)}>{source}</ul>
78+
)}
79+
{imageUrl !== undefined && (
80+
<div className={cx("fr-quote__image", classes.image)}>
81+
<img
82+
src={imageUrl}
83+
className={cx(fr.cx("fr-responsive-img"), classes.imageTag)}
84+
alt=""
85+
/>
86+
</div>
87+
)}
88+
</figcaption>
89+
</figure>
90+
);
91+
})
92+
);
93+
94+
Quote.displayName = symToStr({ Quote });
95+
96+
export default Quote;

stories/Breadcrumb.stories.tsx

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,3 @@ export const LongBreadcrumb = getStory({
3939
{ text: "Page de démo 7", linkProps: { href: "/page7" }, isActive: true }
4040
]
4141
});
42-
43-
export const LongLabelBreadcrumb = getStory({
44-
links: [
45-
{ text: "Accueil", linkProps: { href: "/" } },
46-
{ text: "Page 1", linkProps: { href: "/page1" } },
47-
{ text: "Un article très très long", linkProps: { href: "/article1" }, isActive: true }
48-
]
49-
});

stories/Quote.stories.tsx

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import React from "react";
2+
import { Quote } from "../dist/Quote";
3+
import { sectionName } from "./sectionName";
4+
import { getStoryFactory } from "./getStory";
5+
6+
const { meta, getStory } = getStoryFactory({
7+
sectionName,
8+
"wrappedComponent": { Quote },
9+
"description": `
10+
- [See DSFR documentation](//www.systeme-de-design.gouv.fr/elements-d-interface/composants/citation)
11+
- [See source code](//github.com/codegouvfr/react-dsfr/blob/main/src/Quote.tsx)`,
12+
"disabledProps": ["lang"]
13+
});
14+
15+
export default meta;
16+
17+
export const Default = getStory({
18+
text: "Lorem [...] elit ut. ",
19+
author: "Auteur",
20+
source: (
21+
<>
22+
<li>
23+
<cite>Ouvrage</cite>
24+
</li>
25+
<li>Détail 1</li>
26+
<li>Détail 2</li>
27+
<li>Détail 3</li>
28+
<li>
29+
<a
30+
target="_blank"
31+
href="[À MODIFIER | Lien vers la sources ou des infos complémentaires]"
32+
>
33+
Détail 4
34+
</a>
35+
</li>
36+
</>
37+
),
38+
imageUrl: "//www.systeme-de-design.gouv.fr/img/placeholder.1x1.png",
39+
size: "xlarge",
40+
className: ""
41+
});
42+
43+
export const QuoteMediumAndAccent = getStory({
44+
text: "Lorem [...] elit ut. ",
45+
author: "Auteur",
46+
source: (
47+
<>
48+
<li>
49+
<cite>Ouvrage</cite>
50+
</li>
51+
<li>Détail 1</li>
52+
<li>Détail 2</li>
53+
<li>Détail 3</li>
54+
<li>
55+
<a
56+
target="_blank"
57+
href="[À MODIFIER | Lien vers la sources ou des infos complémentaires]"
58+
>
59+
Détail 4
60+
</a>
61+
</li>
62+
</>
63+
),
64+
imageUrl: "//www.systeme-de-design.gouv.fr/img/placeholder.1x1.png",
65+
size: "medium",
66+
accentColor: "pink-macaron"
67+
});
68+
69+
export const QuoteWithoutDetails = getStory({
70+
text: "Lorem [...] elit ut. ",
71+
author: "Auteur",
72+
imageUrl: "//www.systeme-de-design.gouv.fr/img/placeholder.1x1.png"
73+
});
74+
75+
export const QuoteWithoutSource = getStory({
76+
text: "Lorem [...] elit ut. ",
77+
imageUrl: "//www.systeme-de-design.gouv.fr/img/placeholder.1x1.png"
78+
});
79+
80+
export const QuoteWithoutIllustration = getStory({
81+
text: "Lorem [...] elit ut. ",
82+
author: "Auteur",
83+
source: (
84+
<>
85+
<li>
86+
<cite>Ouvrage</cite>
87+
</li>
88+
<li>Détail 1</li>
89+
<li>Détail 2</li>
90+
<li>Détail 3</li>
91+
<li>
92+
<a
93+
target="_blank"
94+
href="[À MODIFIER | Lien vers la sources ou des infos complémentaires]"
95+
>
96+
Détail 4
97+
</a>
98+
</li>
99+
</>
100+
)
101+
});
102+
103+
export const QuoteWithAccent = getStory({
104+
text: "Lorem [...] elit ut. ",
105+
imageUrl: "//www.systeme-de-design.gouv.fr/img/placeholder.1x1.png",
106+
accentColor: "yellow-moutarde",
107+
author: "Someone"
108+
});

0 commit comments

Comments
 (0)