since3-website/components/ui/button.tsx
2026-09-25 00:45:33 +02:00

72 lines
2.6 KiB
TypeScript

import { Button as ButtonPrimitive } from "@base-ui/react/button"
import { cva, type VariantProps } from "class-variance-authority"
import { ArrowRight } from "lucide-react"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"group/button relative inline-flex shrink-0 items-center justify-center rounded-full border font-medium whitespace-nowrap transition-[background-color,border-color,color,scale] duration-200 ease-out select-none active:not-aria-[haspopup]:scale-[0.97] disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
{
variants: {
variant: {
// Black on light, white on dark
solid:
"border-transparent bg-fg text-bg hover:bg-ink-800 dark:hover:bg-ink-200",
// Hairline only
outline:
"border-fg/20 bg-transparent text-fg hover:border-fg/60 aria-expanded:border-fg/60",
// Only on top of glass surfaces or dark sections
glass:
"border-white/15 bg-white/10 text-white backdrop-blur-md hover:bg-white/20",
ghost: "border-transparent text-fg hover:bg-fg/5 aria-expanded:bg-fg/5",
link: "rounded-none border-transparent px-0 text-fg underline-offset-4 hover:underline",
},
size: {
default: "h-11 gap-2 px-5 text-[0.9375rem]",
sm: "h-9 gap-1.5 px-4 text-sm",
lg: "h-13 gap-2 px-7 text-base",
icon: "size-10",
"icon-sm": "size-8",
},
},
defaultVariants: {
variant: "solid",
size: "default",
},
}
)
function Button({
className,
variant = "solid",
size = "default",
...props
}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
return (
<ButtonPrimitive
data-slot="button"
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
)
}
/**
* The arrow is not part of the label: it appears on hover only.
* Place it as the last child of a button or a link styled with `buttonVariants`.
*/
function ButtonArrow({ className }: { className?: string }) {
return (
<span
aria-hidden="true"
className={cn(
"-ml-2 grid w-0 overflow-hidden opacity-0 transition-[width,margin,opacity] duration-200 ease-out group-hover/button:ml-0 group-hover/button:w-4 group-hover/button:opacity-100 group-focus-visible/button:ml-0 group-focus-visible/button:w-4 group-focus-visible/button:opacity-100",
className
)}
>
<ArrowRight className="size-4" />
</span>
)
}
export { Button, ButtonArrow, buttonVariants }