Skip to content

Commit c2791c6

Browse files
authored
Merge pull request #453 from mathuo/395-showdndoverlay-is-not-called-always
work-in-progress
2 parents aa8e7e0 + fb6aba1 commit c2791c6

File tree

13 files changed

+446
-185
lines changed

13 files changed

+446
-185
lines changed

packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { DockviewComponent } from '../../dockview/dockviewComponent';
22
import {
3-
DockviewDropTargets,
43
GroupPanelPartInitParameters,
54
IContentRenderer,
65
ITabRenderer,
@@ -2974,7 +2973,7 @@ describe('dockviewComponent', () => {
29742973
expect(showDndOverlay).toHaveBeenCalledWith({
29752974
nativeEvent: eventLeft,
29762975
position: 'left',
2977-
target: DockviewDropTargets.Edge,
2976+
target: 'edge',
29782977
getData: getPanelData,
29792978
});
29802979
expect(showDndOverlay).toBeCalledTimes(1);
@@ -2993,7 +2992,7 @@ describe('dockviewComponent', () => {
29932992
expect(showDndOverlay).toHaveBeenCalledWith({
29942993
nativeEvent: eventRight,
29952994
position: 'right',
2996-
target: DockviewDropTargets.Edge,
2995+
target: 'edge',
29972996
getData: getPanelData,
29982997
});
29992998
expect(showDndOverlay).toBeCalledTimes(2);
@@ -3012,7 +3011,7 @@ describe('dockviewComponent', () => {
30123011
expect(showDndOverlay).toHaveBeenCalledWith({
30133012
nativeEvent: eventTop,
30143013
position: 'top',
3015-
target: DockviewDropTargets.Edge,
3014+
target: 'edge',
30163015
getData: getPanelData,
30173016
});
30183017
expect(showDndOverlay).toBeCalledTimes(3);
@@ -3031,7 +3030,7 @@ describe('dockviewComponent', () => {
30313030
expect(showDndOverlay).toHaveBeenCalledWith({
30323031
nativeEvent: eventBottom,
30333032
position: 'bottom',
3034-
target: DockviewDropTargets.Edge,
3033+
target: 'edge',
30353034
getData: getPanelData,
30363035
});
30373036
expect(showDndOverlay).toBeCalledTimes(4);
@@ -3067,7 +3066,7 @@ describe('dockviewComponent', () => {
30673066
expect(showDndOverlay).toHaveBeenCalledWith({
30683067
nativeEvent: eventTop,
30693068
position: 'center',
3070-
target: DockviewDropTargets.Edge,
3069+
target: 'edge',
30713070
getData: getPanelData,
30723071
});
30733072
expect(showDndOverlay).toBeCalledTimes(5);

packages/dockview-core/src/api/component.api.ts

+23-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {
2-
DockviewDropEvent,
32
IDockviewComponent,
43
SerializedDockview,
54
} from '../dockview/dockviewComponent';
@@ -43,6 +42,11 @@ import {
4342
TabDragEvent,
4443
} from '../dockview/components/titlebar/tabsContainer';
4544
import { Box } from '../types';
45+
import {
46+
DockviewDidDropEvent,
47+
DockviewWillDropEvent,
48+
WillShowOverlayLocationEvent,
49+
} from '../dockview/dockviewGroupPanelModel';
4650

4751
export interface CommonApi<T = any> {
4852
readonly height: number;
@@ -648,10 +652,27 @@ export class DockviewApi implements CommonApi<SerializedDockview> {
648652
/**
649653
* Invoked when a Drag'n'Drop event occurs that the component was unable to handle. Exposed for custom Drag'n'Drop functionality.
650654
*/
651-
get onDidDrop(): Event<DockviewDropEvent> {
655+
get onDidDrop(): Event<DockviewDidDropEvent> {
652656
return this.component.onDidDrop;
653657
}
654658

659+
/**
660+
* Invoked when a Drag'n'Drop event occurs but before dockview handles it giving the user an opportunity to intecept and
661+
* prevent the event from occuring using the standard `preventDefault()` syntax.
662+
*
663+
* Preventing certain events may causes unexpected behaviours, use carefully.
664+
*/
665+
get onWillDrop(): Event<DockviewWillDropEvent> {
666+
return this.component.onWillDrop;
667+
}
668+
669+
/**
670+
*
671+
*/
672+
get onWillShowOverlay(): Event<WillShowOverlayLocationEvent> {
673+
return this.component.onWillShowOverlay;
674+
}
675+
655676
/**
656677
* Invoked before a group is dragged. Exposed for custom Drag'n'Drop functionality.
657678
*/

packages/dockview-core/src/dnd/droptarget.ts

+56-12
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,37 @@
11
import { toggleClass } from '../dom';
2-
import { Emitter, Event } from '../events';
2+
import { DockviewEvent, Emitter, Event } from '../events';
33
import { CompositeDisposable } from '../lifecycle';
44
import { DragAndDropObserver } from './dnd';
55
import { clamp } from '../math';
66
import { Direction } from '../gridview/baseComponentGridview';
77

8+
export interface DroptargetEvent {
9+
readonly position: Position;
10+
readonly nativeEvent: DragEvent;
11+
}
12+
13+
export class WillShowOverlayEvent
14+
extends DockviewEvent
15+
implements DroptargetEvent
16+
{
17+
get nativeEvent(): DragEvent {
18+
return this.options.nativeEvent;
19+
}
20+
21+
get position(): Position {
22+
return this.options.position;
23+
}
24+
25+
constructor(
26+
private readonly options: {
27+
nativeEvent: DragEvent;
28+
position: Position;
29+
}
30+
) {
31+
super();
32+
}
33+
}
34+
835
export function directionToPosition(direction: Direction): Position {
936
switch (direction) {
1037
case 'above':
@@ -39,11 +66,6 @@ export function positionToDirection(position: Position): Direction {
3966
}
4067
}
4168

42-
export interface DroptargetEvent {
43-
readonly position: Position;
44-
readonly nativeEvent: DragEvent;
45-
}
46-
4769
export type Position = 'top' | 'bottom' | 'left' | 'right' | 'center';
4870

4971
export type CanDisplayOverlay =
@@ -70,6 +92,12 @@ const DEFAULT_SIZE: MeasuredValue = {
7092
const SMALL_WIDTH_BOUNDARY = 100;
7193
const SMALL_HEIGHT_BOUNDARY = 100;
7294

95+
export interface DroptargetOptions {
96+
canDisplayOverlay: CanDisplayOverlay;
97+
acceptedTargetZones: Position[];
98+
overlayModel?: DroptargetOverlayModel;
99+
}
100+
73101
export class Droptarget extends CompositeDisposable {
74102
private targetElement: HTMLElement | undefined;
75103
private overlayElement: HTMLElement | undefined;
@@ -79,6 +107,10 @@ export class Droptarget extends CompositeDisposable {
79107
private readonly _onDrop = new Emitter<DroptargetEvent>();
80108
readonly onDrop: Event<DroptargetEvent> = this._onDrop.event;
81109

110+
private readonly _onWillShowOverlay = new Emitter<WillShowOverlayEvent>();
111+
readonly onWillShowOverlay: Event<WillShowOverlayEvent> =
112+
this._onWillShowOverlay.event;
113+
82114
readonly dnd: DragAndDropObserver;
83115

84116
private static USED_EVENT_ID = '__dockview_droptarget_event_is_used__';
@@ -89,11 +121,7 @@ export class Droptarget extends CompositeDisposable {
89121

90122
constructor(
91123
private readonly element: HTMLElement,
92-
private readonly options: {
93-
canDisplayOverlay: CanDisplayOverlay;
94-
acceptedTargetZones: Position[];
95-
overlayModel?: DroptargetOverlayModel;
96-
}
124+
private readonly options: DroptargetOptions
97125
) {
98126
super();
99127

@@ -142,6 +170,22 @@ export class Droptarget extends CompositeDisposable {
142170
return;
143171
}
144172

173+
const willShowOverlayEvent = new WillShowOverlayEvent({
174+
nativeEvent: e,
175+
position: quadrant,
176+
});
177+
178+
/**
179+
* Provide an opportunity to prevent the overlay appearing and in turn
180+
* any dnd behaviours
181+
*/
182+
this._onWillShowOverlay.fire(willShowOverlayEvent);
183+
184+
if (willShowOverlayEvent.defaultPrevented) {
185+
this.removeDropTarget();
186+
return;
187+
}
188+
145189
if (typeof this.options.canDisplayOverlay === 'boolean') {
146190
if (!this.options.canDisplayOverlay) {
147191
this.removeDropTarget();
@@ -192,7 +236,7 @@ export class Droptarget extends CompositeDisposable {
192236
},
193237
});
194238

195-
this.addDisposables(this._onDrop, this.dnd);
239+
this.addDisposables(this._onDrop, this._onWillShowOverlay, this.dnd);
196240
}
197241

198242
setTargetZones(acceptedTargetZones: Position[]): void {

packages/dockview-core/src/dockview/components/panel/content.ts

+1-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import { DockviewComponent } from '../../dockviewComponent';
1010
import { Droptarget } from '../../../dnd/droptarget';
1111
import { DockviewGroupPanelModel } from '../../dockviewGroupPanelModel';
1212
import { getPanelData } from '../../../dnd/dataTransfer';
13-
import { DockviewDropTargets } from '../../types';
1413

1514
export interface IContentContainer extends IDisposable {
1615
readonly dropTarget: Droptarget;
@@ -95,11 +94,7 @@ export class ContentContainer
9594
return !groupHasOnePanelAndIsActiveDragElement;
9695
}
9796

98-
return this.group.canDisplayOverlay(
99-
event,
100-
position,
101-
DockviewDropTargets.Panel
102-
);
97+
return this.group.canDisplayOverlay(event, position, 'panel');
10398
},
10499
});
105100

packages/dockview-core/src/dockview/components/tab/tab.ts

+17-17
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,14 @@ import {
77
} from '../../../dnd/dataTransfer';
88
import { toggleClass } from '../../../dom';
99
import { DockviewComponent } from '../../dockviewComponent';
10-
import { DockviewDropTargets, ITabRenderer } from '../../types';
10+
import { ITabRenderer } from '../../types';
1111
import { DockviewGroupPanel } from '../../dockviewGroupPanel';
12-
import { DroptargetEvent, Droptarget } from '../../../dnd/droptarget';
12+
import {
13+
DroptargetEvent,
14+
Droptarget,
15+
Position,
16+
WillShowOverlayEvent,
17+
} from '../../../dnd/droptarget';
1318
import { DragHandler } from '../../../dnd/abstractDragHandler';
1419
import { IDockviewPanel } from '../../dockviewPanel';
1520

@@ -40,18 +45,9 @@ class TabDragHandler extends DragHandler {
4045
}
4146
}
4247

43-
export interface ITab extends IDisposable {
44-
readonly panel: IDockviewPanel;
45-
readonly element: HTMLElement;
46-
setContent: (element: ITabRenderer) => void;
47-
onChanged: Event<MouseEvent>;
48-
onDrop: Event<DroptargetEvent>;
49-
setActive(isActive: boolean): void;
50-
}
51-
52-
export class Tab extends CompositeDisposable implements ITab {
48+
export class Tab extends CompositeDisposable {
5349
private readonly _element: HTMLElement;
54-
private readonly droptarget: Droptarget;
50+
private readonly dropTarget: Droptarget;
5551
private content: ITabRenderer | undefined = undefined;
5652

5753
private readonly _onChanged = new Emitter<MouseEvent>();
@@ -63,6 +59,8 @@ export class Tab extends CompositeDisposable implements ITab {
6359
private readonly _onDragStart = new Emitter<DragEvent>();
6460
readonly onDragStart = this._onDragStart.event;
6561

62+
readonly onWillShowOverlay: Event<WillShowOverlayEvent>;
63+
6664
public get element(): HTMLElement {
6765
return this._element;
6866
}
@@ -88,7 +86,7 @@ export class Tab extends CompositeDisposable implements ITab {
8886
this.panel
8987
);
9088

91-
this.droptarget = new Droptarget(this._element, {
89+
this.dropTarget = new Droptarget(this._element, {
9290
acceptedTargetZones: ['center'],
9391
canDisplayOverlay: (event, position) => {
9492
if (this.group.locked) {
@@ -112,11 +110,13 @@ export class Tab extends CompositeDisposable implements ITab {
112110
return this.group.model.canDisplayOverlay(
113111
event,
114112
position,
115-
DockviewDropTargets.Tab
113+
'tab'
116114
);
117115
},
118116
});
119117

118+
this.onWillShowOverlay = this.dropTarget.onWillShowOverlay;
119+
120120
this.addDisposables(
121121
this._onChanged,
122122
this._onDropped,
@@ -132,10 +132,10 @@ export class Tab extends CompositeDisposable implements ITab {
132132

133133
this._onChanged.fire(event);
134134
}),
135-
this.droptarget.onDrop((event) => {
135+
this.dropTarget.onDrop((event) => {
136136
this._onDropped.fire(event);
137137
}),
138-
this.droptarget
138+
this.dropTarget
139139
);
140140
}
141141

0 commit comments

Comments
 (0)