69 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			69 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { Link } from 'react-router-dom'
 | |
| import clsx from 'clsx'
 | |
| 
 | |
| const baseStyles = {
 | |
|   solid:
 | |
|     'inline-flex justify-center rounded-lg py-2 px-3 text-sm font-semibold transition-colors',
 | |
|   outline:
 | |
|     'inline-flex justify-center rounded-lg border py-[calc(--spacing(2)-1px)] px-[calc(--spacing(3)-1px)] text-sm transition-colors',
 | |
| }
 | |
| 
 | |
| const variantStyles = {
 | |
|   solid: {
 | |
|     cyan: 'relative overflow-hidden bg-cyan-500 text-white before:absolute before:inset-0 active:before:bg-transparent hover:before:bg-white/10 active:bg-cyan-600 active:text-white/80 before:transition-colors',
 | |
|     white:
 | |
|       'bg-white text-cyan-900 hover:bg-white/90 active:bg-white/90 active:text-cyan-900/70',
 | |
|     gray: 'bg-gray-800 text-white hover:bg-gray-900 active:bg-gray-800 active:text-white/80',
 | |
|     green: 'bg-green-500 text-white hover:bg-green-600',
 | |
|   },
 | |
|   outline: {
 | |
|     gray: 'border-gray-300 text-gray-700 hover:border-cyan-500 active:border-cyan-500',
 | |
|     white: 'border-gray-300 text-white hover:border-cyan-500 active:border-cyan-500',
 | |
|   },
 | |
| }
 | |
| 
 | |
| type ButtonProps = (
 | |
|   | {
 | |
|       variant?: 'solid'
 | |
|       color?: keyof typeof variantStyles.solid
 | |
|     }
 | |
|   | {
 | |
|       variant: 'outline'
 | |
|       color?: keyof typeof variantStyles.outline
 | |
|     }
 | |
| ) &
 | |
|   (
 | |
|     | (Omit<React.ComponentPropsWithoutRef<typeof Link>, 'color'> & { to: string; as?: 'link' })
 | |
|     | (Omit<React.ComponentPropsWithoutRef<'a'>, 'color'> & { to: string; as: 'a' })
 | |
|     | (Omit<React.ComponentPropsWithoutRef<'button'>, 'color'> & {
 | |
|         to?: undefined
 | |
|         as?: undefined
 | |
|       })
 | |
|   )
 | |
| 
 | |
| export function Button({ className, as, ...props }: ButtonProps) {
 | |
|   props.variant ??= 'solid'
 | |
|   props.color ??= 'gray'
 | |
| 
 | |
|   className = clsx(
 | |
|     baseStyles[props.variant],
 | |
|     props.variant === 'outline'
 | |
|       ? variantStyles.outline[props.color]
 | |
|       : props.variant === 'solid'
 | |
|         ? variantStyles.solid[props.color]
 | |
|         : undefined,
 | |
|     className,
 | |
|   )
 | |
| 
 | |
|   if (typeof props.to === 'undefined') {
 | |
|     return <button className={className} {...props} />
 | |
|   }
 | |
|   
 | |
|   if (as === 'a') {
 | |
|     const { to, variant, color, ...rest } = props as any
 | |
|     return <a className={className} href={to} {...rest} />
 | |
|   }
 | |
|   
 | |
|   return <Link className={className} {...props} />
 | |
| }
 |