fix(frontend): skip cursor tracking effect during deferred cursor updates
Root cause: when onCategoryEnter scheduled a deferred setCursorOffset, the tracking effect ran BEFORE setTimeout and read the OLD DOM cursor position (still "@a" → position 2), overwriting the new cursor position of 4 in a subsequent render. Fix: add skipCursorTrackingRef flag. Set it before setTimeout fires, clear it when setTimeout executes. The tracking effect checks the flag and skips its update during the flush window. Same fix applied to insertCategory imperative handle.
This commit is contained in:
parent
fb09553b79
commit
126ffda4fe
@ -83,7 +83,11 @@ const ChatInputArea = memo(function ChatInputArea({
|
||||
|
||||
// Track DOM cursor offset → ms.cursorOffset on every render
|
||||
const prevCursorRef = useRef(ms.cursorOffset);
|
||||
// Set when a deferred cursor update is scheduled; cleared when it fires.
|
||||
// Prevents the tracking effect from overwriting a programmatically-set cursor.
|
||||
const skipCursorTrackingRef = useRef(false);
|
||||
useEffect(() => {
|
||||
if (skipCursorTrackingRef.current) return;
|
||||
const el = containerRef.current;
|
||||
if (!el) return;
|
||||
const sel = window.getSelection();
|
||||
@ -131,7 +135,9 @@ const ChatInputArea = memo(function ChatInputArea({
|
||||
const newCursorPos = startPos + 1 + category.length + 1;
|
||||
onDraftChangeRef.current(newValue);
|
||||
ms.setValue(newValue);
|
||||
skipCursorTrackingRef.current = true;
|
||||
setTimeout(() => {
|
||||
skipCursorTrackingRef.current = false;
|
||||
ms.setCursorOffset(newCursorPos);
|
||||
ms.setShowMentionPopover(!!newValue.substring(0, newCursorPos).match(/@([^:@\s]*)(:([^\s]*))?$/));
|
||||
}, 0);
|
||||
@ -249,8 +255,14 @@ const ChatInputArea = memo(function ChatInputArea({
|
||||
const newCursorPos = startPos + 1 + category.length + 1;
|
||||
onDraftChangeRef.current(newValue);
|
||||
ms.setValue(newValue);
|
||||
// Defer cursor update until after DOM has flushed the new mention value
|
||||
setTimeout(() => ms.setCursorOffset(newCursorPos), 0);
|
||||
// Defer cursor update until after DOM has flushed the new mention value.
|
||||
// Skip tracking effect during the flush window to avoid it overwriting
|
||||
// the deferred cursor with the old DOM position.
|
||||
skipCursorTrackingRef.current = true;
|
||||
setTimeout(() => {
|
||||
skipCursorTrackingRef.current = false;
|
||||
ms.setCursorOffset(newCursorPos);
|
||||
}, 0);
|
||||
}}
|
||||
suggestions={ms.suggestions}
|
||||
selectedIndex={ms.selectedIndex}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user