Let a rail hide when collapsed instead of narrowing
Plan step 25 (navigation Missing): M3's "Expanded behavior | Hide when collapsed" was only implicit below `medium` in the adaptive rail. `<x-navigation-rail hide-when-collapsed>` (collapsible and adaptive rails) takes the rail out of the layout when it is collapsed; `$store.rail.show()` from an app-bar menu button brings it back expanded over a scrim, sliding in, and its own menu button docks it again. It does not reach the bands where the window, not the visitor, collapses a rail (below `medium` for collapsible, `medium` for adaptive), since M3's collapsed rail may never hide. Every `rail-collapsed` branch now stops while the rail is open. `<x-app-shell hide-rail-when-collapsed>` exposes it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
co-authored by
Claude Opus 5
parent
a5acbe7f6b
commit
9c047a8fb1
+63
-16
@@ -13,12 +13,12 @@
|
||||
* button opens it over a scrim (`show()`), and Escape, the scrim or leaving the page closes it
|
||||
* (`hide()`). It is never remembered.
|
||||
*
|
||||
* `materialNavigationRail` is one rail's view of the store for its `mode` — see
|
||||
* resources/views/components/navigation-rail.blade.php.
|
||||
* `materialNavigationRail` is one rail's view of the store for its `mode` and whether it hides
|
||||
* when collapsed — see resources/views/components/navigation-rail.blade.php.
|
||||
*
|
||||
* `materialNavigationBar` is `<x-navigation-bar hide-on-scroll>` — see the same file's sibling.
|
||||
*/
|
||||
import { from } from './breakpoints.js'
|
||||
import { from, upTo } from './breakpoints.js'
|
||||
|
||||
/*
|
||||
* The active indicator grows out of its centre when a page arrives through wire:navigate. The
|
||||
@@ -96,14 +96,29 @@ document.addEventListener('alpine:init', () => {
|
||||
// A destination chosen in the modal rail leaves the page; the next one starts with it shut.
|
||||
document.addEventListener('livewire:navigating', () => window.Alpine.store('rail').hide())
|
||||
|
||||
window.Alpine.data('materialNavigationRail', (mode) => ({
|
||||
window.Alpine.data('materialNavigationRail', (mode, hideWhenCollapsed = false) => ({
|
||||
wide: mode === 'adaptive' ? from('expanded').matches : false,
|
||||
roomy: mode === 'adaptive' ? from('large').matches : false,
|
||||
tight: mode === 'collapsible' ? upTo('medium').matches : false,
|
||||
queries: [],
|
||||
listeners: [],
|
||||
|
||||
init() {
|
||||
if (mode !== 'adaptive') {
|
||||
// Below `medium` a collapsible rail is held at its collapsed width whatever the
|
||||
// visitor chose, so `hide-when-collapsed` does not reach it there.
|
||||
// A drawer left open as the window narrows past it is shut, as the adaptive
|
||||
// rail's is below, or it would spring open again the next time the rail is away.
|
||||
if (mode === 'collapsible' && hideWhenCollapsed) {
|
||||
this.watch(upTo('medium'), (matches) => {
|
||||
this.tight = matches
|
||||
|
||||
if (matches) {
|
||||
this.$store.rail.hide()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -136,17 +151,9 @@ document.addEventListener('alpine:init', () => {
|
||||
this.queries.forEach((query, index) => query.removeEventListener('change', this.listeners[index]))
|
||||
},
|
||||
|
||||
/** Whether this rail expands over a scrim rather than in the layout. */
|
||||
get modal() {
|
||||
return mode === 'modal' || (mode === 'adaptive' && !this.wide)
|
||||
},
|
||||
|
||||
get open() {
|
||||
return this.modal && this.$store.rail.open
|
||||
},
|
||||
|
||||
get expanded() {
|
||||
if (this.open || mode === 'expanded') {
|
||||
/** What this rail's mode and the visitor's choice make of it, before anything opens it. */
|
||||
get standing() {
|
||||
if (mode === 'expanded') {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -163,9 +170,49 @@ document.addEventListener('alpine:init', () => {
|
||||
return mode === 'collapsible'
|
||||
},
|
||||
|
||||
/** Whether the mode or the window leaves no room for an expanded rail in the layout. */
|
||||
get cramped() {
|
||||
return mode === 'modal' || (mode === 'adaptive' && !this.wide)
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether the rail has left the layout altogether — `hide-when-collapsed`, once the
|
||||
* visitor collapses it. Not in the two bands where it is the window size class and not the
|
||||
* visitor that collapses a rail: M3's "collapsed rail may not hide". The same two numbers
|
||||
* are in resources/css/components/navigation.css.
|
||||
*/
|
||||
get away() {
|
||||
if (!hideWhenCollapsed || this.cramped || this.standing) {
|
||||
return false
|
||||
}
|
||||
|
||||
return mode === 'adaptive' ? this.wide : !this.tight
|
||||
},
|
||||
|
||||
/** Whether this rail expands over a scrim rather than in the layout. */
|
||||
get modal() {
|
||||
// A rail that is away has nothing left in the layout to expand, so the menu button
|
||||
// that brings it back — the app bar's — opens it over the page.
|
||||
return this.cramped || this.away
|
||||
},
|
||||
|
||||
get open() {
|
||||
return this.modal && this.$store.rail.open
|
||||
},
|
||||
|
||||
get expanded() {
|
||||
return this.open || this.standing
|
||||
},
|
||||
|
||||
/** The rail's own menu button: open or close the modal, or collapse and expand in place. */
|
||||
menu() {
|
||||
if (this.modal) {
|
||||
if (this.open && this.away) {
|
||||
// This rail is only over the page because it hid itself, so the button docks it
|
||||
// back into the layout — the same "expand" it means on a rail that is standing
|
||||
// there. Expanding drops `away`, which closes the drawer behind it.
|
||||
this.$store.rail.expand()
|
||||
this.$store.rail.hide()
|
||||
} else if (this.modal) {
|
||||
this.$store.rail.open ? this.$store.rail.hide() : this.$store.rail.show()
|
||||
} else {
|
||||
// `set`, not `toggle`: with nothing stored the store's `collapsed` is only
|
||||
|
||||
Reference in New Issue
Block a user