@opensig/opendesign
Version:
142 lines (141 loc) • 4.11 kB
JavaScript
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
};