```
return class DndPlugin extends RectLifecycleInterface {

    constructor() {
      super(); 

      this.currentRect = null;

      this.action = NULL;

      this.host = null;

      this.startX = 0;
      this.startY = 0;

      this.startRect = null;

      this.boundOnMouseMove = this.onMouseMove.bind(this);
      this.boundOnMouseUp = this.onMouseUp.bind(this);

      this.listeners = new WeakMap();

      this.isAnimating = false;  

      this.MIN_WIDTH = 50;  
      this.MIN_HEIGHT = 50; 
    }

    attach(host) {
      if (host) {
        this.host = host;
      }
      return null;
    }

    onRectCreate(rect, element) {

      const callback = this.onMouseDown.bind(this, rect);

      this.listeners.set(element, callback);

      element.addEventListener('mousedown', callback);
    }

    onRectRemove(rect, element) {
      const callback = this.listeners.get(element);
      if (callback) {

        element.removeEventListener('mousedown', callback);

        this.listeners.delete(element);
      }
    }

    onMouseDown(rect, e) {
      const rectElement = e.target;
      if (!rectElement) return;
      const rectStyle = rectElement.style;
      const hostStyle = this.host.style;
      const width = parseFloat(rectStyle.getPropertyValue('--width'));
      const height = parseFloat(rectStyle.getPropertyValue('--height'));
      const borderSize = parseFloat(rectStyle.getPropertyValue('--border-size') || hostStyle.getPropertyValue('--border-size')) || 6;
      const vertexSize = parseFloat(rectStyle.getPropertyValue('--vertex-size') || hostStyle.getPropertyValue('--vertex-size')) || 0;

      const bbox = rectElement.getBoundingClientRect();

      const cursorOffsetX = e.clientX - bbox.left;
      const cursorOffsetY = e.clientY - bbox.top;

      const xOffset = width - borderSize;
      const yOffset = height - borderSize;

      const halfVertexMinusBorder = (vertexSize - borderSize) / 2;
      const halfVertexPlusBorder = (vertexSize + borderSize) / 2;

      const minX = -halfVertexMinusBorder;
      const maxX = halfVertexPlusBorder + xOffset;

      const minY = minX;
      const maxY = halfVertexPlusBorder + yOffset;

      if (cursorOffsetX < minX || cursorOffsetX > maxX || cursorOffsetY < minY || cursorOffsetY > maxY) {
        return;
      }

      const xSorted = [

        0,
        borderSize,
        halfVertexPlusBorder,
        -halfVertexMinusBorder + xOffset,
        width - borderSize,
        width

      ];

      const ySorted = [

        0,
        borderSize,
        halfVertexPlusBorder,
        -halfVertexMinusBorder + yOffset,
        height - borderSize,
        height

      ];

      let xi = 0;
      let yi = 0;

      for (; xi < 6 && cursorOffsetX >= xSorted[xi]; xi++) { }

      for (; yi < 6 && cursorOffsetY >= ySorted[yi]; yi++) { }

      this.action = ACTION_TABLE[yi][xi];

      if (this.action === NULL) {
        return;
      }

      this.startX = e.clientX;
      this.startY = e.clientY;

      this.currentRect = rect;
      this.startRect = { x: parseInt(rectStyle.left, 10), y: parseInt(rectStyle.top, 10), width, height };

      e.preventDefault();

      document.addEventListener('mousemove', this.boundOnMouseMove);
      document.addEventListener('mouseup', this.boundOnMouseUp);
    }

    onMouseMove(e) {
      if (!this.currentRect || this.isAnimating) return;
      this.isAnimating = true;

      const dx = e.clientX - this.startX;
      const dy = e.clientY - this.startY;

      if (this.action === MOVE) {
        this.moveRect(this.currentRect, this.startRect, dx, dy);
      } else {
        this.resizeRect(this.currentRect, this.startRect, dx, dy);
      }
    }

    moveRect(rect, startRect, dx, dy) {
      let {x, y} = startRect;
      x += dx;
      y += dy;

      requestAnimationFrame(() => {
        rect.update({ x, y });

        this.isAnimating = false;
      });
    }

    resizeRect(rect, startRect, dx, dy) {
      const action = this.action;

      const {x: startX, y: startY, width: startWidth, height: startHeight} = startRect;

      const width = Math.max(startWidth + WIDTH_CHANGE_TABLE[action] * dx, this.MIN_WIDTH);
      const height = Math.max(startHeight + HEIGHT_CHANGE_TABLE[action] * dy, this.MIN_HEIGHT);

      const x = startX + X_CHANGE_TABLE[action] * (startWidth - width);
      const y = startY + Y_CHANGE_TABLE[action] * (startHeight - height);

      requestAnimationFrame(() => {
        this.updateRect(rect, startRect, { x, y, width, height });

        this.isAnimating = false;
      });
    }

    updateRect(rect, startRect, newRect) {
      const updates = {};

      for (const key in newRect) {
        if (newRect[key] !== startRect[key]) {
          updates[key] = newRect[key];
        }
      }

      if (Object.keys(updates).length > 0) {
        rect.update(updates);
      }
    }

    onMouseUp() {

      document.removeEventListener('mousemove', this.boundOnMouseMove);
      document.removeEventListener('mouseup', this.boundOnMouseUp);

      this.currentRect = null;
      this.action = NULL;

      this.isAnimating = false;
    }
  }
})();
```
suggest better variable names especially `startRect`