dockview-core 6.3.0 → 6.4.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
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Floating clone that follows the pointer; appended to the owning
|
|
3
|
+
* document's body with `pointer-events: none` so it doesn't intercept
|
|
4
|
+
* hit-testing.
|
|
5
|
+
*/
|
|
6
|
+
export class PointerGhost {
|
|
7
|
+
constructor(opts) {
|
|
8
|
+
var _a, _b, _c, _d, _e;
|
|
9
|
+
this._disposed = false;
|
|
10
|
+
this.element = opts.element;
|
|
11
|
+
this.offsetX = (_a = opts.offsetX) !== null && _a !== void 0 ? _a : 0;
|
|
12
|
+
this.offsetY = (_b = opts.offsetY) !== null && _b !== void 0 ? _b : 0;
|
|
13
|
+
// Animate via transform (see update); position:fixed for scroll-independence.
|
|
14
|
+
this.element.style.position = 'fixed';
|
|
15
|
+
this.element.style.left = '0px';
|
|
16
|
+
this.element.style.top = '0px';
|
|
17
|
+
this.element.style.pointerEvents = 'none';
|
|
18
|
+
this.element.style.zIndex = '99999';
|
|
19
|
+
this.element.style.opacity = String((_c = opts.opacity) !== null && _c !== void 0 ? _c : 0.8);
|
|
20
|
+
this.element.style.willChange = 'transform';
|
|
21
|
+
this.element.style.transform = `translate3d(${opts.initialX - this.offsetX}px, ${opts.initialY - this.offsetY}px, 0)`;
|
|
22
|
+
const ownerDocument = (_e = (_d = opts.owner) === null || _d === void 0 ? void 0 : _d.ownerDocument) !== null && _e !== void 0 ? _e : document;
|
|
23
|
+
ownerDocument.body.appendChild(this.element);
|
|
24
|
+
}
|
|
25
|
+
update(clientX, clientY) {
|
|
26
|
+
if (this._disposed) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// translate3d composites on the GPU — no layout per pointermove.
|
|
30
|
+
this.element.style.transform = `translate3d(${clientX - this.offsetX}px, ${clientY - this.offsetY}px, 0)`;
|
|
31
|
+
}
|
|
32
|
+
dispose() {
|
|
33
|
+
if (this._disposed) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
this._disposed = true;
|
|
37
|
+
this.element.remove();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Position } from '../droptarget';
|
|
2
|
+
export interface PointerDragEvent {
|
|
3
|
+
readonly clientX: number;
|
|
4
|
+
readonly clientY: number;
|
|
5
|
+
readonly pointerEvent: PointerEvent;
|
|
6
|
+
}
|
|
7
|
+
export interface PointerDroptargetEvent {
|
|
8
|
+
readonly position: Position;
|
|
9
|
+
readonly nativeEvent: PointerEvent;
|
|
10
|
+
}
|
|
11
|
+
export interface IPointerDropTargetHandle {
|
|
12
|
+
readonly element: HTMLElement;
|
|
13
|
+
handleDragOver(event: PointerDragEvent): void;
|
|
14
|
+
handleDragLeave(): void;
|
|
15
|
+
handleDrop(event: PointerDragEvent): void;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -2,10 +2,11 @@ import { CompositeDisposable, IDisposable } from '../../../lifecycle';
|
|
|
2
2
|
import { Event } from '../../../events';
|
|
3
3
|
import { IDockviewPanel } from '../../dockviewPanel';
|
|
4
4
|
import { DockviewComponent } from '../../dockviewComponent';
|
|
5
|
-
import { Droptarget } from '../../../dnd/droptarget';
|
|
5
|
+
import { Droptarget, IDropTarget } from '../../../dnd/droptarget';
|
|
6
6
|
import { DockviewGroupPanelModel } from '../../dockviewGroupPanelModel';
|
|
7
7
|
export interface IContentContainer extends IDisposable {
|
|
8
8
|
readonly dropTarget: Droptarget;
|
|
9
|
+
readonly pointerDropTarget: IDropTarget;
|
|
9
10
|
onDidFocus: Event<void>;
|
|
10
11
|
onDidBlur: Event<void>;
|
|
11
12
|
element: HTMLElement;
|
|
@@ -32,6 +33,7 @@ export declare class ContentContainer extends CompositeDisposable implements ICo
|
|
|
32
33
|
readonly onDidBlur: Event<void>;
|
|
33
34
|
get element(): HTMLElement;
|
|
34
35
|
readonly dropTarget: Droptarget;
|
|
36
|
+
readonly pointerDropTarget: IDropTarget;
|
|
35
37
|
constructor(accessor: DockviewComponent, group: DockviewGroupPanelModel);
|
|
36
38
|
show(): void;
|
|
37
39
|
hide(): void;
|
|
@@ -2,6 +2,7 @@ import { CompositeDisposable, MutableDisposable, } from '../../../lifecycle';
|
|
|
2
2
|
import { Emitter } from '../../../events';
|
|
3
3
|
import { trackFocus } from '../../../dom';
|
|
4
4
|
import { Droptarget } from '../../../dnd/droptarget';
|
|
5
|
+
import { pointerBackend } from '../../../dnd/backend';
|
|
5
6
|
import { getPanelData } from '../../../dnd/dataTransfer';
|
|
6
7
|
export class ContentContainer extends CompositeDisposable {
|
|
7
8
|
get element() {
|
|
@@ -21,6 +22,25 @@ export class ContentContainer extends CompositeDisposable {
|
|
|
21
22
|
this._element.tabIndex = -1;
|
|
22
23
|
this.addDisposables(this._onDidFocus, this._onDidBlur);
|
|
23
24
|
const target = group.dropTargetContainer;
|
|
25
|
+
const canDisplayOverlay = (event, position) => {
|
|
26
|
+
if (this.group.locked === 'no-drop-target' ||
|
|
27
|
+
(this.group.locked && position === 'center')) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
const data = getPanelData();
|
|
31
|
+
if (!data &&
|
|
32
|
+
event.shiftKey &&
|
|
33
|
+
this.group.location.type !== 'floating') {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
if (data && data.viewId === this.accessor.id) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
return this.group.canDisplayOverlay(event, position, 'content');
|
|
40
|
+
};
|
|
41
|
+
// `dropTarget` stays the concrete `Droptarget` (not via the backend
|
|
42
|
+
// factory) because overlayRenderContainer forwards HTML5 drag events
|
|
43
|
+
// through `dropTarget.dnd` — that field is not part of `IDropTarget`.
|
|
24
44
|
this.dropTarget = new Droptarget(this.element, {
|
|
25
45
|
getOverlayOutline: () => {
|
|
26
46
|
var _a;
|
|
@@ -30,25 +50,22 @@ export class ContentContainer extends CompositeDisposable {
|
|
|
30
50
|
},
|
|
31
51
|
className: 'dv-drop-target-content',
|
|
32
52
|
acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
|
|
33
|
-
canDisplayOverlay
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (data && data.viewId === this.accessor.id) {
|
|
45
|
-
return true;
|
|
46
|
-
}
|
|
47
|
-
return this.group.canDisplayOverlay(event, position, 'content');
|
|
53
|
+
canDisplayOverlay,
|
|
54
|
+
getOverrideTarget: target ? () => target.model : undefined,
|
|
55
|
+
});
|
|
56
|
+
this.pointerDropTarget = pointerBackend.createDropTarget(this.element, {
|
|
57
|
+
acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
|
|
58
|
+
canDisplayOverlay,
|
|
59
|
+
getOverlayOutline: () => {
|
|
60
|
+
var _a;
|
|
61
|
+
return ((_a = accessor.options.theme) === null || _a === void 0 ? void 0 : _a.dndPanelOverlay) === 'group'
|
|
62
|
+
? this.element.parentElement
|
|
63
|
+
: null;
|
|
48
64
|
},
|
|
65
|
+
className: 'dv-drop-target-content',
|
|
49
66
|
getOverrideTarget: target ? () => target.model : undefined,
|
|
50
67
|
});
|
|
51
|
-
this.addDisposables(this.dropTarget);
|
|
68
|
+
this.addDisposables(this.dropTarget, this.pointerDropTarget);
|
|
52
69
|
}
|
|
53
70
|
show() {
|
|
54
71
|
this.element.style.display = '';
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { shiftAbsoluteElementIntoView } from '../../dom';
|
|
2
2
|
import { addDisposableListener } from '../../events';
|
|
3
3
|
import { CompositeDisposable, Disposable, MutableDisposable, } from '../../lifecycle';
|
|
4
|
+
function isCoarsePrimaryInput(win) {
|
|
5
|
+
if (!win.matchMedia) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
const coarse = win.matchMedia('(pointer: coarse)').matches;
|
|
9
|
+
const fine = win.matchMedia('(pointer: fine)').matches;
|
|
10
|
+
return coarse && !fine;
|
|
11
|
+
}
|
|
4
12
|
export class PopupService extends CompositeDisposable {
|
|
5
13
|
constructor(root, win = window) {
|
|
6
14
|
super();
|
|
@@ -39,8 +47,22 @@ export class PopupService extends CompositeDisposable {
|
|
|
39
47
|
wrapper.style.left = `${position.x - offsetX}px`;
|
|
40
48
|
this._element.appendChild(wrapper);
|
|
41
49
|
this._active = wrapper;
|
|
50
|
+
// Outside-pointerdown dismissal is suppressed for a short grace
|
|
51
|
+
// window after opening. Touch long-press callers (chip / tab context
|
|
52
|
+
// menus) open the popover while the user's finger is still pressing
|
|
53
|
+
// the source element — Android Chrome can dispatch a follow-up
|
|
54
|
+
// synthetic pointerdown tied to the gesture, and the release-then-
|
|
55
|
+
// retap motion can land just outside the wrapper. Either would
|
|
56
|
+
// dismiss the popover before the user can see or interact with it.
|
|
57
|
+
// The grace window is short enough that intentional outside taps
|
|
58
|
+
// still feel responsive.
|
|
59
|
+
const openedAt = Date.now();
|
|
60
|
+
const POINTERDOWN_GRACE_MS = 200;
|
|
42
61
|
this._activeDisposable.value = new CompositeDisposable(addDisposableListener(this._window, 'pointerdown', (event) => {
|
|
43
62
|
var _a;
|
|
63
|
+
if (Date.now() - openedAt < POINTERDOWN_GRACE_MS) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
44
66
|
const target = event.target;
|
|
45
67
|
if (!(target instanceof HTMLElement)) {
|
|
46
68
|
return;
|
|
@@ -58,6 +80,18 @@ export class PopupService extends CompositeDisposable {
|
|
|
58
80
|
this.close();
|
|
59
81
|
}
|
|
60
82
|
}), addDisposableListener(this._window, 'resize', () => {
|
|
83
|
+
// On touch-primary devices, common interactions resize the
|
|
84
|
+
// window: on-screen keyboard pop, orientation change, browser
|
|
85
|
+
// address-bar collapse. None of these mean "the user wants
|
|
86
|
+
// the popover dismissed". Specifically, focusing the chip
|
|
87
|
+
// context menu's rename input pops the keyboard, which would
|
|
88
|
+
// otherwise close the menu the moment the user goes to edit
|
|
89
|
+
// it. Desktop / hybrid input keeps the existing behaviour —
|
|
90
|
+
// there a resize genuinely means the user has resized the
|
|
91
|
+
// window and the popover position is now stale.
|
|
92
|
+
if (isCoarsePrimaryInput(this._window)) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
61
95
|
this.close();
|
|
62
96
|
}));
|
|
63
97
|
this._window.requestAnimationFrame(() => {
|
|
@@ -12,8 +12,11 @@ export declare class Tab extends CompositeDisposable {
|
|
|
12
12
|
private readonly group;
|
|
13
13
|
private readonly _element;
|
|
14
14
|
private readonly dropTarget;
|
|
15
|
+
private readonly pointerDropTarget;
|
|
15
16
|
private content;
|
|
16
|
-
private readonly
|
|
17
|
+
private readonly html5DragSource;
|
|
18
|
+
private readonly pointerDragSource;
|
|
19
|
+
private readonly panelTransfer;
|
|
17
20
|
private _direction;
|
|
18
21
|
private readonly _onPointDown;
|
|
19
22
|
readonly onPointerDown: Event<MouseEvent>;
|
|
@@ -22,9 +25,9 @@ export declare class Tab extends CompositeDisposable {
|
|
|
22
25
|
private readonly _onDropped;
|
|
23
26
|
readonly onDrop: Event<DroptargetEvent>;
|
|
24
27
|
private readonly _onDragStart;
|
|
25
|
-
readonly onDragStart: Event<DragEvent>;
|
|
28
|
+
readonly onDragStart: Event<PointerEvent | DragEvent>;
|
|
26
29
|
private readonly _onDragEnd;
|
|
27
|
-
readonly onDragEnd: Event<DragEvent>;
|
|
30
|
+
readonly onDragEnd: Event<PointerEvent | DragEvent>;
|
|
28
31
|
readonly onWillShowOverlay: Event<WillShowOverlayEvent>;
|
|
29
32
|
get element(): HTMLElement;
|
|
30
33
|
constructor(panel: IDockviewPanel, accessor: DockviewComponent, group: DockviewGroupPanel);
|
|
@@ -33,4 +36,9 @@ export declare class Tab extends CompositeDisposable {
|
|
|
33
36
|
private _buildOverlayModel;
|
|
34
37
|
setDirection(direction: DockviewHeaderDirection): void;
|
|
35
38
|
updateDragAndDropState(): void;
|
|
39
|
+
/**
|
|
40
|
+
* Vertical tabs are flipped to horizontal so the ghost stays readable
|
|
41
|
+
* during the drag rather than appearing sideways-rotated.
|
|
42
|
+
*/
|
|
43
|
+
private _buildGhostElement;
|
|
36
44
|
}
|
|
@@ -1,27 +1,10 @@
|
|
|
1
|
-
import { addDisposableListener, Emitter } from '../../../events';
|
|
1
|
+
import { addDisposableListener, Emitter, Event } from '../../../events';
|
|
2
2
|
import { CompositeDisposable } from '../../../lifecycle';
|
|
3
3
|
import { getPanelData, LocalSelectionTransfer, PanelTransfer, } from '../../../dnd/dataTransfer';
|
|
4
4
|
import { toggleClass } from '../../../dom';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
class TabDragHandler extends DragHandler {
|
|
9
|
-
constructor(element, accessor, group, panel, disabled) {
|
|
10
|
-
super(element, disabled);
|
|
11
|
-
this.accessor = accessor;
|
|
12
|
-
this.group = group;
|
|
13
|
-
this.panel = panel;
|
|
14
|
-
this.panelTransfer = LocalSelectionTransfer.getInstance();
|
|
15
|
-
}
|
|
16
|
-
getData(event) {
|
|
17
|
-
this.panelTransfer.setData([new PanelTransfer(this.accessor.id, this.group.id, this.panel.id)], PanelTransfer.prototype);
|
|
18
|
-
return {
|
|
19
|
-
dispose: () => {
|
|
20
|
-
this.panelTransfer.clearData(PanelTransfer.prototype);
|
|
21
|
-
},
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
}
|
|
5
|
+
import { html5Backend, pointerBackend, } from '../../../dnd/backend';
|
|
6
|
+
import { LongPressDetector } from '../../../dnd/pointer/longPress';
|
|
7
|
+
import { resolveDndCapabilities } from '../../dndCapabilities';
|
|
25
8
|
export class Tab extends CompositeDisposable {
|
|
26
9
|
get element() {
|
|
27
10
|
return this._element;
|
|
@@ -32,6 +15,7 @@ export class Tab extends CompositeDisposable {
|
|
|
32
15
|
this.accessor = accessor;
|
|
33
16
|
this.group = group;
|
|
34
17
|
this.content = undefined;
|
|
18
|
+
this.panelTransfer = LocalSelectionTransfer.getInstance();
|
|
35
19
|
this._direction = 'horizontal';
|
|
36
20
|
this._onPointDown = new Emitter();
|
|
37
21
|
this.onPointerDown = this._onPointDown.event;
|
|
@@ -43,114 +27,106 @@ export class Tab extends CompositeDisposable {
|
|
|
43
27
|
this.onDragStart = this._onDragStart.event;
|
|
44
28
|
this._onDragEnd = new Emitter();
|
|
45
29
|
this.onDragEnd = this._onDragEnd.event;
|
|
30
|
+
const caps = resolveDndCapabilities(this.accessor.options);
|
|
46
31
|
this._element = document.createElement('div');
|
|
47
32
|
this._element.className = 'dv-tab';
|
|
48
33
|
this._element.tabIndex = 0;
|
|
49
|
-
this._element.draggable =
|
|
34
|
+
this._element.draggable = caps.html5;
|
|
50
35
|
toggleClass(this.element, 'dv-inactive-tab', true);
|
|
51
|
-
|
|
52
|
-
|
|
36
|
+
const canDisplayOverlay = (event, position) => {
|
|
37
|
+
var _a;
|
|
38
|
+
if (this.group.locked) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
const data = getPanelData();
|
|
42
|
+
if (data && this.accessor.id === data.viewId) {
|
|
43
|
+
// Smooth-reorder takes over the in-flight visual when active,
|
|
44
|
+
// so individual tab overlays are suppressed for internal drags.
|
|
45
|
+
if (((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) === 'smooth') {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
return this.group.model.canDisplayOverlay(event, position, 'tab');
|
|
51
|
+
};
|
|
52
|
+
this.dropTarget = html5Backend.createDropTarget(this._element, {
|
|
53
|
+
acceptedTargetZones: ['left', 'right'],
|
|
54
|
+
overlayModel: this._buildOverlayModel(),
|
|
55
|
+
canDisplayOverlay,
|
|
56
|
+
getOverrideTarget: () => { var _a; return (_a = group.model.dropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
|
|
57
|
+
});
|
|
58
|
+
this.pointerDropTarget = pointerBackend.createDropTarget(this._element, {
|
|
53
59
|
acceptedTargetZones: ['left', 'right'],
|
|
54
60
|
overlayModel: this._buildOverlayModel(),
|
|
55
|
-
canDisplayOverlay
|
|
61
|
+
canDisplayOverlay,
|
|
62
|
+
getOverrideTarget: () => { var _a; return (_a = group.model.dropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
|
|
63
|
+
});
|
|
64
|
+
const sharedDragOptions = {
|
|
65
|
+
getData: () => {
|
|
66
|
+
this.panelTransfer.setData([
|
|
67
|
+
new PanelTransfer(this.accessor.id, this.group.id, this.panel.id),
|
|
68
|
+
], PanelTransfer.prototype);
|
|
69
|
+
return {
|
|
70
|
+
dispose: () => {
|
|
71
|
+
this.panelTransfer.clearData(PanelTransfer.prototype);
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
// 30/-10 matches the HTML5 setDragImage offset that has been
|
|
76
|
+
// shipped for years; pointer backend wraps in PointerGhost,
|
|
77
|
+
// HTML5 backend feeds into setDragImage.
|
|
78
|
+
createGhost: () => ({
|
|
79
|
+
element: this._buildGhostElement(),
|
|
80
|
+
offsetX: 30,
|
|
81
|
+
offsetY: -10,
|
|
82
|
+
}),
|
|
83
|
+
onDragStart: (event) => {
|
|
56
84
|
var _a;
|
|
57
|
-
|
|
58
|
-
|
|
85
|
+
this._onDragStart.fire(event);
|
|
86
|
+
if (!(event instanceof PointerEvent) &&
|
|
87
|
+
((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) === 'smooth') {
|
|
88
|
+
// Delay collapse to next frame so the browser
|
|
89
|
+
// captures the full drag image first.
|
|
90
|
+
requestAnimationFrame(() => {
|
|
91
|
+
toggleClass(this.element, 'dv-tab--dragging', true);
|
|
92
|
+
});
|
|
59
93
|
}
|
|
60
|
-
const data = getPanelData();
|
|
61
|
-
if (data && this.accessor.id === data.viewId) {
|
|
62
|
-
if (((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) === 'smooth') {
|
|
63
|
-
// When smooth reorder is enabled, the Tabs
|
|
64
|
-
// container handles all intra-accessor drops
|
|
65
|
-
// (both same-group and cross-group) via
|
|
66
|
-
// animation. Suppress the per-tab overlay so
|
|
67
|
-
// the tab is dropped *beside* rather than *on*.
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
return true;
|
|
71
|
-
}
|
|
72
|
-
return this.group.model.canDisplayOverlay(event, position, 'tab');
|
|
73
94
|
},
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
95
|
+
onDragEnd: (event) => {
|
|
96
|
+
this._onDragEnd.fire(event);
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
this.html5DragSource = html5Backend.createDragSource(this._element, Object.assign(Object.assign({}, sharedDragOptions), { disabled: !caps.html5 }));
|
|
100
|
+
this.pointerDragSource = pointerBackend.createDragSource(this._element, Object.assign(Object.assign({}, sharedDragOptions), { disabled: !caps.pointer, touchOnly: !caps.pointerHandlesMouse, isCancelled: () => !resolveDndCapabilities(this.accessor.options).pointer }));
|
|
101
|
+
// Both droptargets feed the same downstream stream; consumers don't
|
|
102
|
+
// need to know which path produced the overlay.
|
|
103
|
+
this.onWillShowOverlay = Event.any(this.dropTarget.onWillShowOverlay, this.pointerDropTarget.onWillShowOverlay);
|
|
77
104
|
this.addDisposables(this._onPointDown, this._onTabClick, this._onDropped, this._onDragStart, this._onDragEnd, this.accessor.onDidOptionsChange(() => {
|
|
78
|
-
this.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const isVertical = this._direction === 'vertical';
|
|
85
|
-
/**
|
|
86
|
-
* Properties to skip when copying computed styles for a
|
|
87
|
-
* vertical tab ghost. `writing-mode` is excluded so we
|
|
88
|
-
* can force `horizontal-tb`. Size and margin logical
|
|
89
|
-
* properties are excluded because their physical meaning
|
|
90
|
-
* flips when writing-mode changes, which would produce
|
|
91
|
-
* incorrect dimensions.
|
|
92
|
-
*/
|
|
93
|
-
const verticalSkip = new Set([
|
|
94
|
-
'writing-mode',
|
|
95
|
-
'inline-size',
|
|
96
|
-
'block-size',
|
|
97
|
-
'min-inline-size',
|
|
98
|
-
'min-block-size',
|
|
99
|
-
'max-inline-size',
|
|
100
|
-
'max-block-size',
|
|
101
|
-
'margin-inline',
|
|
102
|
-
'margin-inline-start',
|
|
103
|
-
'margin-inline-end',
|
|
104
|
-
'margin-block',
|
|
105
|
-
'margin-block-start',
|
|
106
|
-
'margin-block-end',
|
|
107
|
-
'padding-inline',
|
|
108
|
-
'padding-inline-start',
|
|
109
|
-
'padding-inline-end',
|
|
110
|
-
'padding-block',
|
|
111
|
-
'padding-block-start',
|
|
112
|
-
'padding-block-end',
|
|
113
|
-
]);
|
|
114
|
-
Array.from(style).forEach((key) => {
|
|
115
|
-
if (isVertical && verticalSkip.has(key)) {
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
newNode.style.setProperty(key, style.getPropertyValue(key), style.getPropertyPriority(key));
|
|
119
|
-
});
|
|
120
|
-
if (isVertical) {
|
|
121
|
-
// Force horizontal text flow and swap the physical
|
|
122
|
-
// dimensions so the ghost appears as a horizontal tab.
|
|
123
|
-
newNode.style.setProperty('writing-mode', 'horizontal-tb');
|
|
124
|
-
newNode.style.setProperty('width', style.height);
|
|
125
|
-
newNode.style.setProperty('height', style.width);
|
|
126
|
-
}
|
|
127
|
-
newNode.style.position = 'absolute';
|
|
128
|
-
newNode.classList.add('dv-tab-ghost-drag');
|
|
129
|
-
addGhostImage(event.dataTransfer, newNode, {
|
|
130
|
-
y: -10,
|
|
131
|
-
x: 30,
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
this._onDragStart.fire(event);
|
|
135
|
-
if (((_a = this.accessor.options.theme) === null || _a === void 0 ? void 0 : _a.tabAnimation) === 'smooth') {
|
|
136
|
-
// Delay collapse to next frame so the browser
|
|
137
|
-
// captures the full drag image first
|
|
138
|
-
requestAnimationFrame(() => {
|
|
139
|
-
toggleClass(this.element, 'dv-tab--dragging', true);
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
}), addDisposableListener(this._element, 'dragend', (event) => {
|
|
105
|
+
const model = this._buildOverlayModel();
|
|
106
|
+
this.dropTarget.setOverlayModel(model);
|
|
107
|
+
this.pointerDropTarget.setOverlayModel(model);
|
|
108
|
+
}), addDisposableListener(this._element, 'dragend', () => {
|
|
109
|
+
// The shared onDragEnd handler already fires _onDragEnd via
|
|
110
|
+
// the HTML5 backend; just strip the dragging class here.
|
|
143
111
|
toggleClass(this.element, 'dv-tab--dragging', false);
|
|
144
|
-
|
|
145
|
-
}), this.dragHandler, addDisposableListener(this._element, 'pointerdown', (event) => {
|
|
112
|
+
}), this.html5DragSource, addDisposableListener(this._element, 'pointerdown', (event) => {
|
|
146
113
|
this._onPointDown.fire(event);
|
|
147
114
|
}), addDisposableListener(this._element, 'click', (event) => {
|
|
148
115
|
this._onTabClick.fire(event);
|
|
149
116
|
}), addDisposableListener(this._element, 'contextmenu', (event) => {
|
|
150
117
|
this.accessor.contextMenuController.show(this.panel, this.group, event);
|
|
118
|
+
}), new LongPressDetector(this._element, {
|
|
119
|
+
onLongPress: (event) => {
|
|
120
|
+
// Don't let a subsequent finger move arm a drag on top
|
|
121
|
+
// of the just-opened menu.
|
|
122
|
+
this.pointerDragSource.cancelPending();
|
|
123
|
+
this.accessor.contextMenuController.show(this.panel, this.group, event);
|
|
124
|
+
},
|
|
151
125
|
}), this.dropTarget.onDrop((event) => {
|
|
152
126
|
this._onDropped.fire(event);
|
|
153
|
-
}), this.
|
|
127
|
+
}), this.pointerDropTarget.onDrop((event) => {
|
|
128
|
+
this._onDropped.fire(event);
|
|
129
|
+
}), this.dropTarget, this.pointerDropTarget, this.pointerDragSource);
|
|
154
130
|
}
|
|
155
131
|
setActive(isActive) {
|
|
156
132
|
toggleClass(this.element, 'dv-active-tab', isActive);
|
|
@@ -180,10 +156,59 @@ export class Tab extends CompositeDisposable {
|
|
|
180
156
|
}
|
|
181
157
|
setDirection(direction) {
|
|
182
158
|
this._direction = direction;
|
|
183
|
-
|
|
159
|
+
const zones = direction === 'vertical' ? ['top', 'bottom'] : ['left', 'right'];
|
|
160
|
+
this.dropTarget.setTargetZones(zones);
|
|
161
|
+
this.pointerDropTarget.setTargetZones(zones);
|
|
184
162
|
}
|
|
185
163
|
updateDragAndDropState() {
|
|
186
|
-
|
|
187
|
-
this.
|
|
164
|
+
const caps = resolveDndCapabilities(this.accessor.options);
|
|
165
|
+
this._element.draggable = caps.html5;
|
|
166
|
+
this.html5DragSource.setDisabled(!caps.html5);
|
|
167
|
+
this.pointerDragSource.setDisabled(!caps.pointer);
|
|
168
|
+
this.pointerDragSource.setTouchOnly(!caps.pointerHandlesMouse);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Vertical tabs are flipped to horizontal so the ghost stays readable
|
|
172
|
+
* during the drag rather than appearing sideways-rotated.
|
|
173
|
+
*/
|
|
174
|
+
_buildGhostElement() {
|
|
175
|
+
const style = getComputedStyle(this.element);
|
|
176
|
+
const newNode = this.element.cloneNode(true);
|
|
177
|
+
const isVertical = this._direction === 'vertical';
|
|
178
|
+
const verticalSkip = new Set([
|
|
179
|
+
'writing-mode',
|
|
180
|
+
'inline-size',
|
|
181
|
+
'block-size',
|
|
182
|
+
'min-inline-size',
|
|
183
|
+
'min-block-size',
|
|
184
|
+
'max-inline-size',
|
|
185
|
+
'max-block-size',
|
|
186
|
+
'margin-inline',
|
|
187
|
+
'margin-inline-start',
|
|
188
|
+
'margin-inline-end',
|
|
189
|
+
'margin-block',
|
|
190
|
+
'margin-block-start',
|
|
191
|
+
'margin-block-end',
|
|
192
|
+
'padding-inline',
|
|
193
|
+
'padding-inline-start',
|
|
194
|
+
'padding-inline-end',
|
|
195
|
+
'padding-block',
|
|
196
|
+
'padding-block-start',
|
|
197
|
+
'padding-block-end',
|
|
198
|
+
]);
|
|
199
|
+
Array.from(style).forEach((key) => {
|
|
200
|
+
if (isVertical && verticalSkip.has(key)) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
newNode.style.setProperty(key, style.getPropertyValue(key), style.getPropertyPriority(key));
|
|
204
|
+
});
|
|
205
|
+
if (isVertical) {
|
|
206
|
+
newNode.style.setProperty('writing-mode', 'horizontal-tb');
|
|
207
|
+
newNode.style.setProperty('width', style.height);
|
|
208
|
+
newNode.style.setProperty('height', style.width);
|
|
209
|
+
}
|
|
210
|
+
newNode.style.position = 'absolute';
|
|
211
|
+
newNode.classList.add('dv-tab-ghost-drag');
|
|
212
|
+
return newNode;
|
|
188
213
|
}
|
|
189
214
|
}
|
|
@@ -4,6 +4,14 @@ import { ITabGroup } from '../../tabGroup';
|
|
|
4
4
|
import { TabGroupColorPalette } from '../../tabGroupAccent';
|
|
5
5
|
import { ITabGroupChipRenderer } from '../../framework';
|
|
6
6
|
import { DockviewApi } from '../../../api/component.api';
|
|
7
|
+
/**
|
|
8
|
+
* Visual chip for a tab group. Owns the DOM element, label, click /
|
|
9
|
+
* context-menu interactions, and exposes a long-press gesture as a
|
|
10
|
+
* second `onContextMenu` source. Drag-and-drop wiring lives in
|
|
11
|
+
* `TabGroupManager` — the manager constructs the drag sources on this
|
|
12
|
+
* chip's element so it can include tabs-list context (custom group
|
|
13
|
+
* drag image, tab-group transfer payload).
|
|
14
|
+
*/
|
|
7
15
|
export declare class TabGroupChip extends CompositeDisposable implements ITabGroupChipRenderer {
|
|
8
16
|
private readonly _palette?;
|
|
9
17
|
private readonly _element;
|
|
@@ -12,9 +20,8 @@ export declare class TabGroupChip extends CompositeDisposable implements ITabGro
|
|
|
12
20
|
private readonly _onClick;
|
|
13
21
|
readonly onClick: Event<MouseEvent>;
|
|
14
22
|
private readonly _onContextMenu;
|
|
23
|
+
/** Fires on right-click and on touch long-press. */
|
|
15
24
|
readonly onContextMenu: Event<MouseEvent>;
|
|
16
|
-
private readonly _onDragStart;
|
|
17
|
-
readonly onDragStart: Event<DragEvent>;
|
|
18
25
|
get element(): HTMLElement;
|
|
19
26
|
constructor(_palette?: TabGroupColorPalette | undefined);
|
|
20
27
|
init(params: {
|
|
@@ -2,6 +2,15 @@ import { addDisposableListener, Emitter } from '../../../events';
|
|
|
2
2
|
import { CompositeDisposable } from '../../../lifecycle';
|
|
3
3
|
import { toggleClass } from '../../../dom';
|
|
4
4
|
import { applyTabGroupAccent, } from '../../tabGroupAccent';
|
|
5
|
+
import { LongPressDetector } from '../../../dnd/pointer/longPress';
|
|
6
|
+
/**
|
|
7
|
+
* Visual chip for a tab group. Owns the DOM element, label, click /
|
|
8
|
+
* context-menu interactions, and exposes a long-press gesture as a
|
|
9
|
+
* second `onContextMenu` source. Drag-and-drop wiring lives in
|
|
10
|
+
* `TabGroupManager` — the manager constructs the drag sources on this
|
|
11
|
+
* chip's element so it can include tabs-list context (custom group
|
|
12
|
+
* drag image, tab-group transfer payload).
|
|
13
|
+
*/
|
|
5
14
|
export class TabGroupChip extends CompositeDisposable {
|
|
6
15
|
get element() {
|
|
7
16
|
return this._element;
|
|
@@ -12,22 +21,22 @@ export class TabGroupChip extends CompositeDisposable {
|
|
|
12
21
|
this._onClick = new Emitter();
|
|
13
22
|
this.onClick = this._onClick.event;
|
|
14
23
|
this._onContextMenu = new Emitter();
|
|
24
|
+
/** Fires on right-click and on touch long-press. */
|
|
15
25
|
this.onContextMenu = this._onContextMenu.event;
|
|
16
|
-
this._onDragStart = new Emitter();
|
|
17
|
-
this.onDragStart = this._onDragStart.event;
|
|
18
26
|
this._element = document.createElement('div');
|
|
19
27
|
this._element.className = 'dv-tab-group-chip';
|
|
20
28
|
this._element.tabIndex = 0;
|
|
21
|
-
this._element.draggable = true;
|
|
22
29
|
this._label = document.createElement('span');
|
|
23
30
|
this._label.className = 'dv-tab-group-chip-label';
|
|
24
31
|
this._element.appendChild(this._label);
|
|
25
|
-
this.addDisposables(this._onClick, this._onContextMenu,
|
|
32
|
+
this.addDisposables(this._onClick, this._onContextMenu, new LongPressDetector(this._element, {
|
|
33
|
+
onLongPress: (event) => {
|
|
34
|
+
this._onContextMenu.fire(event);
|
|
35
|
+
},
|
|
36
|
+
}), addDisposableListener(this._element, 'click', (event) => {
|
|
26
37
|
this._onClick.fire(event);
|
|
27
38
|
}), addDisposableListener(this._element, 'contextmenu', (event) => {
|
|
28
39
|
this._onContextMenu.fire(event);
|
|
29
|
-
}), addDisposableListener(this._element, 'dragstart', (event) => {
|
|
30
|
-
this._onDragStart.fire(event);
|
|
31
40
|
}));
|
|
32
41
|
}
|
|
33
42
|
init(params) {
|