UNPKG

@imcyk/context-menu

Version:

基于vue3+vite+ts的右键菜单组件,适用于组合式api和选项式api。

476 lines (475 loc) 16.8 kB
import { defineComponent as X, useSlots as ye, ref as x, inject as _, openBlock as u, createElementBlock as y, normalizeClass as H, unref as d, Fragment as I, createElementVNode as S, createBlock as j, resolveDynamicComponent as B, toDisplayString as be, createCommentVNode as R, renderSlot as ae, computed as ge, provide as P, onMounted as re, nextTick as xe, resolveComponent as ke, normalizeStyle as J, withModifiers as Ce, renderList as we, createVNode as U, createSlots as _e, withCtx as Ee, withDirectives as K, vShow as Q, onUnmounted as Me, h as We, render as Z } from "vue"; let V = null; const Oe = (e) => { V == null || V.closeMenu(), V = e; }, Ne = (e) => { V = null; }; process.env.NODE_ENV !== "production" && Object.freeze({}); process.env.NODE_ENV !== "production" && Object.freeze([]); const Se = () => { }, He = Object.assign, Te = Array.isArray, Pe = (e) => typeof e == "function", De = (e) => typeof e == "symbol"; let $e; function Ve(e, t = $e) { t && t.active && t.effects.push(e); } const ee = (e) => { const t = new Set(e); return t.w = 0, t.n = 0, t; }, ue = (e) => (e.w & E) > 0, de = (e) => (e.n & E) > 0, Ae = ({ deps: e }) => { if (e.length) for (let t = 0; t < e.length; t++) e[t].w |= E; }, Re = (e) => { const { deps: t } = e; if (t.length) { let o = 0; for (let n = 0; n < t.length; n++) { const s = t[n]; ue(s) && !de(s) ? s.delete(e) : t[o++] = s, s.w &= ~E, s.n &= ~E; } t.length = o; } }; let A = 0, E = 1; const G = 30; let h; Symbol(process.env.NODE_ENV !== "production" ? "iterate" : ""); Symbol(process.env.NODE_ENV !== "production" ? "Map key iterate" : ""); class je { constructor(t, o = null, n) { this.fn = t, this.scheduler = o, this.active = !0, this.deps = [], this.parent = void 0, Ve(this, n); } run() { if (!this.active) return this.fn(); let t = h, o = L; for (; t; ) { if (t === this) return; t = t.parent; } try { return this.parent = h, h = this, L = !0, E = 1 << ++A, A <= G ? Ae(this) : te(this), this.fn(); } finally { A <= G && Re(this), E = 1 << --A, h = this.parent, L = o, this.parent = void 0, this.deferStop && this.stop(); } } stop() { h === this ? this.deferStop = !0 : this.active && (te(this), this.onStop && this.onStop(), this.active = !1); } } function te(e) { const { deps: t } = e; if (t.length) { for (let o = 0; o < t.length; o++) t[o].delete(e); t.length = 0; } } let L = !0; function ne(e, t) { let o = !1; A <= G ? de(e) || (e.n |= E, o = !ue(e)) : o = !e.has(h), o && (e.add(h), h.deps.push(e), process.env.NODE_ENV !== "production" && h.onTrack && h.onTrack(Object.assign({ effect: h }, t))); } function oe(e, t) { const o = Te(e) ? e : [...e]; for (const n of o) n.computed && se(n, t); for (const n of o) n.computed || se(n, t); } function se(e, t) { (e !== h || e.allowRecurse) && (process.env.NODE_ENV !== "production" && e.onTrigger && e.onTrigger(He({ effect: e }, t)), e.scheduler ? e.scheduler() : e.run()); } new Set( /* @__PURE__ */ Object.getOwnPropertyNames(Symbol).filter((e) => e !== "arguments" && e !== "caller").map((e) => Symbol[e]).filter(De) ); function F(e) { const t = e && e.__v_raw; return t ? F(t) : e; } function Be(e) { L && h && (e = F(e), process.env.NODE_ENV !== "production" ? ne(e.dep || (e.dep = ee()), { target: e, type: "get", key: "value" }) : ne(e.dep || (e.dep = ee()))); } function Le(e, t) { e = F(e), e.dep && (process.env.NODE_ENV !== "production" ? oe(e.dep, { target: e, type: "set", key: "value", newValue: t }) : oe(e.dep)); } var fe; class ze { constructor(t, o, n, s) { this._setter = o, this.dep = void 0, this.__v_isRef = !0, this[fe] = !1, this._dirty = !0, this.effect = new je(t, () => { this._dirty || (this._dirty = !0, Le(this)); }), this.effect.computed = this, this.effect.active = this._cacheable = !s, this.__v_isReadonly = n; } get value() { const t = F(this); return Be(t), (t._dirty || !t._cacheable) && (t._dirty = !1, t._value = t.effect.run()), t._value; } set value(t) { this._setter(t); } } fe = "__v_isReadonly"; function Fe(e, t, o = !1) { let n, s; const a = Pe(e); a ? (n = e, s = process.env.NODE_ENV !== "production" ? () => { console.warn("Write operation failed: computed value is readonly"); } : Se) : (n = e.get, s = e.set); const r = new ze(n, s, a || !s, o); return process.env.NODE_ENV !== "production" && t && !o && (r.effect.onTrack = t.onTrack, r.effect.onTrigger = t.onTrigger), r; } const Ie = { class: "icon" }, Ue = { key: 0, class: "label" }, Ge = { name: "i-context-menu-item" }, Xe = /* @__PURE__ */ X({ ...Ge, props: { disabled: { type: Boolean, default: !1 }, customComponent: null, customClass: { default: "" }, label: { default: "" }, icon: { default: "" }, iconFontClass: { default: "iconfont" }, showRightArrow: { type: Boolean, default: !1 }, clickClose: { type: Boolean, default: !0 }, clickableWhenHasChildren: { type: Boolean, default: !1 }, clickHandler: { type: Function, default: () => { } }, metadata: { default: () => ({}) } }, setup(e) { const t = e, o = ye(), n = x(!1), s = _("menuContext"), a = _("globalNamespace"), r = _("globalFrom"), T = _("globalCloseMenu"), k = _("globalOptions"), b = () => { s.checkCloseOtherSubMenuTimeOut() || s.closeOtherSubMenu(), s.addOpenedSubMenu(() => { n.value = !1; }), n.value = !0; }, g = Fe(() => { const f = { disabled: t.disabled, label: t.label, icon: t.icon, iconFontClass: t.iconFontClass, showRightArrow: t.showRightArrow, clickClose: t.clickClose, clickableWhenHasChildren: t.clickableWhenHasChildren, metadata: t.metadata }; return r && (f.from = r), f; }), M = () => { t.disabled || (o.submenu ? t.clickableWhenHasChildren && typeof t.clickHandler == "function" && t.clickHandler(t.metadata, g.value) : (typeof t.clickHandler == "function" && t.clickHandler(t.metadata, g.value), t.clickClose && T())); }; return (f, C) => (u(), y("div", { class: H([d(a) + "context-menu-item", e.disabled ? "disabled" : "", e.customClass]), onClick: M, onMouseenter: b }, [ e.customComponent ? (u(), j(B(e.customComponent), { key: 1, data: d(g) }, null, 8, ["data"])) : (u(), y(I, { key: 0 }, [ S("div", Ie, [ typeof e.icon == "string" ? (u(), y("i", { key: 0, class: H([e.icon, e.iconFontClass]) }, null, 2)) : (u(), j(B(e.icon), { key: 1, data: d(g) }, null, 8, ["data"])) ]), typeof e.label == "string" ? (u(), y("span", Ue, be(e.label), 1)) : (u(), j(B(e.label), { key: 1, data: d(g) }, null, 8, ["data"])), e.showRightArrow ? (u(), y(I, { key: 2 }, [ typeof (d(k).moreArrow || "") == "string" ? (u(), y("div", { key: 0, class: H(["right-arrow", "more", d(k).moreArrow]) }, null, 2)) : (u(), j(B(d(k).moreArrow), { key: 1, data: { ...d(g), className: ["right-arrow", "more"] } }, null, 8, ["data"])) ], 64)) : R("", !0) ], 64)), n.value ? ae(f.$slots, "submenu", { key: 2 }) : R("", !0) ], 34)); } }); var Ye = /^\d+((px)|%)?$/; function me(e) { let t = e.offsetTop; return e.offsetParent != null && (t -= e.offsetParent.scrollTop, t += me(e.offsetParent)), t; } function he(e) { let t = e.offsetLeft; return e.offsetParent != null && (t -= e.offsetParent.scrollLeft, t += he(e.offsetParent)), t; } const le = (e) => Ye.test(String(e)), qe = { key: 0, class: "divided" }, Je = /* @__PURE__ */ S("div", { class: "double-arrow" }, null, -1), Ke = [ Je ], Qe = /* @__PURE__ */ S("div", { class: "double-arrow" }, null, -1), Ze = [ Qe ], et = { name: "i-context-menu-sub" }, tt = /* @__PURE__ */ X({ ...et, props: { items: null, maxWidth: null, minWidth: null, adjustPosition: { type: Boolean, default: !0 } }, setup(e) { const t = e, o = 3, n = document.body.clientHeight, s = document.body.clientWidth; let a = 0; const r = _("globalOptions"), T = _("menuContext"), k = _("globalNamespace"), { zIndex: b, getMyPosition: g, getParentWidth: M } = T, f = x(!1), C = x(0), m = x(0), $ = [], w = x({ x: 0, y: 0 }), p = x(), W = x(), Y = x(), pe = { zIndex: b + 1, getMyPosition: () => { const c = { x: 0, y: 0 }; return p.value && (c.x = p.value.offsetWidth + (r.xOffset || 0)), r.yOffset && (c.y = r.yOffset), c; }, getParentWidth: () => { var c; return (c = p.value) == null ? void 0 : c.offsetWidth; }, addOpenedSubMenu(c) { $.push(c); }, closeOtherSubMenu() { $.forEach((c) => c()), $.splice(0, $.length); }, checkCloseOtherSubMenuTimeOut() { return a ? (clearTimeout(a), a = 0, !0) : !1; }, closeOtherSubMenuWithTimeOut() { a = setTimeout(() => { a = 0, this.closeOtherSubMenu(); }, 200); } }, q = (c) => { var v, O, i, N; let l = 0; c == "down" ? l = Math.max(C.value - 50, -m.value) : l = Math.min(C.value + 50, 0), l > 0 && (l = 0), l < Number((v = W.value) == null ? void 0 : v.offsetHeight) - Number((O = p.value) == null ? void 0 : O.offsetHeight) && (l = Number((i = W.value) == null ? void 0 : i.offsetHeight) - Number((N = p.value) == null ? void 0 : N.offsetHeight)), C.value = l; }, ve = ge(() => { const c = n * 0.95, l = n * 0.8, v = (r == null ? void 0 : r.maxHeight) || 0; return { maxWidth: t.maxWidth ? le(t.maxWidth) ? t.maxWidth : t.maxWidth + "px" : "", minWidth: t.minWidth ? le(t.minWidth) ? t.minWidth : t.minWidth + "px" : "", maxHeight: (l > v ? l : c > v && v != 0 ? v : c) + "px", zIndex: b, left: `${w.value.x}px`, top: `${w.value.y}px` }; }); return P("menuContext", pe), re(() => { w.value = g(), xe(() => { const c = p.value, l = W.value; if (!c || !l) return !1; if (t.adjustPosition && p.value && Y.value) { m.value = c.offsetHeight - (l == null ? void 0 : l.offsetHeight), f.value = c.offsetHeight > (l == null ? void 0 : l.offsetHeight); const v = he(c), O = me(l); v + c.offsetWidth - s > 0 ? w.value.x -= (M ? M() : 0) + c.offsetWidth - o : w.value.x -= o; const N = O + l.offsetHeight - n; N > 0 && (w.value.y -= N * 1.05); } }); }), (c, l) => { var O; const v = ke("i-context-menu-sub"); return u(), y("div", { class: H([d(k) + "context-menu-sub", ((O = d(r)) == null ? void 0 : O.customClass) || ""]), style: J(d(ve)), onContextmenu: l[2] || (l[2] = Ce(() => { }, ["stop", "prevent"])), ref_key: "sub", ref: W }, [ S("div", { class: H([d(k) + "context-menu-sub-body"]), ref_key: "menu", ref: p, style: J({ top: `${C.value}px` }) }, [ e.items ? (u(!0), y(I, { key: 0 }, we(e.items, (i, N) => (u(), y("div", { key: N }, [ U(Xe, { clickHandler: i.onClick, disabled: i.disabled, iconFontClass: d(r).iconFontClass, icon: i.icon, label: i.label, customComponent: i.customComponent, customClass: i.customClass, clickClose: i.clickClose, clickableWhenHasChildren: i.clickableWhenHasChildren, showRightArrow: i.children && i.children.length > 0, metadata: i.metadata || {} }, _e({ _: 2 }, [ i.children && i.children.length > 0 ? { name: "submenu", fn: Ee(() => [ U(v, { items: i.children, maxWidth: i.maxWidth, minWidth: i.minWidth, adjustPosition: i.adjustSubMenuPosition }, null, 8, ["items", "maxWidth", "minWidth", "adjustPosition"]) ]), key: "0" } : void 0 ]), 1032, ["clickHandler", "disabled", "iconFontClass", "icon", "label", "customComponent", "customClass", "clickClose", "clickableWhenHasChildren", "showRightArrow", "metadata"]), i.divided ? (u(), y("div", qe)) : R("", !0) ]))), 128)) : R("", !0) ], 6), S("div", { class: H([d(k) + "context-menu-scroll"]), ref_key: "scroll", ref: Y }, [ K(S("div", { class: "updown up", onClick: l[0] || (l[0] = (i) => q("up")) }, Ke, 512), [ [Q, f.value && C.value < 0] ]), K(S("div", { class: "updown down", onClick: l[1] || (l[1] = (i) => q("down")) }, Ze, 512), [ [Q, f.value && C.value > -m.value] ]) ], 2) ], 38); }; } }), nt = { name: "i-context-menu" }, ot = /* @__PURE__ */ X({ ...nt, props: { options: null, namespace: null, from: { default: "" } }, emits: ["close"], setup(e, { expose: t, emit: o }) { const n = e, s = x("context-menu-host"), a = x(!0), r = { zIndex: (n.options || {}).zIndex || 100, getMyPosition: () => ({ x: n.options.x, y: n.options.y }), addOpenedSubMenu: () => { }, closeOtherSubMenu: () => { } }, T = () => { document.removeEventListener("click", f, !0), document.removeEventListener("contextmenu", f, !0), document.removeEventListener("wheel", M, !0); }, k = () => { document.addEventListener("click", f, !0), document.addEventListener("contextmenu", f, !0), document.addEventListener("wheel", M, !0); }, b = () => { a.value = !1, o("close"), Ne(); }, g = (m) => { for (; m; ) { if (m.classList && m.classList.contains(s.value)) return !1; m = m.parentNode; } T(), b(); }, M = () => { n.options.closeWhenScroll !== !1 && b(); }; function f(m) { g(m.target); } const C = () => { Oe({ closeMenu: b }); }; return P("globalOptions", n.options), P("globalNamespace", n.namespace || ""), P("globalFrom", n.from), P("globalCloseMenu", b), P("menuContext", r), C(), re(() => { k(); }), Me(() => { T(); }), t({ closeMenu: b }), (m, $) => { var w, p, W; return a.value ? (u(), y("div", { key: 0, class: H([e.namespace + "context-menu", s.value, e.options.customClass]) }, [ U(tt, { items: (w = e.options) == null ? void 0 : w.items, "max-width": (p = e.options) == null ? void 0 : p.maxWidth, "min-width": (W = e.options) == null ? void 0 : W.minWidth }, null, 8, ["items", "max-width", "min-width"]), ae(m.$slots, "default") ], 2)) : R("", !0); }; } }); const st = { prefix: "", alias: "", namespace: "" }; let z = {}; const lt = ({ options: e, namespace: t, from: o }, n, s) => { const a = We( ot, { options: e, namespace: t, from: o, onClose: () => { Z(null, n); } }, s ); return Z(a, n), document.body.appendChild(n.firstElementChild), a.component; }, ie = (e) => Array.isArray(e) ? { items: e } : e && typeof e == "object" ? e : {}, it = (e) => e.replace(/[_-]+[a-zA-z]/g, (t) => t.substr(-1).toUpperCase()), D = (e, t, o) => { const { namespace: n } = z, s = document.createElement("div"); return lt({ options: e, namespace: n ? n + "-" : "", from: o || "" }, s, t); }, ce = (e, t) => { e.preventDefault(); const { value: o, arg: n = "default" } = t; if (o && typeof o == "object") D({ ...ie(o), x: e.x, y: e.y }); else { const s = o || "", { globalMenus: a = {} } = z; D({ ...ie(a[n]), x: e.x, y: e.y }, void 0, s); } }, ct = (e, t) => { e.directive(t, { mounted: (o, n) => { o.addEventListener("contextmenu", (s) => ce(s, n)); }, beforeMount: (o) => { o.removeEventListener("contextmenu", ce); } }); }, at = (e, t) => { e.provide(t, D), e.config.globalProperties["$" + t] = D; }, rt = (e, t) => { z = { ...st, ...t }; const { prefix: o, alias: n } = z, s = n || it([o || "", "context", "menu"].filter((a) => a && a.trim()).join("-")); e.provide(s, D), e.config.globalProperties["$" + s] = D, at(e, s), ct(e, s); }, dt = { install: rt }; export { dt as default };