dockview-core
Version:
Zero dependency layout manager supporting tabs, groups, grids and splitviews for vanilla TypeScript
245 lines (244 loc) • 12.8 kB
JavaScript
;
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;