fix(sync): no conflicts with one's own text, one copy per conflict

- Leaving the tab sent pending text with keepalive but kept it queued;
  typing on folded it with newer keystrokes under the old base version,
  which then conflicted with the user's own text. The flushed batch now
  becomes the batch in flight.
- After a conflict, the focused field still showed the losing text and
  every further batch made another copy. Typing on goes into the one
  copy until the cursor leaves; on leaving, the field shows the block's
  current text, and entering a block bases edits on what it shows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-11-02 11:30:08 +01:00
1 parent 08d35a4a81
commit c021946c7f
3 files changed
+118 -12

No files matched your search

@@ -270,11 +270,17 @@ export const OutlinerBlock: React.FC<OutlinerBlockProps> = ({
document.activeElement === textareaRef.current;
const acceptAfterUndo = Date.now() < acceptRemoteUntilRef.current;
if ((!isActivelyEditing || acceptAfterUndo) && block.content !== localContentRef.current) {
// Also when the cursor leaves: after a conflict the field held the user's own text, which now stands
// in the conflict copy, while the block itself keeps the other version
if (
(!isActivelyEditing || acceptAfterUndo) &&
debounceTimerRef.current === null &&
block.content !== localContentRef.current
) {
setLocalContent(block.content || '');
localContentRef.current = block.content || '';
}
}, [block.content]);
}, [block.content, isLocallyFocused]);
// Handle window blur / focus to instantly flush debounced input and clear zombie focus
useEffect(() => {