Files
livewire-material/resources/views/showcase/sections/fields.blade.php
T
Andreas Reinhold / reiniandClaude Fable 5.1 72a3e22fbc Bound a text field's width from medium
M3 § Text Fields, Behaviour: compact may let a field span full width, but
medium and expanded must bound it — "never let it span the full width of a
large screen". Nothing in the package capped a field (plan step 24, audit
docs/audits/m3-alignment/inputs.md § Missing). From `medium` a field now stops
at 40rem — the site names no number, so the header says where this one comes
from — which a `max-w-*` class beats and `full` takes off. The search bar
already carries M3's own 720px.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
2026-09-14 06:23:08 +02:00

185 lines
12 KiB
PHP

@php
$examples = [
'Outlined and filled text fields' => <<<'BLADE'
<div class="grid w-full gap-6 medium:grid-cols-2">
<div class="grid content-start gap-4">
<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 />
</div>
<div class="grid content-start gap-4">
<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 />
</div>
</div>
BLADE,
'Errors, required and sizes' => <<<'BLADE'
<div class="grid w-full gap-6 medium:grid-cols-2">
<div class="grid content-start gap-4">
<x-input label="Email" required />
<x-field id="showcase-error" label="Expiry" :messages="['Choose a date in the future.']">
<input id="showcase-error" class="field-control" value="2020-01-01" aria-invalid="true" />
</x-field>
</div>
<div class="grid content-start gap-4">
<x-field id="showcase-error-filled" variant="filled" label="Expiry" :messages="['Choose a date in the future.']">
<input id="showcase-error-filled" class="field-control" value="2020-01-01" aria-invalid="true" />
</x-field>
<div class="flex flex-wrap items-center gap-3">
<x-input size="sm" icon="search" placeholder="Filter" aria-label="Filter" class="w-48" />
<x-input size="xs" placeholder="Find" aria-label="Find" class="w-36" />
</div>
</div>
</div>
BLADE,
'Width at medium and above' => <<<'BLADE'
<div class="w-full space-y-4">
{{-- 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="max-w-xs" hint="A max-w-* class 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" />
</div>
BLADE,
'Character counter' => <<<'BLADE'
<div class="grid w-full gap-6 medium:grid-cols-2">
<div class="grid content-start gap-4">
<x-input label="Share name" maxlength="40" counter hint="Recipients see this name" />
<x-input variant="filled" label="Subject" maxlength="60" counter />
</div>
<x-textarea label="Message for recipients" maxlength="180" counter rows="3" hint="Sent with the link" />
</div>
BLADE,
'Textarea and select' => <<<'BLADE'
<div class="grid w-full gap-6 medium:grid-cols-2">
<div class="grid content-start gap-4">
<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" />
</div>
<div class="grid content-start gap-4">
<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 />
</div>
</div>
BLADE,
'Checkboxes' => <<<'BLADE'
<div class="grid w-full gap-6 expanded:grid-cols-3">
<div class="grid content-start gap-4">
<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" />
</div>
<div class="grid content-start gap-4">
<x-checkbox label="Disabled" disabled />
<x-checkbox label="Disabled and ticked" checked disabled />
<x-checkbox label="Disabled, partly ticked" indeterminate disabled />
</div>
<div class="grid content-start gap-4">
<x-checkbox label="Show in the dashboard" right />
<x-checkbox aria-label="Unlabelled" />
</div>
</div>
BLADE,
'Radio buttons' => <<<'BLADE'
<div class="grid w-full gap-6 medium:grid-cols-2">
<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" />
</div>
BLADE,
'Switches' => <<<'BLADE'
<div class="grid w-full gap-6 expanded:grid-cols-3">
<div class="grid content-start gap-4">
<x-toggle label="Email notifications" checked />
<x-toggle label="Weekly summary" />
</div>
<div class="grid content-start gap-4">
<x-toggle label="With icons" icons checked />
<x-toggle label="With icons, off" icons />
<x-toggle label="Only the check" icons="selected" checked />
</div>
<div class="grid content-start gap-4">
<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 />
</div>
</div>
BLADE,
'Choices' => <<<'BLADE'
<div class="grid w-full gap-6 medium:grid-cols-2">
<div class="grid content-start gap-6">
<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']]" />
</div>
<div class="grid content-start gap-4">
<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]]" />
</div>
</div>
BLADE,
'Search' => <<<'BLADE'
<div class="grid w-full gap-6 medium:grid-cols-2">
<div x-data="{ query: '' }">
<x-search x-model="query" placeholder="Search shares">
<x-list>
<x-list-item title="holiday-photos.zip" description="248 MB · 3 days left" icon="folder_zip" link="#fields" x-show="'holiday-photos.zip'.includes(query.toLowerCase())" />
<x-list-item title="contract.pdf" description="1.2 MB · 1 hour left" icon="picture_as_pdf" link="#fields" x-show="'contract.pdf'.includes(query.toLowerCase())" />
<x-list-item title="design-review.mp4" description="3.4 GB · 7 days left" icon="movie" link="#fields" x-show="'design-review.mp4'.includes(query.toLowerCase())" />
</x-list>
<x-slot:trailing>
<span class="grid size-8 place-items-center rounded-corner-full bg-primary-container type-label-lg text-on-primary-container">AR</span>
</x-slot:trailing>
</x-search>
</div>
{{-- M3's resting bar is 360px and grows to 720 while focused; --search-width sets the resting one. --}}
<div style="--search-width: 22.5rem">
<x-search placeholder="Search in settings" docked>
<x-slot:empty>Type to search your settings.</x-slot:empty>
</x-search>
</div>
</div>
BLADE,
'A form' => <<<'BLADE'
<x-card variant="outlined" class="w-full max-w-xl">
<x-form x-on:submit.prevent="materialToast('Share created', { type: 'success' })" separator>
<x-input label="Share name" required />
<x-textarea label="Message for recipients" />
<x-select label="Expires after" :options="[['id' => 24, 'name' => '1 day'], ['id' => 168, 'name' => '7 days']]" />
<x-toggle label="Protect with a password" right />
<x-slot:actions>
<x-button label="Cancel" type="reset" />
<x-button label="Create share" variant="filled" type="submit" />
</x-slot:actions>
</x-form>
</x-card>
BLADE,
];
@endphp
<section id="fields" class="scroll-mt-24 space-y-6">
<h2 class="type-headline-md">Text fields and selection</h2>
<p class="max-w-3xl type-body-md text-on-surface-variant">
<code>&lt;x-input&gt;</code>, <code>&lt;x-password&gt;</code>, <code>&lt;x-textarea&gt;</code>, <code>&lt;x-select&gt;</code>, <code>&lt;x-file&gt;</code>
(all on <code>&lt;x-field&gt;</code>, outlined or filled), <code>&lt;x-checkbox&gt;</code>, <code>&lt;x-radio&gt;</code>, <code>&lt;x-toggle&gt;</code>, <code>&lt;x-choices&gt;</code>, <code>&lt;x-search&gt;</code> and <code>&lt;x-form&gt;</code>.
</p>
@foreach ($examples as $title => $code)
<x-showcase::example :$title :$code />
@endforeach
</section>