UNPKG

element-plus

Version:

A Component Library for Vue 3

292 lines (289 loc) 10.1 kB
import { defineComponent, getCurrentInstance, computed, inject, ref, reactive, watch, provide, onMounted, onBeforeUnmount, h, Fragment, withDirectives, vShow } from 'vue'; import { useTimeoutFn } from '@vueuse/core'; import _CollapseTransition from '../../collapse-transition/index.mjs'; import { ElTooltip } from '../../tooltip/index.mjs'; import '../../../utils/index.mjs'; import '../../../hooks/index.mjs'; import { ArrowDown, ArrowRight } from '@element-plus/icons-vue'; import { ElIcon } from '../../icon/index.mjs'; import useMenu from './use-menu.mjs'; import { useMenuCssVar } from './use-menu-css-var.mjs'; import { buildProps } from '../../../utils/vue/props/runtime.mjs'; import { useNamespace } from '../../../hooks/use-namespace/index.mjs'; import { throwError } from '../../../utils/error.mjs'; const subMenuProps = buildProps({ index: { type: String, required: true }, showTimeout: { type: Number, default: 300 }, hideTimeout: { type: Number, default: 300 }, popperClass: String, disabled: Boolean, popperAppendToBody: { type: Boolean, default: void 0 }, popperOffset: { type: Number, default: 6 } }); const COMPONENT_NAME = "ElSubMenu"; var SubMenu = defineComponent({ name: COMPONENT_NAME, props: subMenuProps, setup(props, { slots, expose }) { const instance = getCurrentInstance(); const { indexPath, parentMenu } = useMenu(instance, computed(() => props.index)); const nsMenu = useNamespace("menu"); const nsSubMenu = useNamespace("sub-menu"); const rootMenu = inject("rootMenu"); if (!rootMenu) throwError(COMPONENT_NAME, "can not inject root menu"); const subMenu = inject(`subMenu:${parentMenu.value.uid}`); if (!subMenu) throwError(COMPONENT_NAME, "can not inject sub menu"); const items = ref({}); const subMenus = ref({}); let timeout; const mouseInChild = ref(false); const verticalTitleRef = ref(); const vPopper = ref(null); const currentPlacement = computed(() => mode.value === "horizontal" && isFirstLevel.value ? "bottom-start" : "right-start"); const subMenuTitleIcon = computed(() => { return mode.value === "horizontal" && isFirstLevel.value || mode.value === "vertical" && !rootMenu.props.collapse ? ArrowDown : ArrowRight; }); const isFirstLevel = computed(() => { return subMenu.level === 0; }); const appendToBody = computed(() => { return props.popperAppendToBody === void 0 ? isFirstLevel.value : Boolean(props.popperAppendToBody); }); const menuTransitionName = computed(() => rootMenu.props.collapse ? `${nsMenu.namespace.value}-zoom-in-left` : `${nsMenu.namespace.value}-zoom-in-top`); const fallbackPlacements = computed(() => mode.value === "horizontal" && isFirstLevel.value ? [ "bottom-start", "bottom-end", "top-start", "top-end", "right-start", "left-start" ] : [ "right-start", "left-start", "bottom-start", "bottom-end", "top-start", "top-end" ]); const opened = computed(() => rootMenu.openedMenus.includes(props.index)); const active = computed(() => { let isActive = false; Object.values(items.value).forEach((item2) => { if (item2.active) { isActive = true; } }); Object.values(subMenus.value).forEach((subItem) => { if (subItem.active) { isActive = true; } }); return isActive; }); const backgroundColor = computed(() => rootMenu.props.backgroundColor || ""); const activeTextColor = computed(() => rootMenu.props.activeTextColor || ""); const textColor = computed(() => rootMenu.props.textColor || ""); const mode = computed(() => rootMenu.props.mode); const item = reactive({ index: props.index, indexPath, active }); const titleStyle = computed(() => { if (mode.value !== "horizontal") { return { color: textColor.value }; } return { borderBottomColor: active.value ? rootMenu.props.activeTextColor ? activeTextColor.value : "" : "transparent", color: active.value ? activeTextColor.value : textColor.value }; }); const doDestroy = () => { var _a, _b, _c; return (_c = (_b = (_a = vPopper.value) == null ? void 0 : _a.popperRef) == null ? void 0 : _b.popperInstanceRef) == null ? void 0 : _c.destroy(); }; const handleCollapseToggle = (value) => { if (!value) { doDestroy(); } }; const handleClick = () => { if (rootMenu.props.menuTrigger === "hover" && rootMenu.props.mode === "horizontal" || rootMenu.props.collapse && rootMenu.props.mode === "vertical" || props.disabled) return; rootMenu.handleSubMenuClick({ index: props.index, indexPath: indexPath.value, active: active.value }); }; const handleMouseenter = (event, showTimeout = props.showTimeout) => { var _a; if (event.type === "focus") { return; } if (rootMenu.props.menuTrigger === "click" && rootMenu.props.mode === "horizontal" || !rootMenu.props.collapse && rootMenu.props.mode === "vertical" || props.disabled) { return; } subMenu.mouseInChild.value = true; timeout == null ? void 0 : timeout(); ({ stop: timeout } = useTimeoutFn(() => { rootMenu.openMenu(props.index, indexPath.value); }, showTimeout)); if (appendToBody.value) { (_a = parentMenu.value.vnode.el) == null ? void 0 : _a.dispatchEvent(new MouseEvent("mouseenter")); } }; const handleMouseleave = (deepDispatch = false) => { var _a, _b; if (rootMenu.props.menuTrigger === "click" && rootMenu.props.mode === "horizontal" || !rootMenu.props.collapse && rootMenu.props.mode === "vertical") { return; } timeout == null ? void 0 : timeout(); subMenu.mouseInChild.value = false; ({ stop: timeout } = useTimeoutFn(() => !mouseInChild.value && rootMenu.closeMenu(props.index, indexPath.value), props.hideTimeout)); if (appendToBody.value && deepDispatch) { if (((_a = instance.parent) == null ? void 0 : _a.type.name) === "ElSubMenu") { (_b = subMenu.handleMouseleave) == null ? void 0 : _b.call(subMenu, true); } } }; watch(() => rootMenu.props.collapse, (value) => handleCollapseToggle(Boolean(value))); { const addSubMenu = (item2) => { subMenus.value[item2.index] = item2; }; const removeSubMenu = (item2) => { delete subMenus.value[item2.index]; }; provide(`subMenu:${instance.uid}`, { addSubMenu, removeSubMenu, handleMouseleave, mouseInChild, level: subMenu.level + 1 }); } expose({ opened }); onMounted(() => { rootMenu.addSubMenu(item); subMenu.addSubMenu(item); }); onBeforeUnmount(() => { subMenu.removeSubMenu(item); rootMenu.removeSubMenu(item); }); return () => { var _a; const titleTag = [ (_a = slots.title) == null ? void 0 : _a.call(slots), h(ElIcon, { class: nsSubMenu.e("icon-arrow") }, { default: () => h(subMenuTitleIcon.value) }) ]; const ulStyle = useMenuCssVar(rootMenu.props, subMenu.level + 1); const child = rootMenu.isMenuPopup ? h(ElTooltip, { ref: vPopper, visible: opened.value, effect: "light", pure: true, offset: props.popperOffset, showArrow: false, persistent: true, popperClass: props.popperClass, placement: currentPlacement.value, teleported: appendToBody.value, fallbackPlacements: fallbackPlacements.value, transition: menuTransitionName.value, gpuAcceleration: false }, { content: () => { var _a2; return h("div", { class: [ nsMenu.m(mode.value), nsMenu.m("popup-container"), props.popperClass ], onMouseenter: (evt) => handleMouseenter(evt, 100), onMouseleave: () => handleMouseleave(true), onFocus: (evt) => handleMouseenter(evt, 100) }, [ h("ul", { class: [ nsMenu.b(), nsMenu.m("popup"), nsMenu.m(`popup-${currentPlacement.value}`) ], style: ulStyle.value }, [(_a2 = slots.default) == null ? void 0 : _a2.call(slots)]) ]); }, default: () => h("div", { class: nsSubMenu.e("title"), style: [ titleStyle.value, { backgroundColor: backgroundColor.value } ], onClick: handleClick }, titleTag) }) : h(Fragment, {}, [ h("div", { class: nsSubMenu.e("title"), style: [ titleStyle.value, { backgroundColor: backgroundColor.value } ], ref: verticalTitleRef, onClick: handleClick }, titleTag), h(_CollapseTransition, {}, { default: () => { var _a2; return withDirectives(h("ul", { role: "menu", class: [nsMenu.b(), nsMenu.m("inline")], style: ulStyle.value }, [(_a2 = slots.default) == null ? void 0 : _a2.call(slots)]), [[vShow, opened.value]]); } }) ]); return h("li", { class: [ nsSubMenu.b(), nsSubMenu.is("active", active.value), nsSubMenu.is("opened", opened.value), nsSubMenu.is("disabled", props.disabled) ], role: "menuitem", ariaHaspopup: true, ariaExpanded: opened.value, onMouseenter: handleMouseenter, onMouseleave: () => handleMouseleave(true), onFocus: handleMouseenter }, [child]); }; } }); export { SubMenu as default, subMenuProps }; //# sourceMappingURL=sub-menu.mjs.map