Files
tier-maker/frontend/src/composables/useToast.js

62 lines
1.7 KiB
JavaScript

import { readonly, ref } from 'vue'
const toasts = ref([])
let toastSeq = 0
const TOAST_EXIT_MS = 220
function clearToastTimer(toast) {
if (toast?.timerId) {
window.clearTimeout(toast.timerId)
toast.timerId = 0
}
}
function removeToast(id) {
toasts.value = toasts.value.filter((toast) => toast.id !== id)
}
function dismissToast(id) {
const target = toasts.value.find((toast) => toast.id === id)
if (!target || target.isClosing) return
clearToastTimer(target)
target.isClosing = true
target.timerId = window.setTimeout(() => removeToast(id), TOAST_EXIT_MS)
}
function showToast(message, { type = 'info', duration = 2600 } = {}) {
if (!message) return ''
const duplicated = toasts.value.find((toast) => toast.message === message && toast.type === type && !toast.isClosing)
if (duplicated) {
duplicated.count = (duplicated.count || 1) + 1
clearToastTimer(duplicated)
if (duration > 0) {
duplicated.timerId = window.setTimeout(() => dismissToast(duplicated.id), duration)
}
toasts.value = [...toasts.value]
return duplicated.id
}
const id = `toast-${++toastSeq}`
const nextToast = { id, message, type, count: 1, isClosing: false, timerId: 0 }
toasts.value = [...toasts.value, nextToast]
if (duration > 0) {
nextToast.timerId = window.setTimeout(() => dismissToast(id), duration)
}
return id
}
export function useToast() {
return {
toasts: readonly(toasts),
dismissToast,
showToast,
success: (message, options = {}) => showToast(message, { type: 'success', ...options }),
error: (message, options = {}) => showToast(message, { type: 'error', ...options }),
info: (message, options = {}) => showToast(message, { type: 'info', ...options }),
}
}