import { AnchorHTMLAttributes, ButtonHTMLAttributes, ComponentProps, DetailedHTMLProps, HTMLAttributeAnchorTarget, HTMLAttributes, } from "react"; import { twMerge } from "tailwind-merge"; import Loading from "../elements/Loading"; export type TWUIButtonProps = DetailedHTMLProps< ButtonHTMLAttributes, HTMLButtonElement > & { title: string; variant?: "normal" | "ghost" | "outlined"; color?: | "primary" | "secondary" | "text" | "white" | "accent" | "gray" | "error" | "warning" | "success"; size?: "small" | "smaller" | "normal" | "large" | "larger"; loadingIconSize?: React.ComponentProps["size"]; href?: string; target?: HTMLAttributeAnchorTarget; loading?: boolean; linkProps?: DetailedHTMLProps< AnchorHTMLAttributes, HTMLAnchorElement >; beforeIcon?: React.ReactNode; afterIcon?: React.ReactNode; buttonContentProps?: DetailedHTMLProps< HTMLAttributes, HTMLDivElement >; loadingProps?: ComponentProps; }; /** * # Buttons * @className twui-button-general * @className twui-button-content-wrapper * @className twui-button-primary * @className twui-button-primary-outlined * @className twui-button-primary-ghost * @className twui-button-secondary * @className twui-button-secondary-outlined * @className twui-button-secondary-ghost * @className twui-button-white * @className twui-button-white-outlined * @className twui-button-white-ghost * @className twui-button-accent * @className twui-button-accent-outlined * @className twui-button-accent-ghost * @className twui-button-gray * @className twui-button-gray-outlined * @className twui-button-gray-ghost * * @example ```css CSS directive: //@theme inline { --breakpoint-xs: 350px; --color-primary: #000000; --color-primary-hover: #29292b; --color-primary-outline: #29292b; --color-primary-text: #29292b; --color-primary-dark: #29292b; --color-primary-dark-hover: #4b4b4b; --color-primary-dark-outline: #4b4b4b; --color-primary-dark-text: #4b4b4b; --color-secondary: #000000; --color-secondary-hover: #dddddd; --color-secondary-outline: #dddddd; --color-secondary-text: #dddddd; --color-secondary-dark: #000000; --color-secondary-dark-hover: #dddddd; --color-secondary-dark-outline: #dddddd; --color-secondary-dark-text: #dddddd; --color-accent: #000000; --color-accent-hover: #dddddd; --color-accent-outline: #dddddd; --color-accent-text: #dddddd; --color-accent-dark: #000000; --color-accent-dark-hover: #dddddd; --color-accent-dark-outline: #dddddd; --color-accent-dark-text: #dddddd; } ``` */ export default function Button({ href, target, variant, color, size, buttonContentProps, linkProps, beforeIcon, afterIcon, loading, loadingIconSize, loadingProps, ...props }: TWUIButtonProps) { const finalClassName: string = (() => { if (variant == "normal" || !variant) { if (color == "primary" || !color) return twMerge( "bg-primary hover:bg-primary-hover text-white", "dark:bg-primary-dark hover:dark:bg-primary-dark-hover text-white", "twui-button-primary" ); if (color == "secondary") return twMerge( "bg-secondary hover:bg-secondary-hover text-white", "twui-button-secondary" ); if (color == "white") return twMerge( "!bg-white hover:!bg-slate-200 !text-slate-800", "twui-button-white" ); if (color == "accent") return twMerge( "bg-accent hover:bg-accent-hover text-white", "twui-button-accent" ); if (color == "gray") return twMerge( "bg-gray hover:bg-gray-hover text-foreground-light", "dark:bg-gray-dark hover:dark:bg-gray-dark-hover dark:text-foreground-dark", "twui-button-gray" ); if (color == "success") return twMerge( "bg-success hover:bg-success-hover text-white", "dark:bg-success hover:dark:bg-success-hover text-white", "twui-button-success" ); if (color == "error") return twMerge( "bg-error hover:bg-error-hover text-white", "dark:bg-error hover:dark:bg-error-hover text-white", "twui-button-error" ); } else if (variant == "outlined") { if (color == "primary" || !color) return twMerge( "bg-transparent outline outline-1 outline-primary", "text-primary-text dark:text-primary-dark-text dark:outline-primary-dark-outline", "twui-button-primary-outlined" ); if (color == "secondary") return twMerge( "bg-transparent outline outline-1 outline-secondary", "text-secondary", "twui-button-secondary-outlined" ); if (color == "accent") return twMerge( "bg-transparent outline outline-1 outline-accent", "text-accent", "twui-button-accent-outlined" ); if (color == "gray") return twMerge( "bg-transparent outline outline-1 outline-slate-300", "text-slate-600 dark:text-white/60 dark:outline-white/30", "twui-button-gray-outlined" ); if (color == "white") return twMerge( "bg-transparent outline outline-1 outline-white/50", "text-white", "twui-button-white-outlined" ); if (color == "error") return twMerge( "bg-transparent outline outline-1 outline-error text-error", "dark:outline-error dark:text-error-dark", "twui-button-error-outlined" ); } else if (variant == "ghost") { if (color == "primary" || !color) return twMerge( "bg-transparent dark:bg-transparent outline-none p-2", "text-primary-text dark:text-primary-dark-text hover:bg-transparent dark:hover:bg-transparent", "twui-button-primary-ghost" ); if (color == "secondary") return twMerge( "bg-transparent dark:bg-transparent outline-none p-2", "text-secondary hover:bg-transparent dark:hover:bg-transparent", "twui-button-secondary-ghost" ); if (color == "text") return twMerge( "bg-transparent dark:bg-transparent outline-none p-2 dark:text-foreground-dark", "text-foreground-light hover:bg-transparent dark:hover:bg-transparent", "twui-button-secondary-ghost" ); if (color == "accent") return twMerge( "bg-transparent dark:bg-transparent outline-none p-2", "text-accent hover:bg-transparent dark:hover:bg-transparent", "twui-button-accent-ghost" ); if (color == "gray") return twMerge( "bg-transparent dark:bg-transparent outline-none p-2 hover:bg-transparent dark:hover:bg-transparent", "text-slate-600 dark:text-white/70 hover:opacity-80", "twui-button-gray-ghost" ); if (color == "error") return twMerge( "bg-transparent outline-none p-2", "text-red-600 dark:text-red-400", "twui-button-error-ghost" ); if (color == "warning") return twMerge( "bg-transparent outline-none p-2", "text-yellow-600", "twui-button-warning-ghost" ); if (color == "success") return twMerge( "bg-transparent outline-none p-2", "text-success", "twui-button-success-ghost" ); if (color == "white") return twMerge( "bg-transparent outline-none p-2", "text-white", "twui-button-white-ghost" ); } return ""; })(); const buttonComponent = ( {beforeIcon && beforeIcon} {props.children} {afterIcon && afterIcon} {loading && ( { if (loadingIconSize) return loadingIconSize; switch (size) { case "small": return "small"; case "smaller": return "smaller"; default: return "normal"; } })()} {...loadingProps} className={twMerge("absolute", loadingProps?.className)} /> )} ); if (href) return ( {buttonComponent} ); return buttonComponent; }