160 lines
4.2 KiB
JavaScript
160 lines
4.2 KiB
JavaScript
const toasts = new Map();
|
|
|
|
const toastsContainer = t.div({ className: "toasts-container" });
|
|
|
|
/**
|
|
* Removes a single notification by its reference (key or content).
|
|
*
|
|
* @param {string|Node} toastRef
|
|
* @param {boolean} [animate]
|
|
*/
|
|
function removeToast(toastRef, animate = true) {
|
|
const toast = toasts.get(toastRef);
|
|
if (!toast || !toast.isConnected) {
|
|
return;
|
|
}
|
|
|
|
toasts.delete(toastRef);
|
|
clearTimeout(toast._removeTimeout);
|
|
|
|
if (animate) {
|
|
toast.classList.add("removing");
|
|
setTimeout(() => {
|
|
toast.remove();
|
|
}, 300);
|
|
} else {
|
|
toast.remove();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes all registered notifications.
|
|
*
|
|
* @param {boolean} [animate]
|
|
*/
|
|
function removeAllToasts(animate = true) {
|
|
toasts.forEach((_, key) => {
|
|
window.app.toasts.remove(key, animate);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Adds "info" notification.
|
|
*
|
|
* @see {@link addToast}
|
|
*/
|
|
function infoToast(textOrElem, options = {}) {
|
|
options.type = "info";
|
|
options.duration = options.duration || 3000;
|
|
|
|
addToast(textOrElem, options);
|
|
}
|
|
|
|
/**
|
|
* Adds "success" notification.
|
|
*
|
|
* @see {@link addToast}
|
|
*/
|
|
function successToast(textOrElem, options = {}) {
|
|
options.type = "success";
|
|
options.duration = options.duration || 3000;
|
|
|
|
addToast(textOrElem, options);
|
|
}
|
|
|
|
/**
|
|
* Adds "error" notification.
|
|
*
|
|
* @see {@link addToast}
|
|
*/
|
|
function errorToast(textOrElem, options = {}) {
|
|
options.type = "error";
|
|
options.duration = options.duration || 3500;
|
|
|
|
addToast(textOrElem, options);
|
|
}
|
|
|
|
/**
|
|
* Creates and registers a new toast notification.
|
|
*
|
|
* @param {string|Node} textOrElem The content of the notification as plain text or DOM node.
|
|
* @param {object} [options] Toast options.
|
|
* @param {number} [options.duration] Duration time in ms the notifaction would be active.
|
|
* @param {string} [options.key] Optional identifier that could be used to manually remove the specific notification (default to `textOrElem`).
|
|
* @param {string} [options.type] The CSS class type of the notification.
|
|
*/
|
|
function addToast(textOrElem, options = {}) {
|
|
options = Object.assign({ duration: 3000, key: undefined, type: "info" }, options);
|
|
|
|
if (!toastsContainer.isConnected) {
|
|
document.body.appendChild(toastsContainer);
|
|
}
|
|
|
|
const toastRef = options.key || textOrElem;
|
|
|
|
if (toasts.has(toastRef)) {
|
|
removeToast(toastRef, false);
|
|
}
|
|
|
|
function initRemoveTimer(el) {
|
|
if (el?._removeTimeout) {
|
|
clearTimeout(el?._removeTimeout);
|
|
}
|
|
|
|
el._removeTimeout = setTimeout(() => {
|
|
removeToast(toastRef);
|
|
}, options.duration);
|
|
}
|
|
|
|
let newToast = t.div(
|
|
{
|
|
className: `toast ${options.type || ""}`,
|
|
onmount: (el) => {
|
|
initRemoveTimer(el);
|
|
},
|
|
onunmount: (el) => {
|
|
if (el?._removeTimeout) {
|
|
clearTimeout(el?._removeTimeout);
|
|
newToast = null;
|
|
}
|
|
},
|
|
onmouseover: () => {
|
|
clearTimeout(newToast?._removeTimeout);
|
|
},
|
|
onmouseout: () => {
|
|
initRemoveTimer(newToast);
|
|
},
|
|
},
|
|
t.div(
|
|
{ className: "toast-container" },
|
|
t.div({ className: "toast-icon" }),
|
|
t.div(
|
|
{ className: "toast-content" },
|
|
textOrElem,
|
|
t.button(
|
|
{
|
|
type: "button",
|
|
className: "m-l-auto btn circle sm transparent secondary toast-remove",
|
|
title: "Clear",
|
|
onclick: () => removeToast(toastRef),
|
|
},
|
|
t.i({ className: "ri-close-line", ariaHidden: true }),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
toasts.set(toastRef, newToast);
|
|
toastsContainer.prepend(newToast);
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
|
|
window.app = window.app || {};
|
|
window.app.toasts = window.app.toasts || {};
|
|
window.app.toasts.info = infoToast;
|
|
window.app.toasts.error = errorToast;
|
|
window.app.toasts.success = successToast;
|
|
window.app.toasts.remove = removeToast;
|
|
window.app.toasts.removeAll = removeAllToasts;
|