dockview-core 6.3.0 → 6.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/cjs/dnd/backend.d.ts +70 -0
- package/dist/cjs/dnd/backend.js +171 -0
- package/dist/cjs/dnd/dropOverlay.d.ts +20 -0
- package/dist/cjs/dnd/dropOverlay.js +197 -0
- package/dist/cjs/dnd/droptarget.d.ts +20 -6
- package/dist/cjs/dnd/droptarget.js +14 -208
- package/dist/cjs/dnd/pointer/index.d.ts +11 -0
- package/dist/cjs/dnd/pointer/index.js +13 -0
- package/dist/cjs/dnd/pointer/longPress.d.ts +32 -0
- package/dist/cjs/dnd/pointer/longPress.js +151 -0
- package/dist/cjs/dnd/pointer/pointerDragController.d.ts +60 -0
- package/dist/cjs/dnd/pointer/pointerDragController.js +241 -0
- package/dist/cjs/dnd/pointer/pointerDragSource.d.ts +61 -0
- package/dist/cjs/dnd/pointer/pointerDragSource.js +195 -0
- package/dist/cjs/dnd/pointer/pointerDropTarget.d.ts +39 -0
- package/dist/cjs/dnd/pointer/pointerDropTarget.js +198 -0
- package/dist/cjs/dnd/pointer/pointerGhost.d.ts +30 -0
- package/dist/cjs/dnd/pointer/pointerGhost.js +44 -0
- package/dist/cjs/dnd/pointer/types.d.ts +16 -0
- package/dist/cjs/dnd/pointer/types.js +2 -0
- package/dist/cjs/dockview/components/panel/content.d.ts +3 -1
- package/dist/cjs/dockview/components/panel/content.js +33 -16
- package/dist/cjs/dockview/components/popupService.js +34 -0
- package/dist/cjs/dockview/components/tab/tab.d.ts +11 -3
- package/dist/cjs/dockview/components/tab/tab.js +151 -117
- package/dist/cjs/dockview/components/titlebar/tabGroupChip.d.ts +9 -2
- package/dist/cjs/dockview/components/titlebar/tabGroupChip.js +15 -6
- package/dist/cjs/dockview/components/titlebar/tabGroups.d.ts +33 -5
- package/dist/cjs/dockview/components/titlebar/tabGroups.js +231 -40
- package/dist/cjs/dockview/components/titlebar/tabs.d.ts +38 -1
- package/dist/cjs/dockview/components/titlebar/tabs.js +372 -251
- package/dist/cjs/dockview/components/titlebar/tabsContainer.d.ts +5 -3
- package/dist/cjs/dockview/components/titlebar/voidContainer.d.ts +6 -2
- package/dist/cjs/dockview/components/titlebar/voidContainer.js +189 -27
- package/dist/cjs/dockview/contextMenu.js +19 -4
- package/dist/cjs/dockview/dndCapabilities.d.ts +19 -0
- package/dist/cjs/dockview/dndCapabilities.js +39 -0
- package/dist/cjs/dockview/dockviewComponent.d.ts +1 -0
- package/dist/cjs/dockview/dockviewComponent.js +54 -33
- package/dist/cjs/dockview/dockviewGroupPanelModel.d.ts +9 -5
- package/dist/cjs/dockview/dockviewGroupPanelModel.js +25 -11
- package/dist/cjs/dockview/events.d.ts +2 -1
- package/dist/cjs/dockview/events.js +1 -0
- package/dist/cjs/dockview/options.d.ts +18 -3
- package/dist/cjs/dockview/options.js +1 -0
- package/dist/cjs/dom.js +7 -3
- package/dist/cjs/overlay/overlay.d.ts +12 -0
- package/dist/cjs/overlay/overlay.js +84 -16
- package/dist/cjs/paneview/draggablePaneviewPanel.d.ts +3 -1
- package/dist/cjs/paneview/draggablePaneviewPanel.js +27 -26
- package/dist/cjs/paneview/options.d.ts +4 -3
- package/dist/dockview-core.js +2199 -834
- package/dist/dockview-core.min.js +2 -2
- package/dist/dockview-core.min.js.map +1 -1
- package/dist/dockview-core.min.noStyle.js +2 -2
- package/dist/dockview-core.min.noStyle.js.map +1 -1
- package/dist/dockview-core.noStyle.js +2202 -837
- package/dist/esm/dnd/backend.d.ts +70 -0
- package/dist/esm/dnd/backend.js +148 -0
- package/dist/esm/dnd/dropOverlay.d.ts +20 -0
- package/dist/esm/dnd/dropOverlay.js +192 -0
- package/dist/esm/dnd/droptarget.d.ts +20 -6
- package/dist/esm/dnd/droptarget.js +16 -210
- package/dist/esm/dnd/pointer/index.d.ts +11 -0
- package/dist/esm/dnd/pointer/index.js +5 -0
- package/dist/esm/dnd/pointer/longPress.d.ts +32 -0
- package/dist/esm/dnd/pointer/longPress.js +127 -0
- package/dist/esm/dnd/pointer/pointerDragController.d.ts +60 -0
- package/dist/esm/dnd/pointer/pointerDragController.js +191 -0
- package/dist/esm/dnd/pointer/pointerDragSource.d.ts +61 -0
- package/dist/esm/dnd/pointer/pointerDragSource.js +171 -0
- package/dist/esm/dnd/pointer/pointerDropTarget.d.ts +39 -0
- package/dist/esm/dnd/pointer/pointerDropTarget.js +168 -0
- package/dist/esm/dnd/pointer/pointerGhost.d.ts +30 -0
- package/dist/esm/dnd/pointer/pointerGhost.js +39 -0
- package/dist/esm/dnd/pointer/types.d.ts +16 -0
- package/dist/esm/dnd/pointer/types.js +1 -0
- package/dist/esm/dockview/components/panel/content.d.ts +3 -1
- package/dist/esm/dockview/components/panel/content.js +33 -16
- package/dist/esm/dockview/components/popupService.js +34 -0
- package/dist/esm/dockview/components/tab/tab.d.ts +11 -3
- package/dist/esm/dockview/components/tab/tab.js +139 -114
- package/dist/esm/dockview/components/titlebar/tabGroupChip.d.ts +9 -2
- package/dist/esm/dockview/components/titlebar/tabGroupChip.js +15 -6
- package/dist/esm/dockview/components/titlebar/tabGroups.d.ts +33 -5
- package/dist/esm/dockview/components/titlebar/tabGroups.js +177 -12
- package/dist/esm/dockview/components/titlebar/tabs.d.ts +38 -1
- package/dist/esm/dockview/components/titlebar/tabs.js +348 -227
- package/dist/esm/dockview/components/titlebar/tabsContainer.d.ts +5 -3
- package/dist/esm/dockview/components/titlebar/voidContainer.d.ts +6 -2
- package/dist/esm/dockview/components/titlebar/voidContainer.js +179 -31
- package/dist/esm/dockview/contextMenu.js +19 -4
- package/dist/esm/dockview/dndCapabilities.d.ts +19 -0
- package/dist/esm/dockview/dndCapabilities.js +36 -0
- package/dist/esm/dockview/dockviewComponent.d.ts +1 -0
- package/dist/esm/dockview/dockviewComponent.js +55 -34
- package/dist/esm/dockview/dockviewGroupPanelModel.d.ts +9 -5
- package/dist/esm/dockview/dockviewGroupPanelModel.js +24 -11
- package/dist/esm/dockview/events.d.ts +2 -1
- package/dist/esm/dockview/events.js +1 -0
- package/dist/esm/dockview/options.d.ts +18 -3
- package/dist/esm/dockview/options.js +1 -0
- package/dist/esm/dom.js +7 -3
- package/dist/esm/overlay/overlay.d.ts +12 -0
- package/dist/esm/overlay/overlay.js +85 -17
- package/dist/esm/paneview/draggablePaneviewPanel.d.ts +3 -1
- package/dist/esm/paneview/draggablePaneviewPanel.js +26 -20
- package/dist/esm/paneview/options.d.ts +4 -3
- package/dist/package/main.cjs.js +2202 -837
- package/dist/package/main.cjs.min.js +2 -2
- package/dist/package/main.esm.min.mjs +2 -2
- package/dist/package/main.esm.mjs +2202 -837
- package/dist/styles/dockview.css +117 -1
- package/package.json +3 -1
- package/dist/cjs/dnd/abstractDragHandler.d.ts +0 -14
- package/dist/cjs/dnd/abstractDragHandler.js +0 -86
- package/dist/cjs/dnd/groupDragHandler.d.ts +0 -12
- package/dist/cjs/dnd/groupDragHandler.js +0 -104
- package/dist/esm/dnd/abstractDragHandler.d.ts +0 -14
- package/dist/esm/dnd/abstractDragHandler.js +0 -63
- package/dist/esm/dnd/groupDragHandler.d.ts +0 -12
- package/dist/esm/dnd/groupDragHandler.js +0 -81
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* dockview-core
|
|
3
|
-
* @version 6.
|
|
3
|
+
* @version 6.5.0
|
|
4
4
|
* @link https://github.com/mathuo/dockview
|
|
5
5
|
* @license MIT
|
|
6
6
|
*/
|
|
@@ -545,7 +545,7 @@ function addTestId(element, id) {
|
|
|
545
545
|
* Should be more efficient than element.querySelectorAll("*") since there
|
|
546
546
|
* is no need to store every element in-memory using this approach
|
|
547
547
|
*/
|
|
548
|
-
function allTagsNamesInclusiveOfShadowDoms(tagNames) {
|
|
548
|
+
function allTagsNamesInclusiveOfShadowDoms(tagNames, rootNode) {
|
|
549
549
|
const iframes = [];
|
|
550
550
|
function findIframesInNode(node) {
|
|
551
551
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
@@ -560,11 +560,15 @@ function allTagsNamesInclusiveOfShadowDoms(tagNames) {
|
|
|
560
560
|
}
|
|
561
561
|
}
|
|
562
562
|
}
|
|
563
|
-
|
|
563
|
+
// Document → walk from its root element. Element → walk from itself.
|
|
564
|
+
const startEl = rootNode instanceof Document
|
|
565
|
+
? rootNode.documentElement
|
|
566
|
+
: rootNode;
|
|
567
|
+
findIframesInNode(startEl);
|
|
564
568
|
return iframes;
|
|
565
569
|
}
|
|
566
570
|
function disableIframePointEvents(rootNode = document) {
|
|
567
|
-
const iframes = allTagsNamesInclusiveOfShadowDoms(['IFRAME', 'WEBVIEW']);
|
|
571
|
+
const iframes = allTagsNamesInclusiveOfShadowDoms(['IFRAME', 'WEBVIEW'], rootNode);
|
|
568
572
|
const original = new WeakMap(); // don't hold onto HTMLElement references longer than required
|
|
569
573
|
for (const iframe of iframes) {
|
|
570
574
|
original.set(iframe, iframe.style.pointerEvents);
|
|
@@ -3984,67 +3988,6 @@ class DockviewApi {
|
|
|
3984
3988
|
}
|
|
3985
3989
|
}
|
|
3986
3990
|
|
|
3987
|
-
class DragHandler extends CompositeDisposable {
|
|
3988
|
-
constructor(el, disabled) {
|
|
3989
|
-
super();
|
|
3990
|
-
this.el = el;
|
|
3991
|
-
this.disabled = disabled;
|
|
3992
|
-
this.dataDisposable = new MutableDisposable();
|
|
3993
|
-
this.pointerEventsDisposable = new MutableDisposable();
|
|
3994
|
-
this._onDragStart = new Emitter();
|
|
3995
|
-
this.onDragStart = this._onDragStart.event;
|
|
3996
|
-
this.addDisposables(this._onDragStart, this.dataDisposable, this.pointerEventsDisposable);
|
|
3997
|
-
this.configure();
|
|
3998
|
-
}
|
|
3999
|
-
setDisabled(disabled) {
|
|
4000
|
-
this.disabled = disabled;
|
|
4001
|
-
}
|
|
4002
|
-
isCancelled(_event) {
|
|
4003
|
-
return false;
|
|
4004
|
-
}
|
|
4005
|
-
configure() {
|
|
4006
|
-
this.addDisposables(this._onDragStart, addDisposableListener(this.el, 'dragstart', (event) => {
|
|
4007
|
-
if (event.defaultPrevented ||
|
|
4008
|
-
this.isCancelled(event) ||
|
|
4009
|
-
this.disabled) {
|
|
4010
|
-
event.preventDefault();
|
|
4011
|
-
return;
|
|
4012
|
-
}
|
|
4013
|
-
const iframes = disableIframePointEvents();
|
|
4014
|
-
this.pointerEventsDisposable.value = {
|
|
4015
|
-
dispose: () => {
|
|
4016
|
-
iframes.release();
|
|
4017
|
-
},
|
|
4018
|
-
};
|
|
4019
|
-
this.el.classList.add('dv-dragged');
|
|
4020
|
-
setTimeout(() => this.el.classList.remove('dv-dragged'), 0);
|
|
4021
|
-
this.dataDisposable.value = this.getData(event);
|
|
4022
|
-
this._onDragStart.fire(event);
|
|
4023
|
-
if (event.dataTransfer) {
|
|
4024
|
-
event.dataTransfer.effectAllowed = 'move';
|
|
4025
|
-
const hasData = event.dataTransfer.items.length > 0;
|
|
4026
|
-
if (!hasData) {
|
|
4027
|
-
/**
|
|
4028
|
-
* Although this is not used by dockview many third party dnd libraries will check
|
|
4029
|
-
* dataTransfer.types to determine valid drag events.
|
|
4030
|
-
*
|
|
4031
|
-
* For example: in react-dnd if dataTransfer.types is not set then the dragStart event will be cancelled
|
|
4032
|
-
* through .preventDefault(). Since this is applied globally to all drag events this would break dockviews
|
|
4033
|
-
* dnd logic. You can see the code at
|
|
4034
|
-
P * https://github.com/react-dnd/react-dnd/blob/main/packages/backend-html5/src/HTML5BackendImpl.ts#L542
|
|
4035
|
-
*/
|
|
4036
|
-
event.dataTransfer.setData('text/plain', '');
|
|
4037
|
-
}
|
|
4038
|
-
}
|
|
4039
|
-
}), addDisposableListener(this.el, 'dragend', () => {
|
|
4040
|
-
this.pointerEventsDisposable.dispose();
|
|
4041
|
-
setTimeout(() => {
|
|
4042
|
-
this.dataDisposable.dispose(); // allow the data to be read by other handlers before disposing
|
|
4043
|
-
}, 0);
|
|
4044
|
-
}));
|
|
4045
|
-
}
|
|
4046
|
-
}
|
|
4047
|
-
|
|
4048
3991
|
class DragAndDropObserver extends CompositeDisposable {
|
|
4049
3992
|
constructor(element, callbacks) {
|
|
4050
3993
|
super();
|
|
@@ -4095,48 +4038,197 @@ class DragAndDropObserver extends CompositeDisposable {
|
|
|
4095
4038
|
}
|
|
4096
4039
|
}
|
|
4097
4040
|
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
const
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4041
|
+
// Two render paths: in-place (dropzone appended to drop element) and
|
|
4042
|
+
// anchored (overlay rendered into an external anchor container).
|
|
4043
|
+
const DEFAULT_SIZE = { value: 50, type: 'percentage' };
|
|
4044
|
+
const SMALL_WIDTH_BOUNDARY = 100;
|
|
4045
|
+
const SMALL_HEIGHT_BOUNDARY = 100;
|
|
4046
|
+
function createOverlayElements() {
|
|
4047
|
+
const dropzone = document.createElement('div');
|
|
4048
|
+
dropzone.className = 'dv-drop-target-dropzone';
|
|
4049
|
+
const selection = document.createElement('div');
|
|
4050
|
+
selection.className = 'dv-drop-target-selection';
|
|
4051
|
+
dropzone.appendChild(selection);
|
|
4052
|
+
return { dropzone, selection };
|
|
4053
|
+
}
|
|
4054
|
+
function computeOverlayShape(quadrant, width, height, overlayModel) {
|
|
4055
|
+
var _a, _b, _c;
|
|
4056
|
+
const smallWidthBoundary = (_a = overlayModel === null || overlayModel === void 0 ? void 0 : overlayModel.smallWidthBoundary) !== null && _a !== void 0 ? _a : SMALL_WIDTH_BOUNDARY;
|
|
4057
|
+
const smallHeightBoundary = (_b = overlayModel === null || overlayModel === void 0 ? void 0 : overlayModel.smallHeightBoundary) !== null && _b !== void 0 ? _b : SMALL_HEIGHT_BOUNDARY;
|
|
4058
|
+
const isSmallX = width < smallWidthBoundary;
|
|
4059
|
+
const isSmallY = height < smallHeightBoundary;
|
|
4060
|
+
const isLeft = quadrant === 'left';
|
|
4061
|
+
const isRight = quadrant === 'right';
|
|
4062
|
+
const isTop = quadrant === 'top';
|
|
4063
|
+
const isBottom = quadrant === 'bottom';
|
|
4064
|
+
const rightClass = !isSmallX && isRight;
|
|
4065
|
+
const leftClass = !isSmallX && isLeft;
|
|
4066
|
+
const topClass = !isSmallY && isTop;
|
|
4067
|
+
const bottomClass = !isSmallY && isBottom;
|
|
4068
|
+
let size = 1;
|
|
4069
|
+
const sizeOptions = (_c = overlayModel === null || overlayModel === void 0 ? void 0 : overlayModel.size) !== null && _c !== void 0 ? _c : DEFAULT_SIZE;
|
|
4070
|
+
if (sizeOptions.type === 'percentage') {
|
|
4071
|
+
size = clamp(sizeOptions.value, 0, 100) / 100;
|
|
4072
|
+
}
|
|
4073
|
+
else {
|
|
4074
|
+
if (rightClass || leftClass) {
|
|
4075
|
+
size = clamp(0, sizeOptions.value, width) / width;
|
|
4076
|
+
}
|
|
4077
|
+
if (topClass || bottomClass) {
|
|
4078
|
+
size = clamp(0, sizeOptions.value, height) / height;
|
|
4079
|
+
}
|
|
4080
|
+
}
|
|
4081
|
+
return {
|
|
4082
|
+
isSmallX,
|
|
4083
|
+
isSmallY,
|
|
4084
|
+
isLeft,
|
|
4085
|
+
isRight,
|
|
4086
|
+
isTop,
|
|
4087
|
+
isBottom,
|
|
4088
|
+
rightClass,
|
|
4089
|
+
leftClass,
|
|
4090
|
+
topClass,
|
|
4091
|
+
bottomClass,
|
|
4092
|
+
size,
|
|
4093
|
+
};
|
|
4094
|
+
}
|
|
4095
|
+
function renderInPlaceOverlay(overlay, quadrant, width, height, overlayModel) {
|
|
4096
|
+
const shape = computeOverlayShape(quadrant, width, height, overlayModel);
|
|
4097
|
+
const { rightClass, leftClass, topClass, bottomClass, size } = shape;
|
|
4098
|
+
const box = { top: '0px', left: '0px', width: '100%', height: '100%' };
|
|
4099
|
+
if (rightClass) {
|
|
4100
|
+
box.left = `${100 * (1 - size)}%`;
|
|
4101
|
+
box.width = `${100 * size}%`;
|
|
4102
|
+
}
|
|
4103
|
+
else if (leftClass) {
|
|
4104
|
+
box.width = `${100 * size}%`;
|
|
4105
|
+
}
|
|
4106
|
+
else if (topClass) {
|
|
4107
|
+
box.height = `${100 * size}%`;
|
|
4108
|
+
}
|
|
4109
|
+
else if (bottomClass) {
|
|
4110
|
+
box.top = `${100 * (1 - size)}%`;
|
|
4111
|
+
box.height = `${100 * size}%`;
|
|
4112
|
+
}
|
|
4113
|
+
if (shape.isSmallX && shape.isLeft) {
|
|
4114
|
+
box.width = '4px';
|
|
4115
|
+
}
|
|
4116
|
+
if (shape.isSmallX && shape.isRight) {
|
|
4117
|
+
box.left = `${width - 4}px`;
|
|
4118
|
+
box.width = '4px';
|
|
4119
|
+
}
|
|
4120
|
+
if (shape.isSmallY && shape.isTop) {
|
|
4121
|
+
box.height = '4px';
|
|
4122
|
+
}
|
|
4123
|
+
if (shape.isSmallY && shape.isBottom) {
|
|
4124
|
+
box.top = `${height - 4}px`;
|
|
4125
|
+
box.height = '4px';
|
|
4126
|
+
}
|
|
4127
|
+
overlay.style.top = box.top;
|
|
4128
|
+
overlay.style.left = box.left;
|
|
4129
|
+
overlay.style.width = box.width;
|
|
4130
|
+
overlay.style.height = box.height;
|
|
4131
|
+
overlay.style.visibility = 'visible';
|
|
4132
|
+
if (!overlay.style.transform || overlay.style.transform === '') {
|
|
4133
|
+
overlay.style.transform = 'translate3d(0, 0, 0)';
|
|
4134
|
+
}
|
|
4135
|
+
const isLine = (shape.isSmallX && (shape.isLeft || shape.isRight)) ||
|
|
4136
|
+
(shape.isSmallY && (shape.isTop || shape.isBottom));
|
|
4137
|
+
toggleClass(overlay, 'dv-drop-target-small-vertical', shape.isSmallY);
|
|
4138
|
+
toggleClass(overlay, 'dv-drop-target-small-horizontal', shape.isSmallX);
|
|
4139
|
+
toggleClass(overlay, 'dv-drop-target-selection-line', isLine);
|
|
4140
|
+
toggleClass(overlay, 'dv-drop-target-left', shape.isLeft);
|
|
4141
|
+
toggleClass(overlay, 'dv-drop-target-right', shape.isRight);
|
|
4142
|
+
toggleClass(overlay, 'dv-drop-target-top', shape.isTop);
|
|
4143
|
+
toggleClass(overlay, 'dv-drop-target-bottom', shape.isBottom);
|
|
4144
|
+
toggleClass(overlay, 'dv-drop-target-center', quadrant === 'center');
|
|
4145
|
+
}
|
|
4146
|
+
function checkAnchoredBoundsChanged(overlay, bounds) {
|
|
4147
|
+
const topPx = `${Math.round(bounds.top)}px`;
|
|
4148
|
+
const leftPx = `${Math.round(bounds.left)}px`;
|
|
4149
|
+
const widthPx = `${Math.round(bounds.width)}px`;
|
|
4150
|
+
const heightPx = `${Math.round(bounds.height)}px`;
|
|
4151
|
+
return (overlay.style.top !== topPx ||
|
|
4152
|
+
overlay.style.left !== leftPx ||
|
|
4153
|
+
overlay.style.width !== widthPx ||
|
|
4154
|
+
overlay.style.height !== heightPx);
|
|
4155
|
+
}
|
|
4156
|
+
function applyAnchoredBounds(overlay, bounds) {
|
|
4157
|
+
overlay.style.top = `${Math.round(bounds.top)}px`;
|
|
4158
|
+
overlay.style.left = `${Math.round(bounds.left)}px`;
|
|
4159
|
+
overlay.style.width = `${Math.round(bounds.width)}px`;
|
|
4160
|
+
overlay.style.height = `${Math.round(bounds.height)}px`;
|
|
4161
|
+
overlay.style.visibility = 'visible';
|
|
4162
|
+
if (!overlay.style.transform || overlay.style.transform === '') {
|
|
4163
|
+
overlay.style.transform = 'translate3d(0, 0, 0)';
|
|
4164
|
+
}
|
|
4165
|
+
}
|
|
4166
|
+
/** `boundsChanged: false` lets callers skip redundant work on tight drag loops. */
|
|
4167
|
+
function renderAnchoredOverlay(args) {
|
|
4168
|
+
const shape = computeOverlayShape(args.quadrant, args.width, args.height, args.overlayModel);
|
|
4169
|
+
const { rightClass, leftClass, topClass, bottomClass, size } = shape;
|
|
4170
|
+
const elBox = args.outlineElement.getBoundingClientRect();
|
|
4171
|
+
const ta = args.targetModel.getElements(undefined, args.outlineElement);
|
|
4172
|
+
const el = ta.root;
|
|
4173
|
+
const overlay = ta.overlay;
|
|
4174
|
+
const bigbox = el.getBoundingClientRect();
|
|
4175
|
+
const rootTop = elBox.top - bigbox.top;
|
|
4176
|
+
const rootLeft = elBox.left - bigbox.left;
|
|
4177
|
+
const box = {
|
|
4178
|
+
top: rootTop,
|
|
4179
|
+
left: rootLeft,
|
|
4180
|
+
width: args.width,
|
|
4181
|
+
height: args.height,
|
|
4182
|
+
};
|
|
4183
|
+
if (rightClass) {
|
|
4184
|
+
box.left = rootLeft + args.width * (1 - size);
|
|
4185
|
+
box.width = args.width * size;
|
|
4186
|
+
}
|
|
4187
|
+
else if (leftClass) {
|
|
4188
|
+
box.width = args.width * size;
|
|
4189
|
+
}
|
|
4190
|
+
else if (topClass) {
|
|
4191
|
+
box.height = args.height * size;
|
|
4192
|
+
}
|
|
4193
|
+
else if (bottomClass) {
|
|
4194
|
+
box.top = rootTop + args.height * (1 - size);
|
|
4195
|
+
box.height = args.height * size;
|
|
4196
|
+
}
|
|
4197
|
+
if (shape.isSmallX && shape.isLeft) {
|
|
4198
|
+
box.width = 4;
|
|
4199
|
+
}
|
|
4200
|
+
if (shape.isSmallX && shape.isRight) {
|
|
4201
|
+
box.left = rootLeft + args.width - 4;
|
|
4202
|
+
box.width = 4;
|
|
4203
|
+
}
|
|
4204
|
+
if (shape.isSmallY && shape.isTop) {
|
|
4205
|
+
box.height = 4;
|
|
4206
|
+
}
|
|
4207
|
+
if (shape.isSmallY && shape.isBottom) {
|
|
4208
|
+
box.top = rootTop + args.height - 4;
|
|
4209
|
+
box.height = 4;
|
|
4210
|
+
}
|
|
4211
|
+
if (!checkAnchoredBoundsChanged(overlay, box)) {
|
|
4212
|
+
return { boundsChanged: false, targetChanged: ta.changed };
|
|
4213
|
+
}
|
|
4214
|
+
applyAnchoredBounds(overlay, box);
|
|
4215
|
+
overlay.className = `dv-drop-target-anchor${args.className ? ` ${args.className}` : ''}`;
|
|
4216
|
+
toggleClass(overlay, 'dv-drop-target-left', shape.isLeft);
|
|
4217
|
+
toggleClass(overlay, 'dv-drop-target-right', shape.isRight);
|
|
4218
|
+
toggleClass(overlay, 'dv-drop-target-top', shape.isTop);
|
|
4219
|
+
toggleClass(overlay, 'dv-drop-target-bottom', shape.isBottom);
|
|
4220
|
+
toggleClass(overlay, 'dv-drop-target-anchor-line', (shape.isSmallX && (shape.isLeft || shape.isRight)) ||
|
|
4221
|
+
(shape.isSmallY && (shape.isTop || shape.isBottom)));
|
|
4222
|
+
toggleClass(overlay, 'dv-drop-target-center', args.quadrant === 'center');
|
|
4223
|
+
if (ta.changed) {
|
|
4224
|
+
toggleClass(overlay, 'dv-drop-target-anchor-container-changed', true);
|
|
4225
|
+
setTimeout(() => {
|
|
4226
|
+
toggleClass(overlay, 'dv-drop-target-anchor-container-changed', false);
|
|
4227
|
+
}, 10);
|
|
4228
|
+
}
|
|
4229
|
+
return { boundsChanged: true, targetChanged: ta.changed };
|
|
4139
4230
|
}
|
|
4231
|
+
|
|
4140
4232
|
class WillShowOverlayEvent extends DockviewEvent {
|
|
4141
4233
|
get nativeEvent() {
|
|
4142
4234
|
return this.options.nativeEvent;
|
|
@@ -4181,16 +4273,10 @@ function positionToDirection(position) {
|
|
|
4181
4273
|
throw new Error(`invalid position '${position}'`);
|
|
4182
4274
|
}
|
|
4183
4275
|
}
|
|
4184
|
-
const DEFAULT_ACTIVATION_SIZE = {
|
|
4276
|
+
const DEFAULT_ACTIVATION_SIZE$1 = {
|
|
4185
4277
|
value: 20,
|
|
4186
4278
|
type: 'percentage',
|
|
4187
4279
|
};
|
|
4188
|
-
const DEFAULT_SIZE = {
|
|
4189
|
-
value: 50,
|
|
4190
|
-
type: 'percentage',
|
|
4191
|
-
};
|
|
4192
|
-
const SMALL_WIDTH_BOUNDARY = 100;
|
|
4193
|
-
const SMALL_HEIGHT_BOUNDARY = 100;
|
|
4194
4280
|
class Droptarget extends CompositeDisposable {
|
|
4195
4281
|
get disabled() {
|
|
4196
4282
|
return this._disabled;
|
|
@@ -4271,20 +4357,12 @@ class Droptarget extends CompositeDisposable {
|
|
|
4271
4357
|
this.markAsUsed(e);
|
|
4272
4358
|
if (overrideTarget) ;
|
|
4273
4359
|
else if (!this.targetElement) {
|
|
4274
|
-
|
|
4275
|
-
this.targetElement
|
|
4276
|
-
this.overlayElement =
|
|
4277
|
-
this.overlayElement.className = 'dv-drop-target-selection';
|
|
4360
|
+
const els = createOverlayElements();
|
|
4361
|
+
this.targetElement = els.dropzone;
|
|
4362
|
+
this.overlayElement = els.selection;
|
|
4278
4363
|
this._state = 'center';
|
|
4279
|
-
this.targetElement.appendChild(this.overlayElement);
|
|
4280
4364
|
target.classList.add('dv-drop-target');
|
|
4281
4365
|
target.append(this.targetElement);
|
|
4282
|
-
// this.overlayElement.style.opacity = '0';
|
|
4283
|
-
// requestAnimationFrame(() => {
|
|
4284
|
-
// if (this.overlayElement) {
|
|
4285
|
-
// this.overlayElement.style.opacity = '';
|
|
4286
|
-
// }
|
|
4287
|
-
// });
|
|
4288
4366
|
}
|
|
4289
4367
|
this.toggleClasses(quadrant, width, height);
|
|
4290
4368
|
this._state = quadrant;
|
|
@@ -4354,166 +4432,29 @@ class Droptarget extends CompositeDisposable {
|
|
|
4354
4432
|
return typeof value === 'boolean' && value;
|
|
4355
4433
|
}
|
|
4356
4434
|
toggleClasses(quadrant, width, height) {
|
|
4357
|
-
var _a, _b, _c, _d, _e
|
|
4435
|
+
var _a, _b, _c, _d, _e;
|
|
4358
4436
|
const target = (_b = (_a = this.options).getOverrideTarget) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
4359
|
-
if (!target && !this.overlayElement) {
|
|
4360
|
-
return;
|
|
4361
|
-
}
|
|
4362
|
-
const smallWidthBoundary = (_d = (_c = this.options.overlayModel) === null || _c === void 0 ? void 0 : _c.smallWidthBoundary) !== null && _d !== void 0 ? _d : SMALL_WIDTH_BOUNDARY;
|
|
4363
|
-
const smallHeightBoundary = (_f = (_e = this.options.overlayModel) === null || _e === void 0 ? void 0 : _e.smallHeightBoundary) !== null && _f !== void 0 ? _f : SMALL_HEIGHT_BOUNDARY;
|
|
4364
|
-
const isSmallX = width < smallWidthBoundary;
|
|
4365
|
-
const isSmallY = height < smallHeightBoundary;
|
|
4366
|
-
const isLeft = quadrant === 'left';
|
|
4367
|
-
const isRight = quadrant === 'right';
|
|
4368
|
-
const isTop = quadrant === 'top';
|
|
4369
|
-
const isBottom = quadrant === 'bottom';
|
|
4370
|
-
const rightClass = !isSmallX && isRight;
|
|
4371
|
-
const leftClass = !isSmallX && isLeft;
|
|
4372
|
-
const topClass = !isSmallY && isTop;
|
|
4373
|
-
const bottomClass = !isSmallY && isBottom;
|
|
4374
|
-
let size = 1;
|
|
4375
|
-
const sizeOptions = (_h = (_g = this.options.overlayModel) === null || _g === void 0 ? void 0 : _g.size) !== null && _h !== void 0 ? _h : DEFAULT_SIZE;
|
|
4376
|
-
if (sizeOptions.type === 'percentage') {
|
|
4377
|
-
size = clamp(sizeOptions.value, 0, 100) / 100;
|
|
4378
|
-
}
|
|
4379
|
-
else {
|
|
4380
|
-
if (rightClass || leftClass) {
|
|
4381
|
-
size = clamp(0, sizeOptions.value, width) / width;
|
|
4382
|
-
}
|
|
4383
|
-
if (topClass || bottomClass) {
|
|
4384
|
-
size = clamp(0, sizeOptions.value, height) / height;
|
|
4385
|
-
}
|
|
4386
|
-
}
|
|
4387
4437
|
if (target) {
|
|
4388
|
-
const outlineEl = (
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
left: rootLeft,
|
|
4399
|
-
width: width,
|
|
4400
|
-
height: height,
|
|
4401
|
-
};
|
|
4402
|
-
if (rightClass) {
|
|
4403
|
-
box.left = rootLeft + width * (1 - size);
|
|
4404
|
-
box.width = width * size;
|
|
4405
|
-
}
|
|
4406
|
-
else if (leftClass) {
|
|
4407
|
-
box.width = width * size;
|
|
4408
|
-
}
|
|
4409
|
-
else if (topClass) {
|
|
4410
|
-
box.height = height * size;
|
|
4411
|
-
}
|
|
4412
|
-
else if (bottomClass) {
|
|
4413
|
-
box.top = rootTop + height * (1 - size);
|
|
4414
|
-
box.height = height * size;
|
|
4415
|
-
}
|
|
4416
|
-
if (isSmallX && isLeft) {
|
|
4417
|
-
box.width = 4;
|
|
4418
|
-
}
|
|
4419
|
-
if (isSmallX && isRight) {
|
|
4420
|
-
box.left = rootLeft + width - 4;
|
|
4421
|
-
box.width = 4;
|
|
4422
|
-
}
|
|
4423
|
-
if (isSmallY && isTop) {
|
|
4424
|
-
box.height = 4;
|
|
4425
|
-
}
|
|
4426
|
-
if (isSmallY && isBottom) {
|
|
4427
|
-
box.top = rootTop + height - 4;
|
|
4428
|
-
box.height = 4;
|
|
4429
|
-
}
|
|
4430
|
-
// Use GPU-optimized bounds checking and setting
|
|
4431
|
-
if (!checkBoundsChanged(overlay, box)) {
|
|
4432
|
-
return;
|
|
4433
|
-
}
|
|
4434
|
-
setGPUOptimizedBounds(overlay, box);
|
|
4435
|
-
overlay.className = `dv-drop-target-anchor${this.options.className ? ` ${this.options.className}` : ''}`;
|
|
4436
|
-
toggleClass(overlay, 'dv-drop-target-left', isLeft);
|
|
4437
|
-
toggleClass(overlay, 'dv-drop-target-right', isRight);
|
|
4438
|
-
toggleClass(overlay, 'dv-drop-target-top', isTop);
|
|
4439
|
-
toggleClass(overlay, 'dv-drop-target-bottom', isBottom);
|
|
4440
|
-
toggleClass(overlay, 'dv-drop-target-anchor-line', (isSmallX && (isLeft || isRight)) ||
|
|
4441
|
-
(isSmallY && (isTop || isBottom)));
|
|
4442
|
-
toggleClass(overlay, 'dv-drop-target-center', quadrant === 'center');
|
|
4443
|
-
if (ta.changed) {
|
|
4444
|
-
toggleClass(overlay, 'dv-drop-target-anchor-container-changed', true);
|
|
4445
|
-
setTimeout(() => {
|
|
4446
|
-
toggleClass(overlay, 'dv-drop-target-anchor-container-changed', false);
|
|
4447
|
-
}, 10);
|
|
4448
|
-
}
|
|
4438
|
+
const outlineEl = (_e = (_d = (_c = this.options).getOverlayOutline) === null || _d === void 0 ? void 0 : _d.call(_c)) !== null && _e !== void 0 ? _e : this.element;
|
|
4439
|
+
renderAnchoredOverlay({
|
|
4440
|
+
outlineElement: outlineEl,
|
|
4441
|
+
targetModel: target,
|
|
4442
|
+
quadrant,
|
|
4443
|
+
width,
|
|
4444
|
+
height,
|
|
4445
|
+
overlayModel: this.options.overlayModel,
|
|
4446
|
+
className: this.options.className,
|
|
4447
|
+
});
|
|
4449
4448
|
return;
|
|
4450
4449
|
}
|
|
4451
4450
|
if (!this.overlayElement) {
|
|
4452
4451
|
return;
|
|
4453
4452
|
}
|
|
4454
|
-
|
|
4455
|
-
/**
|
|
4456
|
-
* You can also achieve the overlay placement using the transform CSS property
|
|
4457
|
-
* to translate and scale the element however this has the undesired effect of
|
|
4458
|
-
* 'skewing' the element. Comment left here for anybody that ever revisits this.
|
|
4459
|
-
*
|
|
4460
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/transform
|
|
4461
|
-
*
|
|
4462
|
-
* right
|
|
4463
|
-
* translateX(${100 * (1 - size) / 2}%) scaleX(${scale})
|
|
4464
|
-
*
|
|
4465
|
-
* left
|
|
4466
|
-
* translateX(-${100 * (1 - size) / 2}%) scaleX(${scale})
|
|
4467
|
-
*
|
|
4468
|
-
* top
|
|
4469
|
-
* translateY(-${100 * (1 - size) / 2}%) scaleY(${scale})
|
|
4470
|
-
*
|
|
4471
|
-
* bottom
|
|
4472
|
-
* translateY(${100 * (1 - size) / 2}%) scaleY(${scale})
|
|
4473
|
-
*/
|
|
4474
|
-
if (rightClass) {
|
|
4475
|
-
box.left = `${100 * (1 - size)}%`;
|
|
4476
|
-
box.width = `${100 * size}%`;
|
|
4477
|
-
}
|
|
4478
|
-
else if (leftClass) {
|
|
4479
|
-
box.width = `${100 * size}%`;
|
|
4480
|
-
}
|
|
4481
|
-
else if (topClass) {
|
|
4482
|
-
box.height = `${100 * size}%`;
|
|
4483
|
-
}
|
|
4484
|
-
else if (bottomClass) {
|
|
4485
|
-
box.top = `${100 * (1 - size)}%`;
|
|
4486
|
-
box.height = `${100 * size}%`;
|
|
4487
|
-
}
|
|
4488
|
-
if (isSmallX && isLeft) {
|
|
4489
|
-
box.width = '4px';
|
|
4490
|
-
}
|
|
4491
|
-
if (isSmallX && isRight) {
|
|
4492
|
-
box.left = `${width - 4}px`;
|
|
4493
|
-
box.width = '4px';
|
|
4494
|
-
}
|
|
4495
|
-
if (isSmallY && isTop) {
|
|
4496
|
-
box.height = '4px';
|
|
4497
|
-
}
|
|
4498
|
-
if (isSmallY && isBottom) {
|
|
4499
|
-
box.top = `${height - 4}px`;
|
|
4500
|
-
box.height = '4px';
|
|
4501
|
-
}
|
|
4502
|
-
setGPUOptimizedBoundsFromStrings(this.overlayElement, box);
|
|
4503
|
-
const isLine = (isSmallX && (isLeft || isRight)) ||
|
|
4504
|
-
(isSmallY && (isTop || isBottom));
|
|
4505
|
-
toggleClass(this.overlayElement, 'dv-drop-target-small-vertical', isSmallY);
|
|
4506
|
-
toggleClass(this.overlayElement, 'dv-drop-target-small-horizontal', isSmallX);
|
|
4507
|
-
toggleClass(this.overlayElement, 'dv-drop-target-selection-line', isLine);
|
|
4508
|
-
toggleClass(this.overlayElement, 'dv-drop-target-left', isLeft);
|
|
4509
|
-
toggleClass(this.overlayElement, 'dv-drop-target-right', isRight);
|
|
4510
|
-
toggleClass(this.overlayElement, 'dv-drop-target-top', isTop);
|
|
4511
|
-
toggleClass(this.overlayElement, 'dv-drop-target-bottom', isBottom);
|
|
4512
|
-
toggleClass(this.overlayElement, 'dv-drop-target-center', quadrant === 'center');
|
|
4453
|
+
renderInPlaceOverlay(this.overlayElement, quadrant, width, height, this.options.overlayModel);
|
|
4513
4454
|
}
|
|
4514
4455
|
calculateQuadrant(overlayType, x, y, width, height) {
|
|
4515
4456
|
var _a, _b;
|
|
4516
|
-
const activationSizeOptions = (_b = (_a = this.options.overlayModel) === null || _a === void 0 ? void 0 : _a.activationSize) !== null && _b !== void 0 ? _b : DEFAULT_ACTIVATION_SIZE;
|
|
4457
|
+
const activationSizeOptions = (_b = (_a = this.options.overlayModel) === null || _a === void 0 ? void 0 : _a.activationSize) !== null && _b !== void 0 ? _b : DEFAULT_ACTIVATION_SIZE$1;
|
|
4517
4458
|
const isPercentage = activationSizeOptions.type === 'percentage';
|
|
4518
4459
|
if (isPercentage) {
|
|
4519
4460
|
return calculateQuadrantAsPercentage(overlayType, x, y, width, height, activationSizeOptions.value);
|
|
@@ -4571,6 +4512,723 @@ function calculateQuadrantAsPixels(overlayType, x, y, width, height, threshold)
|
|
|
4571
4512
|
return 'center';
|
|
4572
4513
|
}
|
|
4573
4514
|
|
|
4515
|
+
function addGhostImage(dataTransfer, ghostElement, options) {
|
|
4516
|
+
var _a, _b;
|
|
4517
|
+
// class dockview provides to force ghost image to be drawn on a different layer and prevent weird rendering issues
|
|
4518
|
+
addClasses(ghostElement, 'dv-dragged');
|
|
4519
|
+
// move the element off-screen initially otherwise it may in some cases be rendered at (0,0) momentarily
|
|
4520
|
+
ghostElement.style.top = '-9999px';
|
|
4521
|
+
document.body.appendChild(ghostElement);
|
|
4522
|
+
dataTransfer.setDragImage(ghostElement, (_a = options === null || options === void 0 ? void 0 : options.x) !== null && _a !== void 0 ? _a : 0, (_b = options === null || options === void 0 ? void 0 : options.y) !== null && _b !== void 0 ? _b : 0);
|
|
4523
|
+
setTimeout(() => {
|
|
4524
|
+
removeClasses(ghostElement, 'dv-dragged');
|
|
4525
|
+
ghostElement.remove();
|
|
4526
|
+
}, 0);
|
|
4527
|
+
}
|
|
4528
|
+
|
|
4529
|
+
/**
|
|
4530
|
+
* Singleton — only one pointer-driven drag active at a time.
|
|
4531
|
+
*
|
|
4532
|
+
* State is shared across every Dockview instance on the page. Targets
|
|
4533
|
+
* from instance B receive hit-tests from drags originating in instance A;
|
|
4534
|
+
* that's intentional for cross-instance drops since `LocalSelectionTransfer`
|
|
4535
|
+
* is also process-wide. The corollary is that every Tabs subscriber to
|
|
4536
|
+
* `onDragMove` fires for every pointer drag globally — each subscriber
|
|
4537
|
+
* hit-tests against its own DOM, so this is O(N) per pointermove where N
|
|
4538
|
+
* is the number of registered listeners across all instances.
|
|
4539
|
+
*/
|
|
4540
|
+
class PointerDragController extends CompositeDisposable {
|
|
4541
|
+
static getInstance() {
|
|
4542
|
+
if (!PointerDragController._instance) {
|
|
4543
|
+
PointerDragController._instance = new PointerDragController();
|
|
4544
|
+
}
|
|
4545
|
+
return PointerDragController._instance;
|
|
4546
|
+
}
|
|
4547
|
+
constructor() {
|
|
4548
|
+
super();
|
|
4549
|
+
this._targets = new Set();
|
|
4550
|
+
/** Kept in sync with `_targets` so hit-testing is allocation-free. */
|
|
4551
|
+
this._targetByElement = new Map();
|
|
4552
|
+
this._onDragStart = new Emitter();
|
|
4553
|
+
this.onDragStart = this._onDragStart.event;
|
|
4554
|
+
this._onDragMove = new Emitter();
|
|
4555
|
+
this.onDragMove = this._onDragMove.event;
|
|
4556
|
+
this._onDragEnd = new Emitter();
|
|
4557
|
+
this.onDragEnd = this._onDragEnd.event;
|
|
4558
|
+
this.addDisposables(this._onDragStart, this._onDragMove, this._onDragEnd);
|
|
4559
|
+
}
|
|
4560
|
+
get active() {
|
|
4561
|
+
return this._active;
|
|
4562
|
+
}
|
|
4563
|
+
registerTarget(target) {
|
|
4564
|
+
this._targets.add(target);
|
|
4565
|
+
this._targetByElement.set(target.element, target);
|
|
4566
|
+
return {
|
|
4567
|
+
dispose: () => {
|
|
4568
|
+
this._targets.delete(target);
|
|
4569
|
+
if (this._targetByElement.get(target.element) === target) {
|
|
4570
|
+
this._targetByElement.delete(target.element);
|
|
4571
|
+
}
|
|
4572
|
+
if (this._currentTarget === target) {
|
|
4573
|
+
this._currentTarget = undefined;
|
|
4574
|
+
}
|
|
4575
|
+
},
|
|
4576
|
+
};
|
|
4577
|
+
}
|
|
4578
|
+
beginDrag(args) {
|
|
4579
|
+
var _a, _b, _c;
|
|
4580
|
+
if (this._active) {
|
|
4581
|
+
this.cancel();
|
|
4582
|
+
}
|
|
4583
|
+
const { pointerEvent, source } = args;
|
|
4584
|
+
// Call `getData()` before mutating controller state — a throw
|
|
4585
|
+
// here would otherwise leave `_active` populated with no window
|
|
4586
|
+
// listeners installed, blocking every subsequent drag.
|
|
4587
|
+
const dataDisposable = args.getData();
|
|
4588
|
+
this._active = {
|
|
4589
|
+
pointerId: pointerEvent.pointerId,
|
|
4590
|
+
startX: pointerEvent.clientX,
|
|
4591
|
+
startY: pointerEvent.clientY,
|
|
4592
|
+
source,
|
|
4593
|
+
};
|
|
4594
|
+
this._onDragMoveCallback = args.onDragMove;
|
|
4595
|
+
this._onDragEndCallback = args.onDragEnd;
|
|
4596
|
+
this._dataDisposable = dataDisposable;
|
|
4597
|
+
this._ghost = args.ghost;
|
|
4598
|
+
// Iframes capture pointermove once the cursor crosses into them,
|
|
4599
|
+
// which would freeze the drag from the parent window's POV.
|
|
4600
|
+
this._iframeShield = disableIframePointEvents((_a = source.ownerDocument) !== null && _a !== void 0 ? _a : document);
|
|
4601
|
+
const startEvent = {
|
|
4602
|
+
clientX: pointerEvent.clientX,
|
|
4603
|
+
clientY: pointerEvent.clientY,
|
|
4604
|
+
pointerEvent,
|
|
4605
|
+
};
|
|
4606
|
+
this._onDragStart.fire(startEvent);
|
|
4607
|
+
// Source's owning window — popout drags fire on their own window,
|
|
4608
|
+
// not the main one.
|
|
4609
|
+
const targetWindow = (_c = (_b = source.ownerDocument) === null || _b === void 0 ? void 0 : _b.defaultView) !== null && _c !== void 0 ? _c : window;
|
|
4610
|
+
this._moveListener = addDisposableListener(targetWindow, 'pointermove', (e) => {
|
|
4611
|
+
if (!this._active || e.pointerId !== this._active.pointerId) {
|
|
4612
|
+
return;
|
|
4613
|
+
}
|
|
4614
|
+
this._handleMove(e);
|
|
4615
|
+
});
|
|
4616
|
+
this._upListener = addDisposableListener(targetWindow, 'pointerup', (e) => {
|
|
4617
|
+
if (!this._active || e.pointerId !== this._active.pointerId) {
|
|
4618
|
+
return;
|
|
4619
|
+
}
|
|
4620
|
+
this._handleEnd(e, true);
|
|
4621
|
+
});
|
|
4622
|
+
this._cancelListener = addDisposableListener(targetWindow, 'pointercancel', (e) => {
|
|
4623
|
+
if (!this._active || e.pointerId !== this._active.pointerId) {
|
|
4624
|
+
return;
|
|
4625
|
+
}
|
|
4626
|
+
this._handleEnd(e, false);
|
|
4627
|
+
});
|
|
4628
|
+
}
|
|
4629
|
+
cancel() {
|
|
4630
|
+
var _a, _b;
|
|
4631
|
+
if (!this._active) {
|
|
4632
|
+
return;
|
|
4633
|
+
}
|
|
4634
|
+
(_a = this._currentTarget) === null || _a === void 0 ? void 0 : _a.handleDragLeave();
|
|
4635
|
+
this._teardown();
|
|
4636
|
+
(_b = this._dataDisposable) === null || _b === void 0 ? void 0 : _b.dispose();
|
|
4637
|
+
this._dataDisposable = undefined;
|
|
4638
|
+
}
|
|
4639
|
+
_findTargetUnder(x, y) {
|
|
4640
|
+
var _a, _b;
|
|
4641
|
+
// `elementsFromPoint` is topmost-first; walk up to find the closest
|
|
4642
|
+
// registered ancestor (so a tab beats the layout-root that contains it).
|
|
4643
|
+
// Use the source's owning document so popout drags hit their own targets.
|
|
4644
|
+
const sourceDoc = (_b = (_a = this._active) === null || _a === void 0 ? void 0 : _a.source.ownerDocument) !== null && _b !== void 0 ? _b : document;
|
|
4645
|
+
const elements = sourceDoc.elementsFromPoint(x, y);
|
|
4646
|
+
for (const el of elements) {
|
|
4647
|
+
let current = el;
|
|
4648
|
+
while (current) {
|
|
4649
|
+
const target = this._targetByElement.get(current);
|
|
4650
|
+
if (target) {
|
|
4651
|
+
return target;
|
|
4652
|
+
}
|
|
4653
|
+
current = current.parentElement;
|
|
4654
|
+
}
|
|
4655
|
+
}
|
|
4656
|
+
return undefined;
|
|
4657
|
+
}
|
|
4658
|
+
_handleMove(e) {
|
|
4659
|
+
var _a, _b, _c;
|
|
4660
|
+
(_a = this._ghost) === null || _a === void 0 ? void 0 : _a.update(e.clientX, e.clientY);
|
|
4661
|
+
const dragEvent = {
|
|
4662
|
+
clientX: e.clientX,
|
|
4663
|
+
clientY: e.clientY,
|
|
4664
|
+
pointerEvent: e,
|
|
4665
|
+
};
|
|
4666
|
+
const newTarget = this._findTargetUnder(e.clientX, e.clientY);
|
|
4667
|
+
if (newTarget !== this._currentTarget) {
|
|
4668
|
+
(_b = this._currentTarget) === null || _b === void 0 ? void 0 : _b.handleDragLeave();
|
|
4669
|
+
this._currentTarget = newTarget;
|
|
4670
|
+
}
|
|
4671
|
+
if (newTarget) {
|
|
4672
|
+
newTarget.handleDragOver(dragEvent);
|
|
4673
|
+
}
|
|
4674
|
+
(_c = this._onDragMoveCallback) === null || _c === void 0 ? void 0 : _c.call(this, dragEvent);
|
|
4675
|
+
this._onDragMove.fire(dragEvent);
|
|
4676
|
+
}
|
|
4677
|
+
_handleEnd(e, dropped) {
|
|
4678
|
+
var _a;
|
|
4679
|
+
const dragEvent = {
|
|
4680
|
+
clientX: e.clientX,
|
|
4681
|
+
clientY: e.clientY,
|
|
4682
|
+
pointerEvent: e,
|
|
4683
|
+
};
|
|
4684
|
+
if (dropped && this._currentTarget) {
|
|
4685
|
+
this._currentTarget.handleDrop(dragEvent);
|
|
4686
|
+
}
|
|
4687
|
+
else {
|
|
4688
|
+
(_a = this._currentTarget) === null || _a === void 0 ? void 0 : _a.handleDragLeave();
|
|
4689
|
+
}
|
|
4690
|
+
const onEnd = this._onDragEndCallback;
|
|
4691
|
+
const dataDisposable = this._dataDisposable;
|
|
4692
|
+
this._teardown();
|
|
4693
|
+
this._dataDisposable = undefined;
|
|
4694
|
+
// Defer disposal so drop handlers can still read the transfer data.
|
|
4695
|
+
setTimeout(() => dataDisposable === null || dataDisposable === void 0 ? void 0 : dataDisposable.dispose(), 0);
|
|
4696
|
+
onEnd === null || onEnd === void 0 ? void 0 : onEnd(dragEvent, dropped);
|
|
4697
|
+
this._onDragEnd.fire(dragEvent);
|
|
4698
|
+
}
|
|
4699
|
+
_teardown() {
|
|
4700
|
+
var _a, _b, _c, _d, _e;
|
|
4701
|
+
this._currentTarget = undefined;
|
|
4702
|
+
this._active = undefined;
|
|
4703
|
+
this._onDragMoveCallback = undefined;
|
|
4704
|
+
this._onDragEndCallback = undefined;
|
|
4705
|
+
(_a = this._ghost) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
4706
|
+
this._ghost = undefined;
|
|
4707
|
+
(_b = this._iframeShield) === null || _b === void 0 ? void 0 : _b.release();
|
|
4708
|
+
this._iframeShield = undefined;
|
|
4709
|
+
(_c = this._moveListener) === null || _c === void 0 ? void 0 : _c.dispose();
|
|
4710
|
+
(_d = this._upListener) === null || _d === void 0 ? void 0 : _d.dispose();
|
|
4711
|
+
(_e = this._cancelListener) === null || _e === void 0 ? void 0 : _e.dispose();
|
|
4712
|
+
this._moveListener = undefined;
|
|
4713
|
+
this._upListener = undefined;
|
|
4714
|
+
this._cancelListener = undefined;
|
|
4715
|
+
}
|
|
4716
|
+
}
|
|
4717
|
+
|
|
4718
|
+
const DEFAULT_ACTIVATION_SIZE = {
|
|
4719
|
+
value: 20,
|
|
4720
|
+
type: 'percentage',
|
|
4721
|
+
};
|
|
4722
|
+
/** Pointer-driven counterpart to `Droptarget` with identical visual output. */
|
|
4723
|
+
class PointerDropTarget extends CompositeDisposable {
|
|
4724
|
+
get disabled() {
|
|
4725
|
+
return this._disabled;
|
|
4726
|
+
}
|
|
4727
|
+
set disabled(value) {
|
|
4728
|
+
this._disabled = value;
|
|
4729
|
+
if (value) {
|
|
4730
|
+
this._removeOverlay();
|
|
4731
|
+
}
|
|
4732
|
+
}
|
|
4733
|
+
get state() {
|
|
4734
|
+
return this._state;
|
|
4735
|
+
}
|
|
4736
|
+
constructor(element, options) {
|
|
4737
|
+
super();
|
|
4738
|
+
this.element = element;
|
|
4739
|
+
this.options = options;
|
|
4740
|
+
this._onDrop = new Emitter();
|
|
4741
|
+
this.onDrop = this._onDrop.event;
|
|
4742
|
+
this._onWillShowOverlay = new Emitter();
|
|
4743
|
+
this.onWillShowOverlay = this._onWillShowOverlay.event;
|
|
4744
|
+
this._disabled = false;
|
|
4745
|
+
this._acceptedTargetZonesSet = new Set(options.acceptedTargetZones);
|
|
4746
|
+
const handle = {
|
|
4747
|
+
element: this.element,
|
|
4748
|
+
handleDragOver: (e) => this._onDragOver(e),
|
|
4749
|
+
handleDragLeave: () => this._onDragLeave(),
|
|
4750
|
+
handleDrop: (e) => this._onDropEvent(e),
|
|
4751
|
+
};
|
|
4752
|
+
this.addDisposables(this._onDrop, this._onWillShowOverlay, PointerDragController.getInstance().registerTarget(handle));
|
|
4753
|
+
}
|
|
4754
|
+
setTargetZones(zones) {
|
|
4755
|
+
this._acceptedTargetZonesSet = new Set(zones);
|
|
4756
|
+
}
|
|
4757
|
+
setOverlayModel(model) {
|
|
4758
|
+
this.options.overlayModel = model;
|
|
4759
|
+
}
|
|
4760
|
+
dispose() {
|
|
4761
|
+
this._removeOverlay();
|
|
4762
|
+
super.dispose();
|
|
4763
|
+
}
|
|
4764
|
+
_onDragOver(event) {
|
|
4765
|
+
var _a, _b, _c, _d, _e;
|
|
4766
|
+
if (this._disabled) {
|
|
4767
|
+
this._removeOverlay();
|
|
4768
|
+
return;
|
|
4769
|
+
}
|
|
4770
|
+
const overrideTarget = (_b = (_a = this.options).getOverrideTarget) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
4771
|
+
if (this._acceptedTargetZonesSet.size === 0) {
|
|
4772
|
+
if (overrideTarget) {
|
|
4773
|
+
return;
|
|
4774
|
+
}
|
|
4775
|
+
this._removeOverlay();
|
|
4776
|
+
return;
|
|
4777
|
+
}
|
|
4778
|
+
const outlineEl = (_e = (_d = (_c = this.options).getOverlayOutline) === null || _d === void 0 ? void 0 : _d.call(_c)) !== null && _e !== void 0 ? _e : this.element;
|
|
4779
|
+
const width = outlineEl.offsetWidth;
|
|
4780
|
+
const height = outlineEl.offsetHeight;
|
|
4781
|
+
if (width === 0 || height === 0) {
|
|
4782
|
+
return;
|
|
4783
|
+
}
|
|
4784
|
+
const rect = outlineEl.getBoundingClientRect();
|
|
4785
|
+
const x = event.clientX - rect.left;
|
|
4786
|
+
const y = event.clientY - rect.top;
|
|
4787
|
+
const quadrant = this._calculateQuadrant(x, y, width, height);
|
|
4788
|
+
if (quadrant === null) {
|
|
4789
|
+
this._removeOverlay();
|
|
4790
|
+
return;
|
|
4791
|
+
}
|
|
4792
|
+
if (!this.options.canDisplayOverlay(event.pointerEvent, quadrant)) {
|
|
4793
|
+
if (overrideTarget) {
|
|
4794
|
+
return;
|
|
4795
|
+
}
|
|
4796
|
+
this._removeOverlay();
|
|
4797
|
+
return;
|
|
4798
|
+
}
|
|
4799
|
+
const willShow = new WillShowOverlayEvent({
|
|
4800
|
+
nativeEvent: event.pointerEvent,
|
|
4801
|
+
position: quadrant,
|
|
4802
|
+
});
|
|
4803
|
+
this._onWillShowOverlay.fire(willShow);
|
|
4804
|
+
if (willShow.defaultPrevented) {
|
|
4805
|
+
this._removeOverlay();
|
|
4806
|
+
return;
|
|
4807
|
+
}
|
|
4808
|
+
if (overrideTarget) {
|
|
4809
|
+
renderAnchoredOverlay({
|
|
4810
|
+
outlineElement: outlineEl,
|
|
4811
|
+
targetModel: overrideTarget,
|
|
4812
|
+
quadrant,
|
|
4813
|
+
width,
|
|
4814
|
+
height,
|
|
4815
|
+
overlayModel: this.options.overlayModel,
|
|
4816
|
+
className: this.options.className,
|
|
4817
|
+
});
|
|
4818
|
+
this._state = quadrant;
|
|
4819
|
+
return;
|
|
4820
|
+
}
|
|
4821
|
+
if (!this._targetElement) {
|
|
4822
|
+
const els = createOverlayElements();
|
|
4823
|
+
this._targetElement = els.dropzone;
|
|
4824
|
+
this._overlayElement = els.selection;
|
|
4825
|
+
this._state = 'center';
|
|
4826
|
+
this.element.classList.add('dv-drop-target');
|
|
4827
|
+
this.element.append(this._targetElement);
|
|
4828
|
+
}
|
|
4829
|
+
if (this._overlayElement) {
|
|
4830
|
+
renderInPlaceOverlay(this._overlayElement, quadrant, width, height, this.options.overlayModel);
|
|
4831
|
+
}
|
|
4832
|
+
this._state = quadrant;
|
|
4833
|
+
}
|
|
4834
|
+
_onDragLeave() {
|
|
4835
|
+
var _a, _b;
|
|
4836
|
+
const overrideTarget = (_b = (_a = this.options).getOverrideTarget) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
4837
|
+
// Anchor target owns its own lifecycle; just clear our latched
|
|
4838
|
+
// state so a subsequent pointerup doesn't fire a stale drop.
|
|
4839
|
+
if (overrideTarget) {
|
|
4840
|
+
this._state = undefined;
|
|
4841
|
+
overrideTarget.clear();
|
|
4842
|
+
return;
|
|
4843
|
+
}
|
|
4844
|
+
this._removeOverlay();
|
|
4845
|
+
}
|
|
4846
|
+
_onDropEvent(event) {
|
|
4847
|
+
var _a, _b;
|
|
4848
|
+
const state = this._state;
|
|
4849
|
+
const overrideTarget = (_b = (_a = this.options).getOverrideTarget) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
4850
|
+
this._removeOverlay();
|
|
4851
|
+
overrideTarget === null || overrideTarget === void 0 ? void 0 : overrideTarget.clear();
|
|
4852
|
+
if (state) {
|
|
4853
|
+
this._onDrop.fire({
|
|
4854
|
+
position: state,
|
|
4855
|
+
nativeEvent: event.pointerEvent,
|
|
4856
|
+
});
|
|
4857
|
+
}
|
|
4858
|
+
}
|
|
4859
|
+
_calculateQuadrant(x, y, width, height) {
|
|
4860
|
+
var _a, _b;
|
|
4861
|
+
const activation = (_b = (_a = this.options.overlayModel) === null || _a === void 0 ? void 0 : _a.activationSize) !== null && _b !== void 0 ? _b : DEFAULT_ACTIVATION_SIZE;
|
|
4862
|
+
if (activation.type === 'percentage') {
|
|
4863
|
+
return calculateQuadrantAsPercentage(this._acceptedTargetZonesSet, x, y, width, height, activation.value);
|
|
4864
|
+
}
|
|
4865
|
+
return calculateQuadrantAsPixels(this._acceptedTargetZonesSet, x, y, width, height, activation.value);
|
|
4866
|
+
}
|
|
4867
|
+
_removeOverlay() {
|
|
4868
|
+
var _a;
|
|
4869
|
+
if (this._targetElement) {
|
|
4870
|
+
this._state = undefined;
|
|
4871
|
+
(_a = this._targetElement.parentElement) === null || _a === void 0 ? void 0 : _a.classList.remove('dv-drop-target');
|
|
4872
|
+
this._targetElement.remove();
|
|
4873
|
+
this._targetElement = undefined;
|
|
4874
|
+
this._overlayElement = undefined;
|
|
4875
|
+
}
|
|
4876
|
+
else {
|
|
4877
|
+
this._state = undefined;
|
|
4878
|
+
}
|
|
4879
|
+
}
|
|
4880
|
+
}
|
|
4881
|
+
|
|
4882
|
+
const DEFAULT_THRESHOLD = 5;
|
|
4883
|
+
const DEFAULT_TOUCH_INITIATION_DELAY = 250;
|
|
4884
|
+
const DEFAULT_PRESS_TOLERANCE = 8;
|
|
4885
|
+
/**
|
|
4886
|
+
* Pointer-event drag source. Waits for movement past `threshold` (and
|
|
4887
|
+
* touch-only `touchInitiationDelay`) before promoting to a drag so taps
|
|
4888
|
+
* pass through unaffected.
|
|
4889
|
+
*/
|
|
4890
|
+
class PointerDragSource extends CompositeDisposable {
|
|
4891
|
+
constructor(element, options) {
|
|
4892
|
+
var _a;
|
|
4893
|
+
super();
|
|
4894
|
+
this.element = element;
|
|
4895
|
+
this.options = options;
|
|
4896
|
+
this._disabled = false;
|
|
4897
|
+
this._armed = false;
|
|
4898
|
+
this._startX = 0;
|
|
4899
|
+
this._startY = 0;
|
|
4900
|
+
this._touchOnly = (_a = options.touchOnly) !== null && _a !== void 0 ? _a : true;
|
|
4901
|
+
this.addDisposables(addDisposableListener(this.element, 'pointerdown', (e) => {
|
|
4902
|
+
this._onPointerDown(e);
|
|
4903
|
+
}));
|
|
4904
|
+
}
|
|
4905
|
+
setDisabled(value) {
|
|
4906
|
+
this._disabled = value;
|
|
4907
|
+
if (value) {
|
|
4908
|
+
this._cancelPending();
|
|
4909
|
+
}
|
|
4910
|
+
}
|
|
4911
|
+
/**
|
|
4912
|
+
* `false` lets the pointer source also handle mouse pointers; used when
|
|
4913
|
+
* `dndStrategy: 'pointer'` to drive every input type through this path.
|
|
4914
|
+
*/
|
|
4915
|
+
setTouchOnly(value) {
|
|
4916
|
+
if (this._touchOnly === value) {
|
|
4917
|
+
return;
|
|
4918
|
+
}
|
|
4919
|
+
this._touchOnly = value;
|
|
4920
|
+
// A pending mouse-tracked drag should be abandoned if we re-enable
|
|
4921
|
+
// the touch-only filter mid-flight.
|
|
4922
|
+
if (value) {
|
|
4923
|
+
this._cancelPending();
|
|
4924
|
+
}
|
|
4925
|
+
}
|
|
4926
|
+
_shouldHandle(event) {
|
|
4927
|
+
var _a, _b;
|
|
4928
|
+
if (this._disabled) {
|
|
4929
|
+
return false;
|
|
4930
|
+
}
|
|
4931
|
+
// Pointer-type filter runs before isCancelled — consumer state read
|
|
4932
|
+
// by isCancelled may not be populated for events we'll never handle.
|
|
4933
|
+
if (this._touchOnly &&
|
|
4934
|
+
event.pointerType !== 'touch' &&
|
|
4935
|
+
event.pointerType !== 'pen') {
|
|
4936
|
+
return false;
|
|
4937
|
+
}
|
|
4938
|
+
if ((_b = (_a = this.options).isCancelled) === null || _b === void 0 ? void 0 : _b.call(_a, event)) {
|
|
4939
|
+
return false;
|
|
4940
|
+
}
|
|
4941
|
+
return true;
|
|
4942
|
+
}
|
|
4943
|
+
_onPointerDown(event) {
|
|
4944
|
+
var _a, _b, _c, _d, _e;
|
|
4945
|
+
if (!this._shouldHandle(event)) {
|
|
4946
|
+
return;
|
|
4947
|
+
}
|
|
4948
|
+
// Defensive: a fresh pointerdown supersedes any in-flight tracking.
|
|
4949
|
+
this._cancelPending();
|
|
4950
|
+
this._pendingPointerId = event.pointerId;
|
|
4951
|
+
this._startX = event.clientX;
|
|
4952
|
+
this._startY = event.clientY;
|
|
4953
|
+
this._startEvent = event;
|
|
4954
|
+
const isTouch = event.pointerType === 'touch' || event.pointerType === 'pen';
|
|
4955
|
+
// Touch waits a short window so a still finger can press-and-hold
|
|
4956
|
+
// before drifting; once the timer fires, any motion past `threshold`
|
|
4957
|
+
// begins the drag.
|
|
4958
|
+
const initiationDelayOpt = this.options.touchInitiationDelay;
|
|
4959
|
+
const initiationDelay = (_a = (typeof initiationDelayOpt === 'function'
|
|
4960
|
+
? initiationDelayOpt()
|
|
4961
|
+
: initiationDelayOpt)) !== null && _a !== void 0 ? _a : DEFAULT_TOUCH_INITIATION_DELAY;
|
|
4962
|
+
this._armed = !isTouch || initiationDelay <= 0;
|
|
4963
|
+
if (isTouch && initiationDelay > 0 && isFinite(initiationDelay)) {
|
|
4964
|
+
this._armTimer = setTimeout(() => {
|
|
4965
|
+
this._armTimer = undefined;
|
|
4966
|
+
this._armed = true;
|
|
4967
|
+
}, initiationDelay);
|
|
4968
|
+
}
|
|
4969
|
+
const threshold = (_b = this.options.threshold) !== null && _b !== void 0 ? _b : DEFAULT_THRESHOLD;
|
|
4970
|
+
const pressToleranceOpt = this.options.pressTolerance;
|
|
4971
|
+
const pressTolerance = (_c = (typeof pressToleranceOpt === 'function'
|
|
4972
|
+
? pressToleranceOpt()
|
|
4973
|
+
: pressToleranceOpt)) !== null && _c !== void 0 ? _c : DEFAULT_PRESS_TOLERANCE;
|
|
4974
|
+
// Source's owning window — popout drags fire on their own window.
|
|
4975
|
+
const targetWindow = (_e = (_d = this.element.ownerDocument) === null || _d === void 0 ? void 0 : _d.defaultView) !== null && _e !== void 0 ? _e : window;
|
|
4976
|
+
this._pendingMoveListener = addDisposableListener(targetWindow, 'pointermove', (moveEvent) => {
|
|
4977
|
+
if (moveEvent.pointerId !== this._pendingPointerId) {
|
|
4978
|
+
return;
|
|
4979
|
+
}
|
|
4980
|
+
const dx = moveEvent.clientX - this._startX;
|
|
4981
|
+
const dy = moveEvent.clientY - this._startY;
|
|
4982
|
+
const distance = Math.hypot(dx, dy);
|
|
4983
|
+
if (this._armed) {
|
|
4984
|
+
if (distance >= threshold) {
|
|
4985
|
+
this._beginDrag(moveEvent);
|
|
4986
|
+
}
|
|
4987
|
+
return;
|
|
4988
|
+
}
|
|
4989
|
+
// Pre-arm phase: a flick past `pressTolerance` in any
|
|
4990
|
+
// direction is treated as drag intent. The element opts out
|
|
4991
|
+
// of native scroll via `touch-action: none`; container-level
|
|
4992
|
+
// scrolling lives on the surrounding strip's empty space.
|
|
4993
|
+
if (distance > pressTolerance) {
|
|
4994
|
+
this._beginDrag(moveEvent);
|
|
4995
|
+
}
|
|
4996
|
+
});
|
|
4997
|
+
this._pendingUpListener = addDisposableListener(targetWindow, 'pointerup', (upEvent) => {
|
|
4998
|
+
if (upEvent.pointerId !== this._pendingPointerId) {
|
|
4999
|
+
return;
|
|
5000
|
+
}
|
|
5001
|
+
this._cancelPending();
|
|
5002
|
+
});
|
|
5003
|
+
this._pendingCancelListener = addDisposableListener(targetWindow, 'pointercancel', (cancelEvent) => {
|
|
5004
|
+
if (cancelEvent.pointerId !== this._pendingPointerId) {
|
|
5005
|
+
return;
|
|
5006
|
+
}
|
|
5007
|
+
this._cancelPending();
|
|
5008
|
+
});
|
|
5009
|
+
}
|
|
5010
|
+
/** For sibling gesture detectors (e.g. LongPressDetector) to dismiss a pending drag. */
|
|
5011
|
+
cancelPending() {
|
|
5012
|
+
this._cancelPending();
|
|
5013
|
+
}
|
|
5014
|
+
_cancelPending() {
|
|
5015
|
+
var _a, _b, _c;
|
|
5016
|
+
this._pendingPointerId = undefined;
|
|
5017
|
+
if (this._armTimer !== undefined) {
|
|
5018
|
+
clearTimeout(this._armTimer);
|
|
5019
|
+
this._armTimer = undefined;
|
|
5020
|
+
}
|
|
5021
|
+
this._armed = false;
|
|
5022
|
+
(_a = this._pendingMoveListener) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
5023
|
+
(_b = this._pendingUpListener) === null || _b === void 0 ? void 0 : _b.dispose();
|
|
5024
|
+
(_c = this._pendingCancelListener) === null || _c === void 0 ? void 0 : _c.dispose();
|
|
5025
|
+
this._pendingMoveListener = undefined;
|
|
5026
|
+
this._pendingUpListener = undefined;
|
|
5027
|
+
this._pendingCancelListener = undefined;
|
|
5028
|
+
this._startEvent = undefined;
|
|
5029
|
+
}
|
|
5030
|
+
_beginDrag(triggerEvent) {
|
|
5031
|
+
var _a, _b, _c, _d, _e;
|
|
5032
|
+
const startEvent = (_a = this._startEvent) !== null && _a !== void 0 ? _a : triggerEvent;
|
|
5033
|
+
this._cancelPending();
|
|
5034
|
+
(_c = (_b = this.options).onDragStart) === null || _c === void 0 ? void 0 : _c.call(_b, startEvent);
|
|
5035
|
+
const ghost = (_e = (_d = this.options).createGhost) === null || _e === void 0 ? void 0 : _e.call(_d, startEvent);
|
|
5036
|
+
PointerDragController.getInstance().beginDrag({
|
|
5037
|
+
pointerEvent: triggerEvent,
|
|
5038
|
+
source: this.element,
|
|
5039
|
+
getData: () => this.options.getData(startEvent),
|
|
5040
|
+
ghost,
|
|
5041
|
+
onDragMove: this.options.onDragMove,
|
|
5042
|
+
onDragEnd: this.options.onDragEnd,
|
|
5043
|
+
});
|
|
5044
|
+
}
|
|
5045
|
+
dispose() {
|
|
5046
|
+
this._cancelPending();
|
|
5047
|
+
super.dispose();
|
|
5048
|
+
}
|
|
5049
|
+
}
|
|
5050
|
+
|
|
5051
|
+
/**
|
|
5052
|
+
* Floating clone that follows the pointer; appended to the owning
|
|
5053
|
+
* document's body with `pointer-events: none` so it doesn't intercept
|
|
5054
|
+
* hit-testing.
|
|
5055
|
+
*/
|
|
5056
|
+
class PointerGhost {
|
|
5057
|
+
constructor(opts) {
|
|
5058
|
+
var _a, _b, _c, _d, _e;
|
|
5059
|
+
this._disposed = false;
|
|
5060
|
+
this.element = opts.element;
|
|
5061
|
+
this.offsetX = (_a = opts.offsetX) !== null && _a !== void 0 ? _a : 0;
|
|
5062
|
+
this.offsetY = (_b = opts.offsetY) !== null && _b !== void 0 ? _b : 0;
|
|
5063
|
+
// Animate via transform (see update); position:fixed for scroll-independence.
|
|
5064
|
+
this.element.style.position = 'fixed';
|
|
5065
|
+
this.element.style.left = '0px';
|
|
5066
|
+
this.element.style.top = '0px';
|
|
5067
|
+
this.element.style.pointerEvents = 'none';
|
|
5068
|
+
this.element.style.zIndex = '99999';
|
|
5069
|
+
this.element.style.opacity = String((_c = opts.opacity) !== null && _c !== void 0 ? _c : 0.8);
|
|
5070
|
+
this.element.style.willChange = 'transform';
|
|
5071
|
+
this.element.style.transform = `translate3d(${opts.initialX - this.offsetX}px, ${opts.initialY - this.offsetY}px, 0)`;
|
|
5072
|
+
const ownerDocument = (_e = (_d = opts.owner) === null || _d === void 0 ? void 0 : _d.ownerDocument) !== null && _e !== void 0 ? _e : document;
|
|
5073
|
+
ownerDocument.body.appendChild(this.element);
|
|
5074
|
+
}
|
|
5075
|
+
update(clientX, clientY) {
|
|
5076
|
+
if (this._disposed) {
|
|
5077
|
+
return;
|
|
5078
|
+
}
|
|
5079
|
+
// translate3d composites on the GPU — no layout per pointermove.
|
|
5080
|
+
this.element.style.transform = `translate3d(${clientX - this.offsetX}px, ${clientY - this.offsetY}px, 0)`;
|
|
5081
|
+
}
|
|
5082
|
+
dispose() {
|
|
5083
|
+
if (this._disposed) {
|
|
5084
|
+
return;
|
|
5085
|
+
}
|
|
5086
|
+
this._disposed = true;
|
|
5087
|
+
this.element.remove();
|
|
5088
|
+
}
|
|
5089
|
+
}
|
|
5090
|
+
|
|
5091
|
+
/**
|
|
5092
|
+
* HTML5 drag source. Listens for the native `dragstart` event, calls
|
|
5093
|
+
* `getData` to populate transfer, optionally renders the ghost via
|
|
5094
|
+
* `setDragImage`, fires `onDragStart` / `onDragEnd`, and tears down the
|
|
5095
|
+
* transfer disposer after `dragend`.
|
|
5096
|
+
*/
|
|
5097
|
+
class Html5DragSource extends CompositeDisposable {
|
|
5098
|
+
constructor(el, opts) {
|
|
5099
|
+
super();
|
|
5100
|
+
this.el = el;
|
|
5101
|
+
this.opts = opts;
|
|
5102
|
+
this._dataDisposable = new MutableDisposable();
|
|
5103
|
+
this._pointerEventsDisposable = new MutableDisposable();
|
|
5104
|
+
this._disabled = !!opts.disabled;
|
|
5105
|
+
this.addDisposables(this._dataDisposable, this._pointerEventsDisposable, addDisposableListener(this.el, 'dragstart', (event) => {
|
|
5106
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
5107
|
+
if (event.defaultPrevented ||
|
|
5108
|
+
this._disabled ||
|
|
5109
|
+
((_b = (_a = this.opts).isCancelled) === null || _b === void 0 ? void 0 : _b.call(_a, event))) {
|
|
5110
|
+
event.preventDefault();
|
|
5111
|
+
return;
|
|
5112
|
+
}
|
|
5113
|
+
// Iframes capture pointermove once the cursor enters them,
|
|
5114
|
+
// which freezes drag tracking from the parent window's
|
|
5115
|
+
// POV. Shield the source's owning document so popout-window
|
|
5116
|
+
// drags shield the popout, not the main window.
|
|
5117
|
+
const iframes = disableIframePointEvents((_c = this.el.ownerDocument) !== null && _c !== void 0 ? _c : document);
|
|
5118
|
+
this._pointerEventsDisposable.value = {
|
|
5119
|
+
dispose: () => iframes.release(),
|
|
5120
|
+
};
|
|
5121
|
+
this.el.classList.add('dv-dragged');
|
|
5122
|
+
setTimeout(() => this.el.classList.remove('dv-dragged'), 0);
|
|
5123
|
+
this._dataDisposable.value = this.opts.getData(event);
|
|
5124
|
+
const ghost = (_e = (_d = this.opts).createGhost) === null || _e === void 0 ? void 0 : _e.call(_d, event);
|
|
5125
|
+
if (ghost && event.dataTransfer) {
|
|
5126
|
+
addGhostImage(event.dataTransfer, ghost.element, {
|
|
5127
|
+
x: (_f = ghost.offsetX) !== null && _f !== void 0 ? _f : 0,
|
|
5128
|
+
y: (_g = ghost.offsetY) !== null && _g !== void 0 ? _g : 0,
|
|
5129
|
+
});
|
|
5130
|
+
if (ghost.dispose) {
|
|
5131
|
+
// addGhostImage removes the element from the DOM on
|
|
5132
|
+
// the next tick; dispose the framework renderer on
|
|
5133
|
+
// the same schedule.
|
|
5134
|
+
const disposeGhost = ghost.dispose;
|
|
5135
|
+
setTimeout(() => disposeGhost(), 0);
|
|
5136
|
+
}
|
|
5137
|
+
}
|
|
5138
|
+
if (event.dataTransfer) {
|
|
5139
|
+
event.dataTransfer.effectAllowed = 'move';
|
|
5140
|
+
// Some third-party DnD libs (e.g. react-dnd) cancel the
|
|
5141
|
+
// dragstart when `dataTransfer.types` is empty.
|
|
5142
|
+
if (event.dataTransfer.items.length === 0) {
|
|
5143
|
+
event.dataTransfer.setData('text/plain', '');
|
|
5144
|
+
}
|
|
5145
|
+
}
|
|
5146
|
+
(_j = (_h = this.opts).onDragStart) === null || _j === void 0 ? void 0 : _j.call(_h, event);
|
|
5147
|
+
}), addDisposableListener(this.el, 'dragend', (event) => {
|
|
5148
|
+
var _a, _b;
|
|
5149
|
+
this._pointerEventsDisposable.dispose();
|
|
5150
|
+
// Defer disposal so drop handlers can still read the
|
|
5151
|
+
// transfer payload before it clears.
|
|
5152
|
+
setTimeout(() => this._dataDisposable.dispose(), 0);
|
|
5153
|
+
(_b = (_a = this.opts).onDragEnd) === null || _b === void 0 ? void 0 : _b.call(_a, event);
|
|
5154
|
+
}));
|
|
5155
|
+
}
|
|
5156
|
+
setDisabled(value) {
|
|
5157
|
+
this._disabled = value;
|
|
5158
|
+
}
|
|
5159
|
+
setTouchOnly(_) {
|
|
5160
|
+
// No-op — HTML5 path can't filter by pointer type.
|
|
5161
|
+
}
|
|
5162
|
+
cancelPending() {
|
|
5163
|
+
// No-op — HTML5 has no pre-arm phase to cancel.
|
|
5164
|
+
}
|
|
5165
|
+
}
|
|
5166
|
+
class Html5DragBackend {
|
|
5167
|
+
constructor() {
|
|
5168
|
+
this.kind = 'html5';
|
|
5169
|
+
}
|
|
5170
|
+
createDropTarget(element, options) {
|
|
5171
|
+
return new Droptarget(element, options);
|
|
5172
|
+
}
|
|
5173
|
+
createDragSource(element, options) {
|
|
5174
|
+
return new Html5DragSource(element, options);
|
|
5175
|
+
}
|
|
5176
|
+
}
|
|
5177
|
+
class PointerDragBackend {
|
|
5178
|
+
constructor() {
|
|
5179
|
+
this.kind = 'pointer';
|
|
5180
|
+
}
|
|
5181
|
+
createDropTarget(element, options) {
|
|
5182
|
+
return new PointerDropTarget(element, options);
|
|
5183
|
+
}
|
|
5184
|
+
createDragSource(element, options) {
|
|
5185
|
+
const pointerCreateGhost = options.createGhost
|
|
5186
|
+
? (event) => {
|
|
5187
|
+
const spec = options.createGhost(event);
|
|
5188
|
+
if (!spec) {
|
|
5189
|
+
return undefined;
|
|
5190
|
+
}
|
|
5191
|
+
const ghost = new PointerGhost({
|
|
5192
|
+
element: spec.element,
|
|
5193
|
+
initialX: event.clientX,
|
|
5194
|
+
initialY: event.clientY,
|
|
5195
|
+
offsetX: spec.offsetX,
|
|
5196
|
+
offsetY: spec.offsetY,
|
|
5197
|
+
owner: element,
|
|
5198
|
+
});
|
|
5199
|
+
if (spec.dispose) {
|
|
5200
|
+
const baseDispose = ghost.dispose.bind(ghost);
|
|
5201
|
+
const disposeSpec = spec.dispose;
|
|
5202
|
+
ghost.dispose = () => {
|
|
5203
|
+
baseDispose();
|
|
5204
|
+
disposeSpec();
|
|
5205
|
+
};
|
|
5206
|
+
}
|
|
5207
|
+
return ghost;
|
|
5208
|
+
}
|
|
5209
|
+
: undefined;
|
|
5210
|
+
const source = new PointerDragSource(element, {
|
|
5211
|
+
getData: options.getData,
|
|
5212
|
+
isCancelled: options.isCancelled,
|
|
5213
|
+
onDragStart: options.onDragStart,
|
|
5214
|
+
onDragEnd: options.onDragEnd
|
|
5215
|
+
? (event) => options.onDragEnd(event.pointerEvent)
|
|
5216
|
+
: undefined,
|
|
5217
|
+
createGhost: pointerCreateGhost,
|
|
5218
|
+
touchOnly: options.touchOnly,
|
|
5219
|
+
touchInitiationDelay: options.touchInitiationDelay,
|
|
5220
|
+
pressTolerance: options.pressTolerance,
|
|
5221
|
+
threshold: options.threshold,
|
|
5222
|
+
});
|
|
5223
|
+
if (options.disabled) {
|
|
5224
|
+
source.setDisabled(true);
|
|
5225
|
+
}
|
|
5226
|
+
return source;
|
|
5227
|
+
}
|
|
5228
|
+
}
|
|
5229
|
+
const html5Backend = new Html5DragBackend();
|
|
5230
|
+
const pointerBackend = new PointerDragBackend();
|
|
5231
|
+
|
|
4574
5232
|
const PROPERTY_KEYS_PANEVIEW = (() => {
|
|
4575
5233
|
/**
|
|
4576
5234
|
* by readong the keys from an empty value object TypeScript will error
|
|
@@ -5036,35 +5694,42 @@ class DraggablePaneviewPanel extends PaneviewPanel {
|
|
|
5036
5694
|
const id = this.id;
|
|
5037
5695
|
const accessorId = this.accessor.id;
|
|
5038
5696
|
this.header.draggable = true;
|
|
5039
|
-
|
|
5040
|
-
getData() {
|
|
5697
|
+
const sharedDragOptions = {
|
|
5698
|
+
getData: () => {
|
|
5041
5699
|
LocalSelectionTransfer.getInstance().setData([new PaneTransfer(accessorId, id)], PaneTransfer.prototype);
|
|
5042
5700
|
return {
|
|
5043
5701
|
dispose: () => {
|
|
5044
5702
|
LocalSelectionTransfer.getInstance().clearData(PaneTransfer.prototype);
|
|
5045
5703
|
},
|
|
5046
5704
|
};
|
|
5705
|
+
},
|
|
5706
|
+
};
|
|
5707
|
+
this.html5DragSource = html5Backend.createDragSource(this.header, sharedDragOptions);
|
|
5708
|
+
this.pointerDragSource = pointerBackend.createDragSource(this.header, sharedDragOptions);
|
|
5709
|
+
const canDisplayOverlay = (event, position) => {
|
|
5710
|
+
const data = getPaneData();
|
|
5711
|
+
if (data) {
|
|
5712
|
+
if (data.paneId !== this.id &&
|
|
5713
|
+
data.viewId === this.accessor.id) {
|
|
5714
|
+
return true;
|
|
5715
|
+
}
|
|
5047
5716
|
}
|
|
5048
|
-
|
|
5049
|
-
|
|
5717
|
+
const firedEvent = new PaneviewUnhandledDragOverEvent(event, position, getPaneData, this);
|
|
5718
|
+
this._onUnhandledDragOverEvent.fire(firedEvent);
|
|
5719
|
+
return firedEvent.isAccepted;
|
|
5720
|
+
};
|
|
5721
|
+
const dropTargetOptions = {
|
|
5050
5722
|
acceptedTargetZones: ['top', 'bottom'],
|
|
5051
5723
|
overlayModel: {
|
|
5052
5724
|
activationSize: { type: 'percentage', value: 50 },
|
|
5053
5725
|
},
|
|
5054
|
-
canDisplayOverlay
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
}
|
|
5062
|
-
const firedEvent = new PaneviewUnhandledDragOverEvent(event, position, getPaneData, this);
|
|
5063
|
-
this._onUnhandledDragOverEvent.fire(firedEvent);
|
|
5064
|
-
return firedEvent.isAccepted;
|
|
5065
|
-
},
|
|
5066
|
-
});
|
|
5067
|
-
this.addDisposables(this._onDidDrop, this.handler, this.target, this.target.onDrop((event) => {
|
|
5726
|
+
canDisplayOverlay,
|
|
5727
|
+
};
|
|
5728
|
+
this.target = html5Backend.createDropTarget(this.element, dropTargetOptions);
|
|
5729
|
+
this.pointerTarget = pointerBackend.createDropTarget(this.element, dropTargetOptions);
|
|
5730
|
+
this.addDisposables(this._onDidDrop, this.html5DragSource, this.pointerDragSource, this.target, this.pointerTarget, this.target.onDrop((event) => {
|
|
5731
|
+
this.onDrop(event);
|
|
5732
|
+
}), this.pointerTarget.onDrop((event) => {
|
|
5068
5733
|
this.onDrop(event);
|
|
5069
5734
|
}));
|
|
5070
5735
|
}
|
|
@@ -5119,6 +5784,25 @@ class ContentContainer extends CompositeDisposable {
|
|
|
5119
5784
|
this._element.tabIndex = -1;
|
|
5120
5785
|
this.addDisposables(this._onDidFocus, this._onDidBlur);
|
|
5121
5786
|
const target = group.dropTargetContainer;
|
|
5787
|
+
const canDisplayOverlay = (event, position) => {
|
|
5788
|
+
if (this.group.locked === 'no-drop-target' ||
|
|
5789
|
+
(this.group.locked && position === 'center')) {
|
|
5790
|
+
return false;
|
|
5791
|
+
}
|
|
5792
|
+
const data = getPanelData();
|
|
5793
|
+
if (!data &&
|
|
5794
|
+
event.shiftKey &&
|
|
5795
|
+
this.group.location.type !== 'floating') {
|
|
5796
|
+
return false;
|
|
5797
|
+
}
|
|
5798
|
+
if (data && data.viewId === this.accessor.id) {
|
|
5799
|
+
return true;
|
|
5800
|
+
}
|
|
5801
|
+
return this.group.canDisplayOverlay(event, position, 'content');
|
|
5802
|
+
};
|
|
5803
|
+
// `dropTarget` stays the concrete `Droptarget` (not via the backend
|
|
5804
|
+
// factory) because overlayRenderContainer forwards HTML5 drag events
|
|
5805
|
+
// through `dropTarget.dnd` — that field is not part of `IDropTarget`.
|
|
5122
5806
|
this.dropTarget = new Droptarget(this.element, {
|
|
5123
5807
|
getOverlayOutline: () => {
|
|
5124
5808
|
var _a;
|
|
@@ -5128,25 +5812,22 @@ class ContentContainer extends CompositeDisposable {
|
|
|
5128
5812
|
},
|
|
5129
5813
|
className: 'dv-drop-target-content',
|
|
5130
5814
|
acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
|
|
5131
|
-
canDisplayOverlay
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
if (data && data.viewId === this.accessor.id) {
|
|
5143
|
-
return true;
|
|
5144
|
-
}
|
|
5145
|
-
return this.group.canDisplayOverlay(event, position, 'content');
|
|
5815
|
+
canDisplayOverlay,
|
|
5816
|
+
getOverrideTarget: target ? () => target.model : undefined,
|
|
5817
|
+
});
|
|
5818
|
+
this.pointerDropTarget = pointerBackend.createDropTarget(this.element, {
|
|
5819
|
+
acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
|
|
5820
|
+
canDisplayOverlay,
|
|
5821
|
+
getOverlayOutline: () => {
|
|
5822
|
+
var _a;
|
|
5823
|
+
return ((_a = accessor.options.theme) === null || _a === void 0 ? void 0 : _a.dndPanelOverlay) === 'group'
|
|
5824
|
+
? this.element.parentElement
|
|
5825
|
+
: null;
|
|
5146
5826
|
},
|
|
5827
|
+
className: 'dv-drop-target-content',
|
|
5147
5828
|
getOverrideTarget: target ? () => target.model : undefined,
|
|
5148
5829
|
});
|
|
5149
|
-
this.addDisposables(this.dropTarget);
|
|
5830
|
+
this.addDisposables(this.dropTarget, this.pointerDropTarget);
|
|
5150
5831
|
}
|
|
5151
5832
|
show() {
|
|
5152
5833
|
this.element.style.display = '';
|
|
@@ -5234,37 +5915,169 @@ class ContentContainer extends CompositeDisposable {
|
|
|
5234
5915
|
}
|
|
5235
5916
|
}
|
|
5236
5917
|
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5918
|
+
const DEFAULT_DELAY = 500;
|
|
5919
|
+
const DEFAULT_TOLERANCE = 8;
|
|
5920
|
+
/**
|
|
5921
|
+
* Passive — does not consume the pointer; movement past `tolerance`
|
|
5922
|
+
* cancels silently so a sibling `PointerDragSource` can take over.
|
|
5923
|
+
*/
|
|
5924
|
+
class LongPressDetector extends CompositeDisposable {
|
|
5925
|
+
constructor(element, options) {
|
|
5926
|
+
super();
|
|
5927
|
+
this.element = element;
|
|
5928
|
+
this.options = options;
|
|
5929
|
+
this._startX = 0;
|
|
5930
|
+
this._startY = 0;
|
|
5931
|
+
this.addDisposables(addDisposableListener(this.element, 'pointerdown', (e) => {
|
|
5932
|
+
this._onPointerDown(e);
|
|
5933
|
+
}));
|
|
5934
|
+
}
|
|
5935
|
+
_onPointerDown(event) {
|
|
5936
|
+
var _a, _b, _c, _d, _e;
|
|
5937
|
+
const touchOnly = (_a = this.options.touchOnly) !== null && _a !== void 0 ? _a : true;
|
|
5938
|
+
if (touchOnly &&
|
|
5939
|
+
event.pointerType !== 'touch' &&
|
|
5940
|
+
event.pointerType !== 'pen') {
|
|
5941
|
+
return;
|
|
5942
|
+
}
|
|
5943
|
+
// Defensive — supersede any in-flight press.
|
|
5944
|
+
this._cancelPending();
|
|
5945
|
+
this._pointerId = event.pointerId;
|
|
5946
|
+
this._startX = event.clientX;
|
|
5947
|
+
this._startY = event.clientY;
|
|
5948
|
+
const delay = (_b = this.options.delay) !== null && _b !== void 0 ? _b : DEFAULT_DELAY;
|
|
5949
|
+
const tolerance = (_c = this.options.tolerance) !== null && _c !== void 0 ? _c : DEFAULT_TOLERANCE;
|
|
5950
|
+
// Source's owning window — popout drags fire on their own window.
|
|
5951
|
+
const targetWindow = (_e = (_d = this.element.ownerDocument) === null || _d === void 0 ? void 0 : _d.defaultView) !== null && _e !== void 0 ? _e : window;
|
|
5952
|
+
this._timer = setTimeout(() => {
|
|
5953
|
+
this._timer = undefined;
|
|
5954
|
+
this._cancelPending();
|
|
5955
|
+
// Touch browsers synthesize a compatibility `contextmenu` event
|
|
5956
|
+
// for long-press. preventDefault on the original pointerdown is
|
|
5957
|
+
// too late (already dispatched), so install a one-shot
|
|
5958
|
+
// capture-phase guard for the next contextmenu. Without this,
|
|
5959
|
+
// consumers that don't preventDefault inside their onLongPress
|
|
5960
|
+
// (or that early-return before doing so) leak the browser's
|
|
5961
|
+
// native menu on top of theirs.
|
|
5962
|
+
this._installContextMenuGuard(targetWindow);
|
|
5963
|
+
// Same idea for `click`: when the user releases their finger
|
|
5964
|
+
// after the long-press, touch browsers dispatch a `click` to
|
|
5965
|
+
// the element the touch ended on (the source). Consumers
|
|
5966
|
+
// typically wire click to a primary action (e.g. tab activate,
|
|
5967
|
+
// tab-group chip collapse-toggle). Without this guard, the
|
|
5968
|
+
// long-press immediately fires both the context menu AND the
|
|
5969
|
+
// primary action — and the action's side effects (e.g. a chip
|
|
5970
|
+
// collapse animation) read as a screen wobble while the menu
|
|
5971
|
+
// is supposed to be open. Scoped to the source element so
|
|
5972
|
+
// clicks on menu items elsewhere remain effective.
|
|
5973
|
+
this._installClickGuard(targetWindow);
|
|
5974
|
+
this.options.onLongPress(event);
|
|
5975
|
+
}, delay);
|
|
5976
|
+
this._moveListener = addDisposableListener(targetWindow, 'pointermove', (moveEvent) => {
|
|
5977
|
+
if (moveEvent.pointerId !== this._pointerId) {
|
|
5978
|
+
return;
|
|
5979
|
+
}
|
|
5980
|
+
const dx = moveEvent.clientX - this._startX;
|
|
5981
|
+
const dy = moveEvent.clientY - this._startY;
|
|
5982
|
+
if (Math.hypot(dx, dy) > tolerance) {
|
|
5983
|
+
this._cancelPending();
|
|
5984
|
+
}
|
|
5985
|
+
});
|
|
5986
|
+
this._upListener = addDisposableListener(targetWindow, 'pointerup', (upEvent) => {
|
|
5987
|
+
if (upEvent.pointerId !== this._pointerId) {
|
|
5988
|
+
return;
|
|
5989
|
+
}
|
|
5990
|
+
this._cancelPending();
|
|
5991
|
+
});
|
|
5992
|
+
this._cancelListener = addDisposableListener(targetWindow, 'pointercancel', (cancelEvent) => {
|
|
5993
|
+
if (cancelEvent.pointerId !== this._pointerId) {
|
|
5994
|
+
return;
|
|
5995
|
+
}
|
|
5996
|
+
this._cancelPending();
|
|
5997
|
+
});
|
|
5998
|
+
}
|
|
5999
|
+
_installContextMenuGuard(targetWindow) {
|
|
6000
|
+
let guard;
|
|
6001
|
+
const timeout = setTimeout(() => guard === null || guard === void 0 ? void 0 : guard.dispose(), 500);
|
|
6002
|
+
guard = addDisposableListener(targetWindow, 'contextmenu', (event) => {
|
|
6003
|
+
event.preventDefault();
|
|
6004
|
+
clearTimeout(timeout);
|
|
6005
|
+
guard === null || guard === void 0 ? void 0 : guard.dispose();
|
|
6006
|
+
}, { capture: true });
|
|
6007
|
+
}
|
|
6008
|
+
_installClickGuard(targetWindow) {
|
|
6009
|
+
let guard;
|
|
6010
|
+
const timeout = setTimeout(() => guard === null || guard === void 0 ? void 0 : guard.dispose(), 500);
|
|
6011
|
+
guard = addDisposableListener(targetWindow, 'click', (event) => {
|
|
6012
|
+
// Only suppress clicks targeted at the long-pressed element
|
|
6013
|
+
// or its descendants. A user tap on a context menu item (or
|
|
6014
|
+
// anywhere else) still gets through unchanged.
|
|
6015
|
+
const target = event.target;
|
|
6016
|
+
if (target && this.element.contains(target)) {
|
|
6017
|
+
event.preventDefault();
|
|
6018
|
+
event.stopPropagation();
|
|
6019
|
+
}
|
|
6020
|
+
clearTimeout(timeout);
|
|
6021
|
+
guard === null || guard === void 0 ? void 0 : guard.dispose();
|
|
6022
|
+
}, { capture: true });
|
|
6023
|
+
}
|
|
6024
|
+
_cancelPending() {
|
|
6025
|
+
var _a, _b, _c;
|
|
6026
|
+
if (this._timer !== undefined) {
|
|
6027
|
+
clearTimeout(this._timer);
|
|
6028
|
+
this._timer = undefined;
|
|
6029
|
+
}
|
|
6030
|
+
this._pointerId = undefined;
|
|
6031
|
+
(_a = this._moveListener) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
6032
|
+
(_b = this._upListener) === null || _b === void 0 ? void 0 : _b.dispose();
|
|
6033
|
+
(_c = this._cancelListener) === null || _c === void 0 ? void 0 : _c.dispose();
|
|
6034
|
+
this._moveListener = undefined;
|
|
6035
|
+
this._upListener = undefined;
|
|
6036
|
+
this._cancelListener = undefined;
|
|
6037
|
+
}
|
|
6038
|
+
dispose() {
|
|
6039
|
+
this._cancelPending();
|
|
6040
|
+
super.dispose();
|
|
6041
|
+
}
|
|
5249
6042
|
}
|
|
5250
6043
|
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
6044
|
+
function resolveDndCapabilities(options) {
|
|
6045
|
+
if (options.disableDnd) {
|
|
6046
|
+
return { html5: false, pointer: false, pointerHandlesMouse: false };
|
|
6047
|
+
}
|
|
6048
|
+
switch (options.dndStrategy) {
|
|
6049
|
+
case 'pointer':
|
|
6050
|
+
return { html5: false, pointer: true, pointerHandlesMouse: true };
|
|
6051
|
+
case 'html5':
|
|
6052
|
+
return { html5: true, pointer: false, pointerHandlesMouse: false };
|
|
6053
|
+
case 'auto':
|
|
6054
|
+
case undefined:
|
|
6055
|
+
default:
|
|
6056
|
+
// On touch-primary devices (phones / basic tablets) HTML5 DnD's
|
|
6057
|
+
// native long-press intercepts the gesture before our pointer
|
|
6058
|
+
// backend can react — Android Chrome launches a system drag with
|
|
6059
|
+
// its half-transparent thumbnail, and the long-press context menu
|
|
6060
|
+
// never opens. Disable HTML5 there so the pointer backend owns
|
|
6061
|
+
// every gesture. Hybrid devices (touchscreen laptops, Surface,
|
|
6062
|
+
// iPad with mouse) keep both backends — mouse uses HTML5, touch
|
|
6063
|
+
// falls back to whichever backend the underlying element wired.
|
|
6064
|
+
return isCoarsePrimaryInput$2()
|
|
6065
|
+
? { html5: false, pointer: true, pointerHandlesMouse: true }
|
|
6066
|
+
: { html5: true, pointer: true, pointerHandlesMouse: false };
|
|
5258
6067
|
}
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
this.panelTransfer.clearData(PanelTransfer.prototype);
|
|
5264
|
-
},
|
|
5265
|
-
};
|
|
6068
|
+
}
|
|
6069
|
+
function isCoarsePrimaryInput$2() {
|
|
6070
|
+
if (typeof window === 'undefined' || !window.matchMedia) {
|
|
6071
|
+
return false;
|
|
5266
6072
|
}
|
|
6073
|
+
// Coarse pointer without any fine pointer = phone-class device. A laptop
|
|
6074
|
+
// touchscreen reports both, and we want HTML5 to remain available there
|
|
6075
|
+
// because a real mouse is also plugged in.
|
|
6076
|
+
const coarse = window.matchMedia('(pointer: coarse)').matches;
|
|
6077
|
+
const fine = window.matchMedia('(pointer: fine)').matches;
|
|
6078
|
+
return coarse && !fine;
|
|
5267
6079
|
}
|
|
6080
|
+
|
|
5268
6081
|
class Tab extends CompositeDisposable {
|
|
5269
6082
|
get element() {
|
|
5270
6083
|
return this._element;
|
|
@@ -5275,6 +6088,7 @@ class Tab extends CompositeDisposable {
|
|
|
5275
6088
|
this.accessor = accessor;
|
|
5276
6089
|
this.group = group;
|
|
5277
6090
|
this.content = undefined;
|
|
6091
|
+
this.panelTransfer = LocalSelectionTransfer.getInstance();
|
|
5278
6092
|
this._direction = 'horizontal';
|
|
5279
6093
|
this._onPointDown = new Emitter();
|
|
5280
6094
|
this.onPointerDown = this._onPointDown.event;
|
|
@@ -5286,114 +6100,106 @@ class Tab extends CompositeDisposable {
|
|
|
5286
6100
|
this.onDragStart = this._onDragStart.event;
|
|
5287
6101
|
this._onDragEnd = new Emitter();
|
|
5288
6102
|
this.onDragEnd = this._onDragEnd.event;
|
|
6103
|
+
const caps = resolveDndCapabilities(this.accessor.options);
|
|
5289
6104
|
this._element = document.createElement('div');
|
|
5290
6105
|
this._element.className = 'dv-tab';
|
|
5291
6106
|
this._element.tabIndex = 0;
|
|
5292
|
-
this._element.draggable =
|
|
6107
|
+
this._element.draggable = caps.html5;
|
|
5293
6108
|
toggleClass(this.element, 'dv-inactive-tab', true);
|
|
5294
|
-
|
|
5295
|
-
|
|
6109
|
+
const canDisplayOverlay = (event, position) => {
|
|
6110
|
+
var _a;
|
|
6111
|
+
if (this.group.locked) {
|
|
6112
|
+
return false;
|
|
6113
|
+
}
|
|
6114
|
+
const data = getPanelData();
|
|
6115
|
+
if (data && this.accessor.id === data.viewId) {
|
|
6116
|
+
// Smooth-reorder takes over the in-flight visual when active,
|
|
6117
|
+
// so individual tab overlays are suppressed for internal drags.
|
|
6118
|
+
if (((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) === 'smooth') {
|
|
6119
|
+
return false;
|
|
6120
|
+
}
|
|
6121
|
+
return true;
|
|
6122
|
+
}
|
|
6123
|
+
return this.group.model.canDisplayOverlay(event, position, 'tab');
|
|
6124
|
+
};
|
|
6125
|
+
this.dropTarget = html5Backend.createDropTarget(this._element, {
|
|
5296
6126
|
acceptedTargetZones: ['left', 'right'],
|
|
5297
6127
|
overlayModel: this._buildOverlayModel(),
|
|
5298
|
-
canDisplayOverlay
|
|
6128
|
+
canDisplayOverlay,
|
|
6129
|
+
getOverrideTarget: () => { var _a; return (_a = group.model.dropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
|
|
6130
|
+
});
|
|
6131
|
+
this.pointerDropTarget = pointerBackend.createDropTarget(this._element, {
|
|
6132
|
+
acceptedTargetZones: ['left', 'right'],
|
|
6133
|
+
overlayModel: this._buildOverlayModel(),
|
|
6134
|
+
canDisplayOverlay,
|
|
6135
|
+
getOverrideTarget: () => { var _a; return (_a = group.model.dropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
|
|
6136
|
+
});
|
|
6137
|
+
const sharedDragOptions = {
|
|
6138
|
+
getData: () => {
|
|
6139
|
+
this.panelTransfer.setData([
|
|
6140
|
+
new PanelTransfer(this.accessor.id, this.group.id, this.panel.id),
|
|
6141
|
+
], PanelTransfer.prototype);
|
|
6142
|
+
return {
|
|
6143
|
+
dispose: () => {
|
|
6144
|
+
this.panelTransfer.clearData(PanelTransfer.prototype);
|
|
6145
|
+
},
|
|
6146
|
+
};
|
|
6147
|
+
},
|
|
6148
|
+
// 30/-10 matches the HTML5 setDragImage offset that has been
|
|
6149
|
+
// shipped for years; pointer backend wraps in PointerGhost,
|
|
6150
|
+
// HTML5 backend feeds into setDragImage.
|
|
6151
|
+
createGhost: () => ({
|
|
6152
|
+
element: this._buildGhostElement(),
|
|
6153
|
+
offsetX: 30,
|
|
6154
|
+
offsetY: -10,
|
|
6155
|
+
}),
|
|
6156
|
+
onDragStart: (event) => {
|
|
5299
6157
|
var _a;
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
// (both same-group and cross-group) via
|
|
5309
|
-
// animation. Suppress the per-tab overlay so
|
|
5310
|
-
// the tab is dropped *beside* rather than *on*.
|
|
5311
|
-
return false;
|
|
5312
|
-
}
|
|
5313
|
-
return true;
|
|
6158
|
+
this._onDragStart.fire(event);
|
|
6159
|
+
if (!(event instanceof PointerEvent) &&
|
|
6160
|
+
((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) === 'smooth') {
|
|
6161
|
+
// Delay collapse to next frame so the browser
|
|
6162
|
+
// captures the full drag image first.
|
|
6163
|
+
requestAnimationFrame(() => {
|
|
6164
|
+
toggleClass(this.element, 'dv-tab--dragging', true);
|
|
6165
|
+
});
|
|
5314
6166
|
}
|
|
5315
|
-
return this.group.model.canDisplayOverlay(event, position, 'tab');
|
|
5316
6167
|
},
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
6168
|
+
onDragEnd: (event) => {
|
|
6169
|
+
this._onDragEnd.fire(event);
|
|
6170
|
+
},
|
|
6171
|
+
};
|
|
6172
|
+
this.html5DragSource = html5Backend.createDragSource(this._element, Object.assign(Object.assign({}, sharedDragOptions), { disabled: !caps.html5 }));
|
|
6173
|
+
this.pointerDragSource = pointerBackend.createDragSource(this._element, Object.assign(Object.assign({}, sharedDragOptions), { disabled: !caps.pointer, touchOnly: !caps.pointerHandlesMouse, isCancelled: () => !resolveDndCapabilities(this.accessor.options).pointer }));
|
|
6174
|
+
// Both droptargets feed the same downstream stream; consumers don't
|
|
6175
|
+
// need to know which path produced the overlay.
|
|
6176
|
+
this.onWillShowOverlay = Event.any(this.dropTarget.onWillShowOverlay, this.pointerDropTarget.onWillShowOverlay);
|
|
5320
6177
|
this.addDisposables(this._onPointDown, this._onTabClick, this._onDropped, this._onDragStart, this._onDragEnd, this.accessor.onDidOptionsChange(() => {
|
|
5321
|
-
this.
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
const isVertical = this._direction === 'vertical';
|
|
5328
|
-
/**
|
|
5329
|
-
* Properties to skip when copying computed styles for a
|
|
5330
|
-
* vertical tab ghost. `writing-mode` is excluded so we
|
|
5331
|
-
* can force `horizontal-tb`. Size and margin logical
|
|
5332
|
-
* properties are excluded because their physical meaning
|
|
5333
|
-
* flips when writing-mode changes, which would produce
|
|
5334
|
-
* incorrect dimensions.
|
|
5335
|
-
*/
|
|
5336
|
-
const verticalSkip = new Set([
|
|
5337
|
-
'writing-mode',
|
|
5338
|
-
'inline-size',
|
|
5339
|
-
'block-size',
|
|
5340
|
-
'min-inline-size',
|
|
5341
|
-
'min-block-size',
|
|
5342
|
-
'max-inline-size',
|
|
5343
|
-
'max-block-size',
|
|
5344
|
-
'margin-inline',
|
|
5345
|
-
'margin-inline-start',
|
|
5346
|
-
'margin-inline-end',
|
|
5347
|
-
'margin-block',
|
|
5348
|
-
'margin-block-start',
|
|
5349
|
-
'margin-block-end',
|
|
5350
|
-
'padding-inline',
|
|
5351
|
-
'padding-inline-start',
|
|
5352
|
-
'padding-inline-end',
|
|
5353
|
-
'padding-block',
|
|
5354
|
-
'padding-block-start',
|
|
5355
|
-
'padding-block-end',
|
|
5356
|
-
]);
|
|
5357
|
-
Array.from(style).forEach((key) => {
|
|
5358
|
-
if (isVertical && verticalSkip.has(key)) {
|
|
5359
|
-
return;
|
|
5360
|
-
}
|
|
5361
|
-
newNode.style.setProperty(key, style.getPropertyValue(key), style.getPropertyPriority(key));
|
|
5362
|
-
});
|
|
5363
|
-
if (isVertical) {
|
|
5364
|
-
// Force horizontal text flow and swap the physical
|
|
5365
|
-
// dimensions so the ghost appears as a horizontal tab.
|
|
5366
|
-
newNode.style.setProperty('writing-mode', 'horizontal-tb');
|
|
5367
|
-
newNode.style.setProperty('width', style.height);
|
|
5368
|
-
newNode.style.setProperty('height', style.width);
|
|
5369
|
-
}
|
|
5370
|
-
newNode.style.position = 'absolute';
|
|
5371
|
-
newNode.classList.add('dv-tab-ghost-drag');
|
|
5372
|
-
addGhostImage(event.dataTransfer, newNode, {
|
|
5373
|
-
y: -10,
|
|
5374
|
-
x: 30,
|
|
5375
|
-
});
|
|
5376
|
-
}
|
|
5377
|
-
this._onDragStart.fire(event);
|
|
5378
|
-
if (((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) === 'smooth') {
|
|
5379
|
-
// Delay collapse to next frame so the browser
|
|
5380
|
-
// captures the full drag image first
|
|
5381
|
-
requestAnimationFrame(() => {
|
|
5382
|
-
toggleClass(this.element, 'dv-tab--dragging', true);
|
|
5383
|
-
});
|
|
5384
|
-
}
|
|
5385
|
-
}), addDisposableListener(this._element, 'dragend', (event) => {
|
|
6178
|
+
const model = this._buildOverlayModel();
|
|
6179
|
+
this.dropTarget.setOverlayModel(model);
|
|
6180
|
+
this.pointerDropTarget.setOverlayModel(model);
|
|
6181
|
+
}), addDisposableListener(this._element, 'dragend', () => {
|
|
6182
|
+
// The shared onDragEnd handler already fires _onDragEnd via
|
|
6183
|
+
// the HTML5 backend; just strip the dragging class here.
|
|
5386
6184
|
toggleClass(this.element, 'dv-tab--dragging', false);
|
|
5387
|
-
|
|
5388
|
-
}), this.dragHandler, addDisposableListener(this._element, 'pointerdown', (event) => {
|
|
6185
|
+
}), this.html5DragSource, addDisposableListener(this._element, 'pointerdown', (event) => {
|
|
5389
6186
|
this._onPointDown.fire(event);
|
|
5390
6187
|
}), addDisposableListener(this._element, 'click', (event) => {
|
|
5391
6188
|
this._onTabClick.fire(event);
|
|
5392
6189
|
}), addDisposableListener(this._element, 'contextmenu', (event) => {
|
|
5393
6190
|
this.accessor.contextMenuController.show(this.panel, this.group, event);
|
|
6191
|
+
}), new LongPressDetector(this._element, {
|
|
6192
|
+
onLongPress: (event) => {
|
|
6193
|
+
// Don't let a subsequent finger move arm a drag on top
|
|
6194
|
+
// of the just-opened menu.
|
|
6195
|
+
this.pointerDragSource.cancelPending();
|
|
6196
|
+
this.accessor.contextMenuController.show(this.panel, this.group, event);
|
|
6197
|
+
},
|
|
5394
6198
|
}), this.dropTarget.onDrop((event) => {
|
|
5395
6199
|
this._onDropped.fire(event);
|
|
5396
|
-
}), this.
|
|
6200
|
+
}), this.pointerDropTarget.onDrop((event) => {
|
|
6201
|
+
this._onDropped.fire(event);
|
|
6202
|
+
}), this.dropTarget, this.pointerDropTarget, this.pointerDragSource);
|
|
5397
6203
|
}
|
|
5398
6204
|
setActive(isActive) {
|
|
5399
6205
|
toggleClass(this.element, 'dv-active-tab', isActive);
|
|
@@ -5423,11 +6229,60 @@ class Tab extends CompositeDisposable {
|
|
|
5423
6229
|
}
|
|
5424
6230
|
setDirection(direction) {
|
|
5425
6231
|
this._direction = direction;
|
|
5426
|
-
|
|
6232
|
+
const zones = direction === 'vertical' ? ['top', 'bottom'] : ['left', 'right'];
|
|
6233
|
+
this.dropTarget.setTargetZones(zones);
|
|
6234
|
+
this.pointerDropTarget.setTargetZones(zones);
|
|
5427
6235
|
}
|
|
5428
6236
|
updateDragAndDropState() {
|
|
5429
|
-
|
|
5430
|
-
this.
|
|
6237
|
+
const caps = resolveDndCapabilities(this.accessor.options);
|
|
6238
|
+
this._element.draggable = caps.html5;
|
|
6239
|
+
this.html5DragSource.setDisabled(!caps.html5);
|
|
6240
|
+
this.pointerDragSource.setDisabled(!caps.pointer);
|
|
6241
|
+
this.pointerDragSource.setTouchOnly(!caps.pointerHandlesMouse);
|
|
6242
|
+
}
|
|
6243
|
+
/**
|
|
6244
|
+
* Vertical tabs are flipped to horizontal so the ghost stays readable
|
|
6245
|
+
* during the drag rather than appearing sideways-rotated.
|
|
6246
|
+
*/
|
|
6247
|
+
_buildGhostElement() {
|
|
6248
|
+
const style = getComputedStyle(this.element);
|
|
6249
|
+
const newNode = this.element.cloneNode(true);
|
|
6250
|
+
const isVertical = this._direction === 'vertical';
|
|
6251
|
+
const verticalSkip = new Set([
|
|
6252
|
+
'writing-mode',
|
|
6253
|
+
'inline-size',
|
|
6254
|
+
'block-size',
|
|
6255
|
+
'min-inline-size',
|
|
6256
|
+
'min-block-size',
|
|
6257
|
+
'max-inline-size',
|
|
6258
|
+
'max-block-size',
|
|
6259
|
+
'margin-inline',
|
|
6260
|
+
'margin-inline-start',
|
|
6261
|
+
'margin-inline-end',
|
|
6262
|
+
'margin-block',
|
|
6263
|
+
'margin-block-start',
|
|
6264
|
+
'margin-block-end',
|
|
6265
|
+
'padding-inline',
|
|
6266
|
+
'padding-inline-start',
|
|
6267
|
+
'padding-inline-end',
|
|
6268
|
+
'padding-block',
|
|
6269
|
+
'padding-block-start',
|
|
6270
|
+
'padding-block-end',
|
|
6271
|
+
]);
|
|
6272
|
+
Array.from(style).forEach((key) => {
|
|
6273
|
+
if (isVertical && verticalSkip.has(key)) {
|
|
6274
|
+
return;
|
|
6275
|
+
}
|
|
6276
|
+
newNode.style.setProperty(key, style.getPropertyValue(key), style.getPropertyPriority(key));
|
|
6277
|
+
});
|
|
6278
|
+
if (isVertical) {
|
|
6279
|
+
newNode.style.setProperty('writing-mode', 'horizontal-tb');
|
|
6280
|
+
newNode.style.setProperty('width', style.height);
|
|
6281
|
+
newNode.style.setProperty('height', style.width);
|
|
6282
|
+
}
|
|
6283
|
+
newNode.style.position = 'absolute';
|
|
6284
|
+
newNode.classList.add('dv-tab-ghost-drag');
|
|
6285
|
+
return newNode;
|
|
5431
6286
|
}
|
|
5432
6287
|
}
|
|
5433
6288
|
|
|
@@ -5435,6 +6290,7 @@ class DockviewWillShowOverlayLocationEvent {
|
|
|
5435
6290
|
get kind() {
|
|
5436
6291
|
return this.options.kind;
|
|
5437
6292
|
}
|
|
6293
|
+
/** Narrow with `instanceof DragEvent` before reading `dataTransfer`. */
|
|
5438
6294
|
get nativeEvent() {
|
|
5439
6295
|
return this.event.nativeEvent;
|
|
5440
6296
|
}
|
|
@@ -5465,131 +6321,202 @@ class DockviewWillShowOverlayLocationEvent {
|
|
|
5465
6321
|
}
|
|
5466
6322
|
}
|
|
5467
6323
|
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
this.panelTransfer = LocalSelectionTransfer.getInstance();
|
|
5474
|
-
this.addDisposables(addDisposableListener(element, 'pointerdown', (e) => {
|
|
5475
|
-
if (e.shiftKey) {
|
|
5476
|
-
/**
|
|
5477
|
-
* You cannot call e.preventDefault() because that will prevent drag events from firing
|
|
5478
|
-
* but we also need to stop any group overlay drag events from occuring
|
|
5479
|
-
* Use a custom event marker that can be checked by the overlay drag events
|
|
5480
|
-
*/
|
|
5481
|
-
quasiPreventDefault(e);
|
|
5482
|
-
}
|
|
5483
|
-
}, true));
|
|
5484
|
-
}
|
|
5485
|
-
isCancelled(_event) {
|
|
5486
|
-
if (this.group.api.location.type === 'floating' && !_event.shiftKey) {
|
|
5487
|
-
return true;
|
|
5488
|
-
}
|
|
5489
|
-
if (this.group.api.location.type === 'edge' && this.group.size === 0) {
|
|
5490
|
-
return true;
|
|
5491
|
-
}
|
|
5492
|
-
return false;
|
|
5493
|
-
}
|
|
5494
|
-
getData(dragEvent) {
|
|
5495
|
-
const dataTransfer = dragEvent.dataTransfer;
|
|
5496
|
-
this.panelTransfer.setData([new PanelTransfer(this.accessor.id, this.group.id, null)], PanelTransfer.prototype);
|
|
5497
|
-
const style = window.getComputedStyle(this.el);
|
|
5498
|
-
const bgColor = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-background-color');
|
|
5499
|
-
const color = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-color');
|
|
5500
|
-
if (dataTransfer) {
|
|
5501
|
-
const createGhost = this.accessor.options.createGroupDragGhostComponent;
|
|
5502
|
-
let ghostElement;
|
|
5503
|
-
let customRenderer;
|
|
5504
|
-
if (createGhost) {
|
|
5505
|
-
customRenderer = createGhost(this.group);
|
|
5506
|
-
customRenderer.init({
|
|
5507
|
-
group: this.group,
|
|
5508
|
-
api: this.accessor.api,
|
|
5509
|
-
});
|
|
5510
|
-
ghostElement = customRenderer.element;
|
|
5511
|
-
ghostElement.style.position = 'absolute';
|
|
5512
|
-
ghostElement.style.pointerEvents = 'none';
|
|
5513
|
-
ghostElement.style.top = '-9999px';
|
|
5514
|
-
}
|
|
5515
|
-
else {
|
|
5516
|
-
ghostElement = document.createElement('div');
|
|
5517
|
-
ghostElement.style.backgroundColor = bgColor;
|
|
5518
|
-
ghostElement.style.color = color;
|
|
5519
|
-
ghostElement.style.padding = '2px 8px';
|
|
5520
|
-
ghostElement.style.height = '24px';
|
|
5521
|
-
ghostElement.style.fontSize = '11px';
|
|
5522
|
-
ghostElement.style.lineHeight = '20px';
|
|
5523
|
-
ghostElement.style.borderRadius = '12px';
|
|
5524
|
-
ghostElement.style.position = 'absolute';
|
|
5525
|
-
ghostElement.style.pointerEvents = 'none';
|
|
5526
|
-
ghostElement.style.top = '-9999px';
|
|
5527
|
-
ghostElement.textContent = `Multiple Panels (${this.group.size})`;
|
|
5528
|
-
}
|
|
5529
|
-
addGhostImage(dataTransfer, ghostElement, { y: -10, x: 30 });
|
|
5530
|
-
if (customRenderer === null || customRenderer === void 0 ? void 0 : customRenderer.dispose) {
|
|
5531
|
-
// addGhostImage removes the element from the DOM on the next
|
|
5532
|
-
// tick; dispose the framework renderer on the same schedule.
|
|
5533
|
-
const renderer = customRenderer;
|
|
5534
|
-
setTimeout(() => { var _a; return (_a = renderer.dispose) === null || _a === void 0 ? void 0 : _a.call(renderer); }, 0);
|
|
5535
|
-
}
|
|
5536
|
-
}
|
|
5537
|
-
return {
|
|
5538
|
-
dispose: () => {
|
|
5539
|
-
this.panelTransfer.clearData(PanelTransfer.prototype);
|
|
5540
|
-
},
|
|
5541
|
-
};
|
|
5542
|
-
}
|
|
5543
|
-
}
|
|
5544
|
-
|
|
6324
|
+
// Floating-group redock via touch: require a deliberate long press so the
|
|
6325
|
+
// "move the float around" gesture doesn't double-trigger the redock ghost.
|
|
6326
|
+
// Infinity pressTolerance disables the pre-arm flick override; any motion
|
|
6327
|
+
// during the wait is treated as drag-the-float, not redock intent.
|
|
6328
|
+
const FLOATING_REDOCK_INITIATION_DELAY_MS = 500;
|
|
5545
6329
|
class VoidContainer extends CompositeDisposable {
|
|
5546
6330
|
get element() {
|
|
5547
6331
|
return this._element;
|
|
5548
6332
|
}
|
|
5549
6333
|
constructor(accessor, group) {
|
|
6334
|
+
var _a, _b;
|
|
5550
6335
|
super();
|
|
5551
6336
|
this.accessor = accessor;
|
|
5552
6337
|
this.group = group;
|
|
6338
|
+
this.panelTransfer = LocalSelectionTransfer.getInstance();
|
|
5553
6339
|
this._onDrop = new Emitter();
|
|
5554
6340
|
this.onDrop = this._onDrop.event;
|
|
5555
6341
|
this._onDragStart = new Emitter();
|
|
5556
6342
|
this.onDragStart = this._onDragStart.event;
|
|
6343
|
+
const caps = resolveDndCapabilities(this.accessor.options);
|
|
5557
6344
|
this._element = document.createElement('div');
|
|
5558
6345
|
this._element.className = 'dv-void-container';
|
|
5559
|
-
this._element.draggable =
|
|
5560
|
-
toggleClass(this._element, 'dv-draggable',
|
|
6346
|
+
this._element.draggable = caps.html5;
|
|
6347
|
+
toggleClass(this._element, 'dv-draggable', caps.html5 || caps.pointer);
|
|
5561
6348
|
this.addDisposables(this._onDrop, this._onDragStart, addDisposableListener(this._element, 'pointerdown', () => {
|
|
5562
6349
|
this.accessor.doSetGroupActive(this.group);
|
|
5563
|
-
})
|
|
5564
|
-
|
|
5565
|
-
|
|
6350
|
+
}),
|
|
6351
|
+
// Shift+pointerdown marks the event so the group's overlay
|
|
6352
|
+
// drag (move-by-floating) sees it was consumed and doesn't
|
|
6353
|
+
// fire alongside the HTML5 drag. quasiPreventDefault sets the
|
|
6354
|
+
// marker without calling preventDefault — that would also
|
|
6355
|
+
// block dragstart, which we need to fire.
|
|
6356
|
+
addDisposableListener(this._element, 'pointerdown', (e) => {
|
|
6357
|
+
if (e.shiftKey) {
|
|
6358
|
+
quasiPreventDefault(e);
|
|
6359
|
+
}
|
|
6360
|
+
}, true));
|
|
6361
|
+
const canDisplayOverlay = (event, position) => {
|
|
6362
|
+
if (this.group.api.locked) {
|
|
6363
|
+
// Dropping on the void/header space adds the panel
|
|
6364
|
+
// to this group, which `locked` is meant to prevent
|
|
6365
|
+
// (both `true` and `'no-drop-target'`).
|
|
6366
|
+
return false;
|
|
6367
|
+
}
|
|
6368
|
+
const data = getPanelData();
|
|
6369
|
+
if (data && this.accessor.id === data.viewId) {
|
|
6370
|
+
return true;
|
|
6371
|
+
}
|
|
6372
|
+
return group.model.canDisplayOverlay(event, position, 'header_space');
|
|
6373
|
+
};
|
|
6374
|
+
this.dropTarget = html5Backend.createDropTarget(this._element, {
|
|
5566
6375
|
acceptedTargetZones: ['center'],
|
|
5567
|
-
canDisplayOverlay
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
6376
|
+
canDisplayOverlay,
|
|
6377
|
+
getOverrideTarget: () => { var _a; return (_a = group.model.dropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
|
|
6378
|
+
});
|
|
6379
|
+
this.pointerDropTarget = pointerBackend.createDropTarget(this._element, {
|
|
6380
|
+
acceptedTargetZones: ['center'],
|
|
6381
|
+
canDisplayOverlay,
|
|
6382
|
+
getOverrideTarget: () => { var _a; return (_a = group.model.dropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
|
|
6383
|
+
});
|
|
6384
|
+
const buildMultiPanelsGhost = () => {
|
|
6385
|
+
const ghostEl = document.createElement('div');
|
|
6386
|
+
const style = window.getComputedStyle(this._element);
|
|
6387
|
+
const bgColor = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-background-color');
|
|
6388
|
+
const color = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-color');
|
|
6389
|
+
ghostEl.style.backgroundColor = bgColor;
|
|
6390
|
+
ghostEl.style.color = color;
|
|
6391
|
+
ghostEl.style.padding = '2px 8px';
|
|
6392
|
+
ghostEl.style.height = '24px';
|
|
6393
|
+
ghostEl.style.fontSize = '11px';
|
|
6394
|
+
ghostEl.style.lineHeight = '20px';
|
|
6395
|
+
ghostEl.style.borderRadius = '12px';
|
|
6396
|
+
ghostEl.style.whiteSpace = 'nowrap';
|
|
6397
|
+
ghostEl.style.boxSizing = 'border-box';
|
|
6398
|
+
// HTML5 setDragImage snapshots the element as appended to the
|
|
6399
|
+
// document; a default block-level div would stretch to the
|
|
6400
|
+
// body's width and render as a viewport-wide bar.
|
|
6401
|
+
ghostEl.style.display = 'inline-block';
|
|
6402
|
+
ghostEl.textContent = `Multiple Panels (${this.group.size})`;
|
|
6403
|
+
return ghostEl;
|
|
6404
|
+
};
|
|
6405
|
+
const buildGhostSpec = () => {
|
|
6406
|
+
const createGhost = this.accessor.options.createGroupDragGhostComponent;
|
|
6407
|
+
if (createGhost) {
|
|
6408
|
+
const renderer = createGhost(this.group);
|
|
6409
|
+
renderer.init({
|
|
6410
|
+
group: this.group,
|
|
6411
|
+
api: this.accessor.api,
|
|
6412
|
+
});
|
|
6413
|
+
return {
|
|
6414
|
+
element: renderer.element,
|
|
6415
|
+
offsetX: 30,
|
|
6416
|
+
offsetY: -10,
|
|
6417
|
+
dispose: renderer.dispose
|
|
6418
|
+
? () => { var _a; return (_a = renderer.dispose) === null || _a === void 0 ? void 0 : _a.call(renderer); }
|
|
6419
|
+
: undefined,
|
|
6420
|
+
};
|
|
6421
|
+
}
|
|
6422
|
+
return {
|
|
6423
|
+
element: buildMultiPanelsGhost(),
|
|
6424
|
+
offsetX: 30,
|
|
6425
|
+
offsetY: -10,
|
|
6426
|
+
};
|
|
6427
|
+
};
|
|
6428
|
+
const sharedDragOptions = {
|
|
6429
|
+
getData: () => {
|
|
6430
|
+
this.panelTransfer.setData([new PanelTransfer(this.accessor.id, this.group.id, null)], PanelTransfer.prototype);
|
|
6431
|
+
return {
|
|
6432
|
+
dispose: () => {
|
|
6433
|
+
this.panelTransfer.clearData(PanelTransfer.prototype);
|
|
6434
|
+
},
|
|
6435
|
+
};
|
|
6436
|
+
},
|
|
6437
|
+
createGhost: buildGhostSpec,
|
|
6438
|
+
onDragStart: (event) => {
|
|
6439
|
+
this._onDragStart.fire(event);
|
|
6440
|
+
},
|
|
6441
|
+
};
|
|
6442
|
+
this.html5DragSource = html5Backend.createDragSource(this._element, Object.assign(Object.assign({}, sharedDragOptions), { disabled: !caps.html5, isCancelled: (event) => {
|
|
6443
|
+
// HTML5: floating groups need shift+drag as the explicit
|
|
6444
|
+
// detach gesture (otherwise click-and-drag conflicts with
|
|
6445
|
+
// moving the floating group itself).
|
|
6446
|
+
if (this.group.api.location.type === 'floating' &&
|
|
6447
|
+
!event.shiftKey) {
|
|
6448
|
+
return true;
|
|
5573
6449
|
}
|
|
5574
|
-
|
|
5575
|
-
|
|
6450
|
+
if (this.group.api.location.type === 'edge' &&
|
|
6451
|
+
this.group.size === 0) {
|
|
5576
6452
|
return true;
|
|
5577
6453
|
}
|
|
5578
|
-
return
|
|
5579
|
-
}
|
|
5580
|
-
|
|
5581
|
-
})
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
6454
|
+
return false;
|
|
6455
|
+
} }));
|
|
6456
|
+
const isFloating = () => { 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'; };
|
|
6457
|
+
this.pointerDragSource = pointerBackend.createDragSource(this._element, Object.assign(Object.assign({}, sharedDragOptions), { disabled: !caps.pointer, touchOnly: !caps.pointerHandlesMouse,
|
|
6458
|
+
// Floating groups share this element with the overlay's
|
|
6459
|
+
// move-the-float drag. Without a longer hold + tolerance
|
|
6460
|
+
// override, both gestures commit simultaneously and the
|
|
6461
|
+
// user sees the float follow their finger *and* a ghost.
|
|
6462
|
+
touchInitiationDelay: () => isFloating() ? FLOATING_REDOCK_INITIATION_DELAY_MS : 250, pressTolerance: () => (isFloating() ? Infinity : 8), isCancelled: () => {
|
|
6463
|
+
if (!resolveDndCapabilities(this.accessor.options).pointer) {
|
|
6464
|
+
return true;
|
|
6465
|
+
}
|
|
6466
|
+
// Pointer: long-press IS the deliberate gesture, so
|
|
6467
|
+
// floating groups don't need the shift gate.
|
|
6468
|
+
if (this.group.api.location.type === 'edge' &&
|
|
6469
|
+
this.group.size === 0) {
|
|
6470
|
+
return true;
|
|
6471
|
+
}
|
|
6472
|
+
return false;
|
|
6473
|
+
}, onDragStart: (event) => {
|
|
6474
|
+
var _a;
|
|
6475
|
+
// Redock just committed — abort any in-flight overlay
|
|
6476
|
+
// move so the float stops following the finger while
|
|
6477
|
+
// the ghost takes over.
|
|
6478
|
+
(_a = this.getFloatingOverlay()) === null || _a === void 0 ? void 0 : _a.cancelPendingDrag();
|
|
6479
|
+
this._onDragStart.fire(event);
|
|
6480
|
+
} }));
|
|
6481
|
+
// Mirror direction: once the overlay's move-the-float gesture has
|
|
6482
|
+
// actually moved something, cancel the pending redock arm so the
|
|
6483
|
+
// ghost doesn't appear mid-drag if the user holds past 500ms.
|
|
6484
|
+
const overlayMoveSub = new MutableDisposable();
|
|
6485
|
+
const refreshOverlayMoveSub = () => {
|
|
6486
|
+
const overlay = this.getFloatingOverlay();
|
|
6487
|
+
overlayMoveSub.value = overlay
|
|
6488
|
+
? overlay.onDidStartMoving(() => {
|
|
6489
|
+
this.pointerDragSource.cancelPending();
|
|
6490
|
+
})
|
|
6491
|
+
: Disposable.NONE;
|
|
6492
|
+
};
|
|
6493
|
+
refreshOverlayMoveSub();
|
|
6494
|
+
this.addDisposables(overlayMoveSub);
|
|
6495
|
+
const locationChange = (_b = (_a = this.group) === null || _a === void 0 ? void 0 : _a.api) === null || _b === void 0 ? void 0 : _b.onDidLocationChange;
|
|
6496
|
+
if (locationChange) {
|
|
6497
|
+
this.addDisposables(locationChange(refreshOverlayMoveSub));
|
|
6498
|
+
}
|
|
6499
|
+
this.onWillShowOverlay = Event.any(this.dropTarget.onWillShowOverlay, this.pointerDropTarget.onWillShowOverlay);
|
|
6500
|
+
this.addDisposables(this.html5DragSource, this.dropTarget.onDrop((event) => {
|
|
6501
|
+
this._onDrop.fire(event);
|
|
6502
|
+
}), this.pointerDropTarget.onDrop((event) => {
|
|
5586
6503
|
this._onDrop.fire(event);
|
|
5587
|
-
}), this.dropTarget);
|
|
6504
|
+
}), this.dropTarget, this.pointerDropTarget, this.pointerDragSource);
|
|
5588
6505
|
}
|
|
5589
6506
|
updateDragAndDropState() {
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
6507
|
+
const caps = resolveDndCapabilities(this.accessor.options);
|
|
6508
|
+
this._element.draggable = caps.html5;
|
|
6509
|
+
toggleClass(this._element, 'dv-draggable', caps.html5 || caps.pointer);
|
|
6510
|
+
this.html5DragSource.setDisabled(!caps.html5);
|
|
6511
|
+
this.pointerDragSource.setDisabled(!caps.pointer);
|
|
6512
|
+
this.pointerDragSource.setTouchOnly(!caps.pointerHandlesMouse);
|
|
6513
|
+
}
|
|
6514
|
+
getFloatingOverlay() {
|
|
6515
|
+
var _a, _b;
|
|
6516
|
+
if (!this.group) {
|
|
6517
|
+
return undefined;
|
|
6518
|
+
}
|
|
6519
|
+
return (_b = (_a = this.accessor.floatingGroups) === null || _a === void 0 ? void 0 : _a.find((fg) => fg.group === this.group)) === null || _b === void 0 ? void 0 : _b.overlay;
|
|
5593
6520
|
}
|
|
5594
6521
|
}
|
|
5595
6522
|
|
|
@@ -5845,6 +6772,14 @@ function resolveTabGroupAccent(color, palette) {
|
|
|
5845
6772
|
return (palette !== null && palette !== void 0 ? palette : getFallbackPalette()).resolveValue(color);
|
|
5846
6773
|
}
|
|
5847
6774
|
|
|
6775
|
+
/**
|
|
6776
|
+
* Visual chip for a tab group. Owns the DOM element, label, click /
|
|
6777
|
+
* context-menu interactions, and exposes a long-press gesture as a
|
|
6778
|
+
* second `onContextMenu` source. Drag-and-drop wiring lives in
|
|
6779
|
+
* `TabGroupManager` — the manager constructs the drag sources on this
|
|
6780
|
+
* chip's element so it can include tabs-list context (custom group
|
|
6781
|
+
* drag image, tab-group transfer payload).
|
|
6782
|
+
*/
|
|
5848
6783
|
class TabGroupChip extends CompositeDisposable {
|
|
5849
6784
|
get element() {
|
|
5850
6785
|
return this._element;
|
|
@@ -5855,22 +6790,22 @@ class TabGroupChip extends CompositeDisposable {
|
|
|
5855
6790
|
this._onClick = new Emitter();
|
|
5856
6791
|
this.onClick = this._onClick.event;
|
|
5857
6792
|
this._onContextMenu = new Emitter();
|
|
6793
|
+
/** Fires on right-click and on touch long-press. */
|
|
5858
6794
|
this.onContextMenu = this._onContextMenu.event;
|
|
5859
|
-
this._onDragStart = new Emitter();
|
|
5860
|
-
this.onDragStart = this._onDragStart.event;
|
|
5861
6795
|
this._element = document.createElement('div');
|
|
5862
6796
|
this._element.className = 'dv-tab-group-chip';
|
|
5863
6797
|
this._element.tabIndex = 0;
|
|
5864
|
-
this._element.draggable = true;
|
|
5865
6798
|
this._label = document.createElement('span');
|
|
5866
6799
|
this._label.className = 'dv-tab-group-chip-label';
|
|
5867
6800
|
this._element.appendChild(this._label);
|
|
5868
|
-
this.addDisposables(this._onClick, this._onContextMenu,
|
|
6801
|
+
this.addDisposables(this._onClick, this._onContextMenu, new LongPressDetector(this._element, {
|
|
6802
|
+
onLongPress: (event) => {
|
|
6803
|
+
this._onContextMenu.fire(event);
|
|
6804
|
+
},
|
|
6805
|
+
}), addDisposableListener(this._element, 'click', (event) => {
|
|
5869
6806
|
this._onClick.fire(event);
|
|
5870
6807
|
}), addDisposableListener(this._element, 'contextmenu', (event) => {
|
|
5871
6808
|
this._onContextMenu.fire(event);
|
|
5872
|
-
}), addDisposableListener(this._element, 'dragstart', (event) => {
|
|
5873
|
-
this._onDragStart.fire(event);
|
|
5874
6809
|
}));
|
|
5875
6810
|
}
|
|
5876
6811
|
init(params) {
|
|
@@ -6334,6 +7269,12 @@ class TabGroupManager {
|
|
|
6334
7269
|
this._positionChipForGroup(tabGroup);
|
|
6335
7270
|
}
|
|
6336
7271
|
}
|
|
7272
|
+
updateDirection() {
|
|
7273
|
+
const isVertical = this._ctx.getDirection() === 'vertical';
|
|
7274
|
+
for (const [, entry] of this._chipRenderers) {
|
|
7275
|
+
entry.dropTarget.setTargetZones(isVertical ? ['top'] : ['left']);
|
|
7276
|
+
}
|
|
7277
|
+
}
|
|
6337
7278
|
snapshotChipWidths() {
|
|
6338
7279
|
const widths = new Map();
|
|
6339
7280
|
for (const [groupId, entry] of this._chipRenderers) {
|
|
@@ -6427,6 +7368,45 @@ class TabGroupManager {
|
|
|
6427
7368
|
(_a = this._pendingTransitionCleanups.get(panelId)) === null || _a === void 0 ? void 0 : _a();
|
|
6428
7369
|
this._pendingTransitionCleanups.delete(panelId);
|
|
6429
7370
|
}
|
|
7371
|
+
updateDragAndDropState() {
|
|
7372
|
+
const caps = resolveDndCapabilities(this._ctx.accessor.options);
|
|
7373
|
+
for (const entry of this._chipRenderers.values()) {
|
|
7374
|
+
entry.chip.element.draggable = caps.html5;
|
|
7375
|
+
entry.html5DragSource.setDisabled(!caps.html5);
|
|
7376
|
+
entry.pointerDragSource.setDisabled(!caps.pointer);
|
|
7377
|
+
entry.pointerDragSource.setTouchOnly(!caps.pointerHandlesMouse);
|
|
7378
|
+
}
|
|
7379
|
+
}
|
|
7380
|
+
/**
|
|
7381
|
+
* Synchronously dispose the chip drag sources for an in-flight chip
|
|
7382
|
+
* drag. Called from `_commitGroupMove` so the transfer payload +
|
|
7383
|
+
* iframe shield are released BEFORE the cross-group move detaches
|
|
7384
|
+
* the chip (chip dispose is scheduled on a microtask via
|
|
7385
|
+
* `_scheduleTabGroupUpdate`, which is too late for callers that read
|
|
7386
|
+
* `getPanelData()` synchronously after the move). Idempotent — the
|
|
7387
|
+
* subsequent `update()` will also dispose the sources.
|
|
7388
|
+
*/
|
|
7389
|
+
disposeChipDrag(tabGroupId) {
|
|
7390
|
+
var _a, _b;
|
|
7391
|
+
const entry = this._chipRenderers.get(tabGroupId);
|
|
7392
|
+
if (!entry) {
|
|
7393
|
+
return;
|
|
7394
|
+
}
|
|
7395
|
+
// Optional-chained because tests may inject minimal entries
|
|
7396
|
+
// that skip the manager's normal `_ensureChipForGroup` flow.
|
|
7397
|
+
(_a = entry.html5DragSource) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
7398
|
+
(_b = entry.pointerDragSource) === null || _b === void 0 ? void 0 : _b.dispose();
|
|
7399
|
+
}
|
|
7400
|
+
/** Cloned chip rect used as the pointer follow-finger ghost. */
|
|
7401
|
+
_buildChipGhostElement(chipEl) {
|
|
7402
|
+
const style = getComputedStyle(chipEl);
|
|
7403
|
+
const clone = chipEl.cloneNode(true);
|
|
7404
|
+
Array.from(style).forEach((key) => {
|
|
7405
|
+
clone.style.setProperty(key, style.getPropertyValue(key), style.getPropertyPriority(key));
|
|
7406
|
+
});
|
|
7407
|
+
clone.style.position = 'absolute';
|
|
7408
|
+
return clone;
|
|
7409
|
+
}
|
|
6430
7410
|
disposeAll() {
|
|
6431
7411
|
var _a;
|
|
6432
7412
|
(_a = this._indicator) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
@@ -6472,6 +7452,74 @@ class TabGroupManager {
|
|
|
6472
7452
|
? createChip(tabGroup)
|
|
6473
7453
|
: new TabGroupChip(this._ctx.accessor.tabGroupColorPalette);
|
|
6474
7454
|
chip.init({ tabGroup, api: this._ctx.accessor.api });
|
|
7455
|
+
const caps = resolveDndCapabilities(this._ctx.accessor.options);
|
|
7456
|
+
chip.element.draggable = caps.html5;
|
|
7457
|
+
const panelTransfer = LocalSelectionTransfer.getInstance();
|
|
7458
|
+
// Shared `getData` for both backends. Sets a group-level
|
|
7459
|
+
// PanelTransfer (panelId=null, tabGroupId identifies the group).
|
|
7460
|
+
// The returned disposer clears it on drag end.
|
|
7461
|
+
const getData = () => {
|
|
7462
|
+
panelTransfer.setData([
|
|
7463
|
+
new PanelTransfer(this._ctx.accessor.id, this._ctx.group.id, null, tabGroup.id),
|
|
7464
|
+
], PanelTransfer.prototype);
|
|
7465
|
+
return {
|
|
7466
|
+
dispose: () => {
|
|
7467
|
+
panelTransfer.clearData(PanelTransfer.prototype);
|
|
7468
|
+
},
|
|
7469
|
+
};
|
|
7470
|
+
};
|
|
7471
|
+
// The chip's HTML5 drag image is the cloned tabs list (chip only),
|
|
7472
|
+
// mounted inside the dockview root for CSS-variable inheritance and
|
|
7473
|
+
// positioned against the chip's in-place rect. Layout-dependent
|
|
7474
|
+
// offset means we set the drag image directly in `onDragStart`
|
|
7475
|
+
// (inside the dragstart handler) rather than via the generic
|
|
7476
|
+
// `createGhost` factory, which only knows about ghost specs that
|
|
7477
|
+
// can be appended to `document.body`.
|
|
7478
|
+
const html5DragSource = html5Backend.createDragSource(chip.element, {
|
|
7479
|
+
getData,
|
|
7480
|
+
disabled: !caps.html5,
|
|
7481
|
+
isCancelled: () => !resolveDndCapabilities(this._ctx.accessor.options).html5,
|
|
7482
|
+
onDragStart: (event) => {
|
|
7483
|
+
// Type guard via `dataTransfer` — `instanceof DragEvent`
|
|
7484
|
+
// would throw in jsdom which doesn't ship a DragEvent
|
|
7485
|
+
// constructor.
|
|
7486
|
+
if ('dataTransfer' in event && event.dataTransfer) {
|
|
7487
|
+
this.setGroupDragImage(event, tabGroup, chip.element);
|
|
7488
|
+
}
|
|
7489
|
+
this._callbacks.onChipDragStart(tabGroup, chip, event);
|
|
7490
|
+
},
|
|
7491
|
+
onDragEnd: (event) => {
|
|
7492
|
+
var _a, _b;
|
|
7493
|
+
(_b = (_a = this._callbacks).onChipDragEnd) === null || _b === void 0 ? void 0 : _b.call(_a, tabGroup, chip, event);
|
|
7494
|
+
},
|
|
7495
|
+
});
|
|
7496
|
+
// Synchronous panelTransfer cleanup directly on the chip element.
|
|
7497
|
+
// `Html5DragSource`'s dragend defers data disposal via `setTimeout(0)`
|
|
7498
|
+
// so drop handlers can read the payload — but a chip drag that
|
|
7499
|
+
// ends via `moveGroupOrPanel` (no actual drop event) needs the
|
|
7500
|
+
// singleton cleared immediately, otherwise a synchronous
|
|
7501
|
+
// `getPanelData()` after the move still sees the stale chip
|
|
7502
|
+
// payload. Attached directly (not via `addDisposableListener`) so
|
|
7503
|
+
// the listener survives chip disposal in the detach-then-dragend
|
|
7504
|
+
// cross-group path; `once: true` auto-removes after the single
|
|
7505
|
+
// dragend that we care about. (#1254)
|
|
7506
|
+
chip.element.addEventListener('dragend', () => {
|
|
7507
|
+
panelTransfer.clearData(PanelTransfer.prototype);
|
|
7508
|
+
}, { once: true });
|
|
7509
|
+
const pointerDragSource = pointerBackend.createDragSource(chip.element, {
|
|
7510
|
+
getData,
|
|
7511
|
+
disabled: !caps.pointer,
|
|
7512
|
+
touchOnly: !caps.pointerHandlesMouse,
|
|
7513
|
+
isCancelled: () => !resolveDndCapabilities(this._ctx.accessor.options).pointer,
|
|
7514
|
+
createGhost: () => ({
|
|
7515
|
+
element: this._buildChipGhostElement(chip.element),
|
|
7516
|
+
offsetX: 8,
|
|
7517
|
+
offsetY: 8,
|
|
7518
|
+
}),
|
|
7519
|
+
onDragStart: (event) => {
|
|
7520
|
+
this._callbacks.onChipDragStart(tabGroup, chip, event);
|
|
7521
|
+
},
|
|
7522
|
+
});
|
|
6475
7523
|
const disposables = [
|
|
6476
7524
|
tabGroup.onDidChange(() => {
|
|
6477
7525
|
var _a;
|
|
@@ -6485,24 +7533,70 @@ class TabGroupManager {
|
|
|
6485
7533
|
tabGroup.onDidCollapseChange(() => {
|
|
6486
7534
|
this._updateTabGroupClasses();
|
|
6487
7535
|
}),
|
|
7536
|
+
html5DragSource,
|
|
7537
|
+
pointerDragSource,
|
|
6488
7538
|
];
|
|
6489
|
-
//
|
|
7539
|
+
// Context menu: built-in TabGroupChip already aggregates right-click
|
|
7540
|
+
// + touch long-press into `onContextMenu`. Custom chip renderers
|
|
7541
|
+
// don't, so attach a long-press detector and contextmenu listener
|
|
7542
|
+
// directly on their element.
|
|
7543
|
+
const onContextMenu = (event) => {
|
|
7544
|
+
// A long-press on a chip should preempt the in-flight pointer
|
|
7545
|
+
// drag and open the menu instead.
|
|
7546
|
+
pointerDragSource.cancelPending();
|
|
7547
|
+
this._callbacks.onChipContextMenu(tabGroup, event);
|
|
7548
|
+
};
|
|
6490
7549
|
if (chip instanceof TabGroupChip) {
|
|
6491
|
-
disposables.push(chip.onContextMenu(
|
|
6492
|
-
this._callbacks.onChipContextMenu(tabGroup, event);
|
|
6493
|
-
}), chip.onDragStart((event) => {
|
|
6494
|
-
this._callbacks.onChipDragStart(tabGroup, chip, event);
|
|
6495
|
-
}));
|
|
7550
|
+
disposables.push(chip.onContextMenu(onContextMenu));
|
|
6496
7551
|
}
|
|
6497
7552
|
else {
|
|
6498
|
-
disposables.push(
|
|
6499
|
-
|
|
6500
|
-
}), addDisposableListener(chip.element, '
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
7553
|
+
disposables.push(new LongPressDetector(chip.element, {
|
|
7554
|
+
onLongPress: onContextMenu,
|
|
7555
|
+
}), addDisposableListener(chip.element, 'contextmenu', onContextMenu));
|
|
7556
|
+
}
|
|
7557
|
+
// The chip sits before its group's first tab in the DOM, so it
|
|
7558
|
+
// covers the "drop before the group" position. Without a drop
|
|
7559
|
+
// target here, dropping a tab over the chip is a dead zone —
|
|
7560
|
+
// particularly visible when the group is first in the tabs list
|
|
7561
|
+
// and there's no preceding tab whose right zone covers position 0.
|
|
7562
|
+
// The smooth animation path already shifts the chip's margin to
|
|
7563
|
+
// open a gap, so suppress the overlay in that mode.
|
|
7564
|
+
const isVertical = this._ctx.getDirection() === 'vertical';
|
|
7565
|
+
const dropTarget = new Droptarget(chip.element, {
|
|
7566
|
+
acceptedTargetZones: isVertical ? ['top'] : ['left'],
|
|
7567
|
+
overlayModel: {
|
|
7568
|
+
activationSize: { value: 100, type: 'percentage' },
|
|
7569
|
+
},
|
|
7570
|
+
canDisplayOverlay: (event, position) => {
|
|
7571
|
+
var _a;
|
|
7572
|
+
if (this._ctx.group.locked) {
|
|
7573
|
+
return false;
|
|
7574
|
+
}
|
|
7575
|
+
if (this._ctx.accessor.options.disableDnd) {
|
|
7576
|
+
return false;
|
|
7577
|
+
}
|
|
7578
|
+
const data = getPanelData();
|
|
7579
|
+
if (data && this._ctx.accessor.id === data.viewId) {
|
|
7580
|
+
if (((_a = this._ctx.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) ===
|
|
7581
|
+
'smooth') {
|
|
7582
|
+
return false;
|
|
7583
|
+
}
|
|
7584
|
+
return true;
|
|
7585
|
+
}
|
|
7586
|
+
return this._ctx.group.model.canDisplayOverlay(event, position, 'tab');
|
|
7587
|
+
},
|
|
7588
|
+
});
|
|
7589
|
+
disposables.push(dropTarget, dropTarget.onDrop((event) => {
|
|
7590
|
+
this._callbacks.onChipDrop(tabGroup, event);
|
|
7591
|
+
}));
|
|
6504
7592
|
const disposable = new CompositeDisposable(...disposables);
|
|
6505
|
-
this._chipRenderers.set(tabGroup.id, {
|
|
7593
|
+
this._chipRenderers.set(tabGroup.id, {
|
|
7594
|
+
chip,
|
|
7595
|
+
html5DragSource,
|
|
7596
|
+
pointerDragSource,
|
|
7597
|
+
disposable,
|
|
7598
|
+
dropTarget,
|
|
7599
|
+
});
|
|
6506
7600
|
// Group is born collapsed (cross-group drop, layout restore, etc.):
|
|
6507
7601
|
// its tabs are about to be added without the collapsed class. Skip
|
|
6508
7602
|
// the animation in the upcoming _updateTabGroupClasses call so they
|
|
@@ -6761,6 +7855,7 @@ class Tabs extends CompositeDisposable {
|
|
|
6761
7855
|
for (const tab of this._tabs) {
|
|
6762
7856
|
tab.value.setDirection(value);
|
|
6763
7857
|
}
|
|
7858
|
+
this._tabGroupManager.updateDirection();
|
|
6764
7859
|
}
|
|
6765
7860
|
constructor(group, accessor, options) {
|
|
6766
7861
|
super();
|
|
@@ -6780,7 +7875,7 @@ class Tabs extends CompositeDisposable {
|
|
|
6780
7875
|
this._voidContainer = null;
|
|
6781
7876
|
this._voidContainerListeners = null;
|
|
6782
7877
|
this._extendedDropZone = null;
|
|
6783
|
-
this.
|
|
7878
|
+
this._pointerInsideTabsList = false;
|
|
6784
7879
|
this._onTabDragStart = new Emitter();
|
|
6785
7880
|
this.onTabDragStart = this._onTabDragStart.event;
|
|
6786
7881
|
this._onDrop = new Emitter();
|
|
@@ -6815,13 +7910,40 @@ class Tabs extends CompositeDisposable {
|
|
|
6815
7910
|
onChipDragStart: (tabGroup, chip, event) => {
|
|
6816
7911
|
this._handleChipDragStart(tabGroup, chip, event);
|
|
6817
7912
|
},
|
|
7913
|
+
onChipDragEnd: () => {
|
|
7914
|
+
// HTML5 chip dragend (incl. cancels). The Html5DragSource
|
|
7915
|
+
// owns the listener on the chip element, so this fires
|
|
7916
|
+
// even if the chip was detached cross-group — the
|
|
7917
|
+
// element keeps its listeners until the source is
|
|
7918
|
+
// disposed. resetDragAnimation is a no-op after a
|
|
7919
|
+
// successful drop (anim state already null) thanks to
|
|
7920
|
+
// the gating inside it.
|
|
7921
|
+
this.resetDragAnimation();
|
|
7922
|
+
},
|
|
7923
|
+
onChipDrop: (tabGroup, event) => {
|
|
7924
|
+
this._handleChipDrop(tabGroup, event);
|
|
7925
|
+
},
|
|
6818
7926
|
});
|
|
6819
7927
|
this.addDisposables(this._onOverflowTabsChange, this._observerDisposable, this._onWillShowOverlay, this._onDrop, this._onTabDragStart, {
|
|
6820
7928
|
dispose: () => {
|
|
6821
7929
|
var _a;
|
|
6822
7930
|
(_a = this._flipTransitionCleanup) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
6823
7931
|
},
|
|
6824
|
-
},
|
|
7932
|
+
},
|
|
7933
|
+
// Pointer-side cleanup: when any pointer drag ends, tear
|
|
7934
|
+
// down smooth-reorder anim state the dragover bridge may
|
|
7935
|
+
// have installed. The chip's pointer drag source handles
|
|
7936
|
+
// its own transfer payload + iframe-shield cleanup.
|
|
7937
|
+
PointerDragController.getInstance().onDragEnd(() => {
|
|
7938
|
+
this._pointerInsideTabsList = false;
|
|
7939
|
+
this.resetDragAnimation();
|
|
7940
|
+
}),
|
|
7941
|
+
// Pointer-event mirror of the HTML5 dragover / dragleave handlers
|
|
7942
|
+
// below. Drives smooth-reorder for `dndStrategy: 'pointer'` and
|
|
7943
|
+
// for touch drags in `'auto'`.
|
|
7944
|
+
PointerDragController.getInstance().onDragMove((e) => {
|
|
7945
|
+
this._handlePointerDragMove(e.clientX, e.clientY);
|
|
7946
|
+
}), addDisposableListener(this.element, 'pointerdown', (event) => {
|
|
6825
7947
|
if (event.defaultPrevented) {
|
|
6826
7948
|
return;
|
|
6827
7949
|
}
|
|
@@ -6829,135 +7951,60 @@ class Tabs extends CompositeDisposable {
|
|
|
6829
7951
|
if (isLeftClick) {
|
|
6830
7952
|
this.accessor.doSetGroupActive(this.group);
|
|
6831
7953
|
}
|
|
6832
|
-
}),
|
|
6833
|
-
|
|
6834
|
-
|
|
7954
|
+
}),
|
|
7955
|
+
// Trackpad / wheel forwarding. The strip scrolls along its own
|
|
7956
|
+
// axis (x for horizontal headers, y for vertical), so deltaY
|
|
7957
|
+
// from a plain mouse wheel maps onto the strip's axis too —
|
|
7958
|
+
// this gives the VS Code-style "scroll over tab bar to page
|
|
7959
|
+
// through tabs" feel. We only consume the event when the strip
|
|
7960
|
+
// is actually overflowing in the direction the user wheeled in,
|
|
7961
|
+
// so a wheel at the edge of a non-overflowing strip still
|
|
7962
|
+
// bubbles up and scrolls the page. `{ passive: false }` is
|
|
7963
|
+
// required because we call preventDefault().
|
|
7964
|
+
addDisposableListener(this._tabsList, 'wheel', (event) => {
|
|
7965
|
+
const isVertical = this._direction === 'vertical';
|
|
7966
|
+
const primary = isVertical
|
|
7967
|
+
? event.deltaY || event.deltaX
|
|
7968
|
+
: event.deltaX || event.deltaY;
|
|
7969
|
+
if (primary === 0) {
|
|
6835
7970
|
return;
|
|
6836
7971
|
}
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
|
|
6841
|
-
|
|
6842
|
-
|
|
6843
|
-
data.groupId !== this.group.id &&
|
|
6844
|
-
this._animState.sourceTabGroupId !== data.tabGroupId) {
|
|
6845
|
-
this._animState = null;
|
|
6846
|
-
}
|
|
6847
|
-
}
|
|
6848
|
-
if (!this._animState) {
|
|
6849
|
-
const data = getPanelData();
|
|
6850
|
-
// In default animation mode, individual tab drops
|
|
6851
|
-
// are handled by per-tab Droptargets. But tab group
|
|
6852
|
-
// chip drags still need tab-list-level handling so
|
|
6853
|
-
// that drops on gaps / void space work.
|
|
6854
|
-
if (((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) ===
|
|
6855
|
-
'default' &&
|
|
6856
|
-
!(data === null || data === void 0 ? void 0 : data.tabGroupId)) {
|
|
6857
|
-
return;
|
|
6858
|
-
}
|
|
6859
|
-
if (data &&
|
|
6860
|
-
(data.panelId || data.tabGroupId) &&
|
|
6861
|
-
data.groupId !== this.group.id) {
|
|
6862
|
-
const avgWidth = this.getAverageTabWidth();
|
|
6863
|
-
if (data.tabGroupId) {
|
|
6864
|
-
// External group drag — look up the
|
|
6865
|
-
// source tab group to size the gap
|
|
6866
|
-
const sourceGroup = this.accessor.getPanel(data.groupId);
|
|
6867
|
-
const sourceTg = sourceGroup === null || sourceGroup === void 0 ? void 0 : sourceGroup.model.getTabGroups().find((tg) => tg.id === data.tabGroupId);
|
|
6868
|
-
const panelCount = (_b = sourceTg === null || sourceTg === void 0 ? void 0 : sourceTg.panelIds.length) !== null && _b !== void 0 ? _b : 1;
|
|
6869
|
-
const groupGapWidth = avgWidth * panelCount + avgWidth;
|
|
6870
|
-
this._animState = {
|
|
6871
|
-
sourceTabId: '',
|
|
6872
|
-
sourceIndex: -1,
|
|
6873
|
-
tabPositions: this.snapshotTabPositions(),
|
|
6874
|
-
chipPositions: this._tabGroupManager.snapshotChipWidths(),
|
|
6875
|
-
currentInsertionIndex: null,
|
|
6876
|
-
targetTabGroupId: null,
|
|
6877
|
-
sourceTabGroupId: data.tabGroupId,
|
|
6878
|
-
sourceGroupPanelIds: sourceTg
|
|
6879
|
-
? new Set(sourceTg.panelIds)
|
|
6880
|
-
: new Set(),
|
|
6881
|
-
sourceChipWidth: avgWidth,
|
|
6882
|
-
cursorOffsetFromDragLeft: groupGapWidth / 2,
|
|
6883
|
-
sourceGapWidth: groupGapWidth,
|
|
6884
|
-
containerLeft: this._tabsList.getBoundingClientRect()
|
|
6885
|
-
.left,
|
|
6886
|
-
};
|
|
6887
|
-
}
|
|
6888
|
-
else {
|
|
6889
|
-
this._animState = {
|
|
6890
|
-
sourceTabId: data.panelId,
|
|
6891
|
-
sourceIndex: -1,
|
|
6892
|
-
tabPositions: this.snapshotTabPositions(),
|
|
6893
|
-
chipPositions: this._tabGroupManager.snapshotChipWidths(),
|
|
6894
|
-
currentInsertionIndex: null,
|
|
6895
|
-
targetTabGroupId: null,
|
|
6896
|
-
sourceTabGroupId: null,
|
|
6897
|
-
sourceGroupPanelIds: null,
|
|
6898
|
-
sourceChipWidth: 0,
|
|
6899
|
-
cursorOffsetFromDragLeft: avgWidth / 2,
|
|
6900
|
-
sourceGapWidth: avgWidth,
|
|
6901
|
-
containerLeft: this._tabsList.getBoundingClientRect()
|
|
6902
|
-
.left,
|
|
6903
|
-
};
|
|
6904
|
-
}
|
|
6905
|
-
}
|
|
6906
|
-
else {
|
|
6907
|
-
return;
|
|
6908
|
-
}
|
|
6909
|
-
}
|
|
6910
|
-
event.preventDefault(); // allow drop to fire on the container
|
|
6911
|
-
// For intra-group drag (sourceIndex >= 0) the gap
|
|
6912
|
-
// animation is the sole visual indicator — clear any
|
|
6913
|
-
// stale anchor overlay that may have been set while the
|
|
6914
|
-
// cursor was over the panel content area or another zone.
|
|
6915
|
-
// External drags (sourceIndex === -1) leave the overlay
|
|
6916
|
-
// to the individual tab Droptargets so cross-group
|
|
6917
|
-
// animation is not disrupted.
|
|
6918
|
-
if (this._animState.sourceIndex !== -1) {
|
|
6919
|
-
(_d = (_c = this.group.model.dropTargetContainer) === null || _c === void 0 ? void 0 : _c.model) === null || _d === void 0 ? void 0 : _d.clear();
|
|
6920
|
-
}
|
|
6921
|
-
this.handleDragOver(event);
|
|
6922
|
-
}, true), addDisposableListener(this._tabsList, 'dragleave', (event) => {
|
|
6923
|
-
var _a, _b, _c;
|
|
6924
|
-
if (!this._animState) {
|
|
7972
|
+
const max = isVertical
|
|
7973
|
+
? this._tabsList.scrollHeight -
|
|
7974
|
+
this._tabsList.clientHeight
|
|
7975
|
+
: this._tabsList.scrollWidth -
|
|
7976
|
+
this._tabsList.clientWidth;
|
|
7977
|
+
if (max <= 0) {
|
|
6925
7978
|
return;
|
|
6926
7979
|
}
|
|
6927
|
-
const
|
|
6928
|
-
|
|
6929
|
-
|
|
7980
|
+
const current = isVertical
|
|
7981
|
+
? this._tabsList.scrollTop
|
|
7982
|
+
: this._tabsList.scrollLeft;
|
|
7983
|
+
// At the edge in the wheel direction: let the page
|
|
7984
|
+
// scroll instead of trapping the gesture.
|
|
7985
|
+
if ((primary < 0 && current <= 0) ||
|
|
7986
|
+
(primary > 0 && current >= max)) {
|
|
6930
7987
|
return;
|
|
6931
7988
|
}
|
|
6932
|
-
|
|
6933
|
-
//
|
|
6934
|
-
//
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
|
|
7989
|
+
event.preventDefault();
|
|
7990
|
+
// Custom-scrollbar mode wraps the tabs list and installs
|
|
7991
|
+
// its own wheel listener that rewrites scrollLeft from a
|
|
7992
|
+
// deltaY-only tracker. Without stopPropagation that
|
|
7993
|
+
// handler would clobber our deltaX-aware update.
|
|
7994
|
+
event.stopPropagation();
|
|
7995
|
+
if (isVertical) {
|
|
7996
|
+
this._tabsList.scrollTop = current + primary;
|
|
6939
7997
|
}
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
// still land at the end position.
|
|
6943
|
-
const rt = event.relatedTarget;
|
|
6944
|
-
const isVoid = this._voidContainer &&
|
|
6945
|
-
rt &&
|
|
6946
|
-
(rt === this._voidContainer ||
|
|
6947
|
-
this._voidContainer.contains(rt));
|
|
6948
|
-
if (isVoid) {
|
|
6949
|
-
return;
|
|
7998
|
+
else {
|
|
7999
|
+
this._tabsList.scrollLeft = current + primary;
|
|
6950
8000
|
}
|
|
6951
|
-
|
|
6952
|
-
if (this.
|
|
6953
|
-
|
|
6954
|
-
|
|
6955
|
-
this._animState = null;
|
|
6956
|
-
}
|
|
6957
|
-
else {
|
|
6958
|
-
this._animState.currentInsertionIndex = null;
|
|
6959
|
-
}
|
|
8001
|
+
}, { passive: false }), addDisposableListener(this._tabsList, 'dragover', (event) => {
|
|
8002
|
+
if (this._processDragOver(event.clientX)) {
|
|
8003
|
+
// Allow `drop` to fire on the tabs list container.
|
|
8004
|
+
event.preventDefault();
|
|
6960
8005
|
}
|
|
8006
|
+
}, true), addDisposableListener(this._tabsList, 'dragleave', (event) => {
|
|
8007
|
+
this._processDragLeave(event.relatedTarget);
|
|
6961
8008
|
}, true), addDisposableListener(this._tabsList, 'dragend', () => {
|
|
6962
8009
|
this.resetDragAnimation();
|
|
6963
8010
|
}), addDisposableListener(this._tabsList, 'drop', (event) => {
|
|
@@ -7079,6 +8126,9 @@ class Tabs extends CompositeDisposable {
|
|
|
7079
8126
|
const disposable = new CompositeDisposable(tab.onDragStart((event) => {
|
|
7080
8127
|
var _a;
|
|
7081
8128
|
this._onTabDragStart.fire({ nativeEvent: event, panel });
|
|
8129
|
+
// Both HTML5 and pointer drags initialize _animState. Cleanup
|
|
8130
|
+
// is wired in both paths: HTML5 via dragend/drop on _tabsList,
|
|
8131
|
+
// pointer via PointerDragController.onDragEnd subscriptions.
|
|
7082
8132
|
if (((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) === 'smooth') {
|
|
7083
8133
|
const tabWidth = tab.element.getBoundingClientRect().width;
|
|
7084
8134
|
const sourceIndex = this._tabs.findIndex((x) => x.value === tab);
|
|
@@ -7338,6 +8388,7 @@ class Tabs extends CompositeDisposable {
|
|
|
7338
8388
|
for (const tab of this._tabs) {
|
|
7339
8389
|
tab.value.updateDragAndDropState();
|
|
7340
8390
|
}
|
|
8391
|
+
this._tabGroupManager.updateDragAndDropState();
|
|
7341
8392
|
}
|
|
7342
8393
|
/**
|
|
7343
8394
|
* Synchronize chip elements and CSS classes for all tab groups
|
|
@@ -7349,6 +8400,13 @@ class Tabs extends CompositeDisposable {
|
|
|
7349
8400
|
refreshTabGroupAccent() {
|
|
7350
8401
|
this._tabGroupManager.refreshAccents();
|
|
7351
8402
|
}
|
|
8403
|
+
/**
|
|
8404
|
+
* Tabs-list-specific side effects of a chip drag start. The chip's
|
|
8405
|
+
* drag sources (constructed by `TabGroupManager`) own the transfer
|
|
8406
|
+
* payload, iframe shielding, dataTransfer setup, and the HTML5 drag
|
|
8407
|
+
* image. This method just sets up the smooth-reorder anim state and
|
|
8408
|
+
* collapses the source-group tabs in the tabs list.
|
|
8409
|
+
*/
|
|
7352
8410
|
_handleChipDragStart(tabGroup, chip, event) {
|
|
7353
8411
|
var _a;
|
|
7354
8412
|
const firstPanelId = tabGroup.panelIds[0];
|
|
@@ -7379,89 +8437,79 @@ class Tabs extends CompositeDisposable {
|
|
|
7379
8437
|
sourceGapWidth: groupGapWidth,
|
|
7380
8438
|
containerLeft: this._tabsList.getBoundingClientRect().left,
|
|
7381
8439
|
};
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7399
|
-
|
|
7400
|
-
|
|
7401
|
-
|
|
7402
|
-
};
|
|
7403
|
-
chipElement.addEventListener('dragend', onChipDragEnd);
|
|
7404
|
-
this._chipDragCleanup = {
|
|
7405
|
-
dispose: () => {
|
|
7406
|
-
chipElement.removeEventListener('dragend', onChipDragEnd);
|
|
7407
|
-
panelTransfer.clearData(PanelTransfer.prototype);
|
|
7408
|
-
iframes.release();
|
|
7409
|
-
},
|
|
7410
|
-
};
|
|
7411
|
-
if (event.dataTransfer) {
|
|
7412
|
-
event.dataTransfer.effectAllowed = 'move';
|
|
7413
|
-
if (event.dataTransfer.items.length === 0) {
|
|
7414
|
-
event.dataTransfer.setData('text/plain', '');
|
|
7415
|
-
}
|
|
7416
|
-
}
|
|
7417
|
-
if (((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) === 'smooth') {
|
|
7418
|
-
// Collapse group tabs + chip after the browser
|
|
7419
|
-
// captures the drag image, then open the gap at the
|
|
7420
|
-
// source position — all instant (no transitions).
|
|
7421
|
-
const groupPanelIds = new Set(tabGroup.panelIds);
|
|
7422
|
-
this._pendingCollapse = true;
|
|
7423
|
-
requestAnimationFrame(() => {
|
|
7424
|
-
var _a;
|
|
7425
|
-
var _b;
|
|
7426
|
-
this._pendingCollapse = false;
|
|
7427
|
-
if (!this._animState) {
|
|
7428
|
-
return;
|
|
7429
|
-
}
|
|
7430
|
-
// Collapse all group tabs instantly
|
|
7431
|
-
for (const t of this._tabs) {
|
|
7432
|
-
if (groupPanelIds.has(t.value.panel.id)) {
|
|
7433
|
-
t.value.element.style.transition = 'none';
|
|
7434
|
-
toggleClass(t.value.element, 'dv-tab--dragging', true);
|
|
7435
|
-
}
|
|
7436
|
-
}
|
|
7437
|
-
// Collapse the group chip instantly
|
|
7438
|
-
const chipEntry = this._tabGroupManager.chipRenderers.get(tabGroup.id);
|
|
7439
|
-
if (chipEntry) {
|
|
7440
|
-
chipEntry.chip.element.style.transition = 'none';
|
|
7441
|
-
toggleClass(chipEntry.chip.element, 'dv-tab-group-chip--dragging', true);
|
|
7442
|
-
}
|
|
7443
|
-
// Single reflow for the entire batch
|
|
7444
|
-
void this._tabsList.offsetHeight;
|
|
7445
|
-
const underline = this._tabGroupManager.groupUnderlines.get(tabGroup.id);
|
|
7446
|
-
if (underline) {
|
|
7447
|
-
underline.style.display = 'none';
|
|
7448
|
-
}
|
|
7449
|
-
(_a = (_b = this._animState).currentInsertionIndex) !== null && _a !== void 0 ? _a : (_b.currentInsertionIndex = firstIdx);
|
|
7450
|
-
// Apply gap with transitions disabled
|
|
7451
|
-
this.applyDragOverTransforms(true);
|
|
7452
|
-
// Re-enable transitions for subsequent moves
|
|
7453
|
-
for (const t of this._tabs) {
|
|
7454
|
-
if (groupPanelIds.has(t.value.panel.id)) {
|
|
7455
|
-
t.value.element.style.removeProperty('transition');
|
|
7456
|
-
}
|
|
8440
|
+
if (((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) !== 'smooth') {
|
|
8441
|
+
return;
|
|
8442
|
+
}
|
|
8443
|
+
// Collapse group tabs + chip after the browser captures the drag
|
|
8444
|
+
// image, then open the gap at the source position — all instant
|
|
8445
|
+
// (no transitions).
|
|
8446
|
+
const groupPanelIds = new Set(tabGroup.panelIds);
|
|
8447
|
+
this._pendingCollapse = true;
|
|
8448
|
+
requestAnimationFrame(() => {
|
|
8449
|
+
var _a;
|
|
8450
|
+
var _b;
|
|
8451
|
+
this._pendingCollapse = false;
|
|
8452
|
+
if (!this._animState) {
|
|
8453
|
+
return;
|
|
8454
|
+
}
|
|
8455
|
+
// Collapse all group tabs instantly
|
|
8456
|
+
for (const t of this._tabs) {
|
|
8457
|
+
if (groupPanelIds.has(t.value.panel.id)) {
|
|
8458
|
+
t.value.element.style.transition = 'none';
|
|
8459
|
+
toggleClass(t.value.element, 'dv-tab--dragging', true);
|
|
7457
8460
|
}
|
|
7458
|
-
|
|
7459
|
-
|
|
8461
|
+
}
|
|
8462
|
+
// Collapse the group chip instantly
|
|
8463
|
+
const chipEntry = this._tabGroupManager.chipRenderers.get(tabGroup.id);
|
|
8464
|
+
if (chipEntry) {
|
|
8465
|
+
chipEntry.chip.element.style.transition = 'none';
|
|
8466
|
+
toggleClass(chipEntry.chip.element, 'dv-tab-group-chip--dragging', true);
|
|
8467
|
+
}
|
|
8468
|
+
// Single reflow for the entire batch
|
|
8469
|
+
void this._tabsList.offsetHeight;
|
|
8470
|
+
const underline = this._tabGroupManager.groupUnderlines.get(tabGroup.id);
|
|
8471
|
+
if (underline) {
|
|
8472
|
+
underline.style.display = 'none';
|
|
8473
|
+
}
|
|
8474
|
+
(_a = (_b = this._animState).currentInsertionIndex) !== null && _a !== void 0 ? _a : (_b.currentInsertionIndex = firstIdx);
|
|
8475
|
+
this.applyDragOverTransforms(true);
|
|
8476
|
+
for (const t of this._tabs) {
|
|
8477
|
+
if (groupPanelIds.has(t.value.panel.id)) {
|
|
8478
|
+
t.value.element.style.removeProperty('transition');
|
|
7460
8479
|
}
|
|
7461
|
-
}
|
|
8480
|
+
}
|
|
8481
|
+
if (chipEntry) {
|
|
8482
|
+
chipEntry.chip.element.style.removeProperty('transition');
|
|
8483
|
+
}
|
|
8484
|
+
});
|
|
8485
|
+
}
|
|
8486
|
+
/**
|
|
8487
|
+
* A drop on a tab group chip means "insert before this group". Resolve to
|
|
8488
|
+
* the index of the group's first tab, adjusting for same-group removal
|
|
8489
|
+
* (when the source tab is currently to the left of the target slot, its
|
|
8490
|
+
* removal shifts the insertion index down by one). Always clears
|
|
8491
|
+
* `targetTabGroupId` so the dropped tab lands outside the group.
|
|
8492
|
+
*/
|
|
8493
|
+
_handleChipDrop(tabGroup, event) {
|
|
8494
|
+
const firstPanelId = tabGroup.panelIds[0];
|
|
8495
|
+
if (!firstPanelId) {
|
|
8496
|
+
return;
|
|
8497
|
+
}
|
|
8498
|
+
const insertionIndex = this._tabs.findIndex((x) => x.value.panel.id === firstPanelId);
|
|
8499
|
+
if (insertionIndex === -1) {
|
|
8500
|
+
return;
|
|
7462
8501
|
}
|
|
7463
|
-
|
|
7464
|
-
this.
|
|
8502
|
+
const data = getPanelData();
|
|
8503
|
+
const sourceIndex = data && data.groupId === this.group.id && data.panelId
|
|
8504
|
+
? this._tabs.findIndex((x) => x.value.panel.id === data.panelId)
|
|
8505
|
+
: -1;
|
|
8506
|
+
const adjustedIndex = insertionIndex -
|
|
8507
|
+
(sourceIndex !== -1 && sourceIndex < insertionIndex ? 1 : 0);
|
|
8508
|
+
this._onDrop.fire({
|
|
8509
|
+
event: event.nativeEvent,
|
|
8510
|
+
index: adjustedIndex,
|
|
8511
|
+
targetTabGroupId: null,
|
|
8512
|
+
});
|
|
7465
8513
|
}
|
|
7466
8514
|
/**
|
|
7467
8515
|
* Sets the broader container that is part of the same logical drop surface
|
|
@@ -7523,6 +8571,164 @@ class Tabs extends CompositeDisposable {
|
|
|
7523
8571
|
}
|
|
7524
8572
|
return total / this._tabs.length;
|
|
7525
8573
|
}
|
|
8574
|
+
/**
|
|
8575
|
+
* Pointer-event entry point. The HTML5 path enters via the per-element
|
|
8576
|
+
* `dragover` listener; this one hit-tests the global pointer-drag
|
|
8577
|
+
* position against the tabs list and routes through the same shared
|
|
8578
|
+
* `_processDragOver` / `_processDragLeave` helpers.
|
|
8579
|
+
*/
|
|
8580
|
+
_handlePointerDragMove(clientX, clientY) {
|
|
8581
|
+
var _a;
|
|
8582
|
+
const sourceDoc = (_a = this._tabsList.ownerDocument) !== null && _a !== void 0 ? _a : document;
|
|
8583
|
+
const elAtPoint = sourceDoc.elementFromPoint(clientX, clientY);
|
|
8584
|
+
const inside = !!elAtPoint &&
|
|
8585
|
+
(this._tabsList.contains(elAtPoint) ||
|
|
8586
|
+
(!!this._extendedDropZone &&
|
|
8587
|
+
this._extendedDropZone.contains(elAtPoint)));
|
|
8588
|
+
if (!inside) {
|
|
8589
|
+
if (this._pointerInsideTabsList) {
|
|
8590
|
+
this._pointerInsideTabsList = false;
|
|
8591
|
+
this._processDragLeave(elAtPoint);
|
|
8592
|
+
}
|
|
8593
|
+
return;
|
|
8594
|
+
}
|
|
8595
|
+
this._pointerInsideTabsList = true;
|
|
8596
|
+
this._processDragOver(clientX);
|
|
8597
|
+
}
|
|
8598
|
+
/**
|
|
8599
|
+
* Shared body of the dragover entry point. Refreshes stale anim state
|
|
8600
|
+
* for a changed drag identity, initializes anim state for incoming
|
|
8601
|
+
* cross-group drags, and dispatches to the gap-following math in
|
|
8602
|
+
* `handleDragOver`. Returns true when this tabs list has taken
|
|
8603
|
+
* ownership of the drag — HTML5 callers use this to gate
|
|
8604
|
+
* `event.preventDefault()`.
|
|
8605
|
+
*/
|
|
8606
|
+
_processDragOver(clientX) {
|
|
8607
|
+
var _a, _b, _c, _d;
|
|
8608
|
+
if (this.accessor.options.disableDnd) {
|
|
8609
|
+
return false;
|
|
8610
|
+
}
|
|
8611
|
+
// Stale-state guard: if a previous drag's anim state is still here
|
|
8612
|
+
// but the current drag is a different identity, drop the stale one
|
|
8613
|
+
// so the new drag starts from a clean slate.
|
|
8614
|
+
if (this._animState) {
|
|
8615
|
+
const data = getPanelData();
|
|
8616
|
+
if ((data === null || data === void 0 ? void 0 : data.tabGroupId) &&
|
|
8617
|
+
data.groupId !== this.group.id &&
|
|
8618
|
+
this._animState.sourceTabGroupId !== data.tabGroupId) {
|
|
8619
|
+
this._animState = null;
|
|
8620
|
+
}
|
|
8621
|
+
}
|
|
8622
|
+
if (!this._animState) {
|
|
8623
|
+
const data = getPanelData();
|
|
8624
|
+
// In default animation mode, individual tab drops are handled
|
|
8625
|
+
// by per-tab Droptargets; only chip drags need tabs-list-level
|
|
8626
|
+
// handling so drops on void space still work.
|
|
8627
|
+
if (((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) === 'default' &&
|
|
8628
|
+
!(data === null || data === void 0 ? void 0 : data.tabGroupId)) {
|
|
8629
|
+
return false;
|
|
8630
|
+
}
|
|
8631
|
+
if (data &&
|
|
8632
|
+
(data.panelId || data.tabGroupId) &&
|
|
8633
|
+
data.groupId !== this.group.id) {
|
|
8634
|
+
const avgWidth = this.getAverageTabWidth();
|
|
8635
|
+
if (data.tabGroupId) {
|
|
8636
|
+
// External group drag — look up the source group to
|
|
8637
|
+
// size the gap.
|
|
8638
|
+
const sourceGroup = this.accessor.getPanel(data.groupId);
|
|
8639
|
+
const sourceTg = sourceGroup === null || sourceGroup === void 0 ? void 0 : sourceGroup.model.getTabGroups().find((tg) => tg.id === data.tabGroupId);
|
|
8640
|
+
const panelCount = (_b = sourceTg === null || sourceTg === void 0 ? void 0 : sourceTg.panelIds.length) !== null && _b !== void 0 ? _b : 1;
|
|
8641
|
+
const groupGapWidth = avgWidth * panelCount + avgWidth;
|
|
8642
|
+
this._animState = {
|
|
8643
|
+
sourceTabId: '',
|
|
8644
|
+
sourceIndex: -1,
|
|
8645
|
+
tabPositions: this.snapshotTabPositions(),
|
|
8646
|
+
chipPositions: this._tabGroupManager.snapshotChipWidths(),
|
|
8647
|
+
currentInsertionIndex: null,
|
|
8648
|
+
targetTabGroupId: null,
|
|
8649
|
+
sourceTabGroupId: data.tabGroupId,
|
|
8650
|
+
sourceGroupPanelIds: sourceTg
|
|
8651
|
+
? new Set(sourceTg.panelIds)
|
|
8652
|
+
: new Set(),
|
|
8653
|
+
sourceChipWidth: avgWidth,
|
|
8654
|
+
cursorOffsetFromDragLeft: groupGapWidth / 2,
|
|
8655
|
+
sourceGapWidth: groupGapWidth,
|
|
8656
|
+
containerLeft: this._tabsList.getBoundingClientRect().left,
|
|
8657
|
+
};
|
|
8658
|
+
}
|
|
8659
|
+
else {
|
|
8660
|
+
this._animState = {
|
|
8661
|
+
sourceTabId: data.panelId,
|
|
8662
|
+
sourceIndex: -1,
|
|
8663
|
+
tabPositions: this.snapshotTabPositions(),
|
|
8664
|
+
chipPositions: this._tabGroupManager.snapshotChipWidths(),
|
|
8665
|
+
currentInsertionIndex: null,
|
|
8666
|
+
targetTabGroupId: null,
|
|
8667
|
+
sourceTabGroupId: null,
|
|
8668
|
+
sourceGroupPanelIds: null,
|
|
8669
|
+
sourceChipWidth: 0,
|
|
8670
|
+
cursorOffsetFromDragLeft: avgWidth / 2,
|
|
8671
|
+
sourceGapWidth: avgWidth,
|
|
8672
|
+
containerLeft: this._tabsList.getBoundingClientRect().left,
|
|
8673
|
+
};
|
|
8674
|
+
}
|
|
8675
|
+
}
|
|
8676
|
+
else {
|
|
8677
|
+
return false;
|
|
8678
|
+
}
|
|
8679
|
+
}
|
|
8680
|
+
// For intra-group drag (sourceIndex >= 0) the gap animation is the
|
|
8681
|
+
// sole visual indicator — clear any stale anchor overlay that may
|
|
8682
|
+
// have been set while the cursor was over the panel content area or
|
|
8683
|
+
// another zone. External drags (sourceIndex === -1) leave the
|
|
8684
|
+
// overlay to the individual tab Droptargets so cross-group
|
|
8685
|
+
// animation is not disrupted.
|
|
8686
|
+
if (this._animState.sourceIndex !== -1) {
|
|
8687
|
+
(_d = (_c = this.group.model.dropTargetContainer) === null || _c === void 0 ? void 0 : _c.model) === null || _d === void 0 ? void 0 : _d.clear();
|
|
8688
|
+
}
|
|
8689
|
+
this.handleDragOver({ clientX });
|
|
8690
|
+
return true;
|
|
8691
|
+
}
|
|
8692
|
+
/**
|
|
8693
|
+
* Shared body of the dragleave entry point. Preserves anim state when
|
|
8694
|
+
* the drag moves between tabs-list children, into the extended drop
|
|
8695
|
+
* zone, or into the void container; tears it down otherwise.
|
|
8696
|
+
*/
|
|
8697
|
+
_processDragLeave(related) {
|
|
8698
|
+
var _a, _b, _c;
|
|
8699
|
+
if (!this._animState) {
|
|
8700
|
+
return;
|
|
8701
|
+
}
|
|
8702
|
+
// Moves between children of the tabs list aren't real leaves.
|
|
8703
|
+
if (related && this._tabsList.contains(related)) {
|
|
8704
|
+
return;
|
|
8705
|
+
}
|
|
8706
|
+
// Moving into the broader drop zone (e.g. void container, left
|
|
8707
|
+
// actions) — keep anim state alive so external listeners can
|
|
8708
|
+
// continue the gap animation.
|
|
8709
|
+
if (related && ((_a = this._extendedDropZone) === null || _a === void 0 ? void 0 : _a.contains(related))) {
|
|
8710
|
+
this.resetTabTransforms();
|
|
8711
|
+
this._animState.currentInsertionIndex = null;
|
|
8712
|
+
return;
|
|
8713
|
+
}
|
|
8714
|
+
// Leaving toward the void container (empty header space to the
|
|
8715
|
+
// right): keep anim state so a drop can still land at the end.
|
|
8716
|
+
const isVoid = this._voidContainer &&
|
|
8717
|
+
related &&
|
|
8718
|
+
(related === this._voidContainer ||
|
|
8719
|
+
this._voidContainer.contains(related));
|
|
8720
|
+
if (isVoid) {
|
|
8721
|
+
return;
|
|
8722
|
+
}
|
|
8723
|
+
this.resetTabTransforms();
|
|
8724
|
+
if (this._animState.sourceIndex === -1) {
|
|
8725
|
+
(_c = (_b = this.group.model.dropTargetContainer) === null || _b === void 0 ? void 0 : _b.model) === null || _c === void 0 ? void 0 : _c.clear();
|
|
8726
|
+
this._animState = null;
|
|
8727
|
+
}
|
|
8728
|
+
else {
|
|
8729
|
+
this._animState.currentInsertionIndex = null;
|
|
8730
|
+
}
|
|
8731
|
+
}
|
|
7526
8732
|
handleDragOver(event) {
|
|
7527
8733
|
var _a, _b, _c, _d, _e;
|
|
7528
8734
|
if (!this._animState) {
|
|
@@ -7932,20 +9138,23 @@ class Tabs extends CompositeDisposable {
|
|
|
7932
9138
|
* in the model, and run a FLIP animation.
|
|
7933
9139
|
*/
|
|
7934
9140
|
_commitGroupMove(sourceTabGroupId, insertionIndex) {
|
|
7935
|
-
var _a, _b
|
|
7936
|
-
// Read transfer data
|
|
7937
|
-
// _chipDragCleanup clears the global LocalSelectionTransfer
|
|
7938
|
-
// singleton which getPanelData() reads from.
|
|
9141
|
+
var _a, _b;
|
|
9142
|
+
// Read transfer data first.
|
|
7939
9143
|
const data = getPanelData();
|
|
7940
|
-
|
|
7941
|
-
|
|
9144
|
+
// Synchronously dispose the source chip's drag sources, which
|
|
9145
|
+
// clears the panelTransfer payload + iframe shield. Cross-group
|
|
9146
|
+
// moves dissolve the source chip on a microtask, which is too
|
|
9147
|
+
// late: a synchronous `getPanelData()` after this method (or any
|
|
9148
|
+
// sibling dragover handler firing in the same tick) would
|
|
9149
|
+
// otherwise see stale data still referencing the old tabGroupId.
|
|
9150
|
+
this._tabGroupManager.disposeChipDrag(sourceTabGroupId);
|
|
7942
9151
|
// Check if the tab group exists in this group (within-group reorder)
|
|
7943
9152
|
// or in another group (cross-group move).
|
|
7944
9153
|
const isLocal = this.group.model
|
|
7945
9154
|
.getTabGroups()
|
|
7946
9155
|
.some((tg) => tg.id === sourceTabGroupId);
|
|
7947
9156
|
if (isLocal) {
|
|
7948
|
-
if (((
|
|
9157
|
+
if (((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) === 'smooth') {
|
|
7949
9158
|
this._clearGroupDragClasses(sourceTabGroupId);
|
|
7950
9159
|
const firstPositions = this.snapshotTabPositions();
|
|
7951
9160
|
this.resetTabTransforms();
|
|
@@ -7973,7 +9182,7 @@ class Tabs extends CompositeDisposable {
|
|
|
7973
9182
|
this.accessor.moveGroupOrPanel({
|
|
7974
9183
|
from: {
|
|
7975
9184
|
groupId: data.groupId,
|
|
7976
|
-
tabGroupId: (
|
|
9185
|
+
tabGroupId: (_b = data.tabGroupId) !== null && _b !== void 0 ? _b : sourceTabGroupId,
|
|
7977
9186
|
},
|
|
7978
9187
|
to: {
|
|
7979
9188
|
group: this.group,
|
|
@@ -8001,22 +9210,27 @@ class Tabs extends CompositeDisposable {
|
|
|
8001
9210
|
this._tabGroupManager.skipNextCollapseAnimation = true;
|
|
8002
9211
|
}
|
|
8003
9212
|
resetDragAnimation() {
|
|
8004
|
-
var _a, _b;
|
|
8005
9213
|
this._pendingCollapse = false;
|
|
8006
|
-
|
|
8007
|
-
//
|
|
8008
|
-
|
|
8009
|
-
|
|
8010
|
-
|
|
8011
|
-
|
|
8012
|
-
|
|
8013
|
-
|
|
8014
|
-
|
|
8015
|
-
|
|
8016
|
-
|
|
8017
|
-
|
|
8018
|
-
|
|
8019
|
-
|
|
9214
|
+
// After a drop, `tab.onDrop` consumes _animState (sets it to null)
|
|
9215
|
+
// and immediately calls `runFlipAnimation`, which sets transforms
|
|
9216
|
+
// and queues an rAF to trigger the CSS transition. dragend fires
|
|
9217
|
+
// synchronously on the source element BEFORE that rAF runs — if
|
|
9218
|
+
// we cleared transforms here we'd clobber the in-flight FLIP, so
|
|
9219
|
+
// gate the cleanup on _animState still being set (i.e. drag was
|
|
9220
|
+
// cancelled rather than dropped).
|
|
9221
|
+
if (this._animState) {
|
|
9222
|
+
this.resetTabTransforms();
|
|
9223
|
+
if (this._animState.sourceTabGroupId) {
|
|
9224
|
+
this._clearGroupDragClasses(this._animState.sourceTabGroupId);
|
|
9225
|
+
}
|
|
9226
|
+
else {
|
|
9227
|
+
this._removeClassInstantlyBatch(this._tabs.map((t) => t.value.element), 'dv-tab--dragging');
|
|
9228
|
+
}
|
|
9229
|
+
this._animState = null;
|
|
9230
|
+
// Restore any hidden underlines from group drags.
|
|
9231
|
+
for (const [, el] of this._tabGroupManager.groupUnderlines) {
|
|
9232
|
+
el.style.removeProperty('display');
|
|
9233
|
+
}
|
|
8020
9234
|
}
|
|
8021
9235
|
}
|
|
8022
9236
|
runFlipAnimation(firstPositions, sourceTabId, isCrossGroup = false, animRange) {
|
|
@@ -8516,6 +9730,7 @@ const PROPERTY_KEYS_DOCKVIEW = (() => {
|
|
|
8516
9730
|
rootOverlayModel: undefined,
|
|
8517
9731
|
locked: undefined,
|
|
8518
9732
|
disableDnd: undefined,
|
|
9733
|
+
dndStrategy: undefined,
|
|
8519
9734
|
className: undefined,
|
|
8520
9735
|
noPanelsOverlay: undefined,
|
|
8521
9736
|
dndEdges: undefined,
|
|
@@ -8700,6 +9915,10 @@ class TabGroup extends CompositeDisposable {
|
|
|
8700
9915
|
}
|
|
8701
9916
|
|
|
8702
9917
|
class DockviewDidDropEvent extends DockviewEvent {
|
|
9918
|
+
/**
|
|
9919
|
+
* `PointerEvent` for touch drags has no `dataTransfer`; use
|
|
9920
|
+
* `getData()` for the dockview payload regardless of input method.
|
|
9921
|
+
*/
|
|
8703
9922
|
get nativeEvent() {
|
|
8704
9923
|
return this.options.nativeEvent;
|
|
8705
9924
|
}
|
|
@@ -8804,29 +10023,28 @@ class DockviewGroupPanelModel extends CompositeDisposable {
|
|
|
8804
10023
|
toggleClass(this.container, 'dv-groupview-floating', false);
|
|
8805
10024
|
toggleClass(this.container, 'dv-groupview-popout', false);
|
|
8806
10025
|
toggleClass(this.container, 'dv-groupview-edge', false);
|
|
10026
|
+
// Mouse and touch drop targets must agree on accepted zones.
|
|
10027
|
+
const applyZones = (zones) => {
|
|
10028
|
+
this.contentContainer.dropTarget.setTargetZones(zones);
|
|
10029
|
+
this.contentContainer.pointerDropTarget.setTargetZones(zones);
|
|
10030
|
+
};
|
|
8807
10031
|
switch (value.type) {
|
|
8808
10032
|
case 'grid':
|
|
8809
|
-
|
|
8810
|
-
'top',
|
|
8811
|
-
'bottom',
|
|
8812
|
-
'left',
|
|
8813
|
-
'right',
|
|
8814
|
-
'center',
|
|
8815
|
-
]);
|
|
10033
|
+
applyZones(['top', 'bottom', 'left', 'right', 'center']);
|
|
8816
10034
|
break;
|
|
8817
10035
|
case 'floating':
|
|
8818
|
-
|
|
8819
|
-
|
|
10036
|
+
applyZones(['center']);
|
|
10037
|
+
applyZones(value
|
|
8820
10038
|
? ['center']
|
|
8821
10039
|
: ['top', 'bottom', 'left', 'right', 'center']);
|
|
8822
10040
|
toggleClass(this.container, 'dv-groupview-floating', true);
|
|
8823
10041
|
break;
|
|
8824
10042
|
case 'popout':
|
|
8825
|
-
|
|
10043
|
+
applyZones(['center']);
|
|
8826
10044
|
toggleClass(this.container, 'dv-groupview-popout', true);
|
|
8827
10045
|
break;
|
|
8828
10046
|
case 'edge':
|
|
8829
|
-
|
|
10047
|
+
applyZones(['center']);
|
|
8830
10048
|
toggleClass(this.container, 'dv-groupview-edge', true);
|
|
8831
10049
|
break;
|
|
8832
10050
|
}
|
|
@@ -8952,6 +10170,8 @@ class DockviewGroupPanelModel extends CompositeDisposable {
|
|
|
8952
10170
|
// noop
|
|
8953
10171
|
}), this.contentContainer.dropTarget.onDrop((event) => {
|
|
8954
10172
|
this.handleDropEvent('content', event.nativeEvent, event.position);
|
|
10173
|
+
}), this.contentContainer.pointerDropTarget.onDrop((event) => {
|
|
10174
|
+
this.handleDropEvent('content', event.nativeEvent, event.position);
|
|
8955
10175
|
}), this.tabsContainer.onWillShowOverlay((event) => {
|
|
8956
10176
|
this._onWillShowOverlay.fire(event);
|
|
8957
10177
|
}), this.contentContainer.dropTarget.onWillShowOverlay((event) => {
|
|
@@ -8962,6 +10182,14 @@ class DockviewGroupPanelModel extends CompositeDisposable {
|
|
|
8962
10182
|
group: this.groupPanel,
|
|
8963
10183
|
getData: getPanelData,
|
|
8964
10184
|
}));
|
|
10185
|
+
}), this.contentContainer.pointerDropTarget.onWillShowOverlay((event) => {
|
|
10186
|
+
this._onWillShowOverlay.fire(new DockviewWillShowOverlayLocationEvent(event, {
|
|
10187
|
+
kind: 'content',
|
|
10188
|
+
panel: this.activePanel,
|
|
10189
|
+
api: this._api,
|
|
10190
|
+
group: this.groupPanel,
|
|
10191
|
+
getData: getPanelData,
|
|
10192
|
+
}));
|
|
8965
10193
|
}), this._onMove, this._onDidChange, this._onDidDrop, this._onWillDrop, this._onDidAddPanel, this._onDidRemovePanel, this._onDidActivePanelChange, this._onUnhandledDragOverEvent, this._onDidPanelTitleChange, this._onDidPanelParametersChange, this._onDidCreateTabGroup, this._onDidDestroyTabGroup, this._onDidAddPanelToTabGroup, this._onDidRemovePanelFromTabGroup, this._onDidTabGroupChange, this._onDidTabGroupCollapsedChange, this._onDidCreateTabGroup.event(() => {
|
|
8966
10194
|
this._scheduleTabGroupUpdate();
|
|
8967
10195
|
}), this._onDidDestroyTabGroup.event(() => {
|
|
@@ -10965,7 +12193,12 @@ class Overlay extends CompositeDisposable {
|
|
|
10965
12193
|
this.onDidChange = this._onDidChange.event;
|
|
10966
12194
|
this._onDidChangeEnd = new Emitter();
|
|
10967
12195
|
this.onDidChangeEnd = this._onDidChangeEnd.event;
|
|
10968
|
-
this.
|
|
12196
|
+
this._onDidStartMoving = new Emitter();
|
|
12197
|
+
/** Fires once per drag, the first time the float actually moves. */
|
|
12198
|
+
this.onDidStartMoving = this._onDidStartMoving.event;
|
|
12199
|
+
this._dragMove = new MutableDisposable();
|
|
12200
|
+
this._dragCancelled = false;
|
|
12201
|
+
this.addDisposables(this._onDidChange, this._onDidChangeEnd, this._onDidStartMoving, this._dragMove);
|
|
10969
12202
|
this._element.className = 'dv-resize-container';
|
|
10970
12203
|
this._isVisible = true;
|
|
10971
12204
|
this.setupResize('top');
|
|
@@ -11074,16 +12307,60 @@ class Overlay extends CompositeDisposable {
|
|
|
11074
12307
|
result.height = element.height;
|
|
11075
12308
|
return result;
|
|
11076
12309
|
}
|
|
12310
|
+
/**
|
|
12311
|
+
* Abort an in-flight move-the-float drag. Used by the void container
|
|
12312
|
+
* when a redock long-press fires after the move started, so the ghost
|
|
12313
|
+
* gesture wins without the float continuing to follow the finger.
|
|
12314
|
+
* Does not emit `onDidChangeEnd` because no change is being committed.
|
|
12315
|
+
*/
|
|
12316
|
+
cancelPendingDrag() {
|
|
12317
|
+
if (!this._dragMove.value) {
|
|
12318
|
+
return;
|
|
12319
|
+
}
|
|
12320
|
+
this._dragCancelled = true;
|
|
12321
|
+
toggleClass(this._element, 'dv-resize-container-dragging', false);
|
|
12322
|
+
this._dragMove.value = Disposable.NONE;
|
|
12323
|
+
}
|
|
11077
12324
|
setupDrag(dragTarget, options = { inDragMode: false }) {
|
|
11078
|
-
const
|
|
11079
|
-
const track = () => {
|
|
12325
|
+
const track = (captureTarget, pointerId) => {
|
|
11080
12326
|
let offset = null;
|
|
12327
|
+
let hasMoved = false;
|
|
12328
|
+
this._dragCancelled = false;
|
|
11081
12329
|
const iframes = disableIframePointEvents();
|
|
11082
|
-
|
|
12330
|
+
if (captureTarget &&
|
|
12331
|
+
typeof pointerId === 'number' &&
|
|
12332
|
+
typeof captureTarget.setPointerCapture === 'function') {
|
|
12333
|
+
try {
|
|
12334
|
+
captureTarget.setPointerCapture(pointerId);
|
|
12335
|
+
}
|
|
12336
|
+
catch (_a) {
|
|
12337
|
+
// ignore – non-fatal if the browser refuses capture
|
|
12338
|
+
}
|
|
12339
|
+
}
|
|
12340
|
+
const end = () => {
|
|
12341
|
+
toggleClass(this._element, 'dv-resize-container-dragging', false);
|
|
12342
|
+
this._dragMove.value = Disposable.NONE;
|
|
12343
|
+
this._onDidChangeEnd.fire();
|
|
12344
|
+
};
|
|
12345
|
+
this._dragMove.value = new CompositeDisposable({
|
|
11083
12346
|
dispose: () => {
|
|
11084
12347
|
iframes.release();
|
|
12348
|
+
if (captureTarget &&
|
|
12349
|
+
typeof pointerId === 'number' &&
|
|
12350
|
+
typeof captureTarget.releasePointerCapture ===
|
|
12351
|
+
'function') {
|
|
12352
|
+
try {
|
|
12353
|
+
captureTarget.releasePointerCapture(pointerId);
|
|
12354
|
+
}
|
|
12355
|
+
catch (_a) {
|
|
12356
|
+
// ignore – pointer may already be released
|
|
12357
|
+
}
|
|
12358
|
+
}
|
|
11085
12359
|
},
|
|
11086
12360
|
}, addDisposableListener(window, 'pointermove', (e) => {
|
|
12361
|
+
if (this._dragCancelled) {
|
|
12362
|
+
return;
|
|
12363
|
+
}
|
|
11087
12364
|
const containerRect = this.options.container.getBoundingClientRect();
|
|
11088
12365
|
const x = e.clientX - containerRect.left;
|
|
11089
12366
|
const y = e.clientY - containerRect.top;
|
|
@@ -11120,13 +12397,13 @@ class Overlay extends CompositeDisposable {
|
|
|
11120
12397
|
bounds.right = right;
|
|
11121
12398
|
}
|
|
11122
12399
|
this.setBounds(bounds);
|
|
11123
|
-
|
|
11124
|
-
|
|
11125
|
-
|
|
11126
|
-
|
|
11127
|
-
}));
|
|
12400
|
+
if (!hasMoved) {
|
|
12401
|
+
hasMoved = true;
|
|
12402
|
+
this._onDidStartMoving.fire();
|
|
12403
|
+
}
|
|
12404
|
+
}), addDisposableListener(window, 'pointerup', end), addDisposableListener(window, 'pointercancel', end));
|
|
11128
12405
|
};
|
|
11129
|
-
this.addDisposables(
|
|
12406
|
+
this.addDisposables(addDisposableListener(dragTarget, 'pointerdown', (event) => {
|
|
11130
12407
|
if (event.defaultPrevented) {
|
|
11131
12408
|
event.preventDefault();
|
|
11132
12409
|
return;
|
|
@@ -11136,7 +12413,7 @@ class Overlay extends CompositeDisposable {
|
|
|
11136
12413
|
if (quasiDefaultPrevented(event)) {
|
|
11137
12414
|
return;
|
|
11138
12415
|
}
|
|
11139
|
-
track();
|
|
12416
|
+
track(dragTarget, event.pointerId);
|
|
11140
12417
|
}), addDisposableListener(this.options.content, 'pointerdown', (event) => {
|
|
11141
12418
|
if (event.defaultPrevented) {
|
|
11142
12419
|
return;
|
|
@@ -11147,7 +12424,7 @@ class Overlay extends CompositeDisposable {
|
|
|
11147
12424
|
return;
|
|
11148
12425
|
}
|
|
11149
12426
|
if (event.shiftKey) {
|
|
11150
|
-
track();
|
|
12427
|
+
track(this.options.content, event.pointerId);
|
|
11151
12428
|
}
|
|
11152
12429
|
}), addDisposableListener(this.options.content, 'pointerdown', () => {
|
|
11153
12430
|
arialLevelTracker.push(this._element);
|
|
@@ -11165,6 +12442,19 @@ class Overlay extends CompositeDisposable {
|
|
|
11165
12442
|
e.preventDefault();
|
|
11166
12443
|
let startPosition = null;
|
|
11167
12444
|
const iframes = disableIframePointEvents();
|
|
12445
|
+
const pointerId = e.pointerId;
|
|
12446
|
+
if (typeof resizeHandleElement.setPointerCapture === 'function') {
|
|
12447
|
+
try {
|
|
12448
|
+
resizeHandleElement.setPointerCapture(pointerId);
|
|
12449
|
+
}
|
|
12450
|
+
catch (_a) {
|
|
12451
|
+
// ignore – non-fatal if the browser refuses capture
|
|
12452
|
+
}
|
|
12453
|
+
}
|
|
12454
|
+
const end = () => {
|
|
12455
|
+
move.dispose();
|
|
12456
|
+
this._onDidChangeEnd.fire();
|
|
12457
|
+
};
|
|
11168
12458
|
move.value = new CompositeDisposable(addDisposableListener(window, 'pointermove', (e) => {
|
|
11169
12459
|
const containerRect = this.options.container.getBoundingClientRect();
|
|
11170
12460
|
const overlayRect = this._element.getBoundingClientRect();
|
|
@@ -11299,11 +12589,17 @@ class Overlay extends CompositeDisposable {
|
|
|
11299
12589
|
}), {
|
|
11300
12590
|
dispose: () => {
|
|
11301
12591
|
iframes.release();
|
|
12592
|
+
if (typeof resizeHandleElement.releasePointerCapture ===
|
|
12593
|
+
'function') {
|
|
12594
|
+
try {
|
|
12595
|
+
resizeHandleElement.releasePointerCapture(pointerId);
|
|
12596
|
+
}
|
|
12597
|
+
catch (_a) {
|
|
12598
|
+
// ignore – pointer may already be released
|
|
12599
|
+
}
|
|
12600
|
+
}
|
|
11302
12601
|
},
|
|
11303
|
-
}, addDisposableListener(window, 'pointerup',
|
|
11304
|
-
move.dispose();
|
|
11305
|
-
this._onDidChangeEnd.fire();
|
|
11306
|
-
}));
|
|
12602
|
+
}, addDisposableListener(window, 'pointerup', end), addDisposableListener(window, 'pointercancel', end));
|
|
11307
12603
|
}));
|
|
11308
12604
|
}
|
|
11309
12605
|
getMinimumWidth(width) {
|
|
@@ -11828,6 +13124,14 @@ class StrictEventsSequencing extends CompositeDisposable {
|
|
|
11828
13124
|
}
|
|
11829
13125
|
}
|
|
11830
13126
|
|
|
13127
|
+
function isCoarsePrimaryInput$1(win) {
|
|
13128
|
+
if (!win.matchMedia) {
|
|
13129
|
+
return false;
|
|
13130
|
+
}
|
|
13131
|
+
const coarse = win.matchMedia('(pointer: coarse)').matches;
|
|
13132
|
+
const fine = win.matchMedia('(pointer: fine)').matches;
|
|
13133
|
+
return coarse && !fine;
|
|
13134
|
+
}
|
|
11831
13135
|
class PopupService extends CompositeDisposable {
|
|
11832
13136
|
constructor(root, win = window) {
|
|
11833
13137
|
super();
|
|
@@ -11866,8 +13170,22 @@ class PopupService extends CompositeDisposable {
|
|
|
11866
13170
|
wrapper.style.left = `${position.x - offsetX}px`;
|
|
11867
13171
|
this._element.appendChild(wrapper);
|
|
11868
13172
|
this._active = wrapper;
|
|
13173
|
+
// Outside-pointerdown dismissal is suppressed for a short grace
|
|
13174
|
+
// window after opening. Touch long-press callers (chip / tab context
|
|
13175
|
+
// menus) open the popover while the user's finger is still pressing
|
|
13176
|
+
// the source element — Android Chrome can dispatch a follow-up
|
|
13177
|
+
// synthetic pointerdown tied to the gesture, and the release-then-
|
|
13178
|
+
// retap motion can land just outside the wrapper. Either would
|
|
13179
|
+
// dismiss the popover before the user can see or interact with it.
|
|
13180
|
+
// The grace window is short enough that intentional outside taps
|
|
13181
|
+
// still feel responsive.
|
|
13182
|
+
const openedAt = Date.now();
|
|
13183
|
+
const POINTERDOWN_GRACE_MS = 200;
|
|
11869
13184
|
this._activeDisposable.value = new CompositeDisposable(addDisposableListener(this._window, 'pointerdown', (event) => {
|
|
11870
13185
|
var _a;
|
|
13186
|
+
if (Date.now() - openedAt < POINTERDOWN_GRACE_MS) {
|
|
13187
|
+
return;
|
|
13188
|
+
}
|
|
11871
13189
|
const target = event.target;
|
|
11872
13190
|
if (!(target instanceof HTMLElement)) {
|
|
11873
13191
|
return;
|
|
@@ -11885,6 +13203,18 @@ class PopupService extends CompositeDisposable {
|
|
|
11885
13203
|
this.close();
|
|
11886
13204
|
}
|
|
11887
13205
|
}), addDisposableListener(this._window, 'resize', () => {
|
|
13206
|
+
// On touch-primary devices, common interactions resize the
|
|
13207
|
+
// window: on-screen keyboard pop, orientation change, browser
|
|
13208
|
+
// address-bar collapse. None of these mean "the user wants
|
|
13209
|
+
// the popover dismissed". Specifically, focusing the chip
|
|
13210
|
+
// context menu's rename input pops the keyboard, which would
|
|
13211
|
+
// otherwise close the menu the moment the user goes to edit
|
|
13212
|
+
// it. Desktop / hybrid input keeps the existing behaviour —
|
|
13213
|
+
// there a resize genuinely means the user has resized the
|
|
13214
|
+
// window and the popover position is now stale.
|
|
13215
|
+
if (isCoarsePrimaryInput$1(this._window)) {
|
|
13216
|
+
return;
|
|
13217
|
+
}
|
|
11888
13218
|
this.close();
|
|
11889
13219
|
}));
|
|
11890
13220
|
this._window.requestAnimationFrame(() => {
|
|
@@ -11941,6 +13271,14 @@ function buildSeparator() {
|
|
|
11941
13271
|
el.setAttribute('role', 'separator');
|
|
11942
13272
|
return el;
|
|
11943
13273
|
}
|
|
13274
|
+
function isCoarsePrimaryInput() {
|
|
13275
|
+
if (typeof window === 'undefined' || !window.matchMedia) {
|
|
13276
|
+
return false;
|
|
13277
|
+
}
|
|
13278
|
+
const coarse = window.matchMedia('(pointer: coarse)').matches;
|
|
13279
|
+
const fine = window.matchMedia('(pointer: fine)').matches;
|
|
13280
|
+
return coarse && !fine;
|
|
13281
|
+
}
|
|
11944
13282
|
function buildRenameInput(tabGroup) {
|
|
11945
13283
|
const wrapper = document.createElement('div');
|
|
11946
13284
|
wrapper.className = 'dv-context-menu-rename';
|
|
@@ -11961,10 +13299,17 @@ function buildRenameInput(tabGroup) {
|
|
|
11961
13299
|
e.stopPropagation();
|
|
11962
13300
|
});
|
|
11963
13301
|
wrapper.appendChild(input);
|
|
11964
|
-
|
|
11965
|
-
|
|
11966
|
-
|
|
11967
|
-
|
|
13302
|
+
// Skip auto-focus on touch-primary devices: focusing the input pops the
|
|
13303
|
+
// on-screen keyboard, which fires `window resize`, which `PopupService`
|
|
13304
|
+
// listens to and uses to dismiss the popover — so the menu opens, the
|
|
13305
|
+
// keyboard appears, and the menu immediately closes before the user can
|
|
13306
|
+
// type. The user can still tap the input to focus it intentionally.
|
|
13307
|
+
if (!isCoarsePrimaryInput()) {
|
|
13308
|
+
requestAnimationFrame(() => {
|
|
13309
|
+
input.focus();
|
|
13310
|
+
input.select();
|
|
13311
|
+
});
|
|
13312
|
+
}
|
|
11968
13313
|
return wrapper;
|
|
11969
13314
|
}
|
|
11970
13315
|
function buildColorPicker(tabGroup, palette) {
|
|
@@ -12879,7 +14224,7 @@ class DockviewComponent extends BaseGrid {
|
|
|
12879
14224
|
return this._popoutRestorationPromise;
|
|
12880
14225
|
}
|
|
12881
14226
|
constructor(container, options) {
|
|
12882
|
-
var _a, _b, _c, _d, _e, _f;
|
|
14227
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
12883
14228
|
super(container, {
|
|
12884
14229
|
proportionalLayout: true,
|
|
12885
14230
|
orientation: Orientation.HORIZONTAL,
|
|
@@ -12978,37 +14323,51 @@ class DockviewComponent extends BaseGrid {
|
|
|
12978
14323
|
this._floatingOverlayHost = document.createElement('div');
|
|
12979
14324
|
this._floatingOverlayHost.className = 'dv-floating-overlay-host';
|
|
12980
14325
|
this._shellManager.element.appendChild(this._floatingOverlayHost);
|
|
12981
|
-
|
|
12982
|
-
|
|
12983
|
-
|
|
12984
|
-
|
|
12985
|
-
if (data) {
|
|
12986
|
-
if (data.viewId !== this.id) {
|
|
12987
|
-
return false;
|
|
12988
|
-
}
|
|
12989
|
-
if (position === 'center') {
|
|
12990
|
-
// center drop target is only allowed if there are no panels in the grid
|
|
12991
|
-
// floating panels are allowed
|
|
12992
|
-
return this.gridview.length === 0;
|
|
12993
|
-
}
|
|
12994
|
-
return true;
|
|
12995
|
-
}
|
|
12996
|
-
if (position === 'center' && this.gridview.length !== 0) {
|
|
12997
|
-
/**
|
|
12998
|
-
* for external events only show the four-corner drag overlays, disable
|
|
12999
|
-
* the center position so that external drag events can fall through to the group
|
|
13000
|
-
* and panel drop target handlers
|
|
13001
|
-
*/
|
|
14326
|
+
const rootCanDisplayOverlay = (event, position) => {
|
|
14327
|
+
const data = getPanelData();
|
|
14328
|
+
if (data) {
|
|
14329
|
+
if (data.viewId !== this.id) {
|
|
13002
14330
|
return false;
|
|
13003
14331
|
}
|
|
13004
|
-
|
|
13005
|
-
|
|
13006
|
-
|
|
13007
|
-
|
|
14332
|
+
if (position === 'center') {
|
|
14333
|
+
// center drop target is only allowed if there are no panels in the grid
|
|
14334
|
+
// floating panels are allowed
|
|
14335
|
+
return this.gridview.length === 0;
|
|
14336
|
+
}
|
|
14337
|
+
return true;
|
|
14338
|
+
}
|
|
14339
|
+
if (position === 'center' && this.gridview.length !== 0) {
|
|
14340
|
+
/**
|
|
14341
|
+
* for external events only show the four-corner drag overlays, disable
|
|
14342
|
+
* the center position so that external drag events can fall through to the group
|
|
14343
|
+
* and panel drop target handlers
|
|
14344
|
+
*/
|
|
14345
|
+
return false;
|
|
14346
|
+
}
|
|
14347
|
+
const firedEvent = new DockviewUnhandledDragOverEvent(event, 'edge', position, getPanelData);
|
|
14348
|
+
this._onUnhandledDragOverEvent.fire(firedEvent);
|
|
14349
|
+
return firedEvent.isAccepted;
|
|
14350
|
+
};
|
|
14351
|
+
this._rootDropTarget = html5Backend.createDropTarget(this.element, {
|
|
14352
|
+
className: 'dv-drop-target-edge',
|
|
14353
|
+
canDisplayOverlay: rootCanDisplayOverlay,
|
|
13008
14354
|
acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
|
|
13009
14355
|
overlayModel: (_f = options.rootOverlayModel) !== null && _f !== void 0 ? _f : DEFAULT_ROOT_OVERLAY_MODEL,
|
|
13010
14356
|
getOverrideTarget: () => { var _a; return (_a = this.rootDropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
|
|
13011
14357
|
});
|
|
14358
|
+
this._rootPointerDropTarget = pointerBackend.createDropTarget(this.element, {
|
|
14359
|
+
className: 'dv-drop-target-edge',
|
|
14360
|
+
canDisplayOverlay: rootCanDisplayOverlay,
|
|
14361
|
+
acceptedTargetZones: [
|
|
14362
|
+
'top',
|
|
14363
|
+
'bottom',
|
|
14364
|
+
'left',
|
|
14365
|
+
'right',
|
|
14366
|
+
'center',
|
|
14367
|
+
],
|
|
14368
|
+
overlayModel: (_g = options.rootOverlayModel) !== null && _g !== void 0 ? _g : DEFAULT_ROOT_OVERLAY_MODEL,
|
|
14369
|
+
getOverrideTarget: () => { var _a; return (_a = this.rootDropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
|
|
14370
|
+
});
|
|
13012
14371
|
this.updateDropTargetModel(options);
|
|
13013
14372
|
toggleClass(this.gridview.element, 'dv-dockview', true);
|
|
13014
14373
|
toggleClass(this.element, 'dv-debug', !!options.debug);
|
|
@@ -13070,7 +14429,7 @@ class DockviewComponent extends BaseGrid {
|
|
|
13070
14429
|
d.dispose();
|
|
13071
14430
|
}
|
|
13072
14431
|
this._edgeGroupDisposables.clear();
|
|
13073
|
-
}), this._rootDropTarget, this._rootDropTarget.onWillShowOverlay((event) => {
|
|
14432
|
+
}), this._rootDropTarget, this._rootPointerDropTarget, Event.any(this._rootDropTarget.onWillShowOverlay, this._rootPointerDropTarget.onWillShowOverlay)((event) => {
|
|
13074
14433
|
if (this.gridview.length > 0 && event.position === 'center') {
|
|
13075
14434
|
// option only available when no panels in primary grid
|
|
13076
14435
|
return;
|
|
@@ -13082,7 +14441,7 @@ class DockviewComponent extends BaseGrid {
|
|
|
13082
14441
|
group: undefined,
|
|
13083
14442
|
getData: getPanelData,
|
|
13084
14443
|
}));
|
|
13085
|
-
}), this._rootDropTarget.onDrop((event) => {
|
|
14444
|
+
}), Event.any(this._rootDropTarget.onDrop, this._rootPointerDropTarget.onDrop)((event) => {
|
|
13086
14445
|
var _a;
|
|
13087
14446
|
const willDropEvent = new DockviewWillDropEvent({
|
|
13088
14447
|
nativeEvent: event.nativeEvent,
|
|
@@ -13120,7 +14479,7 @@ class DockviewComponent extends BaseGrid {
|
|
|
13120
14479
|
getData: getPanelData,
|
|
13121
14480
|
}));
|
|
13122
14481
|
}
|
|
13123
|
-
})
|
|
14482
|
+
}));
|
|
13124
14483
|
}
|
|
13125
14484
|
setVisible(panel, visible) {
|
|
13126
14485
|
switch (panel.api.location.type) {
|
|
@@ -13632,9 +14991,12 @@ class DockviewComponent extends BaseGrid {
|
|
|
13632
14991
|
}
|
|
13633
14992
|
this.updateDropTargetModel(options);
|
|
13634
14993
|
const oldDisableDnd = this.options.disableDnd;
|
|
14994
|
+
const oldDndStrategy = this.options.dndStrategy;
|
|
13635
14995
|
this._options = Object.assign(Object.assign({}, this.options), options);
|
|
13636
14996
|
const newDisableDnd = this.options.disableDnd;
|
|
13637
|
-
|
|
14997
|
+
const newDndStrategy = this.options.dndStrategy;
|
|
14998
|
+
if (oldDisableDnd !== newDisableDnd ||
|
|
14999
|
+
oldDndStrategy !== newDndStrategy) {
|
|
13638
15000
|
this.updateDragAndDropState();
|
|
13639
15001
|
}
|
|
13640
15002
|
if ('theme' in options) {
|
|
@@ -15198,15 +16560,18 @@ class DockviewComponent extends BaseGrid {
|
|
|
15198
16560
|
}
|
|
15199
16561
|
updateDropTargetModel(options) {
|
|
15200
16562
|
if ('dndEdges' in options) {
|
|
15201
|
-
|
|
15202
|
-
|
|
15203
|
-
|
|
16563
|
+
const disabled = typeof options.dndEdges === 'boolean' &&
|
|
16564
|
+
options.dndEdges === false;
|
|
16565
|
+
this._rootDropTarget.disabled = disabled;
|
|
16566
|
+
this._rootPointerDropTarget.disabled = disabled;
|
|
15204
16567
|
if (typeof options.dndEdges === 'object' &&
|
|
15205
16568
|
options.dndEdges !== null) {
|
|
15206
16569
|
this._rootDropTarget.setOverlayModel(options.dndEdges);
|
|
16570
|
+
this._rootPointerDropTarget.setOverlayModel(options.dndEdges);
|
|
15207
16571
|
}
|
|
15208
16572
|
else {
|
|
15209
16573
|
this._rootDropTarget.setOverlayModel(DEFAULT_ROOT_OVERLAY_MODEL);
|
|
16574
|
+
this._rootPointerDropTarget.setOverlayModel(DEFAULT_ROOT_OVERLAY_MODEL);
|
|
15210
16575
|
}
|
|
15211
16576
|
}
|
|
15212
16577
|
if ('rootOverlayModel' in options) {
|