Draw the FAB without Tailwind

Plan step 36. <x-fab> renders data-md-fab with data-md-size,
data-md-color, data-md-variant, data-md-extended and, collapsing on
scroll, data-md-collapse-on-scroll with a bound data-md-collapsed; it
passes its glyph's size to <x-icon>. fab.css draws FabBaseline/Medium/
LargeTokens and ExtendedFab*Tokens per size, the container and filled
colours, elevation 3 and 4 on hover, the state layer and focus ring,
and the collapse morph that leaves actions.css.

data-fab becomes data-md-fab, also in navigation.css (the rail flattens
a nested FAB) and toolbar.css (a docked toolbar's FAB), with their tests.
The actions browser test gains the owed collapse-on-scroll test.

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 15:06:45 +02:00
co-authored by Claude Opus 5
parent 2a4dcead3d
commit 1cf4f16c95
11 changed files with 357 additions and 146 deletions
@@ -132,14 +132,14 @@ it('hides a collapsible or adaptive rail entirely when told to, and only those',
});
it('flattens a FAB nested in the rail header and morphs its label', function () {
// Both rules hang off `data-fab` on <x-fab>'s root, and both are unlayered, because what they
// Both rules hang off `data-md-fab` on <x-fab>'s root, and both are unlayered, because what they
// beat — the FAB's shadow, its gap, an extended FAB's minimum width — are utilities.
expect(file_get_contents(__DIR__.'/../../../resources/css/components/navigation.css'))
// A nested FAB rests at elevation 0, not the 3 a standalone one has (N-03).
->toContain('[data-navigation-rail-header] [data-fab],')
->toContain('[data-navigation-rail-header] [data-fab]:hover {')
->toContain('[data-navigation-rail-header] [data-md-fab],')
->toContain('[data-navigation-rail-header] [data-md-fab]:hover {')
// One FAB whose label springs shut, not two swapped by display (N-23).
->toContain('[data-navigation-rail-header] [data-fab] > span {')
->toContain('[data-navigation-rail-header] [data-md-fab] > span {')
->toMatch('/@variant rail-collapsed \{\s+min-width: 0;\s+aspect-ratio: 1;\s+gap: 0;/');
});