UNPKG

dockview-core

Version:

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

219 lines (218 loc) 11.5 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 __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.FLOATING_REDOCK_INITIATION_DELAY_MS = exports.GroupDragSource = void 0; var dataTransfer_1 = require("../../../dnd/dataTransfer"); var backend_1 = require("../../../dnd/backend"); var events_1 = require("../../../events"); var lifecycle_1 = require("../../../lifecycle"); var dom_1 = require("../../../dom"); var dndCapabilities_1 = require("../../dndCapabilities"); // Floating-group redock via touch: require a deliberate long press so the // "move the float around" gesture doesn't double-trigger the redock ghost. // Infinity pressTolerance disables the pre-arm flick override; any motion // during the wait is treated as drag-the-float, not redock intent. var FLOATING_REDOCK_INITIATION_DELAY_MS = 500; exports.FLOATING_REDOCK_INITIATION_DELAY_MS = FLOATING_REDOCK_INITIATION_DELAY_MS; /** * The drag-source half of a group drag handle: html5 + pointer drag sources * that publish a group-level `PanelTransfer`, the "Multiple Panels (N)" ghost, * and the floating-group disambiguation that keeps the redock gesture from * firing alongside the overlay's move-the-float gesture. * * Shared by the tab-bar void container and the dedicated floating title bar so * both grab handles redock identically. */ var GroupDragSource = /** @class */ (function (_super) { __extends(GroupDragSource, _super); function GroupDragSource(options) { var _a, _b, _c; var _this = _super.call(this) || this; _this.panelTransfer = dataTransfer_1.LocalSelectionTransfer.getInstance(); _this._onDragStart = new events_1.Emitter(); _this.onDragStart = _this._onDragStart.event; _this._element = options.element; _this.accessor = options.accessor; var group = options.group; _this.groupAccessor = typeof group === 'function' ? group : function () { return group; }; _this.isFloatingMoveHandle = (_a = options.isFloatingMoveHandle) !== null && _a !== void 0 ? _a : (function () { return true; }); var caps = (0, dndCapabilities_1.resolveDndCapabilities)(_this.accessor.options); _this._element.draggable = caps.html5; (0, dom_1.toggleClass)(_this._element, 'dv-draggable', caps.html5 || caps.pointer); _this.addDisposables(_this._onDragStart); var buildMultiPanelsGhost = function () { var ghostEl = document.createElement('div'); var style = window.getComputedStyle(_this._element); var bgColor = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-background-color'); var color = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-color'); ghostEl.style.backgroundColor = bgColor; ghostEl.style.color = color; ghostEl.style.padding = '2px 8px'; ghostEl.style.height = '24px'; ghostEl.style.fontSize = '11px'; ghostEl.style.lineHeight = '20px'; ghostEl.style.borderRadius = '12px'; ghostEl.style.whiteSpace = 'nowrap'; ghostEl.style.boxSizing = 'border-box'; // HTML5 setDragImage snapshots the element as appended to the // document; a default block-level div would stretch to the // body's width and render as a viewport-wide bar. ghostEl.style.display = 'inline-block'; ghostEl.textContent = "Multiple Panels (".concat(_this.group.size, ")"); return ghostEl; }; var buildGhostSpec = function () { var _a, _b; // The custom-ghost resolution (createGroupDragGhostComponent) is // owned by the AdvancedDnD module; core keeps the default chip and // falls back to it when no custom ghost is produced (incl. when // the module is absent). var customGhost = (_b = (_a = _this.accessor).buildGroupDragGhost) === null || _b === void 0 ? void 0 : _b.call(_a, _this.group); if (customGhost) { return customGhost; } return { element: buildMultiPanelsGhost(), offsetX: 30, offsetY: -10, }; }; var sharedDragOptions = { getData: function () { _this.panelTransfer.setData([new dataTransfer_1.PanelTransfer(_this.accessor.id, _this.group.id, null)], dataTransfer_1.PanelTransfer.prototype); return { dispose: function () { _this.panelTransfer.clearData(dataTransfer_1.PanelTransfer.prototype); }, }; }, createGhost: buildGhostSpec, onDragStart: function (event) { _this._onDragStart.fire(event); }, }; _this.html5DragSource = backend_1.html5Backend.createDragSource(_this._element, __assign(__assign({}, sharedDragOptions), { disabled: !caps.html5, isCancelled: function (event) { // HTML5: when this element is the floating window's move // handle, redock needs shift+drag (otherwise click-and-drag // conflicts with moving the float). A non-move-handle (e.g. the // void container when a title bar moves the float) redocks with // a plain drag, like a group in the main grid. if (_this.group.api.location.type === 'floating' && _this.isFloatingMoveHandle() && !event.shiftKey) { return true; } if (_this.group.api.location.type === 'edge' && _this.group.size === 0) { return true; } return false; } })); // Only the move handle needs the touch disambiguation; other handles // redock with the normal grid press behaviour. var isFloating = function () { var _a, _b, _c; return ((_c = (_b = (_a = _this.group) === null || _a === void 0 ? void 0 : _a.api) === null || _b === void 0 ? void 0 : _b.location) === null || _c === void 0 ? void 0 : _c.type) === 'floating' && _this.isFloatingMoveHandle(); }; _this.pointerDragSource = backend_1.pointerBackend.createDragSource(_this._element, __assign(__assign({}, sharedDragOptions), { disabled: !caps.pointer, touchOnly: !caps.pointerHandlesMouse, // Floating groups share this element with the overlay's // move-the-float drag. Without a longer hold + tolerance // override, both gestures commit simultaneously and the // user sees the float follow their finger *and* a ghost. touchInitiationDelay: function () { return isFloating() ? FLOATING_REDOCK_INITIATION_DELAY_MS : 250; }, pressTolerance: function () { return (isFloating() ? Infinity : 8); }, isCancelled: function () { if (!(0, dndCapabilities_1.resolveDndCapabilities)(_this.accessor.options).pointer) { return true; } // Pointer: long-press IS the deliberate gesture, so // floating groups don't need the shift gate. if (_this.group.api.location.type === 'edge' && _this.group.size === 0) { return true; } return false; }, onDragStart: function (event) { var _a; // Redock just committed — abort any in-flight overlay // move so the float stops following the finger while // the ghost takes over. (_a = _this.getFloatingOverlay()) === null || _a === void 0 ? void 0 : _a.cancelPendingDrag(); _this._onDragStart.fire(event); } })); // Mirror direction: once the overlay's move-the-float gesture has // actually moved something, cancel the pending redock arm so the // ghost doesn't appear mid-drag if the user holds past 500ms. var overlayMoveSub = new lifecycle_1.MutableDisposable(); var refreshOverlayMoveSub = function () { var overlay = _this.getFloatingOverlay(); overlayMoveSub.value = overlay ? overlay.onDidStartMoving(function () { _this.pointerDragSource.cancelPending(); }) : lifecycle_1.Disposable.NONE; }; refreshOverlayMoveSub(); _this.addDisposables(overlayMoveSub); var locationChange = (_c = (_b = _this.group) === null || _b === void 0 ? void 0 : _b.api) === null || _c === void 0 ? void 0 : _c.onDidLocationChange; if (locationChange) { _this.addDisposables(locationChange(refreshOverlayMoveSub)); } _this.addDisposables(_this.html5DragSource, _this.pointerDragSource); return _this; } Object.defineProperty(GroupDragSource.prototype, "group", { // Resolved lazily so a retargetable handle (the floating title bar) always // drags the window's *current* anchor group, not the one captured here. get: function () { return this.groupAccessor(); }, enumerable: false, configurable: true }); GroupDragSource.prototype.updateDragAndDropState = function () { var caps = (0, dndCapabilities_1.resolveDndCapabilities)(this.accessor.options); this._element.draggable = caps.html5; (0, dom_1.toggleClass)(this._element, 'dv-draggable', caps.html5 || caps.pointer); this.html5DragSource.setDisabled(!caps.html5); this.pointerDragSource.setDisabled(!caps.pointer); this.pointerDragSource.setTouchOnly(!caps.pointerHandlesMouse); }; GroupDragSource.prototype.getFloatingOverlay = function () { var _this = this; var _a, _b; if (!this.group) { return undefined; } return (_b = (_a = this.accessor.floatingGroups) === null || _a === void 0 ? void 0 : _a.find(function (fg) { return fg.group === _this.group; })) === null || _b === void 0 ? void 0 : _b.overlay; }; return GroupDragSource; }(lifecycle_1.CompositeDisposable)); exports.GroupDragSource = GroupDragSource;