Merge pull request #683 from mathuo/656-renderer-always-causes-floating-group-z-index-bug

feat: correct z-index level for floating always rendered panel
This commit is contained in:
mathuo 2024-08-11 20:41:15 +01:00 committed by GitHub
commit 520aa39724
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 117 additions and 50 deletions

View File

@ -8,11 +8,11 @@ import {
import { fromPartial } from '@total-typescript/shoehorn';
import { Writable, exhaustMicrotaskQueue } from '../__test_utils__/utils';
import { DockviewComponent } from '../../dockview/dockviewComponent';
import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
describe('overlayRenderContainer', () => {
let referenceContainer: IRenderable;
let parentContainer: HTMLElement;
let cut: OverlayRenderContainer;
beforeEach(() => {
parentContainer = document.createElement('div');
@ -21,14 +21,14 @@ describe('overlayRenderContainer', () => {
element: document.createElement('div'),
dropTarget: fromPartial<Droptarget>({}),
};
cut = new OverlayRenderContainer(
parentContainer,
fromPartial<DockviewComponent>({})
);
});
test('that attach(...) and detach(...) mutate the DOM as expected', () => {
const cut = new OverlayRenderContainer(
parentContainer,
fromPartial<DockviewComponent>({})
);
const panelContentEl = document.createElement('div');
const onDidVisibilityChange = new Emitter<any>();
@ -42,6 +42,7 @@ describe('overlayRenderContainer', () => {
onDidDimensionsChange: onDidDimensionsChange.event,
onDidLocationChange: onDidLocationChange.event,
isVisible: true,
location: { type: 'grid' },
},
view: {
content: {
@ -67,6 +68,11 @@ describe('overlayRenderContainer', () => {
});
test('add a view that is not currently in the DOM', async () => {
const cut = new OverlayRenderContainer(
parentContainer,
fromPartial<DockviewComponent>({})
);
const panelContentEl = document.createElement('div');
const onDidVisibilityChange = new Emitter<any>();
@ -80,6 +86,7 @@ describe('overlayRenderContainer', () => {
onDidDimensionsChange: onDidDimensionsChange.event,
onDidLocationChange: onDidLocationChange.event,
isVisible: true,
location: { type: 'grid' },
},
view: {
content: {
@ -197,4 +204,60 @@ describe('overlayRenderContainer', () => {
referenceContainer.element.getBoundingClientRect
).toHaveBeenCalledTimes(3);
});
test('related z-index from `aria-level` set on floating panels', async () => {
const group = fromPartial<DockviewGroupPanel>({});
const element = document.createElement('div');
element.setAttribute('aria-level', '2');
const spy = jest.spyOn(element, 'getAttribute');
const accessor = fromPartial<DockviewComponent>({
floatingGroups: [
{
group,
overlay: {
element,
},
},
],
});
const cut = new OverlayRenderContainer(parentContainer, accessor);
const panelContentEl = document.createElement('div');
const onDidVisibilityChange = new Emitter<any>();
const onDidDimensionsChange = new Emitter<any>();
const onDidLocationChange = new Emitter<any>();
const panel = fromPartial<IDockviewPanel>({
api: {
id: 'test_panel_id',
onDidVisibilityChange: onDidVisibilityChange.event,
onDidDimensionsChange: onDidDimensionsChange.event,
onDidLocationChange: onDidLocationChange.event,
isVisible: true,
group,
location: { type: 'floating' },
},
view: {
content: {
element: panelContentEl,
},
},
group: {
api: {
location: { type: 'floating' },
},
},
});
cut.attach({ panel, referenceContainer });
await exhaustMicrotaskQueue();
expect(spy).toHaveBeenCalledWith('aria-level');
expect(panelContentEl.parentElement!.style.zIndex).toBe('1004');
});
});

View File

@ -87,7 +87,7 @@ export class DockviewPanel
// you are actually just resizing the panels parent which is the group
this.group.api.setSize(event);
}),
this.api.onDidRendererChange((event) => {
this.api.onDidRendererChange(() => {
this.group.model.rerender(this);
})
);

View File

@ -120,6 +120,48 @@ export class OverlayRenderContainer extends CompositeDisposable {
const observerDisposable = new MutableDisposable();
const correctLayerPosition = () => {
if (panel.api.location.type === 'floating') {
queueMicrotask(() => {
const floatingGroup = this.accessor.floatingGroups.find(
(group) => group.group === panel.api.group
);
if (!floatingGroup) {
return;
}
const element = floatingGroup.overlay.element;
const update = () => {
const level = Number(
element.getAttribute('aria-level')
);
focusContainer.style.zIndex = `${
DEFAULT_OVERLAY_Z_INDEX + level * 2 + 1
}`;
};
const observer = new MutationObserver(() => {
update();
});
observerDisposable.value = Disposable.from(() =>
observer.disconnect()
);
observer.observe(element, {
attributeFilter: ['aria-level'],
attributes: true,
});
update();
});
} else {
focusContainer.style.zIndex = ''; // reset the z-index, perhaps CSS will take over here
}
};
const disposable = new CompositeDisposable(
observerDisposable,
/**
@ -147,7 +189,7 @@ export class OverlayRenderContainer extends CompositeDisposable {
},
}),
panel.api.onDidVisibilityChange((event) => {
panel.api.onDidVisibilityChange(() => {
/**
* Control the visibility of the content, however even when not visible (display: none)
* the content is still maintained within the DOM hence DOM specific attributes
@ -162,48 +204,8 @@ export class OverlayRenderContainer extends CompositeDisposable {
resize();
}),
panel.api.onDidLocationChange((event) => {
const isFloating = event.location.type === 'floating';
if (isFloating) {
queueMicrotask(() => {
const floatingGroup = this.accessor.floatingGroups.find(
(group) => group.group === panel.api.group
);
if (!floatingGroup) {
return;
}
const element = floatingGroup.overlay.element;
const update = () => {
const level = Number(
element.getAttribute('aria-level')
);
focusContainer.style.zIndex = `${
DEFAULT_OVERLAY_Z_INDEX + level * 2 + 1
}`;
};
const observer = new MutationObserver(() => {
update();
});
observerDisposable.value = Disposable.from(() =>
observer.disconnect()
);
observer.observe(element, {
attributeFilter: ['aria-level'],
attributes: true,
});
update();
});
} else {
focusContainer.style.zIndex = ''; // reset the z-index, perhaps CSS will take over here
}
panel.api.onDidLocationChange(() => {
correctLayerPosition();
})
);
@ -215,6 +217,8 @@ export class OverlayRenderContainer extends CompositeDisposable {
focusContainer.parentElement?.removeChild(focusContainer);
});
correctLayerPosition();
queueMicrotask(() => {
if (this.isDisposed) {
return;