diff --git a/src/components/room/MentionInput.tsx b/src/components/room/MentionInput.tsx index e12681f..a6a46e2 100644 --- a/src/components/room/MentionInput.tsx +++ b/src/components/room/MentionInput.tsx @@ -166,7 +166,6 @@ export const MentionInput = forwardRef(functi if (!el) return; // If the DOM already contains what we want, nothing to do. - // (Programmatic updates via onChange already set the DOM correctly.) if (getPlainText(el) === value) { isUserInputRef.current = false; return; @@ -176,6 +175,9 @@ export const MentionInput = forwardRef(functi const oldCaret = isUserInputRef.current ? getCaretOffset(el) : 0; const oldLen = internalValueRef.current.length; + // Block selectionchange handler from reading wrong cursor position during DOM update + (window as any).__mentionBlockSelection = true; + // Update DOM el.innerHTML = value.trim() ? renderToHtml(value) : ''; internalValueRef.current = value; @@ -187,6 +189,11 @@ export const MentionInput = forwardRef(functi const newLen = value.length; setCaretAtOffset(el, Math.round(ratio * newLen)); } + + // Unblock selectionchange after DOM has settled + requestAnimationFrame(() => { + (window as any).__mentionBlockSelection = false; + }); }, [value]); /** Handle input changes — extracts plain text from DOM and sends to parent */ diff --git a/src/components/room/RoomChatPanel.tsx b/src/components/room/RoomChatPanel.tsx index 9b3152d..edf03d9 100644 --- a/src/components/room/RoomChatPanel.tsx +++ b/src/components/room/RoomChatPanel.tsx @@ -83,12 +83,13 @@ const ChatInputArea = memo(function ChatInputArea({ // ─── Track DOM cursor offset → ms.cursorOffset on user navigation ────── // Uses selectionchange event which fires when caret moves via arrows/clicks. - // Does NOT fire during programmatic updates, avoiding cursor jumps. + // Ignores programmatic DOM updates (blocked via window.__mentionBlockSelection). const prevCursorRef = useRef(ms.cursorOffset); const skipCursorTrackingRef = useRef(false); useEffect(() => { const readCursor = () => { if (skipCursorTrackingRef.current) return; + if ((window as any).__mentionBlockSelection) return; const el = containerRef.current; if (!el) return; const sel = window.getSelection();