Put the showcase in the app shell, with a page per section
tests / lint (push) Has been cancelled
tests / feature (8.4) (push) Has been cancelled
tests / feature (8.5) (push) Has been cancelled
tests / browser (chrome, chromium) (push) Has been cancelled
tests / browser (firefox, firefox) (push) Has been cancelled
tests / browser (safari, webkit) (push) Has been cancelled

The showcase is now an overview and one page per section behind a
grouped navigation rail, moved between with wire:navigate, instead of
one long page under a scrolling top bar. The switch exposed a WebKit
bug in the menu: inside a focusable region, WebKit moves focus out of
the closing popover before its toggle event, so Escape no longer
returned focus to the trigger. The menu now reads it on beforetoggle.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
This commit is contained in:
Andreas Reinhold / reini
2026-09-13 09:30:26 +02:00
co-authored by Claude Opus 5
parent 23218431bf
commit 889f8a8aa1
20 changed files with 251 additions and 81 deletions
+11 -1
View File
@@ -15,6 +15,7 @@ document.addEventListener('alpine:init', () => {
window.Alpine.data('materialMenu', () => ({
closedAt: -Infinity,
returnFocus: true,
focusWasInside: false,
listeners: [],
init() {
@@ -26,6 +27,13 @@ document.addEventListener('alpine:init', () => {
// and close() have already done their part, synchronously, because this event is
// queued and a screen reader or a test reading aria-expanded in between would be told
// the menu is shut.
// Whether focus was in the menu is read before it closes: once closed, a browser may
// already have handed focus to what had it before the menu opened (WebKit does, when
// that was a focusable region around the trigger).
this.listen(menu, 'beforetoggle', (event) => {
this.focusWasInside = event.newState === 'closed' && menu.contains(document.activeElement)
})
this.listen(menu, 'toggle', (event) => {
const opened = event.newState === 'open'
@@ -37,9 +45,11 @@ document.addEventListener('alpine:init', () => {
this.closedAt = performance.now()
if (this.returnFocus && menu.contains(document.activeElement)) {
if (this.returnFocus && (this.focusWasInside || menu.contains(document.activeElement))) {
this.control()?.focus()
}
this.focusWasInside = false
})
// A press outside closes the menu without pulling focus back to the trigger.