UNPKG

dockview-core

Version:

Zero dependency layout manager supporting tabs, groups, grids and splitviews for vanilla TypeScript

169 lines (168 loc) 6.42 kB
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; } } }