Skip to content

Commit 1772162

Browse files
author
Julien Bouquillon
authored
feat: add Tile component (#41)
* feat: add Tile componen
1 parent 5d2920a commit 1772162

File tree

5 files changed

+162
-2
lines changed

5 files changed

+162
-2
lines changed

COMPONENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,4 @@
4040
- [ ] Tag
4141
- [ ] Download
4242
- [ ] Transcription
43-
- [ ] Tile
43+
- [x] Tile

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@
123123
"./next": "./dist/next.js",
124124
"./mui": "./dist/mui.js",
125125
"./lib": "./dist/lib/index.js",
126+
"./Tile": "./dist/Tile.js",
126127
"./Tabs": "./dist/Tabs.js",
127128
"./Summary": "./dist/Summary.js",
128129
"./Stepper": "./dist/Stepper.js",

src/Tile.tsx

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import React, { memo, forwardRef } from "react";
2+
import type { ReactNode } from "react";
3+
import { symToStr } from "tsafe/symToStr";
4+
import { assert } from "tsafe/assert";
5+
import type { Equals } from "tsafe";
6+
import { RegisteredLinkProps, fr } from "./lib";
7+
import { cx } from "./lib/tools/cx";
8+
import { getLink } from "./lib/routing";
9+
10+
//https://main--ds-gouv.netlify.app/example/component/tile/
11+
export type TileProps = {
12+
className?: string;
13+
title: ReactNode;
14+
linkProps: RegisteredLinkProps;
15+
desc?: ReactNode;
16+
imageUrl?: string;
17+
imageAlt?: string;
18+
grey?: boolean;
19+
20+
/** make the whole tile clickable */
21+
enlargeLink?: boolean;
22+
classes?: Partial<
23+
Record<"root" | "title" | "link" | "body" | "desc" | "img" | "imgTag", string>
24+
>;
25+
/** Default false */
26+
horizontal?: boolean;
27+
};
28+
29+
export namespace TileProps {}
30+
31+
/** @see <https://react-dsfr-components.etalab.studio/?path=/docs/components-tile> */
32+
export const Tile = memo(
33+
forwardRef<HTMLDivElement, TileProps>((props, ref) => {
34+
const {
35+
className,
36+
title,
37+
linkProps,
38+
desc,
39+
imageUrl,
40+
imageAlt,
41+
horizontal = false,
42+
grey = false,
43+
classes = {},
44+
enlargeLink = true,
45+
...rest
46+
} = props;
47+
48+
assert<Equals<keyof typeof rest, never>>();
49+
50+
const { Link } = getLink();
51+
52+
return (
53+
<div
54+
className={cx(
55+
fr.cx(
56+
"fr-tile",
57+
enlargeLink && "fr-enlarge-link",
58+
horizontal && "fr-tile--horizontal",
59+
grey && "fr-tile--grey"
60+
),
61+
classes.root,
62+
className
63+
)}
64+
ref={ref}
65+
{...rest}
66+
>
67+
<div className={cx(fr.cx("fr-tile__body"), classes.body)}>
68+
<h3 className={cx(fr.cx("fr-tile__title"), classes.title)}>
69+
<Link
70+
className={cx(
71+
fr.cx("fr-tile__link"),
72+
classes.link,
73+
linkProps.className
74+
)}
75+
href={linkProps.href}
76+
>
77+
{title}
78+
</Link>
79+
</h3>
80+
<p className={cx(fr.cx("fr-tile__desc"), classes.desc)}>{desc}</p>
81+
</div>
82+
{(imageUrl !== undefined && imageUrl.length && (
83+
<div className={cx(fr.cx("fr-tile__img"), classes.img)}>
84+
<img
85+
className={cx(fr.cx("fr-responsive-img"), classes.imgTag)}
86+
src={imageUrl}
87+
alt={imageAlt}
88+
/>
89+
</div>
90+
)) ||
91+
null}
92+
</div>
93+
);
94+
})
95+
);
96+
97+
Tile.displayName = symToStr({ Tile });
98+
99+
export default Tile;

stories/Tile.stories.tsx

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { Tile } from "../dist/Tile";
2+
import { sectionName } from "./sectionName";
3+
import { getStoryFactory } from "./getStory";
4+
5+
const { meta, getStory } = getStoryFactory({
6+
sectionName,
7+
"wrappedComponent": { Tile },
8+
defaultContainerWidth: 300,
9+
"description": `
10+
- [See DSFR documentation](//www.systeme-de-design.gouv.fr/elements-d-interface/composants/tuile)
11+
- [See DSFR demos](https://main--ds-gouv.netlify.app/example/component/tile/)
12+
- [See source code](//github.com/codegouvfr/react-dsfr/blob/main/src/Tile.tsx)`,
13+
"disabledProps": ["lang"]
14+
});
15+
16+
export default meta;
17+
18+
export const Default = getStory({
19+
linkProps: { href: "#" },
20+
title: "Titre de la tuile",
21+
desc: "Lorem ipsum dolor sit amet, consectetur adipiscing, incididunt, ut labore et dol",
22+
enlargeLink: true,
23+
horizontal: false
24+
});
25+
26+
export const TileWithoutEnlargeLink = getStory({
27+
linkProps: { href: "#" },
28+
title: "Titre de la tuile",
29+
desc: "Lorem ipsum dolor sit amet, consectetur adipiscing, incididunt, ut labore et dol",
30+
enlargeLink: false
31+
});
32+
33+
export const TileWithImage = getStory({
34+
linkProps: { href: "#" },
35+
title: "Titre de la tuile",
36+
desc: "Lorem ipsum dolor sit amet, consectetur adipiscing, incididunt, ut labore et dol",
37+
enlargeLink: false,
38+
imageUrl: "//www.gouvernement.fr/sites/default/files/static_assets/placeholder.1x1.png"
39+
});
40+
41+
export const TileWithImageGrey = getStory({
42+
linkProps: { href: "#" },
43+
title: "Titre de la tuile",
44+
desc: "Lorem ipsum dolor sit amet, consectetur adipiscing, incididunt, ut labore et dol",
45+
enlargeLink: false,
46+
imageUrl: "//www.gouvernement.fr/sites/default/files/static_assets/placeholder.1x1.png",
47+
grey: true
48+
});
49+
50+
export const TileHorizontalWithImage = getStory(
51+
{
52+
linkProps: { href: "#" },
53+
horizontal: true,
54+
title: "Titre de la tuile",
55+
desc: "Lorem ipsum dolor sit amet, consectetur adipiscing, incididunt, ut labore et dol",
56+
enlargeLink: true,
57+
imageUrl: "//www.gouvernement.fr/sites/default/files/static_assets/placeholder.1x1.png"
58+
},
59+
{ defaultContainerWidth: "100%" }
60+
);

stories/getStory.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ export function getStoryFactory<Props extends Record<string, any>>(params: {
9494

9595
function getStory(
9696
props: Props,
97-
params?: { defaultContainerWidth?: number; description?: string }
97+
params?: { defaultContainerWidth?: number | string; description?: string }
9898
): typeof Template {
9999
const { defaultContainerWidth: defaultContainerWidthStoryLevel, description } =
100100
params ?? {};

0 commit comments

Comments
 (0)