"use client"; import { useState, useEffect, useCallback, useRef } from "react"; import { useRouter } from "next/navigation"; function isInputFocused(): boolean { const el = document.activeElement; if (!el) return false; const tag = el.tagName.toLowerCase(); if (tag === "input" || tag === "textarea" || tag === "select") return true; if ((el as HTMLElement).isContentEditable) return true; return false; } interface UseKeyboardNavOptions { itemCount: number; onSelect: (index: number) => void; enabled?: boolean; } export function useKeyboardNav({ itemCount, onSelect, enabled = true, }: UseKeyboardNavOptions) { const [selectedIndex, setSelectedIndex] = useState(-1); const router = useRouter(); const gPressedRef = useRef(false); const gTimerRef = useRef>(undefined); const resetSelection = useCallback(() => { setSelectedIndex(-1); }, []); useEffect(() => { if (!enabled) return; function handleKeyDown(e: KeyboardEvent) { if (isInputFocused()) return; if (gPressedRef.current) { gPressedRef.current = false; clearTimeout(gTimerRef.current); if (e.key === "h") { e.preventDefault(); router.push("/dashboard"); return; } if (e.key === "s") { e.preventDefault(); router.push("/dashboard/settings"); return; } if (e.key === "k") { e.preventDefault(); router.push("/dashboard/keys"); return; } if (e.key === "d") { e.preventDefault(); router.push("/dashboard/decisions"); return; } return; } if (e.key === "g" && !e.metaKey && !e.ctrlKey && !e.altKey) { gPressedRef.current = true; gTimerRef.current = setTimeout(() => { gPressedRef.current = false; }, 500); return; } if (e.key === "j" && !e.metaKey && !e.ctrlKey) { e.preventDefault(); setSelectedIndex((prev) => { const next = prev + 1; return next >= itemCount ? itemCount - 1 : next; }); return; } if (e.key === "k" && !e.metaKey && !e.ctrlKey) { e.preventDefault(); setSelectedIndex((prev) => { const next = prev - 1; return next < 0 ? 0 : next; }); return; } if (e.key === "Enter" && selectedIndex >= 0) { e.preventDefault(); onSelect(selectedIndex); return; } if (e.key === "Escape") { setSelectedIndex(-1); return; } } document.addEventListener("keydown", handleKeyDown); return () => { document.removeEventListener("keydown", handleKeyDown); clearTimeout(gTimerRef.current); }; }, [enabled, itemCount, selectedIndex, onSelect, router]); useEffect(() => { if (selectedIndex < 0) return; const row = document.querySelector(`[data-keyboard-index="${selectedIndex}"]`); if (row) { row.scrollIntoView({ block: "nearest", behavior: "smooth" }); } }, [selectedIndex]); return { selectedIndex, setSelectedIndex, resetSelection }; }