80 lines
2.0 KiB
TypeScript
80 lines
2.0 KiB
TypeScript
'use client';
|
|
|
|
import { useState, type ReactNode, type ButtonHTMLAttributes } from 'react';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
interface TouchButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
children: ReactNode;
|
|
variant?: 'primary' | 'secondary' | 'ghost';
|
|
size?: 'sm' | 'md' | 'lg';
|
|
fullWidth?: boolean;
|
|
}
|
|
|
|
export function TouchButton({
|
|
children,
|
|
variant = 'primary',
|
|
size = 'md',
|
|
fullWidth = false,
|
|
className,
|
|
disabled,
|
|
...props
|
|
}: TouchButtonProps) {
|
|
const [isPressed, setIsPressed] = useState(false);
|
|
|
|
const baseStyles = `
|
|
inline-flex items-center justify-center font-medium
|
|
transition-all duration-150 ease-out
|
|
active:scale-95
|
|
focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2
|
|
disabled:opacity-50 disabled:cursor-not-allowed disabled:active:scale-100
|
|
touch-manipulation
|
|
`;
|
|
|
|
const variants = {
|
|
primary: `
|
|
bg-[#C41E3A] text-white
|
|
hover:bg-[#A01830]
|
|
focus-visible:ring-[#C41E3A]
|
|
${isPressed ? 'bg-[#8B1429]' : ''}
|
|
`,
|
|
secondary: `
|
|
bg-[#F5F5F5] text-[#171717]
|
|
hover:bg-[#E5E5E5]
|
|
border border-[#E5E5E5]
|
|
focus-visible:ring-[#C41E3A]
|
|
${isPressed ? 'bg-[#D4D4D4]' : ''}
|
|
`,
|
|
ghost: `
|
|
bg-transparent text-[#525252]
|
|
hover:bg-[#FEF2F4] hover:text-[#C41E3A]
|
|
focus-visible:ring-[#C41E3A]
|
|
${isPressed ? 'bg-[#FCE8EC] text-[#C41E3A]' : ''}
|
|
`,
|
|
};
|
|
|
|
const sizes = {
|
|
sm: 'text-sm px-4 py-2 rounded-md gap-1.5 min-h-[36px]',
|
|
md: 'text-base px-5 py-2.5 rounded-lg gap-2 min-h-[44px]',
|
|
lg: 'text-lg px-6 py-3 rounded-lg gap-2 min-h-[52px]',
|
|
};
|
|
|
|
return (
|
|
<button
|
|
className={cn(
|
|
baseStyles,
|
|
variants[variant],
|
|
sizes[size],
|
|
fullWidth && 'w-full',
|
|
className
|
|
)}
|
|
disabled={disabled}
|
|
onTouchStart={() => setIsPressed(true)}
|
|
onTouchEnd={() => setIsPressed(false)}
|
|
onTouchCancel={() => setIsPressed(false)}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</button>
|
|
);
|
|
}
|