sub-menu.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', { value: true });
  3. var vue = require('vue');
  4. var core = require('@vueuse/core');
  5. var index$3 = require('../../collapse-transition/index.js');
  6. var index$2 = require('../../tooltip/index.js');
  7. require('../../../utils/index.js');
  8. require('../../../hooks/index.js');
  9. var iconsVue = require('@element-plus/icons-vue');
  10. var index$1 = require('../../icon/index.js');
  11. var useMenu = require('./use-menu.js');
  12. var useMenuCssVar = require('./use-menu-css-var.js');
  13. var runtime = require('../../../utils/vue/props/runtime.js');
  14. var icon = require('../../../utils/vue/icon.js');
  15. var index = require('../../../hooks/use-namespace/index.js');
  16. var error = require('../../../utils/error.js');
  17. var shared = require('@vue/shared');
  18. const subMenuProps = runtime.buildProps({
  19. index: {
  20. type: String,
  21. required: true
  22. },
  23. showTimeout: {
  24. type: Number,
  25. default: 300
  26. },
  27. hideTimeout: {
  28. type: Number,
  29. default: 300
  30. },
  31. popperClass: String,
  32. disabled: Boolean,
  33. popperAppendToBody: {
  34. type: Boolean,
  35. default: void 0
  36. },
  37. popperOffset: {
  38. type: Number,
  39. default: 6
  40. },
  41. expandCloseIcon: {
  42. type: icon.iconPropType
  43. },
  44. expandOpenIcon: {
  45. type: icon.iconPropType
  46. },
  47. collapseCloseIcon: {
  48. type: icon.iconPropType
  49. },
  50. collapseOpenIcon: {
  51. type: icon.iconPropType
  52. }
  53. });
  54. const COMPONENT_NAME = "ElSubMenu";
  55. var SubMenu = vue.defineComponent({
  56. name: COMPONENT_NAME,
  57. props: subMenuProps,
  58. setup(props, { slots, expose }) {
  59. const instance = vue.getCurrentInstance();
  60. const { indexPath, parentMenu } = useMenu["default"](instance, vue.computed(() => props.index));
  61. const nsMenu = index.useNamespace("menu");
  62. const nsSubMenu = index.useNamespace("sub-menu");
  63. const rootMenu = vue.inject("rootMenu");
  64. if (!rootMenu)
  65. error.throwError(COMPONENT_NAME, "can not inject root menu");
  66. const subMenu = vue.inject(`subMenu:${parentMenu.value.uid}`);
  67. if (!subMenu)
  68. error.throwError(COMPONENT_NAME, "can not inject sub menu");
  69. const items = vue.ref({});
  70. const subMenus = vue.ref({});
  71. let timeout;
  72. const mouseInChild = vue.ref(false);
  73. const verticalTitleRef = vue.ref();
  74. const vPopper = vue.ref(null);
  75. const currentPlacement = vue.computed(() => mode.value === "horizontal" && isFirstLevel.value ? "bottom-start" : "right-start");
  76. const subMenuTitleIcon = vue.computed(() => {
  77. return mode.value === "horizontal" && isFirstLevel.value || mode.value === "vertical" && !rootMenu.props.collapse ? props.expandCloseIcon && props.expandOpenIcon ? opened.value ? props.expandOpenIcon : props.expandCloseIcon : iconsVue.ArrowDown : props.collapseCloseIcon && props.collapseOpenIcon ? opened.value ? props.collapseOpenIcon : props.collapseCloseIcon : iconsVue.ArrowRight;
  78. });
  79. const isFirstLevel = vue.computed(() => {
  80. return subMenu.level === 0;
  81. });
  82. const appendToBody = vue.computed(() => {
  83. return props.popperAppendToBody === void 0 ? isFirstLevel.value : Boolean(props.popperAppendToBody);
  84. });
  85. const menuTransitionName = vue.computed(() => rootMenu.props.collapse ? `${nsMenu.namespace.value}-zoom-in-left` : `${nsMenu.namespace.value}-zoom-in-top`);
  86. const fallbackPlacements = vue.computed(() => mode.value === "horizontal" && isFirstLevel.value ? [
  87. "bottom-start",
  88. "bottom-end",
  89. "top-start",
  90. "top-end",
  91. "right-start",
  92. "left-start"
  93. ] : [
  94. "right-start",
  95. "left-start",
  96. "bottom-start",
  97. "bottom-end",
  98. "top-start",
  99. "top-end"
  100. ]);
  101. const opened = vue.computed(() => rootMenu.openedMenus.includes(props.index));
  102. const active = vue.computed(() => {
  103. let isActive = false;
  104. Object.values(items.value).forEach((item2) => {
  105. if (item2.active) {
  106. isActive = true;
  107. }
  108. });
  109. Object.values(subMenus.value).forEach((subItem) => {
  110. if (subItem.active) {
  111. isActive = true;
  112. }
  113. });
  114. return isActive;
  115. });
  116. const backgroundColor = vue.computed(() => rootMenu.props.backgroundColor || "");
  117. const activeTextColor = vue.computed(() => rootMenu.props.activeTextColor || "");
  118. const textColor = vue.computed(() => rootMenu.props.textColor || "");
  119. const mode = vue.computed(() => rootMenu.props.mode);
  120. const item = vue.reactive({
  121. index: props.index,
  122. indexPath,
  123. active
  124. });
  125. const titleStyle = vue.computed(() => {
  126. if (mode.value !== "horizontal") {
  127. return {
  128. color: textColor.value
  129. };
  130. }
  131. return {
  132. borderBottomColor: active.value ? rootMenu.props.activeTextColor ? activeTextColor.value : "" : "transparent",
  133. color: active.value ? activeTextColor.value : textColor.value
  134. };
  135. });
  136. const doDestroy = () => {
  137. var _a, _b, _c;
  138. return (_c = (_b = (_a = vPopper.value) == null ? void 0 : _a.popperRef) == null ? void 0 : _b.popperInstanceRef) == null ? void 0 : _c.destroy();
  139. };
  140. const handleCollapseToggle = (value) => {
  141. if (!value) {
  142. doDestroy();
  143. }
  144. };
  145. const handleClick = () => {
  146. if (rootMenu.props.menuTrigger === "hover" && rootMenu.props.mode === "horizontal" || rootMenu.props.collapse && rootMenu.props.mode === "vertical" || props.disabled)
  147. return;
  148. rootMenu.handleSubMenuClick({
  149. index: props.index,
  150. indexPath: indexPath.value,
  151. active: active.value
  152. });
  153. };
  154. const handleMouseenter = (event, showTimeout = props.showTimeout) => {
  155. var _a;
  156. if (event.type === "focus") {
  157. return;
  158. }
  159. if (rootMenu.props.menuTrigger === "click" && rootMenu.props.mode === "horizontal" || !rootMenu.props.collapse && rootMenu.props.mode === "vertical" || props.disabled) {
  160. return;
  161. }
  162. subMenu.mouseInChild.value = true;
  163. timeout == null ? void 0 : timeout();
  164. ({ stop: timeout } = core.useTimeoutFn(() => {
  165. rootMenu.openMenu(props.index, indexPath.value);
  166. }, showTimeout));
  167. if (appendToBody.value) {
  168. (_a = parentMenu.value.vnode.el) == null ? void 0 : _a.dispatchEvent(new MouseEvent("mouseenter"));
  169. }
  170. };
  171. const handleMouseleave = (deepDispatch = false) => {
  172. var _a, _b;
  173. if (rootMenu.props.menuTrigger === "click" && rootMenu.props.mode === "horizontal" || !rootMenu.props.collapse && rootMenu.props.mode === "vertical") {
  174. return;
  175. }
  176. timeout == null ? void 0 : timeout();
  177. subMenu.mouseInChild.value = false;
  178. ({ stop: timeout } = core.useTimeoutFn(() => !mouseInChild.value && rootMenu.closeMenu(props.index, indexPath.value), props.hideTimeout));
  179. if (appendToBody.value && deepDispatch) {
  180. if (((_a = instance.parent) == null ? void 0 : _a.type.name) === "ElSubMenu") {
  181. (_b = subMenu.handleMouseleave) == null ? void 0 : _b.call(subMenu, true);
  182. }
  183. }
  184. };
  185. vue.watch(() => rootMenu.props.collapse, (value) => handleCollapseToggle(Boolean(value)));
  186. {
  187. const addSubMenu = (item2) => {
  188. subMenus.value[item2.index] = item2;
  189. };
  190. const removeSubMenu = (item2) => {
  191. delete subMenus.value[item2.index];
  192. };
  193. vue.provide(`subMenu:${instance.uid}`, {
  194. addSubMenu,
  195. removeSubMenu,
  196. handleMouseleave,
  197. mouseInChild,
  198. level: subMenu.level + 1
  199. });
  200. }
  201. expose({
  202. opened
  203. });
  204. vue.onMounted(() => {
  205. rootMenu.addSubMenu(item);
  206. subMenu.addSubMenu(item);
  207. });
  208. vue.onBeforeUnmount(() => {
  209. subMenu.removeSubMenu(item);
  210. rootMenu.removeSubMenu(item);
  211. });
  212. return () => {
  213. var _a;
  214. const titleTag = [
  215. (_a = slots.title) == null ? void 0 : _a.call(slots),
  216. vue.h(index$1.ElIcon, {
  217. class: nsSubMenu.e("icon-arrow"),
  218. style: {
  219. transform: opened.value ? props.expandCloseIcon && props.expandOpenIcon || props.collapseCloseIcon && props.collapseOpenIcon && rootMenu.props.collapse ? "none" : "rotateZ(180deg)" : "none"
  220. }
  221. }, {
  222. default: () => shared.isString(subMenuTitleIcon.value) ? vue.h(instance.appContext.components[subMenuTitleIcon.value]) : vue.h(subMenuTitleIcon.value)
  223. })
  224. ];
  225. const ulStyle = useMenuCssVar.useMenuCssVar(rootMenu.props, subMenu.level + 1);
  226. const child = rootMenu.isMenuPopup ? vue.h(index$2.ElTooltip, {
  227. ref: vPopper,
  228. visible: opened.value,
  229. effect: "light",
  230. pure: true,
  231. offset: props.popperOffset,
  232. showArrow: false,
  233. persistent: true,
  234. popperClass: props.popperClass,
  235. placement: currentPlacement.value,
  236. teleported: appendToBody.value,
  237. fallbackPlacements: fallbackPlacements.value,
  238. transition: menuTransitionName.value,
  239. gpuAcceleration: false
  240. }, {
  241. content: () => {
  242. var _a2;
  243. return vue.h("div", {
  244. class: [
  245. nsMenu.m(mode.value),
  246. nsMenu.m("popup-container"),
  247. props.popperClass
  248. ],
  249. onMouseenter: (evt) => handleMouseenter(evt, 100),
  250. onMouseleave: () => handleMouseleave(true),
  251. onFocus: (evt) => handleMouseenter(evt, 100)
  252. }, [
  253. vue.h("ul", {
  254. class: [
  255. nsMenu.b(),
  256. nsMenu.m("popup"),
  257. nsMenu.m(`popup-${currentPlacement.value}`)
  258. ],
  259. style: ulStyle.value
  260. }, [(_a2 = slots.default) == null ? void 0 : _a2.call(slots)])
  261. ]);
  262. },
  263. default: () => vue.h("div", {
  264. class: nsSubMenu.e("title"),
  265. style: [
  266. titleStyle.value,
  267. { backgroundColor: backgroundColor.value }
  268. ],
  269. onClick: handleClick
  270. }, titleTag)
  271. }) : vue.h(vue.Fragment, {}, [
  272. vue.h("div", {
  273. class: nsSubMenu.e("title"),
  274. style: [
  275. titleStyle.value,
  276. { backgroundColor: backgroundColor.value }
  277. ],
  278. ref: verticalTitleRef,
  279. onClick: handleClick
  280. }, titleTag),
  281. vue.h(index$3["default"], {}, {
  282. default: () => {
  283. var _a2;
  284. return vue.withDirectives(vue.h("ul", {
  285. role: "menu",
  286. class: [nsMenu.b(), nsMenu.m("inline")],
  287. style: ulStyle.value
  288. }, [(_a2 = slots.default) == null ? void 0 : _a2.call(slots)]), [[vue.vShow, opened.value]]);
  289. }
  290. })
  291. ]);
  292. return vue.h("li", {
  293. class: [
  294. nsSubMenu.b(),
  295. nsSubMenu.is("active", active.value),
  296. nsSubMenu.is("opened", opened.value),
  297. nsSubMenu.is("disabled", props.disabled)
  298. ],
  299. role: "menuitem",
  300. ariaHaspopup: true,
  301. ariaExpanded: opened.value,
  302. onMouseenter: handleMouseenter,
  303. onMouseleave: () => handleMouseleave(true),
  304. onFocus: handleMouseenter
  305. }, [child]);
  306. };
  307. }
  308. });
  309. exports["default"] = SubMenu;
  310. exports.subMenuProps = subMenuProps;
  311. //# sourceMappingURL=sub-menu.js.map