vue3-modal-manager
Version:
A flexible and powerful modal manager for Vue 3
820 lines (819 loc) • 30.8 kB
JavaScript
var v = Object.defineProperty;
var b = (d, t, e) => t in d ? v(d, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : d[t] = e;
var l = (d, t, e) => b(d, typeof t != "symbol" ? t + "" : t, e);
import { createVNode as E, render as y } from "vue";
class D {
//最小高度
/**
* 初始化函數
* @param currentModal modal
*/
constructor(t) {
l(this, "currentModal");
//modal
l(this, "resizeHandlers", /* @__PURE__ */ new Map());
//儲存個方位拖曳節點
l(this, "resizing", !1);
//是否正在改變大小
l(this, "resizeDirection", "");
//當前調整大小的方位
l(this, "initialSize");
//初始大小及位置
l(this, "initialMouse", { x: 0, y: 0 });
//初始滑鼠位置
l(this, "minWidth", 100);
//最小寬度
l(this, "minHeight", 100);
//==================================拖曳中==================================
/**
* 拖曳中(正在調整大小)
* @param e 滑鼠事件
* @returns
*/
l(this, "handleResize", (t) => {
this.resizing && (t.preventDefault(), requestAnimationFrame(() => {
this.performResize(t);
}));
});
//==================================拖曳結束==================================
/**
* 拖曳結束(結束調整大小)
*/
l(this, "stopResize", () => {
if (!this.resizing) return;
const { container: t, id: e } = this.currentModal;
t.classList.remove("modal-resizing");
const i = t.querySelector(`#${e}`);
i && this.updateHandlesPosition(i);
const n = t.getBoundingClientRect();
this.emitResizeEndEvent(this.currentModal, n.width, n.height), this.resizing = !1, this.resizeDirection = "", document.removeEventListener("mousemove", this.handleResize), document.removeEventListener("mouseup", this.stopResize);
});
this.currentModal = t, this.initialSize = this.createEmptyModalSize(), this.createResizeHandles(t.id), this.bindResize(t.id);
}
//==================================物件初始化==================================
/**
* 初始預設大小及位置
*/
createEmptyModalSize() {
return {
width: 0,
height: 0,
left: 0,
top: 0,
right: 0,
bottom: 0,
mouseLimits: {
limitX: { min: 0, max: 0 },
limitY: { min: 0, max: 0 },
limitXY: { x: { min: 0, max: 0 }, y: { min: 0, max: 0 } }
}
};
}
/**
* 創建調整大小的手柄
* @param modalId modal的ID
* @returns 是否成功創建
*/
createResizeHandles(t) {
const e = ["e", "s", "se", "w", "n", "ne", "sw", "nw"], i = this.currentModal.container.querySelector(`#${t}`);
return i ? (i.querySelectorAll(".resize-handle").length > 0 || (window.getComputedStyle(i).position === "static" && (i.style.position = "relative"), e.forEach((o) => {
const r = document.createElement("div");
r.setAttribute("modalResizeArea", t), r.setAttribute("data-direction", o), r.className = `resize-handle resize-${o}`, Object.assign(r.style, {
position: "absolute",
background: "transparent",
pointerEvents: "auto",
zIndex: "1001"
}), this.setHandleStyle(r, o), i.appendChild(r);
})), !0) : (console.warn(`Modal body element with id ${t} not found`), !1);
}
/**
* 設定調整大小節點
* @param handle 節點dom
* @param direction 方位
*/
setHandleStyle(t, e) {
const n = {
e: { top: "0", right: "0", width: "5px", height: "100%", cursor: "e-resize" },
s: { bottom: "0", left: "0", width: "100%", height: "5px", cursor: "s-resize" },
se: { bottom: "0", right: "0", width: "10px", height: "10px", cursor: "se-resize" },
w: { top: "0", left: "0", width: "5px", height: "100%", cursor: "w-resize" },
n: { top: "0", left: "0", width: "100%", height: "5px", cursor: "n-resize" },
ne: { top: "0", right: "0", width: "10px", height: "10px", cursor: "ne-resize" },
sw: { bottom: "0", left: "0", width: "10px", height: "10px", cursor: "sw-resize" },
nw: { top: "0", left: "0", width: "10px", height: "10px", cursor: "nw-resize" }
}[e];
n && Object.assign(t.style, n);
}
/**
* 重置modal物件
* @param currentModal 當前Modal
*/
setCurrentModal(t) {
const e = this.currentModal.id;
this.unbindResize(e), this.currentModal = t, this.createResizeHandles(t.id), this.bindResize(t.id);
}
//==================================功能綁定==================================
/**
* 綁定調整大小事件
* @param modalId modal的ID
* @returns 是否成功綁定
*/
bindResize(t) {
const e = this.currentModal.container.querySelector(`#${t}`);
if (!e)
return console.warn(`Modal body not found for ${t}`), !1;
const i = e.querySelectorAll(
`[modalResizeArea="${t}"]`
);
return i.length === 0 ? (console.warn(`No resize handles found for modal ${t}`), !1) : (this.resizeHandlers.clear(), i.forEach((n) => {
const s = n.dataset.direction || "", o = (a) => this.startResize(a, s), r = `${t}-${s}`;
this.resizeHandlers.set(r, o), n.addEventListener("mousedown", o);
}), !0);
}
/**
* 解除綁定
* @param modalId modal的ID
*/
unbindResize(t) {
this.resizing && this.forceStopResize();
const e = this.currentModal.container.querySelector(`#${t}`);
e && e.querySelectorAll(
`[modalResizeArea="${t}"]`
).forEach((n) => {
const s = n.dataset.direction || "", o = `${t}-${s}`, r = this.resizeHandlers.get(o);
r && (n.removeEventListener("mousedown", r), this.resizeHandlers.delete(o)), n.remove();
}), this.resizeHandlers.clear();
}
//==================================開始拖曳==================================
/**
* 開始拖曳(開始調整大小)
* @param e 滑鼠事件
* @param direction 方位
* @returns
*/
startResize(t, e) {
if (this.resizing || t.button !== 0) return;
t.preventDefault(), t.stopPropagation(), this.initialMouse = { x: t.clientX, y: t.clientY };
const i = this.calculateInitialPosition();
this.initialSize = {
width: i.width,
height: i.height,
left: i.left,
top: i.top,
right: i.right,
bottom: i.bottom,
mouseLimits: i.mouseLimits
}, this.resizing = !0, this.resizeDirection = e, document.addEventListener("mousemove", this.handleResize), document.addEventListener("mouseup", this.stopResize), this.currentModal.container.classList.add("modal-resizing");
}
/**
* 紀錄拖曳初始位置
*/
calculateInitialPosition() {
const t = this.currentModal.container, e = this.currentModal.boxElement, i = t.getBoundingClientRect(), n = e.getBoundingClientRect(), o = window.getComputedStyle(t).transform;
let r, a, u, h;
if (o !== "none" && o !== "") {
t.style.transform = "none";
const g = i.left + i.width / 2, M = i.top + i.height / 2;
r = g - i.width / 2 - n.left, a = M - i.height / 2 - n.top, u = n.width - (r + i.width), h = n.height - (a + i.height), t.style.left = "auto", t.style.top = "auto", t.style.inset = `${a}px ${u}px ${h}px ${r}px`;
} else
r = i.left - n.left, a = i.top - n.top, u = n.width - (r + i.width), h = n.height - (a + i.height);
const c = {
limitX: {
min: n.left + 5,
max: n.width + n.left - 5
},
limitY: {
min: n.top + 5,
max: n.height + n.top - 5
},
limitXY: {
x: { min: n.left + 9, max: n.width + n.left - 9 },
y: { min: n.top + 9, max: n.height + n.top - 9 }
}
};
return {
width: i.width,
height: i.height,
left: r,
top: a,
right: u,
bottom: h,
mouseLimits: c
};
}
/**
* 動態計算modal大小和位置
* @param e 滑鼠事件
*/
performResize(t) {
const e = t.clientX, i = t.clientY;
let n = e - this.initialMouse.x, s = i - this.initialMouse.y;
const o = this.calcMouseMoveRange();
"min" in o ? this.resizeDirection === "e" || this.resizeDirection === "w" ? n = Math.max(o.min, Math.min(n, o.max)) : s = Math.max(o.min, Math.min(s, o.max)) : (n = Math.max(o.x.min, Math.min(n, o.x.max)), s = Math.max(o.y.min, Math.min(s, o.y.max)));
const r = this.calculateNewSizes(n, s), a = this.currentModal.container.querySelector(
`#${this.currentModal.id}`
);
a && (a.style.width = `${r.width}px`, a.style.height = `${r.height}px`, this.currentModal.container.style.inset = `${r.top}px ${r.right}px ${r.bottom}px ${r.left}px`, this.updateHandlesPosition(a), this.emitResizeEvent(this.currentModal, r.width, r.height));
}
/**
* 計算新的尺寸及大小
* @param deltaX x軸位移
* @param deltaY y軸位移
* @returns
*/
calculateNewSizes(t, e) {
let i = this.initialSize.width, n = this.initialSize.height, s = this.initialSize.left, o = this.initialSize.top, r = this.initialSize.right, a = this.initialSize.bottom;
switch (this.resizeDirection) {
case "e":
i = Math.max(this.minWidth, this.initialSize.width + t), r = this.initialSize.right - (i - this.initialSize.width);
break;
case "w":
i = Math.max(this.minWidth, this.initialSize.width - t), s = this.initialSize.left + (this.initialSize.width - i);
break;
case "s":
n = Math.max(this.minHeight, this.initialSize.height + e), a = this.initialSize.bottom - (n - this.initialSize.height);
break;
case "n":
n = Math.max(this.minHeight, this.initialSize.height - e), o = this.initialSize.top + (this.initialSize.height - n);
break;
case "se":
i = Math.max(this.minWidth, this.initialSize.width + t), n = Math.max(this.minHeight, this.initialSize.height + e), r = this.initialSize.right - (i - this.initialSize.width), a = this.initialSize.bottom - (n - this.initialSize.height);
break;
case "sw":
i = Math.max(this.minWidth, this.initialSize.width - t), n = Math.max(this.minHeight, this.initialSize.height + e), s = this.initialSize.left + (this.initialSize.width - i), a = this.initialSize.bottom - (n - this.initialSize.height);
break;
case "ne":
i = Math.max(this.minWidth, this.initialSize.width + t), n = Math.max(this.minHeight, this.initialSize.height - e), r = this.initialSize.right - (i - this.initialSize.width), o = this.initialSize.top + (this.initialSize.height - n);
break;
case "nw":
i = Math.max(this.minWidth, this.initialSize.width - t), n = Math.max(this.minHeight, this.initialSize.height - e), s = this.initialSize.left + (this.initialSize.width - i), o = this.initialSize.top + (this.initialSize.height - n);
break;
}
return {
width: i,
height: n,
left: s,
top: o,
right: r,
bottom: a
};
}
/**
* 計算各方位滑鼠移動限制
* @returns
*/
calcMouseMoveRange() {
switch (this.resizeDirection) {
case "e":
return {
min: this.minWidth - this.initialSize.width,
max: this.initialSize.mouseLimits.limitX.max - this.initialMouse.x
};
case "w":
return {
min: this.initialSize.mouseLimits.limitX.min - this.initialMouse.x,
max: -(this.minWidth - this.initialSize.width)
};
case "s":
return {
min: this.minHeight - this.initialSize.height,
max: this.initialSize.mouseLimits.limitY.max - this.initialMouse.y
};
case "n":
return {
min: this.initialSize.mouseLimits.limitY.min - this.initialMouse.y,
max: -(this.minHeight - this.initialSize.height)
};
case "se":
case "sw":
case "ne":
case "nw":
const t = {
x: { min: 0, max: 0 },
y: { min: 0, max: 0 }
};
return this.resizeDirection.includes("e") ? (t.x.min = this.minWidth - this.initialSize.width, t.x.max = this.initialSize.mouseLimits.limitXY.x.max - this.initialMouse.x) : (t.x.min = this.initialSize.mouseLimits.limitXY.x.min - this.initialMouse.x, t.x.max = -(this.minWidth - this.initialSize.width)), this.resizeDirection.includes("s") ? (t.y.min = this.minHeight - this.initialSize.height, t.y.max = this.initialSize.mouseLimits.limitXY.y.max - this.initialMouse.y) : (t.y.min = this.initialSize.mouseLimits.limitXY.y.min - this.initialMouse.y, t.y.max = -(this.minHeight - this.initialSize.height)), t;
default:
return { min: 0, max: 0 };
}
}
/**
* 更新節點(handles)位置
* @param modalBody modal元素
*/
updateHandlesPosition(t) {
t.querySelectorAll(".resize-handle").forEach((i) => {
const n = i.dataset.direction;
n && this.setHandleStyle(i, n);
});
}
/**
* 強制結束拖曳
*/
forceStopResize() {
this.resizing = !1, this.resizeDirection = "", this.currentModal.container.classList.remove("modal-resizing"), document.removeEventListener("mousemove", this.handleResize), document.removeEventListener("mouseup", this.stopResize);
}
//==================================發送事件==================================
/**
* 發送正在調整大小事件
* @param modal modal資訊
* @param width 寬度
* @param height 高度
*/
emitResizeEvent(t, e, i) {
const n = new CustomEvent("modal-resize", {
detail: { modalId: t.id, width: e, height: i }
});
t.container.dispatchEvent(n);
}
/**
* 發送調整大小結束事件
* @param modal modal資訊
* @param width 寬度
* @param height 高度
*/
emitResizeEndEvent(t, e, i) {
const n = new CustomEvent("modal-resize-end", {
detail: { modalId: t.id, width: e, height: i }
});
t.container.dispatchEvent(n);
}
//==================================銷毀物件==================================
/**
* 銷毀物件
*/
destroy() {
this.unbindResize(this.currentModal.id), this.forceStopResize();
}
}
class L {
//是否正在拖曳
/**
* 初始化函數
* @param currentModal modal
*/
constructor(t) {
l(this, "currentModal");
//modal
l(this, "modalHeader", null);
//modal header元素
l(this, "handleDrag", null);
//拖曳事件方法
l(this, "initPosition");
//初始位置
l(this, "isDragging", !1);
//==================================開始拖曳==================================
/**
* 開始拖曳
* @param e 滑鼠事件
* @param modalId modal Id
* @returns
*/
l(this, "startDrag", (t) => {
if (this.isDragging || t.button !== 0) return;
this.isDragging = !0;
const { container: e } = this.currentModal, i = e.getBoundingClientRect();
this.initPosition = {
initialMouseX: t.clientX,
initialMouseY: t.clientY,
initialModalX: i.left,
initialModalY: i.top
}, document.addEventListener("mousemove", this.calcMouseDisplacement), document.addEventListener("mouseup", this.stopDrag), t.preventDefault(), t.stopPropagation(), e.classList.add("modal-dragging");
});
//==================================拖曳中==================================
/**
* 計算拖曳modal元件的位移
* @param e 滑鼠事件
* @returns
*/
l(this, "calcMouseDisplacement", (t) => {
if (!this.isDragging) return;
const { container: e, boxElement: i } = this.currentModal, { initialMouseX: n, initialMouseY: s, initialModalX: o, initialModalY: r } = this.initPosition, a = t.clientX - n, u = t.clientY - s;
let h = o + a, m = r + u;
const c = i.getBoundingClientRect(), g = e.getBoundingClientRect(), M = c.left, p = c.right - g.width, w = c.top, S = c.bottom - g.height;
h = Math.max(M, Math.min(h, p)), m = Math.max(w, Math.min(m, S));
const z = h - c.left, x = m - c.top;
e.style.left = `${z}px`, e.style.top = `${x}px`, e.style.transform = "none", this.emitDragEvent(z, x);
});
//==================================拖曳結束==================================
/**
* 停止拖曳
*/
l(this, "stopDrag", () => {
if (!this.isDragging) return;
const { container: t } = this.currentModal;
this.isDragging = !1, document.removeEventListener("mousemove", this.calcMouseDisplacement), document.removeEventListener("mouseup", this.stopDrag), t.classList.remove("modal-dragging");
const e = t.getBoundingClientRect(), i = this.currentModal.boxElement.getBoundingClientRect(), n = e.left - i.left, s = e.top - i.top;
this.emitDragEndEvent(n, s);
});
this.currentModal = t, this.initPosition = {}, this.bindDrag();
}
//==================================物件初始化==================================
/**
* 設置當前modal
* @param currentModal modal
*/
setCurrentModal(t) {
this.currentModal = t, this.modalHeader && (this.unbindDrag(), this.bindDrag());
}
//==================================功能綁定==================================
/**
* 綁定拖曳功能
* modal元件需在拖曳處加上modalDraggableArea='modalId'
* @returns
*/
bindDrag() {
const { id: t, container: e } = this.currentModal;
return this.modalHeader = e.querySelector(`[modalDraggableArea="${t}"]`), this.modalHeader ? (this.modalHeader.style.cursor = "move", this.handleDrag || (this.handleDrag = (i) => this.startDrag(i)), this.modalHeader.addEventListener("mousedown", this.handleDrag), !0) : (console.warn(`Modal drag area not found for modal: ${t}`), !1);
}
/**
* 解除拖曳功能
* @returns
*/
unbindDrag() {
this.modalHeader && (this.modalHeader.style.cursor = "", this.handleDrag && this.modalHeader.removeEventListener("mousedown", this.handleDrag), this.isDragging && this.forceStopDrag());
}
/**
* 強制停止拖曳
*/
forceStopDrag() {
this.isDragging = !1, document.removeEventListener("mousemove", this.calcMouseDisplacement), document.removeEventListener("mouseup", this.stopDrag);
}
//==================================發送事件==================================
/**
* 發送拖拽事件
* @param x 當前X坐標
* @param y 當前Y坐標
*/
emitDragEvent(t, e) {
const i = new CustomEvent("modal-drag", {
detail: {
modalId: this.currentModal.id,
x: t,
y: e
}
});
this.currentModal.container.dispatchEvent(i);
}
/**
* 發送拖拽結束事件
* @param x 最終X坐標
* @param y 最終Y坐標
*/
emitDragEndEvent(t, e) {
const i = new CustomEvent("modal-drag-end", {
detail: {
modalId: this.currentModal.id,
x: t,
y: e
}
});
this.currentModal.container.dispatchEvent(i);
}
//==================================銷毀物件==================================
/**
* 銷毀物件
*/
destroy() {
this.unbindDrag(), this.forceStopDrag();
}
}
class f {
//z-index 預設值
/**
* 初始化函數
* @param options modal router
*/
constructor(t) {
//ModalManager物件
l(this, "appContext");
//vue生成資訊
l(this, "modalRoutes");
//modal rotes
l(this, "ModalList");
//modal 管理列表
l(this, "baseZIndex", 1e3);
this.modalRoutes = t, this.ModalList = /* @__PURE__ */ new Map(), this.appContext = null;
}
install(t) {
t.config.globalProperties.$modalManager = this, t.provide("modalManager", this);
const e = t.mount;
t.mount = (...i) => {
const n = e.call(t, ...i);
return setTimeout(() => {
t._container && t._container._vnode ? this.appContext = t._container._vnode.appContext : console.warn("Modal Manager: Unable to get appContext");
}, 0), n;
};
}
//==========================================創建modal外層元素===================================================
/**
* 建立modal ID
* @param name modal元件名稱
* @returns modal ID
*/
generateId(t) {
const e = Date.now(), i = Math.floor(Math.random() * 1e3);
return `${t}-${e}-${i}`;
}
/**
* 建立modal div(固定)元素
* @param modalId modal ID
* @param direction 方位
* @returns HTMLDivElement
*/
createDivByFixed(t, e = "center") {
const i = document.createElement("div");
return i.setAttribute("data-modalId", t), i.style.position = "fixed", i.style.zIndex = "1000", i.style.width = "100%", i.style.height = "100%", i.style.display = "flex", i.style.backgroundColor = "rgba(0, 0, 0, 0.6)", this.applyFixedModalStyles(i, e), i;
}
/**
* modal div(固定)樣式
*/
applyFixedModalStyles(t, e) {
const n = {
center: {
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
alignItems: "center",
justifyContent: "center"
},
top: {
top: "0",
left: "0",
alignItems: "flex-start",
justifyContent: "center"
},
bottom: {
top: "0",
left: "0",
alignItems: "flex-end",
justifyContent: "center"
},
left: {
top: "0",
left: "0",
alignItems: "center",
justifyContent: "flex-start"
},
right: {
top: "0",
left: "0",
alignItems: "center",
justifyContent: "flex-end"
}
}[e];
n && Object.assign(t.style, n);
}
/**
* 建立modal div(拖拽)元素
*/
createDivByDraggable(t, e) {
const i = document.createElement("div");
return i.setAttribute("data-modalId", t), i.style.position = "absolute", i.style.zIndex = `${this.baseZIndex + this.ModalList.size}`, i.style.width = "max-content", i.style.height = "max-content", e ? this.applyCustomPosition(i, e) : this.applyCenterPosition(i), i;
}
/**
* modal div(拖拽)樣式-自訂義position
*/
applyCustomPosition(t, e) {
t.style.top = e.top ?? "auto", t.style.bottom = e.bottom ?? "auto", t.style.left = e.left ?? "auto", t.style.right = e.right ?? "auto", t.style.transform = "";
}
/**
* modal div(拖拽)樣式-置中
*/
applyCenterPosition(t) {
const e = window.scrollX + window.innerWidth / 2, i = window.scrollY + window.innerHeight / 2;
t.style.left = `${e}px`, t.style.top = `${i}px`, t.style.transform = "translate(-50%, -50%)";
}
async openModal(t, e, i) {
try {
if (e === "fixed") {
const n = i;
return await this.createFixedModal(t, n);
} else if (e === "draggable") {
const n = i;
return await this.createDraggableModal(t, n);
} else
throw new Error(`Unsupported modal mode: ${e}`);
} catch (n) {
return console.error(`Failed to load modal ${t}:`, n), { success: !1, msg: "Failed to load modal", modalId: "" };
}
}
/**
* 建立modal(固定)
* @param name modal route名稱
* @param params 配置參數
* @returns
*/
async createFixedModal(t, e) {
const i = this.modalRoutes.find((n) => n.name === t);
if (!i)
return console.error(`Modal ${t} not found`), { success: !1, msg: "not found Modal", modalId: "" };
try {
const n = this.generateId(t), s = this.createDivByFixed(n, (e == null ? void 0 : e.direction) || "center");
if (!this.mountContainer(s, e == null ? void 0 : e.id))
return { success: !1, msg: "Failed to mount container", modalId: "" };
const r = e != null && e.id ? document.getElementById(e.id) : null;
return this.ModalList.set(n, {
id: n,
container: s,
name: t,
boxElement: r || document.body
}), await this.renderComponent(i, n, e) ? { success: !0, msg: "success", modalId: n } : (this.cleanupFailedModal(n), { success: !1, msg: "Failed to render component", modalId: "" });
} catch (n) {
return console.error(`Failed to load modal ${t}:`, n), { success: !1, msg: "Failed to load modal", modalId: "" };
}
}
/**
* 建立modal(拖曳)
* @param name modal route名稱
* @param params 配置參數
* @returns
*/
async createDraggableModal(t, e) {
const i = this.modalRoutes.find((n) => n.name === t);
if (!i)
return console.error(`Modal ${t} not found`), { success: !1, msg: "not found Modal", modalId: "" };
try {
const n = this.generateId(t), s = this.createDivByDraggable(n, e == null ? void 0 : e.position);
if (s.addEventListener("click", () => this.bringToFront(n)), !this.mountContainer(s, e == null ? void 0 : e.id, e == null ? void 0 : e.position))
return { success: !1, msg: "Failed to mount container", modalId: "" };
const r = e != null && e.id ? document.getElementById(e.id) : null;
return this.ModalList.set(n, {
id: n,
container: s,
name: t,
boxElement: r || document.body
}), await this.renderComponent(i, n, e) ? (await this.setupDraggableModalFeatures(n, e), { success: !0, msg: "success", modalId: n }) : (this.cleanupFailedModal(n), { success: !1, msg: "Failed to render component", modalId: "" });
} catch (n) {
return console.error(`Failed to load modal ${t}:`, n), { success: !1, msg: "Failed to load modal", modalId: "" };
}
}
/**
* 掛載容器至指定元素位置
*/
mountContainer(t, e, i) {
try {
const n = e ? document.getElementById(e) : null;
return n ? (n.style.position = "relative", n.appendChild(t)) : document.body.appendChild(t), i ? this.applyCustomPosition(t, i) : (t.style.top = "50%", t.style.left = "50%", t.style.transform = "translate(-50%, -50%)"), !0;
} catch (n) {
return console.error("Failed to mount container:", n), !1;
}
}
/**
* 渲染组件
*/
async renderComponent(t, e, i) {
try {
const n = await t.component(), s = this.extractComponent(n);
if (!s)
throw new Error("Failed to extract component from module");
const o = this.buildEventProps(e, i), r = this.ModalList.get(e);
if (!r) return !1;
const a = E(s, o);
return this.appContext && (a.appContext = this.appContext), y(a, r.container), !0;
} catch (n) {
return console.error("Failed to load and render component:", n), !1;
}
}
/**
* 提取組件
*/
extractComponent(t) {
return t != null && t.default ? t.default : this.isValidComponent(t) ? t : null;
}
/**
* 检查是否為有效组件
*/
isValidComponent(t) {
return typeof t == "function" || t && typeof t == "object" && (t.render || t.template || t.setup);
}
/**
* 添加props參數 emit事件
*/
buildEventProps(t, e) {
const i = {
...e == null ? void 0 : e.props,
modalId: t,
onClosed: () => this.closeModal(t)
};
return e != null && e.events && Object.entries(e.events).forEach(([n, s]) => {
const o = `on${n.charAt(0).toUpperCase() + n.slice(1)}`;
i[o] = s;
}), i;
}
/**
* 設置modal(拖曳)可選功能
*/
async setupDraggableModalFeatures(t, e) {
const i = this.ModalList.get(t);
if (!(!i || !e))
try {
e.drag && (i.drag = new L(i)), e.resize && (i.resize = new D(i));
} catch (n) {
console.error(`Failed to setup draggable features for modal ${t}:`, n);
}
}
/**
* 清除建置失败的modal
*/
cleanupFailedModal(t) {
var i, n, s, o;
const e = this.ModalList.get(t);
e && (e.container.parentNode && e.container.parentNode.removeChild(e.container), e.drag && ((n = (i = e.drag).destroy) == null || n.call(i)), e.resize && ((o = (s = e.resize).destroy) == null || o.call(s)), this.ModalList.delete(t));
}
//==========================================關閉modal===================================================
/**
* 關閉modal
* @param modalId modal Id
* @returns 返回结果
*/
closeModal(t) {
var i, n, s, o;
const e = this.ModalList.get(t);
if (!e)
return console.warn(`Modal ${t} not found`), !1;
try {
return e.drag && ((n = (i = e.drag).destroy) == null || n.call(i)), e.resize && ((o = (s = e.resize).destroy) == null || o.call(s)), y(null, e.container), e.container.parentNode && e.container.parentNode.removeChild(e.container), e.boxElement.querySelectorAll("div[data-modalId]").length === 0 && (e.boxElement.style.position = ""), this.ModalList.delete(t), !0;
} catch (r) {
return console.error(`Failed to close modal ${t}:`, r), !1;
}
}
/**
* 關閉所有modal
* @returns 返回關閉数量
*/
removeAllModal() {
const t = [...this.ModalList.values()];
let e = 0;
return t.forEach((i) => {
this.closeModal(i.id) && e++;
}), console.log(`%c 移除了 ${e} 個modal`, "color: green; font-size: 14px"), e;
}
//==========================================modal位置===================================================
/**
* 移動視窗至指定容器
* @param modalId
* @param target
* @returns 返回結果
*/
moveToLayers(t, e) {
const i = this.ModalList.get(t);
if (!i)
return console.warn(`Modal ${t} not found`), !1;
const n = document.getElementById(e);
if (!n)
return console.warn(`Target container ${e} not found`), !1;
try {
return i.boxElement.style.position = "", n.style.position = "relative", n.appendChild(i.container), this.applyCenterPosition(i.container), i.boxElement = n, i.resize && i.resize.setCurrentModal(i), i.drag && i.drag.setCurrentModal(i), !0;
} catch (s) {
return console.error(`Failed to move modal ${t} to ${e}:`, s), !1;
}
}
/**
* 計算modal元件階層
* @param modalId modal Id
* @returns 返回結果
*/
bringToFront(t) {
const e = this.ModalList.get(t);
if (!e) return !1;
const i = parseInt(e.container.style.zIndex), n = this.baseZIndex + this.ModalList.size;
return i >= n ? !1 : (this.ModalList.forEach((s) => {
const o = parseInt(s.container.style.zIndex);
s.id === t ? s.container.style.zIndex = `${n}` : o > i && (s.container.style.zIndex = `${o - 1}`);
}), !0);
}
//==========================================工具方法===================================================
/**
* 已開啟的modal狀態列表
*/
getOpenModals() {
return Array.from(this.ModalList.values());
}
/**
* 檢查modal是否存在
*/
hasModal(t) {
return this.ModalList.has(t);
}
/**
* 已開啟modal數量
*/
getModalCount() {
return this.ModalList.size;
}
}
l(f, "modalManager");
const R = (d) => {
const t = new f(d);
return f.modalManager = t, t;
}, H = () => {
const d = f.modalManager;
if (!d)
throw new Error("Modal Manager not initialized. Call createModalManager first.");
return d;
};
export {
R as createModalManager,
H as useModalManager
};