{{-- M3's list-detail canonical layout: a list, and the detail of what is selected in it. Parent and child content: an inbox and a message, folders and a file, settings and a category (docs/reference/m3/foundations-supplement.md § Canonical layouts → List-detail). Its visible-panes table, row by row: compact (below 600px) shows 1 pane; medium (600–839) 1 or 2, and this layout shows 1, M3's recommendation for anything but low-density content; expanded (840+), large (1200–1599) and extra-large (1600+) show 2. So below 840px the list shows until something is selected, then the detail replaces it with a back button; from 840px the list is a fixed pane, 360px wide (412px from 1200px, M3's fixed-pane widths at expanded and at large, § Breakpoints), the detail takes the rest, 24px apart, and no back button shows. Resizing moves between the two as M3 describes ("rotating from expanded to medium collapses two panes back to one"). A right-to-left document puts the list on the right and turns the back arrow. `selected` is what is selected, bound with `wire:model` (the Livewire property, whose value the server also renders from, so the first paint shows the right pane) or `x-model`, or given once as `selected`. Nothing selected is `null`, `false` or `''`. Inside both slots `selected` is in Alpine scope, and `back()` clears it (a boolean to `false`, anything else to `null`). A list item can select with `wire:click="$set('selectedId', 7)"` or `x-on:click="selected = 7"`. M3 shows the list's selected state only where both panes show; give the item `aria-current` for it, which also tells `back()` where to return focus. The back button: `` puts it in the detail pane's own app bar. Without one in the detail slot, the layout draws its own row with it above the detail. Either way it is hidden from 840px. Focus (resources/js/layout.js): below 840px a selection moves focus to the detail pane, and `back()` returns it to the list item it came from — or the item marked `aria-current` or `aria-selected`, or the list — as a dialog returns focus to its trigger (WAI-ARIA APG). From 840px focus stays where it is, since both panes are on screen. The layout keeps M3's margin (16px below medium, 24px from it) unless it sits inside something that already does, such as ``'s content region. It takes `as`, `hide-below` and `hide-from` like every layout component, and the caller's `class` and `style` land on it untouched. Its own attributes belong to Alpine (`wire:ignore.self`), while both slots morph as usual. Drawn by resources/css/layout/list-detail.css. --}} @props([ 'as' => null, 'selected' => null, 'hideBelow' => null, 'hideFrom' => null, ]) @php $layout = \NoNameWeb\LivewireMaterial\Support\Layout::class; $element = $layout::element($as); $model = $attributes->wire('model')->value() ?: null; $initial = $selected; if ($model !== null && ($component = \Livewire\Livewire::current()) !== null) { $initial = data_get($component, $model); } $chosen = $initial !== null && $initial !== false && $initial !== ''; $wire = $attributes->wire('model'); $detailSlot = $detail ?? null; $ownBack = $detailSlot !== null && str_contains((string) $detailSlot, 'data-md-list-detail-back'); $attributes = $attributes->whereDoesntStartWith('wire:model')->merge(array_filter([ 'data-md-list-detail' => true, 'data-md-selected' => $chosen ? true : null, ] + $layout::visibility($hideBelow, $hideFrom), fn ($value): bool => $value !== null)); @endphp <{{ $element }} x-data="materialListDetail(@if ($model !== null) @entangle($wire) @else @js($initial) @endif)" @if ($model === null) x-modelable="selected" @endif x-bind:data-md-selected="hasSelection ? '' : null" x-on:focusin="track($event)" x-on:focusout="track($event)" wire:ignore.self {{ $attributes }} >
{{ $list ?? '' }}
@unless ($ownBack)
@endunless {{ $detailSlot ?? '' }}