Image resize using quill-blot-formatter package restricts the scrolling in the react-quill editor

210 Views Asked by At

I am currently using the React-Quill editor and the functionality for image upload is achieved through the 'formats/image' feature provided by Quill.

Image resize option doesn't included in the react-quill editor by default. Consequently, we have incorporated the quill-blot-formatter package and registered it with the Quill modules to enable this feature.

Quill.register('modules/blotFormatter', BlotFormatter);

The image resize feature works fine but it prohibits the scrolling effect of the Quill editor if the mouse focus is inside the resize window

Image resize prohibits editor scrolling

If the mouse pointer is outside of the image resize area, scrolling functions properly. Hence some of the listener from the ql-blot-formatter stopsPropagation of the mouse events to the react-quill(the event is not bubbling up to the ql-editor).

Could someone kindly assist me in resolving this issue.?

Below is the code snippet that I've implemented for the reference.

QuillEditor.js

import ReactQuill from 'react-quill';

const Quill = ReactQuill.Quill;
const Embed = Quill.import('blots/embed');
import BlotFormatter from 'quill-blot-formatter/dist/BlotFormatter';
import { CustomImage } from './CustomPlugins/CustomImage';

//to register uploaded image as blot
Quill.register(CustomImage, true);
// Register image resize
Quill.register('modules/blotFormatter', BlotFormatter);

<ReactQuill
  ref={editorRef}
  className={`w-full ${height} ${className} `}
  formats={formats}
  id={id}
  modules={modules(toolbarId)}
  theme="snow"
  value={state}
  onChange={handleChange}
      />

function modules(toolbarId) {
     return {
      blotFormatter: {
      specs: [CustomImageSpec], //register the custom spec
      align: {
        icons: alignmentStyles,
      },
    },
  };
}
CustomImageSpec.js

import DeleteIcon from '../../../assets/DeleteIcon.svg';
import { alignToolBar } from './helper';
import ImageSpec from 'quill-blot-formatter/dist/specs/ImageSpec';

// Custom image spec for blot formatter
// Adding delete icon to the blot toolbar on mount phase
export class CustomImageSpec extends ImageSpec {
  img;
  deleteIcon;

  constructor(formatter) {
    super(formatter);
    this.img = null;
    this.deleteIcon = this.createDeleteIcon();
  }

  createDeleteIcon() {
    const spanElement = document.createElement('span');
    const imgElement = document.createElement('img');
    imgElement.src = DeleteIcon;
    imgElement.alt = 'test image';
    const clsList = ['blot-formatter__toolbar-button', 'blot-delete-icon'];
    spanElement.classList.add(...clsList);
    spanElement.appendChild(imgElement);
    spanElement.style.cssText =
      'display: flex; align-items:center; justify-content:center; width: 24px; height: 24px; cursor:pointer; user-select:none; padding: 2px';
    spanElement.addEventListener('click', this.onDeleteIconClick);
    return spanElement;
  }

  init() {
    this.formatter.quill.root.addEventListener('click', this.onClick);
    this.formatter.quill.root.addEventListener('scroll', (e) => {
       this.formatter.repositionOverlay();
    });
  }

  getTargetElement() {
    return this.img;
  }

  onDeleteIconClick = () => {
    // Handle delete icon click
    if (this.img) {
      this.img.remove();
      this.formatter.hide();
    }
  };

  onHide() {
    this.img = null;
  }

  onClick = (event) => {
    const el = event.target;
    if (!el || el.tagName !== 'IMG') {
      return;
    }
    this.img = el;
    this.formatter.show(this);
    alignToolBar(this.formatter);
    this.formatter.overlay
      ?.getElementsByClassName('blot-formatter__toolbar')[0]
      ?.appendChild(this.deleteIcon);
  };
}

CustomImage.js

import { Quill } from 'react-quill';

// eslint-disable-next-line react-refresh/only-export-components
const BaseImage = Quill.import('formats/image');
// const BaseImage = Quill.import('blots/embed')
// eslint-disable-next-line react-refresh/only-export-components
const ATTRIBUTES = ['alt', 'height', 'width', 'style'];

export class CustomImage extends BaseImage {
  static formats(domNode) {
    return ATTRIBUTES.reduce(function (formats, attribute) {
      if (domNode.hasAttribute(attribute)) {
        formats[attribute] = domNode.getAttribute(attribute);
      }
      return formats;
    }, {});
  }
  format(name, value) {
    if (ATTRIBUTES?.indexOf(name) > -1) {
      if (value) {
        this.domNode.setAttribute(name, value);
      } else {
        this.domNode.removeAttribute(name);
      }
    } else {
      super.format(name, value);
    }
  }
}

//to register uploaded image as blot
Quill.register(CustomImage, true);
0

There are 0 best solutions below