Give a closing standard side sheet's room back as it leaves

From `expanded` a standard side sheet sits in the layout beside the
content, and the view took it out of the layout the moment it closed:
`data-md-drawer-collapsed` (`display: none` on the root) followed `! open`
at once, so its fade was never seen and the content beside it took the
sheet's width, and the gap, in one jump — in every engine. M3's side
sheets: opening a standard sheet shrinks the body beside it, and closing
gives the room back.

drawer.css: the standard root is a clipping flex box whose `inline-size`
springs between none and the sheet's width, with a negative margin as
wide as its flex parent's gap (`--md-drawer-gap`), on the sheet's own
exit and entry timings; the sheet keeps its width at the root's far edge,
so it is uncovered from its inner edge while it fades. drawer.blade.php:
`settle()`, from `x-effect`, measures the gap on each change and holds
the collapse (`closing`) for the root's and the sheet's closing
durations, read a frame on; reopening lets a pending end go by. The
binding reads `collapsed`, which only `settle()` and the window's width
write: a binding reading `open` ran before `settle()` in the same flush
and, already queued, did not run again once `closing` changed.

ContainmentTest closes the showcase's sheet at 1000px and samples, in the
page, for the root part-way to none while the column beside it has grown
part of the way, then checks the collapse, the column at the row's full
width, and a reopen part-way through the exit ending fully open; it fails
on the previous code in Chrome, Firefox and Safari. OverlayTest pins the
root's declarations and the view's bindings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Andreas Reinhold / reini
2026-09-16 21:00:23 +02:00
co-authored by Claude Opus 5
parent db6023bf80
commit 99c18e01d8
4 changed files with 172 additions and 7 deletions
+16
View File
@@ -194,6 +194,8 @@ it('puts a side sheet\'s actions on the left, in M3\'s 72dp row', function () {
it('slides a side sheet in from either edge', function () {
expect((string) $this->blade('<x-drawer title="Details" with-close-button>Body</x-drawer>'))
->toContain('x-trap.inert.noscroll="open && ! wide"')
->toContain('x-bind:data-md-drawer-collapsed="collapsed ? \'\' : null"')
->toContain('x-effect="settle(open)"')
->toContain('data-md-side="end"')
->toContain('data-md-drawer-sheet')
->toContain('role="dialog"')
@@ -229,6 +231,8 @@ it('is M3\'s standard side sheet from expanded, and the modal one below', functi
->toContain('--sheet-width: min(400px, 400px)')
->toContain("matchMedia('(width >= 840px)')")
->toContain('x-trap.inert.noscroll="open && ! wide"')
->toContain('x-bind:data-md-drawer-collapsed="collapsed ? \'\' : null"')
->toContain('x-effect="settle(open)"')
->toContain('aria-label="Close"')
->and((string) $this->blade('<x-drawer standard side="start" width="30rem">Body</x-drawer>'))
->toContain('data-md-side="start"')
@@ -241,6 +245,18 @@ it('is M3\'s standard side sheet from expanded, and the modal one below', functi
expect($css->has('[data-md-drawer][data-md-standard]', $expanded))->toBeTrue()
->and($css->declarations('[data-md-drawer][data-md-standard][data-md-drawer-collapsed]', $expanded))->toBe(['display' => 'none'])
// Closing gives the room back as the sheet leaves (M3's side sheets, "Adaptive"): the root's
// inline size and the parent's gap spring to none, and the collapse waits for that exit.
->and($css->declarations('[data-md-drawer][data-md-standard]', $expanded))->toMatchArray([
'overflow' => 'clip',
'inline-size' => '0',
'margin-inline-start' => 'calc(-1 * var(--md-drawer-gap, 0px))',
'transition-property' => 'inline-size, margin-inline',
])
->and($css->declarations('[data-md-drawer][data-md-standard][data-md-open]', $expanded))->toMatchArray([
'inline-size' => 'min(var(--sheet-width), calc(100vw - 64px))',
'margin-inline' => '0',
])
// The old view's `expanded:hidden` on a standard sheet's scrim.
->and($css->declarations('[data-md-drawer][data-md-standard] > [data-md-drawer-scrim]', $expanded))->toBe(['display' => 'none'])
->and($css->declarations('[data-md-drawer][data-md-standard] > [data-md-drawer-sheet]', $expanded))->toHaveKey('box-shadow', 'none')