From 3b47ebf0285ef0758ebf5396face5ee3409422ed Mon Sep 17 00:00:00 2001 From: Andreas Reinhold / reini Date: Mon, 14 Sep 2026 17:09:58 +0200 Subject: [PATCH] Say why the FAB menu's exit rule wins inside the layer Plan step 36. fab-menu.css claimed the item sets no translate or opacity of its own once it has entered; fab-menu-item.css sets both at rest, and the closing rule wins on specificity, which the header now says. fab-menu-item.css named the rule by the root's hook instead of the popover's, and a render test named for the list's scroll asserted the exit; it is named for what it checks. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9 --- resources/css/components/fab-menu-item.css | 2 +- resources/css/components/fab-menu.css | 7 ++++--- tests/Feature/Components/FabMenuTest.php | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/resources/css/components/fab-menu-item.css b/resources/css/components/fab-menu-item.css index 5be3028d..317414f5 100644 --- a/resources/css/components/fab-menu-item.css +++ b/resources/css/components/fab-menu-item.css @@ -7,7 +7,7 @@ * container. * * The entry is `@starting-style` on the item itself; the exit needs the state to be readable - * while the popover is on its way out, which `[data-md-fab-menu]:not(:popover-open) > *` + * while the popover is on its way out, which `[data-md-fab-menu-popover]:not(:popover-open) > *` * (fab-menu.css) drives from the popover's own open state — the popover keeps `display: flex` for * the length of its own discrete transition, so the item has somewhere to animate to (ACT-33). */ diff --git a/resources/css/components/fab-menu.css b/resources/css/components/fab-menu.css index 294de5af..e827920d 100644 --- a/resources/css/components/fab-menu.css +++ b/resources/css/components/fab-menu.css @@ -13,9 +13,10 @@ * entry is `@starting-style` on the item itself; the exit needs the state to be readable while the * popover is on its way out, which `[data-md-fab-menu-popover]:not(:popover-open) > *` is — the * popover keeps `display: flex` for the length of its own discrete transition, so the items have - * somewhere to animate to (ACT-33). Unlayered would beat an item's own declarations, but nothing - * here needs to: the item sets no `translate`/`opacity` of its own once it has entered, so this - * rule, inside the layer, is what always wins while the popover is closed. + * somewhere to animate to (ACT-33). The Tailwind-era rule sat outside the layers to beat the + * item's utilities; inside the layer it still beats fab-menu-item.css's resting `translate: 0 0` + * and `opacity: 1`, on specificity — an attribute and a pseudo-class against the item's one + * attribute — whichever order the two files are bundled in. */ @layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility; diff --git a/tests/Feature/Components/FabMenuTest.php b/tests/Feature/Components/FabMenuTest.php index 4c10af04..c17c8123 100644 --- a/tests/Feature/Components/FabMenuTest.php +++ b/tests/Feature/Components/FabMenuTest.php @@ -65,7 +65,7 @@ it('opens at the corner asked for, secondary and tertiary in their own colours', ]); }); -it('scrolls the list on a short window, behind the close button, which stays fixed', function () { +it('sinks the items back while the list closes, from the popover\'s own open state', function () { expect(ComponentStylesheet::read('fab-menu')->declarations('[data-md-fab-menu-popover]:not(:popover-open) > *'))->toBe([ 'translate' => '0 var(--md-sys-measurement-space100)', 'opacity' => '0',