import { useEffect } from 'react'; /** * Горячие клавиши inbox (когда фокус не в input/textarea/select/contenteditable). * j/k — соседний элемент, 1/2 — действия, Esc — снять фокус списка (опционально). */ export function useInboxHotkeys(options: { enabled?: boolean; onNext: () => void; onPrev: () => void; onPrimary?: () => void; onSecondary?: () => void; onOpen?: () => void; }) { const { enabled = true, onNext, onPrev, onPrimary, onSecondary, onOpen } = options; useEffect(() => { if (!enabled) return; const isTypingTarget = (el: EventTarget | null) => { if (!(el instanceof HTMLElement)) return false; const tag = el.tagName; return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || el.isContentEditable; }; const handler = (e: KeyboardEvent) => { if (e.metaKey || e.ctrlKey || e.altKey) return; if (isTypingTarget(e.target)) return; const key = e.key.toLowerCase(); if (key === 'j' || key === 'arrowdown') { e.preventDefault(); onNext(); } else if (key === 'k' || key === 'arrowup') { e.preventDefault(); onPrev(); } else if (key === 'enter' && onOpen) { e.preventDefault(); onOpen(); } else if (key === '1' && onPrimary) { e.preventDefault(); onPrimary(); } else if (key === '2' && onSecondary) { e.preventDefault(); onSecondary(); } }; window.addEventListener('keydown', handler); return () => window.removeEventListener('keydown', handler); }, [enabled, onNext, onPrev, onPrimary, onSecondary, onOpen]); } export function selectNeighborId( ids: string[], currentId: string, direction: 1 | -1 ): string | null { if (ids.length === 0) return null; const idx = ids.indexOf(currentId); if (idx < 0) return ids[0] ?? null; const next = idx + direction; if (next < 0 || next >= ids.length) return currentId; return ids[next]; } /** Следующий после текущего; если конец — предыдущий. */ export function selectAfterRemove(ids: string[], currentId: string): string | null { const idx = ids.indexOf(currentId); if (idx < 0) return ids[0] ?? null; return ids[idx + 1] ?? ids[idx - 1] ?? null; }