35 lines
1.3 KiB
Templ
35 lines
1.3 KiB
Templ
package components
|
|
|
|
// Modal renders a modal dialog.
|
|
//
|
|
// The <dialog> itself must never be an htmx swap target: swapping its
|
|
// innerHTML would replace the wrapper below (centering + close button) and
|
|
// break the layout. Content is swapped into the inner element with id
|
|
// "<id>-content" instead.
|
|
//
|
|
// In htmx 4 "htmx:after:swap" fires on the requesting element, which lives
|
|
// outside this dialog (e.g. gallery grid buttons). The listener is therefore
|
|
// attached document-wide via the bare hx-on form with "from:body" (the
|
|
// hx-on:<event> form cannot carry trigger specs: attribute names may not
|
|
// contain spaces) and guarded by ctx.target so only swaps into this dialog's
|
|
// content open it.
|
|
templ Modal(id string) {
|
|
<dialog
|
|
id={ id }
|
|
class="m-auto backdrop:bg-black/90 bg-transparent p-0 w-full h-full max-w-none max-h-none"
|
|
hx-on="htmx:after:swap from:body -> if (!this.open && this.contains(ctx.target)) this.showModal()"
|
|
>
|
|
<div class="relative w-full h-full flex items-center justify-center overflow-hidden">
|
|
<button
|
|
class="absolute right-5 top-5 z-10 p-2 text-white"
|
|
hx-on:click="this.closest('dialog').close()"
|
|
>
|
|
X
|
|
</button>
|
|
<div id={ id + "-content" } class="w-full h-full flex items-center justify-center overflow-hidden">
|
|
{ children... }
|
|
</div>
|
|
</div>
|
|
</dialog>
|
|
}
|