From 7160f7435705d9fea4949a890d1e28b2382f49bf Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Wed, 4 Mar 2026 21:47:22 +0000 Subject: [PATCH] fix(dockview-core): use visibility:hidden instead of display:none for always renderer Prevents resize-to-0x0 events when panels with renderer='always' are hidden, which disrupted virtualized components (e.g. data grids) that manage their own scrollbars. Adds pointer-events:none to preserve drag-and-drop behaviour on hidden overlays. Closes #1063. Co-Authored-By: Claude Sonnet 4.6 --- .../overlay/overlayRenderContainer.spec.ts | 23 +++++++++++-------- .../src/overlay/overlayRenderContainer.ts | 8 ++++--- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/packages/dockview-core/src/__tests__/overlay/overlayRenderContainer.spec.ts b/packages/dockview-core/src/__tests__/overlay/overlayRenderContainer.spec.ts index ce9732f127..c7e89283cd 100644 --- a/packages/dockview-core/src/__tests__/overlay/overlayRenderContainer.spec.ts +++ b/packages/dockview-core/src/__tests__/overlay/overlayRenderContainer.spec.ts @@ -169,7 +169,8 @@ describe('overlayRenderContainer', () => { expect(panelContentEl.parentElement).toBe(container); expect(container.parentElement).toBe(parentContainer); - expect(container.style.display).toBe(''); + expect(container.style.visibility).toBe(''); + expect(container.style.pointerEvents).toBe(''); expect(container.style.left).toBe('50px'); expect(container.style.top).toBe('100px'); @@ -181,7 +182,8 @@ describe('overlayRenderContainer', () => { onDidDimensionsChange.fire({}); await exhaustAnimationFrame(); - expect(container.style.display).toBe(''); + expect(container.style.visibility).toBe(''); + expect(container.style.pointerEvents).toBe(''); expect(container.style.left).toBe('49px'); expect(container.style.top).toBe('99px'); @@ -193,22 +195,25 @@ describe('overlayRenderContainer', () => { (panel as Writable).api.isVisible = false; onDidVisibilityChange.fire({}); - expect(container.style.display).toBe('none'); + expect(container.style.visibility).toBe('hidden'); + expect(container.style.pointerEvents).toBe('none'); expect( referenceContainer.element.getBoundingClientRect ).toHaveBeenCalledTimes(2); (panel as Writable).api.isVisible = true; onDidVisibilityChange.fire({}); - expect(container.style.display).toBe(''); + expect(container.style.pointerEvents).toBe(''); + await exhaustAnimationFrame(); + expect(container.style.visibility).toBe(''); - expect(container.style.left).toBe('49px'); - expect(container.style.top).toBe('99px'); - expect(container.style.width).toBe('101px'); - expect(container.style.height).toBe('201px'); + expect(container.style.left).toBe('50px'); + expect(container.style.top).toBe('100px'); + expect(container.style.width).toBe('100px'); + expect(container.style.height).toBe('200px'); expect( referenceContainer.element.getBoundingClientRect - ).toHaveBeenCalledTimes(2); + ).toHaveBeenCalledTimes(3); }); test('related z-index from `aria-level` set on floating panels', async () => { diff --git a/packages/dockview-core/src/overlay/overlayRenderContainer.ts b/packages/dockview-core/src/overlay/overlayRenderContainer.ts index 9bbceb6baa..954e248570 100644 --- a/packages/dockview-core/src/overlay/overlayRenderContainer.ts +++ b/packages/dockview-core/src/overlay/overlayRenderContainer.ts @@ -205,9 +205,11 @@ export class OverlayRenderContainer extends CompositeDisposable { if (panel.api.isVisible) { this.positionCache.invalidate(); resize(); + focusContainer.style.pointerEvents = ''; + } else { + focusContainer.style.visibility = 'hidden'; + focusContainer.style.pointerEvents = 'none'; } - - focusContainer.style.display = panel.api.isVisible ? '' : 'none'; }; const observerDisposable = new MutableDisposable(); @@ -261,7 +263,7 @@ export class OverlayRenderContainer extends CompositeDisposable { * the dnd events for the expect behaviours to continue to occur in terms of dnd * * the dnd observer does not need to be conditional on whether the panel is visible since - * non-visible panels are 'display: none' and in such case the dnd observer will not fire. + * non-visible panels have 'pointer-events: none' and in such case the dnd observer will not fire. */ new DragAndDropObserver(focusContainer, { onDragEnd: (e) => {