'use client' import { Button as HeroButton, Spinner, buttonVariants } from '@heroui/react' import Link from 'next/link' import React, { forwardRef } from 'react' interface ButtonProps { 'aria-controls'?: string 'aria-expanded'?: boolean | 'true' | 'false' 'aria-label'?: string 'aria-pressed'?: boolean | 'true' | 'false' 'aria-checked'?: boolean | 'true' | 'false' 'aria-selected'?: boolean | 'true' | 'false' children: React.ReactNode color?: 'default' | 'primary' | 'secondary' | 'secondary-dark' | 'success' | 'warning' | 'danger' size?: 'sm' | 'md' | 'lg' | 'xl' variant?: 'solid' | 'bordered' | 'light' | 'flat' | 'faded' | 'shadow' | 'ghost' type?: 'button' | 'submit' | 'reset' target?: '_blank' | '_self' radius?: 'none' | 'sm' | 'md' | 'lg' | 'full' role?: React.AriaRole disabled?: boolean isLoading?: boolean iconOnly?: boolean fullWidth?: boolean iconStart?: React.ReactNode iconEnd?: React.ReactNode className?: string to?: string onClick?: () => void } type HeroButtonVariant = 'primary' | 'secondary' | 'tertiary' | 'outline' | 'ghost' | 'danger' | 'danger-soft' function resolveVariant(color: NonNullable, variant: ButtonProps['variant']): HeroButtonVariant { if (color === 'danger') return variant === 'flat' || variant === 'light' ? 'danger-soft' : 'danger' if (color === 'secondary-dark') return variant === 'flat' || variant === 'light' || variant === 'ghost' ? 'tertiary' : 'primary' if (variant === 'ghost') return 'ghost' if (variant === 'bordered' || variant === 'faded') return 'secondary' if (variant === 'light' || variant === 'flat') return 'tertiary' return 'primary' } function resolveSemanticColorStyle( color: NonNullable, variant: ButtonProps['variant'] ): React.CSSProperties | undefined { if (color !== 'secondary-dark') return undefined const isSoft = variant === 'flat' || variant === 'light' || variant === 'ghost' return { '--button-bg': isSoft ? 'transparent' : 'var(--color-secondary-900)', '--button-bg-hover': isSoft ? 'color-mix(in srgb, var(--color-secondary-900) 8%, transparent)' : 'var(--color-secondary-800)', '--button-bg-pressed': isSoft ? 'color-mix(in srgb, var(--color-secondary-900) 12%, transparent)' : 'var(--color-secondary-900)', '--button-fg': isSoft ? 'var(--color-secondary-900)' : '#ffffff', } as React.CSSProperties } function resolveSemanticColorClasses(color: NonNullable, variant: ButtonProps['variant']): string { const isSoft = variant === 'flat' || variant === 'light' if (color === 'success') return isSoft ? 'bg-fifth/10 text-fifth' : 'bg-fifth text-white' if (color === 'warning') return isSoft ? 'bg-fourth-900/10 text-fourth-900' : 'bg-fourth-900 text-tertiary' if (color === 'secondary') return isSoft ? 'bg-tertiary/10 text-tertiary' : 'bg-tertiary text-tertiary' return '' } // Using forwardRef const Button = forwardRef( ( { 'aria-controls': ariaControls, 'aria-expanded': ariaExpanded, 'aria-label': ariaLabel, 'aria-pressed': ariaPressed, 'aria-checked': ariaChecked, 'aria-selected': ariaSelected, children, color = 'primary', size, variant, type = 'button', target = '_self', radius = 'sm', role, disabled, isLoading, iconOnly, fullWidth, iconStart, iconEnd, className, to, onClick, }, ref ) => { const isLink = Boolean(to) const resolvedVariant = resolveVariant(color, variant) const resolvedSize = size === 'xl' ? 'lg' : size const semanticColorStyle = resolveSemanticColorStyle(color, variant) const resolvedClassName = `${size === 'xl' ? 'button--xl' : 'font-semibold'} shadow-none transition-all ${resolveSemanticColorClasses(color, variant)} ${ radius === 'none' ? 'rounded-none' : radius === 'full' ? 'rounded-full' : radius === 'sm' ? 'rounded-lg' : radius === 'md' ? 'rounded-xl' : 'rounded-2xl' } ${className ?? ''}`.trim() const ariaProps = { 'aria-controls': ariaControls, 'aria-expanded': ariaExpanded, 'aria-label': ariaLabel, 'aria-pressed': ariaPressed, 'aria-checked': ariaChecked, 'aria-selected': ariaSelected, role, } if (isLink && to) { return ( {iconStart} {children} {iconEnd} ) } return ( {isLoading ? ( ) : ( <> {iconStart} {children} {iconEnd} )} ) } ) Button.displayName = 'Button' export default Button