ProseMirror / prosemirror

The ProseMirror WYSIWYM editor
http://prosemirror.net/
MIT License
7.61k stars 336 forks source link

Incorrect caret movement around inline-block, with ArrowDown key #1352

Closed lyonbot closed 1 year ago

lyonbot commented 1 year ago

I defined a node with this spec. It is a inline block, and it may contain paragraph inside.

  map.update('button', {
    inline: true,
    content: 'paragraph*',
    group: 'inline',
    defining: false,
    atom: true,
    parseDOM: [{ tag: 'button' }],
    toDOM() {
      return ['button', { class: 'theButton' }, 0];
    },
  })

When caret is before the button, and DownArrow get pressed twice, the caret doesn't precede -- it go back before the button.

https://user-images.githubusercontent.com/13994038/215692091-9b7d6903-0693-4e12-9f20-5e518e6c5a0d.mp4

Reproduce:


I tried debugging with Chrome DevTool. ProseMirror's moveSelectionBlock found the correct ResolvedPos after the button, and returned a TextSelection

image

But due to this line in capturekeys.ts, the correct result got discarded:

I wonder why only NodeSelection is accepted. Is it safe to remove the restriction?

marijnh commented 1 year ago

The code you are looking at is there to create node selections when appropriate. The idea is that in other cases we leave the browser to apply its native cursor motion behavior. (So no, that check should not be removed.)

With odd DOM structure like what you have here (paragraphs in a button?), browsers often do weird things, and you may need to add your own custom key handlers to handle specific types of motions properly. (In Firefox, arrow down seems to skip the button entirely, which actually feels reasonable.)

Handling this kind of stuff is out of scope for the library (because there is an endless amount of it, for all the possible DOM shapes and stylings).

lyonbot commented 1 year ago

I edited the example, the inline block is now:

{
    inline: true,
    content: 'inline*',
    group: 'inline',
    parseDOM: [{ tag: 'span.inline-block' }],
    toDOM() {
      return ['span', { class: 'inline-block' }, 0];
    }
}

The ArrowDown key still behaves weirdly in Chrome.

https://user-images.githubusercontent.com/13994038/216306902-89840f07-73af-4007-8fdc-f5f654eca0ce.mp4

https://glitch.com/edit/#!/enthusiastic-zinc-gum?path=index.js%3A23%3A30

But it works perfectly in Firefox