UNPKG

element-plus

Version:

A Component Library for Vue 3

1 lines 17.8 kB
{"version":3,"file":"sub-menu.mjs","sources":["../../../../../../packages/components/menu/src/sub-menu.ts"],"sourcesContent":["import {\n defineComponent,\n computed,\n ref,\n provide,\n inject,\n getCurrentInstance,\n watch,\n onMounted,\n onBeforeUnmount,\n withDirectives,\n Fragment,\n vShow,\n h,\n reactive,\n} from 'vue'\nimport { useTimeoutFn } from '@vueuse/core'\nimport ElCollapseTransition from '@element-plus/components/collapse-transition'\nimport ElPopper from '@element-plus/components/popper'\nimport { buildProps } from '@element-plus/utils/props'\nimport { throwError } from '@element-plus/utils/error'\nimport { ArrowDown, ArrowRight } from '@element-plus/icons'\nimport { ElIcon } from '@element-plus/components/icon'\nimport useMenu from './use-menu'\nimport { useMenuCssVar } from './use-menu-css-var'\n\nimport type { Placement } from '@element-plus/components/popper'\nimport type { ExtractPropTypes, VNodeArrayChildren, CSSProperties } from 'vue'\nimport type { MenuProvider, SubMenuProvider } from './types'\n\nexport const subMenuProps = buildProps({\n index: {\n type: String,\n required: true,\n },\n showTimeout: {\n type: Number,\n default: 300,\n },\n hideTimeout: {\n type: Number,\n default: 300,\n },\n popperClass: String,\n disabled: Boolean,\n popperAppendToBody: {\n type: Boolean,\n default: undefined,\n },\n} as const)\nexport type SubMenuProps = ExtractPropTypes<typeof subMenuProps>\n\nconst COMPONENT_NAME = 'ElSubMenu'\nexport default defineComponent({\n name: COMPONENT_NAME,\n props: subMenuProps,\n\n setup(props, { slots, expose }) {\n const instance = getCurrentInstance()!\n const { paddingStyle, indexPath, parentMenu } = useMenu(\n instance,\n computed(() => props.index)\n )\n\n // inject\n const rootMenu = inject<MenuProvider>('rootMenu')\n if (!rootMenu) throwError(COMPONENT_NAME, 'can not inject root menu')\n\n const subMenu = inject<SubMenuProvider>(`subMenu:${parentMenu.value!.uid}`)\n if (!subMenu) throwError(COMPONENT_NAME, 'can not inject sub menu')\n\n const items = ref<MenuProvider['items']>({})\n const subMenus = ref<MenuProvider['subMenus']>({})\n\n let timeout: (() => void) | undefined\n const currentPlacement = ref<Placement | ''>('')\n const mouseInChild = ref(false)\n const verticalTitleRef = ref<HTMLDivElement>()\n const vPopper = ref()\n\n // computed\n const subMenuTitleIcon = computed(() => {\n return (mode.value === 'horizontal' && isFirstLevel.value) ||\n (mode.value === 'vertical' && !rootMenu.props.collapse)\n ? ArrowDown\n : ArrowRight\n })\n const isFirstLevel = computed(() => {\n let isFirstLevel = true\n let parent = instance.parent\n while (parent && parent.type.name !== 'ElMenu') {\n if (['ElSubMenu', 'ElMenuItemGroup'].includes(parent.type.name!)) {\n isFirstLevel = false\n break\n } else {\n parent = parent.parent\n }\n }\n return isFirstLevel\n })\n const appendToBody = computed(() => {\n return props.popperAppendToBody === undefined\n ? isFirstLevel.value\n : Boolean(props.popperAppendToBody)\n })\n const menuTransitionName = computed(() =>\n rootMenu.props.collapse ? 'el-zoom-in-left' : 'el-zoom-in-top'\n )\n const fallbackPlacements = computed<Placement[]>(() =>\n mode.value === 'horizontal' && isFirstLevel.value\n ? [\n 'bottom-start',\n 'bottom-end',\n 'top-start',\n 'top-end',\n 'right-start',\n 'left-start',\n ]\n : [\n 'right-start',\n 'left-start',\n 'bottom-start',\n 'bottom-end',\n 'top-start',\n 'top-end',\n ]\n )\n const opened = computed(() => rootMenu.openedMenus.includes(props.index))\n const active = computed(() => {\n let isActive = false\n\n Object.values(items.value).forEach((item) => {\n if (item.active) {\n isActive = true\n }\n })\n\n Object.values(subMenus.value).forEach((subItem) => {\n if (subItem.active) {\n isActive = true\n }\n })\n\n return isActive\n })\n\n const backgroundColor = computed(() => rootMenu.props.backgroundColor || '')\n const activeTextColor = computed(() => rootMenu.props.activeTextColor || '')\n const textColor = computed(() => rootMenu.props.textColor || '')\n const mode = computed(() => rootMenu.props.mode)\n const item = reactive({\n index: props.index,\n indexPath,\n active,\n })\n\n const titleStyle = computed<CSSProperties>(() => {\n if (mode.value !== 'horizontal') {\n return {\n color: textColor.value,\n }\n }\n return {\n borderBottomColor: active.value\n ? rootMenu.props.activeTextColor\n ? activeTextColor.value\n : ''\n : 'transparent',\n color: active.value ? activeTextColor.value : textColor.value,\n }\n })\n\n // methods\n const doDestroy = () => vPopper.value?.doDestroy()\n\n const handleCollapseToggle = (value: boolean) => {\n if (value) {\n updatePlacement()\n } else {\n doDestroy()\n }\n }\n\n const handleClick = () => {\n if (\n (rootMenu.props.menuTrigger === 'hover' &&\n rootMenu.props.mode === 'horizontal') ||\n (rootMenu.props.collapse && rootMenu.props.mode === 'vertical') ||\n props.disabled\n )\n return\n\n rootMenu.handleSubMenuClick({\n index: props.index,\n indexPath: indexPath.value,\n active: active.value,\n })\n }\n\n const handleMouseenter = (\n event: MouseEvent | FocusEvent,\n showTimeout = props.showTimeout\n ) => {\n if (event.type === 'focus' && !event.relatedTarget) {\n return\n }\n if (\n (rootMenu.props.menuTrigger === 'click' &&\n rootMenu.props.mode === 'horizontal') ||\n (!rootMenu.props.collapse && rootMenu.props.mode === 'vertical') ||\n props.disabled\n ) {\n return\n }\n mouseInChild.value = true\n\n timeout?.()\n ;({ stop: timeout } = useTimeoutFn(\n () => rootMenu.openMenu(props.index, indexPath.value),\n showTimeout\n ))\n\n if (appendToBody.value) {\n parentMenu.value.vnode.el?.dispatchEvent(new MouseEvent('mouseenter'))\n }\n }\n\n const handleMouseleave = (deepDispatch = false) => {\n if (\n (rootMenu.props.menuTrigger === 'click' &&\n rootMenu.props.mode === 'horizontal') ||\n (!rootMenu.props.collapse && rootMenu.props.mode === 'vertical')\n ) {\n return\n }\n mouseInChild.value = false\n timeout?.()\n ;({ stop: timeout } = useTimeoutFn(\n () =>\n !mouseInChild.value &&\n rootMenu.closeMenu(props.index, indexPath.value),\n props.hideTimeout\n ))\n\n if (appendToBody.value && deepDispatch) {\n if (instance.parent?.type.name === 'ElSubMenu') {\n subMenu.handleMouseleave?.(true)\n }\n }\n }\n\n const updatePlacement = () => {\n currentPlacement.value =\n mode.value === 'horizontal' && isFirstLevel.value\n ? 'bottom-start'\n : 'right-start'\n }\n\n watch(\n () => rootMenu.props.collapse,\n (value) => handleCollapseToggle(Boolean(value))\n )\n\n // provide\n {\n const addSubMenu: SubMenuProvider['addSubMenu'] = (item) => {\n subMenus.value[item.index] = item\n }\n const removeSubMenu: SubMenuProvider['removeSubMenu'] = (item) => {\n delete subMenus.value[item.index]\n }\n provide<SubMenuProvider>(`subMenu:${instance.uid}`, {\n addSubMenu,\n removeSubMenu,\n handleMouseleave,\n })\n }\n\n // expose\n expose({\n opened,\n })\n\n // lifecycle\n onMounted(() => {\n rootMenu.addSubMenu(item)\n subMenu.addSubMenu(item)\n updatePlacement()\n })\n\n onBeforeUnmount(() => {\n subMenu.removeSubMenu(item)\n rootMenu.removeSubMenu(item)\n })\n\n return () => {\n const titleTag: VNodeArrayChildren = [\n slots.title?.(),\n h(\n ElIcon,\n {\n class: ['el-sub-menu__icon-arrow'],\n },\n { default: () => h(subMenuTitleIcon.value) }\n ),\n ]\n\n const ulStyle = useMenuCssVar(rootMenu.props)\n\n // this render function is only used for bypass `Vue`'s compiler caused patching issue.\n // temporarily mark ElPopper as any due to type inconsistency.\n const child = rootMenu.isMenuPopup\n ? h(\n // TODO: correct popper's type.\n ElPopper as any,\n {\n ref: vPopper,\n manualMode: true,\n visible: opened.value,\n effect: 'light',\n pure: true,\n offset: 6,\n showArrow: false,\n popperClass: props.popperClass,\n placement: currentPlacement.value,\n appendToBody: appendToBody.value,\n fallbackPlacements: fallbackPlacements.value,\n transition: menuTransitionName.value,\n gpuAcceleration: false,\n },\n {\n default: () =>\n h(\n 'div',\n {\n class: [`el-menu--${mode.value}`, props.popperClass],\n onMouseenter: (evt: MouseEvent) =>\n handleMouseenter(evt, 100),\n onMouseleave: () => handleMouseleave(true),\n onFocus: (evt: FocusEvent) => handleMouseenter(evt, 100),\n },\n [\n h(\n 'ul',\n {\n class: [\n 'el-menu el-menu--popup',\n `el-menu--popup-${currentPlacement.value}`,\n ],\n style: ulStyle.value,\n },\n [slots.default?.()]\n ),\n ]\n ),\n trigger: () =>\n h(\n 'div',\n {\n class: 'el-sub-menu__title',\n style: [\n paddingStyle.value,\n titleStyle.value,\n { backgroundColor: backgroundColor.value },\n ],\n onClick: handleClick,\n },\n titleTag\n ),\n }\n )\n : h(Fragment, {}, [\n h(\n 'div',\n {\n class: 'el-sub-menu__title',\n style: [\n paddingStyle.value,\n titleStyle.value,\n { backgroundColor: backgroundColor.value },\n ],\n ref: verticalTitleRef,\n onClick: handleClick,\n },\n titleTag\n ),\n h(\n ElCollapseTransition,\n {},\n {\n default: () =>\n withDirectives(\n h(\n 'ul',\n {\n role: 'menu',\n class: 'el-menu el-menu--inline',\n style: ulStyle.value,\n },\n [slots.default?.()]\n ),\n [[vShow, opened.value]]\n ),\n }\n ),\n ])\n\n return h(\n 'li',\n {\n class: [\n 'el-sub-menu',\n {\n 'is-active': active.value,\n 'is-opened': opened.value,\n 'is-disabled': props.disabled,\n },\n ],\n role: 'menuitem',\n ariaHaspopup: true,\n ariaExpanded: opened.value,\n onMouseenter: handleMouseenter,\n onMouseleave: () => handleMouseleave(true),\n onFocus: handleMouseenter,\n },\n [child]\n )\n }\n },\n})\n"],"names":["ElPopper","ElCollapseTransition"],"mappings":"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"}