All files / web/src/arcade-games/type-racer-jr/components OnScreenKeyboard.tsx

0% Statements 0/116
0% Branches 0/1
0% Functions 0/1
0% Lines 0/116

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                                                                                                                                                                                                                                         
'use client'

import { useCallback } from 'react'
import { css } from '../../../../styled-system/css'
import type { KeyboardLayout } from '../types'

interface OnScreenKeyboardProps {
  onKeyPress: (letter: string) => void
  highlightedLetter?: string
  layout?: KeyboardLayout
}

const LAYOUTS: Record<KeyboardLayout, string[][]> = {
  qwerty: [
    ['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'],
  ],
  dvorak: [
    ['p', 'y', 'f', 'g', 'c', 'r', 'l'],
    ['a', 'o', 'e', 'u', 'i', 'd', 'h', 't', 'n', 's'],
    ['q', 'j', 'k', 'x', 'b', 'm', 'w', 'v', 'z'],
  ],
  abc: [
    ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'],
    ['j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r'],
    ['s', 't', 'u', 'v', 'w', 'x', 'y', 'z'],
  ],
}

/**
 * On-screen keyboard for touch devices.
 * Supports QWERTY, Dvorak, and ABC layouts.
 */
export function OnScreenKeyboard({
  onKeyPress,
  highlightedLetter,
  layout = 'qwerty',
}: OnScreenKeyboardProps) {
  const handlePress = useCallback(
    (letter: string) => {
      onKeyPress(letter)
    },
    [onKeyPress]
  )

  const rows = LAYOUTS[layout]

  return (
    <div
      data-component="OnScreenKeyboard"
      className={css({
        display: 'flex',
        flexDirection: 'column',
        gap: '6px',
        p: '3',
        bg: 'gray.100',
        borderRadius: 'xl',
        maxWidth: '500px',
        mx: 'auto',
        width: '100%',
      })}
    >
      {rows.map((row, rowIdx) => (
        <div
          key={rowIdx}
          className={css({
            display: 'flex',
            gap: '4px',
            justifyContent: 'center',
          })}
        >
          {row.map((letter) => {
            const isHighlighted = letter === highlightedLetter
            return (
              <button
                key={letter}
                type="button"
                onClick={() => handlePress(letter)}
                data-action="type-letter"
                data-letter={letter}
                className={css({
                  flex: '1 1 0',
                  maxWidth: '44px',
                  minHeight: '48px',
                  fontSize: '18px',
                  fontWeight: 'bold',
                  textTransform: 'uppercase',
                  border: '2px solid',
                  borderRadius: 'lg',
                  cursor: 'pointer',
                  transition: 'all 0.1s ease',
                  userSelect: 'none',
                  display: 'flex',
                  alignItems: 'center',
                  justifyContent: 'center',
                  _active: {
                    transform: 'scale(0.92)',
                  },
                })}
                style={{
                  backgroundColor: isHighlighted ? '#dbeafe' : 'white',
                  borderColor: isHighlighted ? '#3b82f6' : '#d1d5db',
                  color: isHighlighted ? '#1d4ed8' : '#374151',
                  boxShadow: isHighlighted ? '0 0 8px rgba(59, 130, 246, 0.3)' : undefined,
                }}
              >
                {letter}
              </button>
            )
          })}
        </div>
      ))}
    </div>
  )
}