"use client"; import React from "react"; import { cls } from "../util"; export type ButtonProps = { children?: React.ReactNode; variant?: "filled" | "outlined" | "text"; disabled?: boolean; color?: "primary" | "secondary" | "text" | "error" | "neutral"; size?: "small" | "medium" | "large" | "xl" | "2xl"; startIcon?: React.ReactNode; fullWidth?: boolean; className?: string; component?: C; onClick?: React.MouseEventHandler; } & React.ComponentPropsWithoutRef; const ButtonInner = React.memo(React.forwardRef< HTMLButtonElement, ButtonProps >(({ children, className, variant = "filled", disabled = false, size = "medium", startIcon = null, fullWidth = false, component: Component, color = "neutral", loading, ...props }: ButtonProps, ref) => { const baseClasses = "typography-button h-fit rounded-md whitespace-nowrap inline-flex items-center justify-center p-2 px-4 focus:outline-none transition ease-in-out duration-150 gap-2"; const buttonClasses = cls({ "w-full": fullWidth, "w-fit": !fullWidth, // Filled Variants "border border-primary bg-primary focus:ring-primary shadow hover:ring-1 hover:ring-primary text-white hover:text-white": variant === "filled" && color === "primary" && !disabled, "border border-secondary bg-secondary focus:ring-secondary shadow hover:ring-1 hover:ring-secondary text-white hover:text-white": variant === "filled" && color === "secondary" && !disabled, "border border-red-500 bg-red-500 hover:bg-red-500 focus:ring-red-500 shadow hover:ring-1 hover:ring-red-600 text-white hover:text-white": variant === "filled" && color === "error" && !disabled, "border border-surface-accent-200 bg-surface-accent-200 hover:bg-surface-accent-300 focus:ring-surface-accent-400 shadow hover:ring-1 hover:ring-surface-accent-400 text-text-primary hover:text-text-primary dark:text-text-primary-dark hover:dark:text-text-primary-dark": variant === "filled" && color === "text" && !disabled, "border border-transparent bg-surface-100 hover:bg-surface-accent-200 text-text-primary dark:bg-surface-800 dark:hover:bg-surface-accent-700 dark:text-text-primary-dark hover:text-text-primary dark:text-text-primary-dark hover:dark:text-text-primary-dark": variant === "filled" && color === "neutral" && !disabled, // Text Variants "border border-transparent text-primary hover:text-primary hover:bg-surface-accent-200 hover:bg-opacity-75 hover:bg-surface-accent-200/75 dark:hover:bg-surface-accent-800": variant === "text" && color === "primary" && !disabled, "border border-transparent text-secondary hover:text-secondary hover:bg-surface-accent-200 hover:bg-opacity-75 hover:bg-surface-accent-200/75 dark:hover:bg-surface-accent-800": variant === "text" && color === "secondary" && !disabled, "border border-transparent text-red-500 hover:text-red-500 hover:bg-red-500 hover:bg-opacity-10 hover:bg-red-500/10": variant === "text" && color === "error" && !disabled, "border border-transparent text-text-primary hover:text-text-primary dark:text-text-primary-dark hover:dark:text-text-primary-dark hover:bg-surface-accent-200 hover:dark:bg-surface-700": variant === "text" && color === "text" && !disabled, "border border-transparent text-text-primary hover:text-text-primary hover:bg-surface-accent-200 dark:text-text-primary-dark dark:hover:text-text-primary-dark dark:hover:bg-surface-accent-700": variant === "text" && color === "neutral" && !disabled, // Outlined Variants "border border-primary text-primary hover:text-primary hover:bg-primary-bg hover:bg-primary/10": variant === "outlined" && color === "primary" && !disabled, "border border-secondary text-secondary hover:text-secondary hover:bg-secondary-bg": variant === "outlined" && color === "secondary" && !disabled, "border border-red-500 text-red-500 hover:text-red-500 hover:bg-red-500 hover:text-white": variant === "outlined" && color === "error" && !disabled, "border border-surface-accent-400 text-text-primary hover:text-text-primary dark:text-text-primary-dark hover:bg-surface-accent-200": variant === "outlined" && color === "text" && !disabled, "border border-surface-300 text-text-primary hover:bg-surface-accent-200 dark:border-surface-600 dark:text-text-primary-dark dark:hover:bg-surface-accent-700": variant === "outlined" && color === "neutral" && !disabled, // Disabled states for all variants "text-text-disabled dark:text-text-disabled-dark": disabled, "border border-transparent opacity-50": variant === "text" && disabled, "border border-surface-500 opacity-50": variant === "outlined" && disabled, "border border-transparent bg-surface-300 dark:bg-surface-500 opacity-70 bg-surface-300/70 dark:bg-surface-500/70": variant === "filled" && disabled, }); const sizeClasses = cls( { "py-1 px-2": size === "small", "py-2 px-4": size === "medium", "py-2.5 px-5": size === "large", "py-3 px-6": size === "xl", "py-4 px-10": size === "2xl" } ); if (Component) { return ( {startIcon} {children} ); } return ( ); })); ButtonInner.displayName = "Button" export const Button = ButtonInner as React.FC>;