Handling focus in plugins

For the record, I did get this working by storing the focus state in the plugin state. The code now looks like this:

const key = new PluginKey('selectionSize');

let selectionSizePlugin = new Plugin({
  key,
  state: {
    init() {
      return false; // assume the view starts out without focus
    },
    apply(transaction, prevFocused) {
      // update plugin state when transaction contains the meta property
      // set by the focus/blur DOM event handlers
      let focused = transaction.getMeta(key);
      return typeof focused === 'boolean' ? focused : prevFocused;
    }
  },
  view(editorView) { return new SelectionSizeTooltip(editorView) },
  props: {
    handleDOMEvents: {
      blur(view) { view.dispatch(view.state.tr.setMeta(key, false)) },
      focus(view) { view.dispatch(view.state.tr.setMeta(key, true)) }
    }
  }
})

class SelectionSizeTooltip {

  // constructor see https://prosemirror.net/examples/tooltip/

  update(view, lastState) {
    let state = view.state
    let focused = key.getState(state);

    // Don't do anything if the document, selection, and focus didn't change
    if (lastState && lastState.doc.eq(state.doc) &&
        lastState.selection.eq(state.selection) &&
        focused === key.getState(lastState)) return

    // Hide the tooltip if the selection is empty
    if (state.selection.empty || !focused) {
      this.tooltip.style.display = "none"
      return
    }

   // rest of the code see https://prosemirror.net/examples/tooltip/
  }
}

Now I am moving the focus state plugin into its own plugin so that it can easily be reused by other similar plugins. But the general principle works great as far as I can tell. Thanks for the help.

4 Likes