import React from 'react'; import { fonts } from '../lib/theme'; type IOSKeyboardProps = { activeKey?: string; /** How many frames since the key was pressed (for highlight decay) */ pressAge?: number; }; const ROW_1 = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p']; const ROW_2 = ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l']; const ROW_3 = ['z', 'x', 'c', 'v', 'b', 'n', 'm']; const KEY_H = 42; const KEY_GAP = 6; const ROW_GAP = 11; const SIDE_PAD = 3; const KEYBOARD_BG = '#1c1c1e'; const KEY_BG = '#3a3a3c'; const KEY_BG_ACTIVE = '#636366'; const KEY_TEXT = '#fff'; const SPECIAL_BG = '#2c2c2e'; const Key: React.FC<{ label: string; width: number; isActive: boolean; pressAge: number; fontSize?: number; }> = ({ label, width, isActive, pressAge, fontSize = 22 }) => { // Highlight decays over 4 frames const highlightOpacity = isActive && pressAge < 4 ? 1 - pressAge / 4 : 0; const bg = highlightOpacity > 0 ? lerpColor(KEY_BG, KEY_BG_ACTIVE, highlightOpacity) : KEY_BG; return (
{label}
); }; function lerpColor(a: string, b: string, t: number): string { const pa = parseInt(a.slice(1), 16); const pb = parseInt(b.slice(1), 16); const r = Math.round(((pa >> 16) & 0xff) * (1 - t) + ((pb >> 16) & 0xff) * t); const g = Math.round(((pa >> 8) & 0xff) * (1 - t) + ((pb >> 8) & 0xff) * t); const bl = Math.round((pa & 0xff) * (1 - t) + (pb & 0xff) * t); return `#${((r << 16) | (g << 8) | bl).toString(16).padStart(6, '0')}`; } export const IOSKeyboard: React.FC = ({ activeKey, pressAge = 99 }) => { const isActive = (key: string) => activeKey !== undefined && key.toLowerCase() === activeKey.toLowerCase(); const age = (key: string) => (isActive(key) ? pressAge : 99); // Backspace/delete key highlight const deleteHighlight = activeKey === '⌫' && pressAge < 4 ? 1 - pressAge / 4 : 0; const deleteBg = deleteHighlight > 0 ? lerpColor(SPECIAL_BG, KEY_BG_ACTIVE, deleteHighlight) : SPECIAL_BG; // Key widths: 10 keys + 9 gaps in ~375px row → each key ~33px const letterKeyW = 33; // Row 2 has 9 keys → same key width but centered with side padding // Row 3 has shift + 7 keys + delete return (
{/* Row 1: q-p */}
{ROW_1.map((k) => ( ))}
{/* Row 2: a-l */}
{ROW_2.map((k) => ( ))}
{/* Row 3: shift + z-m + delete */}
{ROW_3.map((k) => ( ))}
{/* Row 4: 123 / globe / space / return */}
123
{/* Space bar */}
return
); };