Files
pocketbase/ui/src/base/toast.js
T

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;