From f1b46017b8345d8f77f64a9faa3c297c6563eafe Mon Sep 17 00:00:00 2001 From: Eren Erduran Date: Mon, 9 Mar 2026 04:16:58 +0100 Subject: [PATCH 1/2] fix: focus textarea instead of terminal when creating new chat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the terminal panel is open and the user clicks "New Chat", focus was staying on the xterm textarea instead of moving to the chat editor. The requestAnimationFrame callback fired too early — before the browser's focus management settled after React's DOM updates. Switch to setTimeout(100ms) to ensure the editor focus call happens after all pending focus transitions complete. This matches the pattern already used in new-chat-form.tsx. Also adds proper cleanup (clearTimeout) to the useEffect. --- src/renderer/features/agents/main/active-chat.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/renderer/features/agents/main/active-chat.tsx b/src/renderer/features/agents/main/active-chat.tsx index cf85ed17..ccd5b266 100644 --- a/src/renderer/features/agents/main/active-chat.tsx +++ b/src/renderer/features/agents/main/active-chat.tsx @@ -3793,15 +3793,20 @@ const ChatViewInner = memo(function ChatViewInner({ if (!isActive) return if (isMobile) return // Don't autofocus on mobile - // Use requestAnimationFrame to ensure DOM is ready after render - requestAnimationFrame(() => { + // Use setTimeout to ensure focus happens after all React DOM updates + // and browser focus management has settled. requestAnimationFrame alone + // is too early when the terminal is open — the xterm textarea retains + // focus and the editor's focus() call doesn't stick. + const timeoutId = setTimeout(() => { // Skip if sidebar keyboard navigation is active (user is arrowing through sidebar items) if (appStore.get(suppressInputFocusAtom)) { appStore.set(suppressInputFocusAtom, false) return } editorRef.current?.focus() - }) + }, 100) + + return () => clearTimeout(timeoutId) }, [isActive, subChatId, isMobile]) // Refs for handleSend to avoid recreating callback on every messages change From bc69dc237121293fb817461322183d71512a94a8 Mon Sep 17 00:00:00 2001 From: Eren Erduran Date: Mon, 9 Mar 2026 04:53:39 +0100 Subject: [PATCH 2/2] fix: close expanded message dialog when switching sub-chat tabs The Dialog in AgentUserMessageBubble portals to document.body via Radix DialogPortal, escaping the hidden tab's opacity:0 / pointerEvents:none container. When a user expands a message and switches tabs (e.g. via keyboard shortcut), the old dialog remains visible and shows content from the previous sub-chat. Fix by auto-closing the dialog whenever activeSubChatId changes. --- .../features/agents/ui/agent-user-message-bubble.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/renderer/features/agents/ui/agent-user-message-bubble.tsx b/src/renderer/features/agents/ui/agent-user-message-bubble.tsx index 37938c7b..b2a2345d 100644 --- a/src/renderer/features/agents/ui/agent-user-message-bubble.tsx +++ b/src/renderer/features/agents/ui/agent-user-message-bubble.tsx @@ -12,6 +12,7 @@ import { import { AgentImageItem } from "./agent-image-item" import { RenderFileMentions, extractTextMentions, TextMentionBlocks } from "../mentions/render-file-mentions" import { useSearchHighlight, useSearchQuery } from "../search" +import { useAgentSubChatStore } from "../stores/sub-chat-store" interface AgentUserMessageBubbleProps { messageId: string @@ -119,6 +120,14 @@ export const AgentUserMessageBubble = memo(function AgentUserMessageBubble({ const [isExpanded, setIsExpanded] = useState(false) const contentRef = useRef(null) + // Close expanded dialog when user switches sub-chat tabs. + // The Dialog portals to document.body, so it escapes the hidden tab's + // opacity:0 / pointerEvents:none container and would remain visible. + const activeSubChatId = useAgentSubChatStore((s) => s.activeSubChatId) + useEffect(() => { + setIsExpanded(false) + }, [activeSubChatId]) + // Extract quote/diff mentions to display above the bubble const { textMentions, cleanedText } = useMemo( () => extractTextMentions(textContent),