Skip to content

Commit efdfc9d

Browse files
committed
Restore Tile component
1 parent 24af74f commit efdfc9d

File tree

5 files changed

+164
-3
lines changed

5 files changed

+164
-3
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: 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.12.1",
3+
"version": "0.13.0",
44
"description": "French State Design System React integration library",
55
"repository": {
66
"type": "git",
@@ -131,6 +131,7 @@
131131
"./useColors": "./dist/useColors.js",
132132
"./i18n": "./dist/i18n/index.js",
133133
"./mui": "./dist/mui.js",
134+
"./Tile": "./dist/Tile.js",
134135
"./Tabs": "./dist/Tabs.js",
135136
"./Summary": "./dist/Summary.js",
136137
"./Stepper": "./dist/Stepper.js",

src/Tile.tsx

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

0 commit comments

Comments
 (0)