All files / web/src/arcade-games/know-your-world/features/letter-confirmation LetterDisplay.tsx

44.26% Statements 54/122
100% Branches 0/0
0% Functions 0/2
44.26% Lines 54/122

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 1231x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x                                             1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x                                                                                              
/**
 * Letter Display Component
 *
 * Renders a region name with letter-by-letter confirmation highlighting.
 * Used in Learning mode to show which letters have been confirmed,
 * which letter is next, and which are pending.
 *
 * Visual states:
 * - Confirmed: Full opacity
 * - Next: Full opacity with underline
 * - Pending: Dimmed (40% opacity)
 * - Beyond required: Full opacity (no confirmation needed)
 * - Spaces: Always full opacity
 */
 
'use client'
 
import { memo, useMemo } from 'react'
import type { LetterDisplayProps, LetterStatus } from './types'
import { getLetterStatus, getLetterStyles } from './letterUtils'
 
/**
 * Renders a single letter with appropriate styling based on confirmation status.
 */
interface StyledLetterProps {
  char: string
  status: LetterStatus | 'space'
  isDark: boolean
  index: number
}
 
const StyledLetter = memo(function StyledLetter({
  char,
  status,
  isDark,
  index,
}: StyledLetterProps) {
  // Spaces are always shown at full opacity
  if (status === 'space') {
    return (
      <span key={index} style={{ transition: 'all 0.15s ease-out' }}>
        {char}
      </span>
    )
  }

  const styles = getLetterStyles(status, isDark)

  return (
    <span key={index} style={styles}>
      {char}
    </span>
  )
})
 
/**
 * Renders a region name with letter confirmation highlighting.
 *
 * This component handles:
 * - Splitting the name into individual characters
 * - Tracking non-space letter indices
 * - Applying appropriate styles based on confirmation progress
 *
 * @example
 * ```tsx
 * <LetterDisplay
 *   regionName="United States"
 *   requiredLetters={3}
 *   confirmedCount={2}
 *   isComplete={false}
 *   isDark={true}
 * />
 * // Renders: "Un" at full opacity, "i" underlined, "ted States" dimmed
 * ```
 */
export const LetterDisplay = memo(function LetterDisplay({
  regionName,
  requiredLetters,
  confirmedCount,
  isComplete,
  isDark,
  fontSize,
  style,
}: LetterDisplayProps) {
  // Calculate letter statuses and render elements
  const letterElements = useMemo(() => {
    let nonSpaceIndex = 0

    return regionName.split('').map((char, index) => {
      const isSpace = char === ' '

      if (isSpace) {
        return <StyledLetter key={index} char={char} status="space" isDark={isDark} index={index} />
      }

      // Get current index before incrementing
      const currentNonSpaceIndex = nonSpaceIndex
      nonSpaceIndex++

      // Determine letter status
      const status = getLetterStatus(
        currentNonSpaceIndex,
        confirmedCount,
        requiredLetters,
        isComplete
      )

      return <StyledLetter key={index} char={char} status={status} isDark={isDark} index={index} />
    })
  }, [regionName, confirmedCount, requiredLetters, isComplete, isDark])

  return (
    <span
      style={{
        fontSize,
        ...style,
      }}
    >
      {letterElements}
    </span>
  )
})