From a4283ac66b8c24e75a426d997cb70bcbda813716 Mon Sep 17 00:00:00 2001 From: Natxo <1172351+natxocc@users.noreply.github.com> Date: Tue, 31 Mar 2026 12:19:37 +0200 Subject: [PATCH] Implement Toast component for notifications --- src/components/Toast.js | 63 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/components/Toast.js diff --git a/src/components/Toast.js b/src/components/Toast.js new file mode 100644 index 0000000..3d82b35 --- /dev/null +++ b/src/components/Toast.js @@ -0,0 +1,63 @@ +import { $html, $mount } from "sigpro"; +import { Button } from "./Button.js"; + +/** TOAST (Imperative Function) */ +export const Toast = (message, type = "alert-success", duration = 3500) => { + let container = document.getElementById("sigpro-toast-container"); + + // Crear el contenedor global si no existe + if (!container) { + container = $html("div", { + id: "sigpro-toast-container", + class: "fixed top-0 right-0 z-[9999] p-4 flex flex-col gap-2 pointer-events-none", + }); + document.body.appendChild(container); + } + + const toastHost = $html("div", { style: "display: contents" }); + container.appendChild(toastHost); + + let timeoutId; + + const close = () => { + clearTimeout(timeoutId); + const el = toastHost.firstElementChild; + if (el && !el.classList.contains("opacity-0")) { + el.classList.add("translate-x-full", "opacity-0"); + setTimeout(() => { + instance.destroy(); + toastHost.remove(); + // Limpiar el contenedor si ya no hay más toasts + if (!container.hasChildNodes()) container.remove(); + }, 300); + } else { + instance.destroy(); + toastHost.remove(); + } + }; + + const ToastComponent = () => { + const el = $html( + "div", + { + class: `alert alert-soft ${type} shadow-lg transition-all duration-300 translate-x-10 opacity-0 pointer-events-auto`, + }, + [ + $html("span", {}, [typeof message === "function" ? message() : message]), + Button({ class: "btn-xs btn-circle btn-ghost", onclick: close }, "✕") + ], + ); + + // Animación de entrada + requestAnimationFrame(() => el.classList.remove("translate-x-10", "opacity-0")); + return el; + }; + + const instance = $mount(ToastComponent, toastHost); + + if (duration > 0) { + timeoutId = setTimeout(close, duration); + } + + return close; +};