reedsy / quill-cursors

A multi cursor module for Quill text editor.
MIT License
250 stars 53 forks source link

Using a quill editor inside a react-flow is somehow causing cursors to render at strange places. #82

Open zachdaniel opened 2 years ago

zachdaniel commented 2 years ago

CleanShot 2022-06-10 at 20 45 04

I've been trying tons of things to make this work, and if it comes to it I can try to reproduce with a fiddle, but I was wondering if perhaps anyone would have a pointer on what to look for here, if there is some kind of issue using quill in this context w/ a resizing/absolute container (I think that is how react-flow works?).

Happy to provide additional info as needed, but hopefully there is just a lead I've failed to track down somewhere here :)

zachdaniel commented 2 years ago

ah, just seconds after posting this I found something important! On load we are calling reactFlow.fitView(), which ensures that all react flow nodes are available on the page, and if I take that out everything works again.

zachdaniel commented 2 years ago

Okay, so the issue is definitely related to zooming in/out on the react flow :)

zachdaniel commented 2 years ago

So it looks like I need some way for whatever handles the cursors to be aware that the container's dimensions have changed, or something along those lines. Any ideas?

zachdaniel commented 2 years ago

This looks relevant https://github.com/quilljs/quill/issues/635

alecgibson commented 2 years ago

How exactly is the container being resized? An MWE would be needed to debug this.

zachdaniel commented 2 years ago

Hey there :) Sorry for the vague issue, but I've pinned it down. I had to copy this lib into my own code any way due to something strange with the global Quill object as we are also using quill-react and the Quill imported from quill-react is not the same one as the one this library imports. I don't fully understand it, js isn't really my forte. Either way, after copying the code down I was able to chase down the issue. The problem is that the container is resized via "scale" which is not taken into account in the calculation for cursor placement.

This is probably not the most elegant solution, but it worked. I pass a scale object down into the methods like updateCaret and updateSelection

    const scale = {
      x: containerBounds.width / this.quill.container.offsetWidth,
      y: containerBounds.height / this.quill.container.offsetHeight,
    };

This gets threaded down to the places where the position calculations are handled, and used like this:

  private _selectionBlock(selection: ClientRect, container: ClientRect, scale: Scale): HTMLElement {
    const element = document.createElement(Cursor.SELECTION_ELEMENT_TAG);

    element.classList.add(Cursor.SELECTION_BLOCK_CLASS);
    element.style.top = `${(selection.top - container.top) / scale.y}px`;
    element.style.left = `${(selection.left - container.left) / scale.x}px`;
    element.style.width = `${selection.width / scale.x}px`;
    element.style.height = `${selection.height / scale.y}px`;
    element.style.backgroundColor = tinycolor(this.color).setAlpha(0.3).toString();

    return element;
  }
alecgibson commented 2 years ago

Good sleuthing! I've not got a vast amount of time to work on this right now, but will try to take a look over the coming weeks.

Alternatively, @fyvfyv do you want to pick this one up?

fyvfyv commented 2 years ago

@alecgibson Sure, I'll try to take a look soon

lukebrody commented 2 years ago

For anyone who needs a quick-and-dirty fix for this, I have a fork here: https://github.com/lukebrody/quill-cursors (You can set the scale property on the module, see example/main.js)

Ideally this would happen automatically based on how the Quill editor is scaled, but I'm not familiar enough with getting this layout information out of the DOM to implement a PR that does this.