Files
WRNexusJS/packages/csr/test/anchored-overlays.test.ts
T
Clintchiz 7c1fcd19d4
Quality / quality (ubuntu-latest) (push) Failing after 4s
Quality / quality (windows-latest) (push) Canceled after 0s
fix(ui): keep floating menus inside viewport and clipping containers
2026-10-19 17:51:15 +05:30

51 lines
2.5 KiB
TypeScript

import { test, expect } from "bun:test";
import { Window } from "happy-dom";
import { REACTIVE_RUNTIME } from "../src/reactive-runtime.ts";
function fixture(panel: Record<string, number>, clipped = false) {
const win = new Window();
win.document.body.innerHTML = '<div id="clip"><div data-ui-component="ComboBox"><div data-wrn-anchored></div></div></div>';
const element = win.document.querySelector('[data-wrn-anchored]')! as any;
const host = element.parentElement;
const rect = (left: number, top: number, width: number, height: number) => ({left, top, width, height, right:left+width, bottom:top+height});
host.getBoundingClientRect = () => rect(270, 170, 40, 30);
element.getBoundingClientRect = () => rect(panel.left, panel.top,
Math.min(panel.width, parseFloat(element.style.maxWidth) || Infinity),
Math.min(panel.height, parseFloat(element.style.maxHeight) || Infinity));
if (clipped) {
const clip = win.document.querySelector('#clip')! as any;
clip.style.overflow = 'hidden';
clip.getBoundingClientRect = () => rect(100, 50, 220, 220);
Object.defineProperty(clip, 'clientWidth', {value:220});
Object.defineProperty(clip, 'clientHeight', {value:220});
}
const start = REACTIVE_RUNTIME.indexOf(' function isRenderedElement(');
const end = REACTIVE_RUNTIME.indexOf(' function repositionAnchored(', start);
const clamp = new Function('window', 'document', 'ANCHOR_MARGIN', REACTIVE_RUNTIME.slice(start,end) + '; return clampAnchored;')(win, win.document, 8);
return {win, element, clamp};
}
test('anchored panels fit clipping containers and positioning does not drift', async () => {
const {win, element, clamp} = fixture({left:40,top:208,width:180,height:100}, true);
clamp(element);
expect(element.style.translate).toBe('68px -146px');
clamp(element);
expect(element.style.translate).toBe('68px -146px');
await win.happyDOM.close();
});
test('oversized panels become scrollable and recover authored sizing when space returns', async () => {
const {win, element, clamp} = fixture({left:40,top:60,width:500,height:400}, true);
element.style.minWidth = '300px';
clamp(element);
expect(element.style.maxWidth).toBe('204px');
expect(element.style.maxHeight).toBe('204px');
expect(element.style.overflow).toBe('auto');
element.parentElement.parentElement.style.overflow = 'visible';
clamp(element);
expect(element.style.minWidth).toBe('300px');
expect(element.style.maxWidth).toBe('');
await win.happyDOM.close();
});