Draw a standard side sheet's first state without motion

Giving a closing standard sheet its room back made the root's inline
size a transition, with an `@starting-style` for the entry, so a sheet
that starts open grew in on every page load: its open state arrives
through Alpine, after the first paint of the closed root. Nothing should
move while a page loads.

The view now marks the root `data-md-drawer-settled` two frames after
the first `settle()` — once the state Alpine starts with has been
painted — and drawer.css gives the standard sheet's root and sheet no
transitions until then. The browser test loads a page with slowed motion
tokens and a sheet that starts open, and finds it standing at its full
width, shown, with nothing animating; closing it afterwards still
animates. It fails without the change in Chrome and Firefox and passes
in all three engines.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Andreas Reinhold / reini
2026-09-16 21:02:48 +02:00
co-authored by Claude Opus 5
parent 99c18e01d8
commit 1ccf0b639e
3 changed files with 59 additions and 4 deletions
+38 -2
View File
@@ -515,8 +515,8 @@ it('gives a closing standard side sheet\'s room back to the content beside it as
$column = "{$root}.previousElementSibling";
$toggle = "Array.from(document.querySelectorAll('#containment button')).find((button) => button.textContent.trim() === 'Show or hide the filters')";
// The example starts open, and grows in once Alpine opens it: its entry has run when the sheet
// stands at its full 400px and fully shown, with nothing on it still animating.
// The example starts open, and stands open from the first frame Alpine draws: full 400px, fully
// shown, nothing on it animating.
$page = containment()->resize(1000, 800)
->assertScript("{$root}.hasAttribute('data-md-open') && Math.round({$root}.getBoundingClientRect().width) === 400 && getComputedStyle({$sheet}).opacity === '1' && {$root}.getAnimations({ subtree: true }).length === 0");
@@ -565,6 +565,42 @@ it('gives a closing standard side sheet\'s room back to the content beside it as
->assertScript("{$root}.hasAttribute('data-md-open') && ! {$root}.hasAttribute('data-md-drawer-collapsed') && Math.abs({$root}.getBoundingClientRect().width - 400) < 1 && getComputedStyle({$sheet}).opacity === '1'");
});
it('draws a standard side sheet that starts open standing open, without growing it in on load', function () {
// Slow tokens, so a load-time entry would still be running when the page is first read.
Route::middleware('web')->get('/standard-sheet-load-probe', fn () => Blade::render(<<<'BLADE'
<!DOCTYPE html>
<html>
<head>
<x-theme-script />
@vite(config('livewire-material.showcase.vite'))
@livewireStyles
<style>:root { --md-sys-motion-spatial-default-duration: 3000ms; --md-sys-motion-effects-default-duration: 3000ms; }</style>
</head>
<body>
<x-row align="stretch" gap="space300" x-data="{ open: true }">
<x-stack style="flex: 1 1 0%; min-width: 0;">
<button type="button" id="toggle-sheet" x-on:click="open = ! open">Show or hide the filters</button>
</x-stack>
<x-drawer standard title="Filters">Filter the list</x-drawer>
</x-row>
@livewireScripts
</body>
</html>
BLADE));
$root = "document.querySelector('[data-md-drawer]')";
$page = visit('/standard-sheet-load-probe')->resize(1000, 800)->waitForEvent('networkidle')
->assertScript("typeof window.Alpine !== 'undefined' && {$root}.hasAttribute('data-md-drawer-settled')")
->assertScript("{$root}.hasAttribute('data-md-open') && Math.abs({$root}.getBoundingClientRect().width - 400) < 1")
->assertScript("{$root}.getAnimations({ subtree: true }).length === 0")
->assertScript("getComputedStyle({$root}.querySelector('[data-md-drawer-sheet]')).opacity === '1'");
// Settled, it still moves when someone closes it.
$page->script("document.getElementById('toggle-sheet').click()");
$page->assertScript("{$root}.getAnimations({ subtree: true }).length > 0");
});
it('opens a row\'s opener from a press anywhere on the row, but not from its own buttons', function () {
$page = containment();