62 lines
1.7 KiB
JavaScript
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 }),
|
|
}
|
|
}
|