Duplicated Content when using Replace Transform Functions

Hi everyone!

I’m having some odd issues and I’m not sure if I’m doing something wrong or missing a step. I’m having an issue when using replaceSelectionWith and with other functions such as replaceRangeWith, replaceWith etc. I’m trying to replace one node with another node, same type of node in this case, just different attrs. It keeps performing the action, however, it’s also duplicating the content.

I’m trying to resize an image, when an image is selected, a panel opens that has three buttons to resize said image. This code is in my dispatch function:

    $("body").on("click", "#image-resizer-set-small", () => {
      this.view.dispatch(
        this.view.state.tr.replaceWith(from, to,
          this.view.state.schema.nodes.image.createAndFill({
            src: node.attrs.src,
            class: "ProseMirror-Image-small",
          })
        )
      );
    });

    $("body").on("click", "#image-resizer-set-medium", () => {
      this.view.dispatch(
        this.view.state.tr.replaceWith(from, to,
          this.view.state.schema.nodes.image.createAndFill({
            src: node.attrs.src,
            class: "ProseMirror-Image-medium",
          })
        )
      );
    });

    $("body").on("click", "#image-resizer-set-large", () => {
      this.view.dispatch(
        this.view.state.tr.replaceWith(from, to,
          this.view.state.schema.nodes.image.createAndFill({
            src: node.attrs.src,
            class: "ProseMirror-Image-large",
          })
        )
      );
    });

I have the following vars for from and to:

const from = this.view.state.selection.$from.pos;
const to = this.view.state.selection.$to.pos;

node in this case is the existing node that will be replaced, both nodes in this case are the custom image node from a custom schema:

  image: {
inline: true,
attrs: {
  src: {},
  class: { default: "other_html ProseMirror-Image-large" },
},
group: "inline",
draggable: true,
parseDOM: [
  {
    tag: "img[src]",
    getAttrs(dom) {
      return {
        src: dom.getAttribute("src"),
      };
    },
  },
],
toDOM(node) {
  return [
    "figure",
    { class: "imgBlock" },
    ["img", node.attrs, 0],
  ];
 },
},

Please let me know if you need any other information and thank you very much!

If from and to are the same (for a cursor selection), replacing will indeed insert a new node. The way your click handlers close over a fixed pair of from/to variables looks very odd, but I’m not sure how you’re maintaining those variables’ value. The setNodeMarkup method might be useful here.