solid-contextmenu
Version:
Add contextmenu to your solid app with ease
326 lines (325 loc) • 11.2 kB
JavaScript
import { createComponent as k, Portal as Q, mergeProps as U, spread as I, effect as M, className as P, template as W, delegateEvents as X, insert as N } from "solid-js/web";
import { createSignal as D, children as Z, mergeProps as F, createComputed as S, untrack as Y, batch as ee, createContext as te, useContext as ne, splitProps as O, onCleanup as R, createMemo as E, Show as p } from "solid-js";
var g = /* @__PURE__ */ ((e) => (e.menu = "solid-contextmenu", e.submenu = "solid-contextmenu solid-contextmenu__submenu", e.submenuArrow = "solid-contextmenu__submenu-arrow", e.submenuOpen = "solid-contextmenu__submenu--is-open", e.separator = "solid-contextmenu__separator", e.item = "solid-contextmenu__item", e.itemDisabled = "solid-contextmenu__item--disabled", e.itemContent = "solid-contextmenu__item__content", e.theme = "solid-contextmenu__theme--", e.animationWillEnter = "solid-contextmenu__will-enter--", e.animationWillLeave = "solid-contextmenu__will-leave--", e))(g || {}), ie = /* @__PURE__ */ ((e) => (e[e.HIDE_ALL = 0] = "HIDE_ALL", e))(ie || {});
const _e = {
light: "light",
dark: "dark"
}, ge = {
fade: "fade",
flip: "flip",
scale: "scale",
slide: "slide"
};
function j(e) {
requestAnimationFrame(() => {
requestAnimationFrame(e);
});
}
const se = (e) => {
let t, s = !0;
const [i, f] = D(), [A, w] = D(), x = Z(() => e.children), h = e.name || "s";
e = F({
name: h,
enterActiveClass: h + "-enter-active",
enterClass: h + "-enter",
enterToClass: h + "-enter-to",
exitActiveClass: h + "-exit-active",
exitClass: h + "-exit",
exitToClass: h + "-exit-to"
}, e);
const {
onBeforeEnter: b,
onEnter: a,
onAfterEnter: $,
onBeforeExit: m,
onExit: C,
onAfterExit: r
} = e;
function y(n, o) {
if (!s || e.appear) {
let l = function(u) {
n && (!u || u.target === n) && (n.removeEventListener("transitionend", l), n.removeEventListener("animationend", l), n.classList.remove(..._), n.classList.remove(...d), ee(() => {
i() !== n && f(n), A() === n && w(void 0);
}), $ && $(n), e.mode === "inout" && v(n, o));
};
const c = e.enterClass.split(" "), _ = e.enterActiveClass.split(" "), d = e.enterToClass.split(" ");
b && b(n), n.classList.add(...c), n.classList.add(..._), j(() => {
n.classList.remove(...c), n.classList.add(...d), a && a(n, () => l()), (!a || a.length < 2) && (n.addEventListener("transitionend", l), n.addEventListener("animationend", l));
});
}
o && !e.mode ? w(n) : f(n);
}
function v(n, o) {
const c = e.exitClass.split(" "), _ = e.exitActiveClass.split(" "), d = e.exitToClass.split(" ");
if (!o.parentNode)
return l();
m && m(o), o.classList.add(...c), o.classList.add(..._), j(() => {
o.classList.remove(...c), o.classList.add(...d);
}), C && C(o, () => l()), (!C || C.length < 2) && (o.addEventListener("transitionend", l), o.addEventListener("animationend", l));
function l(u) {
(!u || u.target === o) && (o.removeEventListener("transitionend", l), o.removeEventListener("animationend", l), o.classList.remove(..._), o.classList.remove(...d), i() === o && f(void 0), r && r(o), e.mode === "outin" && y(n, o));
}
}
return S((n) => {
for (t = x(); typeof t == "function"; )
t = t();
return Y(() => (t && t !== n && (e.mode !== "outin" ? y(t, n) : s && f(t)), n && n !== t && e.mode !== "inout" && v(t, n), s = !1, t));
}), [i, A];
};
function oe(e) {
return { all: e = e || /* @__PURE__ */ new Map(), on: function(t, s) {
var i = e.get(t);
i ? i.push(s) : e.set(t, [s]);
}, off: function(t, s) {
var i = e.get(t);
i && (s ? i.splice(i.indexOf(s) >>> 0, 1) : e.set(t, []));
}, emit: function(t, s) {
var i = e.get(t);
i && i.slice().map(function(f) {
f(s);
}), (i = e.get("*")) && i.slice().map(function(f) {
f(t, s);
});
} };
}
const L = oe(), G = te(), J = () => ne(G);
function K(e) {
var t, s, i = "";
if (typeof e == "string" || typeof e == "number")
i += e;
else if (typeof e == "object")
if (Array.isArray(e))
for (t = 0; t < e.length; t++)
e[t] && (s = K(e[t])) && (i && (i += " "), i += s);
else
for (t in e)
e[t] && (i && (i += " "), i += t);
return i;
}
function z() {
for (var e, t, s = 0, i = ""; s < arguments.length; )
(e = arguments[s++]) && (t = K(e)) && (i && (i += " "), i += t);
return i;
}
const re = /* @__PURE__ */ W("<div></div>", 2), T = (e, t, s) => e + t <= s ? e : e < t ? s - t : e - t, de = (e, t) => {
const s = {
width: window.innerWidth,
height: window.innerHeight
};
return {
x: T(e.x, t.width, s.width),
y: T(e.y, t.height, s.height)
};
}, we = (e) => {
const [t, s] = O(e, ["id", "theme", "animation", "onShown", "onHidden"]), [i, f] = D(!1), [A, w] = D({
x: 0,
y: 0
});
let x;
const [h, b] = D();
L.on("show", (r) => {
r.id === t.id && (r.event.preventDefault(), b(r.props), f(!0), w(r.position ?? de({
x: r.event.clientX,
y: r.event.clientY
}, {
width: x.offsetWidth,
height: x.offsetHeight
})));
});
const a = () => {
L.emit("hide", t.id), f(!1);
}, $ = F({
shown: i,
animation: "scale",
hide: a,
props: h
}, t);
L.on("hideAll", () => {
a();
}), R(() => {
L.off("show"), L.off("hideAll");
});
const m = E(() => {
let r = "";
return t.animation && (r = `solid-contextmenu-${t.animation}`), console.log(r), r;
}), C = E(() => ({
enterActiveClass: m() + "-enter-active",
exitActiveClass: m() + "-exit-active"
}));
return k(G.Provider, {
value: $,
get children() {
return k(Q, {
get children() {
return k(se, U(C, {
get children() {
return k(p, {
get when() {
return i();
},
get children() {
const r = re.cloneNode(!0), y = x;
return typeof y == "function" ? y(r) : x = r, ae(r, () => a()), I(r, s, !1, !1), M((v) => {
const n = z(g.menu, s.class, {
[`${g.theme}${t.theme}`]: t.theme
}), o = A().x + "px", c = A().y + "px";
return n !== v._v$ && P(r, v._v$ = n), o !== v._v$2 && r.style.setProperty("left", v._v$2 = o), c !== v._v$3 && r.style.setProperty("top", v._v$3 = c), v;
}, {
_v$: void 0,
_v$2: void 0,
_v$3: void 0
}), r;
}
});
}
}));
}
});
}
});
};
function ae(e, t) {
const s = (i) => !e.contains(i.target) && t()?.();
document.body.addEventListener("click", s), R(() => document.body.removeEventListener("click", s));
}
function le(e) {
return typeof e == "function";
}
function B(e, t) {
return le(e) ? e(t) : e;
}
const ce = /* @__PURE__ */ W("<div><div></div></div>", 4), xe = (e) => {
const [t, s] = O(e, ["hidden", "disabled", "onClick", "data", "children"]), i = F({
hidden: !1,
disabled: !1
}, t), {
props: f,
hide: A
} = J(), w = E(() => ({
props: f(),
data: e.data
})), x = E(() => B(i.disabled, w())), h = E(() => B(i.hidden, w())), b = (a) => {
x() || (e.onClick?.({
event: a,
...w()
}), A());
};
return k(p, {
get when() {
return !h();
},
get children() {
const a = ce.cloneNode(!0), $ = a.firstChild;
return a.$$click = b, I(a, s, !1, !0), N($, () => t.children), M((m) => {
const C = z(g.item, {
[g.itemDisabled]: x()
}), r = g.itemContent;
return C !== m._v$ && P(a, m._v$ = C), r !== m._v$2 && P($, m._v$2 = r), m;
}, {
_v$: void 0,
_v$2: void 0
}), a;
}
});
};
X(["click"]);
const ue = /* @__PURE__ */ W("<div></div>", 2), $e = () => (() => {
const e = ue.cloneNode(!0);
return M(() => P(e, g.separator)), e;
})(), fe = /* @__PURE__ */ W("<div></div>", 2), he = /* @__PURE__ */ W("<div><div><span></span></div></div>", 6), Ce = (e) => {
const [t, s] = O(e, ["arrow", "children", "disabled", "hidden", "label", "class"]), i = F({
arrow: "\u25B6\uFE0F",
disabled: !1,
hidden: !1
}, t), {
props: f,
id: A
} = J(), w = E(() => ({
props: f()
})), x = E(() => B(i.disabled, w())), h = E(() => B(i.hidden, w()));
let b, a;
const [$, m] = D({
x: 0,
y: 0
}), C = () => {
const n = b.getBoundingClientRect(), o = a.getBoundingClientRect(), c = {
width: window.innerWidth,
height: window.innerHeight
};
let _ = n.right;
_ + o.width > c.width && (n.left - o.width > 0 ? _ = n.left - o.width : _ = c.width - o.width);
let d = n.top;
d + o.height > c.height && (n.bottom - o.height > 0 ? d = n.bottom - o.height : d = c.height - o.height), m({
x: _,
y: d
}), console.log($());
}, [r, y] = D(!1), v = () => {
y(!0), C();
};
return L.on("hide", (n) => {
n === A && y(!1);
}), R(() => {
L.off("hide");
}), k(p, {
get when() {
return !h();
},
get children() {
const n = he.cloneNode(!0), o = n.firstChild, c = o.firstChild;
n.$$click = () => r() ? y(!1) : v(), n.addEventListener("mouseleave", () => y(!1)), n.addEventListener("mouseenter", () => v()), I(n, s, !1, !0);
const _ = b;
return typeof _ == "function" ? _(o) : b = o, N(o, () => i.label, c), N(c, () => i.arrow), N(n, k(p, {
get when() {
return r();
},
get children() {
const d = fe.cloneNode(!0), l = a;
return typeof l == "function" ? l(d) : a = d, N(d, () => i.children), M((u) => {
const H = g.submenu, V = $().x + "px", q = $().y + "px";
return H !== u._v$ && P(d, u._v$ = H), V !== u._v$2 && d.style.setProperty("left", u._v$2 = V), q !== u._v$3 && d.style.setProperty("top", u._v$3 = q), u;
}, {
_v$: void 0,
_v$2: void 0,
_v$3: void 0
}), d;
}
}), null), M((d) => {
const l = z(g.item, t.class, {
[g.itemDisabled]: x()
}), u = g.itemContent, H = g.submenuArrow;
return l !== d._v$4 && P(n, d._v$4 = l), u !== d._v$5 && P(o, d._v$5 = u), H !== d._v$6 && P(c, d._v$6 = H), d;
}, {
_v$4: void 0,
_v$5: void 0,
_v$6: void 0
}), n;
}
});
};
X(["click"]);
const be = (e) => ({
show: (t, s) => {
process.env.NODE_ENV === "development" && !e?.id && !s?.id && console.error(
"You need to provide an id when initializing the hook `useContextMenu({ id: 'your id' })` or when you display the menu `show(e, { id: 'your id' })`. The later is used to override the one defined during initialization."
), L.emit("show", {
id: s?.id || e?.id,
props: s?.props || e?.props,
event: t,
position: s?.position
});
},
hideAll: () => {
L.emit("hideAll");
}
});
export {
ie as EVENT,
xe as Item,
we as Menu,
g as STYLE,
$e as Separator,
Ce as Submenu,
ge as animation,
_e as theme,
be as useContextMenu
};