import { useEffect, useState } from 'react'; import { BulkApi } from '../api/client.js'; /// /// j/k move focus down/up the list, e archives the focused email, # (shift+3) /// trashes it. Ignored while an input/textarea/select has focus, or while /// the "/" search shortcut is active, so typing is never hijacked. /// `onRemoved(id)` lets the caller drop the row from local state after a /// successful archive/trash. /// export default function useListKeyboardNav(emails, onRemoved) { const [focusedId, setFocusedId] = useState(null); useEffect(() => { const handler = async (e) => { const tag = document.activeElement?.tagName; if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return; if (!emails.length) return; const idx = emails.findIndex((x) => x.id === focusedId); if (e.key === 'j') { e.preventDefault(); const next = idx < 0 ? 0 : Math.min(idx + 1, emails.length - 1); setFocusedId(emails[next].id); } else if (e.key === 'k') { e.preventDefault(); const prev = idx < 0 ? 0 : Math.max(idx - 1, 0); setFocusedId(emails[prev].id); } else if (e.key === 'e' && idx >= 0) { e.preventDefault(); const id = emails[idx].id; await BulkApi.archive([id]); onRemoved(id); } else if (e.key === '#' && idx >= 0) { e.preventDefault(); const id = emails[idx].id; await BulkApi.trash([id]); onRemoved(id); } }; window.addEventListener('keydown', handler); return () => window.removeEventListener('keydown', handler); }, [emails, focusedId, onRemoved]); return focusedId; }