Apply decorations on edited text for Prosemirror object text

465 Views Asked by At

I have a Prosemirror Editor text and, I created a plugin that applies some decorations for text. It's been working pretty well, however, when I try to edit the text, it looks really buggy, and the styles are not properly applied to the text which is been edited.

The text originally had an orange background, but when I start to edit the text with decorations, the decoration from the moment that start to update onwards disappear or only shows in some parts

The video down below demonstrates the issue:

https://i.stack.imgur.com/53b7V.jpg

Basically, this is the code that generates the Decorations:

export const getDecorationsForAnnotations = (
  doc: any,
  data: Data[],
  selectedDataId?: string
) => {
  let decos: any[] = [];
  let initialPos: number | undefined = undefined;
  let finalPos: number | undefined = undefined;
  doc.descendants((node: Node, pos: number, parent: any) => {
   ...
    // ... my logic to filter nodes here

          decos.push(
            Decoration.inline(pos, pos + parent.content.size, {
              style: S.DECORATED_PROSEMIRROR_ANNOTATED_SELECTED_NODE,
            })
          );
        }
      }
    }

    return true;
  });

  return { decos };
};

export const getHighlightAnnotationsPlugin = (
  ...
) => {
  return new Plugin({
    key: new PluginKey("pluginHighlightNotes"),
    state: {
      init(config, editorState) {
        const doc = editorState.doc as any;
        return DecorationSet.create(doc, []);
      },
      apply(transaction, oldEditorState, newEditorState) {
        let data: Data[] | undefined = undefined;
        let decorationSet = undefined;
        let selectedDataId = undefined;
        const mark = new Mark(); // being used to pass metadata to pluginView ( to add components in the DOM )

        if (transaction.getMeta("isTransactionToListen")) {
          data = transaction.getMeta("data") as Data[];
          selectedDataId = transaction.getMeta("selectedDataId") as string;
        } else {
          if (!data && oldEditorState instanceof DecorationSet) {
            // reuse previous state and decorations
            decorationSet = oldEditorState;
          }
        }

        if (!decorationSet && data?.length) {
          const doc = transaction.doc;
          const { decos } = getDecorationsForAnnotations(
            doc,
            data,
            selectedDataId
          );

          decorationSet = DecorationSet.create(doc, decos);
        }

        return decorationSet ? decorationSet : DecorationSet.create(transaction.doc, []);
      },
    },
    view: (editorView: any) => {
      return new pluginView(...);
    },
    props: {
      decorations(state) {
        return this.getState(state);
      },
    },
  });
};

1

There are 1 best solutions below

0
On

I could solve this problem by doing this:

  1. In the pluginView:
      return new pluginView(...);
    },

extract the mouse cursor position (lastState.selection.ranges[0])

  1. Check if the cursor position is inside a decorated text range
  2. If the cursor is inside a decorated text range, then trigger a new Prosemirror transaction to refresh the decorations on the text