A clickable button element with various styles and sizes in neobrutalism design.
1"use client";
2
3import { Slot } from "@radix-ui/react-slot";
4import { type VariantProps, cva } from "class-variance-authority";
5import * as React from "react";
6
7// Utility function for class name merging
8const cn = (...classes: any[]) => classes.filter(Boolean).join(" ");
9
10const buttonVariants = cva(
11 "inline-flex items-center justify-center whitespace-nowrap rounded-base text-sm font-base ring-offset-white transition-all gap-2 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
12 {
13 variants: {
14 variant: {
15 default:
16 "text-mtext bg-main border-2 border-border shadow-shadow hover:translate-x-boxShadowX hover:translate-y-boxShadowY hover:shadow-none",
17 noShadow: "text-mtext bg-main border-2 border-border",
18 neutral:
19 "bg-bw text-text border-2 border-border shadow-shadow hover:translate-x-boxShadowX hover:translate-y-boxShadowY hover:shadow-none",
20 reverse:
21 "text-mtext bg-main border-2 border-border hover:translate-x-reverseBoxShadowX hover:translate-y-reverseBoxShadowY hover:shadow-shadow",
22 },
23 size: {
24 default: "h-10 px-4 py-2",
25 sm: "h-9 px-3",
26 lg: "h-11 px-8",
27 icon: "h-10 w-10",
28 },
29 },
30 defaultVariants: {
31 variant: "default",
32 size: "default",
33 },
34 }
35);
36
37export interface ButtonProps
38 extends React.ButtonHTMLAttributes<HTMLButtonElement>,
39 VariantProps<typeof buttonVariants> {
40 asChild?: boolean;
41}
42
43const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
44 ({ className, variant, size, asChild = false, ...props }, ref) => {
45 const Comp = asChild ? Slot : "button";
46 return (
47 <Comp
48 className={cn(buttonVariants({ variant, size, className }))}
49 ref={ref}
50 {...props}
51 />
52 );
53 }
54);
55Button.displayName = "Button";
56
57export { Button, buttonVariants };
58