@operato/popup 10.29.49 → 10.29.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,69 @@
1
+ import { expect } from '@open-wc/testing';
2
+ import { html, render } from 'lit';
3
+ import '../src/ox-popup-list.js';
4
+ /*
5
+ * A list taller than the room below its select was moved up over the select itself (2026-10-25). In a grid cell the
6
+ * second press of a double-click then landed on an option and picked it. A popup stays off the line it opens from: it
7
+ * shrinks to the room below, or opens above when there is more room there.
8
+ */
9
+ describe('ox-popup placement', () => {
10
+ const frame = () => new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)));
11
+ let list;
12
+ async function open(count, place) {
13
+ const host = document.createElement('div');
14
+ document.body.appendChild(host);
15
+ render(html `<ox-popup-list with-search>
16
+ ${Array.from({ length: count }, (_, i) => html `<div option value=${i}>Option ${i}</div>`)}
17
+ </ox-popup-list>`, host);
18
+ list = host.querySelector('ox-popup-list');
19
+ document.body.appendChild(list);
20
+ host.remove();
21
+ await list.updateComplete;
22
+ list.open({ left: 20, ...place });
23
+ await list.updateComplete;
24
+ await frame();
25
+ return list.getBoundingClientRect();
26
+ }
27
+ afterEach(() => {
28
+ list?.close();
29
+ list?.remove();
30
+ });
31
+ it('a long list under a select with more room below shrinks to that room and keeps its search box', async () => {
32
+ const anchorTop = Math.round(window.innerHeight / 3);
33
+ const box = await open(200, { anchorTop, top: anchorTop + 30 });
34
+ expect(box.top).to.be.at.least(anchorTop + 30 - 0.5);
35
+ expect(box.bottom).to.be.at.most(window.innerHeight + 0.5);
36
+ const search = list.shadowRoot.querySelector('[search]').getBoundingClientRect();
37
+ expect(search.top).to.be.at.least(anchorTop + 30 - 0.5);
38
+ const last = list.querySelector('[option]:last-of-type');
39
+ expect(last.getBoundingClientRect().bottom > box.bottom).to.equal(true);
40
+ });
41
+ it('a long list under a select near the bottom opens above the select', async () => {
42
+ const anchorTop = window.innerHeight - 60;
43
+ const box = await open(200, { anchorTop, top: anchorTop + 30 });
44
+ expect(box.bottom).to.be.at.most(anchorTop + 0.5);
45
+ expect(box.top).to.be.at.least(-0.5);
46
+ });
47
+ it('a short list that fits stays where it was asked to open', async () => {
48
+ const box = await open(3, { anchorTop: 40, top: 70 });
49
+ expect(box.top).to.be.closeTo(70, 0.5);
50
+ });
51
+ it('a menu at a point near the bottom opens above the point, not over it', async () => {
52
+ const point = window.innerHeight - 20;
53
+ const box = await open(30, { top: point });
54
+ expect(box.bottom).to.be.at.most(point + 0.5);
55
+ });
56
+ it('opened again elsewhere, it does not keep the last place or the last cut', async () => {
57
+ const anchorTop = Math.round(window.innerHeight / 2);
58
+ await open(200, { anchorTop, top: anchorTop + 30 });
59
+ list.close();
60
+ list.open({ left: 20, anchorTop: 40, top: 70 });
61
+ await list.updateComplete;
62
+ await frame();
63
+ const box = list.getBoundingClientRect();
64
+ expect(box.top).to.be.closeTo(70, 0.5);
65
+ /* The room below now, less the margin - not the shorter cut of the last opening. */
66
+ expect(box.bottom).to.be.closeTo(window.innerHeight - 10, 0.5);
67
+ });
68
+ });
69
+ //# sourceMappingURL=ox-popup-placement.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ox-popup-placement.test.js","sourceRoot":"","sources":["../../test/ox-popup-placement.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect } from '@open-wc/testing'\nimport { html, render } from 'lit'\n\nimport '../src/ox-popup-list.js'\nimport type { OxPopupList } from '../src/ox-popup-list.js'\n\n/*\n * A list taller than the room below its select was moved up over the select itself (2026-10-25). In a grid cell the\n * second press of a double-click then landed on an option and picked it. A popup stays off the line it opens from: it\n * shrinks to the room below, or opens above when there is more room there.\n */\ndescribe('ox-popup placement', () => {\n const frame = () => new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)))\n let list: OxPopupList\n\n async function open(count: number, place: { top: number; anchorTop?: number }) {\n const host = document.createElement('div')\n document.body.appendChild(host)\n render(\n html`<ox-popup-list with-search>\n ${Array.from({ length: count }, (_, i) => html`<div option value=${i}>Option ${i}</div>`)}\n </ox-popup-list>`,\n host\n )\n list = host.querySelector('ox-popup-list') as OxPopupList\n document.body.appendChild(list)\n host.remove()\n await list.updateComplete\n list.open({ left: 20, ...place })\n await list.updateComplete\n await frame()\n return list.getBoundingClientRect()\n }\n\n afterEach(() => {\n list?.close()\n list?.remove()\n })\n\n it('a long list under a select with more room below shrinks to that room and keeps its search box', async () => {\n const anchorTop = Math.round(window.innerHeight / 3)\n const box = await open(200, { anchorTop, top: anchorTop + 30 })\n expect(box.top).to.be.at.least(anchorTop + 30 - 0.5)\n expect(box.bottom).to.be.at.most(window.innerHeight + 0.5)\n const search = list.shadowRoot!.querySelector('[search]')!.getBoundingClientRect()\n expect(search.top).to.be.at.least(anchorTop + 30 - 0.5)\n const last = list.querySelector('[option]:last-of-type')!\n expect(last.getBoundingClientRect().bottom > box.bottom).to.equal(true)\n })\n\n it('a long list under a select near the bottom opens above the select', async () => {\n const anchorTop = window.innerHeight - 60\n const box = await open(200, { anchorTop, top: anchorTop + 30 })\n expect(box.bottom).to.be.at.most(anchorTop + 0.5)\n expect(box.top).to.be.at.least(-0.5)\n })\n\n it('a short list that fits stays where it was asked to open', async () => {\n const box = await open(3, { anchorTop: 40, top: 70 })\n expect(box.top).to.be.closeTo(70, 0.5)\n })\n\n it('a menu at a point near the bottom opens above the point, not over it', async () => {\n const point = window.innerHeight - 20\n const box = await open(30, { top: point })\n expect(box.bottom).to.be.at.most(point + 0.5)\n })\n\n it('opened again elsewhere, it does not keep the last place or the last cut', async () => {\n const anchorTop = Math.round(window.innerHeight / 2)\n await open(200, { anchorTop, top: anchorTop + 30 })\n list.close()\n list.open({ left: 20, anchorTop: 40, top: 70 })\n await list.updateComplete\n await frame()\n const box = list.getBoundingClientRect()\n expect(box.top).to.be.closeTo(70, 0.5)\n /* The room below now, less the margin - not the shorter cut of the last opening. */\n expect(box.bottom).to.be.closeTo(window.innerHeight - 10, 0.5)\n })\n})\n"]}