fix: light dismiss for header menu/search overlays (outside tap closes, never activates)

This commit is contained in:
ctao
2026-07-25 12:33:09 +02:00
parent 4fa35e5317
commit ffe54bc766
3 changed files with 68 additions and 16 deletions
+28 -4
View File
@@ -110,11 +110,35 @@ const links = [
<script is:inline>
// Header search suggestions (desktop field + mobile reveal); the forms
// are plain GET /search, so everything below is progressive enhancement.
newsSearch({ input: 'hdr-q', list: 'hdr-suggest', status: 'hdr-suggest-status', limit: 6, unit: 'suggestion' });
newsSearch({ input: 'pop-q', list: 'pop-suggest', status: 'pop-suggest-status', limit: 6, unit: 'suggestion' });
newsSearch({ input: 'hdr-q', list: 'hdr-suggest', status: 'hdr-suggest-status', limit: 6, unit: 'suggestion', dismiss: true });
newsSearch({ input: 'pop-q', list: 'pop-suggest', status: 'pop-suggest-status', limit: 6, unit: 'suggestion', dismiss: true });
var pop = document.querySelector('.search-pop');
pop.addEventListener('toggle', function () {
if (pop.open) document.getElementById('pop-q').focus();
if (pop) pop.addEventListener('toggle', function () {
var q = document.getElementById('pop-q');
if (pop.open && q) q.focus();
});
// Light dismiss for the header panels (menu + search reveal) — scrim
// convention (Material/iOS, NN/g error prevention): a tap outside an
// open panel ONLY closes it and must never activate what's underneath.
// <details> has no native light dismiss; the Popover API was evaluated
// and rejected here — its light dismiss deliberately lets the outside
// click THROUGH (::backdrop is spec-forced pointer-events: none), the
// exact behavior research ruled out. Canceling pointerdown doesn't
// cancel the later click (Pointer Events spec), hence the click guard.
var swallow = false;
document.addEventListener('pointerdown', function (e) {
var open = document.querySelector('details[name="header-panel"][open]');
swallow = !!(open && !open.contains(e.target));
if (swallow) { open.open = false; e.preventDefault(); }
}, true);
document.addEventListener('click', function (e) {
if (swallow) { swallow = false; e.preventDefault(); e.stopPropagation(); }
}, true);
// Escape closes the open panel and returns focus to its trigger button
document.addEventListener('keydown', function (e) {
if (e.key !== 'Escape') return;
var open = document.querySelector('details[name="header-panel"][open]');
if (open) { open.open = false; open.querySelector('summary').focus(); }
});
</script>
<main id="main">