83 lines
3 KiB
JavaScript
83 lines
3 KiB
JavaScript
import React, { useRef, useCallback, useMemo } from 'react';
|
|
import LetterInput from './LetterInput';
|
|
import ActorPopover from './ActorPopover';
|
|
|
|
function isLetter(ch) {
|
|
return /[a-zA-Z]/.test(ch);
|
|
}
|
|
|
|
export default function GameRow({ actorName, pos, colStart, totalWidth, hintType, hintText, rowIndex, attemptedLetters = null, revealed = false }) {
|
|
const inputRefs = useRef([]);
|
|
const letters = actorName.split('');
|
|
|
|
const letterIndices = useMemo(
|
|
() => letters.reduce((acc, ch, i) => { if (isLetter(ch)) acc.push(i); return acc; }, []),
|
|
[actorName]
|
|
);
|
|
|
|
const setInputRef = useCallback((index) => (el) => {
|
|
inputRefs.current[index] = el;
|
|
}, []);
|
|
|
|
const focusNextInput = useCallback((charIndex, direction) => {
|
|
const currentPos = letterIndices.indexOf(charIndex);
|
|
const nextPos = currentPos + direction;
|
|
if (nextPos >= 0 && nextPos < letterIndices.length) {
|
|
inputRefs.current[letterIndices[nextPos]]?.focus();
|
|
}
|
|
}, [letterIndices]);
|
|
|
|
return (
|
|
<tr>
|
|
<td className="hint-cell">
|
|
<ActorPopover hintType={hintType} hintText={hintText} />
|
|
</td>
|
|
{Array.from({ length: totalWidth + 1 }, (_, colIndex) => {
|
|
const charIndex = colIndex - colStart;
|
|
const isInRange = charIndex >= 0 && charIndex < letters.length;
|
|
|
|
if (!isInRange) {
|
|
return <td key={colIndex} />;
|
|
}
|
|
|
|
const ch = letters[charIndex];
|
|
|
|
if (!isLetter(ch)) {
|
|
return (
|
|
<td key={colIndex} className="letter-static">
|
|
{ch}
|
|
</td>
|
|
);
|
|
}
|
|
|
|
const isMainActorCell = charIndex === pos;
|
|
const attemptedLetter = typeof attemptedLetters?.[charIndex] === 'string'
|
|
? attemptedLetters[charIndex].toUpperCase()
|
|
: '';
|
|
const correctLetter = ch.toUpperCase();
|
|
const revealState = !revealed || isMainActorCell
|
|
? null
|
|
: attemptedLetter === ''
|
|
? null
|
|
: attemptedLetter === correctLetter
|
|
? 'correct'
|
|
: 'wrong';
|
|
|
|
return (
|
|
<LetterInput
|
|
key={colIndex}
|
|
rowIndex={rowIndex}
|
|
charIndex={charIndex}
|
|
highlighted={isMainActorCell}
|
|
inputRef={setInputRef(charIndex)}
|
|
onNext={() => focusNextInput(charIndex, 1)}
|
|
onPrev={() => focusNextInput(charIndex, -1)}
|
|
value={revealed ? (revealState === 'correct' ? attemptedLetter : correctLetter) : undefined}
|
|
revealState={revealState}
|
|
disabled={revealed}
|
|
/>
|
|
);
|
|
})}
|
|
</tr>
|
|
);
|
|
}
|