src/Plugins/ResizeMirror/ResizeMirror.js
import AbstractPlugin from 'shared/AbstractPlugin';
import {requestNextAnimationFrame} from 'shared/utils';
const onMirrorCreated = Symbol('onMirrorCreated');
const onMirrorDestroy = Symbol('onMirrorDestroy');
const onDragOver = Symbol('onDragOver');
const resize = Symbol('resize');
/**
* ResizeMirror default options
* @property {Object} defaultOptions
* @type {Object}
*/
export const defaultOptions = {};
/**
* The ResizeMirror plugin resizes the mirror element to the dimensions of the draggable element that the mirror is hovering over
* @class ResizeMirror
* @module ResizeMirror
* @extends AbstractPlugin
*/
export default class ResizeMirror extends AbstractPlugin {
/**
* ResizeMirror constructor.
* @constructs ResizeMirror
* @param {Draggable} draggable - Draggable instance
*/
constructor(draggable) {
super(draggable);
/**
* ResizeMirror options
* @property {Object} options
* @type {Object}
*/
this.options = {
...defaultOptions,
...this.getOptions(),
};
/**
* ResizeMirror remembers the last width when resizing the mirror
* to avoid additional writes to the DOM
* @property {number} lastWidth
*/
this.lastWidth = 0;
/**
* ResizeMirror remembers the last height when resizing the mirror
* to avoid additional writes to the DOM
* @property {number} lastHeight
*/
this.lastHeight = 0;
/**
* Keeps track of the mirror element
* @property {HTMLElement} mirror
*/
this.mirror = null;
this[onMirrorCreated] = this[onMirrorCreated].bind(this);
this[onMirrorDestroy] = this[onMirrorDestroy].bind(this);
this[onDragOver] = this[onDragOver].bind(this);
}
/**
* Attaches plugins event listeners
*/
attach() {
this.draggable
.on('mirror:created', this[onMirrorCreated])
.on('drag:over', this[onDragOver])
.on('drag:over:container', this[onDragOver]);
}
/**
* Detaches plugins event listeners
*/
detach() {
this.draggable
.off('mirror:created', this[onMirrorCreated])
.off('mirror:destroy', this[onMirrorDestroy])
.off('drag:over', this[onDragOver])
.off('drag:over:container', this[onDragOver]);
}
/**
* Returns options passed through draggable
* @return {Object}
*/
getOptions() {
return this.draggable.options.resizeMirror || {};
}
/**
* Mirror created handler
* @param {MirrorCreatedEvent} mirrorEvent
* @private
*/
[onMirrorCreated]({mirror}) {
this.mirror = mirror;
}
/**
* Mirror destroy handler
* @param {MirrorDestroyEvent} mirrorEvent
* @private
*/
[onMirrorDestroy]() {
this.mirror = null;
}
/**
* Drag over handler
* @param {DragOverEvent | DragOverContainer} dragEvent
* @private
*/
[onDragOver](dragEvent) {
this[resize](dragEvent);
}
/**
* Resize function for
* @param {DragOverEvent | DragOverContainer} dragEvent
* @private
*/
[resize]({overContainer, over}) {
requestAnimationFrame(() => {
if (!this.mirror.parentNode) {
return;
}
if (this.mirror.parentNode !== overContainer) {
overContainer.appendChild(this.mirror);
}
const overElement = over || this.draggable.getDraggableElementsForContainer(overContainer)[0];
if (!overElement) {
return;
}
requestNextAnimationFrame(() => {
const overRect = overElement.getBoundingClientRect();
if (this.lastHeight === overRect.height && this.lastWidth === overRect.width) {
return;
}
this.mirror.style.width = `${overRect.width}px`;
this.mirror.style.height = `${overRect.height}px`;
this.lastWidth = overRect.width;
this.lastHeight = overRect.height;
});
});
}
}