From f765dd52fc55a1762e86cb10ae6287b6ca6ea122 Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Sat, 27 Jul 2024 20:34:06 +0100 Subject: [PATCH] bug: render mode z-index fixes --- .../src/dnd/abstractDragHandler.ts | 15 ++---- packages/dockview-core/src/dnd/overlay.scss | 2 +- packages/dockview-core/src/dnd/overlay.ts | 51 +++++-------------- .../src/dockview/components/panel/content.ts | 7 ++- .../components/titlebar/voidContainer.ts | 2 +- .../src/dockview/dockviewComponent.ts | 15 ++++-- packages/dockview-core/src/dom.ts | 39 ++++++++++++++ .../src/overlayReadyContainer.scss | 6 ++- .../src/overlayRenderContainer.ts | 18 ++++++- .../dockview-core/src/splitview/splitview.ts | 14 ++--- tsconfig.base.json | 2 + 11 files changed, 101 insertions(+), 70 deletions(-) diff --git a/packages/dockview-core/src/dnd/abstractDragHandler.ts b/packages/dockview-core/src/dnd/abstractDragHandler.ts index 306ab236e..21298f74b 100644 --- a/packages/dockview-core/src/dnd/abstractDragHandler.ts +++ b/packages/dockview-core/src/dnd/abstractDragHandler.ts @@ -1,4 +1,4 @@ -import { getElementsByTagName } from '../dom'; +import { disableIframePointEvents, getElementsByTagName } from '../dom'; import { addDisposableListener, Emitter } from '../events'; import { CompositeDisposable, @@ -40,23 +40,14 @@ export abstract class DragHandler extends CompositeDisposable { return; } - const iframes = [ - ...getElementsByTagName('iframe'), - ...getElementsByTagName('webview'), - ]; + const iframes = disableIframePointEvents(); this.pointerEventsDisposable.value = { dispose: () => { - for (const iframe of iframes) { - iframe.style.pointerEvents = 'auto'; - } + iframes.release(); }, }; - for (const iframe of iframes) { - iframe.style.pointerEvents = 'none'; - } - this.el.classList.add('dv-dragged'); setTimeout(() => this.el.classList.remove('dv-dragged'), 0); diff --git a/packages/dockview-core/src/dnd/overlay.scss b/packages/dockview-core/src/dnd/overlay.scss index 5f95b379a..fe0b4c78f 100644 --- a/packages/dockview-core/src/dnd/overlay.scss +++ b/packages/dockview-core/src/dnd/overlay.scss @@ -30,7 +30,7 @@ z-index: 997; &.dv-bring-to-front { - z-index: 998; + z-index: 999; } border: 1px solid var(--dv-tab-divider-color); diff --git a/packages/dockview-core/src/dnd/overlay.ts b/packages/dockview-core/src/dnd/overlay.ts index c10e2ea80..3cb301288 100644 --- a/packages/dockview-core/src/dnd/overlay.ts +++ b/packages/dockview-core/src/dnd/overlay.ts @@ -1,4 +1,6 @@ import { + applyOnlyToThisElement, + disableIframePointEvents, getElementsByTagName, quasiDefaultPrevented, toggleClass, @@ -13,20 +15,7 @@ import { CompositeDisposable, MutableDisposable } from '../lifecycle'; import { clamp } from '../math'; import { AnchoredBox } from '../types'; -const bringElementToFront = (() => { - let previous: HTMLElement | null = null; - - function pushToTop(element: HTMLElement) { - if (previous !== element && previous !== null) { - toggleClass(previous, 'dv-bring-to-front', false); - } - - toggleClass(element, 'dv-bring-to-front', true); - previous = element; - } - - return pushToTop; -})(); +const bringElementToFront = applyOnlyToThisElement('dv-bring-to-front'); export class Overlay extends CompositeDisposable { private _element: HTMLElement = document.createElement('div'); @@ -88,6 +77,10 @@ export class Overlay extends CompositeDisposable { }); } + bringToFront(): void { + bringElementToFront.update(this._element); + } + setBounds(bounds: Partial = {}): void { if (typeof bounds.height === 'number') { this._element.style.height = `${bounds.height}px`; @@ -207,21 +200,12 @@ 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'; - } + const iframes = disableIframePointEvents(); move.value = new CompositeDisposable( { dispose: () => { - for (const iframe of iframes) { - iframe.style.pointerEvents = 'auto'; - } + iframes.release(); }, }, addDisposableWindowListener(window, 'mousemove', (e) => { @@ -362,13 +346,13 @@ export class Overlay extends CompositeDisposable { this.options.content, 'mousedown', () => { - bringElementToFront(this._element); + bringElementToFront.update(this._element); }, true ) ); - bringElementToFront(this._element); + bringElementToFront.update(this._element); if (options.inDragMode) { track(); @@ -404,14 +388,7 @@ export class Overlay extends CompositeDisposable { originalWidth: number; } | null = null; - const iframes = [ - ...getElementsByTagName('iframe'), - ...getElementsByTagName('webview'), - ]; - - for (const iframe of iframes) { - iframe.style.pointerEvents = 'none'; - } + const iframes = disableIframePointEvents(); move.value = new CompositeDisposable( addDisposableWindowListener(window, 'mousemove', (e) => { @@ -582,9 +559,7 @@ export class Overlay extends CompositeDisposable { }), { dispose: () => { - for (const iframe of iframes) { - iframe.style.pointerEvents = 'auto'; - } + iframes.release(); }, }, addDisposableWindowListener(window, 'mouseup', () => { diff --git a/packages/dockview-core/src/dockview/components/panel/content.ts b/packages/dockview-core/src/dockview/components/panel/content.ts index c39d141bb..bece6440b 100644 --- a/packages/dockview-core/src/dockview/components/panel/content.ts +++ b/packages/dockview-core/src/dockview/components/panel/content.ts @@ -3,7 +3,12 @@ import { IDisposable, MutableDisposable, } from '../../../lifecycle'; -import { Emitter, Event } from '../../../events'; +import { + addDisposableListener, + addDisposableWindowListener, + Emitter, + Event, +} from '../../../events'; import { trackFocus } from '../../../dom'; import { IDockviewPanel } from '../../dockviewPanel'; import { DockviewComponent } from '../../dockviewComponent'; diff --git a/packages/dockview-core/src/dockview/components/titlebar/voidContainer.ts b/packages/dockview-core/src/dockview/components/titlebar/voidContainer.ts index 5709273a8..308580a63 100644 --- a/packages/dockview-core/src/dockview/components/titlebar/voidContainer.ts +++ b/packages/dockview-core/src/dockview/components/titlebar/voidContainer.ts @@ -42,7 +42,7 @@ export class VoidContainer extends CompositeDisposable { this.addDisposables( this._onDrop, this._onDragStart, - addDisposableListener(this._element, 'click', () => { + addDisposableListener(this._element, 'pointerdown', () => { this.accessor.doSetGroupActive(this.group); }) ); diff --git a/packages/dockview-core/src/dockview/dockviewComponent.ts b/packages/dockview-core/src/dockview/dockviewComponent.ts index a9a285b9c..4ee049aaf 100644 --- a/packages/dockview-core/src/dockview/dockviewComponent.ts +++ b/packages/dockview-core/src/dockview/dockviewComponent.ts @@ -927,10 +927,17 @@ 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 - }); + const disposable = new CompositeDisposable( + group.api.onDidActiveChange((event) => { + if (event.isActive) { + overlay.bringToFront(); + } + }), + 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(() => { diff --git a/packages/dockview-core/src/dom.ts b/packages/dockview-core/src/dom.ts index 7953d94dd..eddc2c423 100644 --- a/packages/dockview-core/src/dom.ts +++ b/packages/dockview-core/src/dom.ts @@ -257,3 +257,42 @@ export function isInDocument(element: Element): boolean { export function addTestId(element: HTMLElement, id: string): void { element.setAttribute('data-testid', id); } + +export function disableIframePointEvents() { + const iframes = [ + ...getElementsByTagName('iframe'), + ...getElementsByTagName('webview'), + ]; + const original = new Map(); + + for (const iframe of iframes) { + original.set(iframe, iframe.style.pointerEvents); + iframe.style.pointerEvents = 'none'; + } + + return { + release: () => { + for (const iframe of iframes) { + iframe.style.pointerEvents = original.get(iframe) ?? 'auto'; + } + }, + }; +} + +export function applyOnlyToThisElement(className: string): { + update: (element: HTMLElement) => void; +} { + let previous: WeakRef | null; + + return { + update: (element: HTMLElement): void => { + const ref = previous?.deref(); + if (ref !== element && ref !== undefined) { + toggleClass(ref, className, false); + } + + toggleClass(element, className, true); + previous = new WeakRef(element); + }, + }; +} diff --git a/packages/dockview-core/src/overlayReadyContainer.scss b/packages/dockview-core/src/overlayReadyContainer.scss index 7e08072e4..82f69cc29 100644 --- a/packages/dockview-core/src/overlayReadyContainer.scss +++ b/packages/dockview-core/src/overlayReadyContainer.scss @@ -4,7 +4,11 @@ height: 100%; &.dv-render-overlay-float { - z-index: 999; + z-index: 998; + + &.dv-render-overlay-active { + z-index: 1000; + } } } diff --git a/packages/dockview-core/src/overlayRenderContainer.ts b/packages/dockview-core/src/overlayRenderContainer.ts index c7eb1d2b5..0cb066418 100644 --- a/packages/dockview-core/src/overlayRenderContainer.ts +++ b/packages/dockview-core/src/overlayRenderContainer.ts @@ -1,6 +1,10 @@ import { DragAndDropObserver } from './dnd/dnd'; import { Droptarget } from './dnd/droptarget'; -import { getDomNodePagePosition, toggleClass } from './dom'; +import { + applyOnlyToThisElement, + getDomNodePagePosition, + toggleClass, +} from './dom'; import { CompositeDisposable, Disposable, IDisposable } from './lifecycle'; import { IDockviewPanel } from './dockview/dockviewPanel'; @@ -17,6 +21,8 @@ function createFocusableElement(): HTMLDivElement { return element; } +const bringElementToFront = applyOnlyToThisElement('dv-active'); + export class OverlayRenderContainer extends CompositeDisposable { private readonly map: Record< string, @@ -148,6 +154,16 @@ export class OverlayRenderContainer extends CompositeDisposable { } resize(); + }), + panel.api.onDidActiveGroupChange(() => { + // toggleClass( + // focusContainer, + // 'dv-active', + // panel.api.isGroupActive + // ); + if (panel.api.isGroupActive) { + bringElementToFront.update(focusContainer); + } }) ); diff --git a/packages/dockview-core/src/splitview/splitview.ts b/packages/dockview-core/src/splitview/splitview.ts index 6fd1c2f28..fb1c65ef1 100644 --- a/packages/dockview-core/src/splitview/splitview.ts +++ b/packages/dockview-core/src/splitview/splitview.ts @@ -8,6 +8,7 @@ import { addClasses, toggleClass, getElementsByTagName, + disableIframePointEvents, } from '../dom'; import { Event, Emitter } from '../events'; import { pushToStart, pushToEnd, firstIndex } from '../array'; @@ -437,14 +438,7 @@ export class Splitview { item.enabled = false; } - const iframes = [ - ...getElementsByTagName('iframe'), - ...getElementsByTagName('webview'), - ]; - - for (const iframe of iframes) { - iframe.style.pointerEvents = 'none'; - } + const iframes = disableIframePointEvents(); const start = this._orientation === Orientation.HORIZONTAL @@ -553,9 +547,7 @@ export class Splitview { item.enabled = true; } - for (const iframe of iframes) { - iframe.style.pointerEvents = 'auto'; - } + iframes.release(); this.saveProportions(); diff --git a/tsconfig.base.json b/tsconfig.base.json index b418181bf..cd01be6f2 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -20,6 +20,8 @@ "ES2017.String", "ES2018.Promise", "ES2019", + "ES2020", + "ES2021", "DOM" ] },