From 198fbef34d5968632ecb995a5130a304558ebe36 Mon Sep 17 00:00:00 2001 From: n30nex Date: Sat, 12 Sep 2026 11:30:17 -0400 Subject: [PATCH] Keep node inspector popups above live packet effects (#11) --- CHANGELOG.md | 5 +++++ VERSION | 2 +- web/e2e/visual-smoke.spec.ts | 19 +++++++++++++++++++ web/package-lock.json | 4 ++-- web/package.json | 2 +- web/src/styles.css | 2 ++ 6 files changed, 30 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index baa734c..28b9035 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 0.4.1 - 2026-09-12 + +- Keep desktop node details above live packet trails and map shading so traffic cannot obscure the card. Preserve the toolbar and phone sheet layer order. +- Add a synthetic browser regression that checks the inspector against the actual packet canvas, including when the canvas normally ignores pointer events. + ## 0.4.0 - 2026-09-11 - Expand live packet sounds from 3 to 30 voices: keys, mallets, plucked strings, bells, synths, sonar-like pings and percussion. diff --git a/VERSION b/VERSION index 1d0ba9e..267577d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.0 +0.4.1 diff --git a/web/e2e/visual-smoke.spec.ts b/web/e2e/visual-smoke.spec.ts index b260c5d..b51ad11 100644 --- a/web/e2e/visual-smoke.spec.ts +++ b/web/e2e/visual-smoke.spec.ts @@ -482,6 +482,25 @@ test('focuses recent route neighbors and clears selection on the map', async ({ const inspector = mobile ? page.locator('#node-inspector-sheet') : page.locator('.node-inspector-popup'); await expect(inspector).toBeVisible(); await expect(inspector).toContainText('Alpha'); + // The traffic canvas normally ignores pointer hits, which can hide a paint-order bug. + // Include it in hit testing for one synchronous probe, then restore normal input behavior. + await expect(page.locator('#packet-canvas')).toHaveCSS('pointer-events', 'none'); + const inspectorAboveTraffic = await inspector.evaluate((panel) => { + const traffic = document.getElementById('packet-canvas')!; + const previous = traffic.style.pointerEvents; + const bounds = panel.getBoundingClientRect(); + traffic.style.pointerEvents = 'auto'; + try { + return panel.contains(document.elementFromPoint( + bounds.left + bounds.width / 2, + bounds.top + bounds.height / 2, + )); + } finally { + traffic.style.pointerEvents = previous; + } + }); + expect(inspectorAboveTraffic, 'node details must paint above live packet graphics').toBe(true); + await expect(page.locator('#packet-canvas')).toHaveCSS('pointer-events', 'none'); await expect(inspector.locator('.neighbor-row')).toHaveCount(1); await expect(inspector.locator('.neighbor-row').first()).toContainText('Bravo'); await expect(map).toHaveAttribute('data-neighbor-route-count', '1'); diff --git a/web/package-lock.json b/web/package-lock.json index f86c50f..c0655d9 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,12 +1,12 @@ { "name": "cartolite-server-web", - "version": "0.4.0", + "version": "0.4.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cartolite-server-web", - "version": "0.4.0", + "version": "0.4.1", "dependencies": { "maplibre-gl": "6.4.1" }, diff --git a/web/package.json b/web/package.json index 9a15d19..5347fb5 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "cartolite-server-web", - "version": "0.4.0", + "version": "0.4.1", "private": true, "type": "module", "scripts": { diff --git a/web/src/styles.css b/web/src/styles.css index 5a2cdc6..508a05b 100644 --- a/web/src/styles.css +++ b/web/src/styles.css @@ -406,6 +406,8 @@ button { font: inherit; } .tooltip[hidden] { display: none; } +/* Raise the popup wrapper's stacking context above traffic (4), below controls (8). */ +.node-inspector-popup { z-index: 7; } .node-inspector-popup .maplibregl-popup-content { overflow: hidden; border: 1px solid rgba(123, 205, 209, 0.22);