{"version":3,"file":"cascader.vue.mjs","sources":["../../../../../../packages/components/cascader/src/cascader.vue"],"sourcesContent":["<script lang=\"ts\">\n  import { computed, defineComponent, reactive, ref, watch, provide, toRefs } from 'vue'\n  import { getComponentNamespace, getNamespace } from '../../../utils/global-config'\n\n  import Trigger from '../../trigger/src/trigger'\n\n  import { useFormItem } from '../../form/src/hooks/use-form-item'\n  import { NOOP } from '../../../shared/utils'\n  import SelectTrigger from '../../common/select-trigger.vue'\n  import { isFunction } from '../../../utils/is'\n  import BasePanel from './base-panel'\n\n  import { cascaderProps } from './props'\n  import {\n    transDataToNodes,\n    formatModelValue,\n    getLeafNodes,\n    getNodeKey,\n    getAllLeafNodesByQuery\n  } from './utils'\n\n  import type { CascaderData, CascaderNode, QueryData } from './type'\n  import { useSelectedPath } from './use-selected-path'\n  import { cascaderInjectionKey } from './context'\n  import QueryPanel from './query-panel.vue'\n\n  export default defineComponent({\n    name: getComponentNamespace('Cascader'),\n    components: {\n      Trigger,\n      BasePanel,\n      QueryPanel,\n      SelectTrigger\n    },\n    props: cascaderProps,\n    emits: ['update:modelValue', 'change'],\n    setup(props, { slots, emit }) {\n      const ns = getNamespace('cascader')\n      const { formItem } = useFormItem()\n      const popupVisible = ref(false)\n      const totalLevel = ref(1)\n      const popupRef = ref()\n      // TODO 从表单合并 disabled 属性\n      const mergeDisabled = computed(() => props.disabled)\n      const mergeSize = computed(() => props.size)\n      const nodesData = ref<CascaderNode[]>([])\n      const nodesMap = reactive(new Map<string, CascaderNode>())\n      const selfModel = ref<string[] | string[][]>([])\n      // filterable\n      const queryDataList = ref<QueryData[]>([])\n      const isQueryPattern = ref(false)\n\n      const computedModelValue = computed(() => {\n        return props.modelValue || selfModel.value\n      })\n\n      const pathValueToNodeKeys = computed(() => {\n        // 多选时 二维数据处理 [[1,2,3],[4,5,6]] => ['1-2-3','4-5-6']\n        // 单选 [1,2,3] => ['1-2-3']\n        const values = formatModelValue(computedModelValue.value, {\n          multiple: props.multiple\n        })\n\n        return values\n      })\n\n      const { expandChild } = toRefs(props)\n      const { renderColumns, selectedPath, setSelectedPath, activeKey, setActiveKey } =\n        useSelectedPath(nodesData, { nodesMap, expandChild })\n\n      const currentTagLabel = computed(() => {\n        if (!props.multiple && pathValueToNodeKeys.value.length) {\n          const node = nodesMap.get(pathValueToNodeKeys.value[0])\n          let label = node?.pathLabel?.join(props.separator)\n          if (!props.showAllLevels) {\n            label = node?.pathLabel?.[node!.pathLabel.length - 1]\n          }\n          if (props.inputLabelFormat && node?.pathLabel) {\n            label = props.inputLabelFormat(node?.pathLabel)\n          }\n          return label\n        }\n        return ''\n      })\n\n      const multipleTags = computed(() => {\n        if (!props.multiple) return []\n        const tagLabels = pathValueToNodeKeys.value.map((nodeKey) => {\n          const node = nodesMap.get(nodeKey)\n          const key = node?.key\n          const label = props.showAllLevels\n            ? node?.pathLabel?.[node.pathLabel?.length - 1]\n            : node?.pathLabel?.join(props.separator)\n          return {\n            label,\n            key\n          }\n        })\n        return tagLabels\n      })\n\n      watch(\n        () => popupVisible.value,\n        (value) => {\n          if (value) {\n            const nodeKeys = pathValueToNodeKeys.value\n            if (nodeKeys.length > 0) {\n              // 默认选中最后一个nodeKey\n              const lastNodeKey = nodeKeys[nodeKeys.length - 1]\n              setSelectedPath(lastNodeKey)\n              setActiveKey(lastNodeKey)\n            }\n          }\n        }\n      )\n\n      watch(\n        () => props.data,\n        (newData: CascaderData[]) => {\n          nodesMap.clear()\n          nodesData.value = transDataToNodes(newData, { nodesMap, totalLevel })\n        },\n        { immediate: true, deep: true }\n      )\n\n      const handlePopupVisibleChange = (visible: boolean) => {\n        popupVisible.value = visible\n      }\n\n      const updatePathValue = (pathValue: string[] | string[][]) => {\n        emit('update:modelValue', pathValue)\n        emit('change', pathValue)\n        selfModel.value = pathValue\n\n        // 表单验证\n        if (props.validateEvent) {\n          formItem?.validate?.('change').catch(NOOP)\n        }\n      }\n\n      // 清空事件\n      const handleClear = () => {\n        updatePathValue([])\n        setActiveKey()\n        setSelectedPath()\n        handlePopupVisibleChange(false)\n\n        if (props.filterable) {\n          queryDataList.value = []\n          isQueryPattern.value = false\n        }\n      }\n\n      // 过滤事件\n      const handleFilter = (query: string) => {\n        isQueryPattern.value = !!query\n        if (!isQueryPattern.value) {\n          queryDataList.value = []\n          return\n        }\n        const leafNodes = getAllLeafNodesByQuery(nodesData.value, (node) => {\n          let ret\n          if (isFunction(props.filterMethod)) {\n            ret = props.filterMethod(node, query)\n          } else {\n            ret = node.label && new RegExp(`${query}`, 'i').test(node.label)\n          }\n          return ret\n        })\n        // 从root到leaf依次向下查找\n        const RE = new RegExp(`(${query})`, 'i')\n        queryDataList.value = leafNodes.map((node) => {\n          const isSelected = pathValueToNodeKeys.value.includes(node.key)\n          return {\n            key: node.key,\n            label: node.pathLabel\n              ?.join('/')\n              .replace(RE, `<span style=\"color:var(--bn-danger)\">$1</span>`),\n            isSelected,\n            node\n          }\n        }) as QueryData[]\n      }\n\n      const handleQueryTag = (queryData: QueryData) => {\n        if (props.multiple) {\n          queryData.isSelected = !queryData.isSelected\n          if (queryData.isSelected) {\n            selectMultiple(queryData.node, true)\n          } else {\n            selectMultiple(queryData.node, false)\n          }\n          return\n        }\n        const prevSelectTag = queryDataList.value.find((item) => item.isSelected)\n        if (prevSelectTag) {\n          prevSelectTag.isSelected = false\n        }\n        queryData.isSelected = !queryData.isSelected\n        selectSingle(queryData.node)\n      }\n\n      // 删除多选时的标签\n      const handleTagClose = (tag: Record<string, any>) => {\n        const originPathValue = computedModelValue.value.map((m) => m.slice(0)) as string[][]\n        const index = originPathValue.findIndex((path) => getNodeKey(path) === tag.key && tag.key)\n        if (index < 0) return\n        originPathValue.splice(index, 1)\n        updatePathValue(originPathValue)\n\n        if (props.filterable) {\n          const keys = originPathValue.map((path) => getNodeKey(path))\n          queryDataList.value.forEach((tag) => {\n            tag.isSelected = keys.includes(tag.key)\n          })\n        }\n      }\n\n      const selectSingle = (node: CascaderNode) => {\n        const pathValue: string[] = node.pathValue!.slice(0)\n        handlePopupVisibleChange(false)\n        // 当前node已被选中 就不会出发更新行为\n        if (pathValueToNodeKeys.value.includes(node.key)) {\n          return\n        }\n        setActiveKey(node.key)\n        updatePathValue(pathValue)\n      }\n\n      // check:当前选中还是取消\n      const selectMultiple = (node: CascaderNode, checked: boolean) => {\n        const originPathValue = computedModelValue.value.slice() as string[][]\n        const nodes: CascaderNode[] = props.checkStrictly ? [node] : getLeafNodes(node)\n        if (checked) {\n          nodes.forEach((n) => {\n            if (n.pathValue) {\n              originPathValue.push(n.pathValue.slice(0))\n            }\n          })\n          updatePathValue(originPathValue)\n        } else {\n          const keys = nodes.map((n) => n.key)\n          const pathValues: string[][] = originPathValue.filter(\n            (value) => !keys.includes(value.join('-'))\n          )\n          updatePathValue(pathValues)\n        }\n      }\n\n      const footerOps = {\n        handleCancel() {\n          handleClear()\n          handlePopupVisibleChange(false)\n        },\n        handleOk() {\n          handlePopupVisibleChange(false)\n        }\n      }\n\n      const emitPath = (node: CascaderNode, checked?: boolean) => {\n        if (!props.multiple) {\n          selectSingle(node)\n        } else {\n          selectMultiple(node, checked ?? true)\n        }\n      }\n\n      provide(\n        cascaderInjectionKey,\n        reactive({\n          slots,\n          setSelectedPath,\n          emitPath,\n          setActiveKey,\n          nodeKeys: pathValueToNodeKeys,\n          footer: footerOps\n        })\n      )\n\n      return {\n        ns,\n        popupVisible,\n        mergeDisabled,\n        mergeSize,\n        currentTagLabel,\n        renderColumns,\n        selectedPath,\n        activeKey,\n        multipleTags,\n        totalLevel,\n        popupRef,\n        queryDataList,\n        isQueryPattern,\n        handleFilter,\n        handleClear,\n        handleTagClose,\n        handleQueryTag,\n        handlePopupVisibleChange\n      }\n    }\n  })\n</script>\n\n<template>\n  <div :class=\"[ns]\">\n    <Trigger\n      v-model:popup-visible=\"popupVisible\"\n      position=\"bl\"\n      trigger=\"click\"\n      :unmount-on-close=\"false\"\n      animation-name=\"bn-slide-dynamic-origin\"\n      :popup-offset=\"8\"\n      :disabled=\"mergeDisabled\"\n    >\n      <template #default>\n        <slot name=\"trigger\" :show=\"popupVisible\">\n          <SelectTrigger\n            :input-value=\"currentTagLabel\"\n            :disabled=\"mergeDisabled\"\n            :size=\"mergeSize\"\n            :placeholder=\"placeholder\"\n            :clearable=\"clearable\"\n            :popup-visible=\"popupVisible\"\n            :multiple=\"multiple\"\n            :multiple-tags=\"multipleTags\"\n            :filterable=\"filterable\"\n            :popup-ref=\"popupRef\"\n            :card=\"card\"\n            @clear=\"handleClear\"\n            @filter=\"handleFilter\"\n            @tag-close=\"handleTagClose\"\n            @show=\"handlePopupVisibleChange(true)\"\n          />\n        </slot>\n      </template>\n\n      <template #content>\n        <BasePanel\n          v-if=\"!isQueryPattern\"\n          ref=\"popupRef\"\n          :render-columns=\"renderColumns\"\n          :selected-path=\"selectedPath\"\n          :active-key=\"activeKey\"\n          :multiple=\"multiple\"\n          :check-strictly=\"checkStrictly\"\n          :total-level=\"totalLevel\"\n          :show-footer=\"showFooter\"\n        />\n\n        <QueryPanel\n          v-if=\"isQueryPattern\"\n          ref=\"popupRef\"\n          :query-data-list=\"queryDataList\"\n          @on-tag=\"handleQueryTag\"\n        />\n      </template>\n    </Trigger>\n  </div>\n</template>\n"],"names":["_resolveComponent","_normalizeClass","mergeDisabled","_withCtx","_renderSlot","currentTagLabel","_createVNode","mergeSize","placeholder","clearable","popupVisible","multiple","multipleTags","filterable","popupRef","card","handleClear","handleFilter","handleTagClose","_openBlock","_createBlock","activeKey","checkStrictly","totalLevel","showFooter","isQueryPattern"],"mappings":";;;;;;;;6BAgTEA,iBAqDM,SAAA,CAAA,CAAA;;;;MApDJ,KAmDU,EAAAC,cAAA,CAAA,CAAA,IAAA,CAAA,EAAA,CAAA,CAAA;AAAA,KAAA;AAAA;;QAjDR,iBAAa,IAAA,CAAA,YAAA;AAAA,QACb,uBAAA,EAAe,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,MAAA,KAAA,IAAA,CAAA,YAAA,GAAA,MAAA,CAAA;AAAA,QACd,QAAA,EAAA,IAAA;AAAA,QACD,OAAA,EAAA,OAAA;AAAA,QACC,kBAAe,EAAA,KAAA;AAAA,QACf,gBAAUC,EAAAA,yBAAAA;AAAAA,QAAAA,cAAAA,EAAAA,CAAAA;AAAAA,QAEA,UAAO,IAAA,CAAA,aAAA;AAAA,OAAA,EAAA;AAAA,iBAEdC,QAgBE,MAAA;AAAA,UAfCC,UAAA,CAAA,KAAW,MAAEC,EAAAA,SAAAA,EAAe,EAAA,IAAA,EAAA,IAAA,CAAA,YAAA,EAAA,EAAA,MAAA;AAAA,YAAAC,YAClBJ,wBAAa,EAAA;AAAA,cACvB,eAAMK,IAAS,CAAA,eAAA;AAAA,cACf,UAAaC,IAAAA,CAAAA,aAAAA;AAAAA,cACb,MAAWC,IAAAA,CAAAA,SAAAA;AAAAA,cACX,aAAeC,IAAAA,CAAAA,WAAAA;AAAAA,cACf,WAAUC,IAAAA,CAAAA,SAAAA;AAAAA,cACV,iBAAeC,IAAAA,CAAAA,YAAAA;AAAAA,cACf,UAAU,IAAEC,CAAAA,QAAAA;AAAAA,cACZ,iBAAWC,IAAAA,CAAAA,YAAAA;AAAAA,cACX,YAAMC,IAAI,CAAA,UAAA;AAAA,cACV,aAAOC,IAAAA,CAAAA,QAAAA;AAAAA,cACP,MAAQC,IAAAA,CAAAA,IAAAA;AAAAA,cACR,SAAWC,IAAAA,CAAAA,WAAAA;AAAAA,cACX,UAAI,IAAA,CAAA,YAAA;AAAA,cAAA,YAAA,IAAA,CAAA,cAAA;AAAA;;WAKA,CAAA;AAAA,SAAA,CAAA;AAAA,QACT,OAAA,EAAAf,QAAA,MAAA;AAAA,UAAA,CAAA,IAAA,CAAA,cAAA,IAAAgB,SAEM,EAAA,EAAUC,YAAA,oBAAA,EAAA;AAAA,YACb,GAAA,EAAA,CAAA;AAAA,YACA,GAAA,EAAA,UAAA;AAAA,YACA,kBAAYC,IAAAA,CAAAA,aAAAA;AAAAA,YACZ,iBAAUV,IAAAA,CAAAA,YAAAA;AAAAA,YACV,cAAgBW,IAAAA,CAAAA,SAAAA;AAAAA,YAChB,UAAaC,IAAAA,CAAAA,QAAAA;AAAAA,YACb,kBAAaC,IAAAA,CAAAA,aAAAA;AAAAA,YAAAA,eAAAA,IAAAA,CAAAA,UAAAA;AAAAA;WAIRC,EAAAA,IAAAA,EAAAA,CAAc,EAAA,qIADtB,QAKE,IAAA,CAAA;AAAA,UAAA,IAAA,CAAA,cAAA,IAAAN,SAHI,EAAA,EAAUC,YAAA,qBAAA,EAAA;AAAA,YACb,GAAA,EAAA,CAAA;AAAA,YACA,GAAA,EAAA,UAAA;AAAA,YAAA,mBAAA,IAAA,CAAA,aAAA;AAAA;;;;;;;;;;;;;;;"}