{"version":3,"file":"index2.mjs","sources":["../../../../../src/components/ivue-select/index.vue"],"sourcesContent":["<template>\r\n  <div\r\n    ref=\"selectWrapper\"\r\n    :class=\"classes\"\r\n    v-click-outside:[capture]=\"handleClickOutside\"\r\n    v-click-outside:[capture].mousedown=\"handleClickOutside\"\r\n  >\r\n    <div\r\n      ref=\"reference\"\r\n      :class=\"selectionClasses\"\r\n      :tabindex=\"selectTabindex\"\r\n      @blur=\"handleHeaderFocus\"\r\n      @focus=\"handleHeaderFocus\"\r\n      @click=\"handleToggleMenu\"\r\n      @mouseenter=\"data.hasMouseHover = true\"\r\n      @mouseleave=\"data.hasMouseHover = false\"\r\n      @keydown.down.stop.prevent=\"handleKeyDown\"\r\n      @keydown.up.stop.prevent=\"handleKeyDown\"\r\n      @keydown.enter.stop.prevent=\"handleKeyDown\"\r\n      @keydown.esc.stop.prevent=\"handleKeyDown\"\r\n      @keydown.tab=\"handleKeyDown\"\r\n    >\r\n      <slot name=\"input\">\r\n        <input type=\"hidden\" :name=\"name\" :value=\"currentSelectValue\" />\r\n        <!-- 头部 -->\r\n        <select-head\r\n          :id=\"inputId\"\r\n          :prefix=\"prefix\"\r\n          :filterable=\"filterable\"\r\n          :multiple=\"multiple\"\r\n          :maxTagCount=\"maxTagCount\"\r\n          :multipleIcon=\"multipleIcon\"\r\n          :maxTagPlaceholder=\"maxTagPlaceholder\"\r\n          :placeholder=\"placeholder\"\r\n          :arrowDownIcon=\"arrowDownIcon\"\r\n          :clearable=\"canClearable\"\r\n          :values=\"data.values\"\r\n          :isSearchMethod=\"isSearchMethod\"\r\n          :resetSelectIcon=\"resetSelectIcon\"\r\n          :disabled=\"inputDisabled\"\r\n          :filterQueryProp=\"data.filterQuery\"\r\n          :allowCreate=\"allowCreate\"\r\n          :showCreateItem=\"showCreateItem\"\r\n          @on-clear=\"clearSingleSelect\"\r\n          @on-filter-query-change=\"handleFilterQueryChange\"\r\n          @on-input-focus=\"data.isFocused = true\"\r\n          @on-input-blur=\"data.isFocused = false\"\r\n          @on-enter=\"handleCreateItem\"\r\n          ref=\"selectHead\"\r\n        >\r\n          <template #prefix v-if=\"$slots.prefix\">\r\n            <slot name=\"prefix\"></slot>\r\n          </template>\r\n        </select-head>\r\n      </slot>\r\n    </div>\r\n    <!-- 下拉菜单 -->\r\n    <transition name=\"transition-drop\">\r\n      <drop-down\r\n        :transfer=\"transfer\"\r\n        :data-transfer=\"transfer\"\r\n        :placement=\"placement\"\r\n        :class=\"dropdownClasses\"\r\n        v-transfer-dom\r\n        key=\"IvueSelectDropdown\"\r\n        ref=\"dropdown\"\r\n        v-show=\"dropVisible\"\r\n      >\r\n        <!-- 没有找到数据时的提示 -->\r\n        <ul\r\n          :class=\"[`${prefixCls}-not-find`]\"\r\n          v-show=\"showNotFindText && !allowCreate && notFindText\"\r\n        >\r\n          <li>{{ notFindText }}</li>\r\n        </ul>\r\n        <!-- 列表 -->\r\n        <ul\r\n          :class=\"`${prefixCls}-dropdown-list`\"\r\n          v-if=\"!isSearchMethod || (isSearchMethod && !loading)\"\r\n        >\r\n          <!-- 创建选项 -->\r\n          <ivue-option\r\n            :class=\"createItemClasses\"\r\n            :allowCreate=\"allowCreate\"\r\n            :showCreateItem=\"showCreateItem\"\r\n            :filterQuery=\"data.filterQuery\"\r\n            @on-create=\"handleCreateItem\"\r\n            v-if=\"showCreateItem\"\r\n          >\r\n            <!-- 搜索内容 -->\r\n            <p class=\"text\">{{ data.filterQuery }}</p>\r\n            <!-- 图标 -->\r\n            <ivue-icon>{{ allowCreateIcon }}</ivue-icon>\r\n          </ivue-option>\r\n          <!-- slot -->\r\n          <slot></slot>\r\n        </ul>\r\n        <!-- 加载中 -->\r\n        <ul v-show=\"loading\" :class=\"`${prefixCls}-loading`\">\r\n          <div :class=\"`${prefixCls}-loading--load`\">\r\n            <div class=\"load\" v-ivue-loading=\"true\"></div>\r\n            <!-- loadingText -->\r\n            <span>{{ loadingText }}</span>\r\n          </div>\r\n        </ul>\r\n      </drop-down>\r\n    </transition>\r\n  </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport {\r\n  defineComponent,\r\n  computed,\r\n  reactive,\r\n  getCurrentInstance,\r\n  provide,\r\n  ref,\r\n  nextTick,\r\n  watch,\r\n  onMounted,\r\n  inject,\r\n} from 'vue';\r\nimport mitt from 'mitt';\r\n\r\n// 输入框\r\nimport SelectHead from './select-head.vue';\r\n// 下拉框\r\nimport DropDown from './drop-down.vue';\r\nimport IvueOption from './option.vue';\r\nimport IvueIcon from '../ivue-icon/index.vue';\r\nimport IvueLoading from '../ivue-loading/directive';\r\n\r\n// 注册外部点击事件插件\r\nimport { ClickOutside, TransferDom } from '../../utils/directives';\r\nimport { oneOf } from '../../utils/assist';\r\nimport { useFormItem, useFormItemInputId, useDisabled } from '../../hooks';\r\nimport { debugWarn } from '../../utils/error';\r\n\r\n// type\r\nimport { PopoverContextKey } from '../ivue-popover/types/popover';\r\nimport {\r\n  Props,\r\n  Data,\r\n  DropDownInstance,\r\n  SelectHeadInstance,\r\n  SelectContextKey,\r\n  OptionInstance,\r\n} from './types/select';\r\nimport type { OptionData } from './types/option';\r\n\r\nconst prefixCls = 'ivue-select';\r\n\r\nexport default defineComponent({\r\n  name: prefixCls,\r\n  // 注册局部指令\r\n  directives: { ClickOutside, TransferDom, IvueLoading },\r\n  emits: [\r\n    'update:modelValue',\r\n    'on-change',\r\n    'on-clear',\r\n    'on-menu-open',\r\n    'on-filter-query-change',\r\n    'on-set-default-options',\r\n    'on-create',\r\n    'on-select',\r\n  ],\r\n  props: {\r\n    /**\r\n     * 设置选择的值\r\n     *\r\n     * @type {String, Number, Array}\r\n     */\r\n    modelValue: {\r\n      type: [String, Number, Array],\r\n      default: '',\r\n    },\r\n    /**\r\n     * 远程搜索时，显示默认 label，详见示例\r\n     *\r\n     * @type {String, Number, Array}\r\n     */\r\n    defaultLabel: {\r\n      type: [String, Number, Array],\r\n      default: '',\r\n    },\r\n    /**\r\n     * 选择选项时的颜色\r\n     *\r\n     * @type {String | Array}\r\n     */\r\n    selectedColor: {\r\n      type: [String, Array],\r\n      default: '#5B8EFF',\r\n    },\r\n    /**\r\n     * hover 选择选项时的颜色\r\n     *\r\n     * @type {String | Array}\r\n     */\r\n    hoverColor: {\r\n      type: [String, Array],\r\n      default: () => '#5B8EFF',\r\n    },\r\n    /**\r\n     * 是否开启多选\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    multiple: {\r\n      type: Boolean,\r\n      default: false,\r\n    },\r\n    /**\r\n     * 是否开启多选过滤收起时清除输入\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    multipleFilterableClear: {\r\n      type: Boolean,\r\n      default: false,\r\n    },\r\n    /**\r\n     * 设置多选删除图标\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    multipleIcon: {\r\n      type: String,\r\n      default: 'cancel',\r\n    },\r\n    /**\r\n     * 是否禁用选择组件\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    disabled: {\r\n      type: Boolean,\r\n      default: false,\r\n    },\r\n    /**\r\n     * 是否开启外部点击的 capture 模式，可通过全局配置\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    capture: {\r\n      type: Boolean,\r\n      default() {\r\n        const global = getCurrentInstance().appContext.config.globalProperties;\r\n        return !global.$IVUE ? true : global.$IVUE.capture;\r\n      },\r\n    },\r\n    /**\r\n     * 是否支持搜索\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    filterable: {\r\n      type: Boolean,\r\n      default: false,\r\n    },\r\n    /**\r\n     * input name\r\n     *\r\n     * @type {String}\r\n     */\r\n    name: {\r\n      type: String,\r\n    },\r\n    /**\r\n     * 是否将label和value一起返回\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    labelAndValue: {\r\n      type: Boolean,\r\n      default: false,\r\n    },\r\n    /**\r\n     * 在 Select 内显示图标\r\n     *\r\n     * @type {String}\r\n     */\r\n    prefix: {\r\n      type: String,\r\n    },\r\n    /**\r\n     * 多选时最多显示多少个 tag\r\n     *\r\n     * @type {Number}\r\n     */\r\n    maxTagCount: {\r\n      type: Number,\r\n    },\r\n    /**\r\n     * 隐藏 tag 时显示的内容，参数是剩余项数量\r\n     *\r\n     * @type {Function}\r\n     */\r\n    maxTagPlaceholder: {\r\n      type: Function,\r\n    },\r\n    /**\r\n     * 输入提示\r\n     *\r\n     * @type {String}\r\n     */\r\n    placeholder: {\r\n      type: String,\r\n      default: '请选择',\r\n    },\r\n    /**\r\n     * 是否允许用户创建新条目，需开启 filterable\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    allowCreate: {\r\n      type: Boolean,\r\n      default: false,\r\n    },\r\n    /**\r\n     * 创建新条目按钮图标\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    allowCreateIcon: {\r\n      type: String,\r\n      default: 'reply',\r\n    },\r\n    /**\r\n     * 没有找到数据时的提示\r\n     *\r\n     * @type {String}\r\n     */\r\n    notFindText: {\r\n      type: String,\r\n      default: '无匹配数据',\r\n    },\r\n    /**\r\n     * 搜索方法\r\n     *\r\n     * @type {Function}\r\n     */\r\n    searchMethod: {\r\n      type: Function,\r\n    },\r\n    /**\r\n     * 下拉图标\r\n     *\r\n     * @type {String}\r\n     */\r\n    arrowDownIcon: {\r\n      type: String,\r\n      default: 'keyboard_arrow_down',\r\n    },\r\n    /**\r\n     * 是否可以清除选择\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    clearable: {\r\n      type: Boolean,\r\n      default: false,\r\n    },\r\n    /**\r\n     * 清除选择图标\r\n     *\r\n     * @type {String}\r\n     */\r\n    resetSelectIcon: {\r\n      type: String,\r\n      default: 'cancel',\r\n    },\r\n    /**\r\n     * 开启搜索时，隐藏group组件头\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    filterableHiddenGroup: {\r\n      type: Boolean,\r\n      default: false,\r\n    },\r\n    /**\r\n     * 加载中\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    loading: {\r\n      type: Boolean,\r\n      default: false,\r\n    },\r\n    /**\r\n     * 加载中的文字提示\r\n     *\r\n     * @type {String}\r\n     */\r\n    loadingText: {\r\n      type: String,\r\n      default: '加载中',\r\n    },\r\n    /**\r\n     * 搜索时，只按 label 进行搜索\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    filterByLabel: {\r\n      type: Boolean,\r\n      default: false,\r\n    },\r\n    /**\r\n     * 是否开启还原输入框内容（仅在单选时生效）\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    restoreInputOption: {\r\n      type: Boolean,\r\n      default: true,\r\n    },\r\n    /**\r\n     * 是否将弹层放置于 body 内，在 Tabs、\r\n     * 带有 fixed 的 Table 列内使用时，\r\n     * 建议添加此属性，它将不受父级样式影响，\r\n     * 从而达到更好的效果\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    transfer: {\r\n      type: Boolean,\r\n      default() {\r\n        const global = getCurrentInstance().appContext.config.globalProperties;\r\n\r\n        return !global.$IVUE || global.$IVUE.transfer === ''\r\n          ? false\r\n          : global.$IVUE.transfer;\r\n      },\r\n    },\r\n    /**\r\n     * 弹窗的展开方向\r\n     *\r\n     * @type {String}\r\n     */\r\n    placement: {\r\n      type: String,\r\n      validator(value: string) {\r\n        return oneOf(value, [\r\n          'top',\r\n          'bottom',\r\n          'top-start',\r\n          'bottom-start',\r\n          'top-end',\r\n          'bottom-end',\r\n        ]);\r\n      },\r\n      default: 'bottom-start',\r\n    },\r\n    /**\r\n     * 开启 transfer 时，给浮层添加额外的 class 名称\r\n     *\r\n     * @type {String}\r\n     */\r\n    transferClassName: {\r\n      type: String,\r\n    },\r\n    /**\r\n     * 自动完成\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    autoComplete: {\r\n      type: Boolean,\r\n      default: false,\r\n    },\r\n    /**\r\n     * 外部输入框输入数据\r\n     *\r\n     * @type {String}\r\n     */\r\n    filterQueryProp: {\r\n      type: String,\r\n      default: '',\r\n    },\r\n    /**\r\n     * 输入时是否触发表单的校验\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    validateEvent: {\r\n      type: Boolean,\r\n      default: true,\r\n    },\r\n    /**\r\n     * id\r\n     *\r\n     * @type {String}\r\n     */\r\n    id: {\r\n      type: String,\r\n    },\r\n  },\r\n  setup(props: Props, { emit, slots }) {\r\n    // vm\r\n    const { proxy } = getCurrentInstance();\r\n\r\n    // 事件发射器/发布订阅\r\n    const selectEmitter = mitt();\r\n\r\n    // dom\r\n    const selectWrapper = ref<HTMLDivElement>(null);\r\n    const reference = ref<HTMLDivElement>(null);\r\n    const dropdown = ref<DropDownInstance>();\r\n    const selectHead = ref<SelectHeadInstance>();\r\n\r\n    // 输入框禁用\r\n    const inputDisabled = useDisabled();\r\n\r\n    // ivue-popover\r\n    const popover = inject(PopoverContextKey, {\r\n      default: null,\r\n    });\r\n\r\n    // 设置表单对应的输入框id\r\n    const { formItem } = useFormItem();\r\n\r\n    // 输入框id\r\n    const { inputId } = useFormItemInputId(\r\n      props,\r\n      {\r\n        formItemContext: formItem,\r\n      },\r\n      slots\r\n    );\r\n\r\n    // data\r\n    const data = reactive<Data>({\r\n      /**\r\n       * 是否显示菜单\r\n       *\r\n       * @type {Boolean}\r\n       */\r\n      visibleMenu: false,\r\n      /**\r\n       * 判断是否有焦点\r\n       *\r\n       * @type {Boolean}\r\n       */\r\n      isFocused: false,\r\n      /**\r\n       * 最终渲染的数据\r\n       *\r\n       * @type {Array}\r\n       */\r\n      values: [],\r\n      /**\r\n       * 子选项 dom\r\n       *\r\n       * @type {Array}\r\n       */\r\n      options: [],\r\n      /**\r\n       * 焦点项\r\n       *\r\n       * @type {Number}\r\n       */\r\n      focusIndex: -1,\r\n      /**\r\n       * 是否开始输入框支持搜索\r\n       *\r\n       * @type {Boolean}\r\n       */\r\n      filterQueryChange: false,\r\n      /**\r\n       * 搜索输入框输入数据\r\n       *\r\n       * @type {String}\r\n       */\r\n      filterQuery: props.filterQueryProp || '',\r\n      /**\r\n       * 鼠标悬浮\r\n       *\r\n       * @type {Boolean}\r\n       */\r\n      hasMouseHover: false,\r\n      /**\r\n       * 上一次搜索输入\r\n       *\r\n       * @type {String}\r\n       */\r\n      lastSearchQuery: '',\r\n      /**\r\n       * 事件发射器/发布订阅\r\n       *\r\n       * @type {Function}\r\n       */\r\n      selectEmitter,\r\n      /**\r\n       * 当前有 value 值\r\n       *\r\n       * @type {Boolean}\r\n       */\r\n      hasExpectedValue: false,\r\n      /**\r\n       * 过滤输入内容\r\n       *\r\n       * @type {String}\r\n       */\r\n      _filterQuery: '',\r\n      /**\r\n       * 禁用菜单\r\n       *\r\n       * @type {Boolean}\r\n       */\r\n      disableMenu: false,\r\n    });\r\n\r\n    // computed\r\n\r\n    // 外部样式\r\n    const classes = computed(() => {\r\n      return [\r\n        `${prefixCls}`,\r\n        {\r\n          // 默认\r\n          [`${prefixCls}-default`]: !props.multiple,\r\n          // 是否支持多选\r\n          [`${prefixCls}-multiple`]: props.multiple,\r\n          // 是否禁用\r\n          [`${prefixCls}-disabled`]: inputDisabled.value,\r\n          // 是否显示菜单\r\n          [`${prefixCls}-visible`]: data.visibleMenu,\r\n        },\r\n      ];\r\n    });\r\n\r\n    // 选择框样式\r\n    const selectionClasses = computed(() => {\r\n      return [\r\n        `${prefixCls}-selection-default`,\r\n        {\r\n          [`${prefixCls}-selection`]: !props.autoComplete,\r\n          [`${prefixCls}-selection-focused`]: data.isFocused,\r\n        },\r\n      ];\r\n    });\r\n\r\n    // 创建列表选项样式\r\n    const createItemClasses = computed(() => {\r\n      return [`${prefixCls}-item`, `${prefixCls}-item--create`];\r\n    });\r\n\r\n    // tab 键顺序\r\n    const selectTabindex = computed(() => {\r\n      // 是否禁用选择组件 | 是否支持搜索\r\n      return inputDisabled.value || props.filterable ? -1 : 0;\r\n    });\r\n\r\n    // 当前选择的值\r\n    const currentSelectValue = computed(() => {\r\n      const _value = data.values;\r\n\r\n      // 判断是否有开启返回label和value\r\n      if (props.labelAndValue) {\r\n        return props.multiple ? _value : _value[0];\r\n      } else {\r\n        return props.multiple\r\n          ? _value.map((option: { value: any }) => option.value)\r\n          : (_value[0] || {}).value;\r\n      }\r\n    });\r\n\r\n    // 显示没有数据时的文本\r\n    const showNotFindText = computed(() => {\r\n      // 是否禁用选择组件 | 是否支持搜索\r\n      return (\r\n        selectOptions.value &&\r\n        selectOptions.value.length === 0 &&\r\n        (!isSearchMethod.value || (isSearchMethod.value && !props.loading))\r\n      );\r\n    });\r\n\r\n    // 判断是搜索是否是一个方法\r\n    const isSearchMethod = computed(() => {\r\n      return typeof props.searchMethod === 'function';\r\n    });\r\n\r\n    // 获取菜单选择列表\r\n    const selectOptions = computed(() => {\r\n      // 获取选项的列表\r\n      const selectOptions = [];\r\n\r\n      // 选项计数器，计算有多少个选项\r\n      let optionCounter = -1;\r\n\r\n      // 当前焦点项\r\n      const currentIndex = data.focusIndex;\r\n\r\n      // 获取选择选项的value\r\n      const selectedValues = data.values\r\n        .filter(Boolean)\r\n        .map(({ value }) => value);\r\n\r\n      // 判断是否有自动输入\r\n      if (props.autoComplete) {\r\n        for (const option of data.options) {\r\n          option.data.visible = true;\r\n\r\n          //如果没有 filterQueryChange ，则忽略选项\r\n          const optionFilter = props.filterable\r\n            ? validateOption(option)\r\n            : option;\r\n\r\n          // 不符合条件的选项\r\n          if (!optionFilter) {\r\n            option.data.visible = false;\r\n          } else {\r\n            option.data.visible = true;\r\n          }\r\n\r\n          // autoComplete 过滤输入的内容\r\n          if (data._filterQuery === '') {\r\n            option.data.visible = true;\r\n          }\r\n\r\n          // 有显示选项 加入计数器\r\n          if (option.data.visible) {\r\n            // 选项计数器\r\n            optionCounter = optionCounter + 1;\r\n\r\n            selectOptions.push(\r\n              handleOption(\r\n                option,\r\n                selectedValues,\r\n                optionCounter === currentIndex\r\n              )\r\n            );\r\n          }\r\n        }\r\n\r\n        return selectOptions;\r\n      }\r\n\r\n      // 选项的数据\r\n      for (const option of data.options) {\r\n        //如果没有 filterQueryChange ，则忽略选项\r\n        if (data.filterQueryChange || data.filterQuery) {\r\n          const optionFilter = props.filterable\r\n            ? validateOption(option)\r\n            : option;\r\n\r\n          // 不符合条件的选项\r\n          if (!optionFilter) {\r\n            option.data.visible = false;\r\n          } else {\r\n            option.data.visible = true;\r\n          }\r\n\r\n          // 过滤数组\r\n          if (!optionFilter) {\r\n            continue;\r\n          }\r\n        } else {\r\n          option.data.visible = true;\r\n        }\r\n\r\n        // 有显示选项 加入计数器\r\n        if (option.data.visible) {\r\n          // 选项计数器\r\n          optionCounter = optionCounter + 1;\r\n\r\n          selectOptions.push(\r\n            handleOption(option, selectedValues, optionCounter === currentIndex)\r\n          );\r\n        }\r\n      }\r\n\r\n      // 这是一个组件数组 [components]\r\n      return selectOptions;\r\n    });\r\n\r\n    // 显示下拉菜单\r\n    const dropVisible = computed(() => {\r\n      let status = true;\r\n\r\n      // 没有选项\r\n      const noSelectOptions =\r\n        selectOptions.value && selectOptions.value.length === 0;\r\n\r\n      // 没有加载中\r\n      if (\r\n        !props.loading &&\r\n        data.filterQuery === '' &&\r\n        noSelectOptions &&\r\n        isSearchMethod.value\r\n      ) {\r\n        status = false;\r\n      }\r\n\r\n      // autoComplete\r\n      if (props.autoComplete && noSelectOptions && !props.loading) {\r\n        status = false;\r\n      }\r\n\r\n      return data.visibleMenu && status;\r\n    });\r\n\r\n    // 是否可以显示重置选择按钮\r\n    const canClearable = computed(() => {\r\n      // 多选模式下无效\r\n      return (\r\n        data.hasMouseHover &&\r\n        props.clearable &&\r\n        !props.multiple &&\r\n        !inputDisabled.value\r\n      );\r\n    });\r\n\r\n    // 当前选择的值\r\n    const selectValue = computed(() => {\r\n      // 判断是否有开启返回label和value\r\n      if (props.labelAndValue) {\r\n        return props.multiple ? data.values : data.values[0];\r\n      } else {\r\n        return props.multiple\r\n          ? data.values.map((option) => option.value)\r\n          : (data.values[0] || {}).value;\r\n      }\r\n    });\r\n\r\n    // 显示创建的选项\r\n    const showCreateItem = computed(() => {\r\n      let state = false;\r\n\r\n      // 开启了创建选项, 有搜索内容\r\n      if (props.allowCreate && data.filterQuery !== '') {\r\n        state = true;\r\n\r\n        // 是否有选项列表\r\n        if (data.options && data.options.length) {\r\n          if (data.options.find((item) => item.getLabel === data.filterQuery))\r\n            state = false;\r\n        }\r\n      }\r\n\r\n      return state;\r\n    });\r\n\r\n    // 下拉框样式\r\n    const dropdownClasses = computed(() => {\r\n      return {\r\n        [`${prefixCls}-dropdown--transfer`]: props.transfer,\r\n        [`${prefixCls}-multiple`]: props.multiple && props.transfer,\r\n        ['ivue-auto-complete']: props.autoComplete,\r\n        ['ivue-auto-complete--notdata']:\r\n          selectOptions.value.length === 0 &&\r\n          props.autoComplete &&\r\n          !props.loading,\r\n        [props.transferClassName]: props.transferClassName,\r\n      };\r\n    });\r\n\r\n    // methods\r\n\r\n    // 点击外部\r\n    const handleClickOutside = (event: Event) => {\r\n      // 判断是否显示了菜单\r\n      if (data.visibleMenu) {\r\n        if (event.type === 'mousedown') {\r\n          event.preventDefault();\r\n\r\n          return;\r\n        }\r\n\r\n        // 是否将弹层放置于 body 内\r\n        if (props.transfer) {\r\n          const { $el } = dropdown.value;\r\n          if ($el === event.target || $el.contains(event.target)) {\r\n            return;\r\n          }\r\n        }\r\n\r\n        // 取消焦点\r\n        data.isFocused = false;\r\n\r\n        // 不是自动完成组件\r\n        if (!props.autoComplete) {\r\n          event.stopPropagation();\r\n        }\r\n\r\n        event.preventDefault();\r\n\r\n        // 点击后隐藏菜单\r\n        hideMenu();\r\n      }\r\n      // 关闭\r\n      else {\r\n        // 取消焦点\r\n        data.isFocused = false;\r\n      }\r\n    };\r\n\r\n    // 头部输入框获取焦点\r\n    const handleHeaderFocus = ({ type }) => {\r\n      if (inputDisabled.value) {\r\n        return;\r\n      }\r\n\r\n      data.isFocused = type === 'focus';\r\n    };\r\n\r\n    // 提取选项数据\r\n    const handleOption = (\r\n      option: OptionInstance,\r\n      values: string[],\r\n      isFocused: boolean\r\n    ) => {\r\n      // 如果选项节点没有子组件就直接返回选项节点\r\n      // 是否获取到焦点\r\n      option.data.isFocused = isFocused;\r\n\r\n      return {\r\n        option,\r\n      };\r\n    };\r\n\r\n    // 点击菜单\r\n    const handleToggleMenu = (event: Event, force?: boolean) => {\r\n      // 在Popover嵌套中\r\n      if (data.disableMenu && event) {\r\n        return false;\r\n      }\r\n\r\n      // 选择组件是否禁用\r\n      if (inputDisabled.value) {\r\n        return false;\r\n      }\r\n\r\n      // 设置菜单状态\r\n      data.visibleMenu =\r\n        typeof force !== 'undefined' ? force : !data.visibleMenu;\r\n\r\n      // 菜单收起\r\n      if (!data.visibleMenu) {\r\n        // 取消焦点\r\n        if (props.filterable) {\r\n          const input = proxy.$el.querySelector('input[type=\"text\"]');\r\n\r\n          input.blur();\r\n        }\r\n\r\n        // 更新下拉框\r\n        dropdown.value.update();\r\n      }\r\n    };\r\n\r\n    // 隐藏菜单\r\n    const hideMenu = () => {\r\n      handleToggleMenu(null, false);\r\n    };\r\n\r\n    // 选项菜单点击\r\n    const handleOptionClick = (option: OptionData, status?: string) => {\r\n      // 在Popover嵌套中\r\n      if (popover.data) {\r\n        data.disableMenu = true;\r\n      }\r\n\r\n      // 判断是否开启了多选\r\n      if (props.multiple) {\r\n        const selected = data.values.find(\r\n          ({ value }) => value === option.value\r\n        );\r\n\r\n        // 判断是搜索是否是一个方法\r\n        if (isSearchMethod.value) {\r\n          // 下一个搜索请求 || 搜索输入框输入数据\r\n          data.lastSearchQuery = data.lastSearchQuery || data.filterQuery;\r\n        } else {\r\n          // 下一个搜索请求\r\n          data.lastSearchQuery = '';\r\n        }\r\n\r\n        // 当前是否有对应的选项 && 不是创建新列表\r\n        if (selected) {\r\n          data.values = data.values.filter(\r\n            ({ value }) => value !== option.value\r\n          );\r\n        }\r\n        // 没有当前选项\r\n        else {\r\n          data.values = data.values.concat(option);\r\n        }\r\n\r\n        // 多选项没有\r\n        if (data.values.length === 0) {\r\n          // 重置焦点项\r\n          data.focusIndex = -1;\r\n        }\r\n\r\n        // 鼠标点击选项元素后放回焦点\r\n        data.isFocused = true;\r\n\r\n        // 多选删除了\r\n        if (status === 'delete-multiple') {\r\n          setTimeout(() => {\r\n            // 重置焦点项\r\n            data.focusIndex = -1;\r\n          });\r\n        }\r\n      }\r\n      // 单选\r\n      else {\r\n        // 点击后隐藏菜单\r\n        hideMenu();\r\n\r\n        // 过滤输入框数据\r\n        data.filterQuery = String(option.label).trim();\r\n\r\n        // 最终渲染的数据\r\n        data.values = [option];\r\n\r\n        // 搜索请求\r\n        data.lastSearchQuery = '';\r\n      }\r\n\r\n      // 是否支持搜索\r\n      if (props.filterable) {\r\n        const input = proxy.$el.querySelector('input[type=\"text\"]');\r\n\r\n        // 不是自动输入\r\n        if (!props.autoComplete) {\r\n          // 输入框获取焦点\r\n          nextTick(() => {\r\n            input.focus();\r\n          });\r\n        }\r\n      }\r\n\r\n      // 选择项目时触发\r\n      emit('on-select', option);\r\n\r\n      // 更新下拉框\r\n      dropdown.value.update();\r\n\r\n      nextTick(() => {\r\n        // 有展开菜单才设置焦点\r\n        if (data.visibleMenu) {\r\n          // 获取焦点项\r\n          data.focusIndex = setFocusIndex(option);\r\n        } else {\r\n          data.focusIndex = -1;\r\n        }\r\n      });\r\n\r\n      // 判断是否进行了过滤输入\r\n      if (data.filterQueryChange) {\r\n        // 等菜单动画执行完再清除\r\n        setTimeout(() => {\r\n          data.filterQueryChange = false;\r\n        }, 300);\r\n      }\r\n      // 没有开启过滤\r\n      else {\r\n        // 等菜单动画执行完再清除\r\n        nextTick(() => {\r\n          data.filterQueryChange = false;\r\n        });\r\n      }\r\n    };\r\n\r\n    // 设置选项焦点位置\r\n    const setFocusIndex = (option: OptionData) => {\r\n      return selectOptions.value.findIndex((item) => {\r\n        if (typeof option === 'object') {\r\n          // 判断是否有key 使用key匹配选项\r\n          return item.option.value === option.value;\r\n        } else {\r\n          return item.option.value === option;\r\n        }\r\n      });\r\n    };\r\n\r\n    // 清楚单项选择数据\r\n    const clearSingleSelect = () => {\r\n      // 非多选清除数据\r\n      if (!props.multiple) {\r\n        // 清除上一次搜索输入\r\n        data.lastSearchQuery = '';\r\n\r\n        emit('update:modelValue', '');\r\n      }\r\n\r\n      // API 点击清空按钮时触发\r\n      emit('on-clear');\r\n\r\n      // 隐藏菜单\r\n      hideMenu();\r\n\r\n      // 初始化数据\r\n      if (props.clearable) {\r\n        resetData();\r\n      }\r\n    };\r\n\r\n    // 重置数据\r\n    const resetData = () => {\r\n      // 焦点项\r\n      data.focusIndex = -1;\r\n      // 最终渲染的数据\r\n      data.values = [];\r\n      // 鼠标悬浮\r\n      data.hasMouseHover = false;\r\n\r\n      // 等菜单动画消失后再清除\r\n      // 搜索输入框输入数据\r\n      data.filterQuery = '';\r\n      // 是否开始输入框支持搜索\r\n      data.filterQueryChange = false;\r\n    };\r\n\r\n    // 初始化值\r\n    const getInitialValue = () => {\r\n      let initialValue = Array.isArray(props.modelValue)\r\n        ? props.modelValue\r\n        : [props.modelValue];\r\n\r\n      // 判断 值 === undefined 或者是 ''而且 参数不是无穷大\r\n      if (\r\n        typeof initialValue[0] === 'undefined' ||\r\n        (String(initialValue[0]).trim() === '' &&\r\n          !Number.isFinite(initialValue[0]))\r\n      ) {\r\n        initialValue = [];\r\n      }\r\n\r\n      // 开启搜索，没有多选\r\n      if (isSearchMethod.value && !props.multiple && props.modelValue) {\r\n        // 获取选项数据\r\n        const optionData = getOptionData(props.modelValue);\r\n\r\n        // 过滤输入框数据\r\n        data.filterQuery = optionData\r\n          ? optionData.label\r\n          : String(props.modelValue);\r\n      }\r\n\r\n      return initialValue.filter((item) => {\r\n        return Boolean(item) || item === 0;\r\n      });\r\n    };\r\n\r\n    // 获取选项的值\r\n    const getOptionData = (value: string | number) => {\r\n      const option = data.options.find((option) => {\r\n        return option.value === value || option.getLabel === value;\r\n      });\r\n\r\n      if (!option) {\r\n        return null;\r\n      }\r\n\r\n      //  不是自动完成\r\n      if (!props.autoComplete) {\r\n        // 有展开菜单 -> 获取焦点项\r\n        if (data.visibleMenu) {\r\n          data.focusIndex = setFocusIndex(option as OptionData);\r\n        }\r\n      }\r\n\r\n      return {\r\n        value: option.value,\r\n        label: option.getLabel,\r\n        disabled: option.isDisabled,\r\n      };\r\n    };\r\n\r\n    // 过滤输入框输入\r\n    const handleFilterQueryChange = (filterQuery: string) => {\r\n      // 是否显示下拉菜单\r\n      if (filterQuery.length > 0 && filterQuery !== data.filterQuery) {\r\n        if (props.autoComplete) {\r\n          // 输入框是否获取焦点\r\n          const isInputFocused =\r\n            document.hasFocus &&\r\n            document.hasFocus() &&\r\n            document.activeElement === proxy.$el.querySelector('input');\r\n\r\n          data.visibleMenu = isInputFocused;\r\n        } else {\r\n          data.visibleMenu = true;\r\n        }\r\n      }\r\n\r\n      // 输入框需要过滤的数据\r\n      data.filterQuery = filterQuery;\r\n\r\n      // 输入框过滤输入开始\r\n      data.filterQueryChange = true;\r\n    };\r\n\r\n    // 过滤选项组件\r\n    const validateOption = (options: OptionInstance) => {\r\n      // value\r\n      const value = options.value;\r\n      // label\r\n      const label = options.label || options.value;\r\n      // elm\r\n      const elm = options.$el || '';\r\n\r\n      // 文本内容 将数组元素计算为一个值（从左到右）\r\n      const textContent = elm.textContent;\r\n\r\n      // 把数据转换成字符串\r\n      const stringValues = props.filterByLabel\r\n        ? [label].toString()\r\n        : [value, label, textContent].toString();\r\n\r\n      // 把输入框数据转换成小写去除前后空格\r\n      const filterQuery = data.filterQuery.toLowerCase().trim();\r\n\r\n      // 是否开启搜索 && 没有多选 && 没有输入 && 没有上一个熟人\r\n      if (\r\n        props.filterable &&\r\n        !props.multiple &&\r\n        filterQuery === '' &&\r\n        !data.lastSearchQuery\r\n      ) {\r\n        return false;\r\n      }\r\n\r\n      // 判断 stringValues 数组中是否包含 filterQuery 中的值 includes()\r\n      return stringValues.toLowerCase().includes(filterQuery);\r\n    };\r\n\r\n    // 设置滚动条滚动\r\n    const focusScroll = (index: number) => {\r\n      if (index < 0 || props.autoComplete) {\r\n        return;\r\n      }\r\n\r\n      if (data.options[index]) {\r\n        // update scroll\r\n        const options = data.options[index];\r\n\r\n        // dropdown\r\n        const _dropdown = dropdown.value.$el;\r\n        // 底部距离\r\n        const bottomOverflowDistance =\r\n          options.$el.getBoundingClientRect().bottom -\r\n          _dropdown.getBoundingClientRect().bottom;\r\n\r\n        // 顶部距离\r\n        const topOverflowDistance =\r\n          options.$el.getBoundingClientRect().top -\r\n          _dropdown.getBoundingClientRect().top;\r\n\r\n        // 滚动到底部\r\n        if (bottomOverflowDistance > 0) {\r\n          _dropdown.scrollTop += bottomOverflowDistance;\r\n        }\r\n\r\n        // 滚动到顶部\r\n        if (topOverflowDistance < 0) {\r\n          _dropdown.scrollTop += topOverflowDistance;\r\n        }\r\n      }\r\n    };\r\n\r\n    // 选项销毁\r\n    const handleOptionDestroy = (index: number) => {\r\n      if (index > -1) {\r\n        data.options.splice(index, 1);\r\n      }\r\n    };\r\n\r\n    // 按键\r\n    const handleKeyDown = (event) => {\r\n      const key = event.key || event.code;\r\n      const keyCode = event.keyCode || event.which;\r\n\r\n      // Backspace\r\n      if (key === 'Backspace' || keyCode === 8) {\r\n        return; // so we don't call preventDefault\r\n      }\r\n\r\n      // 展开\r\n      if (data.visibleMenu) {\r\n        // Tab\r\n        if (key === 'Tab') {\r\n          hideMenu();\r\n        }\r\n\r\n        // Esc slide-up\r\n        if (key === 'Escape') {\r\n          hideMenu();\r\n        }\r\n\r\n        // next\r\n        if (key === 'ArrowUp') {\r\n          navigateOptions(-1);\r\n        }\r\n\r\n        // prev\r\n        if (key === 'ArrowDown') {\r\n          navigateOptions(1);\r\n        }\r\n\r\n        // enter\r\n        if (key === 'Enter') {\r\n          if (data.focusIndex === -1) {\r\n            return hideMenu();\r\n          }\r\n\r\n          const optionItem = selectOptions.value[data.focusIndex];\r\n\r\n          if (optionItem) {\r\n            // 获取选项数据\r\n            const option = getOptionData(optionItem.option.value);\r\n\r\n            handleOptionClick(option);\r\n          } else {\r\n            hideMenu();\r\n          }\r\n        }\r\n      } else {\r\n        const keysCanOpenMenu = ['ArrowDown', 'ArrowUp'];\r\n\r\n        // 如果焦点在当前选择框的话按 next or prev 可以打开选项菜单\r\n        if (keysCanOpenMenu.includes(event.key)) {\r\n          handleToggleMenu(null, true);\r\n        }\r\n      }\r\n    };\r\n\r\n    // 下一个选项\r\n    const navigateOptions = (direction: number) => {\r\n      const optionLength = selectOptions.value.length - 1;\r\n\r\n      let index = data.focusIndex + direction;\r\n\r\n      if (index < 0) {\r\n        index = optionLength;\r\n      }\r\n\r\n      // 重置下标\r\n      if (index > optionLength) {\r\n        index = 0;\r\n      }\r\n\r\n      // 寻找下标选项\r\n      if (direction > 0) {\r\n        let activeOption = -1;\r\n        for (let i = 0; i < selectOptions.value.length; i++) {\r\n          // 判断选项是否可选\r\n          const isActiveOption = !selectOptions.value[i].option.disabled;\r\n\r\n          // 设置激活的选项\r\n          if (isActiveOption) {\r\n            activeOption = i;\r\n          }\r\n\r\n          if (activeOption >= index) {\r\n            break;\r\n          }\r\n        }\r\n\r\n        index = activeOption;\r\n      } else {\r\n        let activeOption = selectOptions.value.length;\r\n\r\n        for (let i = optionLength; i >= 0; i--) {\r\n          // 判断选项是否可选\r\n          const isActiveOption = !selectOptions.value[i].option.disabled;\r\n\r\n          // 设置激活的选项\r\n          if (isActiveOption) {\r\n            activeOption = i;\r\n          }\r\n\r\n          if (activeOption <= index) {\r\n            break;\r\n          }\r\n        }\r\n\r\n        index = activeOption;\r\n      }\r\n\r\n      // 设置焦点选项\r\n      data.focusIndex = index;\r\n    };\r\n\r\n    // 检查值是否相等\r\n    const checkValuesNotEqual = (\r\n      value: OptionData,\r\n      publicValue: string[],\r\n      values: OptionData[]\r\n    ) => {\r\n      const strValue = JSON.stringify(value);\r\n      const strPublic = JSON.stringify(publicValue);\r\n      const strValues = JSON.stringify(\r\n        values.map((item) => {\r\n          return item.value;\r\n        })\r\n      );\r\n\r\n      return (\r\n        strValue !== strPublic ||\r\n        strValue !== strValues ||\r\n        strValues !== strPublic\r\n      );\r\n    };\r\n\r\n    // 检查当前值更新状态\r\n    const checkUpdateStatus = () => {\r\n      if (getInitialValue().length > 0 && selectOptions.value.length === 0) {\r\n        data.hasExpectedValue = true;\r\n      }\r\n    };\r\n\r\n    // 创建新列表\r\n    const handleCreateItem = (event: Event) => {\r\n      if (\r\n        props.allowCreate &&\r\n        data.filterQuery !== '' &&\r\n        showCreateItem.value\r\n      ) {\r\n        // 创建新列表点击确认阻止上层 key up Enter 事件触发\r\n        event.stopPropagation();\r\n\r\n        const filterQuery = data.filterQuery;\r\n\r\n        emit('on-create', filterQuery);\r\n\r\n        // 清除输入\r\n        data.filterQuery = '';\r\n\r\n        const option = {\r\n          value: filterQuery,\r\n          label: filterQuery,\r\n          disabled: false,\r\n        };\r\n\r\n        // 多选\r\n        if (props.multiple) {\r\n          handleOptionClick(option, 'create-item');\r\n        } else {\r\n          // 单选时如果不在 nextTick 里执行，无法赋值\r\n          nextTick(() => {\r\n            handleOptionClick(option);\r\n          });\r\n        }\r\n      }\r\n    };\r\n\r\n    // 设置过滤输入框输入\r\n    const setQuery = (query: string) => {\r\n      // 过滤输入框输入\r\n      data._filterQuery = query;\r\n\r\n      // 重置焦点项\r\n      data.focusIndex = -1;\r\n\r\n      if (query) {\r\n        // 过滤输入框输入\r\n        handleFilterQueryChange(query);\r\n\r\n        return;\r\n      }\r\n\r\n      // 输入框未空\r\n      if (query === '') {\r\n        props.searchMethod(query);\r\n      }\r\n\r\n      // 没有输入值\r\n      if (query === null) {\r\n        // 过滤输入框输入\r\n        handleFilterQueryChange('');\r\n\r\n        // 最终渲染的数据\r\n        data.values = [];\r\n\r\n        // 清空搜索关键词后，重新搜索相同的关键词没有触发远程搜索\r\n        data.lastSearchQuery = '';\r\n      }\r\n    };\r\n\r\n    // 获取焦点\r\n    const focus = () => {\r\n      if (props.filterable) {\r\n        (selectHead.value.$refs.input as HTMLElement).focus();\r\n\r\n        // 展开下拉框\r\n        handleToggleMenu(null, true);\r\n      }\r\n    };\r\n\r\n    // 初始化输入\r\n    data.options = [];\r\n\r\n    // onMounted\r\n    onMounted(() => {\r\n      // 设置初始值\r\n      if (!isSearchMethod.value && selectOptions.value.length > 0) {\r\n        data.values = getInitialValue()\r\n          .map((value) => {\r\n            if (typeof value === 'undefined' && !value) {\r\n              return null;\r\n            }\r\n            return getOptionData(value);\r\n          })\r\n          .filter(Boolean);\r\n      }\r\n\r\n      // 有搜索方法，设置默认标签\r\n      if (isSearchMethod.value && props.defaultLabel) {\r\n        // 单选\r\n        if (!props.multiple) {\r\n          data.filterQuery = props.defaultLabel;\r\n\r\n          data.hasExpectedValue = true;\r\n        }\r\n        // 多选\r\n        else if (\r\n          props.multiple &&\r\n          props.defaultLabel instanceof Array &&\r\n          props.modelValue.length === props.defaultLabel.length\r\n        ) {\r\n          const values = props.modelValue.map((item, index) => {\r\n            return {\r\n              value: item,\r\n              label: props.defaultLabel[index],\r\n            };\r\n          });\r\n\r\n          emit('on-set-default-options', values);\r\n\r\n          nextTick(() => {\r\n            data.values = values;\r\n          });\r\n        }\r\n      }\r\n    });\r\n\r\n    // provide\r\n    provide(\r\n      SelectContextKey,\r\n      reactive({\r\n        props,\r\n        selectWrapper,\r\n        reference,\r\n        dropVisible,\r\n        options: data.options,\r\n        values: data.values,\r\n        focusIndex: data.focusIndex,\r\n        handleOptionClick,\r\n        selectEmitter: data.selectEmitter,\r\n        onOptionDestroy: handleOptionDestroy,\r\n      })\r\n    );\r\n\r\n    // watch\r\n\r\n    // 监听设置的值\r\n    watch(\r\n      () => props.modelValue,\r\n      (value) => {\r\n        // 检查当前值更新状态\r\n        checkUpdateStatus();\r\n\r\n        if (value === '') {\r\n          data.values = [];\r\n\r\n          data.filterQueryChange = true;\r\n        }\r\n        // 当前值是否相等\r\n        else if (checkValuesNotEqual(value, selectValue.value, data.values)) {\r\n          // 修改适配\r\n          nextTick(() => {\r\n            if (data.options.length > 0) {\r\n              const values = getInitialValue()\r\n                .map((value) => {\r\n                  if (typeof value === 'undefined' && !value) {\r\n                    return null;\r\n                  }\r\n\r\n                  return getOptionData(value);\r\n                })\r\n                .filter(Boolean);\r\n\r\n              data.values = values;\r\n            }\r\n          });\r\n        }\r\n\r\n        // 在Popover嵌套中\r\n        if (popover.data) {\r\n          data.disableMenu = true;\r\n          popover.data.disableCloseUnderTransfer = true;\r\n\r\n          setTimeout(() => {\r\n            popover.handleCancel();\r\n          }, 300);\r\n\r\n          setTimeout(() => {\r\n            data.disableMenu = false;\r\n          }, 1000);\r\n        }\r\n\r\n        // 输入时是否触发表单的校验\r\n        if (props.validateEvent) {\r\n          formItem?.validate?.('change').catch((err) => debugWarn(err));\r\n        }\r\n      }\r\n    );\r\n\r\n    // 监听最终渲染的数据的变化\r\n    watch(\r\n      () => data.values,\r\n      (newValue, oldValue) => {\r\n        const _newValue = JSON.stringify(newValue);\r\n        const _oldValue = JSON.stringify(oldValue);\r\n\r\n        // 设置v-model的值\r\n        const vModelValue =\r\n          props.labelAndValue && selectValue.value\r\n            ? props.multiple\r\n              ? selectValue.value.map(({ value }) => value)\r\n              : selectValue.value.value\r\n            : selectValue.value;\r\n\r\n        // 输入框值\r\n        const emitInput =\r\n          _newValue !== _oldValue && vModelValue !== props.modelValue;\r\n\r\n        if (emitInput) {\r\n          // 更新 v-model\r\n          emit('update:modelValue', vModelValue);\r\n\r\n          emit('on-change', selectValue.value);\r\n        }\r\n      }\r\n    );\r\n\r\n    // 监听菜单显示隐藏\r\n    watch(\r\n      () => data.visibleMenu,\r\n      (state) => {\r\n        // API 下拉框展开或收起时触发\r\n        emit('on-menu-open', state);\r\n\r\n        // 显示时\r\n        if (state) {\r\n          if (props.filterable) {\r\n            // 触发选项组显示\r\n            data.selectEmitter.emit('ivueOptionGroupQueryChange');\r\n          }\r\n        }\r\n\r\n        // 恢复单选查询值\r\n        const [option] = data.values;\r\n\r\n        // 清除输入\r\n        if (\r\n          option &&\r\n          !data.isFocused &&\r\n          props.filterable &&\r\n          props.multiple &&\r\n          props.multipleFilterableClear\r\n        ) {\r\n          data.filterQuery = '';\r\n\r\n          // 等菜单动画执行完再清除\r\n          nextTick(() => {\r\n            data.filterQueryChange = false;\r\n          });\r\n        }\r\n\r\n        // 在Popover嵌套中\r\n        if (popover.data) {\r\n          popover.data.closeDelay = state ? 300 : 0;\r\n        }\r\n      }\r\n    );\r\n\r\n    // 焦点项\r\n    watch(\r\n      () => data.focusIndex,\r\n      (index) => {\r\n        focusScroll(index);\r\n      }\r\n    );\r\n\r\n    // 监听过滤输入框输入数据\r\n    watch(\r\n      () => data.filterQuery,\r\n      (filterQuery) => {\r\n        // 没有输入内容取消焦点\r\n        if (filterQuery === '') {\r\n          data.focusIndex = -1;\r\n        }\r\n\r\n        // API 搜索词改变时触发\r\n        emit('on-filter-query-change', filterQuery);\r\n\r\n        // 是否是有效查询\r\n        const hasValidQuery =\r\n          filterQuery !== '' &&\r\n          (filterQuery !== data.lastSearchQuery || !data.lastSearchQuery);\r\n\r\n        // 是否有搜索方法\r\n        const shouldCallRemoteMethod =\r\n          // 是否是有效查询\r\n          props.searchMethod && hasValidQuery;\r\n\r\n        // 是否有搜索方法\r\n        if (shouldCallRemoteMethod) {\r\n          data.focusIndex = -1;\r\n\r\n          props.searchMethod(filterQuery);\r\n        }\r\n\r\n        // 开启了远程搜索 && 有上一次输入 && 当前输入为空\r\n        if (data.lastSearchQuery && filterQuery === '' && props.searchMethod) {\r\n          data.focusIndex = -1;\r\n\r\n          props.searchMethod(filterQuery, 'reset');\r\n        }\r\n\r\n        // 正常搜索\r\n        if (filterQuery !== '' && isSearchMethod.value) {\r\n          data.lastSearchQuery = filterQuery;\r\n        }\r\n\r\n        // 输入为空隐藏下拉框 非多选\r\n        if (filterQuery === '' && !props.multiple && !props.searchMethod) {\r\n          // 没有获取焦点隐藏下拉框\r\n          if (!data.isFocused) {\r\n            data.visibleMenu = false;\r\n          }\r\n\r\n          // 等菜单动画执行完再清除\r\n          nextTick(() => {\r\n            data.filterQueryChange = false;\r\n          });\r\n        }\r\n\r\n        // 触发选项组显示;\r\n        data.selectEmitter.emit('ivueOptionGroupQueryChange');\r\n      }\r\n    );\r\n\r\n    // 监听焦点\r\n    watch(\r\n      () => data.isFocused,\r\n      (focused) => {\r\n        // 输入框获取焦点，移除焦点\r\n        const el = props.filterable\r\n          ? proxy.$el.querySelector('input[type=\"text\"]')\r\n          : proxy.$el;\r\n\r\n        el[focused ? 'focus' : 'blur']();\r\n\r\n        // 恢复单选查询值\r\n        const [option] = data.values;\r\n\r\n        // 判断是否有点击删除按钮在进行还原输入框内容\r\n        if (\r\n          option &&\r\n          props.filterable &&\r\n          !props.multiple &&\r\n          !focused &&\r\n          props.restoreInputOption\r\n        ) {\r\n          const label = String(option.label || option.value).trim();\r\n\r\n          if (label && data.filterQuery !== label) {\r\n            data.filterQuery = label;\r\n\r\n            nextTick(() => {\r\n              data.filterQueryChange = false;\r\n\r\n              // 获取焦点项\r\n              data.focusIndex = setFocusIndex(option);\r\n            });\r\n          }\r\n        }\r\n\r\n        // 没有开启还原输入框内容\r\n        if (\r\n          option &&\r\n          props.filterable &&\r\n          !props.multiple &&\r\n          !focused &&\r\n          !props.restoreInputOption\r\n        ) {\r\n          // 更新 v-model\r\n          emit('update:modelValue', data.filterQuery);\r\n        }\r\n      }\r\n    );\r\n\r\n    // 监听选项变化\r\n    watch(\r\n      () => selectOptions.value,\r\n      (value) => {\r\n        // 初始化值\r\n        if (data.hasExpectedValue && value.length > 0) {\r\n          data.values = getInitialValue()\r\n            .map((value) => {\r\n              if (typeof value === 'undefined' && !value) {\r\n                return null;\r\n              }\r\n\r\n              return getOptionData(value);\r\n            })\r\n            .filter(Boolean);\r\n\r\n          data.hasExpectedValue = false;\r\n        }\r\n\r\n        // 更新下拉框\r\n        dropdown.value && dropdown.value.update();\r\n      }\r\n    );\r\n\r\n    // 监听下拉框\r\n    watch(\r\n      () => dropVisible.value,\r\n      (value) => {\r\n        if (value) {\r\n          // 更新下拉框\r\n          dropdown.value.update();\r\n        } else {\r\n          // 销毁下拉框\r\n          dropdown.value.destroy();\r\n        }\r\n      }\r\n    );\r\n\r\n    // 在Popover嵌套中\r\n    if (popover.data) {\r\n      watch(\r\n        () => popover.visible,\r\n        (value) => {\r\n          if (value) {\r\n            data.disableMenu = false;\r\n          }\r\n        }\r\n      );\r\n    }\r\n\r\n    return {\r\n      prefixCls,\r\n\r\n      // dom\r\n      selectWrapper,\r\n      reference,\r\n      dropdown,\r\n      selectHead,\r\n\r\n      // inject\r\n      popover,\r\n\r\n      // data\r\n      data,\r\n      inputId,\r\n      inputDisabled,\r\n\r\n      // computed\r\n      classes,\r\n      selectionClasses,\r\n      createItemClasses,\r\n      selectTabindex,\r\n      currentSelectValue,\r\n      isSearchMethod,\r\n      showNotFindText,\r\n      dropVisible,\r\n      canClearable,\r\n      showCreateItem,\r\n      dropdownClasses,\r\n\r\n      // methods\r\n      handleClickOutside,\r\n      handleHeaderFocus,\r\n      handleOption,\r\n      handleToggleMenu,\r\n      handleFilterQueryChange,\r\n      handleKeyDown,\r\n      handleCreateItem,\r\n      setFocusIndex,\r\n      setQuery,\r\n      clearSingleSelect,\r\n      focus,\r\n      resetData,\r\n    };\r\n  },\r\n  components: {\r\n    SelectHead,\r\n    DropDown,\r\n    IvueOption,\r\n    IvueIcon,\r\n  },\r\n});\r\n</script>\r\n"],"names":["_withDirectives","_openBlock","_createElementBlock","_normalizeClass","_withKeys","_withModifiers","_createElementVNode","_createCommentVNode","_createVNode","_createSlots","_withCtx","_Transition","_createBlock","_toDisplayString","_vShow"],"mappings":";;;;AA0FqB,MAAA,UAAA,GAAA,CAAA,UAAA,CAAA,CAAA;4BAUE,OAAM,CAAA,CAAA;;;;;;;;;;oDAnG3B,eA0GM,CAAA,CAAA;AAxGE,EAAA,OAAAA,cAAA,EAAAC,SAAA,EAAS,EAAAC,kBAAA,CAAA,KAAA,EAAA;AAAA,IAAA,GAAA,EAAA,eAAA;AAAA,IAIf,KAAA,EAgDMC,cAAA,CAAA,IAAA,CAAA,OAAA,CAAA;AAAA,GAAA,EAAA;AAAA,uBA9CE,KAAE,EAAA;AAAA,MACP,GAAA,EAAA,WAAA;AAAA,MACA,KAAA,EAAIA,cAAA,CAAA,IAAA,CAAA,gBAAA,CAAA;AAAA,MACJ,UAAK,IAAA,CAAA,cAAA;AAAA,MACL,MAAK,EAAA,MAAA,sCAAE,iBAAgB,IAAA,IAAA,CAAA,iBAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,MACvB,OAAA,EAAA,MAAA,CAAU,qCAAE,iBAAkB,IAAA,IAAA,CAAA,iBAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,MAC9B,OAAA,EAAA,MAAA,CAAU,qCAAE,gBAAkB,IAAA,IAAA,CAAA,gBAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,MAC9B,YAAA,EAAO,OAAA,CAAA,CAAA,KAAA,MAAA,CAAA,KAAA,CAAA,MAAA,KAAA,IAAA,CAAA,IAAA,CAAA,aAAA,GAAA,IAAA,CAAA;AAAA,MAAoB,YAAA,EAAA,OAAA,CAAA,CAAA,KAAA,MAAA,CAAA,KAAA,CAAA,MAAA,KAAA,IAAA,CAAA,IAAA,CAAA,aAAA,GAAA,KAAA,CAAA;AAAA,MAAA,SAAA,EAAA;AAAA,iEAEC,KAAA,IAAA,CAAa,aAAA,IAAA,IAAA,CAAA,cAAA,GAAA,IAAA,GAAA,CAAA,MAAA,EAAA,SAAA,CAAA,CAAA,EAAA,CAAA,MAAA,CAAA,CAAA,CAAA;AAAA,QAAA,MAAA,CAAA,OAAA,MAAA,CAAA,CAAA,CAAA,GAAAC,SAAAC,aAAA,CAAA,CAAA,GAAA,IAAA,KAAA,IAAA,CACf,aAAa,IAAA,IAAA,CAAA,cAAA,GAAA,IAAA,GAAA,CAAA,MAAA,EAAA,SAAA,CAAA,CAAA,EAAA,CAAA,IAAA,CAAA,CAAA,CAAA;AAAA,QAAA,MAAA,CAAA,OAAA,MAAA,CAAA,CAAA,CAAA,GAAAD,SAAAC,aAAA,CAAA,CAAA,GAC1B,IAAa,KAAA,IAAA,CAAA,aAAA,IAAA,IAAA,CAAA,cAAA,GAAA,IAAA,GAAA,CAAA,MAAA,EAAA,SAAA,CAAA,CAAA,EAAA,CAAA,OAAA,CAAA,CAAA,CAAA;AAAA,QAAA,MAAA,CAAA,QAAA,MAAA,CAAA,EAAA,CAAA,GAAAD,SAAAC,aAAA,CAAA,CAAA,GAAA,IAAA,KAAA,IAAA,CAAA,aAAA,IAAA,IAAA,CAAA,cAAA,GAAA,IAAA,GAAA,CAAA,MAAA,EAAA,SAAA,CAAA,CAAA,EAAA,CAAA,KAAA,CAAA,CAAA,CAAA;AAAA;OAE3B;AAAA,KAAA,EAAA;AAAA,iBACc,IAAQ,CAAA,MAAA,EAAA,OAAA,EAAA,IAAA,MAAA;AAAA,QAAYC,mBAAA,OAAA,EAAA;AAAA,UAAG,IAAK,EAAA,QAAA;AAAA,UAAA,MAAA,IAAA,CAAA,IAAA;AAAA,UACxC,OAAA,IAAA,CAAA,kBAAA;AAAA,SACA,EA4Bc,IAAA,EAAA,CAAA,EAAA,UAAA,CAAA;AAAA,QA3BAC,mBAAA,gBAAA,CAAA;AAAA,QAAAC,YACH,sBAAM,EAAA;AAAA,UACd,IAAA,IAAA,CAAA,OAAA;AAAA,UACA,QAAQ,IAAE,CAAA,MAAA;AAAA,UACV,YAAW,IAAE,CAAA,UAAA;AAAA,UACb,UAAc,IAAA,CAAA,QAAA;AAAA,UACd,aAAiB,IAAA,CAAA,WAAA;AAAA,UACjB,cAAa,IAAA,CAAA,YAAA;AAAA,UACb,mBAAe,IAAA,CAAA,iBAAA;AAAA,UACf,aAAW,IAAA,CAAA,WAAA;AAAA,UACX,eAAQ,IAAK,CAAA,aAAA;AAAA,UACb,WAAgB,IAAA,CAAA,YAAA;AAAA,UAChB,MAAA,EAAiB,KAAA,IAAA,CAAA,MAAA;AAAA,UACjB,gBAAU,IAAA,CAAA,cAAA;AAAA,UACV,iBAAiB,IAAA,CAAA,eAAA;AAAA,UACjB,UAAa,IAAA,CAAA,aAAA;AAAA,UACb,eAAA,EAAgB,KAAA,IAAA,CAAA,WAAA;AAAA,UAChB,aAAU,IAAA,CAAA,WAAA;AAAA,UACV,gBAAsB,IAAA,CAAA,cAAA;AAAA,UACtB,WAAc,IAAA,CAAA,iBAAA;AAAA,UACd,uBAAa,IAAA,CAAA,uBAAA;AAAA,UACb,cAAA,EAAU,OAAgB,CAAA,CAAA,KAAA,MAAA,CAAA,KAAA,CAAA,MAAA,KAAA,IAAA,CAAA,IAAA,CAAA,SAAA,GAAA,IAAA,CAAA;AAAA,UAC3B,aAAA,EAAI,OAAY,CAAA,CAAA,KAAA,MAAA,CAAA,KAAA,CAAA,MAAA,KAAA,IAAA,CAAA,IAAA,CAAA,SAAA,GAAA,KAAA,CAAA;AAAA,UAAA,WAAA,IAAA,CAAA,gBAAA;AAAA,UAEQ,GAAA,EAAA,YAAA;AAAA,SAAA,EAAAC,WAAA,CAAA,EAAA,CAAA,EAAA,GAAA,EAAA;AAAA,UAAb,IAAA,CAAA,OAAA,MAAA,GAAA;AAAA,YACT,IAAA,EAAA,QAAA;AAAA,YAAA,EAAA,EAAAC,QAAA,MAAA;AAAA;;;;;OAKR,CAAA;AAAA,KACA,EAiDa,IAAA,UAAA,CAAA;AAAA,IAAAH,mBAjDI,4BAAiB,CAAA;AAAA,IAAAC,YAAlCG,UAiDa,EAAA;AAAA,MAAA,IAAA,EAAA,iBAAA;AAAA;;eA/CRD,QAAU,MAAA;AAAA,QAAAV,cACG,EAAAC,SAAA,EAAU,EAAAW,WAAA,CAAA,oBAAA,EAAA;AAAA,UACvB,UAAS,IAAE,CAAA,QAAA;AAAA,UACX,iBAAK,IAAA,CAAA,QAAA;AAAA,UAEN,WAAI,IAAA,CAAA,SAAA;AAAA,UACJ,KAAA,EAAIT,cAAU,CAAA,IAAA,CAAA,eAAA,CAAA;AAAA,UAAA,GAAA,EAAA,oBAAA;AAAA;;UAId,OAAA,EAAAO,QAAA,MAAA;AAAA,YAAAH,mBACQ,gEAAM,CAAA;AAAA,YAAAP,cAAA,CAAAM,mBAAA,IAAA,EAAA;AAAA,cAGZ,OAAAH,cAA0B,CAAA,CAAnB,CAAA,EAAA,IAAA,CAAA,oBAAA,CAAA,CAAA;AAAA,aAAA,EAAA;AAAA,iCAFC,IAAe,EAAA,IAAA,EAAAU,gBAAK,IAAe,CAAA,WAAW,GAAA,CAAA,CAAA;AAAA,aAAA,EAAA,CAAA,CAAA,EAAA;AAAA,cAIxD,CAAWC,OAAA,IAAA,CAAA,eAAA,IAAA,CAAA,IAAA,CAAA,WAAA,IAAA,KAAA,WAAA,CAAA;AAAA,aAAA,CAAA;AAAA,YACXP,mBAAA,gBAAA,CAAA;AAAA,YAAA,CAAA,IAAA,CAAA,cAAA,IAAA,IAAA,CAAA,cAAA,IAAA,CAAA,IAAA,CAAA,OAAA,IAAAN,SAAA,EACa,EAAAC,kBAAA,CAAA,IAAA,EAAA;AAAA,cAAA,GAAA,EAAA,CAAA;AAAA,cAGX,KAAa,EAAAC,cAAA,CAAA,CAAA,EAAA,IAAA,CAAA,SAAA,CAAA,cAAA,CAAA,CAAA;AAAA,aAOL,EAAA;AAAA,cANRI,mBAAA,4BAAA,CAAA;AAAA,cAAA,IAAA,CAAA,cAAA,IAAAN,SACQ,EAAA,cAAE,sBAAiB,EAAA;AAAA,gBACxB,GAAA,EAAA,CAAA;AAAA,gBACA,KAAA,gBAAgB,CAAA,IAAA,CAAc,iBAAA,CAAA;AAAA,gBAC9B,aAAa,IAAA,CAAA,WAAA;AAAA,gBACb,gBAAW,IAAA,CAAA,cAAA;AAAA,gBAAA,WAAA,EAAA,KAAA,IAAA,CAAA,WAAA;AAAA;;yBAIZS,QAA0C,MAAA;AAAA,kBAC1CH,mBAAW,4BAAA,CAAA;AAAA,kBACXD,kBAAA,CAA4C,KAAA,UAAA,EAAAO,eAAA,CAAA,KAAA,IAAA,CAAA,WAAA,GAAA,CAAA,CAAA;AAAA,kBAAAN,mBAAjC,gBAAqB,CAAA;AAAA,kBAAlBC,WAAA,CAAA,sBAAA,IAAA,EAAA;AAAA,oBAAA,OAAA,EAAAE,QAAA,MAAA;AAAA;;;;;;eAEhB,EAAA,CAAA,EAAA,CAAA,OAAA,EAAa,kEACbH,kBAAa,CAAA,MAAA,EAAA,IAAA,CAAA;AAAA,cAAAA,mBAAA,QAAA,CAAA;AAAA;aAEf,EAAA,CAAA,CAAA,IAAAA,kBAAA,CACA,QAMK,IAAA,CAAA;AAAA,YANsBA,mBAAA,sBAAA,CAAA;AAAA,YAAAP,cAAA,CAAAM,mBAAA,IAAA,EAAA;AAAA,cACzB,KAIM,EAAAH,cAAA,CAAA,CAAA,EAAA,IAAA,CAAA,SAAA,CAAA,QAAA,CAAA,CAAA;AAAA,aAAA,EAAA;AAAA;sCAHJ,CAA8C,EAAA,IAAA,CAAA,SAAA,CAAA,cAAA,CAAA,CAAA;AAAA,eAAA,EAAA;AAAA;kBAC9C,CAAA,yBAAA,IAAA,CAAA;AAAA,iBACA,CAAA;AAAA,gBAAAI,mBAAA,eAAA,CAAA;AAAA;iBAJQ,CAAA,CAAA;AAAA,aAAA,EAAA,CAAA,CAAA,EAAA;AAAA;;;;cAhCJ,CAAW,UAAA,EAAA,iBAAA,WAAA,EAAA,OAAA,CAAA,CAAA,GAAA;AAAA,UAAA,CAAA,uBAAA,CAAA;AAAA;;;;;;;;MA7DP,wBAAA;AAAA,MAAA,IAAA,CAAA,kBAAA;AAAA;;;;;;;;;"}