UNPKG

dockview-core

Version:

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

152 lines (151 loc) 7.46 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.LongPressDetector = void 0; var events_1 = require("../../events"); var lifecycle_1 = require("../../lifecycle"); var DEFAULT_DELAY = 500; var DEFAULT_TOLERANCE = 8; /** * Passive — does not consume the pointer; movement past `tolerance` * cancels silently so a sibling `PointerDragSource` can take over. */ var LongPressDetector = /** @class */ (function (_super) { __extends(LongPressDetector, _super); function LongPressDetector(element, options) { var _this = _super.call(this) || this; _this.element = element; _this.options = options; _this._startX = 0; _this._startY = 0; _this.addDisposables((0, events_1.addDisposableListener)(_this.element, 'pointerdown', function (e) { _this._onPointerDown(e); })); return _this; } LongPressDetector.prototype._onPointerDown = function (event) { var _this = this; var _a, _b, _c, _d, _e; var touchOnly = (_a = this.options.touchOnly) !== null && _a !== void 0 ? _a : true; if (touchOnly && event.pointerType !== 'touch' && event.pointerType !== 'pen') { return; } // Defensive — supersede any in-flight press. this._cancelPending(); this._pointerId = event.pointerId; this._startX = event.clientX; this._startY = event.clientY; var delay = (_b = this.options.delay) !== null && _b !== void 0 ? _b : DEFAULT_DELAY; var tolerance = (_c = this.options.tolerance) !== null && _c !== void 0 ? _c : DEFAULT_TOLERANCE; // Source's owning window — popout drags fire on their own window. var targetWindow = (_e = (_d = this.element.ownerDocument) === null || _d === void 0 ? void 0 : _d.defaultView) !== null && _e !== void 0 ? _e : window; this._timer = setTimeout(function () { _this._timer = undefined; _this._cancelPending(); // Touch browsers synthesize a compatibility `contextmenu` event // for long-press. preventDefault on the original pointerdown is // too late (already dispatched), so install a one-shot // capture-phase guard for the next contextmenu. Without this, // consumers that don't preventDefault inside their onLongPress // (or that early-return before doing so) leak the browser's // native menu on top of theirs. _this._installContextMenuGuard(targetWindow); // Same idea for `click`: when the user releases their finger // after the long-press, touch browsers dispatch a `click` to // the element the touch ended on (the source). Consumers // typically wire click to a primary action (e.g. tab activate, // tab-group chip collapse-toggle). Without this guard, the // long-press immediately fires both the context menu AND the // primary action — and the action's side effects (e.g. a chip // collapse animation) read as a screen wobble while the menu // is supposed to be open. Scoped to the source element so // clicks on menu items elsewhere remain effective. _this._installClickGuard(targetWindow); _this.options.onLongPress(event); }, delay); this._moveListener = (0, events_1.addDisposableListener)(targetWindow, 'pointermove', function (moveEvent) { if (moveEvent.pointerId !== _this._pointerId) { return; } var dx = moveEvent.clientX - _this._startX; var dy = moveEvent.clientY - _this._startY; if (Math.hypot(dx, dy) > tolerance) { _this._cancelPending(); } }); this._upListener = (0, events_1.addDisposableListener)(targetWindow, 'pointerup', function (upEvent) { if (upEvent.pointerId !== _this._pointerId) { return; } _this._cancelPending(); }); this._cancelListener = (0, events_1.addDisposableListener)(targetWindow, 'pointercancel', function (cancelEvent) { if (cancelEvent.pointerId !== _this._pointerId) { return; } _this._cancelPending(); }); }; LongPressDetector.prototype._installContextMenuGuard = function (targetWindow) { var guard; var timeout = setTimeout(function () { return guard === null || guard === void 0 ? void 0 : guard.dispose(); }, 500); guard = (0, events_1.addDisposableListener)(targetWindow, 'contextmenu', function (event) { event.preventDefault(); clearTimeout(timeout); guard === null || guard === void 0 ? void 0 : guard.dispose(); }, { capture: true }); }; LongPressDetector.prototype._installClickGuard = function (targetWindow) { var _this = this; var guard; var timeout = setTimeout(function () { return guard === null || guard === void 0 ? void 0 : guard.dispose(); }, 500); guard = (0, events_1.addDisposableListener)(targetWindow, 'click', function (event) { // Only suppress clicks targeted at the long-pressed element // or its descendants. A user tap on a context menu item (or // anywhere else) still gets through unchanged. var target = event.target; if (target && _this.element.contains(target)) { event.preventDefault(); event.stopPropagation(); } clearTimeout(timeout); guard === null || guard === void 0 ? void 0 : guard.dispose(); }, { capture: true }); }; LongPressDetector.prototype._cancelPending = function () { var _a, _b, _c; if (this._timer !== undefined) { clearTimeout(this._timer); this._timer = undefined; } this._pointerId = undefined; (_a = this._moveListener) === null || _a === void 0 ? void 0 : _a.dispose(); (_b = this._upListener) === null || _b === void 0 ? void 0 : _b.dispose(); (_c = this._cancelListener) === null || _c === void 0 ? void 0 : _c.dispose(); this._moveListener = undefined; this._upListener = undefined; this._cancelListener = undefined; }; LongPressDetector.prototype.dispose = function () { this._cancelPending(); _super.prototype.dispose.call(this); }; return LongPressDetector; }(lifecycle_1.CompositeDisposable)); exports.LongPressDetector = LongPressDetector;