-
-
Notifications
You must be signed in to change notification settings - Fork 125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Infinite cursor awareness update loop when two prosemirror docs edit same underlying y.XmlFragment #85
Comments
I managed to get this to work by explicitly unsetting the cursor state only on Here is the modified code I am using: const updateCursorInfo = () => {
const ystate = ySyncPluginKey.getState(view.state)
const current = awareness.getLocalState() || {}
if (view.hasFocus() && ystate.binding) {
const selection = getSelection(view.state)
const anchor = absolutePositionToRelativePosition(selection.anchor, ystate.type, ystate.binding.mapping)
const head = absolutePositionToRelativePosition(selection.head, ystate.type, ystate.binding.mapping)
if (
!current[cursorStateField] ||
!Y.compareRelativePositions(Y.createRelativePositionFromJSON(current[cursorStateField].anchor), anchor) ||
!Y.compareRelativePositions(Y.createRelativePositionFromJSON(current[cursorStateField].head), head)
) {
awareness.setLocalStateField(cursorStateField, {
anchor,
head,
})
}
}
}
const unsetCursorInfo = () => {
const current = awareness.getLocalState() || {}
if (current[cursorStateField]) {
awareness.setLocalStateField(cursorStateField, null)
}
}
awareness.on('change', awarenessListener)
view.dom.addEventListener('focusin', updateCursorInfo)
view.dom.addEventListener('focusout', unsetCursorInfo) // Dont use update function for blur event and instead unset
return {
update: updateCursorInfo,
destroy: () => {
view.dom.removeEventListener('focusin', updateCursorInfo)
view.dom.removeEventListener('focusout', unsetCursorInfo)
awareness.off('change', awarenessListener)
unsetCursorInfo()
},
} Let me know if you think this would break in certain situations. Happy to submit a PR if you think it's worth adding! |
I think we also ran into this issue while working with React in strict mode. (but it would also happen if you have two Prosemirror plugin instances listening on the same provider causing the editors to throw updates up to react). |
@bdbch We've been using the solution from @milesingrams for a long while without any issues. I've created a PR with that solution here. |
Describe the bug
I am using TipTap (https://tiptap.dev/) which uses y-prosemirror under the hood to handle collaboration cursors. I have a semi unique situation where I have a page with two editors both which edit the same Y.XmlFragment. When I click on either of the editors to begin editing the cursor starts flickering and runs and infinite cycle of updating the awareness state. I have narrowed down the cycle to this block of code:
y-prosemirror/src/plugins/cursor-plugin.js
Lines 113 to 136 in 984175f
The infinite loop is cycling between:
and
My guess is that while the cursor plugin beautifully handles multiple prosemirror documents on a page, it has issues when two prosemirror documents edit the same underlying Y.XmlFragment.
Perhaps more logic around the editor gaining and losing focus could resolve this. i.e. only update awareness when editor is actively focused and set awareness to null when editor loses focus.
Expected behavior
I expect multiple editors to be able to seamlessly edit the same Y.XmlFragment without causing the awareness updates to enter an infinite loop.
Environment Information
Anyways I'm sure this isn't the most common use case but I would greatly appreciate the help. Thank you for such an awesome tool!
The text was updated successfully, but these errors were encountered: