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 | 22x 16x 16x 2x 14x 6x 6x 4x 6x 4x 4x 2x 4x 2x 2x 1x 1x 1x 1x 1x 1x 22x 22x 22x 22x | /**
* useKeyboardNavigation Hook
* Story 10.8a: Moderator Presentation Page — Functional
*
* Handles keyboard/remote navigation for the moderator presentation page.
*
* ACs: #2–6, #23–24
*/
import { useEffect, useCallback } from 'react';
interface UseKeyboardNavigationOptions {
sectionCount: number;
currentIndex: number;
isBlankActive: boolean;
onNext: () => void;
onPrev: () => void;
onToggleBlank: () => void;
}
export function useKeyboardNavigation({
sectionCount,
currentIndex,
isBlankActive,
onNext,
onPrev,
onToggleBlank,
}: UseKeyboardNavigationOptions): void {
const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
// Guard: ignore key events from input/textarea elements
const target = e.target as HTMLElement;
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {
return;
}
switch (e.key) {
case 'ArrowRight':
case 'ArrowDown':
case 'PageDown':
case ' ':
// Prevent default scroll for these keys
e.preventDefault();
if (!isBlankActive && currentIndex < sectionCount - 1) {
onNext();
}
break;
case 'ArrowLeft':
case 'ArrowUp':
case 'PageUp':
// Prevent default scroll for these keys
e.preventDefault();
if (!isBlankActive && currentIndex > 0) {
onPrev();
}
break;
case 'b':
case 'B':
onToggleBlank();
break;
case 'f':
case 'F':
// AC #5: F toggles fullscreen
if (!document.fullscreenElement) {
void document.documentElement.requestFullscreen();
} else E{
void document.exitFullscreen();
}
break;
case 'Escape':
if (isBlankActive) {
onToggleBlank();
} else if (Edocument.fullscreenElement) {
// Escape exits fullscreen natively; no extra handling needed
}
break;
default:
break;
}
},
[sectionCount, currentIndex, isBlankActive, onNext, onPrev, onToggleBlank]
);
useEffect(() => {
window.addEventListener('keydown', handleKeyDown);
return () => {
window.removeEventListener('keydown', handleKeyDown);
};
}, [handleKeyDown]);
}
|