UNPKG

vue-sidebar-menu

Version:
711 lines (710 loc) 23.3 kB
import { defineComponent as V, getCurrentInstance as xe, computed as m, resolveComponent as Ne, createElementBlock as S, createBlock as x, openBlock as v, normalizeProps as W, mergeProps as $, renderSlot as O, withCtx as H, createElementVNode as A, resolveDynamicComponent as X, createTextVNode as Le, toDisplayString as me, inject as Oe, provide as Se, toRefs as de, ref as R, watch as Me, toHandlers as Ye, unref as p, createCommentVNode as D, Transition as _e, normalizeStyle as ve, normalizeClass as pe, withModifiers as Fe, guardReactiveProps as ke, Fragment as $e, renderList as Te, nextTick as De, onMounted as We, onUnmounted as je, createVNode as ze, withDirectives as qe, vShow as Ve, reactive as Ge } from "vue"; const Je = ["href", "onClick"], Ke = { compatConfig: { MODE: 3, inheritAttrs: !1 } }, Qe = /* @__PURE__ */ V({ ...Ke, __name: "SidebarMenuLink", props: { item: {} }, setup(e) { const n = e, l = xe()?.appContext.config.globalProperties.$router, o = m(() => !!(!n.item.href || n.item.external || !l)); return (a, i) => { const u = Ne("router-link"); return o.value ? (v(), S("a", W($({ key: 0 }, a.$attrs)), [ O(a.$slots, "default") ], 16)) : (v(), x(u, { key: 1, custom: "", to: a.$attrs.href }, { default: H(({ href: h, navigate: s }) => [ A("a", $(a.$attrs, { href: h, onClick: s }), [ O(a.$slots, "default") ], 16, Je) ]), _: 3 }, 8, ["to"])); }; } }), Xe = { compatConfig: { MODE: 3 } }, Ze = /* @__PURE__ */ V({ ...Xe, __name: "SidebarMenuIcon", props: { icon: {} }, setup(e) { const n = e, l = m(() => ({ class: [ "vsm--icon", typeof n.icon == "object" ? n.icon.class : n.icon ], "aria-hidden": !0, ...typeof n.icon == "object" ? n.icon.attributes : {} })); return (o, a) => typeof e.icon == "object" && e.icon.text ? (v(), x(X(e.icon.element ? e.icon.element : "i"), W($({ key: 0 }, l.value)), { default: H(() => [ Le(me(e.icon.text), 1) ]), _: 1 }, 16)) : typeof e.icon == "object" ? (v(), x(X(e.icon.element ? e.icon.element : "i"), W($({ key: 1 }, l.value)), null, 16)) : (v(), S("i", W($({ key: 2 }, l.value)), null, 16)); } }), et = { compatConfig: { MODE: 3 } }, tt = /* @__PURE__ */ V({ ...et, __name: "SidebarMenuBadge", props: { badge: {} }, setup(e) { const n = e, l = m(() => ({ class: ["vsm--badge", n.badge.class], ...n.badge.attributes })); return (o, a) => e.badge.text ? (v(), x(X(e.badge.element ? e.badge.element : "span"), W($({ key: 0 }, l.value)), { default: H(() => [ Le(me(e.badge.text), 1) ]), _: 1 }, 16)) : (v(), x(X(e.badge.element ? e.badge.element : "span"), W($({ key: 1 }, l.value)), null, 16)); } }); function ot(e) { const n = Symbol( e.name || "SidebarInjectionState" ); return [(...a) => { const i = e(...a); return Se(n, i), i; }, () => Oe(n)]; } const [nt, Ie] = ot( (e, n, l, o, a, i, u, h, s, g, P, T) => ({ getSidebarProps: e, getSidebarRef: n, getIsCollapsed: l, getMobileItem: o, getMobileItemRect: a, getCurrentRoute: i, updateIsCollapsed: u, setMobileItem: h, unsetMobileItem: s, clearMobileItemTimeout: g, onRouteChange: P, emitItemClick: T }) ); function lt(e, n) { const { matched: l } = e, { length: o } = l, a = l[o - 1], i = n.matched; if (!a || !i.length) return -1; const u = i.findIndex( Ae.bind(null, a) ); if (u > -1) return u; const h = He(l[o - 2]); return o > 1 && He(a) === h && i[i.length - 1].path !== h ? i.findIndex( Ae.bind(null, l[o - 2]) ) : u; } function at(e, n) { if (Object.keys(e).length !== Object.keys(n).length) return !1; for (const l in e) if (!st(e[l], n[l])) return !1; return !0; } function it(e, n) { for (const l in n) { const o = n[l], a = e[l]; if (typeof o == "string") { if (o !== a) return !1; } else if (!Array.isArray(a) || a.length !== o.length || o.some((i, u) => i !== a[u])) return !1; } return !0; } function He(e) { return e ? e.aliasOf ? e.aliasOf.path : e.path : ""; } function Ae(e, n) { return (e.aliasOf || e) === (n.aliasOf || n); } function st(e, n) { return Array.isArray(e) ? Pe(e, n) : Array.isArray(n) ? Pe(n, e) : e === n; } function Pe(e, n) { return Array.isArray(n) ? e.length === n.length && e.every((l, o) => l === n[o]) : e.length === 1 && e[0] === n; } const rt = { class: "vsm--dropdown" }, ut = { compatConfig: { MODE: 3 } }, ct = /* @__PURE__ */ V({ ...ut, __name: "SidebarMenuItemLink", props: { item: {}, level: {}, activeShow: {} }, emits: ["update-active-show"], setup(e, { emit: n }) { const l = e, o = n, { getSidebarRef: a, getSidebarProps: i, getIsCollapsed: u, getMobileItem: h, getMobileItemRect: s, getCurrentRoute: g, setMobileItem: P, unsetMobileItem: T, clearMobileItemTimeout: G, emitItemClick: j } = Ie(), { linkComponentName: Y } = de(i), { item: r, activeShow: Z, level: z } = de(l), F = R(void 0), c = m(() => z.value === 1), C = (t) => { F.value = t; }, E = xe()?.appContext.config.globalProperties.$router, J = Oe("SidebarMenuScroll"), ie = R(!1), ee = R(!1), L = (t, y) => { if (t.isActive && typeof t.isActive == "function") { const w = t.isActive(t); if (typeof w == "boolean") return w; } if (!t.href || t.external) return !1; if (E) { const w = E.resolve(t.href), k = E.currentRoute.value, M = lt(w, k); return y || t.exact ? M > -1 && M === k.matched.length - 1 && at(k.params, w.params) : M > -1 && it(k.params, w.params); } else return t.href === g.value; }, se = (t) => t ? t.some((y) => re(y) && (L(y) || se(y.child))) : !1, te = m( () => L(r.value) || se(r.value.child) ), oe = m(() => L(r.value, !0)), he = (t) => { (!r.value.href || r.value.disabled) && (t.preventDefault(), r.value.disabled) || (K(t, t.currentTarget.parentElement), B.value && (!r.value.href || te.value) && (I.value = !I.value), j(t, r.value)); }, fe = (t) => { t.stopPropagation(), t.preventDefault(), !r.value.disabled && (B.value && (I.value = !I.value), j(t, r.value)); }, d = (t) => { r.value.disabled || (t.stopPropagation(), ee.value = !0); }, f = (t) => { t.stopPropagation(), ee.value = !1; }, _ = (t) => { r.value.disabled || (i.disableHover ? b.value && B.value && G() : (G(), K(t, t.currentTarget))); }, U = () => { i.disableHover && !B.value || b.value && T(!1, i.disableHover ? void 0 : 300); }, K = (t, y) => { b.value || u.value && setTimeout(() => { c.value && !b.value && P({ item: r.value, itemEl: y }), t.type === "click" && !B.value && T(!1, c.value ? void 0 : 300); }, 0); }, ge = (t) => { t.style.height = t.scrollHeight + "px"; }, be = (t) => { if (t.style.height = "auto", !u.value) { if (i.smoothScroll) { const y = a.value?.children[0], w = t.parentElement; if (y && w) { const k = w.getBoundingClientRect().bottom, M = y.getBoundingClientRect().bottom; k > M && De( () => w.scrollIntoView({ behavior: "smooth", block: "nearest" }) ); } } J(); } }, we = (t) => { if (u.value && c.value) { t.style.display = "none"; return; } t.style.height = t.scrollHeight + "px"; }, ye = () => { u.value || J(); }; function re(t) { return !("header" in t) && !("component" in t); } const I = m({ get: () => B.value ? u.value && c.value ? ne.value : i.showChild ? !0 : i.showOneChild && c.value || i.showOneChild === "deep" ? r.value.id === Z.value : ie.value : !1, set: (t) => { (i.showOneChild && c.value || i.showOneChild === "deep") && o("update-active-show", t ? r.value.id : void 0), ie.value = t; } }), ne = m( () => u.value && c.value ? b.value : ee.value ), B = m(() => "child" in r.value && !!r.value.child?.length), Q = m(() => [ "vsm--link", `vsm--link_level-${z.value}`, { "vsm--link_mobile": b.value, "vsm--link_hover": ne.value, "vsm--link_active": te.value, "vsm--link_disabled": r.value.disabled, "vsm--link_open": I.value }, r.value.class ]), le = m(() => { const t = r.value.href ? r.value.href : "#", y = r.value.external ? "_blank" : "_self", w = r.value.disabled ? -1 : null, k = oe.value ? "page" : null, M = B.value ? I.value : null, Re = M ? `vsm-${l.item.id}` : null; return { href: t, target: y, tabindex: w, "aria-current": k, "aria-expanded": M, "aria-controls": Re, ...r.value.attributes }; }), N = m(() => ({ id: `vsm-${r.value.id}` })), ae = m(() => [ "vsm--item", { "vsm--item_mobile": b.value } ]), b = m(() => l.item.id === h.value?.id), q = (t) => i.rtl ? { right: t } : { left: t }, ue = m(() => ({ position: "absolute", "max-height": `${s.value.maxHeight}px`, width: `${s.value.maxWidth}px`, "overflow-y": "auto", "z-index": "20", ...s.value.dropup ? { bottom: `${s.value.dropup}px` } : { top: `${s.value.top + s.value.height}px` }, ...q(i.widthCollapsed) })), ce = m(() => ({ position: "absolute", top: `${s.value.top}px`, ...q(i.widthCollapsed), width: `${s.value.maxWidth}px`, height: `${s.value.height}px`, "padding-left": `${s.value.padding[0]}px`, "padding-right": `${s.value.padding[1]}px`, "z-index": "20" })), Ce = m(() => ({ position: "absolute", top: `${s.value.top}px`, ...i.rtl ? { right: "0px" } : { left: "0px" }, width: `${s.value.maxWidth + parseInt(i.widthCollapsed)}px`, height: `${s.value.height}px`, "z-index": "10" })); return Me( () => te.value, (t) => { t && (I.value = !0); }, { immediate: !0 } ), (t, y) => (v(), S("li", $({ class: ae.value, onMouseover: d, onMouseout: f }, Ye( p(u) && c.value ? { mouseenter: _, mouseleave: U } : {}, !0 )), [ (v(), x(X(p(Y) ? p(Y) : Qe), $({ item: p(r), class: Q.value }, le.value, { onClick: he }), { default: H(() => [ p(u) && c.value ? (v(), x(_e, { key: 0, name: "slide-animation" }, { default: H(() => [ ne.value ? (v(), S("div", { key: 0, class: "vsm--mobile-bg", style: ve(Ce.value) }, null, 4)) : D("", !0) ]), _: 1 })) : D("", !0), p(r).icon ? (v(), x(Ze, { key: 1, icon: p(r).icon }, null, 8, ["icon"])) : D("", !0), A("div", { class: pe([ "vsm--title", p(u) && c.value && !b.value && "vsm--title_hidden" ]), style: ve(b.value && ce.value) }, [ A("span", null, me(p(r).title), 1), p(r).badge ? (v(), x(tt, { key: 0, badge: p(r).badge }, null, 8, ["badge"])) : D("", !0), B.value ? (v(), S("div", { key: 1, class: pe(["vsm--arrow", { "vsm--arrow_open": I.value }]), onClick: Fe(fe, ["stop"]) }, [ O(t.$slots, "dropdown-icon", W(ke({ isOpen: I.value, toggle: fe }))) ], 2)) : D("", !0) ], 6) ]), _: 3 }, 16, ["item", "class"])), B.value ? (v(), x(_e, { key: 0, appear: b.value, name: "expand", onEnter: ge, onAfterEnter: be, onBeforeLeave: we, onAfterLeave: ye }, { default: H(() => [ I.value ? (v(), S("div", $({ key: 0, class: ["vsm--child", b.value && "vsm--child_mobile"], style: b.value && ue.value }, N.value), [ A("ul", rt, [ (v(!0), S($e, null, Te(p(r).child, (w) => (v(), x(Ue, { key: w.id, item: w, level: p(z) + 1, "active-show": F.value, onUpdateActiveShow: C }, { "dropdown-icon": H(({ isOpen: k, toggle: M }) => [ O(t.$slots, "dropdown-icon", $({ ref_for: !0 }, { isOpen: k, toggle: M })) ]), _: 3 }, 8, ["item", "level", "active-show"]))), 128)) ]) ], 16)) : D("", !0) ]), _: 3 }, 8, ["appear"])) : D("", !0) ], 16)); } }), dt = { key: 0 }, vt = { compatConfig: { MODE: 3 } }, Ue = /* @__PURE__ */ V({ ...vt, __name: "SidebarMenuItem", props: { item: {}, level: {}, activeShow: {} }, emits: ["update-active-show"], setup(e) { const n = e, { getIsCollapsed: l } = Ie(), { item: o, activeShow: a, level: i } = de(n), u = m(() => l.value ? n.item.hidden && n.item.hiddenOnCollapse === void 0 ? !0 : n.item.hiddenOnCollapse === !0 : n.item.hidden === !0); return (h, s) => u.value ? D("", !0) : (v(), S($e, { key: 0 }, [ "component" in p(o) ? (v(), S("li", dt, [ (v(), x(X(p(o).component), W(ke(p(o).props)), null, 16)) ])) : "header" in p(o) ? (v(), S("li", $({ key: 1, class: ["vsm--header", p(o).class] }, p(o).attributes), me(p(o).header), 17)) : (v(), x(ct, { key: 2, item: p(o), level: p(i), "active-show": p(a), onUpdateActiveShow: s[0] || (s[0] = (g) => h.$emit("update-active-show", g)) }, { "dropdown-icon": H(({ isOpen: g, toggle: P }) => [ O(h.$slots, "dropdown-icon", W(ke({ isOpen: g, toggle: P }))) ]), _: 3 }, 8, ["item", "level", "active-show"])) ], 64)); } }), pt = { compatConfig: { MODE: 3 } }, mt = /* @__PURE__ */ V({ ...pt, __name: "SidebarMenuScroll", setup(e) { const { getIsCollapsed: n } = Ie(), l = R(null), o = R(null), a = R(null), i = R(!1); let u = 0, h = !1; const s = R(!1), g = () => { l.value && De(() => { z(); }); }, P = () => { requestAnimationFrame(g); }, T = (c) => { if (!l.value || !o.value || !a.value) return; const C = Math.abs( o.value.getBoundingClientRect().y - c.clientY ), E = a.value.offsetHeight / 2; F(C - E); }, G = (c) => { !l.value || !o.value || !a.value || (c.stopImmediatePropagation(), i.value = !0, window.addEventListener("mousemove", j), window.addEventListener("mouseup", Y), u = a.value.offsetHeight - (c.clientY - a.value.getBoundingClientRect().y)); }, j = (c) => { if (!l.value || !o.value || !a.value || !i.value) return; const C = c.clientY - o.value.getBoundingClientRect().y, E = a.value.offsetHeight - u; s.value = !0, F(C - E); }, Y = (c) => { i.value = !1, u = 0, h || (s.value = !1), window.removeEventListener("mousemove", j), window.removeEventListener("mouseup", Y); }, r = (c) => { s.value = !0, h = !0; }, Z = (c) => { h = !1, i.value || (s.value = !1); }, z = () => { if (!l.value || !o.value || !a.value) return; const c = l.value.clientHeight * 100 / l.value.scrollHeight, C = c < 100 ? c : 0, E = l.value.scrollTop * 100 / l.value.clientHeight || 0; a.value.style.height = `${C}%`, a.value.style.transform = `translateY(${E}%)`; }, F = (c) => { if (!l.value || !o.value || !a.value) return; const C = c * 100 / o.value.offsetHeight; l.value.scrollTop = C * l.value.scrollHeight / 100; }; return Me( () => n.value, () => { g(); } ), We(() => { g(), window.addEventListener("resize", g); }), je(() => { window.removeEventListener("resize", g); }), Se("SidebarMenuScroll", g), (c, C) => (v(), S("div", { class: "vsm--scroll-wrapper", onMouseenter: r, onMouseleave: Z }, [ A("div", { ref_key: "scrollRef", ref: l, class: "vsm--scroll", onScroll: P }, [ O(c.$slots, "default", {}, void 0, !0) ], 544), ze(_e, null, { default: H(() => [ qe(A("div", { ref_key: "scrollBarRef", ref: o, class: "vsm--scroll-bar", onMousedown: T }, [ A("div", { ref_key: "scrollThumbRef", ref: a, class: pe(["vsm--scroll-thumb", [i.value && "vsm--scroll-thumb_clicking"]]), onMousedown: G }, null, 34) ], 544), [ [Ve, s.value] ]) ]), _: 1 }) ], 32)); } }), ht = (e, n) => { const l = e.__vccOpts || e; for (const [o, a] of n) l[o] = a; return l; }, ft = /* @__PURE__ */ ht(mt, [["__scopeId", "data-v-2640f004"]]), gt = { class: "vsm--wrapper" }, bt = ["aria-label"], wt = { compatConfig: { MODE: 3 } }, yt = /* @__PURE__ */ V({ ...wt, __name: "SidebarMenu", props: { menu: {}, collapsed: { type: Boolean }, width: { default: "290px" }, widthCollapsed: { default: "65px" }, showOneChild: { type: [Boolean, String] }, showChild: { type: Boolean }, rtl: { type: Boolean }, relative: { type: Boolean }, hideToggle: { type: Boolean }, theme: {}, disableHover: { type: Boolean }, linkComponentName: {}, smoothScroll: { type: Boolean } }, emits: ["item-click", "update:collapsed"], setup(e, { expose: n, emit: l }) { const o = e, a = l, { collapsed: i } = de(o), u = R(null), h = R(i.value), s = Ge({ item: null, rect: { top: 0, height: 0, padding: [0, 0], maxHeight: 0, maxWidth: 0, dropup: 0 }, timeout: null }), g = R(""), P = R(void 0), T = m(() => s.item), G = m(() => s.rect), j = m( () => h.value ? o.widthCollapsed : o.width ), Y = m(() => [ "v-sidebar-menu", h.value ? "vsm_collapsed" : "vsm_expanded", o.theme && `vsm_${o.theme}`, o.rtl && "vsm_rtl", o.relative && "vsm_relative" ]); let r = 0; const Z = () => `${Date.now()}${r++}`; function z(d) { return d ? d.map((f) => { const _ = { ...f, id: f.id ?? Z() }; return _.child && (_.child = z(_.child)), _; }) : []; } const F = m(() => z(o.menu)), c = () => { s.timeout && (clearTimeout(s.timeout), s.timeout = null); }, C = (d) => { s.item = d; }, E = (d) => { for (const f in d) s.rect[f] = d[f]; }, J = (d = !0, f = 800) => { if (T.value) { if (c(), d) { C(null); return; } s.timeout = setTimeout(() => C(null), f); } }, ie = (d) => { if (!u.value) return; const { top: f, bottom: _, height: U } = d.getBoundingClientRect(), { left: K, right: ge } = u.value.getBoundingClientRect(), be = u.value.firstElementChild, { bottom: we, height: ye } = be.getBoundingClientRect(), re = d.offsetParent, I = re.offsetTop, { top: ne, height: B } = re.getBoundingClientRect(); let Q = window.innerHeight, le = window.innerWidth, N = 0, ae = le, b = Math.max( parseInt(o.width) - parseInt(o.widthCollapsed), 0 ); const q = u.value.parentElement; if (q && o.relative) { Q = q.clientHeight, le = q.clientWidth; const Be = q.getBoundingClientRect(); N = Be.top, ae = Be.right; } const ue = o.rtl ? le - (ae - K) : ae - ge; b = ue <= b ? ue : b; const ce = window.getComputedStyle(d), Ce = parseInt(ce.paddingLeft || "0", 10), t = parseInt(ce.paddingRight || "0", 10), y = f - ne, w = we - f - (ye - (B + I)); let k = Q - (_ - N); const M = Math.min( window.innerHeight, window.innerHeight - N, Q, Q + N ), Ee = M - (Math.max(_, 0) - Math.max(N, 0)) < M * 0.25 ? w : 0; return k = Ee ? f - N : k, { top: y, height: U, padding: [Ce, t], maxWidth: b, maxHeight: k, dropup: Ee }; }, ee = ({ item: d, itemEl: f }) => { c(); const _ = f.children[0], U = ie(_); U && (C(d), E(U)); }, L = () => { g.value = window.location.pathname + window.location.search + window.location.hash; }, se = (d, f) => { a("item-click", d, f); }, te = (d) => { P.value = d; }, oe = (d) => { h.value = d; }, he = () => { J(), oe(!h.value), a("update:collapsed", h.value); }; return xe()?.appContext.config.globalProperties.$router || (We(() => { L(), window.addEventListener("hashchange", L); }), je(() => { window.removeEventListener("hashchange", L); })), Me( () => i.value, (d) => { J(), oe(d); } ), nt( o, u, h, T, G, g, oe, ee, J, c, L, se ), Se("onRouteChange", L), n({ onRouteChange: L }), (d, f) => (v(), S("div", { ref_key: "sidebarRef", ref: u, class: pe(Y.value), style: ve({ "max-width": j.value }) }, [ A("div", gt, [ O(d.$slots, "header"), ze(ft, null, { default: H(() => [ A("ul", { class: "vsm--menu", style: ve({ width: j.value }) }, [ (v(!0), S($e, null, Te(F.value, (_) => (v(), x(Ue, { key: _.id, item: _, level: 1, "active-show": P.value, onUpdateActiveShow: te }, { "dropdown-icon": H(({ isOpen: U, toggle: K }) => [ O(d.$slots, "dropdown-icon", $({ ref_for: !0 }, { isOpen: U, toggle: K }), () => [ f[0] || (f[0] = A("span", { class: "vsm--arrow_default" }, null, -1)) ]) ]), _: 3 }, 8, ["item", "active-show"]))), 128)) ], 4) ]), _: 3 }), O(d.$slots, "footer") ]), e.hideToggle ? D("", !0) : (v(), S("button", { key: 0, class: "vsm--toggle-btn", "aria-label": p(i) ? "Expand sidebar" : "Collapse sidebar", onClick: he }, [ O(d.$slots, "toggle-icon", {}, () => [ f[1] || (f[1] = A("span", { class: "vsm--toggle-btn_default" }, null, -1)) ]) ], 8, bt)) ], 6)); } }), _t = { install(e) { e.component("SidebarMenu", yt); } }; export { yt as SidebarMenu, _t as default }; //# sourceMappingURL=vue-sidebar-menu.esm.js.map