From 46933a2a811e379c77dd97738c3864d9e4f8ab1a Mon Sep 17 00:00:00 2001 From: Alec Koifman Date: Thu, 18 Dec 2025 17:12:49 -0500 Subject: [PATCH] refactor: synchronize focused menu index with refs for improved keyboard navigation - Introduced a ref to keep the focused menu index in sync with state, enhancing keyboard navigation within the terminal context menu. - Updated event handlers to utilize the ref for managing focus, ensuring consistent behavior during menu interactions. - Simplified dependencies in the effect hook for better performance and clarity. --- .../views/terminal-view/terminal-panel.tsx | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/app/src/components/views/terminal-view/terminal-panel.tsx b/apps/app/src/components/views/terminal-view/terminal-panel.tsx index 3cef099d..61c50385 100644 --- a/apps/app/src/components/views/terminal-view/terminal-panel.tsx +++ b/apps/app/src/components/views/terminal-view/terminal-panel.tsx @@ -75,6 +75,7 @@ export function TerminalPanel({ const isMacRef = useRef(false); const contextMenuRef = useRef(null); const [focusedMenuIndex, setFocusedMenuIndex] = useState(0); + const focusedMenuIndexRef = useRef(0); // Detect platform on mount useEffect(() => { @@ -683,12 +684,18 @@ export function TerminalPanel({ // Context menu actions for keyboard navigation const menuActions = ["copy", "paste", "selectAll", "clear"] as const; + // Keep ref in sync with state for use in event handlers + useEffect(() => { + focusedMenuIndexRef.current = focusedMenuIndex; + }, [focusedMenuIndex]); + // Close context menu on click outside or scroll, handle keyboard navigation useEffect(() => { if (!contextMenu) return; // Reset focus index and focus menu when opened setFocusedMenuIndex(0); + focusedMenuIndexRef.current = 0; requestAnimationFrame(() => { const firstButton = contextMenuRef.current?.querySelector('[role="menuitem"]'); firstButton?.focus(); @@ -697,6 +704,11 @@ export function TerminalPanel({ const handleClick = () => closeContextMenu(); const handleScroll = () => closeContextMenu(); const handleKeyDown = (e: KeyboardEvent) => { + const updateFocusIndex = (newIndex: number) => { + focusedMenuIndexRef.current = newIndex; + setFocusedMenuIndex(newIndex); + }; + switch (e.key) { case "Escape": e.preventDefault(); @@ -704,16 +716,16 @@ export function TerminalPanel({ break; case "ArrowDown": e.preventDefault(); - setFocusedMenuIndex((prev) => (prev + 1) % menuActions.length); + updateFocusIndex((focusedMenuIndexRef.current + 1) % menuActions.length); break; case "ArrowUp": e.preventDefault(); - setFocusedMenuIndex((prev) => (prev - 1 + menuActions.length) % menuActions.length); + updateFocusIndex((focusedMenuIndexRef.current - 1 + menuActions.length) % menuActions.length); break; case "Enter": case " ": e.preventDefault(); - handleContextMenuAction(menuActions[focusedMenuIndex]); + handleContextMenuAction(menuActions[focusedMenuIndexRef.current]); break; case "Tab": e.preventDefault(); @@ -731,7 +743,7 @@ export function TerminalPanel({ document.removeEventListener("scroll", handleScroll, true); document.removeEventListener("keydown", handleKeyDown); }; - }, [contextMenu, closeContextMenu, focusedMenuIndex, handleContextMenuAction]); + }, [contextMenu, closeContextMenu, handleContextMenuAction]); // Focus the correct menu item when navigation changes useEffect(() => {