From 0e9b231fed0eba25e334cd0fcfc6595251fe2631 Mon Sep 17 00:00:00 2001 From: Jovines <1246634075@qq.com> Date: Fri, 27 Feb 2026 02:12:29 +0800 Subject: [PATCH] fix(mobile): restore original MobileAgentButton using onPointerUp instead of onClick (#524) The original design used onPointerUp to cycle agents, which doesn't trigger focus transfer and keeps the soft keyboard open. Recent changes switched to onClick which causes button to gain focus and closes the keyboard. - Remove onClick handler entirely - Restore handlePointerDown, handlePointerUp, handlePointerLeave handlers - Use onPointerUp to trigger agent cycling - Add onContextMenu to prevent context menu on long-press - Add extensive comments explaining why pointer events must be used This reverts to the behavior from commit 337c458f where clicking the agent button doesn't close the soft keyboard. Co-authored-by: Jovines --- .../src/components/chat/MobileAgentButton.tsx | 69 ++++++++++--------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/packages/ui/src/components/chat/MobileAgentButton.tsx b/packages/ui/src/components/chat/MobileAgentButton.tsx index 7197cb48..944a6f30 100644 --- a/packages/ui/src/components/chat/MobileAgentButton.tsx +++ b/packages/ui/src/components/chat/MobileAgentButton.tsx @@ -13,58 +13,63 @@ interface MobileAgentButtonProps { const LONG_PRESS_MS = 500; -export const MobileAgentButton: React.FC = ({ onOpenAgentPanel, onCycleAgent, className }) => { +// NOTE: Use pointer events instead of onClick to keep soft keyboard open on mobile +export const MobileAgentButton: React.FC = ({ onCycleAgent, onOpenAgentPanel, className }) => { const { currentAgentName, getVisibleAgents } = useConfigStore(); const currentSessionId = useSessionStore((state) => state.currentSessionId); const sessionAgentName = useSessionStore((state) => currentSessionId ? state.getSessionAgentSelection(currentSessionId) : null ); - const longPressTimerRef = React.useRef | null>(null); - const longPressTriggeredRef = React.useRef(false); const agents = getVisibleAgents(); const uiAgentName = currentSessionId ? (sessionAgentName || currentAgentName) : currentAgentName; const agentLabel = getAgentDisplayName(agents, uiAgentName); const agentColor = getAgentColor(uiAgentName); - const clearLongPressTimer = React.useCallback(() => { + const longPressTimerRef = React.useRef | null>(null); + const isLongPressRef = React.useRef(false); + + const handlePointerDown = () => { + isLongPressRef.current = false; + longPressTimerRef.current = setTimeout(() => { + isLongPressRef.current = true; + onOpenAgentPanel(); + }, LONG_PRESS_MS); + }; + + // Use onPointerUp (not onClick) to prevent focus transfer that closes mobile keyboard + const handlePointerUp = () => { if (longPressTimerRef.current) { clearTimeout(longPressTimerRef.current); longPressTimerRef.current = null; } - }, []); + if (!isLongPressRef.current) { + onCycleAgent(); + } + }; - const startLongPressTimer = React.useCallback(() => { - clearLongPressTimer(); - longPressTriggeredRef.current = false; - longPressTimerRef.current = setTimeout(() => { - longPressTriggeredRef.current = true; - onOpenAgentPanel(); - }, LONG_PRESS_MS); - }, [clearLongPressTimer, onOpenAgentPanel]); + const handlePointerLeave = () => { + if (longPressTimerRef.current) { + clearTimeout(longPressTimerRef.current); + longPressTimerRef.current = null; + } + }; React.useEffect(() => { - return () => clearLongPressTimer(); - }, [clearLongPressTimer]); + return () => { + if (longPressTimerRef.current) { + clearTimeout(longPressTimerRef.current); + } + }; + }, []); return ( ); };