Skip to content

Commit c59e0b5

Browse files
committed
Feat: Select
1 parent 9fb56f1 commit c59e0b5

File tree

6 files changed

+167
-6
lines changed

6 files changed

+167
-6
lines changed

COMPONENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
- [ ] Follow
2323
- [ ] Link
2424
- [x] SkipLinks
25-
- [ ] Select
25+
- [x] Select
2626
- [ ] Side menu
2727
- [x] Call out
2828
- [x] Highlight

README.fr.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ DSFR en pur JavaScript/CSS.
4545
- [x] la plupart des composants peuvent être rendus directement sur le serveur (voir [RSC](https://reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html)). Les autres sont étiquetées `"use client";`.
4646
- [x] [Intégration clef en main pour les différents frameworks de développement: vite, Next.js, y compris la version beta de Next 13 (configuration AppDir) et Create React App](https://react-dsfr.etalab.studio/) si votre
4747
framework n'est pas supporter, il suffit de demander notre, nous avons pour but de couvrir tous les cas d'usage effectifs.
48-
- [ ] tout [les composants de référence implémenter](https://www.systeme-de-design.gouv.fr/elements-d-interface). À ce jour 17/41, [see details](COMPONENTS.md)
48+
- [ ] tout [les composants de référence implémenter](https://www.systeme-de-design.gouv.fr/elements-d-interface). À ce jour 18/41, [see details](COMPONENTS.md)
4949
- [x] seulement le code des composants que vous utilisez effectivement sera inclus dans votre projet final.
5050
- [x] Intégration facultative avec [MUI](https://mui.com/). Si vous utilisez des composants MUI ils seront automatiquement adaptés pour ressembler à des composants DSFR.
5151
Voir là [documentation](https://react-dsfr.etalab.studio/mui-integration).

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ This module is a wrapper/compatibility layer for [@gouvfr/dsfr](https://github.c
4545
- [x] No [white flash when reloading in SSR setup](https://github.com/codegouvfr/@codegouvfr/react-dsfr/issues/2#issuecomment-1257263480).
4646
- [x] Most components are server component ready. The others are labeled with `"use client";`
4747
- [x] [Perfect integration with all major React framework: Next.js (PagesDir and AppDir), Create React App, Vue](https://react-dsfr.etalab.studio/).
48-
- [ ] All [the components](https://www.systeme-de-design.gouv.fr/elements-d-interface) are implemented (17/41, [see details](COMPONENTS.md))
48+
- [ ] All [the components](https://www.systeme-de-design.gouv.fr/elements-d-interface) are implemented (18/41, [see details](COMPONENTS.md))
4949
- [x] Three shakable distribution, cherry pick the components you import. (It's not all in a big .js bundle)
5050
- [x] Optional integration with [MUI](https://mui.com/). If you use MUI components they will
5151
be automatically adapted to look like [DSFR components](https://www.systeme-de-design.gouv.fr/elements-d-interface). See [documentation](https://react-dsfr.etalab.studio/mui-integration).

src/Card.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import type { RegisteredLinkProps } from "./link";
1010
import { getLink } from "./link";
1111
import { cx } from "./tools/cx";
1212

13-
import "./dsfr/component/card/card.css";
14-
1513
//https://main--ds-gouv.netlify.app/example/component/card/
1614
export type CardProps = {
1715
className?: string;

src/Select.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { cx } from "./tools/cx";
1010
export type SelectProps = {
1111
className?: string;
1212
label: ReactNode;
13+
hint?: ReactNode;
1314
nativeSelectProps: React.DetailedHTMLProps<
1415
React.SelectHTMLAttributes<HTMLSelectElement>,
1516
HTMLSelectElement
@@ -31,6 +32,7 @@ export const Select = memo(
3132
const {
3233
className,
3334
label,
35+
hint,
3436
nativeSelectProps,
3537
disabled = false,
3638
children,
@@ -69,6 +71,7 @@ export const Select = memo(
6971
>
7072
<label className={fr.cx("fr-label")} htmlFor={selectId}>
7173
{label}
74+
{hint !== undefined && <span className={fr.cx("fr-hint-text")}>{hint}</span>}
7275
</label>
7376
<select
7477
{...nativeSelectProps}
@@ -83,7 +86,6 @@ export const Select = memo(
8386
<p
8487
id={stateDescriptionId}
8588
className={fr.cx(
86-
"fr-valid-text",
8789
(() => {
8890
switch (state) {
8991
case "error":

stories/Select.stories.tsx

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import React from "react";
2+
import { Select, type SelectProps } from "../dist/Select";
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({
9+
sectionName,
10+
"wrappedComponent": { Select },
11+
"description": `
12+
- [See DSFR documentation](https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/bandeau-d-information-importante)
13+
- [See source code](https://github.com/codegouvfr/react-dsfr/blob/main/src/Notice.tsx)
14+
15+
\`\`\`tsx
16+
import { useState } from "react";
17+
import { Select } from "../../dist/Select";
18+
19+
function MyComponent(){
20+
21+
const [ value, setValue ] = useState("");
22+
23+
return (
24+
<Select
25+
label="Label"
26+
nativeSelectProps={{
27+
onChange: event => setValue(event.target.value),
28+
value
29+
}}
30+
>
31+
<option value="" selected disabled hidden>Selectionnez une option</option>
32+
<option value="1">Option 1</option>
33+
<option value="2">Option 2</option>
34+
<option value="3">Option 3</option>
35+
<option value="4">Option 4</option>
36+
</Select>
37+
);
38+
39+
}
40+
\`\`\`
41+
`,
42+
"argTypes": {
43+
"nativeSelectProps": {
44+
"description": "The props that you would pass to a native `<select />`",
45+
"control": { "type": null }
46+
},
47+
"children": {
48+
"description": "The `children` that you would give a native `<select />`",
49+
"control": { "type": null }
50+
},
51+
"disabled": {
52+
"control": { "type": "boolean" }
53+
},
54+
"hint": {
55+
"control": { "type": "text" }
56+
},
57+
"state": {
58+
"options": (() => {
59+
const options = ["success", "error", "default"] as const;
60+
61+
assert<Equals<typeof options[number], NonNullable<SelectProps["state"]>>>();
62+
63+
return options;
64+
})(),
65+
"control": { "type": "select" }
66+
},
67+
"stateRelatedMessage": {
68+
"description": "Text to provide if the state is defined",
69+
"control": { "type": "text" }
70+
}
71+
},
72+
"disabledProps": ["lang"]
73+
});
74+
75+
export default meta;
76+
77+
export const Default = getStory({
78+
"label": "Label pour liste déroulante",
79+
"nativeSelectProps": {},
80+
"children": (
81+
<>
82+
<option value="" selected disabled hidden>
83+
Selectionnez une option
84+
</option>
85+
<option value="1">Option 1</option>
86+
<option value="2">Option 2</option>
87+
<option value="3">Option 3</option>
88+
<option value="4">Option 4</option>
89+
</>
90+
)
91+
});
92+
93+
export const ErrorState = getStory({
94+
"label": "Label pour liste déroulante",
95+
"state": "error",
96+
"stateRelatedMessage": "Texte d’erreur obligatoire",
97+
"nativeSelectProps": {},
98+
"children": (
99+
<>
100+
<option value="" selected disabled hidden>
101+
Selectionnez une option
102+
</option>
103+
<option value="1">Option 1</option>
104+
<option value="2">Option 2</option>
105+
<option value="3">Option 3</option>
106+
<option value="4">Option 4</option>
107+
</>
108+
)
109+
});
110+
111+
export const SuccessState = getStory({
112+
"label": "Label pour liste déroulante",
113+
"state": "success",
114+
"stateRelatedMessage": "Texte de validation",
115+
"nativeSelectProps": {},
116+
"children": (
117+
<>
118+
<option value="" selected disabled hidden>
119+
Selectionnez une option
120+
</option>
121+
<option value="1">Option 1</option>
122+
<option value="2">Option 2</option>
123+
<option value="3">Option 3</option>
124+
<option value="4">Option 4</option>
125+
</>
126+
)
127+
});
128+
129+
export const Disabled = getStory({
130+
"label": "Label pour liste déroulante",
131+
"disabled": true,
132+
"nativeSelectProps": {},
133+
"children": (
134+
<>
135+
<option value="" selected disabled hidden>
136+
Selectionnez une option
137+
</option>
138+
<option value="1">Option 1</option>
139+
<option value="2">Option 2</option>
140+
<option value="3">Option 3</option>
141+
<option value="4">Option 4</option>
142+
</>
143+
)
144+
});
145+
146+
export const WithHint = getStory({
147+
"label": "Label pour liste déroulante",
148+
"hint": "Texte de description additionnel",
149+
"nativeSelectProps": {},
150+
"children": (
151+
<>
152+
<option value="" selected disabled hidden>
153+
Selectionnez une option
154+
</option>
155+
<option value="1">Option 1</option>
156+
<option value="2">Option 2</option>
157+
<option value="3">Option 3</option>
158+
<option value="4">Option 4</option>
159+
</>
160+
)
161+
});

0 commit comments

Comments
 (0)