import { html, LitElement, nothing } from "lit"; import { customElement, property } from "lit/decorators.js"; import { repeat } from "lit/directives/repeat.js"; import { animate } from "@lit-labs/motion"; import Objects from "@supersoniks/concorde/core/utils/Objects"; import "@supersoniks/concorde/core/components/ui/icon/icon"; import { ifDefined } from "lit/directives/if-defined.js"; import { unsafeHTML } from "lit/directives/unsafe-html.js"; import { styleMap, StyleInfo } from "lit/directives/style-map.js"; import "@supersoniks/concorde/core/components/ui/toast/toast-item"; import { Toast, ToastStatus, } from "@supersoniks/concorde/core/components/ui/toast/types"; import { ConcordeWindow } from "@supersoniks/concorde/core/_types/types"; import { Theme } from "@supersoniks/concorde/core/components/ui/theme/theme"; import { sonicClassPrefix } from "@supersoniks/concorde/core/utils/Utils"; declare const window: ConcordeWindow; const tagName = "sonic-toast"; @customElement(tagName) export class SonicToast extends LitElement { @property({ type: Array }) toasts: Toast[] = []; static delegateToasts = false; createRenderRoot() { return this; } render() { const isIframe = !(window.parent == window); let styles: Readonly = { pointerEvents: "none", gap: "1rem", display: "flex", margin: this.toasts.length ? "1rem" : "0", }; if (!isIframe) { styles = { ...styles, margin: "0", width: "calc(100% - 2.5rem)", position: "fixed", bottom: "1.25rem", right: "1.25rem", zIndex: "10000", maxWidth: "64ch", flexDirection: "column-reverse", }; } // ${window.parent == window ? "fixed-area" : ""} SonicToast.handleExistingToastDelegation(); if (!this.toasts) return nothing; return html`
${repeat( this.toasts, (item) => item.id, (item) => html` this.removeItem(item)} ${animate({ keyframeOptions: { duration: 250, easing: `cubic-bezier(0.250, 0.250, 0.420, 1.225)`, }, in: [ { transform: "translateY(0) scale(1.25)", boxShadow: "0 0 0 rgba(0,0,0,0)", opacity: 0, }, ], out: [ { transform: "scale(.90) ", opacity: 0, duration: 3000, easing: `ease-in-out`, }, ], stabilizeOut: true, })} > ${item.text ? unsafeHTML(item.text) : ""} ` )}
`; } static removeAll() { if (SonicToast.delegateToasts) { SonicToast.handleExistingToastDelegation(); window.parent.postMessage({ type: "removeAllToasts" }, "*"); return; } const toastComponent: SonicToast = SonicToast.getInstance(); if (!toastComponent) return; toastComponent.toasts = toastComponent.toasts.filter((item) => item.ghost); } static removeItemsByStatus(status: ToastStatus) { if (SonicToast.delegateToasts) { SonicToast.handleExistingToastDelegation(); window.parent.postMessage({ type: "removeItemsByStatus", status }, "*"); return; } const toastComponent: SonicToast = SonicToast.getInstance(); if (!toastComponent) return; // Filtrer pour garder seulement les toasts qui ne correspondent pas au statut donné toastComponent.toasts = toastComponent.toasts.filter( (toast) => toast.status !== status ); } // retire les items qui ne sont pas en preserve static removeTemporaryItems() { if (SonicToast.delegateToasts) { SonicToast.handleExistingToastDelegation(); window.parent.postMessage({ type: "removeTemporaryItems" }, "*"); return; } const toastComponent: SonicToast = SonicToast.getInstance(); if (!toastComponent) return; toastComponent.toasts = toastComponent.toasts.filter( (item) => item.preserve ); } // ADD TOAST static instance?: SonicToast; static getInstance() { if (SonicToast.instance) return SonicToast.instance; SonicToast.instance = document.createElement("sonic-toast") as SonicToast; Theme.getPopContainer().prepend(SonicToast.instance); return SonicToast.instance; } static add(conf: Toast) { if (SonicToast.delegateToasts) { SonicToast.handleExistingToastDelegation(); window.parent.postMessage({ type: "addToast", toast: conf }, "*"); return; } // Init toast area si absente (au ou ||||" ); const hasInteractive = interactiveRegExp.test(conf.text); const currentToast = { id: nextId, text: conf.text, title: conf.title, status: conf.status, preserve: hasInteractive ? true : conf.preserve, ghost: conf.ghost, dismissForever: conf.dismissForever, }; // check if the toast is dismissed if (conf.dismissForever && conf.id) { const dismissed = localStorage.getItem("sonic-toast-dismissed") || "{}"; const dismissedObj = JSON.parse(dismissed); if (dismissedObj[conf.id]) { return null; } } if (toastComponent?.toasts.length) { const toastA = { ...currentToast }; for (const toast of toastComponent.toasts) { const toastB = { ...toast }; toastA.id = toastB.id = 0; if ( /*!currentToast.preserve && */ Objects.shallowEqual(toastA, toastB) ) { return null; } } } if (toastComponent) { toastComponent.toasts = [...toastComponent.toasts, currentToast]; } return currentToast; } static handleExistingToastDelegation() { if (!this.delegateToasts) return; const toastComponent: SonicToast = SonicToast.getInstance(); window.parent.postMessage( { type: "addToasts", toasts: toastComponent.toasts }, "*" ); toastComponent.toasts = []; } static removeItem(toastToRemove?: Toast) { if (SonicToast.delegateToasts) { SonicToast.handleExistingToastDelegation(); window.parent.postMessage( { type: "removeToast", toast: toastToRemove }, "*" ); return; } const toastComponent: SonicToast = SonicToast.getInstance(); if (!toastComponent) return; toastComponent.removeItem(toastToRemove); } // Remove Toast removeItem(toastToRemove?: Toast) { if (!toastToRemove) return; this.toasts = this.toasts.filter((toast) => { toast = { ...toast }; delete toast.id; return !Objects.shallowEqual(toast, toastToRemove, false); }); } } if (typeof window !== "undefined") { window[sonicClassPrefix + "Toast"] = window[sonicClassPrefix + "Toast"] || SonicToast; } /** * Handles the context of iframes and performs necessary actions based on received messages. */ function handleIframeContexts() { const onPostMessage = (e: MessageEvent) => { if (e.data.type == "querySonicToastAvailability") { (e.source as Window).postMessage({ type: "sonicToastAvailable" }, "*"); } if (e.data.type == "removeItemsByStatus") { SonicToast.removeItemsByStatus(e.data.status); } if (e.data.type == "removeTemporaryItems") { SonicToast.removeTemporaryItems(); } if (e.data.type == "sonicToastAvailable") { SonicToast.delegateToasts = true; SonicToast.handleExistingToastDelegation(); } if (e.data.type == "addToasts") { SonicToast.getInstance().toasts = [ ...SonicToast.getInstance().toasts, ...e.data.toasts, ]; } if (e.data.type == "removeAllToasts") { SonicToast.removeAll(); } if (e.data.type == "removeToast") { SonicToast.removeItem(e.data.toast); } if (e.data.type == "addToast") { SonicToast.add(e.data.toast); } }; const isIframe = !(window.parent == window); window.addEventListener("message", onPostMessage, false); if (isIframe) { window.parent.postMessage({ type: "querySonicToastAvailability" }, "*"); } // tell iframes that sonic-toast is available if (!isIframe) { for (const iframe of document.querySelectorAll("iframe")) { iframe.contentWindow?.postMessage({ type: "sonicToastAvailable" }, "*"); } } } handleIframeContexts();