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:
co-authored by
Claude Opus 5
parent
5fb8fc6b8f
commit
3fb0a404db
@@ -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> + <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
|
||||
|
||||
@@ -117,6 +117,25 @@ it('indexes exactly the examples each page renders, so an example the index miss
|
||||
}
|
||||
});
|
||||
|
||||
it('writes every example as an application writes it', function () {
|
||||
$files = collect(File::glob(__DIR__.'/../../resources/views/showcase/sections/*.blade.php'))
|
||||
->merge(File::glob(__DIR__.'/../../resources/views/showcase/layout/*.blade.php'));
|
||||
|
||||
$examples = $files->flatMap(function (string $file): array {
|
||||
preg_match_all("/<<<'BLADE'\n(.*?)^\s*BLADE[,;]/sm", File::get($file), $matches);
|
||||
|
||||
return array_map(fn (string $code): array => [basename($file), $code], $matches[1]);
|
||||
});
|
||||
|
||||
expect($examples)->not->toBeEmpty();
|
||||
|
||||
foreach ($examples as [$file, $code]) {
|
||||
// The example component rewrites unprefixed tags to a configured prefix; a namespaced tag
|
||||
// would show an application a form it does not write, and escape that rewrite.
|
||||
expect($code)->not->toContain('x-livewire-material::', "{$file} writes a namespaced tag in an example");
|
||||
}
|
||||
});
|
||||
|
||||
it('does not mount the showcase when disabled', function () {
|
||||
rebootWithShowcase(false);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user