diff --git a/apps/web/src/components/BranchToolbar.tsx b/apps/web/src/components/BranchToolbar.tsx index f5b670cecf0aa3a02543c0ce800b7e5535eb14b6..1e6dd9e923c3f22153196bd54f5fabc61a5d1e33 100644 --- a/apps/web/src/components/BranchToolbar.tsx +++ b/apps/web/src/components/BranchToolbar.tsx @@ -25,9 +25,15 @@ interface BranchToolbarProps { envMode: "local" | "worktree"; onEnvModeChange: (mode: "local" | "worktree") => void; envLocked: boolean; + onComposerFocusRequest?: () => void; } -export default function BranchToolbar({ envMode, onEnvModeChange, envLocked }: BranchToolbarProps) { +export default function BranchToolbar({ + envMode, + onEnvModeChange, + envLocked, + onComposerFocusRequest, +}: BranchToolbarProps) { const { state, dispatch } = useStore(); const api = useNativeApi(); const queryClient = useQueryClient(); @@ -123,6 +129,7 @@ export default function BranchToolbar({ envMode, onEnvModeChange, envLocked }: B setThreadError(null); setThreadBranch(branch.name, null); setIsBranchMenuOpen(false); + onComposerFocusRequest?.(); return; } @@ -135,6 +142,7 @@ export default function BranchToolbar({ envMode, onEnvModeChange, envLocked }: B // Secondary worktree → point the thread at that worktree path. setThreadBranch(branch.name, isMainWorktree ? null : branch.worktreePath); setIsBranchMenuOpen(false); + onComposerFocusRequest?.(); return; } @@ -143,6 +151,7 @@ export default function BranchToolbar({ envMode, onEnvModeChange, envLocked }: B setThreadError(null); setThreadBranch(branch.name, activeWorktreePath); setIsBranchMenuOpen(false); + onComposerFocusRequest?.(); }, }); }; @@ -156,6 +165,7 @@ export default function BranchToolbar({ envMode, onEnvModeChange, envLocked }: B setThreadBranch(name, activeWorktreePath); setBranchQuery(""); setIsBranchMenuOpen(false); + onComposerFocusRequest?.(); }, }); }; diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index 716b8d812b980df9787a44532b327ba00a7ae2a9..8047803c9ccf5c38805ac2408baf921d2fb75a4c 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -298,6 +298,11 @@ export default function ChatView() { const cursor = textarea.value.length; textarea.setSelectionRange(cursor, cursor); }, []); + const scheduleComposerFocus = useCallback(() => { + window.requestAnimationFrame(() => { + focusComposer(); + }); + }, [focusComposer]); const toggleTerminalVisibility = useCallback(() => { if (!activeThreadId) return; dispatch({ @@ -369,6 +374,7 @@ export default function ChatView() { const handleRuntimeModeChange = async (mode: "approval-required" | "full-access") => { if (mode === state.runtimeMode) return; dispatch({ type: "SET_RUNTIME_MODE", mode }); + scheduleComposerFocus(); if (!api) return; const sessionIds = state.threads @@ -898,7 +904,19 @@ export default function ChatView() { threadId: activeThread.id, model: resolveModelSlug(model), }); + scheduleComposerFocus(); }; + const onEffortSelect = (effort: ReasoningEffort) => { + setSelectedEffort(effort); + scheduleComposerFocus(); + }; + const onEnvModeChange = useCallback( + (mode: "local" | "worktree") => { + setEnvMode(mode); + scheduleComposerFocus(); + }, + [scheduleComposerFocus], + ); const onKeyDown = (e: KeyboardEvent) => { if (e.key === "Enter" && !e.shiftKey) { @@ -1302,7 +1320,7 @@ export default function ChatView() { {/* Reasoning effort */} - + {/* Divider */} @@ -1405,7 +1423,12 @@ export default function ChatView() { {isGitRepo && ( - + )} {activeThread.terminalOpen && api && activeProject && (