Rewrite the bottom sheet without Tailwind

Plan step 36 (containment group): <x-bottom-sheet>'s class lists move
into resources/css/components/bottom-sheet.css, keyed on
data-md-bottom-sheet (data-md-open, data-md-standard) and
data-md-bottom-sheet-scrim/-probe/-panel (data-md-preset while
heights/snap gives it stops)/-handle/-grip/-announce/-body/-title/
-actions. x-transition's enter/leave classes are replaced the same way
as drawer.css: @starting-style + transition-behavior: allow-discrete
on the x-show-driven panel, the asymmetric open (spatial-default,
emphasized-decelerate) vs close (effects-default, emphasized-
accelerate) timing coming from the more specific open-state selector's
own transition-duration/-timing-function, which a CSS transition
always takes from the after-change style. data-md-preset adds the
height-between-stops transition (the spatial spring) alongside it,
independent of the open/close slide.

The drag handle (C-01, already fixed in the Tailwind-era markup this
replaces) renders the shared md-focus-ring and md-touch-target classes
instead of a hand-rolled ring: unlike the datepicker's day, its own
visible bar is not a smaller indicator drawn inside a bigger box those
classes cannot reach, so nothing here refines them further. Its 22px
vertical padding (SheetDefaults.kt's DragHandleVerticalPadding) is a
literal, matching alert.css's 12px for the same reason: 22 is not on
the measurement scale.

Hooks renamed data-drag-handle -> data-md-bottom-sheet-handle,
updated in resources/js/bottom-sheet.js and
tests/Browser/ContainmentTest.php; data-sheet -> data-md-drawer in
that test's comment. <x-menu sheet-at-compact> renders this component
unchanged; menu.css now imports bottom-sheet.css, and
tests/Feature/Components/MenuTest.php's stale Tailwind-class assertion
for the embedded sheet is replaced with a hook check. The two
sheet-at-compact browser tests in ActionsTest.php stay on
assertVisible(): the sheet is still x-show-driven (a deliberate choice
for this batch, keeping the existing modal/side-sheet/bottom-sheet
architecture and converting only their styling), so open still shows
as visibility rather than :popover-open; their comments no longer say
"not rewritten in this batch".

Imported from the Containment block of components.css. Browser tests
owed by docs/plans/material-3-browser-tests.md, added to
ContainmentTest.php but not run: dialog divider marks on scroll
(including that a nested dialog keeps its own marks), the full-screen
phone bar, separator always, no fade under reduced motion, the
scrolling body's inset focus ring; bottom sheet preset-height cycling
with its announcement and a drag settling on the nearest stop; the
standard side sheet from 840px without a scrim or a focus trap, modal
below it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
Andreas Reinhold / reini
2026-09-14 21:16:22 +02:00
co-authored by Claude Sonnet 5
parent 9dd527f303
commit 287340b066
10 changed files with 469 additions and 41 deletions
+6 -4
View File
@@ -799,8 +799,10 @@ it('filters a menu\'s items as its field is typed into, moves the highlight with
it('opens a sheet-at-compact menu below 600px, focused on its first item, and the popover from 600px', function () {
$trigger = '#menus button:has-text("Photo")';
// The sheet is <x-bottom-sheet>, still x-show-based (not rewritten in this batch), so its
// openness shows as visibility, not the Popover API's :popover-open.
// The sheet is <x-bottom-sheet>, rewritten (plan step 36) but still x-show-driven — its CSS
// now animates open/close through @starting-style and transition-behavior: allow-discrete
// rather than Alpine's x-transition classes, but x-show still owns the element's display, so
// its openness shows as visibility, not the Popover API's :popover-open.
$dialog = '[role="dialog"][aria-label="Photo actions"]';
$addToAlbum = '#menus [role="menuitem"]:has-text("Add to album")';
@@ -847,8 +849,8 @@ it('filters in the sheet too, and a Livewire render keeps it open with the field
$page->script('window.eval("Livewire.first().touch()")');
// The sheet is <x-bottom-sheet>, still x-show-based, so open shows as visible, not
// :popover-open.
// The sheet is <x-bottom-sheet>, still x-show-driven (see the note above), so open shows as
// visible, not :popover-open.
$page->assertSeeIn('#renders', '1')
->assertVisible('[role="dialog"][aria-label="Assign to"]')
->assertScript(focused("getAttribute('aria-label') === 'Find a person'"))