@imcyk/context-menu
Version:
基于vue3+vite+ts的右键菜单组件,适用于组合式api和选项式api。
476 lines (475 loc) • 16.8 kB
JavaScript
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
};