UNPKG

element-plus

Version:

A Component Library for Vue3.0

439 lines (429 loc) 16.7 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var mitt = require('mitt'); var vue = require('vue'); var ElCollapseTransition = require('../el-collapse-transition'); var ElPopper = require('../el-popper'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var mitt__default = /*#__PURE__*/_interopDefaultLegacy(mitt); var ElCollapseTransition__default = /*#__PURE__*/_interopDefaultLegacy(ElCollapseTransition); var ElPopper__default = /*#__PURE__*/_interopDefaultLegacy(ElPopper); function useMenu(instance, currentIndex) { const rootMenu = vue.inject('rootMenu'); const indexPath = vue.computed(() => { let parent = instance.parent; const path = [currentIndex]; while (parent.type.name !== 'ElMenu') { if (parent.props.index) { path.unshift(parent.props.index); } parent = parent.parent; } return path; }); const parentMenu = vue.computed(() => { let parent = instance.parent; while (parent && ['ElMenu', 'ElSubmenu'].indexOf(parent.type.name) === -1) { parent = parent.parent; } return parent; }); const paddingStyle = vue.computed(() => { let parent = instance.parent; if (rootMenu.props.mode !== 'vertical') return {}; let padding = 20; if (rootMenu.props.collapse) { padding = 20; } else { while (parent && parent.type.name !== 'ElMenu') { if (parent.type.name === 'ElSubmenu') { padding += 20; } parent = parent.parent; } } return { paddingLeft: padding + 'px' }; }); return { parentMenu, paddingStyle, indexPath }; } var script = vue.defineComponent({ name: 'ElSubmenu', componentName: 'ElSubmenu', props: { index: { type: String, required: true, }, showTimeout: { type: Number, default: 300, }, hideTimeout: { type: Number, default: 300, }, popperClass: String, disabled: Boolean, popperAppendToBody: { type: Boolean, default: undefined, }, }, setup(props) { const data = vue.reactive({ popperJS: null, timeout: null, items: {}, submenus: {}, currentPlacement: '', mouseInChild: false, opened: false, }); const verticalTitleRef = vue.ref(null); const popperVnode = vue.ref(null); const instance = vue.getCurrentInstance(); const { paddingStyle, indexPath, parentMenu } = useMenu(instance, props.index); const { openedMenus, isMenuPopup, hoverBackground: rootHoverBackground, methods: rootMethods, props: rootProps, methods: { closeMenu }, rootMenuOn, rootMenuEmit, } = vue.inject('rootMenu'); const { addSubMenu: parentAddSubmenu, removeSubMenu: parentRemoveSubmenu, handleMouseleave: parentHandleMouseleave, } = vue.inject(`subMenu:${parentMenu.value.uid}`); const submenuTitleIcon = vue.computed(() => { return (mode.value === 'horizontal' && isFirstLevel.value) || (mode.value === 'vertical' && !rootProps.collapse) ? 'el-icon-arrow-down' : 'el-icon-arrow-right'; }); const isFirstLevel = vue.computed(() => { let isFirstLevel = true; let parent = instance.parent; while (parent && parent.type.name !== 'ElMenu') { if (['ElSubmenu', 'ElMenuItemGroup'].includes(parent.type.name)) { isFirstLevel = false; break; } else { parent = parent.parent; } } return isFirstLevel; }); const appendToBody = vue.computed(() => { return props.popperAppendToBody === undefined ? isFirstLevel.value : Boolean(props.popperAppendToBody); }); const menuTransitionName = vue.computed(() => { return rootProps.collapse ? 'el-zoom-in-left' : 'el-zoom-in-top'; }); const opened = vue.computed(() => { return openedMenus.value.includes(props.index); }); const active = vue.computed(() => { let isActive = false; const submenus = data.submenus; const items = data.items; Object.keys(items).forEach(index => { if (items[index].active) { isActive = true; } }); Object.keys(submenus).forEach(index => { if (submenus[index].active) { isActive = true; } }); return isActive; }); const backgroundColor = vue.computed(() => { return rootProps.backgroundColor || ''; }); const activeTextColor = vue.computed(() => { return rootProps.activeTextColor || ''; }); const textColor = vue.computed(() => { return rootProps.textColor || ''; }); const mode = vue.computed(() => { return rootProps.mode; }); const titleStyle = vue.computed(() => { if (mode.value !== 'horizontal') { return { color: textColor.value, }; } return { borderBottomColor: active.value ? rootProps.activeTextColor ? activeTextColor.value : '' : 'transparent', color: active.value ? activeTextColor.value : textColor.value, }; }); const subMenuEmitter = mitt__default['default'](); const doDestroy = () => { var _a; (_a = popperVnode.value) === null || _a === void 0 ? void 0 : _a.doDestroy(); }; const handleCollapseToggle = value => { if (value) { updatePlacement(); } else { doDestroy(); } }; const addItem = item => { data.items[item.index] = item; }; const removeItem = item => { delete data.items[item.index]; }; const addSubMenu = item => { data.submenus[item.index] = item; }; const removeSubMenu = item => { delete data.submenus[item.index]; }; const handleClick = () => { const disabled = props.disabled; if ((rootProps.menuTrigger === 'hover' && rootProps.mode === 'horizontal') || (rootProps.collapse && rootProps.mode === 'vertical') || disabled) { return; } rootMenuEmit('submenu:submenu-click', { index: props.index, indexPath }); }; const handleMouseenter = (event, showTimeout = props.showTimeout) => { if (!('ActiveXObject' in window) && event.type === 'focus' && !event.relatedTarget) { return; } const disabled = props.disabled; if ((rootProps.menuTrigger === 'click' && rootProps.mode === 'horizontal') || (!rootProps.collapse && rootProps.mode === 'vertical') || disabled) { return; } subMenuEmitter.emit('submenu:mouse-enter-child'); clearTimeout(data.timeout); data.timeout = setTimeout(() => { rootMethods.openMenu(props.index, indexPath); }, showTimeout); if (appendToBody.value) { parentMenu.value.vnode.el.dispatchEvent(new MouseEvent('mouseenter')); } }; const handleMouseleave = (deepDispatch = false) => { if ((rootProps.menuTrigger === 'click' && rootProps.mode === 'horizontal') || (!rootProps.collapse && rootProps.mode === 'vertical')) { return; } subMenuEmitter.emit('submenu:mouse-leave-child'); clearTimeout(data.timeout); data.timeout = setTimeout(() => { !data.mouseInChild && closeMenu(props.index); }, props.hideTimeout); if (appendToBody.value && deepDispatch) { if (instance.parent.type.name === 'ElSubmenu') { parentHandleMouseleave(true); } } }; const handleTitleMouseenter = () => { var _a; if (mode.value === 'horizontal' && !rootProps.backgroundColor) return; const title = ((_a = popperVnode.value) === null || _a === void 0 ? void 0 : _a.triggerRef) || verticalTitleRef.value; title && (title.style.backgroundColor = rootHoverBackground.value); }; const handleTitleMouseleave = () => { var _a; if (mode.value === 'horizontal' && !rootProps.backgroundColor) return; const title = ((_a = popperVnode.value) === null || _a === void 0 ? void 0 : _a.triggerRef) || verticalTitleRef.value; title && (title.style.backgroundColor = rootProps.backgroundColor || ''); }; const updatePlacement = () => { data.currentPlacement = mode.value === 'horizontal' && isFirstLevel.value ? 'bottom-start' : 'right-start'; }; vue.provide(`subMenu:${instance.uid}`, { addSubMenu, removeSubMenu, handleMouseleave, }); vue.onBeforeMount(() => { rootMenuOn('rootMenu:toggle-collapse', (val) => { handleCollapseToggle(val); }); subMenuEmitter.on('submenu:mouse-enter-child', () => { data.mouseInChild = true; clearTimeout(data.timeout); }); subMenuEmitter.on('submenu:mouse-leave-child', () => { data.mouseInChild = false; clearTimeout(data.timeout); }); }); vue.onMounted(() => { rootMethods.addSubMenu({ index: props.index, indexPath, active, }); parentAddSubmenu({ index: props.index, indexPath, active, }); updatePlacement(); }); vue.onBeforeUnmount(() => { parentRemoveSubmenu({ index: props.index, indexPath, active, }); rootMethods.removeSubMenu({ index: props.index, indexPath, active, }); }); return { data, props, mode, active, isMenuPopup, opened, paddingStyle, titleStyle, backgroundColor, rootProps, menuTransitionName, submenuTitleIcon, appendToBody, handleClick, handleMouseenter, handleMouseleave, handleTitleMouseenter, handleTitleMouseleave, addItem, removeItem, addSubMenu, removeSubMenu, popperVnode, verticalTitleRef, }; }, render() { var _a, _b; const titleTag = [ (_b = (_a = this.$slots).title) === null || _b === void 0 ? void 0 : _b.call(_a), vue.h('i', { class: ['el-submenu__icon-arrow', this.submenuTitleIcon], }, null) ]; const ulStyle = { backgroundColor: this.rootProps.backgroundColor || '', }; const child = this.isMenuPopup ? vue.h(ElPopper__default['default'], { ref: 'popperVNode', manualMode: true, visible: this.opened, 'onUpdate:visible': (val) => this.opened = val, effect: 'light', pure: true, offset: 6, showArrow: false, popperClass: this.popperClass, placement: this.data.currentPlacement, appendToBody: this.appendToBody, }, { default: () => vue.h(vue.Transition, { name: this.menuTransitionName, }, { default: () => { var _a, _b; return vue.withDirectives(vue.h('div', { ref: 'menu', class: [ `el-menu--${this.mode}`, this.popperClass, ], onMouseenter: ($event) => this.handleMouseenter($event, 100), onMouseleave: () => this.handleMouseleave(true), onFocus: ($event) => this.handleMouseenter($event, 100), }, [ vue.h('ul', { class: [ 'el-menu el-menu--popup', `el-menu--popup-${this.data.currentPlacement}`, ], style: ulStyle, }, [(_b = (_a = this.$slots).default) === null || _b === void 0 ? void 0 : _b.call(_a)]), ]), [[vue.vShow, this.opened]]); }, }), trigger: () => vue.h('div', { class: 'el-submenu__title', style: [this.paddingStyle, this.titleStyle, { backgroundColor: this.backgroundColor }], onClick: this.handleClick, onMouseenter: this.handleTitleMouseenter, onMouseleave: this.handleTitleMouseleave, }, titleTag), }) : vue.h(vue.Fragment, {}, [ vue.h('div', { class: 'el-submenu__title', style: [this.paddingStyle, this.titleStyle, { backgroundColor: this.backgroundColor }], ref: 'verticalTitleRef', onClick: this.handleClick, onMouseenter: this.handleTitleMouseenter, onMouseleave: this.handleTitleMouseleave, }, titleTag), vue.h(ElCollapseTransition__default['default'], {}, { default: () => { var _a, _b; return vue.withDirectives(vue.h('ul', { role: 'menu', class: 'el-menu el-menu--inline', style: ulStyle, }, [(_b = (_a = this.$slots).default) === null || _b === void 0 ? void 0 : _b.call(_a)]), [[vue.vShow, this.opened]]); }, }), ]); return vue.h('li', { class: [ 'el-submenu', { 'is-active': this.active, 'is-opened': this.opened, 'is-disabled': this.disabled, }, ], role: 'menuitem', ariaHaspopup: true, ariaExpanded: this.opened, onMouseenter: this.handleMouseenter, onMouseleave: () => this.handleMouseleave(true), onFocus: this.handleMouseenter, }, [child]); }, }); script.__file = "packages/menu/src/submenu.vue"; script.install = (app) => { app.component(script.name, script); }; const _Submenu = script; exports.default = _Submenu;