Slide the navigation rail and fade its scrim out in Firefox too
A rail that was open over the page left it on `transition: … display … allow-discrete`: the compact adaptive rail's slide-out, the slide-out of a rail that hides when collapsed, and every rail scrim's fade. Firefox does not transition `display`, even with `allow-discrete` (Chrome 117 and Safari 18 do), so there the panel and the scrim vanished on the first frame. Unlike the sheets' scrims these are drawn by attribute rules on `data-md-open`, not `x-show`, so Alpine had nothing to hold. navigation.js now marks a rail that closes `data-md-closing` — `sheet` when the panel leaves the window, `scrim` when it stands in the layout again — and drops it once the panel's `translate` and the scrim's `opacity` transitions have finished (at once under reduced motion, or when the rail opens again). navigation-rail.css keeps what is leaving displayed, and a sliding panel in its open geometry, while the attribute is set, and no longer transitions `display` anywhere, so Chrome and Safari do not hold a second time. The view sets it from `x-effect`, beside the `x-bind` that drops `data-md-open`, so both attributes change in one flush: a `$watch` a microtask later let a style read in between settle the scrim as already hidden. The collapsed branches and `--md-navigation-rail-value` are untouched. NavigationTest samples each exit part-way in the page (the compact slide, the hide-when-collapsed slide, a modal rail's scrim) and checks it ends hidden; all three fail on main in Firefox and pass in Chrome, Firefox and Safari. They wait for the entry to finish first: Firefox creates a transition on its next refresh tick, so straight after a change its computed style already reads the end value. NavigationRailTest pins the holds and that no rule transitions `display`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
7db522826b
commit
92e560bef6
@@ -63,10 +63,11 @@ it('takes M3\'s optional divider and turns the container fill off', function ()
|
||||
|
||||
$css = ComponentStylesheet::read('navigation-rail');
|
||||
|
||||
// Neither reaches a rail open over a scrim, which is a surface over the page (N-22).
|
||||
expect($css->declarations('[data-md-navigation-rail][data-md-divider]:not([data-md-open]) > [data-md-navigation-rail-panel]'))
|
||||
// Neither reaches a rail open over a scrim, which is a surface over the page (N-22), nor one
|
||||
// sliding off the window as it closes.
|
||||
expect($css->declarations('[data-md-navigation-rail][data-md-divider]:not([data-md-open], [data-md-closing=\'sheet\']) > [data-md-navigation-rail-panel]'))
|
||||
->toBe(['border-inline-end' => '1px solid var(--md-sys-color-outline-variant)'])
|
||||
->and($css->declarations('[data-md-navigation-rail][data-md-fill=\'false\']:not([data-md-open]) > [data-md-navigation-rail-panel]'))
|
||||
->and($css->declarations('[data-md-navigation-rail][data-md-fill=\'false\']:not([data-md-open], [data-md-closing=\'sheet\']) > [data-md-navigation-rail-panel]'))
|
||||
->toBe(['background-color' => 'transparent'])
|
||||
// A collapsible rail is held to its collapsed width where M3 asks for a bar instead (N-24).
|
||||
->and($css->declarations('[data-md-navigation-rail=\'collapsible\']', ['@media (width < 600px)']))
|
||||
@@ -151,6 +152,31 @@ it('hides a collapsible or adaptive rail entirely when told to, and only those',
|
||||
* every branch sets, and for `--md-navigation-rail-value`, which each branch turns from `expanded`
|
||||
* to `collapsed` so an application's style query answers exactly when the rail's own shape does.
|
||||
*/
|
||||
it('holds a closing rail on screen for its exit rather than transitioning display', function () {
|
||||
$css = ComponentStylesheet::read('navigation-rail');
|
||||
|
||||
// Firefox cannot transition `display`, so no rule tries: the view sets `data-md-closing` beside
|
||||
// `data-md-open`, in the same flush, and navigation.js drops it once the exit has run.
|
||||
$discrete = collect($css->rules())
|
||||
->flatMap(fn (array $rule): array => array_values($rule['declarations']))
|
||||
->filter(fn (string $value): bool => str_contains($value, 'allow-discrete'));
|
||||
|
||||
expect($discrete)->toBeEmpty()
|
||||
->and((string) $this->blade('<x-navigation-rail mode="modal" />'))
|
||||
->toContain('x-bind:data-md-closing="closing"')
|
||||
->toContain('x-effect="settle(open)"')
|
||||
// The panel that leaves the window stays drawn, and in its open geometry, while it slides.
|
||||
->and($css->declarations("[data-md-navigation-rail][data-md-hide-when-collapsed][data-md-closing='sheet'] > [data-md-navigation-rail-panel]"))
|
||||
->toBe(['display' => 'flex'])
|
||||
->and($css->declarations("[data-md-navigation-rail='adaptive'][data-md-closing='sheet'] > [data-md-navigation-rail-panel]", ['@media (width < 600px)']))
|
||||
->toBe(['display' => 'flex'])
|
||||
->and($css->declarations("[data-md-navigation-rail]:is([data-md-open], [data-md-closing='sheet']) > [data-md-navigation-rail-panel]"))
|
||||
->toMatchArray(['position' => 'fixed', 'width' => 'var(--navigation-rail-expanded-width)'])
|
||||
// The scrim stays drawn for its fade whichever way the rail closes.
|
||||
->and($css->declarations('[data-md-navigation-rail][data-md-closing] > [data-md-navigation-rail-scrim]'))
|
||||
->toBe(['display' => 'block']);
|
||||
});
|
||||
|
||||
it('reproduces every branch of the old rail-collapsed variant for the rail\'s own width and its value', function () {
|
||||
$css = ComponentStylesheet::read('navigation-rail');
|
||||
$collapsed = ['width' => 'var(--navigation-rail-collapsed-width)', '--md-navigation-rail-value' => 'collapsed'];
|
||||
|
||||
Reference in New Issue
Block a user