UNPKG

dockview-core

Version:

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

245 lines (244 loc) 12.8 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.VoidContainer = 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; var VoidContainer = /** @class */ (function (_super) { __extends(VoidContainer, _super); function VoidContainer(accessor, group) { var _a, _b; var _this = _super.call(this) || this; _this.accessor = accessor; _this.group = group; _this.panelTransfer = dataTransfer_1.LocalSelectionTransfer.getInstance(); _this._onDrop = new events_1.Emitter(); _this.onDrop = _this._onDrop.event; _this._onDragStart = new events_1.Emitter(); _this.onDragStart = _this._onDragStart.event; var caps = (0, dndCapabilities_1.resolveDndCapabilities)(_this.accessor.options); _this._element = document.createElement('div'); _this._element.className = 'dv-void-container'; _this._element.draggable = caps.html5; (0, dom_1.toggleClass)(_this._element, 'dv-draggable', caps.html5 || caps.pointer); _this.addDisposables(_this._onDrop, _this._onDragStart, (0, events_1.addDisposableListener)(_this._element, 'pointerdown', function () { _this.accessor.doSetGroupActive(_this.group); }), // Shift+pointerdown marks the event so the group's overlay // drag (move-by-floating) sees it was consumed and doesn't // fire alongside the HTML5 drag. quasiPreventDefault sets the // marker without calling preventDefault — that would also // block dragstart, which we need to fire. (0, events_1.addDisposableListener)(_this._element, 'pointerdown', function (e) { if (e.shiftKey) { (0, dom_1.quasiPreventDefault)(e); } }, true)); var canDisplayOverlay = function (event, position) { if (_this.group.api.locked) { // Dropping on the void/header space adds the panel // to this group, which `locked` is meant to prevent // (both `true` and `'no-drop-target'`). return false; } var data = (0, dataTransfer_1.getPanelData)(); if (data && _this.accessor.id === data.viewId) { return true; } return group.model.canDisplayOverlay(event, position, 'header_space'); }; _this.dropTarget = backend_1.html5Backend.createDropTarget(_this._element, { acceptedTargetZones: ['center'], canDisplayOverlay: canDisplayOverlay, getOverrideTarget: function () { var _a; return (_a = group.model.dropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; }, }); _this.pointerDropTarget = backend_1.pointerBackend.createDropTarget(_this._element, { acceptedTargetZones: ['center'], canDisplayOverlay: canDisplayOverlay, getOverrideTarget: function () { var _a; return (_a = group.model.dropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; }, }); 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 createGhost = _this.accessor.options.createGroupDragGhostComponent; if (createGhost) { var renderer_1 = createGhost(_this.group); renderer_1.init({ group: _this.group, api: _this.accessor.api, }); return { element: renderer_1.element, offsetX: 30, offsetY: -10, dispose: renderer_1.dispose ? function () { var _a; return (_a = renderer_1.dispose) === null || _a === void 0 ? void 0 : _a.call(renderer_1); } : undefined, }; } 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: floating groups need shift+drag as the explicit // detach gesture (otherwise click-and-drag conflicts with // moving the floating group itself). if (_this.group.api.location.type === 'floating' && !event.shiftKey) { return true; } if (_this.group.api.location.type === 'edge' && _this.group.size === 0) { return true; } return false; } })); 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.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 = (_b = (_a = _this.group) === null || _a === void 0 ? void 0 : _a.api) === null || _b === void 0 ? void 0 : _b.onDidLocationChange; if (locationChange) { _this.addDisposables(locationChange(refreshOverlayMoveSub)); } _this.onWillShowOverlay = events_1.Event.any(_this.dropTarget.onWillShowOverlay, _this.pointerDropTarget.onWillShowOverlay); _this.addDisposables(_this.html5DragSource, _this.dropTarget.onDrop(function (event) { _this._onDrop.fire(event); }), _this.pointerDropTarget.onDrop(function (event) { _this._onDrop.fire(event); }), _this.dropTarget, _this.pointerDropTarget, _this.pointerDragSource); return _this; } Object.defineProperty(VoidContainer.prototype, "element", { get: function () { return this._element; }, enumerable: false, configurable: true }); VoidContainer.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); }; VoidContainer.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 VoidContainer; }(lifecycle_1.CompositeDisposable)); exports.VoidContainer = VoidContainer;