Files
livewire-material/resources/css/components/navigation-bar-item.css
T
Andreas Reinhold / reiniandClaude Sonnet 5 63d421ccb6 Draw the navigation bar and bar item without Tailwind
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
2026-09-15 00:08:34 +02:00

152 lines
6.0 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* `<x-navigation-bar-item>`: one destination in an `<x-navigation-bar>`
* (NavigationBarVerticalItemTokens.kt, NavigationBarHorizontalItemTokens.kt, androidx Compose
* Material 3, Apache-2.0).
*
* [data-md-navigation-bar-item] data-md-active; the link or button itself
* [data-md-navigation-pill] icon and label; becomes the indicator from 600px
* [data-md-navigation-indicator] the 56×32 indicator around the icon below 600px
* [data-md-navigation-icon] the floating badge's anchor (navigation-item.css)
* [data-md-navigation-label]
*
* Below 600px (the bar's own width — a container query, so a bar in a narrow column keeps this
* layout) the icon sits in a 56×32 `CornerFull` indicator over a label-medium label, both equally
* wide. From 600px icon and label share a 40px horizontal indicator with 16px leading and
* trailing space; the label stays label-medium — `NavigationBarTokens.LabelTextFont` is the bar's
* only label token, and Compose's `ShortNavigationBarItem` passes it for both icon positions (the
* *rail's* horizontal item is label-large, a different component's token; N-08). An active item is
* secondary-container behind on-secondary-container (icon and, from 600px, label); its indicator's
* fill is a background image so it can grow from its centre (navigation-item.css) rather than
* stretch the icon.
*
* The indicator's growing fill and its state layer are shared with the rail's item
* (navigation-item.css); only this file's focus ring and the display swap between the two
* indicator shapes are the bar's own.
*/
@layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility;
@import './icon.css';
@import './badge.css';
@import './navigation-item.css';
@layer material.components {
[data-md-navigation-bar-item] {
--navigation-layer: 0;
position: relative;
display: flex;
flex: 1 1 0%;
min-width: 0;
align-items: center;
justify-content: center;
padding-block: 6px;
color: var(--md-sys-color-on-surface-variant);
text-decoration: none;
cursor: pointer;
outline: none;
-webkit-tap-highlight-color: transparent;
}
[data-md-navigation-bar-item][data-md-active] {
color: var(--md-sys-color-secondary);
}
[data-md-navigation-bar-item] [data-md-navigation-pill] {
display: flex;
min-width: 0;
max-width: 100%;
flex-direction: column;
align-items: center;
gap: 4px;
border-radius: var(--md-sys-shape-corner-full);
font: var(--md-sys-typescale-label-md);
letter-spacing: var(--md-sys-typescale-label-md-tracking);
}
[data-md-navigation-bar-item] [data-md-navigation-label] {
max-width: 100%;
padding-inline: 4px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
[data-md-navigation-bar-item] [data-md-navigation-indicator] {
position: relative;
isolation: isolate;
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: 56px;
height: 32px;
border-radius: var(--md-sys-shape-corner-full);
}
/* Vertical layout (below 600px, or a tall bar at any width): the indicator fills behind the
icon; the pill draws no layer of its own. */
[data-md-navigation-bar-item][data-md-active] [data-md-navigation-indicator] {
background-image: linear-gradient(var(--md-sys-color-secondary-container), var(--md-sys-color-secondary-container));
color: var(--md-sys-color-on-secondary-container);
}
[data-md-navigation-bar-item] [data-md-navigation-pill]::before {
display: none;
}
[data-md-navigation-bar-item]:focus-visible [data-md-navigation-indicator] {
outline: 3px solid var(--md-sys-color-secondary);
outline-offset: 2px;
}
/* Horizontal layout, from 600px: the pill itself fills and takes the layer; the indicator
stops drawing either. Only the short bar (a tall bar keeps the vertical layout). */
@container (width >= 600px) {
[data-md-navigation-bar]:not([data-md-tall]) [data-md-navigation-bar-item] {
min-width: max-content;
}
[data-md-navigation-bar]:not([data-md-tall]) [data-md-navigation-bar-item] [data-md-navigation-pill] {
position: relative;
isolation: isolate;
flex-direction: row;
height: 40px;
padding-inline: 16px;
}
[data-md-navigation-bar]:not([data-md-tall]) [data-md-navigation-bar-item] [data-md-navigation-label] {
padding-inline: 0;
}
[data-md-navigation-bar]:not([data-md-tall]) [data-md-navigation-bar-item][data-md-active] {
color: var(--md-sys-color-on-secondary-container);
}
[data-md-navigation-bar]:not([data-md-tall]) [data-md-navigation-bar-item][data-md-active] [data-md-navigation-pill] {
background-image: linear-gradient(var(--md-sys-color-secondary-container), var(--md-sys-color-secondary-container));
}
[data-md-navigation-bar]:not([data-md-tall]) [data-md-navigation-bar-item][data-md-active] [data-md-navigation-indicator] {
background-image: none;
}
[data-md-navigation-bar]:not([data-md-tall]) [data-md-navigation-bar-item] [data-md-navigation-pill]::before {
display: block;
}
[data-md-navigation-bar]:not([data-md-tall]) [data-md-navigation-bar-item] [data-md-navigation-indicator]::before {
display: none;
}
[data-md-navigation-bar]:not([data-md-tall]) [data-md-navigation-bar-item]:focus-visible [data-md-navigation-indicator] {
outline: none;
}
[data-md-navigation-bar]:not([data-md-tall]) [data-md-navigation-bar-item]:focus-visible [data-md-navigation-pill] {
outline: 3px solid var(--md-sys-color-secondary);
outline-offset: 2px;
}
}
}