From 3a80be9492fb2bfd27ef620628c93cc34068a842 Mon Sep 17 00:00:00 2001 From: Haileyesus Date: Tue, 10 Mar 2026 21:47:52 +0300 Subject: [PATCH] fix(shell): restore terminal focus when switching to the shell tab Pass shell activity state from MainContent through StandaloneShell and use it inside Shell to explicitly focus the xterm instance once the terminal is both initialized and connected. Previously, switching to the Shell tab left focus on the tab button because isActive was being ignored and the terminal never called focus() after the tab activation lifecycle completed. As a result, users had to click inside the terminal before keyboard input would be accepted. This change wires isActive through the shell stack, removes the unused prop handling in Shell, and adds a focus effect that runs when the shell becomes active and ready. The effect uses both requestAnimationFrame and a zero-delay timeout so focus is applied reliably after rendering and connection state updates settle. This restores immediate typing when opening the shell tab and also improves the reconnect path by re-focusing the terminal after the shell connection is ready. --- .../main-content/view/MainContent.tsx | 7 +++++- src/components/shell/view/Shell.tsx | 23 +++++++++++++++---- .../standalone-shell/view/StandaloneShell.tsx | 3 +++ 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/components/main-content/view/MainContent.tsx b/src/components/main-content/view/MainContent.tsx index 5d6ef05..8919715 100644 --- a/src/components/main-content/view/MainContent.tsx +++ b/src/components/main-content/view/MainContent.tsx @@ -146,7 +146,12 @@ function MainContent({ {activeTab === 'shell' && (
- +
)} diff --git a/src/components/shell/view/Shell.tsx b/src/components/shell/view/Shell.tsx index 0f9b7c6..3d51980 100644 --- a/src/components/shell/view/Shell.tsx +++ b/src/components/shell/view/Shell.tsx @@ -40,7 +40,7 @@ export default function Shell({ onProcessComplete = null, minimal = false, autoConnect = false, - isActive, + isActive = true, }: ShellProps) { const { t } = useTranslation('chat'); const [isRestarting, setIsRestarting] = useState(false); @@ -48,9 +48,6 @@ export default function Shell({ const promptCheckTimer = useRef | null>(null); const onOutputRef = useRef<(() => void) | null>(null); - // Keep the public API stable for existing callers that still pass `isActive`. - void isActive; - const { terminalContainerRef, terminalRef, @@ -157,6 +154,24 @@ export default function Shell({ } }, [isConnected]); + useEffect(() => { + if (!isActive || !isInitialized || !isConnected) { + return; + } + + const focusTerminal = () => { + terminalRef.current?.focus(); + }; + + const animationFrameId = window.requestAnimationFrame(focusTerminal); + const timeoutId = window.setTimeout(focusTerminal, 0); + + return () => { + window.cancelAnimationFrame(animationFrameId); + window.clearTimeout(timeoutId); + }; + }, [isActive, isConnected, isInitialized, terminalRef]); + const sendInput = useCallback( (data: string) => { sendSocketMessage(wsRef.current, { type: 'input', data }); diff --git a/src/components/standalone-shell/view/StandaloneShell.tsx b/src/components/standalone-shell/view/StandaloneShell.tsx index c152461..c22ac41 100644 --- a/src/components/standalone-shell/view/StandaloneShell.tsx +++ b/src/components/standalone-shell/view/StandaloneShell.tsx @@ -9,6 +9,7 @@ type StandaloneShellProps = { session?: ProjectSession | null; command?: string | null; isPlainShell?: boolean | null; + isActive?: boolean; autoConnect?: boolean; onComplete?: ((exitCode: number) => void) | null; onClose?: (() => void) | null; @@ -24,6 +25,7 @@ export default function StandaloneShell({ session = null, command = null, isPlainShell = null, + isActive = true, autoConnect = true, onComplete = null, onClose = null, @@ -64,6 +66,7 @@ export default function StandaloneShell({ selectedSession={session} initialCommand={command} isPlainShell={shouldUsePlainShell} + isActive={isActive} onProcessComplete={handleProcessComplete} minimal={minimal} autoConnect={minimal ? true : autoConnect}