Selection changes when inline Decoration is applied

Hey!

I have a plugin that highlights the current selection.

import {Plugin} from 'prosemirror-state'
import {DecorationSet, Decoration} from 'prosemirror-view'

export default new Plugin({
    props: {
        decorations(state) {
            return state.selection.empty ? null : DecorationSet.create(
                state.doc,
                [Decoration.inline(state.selection.from, state.selection.to, {class: 'selection'})]
            )
        }
    }
})

The expected behavior is, that the current selection does not change and the selected text is highlighted. The class selection turns the background green. What happens is, that when the decoration is applied, the selection jumps to the start of the node (paragraph) and the decoration is applied from there. Depending on the direction that i am selecting, the selection sometimes also jumps to the end of the node. A demonstration: http://recordit.co/5XEviIG7L5

Please point me in the right direction so solve this, thanks a lot!

It seems to be a general problem with the native selection when inline decorations are added. I guess it is because of the change in the DOM. Is there a way to sync from the correct selection that was created by prosemirror?!

Remixing the decoration Example on glitch does not result in this error. So either there is a new bug or I am messing something up. Will investigate further!

The problem is coupled to editable, if it is set to false, the selection behaves in that weird manner.

What I am trying to achieve is, that I have a non editable prosemirror view where I can select text and add inline decorations to the selections. The user should not be able to alter the content in any way. I think editable => false is the way to go, however the selection problem needs to be solved. I will have a look at the selection.js in prosemirror-view, if I can figure out what is happening. Help is still much appreciated!

Thank you!

Well it took, uh, 4 months, but I finally took a look at this today. I think this patch should help with this. If you’re still interested, could you take a look?

Hey

I am seeing this issue after the fix.

Updated to prosemirror-view: 1.2.0 and I can see this issue. It is more pronounced in Safari 10.1 (It only happens when the inline decoration contains the selection, the selection is moved) Is it possible that there is a race condition here?

Thanks for any assistance here.

Thanks for the Patch marjin! I had a quick test and it seems to work now, I will get back here when I have had the chance to test it thoroughly.

Same here for:

"prosemirror-state": "^1.3.4",
    "prosemirror-view": "^1.20.2"

Did you find any workaround for this?

Hey, this still seems to be an issue today:

2021-12-20 17-32-56.2021-12-20 17_33_47

I’ve made a simplified example with a prosemirror plugin in tiptap: distracted-fast-j6ucv - CodeSandbox

It happens a bit intermittently, when the decoration is applied while highlighting text, the selection to jumps to the end of the text selection. If decoration is not supposed to work like this, is there any alternative way to add a class to the user selected text?

– Update: if I add this to the plugin, I don’t get this selection issue:

handleDOMEvents: {
            mousedown: (view, event) => {
              return true;
            },
            mouseup: (view, event) => {
              return true;
            }
          },

I’m not sure yet what implications to the rest of my app this will have, but it seems a good workaround for now (try here: eager-shadow-ginr3 - CodeSandbox)

– just tried again, intercepting mousedown isn’t good solution

That’s quite a different issue (it doesn’t require the editor to be uneditable, for one thing). This patch might help with it.

1 Like

Thanks a lot for the patch, that was fast! I’m struggling to try it with my project as the tiptap package has its own package.json with the npm version of prosemirror-view, so I’m not sure how to use it with the github update yet.

After I find out, I’ll let you know if it did the trick.

You should be able to clone the prosemirror-view repository, do a local build (npm install), and then copy the contents of dist/ into your own node_modules/prosemirror-view/dist/ to run a version from git.

1 Like

Oh great, I’ll give that a go soon and let you know if it solved my issue, thanks again!

This seems to still happen in some form. In my case it is not only when the mouse is used, but also the keyboard. I tried to pull out a reproducible example of our codebase.

Here is a description of how it happens for us:

  • Our list items are not defining, but we want defining behaviour when the full list item is selected so it is preserved upon paste only when at least the full content is selected. Otherwise if you select some partial content it will paste without the list item.
  • To do this we use a plugin that implements createSelectionBetween. This extends the selection to before and after the list item, so the copied slice has the appropriate open start and end and the content pastes as list item.
  • We have another plugin that adds an inline decoration between the selection from and to position if it’s either an AllSelection or a TextSelection. This is to show a greyed out selection if the editor loses focus.

How to reproduce:

  • Add three list items “abc”, “def”, “ghi”
  • Put your cursor after “def”
  • Shift + Left Arrow three times. Notice how the selection (output in the browser console) now shows correctly the extended selection 8 to 15 (extended from 10 to 13, which is the start/end of the inner paragraph).
  • Shift + Left Arrow once more and notice how the selection is now 6 to 17. The 17 is the issue here. You can see that the plugin never extended to 17.

Observations

  • With the decorations disabled the selection stays at 15 as expected, even when using Shift + Left Arrow
  • This seems to only happen when the text selection is from before a node to after. If I remove the extend selection logic it also doesn’t happen. Might this be an issue because we use text selections incorrectly (as in they don’t point into text blocks)?
  • This behaviour doesn’t occur in Safari at all, only Chrome. Safari correctly keeps the end of the selection at 15.

Let me know if I can be of any help here.

The glitch link is giving me a 404. Can you recreate it?

But yeah, text selections not pointing into inline positions are not supported. I guess I’ll add a warning for those since people keep tripping over them.

I never got a notification about your reply, sorry! I ended up re-writing our plugin to serialize the clipboard content differently, instead of “extending the selection”. I think our issue was coming from exactly that and I appreciate you putting in a warning :slight_smile: While it does work, browser behaviour varies greatly so it makes total sense to not support it in prosemirror.