'use client'; import { useEffect, useRef } from 'react'; import { X } from 'lucide-react'; interface KeyboardShortcutsModalProps { open: boolean; onClose: () => void; } const shortcuts = [ { key: 'R', description: 'Rectangle tool' }, { key: 'S', description: 'Span tool' }, { key: 'L', description: 'Line tool' }, { key: 'D', description: 'Delete tool' }, { key: 'T', description: 'Toggle theme (light/dark)' }, { key: 'Esc', description: 'Deselect tool / cancel action' }, { key: 'Del / ⌫', description: 'Delete selected annotation' }, { key: 'Enter', description: 'Edit selected span' }, { key: '1–6', description: 'Quick-assign span label (during span creation)' }, { key: '?', description: 'Show this help' }, ]; const FOCUSABLE_SELECTORS = [ 'a[href]', 'button:not([disabled])', 'textarea:not([disabled])', 'input:not([disabled])', 'select:not([disabled])', '[tabindex]:not([tabindex="-1"])', ].join(', '); export default function KeyboardShortcutsModal({ open, onClose }: KeyboardShortcutsModalProps) { const dialogRef = useRef(null); // Escape / ? key handler useEffect(() => { if (!open) return; const handleKey = (e: KeyboardEvent) => { if (e.key === 'Escape' || e.key === '?') { onClose(); } }; window.addEventListener('keydown', handleKey); return () => window.removeEventListener('keydown', handleKey); }, [open, onClose]); // Focus trapping useEffect(() => { if (!open) return; const dialog = dialogRef.current; if (!dialog) return; // Move focus into the dialog on open const firstFocusable = dialog.querySelector(FOCUSABLE_SELECTORS); firstFocusable?.focus(); const handleTabKey = (e: KeyboardEvent) => { if (e.key !== 'Tab') return; const focusableElements = Array.from( dialog.querySelectorAll(FOCUSABLE_SELECTORS) ).filter((el) => !el.closest('[disabled]')); if (focusableElements.length === 0) { e.preventDefault(); return; } const first = focusableElements[0]; const last = focusableElements[focusableElements.length - 1]; if (e.shiftKey) { if (document.activeElement === first) { e.preventDefault(); last.focus(); } } else { if (document.activeElement === last) { e.preventDefault(); first.focus(); } } }; dialog.addEventListener('keydown', handleTabKey); return () => dialog.removeEventListener('keydown', handleTabKey); }, [open]); if (!open) return null; return (
e.stopPropagation()} >

Keyboard Shortcuts

{shortcuts.map(({ key, description }) => ( ))}
{key} {description}

Press ? or Esc to close

); }