Leon4gr45's picture
Deploy to clean space
75fefa7 verified
"use client";
import React from "react";
import { cn } from "@/utils/cn";
import { LucideIcon } from "lucide-react";
interface SlateButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
icon?:
| LucideIcon
| React.ComponentType<{
className?: string;
isHovered?: boolean;
isOpen?: boolean;
}>
| React.ReactNode;
iconPosition?: "left" | "right";
children: React.ReactNode;
size?: "sm" | "md" | "lg";
fullWidth?: boolean;
isLoading?: boolean;
isOpen?: boolean;
}
export const SlateButton = React.forwardRef<
HTMLButtonElement,
SlateButtonProps
>(
(
{
icon: Icon,
iconPosition = "left",
children,
className,
size = "md",
fullWidth = false,
isLoading = false,
isOpen = false,
disabled,
...props
},
ref,
) => {
const [isHovered, setIsHovered] = React.useState(false);
const sizeClasses = {
sm: "h-32 px-12 text-body-small gap-6",
md: "h-40 px-16 text-body-medium gap-8",
lg: "h-48 px-24 text-body-large gap-10",
};
const iconSizes = {
sm: "w-14 h-14",
md: "w-16 h-16",
lg: "w-20 h-20",
};
return (
<button
ref={ref}
className={cn(
// Base styles
"inline-flex items-center justify-center rounded-12 transition-all",
// Colors
"bg-black-alpha-4 text-accent-black",
"hover:bg-black-alpha-6",
"active:scale-[0.98]",
// Border
// "border-0",
// Size
sizeClasses[size],
// States
disabled && "opacity-50 cursor-not-allowed",
isLoading && "cursor-wait",
// Full width
fullWidth && "w-full",
className,
)}
disabled={disabled || isLoading}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
{...props}
>
{isLoading ? (
<div className={cn("animate-spin rounded-full", iconSizes[size])} />
) : (
<>
{Icon &&
iconPosition === "left" &&
(React.isValidElement(Icon) ? (
Icon
) : (
//@ts-expect-error - Icon component type allows JSX element
<Icon
className={cn(iconSizes[size], "flex-shrink-0")}
isHovered={isHovered}
isOpen={isOpen}
/>
))}
{children}
{Icon &&
iconPosition === "right" &&
(React.isValidElement(Icon) ? (
Icon
) : (
//@ts-expect-error - Icon component type allows JSX element
<Icon
className={cn(iconSizes[size], "flex-shrink-0")}
isHovered={isHovered}
isOpen={isOpen}
/>
))}
</>
)}
</button>
);
},
);
SlateButton.displayName = "SlateButton";