{"version":3,"file":"select.vue.mjs","sources":["../../../../../../packages/components/select/src/select.vue"],"sourcesContent":["<script lang=\"ts\">\n  import {\n    computed,\n    defineComponent,\n    ref,\n    provide,\n    reactive,\n    watch,\n    nextTick,\n    onUnmounted\n  } from 'vue'\n  import type { VNode, ComponentPublicInstance } from 'vue'\n  import { getComponentNamespace, getNamespace } from '../../../utils/global-config'\n  import Trigger from '../../trigger/src/trigger'\n  import { BnIconLoading, BnIconEmpty } from '../../icon'\n  import SelectTrigger from '../../common/select-trigger.vue'\n  import { Scrollbar } from '../../scrollbar'\n  import type { ScrollbarInstance } from '../../scrollbar'\n\n  // 表单\n  import { useFormItem } from '../../form/src/hooks/use-form-item'\n\n  import { NOOP } from '../../../shared/utils'\n  import { isArray, isComponentInstance, isFunction } from '../../../utils/is'\n  import { debounce } from '../../../utils/throttle-debounce'\n  import { Empty } from '../../empty'\n  import SelectMenu from './menu.vue'\n  import { selectInjectKey } from './context'\n  import { selectProps } from './props'\n\n  import OptionsExtract from './options-extract'\n  import OptionsRender from './options-render'\n\n  import type { OptVmProxy } from './types'\n\n  export default defineComponent({\n    name: getComponentNamespace('Select'),\n    components: {\n      Trigger,\n      SelectMenu,\n      Scrollbar,\n      BnIconLoading,\n      SelectTrigger,\n      OptionsExtract,\n      OptionsRender,\n      Empty,\n      BnIconEmpty\n    },\n    props: selectProps,\n    emits: ['update:modelValue', 'change'],\n    setup(props, { emit }) {\n      const ns = getNamespace('select')\n      // TODO 从表单合并 disabled 属性\n      const mergeDisabled = computed(() => props.disabled)\n      const mergeSize = computed(() => props.size)\n\n      const cls = computed(() => [ns, mergeDisabled.value && 'is-disabled'])\n\n      const optionsVns = ref<VNode[]>([])\n      const optionValues = computed(() => optionsVns.value.map((opt) => opt.props?.value))\n      const popupVisible = ref(false)\n      const selectedLabelOnlySingle = ref('')\n      const multipleTags = ref<{ label: string; key: string }[]>([])\n      const currentSelected = ref<OptVmProxy | OptVmProxy[]>(props.multiple ? [] : ({} as any))\n      const cachedOptionsVmProxies = ref(new Map())\n      const selectTriggerRef = ref()\n      const scrollbarRef = ref<ScrollbarInstance>()\n      const popupRef = ref()\n\n      // 缓存的cachedOptionsVmProxies  Array\n      const cachedOptionsVmProxiesToArray = computed(() =>\n        Array.from<OptVmProxy>(cachedOptionsVmProxies.value.values())\n      )\n\n      const isEmpty = computed(() => {\n        const renderOptions = cachedOptionsVmProxiesToArray.value.filter((opt) =>\n          optionValues.value.includes(opt.value)\n        )\n        return !renderOptions.some((s) => s.visible)\n      })\n\n      const getOptionByValue = (value: any): OptVmProxy | undefined => {\n        const option = cachedOptionsVmProxiesToArray.value.find((opt) => opt.currentValue === value)\n        return option\n      }\n      const handleClear = () => {\n        const value = props.multiple ? [] : ''\n        emit('update:modelValue', value)\n        emit('change', value)\n\n        if (!props.multiple && props.remote) {\n          selectedLabelOnlySingle.value = ''\n        }\n\n        if (props.multiple && props.remote) {\n          multipleTags.value = []\n        }\n\n        handleClosePopup()\n      }\n\n      const emitSelectValue = (selected: OptVmProxy | OptVmProxy[]) => {\n        if (props.multiple) {\n          const values = (selected as OptVmProxy[]).map((opt) => opt.currentValue)\n          emit('update:modelValue', values)\n          emit('change', values)\n          return\n        }\n        const value = (selected as OptVmProxy).currentValue\n        emit('update:modelValue', value)\n        emit('change', value)\n        handleClosePopup()\n      }\n\n      const handleClosePopup = () => {\n        popupVisible.value = false\n      }\n\n      const handleShowPopup = () => {\n        popupVisible.value = true\n      }\n\n      const optionItemCreate = (optVmProxy: any) => {\n        cachedOptionsVmProxies.value.set(optVmProxy.value, optVmProxy)\n      }\n\n      const optionItemDestroy = (optVmProxy: OptVmProxy) => {\n        // 当前为远程多选搜索模式时，缓存的optVmProxy不要清除，为了后面状态同步。\n        if (props.remote && props.multiple) return\n        const key = optVmProxy.currentValue\n        if (cachedOptionsVmProxies.value.get(key)) {\n          cachedOptionsVmProxies.value.delete(key)\n        }\n      }\n\n      const optionItemSelect = (optVmProxy: OptVmProxy) => {\n        if (!props.multiple) {\n          if (currentSelected.value !== optVmProxy) {\n            emitSelectValue(optVmProxy)\n            if (props.remote) {\n              selectedLabelOnlySingle.value = optVmProxy.currentLabel ?? ''\n            }\n          } else {\n            handleClosePopup()\n            if (props.filterable) {\n              selectTriggerRef.value?.resetQuery()\n            }\n          }\n          return\n        }\n        const origin = (currentSelected.value as OptVmProxy[]).slice()\n        const index = origin.findIndex((opt) => opt === optVmProxy)\n        if (index > -1) {\n          // 删除\n          origin.splice(index, 1)\n        } else {\n          // 新增\n          origin.push(optVmProxy)\n        }\n        emitSelectValue(origin)\n      }\n\n      const optionItemHoverChange = (optProxy: OptVmProxy) => {\n        cachedOptionsVmProxiesToArray.value.forEach((opt) => {\n          opt.isHover = opt === optProxy\n        })\n      }\n      const getMultipleTags = (selected: OptVmProxy[]) => {\n        return selected.map((opt) => {\n          opt.isSelected = true\n          return {\n            key: opt.currentValue as string,\n            label: opt.currentLabel\n          }\n        })\n      }\n\n      // 维护内部当前选中的item状态\n      watch(\n        () => currentSelected.value,\n        (selected: OptVmProxy | OptVmProxy[]) => {\n          cachedOptionsVmProxiesToArray.value.forEach((opt) => {\n            opt.isSelected = false\n          })\n          if (props.multiple && isArray(selected)) {\n            multipleTags.value = getMultipleTags(selected as OptVmProxy[])\n          } else {\n            const _selected = selected as OptVmProxy\n            if (isComponentInstance(_selected)) {\n              _selected.isSelected = true\n            }\n            if (!props.remote) {\n              // 重置选中的label\n              selectedLabelOnlySingle.value = _selected.currentLabel ?? ''\n            }\n          }\n        }\n      )\n      // 多选 删除标签\n      const handleTagClose = (tag: { label: string; key: string }) => {\n        const key = tag.key\n        const origin = (currentSelected.value as OptVmProxy[]).slice()\n        const index = origin.findIndex((opt) => opt.currentValue === key)\n        if (index > -1) {\n          origin.splice(index, 1)\n        }\n        emitSelectValue(origin)\n      }\n\n      // 当插槽发生变化时，重新更新\n      const onUpdateOptionsVns = (vns: VNode[]) => {\n        optionsVns.value = vns\n      }\n\n      const whetherResetOptionVns = () => {\n        if (props.remote) {\n          onUpdateOptionsVns([])\n        }\n      }\n\n      const setSelected = async () => {\n        await nextTick()\n        if (!props.multiple) {\n          const option = getOptionByValue(props.modelValue)\n          if (!option) {\n            currentSelected.value = {} as any\n            return\n          }\n          currentSelected.value = option\n          return\n        }\n        const modelValue = isArray(props.modelValue) ? props.modelValue : [props.modelValue]\n        const optVmProxies = modelValue.map((value) => getOptionByValue(value))\n        currentSelected.value = (optVmProxies as OptVmProxy[]).filter(Boolean)\n      }\n\n      // 搜索过滤\n      const handleFilter = debounce(\n        (query: string) => {\n          if (props.remote) {\n            onUpdateOptionsVns([])\n            nextTick(() => {\n              if (isFunction(props.remoteMethod)) {\n                props.remoteMethod(query)\n              }\n            })\n          } else {\n            cachedOptionsVmProxiesToArray.value.forEach((optVmProxy) => {\n              let visible = false\n              if (!query) {\n                visible = true\n              } else if (isFunction(props.filterMethod)) {\n                visible = props.filterMethod(optVmProxy, query)\n              } else {\n                visible = new RegExp(`${query}`, 'i').test(optVmProxy.currentLabel)\n              }\n              optVmProxy.visible = visible\n            })\n          }\n        },\n        props.remote ? props.filterDebounce : 0,\n        true\n      )\n\n      // 让选中的optionItem出现在可视区 多选的话就以第一个为准\n      const updateOptionItemToVisible = () => {\n        const _currentSelected = currentSelected.value as unknown as ComponentPublicInstance\n        const el = (\n          isArray(_currentSelected) ? _currentSelected[0]?.$el : _currentSelected.$el\n        ) as HTMLElement\n        if (!el) return\n        const visibleHeight = scrollbarRef.value?.containerRef?.getBoundingClientRect()\n          .height as number\n        const offsetTop = el.offsetTop\n        const elHeight = el.getBoundingClientRect().height\n        const top = offsetTop + elHeight - visibleHeight\n        if (top > 0) {\n          scrollbarRef.value?.scrollTop(top)\n        }\n      }\n\n      // 表单验证\n      const { formItem } = useFormItem()\n\n      // option插槽数据变化\n      watch(\n        () => optionsVns.value,\n        (vns) => {\n          if (vns.length === 0) return\n          setSelected()\n        }\n      )\n\n      // 数据发生变化,进行表单验证\n      watch(\n        () => props.modelValue,\n        () => {\n          setSelected()\n          // 触发表单验证\n          if (props.validateEvent) {\n            formItem?.validate('change').catch(NOOP)\n          }\n        },\n        {\n          deep: true\n        }\n      )\n\n      onUnmounted(() => {\n        cachedOptionsVmProxies.value.clear()\n      })\n\n      provide(\n        selectInjectKey,\n        reactive({\n          multiple: props.multiple,\n          popupClass: props.popupClass,\n          compact: props.compact,\n          optionItemCreate,\n          optionItemDestroy,\n          optionItemSelect,\n          optionItemHoverChange\n        })\n      )\n\n      return {\n        ns,\n        cls,\n        popupVisible,\n        isEmpty,\n        onUpdateOptionsVns,\n        mergeDisabled,\n        mergeSize,\n        handleClosePopup,\n        scrollbarRef,\n        popupRef,\n        handleClear,\n        optionsVns,\n        selectedLabelOnlySingle,\n        multipleTags,\n        handleTagClose,\n        handleFilter,\n        updateOptionItemToVisible,\n        handleShowPopup,\n        whetherResetOptionVns,\n        selectTriggerRef\n      }\n    }\n  })\n</script>\n\n<template>\n  <div :class=\"cls\">\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      auto-fit-popup-min-width\n      :popup-offset=\"8\"\n      :disabled=\"mergeDisabled\"\n      @show=\"updateOptionItemToVisible\"\n      @hide=\"whetherResetOptionVns\"\n    >\n      <template #default>\n        <SelectTrigger\n          ref=\"selectTriggerRef\"\n          :input-value=\"selectedLabelOnlySingle\"\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          @tag-close=\"handleTagClose\"\n          @filter=\"handleFilter\"\n          @show=\"handleShowPopup\"\n        />\n      </template>\n\n      <template #content>\n        <SelectMenu ref=\"popupRef\">\n          <Scrollbar ref=\"scrollbarRef\" style=\"max-height: 224px\">\n            <OptionsRender :options-vns=\"optionsVns\" />\n\n            <template v-if=\"isEmpty && !loading\">\n              <p :class=\"[`${ns}__empty`]\" @click=\"handleClosePopup\">\n                <slot name=\"empty\">\n                  <Empty :description=\"noDataText\">\n                    <template #image>\n                      <BnIconEmpty size=\"38\" />\n                    </template>\n                  </Empty>\n                </slot>\n              </p>\n            </template>\n            <template v-if=\"isEmpty && loading\">\n              <p :class=\"[`${ns}__empty`]\" @click=\"handleClosePopup\">\n                <BnIconLoading />\n                <span style=\"margin-left: 4px\">{{ loadingText }}</span>\n              </p>\n            </template>\n          </Scrollbar>\n        </SelectMenu>\n      </template>\n    </Trigger>\n\n    <OptionsExtract @update-options=\"onUpdateOptionsVns\">\n      <slot></slot>\n    </OptionsExtract>\n  </div>\n</template>\n"],"names":["_resolveComponent","_normalizeClass","updateOptionItemToVisible","whetherResetOptionVns","_withCtx","_createVNode","selectedLabelOnlySingle","mergeSize","placeholder","clearable","popupVisible","multiple","multipleTags","filterable","popupRef","card","handleClear","handleFilter","handleShowPopup","isEmpty","loading","_openBlock","_createElementBlock","ns","_createCommentVNode"],"mappings":"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"}