Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | 'use client' import { useCallback, useEffect, useRef } from 'react' import Keyboard from 'react-simple-keyboard' import 'react-simple-keyboard/build/css/index.css' import { css } from '@styled/css' import { useIsTouchDevice } from '../hooks/useDeviceCapabilities' // Re-export for backwards compatibility export { useIsTouchDevice } from '../hooks/useDeviceCapabilities' interface SimpleLetterKeyboardProps { /** Whether to show uppercase or lowercase letters */ uppercase: boolean /** Called when a letter is pressed */ onKeyPress: (letter: string) => void /** Whether the keyboard is in dark mode */ isDark?: boolean /** Force show keyboard even on non-touch devices (for testing/storybook) */ forceShow?: boolean } /** * A simple on-screen keyboard for mobile devices. * Shows only letters (no numbers, no shift, no special keys). * Matches the case of the displayed region name. * Only renders on touch-based devices (mobile/tablet). */ export function SimpleLetterKeyboard({ uppercase, onKeyPress, isDark = false, forceShow = false, }: SimpleLetterKeyboardProps) { const keyboardRef = useRef<any>(null) const isTouchDevice = useIsTouchDevice() // Define a letters-only layout (no space bar - region names don't have spaces in first 3 chars) const layout = { default: uppercase ? ['Q W E R T Y U I O P', 'A S D F G H J K L', 'Z X C V B N M'] : ['q w e r t y u i o p', 'a s d f g h j k l', 'z x c v b n m'], } const handleKeyPress = useCallback( (button: string) => { onKeyPress(button) }, [onKeyPress] ) // Prevent keyboard from stealing focus and causing issues useEffect(() => { // The keyboard should not focus anything const keyboard = keyboardRef.current if (keyboard?.keyboardDOM) { keyboard.keyboardDOM.addEventListener('mousedown', (e: MouseEvent) => { e.preventDefault() }) keyboard.keyboardDOM.addEventListener('touchstart', (e: TouchEvent) => { e.preventDefault() }) } }, []) // Don't render on non-touch devices (desktop with mouse/keyboard) unless forceShow is true if (!isTouchDevice && !forceShow) { return null } // Use actual CSS color values since Panda tokens don't work in nested selectors const colors = { keyboardBg: isDark ? 'rgba(30, 41, 59, 0.95)' : 'rgba(255, 255, 255, 0.98)', keyboardBorder: isDark ? '#475569' : '#cbd5e1', buttonBg: isDark ? '#334155' : '#f1f5f9', buttonColor: isDark ? '#ffffff' : '#0f172a', buttonBorder: isDark ? '#475569' : '#cbd5e1', buttonActiveBg: isDark ? '#2563eb' : '#3b82f6', } return ( <div data-element="simple-letter-keyboard" className={css({ width: '100%', })} > <style>{` .simple-letter-keyboard .simple-keyboard { background: ${colors.keyboardBg}; border-radius: 12px; padding: 8px; border: 1px solid ${colors.keyboardBorder}; } .simple-letter-keyboard .hg-button { height: 44px; border-radius: 6px; background: ${colors.buttonBg}; color: ${colors.buttonColor}; border: 1px solid ${colors.buttonBorder}; font-size: 18px; font-weight: 600; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); transition: all 0.1s ease; min-width: 28px; flex: 1; margin: 2px; } .simple-letter-keyboard .hg-button:active { background: ${colors.buttonActiveBg}; color: white; transform: scale(0.95); } .simple-letter-keyboard .hg-row { display: flex; justify-content: center; margin-bottom: 2px; } `}</style> <div className="simple-letter-keyboard"> <Keyboard keyboardRef={(r) => (keyboardRef.current = r)} layout={layout} onKeyPress={handleKeyPress} theme="hg-theme-default simple-keyboard" physicalKeyboardHighlight={false} physicalKeyboardHighlightPress={false} disableButtonHold={true} stopMouseDownPropagation={true} stopMouseUpPropagation={true} /> </div> </div> ) } |