UNPKG

@opensig/opendesign

Version:

142 lines (141 loc) 4.11 kB
import { render, createVNode, nextTick } from "vue"; import { isString, isNumber } from "../_utils/is.mjs"; import { resolveHtmlElement } from "../_utils/vue-utils.mjs"; import _sfc_main from "./OToastList.vue.mjs"; import { Duration } from "./types.mjs"; const DEFAULT_OPTIONS = { position: "bottom" }; const instanceMap = /* @__PURE__ */ new Map(); const normalizeOptions = (params) => { const options = !params || isString(params) ? { content: params } : params; const { long, duration } = options; const defaultDuration = long ? Duration.LONG : Duration.NORMAL; const rlt = isNumber(duration) && duration > 0 ? duration : defaultDuration; const normalized = { ...DEFAULT_OPTIONS, ...options, duration: rlt }; return normalized; }; const getToastStyle = (targetEl, position = "top", align = "left", offset = 8) => { if (!targetEl) { return; } const rect = targetEl.getBoundingClientRect(); let pos = "bottom"; let top = window.innerHeight - rect.top + offset; let left = rect.left; let transform = "translateX(-50%)"; if (position === "bottom") { pos = "top"; top = rect.top + rect.height + offset; } if (align === "right") { left = rect.left + rect.width; transform = "translateX(-100%)"; } else if (align === "left") { left = rect.left; transform = "translateX(0%)"; } else { left = rect.left + rect.width / 2; transform = "translateX(-50%)"; } if (position === "center") { pos = "top"; left = rect.left + rect.width / 2; top = rect.top + rect.height / 2; transform = "translate(-50%, -50%)"; } return { position: pos, "--toast-list-offset": `${top}px`, [`--toast-list-${pos}-offset`]: `${top}px`, left: `${left}px`, transform }; }; const createToastListVnode = ({ position, wrap, style, targetEl }) => { return createVNode(_sfc_main, { position: (style == null ? void 0 : style.position) ?? position, onDestroy: async () => { if (wrap) { render(null, wrap); await nextTick(); document.body.removeChild(wrap); } instanceMap.delete(targetEl ?? position); }, style }); }; const showToast = (target, closeHandlers, params) => { const options = normalizeOptions(params); const { position, targetAlign, targetOffset } = options; let id = -1; let instance; let isClosed = false; resolveHtmlElement(target).then((targetEl) => { var _a, _b, _c; if (isClosed) { return; } const toastStyle = getToastStyle(targetEl, position, targetAlign, targetOffset); instance = instanceMap.get(targetEl ?? position); if (!instance) { const wrap = document.createElement("div"); const vnode = createToastListVnode({ position, wrap, style: toastStyle, targetEl }); closeAll(); render(vnode, wrap); const vm = vnode.component; id = (_a = vm.exposed) == null ? void 0 : _a.add(options); instance = vm; instanceMap.set(targetEl ?? position, instance); document.body.appendChild(wrap); } else { (_b = instance.exposed) == null ? void 0 : _b.remove(id); id = (_c = instance.exposed) == null ? void 0 : _c.add(options); } }); const closeHandler = () => { var _a; isClosed = true; (_a = instance == null ? void 0 : instance.exposed) == null ? void 0 : _a.close(id); closeHandlers.delete(closeHandler); }; closeHandlers.add(closeHandler); return closeHandler; }; const closeAll = () => { var _a; for (const ins of instanceMap.values()) { (_a = ins == null ? void 0 : ins.exposed) == null ? void 0 : _a.removeAll(); } }; const close = (closeHandlers) => { closeHandlers.forEach((handler) => handler()); }; function useToast(target) { const closeHandlers = /* @__PURE__ */ new Set(); return { show: showToast.bind(null, target, closeHandlers), /** 关闭本 useToast 实例渲染的所有消息 */ close: close.bind(null, closeHandlers), /** 关闭所有实例渲染的所有消息 */ closeAll }; } export { useToast };