diff --git a/package.json b/package.json index db252dc5a..1b3822c36 100755 --- a/package.json +++ b/package.json @@ -126,6 +126,7 @@ "./Tabs": "./dist/Tabs.js", "./Stepper": "./dist/Stepper.js", "./SkipLinks": "./dist/SkipLinks.js", + "./Quote": "./dist/Quote.js", "./Notice": "./dist/Notice.js", "./Highlight": "./dist/Highlight.js", "./Header": "./dist/Header/index.js", diff --git a/src/Quote.tsx b/src/Quote.tsx new file mode 100644 index 000000000..8fd21063e --- /dev/null +++ b/src/Quote.tsx @@ -0,0 +1,96 @@ +import React, { memo, forwardRef, ReactNode } from "react"; +import { symToStr } from "tsafe/symToStr"; +import { assert } from "tsafe/assert"; +import type { Equals } from "tsafe"; + +import { FrClassName } from "./lib/generatedFromCss/classNames"; +import { cx } from "./lib/tools/cx"; +import { fr } from "./lib"; + +import "./dsfr/component/quote/quote.css"; + +export type QuoteProps = { + className?: string; + text: ReactNode; + author?: ReactNode; + source?: ReactNode; + sourceUrl?: string; + imageUrl?: string; + size?: "medium" | "large" | "xlarge"; + accentColor?: QuoteProps.AccentColor; + classes?: Partial>; +}; + +export namespace QuoteProps { + type ExtractAccentColor = FrClassName extends `fr-quote--${infer AccentColor}` + ? AccentColor + : never; + + export type AccentColor = ExtractAccentColor; +} + +/** @see */ +export const Quote = memo( + forwardRef((props, ref) => { + const { + className, + text, + author, + source, + sourceUrl, + imageUrl, + size = "xlarge", + accentColor, + classes = {}, + ...rest + } = props; + + assert>(); + + return ( +
+
+

+ « {text} » +

+
+
+ {author !== undefined && ( +

{author}

+ )} + {source !== undefined && ( +
    {source}
+ )} + {imageUrl !== undefined && ( +
+ +
+ )} +
+
+ ); + }) +); + +Quote.displayName = symToStr({ Quote }); + +export default Quote; diff --git a/stories/Quote.stories.tsx b/stories/Quote.stories.tsx new file mode 100644 index 000000000..86fd41e9a --- /dev/null +++ b/stories/Quote.stories.tsx @@ -0,0 +1,108 @@ +import React from "react"; +import { Quote } from "../dist/Quote"; +import { sectionName } from "./sectionName"; +import { getStoryFactory } from "./getStory"; + +const { meta, getStory } = getStoryFactory({ + sectionName, + "wrappedComponent": { Quote }, + "description": ` +- [See DSFR documentation](//www.systeme-de-design.gouv.fr/elements-d-interface/composants/citation) +- [See source code](//github.com/codegouvfr/react-dsfr/blob/main/src/Quote.tsx)`, + "disabledProps": ["lang"] +}); + +export default meta; + +export const Default = getStory({ + text: "Lorem [...] elit ut. ", + author: "Auteur", + source: ( + <> +
  • + Ouvrage +
  • +
  • Détail 1
  • +
  • Détail 2
  • +
  • Détail 3
  • +
  • + + Détail 4 + +
  • + + ), + imageUrl: "//www.systeme-de-design.gouv.fr/img/placeholder.1x1.png", + size: "xlarge", + className: "" +}); + +export const QuoteMediumAndAccent = getStory({ + text: "Lorem [...] elit ut. ", + author: "Auteur", + source: ( + <> +
  • + Ouvrage +
  • +
  • Détail 1
  • +
  • Détail 2
  • +
  • Détail 3
  • +
  • + + Détail 4 + +
  • + + ), + imageUrl: "//www.systeme-de-design.gouv.fr/img/placeholder.1x1.png", + size: "medium", + accentColor: "pink-macaron" +}); + +export const QuoteWithoutDetails = getStory({ + text: "Lorem [...] elit ut. ", + author: "Auteur", + imageUrl: "//www.systeme-de-design.gouv.fr/img/placeholder.1x1.png" +}); + +export const QuoteWithoutSource = getStory({ + text: "Lorem [...] elit ut. ", + imageUrl: "//www.systeme-de-design.gouv.fr/img/placeholder.1x1.png" +}); + +export const QuoteWithoutIllustration = getStory({ + text: "Lorem [...] elit ut. ", + author: "Auteur", + source: ( + <> +
  • + Ouvrage +
  • +
  • Détail 1
  • +
  • Détail 2
  • +
  • Détail 3
  • +
  • + + Détail 4 + +
  • + + ) +}); + +export const QuoteWithAccent = getStory({ + text: "Lorem [...] elit ut. ", + imageUrl: "//www.systeme-de-design.gouv.fr/img/placeholder.1x1.png", + accentColor: "yellow-moutarde", + author: "Someone" +});