import { useEffect, useMemo, useRef, useState } from 'react'; import { cn } from '../../lib/utils'; import { KeyboardLayout, StrokeStyle, generatePath, getKeyboardLayout } from './keyboard-utils'; export type SignaturePadKeyboardProps = { className?: string; onChange: (_value: string) => void; }; export const SignaturePadKeyboard = ({ className, onChange }: SignaturePadKeyboardProps) => { const [name, setName] = useState(''); const [currentKeyboardLayout] = useState(KeyboardLayout.QWERTY); const curveType = 'linear'; const includeNumbers = false; const strokeConfig = { style: StrokeStyle.SOLID, color: '#000000', gradientStart: '#ff6b6b', gradientEnd: '#4ecdc4', width: 3, }; const inputRef = useRef(null); useEffect(() => { if (inputRef.current) { inputRef.current.focus(); } }, []); useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { const isInputFocused = document.activeElement === inputRef.current; const isAnyInputFocused = document.activeElement?.tagName === 'INPUT'; if (!isInputFocused && !isAnyInputFocused) { const regex = includeNumbers ? /^[a-zA-Z0-9]$/ : /^[a-zA-Z]$/; if (regex.test(e.key) || e.key === 'Backspace') { inputRef.current?.focus(); } } }; window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); }, [includeNumbers]); // Generate signature path const signaturePath = useMemo(() => { if (!name) return ''; const points = []; const currentLayout = getKeyboardLayout(currentKeyboardLayout, includeNumbers); for (const char of name.toUpperCase()) { if (char in currentLayout) { const { x, y } = currentLayout[char]; const yOffset = includeNumbers ? 100 : 40; points.push({ x: x * 60 + 28, y: y * 60 + yOffset }); } } if (points.length === 0) return ''; return generatePath(points, curveType); }, [name, currentKeyboardLayout, curveType, includeNumbers]); // Update parent component when signature changes useEffect(() => { if (signaturePath && name) { // Convert SVG to data URL for consistency with other signature types const svgData = generateSVGDataURL(signaturePath); onChange(svgData); } else { onChange(''); } }, [signaturePath, name, onChange]); const generateSVGDataURL = (path: string): string => { const height = includeNumbers ? 260 : 200; const gradients = strokeConfig.style === StrokeStyle.GRADIENT ? ` ` : ''; const strokeColor = strokeConfig.style === StrokeStyle.SOLID ? strokeConfig.color : 'url(#pathGradient)'; const svgContent = ` ${gradients} `; return `data:image/svg+xml;base64,${btoa(svgContent)}`; }; return (
setName(e.target.value)} className="sr-only" autoFocus />
{strokeConfig.style === StrokeStyle.GRADIENT && ( )} {signaturePath && ( )}
{name}
); };