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
78 lines
3.9 KiB
PHP
78 lines
3.9 KiB
PHP
{{-- A checkbox, M3's: an 18px box that fills with primary when ticked, in a 40px state layer. The
|
|
tick and the dash fill the box at CheckboxTokens' 18px icon size, drawn from the 20 optical cut.
|
|
|
|
The label and its hint sit beside it and are its accessible name — the whole row is the
|
|
`<label>`, so either can be pressed. `right` puts the box at the end of the row, for a setting
|
|
read left to right. `indeterminate` shows the mixed state of a "select all" whose items are
|
|
partly ticked: HTML has no attribute for it, so the input is marked `data-indeterminate` and
|
|
resources/js/field.js keeps the property in step, on load and after every morph. Errors are
|
|
read from the bag under the `wire:model` name. Every other attribute reaches the `<input>`
|
|
(resources/css/components/selection.css).
|
|
|
|
Without a label — a "select all" in a table header, a row's tick — the row is only the 18px box,
|
|
so the box carries `touch-target` and catches presses over M3's 48px minimum.
|
|
|
|
Grouping is the caller's, not this component's: M3 asks that from `expanded` (840px) a set of
|
|
related checkboxes be gathered into a contained region rather than left as one long column
|
|
(docs/reference/m3/components-navigation-selection-inputs.md § Checkbox, Behaviour). Lay the
|
|
group out yourself — `<div class="grid gap-4 expanded:grid-cols-2">` around the checkboxes, or a
|
|
`<x-card>` or side sheet holding them — and give the group a heading that names what it asks. --}}
|
|
|
|
@props([
|
|
'label' => null,
|
|
'hint' => null,
|
|
'right' => false,
|
|
'indeterminate' => false,
|
|
])
|
|
|
|
@php
|
|
$model = $attributes->whereStartsWith('wire:model')->first();
|
|
$id = $attributes->get('id') ?? 'check-'.substr(md5($model.'|'.$label.'|'.$attributes->get('value')), 0, 12);
|
|
// A plain form's field is named, not bound: its errors are under its name (`files[]` → `files`, `a[b]` → `a.b`).
|
|
$errorKey = $model ?? (filled($attributes->get('name')) ? str_replace(['[]', '[', ']'], ['', '.', ''], (string) $attributes->get('name')) : null);
|
|
$messages = $errorKey !== null && isset($errors) ? \Illuminate\Support\Arr::flatten($errors->get($errorKey)) : [];
|
|
@endphp
|
|
|
|
<div {{ $attributes->only(['class', 'wire:key'])->class(['min-w-0']) }}>
|
|
<label for="{{ $id }}" data-selection @if ($messages !== []) data-invalid @endif @class([
|
|
'flex gap-4',
|
|
'items-start' => filled($hint),
|
|
'items-center' => blank($hint),
|
|
'flex-row-reverse justify-between' => $right,
|
|
])>
|
|
<span data-checkbox @class([
|
|
'mt-[3px]' => filled($hint),
|
|
'touch-target' => blank($label) && blank($hint),
|
|
])>
|
|
<input
|
|
{{ $attributes->except(['class', 'id', 'wire:key']) }}
|
|
id="{{ $id }}"
|
|
type="checkbox"
|
|
@if ($indeterminate) data-indeterminate @endif
|
|
@if ($messages !== []) aria-invalid="true" aria-describedby="{{ $id }}-support" @endif
|
|
/>
|
|
<x-livewire-material::icon name="check" class="size-4.5" optical="20" data-check />
|
|
<x-livewire-material::icon name="remove" class="size-4.5" optical="20" data-mixed />
|
|
</span>
|
|
|
|
@if (filled($label) || filled($hint))
|
|
<span class="min-w-0">
|
|
@if (filled($label))
|
|
<span class="block type-body-lg text-on-surface" data-selection-label>{{ $label }}</span>
|
|
@endif
|
|
@if (filled($hint))
|
|
<span class="mt-0.5 block type-body-sm text-on-surface-variant">{{ $hint }}</span>
|
|
@endif
|
|
</span>
|
|
@endif
|
|
</label>
|
|
|
|
@if ($messages !== [])
|
|
<div id="{{ $id }}-support" class="mt-1 type-body-sm text-error" role="alert">
|
|
@foreach ($messages as $message)
|
|
<p>{{ $message }}</p>
|
|
@endforeach
|
|
</div>
|
|
@endif
|
|
</div>
|