Skip to content

Commit 7b0ee33

Browse files
committed
Add Button component
1 parent 7bf5c62 commit 7b0ee33

File tree

1 file changed

+90
-0
lines changed

1 file changed

+90
-0
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { clsx } from "clsx"
2+
import { Anchor } from "./anchor"
3+
4+
type Size = "md" | "lg"
5+
6+
// eslint-disable-next-line @typescript-eslint/no-namespace
7+
export declare namespace ButtonProps {
8+
export interface BaseProps {
9+
size?: Size
10+
}
11+
12+
export interface AnchorProps
13+
extends BaseProps,
14+
React.DetailedHTMLProps<
15+
React.AnchorHTMLAttributes<HTMLAnchorElement>,
16+
HTMLAnchorElement
17+
> {
18+
href: string
19+
as?: never
20+
className?: string
21+
}
22+
23+
export interface ButtonProps
24+
extends BaseProps,
25+
React.DetailedHTMLProps<
26+
React.ButtonHTMLAttributes<HTMLButtonElement>,
27+
HTMLButtonElement
28+
> {
29+
href?: never
30+
as?: never
31+
className?: string
32+
disabled?: boolean
33+
type?: "button" | "submit" | "reset"
34+
onClick?: React.MouseEventHandler<HTMLButtonElement>
35+
}
36+
37+
/**
38+
* Use inside `<summary>` or as visual part of bigger interactive element.
39+
* Prefer `a` and `button` Buttons otherwise.
40+
*/
41+
export interface NonInteractiveProps
42+
extends BaseProps,
43+
React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> {
44+
href?: never
45+
as: "span" | "div"
46+
className?: string
47+
}
48+
}
49+
50+
export type ButtonProps =
51+
| ButtonProps.AnchorProps
52+
| ButtonProps.ButtonProps
53+
| ButtonProps.NonInteractiveProps
54+
55+
export function Button(props: ButtonProps) {
56+
const className = clsx(
57+
"relative flex items-center justify-center gap-2.5 rounded-lg font-normal text-base/none text-neu-0 font-sans h-14 px-8 data-[size=md]:h-12",
58+
props.className,
59+
)
60+
61+
const styleAttrs = { "data-size": props.size }
62+
63+
if ("href" in props && typeof props.href === "string") {
64+
const { className: _1, size: _2, children, ...rest } = props
65+
66+
return (
67+
<Anchor className={className} {...styleAttrs} {...rest}>
68+
{children}
69+
</Anchor>
70+
)
71+
}
72+
73+
if (props.as) {
74+
const { className: _1, size: _2, children, as, ...rest } = props
75+
const Root = as as "span" // we don't need HTMLDivElement type
76+
return (
77+
<Root className={className} {...styleAttrs} {...rest}>
78+
{children}
79+
</Root>
80+
)
81+
}
82+
83+
const { className: _1, size: _2, children, ...rest } = props
84+
85+
return (
86+
<button className={className} {...styleAttrs} {...rest}>
87+
{children}
88+
</button>
89+
)
90+
}

0 commit comments

Comments
 (0)