Cursor isn't behaving when saving and reloading states

Before loading a new document into the editor, I save the current state so that it can be restored using view.setState().

This works fine if I just switch back and forth between states. But if I interact with the document, even just to give it focus by placing a cursor inside the editor, then, after I switch to another state using view.setState(), a cursor is placed at the bottom of the editor which scrolls the editor down to the bottom and disables any selection that was in the restored state.

I am getting this issue with even the most minimalist set up with no extensions. Any idea might be happening?

I’m not able to reproduce. Could you show a minimal script + precise instructions on how to get it to happen?

Thank you for taking a look.

I’ve dug into this some more and I’m not sure that is related to CodeMirror so I don’t want to take up too much of your time.

I’ve found that the issue only occurs when navigating between states using a key command. When the editor is focused there doesn’t seem to be any way to prevent the keystroke from landing in the editor even if the event is prevented from propagating.

Here’s a quick demo. Mod-/ toggles between states.

const view = new EditorView({ parent: document.body, })
const ext = [ EditorState.allowMultipleSelections.of(true), drawSelection()]

const store = new Map()
store.set(1, EditorState.create({ doc: 'Doc 1\nLorem Ipsum', extensions: ext }))
store.set(2, EditorState.create({ doc: 'Doc 2\nLorem Ipsum', extensions: ext }))

let current = 1
view.setState(store.get(current))
view.dispatch(view.state.update({selection: {anchor: 1, head: 3}}))

window.addEventListener('keydown', handler, true)

function handler (e) {
  if (e.key === '/' && e.metaKey) {
    toggleState()
    e.stopPropagation()
  }
}

function toggleState () {
  const next = current === 1 ? 2 : 1
  store.set(current, view.state)
  view.setState(store.get(next))
  current = next
}

Doing preventDefault will cause the editor to not further handle the event. It doesn’t look at stopPropagation.

This patch should help with this.

That patch seems to work perfectly. Thank you.

(My last post before marijn committed the patch was accidentally deleted. Here it is again to avoid having to dig through the edit history to see why the patch was needed.)

Unfortunately preventDefault() doesn’t solve this even though it does prevent the keystroke from landing.

Here’s a simpler example. The selection is there in the state after the update but it isn’t visible and the cursor is placed at the end of the text. If you contentDOM.blur() before setState() the problem disappears but then you lose the selection when you click back into the editor.

window.onkeydown = (e) => {
  if (e.key === '/') { 
    e.preventDefault()
    const state = EditorState.create({
      extensions: ext,
      doc: 'Lorem Ipsum',
      selection: {anchor: 1, head: 3},
    })
    view.setState(state)
    console.log(view.state.selection)
  }
}