M3 § Checkbox, Behaviour asks that from expanded (840px) related checkboxes be gathered into a contained region rather than left as one long column. That is a rule about the page around the control, not about the control, so it is written down rather than built: the component's header and its SKILL.md entry now say it, and the showcase lays a group out in an `expanded:grid-cols-2` card (plan step 24, audit docs/audits/m3-alignment/inputs.md § Missing). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
202 lines
13 KiB
PHP
202 lines
13 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,
|
|
'A checkbox group at expanded' => <<<'BLADE'
|
|
{{-- M3: from expanded (840px), gather related checkboxes into a contained region instead of one long column. --}}
|
|
<x-card variant="outlined" class="w-full max-w-2xl">
|
|
<fieldset>
|
|
<legend class="mb-4 type-title-sm text-on-surface">Tell me about</legend>
|
|
|
|
<div class="grid gap-4 expanded:grid-cols-2">
|
|
<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" />
|
|
</div>
|
|
</fieldset>
|
|
</x-card>
|
|
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><x-input></code>, <code><x-password></code>, <code><x-textarea></code>, <code><x-select></code>, <code><x-file></code>
|
|
(all on <code><x-field></code>, outlined or filled), <code><x-checkbox></code>, <code><x-radio></code>, <code><x-toggle></code>, <code><x-choices></code>, <code><x-search></code> and <code><x-form></code>.
|
|
</p>
|
|
|
|
@foreach ($examples as $title => $code)
|
|
<x-showcase::example :$title :$code />
|
|
@endforeach
|
|
</section>
|