Merge pull request #308 from mathuo/230-explore-floating-groups

230 explore floating groups
This commit is contained in:
mathuo 2023-07-20 21:34:22 +01:00 committed by GitHub
commit 430f97fd7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 92 additions and 55 deletions

View File

@ -96,7 +96,7 @@ describe('componentFactory', () => {
expect(component).toHaveBeenCalled();
expect(componentResult instanceof component);
expect(componentResult instanceof component).toBeTruthy();
});
});
});

View File

@ -1,4 +1,8 @@
import { quasiDefaultPrevented, toggleClass } from '../dom';
import {
getElementsByTagName,
quasiDefaultPrevented,
toggleClass,
} from '../dom';
import {
Emitter,
Event,
@ -29,6 +33,9 @@ export class Overlay extends CompositeDisposable {
private readonly _onDidChange = new Emitter<void>();
readonly onDidChange: Event<void> = this._onDidChange.event;
private readonly _onDidChangeEnd = new Emitter<void>();
readonly onDidChangeEnd: Event<void> = this._onDidChangeEnd.event;
private static MINIMUM_HEIGHT = 20;
private static MINIMUM_WIDTH = 20;
@ -46,9 +53,10 @@ export class Overlay extends CompositeDisposable {
) {
super();
this.addDisposables(this._onDidChange);
this.addDisposables(this._onDidChange, this._onDidChangeEnd);
this._element.className = 'dv-resize-container';
this.setupOverlay();
this.setupResize('top');
this.setupResize('bottom');
this.setupResize('left');
@ -62,7 +70,12 @@ export class Overlay extends CompositeDisposable {
this.options.container.appendChild(this._element);
// if input bad resize within acceptable boundaries
this.renderWithinBoundaryConditions();
this.setBounds({
height: this.options.height,
width: this.options.width,
top: this.options.top,
left: this.options.left,
});
}
setBounds(
@ -71,7 +84,7 @@ export class Overlay extends CompositeDisposable {
width: number;
top: number;
left: number;
}>
}> = {}
): void {
if (typeof bounds.height === 'number') {
this._element.style.height = `${bounds.height}px`;
@ -86,25 +99,11 @@ export class Overlay extends CompositeDisposable {
this._element.style.left = `${bounds.left}px`;
}
this.renderWithinBoundaryConditions();
}
toJSON(): { top: number; left: number; height: number; width: number } {
const container = this.options.container.getBoundingClientRect();
const element = this._element.getBoundingClientRect();
return {
top: element.top - container.top,
left: element.left - container.left,
width: element.width,
height: element.height,
};
}
renderWithinBoundaryConditions(): void {
const containerRect = this.options.container.getBoundingClientRect();
const overlayRect = this._element.getBoundingClientRect();
// region: ensure bounds within allowable limits
// a minimum width of minimumViewportWidth must be inside the viewport
const xOffset = Math.max(
0,
@ -131,6 +130,20 @@ export class Overlay extends CompositeDisposable {
this._element.style.left = `${left}px`;
this._element.style.top = `${top}px`;
this._onDidChange.fire();
}
toJSON(): { top: number; left: number; height: number; width: number } {
const container = this.options.container.getBoundingClientRect();
const element = this._element.getBoundingClientRect();
return {
top: element.top - container.top,
left: element.left - container.left,
width: element.width,
height: element.height,
};
}
setupDrag(
@ -142,7 +155,23 @@ export class Overlay extends CompositeDisposable {
const track = () => {
let offset: { x: number; y: number } | null = null;
const iframes = [
...getElementsByTagName('iframe'),
...getElementsByTagName('webview'),
];
for (const iframe of iframes) {
iframe.style.pointerEvents = 'none';
}
move.value = new CompositeDisposable(
{
dispose: () => {
for (const iframe of iframes) {
iframe.style.pointerEvents = 'auto';
}
},
},
addDisposableWindowListener(window, 'mousemove', (e) => {
const containerRect =
this.options.container.getBoundingClientRect();
@ -191,8 +220,7 @@ export class Overlay extends CompositeDisposable {
)
);
this._element.style.left = `${left}px`;
this._element.style.top = `${top}px`;
this.setBounds({ top, left });
}),
addDisposableWindowListener(window, 'mouseup', () => {
toggleClass(
@ -202,7 +230,7 @@ export class Overlay extends CompositeDisposable {
);
move.dispose();
this._onDidChange.fire();
this._onDidChangeEnd.fire();
})
);
};
@ -259,15 +287,6 @@ export class Overlay extends CompositeDisposable {
}
}
private setupOverlay(): void {
this._element.style.height = `${this.options.height}px`;
this._element.style.width = `${this.options.width}px`;
this._element.style.left = `${this.options.left}px`;
this._element.style.top = `${this.options.top}px`;
this._element.className = 'dv-resize-container';
}
private setupResize(
direction:
| 'top'
@ -297,6 +316,15 @@ export class Overlay extends CompositeDisposable {
originalWidth: number;
} | null = null;
const iframes = [
...getElementsByTagName('iframe'),
...getElementsByTagName('webview'),
];
for (const iframe of iframes) {
iframe.style.pointerEvents = 'none';
}
move.value = new CompositeDisposable(
addDisposableWindowListener(window, 'mousemove', (e) => {
const containerRect =
@ -317,10 +345,10 @@ export class Overlay extends CompositeDisposable {
};
}
let top: number | null = null;
let height: number | null = null;
let left: number | null = null;
let width: number | null = null;
let top: number | undefined = undefined;
let height: number | undefined = undefined;
let left: number | undefined = undefined;
let width: number | undefined = undefined;
const minimumInViewportHeight =
this.options.minimumInViewportHeight;
@ -431,22 +459,18 @@ export class Overlay extends CompositeDisposable {
break;
}
if (height !== null) {
this._element.style.height = `${height}px`;
}
if (top !== null) {
this._element.style.top = `${top}px`;
}
if (left !== null) {
this._element.style.left = `${left}px`;
}
if (width !== null) {
this._element.style.width = `${width}px`;
}
this.setBounds({ height, width, top, left });
}),
{
dispose: () => {
for (const iframe of iframes) {
iframe.style.pointerEvents = 'auto';
}
},
},
addDisposableWindowListener(window, 'mouseup', () => {
move.dispose();
this._onDidChange.fire();
this._onDidChangeEnd.fire();
})
);
})

View File

@ -45,7 +45,7 @@ import { DockviewGroupPanel } from './dockviewGroupPanel';
import { DockviewPanelModel } from './dockviewPanelModel';
import { getPanelData } from '../dnd/dataTransfer';
import { Overlay } from '../dnd/overlay';
import { toggleClass } from '../dom';
import { toggleClass, watchElementResize } from '../dom';
import {
DockviewFloatingGroupPanel,
IDockviewFloatingGroupPanel,
@ -369,8 +369,19 @@ export class DockviewComponent
overlay
);
const disposable = watchElementResize(group.element, (entry) => {
const { width, height } = entry.contentRect;
group.layout(width, height); // let the group know it's size is changing so it can fire events to the panel
});
floatingGroupPanel.addDisposables(
overlay.onDidChange(() => {
// this is either a resize or a move
// to inform the panels .layout(...) the group with it's current size
// don't care about resize since the above watcher handles that
group.layout(group.height, group.width);
}),
overlay.onDidChangeEnd(() => {
this._bufferOnDidLayoutChange.fire();
}),
group.onDidChange((event) => {
@ -381,6 +392,8 @@ export class DockviewComponent
}),
{
dispose: () => {
disposable.dispose();
group.model.isFloating = false;
remove(this.floatingGroups, floatingGroupPanel);
this.updateWatermark();
@ -451,7 +464,7 @@ export class DockviewComponent
if (this.floatingGroups) {
for (const floating of this.floatingGroups) {
// ensure floting groups stay within visible boundaries
floating.overlay.renderWithinBoundaryConditions();
floating.overlay.setBounds();
}
}
}
@ -621,7 +634,7 @@ export class DockviewComponent
}
for (const floatingGroup of this.floatingGroups) {
floatingGroup.overlay.renderWithinBoundaryConditions();
floatingGroup.overlay.setBounds();
}
if (typeof activeGroup === 'string') {

View File

@ -210,7 +210,6 @@ export const DockviewPersistance = (props: { theme?: string }) => {
<div
style={{
flexGrow: 1,
overflow: 'hidden',
}}
>
<DockviewReact

View File

@ -78,6 +78,7 @@ export const HoistedDockviewPanel = <T extends object>(
style={{
position: 'absolute',
overflow: 'hidden',
zIndex: 999,
pointerEvents: 'none', // prevent this wrapper contain stealing events
}}
>