{"version":3,"file":"index.mjs","sources":["../../../../../../packages/components/cascader-panel/src/index.vue"],"sourcesContent":["<template>\n  <div\n    :class=\"[\n      namespace,\n      border && 'is-bordered'\n    ]\"\n    @keydown=\"handleKeyDown\"\n  >\n    <hl-cascader-menu\n      v-for=\"(menu, index) in menus\"\n      :key=\"index\"\n      :ref=\"item => menuList[index] = item\"\n      :index=\"index\"\n      :nodes=\"[...menu]\"\n    />\n  </div>\n</template>\n\n<script lang='ts'>\nimport {\n  computed, defineComponent, nextTick,\n  onBeforeUpdate, onMounted,\n  provide, reactive,\n  ref, watch,\n} from 'vue'\nimport { isEqual, flattenDeep, cloneDeep } from 'lodash-unified'\nimport { focusNode, getSibling, scrollIntoView, castArray, unique, isClient, isEmpty } from '@hongluan-ui/utils'\nimport { EVENT_CODE, UPDATE_MODEL_EVENT, CHANGE_EVENT } from '@hongluan-ui/constants'\nimport { useNamespace } from '@hongluan-ui/hooks'\nimport HlCascaderMenu from './menu.vue'\nimport Store from './store'\nimport Node from './node'\nimport { CommonProps, useCascaderConfig } from './config'\nimport { checkNode, getMenuIndex, sortByOriginalOrder } from './utils'\nimport { CASCADER_PANEL_INJECTION_KEY } from './types'\n\nimport type { PropType } from 'vue'\nimport type { Nullable } from '@hongluan-ui/utils'\nimport type {\n  CascaderValue,\n  CascaderNode,\n  CascaderNodeValue,\n  CascaderOption,\n  RenderLabel,\n  CascaderPanelContext,\n} from './types'\n\nexport default defineComponent({\n  name: 'CascaderPanel',\n\n  components: {\n    HlCascaderMenu,\n  },\n\n  props: {\n    ...CommonProps,\n    border: {\n      type: Boolean,\n      default: true,\n    },\n    renderLabel: Function as PropType<RenderLabel>,\n  },\n\n  emits: [\n    UPDATE_MODEL_EVENT,\n    CHANGE_EVENT,\n    'close',\n    'expand-change',\n  ],\n\n  setup(props, { emit, slots }) {\n    // for interrupt sync check status in lazy mode\n    let manualChecked = false\n\n    const config = useCascaderConfig(props)\n\n    let store: Nullable<Store> = null\n    const initialLoaded = ref(true)\n    const menuList = ref<any[]>([])\n    const checkedValue = ref<Nullable<CascaderValue>>(null)\n    const menus = ref<CascaderNode[][]>([])\n    const expandingNode = ref<Nullable<CascaderNode>>(null)\n    const checkedNodes = ref<CascaderNode[]>([])\n\n    const isHoverMenu = computed(() => config.value.expandTrigger === 'hover')\n    const renderLabelFn = computed(() => props.renderLabel || slots.default)\n\n    const initStore = () => {\n      const { options } = props\n      const cfg = config.value\n\n      manualChecked = false\n      store = new Store(options, cfg)\n      menus.value = [store.getNodes()]\n\n      if (cfg.lazy && isEmpty(props.options)) {\n        initialLoaded.value = false\n        lazyLoad(undefined, list => {\n          if (list) {\n            store = new Store(list, cfg)\n            menus.value = [store.getNodes()]\n          }\n          initialLoaded.value = true\n          syncCheckedValue(false, true)\n        })\n      } else {\n        syncCheckedValue(false, true)\n      }\n    }\n\n    const lazyLoad: CascaderPanelContext['lazyLoad'] = (node, cb) => {\n      const cfg = config.value\n      node = node || new Node({}, cfg, undefined, true)\n      node.loading = true\n\n      const resolve = (dataList: CascaderOption[]) => {\n        const _node = node as Node\n        const parent = _node.root ? null : _node\n        dataList && store?.appendNodes(dataList, parent as any)\n        _node.loading = false\n        _node.loaded = true\n        _node.childrenData = _node.childrenData || []\n        cb && cb(dataList)\n      }\n\n      cfg.lazyLoad(node, resolve as any)\n    }\n\n    const expandNode: CascaderPanelContext['expandNode'] = (node, silent) => {\n      const { level } = node\n      const newMenus = menus.value.slice(0, level)\n      let newExpandingNode: Nullable<CascaderNode>\n\n      if (node.isLeaf) {\n        newExpandingNode = node.pathNodes[level - 2]\n      } else {\n        newExpandingNode = node\n        newMenus.push(node.children)\n      }\n\n      if(expandingNode.value?.uid !== newExpandingNode?.uid) {\n        expandingNode.value = node\n        menus.value = newMenus\n        !silent && emit('expand-change', node?.pathValues || [])\n      }\n    }\n\n    const handleCheckChange: CascaderPanelContext['handleCheckChange'] = (node, checked, emitClose = true) => {\n      const { checkStrictly, multiple } = config.value\n      const oldNode = checkedNodes.value[0]\n      manualChecked = true\n\n      !multiple && oldNode?.doCheck(false)\n      node.doCheck(checked)\n      calculateCheckedValue()\n      emitClose && !multiple && !checkStrictly && emit('close')\n      !emitClose && !multiple && !checkStrictly && expandParentNode(node)\n    }\n\n    const expandParentNode = node => {\n      if (!node) return\n      node = node.parent\n      expandParentNode(node)\n      node && expandNode(node)\n    }\n\n    const getFlattedNodes = (leafOnly: boolean) => {\n      return store?.getFlattedNodes(leafOnly)\n    }\n\n    const getCheckedNodes = (leafOnly: boolean) => {\n      return getFlattedNodes(leafOnly)?.filter(node => node.checked !== false)\n\n    }\n\n    const clearCheckedNodes = () => {\n      checkedNodes.value.forEach(node => node.doCheck(false))\n      calculateCheckedValue()\n      menus.value = menus.value.slice(0, 1)\n      expandingNode.value = null\n      emit('expand-change', [])\n    }\n\n    const calculateCheckedValue = () => {\n      const { checkStrictly, multiple } = config.value\n      const oldNodes = checkedNodes.value\n      const newNodes = getCheckedNodes(!checkStrictly)\n      // ensure the original order\n      const nodes = sortByOriginalOrder(oldNodes, newNodes)\n      const values = nodes.map(node => node.valueByOption)\n      checkedNodes.value = nodes\n      checkedValue.value = multiple ? values : (values[0] ?? null)\n    }\n\n    const syncCheckedValue = (loaded = false, forced = false) => {\n      const { modelValue } = props\n      const { lazy, multiple, checkStrictly } = config.value\n      const leafOnly = !checkStrictly\n\n      if (\n        !initialLoaded.value ||\n        manualChecked ||\n        !forced && isEqual(modelValue, checkedValue.value)\n      ) return\n\n      if (lazy && !loaded) {\n        const values: CascaderNodeValue[] = unique(flattenDeep(castArray(modelValue)))\n        const nodes = values\n          .map(val => store?.getNodeByValue(val))\n          .filter(node => !!node && !node.loaded && !node.loading) as Node[]\n\n        if (nodes.length) {\n          nodes.forEach(node => {\n            lazyLoad(node, () => syncCheckedValue(false, forced))\n          })\n        } else {\n          syncCheckedValue(true, forced)\n        }\n      } else {\n        const values = multiple ? castArray(modelValue) : [modelValue]\n        const nodes = unique(values.map((val: CascaderNodeValue) => store?.getNodeByValue(val, leafOnly))) as Node[]\n        syncMenuState(nodes, forced)\n        checkedValue.value = cloneDeep(modelValue)\n      }\n    }\n\n    const syncMenuState = (newCheckedNodes: CascaderNode[], reserveExpandingState = true) => {\n      const { checkStrictly } = config.value\n      const oldNodes = checkedNodes.value\n      const newNodes = newCheckedNodes.filter(node => !!node && (checkStrictly || node.isLeaf))\n      const oldExpandingNode = store?.getSameNode(expandingNode.value)\n      const newExpandingNode = reserveExpandingState && oldExpandingNode || newNodes[0]\n\n      if (newExpandingNode) {\n        newExpandingNode.pathNodes.forEach(node => expandNode(node, true))\n      } else {\n        expandingNode.value = null\n      }\n\n      oldNodes.forEach(node => node.doCheck(false))\n      reactive(newNodes).forEach(node => node.doCheck(true))\n\n      checkedNodes.value = newNodes\n      nextTick(scrollToExpandingNode)\n    }\n\n    const scrollToExpandingNode = () => {\n      if (!isClient) return\n\n      menuList.value.forEach(menu => {\n        const menuElement = menu?.$el\n        if (menuElement) {\n          const container = menuElement.querySelector('.scrollbar-wrap')\n          const activeNode = menuElement.querySelector('.cascader-node.is-active') ||\n            menuElement.querySelector('.cascader-node.in-active-path')\n          scrollIntoView(container, activeNode)\n        }\n      })\n    }\n\n    const handleKeyDown = (e: KeyboardEvent) => {\n      const target = e.target as HTMLElement\n      const { code } = e\n\n      switch (code) {\n        case EVENT_CODE.up:\n        case EVENT_CODE.down:\n          const distance = code === EVENT_CODE.up ? -1 : 1\n          focusNode(getSibling(target, distance, '.cascader-node[tabindex=\"-1\"]') as HTMLElement)\n          break\n        case EVENT_CODE.left:\n          const preMenu = menuList.value[getMenuIndex(target) - 1]\n          const expandedNode = preMenu?.$el.querySelector('.cascader-node[aria-expanded=\"true\"]')\n          focusNode(expandedNode)\n          break\n        case EVENT_CODE.right:\n          const nextMenu = menuList.value[getMenuIndex(target) + 1]\n          const firstNode = nextMenu?.$el.querySelector('.cascader-node[tabindex=\"-1\"]')\n          focusNode(firstNode)\n          break\n        case EVENT_CODE.enter:\n          checkNode(target)\n          break\n      }\n    }\n\n    provide(CASCADER_PANEL_INJECTION_KEY, reactive({\n      config,\n      expandingNode,\n      checkedNodes,\n      isHoverMenu,\n      initialLoaded,\n      renderLabelFn,\n      lazyLoad,\n      expandNode,\n      handleCheckChange,\n    }))\n\n    watch([config, () => props.options], initStore, {\n      deep: true,\n      immediate: true,\n    })\n\n    watch(() => props.modelValue, () => {\n      manualChecked = false\n      syncCheckedValue()\n    }, {\n      deep: true,\n    })\n\n    watch(\n      () => checkedValue.value,\n      val => {\n        if (!isEqual(val, props.modelValue)) {\n          emit(UPDATE_MODEL_EVENT, val)\n          emit(CHANGE_EVENT, val)\n        }\n      },\n    )\n\n    onBeforeUpdate(() => menuList.value = [])\n\n    onMounted(() => !isEmpty(props.modelValue) && syncCheckedValue())\n    const { namespace } = useNamespace('cascader-panel')\n    return {\n      namespace,\n      menuList,\n      menus,\n      checkedNodes,\n      handleKeyDown,\n      handleCheckChange,\n      getFlattedNodes,\n      /**\n       * @description get an array of currently selected node,(leafOnly) whether only return the leaf checked nodes, default is `false`\n       */\n      getCheckedNodes,\n      /**\n       * @description clear checked nodes\n       */\n      clearCheckedNodes,\n      calculateCheckedValue,\n      scrollToExpandingNode,\n    }\n  },\n})\n</script>\n"],"names":["_openBlock"],"mappings":"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"}