svelte-5-french-toast
Version:
Buttery smooth Svelte 5 toasts. Lightweight, customizable, and beautiful by default. Svelte 5 Only
98 lines (97 loc) • 2.74 kB
JavaScript
import { get, writable } from 'svelte/store';
import writableDerived from 'svelte-writable-derived';
const TOAST_LIMIT = 20;
export const toasts = writable([]);
export const pausedAt = writable(null);
const toastTimeouts = new Map();
const addToRemoveQueue = (toastId) => {
if (toastTimeouts.has(toastId)) {
return;
}
const timeout = setTimeout(() => {
toastTimeouts.delete(toastId);
remove(toastId);
}, 1000);
toastTimeouts.set(toastId, timeout);
};
const clearFromRemoveQueue = (toastId) => {
const timeout = toastTimeouts.get(toastId);
if (timeout) {
clearTimeout(timeout);
}
};
export function update(toast, clearTimeout = true) {
if (clearTimeout && toast.id) {
clearFromRemoveQueue(toast.id);
}
toasts.update(($toasts) => $toasts.map((t) => (t.id === toast.id ? { ...t, ...toast } : t)));
}
export function add(toast) {
toasts.update(($toasts) => [toast, ...$toasts].slice(0, TOAST_LIMIT));
}
export function upsert(toast) {
if (get(toasts).find((t) => t.id === toast.id)) {
update(toast);
}
else {
add(toast);
}
}
export function dismiss(toastId) {
toasts.update(($toasts) => {
if (toastId) {
addToRemoveQueue(toastId);
}
else {
$toasts.forEach((toast) => {
addToRemoveQueue(toast.id);
});
}
return $toasts.map((t) => t.id === toastId || toastId === undefined ? { ...t, visible: false } : t);
});
}
export function remove(toastId) {
toasts.update(($toasts) => {
if (toastId === undefined) {
return [];
}
return $toasts.filter((t) => t.id !== toastId);
});
}
export function startPause(time) {
pausedAt.set(time);
}
export function endPause(time) {
let diff;
pausedAt.update(($pausedAt) => {
diff = time - ($pausedAt || 0);
return null;
});
toasts.update(($toasts) => $toasts.map((t) => ({
...t,
pauseDuration: t.pauseDuration + diff
})));
}
const defaultTimeouts = {
blank: 4000,
error: 4000,
success: 2000,
loading: Infinity,
custom: 4000
};
export function useToasterStore(toastOptions = {}) {
const mergedToasts = writableDerived(toasts, ($toasts) => $toasts.map((t) => ({
...toastOptions,
...toastOptions[t.type],
...t,
duration: t.duration ||
toastOptions[t.type]?.duration ||
toastOptions?.duration ||
defaultTimeouts[t.type],
style: [toastOptions.style, toastOptions[t.type]?.style, t.style].join(';')
})), ($toasts) => $toasts);
return {
toasts: mergedToasts,
pausedAt
};
}