Skip to content

Commit

Permalink
feat: gready render mode
Browse files Browse the repository at this point in the history
  • Loading branch information
mathuo committed Nov 26, 2023
1 parent b17aa24 commit 9541030
Show file tree
Hide file tree
Showing 15 changed files with 557 additions and 185 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { CompositeDisposable } from '../../../../lifecycle';
import { PanelUpdateEvent } from '../../../../panel/types';
import { IDockviewPanel } from '../../../../dockview/dockviewPanel';
import { IDockviewPanelModel } from '../../../../dockview/dockviewPanelModel';
import { DockviewComponent } from '../../../../dockview/dockviewComponent';

class TestContentRenderer
extends CompositeDisposable
Expand Down Expand Up @@ -56,7 +57,14 @@ describe('contentContainer', () => {
let blur = 0;

const disposable = new CompositeDisposable();
const cut = new ContentContainer();

const dockviewComponent = jest.fn<DockviewComponent, []>(() => {
return {
renderMode: 'destructive',
} as DockviewComponent;
});

const cut = new ContentContainer(dockviewComponent(), jest.fn() as any);

disposable.addDisposables(
cut.onDidFocus(() => {
Expand Down
21 changes: 19 additions & 2 deletions packages/dockview-core/src/api/dockviewPanelApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ import { Emitter, Event } from '../events';
import { GridviewPanelApiImpl, GridviewPanelApi } from './gridviewPanelApi';
import { DockviewGroupPanel } from '../dockview/dockviewGroupPanel';
import { MutableDisposable } from '../lifecycle';
import { IDockviewPanel } from '../dockview/dockviewPanel';
import { DockviewPanel, IDockviewPanel } from '../dockview/dockviewPanel';
import { DockviewComponent } from '../dockview/dockviewComponent';
import { Position } from '../dnd/droptarget';
import { RenderMode } from '../dockview/components/greadyRenderContainer';

export interface TitleEvent {
readonly title: string;
}

export interface RenderModeEvent {
renderMode: RenderMode;
}

/*
* omit visibility modifiers since the visibility of a single group doesn't make sense
* because it belongs to a groupview
Expand All @@ -21,6 +26,7 @@ export interface DockviewPanelApi
> {
readonly group: DockviewGroupPanel;
readonly isGroupActive: boolean;
readonly renderMode: RenderMode;
readonly title: string | undefined;
readonly onDidActiveGroupChange: Event<void>;
readonly onDidGroupChange: Event<void>;
Expand Down Expand Up @@ -48,6 +54,9 @@ export class DockviewPanelApiImpl
private readonly _onDidGroupChange = new Emitter<void>();
readonly onDidGroupChange = this._onDidGroupChange.event;

readonly _onDidRenderModeChange = new Emitter<RenderModeEvent>();
readonly onDidRenderModeChange = this._onDidRenderModeChange.event;

private readonly disposable = new MutableDisposable();

get title(): string | undefined {
Expand All @@ -58,6 +67,10 @@ export class DockviewPanelApiImpl
return !!this.group?.isActive;
}

get renderMode(): RenderMode {
return this.panel.renderMode;
}

set group(value: DockviewGroupPanel) {
const isOldGroupActive = this.isGroupActive;

Expand All @@ -81,7 +94,7 @@ export class DockviewPanelApiImpl
}

constructor(
private panel: IDockviewPanel,
private panel: DockviewPanel,
group: DockviewGroupPanel,
private readonly accessor: DockviewComponent
) {
Expand Down Expand Up @@ -117,6 +130,10 @@ export class DockviewPanelApiImpl
this.panel.setTitle(title);
}

setRenderMode(renderMode: RenderMode): void {
this.panel.setRenderMode(renderMode);
}

close(): void {
this.group.model.closePanel(this.panel);
}
Expand Down
50 changes: 35 additions & 15 deletions packages/dockview-core/src/dnd/dnd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,43 @@ export class DragAndDropObserver extends CompositeDisposable {
this.registerListeners();
}

onDragEnter(e: DragEvent): void {
this.target = e.target;
this.callbacks.onDragEnter(e);
}

onDragOver(e: DragEvent): void {
e.preventDefault(); // needed so that the drop event fires (https://stackoverflow.com/questions/21339924/drop-event-not-firing-in-chrome)

if (this.callbacks.onDragOver) {
this.callbacks.onDragOver(e);
}
}

onDragLeave(e: DragEvent): void {
if (this.target === e.target) {
this.target = null;

this.callbacks.onDragLeave(e);
}
}

onDragEnd(e: DragEvent): void {
this.target = null;
this.callbacks.onDragEnd(e);
}

onDrop(e: DragEvent): void {
this.callbacks.onDrop(e);
}

private registerListeners(): void {
this.addDisposables(
addDisposableListener(
this.element,
'dragenter',
(e: DragEvent) => {
this.target = e.target;
this.callbacks.onDragEnter(e);
this.onDragEnter(e);
},
true
)
Expand All @@ -39,36 +68,27 @@ export class DragAndDropObserver extends CompositeDisposable {
this.element,
'dragover',
(e: DragEvent) => {
e.preventDefault(); // needed so that the drop event fires (https://stackoverflow.com/questions/21339924/drop-event-not-firing-in-chrome)

if (this.callbacks.onDragOver) {
this.callbacks.onDragOver(e);
}
this.onDragOver(e);
},
true
)
);

this.addDisposables(
addDisposableListener(this.element, 'dragleave', (e: DragEvent) => {
if (this.target === e.target) {
this.target = null;

this.callbacks.onDragLeave(e);
}
this.onDragLeave(e);
})
);

this.addDisposables(
addDisposableListener(this.element, 'dragend', (e: DragEvent) => {
this.target = null;
this.callbacks.onDragEnd(e);
this.onDragEnd(e);
})
);

this.addDisposables(
addDisposableListener(this.element, 'drop', (e: DragEvent) => {
this.callbacks.onDrop(e);
this.onDrop(e);
})
);
}
Expand Down
175 changes: 88 additions & 87 deletions packages/dockview-core/src/dnd/droptarget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ export class Droptarget extends CompositeDisposable {
private readonly _onDrop = new Emitter<DroptargetEvent>();
readonly onDrop: Event<DroptargetEvent> = this._onDrop.event;

readonly dnd: DragAndDropObserver;

private static USED_EVENT_ID = '__dockview_droptarget_event_is_used__';

get state(): Position | undefined {
Expand Down Expand Up @@ -90,98 +92,97 @@ export class Droptarget extends CompositeDisposable {
this.options.acceptedTargetZones
);

this.addDisposables(
this._onDrop,
new DragAndDropObserver(this.element, {
onDragEnter: () => undefined,
onDragOver: (e) => {
if (this._acceptedTargetZonesSet.size === 0) {
this.removeDropTarget();
return;
}

const width = this.element.clientWidth;
const height = this.element.clientHeight;

if (width === 0 || height === 0) {
return; // avoid div!0
}

const rect = (
e.currentTarget as HTMLElement
).getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;

const quadrant = this.calculateQuadrant(
this._acceptedTargetZonesSet,
x,
y,
width,
height
);

/**
* If the event has already been used by another DropTarget instance
* then don't show a second drop target, only one target should be
* active at any one time
*/
if (this.isAlreadyUsed(e) || quadrant === null) {
// no drop target should be displayed
this.removeDropTarget();
return;
}
this.dnd = new DragAndDropObserver(this.element, {
onDragEnter: () => undefined,
onDragOver: (e) => {
if (this._acceptedTargetZonesSet.size === 0) {
this.removeDropTarget();
return;
}

const width = this.element.clientWidth;
const height = this.element.clientHeight;

if (width === 0 || height === 0) {
return; // avoid div!0
}

const rect = (
e.currentTarget as HTMLElement
).getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;

const quadrant = this.calculateQuadrant(
this._acceptedTargetZonesSet,
x,
y,
width,
height
);

/**
* If the event has already been used by another DropTarget instance
* then don't show a second drop target, only one target should be
* active at any one time
*/
if (this.isAlreadyUsed(e) || quadrant === null) {
// no drop target should be displayed
this.removeDropTarget();
return;
}

if (typeof this.options.canDisplayOverlay === 'boolean') {
if (!this.options.canDisplayOverlay) {
this.removeDropTarget();
return;
}
} else if (!this.options.canDisplayOverlay(e, quadrant)) {
if (typeof this.options.canDisplayOverlay === 'boolean') {
if (!this.options.canDisplayOverlay) {
this.removeDropTarget();
return;
}

this.markAsUsed(e);

if (!this.targetElement) {
this.targetElement = document.createElement('div');
this.targetElement.className = 'drop-target-dropzone';
this.overlayElement = document.createElement('div');
this.overlayElement.className = 'drop-target-selection';
this._state = 'center';
this.targetElement.appendChild(this.overlayElement);

this.element.classList.add('drop-target');
this.element.append(this.targetElement);
}

this.toggleClasses(quadrant, width, height);

this.setState(quadrant);
},
onDragLeave: () => {
this.removeDropTarget();
},
onDragEnd: () => {
} else if (!this.options.canDisplayOverlay(e, quadrant)) {
this.removeDropTarget();
},
onDrop: (e) => {
e.preventDefault();

const state = this._state;

this.removeDropTarget();

if (state) {
// only stop the propagation of the event if we are dealing with it
// which is only when the target has state
e.stopPropagation();
this._onDrop.fire({ position: state, nativeEvent: e });
}
},
})
);
return;
}

this.markAsUsed(e);

if (!this.targetElement) {
this.targetElement = document.createElement('div');
this.targetElement.className = 'drop-target-dropzone';
this.overlayElement = document.createElement('div');
this.overlayElement.className = 'drop-target-selection';
this._state = 'center';
this.targetElement.appendChild(this.overlayElement);

this.element.classList.add('drop-target');
this.element.append(this.targetElement);
}

this.toggleClasses(quadrant, width, height);

this.setState(quadrant);
},
onDragLeave: () => {
this.removeDropTarget();
},
onDragEnd: () => {
this.removeDropTarget();
},
onDrop: (e) => {
e.preventDefault();

const state = this._state;

this.removeDropTarget();

if (state) {
// only stop the propagation of the event if we are dealing with it
// which is only when the target has state
e.stopPropagation();
this._onDrop.fire({ position: state, nativeEvent: e });
}
},
});

this.addDisposables(this._onDrop, this.dnd);
}

setTargetZones(acceptedTargetZones: Position[]): void {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.dv-render-overlay {
position: absolute;
z-index: 1;

&.dv-render-overlay-float {
z-index: 999;
}
}

.dv-debug {
.dv-render-overlay {
outline: 1px solid red;
outline-offset: -1;
}
}
Loading

0 comments on commit 9541030

Please sign in to comment.