From 12183715689811c89fc36850a6a79afa0ed38a6f Mon Sep 17 00:00:00 2001 From: Andreas Reinhold / reini Date: Mon, 14 Sep 2026 06:12:44 +0200 Subject: [PATCH] Give the account-menu avatar a state layer The trigger had the focus ring but no hover and no pressed feedback at all, where every comparable trigger in the library carries `state-layer` and M3 asks for two visual indicators per state. An avatar image sits behind the layer, so the wash shows over a photograph too. Plan: docs/plans/material-3-alignment.md, step 21 (navigation N-15). Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9 --- resources/views/components/account-menu.blade.php | 6 ++++-- tests/Feature/Components/AppBarTest.php | 7 ++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/resources/views/components/account-menu.blade.php b/resources/views/components/account-menu.blade.php index 00c968a9..3719ed9b 100644 --- a/resources/views/components/account-menu.blade.php +++ b/resources/views/components/account-menu.blade.php @@ -38,10 +38,12 @@ type="button" aria-label="{{ $label }}" data-account-menu - class="touch-target focus-ring inline-flex size-10 shrink-0 cursor-pointer items-center justify-center rounded-corner-full bg-primary-container type-label-lg text-on-primary-container" + class="state-layer touch-target focus-ring inline-flex size-10 shrink-0 cursor-pointer items-center justify-center rounded-corner-full bg-primary-container type-label-lg text-on-primary-container" > @if ($image) - + {{-- Behind the state layer (`state-layer` paints its ::before at z-index -1), so an + avatar image still shows the hover and pressed states over it. --}} + @elseif (filled($initials)) {{ $initials }} @else diff --git a/tests/Feature/Components/AppBarTest.php b/tests/Feature/Components/AppBarTest.php index cb3d9bdb..369d254e 100644 --- a/tests/Feature/Components/AppBarTest.php +++ b/tests/Feature/Components/AppBarTest.php @@ -146,8 +146,9 @@ it('opens an account menu from the initials of a name', function () { expect($html) ->toContain('aria-label="Account"') ->toContain('data-account-menu') - // The 40px avatar reaches 48px, and nothing clips the pseudo-target (N-01). - ->toContain('touch-target') + // The 40px avatar reaches 48px, and nothing clips the pseudo-target (N-01); the trigger + // has a hover and a pressed state like every other trigger in the library (N-15). + ->toContain('state-layer touch-target focus-ring') ->not->toContain('overflow-hidden') ->toMatch('/>\s*AM\s*<\/button>/') ->toContain('anna@example.com') @@ -155,6 +156,6 @@ it('opens an account menu from the initials of a name', function () { ->toContain('data-account-theme') ->toContain('Sign out') ->and((string) $this->blade('')) - ->toContain('') + ->toContain('') ->not->toContain('data-account-theme'); });