How to disable a plugin when a composition is active?

I have this plugin that basically adds dir="ltr" or dir="rtl" to a node based on its content:

function TextDirectionPlugin({ types }: { types: string[] }) {
  return new Plugin({
    key: new PluginKey('textDirection'),
    appendTransaction: (transactions, oldState, newState) => {
      const docChanges = transactions.some(
        (transaction) => transaction.docChanged
      );

      if (!docChanges) {
        return;
      }

      let modified = false;
      const tr = newState.tr;

      newState.doc.descendants((node, pos) => {
        if (types.includes(node.type.name)) {
          const docChanges = transactions.some(
            (transaction) => transaction.docChanged
          );
          if (!docChanges) {
            return;
          }

          tr.setNodeAttribute(pos, 'dir', getTextDirection(node.textContent));

          // `tr.setNodeAttribute` resets the stored marks so we'll restore them
          const marks =
            newState.storedMarks ||
            (newState.selection.$to.parentOffset &&
              newState.selection.$from.marks());

          if (marks) {
            tr.ensureMarks(marks);
          }

          modified = true;
        }
      });

      return modified ? tr : null;
    },
  });
}

I want to disable this plugin (meaning I don’t want to append a new transaction) when a composition is active.

EditorView has the composing property that exposes this information. However, I can’t find a way to access it within appendTransaction and I’m stock.

What’s the correct way to do this?

appendTransaction doesn’t have access to the view (it happens purely at the level of the EditorState object). The way to go here is probably to schedule these direction change transactions from a view plugin. You’ll have to run dispatch asynchronously (for example in a Promise.resolve().then), to avoid reentrancy issues (where a new update is started in the middle of applying a previous update).

1 Like