Skip to content

Commit 3931634

Browse files
marc-gavaniergarronej
authored andcommitted
feat: add highlight component
1 parent 41679d1 commit 3931634

File tree

3 files changed

+133
-0
lines changed

3 files changed

+133
-0
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@
125125
"./lib": "./dist/lib/index.js",
126126
"./Tabs": "./dist/Tabs.js",
127127
"./Notice": "./dist/Notice.js",
128+
"./Highlight": "./dist/Highlight.js",
128129
"./Header": "./dist/Header/index.js",
129130
"./DisplaySettingsDialog": "./dist/DisplaySettingsDialog.js",
130131
"./Badge": "./dist/Badge.js",

src/Highlight.tsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
import { fr } from "./lib";
6+
import { cx } from "./lib/tools/cx";
7+
8+
// We make users import dsfr.css, so we don't need to import the scoped CSS
9+
// but in the future if we have a complete component coverage it
10+
// we could stop requiring users to import the hole CSS and only import on a
11+
// per component basis.
12+
import "./dsfr/component/highlight/highlight.css";
13+
14+
export type HighlightProps = {
15+
className?: string;
16+
classes?: Partial<Record<"root" | "content", string>>;
17+
size?: HighlightProps.Size;
18+
children: NonNullable<ReactNode>;
19+
};
20+
21+
export namespace HighlightProps {
22+
export type Size = "sm" | "lg";
23+
}
24+
25+
/** @see <https://react-dsfr-components.etalab.studio/?path=/docs/components-highlight> */
26+
export const Highlight = memo(
27+
forwardRef<HTMLDivElement, HighlightProps>(props => {
28+
const { className, classes = {}, children, size, ...rest } = props;
29+
30+
assert<Equals<keyof typeof rest, never>>();
31+
32+
return (
33+
<div className={cx(fr.cx("fr-highlight"), classes.root, className)} {...rest}>
34+
<p className={cx(fr.cx({ [`fr-text--${size}`]: size }), classes.content)}>
35+
{children}
36+
</p>
37+
</div>
38+
);
39+
})
40+
);
41+
42+
Highlight.displayName = symToStr({ Highlight });
43+
44+
export default Highlight;

stories/Highlight.stories.tsx

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { Highlight } from "../dist/Highlight";
2+
import type { HighlightProps } from "../dist/Highlight";
3+
import { sectionName } from "./sectionName";
4+
import { getStoryFactory } from "./getStory";
5+
import { assert } from "tsafe/assert";
6+
import type { Equals } from "tsafe";
7+
8+
const { meta, getStory } = getStoryFactory<HighlightProps>({
9+
sectionName,
10+
wrappedComponent: { Highlight },
11+
description: `
12+
- [See DSFR documentation](https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/mise-en-exergue)
13+
- [See source code](https://github.com/codegouvfr/react-dsfr/blob/main/src/Highlight.tsx)`,
14+
argTypes: {
15+
size: {
16+
options: (() => {
17+
const sizes = ["sm", "lg"] as const;
18+
19+
assert<Equals<typeof sizes[number], HighlightProps.Size>>();
20+
21+
return [null, ...sizes];
22+
})(),
23+
control: { type: "select", labels: { null: "default", sm: "small", lg: "large" } },
24+
description: "Content text size"
25+
},
26+
children: {
27+
type: { name: "string", required: true },
28+
description: "Text to display as highlight content"
29+
},
30+
classes: {
31+
control: "object",
32+
description:
33+
'Add custom classes for "root" or "content" component inner elements. Associate custom class values with "root" or "content" keys'
34+
}
35+
},
36+
disabledProps: ["lang"]
37+
});
38+
39+
export default meta;
40+
41+
export const Default = getStory({
42+
children:
43+
"Les parents d’enfants de 11 à 14 ans n’ont aucune démarche à accomplir : les CAF versent automatiquement l’ARS aux familles déjà allocataires qui remplissent les conditions."
44+
});
45+
46+
export const HighlightSmall = getStory(
47+
{
48+
children: "Highlight contains a text with small font size",
49+
size: "sm"
50+
},
51+
{
52+
description: "Small `Highlight`"
53+
}
54+
);
55+
56+
export const HighlightLarge = getStory(
57+
{
58+
children: "Highlight contains a text with large font size",
59+
size: "lg"
60+
},
61+
{
62+
description: "Large `Highlight`"
63+
}
64+
);
65+
66+
export const HighlightCustomGreenAccentColor = getStory(
67+
{
68+
children: "Highlight contains a text with custom green emeraude accent color",
69+
classes: {
70+
root: "fr-highlight--green-emeraude"
71+
}
72+
},
73+
{
74+
description: "Large `Highlight`"
75+
}
76+
);
77+
78+
export const HighlightCustomBrownAccentColor = getStory(
79+
{
80+
children: "Highlight contains a text with custom brown caramel accent color",
81+
classes: {
82+
root: "fr-highlight--brown-caramel"
83+
}
84+
},
85+
{
86+
description: "Large `Highlight`"
87+
}
88+
);

0 commit comments

Comments
 (0)