UNPKG

ftt-ui-components

Version:

some components for vuetify3/element-plus/... with vue3.

149 lines (121 loc) 3.49 kB
import { render, createVNode } from 'vue' import { messageDefaults, messageTypes } from './message' import MessageConstructor from './message.vue' import { isString, isVNode, isFunction, isElement } from '../../utils' import { isClient } from '@vueuse/core' import { instances } from './instance' import { useZIndex } from '../../hooks' import type { AppContext } from 'vue' import type { MessageContext } from './instance' import type { Message, MessageFn, MessageHandler, MessageOptions, MessageParams, MessageParamsNormalized, messageType, } from './message' let seed = 1 const normalizeOptions = (params?: MessageParams) => { const options: MessageOptions = !params || isString(params) || isVNode(params) || isFunction(params) ? { message: params } : params const normalized = { ...messageDefaults, ...options, } if (!normalized.appendTo) { normalized.appendTo = document.body } else if (isString(normalized.appendTo)) { let appendTo = document.querySelector<HTMLElement>(normalized.appendTo) // should fallback to default value with a warning if (!isElement(appendTo)) { appendTo = document.body } normalized.appendTo = appendTo } return normalized as MessageParamsNormalized } const closeMessage = (instance: MessageContext) => { const idx = instances.indexOf(instance) if (idx === -1) return instances.splice(idx, 1) const { handler } = instance handler.close() } const createMessage = ( { appendTo, ...options }: MessageParamsNormalized, context?: AppContext | null ): MessageContext => { const { nextZIndex } = useZIndex() const id = `message_${seed++}` const userOnClose = options.onClose const container = document.createElement('div') const props = { ...options, zIndex: nextZIndex() + options.zIndex, id, onClose() { userOnClose?.() closeMessage(instance) }, onDestroy() { render(null, container) }, } const vnode = createVNode( MessageConstructor, props, isFunction(props.message) || isVNode(props.message) ? { default: props.message } : null ) vnode.appContext = context || message._context render(vnode, container) // appendTo.appendChild(container.firstElementChild) appendTo.appendChild(container) const vm = vnode.component const handler: MessageHandler = { close: () => (vm.exposeProxy.visible = false), } const instance: MessageContext = { id, vnode, vm, handler, props: (vnode.component as any).props, } return instance } const message: MessageFn & Partial<Message> & { _context: AppContext | null } = (options = {}, context) => { if (!isClient) return { close: () => undefined } const normalized = normalizeOptions(options) if (normalized.grouping && instances.length) { const instance = instances.find( ({ vnode: vm }) => vm.props?.message === normalized.message ) if (instance) { instance.props.repeatNum += 1 instance.props.type = normalized.type return instance.handler } } const instance = createMessage(normalized, context) instances.push(instance) return instance.handler } export function closeAll(type?: messageType): void { for (const instance of instances) { if (!type || type === instance.props.type) { instance.handler.close() } } } message.closeAll = closeAll message._context = null export default message as Message