Write the showcase examples' layout tags as an application does

Plan step 38 review: nine sections' examples wrapped their components
in <x-livewire-material::stack>, ::row and ::grid (148 tags) beside an
unprefixed <x-button>, while bars, containment and the layout pages
wrote <x-stack>. The code sample is what an application copies, and
the example component rewrites only unprefixed tags to a configured
prefix, so the namespaced ones taught a second form and escaped it.
Every example now writes <x-stack>, <x-row> and <x-grid>; a test
rejects a namespaced tag inside an example heredoc.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
Andreas Reinhold / reini
2026-09-15 06:11:08 +02:00
co-authored by Claude Opus 5
parent 5fb8fc6b8f
commit 3fb0a404db
10 changed files with 167 additions and 148 deletions
@@ -77,7 +77,7 @@
</x-button-group>
BLADE,
'A connected group that owns its selection' => <<<'BLADE'
<x-livewire-material::stack gap="space300" x-data="{ view: 'week', marks: ['bold'] }">
<x-stack gap="space300" x-data="{ view: 'week', marks: ['bold'] }">
<x-button-group connected selection="single" required label="View" x-model="view">
<x-button label="Day" value="day" variant="tonal" :selected="false" />
<x-button label="Week" value="week" variant="tonal" :selected="true" />
@@ -94,7 +94,7 @@
View: <code x-text="view"></code> · marks: <code x-text="marks.join(', ') || 'none'"></code>.
The shape follows at once; the colours come from each button's own <code>:selected</code>, which a Livewire render brings back.
</p>
</x-livewire-material::stack>
</x-stack>
BLADE,
'Square groups (hold a button down)' => <<<'BLADE'
<x-button-group label="Square standard" size="md" shape="square">
@@ -109,16 +109,16 @@
<x-button icon="format_underlined" aria-label="Underline" variant="tonal" :selected="false" />
</x-button-group>
<x-livewire-material::stack x-data="{ density: 'cosy' }">
<x-stack x-data="{ density: 'cosy' }">
<x-group label="Density" name="showcase-density" shape="square" x-model="density" inline :options="[
['id' => 'compact', 'name' => 'Compact'],
['id' => 'cosy', 'name' => 'Cosy'],
['id' => 'roomy', 'name' => 'Roomy'],
]" />
</x-livewire-material::stack>
</x-stack>
BLADE,
'A choice as a connected group' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'medium' => 2]" gap="space300" x-data="{ theme: 'system', days: ['mon'] }">
<x-grid :columns="['compact' => 1, 'medium' => 2]" gap="space300" x-data="{ theme: 'system', days: ['mon'] }">
<x-group label="Theme" name="showcase-theme" x-model="theme" :options="[
['id' => 'light', 'name' => 'Light', 'icon' => 'light_mode'],
['id' => 'dark', 'name' => 'Dark', 'icon' => 'dark_mode'],
@@ -131,7 +131,7 @@
['id' => 'wed', 'name' => 'Wed'],
['id' => 'thu', 'name' => 'Thu', 'disabled' => true],
]" />
</x-livewire-material::grid>
</x-grid>
BLADE,
'Split buttons' => <<<'BLADE'
<x-split-button label="Download all" icon="download" menu-label="Download options">
@@ -1,17 +1,17 @@
@php
$examples = [
'Assist chips' => <<<'BLADE'
<x-livewire-material::row gap="space100" wrap align="center" x-data>
<x-row gap="space100" wrap align="center" x-data>
<x-chip label="Add to calendar" icon="event" x-on:click="materialToast('Added to your calendar')" />
<x-chip label="Directions" icon="directions" link="#chips" />
<x-chip label="Share" icon="share" elevated tooltip="Share this file" />
<x-chip label="Material 3 guidelines" icon-right="open_in_new" link="https://m3.material.io/components/chips" external />
<x-chip label="Unavailable" icon="block" disabled />
<x-chip label="Unavailable" icon="block" elevated disabled />
</x-livewire-material::row>
</x-row>
BLADE,
'Filter chips' => <<<'BLADE'
<x-livewire-material::stack gap="space300" x-data="{ kinds: ['photos'] }">
<x-stack gap="space300" x-data="{ kinds: ['photos'] }">
<x-chip-set label="File types" hint="Show only these kinds of file">
<x-chip type="filter" label="Photos" value="photos" x-model="kinds" />
<x-chip type="filter" label="Documents" value="documents" x-model="kinds" />
@@ -25,10 +25,10 @@
<x-chip type="filter" label="Expiring" name="expiring" icon-right="arrow_drop_down" />
<x-chip type="filter" label="Archived" name="archived" :selected="true" disabled />
</x-chip-set>
</x-livewire-material::stack>
</x-stack>
BLADE,
'Input chips' => <<<'BLADE'
<x-livewire-material::stack gap="space300" x-data="{ recipients: ['anna@example.com', 'ben@example.com', 'chiara@example.com'] }">
<x-stack gap="space300" x-data="{ recipients: ['anna@example.com', 'ben@example.com', 'chiara@example.com'] }">
<x-chip-set label="Recipients" hint="Backspace or Delete removes the focused chip">
<template x-for="recipient in recipients" :key="recipient">
<x-chip type="input" icon="mail" removable remove="recipients = recipients.filter((other) => other !== recipient)"><span x-text="recipient"></span></x-chip>
@@ -41,7 +41,7 @@
<x-chip type="input" label="contract.pdf" icon="picture_as_pdf" x-on:click="materialToast('contract.pdf')" />
<x-chip type="input" label="Chiara Rossi" avatar="CR" removable disabled />
</x-chip-set>
</x-livewire-material::stack>
</x-stack>
BLADE,
'Suggestion chips' => <<<'BLADE'
<x-chip-set label="Suggested replies">
@@ -16,26 +16,26 @@
<x-badge value="Beta" tonal color="plain" data-md-showcase-badge-plain />
BLADE,
'Snackbars' => <<<'BLADE'
<x-livewire-material::row gap="space200" wrap align="center" x-data>
<x-row gap="space200" wrap align="center" x-data>
<x-button label="Saved" variant="tonal" x-on:click="materialToast('Settings saved', { type: 'success' })" />
<x-button label="With a description" variant="tonal" x-on:click="materialToast('Upload failed', { type: 'error', description: 'The file is larger than 4 GB.' })" />
<x-button label="With an action" variant="tonal" x-on:click="materialToast('Share deleted', { action: { label: 'Undo', handler: () => materialToast('Share restored', { type: 'info' }) } })" />
<x-button label="Until dismissed" variant="tonal" x-on:click="materialToast('Your storage is almost full', { type: 'warning', timeout: 0 })" />
<x-button label="Sticky, with an event" variant="tonal" x-on:click="materialToast('A new version is ready', { type: 'info', sticky: true, action: { label: 'Reload', event: 'showcase:reload' } })" x-on:showcase:reload.window="materialToast('Reloading…')" />
</x-livewire-material::row>
</x-row>
BLADE,
'Two lines, and the keyboard shortcut that reaches them' => <<<'BLADE'
<x-livewire-material::stack gap="space200" x-data>
<x-livewire-material::row gap="space200" wrap align="center">
<x-stack gap="space200" x-data>
<x-row gap="space200" wrap align="center">
<x-button label="Two lines" variant="tonal" x-on:click="materialToast('Upload paused', { description: 'The connection dropped at 64%. It carries on when you are back.' })" />
<x-button label="Two lines, with an action" variant="tonal" x-on:click="materialToast('Upload paused', { description: 'The connection dropped at 64%. It carries on when you are back.', action: { label: 'Retry now', handler: () => materialToast('Retrying…') } })" />
</x-livewire-material::row>
</x-row>
<p class="md-type-body-md md-ink-variant">
A description makes the snackbar 68px, M3's two-line height; below <code>medium</code> the action wraps under the text.
Press <kbd class="md-type-label-md" data-md-showcase-kbd>Alt</kbd>&nbsp;+&nbsp;<kbd class="md-type-label-md" data-md-showcase-kbd>G</kbd> to move the focus to a snackbar that has an action.
</p>
</x-livewire-material::stack>
</x-stack>
BLADE,
'Plain tooltips' => <<<'BLADE'
<x-button icon="content_copy" tooltip="Copy link" />
@@ -57,7 +57,7 @@
</x-rich-tooltip>
BLADE,
'Alerts' => <<<'BLADE'
<x-livewire-material::stack gap="space200">
<x-stack gap="space200">
<x-alert title="Storage almost full" description="3.8 GB of 4 GB used. Old shares are deleted when they expire." color="warning" />
<x-alert description="Links are shown only once. Copy yours before you leave the page." dismissible />
<x-alert title="Upload failed" color="error">
@@ -65,27 +65,27 @@
<x-slot:actions><x-button label="Try again" /></x-slot:actions>
</x-alert>
<x-alert description="Settings saved." color="success" />
</x-livewire-material::stack>
</x-stack>
BLADE,
'Stats' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'medium' => 2, 'expanded' => 4]" gap="space200">
<x-grid :columns="['compact' => 1, 'medium' => 2, 'expanded' => 4]" gap="space200">
<x-stat title="Shares" value="1,204" icon="link" description="12 this week" />
<x-stat title="Files" value="8,317" icon="description" />
<x-stat title="Stored" value="3.2 GB" icon="hard_drive" description="of 4 GB" />
<x-stat title="Downloads" value="42,019" icon="download" />
</x-livewire-material::grid>
</x-grid>
BLADE,
'Empty state' => <<<'BLADE'
<x-livewire-material::stack gap="space200">
<x-stack gap="space200">
<x-empty-state icon="upload_file" title="No shares yet" description="Files you share appear here, with their links and when they expire.">
<x-slot:actions>
<x-button label="Upload files" icon="upload" variant="filled" />
</x-slot:actions>
</x-empty-state>
</x-livewire-material::stack>
</x-stack>
BLADE,
'Empty state with an illustration' => <<<'BLADE'
<x-livewire-material::stack gap="space200">
<x-stack gap="space200">
<x-empty-state title="No routes yet" description="Draw a route on the map, or import one from a GPX file.">
<x-slot:illustration style="color: var(--md-sys-color-primary)">
<svg style="width: 128px; height: 128px" viewBox="0 0 120 120" fill="none" aria-hidden="true">
@@ -100,7 +100,7 @@
<x-button label="Draw a route" icon="route" variant="filled" />
</x-slot:actions>
</x-empty-state>
</x-livewire-material::stack>
</x-stack>
BLADE,
];
@endphp
@@ -35,10 +35,10 @@
</div>
BLADE,
'Pagination' => <<<'BLADE'
<x-livewire-material::stack gap="space300">
<x-stack gap="space300">
{{ (new \Illuminate\Pagination\LengthAwarePaginator(range(1, 10), 95, 10, 3, ['path' => '#data']))->links() }}
{{ (new \Illuminate\Pagination\Paginator(range(1, 11), 10, 2, ['path' => '#data']))->links() }}
</x-livewire-material::stack>
</x-stack>
BLADE,
];
@endphp
@@ -1,96 +1,96 @@
@php
$examples = [
'Outlined and filled text fields' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-livewire-material::stack gap="space200">
<x-grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-stack gap="space200">
<x-input label="Share name" hint="Recipients see this name" />
<x-input label="Recipient" icon="mail" type="email" placeholder="name@example.com" clearable value="anna@example.com" />
<x-input label="Price" prefix="CHF" suffix="per month" type="number" value="12" />
<x-input label="Share link" value="https://sealshare.test/s/8f3k2" readonly copyable />
<x-password label="Password" hint="At least 12 characters" />
<x-input label="Disabled" value="Not editable" disabled />
</x-livewire-material::stack>
</x-stack>
<x-livewire-material::stack gap="space200">
<x-stack gap="space200">
<x-input variant="filled" label="Share name" hint="Recipients see this name" />
<x-input variant="filled" label="Recipient" icon="mail" type="email" placeholder="name@example.com" clearable value="anna@example.com" />
<x-input variant="filled" label="Price" prefix="CHF" suffix="per month" type="number" value="12" />
<x-input variant="filled" label="Search" icon="search" icon-right="mic" />
<x-password variant="filled" label="Password" hint="At least 12 characters" />
<x-input variant="filled" label="Disabled" value="Not editable" disabled />
</x-livewire-material::stack>
</x-livewire-material::grid>
</x-stack>
</x-grid>
BLADE,
'Errors, required and sizes' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-livewire-material::stack gap="space200">
<x-grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-stack gap="space200">
<x-input label="Email" required />
<x-field id="showcase-error" label="Expiry" :messages="['Choose a date in the future.']">
<input id="showcase-error" data-md-field-control value="2020-01-01" aria-invalid="true" />
</x-field>
</x-livewire-material::stack>
</x-stack>
<x-livewire-material::stack gap="space200">
<x-stack gap="space200">
<x-field id="showcase-error-filled" variant="filled" label="Expiry" :messages="['Choose a date in the future.']">
<input id="showcase-error-filled" data-md-field-control value="2020-01-01" aria-invalid="true" />
</x-field>
<x-livewire-material::row gap="space125" wrap align="center">
<x-row gap="space125" wrap align="center">
<x-input size="sm" icon="search" placeholder="Filter" aria-label="Filter" class="showcase-w-sm" />
<x-input size="xs" placeholder="Find" aria-label="Find" class="showcase-w-xs" />
</x-livewire-material::row>
</x-livewire-material::stack>
</x-livewire-material::grid>
</x-row>
</x-stack>
</x-grid>
BLADE,
'Width at medium and above' => <<<'BLADE'
<x-livewire-material::stack gap="space200">
<x-stack gap="space200">
{{-- M3: never let a text field span the full width of a large screen. From medium it stops at 40rem. --}}
<x-input label="Bounded, the default" hint="No wider than 40rem from medium, however wide the pane is" />
<x-input label="Narrower" class="showcase-w-narrow" hint="An unlayered rule from the call site wins" />
<x-input label="The width of the pane" full icon="search" hint="`full` takes the bound off — for a search row or an editor" />
</x-livewire-material::stack>
</x-stack>
BLADE,
'Character counter' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-livewire-material::stack gap="space200">
<x-grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-stack gap="space200">
<x-input label="Share name" maxlength="40" counter hint="Recipients see this name" />
<x-input variant="filled" label="Subject" maxlength="60" counter />
</x-livewire-material::stack>
</x-stack>
<x-textarea label="Message for recipients" maxlength="180" counter rows="3" hint="Sent with the link" />
</x-livewire-material::grid>
</x-grid>
BLADE,
'Textarea and select' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-livewire-material::stack gap="space200">
<x-grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-stack gap="space200">
<x-textarea label="Message" hint="Grows as you type, up to six lines" rows="2" max-rows="6" />
<x-select label="Expires after" :options="[['id' => 1, 'name' => '1 hour'], ['id' => 24, 'name' => '1 day'], ['id' => 168, 'name' => '7 days'], ['id' => 720, 'name' => '30 days', 'disabled' => true]]" />
<x-file label="Attachments" multiple hint="Up to 2 GB" />
</x-livewire-material::stack>
</x-stack>
<x-livewire-material::stack gap="space200">
<x-stack gap="space200">
<x-textarea variant="filled" label="Message" hint="Grows as you type, up to six lines" rows="2" max-rows="6" />
<x-select variant="filled" label="Expires after" icon="schedule" placeholder="Choose…" :options="[['id' => 1, 'name' => '1 hour'], ['id' => 24, 'name' => '1 day'], ['id' => 168, 'name' => '7 days']]" />
<x-file variant="filled" label="Attachments" multiple />
</x-livewire-material::stack>
</x-livewire-material::grid>
</x-stack>
</x-grid>
BLADE,
'Checkboxes' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'expanded' => 3]" gap="space300">
<x-livewire-material::stack gap="space200">
<x-grid :columns="['compact' => 1, 'expanded' => 3]" gap="space300">
<x-stack gap="space200">
<x-checkbox label="Notify me on download" checked />
<x-checkbox label="Select all files" indeterminate />
<x-checkbox label="Burn after reading" hint="The share is deleted after its first download" />
</x-livewire-material::stack>
<x-livewire-material::stack gap="space200">
</x-stack>
<x-stack gap="space200">
<x-checkbox label="Disabled" disabled />
<x-checkbox label="Disabled and ticked" checked disabled />
<x-checkbox label="Disabled, partly ticked" indeterminate disabled />
</x-livewire-material::stack>
<x-livewire-material::stack gap="space200">
</x-stack>
<x-stack gap="space200">
<x-checkbox label="Show in the dashboard" right />
<x-checkbox aria-label="Unlabelled" />
</x-livewire-material::stack>
</x-livewire-material::grid>
</x-stack>
</x-grid>
BLADE,
'A checkbox group at expanded' => <<<'BLADE'
{{-- M3: from expanded (840px), gather related checkboxes into a contained region instead of one long column. --}}
@@ -98,56 +98,56 @@
<fieldset>
<legend class="md-type-title-sm md-ink" data-md-showcase-legend>Tell me about</legend>
<x-livewire-material::grid :columns="['compact' => 1, 'expanded' => 2]" gap="space200">
<x-grid :columns="['compact' => 1, 'expanded' => 2]" gap="space200">
<x-checkbox label="Downloads" name="notify[]" value="downloads" checked />
<x-checkbox label="Comments" name="notify[]" value="comments" />
<x-checkbox label="Expiring shares" name="notify[]" value="expiring" checked />
<x-checkbox label="Failed uploads" name="notify[]" value="failed" />
<x-checkbox label="New team members" name="notify[]" value="members" />
<x-checkbox label="Weekly summary" name="notify[]" value="summary" />
</x-livewire-material::grid>
</x-grid>
</fieldset>
</x-card>
BLADE,
'Radio buttons' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-radio label="Who can open the link" name="showcase-audience" value="password" :options="[['id' => 'anyone', 'name' => 'Anyone with the link'], ['id' => 'password', 'name' => 'Anyone with the password', 'hint' => 'Share the password separately'], ['id' => 'team', 'name' => 'My team only', 'disabled' => true]]" />
<x-radio label="Theme" name="showcase-radio-theme" value="system" inline :options="[['id' => 'light', 'name' => 'Light'], ['id' => 'dark', 'name' => 'Dark'], ['id' => 'system', 'name' => 'System']]" hint="Inline from sm" />
</x-livewire-material::grid>
</x-grid>
BLADE,
'Switches' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'expanded' => 3]" gap="space300">
<x-livewire-material::stack gap="space200">
<x-grid :columns="['compact' => 1, 'expanded' => 3]" gap="space300">
<x-stack gap="space200">
<x-toggle label="Email notifications" checked />
<x-toggle label="Weekly summary" />
</x-livewire-material::stack>
<x-livewire-material::stack gap="space200">
</x-stack>
<x-stack gap="space200">
<x-toggle label="With icons" icons checked />
<x-toggle label="With icons, off" icons />
<x-toggle label="Only the check" icons="selected" checked />
</x-livewire-material::stack>
<x-livewire-material::stack gap="space200">
</x-stack>
<x-stack gap="space200">
<x-toggle label="Disabled" disabled />
<x-toggle label="Disabled, on" checked disabled icons />
<x-toggle label="Public link" hint="Anyone with the link can open it" right />
</x-livewire-material::stack>
</x-livewire-material::grid>
</x-stack>
</x-grid>
BLADE,
'Choices' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-livewire-material::stack gap="space300">
<x-grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-stack gap="space300">
<x-choices label="Days you are free" hint="Filter chips: any number" :value="[1, 3]" :options="[['id' => 1, 'name' => 'Mon'], ['id' => 2, 'name' => 'Tue'], ['id' => 3, 'name' => 'Wed'], ['id' => 4, 'name' => 'Thu'], ['id' => 5, 'name' => 'Fri'], ['id' => 6, 'name' => 'Sat', 'disabled' => true]]" />
<x-choices label="Expires after" single :value="24" :options="[['id' => 1, 'name' => '1 hour'], ['id' => 24, 'name' => '1 day'], ['id' => 168, 'name' => '7 days']]" />
</x-livewire-material::stack>
</x-stack>
<x-livewire-material::stack gap="space200">
<x-stack gap="space200">
<x-choices label="Time zone" searchable icon="public" value="Europe/Zurich" :options="collect(timezone_identifiers_list())->map(fn ($zone) => ['id' => $zone, 'name' => str_replace('_', ' ', $zone)])->all()" />
<x-choices label="Language" searchable variant="filled" placeholder="Type a language" :options="[['id' => 'de', 'name' => 'Deutsch'], ['id' => 'en', 'name' => 'English'], ['id' => 'fr', 'name' => 'Français'], ['id' => 'it', 'name' => 'Italiano'], ['id' => 'rm', 'name' => 'Rumantsch', 'disabled' => true]]" />
</x-livewire-material::stack>
</x-livewire-material::grid>
</x-stack>
</x-grid>
BLADE,
'Search' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<div x-data="{ query: '' }">
<x-search x-model="query" placeholder="Search shares">
<x-list>
@@ -167,10 +167,10 @@
<x-slot:empty>Type to search your settings.</x-slot:empty>
</x-search>
</div>
</x-livewire-material::grid>
</x-grid>
BLADE,
'Search entry points and suggestions' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<div x-data="{ query: '' }">
<x-search x-model="query" placeholder="Search shares">
<x-slot:suggestions>
@@ -201,7 +201,7 @@
<x-slot:empty>No shares match.</x-slot:empty>
</x-search>
</div>
</x-livewire-material::grid>
</x-grid>
BLADE,
'A form' => <<<'BLADE'
<x-card variant="outlined" data-md-showcase-demo-card data-md-showcase-size="md">
@@ -1,73 +1,73 @@
@php
$examples = [
'Docked' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'medium' => 2]" gap="space300" x-data="{ expires: '{{ now()->addWeek()->format('Y-m-d') }}', starts: null }">
<x-livewire-material::stack gap="space200">
<x-grid :columns="['compact' => 1, 'medium' => 2]" gap="space300" x-data="{ expires: '{{ now()->addWeek()->format('Y-m-d') }}', starts: null }">
<x-stack gap="space200">
<x-datepicker label="Expires on" clearable x-model="expires" hint="Type a date or pick one" />
<p class="md-type-body-sm md-ink-variant">Bound value: <code x-text="JSON.stringify(expires)"></code></p>
</x-livewire-material::stack>
</x-stack>
<x-livewire-material::stack gap="space200">
<x-stack gap="space200">
<x-datepicker label="Starts on" variant="filled" icon="event" x-model="starts" />
<p class="md-type-body-sm md-ink-variant">Bound value: <code x-text="JSON.stringify(starts)"></code></p>
</x-livewire-material::stack>
</x-livewire-material::grid>
</x-stack>
</x-grid>
BLADE,
'Modal and modal input' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'medium' => 2]" gap="space300" x-data="{ birthday: '1990-05-17', delivery: null }">
<x-livewire-material::stack gap="space200">
<x-grid :columns="['compact' => 1, 'medium' => 2]" gap="space300" x-data="{ birthday: '1990-05-17', delivery: null }">
<x-stack gap="space200">
<x-datepicker label="Birthday" mode="modal" x-model="birthday" :max="now()" />
<p class="md-type-body-sm md-ink-variant">Bound value: <code x-text="JSON.stringify(birthday)"></code></p>
</x-livewire-material::stack>
</x-stack>
<x-livewire-material::stack gap="space200">
<x-stack gap="space200">
<x-datepicker label="Delivery" mode="input" x-model="delivery" hint="Opens on a text field" />
<p class="md-type-body-sm md-ink-variant">Bound value: <code x-text="JSON.stringify(delivery)"></code></p>
</x-livewire-material::stack>
</x-livewire-material::grid>
</x-stack>
</x-grid>
BLADE,
'Range' => <<<'BLADE'
{{-- Narrow the window below 600px: a range picker becomes M3's full-screen one, with a close button, Save, and the months scrolled through. --}}
<x-livewire-material::grid :columns="['compact' => 1, 'medium' => 2]" gap="space300" x-data="{ trip: { start: '{{ now()->addDays(3)->format('Y-m-d') }}', end: '{{ now()->addDays(9)->format('Y-m-d') }}' }, leave: { start: null, end: null } }">
<x-livewire-material::stack gap="space200">
<x-grid :columns="['compact' => 1, 'medium' => 2]" gap="space300" x-data="{ trip: { start: '{{ now()->addDays(3)->format('Y-m-d') }}', end: '{{ now()->addDays(9)->format('Y-m-d') }}' }, leave: { start: null, end: null } }">
<x-stack gap="space200">
<x-datepicker label="Trip" range x-model="trip" />
<p class="md-type-body-sm md-ink-variant">Bound value: <code x-text="JSON.stringify(trip)"></code></p>
</x-livewire-material::stack>
</x-stack>
<x-livewire-material::stack gap="space200">
<x-stack gap="space200">
<x-datepicker label="Leave" range mode="modal" x-model="leave" hint="Full screen on a compact window" />
<p class="md-type-body-sm md-ink-variant">Bound value: <code x-text="JSON.stringify(leave)"></code></p>
</x-livewire-material::stack>
</x-livewire-material::grid>
</x-stack>
</x-grid>
BLADE,
'First day of the week and format' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'medium' => 2]" gap="space300" x-data="{ race: '{{ now()->addMonth()->format('Y-m-d') }}', block: { start: null, end: null } }">
<x-livewire-material::stack gap="space200">
<x-grid :columns="['compact' => 1, 'medium' => 2]" gap="space300" x-data="{ race: '{{ now()->addMonth()->format('Y-m-d') }}', block: { start: null, end: null } }">
<x-stack gap="space200">
<x-datepicker label="Race day" week-start="0" format="yyyy-MM-dd" x-model="race" hint="Weeks start on Sunday; typed year first" />
<p class="md-type-body-sm md-ink-variant">Bound value: <code x-text="JSON.stringify(race)"></code></p>
</x-livewire-material::stack>
</x-stack>
<x-livewire-material::stack gap="space200">
<x-stack gap="space200">
<x-datepicker label="Training block" range mode="modal" week-start="1" format="dd.MM.yyyy" x-model="block" />
<p class="md-type-body-sm md-ink-variant">Bound value: <code x-text="JSON.stringify(block)"></code></p>
</x-livewire-material::stack>
</x-livewire-material::grid>
</x-stack>
</x-grid>
BLADE,
'Limits, errors and states' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-livewire-material::stack gap="space200">
<x-grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-stack gap="space200">
<x-datepicker label="Within the next 30 days" :min="now()" :max="now()->addDays(30)" hint="Days outside are disabled" />
<x-datepicker label="Required" required />
</x-livewire-material::stack>
</x-stack>
<x-livewire-material::stack gap="space200">
<x-stack gap="space200">
<x-datepicker label="Disabled" value="2026-09-13" disabled />
<x-datepicker label="Read-only" value="2026-09-13" readonly />
<x-livewire-material::row gap="space125" wrap align="center">
<x-row gap="space125" wrap align="center">
<x-datepicker size="sm" aria-label="From" class="showcase-w-sm" />
</x-livewire-material::row>
</x-livewire-material::stack>
</x-livewire-material::grid>
</x-row>
</x-stack>
</x-grid>
BLADE,
];
@endphp
@@ -31,15 +31,15 @@
<x-progress value="55" wavy color="info" label="Info" />
BLADE,
'Following a value in the browser (bind)' => <<<'BLADE'
<x-livewire-material::stack gap="space300" x-data="{ progress: 30 }">
<x-stack gap="space300" x-data="{ progress: 30 }">
<x-button label="Set a random value" variant="tonal" x-on:click="progress = Math.round(Math.random() * 100)" />
<x-progress bind="progress" label="Bound" />
<x-progress bind="progress" wavy label="Bound wavy" />
<x-livewire-material::row gap="space300">
<x-row gap="space300">
<x-progress bind="progress" circular label="Bound circular" />
<x-progress bind="progress" circular wavy label="Bound circular wavy" />
</x-livewire-material::row>
</x-livewire-material::stack>
</x-row>
</x-stack>
BLADE,
];
@@ -1,55 +1,55 @@
@php
$examples = [
'Standard, discrete and disabled' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'expanded' => 3]" gap="space400">
<x-grid :columns="['compact' => 1, 'expanded' => 3]" gap="space400">
<x-slider label="Volume" value="40" hint="Drag the handle or use the arrow keys" />
<x-slider label="Quality" value="6" :max="10" ticks />
<x-slider label="Locked" value="70" disabled />
</x-livewire-material::grid>
</x-grid>
BLADE,
'Sizes, with an inset icon from md' => <<<'BLADE'
<x-livewire-material::stack gap="space300">
<x-stack gap="space300">
<x-slider label="Extra small (16px track)" value="30" />
<x-slider label="Small (24px)" value="45" size="sm" />
<x-slider label="Medium (40px)" value="60" size="md" icon="volume_up" />
<x-slider label="Large (56px)" value="12" size="lg" icon="light_mode" />
<x-slider label="Extra large (96px)" value="75" size="xl" icon="brightness_medium" />
</x-livewire-material::stack>
</x-stack>
BLADE,
'Range and centred' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'medium' => 2]" gap="space400">
<x-grid :columns="['compact' => 1, 'medium' => 2]" gap="space400">
<x-slider label="Price" :value="[20, 60]" range ticks :step="10" hint="Handles never cross" />
<x-slider label="Balance" value="15" :min="-50" :max="50" centered />
</x-livewire-material::grid>
</x-grid>
BLADE,
'Vertical' => <<<'BLADE'
{{-- M3 Expressive's second orientation. A vertical slider needs a height: it is on the wrapper, which the label and hint share. --}}
<x-livewire-material::row gap="space500" wrap align="end">
<x-row gap="space500" wrap align="end">
<x-slider label="Volume" orientation="vertical" value="40" style="height: 256px;" hint="Up and Down" />
<x-slider label="Warmth" orientation="vertical" value="6" :max="10" ticks style="height: 256px;" />
<x-slider label="Brightness" orientation="vertical" value="70" size="md" icon="light_mode" style="height: 256px;" />
<x-slider label="Always labelled" orientation="vertical" value="55" value-label="always" color="tertiary" style="height: 256px;" />
<x-slider label="Locked" orientation="vertical" value="25" disabled style="height: 256px;" />
</x-livewire-material::row>
</x-row>
BLADE,
'Colours and value labels' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'expanded' => 3]" gap="space400">
<x-grid :columns="['compact' => 1, 'expanded' => 3]" gap="space400">
<x-slider label="Always labelled" value="55" color="secondary" value-label="always" size="sm" />
<x-slider label="Tertiary, no label" value="35" color="tertiary" value-label="never" size="sm" />
<x-slider label="Error" :value="[30, 70]" color="error" range size="sm" />
</x-livewire-material::grid>
</x-grid>
BLADE,
'Bound with x-model' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'medium' => 2]" gap="space400" x-data="{ volume: 25, price: [100, 300] }">
<x-livewire-material::stack gap="space100">
<x-grid :columns="['compact' => 1, 'medium' => 2]" gap="space400" x-data="{ volume: 25, price: [100, 300] }">
<x-stack gap="space100">
<x-slider label="Bound volume" x-model="volume" />
<p class="md-type-body-md md-ink-variant">volume: <span data-bound="volume" x-text="volume"></span> <x-button label="Set 80" x-on:click="volume = 80" /></p>
</x-livewire-material::stack>
<x-livewire-material::stack gap="space100">
</x-stack>
<x-stack gap="space100">
<x-slider label="Bound price" x-model="price" range :max="500" :step="25" ticks />
<p class="md-type-body-md md-ink-variant">price: <span data-bound="price" x-text="JSON.stringify(price)"></span></p>
</x-livewire-material::stack>
</x-livewire-material::grid>
</x-stack>
</x-grid>
BLADE,
];
@endphp
@@ -1,32 +1,32 @@
@php
$examples = [
'12 and 24 hours, outlined and filled' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-livewire-material::stack gap="space200">
<x-grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-stack gap="space200">
<x-timepicker label="Meeting starts" value="09:30" hint="The locale's clock" />
<x-timepicker label="Pick-up" value="17:15" format="12" icon="local_shipping" clearable />
<x-timepicker label="Disabled" value="12:00" disabled />
</x-livewire-material::stack>
</x-stack>
<x-livewire-material::stack gap="space200">
<x-stack gap="space200">
<x-timepicker variant="filled" label="Alarm" value="06:45" format="24" icon="alarm" />
<x-timepicker variant="filled" label="Reminder" format="24" hint="Opens at the current time" />
<x-timepicker variant="filled" label="Required" format="24" required />
</x-livewire-material::stack>
</x-livewire-material::grid>
</x-stack>
</x-grid>
BLADE,
'Steps and limits' => <<<'BLADE'
<x-livewire-material::grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-livewire-material::stack gap="space200">
<x-grid :columns="['compact' => 1, 'medium' => 2]" gap="space300">
<x-stack gap="space200">
<x-timepicker label="Appointment" value="10:00" format="24" step="15" min="08:00" max="17:30" hint="Quarter hours from 08:00 to 17:30" />
<x-timepicker label="Night shift starts" value="23:00" format="24" min="22:00" max="06:00" hint="From 22:00, across midnight, to 06:00" />
</x-livewire-material::stack>
</x-stack>
<x-livewire-material::stack gap="space200" x-data="{ time: '14:05' }">
<x-stack gap="space200" x-data="{ time: '14:05' }">
<x-timepicker label="Bound with x-model" x-model="time" format="12" step="5" />
<p class="md-type-body-md md-ink-variant">Stored as <code x-text="time ?? 'null'"></code></p>
</x-livewire-material::stack>
</x-livewire-material::grid>
</x-stack>
</x-grid>
BLADE,
];
@endphp