mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-06 08:15:45 +00:00
fix: keep the window's buttons clear of the app's after a maximise, restore, snap or resize
This commit is contained in:
@@ -348,6 +348,32 @@ describe('the window controls over the app', () => {
|
||||
expect(root.hasAttribute(CONTROLS_ATTRIBUTE)).toBe(false);
|
||||
expect(rightInset()).toBe('');
|
||||
});
|
||||
|
||||
describe('when the window changes size in one step', () => {
|
||||
const startWidth = window.innerWidth;
|
||||
const setWidth = (width: number) => Object.defineProperty(window, 'innerWidth', { value: width, configurable: true, writable: true });
|
||||
afterEach(() => setWidth(startWidth));
|
||||
|
||||
// As Chromium does it: geometrychange with the new rect while the page still has
|
||||
// its old width, then the page takes the new width and fires resize.
|
||||
const resizeTo = (fake: EventTarget, width: number) => act(() => {
|
||||
(fake as unknown as { getTitlebarAreaRect: () => object }).getTitlebarAreaRect = () => ({ x: 0, y: 0, width: width - 137, height: 56 });
|
||||
fake.dispatchEvent(new Event('geometrychange'));
|
||||
setWidth(width);
|
||||
window.dispatchEvent(new Event('resize'));
|
||||
});
|
||||
|
||||
it('keeps the room for the controls after a maximise, a restore, a snap and a shrink', () => {
|
||||
setWidth(1366);
|
||||
const fake = overlayAt(0, 1366 - 137);
|
||||
render(<WindowControlsHost />);
|
||||
expect(rightInset()).toBe('137px');
|
||||
for (const width of [2048, 1366, 1024, 640, 1920]) {
|
||||
resizeTo(fake, width);
|
||||
expect(rightInset(), `at ${width} px`).toBe('137px');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('which rows hold the controls', () => {
|
||||
|
||||
@@ -94,9 +94,14 @@ export function applyControlsArea(area: TitlebarArea | null, root: HTMLElement =
|
||||
|
||||
/**
|
||||
* Calls `listener` now and whenever the overlay's size or visibility changes
|
||||
* (`geometrychange`). Without the API it calls it once with null and listens
|
||||
* to nothing, so a browser without it runs no extra code. Returns the
|
||||
* unsubscribe.
|
||||
* (`geometrychange`), and again when the page's width does (`resize`).
|
||||
* Without the API it calls it once with null and listens to nothing, so a
|
||||
* browser without it runs no extra code. Returns the unsubscribe.
|
||||
*
|
||||
* `geometrychange` comes before the page has its new width: after a maximise,
|
||||
* restore, snap or drag the rect is the new one and innerWidth still the old,
|
||||
* so the room worked out from the two is wrong (none at all after growing, more
|
||||
* than the window after shrinking). The `resize` that follows has both.
|
||||
*/
|
||||
export function watchTitlebarArea(listener: (area: TitlebarArea | null) => void): () => void {
|
||||
listener(readTitlebarArea());
|
||||
@@ -104,7 +109,11 @@ export function watchTitlebarArea(listener: (area: TitlebarArea | null) => void)
|
||||
if (!current) return () => {};
|
||||
const onChange = () => listener(readTitlebarArea());
|
||||
current.addEventListener('geometrychange', onChange);
|
||||
return () => current.removeEventListener('geometrychange', onChange);
|
||||
window.addEventListener('resize', onChange);
|
||||
return () => {
|
||||
current.removeEventListener('geometrychange', onChange);
|
||||
window.removeEventListener('resize', onChange);
|
||||
};
|
||||
}
|
||||
|
||||
const ROW_CANDIDATES = '[data-window-top-row], [data-composer-header], header, div.h-14, div.min-h-14, div.h-12, div.h-16, div.min-h-16';
|
||||
|
||||
Reference in New Issue
Block a user