Rewrite the showcase's Containment section without Tailwind

Plan step 38 (last batch): every example moves onto the layout
components, the md-* text classes and tokens. Wrapper divs that only
sized or grouped a demo (grid/list widths, the divider-and-collapse
stack, the dragged-card scope) become <x-grid>/<x-stack>/<x-row> with
an inline style where a specific px width still matters; a video
thumbnail's Tailwind gradient utility becomes an inline
background/color pair since each list-item's own colours differ. The
standard side sheet demo keeps M3's row-then-column breakpoint through
<x-row stack-below="expanded">, with a data-md-showcase-side-sheet-demo
hook that restores the row's own stretch alignment once it collapses
to a column (an explicit align="start", needed for the row layout,
would otherwise leave it shrink-wrapped).

Every id, data-md-* selector and visible string the Chromium
ContainmentTest reads (#containment, its dialog/sheet/card queries) is
unchanged; no demo content removed.

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-15 05:32:02 +02:00
co-authored by Claude Sonnet 5
parent 9e661836d6
commit c53c94174d
2 changed files with 72 additions and 53 deletions
+21
View File
@@ -32,6 +32,16 @@
* attribute, so a few widths below are plain `.showcase-*` classes instead of `data-md-showcase-*`
* hooks — the same "caller's class" mechanism any application would reach for, deliberately not
* named `md-*` since they are not part of the fixed set text.css declares.
*
* Batch 4 (the last: containment, carousel, bars, navigation, pages) adds the standard side
* sheet demo's own breakpoint (a `<x-row>` beats its own `stack-below` alignment back to `stretch`
* once collapsed to a column, which an `align` the row mode needs would otherwise leave
* shrink-wrapped), a bordered app-bar/toolbar frame (plain, `visible` for the search bar whose
* docked suggestions must not clip, `rounded` for the large-screen docked toolbar), a narrow
* scrollable-tabs box, and the navigation bar and rail demo frames (`bar`, `bar-wide` inside its
* own horizontal-scroll wrapper, `rail`, `rail-wide`) with their filler "page" and content panes.
* Every per-item carousel colour stays the caller's own inline `style`, the same mechanism as the
* colour swatch above.
*/
@layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility;
@@ -446,6 +456,17 @@
width: 100%;
overflow-x: auto;
}
/* Containment: the standard side sheet demo is a row from `expanded` (840px), M3's own
condition for a co-planar sheet, and a column below it — `<x-row>`'s own `stack-below`
stacks it there, but leaves the `align="start"` the row layout needs (so the sheet does not
stretch to the text column's height) in place, which would otherwise shrink-wrap both
columns instead of stacking them full width. */
@media (width < 840px) {
[data-md-showcase-side-sheet-demo] {
align-items: stretch;
}
}
}
/* A handful of call sites (<x-input>, <x-datepicker>, <x-slider>) forward only `class` and
@@ -1,7 +1,7 @@
@php
$examples = [
'Cards' => <<<'BLADE'
<div class="grid w-full gap-4 expanded:grid-cols-3">
<x-grid :columns="['compact' => 1, 'expanded' => 3]" gap="space200" style="width: 100%;">
<x-card title="Filled" subtitle="surface-container-highest">
The default card.
<x-slot:actions><x-button label="Open" /></x-slot:actions>
@@ -15,36 +15,36 @@
<x-card title="Outlined" subtitle="an outline-variant edge" variant="outlined" separator>
Quiet, on the surface itself.
</x-card>
</div>
</x-grid>
BLADE,
'A card that opens from anywhere on it' => <<<'BLADE'
<x-card variant="outlined" data-md-list-row class="w-full max-w-sm">
<a href="#containment" data-md-list-open class="type-title-md">holiday-photos.zip</a>
<p class="mt-1 text-on-surface-variant">248 MB · expires in 3 days</p>
<x-card variant="outlined" data-md-list-row style="width: 100%; max-width: 384px;">
<a href="#containment" data-md-list-open class="md-type-title-md">holiday-photos.zip</a>
<p class="md-ink-variant" style="margin-top: var(--md-sys-measurement-space50);">248 MB · expires in 3 days</p>
<x-slot:actions>
<x-button label="Copy link" icon="content_copy" x-on:click="materialToast('Link copied', { type: 'success' })" />
</x-slot:actions>
</x-card>
BLADE,
'A directly actionable card: the card is the tab stop' => <<<'BLADE'
<x-card variant="elevated" actionable role="link" title="contract.pdf" class="w-full max-w-sm">
<a href="#containment" data-md-list-open tabindex="-1" class="type-title-md">contract.pdf</a>
<p class="mt-1 text-on-surface-variant">1.2 MB · downloaded twice</p>
<x-card variant="elevated" actionable role="link" title="contract.pdf" style="width: 100%; max-width: 384px;">
<a href="#containment" data-md-list-open tabindex="-1" class="md-type-title-md">contract.pdf</a>
<p class="md-ink-variant" style="margin-top: var(--md-sys-measurement-space50);">1.2 MB · downloaded twice</p>
<x-slot:actions>
<x-button label="Copy link" icon="content_copy" x-on:click="materialToast('Link copied', { type: 'success' })" />
</x-slot:actions>
</x-card>
BLADE,
'A card being dragged' => <<<'BLADE'
<div x-data="{ dragged: false }" class="w-full max-w-sm space-y-4">
<x-stack gap="space200" x-data="{ dragged: false }" style="width: 100%; max-width: 384px;">
<x-button label="Pick it up or put it down" variant="tonal" x-on:click="dragged = ! dragged" />
<x-card variant="elevated" title="holiday-photos.zip" subtitle="248 MB" x-bind:data-md-dragged="dragged || null">
Elevation 4 and the 16% state layer, for as long as the application says the card is being carried.
</x-card>
</div>
</x-stack>
BLADE,
'Lists' => <<<'BLADE'
<div class="grid w-full gap-6 medium:grid-cols-2">
<x-grid :columns="['compact' => 1, 'medium' => 2]" gap="space300" style="width: 100%;">
<x-list dividers label="Files">
<x-list-item title="holiday-photos.zip" description="248 MB" icon="folder_zip" trailing="3 days" />
<x-list-item title="contract.pdf" overline="Password protected" description="1.2 MB · downloaded twice" icon="picture_as_pdf" trailing="1 hour" />
@@ -59,35 +59,35 @@
</x-list-item>
<x-list-item title="Dan Fischer" description="Invitation withdrawn" avatar="DF" link="#containment" disabled />
</x-list>
</div>
</x-grid>
BLADE,
'A list to choose from' => <<<'BLADE'
<x-list selectable label="Expiry" class="w-full max-w-sm">
<x-list selectable label="Expiry" style="width: 100%; max-width: 384px;">
<x-list-item title="One hour" :selected="false" />
<x-list-item title="Three days" :selected="true" />
<x-list-item title="Thirty days" :selected="false" />
</x-list>
BLADE,
'A list with leading video' => <<<'BLADE'
<x-list dividers label="Clips" class="w-full max-w-md">
<x-list dividers label="Clips" style="width: 100%; max-width: 448px;">
<x-list-item title="Sunrise over the lake" description="2:14 · 48 MB">
<x-slot:video>
<div class="grid place-items-center bg-linear-to-br from-primary-container to-tertiary-container text-on-primary-container">
<x-icon name="play_circle" class="size-6" />
<div style="display: grid; place-items: center; background: linear-gradient(to bottom right, var(--md-sys-color-primary-container), var(--md-sys-color-tertiary-container)); color: var(--md-sys-color-on-primary-container);">
<x-icon name="play_circle" />
</div>
</x-slot:video>
</x-list-item>
<x-list-item overline="Draft" title="Walking the old town" description="Uploaded yesterday · 7:48">
<x-slot:video>
<div class="grid place-items-center bg-linear-to-br from-secondary-container to-primary-container text-on-secondary-container">
<x-icon name="play_circle" class="size-6" />
<div style="display: grid; place-items: center; background: linear-gradient(to bottom right, var(--md-sys-color-secondary-container), var(--md-sys-color-primary-container)); color: var(--md-sys-color-on-secondary-container);">
<x-icon name="play_circle" />
</div>
</x-slot:video>
</x-list-item>
</x-list>
BLADE,
'Dividers and collapse' => <<<'BLADE'
<div class="w-full space-y-4">
<x-stack gap="space200" style="width: 100%;">
<x-collapse title="How long do links last?" icon="schedule" open>
Until the expiry you chose, from one hour to thirty days.
</x-collapse>
@@ -95,33 +95,33 @@
<x-collapse title="Can recipients upload files?" variant="filled">
No. They can only download what you shared.
</x-collapse>
<div class="flex h-10 items-center gap-4"><span>Left</span><x-divider vertical /><span>Right</span></div>
</div>
<x-row gap="space200" align="center" style="height: 40px;"><span>Left</span><x-divider vertical /><span>Right</span></x-row>
</x-stack>
BLADE,
'A divider with a subheader' => <<<'BLADE'
<div class="w-full max-w-md">
<div style="width: 100%; max-width: 448px;">
<x-divider text="Today" />
<x-list label="Today">
<x-list-item title="holiday-photos.zip" description="Shared with 3 people" icon="folder_zip" />
<x-list-item title="contract.pdf" description="Downloaded twice" icon="picture_as_pdf" />
</x-list>
<x-divider text="Earlier this week" class="mt-2" />
<x-divider text="Earlier this week" style="margin-top: var(--md-sys-measurement-space100);" />
<x-list label="Earlier this week">
<x-list-item title="minutes.docx" description="Expired" icon="description" />
</x-list>
</div>
BLADE,
'Collapse bound to a property' => <<<'BLADE'
<div x-data="{ advanced: false }" class="w-full space-y-4">
<div class="flex flex-wrap items-center gap-4">
<x-stack gap="space200" x-data="{ advanced: false }" style="width: 100%;">
<x-row wrap align="center" gap="space200">
<x-button label="Open" variant="tonal" x-on:click="advanced = true" />
<x-button label="Close" variant="tonal" x-on:click="advanced = false" />
<span class="type-body-md text-on-surface-variant">advanced: <span x-text="advanced"></span></span>
</div>
<span class="md-type-body-md md-ink-variant">advanced: <span x-text="advanced"></span></span>
</x-row>
<x-collapse title="Advanced settings" icon="tune" variant="filled" x-model="advanced">
Bound with x-model here. In a Livewire view, wire:model="advanced" binds a boolean property the same way, and the page arrives with it open or closed as the property is.
</x-collapse>
</div>
</x-stack>
BLADE,
'Dialogs' => <<<'BLADE'
<div x-data="{ open: false }">
@@ -157,7 +157,7 @@
<div x-data="{ open: false }">
<x-button label="Long body" variant="tonal" x-on:click="open = true" />
<x-modal title="Terms of the share link" subtitle="Scroll them: a rule appears under the headline once the text leaves its top, and the one over the buttons goes at its end.">
<div class="space-y-4">
<x-stack gap="space200">
<p>A share link opens the files you chose, and only those. Adding a file to the folder later does not add it to a link you have already sent; make a new link for it.</p>
<p>Anyone who has the link can open it until it expires. Forwarding the link forwards that access, so send it to the people who need it and to nobody else.</p>
<p>A password, when you set one, is asked for every time the link is opened. Send it separately from the link, by another channel, so one intercepted message is not enough.</p>
@@ -168,7 +168,7 @@
<p>Previews are generated for images, PDFs and plain text. Other types show their name, size and an icon.</p>
<p>Deleting a file you shared removes it from every link that holds it. People who open such a link see the files that are left.</p>
<p>These terms apply to every link you create from now on. Links you created before keep the terms they were made under.</p>
</div>
</x-stack>
<x-slot:actions>
<x-button label="Decline" x-on:click="close()" />
<x-button label="Accept" x-on:click="close()" />
@@ -188,25 +188,23 @@
</div>
BLADE,
'A standard side sheet: co-planar from expanded, modal below' => <<<'BLADE'
<div x-data="{ open: true }" class="w-full">
<div class="expanded:flex expanded:items-start expanded:gap-6">
<div class="min-w-0 flex-1 space-y-4">
<x-button label="Show or hide the filters" variant="tonal" x-on:click="open = ! open" />
<p class="type-body-md text-on-surface-variant">
From <code>expanded</code> (840px) the sheet beside this text is co-planar: no scrim, no focus trap, flat on the surface, divided from this column by a rule. Narrow the window and the same sheet becomes the modal one.
</p>
</div>
<x-row data-md-showcase-side-sheet-demo align="start" gap="space300" stack-below="expanded" x-data="{ open: true }">
<x-stack gap="space200" style="flex: 1 1 0%; min-width: 0;">
<x-button label="Show or hide the filters" variant="tonal" x-on:click="open = ! open" />
<p class="md-type-body-md md-ink-variant">
From <code>expanded</code> (840px) the sheet beside this text is co-planar: no scrim, no focus trap, flat on the surface, divided from this column by a rule. Narrow the window and the same sheet becomes the modal one.
</p>
</x-stack>
<x-drawer standard title="Filters" subtitle="Narrow the list down">
<x-list selectable label="Expiry">
<x-list-item title="One hour" :selected="false" />
<x-list-item title="Three days" :selected="true" />
<x-list-item title="Thirty days" :selected="false" />
</x-list>
<x-slot:actions><x-button label="Apply" variant="filled" /></x-slot:actions>
</x-drawer>
</div>
</div>
<x-drawer standard title="Filters" subtitle="Narrow the list down">
<x-list selectable label="Expiry">
<x-list-item title="One hour" :selected="false" />
<x-list-item title="Three days" :selected="true" />
<x-list-item title="Thirty days" :selected="false" />
</x-list>
<x-slot:actions><x-button label="Apply" variant="filled" /></x-slot:actions>
</x-drawer>
</x-row>
BLADE,
'Sheets' => <<<'BLADE'
<div x-data="{ open: false }">
@@ -235,7 +233,7 @@
<div x-data="{ open: false }">
<x-button label="Bottom sheet with preset heights" variant="tonal" x-on:click="open = true" />
<x-bottom-sheet title="Nearby places" snap>
<p class="type-body-md text-on-surface-variant">Press the drag handle, or focus it and press Enter, to move to the next height; from the last it closes. Dragging it settles on the nearest.</p>
<p class="md-type-body-md md-ink-variant">Press the drag handle, or focus it and press Enter, to move to the next height; from the last it closes. Dragging it settles on the nearest.</p>
<x-list>
<x-list-item title="Hafen" description="240 m · open until 23:00" icon="location_on" />
<x-list-item title="Stadtbibliothek" description="600 m · closes at 18:00" icon="location_on" />
@@ -247,10 +245,10 @@
];
@endphp
<section id="containment" class="scroll-mt-24 space-y-6">
<h2 class="type-headline-md">Containment</h2>
<x-livewire-material::stack as="section" id="containment" gap="space300">
<h2 class="md-type-headline-md">Containment</h2>
<p class="max-w-3xl type-body-md text-on-surface-variant">
<p class="md-type-body-md md-ink-variant">
<code>&lt;x-card&gt;</code>, <code>&lt;x-list&gt;</code> and <code>&lt;x-list-item&gt;</code>, <code>&lt;x-divider&gt;</code>, <code>&lt;x-collapse&gt;</code>,
<code>&lt;x-modal&gt;</code>, <code>&lt;x-drawer&gt;</code> and <code>&lt;x-bottom-sheet&gt;</code>.
</p>
@@ -258,4 +256,4 @@
@foreach ($examples as $title => $code)
<x-showcase::example :$title :$code />
@endforeach
</section>
</x-livewire-material::stack>