UNPKG

vue-sidebar-menu

Version:
1,281 lines (1,193 loc) 42.1 kB
import { toRefs, ref, reactive, computed, provide, inject, getCurrentInstance, watch, nextTick, resolveComponent, openBlock, createElementBlock, normalizeProps, mergeProps, renderSlot, createBlock, withCtx, createElementVNode, resolveDynamicComponent, createTextVNode, toDisplayString, unref, guardReactiveProps, toHandlers, Transition, normalizeStyle, createCommentVNode, normalizeClass, Fragment, renderList, onMounted, onUnmounted, createVNode, withDirectives, vShow } from 'vue'; var initSidebar = function initSidebar(props, emits) { var _toRefs = toRefs(props), collapsed = _toRefs.collapsed, relative = _toRefs.relative, width = _toRefs.width, widthCollapsed = _toRefs.widthCollapsed, rtl = _toRefs.rtl; var sidebarRef = ref(null); var isCollapsed = ref(collapsed.value); var mobileItem = reactive({ item: null, rect: { top: 0, height: 0, padding: [0, 0], maxHeight: 0, maxWidth: 0, dropup: 0 }, timeout: null }); var getMobileItem = computed(function () { return mobileItem.item; }); var getMobileItemRect = computed(function () { return mobileItem.rect; }); var currentRoute = ref(''); var updateIsCollapsed = function updateIsCollapsed(val) { isCollapsed.value = val; }; var setMobileItem = function setMobileItem(_ref) { var item = _ref.item, itemEl = _ref.itemEl; clearMobileItemTimeout(); var linkEl = itemEl.children[0]; var rect = getMobileItemRectFromEl(linkEl); updateMobileItem(item); updateMobileItemRect(rect); }; var getMobileItemRectFromEl = function getMobileItemRectFromEl(el) { var _el$getBoundingClient = el.getBoundingClientRect(), elTop = _el$getBoundingClient.top, elBottom = _el$getBoundingClient.bottom, elHeight = _el$getBoundingClient.height; var _sidebarRef$value$get = sidebarRef.value.getBoundingClientRect(), sidebarLeft = _sidebarRef$value$get.left, sidebarRight = _sidebarRef$value$get.right; var _sidebarRef$value$fir = sidebarRef.value.firstElementChild.getBoundingClientRect(), wrapperBottom = _sidebarRef$value$fir.bottom, wrapperHeight = _sidebarRef$value$fir.height; var scrollWrapperEl = el.offsetParent; var scrollWrapperOffsetTop = scrollWrapperEl.offsetTop; var _scrollWrapperEl$getB = scrollWrapperEl.getBoundingClientRect(), scrollWrapperTop = _scrollWrapperEl$getB.top, scrollWrapperHeight = _scrollWrapperEl$getB.height; var parentHeight = window.innerHeight; var parentWidth = window.innerWidth; var parentTop = 0; var parentRight = parentWidth; var maxWidth = parseInt(width.value) - parseInt(widthCollapsed.value); if (relative.value) { var parent = sidebarRef.value.parentElement; parentHeight = parent.clientHeight; parentWidth = parent.clientWidth; parentTop = parent.getBoundingClientRect().top; parentRight = parent.getBoundingClientRect().right; } var rectWidth = rtl.value ? parentWidth - (parentRight - sidebarLeft) : parentRight - sidebarRight; maxWidth = rectWidth <= maxWidth ? rectWidth : maxWidth; var _window$getComputedSt = window.getComputedStyle(el), pl = _window$getComputedSt.paddingLeft, pr = _window$getComputedSt.paddingRight; var paddingLeft = parseInt(pl); var paddingRight = parseInt(pr); var absoluteTop = elTop - scrollWrapperTop; var absoluteBottom = wrapperBottom - elTop - (wrapperHeight - (scrollWrapperHeight + scrollWrapperOffsetTop)); var maxHeight = parentHeight - (elBottom - parentTop); var parentVisibleHeight = Math.min(window.innerHeight, window.innerHeight - parentTop, parentHeight, parentHeight + parentTop); var maxVisible = parentVisibleHeight - (Math.max(elBottom, 0) - Math.max(parentTop, 0)); var dropup = maxVisible < parentVisibleHeight * 0.25 ? absoluteBottom : 0; maxHeight = dropup ? elTop - parentTop : maxHeight; return { top: absoluteTop, height: elHeight, padding: [paddingLeft, paddingRight], maxWidth: maxWidth, maxHeight: maxHeight, dropup: dropup }; }; var unsetMobileItem = function unsetMobileItem() { var immediate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; var delay = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 800; if (!getMobileItem.value) return; clearMobileItemTimeout(); if (immediate) { updateMobileItem(null); return; } mobileItem.timeout = setTimeout(function () { updateMobileItem(null); }, delay); }; var clearMobileItemTimeout = function clearMobileItemTimeout() { if (mobileItem.timeout) clearTimeout(mobileItem.timeout); }; var updateMobileItem = function updateMobileItem(item) { mobileItem.item = item; }; var updateMobileItemRect = function updateMobileItemRect(mobileItemRect) { Object.keys(mobileItem.rect).forEach(function (key) { mobileItem.rect[key] = mobileItemRect[key]; }); }; var updateCurrentRoute = function updateCurrentRoute() { var route = window.location.pathname + window.location.search + window.location.hash; currentRoute.value = route; }; var onItemClick = function onItemClick(event, item) { emits('item-click', event, item); }; provide('vsmProps', props); provide('getSidebarRef', sidebarRef); provide('getIsCollapsed', isCollapsed); provide('getMobileItem', getMobileItem); provide('getMobileItemRect', getMobileItemRect); provide('getCurrentRoute', currentRoute); provide('updateIsCollapsed', updateIsCollapsed); provide('setMobileItem', setMobileItem); provide('unsetMobileItem', unsetMobileItem); provide('clearMobileItemTimeout', clearMobileItemTimeout); provide('onRouteChange', updateCurrentRoute); provide('emitItemClick', onItemClick); return { getSidebarRef: sidebarRef, getIsCollapsed: isCollapsed, getMobileItem: getMobileItem, getMobileItemRect: getMobileItemRect, getCurrentRoute: currentRoute, updateIsCollapsed: updateIsCollapsed, setMobileItem: setMobileItem, unsetMobileItem: unsetMobileItem, clearMobileItemTimeout: clearMobileItemTimeout, updateCurrentRoute: updateCurrentRoute, onItemClick: onItemClick }; }; var useSidebar = function useSidebar() { return { getSidebarProps: inject('vsmProps'), getSidebarRef: inject('getSidebarRef'), getIsCollapsed: inject('getIsCollapsed'), getMobileItem: inject('getMobileItem'), getMobileItemRect: inject('getMobileItemRect'), getCurrentRoute: inject('getCurrentRoute'), updateIsCollapsed: inject('updateIsCollapsed'), setMobileItem: inject('setMobileItem'), unsetMobileItem: inject('unsetMobileItem'), clearMobileItemTimeout: inject('clearMobileItemTimeout'), onRouteChange: inject('onRouteChange'), emitItemClick: inject('emitItemClick') }; }; function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } // Adapted from vue-router-next // See: https://github.com/vuejs/vue-router-next/blob/master/src/RouterLink.ts function activeRecordIndex(route, currentRoute) { var matched = route.matched; var length = matched.length; var routeMatched = matched[length - 1]; var currentMatched = currentRoute.matched; if (!routeMatched || !currentMatched.length) return -1; var index = currentMatched.findIndex(isSameRouteRecord.bind(null, routeMatched)); if (index > -1) return index; var parentRecordPath = getOriginalPath(matched[length - 2]); return length > 1 && getOriginalPath(routeMatched) === parentRecordPath && currentMatched[currentMatched.length - 1].path !== parentRecordPath ? currentMatched.findIndex(isSameRouteRecord.bind(null, matched[length - 2])) : index; } function isSameRouteLocationParams(a, b) { if (Object.keys(a).length !== Object.keys(b).length) return false; for (var key in a) { if (!isSameRouteLocationParamsValue(a[key], b[key])) return false; } return true; } function includesParams(outer, inner) { var _loop = function _loop() { var innerValue = inner[key]; var outerValue = outer[key]; if (typeof innerValue === 'string') { if (innerValue !== outerValue) return { v: false }; } else { if (!Array.isArray(outerValue) || outerValue.length !== innerValue.length || innerValue.some(function (value, i) { return value !== outerValue[i]; })) { return { v: false }; } } }, _ret; for (var key in inner) { _ret = _loop(); if (_ret) return _ret.v; } return true; } function getOriginalPath(record) { return record ? record.aliasOf ? record.aliasOf.path : record.path : ''; } function isSameRouteRecord(a, b) { return (a.aliasOf || a) === (b.aliasOf || b); } function isSameRouteLocationParamsValue(a, b) { return Array.isArray(a) ? isEquivalentArray(a, b) : Array.isArray(b) ? isEquivalentArray(b, a) : a === b; } function isEquivalentArray(a, b) { return Array.isArray(b) ? a.length === b.length && a.every(function (value, i) { return value === b[i]; }) : a.length === 1 && a[0] === b; } function useItem(props, emits) { var router = getCurrentInstance().appContext.config.globalProperties.$router; var _useSidebar = useSidebar(), getSidebarRef = _useSidebar.getSidebarRef, sidebarProps = _useSidebar.getSidebarProps, isCollapsed = _useSidebar.getIsCollapsed, mobileItem = _useSidebar.getMobileItem, mobileItemRect = _useSidebar.getMobileItemRect, currentRoute = _useSidebar.getCurrentRoute, setMobileItem = _useSidebar.setMobileItem, unsetMobileItem = _useSidebar.unsetMobileItem, clearMobileItemTimeout = _useSidebar.clearMobileItemTimeout, emitItemClick = _useSidebar.emitItemClick; var emitScrollUpdate = inject('emitScrollUpdate'); var itemShow = ref(false); var itemHover = ref(false); var active = computed(function () { return isLinkActive(props.item) || _isChildActive(props.item.child); }); var exactActive = computed(function () { return isLinkActive(props.item, true); }); var isLinkActive = function isLinkActive(item, exact) { if (item.isActive && typeof item.isActive === 'function') { var isActive = item.isActive(item); if (typeof isActive === 'boolean') { return isActive; } } if (!item.href || item.external) return false; if (router) { var route = router.resolve(item.href); var routerCurrentRoute = router.currentRoute.value; var activeIndex = activeRecordIndex(route, routerCurrentRoute); if (exact || item.exact) { return activeIndex > -1 && activeIndex === routerCurrentRoute.matched.length - 1 && isSameRouteLocationParams(routerCurrentRoute.params, route.params); } return activeIndex > -1 && includesParams(routerCurrentRoute.params, route.params); } else { return item.href === currentRoute.value; } }; var _isChildActive = function isChildActive(child) { if (!child) return false; return child.some(function (item) { return isLinkActive(item) || _isChildActive(item.child); }); }; var onLinkClick = function onLinkClick(event) { if (!props.item.href || props.item.disabled) { event.preventDefault(); if (props.item.disabled) return; } emitMobileItem(event, event.currentTarget.parentElement); if (hasChild.value) { if (!props.item.href || active.value) { show.value = !show.value; } } emitItemClick(event, props.item); }; var onMouseOver = function onMouseOver(event) { if (props.item.disabled) return; event.stopPropagation(); itemHover.value = true; }; var onMouseOut = function onMouseOut(event) { event.stopPropagation(); itemHover.value = false; }; var onMouseEnter = function onMouseEnter(event) { if (props.item.disabled) return; if (sidebarProps.disableHover) { if (isMobileItem.value && hasChild.value) { clearMobileItemTimeout(); } } else { clearMobileItemTimeout(); emitMobileItem(event, event.currentTarget); } }; var onMouseLeave = function onMouseLeave() { if (sidebarProps.disableHover && !hasChild.value) return; if (isMobileItem.value) { unsetMobileItem(false, !sidebarProps.disableHover ? 300 : undefined); } }; var emitMobileItem = function emitMobileItem(event, itemEl) { if (isMobileItem.value) return; if (isCollapsed.value) { setTimeout(function () { if (isFirstLevel.value) { if (!isMobileItem.value) { setMobileItem({ item: props.item, itemEl: itemEl }); } } if (event.type === 'click' && !hasChild.value) { unsetMobileItem(false, !isFirstLevel.value ? 300 : undefined); } }, 0); } }; var onExpandEnter = function onExpandEnter(el) { el.style.height = el.scrollHeight + 'px'; }; var onExpandAfterEnter = function onExpandAfterEnter(el) { el.style.height = 'auto'; if (!isCollapsed.value) { var sidebarWrapper = getSidebarRef.value.children[0]; var _el$getBoundingClient = el.getBoundingClientRect(), collapseBottom = _el$getBoundingClient.bottom; var _sidebarWrapper$getBo = sidebarWrapper.getBoundingClientRect(), wrapperBottom = _sidebarWrapper$getBo.bottom; if (collapseBottom > wrapperBottom) { nextTick(function () { el.scrollIntoView({ behavior: 'smooth', block: 'end' }); }); } emitScrollUpdate(); } }; var onExpandBeforeLeave = function onExpandBeforeLeave(el) { if (isCollapsed.value && isFirstLevel.value) { el.style.display = 'none'; return; } el.style.height = el.scrollHeight + 'px'; }; var onExpandAfterLeave = function onExpandAfterLeave() { if (!isCollapsed.value) { emitScrollUpdate(); } }; var show = computed({ get: function get() { if (!hasChild.value) return false; if (isCollapsed.value && isFirstLevel.value) return hover.value; if (sidebarProps.showChild) return true; if (sidebarProps.showOneChild && isFirstLevel.value || sidebarProps.showOneChild === 'deep') { return props.item.id === props.activeShow; } else { return itemShow.value; } }, set: function set(show) { if (sidebarProps.showOneChild && isFirstLevel.value || sidebarProps.showOneChild === 'deep') { if (show) { emits('update-active-show', props.item.id); } else { emits('update-active-show', undefined); } } itemShow.value = show; } }); var hover = computed(function () { return isCollapsed.value && isFirstLevel.value ? isMobileItem.value : itemHover.value; }); var isFirstLevel = computed(function () { return props.level === 1; }); var isHidden = computed(function () { if (isCollapsed.value) { if (props.item.hidden && props.item.hiddenOnCollapse === undefined) { return true; } else { return props.item.hiddenOnCollapse === true; } } else { return props.item.hidden === true; } }); var hasChild = computed(function () { return !!(props.item.child && props.item.child.length > 0); }); var linkClass = computed(function () { return ['vsm--link', "vsm--link_level-".concat(props.level), { 'vsm--link_mobile': isMobileItem.value, 'vsm--link_hover': hover.value, 'vsm--link_active': active.value, 'vsm--link_disabled': props.item.disabled, 'vsm--link_open': show.value }, props.item.class]; }); var linkAttrs = computed(function () { var href = props.item.href ? props.item.href : '#'; var target = props.item.external ? '_blank' : '_self'; var tabindex = props.item.disabled ? -1 : null; var ariaCurrent = exactActive.value ? 'page' : null; var ariaExpanded = hasChild.value ? show.value : null; var ariaControls = ariaExpanded ? "vsm-".concat(props.item.id) : null; return _objectSpread2({ href: href, target: target, tabindex: tabindex, 'aria-current': ariaCurrent, 'aria-expanded': ariaExpanded, 'aria-controls': ariaControls }, props.item.attributes); }); var childAttrs = computed(function () { return { id: "vsm-".concat(props.item.id) }; }); var itemClass = computed(function () { return ['vsm--item', { 'vsm--item_mobile': isMobileItem.value }]; }); var isMobileItem = computed(function () { var _mobileItem$value; return props.item.id === ((_mobileItem$value = mobileItem.value) === null || _mobileItem$value === void 0 ? void 0 : _mobileItem$value.id); }); var mobileItemDropdownStyle = computed(function () { return _objectSpread2(_objectSpread2({ position: 'absolute', 'max-height': "".concat(mobileItemRect.value.maxHeight, "px"), width: "".concat(mobileItemRect.value.maxWidth, "px"), 'overflow-y': 'auto' }, !mobileItemRect.value.dropup ? { top: "".concat(mobileItemRect.value.top + mobileItemRect.value.height, "px") } : { bottom: "".concat(mobileItemRect.value.dropup, "px") }), !sidebarProps.rtl ? { left: sidebarProps.widthCollapsed } : { right: sidebarProps.widthCollapsed }); }); var mobileItemStyle = computed(function () { return _objectSpread2(_objectSpread2({ position: 'absolute', top: "".concat(mobileItemRect.value.top, "px") }, !sidebarProps.rtl ? { left: sidebarProps.widthCollapsed } : { right: sidebarProps.widthCollapsed }), {}, { width: "".concat(mobileItemRect.value.maxWidth, "px"), height: "".concat(mobileItemRect.value.height, "px"), 'padding-left': "".concat(mobileItemRect.value.padding[0], "px"), 'padding-right': "".concat(mobileItemRect.value.padding[1], "px"), 'z-index': '20' }); }); var mobileItemBackgroundStyle = computed(function () { return _objectSpread2(_objectSpread2({ position: 'absolute', top: "".concat(mobileItemRect.value.top, "px") }, !sidebarProps.rtl ? { left: '0px' } : { right: '0px' }), {}, { width: "".concat(mobileItemRect.value.maxWidth + parseInt(sidebarProps.widthCollapsed), "px"), height: "".concat(mobileItemRect.value.height, "px"), 'z-index': '10' }); }); watch(function () { return active.value; }, function () { if (active.value) { show.value = true; } }, { immediate: true }); return { active: active, exactActive: exactActive, show: show, hover: hover, isFirstLevel: isFirstLevel, isHidden: isHidden, hasChild: hasChild, linkClass: linkClass, linkAttrs: linkAttrs, childAttrs: childAttrs, itemClass: itemClass, isMobileItem: isMobileItem, mobileItemDropdownStyle: mobileItemDropdownStyle, mobileItemStyle: mobileItemStyle, mobileItemBackgroundStyle: mobileItemBackgroundStyle, onLinkClick: onLinkClick, onMouseOver: onMouseOver, onMouseOut: onMouseOut, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onExpandEnter: onExpandEnter, onExpandAfterEnter: onExpandAfterEnter, onExpandBeforeLeave: onExpandBeforeLeave, onExpandAfterLeave: onExpandAfterLeave }; } const _hoisted_1$2 = ["href", "onClick"]; const __default__$5 = { compatConfig: { MODE: 3, inheritAttrs: false, }, }; var script$5 = /*@__PURE__*/Object.assign(__default__$5, { __name: 'SidebarMenuLink', props: { item: { type: Object, required: true, }, }, setup(__props) { const props = __props; const router = getCurrentInstance().appContext.config.globalProperties.$router; const isHyperLink = computed(() => { return !!(!props.item.href || props.item.external || !router) }); return (_ctx, _cache) => { const _component_router_link = resolveComponent("router-link"); return (isHyperLink.value) ? (openBlock(), createElementBlock("a", normalizeProps(mergeProps({ key: 0 }, _ctx.$attrs)), [ renderSlot(_ctx.$slots, "default") ], 16 /* FULL_PROPS */)) : (openBlock(), createBlock(_component_router_link, { key: 1, custom: "", to: _ctx.$attrs.href }, { default: withCtx(({ href, navigate }) => [ createElementVNode("a", mergeProps(_ctx.$attrs, { href: href, onClick: navigate }), [ renderSlot(_ctx.$slots, "default") ], 16 /* FULL_PROPS */, _hoisted_1$2) ]), _: 3 /* FORWARDED */ }, 8 /* PROPS */, ["to"])) } } }); script$5.__file = "src/components/SidebarMenuLink.vue"; const __default__$4 = { compatConfig: { MODE: 3 }, }; var script$4 = /*@__PURE__*/Object.assign(__default__$4, { __name: 'SidebarMenuIcon', props: { icon: { type: [String, Object], default: '', }, }, setup(__props) { const props = __props; const attributes = computed(() => { return { class: [ 'vsm--icon', typeof props.icon === 'object' ? props.icon.class : props.icon, ], 'aria-hidden': true, ...props.icon.attributes, } }); return (_ctx, _cache) => { return (typeof __props.icon === 'object' && __props.icon.text) ? (openBlock(), createBlock(resolveDynamicComponent(__props.icon.element ? __props.icon.element : 'i'), normalizeProps(mergeProps({ key: 0 }, attributes.value)), { default: withCtx(() => [ createTextVNode(toDisplayString(__props.icon.text), 1 /* TEXT */) ]), _: 1 /* STABLE */ }, 16 /* FULL_PROPS */)) : (typeof __props.icon === 'object') ? (openBlock(), createBlock(resolveDynamicComponent(__props.icon.element ? __props.icon.element : 'i'), normalizeProps(mergeProps({ key: 1 }, attributes.value)), null, 16 /* FULL_PROPS */)) : (openBlock(), createElementBlock("i", normalizeProps(mergeProps({ key: 2 }, attributes.value)), null, 16 /* FULL_PROPS */)) } } }); script$4.__file = "src/components/SidebarMenuIcon.vue"; const __default__$3 = { compatConfig: { MODE: 3 }, }; var script$3 = /*@__PURE__*/Object.assign(__default__$3, { __name: 'SidebarMenuBadge', props: { badge: { type: Object, default: () => {}, }, }, setup(__props) { const props = __props; const attributes = computed(() => { return { class: ['vsm--badge', props.badge.class], ...props.badge.attributes, } }); return (_ctx, _cache) => { return (__props.badge.text) ? (openBlock(), createBlock(resolveDynamicComponent(__props.badge.element ? __props.badge.element : 'span'), normalizeProps(mergeProps({ key: 0 }, attributes.value)), { default: withCtx(() => [ createTextVNode(toDisplayString(__props.badge.text), 1 /* TEXT */) ]), _: 1 /* STABLE */ }, 16 /* FULL_PROPS */)) : (openBlock(), createBlock(resolveDynamicComponent(__props.badge.element ? __props.badge.element : 'span'), normalizeProps(mergeProps({ key: 1 }, attributes.value)), null, 16 /* FULL_PROPS */)) } } }); script$3.__file = "src/components/SidebarMenuBadge.vue"; const _hoisted_1$1 = { key: 0 }; const _hoisted_2$1 = { class: "vsm--dropdown" }; const __default__$2 = { compatConfig: { MODE: 3 }, }; var script$2 = /*@__PURE__*/Object.assign(__default__$2, { __name: 'SidebarMenuItem', props: { item: { type: Object, required: true, }, level: { type: Number, default: 1, }, activeShow: { type: String, default: undefined, }, }, emits: ['update-active-show'], setup(__props, { emit: __emit }) { const props = __props; const emits = __emit; const { getSidebarProps, getIsCollapsed: isCollapsed } = useSidebar(); const { linkComponentName } = toRefs(getSidebarProps); const subActiveShow = ref(undefined); const updateActiveShow = (id) => { subActiveShow.value = id; }; const { show, hover, isFirstLevel, isHidden, hasChild, linkClass, linkAttrs, childAttrs, itemClass, isMobileItem, mobileItemStyle, mobileItemDropdownStyle, mobileItemBackgroundStyle, onLinkClick, onMouseOver, onMouseOut, onMouseEnter, onMouseLeave, onExpandEnter, onExpandAfterEnter, onExpandBeforeLeave, onExpandAfterLeave, } = useItem(props, emits); return (_ctx, _cache) => { const _component_sidebar_menu_item = resolveComponent("sidebar-menu-item", true); return (__props.item.component && !unref(isHidden)) ? (openBlock(), createElementBlock("li", _hoisted_1$1, [ (openBlock(), createBlock(resolveDynamicComponent(__props.item.component), normalizeProps(guardReactiveProps(__props.item.props)), null, 16 /* FULL_PROPS */)) ])) : (__props.item.header && !unref(isHidden)) ? (openBlock(), createElementBlock("li", mergeProps({ key: 1, class: ['vsm--header', __props.item.class] }, __props.item.attributes), toDisplayString(__props.item.header), 17 /* TEXT, FULL_PROPS */)) : (!unref(isHidden)) ? (openBlock(), createElementBlock("li", mergeProps({ key: 2, class: unref(itemClass), onMouseover: _cache[0] || (_cache[0] = (...args) => (unref(onMouseOver) && unref(onMouseOver)(...args))), onMouseout: _cache[1] || (_cache[1] = (...args) => (unref(onMouseOut) && unref(onMouseOut)(...args))) }, toHandlers( unref(isCollapsed) && unref(isFirstLevel) ? { mouseenter: unref(onMouseEnter), mouseleave: unref(onMouseLeave) } : {} , true)), [ (openBlock(), createBlock(resolveDynamicComponent(unref(linkComponentName) ? unref(linkComponentName) : script$5), mergeProps({ item: __props.item, class: unref(linkClass) }, unref(linkAttrs), { onClick: unref(onLinkClick) }), { default: withCtx(() => [ (unref(isCollapsed) && unref(isFirstLevel)) ? (openBlock(), createBlock(Transition, { key: 0, name: "slide-animation" }, { default: withCtx(() => [ (unref(hover)) ? (openBlock(), createElementBlock("div", { key: 0, class: "vsm--mobile-bg", style: normalizeStyle(unref(mobileItemBackgroundStyle)) }, null, 4 /* STYLE */)) : createCommentVNode("v-if", true) ]), _: 1 /* STABLE */ })) : createCommentVNode("v-if", true), (__props.item.icon) ? (openBlock(), createBlock(script$4, { key: 1, icon: __props.item.icon }, null, 8 /* PROPS */, ["icon"])) : createCommentVNode("v-if", true), createElementVNode("div", { class: normalizeClass([ 'vsm--title', unref(isCollapsed) && unref(isFirstLevel) && !unref(isMobileItem) && 'vsm--title_hidden', ]), style: normalizeStyle(unref(isMobileItem) && unref(mobileItemStyle)) }, [ createElementVNode("span", null, toDisplayString(__props.item.title), 1 /* TEXT */), (__props.item.badge) ? (openBlock(), createBlock(script$3, { key: 0, badge: __props.item.badge }, null, 8 /* PROPS */, ["badge"])) : createCommentVNode("v-if", true), (unref(hasChild)) ? (openBlock(), createElementBlock("div", { key: 1, class: normalizeClass(['vsm--arrow', { 'vsm--arrow_open': unref(show) }]) }, [ renderSlot(_ctx.$slots, "dropdown-icon", normalizeProps(guardReactiveProps({ isOpen: unref(show) }))) ], 2 /* CLASS */)) : createCommentVNode("v-if", true) ], 6 /* CLASS, STYLE */) ]), _: 3 /* FORWARDED */ }, 16 /* FULL_PROPS */, ["item", "class", "onClick"])), (unref(hasChild)) ? (openBlock(), createBlock(Transition, { key: 0, appear: unref(isMobileItem), name: "expand", onEnter: unref(onExpandEnter), onAfterEnter: unref(onExpandAfterEnter), onBeforeLeave: unref(onExpandBeforeLeave), onAfterLeave: unref(onExpandAfterLeave) }, { default: withCtx(() => [ (unref(show)) ? (openBlock(), createElementBlock("div", mergeProps({ key: 0, class: ['vsm--child', unref(isMobileItem) && 'vsm--child_mobile'], style: unref(isMobileItem) && unref(mobileItemDropdownStyle) }, unref(childAttrs)), [ createElementVNode("ul", _hoisted_2$1, [ (openBlock(true), createElementBlock(Fragment, null, renderList(__props.item.child, (subItem) => { return (openBlock(), createBlock(_component_sidebar_menu_item, { key: subItem.id, item: subItem, level: __props.level + 1, "active-show": subActiveShow.value, onUpdateActiveShow: updateActiveShow }, { "dropdown-icon": withCtx(({ isOpen }) => [ renderSlot(_ctx.$slots, "dropdown-icon", mergeProps({ ref_for: true }, { isOpen })) ]), _: 2 /* DYNAMIC */ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["item", "level", "active-show"])) }), 128 /* KEYED_FRAGMENT */)) ]) ], 16 /* FULL_PROPS */)) : createCommentVNode("v-if", true) ]), _: 3 /* FORWARDED */ }, 8 /* PROPS */, ["appear", "onEnter", "onAfterEnter", "onBeforeLeave", "onAfterLeave"])) : createCommentVNode("v-if", true) ], 16 /* FULL_PROPS */)) : createCommentVNode("v-if", true) } } }); script$2.__file = "src/components/SidebarMenuItem.vue"; const __default__$1 = { compatConfig: { MODE: 3 }, }; var script$1 = /*@__PURE__*/Object.assign(__default__$1, { __name: 'SidebarMenuScroll', setup(__props) { const { getIsCollapsed: isCollapsed } = useSidebar(); const scrollRef = ref(null); const scrollBarRef = ref(null); const scrollThumbRef = ref(null); const cursorDown = ref(false); let cursorY = 0; let cursorIn = false; const visible = ref(false); const onScrollUpdate = () => { if (!scrollRef.value) return nextTick(() => { updateThumb(); }); }; const onScroll = () => { requestAnimationFrame(onScrollUpdate); }; const onClick = (e) => { const offset = Math.abs( scrollBarRef.value.getBoundingClientRect().y - e.clientY ); const thumbHalf = scrollThumbRef.value.offsetHeight / 2; updateScrollTop(offset - thumbHalf); }; const onMouseDown = (e) => { e.stopImmediatePropagation(); cursorDown.value = true; window.addEventListener('mousemove', onMouseMove); window.addEventListener('mouseup', onMouseUp); cursorY = scrollThumbRef.value.offsetHeight - (e.clientY - scrollThumbRef.value.getBoundingClientRect().y); }; const onMouseMove = (e) => { if (!cursorDown.value) return const offset = e.clientY - scrollBarRef.value.getBoundingClientRect().y; const thumbClickPosition = scrollThumbRef.value.offsetHeight - cursorY; visible.value = true; updateScrollTop(offset - thumbClickPosition); }; const onMouseUp = (e) => { cursorDown.value = false; cursorY = 0; if (!cursorIn) { visible.value = false; } window.removeEventListener('mousemove', onMouseMove); window.removeEventListener('mouseup', onMouseUp); }; const onMouseEnter = (e) => { visible.value = true; cursorIn = true; }; const onMouseLeave = (e) => { cursorIn = false; if (!cursorDown.value) { visible.value = false; } }; const updateThumb = () => { const heightPerc = (scrollRef.value.clientHeight * 100) / scrollRef.value.scrollHeight; const thumbHeightPerc = heightPerc < 100 ? heightPerc : 0; const thumbYPerc = (scrollRef.value.scrollTop * 100) / scrollRef.value.clientHeight || 0; scrollThumbRef.value.style.height = `${thumbHeightPerc}%`; scrollThumbRef.value.style.transform = `translateY(${thumbYPerc}%)`; }; const updateScrollTop = (y) => { const scrollPerc = (y * 100) / scrollBarRef.value.offsetHeight; scrollRef.value.scrollTop = (scrollPerc * scrollRef.value.scrollHeight) / 100; }; watch( () => isCollapsed.value, () => { onScrollUpdate(); } ); onMounted(() => { onScrollUpdate(); window.addEventListener('resize', onScrollUpdate); }); onUnmounted(() => { window.removeEventListener('resize', onScrollUpdate); }); provide('emitScrollUpdate', onScrollUpdate); return (_ctx, _cache) => { return (openBlock(), createElementBlock("div", { class: "vsm--scroll-wrapper", onMouseenter: onMouseEnter, onMouseleave: onMouseLeave }, [ createElementVNode("div", { ref_key: "scrollRef", ref: scrollRef, class: "vsm--scroll", onScroll: onScroll }, [ renderSlot(_ctx.$slots, "default") ], 544 /* NEED_HYDRATION, NEED_PATCH */), createVNode(Transition, { persisted: "" }, { default: withCtx(() => [ withDirectives(createElementVNode("div", { ref_key: "scrollBarRef", ref: scrollBarRef, class: "vsm--scroll-bar", onMousedown: onClick }, [ createElementVNode("div", { ref_key: "scrollThumbRef", ref: scrollThumbRef, class: normalizeClass(["vsm--scroll-thumb", [cursorDown.value && 'vsm--scroll-thumb_clicking']]), onMousedown: onMouseDown }, null, 34 /* CLASS, NEED_HYDRATION */) ], 544 /* NEED_HYDRATION, NEED_PATCH */), [ [vShow, visible.value] ]) ]), _: 1 /* STABLE */ }) ], 32 /* NEED_HYDRATION */)) } } }); script$1.__scopeId = "data-v-402f9588"; script$1.__file = "src/components/SidebarMenuScroll.vue"; const _hoisted_1 = { class: "vsm--wrapper" }; const _hoisted_2 = ["aria-label"]; const __default__ = { compatConfig: { MODE: 3 }, }; var script = /*@__PURE__*/Object.assign(__default__, { __name: 'SidebarMenu', props: { menu: { type: Array, required: true, }, collapsed: { type: Boolean, default: false, }, width: { type: String, default: '290px', }, widthCollapsed: { type: String, default: '65px', }, showChild: { type: Boolean, default: false, }, theme: { type: String, default: undefined, validator: (value) => ['', 'white-theme'].includes(value), }, showOneChild: { type: [Boolean, String], default: false, validator(value) { if (typeof value === 'string') { return ['deep'].includes(value) } else { return typeof value === 'boolean' } }, }, rtl: { type: Boolean, default: false, }, relative: { type: Boolean, default: false, }, hideToggle: { type: Boolean, default: false, }, disableHover: { type: Boolean, default: false, }, linkComponentName: { type: String, default: undefined, }, }, emits: { 'item-click'(event, item) { return !!(event && item) }, 'update:collapsed'(collapsed) { return !!(typeof collapsed === 'boolean') }, }, setup(__props, { expose: __expose, emit: __emit }) { const props = __props; const emits = __emit; const { getSidebarRef: sidebarMenuRef, getIsCollapsed: isCollapsed, updateIsCollapsed, unsetMobileItem, updateCurrentRoute, } = initSidebar(props, emits); const activeShow = ref(undefined); const computedMenu = computed(() => { let id = 0; function transformItems(items) { function randomId() { return `${Date.now() + '' + id++}` } return items.map((item) => { return { id: randomId(), ...item, ...(item.child && { child: transformItems(item.child) }), } }) } return transformItems(props.menu) }); const sidebarWidth = computed(() => { return isCollapsed.value ? props.widthCollapsed : props.width }); const sidebarClass = computed(() => { return [ 'v-sidebar-menu', !isCollapsed.value ? 'vsm_expanded' : 'vsm_collapsed', props.theme && `vsm_${props.theme}`, props.rtl && 'vsm_rtl', props.relative && 'vsm_relative', ] }); const updateActiveShow = (id) => { activeShow.value = id; }; const onToggleClick = () => { unsetMobileItem(); updateIsCollapsed(!isCollapsed.value); emits('update:collapsed', isCollapsed.value); }; watch( () => props.collapsed, (currentCollapsed) => { unsetMobileItem(); updateIsCollapsed(currentCollapsed); } ); const router = getCurrentInstance().appContext.config.globalProperties.$router; if (!router) { onMounted(() => { updateCurrentRoute(); window.addEventListener('hashchange', updateCurrentRoute); }); onUnmounted(() => { window.removeEventListener('hashchange', updateCurrentRoute); }); } __expose({ onRouteChange: updateCurrentRoute, }); return (_ctx, _cache) => { return (openBlock(), createElementBlock("div", { ref_key: "sidebarMenuRef", ref: sidebarMenuRef, class: normalizeClass([sidebarClass.value]), style: normalizeStyle({ 'max-width': sidebarWidth.value }) }, [ createElementVNode("div", _hoisted_1, [ renderSlot(_ctx.$slots, "header"), createVNode(script$1, null, { default: withCtx(() => [ createElementVNode("ul", { class: "vsm--menu", style: normalizeStyle({ width: sidebarWidth.value }) }, [ (openBlock(true), createElementBlock(Fragment, null, renderList(computedMenu.value, (item) => { return (openBlock(), createBlock(script$2, { key: item.id, item: item, "active-show": activeShow.value, onUpdateActiveShow: updateActiveShow }, { "dropdown-icon": withCtx(({ isOpen }) => [ renderSlot(_ctx.$slots, "dropdown-icon", mergeProps({ ref_for: true }, { isOpen }), () => [ _cache[0] || (_cache[0] = createElementVNode("span", { class: "vsm--arrow_default" }, null, -1 /* HOISTED */)) ]) ]), _: 2 /* DYNAMIC */ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["item", "active-show"])) }), 128 /* KEYED_FRAGMENT */)) ], 4 /* STYLE */) ]), _: 3 /* FORWARDED */ }), renderSlot(_ctx.$slots, "footer") ]), (!__props.hideToggle) ? (openBlock(), createElementBlock("button", { key: 0, class: "vsm--toggle-btn", "aria-label": __props.collapsed ? 'Expand sidebar' : 'Collapse sidebar', onClick: onToggleClick }, [ renderSlot(_ctx.$slots, "toggle-icon", {}, () => [ _cache[1] || (_cache[1] = createElementVNode("span", { class: "vsm--toggle-btn_default" }, null, -1 /* HOISTED */)) ]) ], 8 /* PROPS */, _hoisted_2)) : createCommentVNode("v-if", true) ], 6 /* CLASS, STYLE */)) } } }); script.__file = "src/components/SidebarMenu.vue"; var index = { install: function install(Vue) { Vue.component('SidebarMenu', script); } }; export { script as SidebarMenu, index as default }; //# sourceMappingURL=vue-sidebar-menu.esm.js.map