From 5d9bdebf59f85c312efb8d98ac1a35e97a7e9821 Mon Sep 17 00:00:00 2001 From: lilleman Date: Wed, 5 Aug 2026 01:37:58 +0200 Subject: [PATCH] Close the popup menus on an outside click, via the popover API --- AGENTS.md | 8 ++++++++ README.md | 8 ++++++-- e2e-tests/full-flow.spec.ts | 13 ++++++++---- e2e-tests/language.spec.ts | 4 ++-- e2e-tests/visual.spec.ts | 29 ++++++++++++++++++++++++++ public/css/styles.css | 38 ++++++++++++++++++++++------------- src/ui/data-table.test.ts | 5 +++-- src/ui/menu.test.ts | 26 ++++++++++++++++-------- src/ui/shell.test.ts | 8 ++++++-- todo.md | 2 +- views/partials/data-table.ejs | 8 +++++--- views/partials/menu.ejs | 28 ++++++++++++++------------ views/partials/shell.ejs | 34 +++++++++++++++---------------- 13 files changed, 142 insertions(+), 69 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 4cdb57a..a5a42a6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -168,6 +168,14 @@ them. Revisit only if the stated reason stops holding. workspace dir, so ci.sh's web-image build races another run's container creation on the `-web` tag. Accepted for a single-maintainer cadence; serialize with a workflow `concurrency` group if it ever bites. +- **A dropdown is a `'); +}); + +test("menu mints its own popover id, so two menus on one page never cross-wire", async () => { + const idOf = (html: string): string => html.match(/popovertarget="([^"]+)"/)?.[1] ?? ""; + + const one = flat(await render()); + const two = flat(await render()); + assert.match(one, new RegExp(` diff --git a/views/partials/shell.ejs b/views/partials/shell.ejs index d0b5bf8..91462ee 100644 --- a/views/partials/shell.ejs +++ b/views/partials/shell.ejs @@ -57,24 +57,22 @@