Skip to content
Snippets Groups Projects
Verified Commit 5babf540 authored by Adrian Paschkowski's avatar Adrian Paschkowski :thinking:
Browse files

Make combined a/button component type safe

parent da2f9303
Branches
No related tags found
No related merge requests found
......@@ -84,8 +84,8 @@ export default function WidgetsPage() {
<Button loading outlined>
Loading Outlined
</Button>
<Button href="https://google.com/">Link</Button>
<Button loading href="https://google.com/">
<Button as="a" href="https://google.com/">Link</Button>
<Button as="a" loading href="https://google.com/">
Loading Link
</Button>
</div>
......
......@@ -3,14 +3,16 @@ import Spinner from "./Spinner";
type ButtonStyle = "info" | "success" | "warn" | "danger" | "link";
interface BaseProps {
type ButtonOrLinkProps =
| (React.ButtonHTMLAttributes<HTMLButtonElement> & { as?: "button" })
| (React.AnchorHTMLAttributes<HTMLAnchorElement> & { as: "a" });
type Props = ButtonOrLinkProps & {
buttonStyle?: ButtonStyle;
small?: boolean;
outlined?: boolean;
loading?: boolean;
}
type Props = BaseProps & (JSX.IntrinsicElements["button"] | JSX.IntrinsicElements["a"]);
};
const buttonStyleToClass: Record<ButtonStyle, string> = {
info: "text-white bg-blue-500 hover:bg-blue-600 dark:bg-blue-800 dark:hover:bg-blue-900",
......@@ -65,13 +67,29 @@ export default function Button({ buttonStyle, small, outlined, loading, classNam
props.type ??= "button";
}
const Element = "href" in props ? "a" : "button";
const commonProps = {
className: classes,
disabled: disabled || loading,
};
return (
// @ts-expect-error: Can't be bothered debugging these types, I already wasted 15 minutes on this
<Element className={classes} disabled={disabled || loading} {...props}>
const commonChildren = (
<>
{loading && <Spinner className="w-4 h-4 fill-current" />}
{children}
</Element>
</>
);
// Element creation is separated like this for type safety
if (props.as === "a") {
return (
<a {...props} {...commonProps}>
{commonChildren}
</a>
);
}
return (
<button {...props} {...commonProps}>
{commonChildren}
</button>
);
}
......@@ -97,7 +97,7 @@ function Guild({ id, name, iconHash, memberCount, inviteCode, roles, isMember }:
<Message id="widgets.discord.joined" />
</Button>
) : (
<Button small href={DISCORD_INVITE_URL(inviteCode)}>
<Button as="a" small href={DISCORD_INVITE_URL(inviteCode)}>
<Message id="widgets.discord.join" />
</Button>
)}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment