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.
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.to, I would need to calculate the new selection in a more complex way. My current solution is to get the offset of the
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?
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?