UNPKG

3.46 kBTypeScriptView Raw
1import React, { memo, forwardRef, type ReactNode, type CSSProperties } from "react";
2import { symToStr } from "tsafe/symToStr";
3import { assert } from "tsafe/assert";
4import type { Equals } from "tsafe";
5import type { FrClassName } from "./fr/generatedFromCss/classNames";
6import { cx } from "./tools/cx";
7import { fr } from "./fr";
8import { useAnalyticsId } from "./tools/useAnalyticsId";
9
10export type QuoteProps = {
11 id?: string;
12 className?: string;
13 text: ReactNode;
14 author?: ReactNode;
15 source?: ReactNode;
16 sourceUrl?: string;
17 imageUrl?: string;
18 size?: "medium" | "large" | "xlarge";
19 accentColor?: QuoteProps.AccentColor;
20 classes?: Partial<Record<"root" | "author" | "source" | "image" | "imageTag" | "text", string>>;
21 style?: CSSProperties;
22};
23
24export 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://components.react-dsfr.codegouv.studio/?path=/docs/components-quote> */
33export const Quote = memo(
34 forwardRef<HTMLDivElement, QuoteProps>((props, ref) => {
35 const {
36 id: id_props,
37 className,
38 text,
39 author,
40 source,
41 sourceUrl,
42 imageUrl,
43 size = "xlarge",
44 accentColor,
45 classes = {},
46 style,
47 ...rest
48 } = props;
49
50 assert<Equals<keyof typeof rest, never>>();
51
52 const id = useAnalyticsId({
53 "defaultIdPrefix": "fr-quote",
54 "explicitlyProvidedId": id_props
55 });
56
57 return (
58 <figure
59 id={id}
60 className={cx(
61 fr.cx("fr-quote"),
62 imageUrl && fr.cx("fr-quote--column"),
63 accentColor && `fr-quote--${accentColor}`,
64 classes.root,
65 className
66 )}
67 style={style}
68 ref={ref}
69 >
70 <blockquote cite={sourceUrl}>
71 <p
72 className={cx(
73 size === "large" && fr.cx("fr-text--lg"),
74 size === "medium" && fr.cx("fr-text--md"),
75 classes.text
76 )}
77 >
78 « {text} »
79 </p>
80 </blockquote>
81 <figcaption>
82 {author !== undefined && (
83 <p className={cx(fr.cx("fr-quote__author"), classes.author)}>{author}</p>
84 )}
85 {source !== undefined && (
86 <ul className={cx(fr.cx("fr-quote__source"), classes.source)}>{source}</ul>
87 )}
88 {imageUrl !== undefined && (
89 <div className={cx("fr-quote__image", classes.image)}>
90 <img
91 src={imageUrl}
92 className={cx(fr.cx("fr-responsive-img"), classes.imageTag)}
93 alt=""
94 />
95 </div>
96 )}
97 </figcaption>
98 </figure>
99 );
100 })
101);
102
103Quote.displayName = symToStr({ Quote });
104
105export default Quote;
106
\No newline at end of file