{"version":3,"file":"menu.mjs","sources":["../../../../../src/components/ivue-menu/menu.vue"],"sourcesContent":["<template>\r\n  <ul :class=\"wrapperClasses\" :style=\"wrapperStyles\">\r\n    <slot></slot>\r\n  </ul>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { computed, onMounted, reactive, provide, watch, nextTick } from 'vue';\r\nimport { oneOf } from '../../utils/assist';\r\nimport { findComponentsUpward } from '../../utils/helpers';\r\n\r\n// ts\r\nimport { MenuContextKey, Props, Data } from './types/menu';\r\n\r\nconst prefixCls = 'ivue-menu';\r\n\r\nexport default {\r\n  name: prefixCls,\r\n  emits: ['on-select', 'on-open-change'],\r\n  props: {\r\n    /**\r\n     * 主题，可选值为 light、dark、primary，其中 primary 只适用于 mode=\"horizontal\"\r\n     *\r\n     * @type {String}\r\n     */\r\n    theme: {\r\n      type: String,\r\n      validator(value: string) {\r\n        return oneOf(value, ['light', 'dark', 'primary']);\r\n      },\r\n      default: 'light',\r\n    },\r\n    /**\r\n     * 菜单类型，可选值为 horizontal（水平） 和 vertical（垂直）\r\n     *\r\n     * @type {String}\r\n     */\r\n    mode: {\r\n      type: String,\r\n      validator(value: string) {\r\n        return oneOf(value, ['horizontal', 'vertical']);\r\n      },\r\n      default: 'vertical',\r\n    },\r\n    /**\r\n     * 垂直宽度\r\n     *\r\n     * @type {String}\r\n     */\r\n    width: {\r\n      type: String,\r\n      default: '240px',\r\n    },\r\n    /**\r\n     * 展开的 Submenu 的 name 集合\r\n     *\r\n     * @type {Array}\r\n     */\r\n    openNames: {\r\n      type: Array,\r\n      default: () => [],\r\n    },\r\n    /**\r\n     * 激活菜单的 name 值\r\n     *\r\n     * @type {String | Number}\r\n     */\r\n    activeName: {\r\n      type: [String, Number],\r\n    },\r\n    /**\r\n     * 是否开启手风琴模式，开启后每次至多展开一个子菜单\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    accordion: {\r\n      type: Boolean,\r\n      default: false,\r\n    },\r\n  },\r\n  setup(props: Props, { emit }) {\r\n    // data\r\n    const data = reactive<Data>({\r\n      /**\r\n       * 展开的 Submenu 的 name 集合\r\n       *\r\n       * @type {Array}\r\n       */\r\n      openedNames: [],\r\n      /**\r\n       * 子菜单列表\r\n       *\r\n       * @type {Array}\r\n       */\r\n      menuItemList: [],\r\n      /**\r\n       * 下拉菜单列表\r\n       *\r\n       * @type {Array}\r\n       */\r\n      submenuList: [],\r\n      /**\r\n       * 当前激活的名称\r\n       *\r\n       * @type {String | Number}\r\n       */\r\n      currentActiveName: props.activeName,\r\n      /**\r\n       * 是否渲染完毕\r\n       *\r\n       * @type {Boolean}\r\n       */\r\n      ready: false,\r\n    });\r\n\r\n    // computed\r\n\r\n    // 外部样式\r\n    const wrapperClasses = computed(() => {\r\n      let theme = props.theme;\r\n\r\n      // 垂直 &&  primary\r\n      if (props.mode === 'vertical' && props.theme === 'primary') {\r\n        theme = 'light';\r\n      }\r\n\r\n      return [\r\n        `${prefixCls}`,\r\n        // 主题\r\n        `${prefixCls}-${theme}`,\r\n        {\r\n          // 菜单类型\r\n          [`${prefixCls}-${props.mode}`]: props.mode,\r\n        },\r\n      ];\r\n    });\r\n\r\n    // 外部样式\r\n    const wrapperStyles = computed(() => {\r\n      const style: {\r\n        width?: string;\r\n      } = {};\r\n\r\n      // 垂直宽度\r\n      if (props.mode === 'vertical') {\r\n        style.width = props.width;\r\n      }\r\n\r\n      return style;\r\n    });\r\n\r\n    // methods\r\n\r\n    // 激活当前子菜单\r\n    const updateActiveName = (activeName?: string | number) => {\r\n      // 是否有需要激活的name\r\n      if (activeName) {\r\n        data.currentActiveName = activeName;\r\n      }\r\n\r\n      // 没有菜单\r\n      if (data.currentActiveName === undefined) {\r\n        data.currentActiveName = -1;\r\n      }\r\n\r\n      // 子菜单列表\r\n      data.submenuList\r\n        .map((item) => item.submenu)\r\n        .forEach((item) => {\r\n          item.activeName(false);\r\n        });\r\n\r\n      // 菜单列表\r\n      data.menuItemList.forEach((item) => {\r\n        // 激活子菜单\r\n        item.activeName(data.currentActiveName);\r\n      });\r\n    };\r\n\r\n    // 激活子菜单\r\n    const menuItemActive = (name: string | number) => {\r\n      // 当前激活的名称\r\n      data.currentActiveName = name;\r\n\r\n      // 更新打开的菜单名称\r\n      updateOpenKeys(name);\r\n\r\n      emit('on-select', name);\r\n    };\r\n\r\n    // 发送选择事件\r\n    const handleEmitSelectEvent = (name: string | number) => {\r\n      emit('on-select', name);\r\n    };\r\n\r\n    // 更新打开的菜单名称\r\n    const updateOpenKeys = (name) => {\r\n      const names = [...data.openedNames];\r\n\r\n      const index = names.indexOf(name);\r\n      const submenuList = data.submenuList.map((item) => item.submenu);\r\n\r\n      // 手风琴模式\r\n      if (props.accordion) {\r\n        // 关闭下拉菜单\r\n        submenuList.forEach((item) => {\r\n          item.data.opened = false;\r\n        });\r\n      }\r\n\r\n      //  开的 Submenu 的 name 集合 有当前菜单\r\n      if (index >= 0) {\r\n        let currentSubmenu = null;\r\n\r\n        // 关闭当前子菜单\r\n        submenuList.forEach((item) => {\r\n          if (item.name === name) {\r\n            currentSubmenu = item;\r\n\r\n            item.data.opened = false;\r\n          }\r\n        });\r\n\r\n        if (currentSubmenu) {\r\n          // 打开当前组件子菜单\r\n          findComponentsUpward(currentSubmenu, 'ivue-menu-submenu').forEach(\r\n            (item) => {\r\n              item.data.opened = true;\r\n            }\r\n          );\r\n        }\r\n\r\n        // 子菜单列表全部关闭\r\n        currentSubmenu.data.childSubmenuList\r\n          .map((item) => item.submenu)\r\n          .forEach((item) => {\r\n            item.data.opened = false;\r\n          });\r\n      }\r\n      // 没有当前菜单\r\n      else {\r\n        // 手风琴模式\r\n        if (props.accordion) {\r\n          let currentSubmenu = null;\r\n\r\n          // 打开当前子菜单\r\n          submenuList.forEach((item) => {\r\n            if (item.name === name) {\r\n              currentSubmenu = item;\r\n\r\n              item.data.opened = true;\r\n            }\r\n          });\r\n\r\n          if (currentSubmenu) {\r\n            findComponentsUpward(currentSubmenu, 'ivue-menu-submenu').forEach(\r\n              (item) => {\r\n                item.data.opened = true;\r\n              }\r\n            );\r\n          }\r\n        } else {\r\n          // 打开子菜单\r\n          const submenuList = data.submenuList.map((item) => item.submenu);\r\n\r\n          submenuList.forEach((item) => {\r\n            if (item.name === name) {\r\n              item.data.opened = true;\r\n            }\r\n          });\r\n        }\r\n      }\r\n\r\n      // 获取当前打开的子菜单\r\n      const openedNames = submenuList\r\n        .filter((item) => item.data.opened)\r\n        .map((item) => item.name);\r\n\r\n      // 展开的 Submenu 的 name 集合\r\n      data.openedNames = [...openedNames];\r\n\r\n      // 当前展开的 Submenu 的 name 值数组\r\n      emit('on-open-change', openedNames);\r\n    };\r\n\r\n    // 选择当前菜单\r\n    const handleMenuItemSelect = (name: string | number) => {\r\n      data.currentActiveName = name;\r\n\r\n      emit('on-select', name);\r\n    };\r\n\r\n    // 展开子菜单\r\n    const updateOpened = (openedNames?: any[]) => {\r\n      // 是否有需要激活的菜单\r\n      if (openedNames) {\r\n        data.openedNames = openedNames;\r\n      }\r\n\r\n      const items = data.submenuList.map((item) => item.submenu);\r\n\r\n      if (items.length) {\r\n        items.forEach((item) => {\r\n          // 展开子菜单\r\n          if (data.openedNames.indexOf(item.name) > -1) {\r\n            item.data.opened = true;\r\n          }\r\n          // 关闭子菜单\r\n          else {\r\n            item.data.opened = false;\r\n          }\r\n        });\r\n      }\r\n    };\r\n\r\n    // provide\r\n\r\n    provide(\r\n      MenuContextKey,\r\n      reactive({\r\n        data,\r\n        mode: props.mode,\r\n        menuItemActive,\r\n        handleEmitSelectEvent,\r\n        updateOpenKeys,\r\n        handleMenuItemSelect,\r\n      })\r\n    );\r\n\r\n    // watch\r\n\r\n    // 监听激活菜单的 name 值\r\n    watch(\r\n      () => props.activeName,\r\n      (value) => {\r\n        data.currentActiveName = value;\r\n      }\r\n    );\r\n\r\n    // 监听当前激活的名称\r\n    watch(\r\n      () => data.currentActiveName,\r\n      () => {\r\n        updateActiveName();\r\n      }\r\n    );\r\n\r\n    // 监听展开的 Submenu 的 name 集合\r\n    watch(\r\n      () => props.openNames,\r\n      (value) => {\r\n        data.openedNames = value;\r\n\r\n        // 展开菜单\r\n        updateOpened();\r\n      }\r\n    );\r\n\r\n    // onMounted\r\n    onMounted(() => {\r\n      // 展开的 Submenu 的 name 集合\r\n      data.openedNames = [...props.openNames];\r\n\r\n      // 展开菜单\r\n      updateOpened();\r\n\r\n      nextTick(() => {\r\n        // 激活子菜单\r\n        updateActiveName();\r\n\r\n        // 渲染完成\r\n        data.ready = true;\r\n      });\r\n    });\r\n\r\n    return {\r\n      prefixCls,\r\n\r\n      // data\r\n      data,\r\n\r\n      // computed\r\n      wrapperClasses,\r\n      wrapperStyles,\r\n      updateOpenKeys,\r\n      updateOpened,\r\n      updateActiveName,\r\n    };\r\n  },\r\n};\r\n</script>\r\n"],"names":["_openBlock","_createElementBlock","_normalizeClass","_normalizeStyle"],"mappings":";;;;AACY,SAAA,YAAA,IAAE,EAAA,MAAA,EAAc,MAAA,EAAA,MAAA,EAAA,OAAA,QAAA,EAAA;AAAQ,EAAA,OAAAA,SAAA,EAAA,EAAAC,kBAAA,CAAE,IAAa,EAAA;AAAA,IAAA,KAAA,EAAAC,cAAA,CAAA,MAAA,CAAA,cAAA,CAAA;AAAA,IAC/C,KAAA,EAAaC,cAAA,CAAA,MAAA,CAAA,aAAA,CAAA;AAAA,GAAA,EAAA;AAAA;;;;;;;"}