Hi. I’m trying to implement a moving block feature similar to Notion’s, which allows users to move a block (or multiple blocks) up or down by pressing a keyboard shortcut. Check the video below for a quick demo of Notion’s implementation.
My current plan is to delete the whole selected block (by using tr.delete
) and then insert the block in the appropriate position again (by using tr.insert
). By doing that, I can’t use tr.mapping.map
to map a position inside the selected block. This leads to two problems: preserving selection and preserving decoration.
Selection
ProseMirror already has two ways to move a block: Cut-and-Paste (Ctrl-X then Ctrl-V) and Drag-and-Drop. In both these two situations, users won’t expect their selection to be preserved. But when users move a block using keyboard shortcut, they want their selection to remain the same. Check the video above as an example.
Since I can’t simply use tr.mapping.map
to map selection.from
and selection.to
, I would need to calculate the new selection in a more complex way. My current solution is to get the offset of the from
/to
against the selected node, and then set the selection based on the start position of the new inserted node.
This should be doable, at least in theory, but it’s still a little complex. Is there an easier way to preserve the selection?
Decoration
If I don’t get it wrong, a decoration requires mapping.map
to get its new position after a transaction. Since mapping.map
doesn’t work here. I will lose a decoration insert the selected node after moving this block. This issue is both for moving blocks with Drag-and-Drop and with keyboard shortcut.
I can use the official image upload example to demonstrate this issue. Notice that the image placeholder inside node B
disappears after I move node B
, which causes the image to fail to be inserted later.
Is there a way to preserve the decoration?