Give a list item M3's gaps, alignment and expressive icon size

Plan step 19, containment.md C-14, C-15 and C-26. The leading and
trailing gap was 12px where ListItem.kt's LeadingContentEndPadding and
TrailingContentStartPadding are 16dp; a three-line item was
middle-aligned and padded 10px where M3 top-aligns an 88dp item and
Compose pads it 12; and a segmented list's icons stayed at the baseline
24dp instead of ListTokens' expressive 20dp, which the item now reads
from its list with `@aware` and draws from the 20 optical cut.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
Andreas Reinhold / reini
2026-09-14 06:04:19 +02:00
co-authored by Claude Opus 5
parent dcd28707dd
commit 26a9230a48
3 changed files with 41 additions and 13 deletions
+21 -8
View File
@@ -8,7 +8,11 @@
`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 (ListTokens, androidx Compose Material 3, Apache-2.0).
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
@@ -38,10 +42,12 @@
'disabled' => false,
])
{{-- Whether the `<x-list>` around it is one a person chooses from, and how many it takes. --}}
{{-- The `<x-list>` 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
@@ -50,6 +56,11 @@
$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
<div
@@ -60,10 +71,12 @@
@if ($selected) data-selected @endif
@if ($disabled) aria-disabled="true" @endif
{{ $attributes->class([
'relative flex items-center gap-3 px-4 text-on-surface',
'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.5' => $lines === 1,
'min-h-22 py-2.5' => $lines === 2,
'min-h-18 py-2' => $lines === 1,
'min-h-22 py-3' => $lines === 2,
'pointer-events-none text-on-surface/38' => $disabled,
]) }}
>
@@ -78,7 +91,7 @@
@elseif ($image)
<img src="{{ $image }}" alt="" class="size-14 shrink-0 rounded-corner-sm object-cover" />
@elseif ($icon)
<x-livewire-material::icon :name="$icon" :class="\Illuminate\Support\Arr::toCssClasses(['size-6', 'text-on-surface-variant' => ! $selected && ! $disabled])" />
<x-livewire-material::icon :name="$icon" :optical="$optical" :class="\Illuminate\Support\Arr::toCssClasses([$iconSize, 'text-on-surface-variant' => ! $selected && ! $disabled])" />
@endif
<div class="min-w-0 flex-1">
@@ -111,8 +124,8 @@
@endif
@if ($iconRight)
<x-livewire-material::icon :name="$iconRight" :class="\Illuminate\Support\Arr::toCssClasses(['size-6', 'text-on-surface-variant' => ! $selected && ! $disabled])" />
<x-livewire-material::icon :name="$iconRight" :optical="$optical" :class="\Illuminate\Support\Arr::toCssClasses([$iconSize, 'text-on-surface-variant' => ! $selected && ! $disabled])" />
@elseif ($check)
<x-livewire-material::icon name="check" class="size-6" />
<x-livewire-material::icon name="check" :optical="$optical" :class="$iconSize" />
@endif
</div>