I am in the process of creating a custom YJS provider for my application, as discussed here. My goal is to implement awareness and transmit cursor position through this provider.
I have reviewed the Awareness & Presence and Y.RelativePosition documentation, but the usage of the RelativePosition API remains unclear.
In the documentation, the variable
ytext is mentioned but its exact reference is ambiguous to me. Is it referring to the currently selected text? If so, how can I access it?
I am utilizing TipTap and Prosemirror, and have the ability to determine the absolute position and the selected node within Prosemirror.
Your assistance is greatly appreciated. Thank you.
The RelativePosition API works on any
Y.Text instance (or sequence-like shared type). I don’t see anything to suggest that it will work on the TipTap editor.
You can put any data into Awareness, so as long as you can encode the cursor position you can share it with all clients.
You may want to check out the CollaborationCursor extension for TipTap:
Thank you for your answer @raine.
Let me clarify what I want to do:
- I want to get the cursor position from YJS instead of getting it from TipTap (as the one from TipTap is absolute and sometimes lead to issues where the cursor moves to the next line if the text isn’t updated yet)
- I’m not sure to understand what
Y.Text instance I should get. My document is linked with YJS using the
@tiptap/extension-collaboration extension and my custom provider. I’m not sure to understand how to get a
Y.Text instance from my doc?
Your Doc will have one or more shared types on it, but I don’t know what TipTap uses under the hood. I assume that TipTap has a more complex data structure than
Y.Text in order to store attributes or hierarchical nodes. If that’s the case, then the RelativePosition API will not work for you. It only works with sequence-like shared types.
This might be a better question for TipTap. I provided the links to the CollaborationCursor extension since I assume they somehow share the cursor position there, but it’s not obvious from the code.
Ah ok. I thought I could take the absolute position from TipTap/Prosemirror (same structure under the wood) and convert it to a YJS relative position.
I looked at the extension code and it mostly rely on the
y-prosemirror extension that uses the RelativePosition API: https://github.com/yjs/y-prosemirror/blob/master/src/plugins/cursor-plugin.js#L215
But similarly, in this code, I’m not sure how to adapt
const ystate = ySyncPluginKey.getState(view.state) to my own provider (what’s
view in this context?).
Okay, so they are using the generic
Y.createRelativePositionFromTypeIndex method. Hopefully that gives you something you can encode in Awareness.
Unfortunately I’m outside my expertise at this point, as I have never used TipTap or Prosemirror. Though it seems to me that a custom provider should just propagate Awareness regardless of what is in it. It would be the client’s responsibility to update the cursor position on the Awareness object.
I’m going to dig deeper to understand how to copy what
y-prosemirror is doing.
Right now, I’m stuck on what
Y.Text should be. Should it be the whole document in a
Y.Text instance (but it doesn’t really make sense, right?), or just the line I’ve selected? What if there are several lines inside the selection? This question is not just for Prosemirror, but also what YJS expects, no matter what library is used.
If you want to use
Y.createRelativePositionFromTypeIndex directly, you would pass the
Y.XmlFragment of the editor, i.e.
ystate.type as seen here.
However, you might need to use
absolutePositionToRelativePosition provided by
y-prosemirror and just save that position to Awareness. It seems to do quite a bit of work traversing all nodes in the Document in order to generate a relative position that represents the entire Document, not just the top level.