@props([ 'wireModel' => null, // Livewire boolean property to entangle (client-driven open/close) 'show' => false, // Legacy value flag (server-driven fallback) 'title' => '', 'titleEdit' => null, // optional: in wire-model mode the header switches to this // label client-side whenever $wire.editingId is truthy, so an // Edit opened purely by Alpine still reads "Edit …" with no fetch 'close' => 'closeModal', 'size' => 'md', ]) {{-- Two modes: 1. Client-driven (preferred) — pass wire-model="showModal". Visibility is entangled to that Livewire property but DEFERRED (Livewire 3 @entangle without .live), so opening/closing never triggers a server round-trip on its own. Closing therefore does NOT re-render the (heavy) parent list — the ✕ and the Cancel button flip Alpine state only. UX RULE (critical): a form modal must NEVER close by accident, so a backdrop (outside) click and the Escape key are intentionally NOT wired to close it. Only the ✕ button, a Cancel button, or a successful save (which sets the property false server-side) close it. The slot stays in the DOM so wire:model fields keep their binding; x-show just toggles it. The server keeps the modal open on a validation error. 2. Legacy (server-driven) — pass :show="$flag" + close="...". Rendered only while $show is true. Kept for screens not yet migrated to mode 1. Same rule: no backdrop / Escape close — only the ✕ button. --}} @if ($wireModel !== null)
@if ($titleEdit !== null)

@else

{{ $title }}

@endif
{{ $slot }}
@isset($footer) @endisset
@elseif ($show)

{{ $title }}

{{ $slot }}
@isset($footer) @endisset
@endif