Skip to content

Commit 90d7de9

Browse files
committed
update component using Link / RegisteredLinkProps, passing ref with proper type
1 parent 60810e5 commit 90d7de9

File tree

1 file changed

+58
-58
lines changed

1 file changed

+58
-58
lines changed

src/Button.tsx

Lines changed: 58 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,84 @@
11
import React, { memo, forwardRef } from "react";
2-
// import { symToStr } from "tsafe/symToStr";
32
import { fr } from "./lib";
43
import { cx } from "./lib/tools/cx";
54
import type { FrIconClassName, RiIconClassName } from "./lib/generatedFromCss/classNames";
5+
import { RegisteredLinkProps, useLink } from "./lib/routing";
6+
import { assert } from "tsafe/assert";
7+
import type { Equals } from "tsafe";
68

7-
// We make users import dsfr.css, so we don't need to import the scoped CSS
8-
// but in the future if we have a complete component coverage it
9-
// we could stop requiring users to import the hole CSS and only import on a
10-
// per component basis.
11-
import "./dsfr/component/button/button.css";
12-
13-
// This is just an example, we should get types from .fr-icon-* list
14-
// const icons = ["fr-icon-checkbox-circle-line", "fr-icon-account-circle-fill"] as const;
15-
// type IconType = typeof icons[number];
16-
17-
type IconType = FrIconClassName | RiIconClassName;
18-
19-
type ButtonIcon = {
20-
name: IconType;
21-
position?: "left" | "right";
22-
};
23-
24-
type ButtonCommonProps = {
25-
label: string;
26-
icon?: ButtonIcon;
27-
priority?: "secondary" | "tertiary";
28-
className?: string;
29-
size?: ButtonProps.Size;
30-
};
31-
32-
export type ButtonProps = ButtonCommonProps & (ButtonProps.Anchor | ButtonProps.Button);
9+
export type ButtonProps = ButtonProps.Anchor | ButtonProps.Button;
3310

3411
export namespace ButtonProps {
35-
export type Size = "sm" | "lg";
36-
export type Anchor = {
37-
href: string | null;
38-
target?: React.HTMLAttributeAnchorTarget;
12+
type Common = {
13+
className?: string;
14+
label: string;
15+
icon?: {
16+
iconId: FrIconClassName | RiIconClassName;
17+
position?: "left" | "right";
18+
};
19+
priority?: "secondary" | "tertiary";
20+
size?: "sm" | "lg";
21+
};
22+
23+
export type Anchor = Common & {
24+
linkProps: RegisteredLinkProps;
25+
onClick?: never;
3926
disabled?: never;
4027
type?: never;
41-
onClick?: never;
4228
};
43-
export type Button = {
44-
onClick?: React.MouseEventHandler<HTMLButtonElement>;
29+
export type Button = Common & {
30+
linkProps?: never;
31+
onClick: React.MouseEventHandler<HTMLButtonElement>;
4532
disabled?: boolean;
4633
type?: "button" | "submit" | "reset";
47-
href?: never;
48-
target?: never;
4934
};
5035
}
5136

5237
export const Button = memo(
53-
forwardRef<HTMLButtonElement | HTMLAnchorElement, ButtonProps>(props => {
54-
const { icon, priority, className, size, label } = props;
38+
forwardRef<HTMLButtonElement | HTMLAnchorElement, ButtonProps>((props, ref) => {
39+
const {
40+
icon,
41+
priority,
42+
className,
43+
size,
44+
label,
45+
linkProps,
46+
onClick,
47+
disabled,
48+
type,
49+
...rest
50+
} = props;
51+
52+
assert<Equals<keyof typeof rest, never>>();
53+
54+
const { Link } = useLink();
5555

5656
const buttonClassName = cx(
5757
fr.cx("fr-btn"),
5858
priority && fr.cx(`fr-btn--${priority}`),
5959
size && fr.cx(`fr-btn--${size}`),
60-
icon && cx(fr.cx(icon.name), icon.position && fr.cx(`fr-btn--icon-${icon.position}`)),
60+
icon && cx(fr.cx(icon.iconId), icon.position && fr.cx(`fr-btn--icon-${icon.position}`)),
6161
className
6262
);
63-
const Component =
64-
"href" in props ? (
65-
<a
66-
className={buttonClassName}
67-
href={props.href ?? undefined}
68-
target={props.target || "_self"}
69-
>
70-
{label}
71-
</a>
72-
) : (
73-
<button
74-
className={buttonClassName}
75-
type={props.type}
76-
onClick={props.onClick}
77-
disabled={props.disabled}
78-
>
79-
{label}
80-
</button>
81-
);
63+
const Component = linkProps ? (
64+
<Link
65+
{...linkProps}
66+
className={buttonClassName}
67+
ref={ref as React.ForwardedRef<HTMLAnchorElement>}
68+
>
69+
{label}
70+
</Link>
71+
) : (
72+
<button
73+
className={buttonClassName}
74+
type={type}
75+
onClick={onClick}
76+
disabled={disabled}
77+
ref={ref as React.ForwardedRef<HTMLButtonElement>}
78+
>
79+
{label}
80+
</button>
81+
);
8282

8383
return Component;
8484
})

0 commit comments

Comments
 (0)