@stackoverfloweth/prefect-design
Version:
A collection of low-level Vue components.
106 lines (80 loc) • 2.4 kB
text/typescript
import { App, createApp, reactive, Plugin, Component, markRaw } from 'vue'
import ToastContainer from '@/components/Toast/ToastContainer.vue'
type ToastType = 'default' | 'success' | 'error'
type Toast = {
id: number,
message: string | Component,
type: ToastType,
dismissible: boolean,
timeout: number | false,
dismiss: () => void,
}
type ToastOptions = {
dismissible?: boolean,
timeout?: number | false,
}
type ToastPluginOptions = {
mountPoint?: Element | string,
}
let toastId = 0
const queue: Toast[] = reactive([])
function getToastId(): number {
return toastId++
}
function hideToast(id: number): void {
const index = queue.findIndex(toast => toast.id === id)
if (index > -1) {
queue.splice(index, 1)
}
}
function createDefaultMountElement(): Element {
const element = document.createElement('div')
element.id = 'prefect-design-toast-app'
document.body.appendChild(element)
return element
}
function tryQuerySelector(query: string): Element {
const element = document.querySelector(query)
if (!element) {
throw new Error(
"Toast plugin wasn't provided a valid mount point. Make sure the mount point exists in the DOM or pass nothing to create one automatically.",
)
}
return element
}
function getMountElement(mountPoint: Element | string | undefined): Element {
if (!mountPoint) {
return createDefaultMountElement()
}
if (typeof mountPoint === 'string') {
return tryQuerySelector(mountPoint)
}
return mountPoint
}
function showToast(message: string | Component, type: ToastType = 'default', options?: ToastOptions): Toast {
const id = getToastId()
const defaultOptions: Required<ToastOptions> = {
dismissible: true,
timeout: 5000,
}
const rawMessage = typeof message === 'string' ? message : markRaw(message)
const toast: Toast = {
...defaultOptions,
id,
message: rawMessage,
type,
dismiss: () => hideToast(id),
...options,
}
queue.unshift(toast)
return toast
}
const ToastPlugin: Required<Plugin> = {
install: (app: App, options: ToastPluginOptions = {}) => {
const element = getMountElement(options.mountPoint)
createApp(ToastContainer).mount(element)
app.config.globalProperties.$toast = showToast
},
}
export type { Toast, ToastType, ToastOptions, ToastPluginOptions }
export { ToastPlugin, queue, showToast, hideToast }