dockview-core
Version:
Zero dependency layout manager supporting tabs, groups, grids and splitviews for vanilla TypeScript
169 lines (168 loc) • 6.42 kB
JavaScript
import { Emitter } from '../../events';
import { CompositeDisposable } from '../../lifecycle';
import { createOverlayElements, renderAnchoredOverlay, renderInPlaceOverlay, } from '../dropOverlay';
import { calculateQuadrantAsPercentage, calculateQuadrantAsPixels, WillShowOverlayEvent, } from '../droptarget';
import { PointerDragController } from './pointerDragController';
const DEFAULT_ACTIVATION_SIZE = {
value: 20,
type: 'percentage',
};
/** Pointer-driven counterpart to `Droptarget` with identical visual output. */
export class PointerDropTarget extends CompositeDisposable {
get disabled() {
return this._disabled;
}
set disabled(value) {
this._disabled = value;
if (value) {
this._removeOverlay();
}
}
get state() {
return this._state;
}
constructor(element, options) {
super();
this.element = element;
this.options = options;
this._onDrop = new Emitter();
this.onDrop = this._onDrop.event;
this._onWillShowOverlay = new Emitter();
this.onWillShowOverlay = this._onWillShowOverlay.event;
this._disabled = false;
this._acceptedTargetZonesSet = new Set(options.acceptedTargetZones);
const handle = {
element: this.element,
handleDragOver: (e) => this._onDragOver(e),
handleDragLeave: () => this._onDragLeave(),
handleDrop: (e) => this._onDropEvent(e),
};
this.addDisposables(this._onDrop, this._onWillShowOverlay, PointerDragController.getInstance().registerTarget(handle));
}
setTargetZones(zones) {
this._acceptedTargetZonesSet = new Set(zones);
}
setOverlayModel(model) {
this.options.overlayModel = model;
}
dispose() {
this._removeOverlay();
super.dispose();
}
_onDragOver(event) {
var _a, _b, _c, _d, _e;
if (this._disabled) {
this._removeOverlay();
return;
}
const overrideTarget = (_b = (_a = this.options).getOverrideTarget) === null || _b === void 0 ? void 0 : _b.call(_a);
if (this._acceptedTargetZonesSet.size === 0) {
if (overrideTarget) {
return;
}
this._removeOverlay();
return;
}
const outlineEl = (_e = (_d = (_c = this.options).getOverlayOutline) === null || _d === void 0 ? void 0 : _d.call(_c)) !== null && _e !== void 0 ? _e : this.element;
const width = outlineEl.offsetWidth;
const height = outlineEl.offsetHeight;
if (width === 0 || height === 0) {
return;
}
const rect = outlineEl.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
const quadrant = this._calculateQuadrant(x, y, width, height);
if (quadrant === null) {
this._removeOverlay();
return;
}
if (!this.options.canDisplayOverlay(event.pointerEvent, quadrant)) {
if (overrideTarget) {
return;
}
this._removeOverlay();
return;
}
const willShow = new WillShowOverlayEvent({
nativeEvent: event.pointerEvent,
position: quadrant,
});
this._onWillShowOverlay.fire(willShow);
if (willShow.defaultPrevented) {
this._removeOverlay();
return;
}
if (overrideTarget) {
renderAnchoredOverlay({
outlineElement: outlineEl,
targetModel: overrideTarget,
quadrant,
width,
height,
overlayModel: this.options.overlayModel,
className: this.options.className,
});
this._state = quadrant;
return;
}
if (!this._targetElement) {
const els = createOverlayElements();
this._targetElement = els.dropzone;
this._overlayElement = els.selection;
this._state = 'center';
this.element.classList.add('dv-drop-target');
this.element.append(this._targetElement);
}
if (this._overlayElement) {
renderInPlaceOverlay(this._overlayElement, quadrant, width, height, this.options.overlayModel);
}
this._state = quadrant;
}
_onDragLeave() {
var _a, _b;
const overrideTarget = (_b = (_a = this.options).getOverrideTarget) === null || _b === void 0 ? void 0 : _b.call(_a);
// Anchor target owns its own lifecycle; just clear our latched
// state so a subsequent pointerup doesn't fire a stale drop.
if (overrideTarget) {
this._state = undefined;
overrideTarget.clear();
return;
}
this._removeOverlay();
}
_onDropEvent(event) {
var _a, _b;
const state = this._state;
const overrideTarget = (_b = (_a = this.options).getOverrideTarget) === null || _b === void 0 ? void 0 : _b.call(_a);
this._removeOverlay();
overrideTarget === null || overrideTarget === void 0 ? void 0 : overrideTarget.clear();
if (state) {
this._onDrop.fire({
position: state,
nativeEvent: event.pointerEvent,
});
}
}
_calculateQuadrant(x, y, width, height) {
var _a, _b;
const activation = (_b = (_a = this.options.overlayModel) === null || _a === void 0 ? void 0 : _a.activationSize) !== null && _b !== void 0 ? _b : DEFAULT_ACTIVATION_SIZE;
if (activation.type === 'percentage') {
return calculateQuadrantAsPercentage(this._acceptedTargetZonesSet, x, y, width, height, activation.value);
}
return calculateQuadrantAsPixels(this._acceptedTargetZonesSet, x, y, width, height, activation.value);
}
_removeOverlay() {
var _a;
if (this._targetElement) {
this._state = undefined;
(_a = this._targetElement.parentElement) === null || _a === void 0 ? void 0 : _a.classList.remove('dv-drop-target');
this._targetElement.remove();
this._targetElement = undefined;
this._overlayElement = undefined;
}
else {
this._state = undefined;
}
}
}