Moving blocks in Y-ProseMirror

We have been working on improving conflict-resolution in our offline note app using y-prosemirror. We have changed the list structure from two-level nested element (<ul><li>) to one-level flat element (<div>). This will help us to prevent conflicts when changing the type of list item.

:arrow_up: Old structure. Notice that we will lose character b and c after merging.

:arrow_up: New structure. We won’t lose anything.


I would like to take my work a step further and improve conflict resolution when moving blocks (e.g. drag-and-drop).

:arrow_up: An example of moving block with y-prosemirror. I expect to get Item Bb and Item Aa at the end, but I actually get Item Ba and Item Ab,

To do this, I’m considering assigning a unique id to each block element (e.g. list item), and make sure this id doesn’t change when moving blocks. This way, I can implement a block-level move operation by comparing the unique id. Similar to the example with yarray in this comment about moving elements in lists. However I’m not sure if this approach is doable with y-prosemirror. I would be very grateful for any advice on this strategy.

If you are offline-first, don’t think this is doable without some heavy hacks. The best way to do it would probably be implmenting a “move” operation in Yjs. AFAIK there is no such thing nor one coming up any time soon. So, you could implement it yourself - or - as you explained, use an unique ID. Problem with that is you can’t ensure it to be unique at least at ProseMirror level (dunno if there is unique Yjs block ID?).

So you have to include a conflict resolution after each transaction to clean up duplicates incase something weird happens. But certainly, you could probably use those.

At ProseMirror level you could also track the operations and keep a log of them. But that wouldn’t help if Yjs resolves the conflicts in a weird way.

Did you try both ways where the insert is done first, swap next and vice-versa? Did it change the result?

Making sure every ProseMirror node has a unique id, although might hurt performance, is doable without modify ProseMirror itself. On the another hand, I don’t know how to add “move operation” to YJS without modify Yjs itself, and I’m unlikely to implement such complex feature by myself.

I’d myself probably just avoid the whole thing all together if possible but definitely unique ProseMirror ids should be doable :+1: