import type { ReactNode } from 'react'
import React from 'react'
export type ButtonVariant = 'primary' | 'secondary' | 'success' | 'danger' | 'ghost'
export type ButtonSize = 'small' | 'medium' | 'large'
interface ButtonProps {
children: ReactNode
variant?: ButtonVariant
size?: ButtonSize
disabled?: boolean
loading?: boolean
onClick?: () => void
type?: 'button' | 'submit' | 'reset'
className?: string
'aria-label'?: string
'aria-expanded'?: boolean
'aria-haspopup'?: boolean | 'true' | 'false' | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog'
'aria-selected'?: boolean
role?: string
id?: string
}
function getVariantClasses(variant: ButtonVariant): string {
switch (variant) {
case 'primary':
return 'bg-neon-cyan/20 hover:bg-neon-cyan/30 text-neon-cyan border-neon-cyan/50 hover:shadow-glow-cyan'
case 'secondary':
return 'bg-cyber-light hover:bg-cyber-dark text-cyber-accent border-neon-cyan/30 hover:border-neon-cyan/50'
case 'success':
return 'bg-neon-green/20 hover:bg-neon-green/30 text-neon-green border-neon-green/50 hover:shadow-glow-green'
case 'danger':
return 'bg-red-500/20 hover:bg-red-500/30 text-red-400 border-red-500/50'
case 'ghost':
return 'bg-transparent hover:bg-cyber-light text-cyber-accent border-transparent hover:border-neon-cyan/30'
default:
return 'bg-neon-cyan/20 hover:bg-neon-cyan/30 text-neon-cyan border-neon-cyan/50 hover:shadow-glow-cyan'
}
}
function getSizeClasses(size: ButtonSize): string {
switch (size) {
case 'small':
return 'px-3 py-1.5 text-sm'
case 'medium':
return 'px-4 py-2 text-base'
case 'large':
return 'px-6 py-3 text-lg'
default:
return 'px-4 py-2 text-base'
}
}
function LoadingSpinner(): React.ReactElement {
return (
)
}
function ButtonContent({
children,
loading,
}: {
children: ReactNode
loading: boolean
}): React.ReactElement {
return (
<>
{loading && (
)}
{children}
>
)
}
export const Button = React.forwardRef((props, ref): React.ReactElement => {
const {
children,
variant = 'primary',
size = 'medium',
disabled = false,
loading = false,
onClick,
type = 'button',
className = '',
'aria-label': ariaLabel,
'aria-expanded': ariaExpanded,
'aria-haspopup': ariaHaspopup,
'aria-selected': ariaSelected,
role: roleProp,
id,
} = props
const variantClasses = getVariantClasses(variant)
const sizeClasses = getSizeClasses(size)
const baseClasses = 'inline-flex items-center justify-center rounded-lg font-medium transition-all border focus:outline-none focus:ring-2 focus:ring-neon-cyan disabled:opacity-50 disabled:cursor-not-allowed'
const combinedClasses = `${baseClasses} ${variantClasses} ${sizeClasses} ${className}`.trim()
return (
)
})
Button.displayName = 'Button'