@props([
'anchor' => 'se',
])
@php
use App\Support\Ui\Pulse;
$seed = Pulse::pending();
$anchorClass = match ($anchor) {
'nw' => 'top-4 left-4 items-start',
'n' => 'top-4 inset-x-0 items-center',
'ne' => 'top-4 right-4 items-end',
'sw' => 'bottom-4 left-4 items-start',
's' => 'bottom-4 inset-x-0 items-center',
default => 'bottom-4 right-4 items-end',
};
@endphp
class(['pointer-events-none fixed z-[80] flex max-w-md flex-col gap-2', $anchorClass]) }}
aria-live="polite"
x-data="{
stack: [],
boot: @js($seed),
init() {
if (this.boot) this.ingest(this.boot)
},
ingest(raw) {
const packet = Array.isArray(raw) ? raw[0] : raw
if (! packet || typeof packet !== 'object') return
const copy = packet.copy ?? packet.body ?? packet.message ?? packet.text ?? null
if (! copy) return
const uid = packet.uid || packet.id || (Date.now() + '-' + Math.random().toString(16).slice(2))
const row = {
uid,
copy,
eyebrow: packet.eyebrow ?? packet.title ?? packet.heading ?? null,
tone: packet.tone ?? packet.variant ?? 'note',
linger: Number(packet.linger ?? packet.duration ?? 4500),
open: true,
}
this.stack = [...this.stack, row]
if (row.linger > 0) {
setTimeout(() => this.retire(uid), row.linger)
}
},
retire(uid) {
this.stack = this.stack.map((item) =>
item.uid === uid ? { ...item, open: false } : item
)
setTimeout(() => {
this.stack = this.stack.filter((item) => item.uid !== uid)
}, 180)
},
toneOf(tone) {
if (tone === 'ok' || tone === 'success') return 'ok'
if (tone === 'fail' || tone === 'danger') return 'fail'
if (tone === 'warn' || tone === 'warning') return 'warn'
return 'note'
},
}"
x-on:krikkit-pulse.window="ingest($event.detail)"
>