diff --git a/web/src/components/MessageComposer.tsx b/web/src/components/MessageComposer.tsx index 347f7b9..cdb4ab7 100644 --- a/web/src/components/MessageComposer.tsx +++ b/web/src/components/MessageComposer.tsx @@ -108,6 +108,7 @@ export function MessageComposer() { const pointerUpHandlerRef = useRef<((event: globalThis.PointerEvent) => void) | null>(null); const recordingStateRef = useRef("idle"); const lastEditingMessageIdRef = useRef(null); + const prevActiveChatIdRef = useRef(null); const [isUploading, setIsUploading] = useState(false); const [uploadProgress, setUploadProgress] = useState(0); @@ -255,6 +256,15 @@ export function MessageComposer() { } }, [activeChatId]); + useEffect(() => { + const prev = prevActiveChatIdRef.current; + if (prev && prev !== activeChatId) { + const ws = getWs(); + ws?.send(JSON.stringify({ event: "typing_stop", payload: { chat_id: prev } })); + } + prevActiveChatIdRef.current = activeChatId; + }, [activeChatId]); + useEffect(() => { const onVisibility = () => { if (document.visibilityState === "hidden" && recordingStateRef.current === "recording") { @@ -1297,6 +1307,11 @@ export function MessageComposer() { sendRealtimeChatEvent(next.trim().length > 0 ? "typing_start" : "typing_stop"); } }} + onBlur={() => { + if (activeChatId) { + sendRealtimeChatEvent("typing_stop"); + } + }} /> {hasTextToSend ? (