From 3b27621623a392a11688a1836501d0535681207f Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Tue, 18 Jul 2023 20:46:34 +0100 Subject: [PATCH 1/5] feat: link api resize events to overlay for floating panels --- .../dockview/dockviewComponent.spec.ts | 33 +++++++++++++++++++ .../src/dockview/dockviewComponent.ts | 6 ++++ 2 files changed, 39 insertions(+) diff --git a/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts b/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts index 778df49d6..847372d8e 100644 --- a/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts +++ b/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts @@ -3787,4 +3787,37 @@ describe('dockviewComponent', () => { dockview.element.querySelectorAll('.view-container > .view').length ).toBe(0); }); + + test('that api.setSize applies to the overlay for floating panels', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent({ + parentElement: container, + components: { + default: PanelContentPartTest, + }, + tabComponents: { + test_tab_id: PanelTabPartTest, + }, + orientation: Orientation.HORIZONTAL, + }); + + dockview.layout(1000, 500); + + const panel1 = dockview.addPanel({ + id: 'panel_1', + component: 'default', + floating: true, + }); + + panel1.api.setSize({ height: 123, width: 256 }); + + const items = dockview.element.querySelectorAll('.dv-resize-container'); + expect(items.length).toBe(1); + + const el = items[0] as HTMLElement; + + expect(el.style.height).toBe('123px'); + expect(el.style.width).toBe('256px'); + }); }); diff --git a/packages/dockview-core/src/dockview/dockviewComponent.ts b/packages/dockview-core/src/dockview/dockviewComponent.ts index d8c64938d..206b42a4e 100644 --- a/packages/dockview-core/src/dockview/dockviewComponent.ts +++ b/packages/dockview-core/src/dockview/dockviewComponent.ts @@ -373,6 +373,12 @@ export class DockviewComponent overlay.onDidChange(() => { this._bufferOnDidLayoutChange.fire(); }), + group.onDidChange((event) => { + overlay.setBounds({ + height: event?.height, + width: event?.width, + }); + }), { dispose: () => { group.model.isFloating = false; From e089b29442de4ec2a8df7cce2c3045a11301d1e0 Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Tue, 18 Jul 2023 20:47:10 +0100 Subject: [PATCH 2/5] feat: overlay resizing outside of main viewport but within bounds --- packages/dockview-core/src/dnd/overlay.ts | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/packages/dockview-core/src/dnd/overlay.ts b/packages/dockview-core/src/dnd/overlay.ts index 6d818725a..36f8fb2d0 100644 --- a/packages/dockview-core/src/dnd/overlay.ts +++ b/packages/dockview-core/src/dnd/overlay.ts @@ -322,10 +322,15 @@ export class Overlay extends CompositeDisposable { let left: number | null = null; let width: number | null = null; - function moveTop() { + const minimumInViewportHeight = + this.options.minimumInViewportHeight; + const minimumInViewportWidth = + this.options.minimumInViewportWidth; + + function moveTop(): void { top = clamp( y, - 0, + -minimumInViewportHeight, Math.max( 0, startPosition!.originalY + @@ -339,7 +344,7 @@ export class Overlay extends CompositeDisposable { top; } - function moveBottom() { + function moveBottom(): void { top = startPosition!.originalY - startPosition!.originalHeight; @@ -351,15 +356,16 @@ export class Overlay extends CompositeDisposable { 0, containerRect.height - startPosition!.originalY + - startPosition!.originalHeight + startPosition!.originalHeight + + minimumInViewportHeight ) ); } - function moveLeft() { + function moveLeft(): void { left = clamp( x, - 0, + -minimumInViewportWidth, Math.max( 0, startPosition!.originalX + @@ -373,7 +379,7 @@ export class Overlay extends CompositeDisposable { left; } - function moveRight() { + function moveRight(): void { left = startPosition!.originalX - startPosition!.originalWidth; @@ -384,7 +390,8 @@ export class Overlay extends CompositeDisposable { 0, containerRect.width - startPosition!.originalX + - startPosition!.originalWidth + startPosition!.originalWidth + + minimumInViewportWidth ) ); } From c89dd5009a1bab8b4a3643e6511afe93a4f7c986 Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Wed, 19 Jul 2023 21:30:16 +0100 Subject: [PATCH 3/5] feat: adjust floating group boundaries --- packages/dockview-core/src/dnd/overlay.ts | 64 ++++++++++++----------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/packages/dockview-core/src/dnd/overlay.ts b/packages/dockview-core/src/dnd/overlay.ts index 36f8fb2d0..f9c52753e 100644 --- a/packages/dockview-core/src/dnd/overlay.ts +++ b/packages/dockview-core/src/dnd/overlay.ts @@ -330,13 +330,18 @@ export class Overlay extends CompositeDisposable { function moveTop(): void { top = clamp( y, - -minimumInViewportHeight, - Math.max( - 0, - startPosition!.originalY + - startPosition!.originalHeight - - Overlay.MINIMUM_HEIGHT - ) + -Number.MAX_VALUE, + startPosition!.originalY + + startPosition!.originalHeight > + containerRect.height + ? containerRect.height - + minimumInViewportHeight + : Math.max( + 0, + startPosition!.originalY + + startPosition!.originalHeight - + Overlay.MINIMUM_HEIGHT + ) ); height = startPosition!.originalY + @@ -351,28 +356,30 @@ export class Overlay extends CompositeDisposable { height = clamp( y - top, - Overlay.MINIMUM_HEIGHT, - Math.max( - 0, - containerRect.height - - startPosition!.originalY + - startPosition!.originalHeight + - minimumInViewportHeight - ) + top < 0 + ? -top + minimumInViewportHeight + : Overlay.MINIMUM_HEIGHT, + Number.MAX_VALUE ); } function moveLeft(): void { left = clamp( x, - -minimumInViewportWidth, - Math.max( - 0, - startPosition!.originalX + - startPosition!.originalWidth - - Overlay.MINIMUM_WIDTH - ) + -Number.MAX_VALUE, + startPosition!.originalX + + startPosition!.originalWidth > + containerRect.width + ? containerRect.width - + minimumInViewportWidth + : Math.max( + 0, + startPosition!.originalX + + startPosition!.originalWidth - + Overlay.MINIMUM_WIDTH + ) ); + width = startPosition!.originalX + startPosition!.originalWidth - @@ -383,16 +390,13 @@ export class Overlay extends CompositeDisposable { left = startPosition!.originalX - startPosition!.originalWidth; + width = clamp( x - left, - Overlay.MINIMUM_WIDTH, - Math.max( - 0, - containerRect.width - - startPosition!.originalX + - startPosition!.originalWidth + - minimumInViewportWidth - ) + left < 0 + ? -left + minimumInViewportWidth + : Overlay.MINIMUM_WIDTH, + Number.MAX_VALUE ); } From 0eec3691200c3c0373ab5627441aa824f311f548 Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Thu, 20 Jul 2023 20:54:09 +0100 Subject: [PATCH 4/5] feat: propagate resize and move events when in floating mode --- packages/dockview-core/src/dnd/overlay.ts | 124 +++++++++++------- .../src/dockview/dockviewComponent.ts | 19 ++- .../floatinggroup-dockview/src/app.tsx | 1 - .../src/hoistedDockviewPanel.tsx | 1 + 4 files changed, 91 insertions(+), 54 deletions(-) diff --git a/packages/dockview-core/src/dnd/overlay.ts b/packages/dockview-core/src/dnd/overlay.ts index f9c52753e..29fb4376f 100644 --- a/packages/dockview-core/src/dnd/overlay.ts +++ b/packages/dockview-core/src/dnd/overlay.ts @@ -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(); readonly onDidChange: Event = this._onDidChange.event; + private readonly _onDidChangeEnd = new Emitter(); + readonly onDidChangeEnd: Event = 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(); }) ); }) diff --git a/packages/dockview-core/src/dockview/dockviewComponent.ts b/packages/dockview-core/src/dockview/dockviewComponent.ts index 206b42a4e..21e579895 100644 --- a/packages/dockview-core/src/dockview/dockviewComponent.ts +++ b/packages/dockview-core/src/dockview/dockviewComponent.ts @@ -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') { diff --git a/packages/docs/sandboxes/floatinggroup-dockview/src/app.tsx b/packages/docs/sandboxes/floatinggroup-dockview/src/app.tsx index 507ab5a8e..722c98e25 100644 --- a/packages/docs/sandboxes/floatinggroup-dockview/src/app.tsx +++ b/packages/docs/sandboxes/floatinggroup-dockview/src/app.tsx @@ -210,7 +210,6 @@ export const DockviewPersistance = (props: { theme?: string }) => {
( style={{ position: 'absolute', overflow: 'hidden', + zIndex: 999, pointerEvents: 'none', // prevent this wrapper contain stealing events }} > From 59f9016e8d98570e4414086f2c7c12d68ae2c0e9 Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Thu, 20 Jul 2023 21:19:34 +0100 Subject: [PATCH 5/5] test: fix assertion --- .../dockview-core/src/__tests__/panel/componentFactory.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dockview-core/src/__tests__/panel/componentFactory.spec.ts b/packages/dockview-core/src/__tests__/panel/componentFactory.spec.ts index 3fc2c0c53..4e330056a 100644 --- a/packages/dockview-core/src/__tests__/panel/componentFactory.spec.ts +++ b/packages/dockview-core/src/__tests__/panel/componentFactory.spec.ts @@ -96,7 +96,7 @@ describe('componentFactory', () => { expect(component).toHaveBeenCalled(); - expect(componentResult instanceof component); + expect(componentResult instanceof component).toBeTruthy(); }); }); });