mirror of
https://github.com/mathuo/dockview
synced 2025-09-08 18:36:51 +00:00
Merge branch '170-allow-dnd-of-entire-dockview-groups' of https://github.com/mathuo/dockview into 176-dnd-to-edge-of-dockview
This commit is contained in:
commit
78336d6d90
@ -3,7 +3,7 @@ import { DragHandler } from '../../dnd/abstractDragHandler';
|
|||||||
import { IDisposable } from '../../lifecycle';
|
import { IDisposable } from '../../lifecycle';
|
||||||
|
|
||||||
describe('abstractDragHandler', () => {
|
describe('abstractDragHandler', () => {
|
||||||
test('that className dragged is added to element after dragstart event', () => {
|
test('that className dv-dragged is added to element after dragstart event', () => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
|
|
||||||
const element = document.createElement('div');
|
const element = document.createElement('div');
|
||||||
@ -26,13 +26,13 @@ describe('abstractDragHandler', () => {
|
|||||||
}
|
}
|
||||||
})(element);
|
})(element);
|
||||||
|
|
||||||
expect(element.classList.contains('dragged')).toBeFalsy();
|
expect(element.classList.contains('dv-dragged')).toBeFalsy();
|
||||||
|
|
||||||
fireEvent.dragStart(element);
|
fireEvent.dragStart(element);
|
||||||
expect(element.classList.contains('dragged')).toBeTruthy();
|
expect(element.classList.contains('dv-dragged')).toBeTruthy();
|
||||||
|
|
||||||
jest.runAllTimers();
|
jest.runAllTimers();
|
||||||
expect(element.classList.contains('dragged')).toBeFalsy();
|
expect(element.classList.contains('dv-dragged')).toBeFalsy();
|
||||||
|
|
||||||
handler.dispose();
|
handler.dispose();
|
||||||
});
|
});
|
||||||
|
@ -34,8 +34,8 @@ export abstract class DragHandler extends CompositeDisposable {
|
|||||||
iframe.style.pointerEvents = 'none';
|
iframe.style.pointerEvents = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
this.el.classList.add('dragged');
|
this.el.classList.add('dv-dragged');
|
||||||
setTimeout(() => this.el.classList.remove('dragged'), 0);
|
setTimeout(() => this.el.classList.remove('dv-dragged'), 0);
|
||||||
|
|
||||||
this.disposable.value = this.getData(event.dataTransfer);
|
this.disposable.value = this.getData(event.dataTransfer);
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ export function addGhostImage(
|
|||||||
ghostElement: HTMLElement
|
ghostElement: HTMLElement
|
||||||
) {
|
) {
|
||||||
// class dockview provides to force ghost image to be drawn on a different layer and prevent weird rendering issues
|
// class dockview provides to force ghost image to be drawn on a different layer and prevent weird rendering issues
|
||||||
addClasses(ghostElement, 'dragged');
|
addClasses(ghostElement, 'dv-dragged');
|
||||||
|
|
||||||
document.body.appendChild(ghostElement);
|
document.body.appendChild(ghostElement);
|
||||||
dataTransfer.setDragImage(ghostElement, 0, 0);
|
dataTransfer.setDragImage(ghostElement, 0, 0);
|
||||||
|
60
packages/dockview/src/dnd/groupDragHandler.ts
Normal file
60
packages/dockview/src/dnd/groupDragHandler.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { GroupPanel } from '../groupview/groupviewPanel';
|
||||||
|
import { IDisposable } from '../lifecycle';
|
||||||
|
import { DragHandler } from './abstractDragHandler';
|
||||||
|
import { LocalSelectionTransfer, PanelTransfer } from './dataTransfer';
|
||||||
|
import { addGhostImage } from './ghost';
|
||||||
|
|
||||||
|
export class GroupDragHandler extends DragHandler {
|
||||||
|
private readonly panelTransfer =
|
||||||
|
LocalSelectionTransfer.getInstance<PanelTransfer>();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
element: HTMLElement,
|
||||||
|
private readonly accessorId: string,
|
||||||
|
private readonly group: GroupPanel
|
||||||
|
) {
|
||||||
|
super(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
getData(dataTransfer: DataTransfer | null): IDisposable {
|
||||||
|
this.panelTransfer.setData(
|
||||||
|
[new PanelTransfer(this.accessorId, this.group.id, null)],
|
||||||
|
PanelTransfer.prototype
|
||||||
|
);
|
||||||
|
|
||||||
|
const style = window.getComputedStyle(this.el);
|
||||||
|
|
||||||
|
const bgColor = style.getPropertyValue(
|
||||||
|
'--dv-activegroup-visiblepanel-tab-background-color'
|
||||||
|
);
|
||||||
|
const color = style.getPropertyValue(
|
||||||
|
'--dv-activegroup-visiblepanel-tab-color'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (dataTransfer) {
|
||||||
|
const ghostElement = document.createElement('div');
|
||||||
|
|
||||||
|
ghostElement.style.backgroundColor = bgColor;
|
||||||
|
ghostElement.style.color = color;
|
||||||
|
ghostElement.style.padding = '2px 8px';
|
||||||
|
ghostElement.style.height = '24px';
|
||||||
|
ghostElement.style.fontSize = '11px';
|
||||||
|
ghostElement.style.lineHeight = '20px';
|
||||||
|
ghostElement.style.borderRadius = '12px';
|
||||||
|
ghostElement.style.position = 'absolute';
|
||||||
|
ghostElement.textContent = `Multiple Panels (${this.group.size})`;
|
||||||
|
|
||||||
|
addGhostImage(dataTransfer, ghostElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
dispose: () => {
|
||||||
|
this.panelTransfer.clearData(PanelTransfer.prototype);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
.dragged {
|
.dv-dragged {
|
||||||
transform: translate3d(
|
transform: translate3d(
|
||||||
0px,
|
0px,
|
||||||
0px,
|
0px,
|
||||||
@ -9,7 +9,7 @@
|
|||||||
.tab {
|
.tab {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
||||||
&.dragging {
|
&.dv-tab-dragging {
|
||||||
.tab-action {
|
.tab-action {
|
||||||
background-color: var(--dv-activegroup-visiblepanel-tab-color);
|
background-color: var(--dv-activegroup-visiblepanel-tab-color);
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,3 @@
|
|||||||
.custom-dragging {
|
|
||||||
height: 24px;
|
|
||||||
line-height: 24px;
|
|
||||||
font-size: 11px;
|
|
||||||
width: 100px;
|
|
||||||
background-color: dodgerblue;
|
|
||||||
color: ghostwhite;
|
|
||||||
border-radius: 11px;
|
|
||||||
position: absolute;
|
|
||||||
padding-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.groupview {
|
.groupview {
|
||||||
&.active-group {
|
&.active-group {
|
||||||
> .tabs-and-actions-container > .tabs-container > .tab {
|
> .tabs-and-actions-container > .tabs-container > .tab {
|
||||||
@ -50,7 +38,7 @@
|
|||||||
* therefore we also set some stylings for the dragging event
|
* therefore we also set some stylings for the dragging event
|
||||||
**/
|
**/
|
||||||
.tab {
|
.tab {
|
||||||
&.dragging {
|
&.dv-tab-dragging {
|
||||||
background-color: var(
|
background-color: var(
|
||||||
--dv-activegroup-visiblepanel-tab-background-color
|
--dv-activegroup-visiblepanel-tab-background-color
|
||||||
);
|
);
|
||||||
|
@ -702,43 +702,8 @@ export class DockviewComponent
|
|||||||
|
|
||||||
if (itemId === undefined) {
|
if (itemId === undefined) {
|
||||||
if (sourceGroup) {
|
if (sourceGroup) {
|
||||||
if (!target || target === Position.Center) {
|
this.moveGroup(sourceGroup, referenceGroup, target);
|
||||||
const activePanel = sourceGroup.activePanel;
|
|
||||||
const panels = [...sourceGroup.panels].map((p) =>
|
|
||||||
sourceGroup.model.removePanel(p.id)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (sourceGroup?.model.size === 0) {
|
|
||||||
this.doRemoveGroup(sourceGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const panel of panels) {
|
|
||||||
referenceGroup.model.openPanel(panel, {
|
|
||||||
skipSetPanelActive: panel !== activePanel,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.gridview.removeView(
|
|
||||||
getGridLocation(sourceGroup.element)
|
|
||||||
);
|
|
||||||
|
|
||||||
const referenceLocation = getGridLocation(
|
|
||||||
referenceGroup.element
|
|
||||||
);
|
|
||||||
const dropLocation = getRelativeLocation(
|
|
||||||
this.gridview.orientation,
|
|
||||||
referenceLocation,
|
|
||||||
target
|
|
||||||
);
|
|
||||||
|
|
||||||
this.gridview.addView(
|
|
||||||
sourceGroup,
|
|
||||||
Sizing.Distribute,
|
|
||||||
dropLocation
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -815,6 +780,48 @@ export class DockviewComponent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private moveGroup(
|
||||||
|
sourceGroup: GroupPanel,
|
||||||
|
referenceGroup: GroupPanel,
|
||||||
|
target: Position
|
||||||
|
): void {
|
||||||
|
if (sourceGroup) {
|
||||||
|
if (!target || target === Position.Center) {
|
||||||
|
const activePanel = sourceGroup.activePanel;
|
||||||
|
const panels = [...sourceGroup.panels].map((p) =>
|
||||||
|
sourceGroup.model.removePanel(p.id)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (sourceGroup?.model.size === 0) {
|
||||||
|
this.doRemoveGroup(sourceGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const panel of panels) {
|
||||||
|
referenceGroup.model.openPanel(panel, {
|
||||||
|
skipSetPanelActive: panel !== activePanel,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.gridview.removeView(getGridLocation(sourceGroup.element));
|
||||||
|
|
||||||
|
const referenceLocation = getGridLocation(
|
||||||
|
referenceGroup.element
|
||||||
|
);
|
||||||
|
const dropLocation = getRelativeLocation(
|
||||||
|
this.gridview.orientation,
|
||||||
|
referenceLocation,
|
||||||
|
target
|
||||||
|
);
|
||||||
|
|
||||||
|
this.gridview.addView(
|
||||||
|
sourceGroup,
|
||||||
|
Sizing.Distribute,
|
||||||
|
dropLocation
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
doSetGroupActive(group: GroupPanel | undefined, skipFocus?: boolean): void {
|
doSetGroupActive(group: GroupPanel | undefined, skipFocus?: boolean): void {
|
||||||
const isGroupAlreadyFocused = this._activeGroup === group;
|
const isGroupAlreadyFocused = this._activeGroup === group;
|
||||||
super.doSetGroupActive(group, skipFocus);
|
super.doSetGroupActive(group, skipFocus);
|
||||||
|
@ -704,7 +704,9 @@ export class Groupview extends CompositeDisposable implements IGroupview {
|
|||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
if (data.panelId === null) {
|
if (data.panelId === null) {
|
||||||
|
// this is a group move dnd event
|
||||||
const { groupId } = data;
|
const { groupId } = data;
|
||||||
|
|
||||||
this._onMove.fire({
|
this._onMove.fire({
|
||||||
target: position,
|
target: position,
|
||||||
groupId: groupId,
|
groupId: groupId,
|
||||||
|
@ -1,73 +1,13 @@
|
|||||||
import { last } from '../../array';
|
import { last } from '../../array';
|
||||||
import { DragHandler } from '../../dnd/abstractDragHandler';
|
import { getPanelData } from '../../dnd/dataTransfer';
|
||||||
import {
|
|
||||||
getPanelData,
|
|
||||||
LocalSelectionTransfer,
|
|
||||||
PanelTransfer,
|
|
||||||
} from '../../dnd/dataTransfer';
|
|
||||||
import { Droptarget, DroptargetEvent } from '../../dnd/droptarget';
|
import { Droptarget, DroptargetEvent } from '../../dnd/droptarget';
|
||||||
import { addGhostImage } from '../../dnd/ghost';
|
import { GroupDragHandler } from '../../dnd/groupDragHandler';
|
||||||
import { DockviewComponent } from '../../dockview/dockviewComponent';
|
import { DockviewComponent } from '../../dockview/dockviewComponent';
|
||||||
import { addDisposableListener, Emitter, Event } from '../../events';
|
import { addDisposableListener, Emitter, Event } from '../../events';
|
||||||
import { CompositeDisposable, IDisposable } from '../../lifecycle';
|
import { CompositeDisposable } from '../../lifecycle';
|
||||||
import { DockviewDropTargets } from '../dnd';
|
import { DockviewDropTargets } from '../dnd';
|
||||||
import { GroupPanel } from '../groupviewPanel';
|
import { GroupPanel } from '../groupviewPanel';
|
||||||
|
|
||||||
class CustomDragHandler extends DragHandler {
|
|
||||||
private readonly panelTransfer =
|
|
||||||
LocalSelectionTransfer.getInstance<PanelTransfer>();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
element: HTMLElement,
|
|
||||||
private readonly accessorId: string,
|
|
||||||
private readonly group: GroupPanel
|
|
||||||
) {
|
|
||||||
super(element);
|
|
||||||
}
|
|
||||||
|
|
||||||
getData(dataTransfer: DataTransfer | null): IDisposable {
|
|
||||||
this.panelTransfer.setData(
|
|
||||||
[new PanelTransfer(this.accessorId, this.group.id, null)],
|
|
||||||
PanelTransfer.prototype
|
|
||||||
);
|
|
||||||
|
|
||||||
const style = window.getComputedStyle(this.el);
|
|
||||||
|
|
||||||
const bgColor = style.getPropertyValue(
|
|
||||||
'--dv-activegroup-visiblepanel-tab-background-color'
|
|
||||||
);
|
|
||||||
const color = style.getPropertyValue(
|
|
||||||
'--dv-activegroup-visiblepanel-tab-color'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (dataTransfer) {
|
|
||||||
const ghostElement = document.createElement('div');
|
|
||||||
|
|
||||||
ghostElement.style.backgroundColor = bgColor;
|
|
||||||
ghostElement.style.color = color;
|
|
||||||
ghostElement.style.padding = '2px 8px';
|
|
||||||
ghostElement.style.height = '24px';
|
|
||||||
ghostElement.style.fontSize = '11px';
|
|
||||||
ghostElement.style.lineHeight = '20px';
|
|
||||||
ghostElement.style.borderRadius = '12px';
|
|
||||||
ghostElement.style.position = 'absolute';
|
|
||||||
ghostElement.textContent = `Multiple Panels (${this.group.size})`;
|
|
||||||
|
|
||||||
addGhostImage(dataTransfer, ghostElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
dispose: () => {
|
|
||||||
this.panelTransfer.clearData(PanelTransfer.prototype);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public dispose(): void {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class VoidContainer extends CompositeDisposable {
|
export class VoidContainer extends CompositeDisposable {
|
||||||
private readonly _element: HTMLElement;
|
private readonly _element: HTMLElement;
|
||||||
private readonly voidDropTarget: Droptarget;
|
private readonly voidDropTarget: Droptarget;
|
||||||
@ -98,11 +38,7 @@ export class VoidContainer extends CompositeDisposable {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const handler = new CustomDragHandler(
|
const handler = new GroupDragHandler(this._element, accessor.id, group);
|
||||||
this._element,
|
|
||||||
accessor.id,
|
|
||||||
group
|
|
||||||
);
|
|
||||||
|
|
||||||
this.voidDropTarget = new Droptarget(this._element, {
|
this.voidDropTarget = new Droptarget(this._element, {
|
||||||
acceptedTargetZones: ['center'],
|
acceptedTargetZones: ['center'],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user