Plan step 36 (navigation group, second batch): <x-navigation-bar>'s and <x-navigation-bar-item>'s class lists move into resources/css/components/navigation-bar.css and navigation-bar-item.css, keyed on data-md-navigation-bar (data-md-tall, data-md-hide-on-scroll/ -hidden) and data-md-navigation-bar-item (data-md-active), both in material.components. The indicator's growing fill and its state layer, shared with the rail's item, move into a new navigation-item.css both files import — the day's own layer in datepicker.css is the precedent for keeping it out of the shared foundation classes: the element focused and pressed is the whole item, the layer drawn only on the smaller indicator or pill inside it, which md-state-layer cannot do and :focus-visible never matches. The wash colour moves from a dead on-surface base overridden by both items to a shared on-secondary- container declaration, and its opacities from literal 0.08/0.1 to state.css's own tokens — no visible change, since the numbers matched. Every size is px (16dp Tailwind quirks aside, this file had none); the bar's own item-count and container-query layout, N-08's label-medium fix and N-19's on-secondary-container wash already matched the audit, so only hooks, units and layer needed to change. The scaffold's hide-on-scroll offset rule (`--material-bottom-bar`, navigation-bar.css) stays unlayered: <x-scaffold> still publishes that variable with a Tailwind utility until its own rewrite, and a rule in any layer loses to it regardless of specificity — unlike the FAB overrides the rail commit moves into material.components, which only have to beat another material.components rule. navigation.css is not deleted yet (still Tailwind's for the rail); its "Navigation" comment in tailwind.css narrows as each stream leaves. navigation-bar.css is not in NavigationStylesheetsTest.php's dataset: its one unlayered rule breaks that test's "every block is material.components" assumption, so the same checks are in NavigationBarTest.php instead, the same reason ErrorPagesTest.php carries error-page.css's. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
67 lines
3.3 KiB
PHP
67 lines
3.3 KiB
PHP
{{-- M3 Expressive's flexible navigation bar: three to five destinations at the bottom of a
|
||
compact window.
|
||
|
||
<div class="fixed inset-x-0 bottom-0 z-30 medium:hidden">
|
||
<x-navigation-bar>
|
||
<x-navigation-bar-item label="Inbox" icon="inbox" link="/inbox" active badge="12" />
|
||
<x-navigation-bar-item label="Starred" icon="star" link="/starred" />
|
||
<x-navigation-bar-item label="Sent" icon="send" link="/sent" />
|
||
</x-navigation-bar>
|
||
</div>
|
||
|
||
The short bar, 64px tall in surface-container, with the bottom safe area added under it. On a
|
||
bar narrower than 600px (M3's compact window) each item is the icon in a 56×32 indicator over a
|
||
label-medium label, and the items share the width equally. From 600px (medium) icon and label
|
||
sit side by side in a 40px pill and the items gather in the middle, with the padding Compose's
|
||
Centered arrangement gives three to six items. Both follow the bar's own width (a container
|
||
query), so a bar in a narrow column keeps the compact items.
|
||
|
||
`tall` is M3's other container: 80px (NavigationBarTokens.TallContainerHeight) with the
|
||
vertical item layout at every width — icon over label, never side by side — for a bar whose
|
||
labels need the room. The short bar stays the default.
|
||
|
||
`hide-on-scroll` is M3's scrolling behaviour: the bar slides out of the window on a scroll
|
||
down and springs back on a scroll up, never before the first screenful has gone by, and never
|
||
while a snackbar, a bottom sheet or a drawer is on screen — those are anchored to the bar's
|
||
edge and would slide with it. Focus reaching the bar brings it back, which is as close as the
|
||
web gets to M3's "never hide it while a screen reader is active". Inside `<x-scaffold>`
|
||
`--material-bottom-bar` follows the bar down and up, so a `fab` button, the snackbar and the
|
||
page's bottom padding keep their distance from it rather than from where it was.
|
||
|
||
It does not position itself: wrap it in the element that pins it (`fixed inset-x-0 bottom-0`)
|
||
and hides it where a rail takes over. `<x-scaffold>` does both, and lifts the snackbar and a
|
||
`fab` button above it through `--material-bottom-bar`.
|
||
|
||
`label` names the landmark ("Main" by default); `tall` picks the 80px container;
|
||
`hide-on-scroll` lets it leave the window while the page scrolls down.
|
||
|
||
Values from androidx Compose Material 3 (Apache-2.0), androidx-main
|
||
27cf9a7d5788aa0f5f2d8b6699ce279560daf326: NavigationBarTokens.kt,
|
||
NavigationBarVerticalItemTokens.kt, NavigationBarHorizontalItemTokens.kt and
|
||
ShortNavigationBar.kt, all under
|
||
https://github.com/androidx/androidx/tree/androidx-main/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3
|
||
— the styles are resources/css/components/navigation-bar.css. --}}
|
||
|
||
@props([
|
||
'label' => null,
|
||
'tall' => false,
|
||
'hideOnScroll' => false,
|
||
])
|
||
|
||
<nav
|
||
aria-label="{{ $label ?? __('Main') }}"
|
||
data-md-navigation-bar
|
||
@if ($tall) data-md-tall @endif
|
||
@if ($hideOnScroll)
|
||
data-md-hide-on-scroll
|
||
x-data="materialNavigationBar"
|
||
x-bind:data-md-hidden="away ? '' : null"
|
||
x-on:focusin="show()"
|
||
@endif
|
||
{{ $attributes }}
|
||
>
|
||
<div data-md-navigation-bar-items>
|
||
{{ $slot }}
|
||
</div>
|
||
</nav>
|