Skip to content

Commit c52575e

Browse files
committed
Improve Button API
1 parent 3339e88 commit c52575e

File tree

2 files changed

+67
-74
lines changed

2 files changed

+67
-74
lines changed

src/Button.tsx

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ export namespace ButtonProps {
1616
iconId: FrIconClassName | RiIconClassName;
1717
position?: "left" | "right";
1818
};
19-
priority?: "secondary" | "tertiary";
20-
size?: "sm" | "lg";
19+
/** Default primary */
20+
priority?: "primary" | "secondary" | "tertiary";
21+
/** Default medium */
22+
size?: "small" | "medium" | "large";
2123
};
2224

2325
export type Anchor = Common & {
@@ -30,18 +32,19 @@ export namespace ButtonProps {
3032
linkProps?: never;
3133
onClick: React.MouseEventHandler<HTMLButtonElement>;
3234
disabled?: boolean;
35+
/** Default "button" */
3336
type?: "button" | "submit" | "reset";
3437
};
3538
}
3639

3740
export const Button = memo(
3841
forwardRef<HTMLButtonElement | HTMLAnchorElement, ButtonProps>((props, ref) => {
3942
const {
40-
icon,
41-
priority,
4243
className,
43-
size,
4444
label,
45+
icon,
46+
priority = "primary",
47+
size = "medium",
4548
linkProps,
4649
onClick,
4750
disabled,
@@ -55,9 +58,23 @@ export const Button = memo(
5558

5659
const buttonClassName = cx(
5760
fr.cx("fr-btn"),
58-
priority && fr.cx(`fr-btn--${priority}`),
59-
size && fr.cx(`fr-btn--${size}`),
60-
icon && cx(fr.cx(icon.iconId), icon.position && fr.cx(`fr-btn--icon-${icon.position}`)),
61+
priority !== "primary" && fr.cx(`fr-btn--${priority}`),
62+
size !== "medium" &&
63+
fr.cx(
64+
`fr-btn--${(() => {
65+
switch (size) {
66+
case "small":
67+
return "sm";
68+
case "large":
69+
return "lg";
70+
}
71+
})()}`
72+
),
73+
icon !== undefined &&
74+
cx(
75+
fr.cx(icon.iconId),
76+
icon.position !== undefined && fr.cx(`fr-btn--icon-${icon.position}`)
77+
),
6178
className
6279
);
6380
const Component = linkProps ? (

stories/Button.stories.tsx

Lines changed: 42 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,79 @@
11
import { Button } from "../dist/Button";
2-
import type { ButtonProps } from "../dist/Button";
32
import { sectionName } from "./sectionName";
4-
import { getStoryFactory } from "./getStory";
3+
import { getStoryFactory, logCallbacks } from "./getStory";
54

6-
const { meta, getStory } = getStoryFactory<ButtonProps>({
5+
const { meta, getStory } = getStoryFactory({
76
sectionName,
8-
wrappedComponent: { Button },
9-
description: `
7+
"wrappedComponent": { Button },
8+
"description": `
109
- [See DSFR documentation](https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/bouton)
1110
- [See source code](https://github.com/codegouvfr/react-dsfr/blob/main/src/Button.tsx)`,
12-
"argTypes": {
13-
"priority": {
14-
"options": ((): ButtonProps["priority"][] => ["secondary", "tertiary"])(),
15-
"control": { "type": "radio" }
16-
},
17-
"label": {
18-
"description": `Required`
19-
},
20-
"href": {
21-
"description":
22-
"If set, Button component will render a <a> tag, otherwise, it will render a <button>"
23-
},
24-
"type": {
25-
"options": ((): ButtonProps["type"][] => ["button", "submit", "reset"])(),
26-
"control": { "type": "radio" },
27-
"description":
28-
"Type can only be set on <button> element. If the Button component has no href, it will render a <button> element. If type prop is not set, it will render a type='submit' attribute (default value for a <button> element"
29-
},
30-
"onClick": {
31-
"description":
32-
"onClick callback, can only be set if Button has no href prop set (to prevent onClick='window.open()' type behavior)"
33-
},
34-
"disabled": {
35-
"description":
36-
"Can only be set if Button has no href prop set (disabled can't be set on <a> element)"
37-
},
38-
"target": {
39-
"description": `Can only be set with a href attribute`,
40-
"options": ((): ButtonProps["target"][] => ["_self", "_blank", "_parent", "_top"])()
41-
},
42-
"size": {
43-
"description": `Can only be set with a href attribute`,
44-
"options": ((): ButtonProps["size"][] => ["sm", "lg"])()
45-
}
46-
},
4711
"disabledProps": ["lang"]
4812
});
4913

5014
export default meta;
5115

5216
export const Default = getStory({
53-
label: "Simple button"
17+
"label": "Simple button",
18+
...logCallbacks(["onClick"])
5419
});
5520

5621
export const ButtonSecondary = getStory({
57-
priority: "secondary",
58-
label: "Simple button - secondary"
22+
"priority": "secondary",
23+
"label": "Simple button - secondary",
24+
...logCallbacks(["onClick"])
5925
});
6026

6127
export const ButtonTertiary = getStory({
62-
priority: "tertiary",
63-
label: "Simple button - tertiary"
28+
"priority": "tertiary",
29+
"label": "Simple button - tertiary",
30+
...logCallbacks(["onClick"])
6431
});
6532

6633
export const ButtonDisabled = getStory({
67-
label: "Simple button - disabled",
68-
disabled: true
34+
"label": "Simple button - disabled",
35+
"disabled": true,
36+
...logCallbacks(["onClick"])
6937
});
7038

7139
export const ButtonWithIconDefault = getStory({
72-
label: "Simple button with icon",
73-
icon: {
74-
name: "fr-icon-account-circle-fill"
75-
}
40+
"label": "Simple button with icon",
41+
"icon": {
42+
iconId: "fr-icon-account-circle-fill"
43+
},
44+
...logCallbacks(["onClick"])
7645
});
7746

7847
export const ButtonWithIconLeft = getStory({
79-
label: "Simple button with icon",
80-
icon: {
81-
name: "fr-icon-account-circle-fill",
82-
position: "left"
83-
}
48+
"label": "Simple button with icon",
49+
"icon": {
50+
"iconId": "fr-icon-account-circle-fill",
51+
"position": "left"
52+
},
53+
...logCallbacks(["onClick"])
8454
});
8555

8656
export const ButtonWithIconRight = getStory({
87-
label: "Simple button with icon",
88-
icon: {
89-
name: "fr-icon-account-circle-fill",
90-
position: "right"
91-
}
57+
"label": "Simple button with icon",
58+
"icon": {
59+
"iconId": "fr-icon-account-circle-fill",
60+
"position": "right"
61+
},
62+
...logCallbacks(["onClick"])
9263
});
9364

9465
export const DefaultAnchorButton = getStory({
95-
label: "Simple button - with href (anchor)",
96-
href: "https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/bouton"
66+
"label": "Simple button - with href (anchor)",
67+
"linkProps": {
68+
"href": "https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/bouton",
69+
"target": "_blank"
70+
}
9771
});
9872

9973
export const DefaultAnchorButtonWithTargetBlank = getStory({
100-
label: "Simple button - with href (anchor) and target _blank",
101-
target: "_blank",
102-
href: "https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/bouton"
74+
"label": "Simple button - with href (anchor) and target _blank",
75+
"linkProps": {
76+
"target": "_blank",
77+
"href": "https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/bouton"
78+
}
10379
});

0 commit comments

Comments
 (0)