Rest a FAB nested in the rail at elevation 0

M3 puts a FAB nested in another component at level 0, and the documented pattern
puts one in the rail's header, so every documented use sat at elevation 3. The
rule is unlayered: the FAB's shadow is a utility and a layer would lose to it.
Plan: docs/plans/material-3-alignment.md, step 14 (navigation N-03).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
Andreas Reinhold / reini
2026-09-14 05:54:52 +02:00
co-authored by Claude Opus 5
parent 4d4862189a
commit 98afef7b45
3 changed files with 30 additions and 1 deletions
@@ -51,6 +51,21 @@ it('keeps the header and footer out of the scrolling destinations', function ()
->toMatch('/data-navigation-rail-header.*Brand.*FAB.*data-navigation-rail-destinations.*Inbox.*data-navigation-rail-footer.*Account/s');
});
it('flattens a FAB nested in the rail header to elevation 0', function () {
$html = (string) $this->blade(<<<'BLADE'
<x-navigation-rail mode="expanded">
<x-slot:header><x-fab icon="edit" tooltip-right="Compose" /></x-slot:header>
</x-navigation-rail>
BLADE);
// The hook the unlayered rule in navigation.css needs (N-03).
expect($html)->toContain('data-fab');
expect(file_get_contents(__DIR__.'/../../../resources/css/components/navigation.css'))
->toContain('[data-navigation-rail-header] [data-fab],')
->toContain('[data-navigation-rail-header] [data-fab]:hover {');
});
it('draws a destination in both shapes, with its count on the icon and at the end', function () {
$html = (string) $this->blade('<x-navigation-rail-item label="Inbox" icon="inbox" link="/inbox" active badge="12" />');