{{-- One M3 list item: a headline with what leads it, what supports it and what trails it. `title` (or the slot) is the body-large headline; `overline` sits above it (label-small), `description` under it (body-medium, up to two lines). The leading element is one of `icon`, `avatar` (an image URL, or initials in primary-container) or `image` (a 56px thumbnail), or a `leading` slot (a checkbox, a switch). The trailing element is `trailing` text (label-small), `icon-right`, or an `end` slot for controls (a menu, a switch). One-, two- and three-line heights (56, 72, 88px) follow from what is given, 16px between the item and what leads or trails it, and a three-line item top-aligns rather than centring — M3 aligns an item middle "by default, top-aligned if the item is 88dp+ or has 3+ lines of text". Its icons are 24px, or 20px in a `segmented` list, which is M3 Expressive's (ListTokens, androidx Compose Material 3, Apache-2.0). `link` makes the whole item the link. Otherwise, to make it open something while its trailing controls keep their own presses, give it `data-list-row` and put `data-list-open` on the one control that opens — see resources/js/list-rows.js. `selected` (true) is M3's selected item, in secondary-container; `disabled` greys it to 38%, drops its link and announces it `aria-disabled` — M3's states model treats disabled as not interactive, so a disabled item answers neither the pointer nor the keyboard. It takes its role from the `` around it: a `listitem` in a plain list, where `selected` is `aria-current`, and an `option` announcing `aria-selected` in a `selectable` one. M3 asks for two cues on a selected item, never colour alone, so a selected option also draws a trailing check unless `icon-right` says otherwise. --}} @props([ 'title' => null, 'overline' => null, 'description' => null, 'icon' => null, 'avatar' => null, 'image' => null, 'trailing' => null, 'iconRight' => null, 'link' => null, 'external' => false, 'noWireNavigate' => false, 'selected' => false, 'disabled' => false, ]) {{-- The `` around it: whether it is one a person chooses from and how many it takes, and whether it is the expressive (segmented) one, whose icons are a size smaller. --}} @aware([ 'selectable' => false, 'selection' => null, 'segmented' => false, ]) @php $isLink = filled($link) && ! $disabled; $lines = (filled($overline) ? 1 : 0) + (filled($description) ? 1 : 0); $initials = filled($avatar) && ! str_contains((string) $avatar, '/') && ! str_contains((string) $avatar, '.'); $option = $selectable || $selection !== null; $check = $option && $selected && blank($iconRight); // ListTokens.kt:153,156,332,335 — ItemLeading/TrailingIconExpressiveSize = 20dp against the // baseline 24dp. At 20px the symbol is drawn from the 20 optical cut, not the 24 scaled down. $iconSize = $segmented ? 'size-5' : 'size-6'; $optical = $segmented ? '20' : '24'; @endphp
class([ 'relative flex gap-4 px-4 text-on-surface', 'items-center' => $lines !== 2, 'items-start' => $lines === 2, 'min-h-14 py-2' => $lines === 0, 'min-h-18 py-2' => $lines === 1, 'min-h-22 py-3' => $lines === 2, 'pointer-events-none text-on-surface/38' => $disabled, ]) }} > @isset($leading)
{{ $leading }}
@elseif ($avatar) @if ($initials) @else @endif @elseif ($image) @elseif ($icon) @endif
@if ($overline)

! $selected])>{{ $overline }}

@endif @if ($isLink) {{ $title ?? $slot }} @else

{{ $title ?? $slot }}

@endif @if ($description)

! $selected])>{{ $description }}

@endif
@isset($end)
{{ $end }}
@endisset @if ($trailing) ! $selected])>{{ $trailing }} @endif @if ($iconRight) @elseif ($check) @endif