{{-- An M3 dialog, on the native `` opened with `showModal()`. Native because it gets the hard parts right on its own: the top layer above everything, the rest of the page inert, focus moved in and handed back, Escape. The open state is the Livewire property in `wire:model` (entangled live) — a flag (`$confirmingDelete`) or an id (`$deletingShareId`) — and closing writes back whichever "closed" means for it, `false` or `null`. Without `wire:model` it reads and writes `open` in the Alpine scope around it:
`wire:ignore.self`, because `showModal()` sets the `open` attribute, which the server's HTML does not have: without it the next Livewire render morphs the attribute away and the dialog shuts under the person using it. The contents still morph. M3's basic dialog (DialogTokens, androidx Compose Material 3, Apache-2.0): surface-container- high, extra-large corner, elevation 3, a headline-small `title`, body-medium `subtitle` in on-surface-variant, and the `actions` slot at the end. `icon` puts a secondary-coloured icon above a centred title, as M3 draws a dialog with a hero icon. `fullscreen` makes a dialog that holds a form take the whole screen on a compact window (below `medium`, 600px — M3 uses full-screen dialogs "only in compact breakpoints"), with a 56px close-and-title bar clear of the notch. `persistent` ignores Escape and the scrim, for a dialog that must be answered. It opens on the fast spatial spring and closes at once, as M3's do. "Dialog content generally shouldn't scroll; if it must, the title stays pinned at the top and the buttons at the bottom" (docs/reference/m3/components-actions-communication-containment.md § Dialogs → Behaviour): the header and the action row are their own rows of the flex column and only the body between them scrolls, each with the 24dp padding the box used to carry. `separator` draws M3's divider under the pinned header and above the pinned actions. `alert` is M3's "on web, basic dialogs should have the alert dialog role": it sets `role="alertdialog"` and points `aria-describedby` at the body, for the dialog that interrupts to say something important. It is opt-in, because ARIA-APG keeps `alertdialog` for exactly that and a form dialog would over-announce with it. A `subtitle` is always the dialog's description. --}} @props([ 'title' => null, 'subtitle' => null, 'icon' => null, 'separator' => false, 'persistent' => false, 'fullscreen' => false, 'alert' => false, 'boxClass' => null, ]) @php $model = $attributes->wire('model')->value() ?: null; $id = $attributes->get('id') ?? 'material-dialog-'.substr(md5($model.'|'.$title), 0, 10); $header = filled($title) || filled($subtitle) || $icon; $describedBy = implode(' ', array_filter([ filled($subtitle) ? $id.'-subtitle' : null, $alert && $slot->isNotEmpty() ? $id.'-body' : null, ])); @endphp whereDoesntStartWith('wire:model')->except(['id', 'class'])->merge(['id' => $id]) }} @class([ 'm-auto max-h-[calc(100dvh-3rem)] w-[calc(100vw-3rem)] max-w-[35rem] min-w-70 overflow-visible bg-transparent p-0 text-on-surface', 'backdrop:bg-scrim/32', 'opacity-100 scale-100 starting:opacity-0 starting:scale-95 transition-[opacity,scale] duration-(--md-sys-motion-spatial-fast-duration) ease-spatial-fast', 'max-medium:m-0 max-medium:h-dvh max-medium:max-h-none max-medium:w-full max-medium:max-w-none max-medium:min-w-0' => $fullscreen, $attributes->get('class'), ]) >
$fullscreen, $boxClass, ])> @if ($fullscreen)
@if (filled($title)) {{ $title }} @endif
@endif @if ($header) {{-- A full-screen dialog's bar names it on a phone, so only the subtitle stays there. --}}
$fullscreen && ! $icon && blank($subtitle), 'text-center' => $icon])> @if ($icon) @endif @if (filled($title))

$fullscreen && ! $icon])>{{ $title }}

@endif @if (filled($subtitle))

filled($title) || $icon, 'max-medium:mt-0' => $fullscreen && ! $icon])>{{ $subtitle }}

@endif @if ($separator) @endif
@endif @if ($slot->isNotEmpty())
$header, 'pt-6' => ! $header, 'pb-6' => ! isset($actions), ])> {{ $slot }}
@endif @isset($actions) @if ($separator) @endif
$fullscreen, ])> {{ $actions }}
@endisset