'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var vue = require('vue'); var lodashUnified = require('lodash-unified'); var core = require('@vueuse/core'); require('../../../utils/index.js'); require('../../../constants/index.js'); require('../../../hooks/index.js'); require('../../form/index.js'); var index = require('../../../hooks/use-locale/index.js'); var index$1 = require('../../../hooks/use-id/index.js'); var index$2 = require('../../../hooks/use-namespace/index.js'); var index$3 = require('../../../hooks/use-composition/index.js'); var index$4 = require('../../../hooks/use-focus-controller/index.js'); var useFormItem = require('../../form/src/hooks/use-form-item.js'); var index$5 = require('../../../hooks/use-empty-values/index.js'); var shared = require('@vue/shared'); var icon = require('../../../utils/vue/icon.js'); var useFormCommonProps = require('../../form/src/hooks/use-form-common-props.js'); var types = require('../../../utils/types.js'); var error = require('../../../utils/error.js'); var event = require('../../../constants/event.js'); var aria = require('../../../constants/aria.js'); var scroll = require('../../../utils/dom/scroll.js'); const MINIMUM_INPUT_WIDTH = 11; const useSelect = (props, emit) => { const { t } = index.useLocale(); const contentId = index$1.useId(); const nsSelect = index$2.useNamespace("select"); const nsInput = index$2.useNamespace("input"); const states = vue.reactive({ inputValue: "", options: /* @__PURE__ */ new Map(), cachedOptions: /* @__PURE__ */ new Map(), disabledOptions: /* @__PURE__ */ new Map(), optionValues: [], selected: [], selectionWidth: 0, calculatorWidth: 0, collapseItemWidth: 0, selectedLabel: "", hoveringIndex: -1, previousQuery: null, inputHovering: false, menuVisibleOnFocus: false, isBeforeHide: false }); const selectRef = vue.ref(null); const selectionRef = vue.ref(null); const tooltipRef = vue.ref(null); const tagTooltipRef = vue.ref(null); const inputRef = vue.ref(null); const calculatorRef = vue.ref(null); const prefixRef = vue.ref(null); const suffixRef = vue.ref(null); const menuRef = vue.ref(null); const tagMenuRef = vue.ref(null); const collapseItemRef = vue.ref(null); const scrollbarRef = vue.ref(null); const { isComposing, handleCompositionStart, handleCompositionUpdate, handleCompositionEnd } = index$3.useComposition({ afterComposition: (e) => onInput(e) }); const { wrapperRef, isFocused } = index$4.useFocusController(inputRef, { beforeFocus() { return selectDisabled.value; }, afterFocus() { if (props.automaticDropdown && !expanded.value) { expanded.value = true; states.menuVisibleOnFocus = true; } }, beforeBlur(event) { var _a, _b; return ((_a = tooltipRef.value) == null ? void 0 : _a.isFocusInsideContent(event)) || ((_b = tagTooltipRef.value) == null ? void 0 : _b.isFocusInsideContent(event)); }, afterBlur() { expanded.value = false; states.menuVisibleOnFocus = false; } }); const expanded = vue.ref(false); const hoverOption = vue.ref(); const { form, formItem } = useFormItem.useFormItem(); const { inputId } = useFormItem.useFormItemInputId(props, { formItemContext: formItem }); const { valueOnClear, isEmptyValue } = index$5.useEmptyValues(props); const selectDisabled = vue.computed(() => props.disabled || (form == null ? void 0 : form.disabled)); const hasModelValue = vue.computed(() => { return shared.isArray(props.modelValue) ? props.modelValue.length > 0 : !isEmptyValue(props.modelValue); }); const showClose = vue.computed(() => { return props.clearable && !selectDisabled.value && states.inputHovering && hasModelValue.value; }); const iconComponent = vue.computed(() => props.remote && props.filterable && !props.remoteShowSuffix ? "" : props.suffixIcon); const iconReverse = vue.computed(() => nsSelect.is("reverse", iconComponent.value && expanded.value)); const validateState = vue.computed(() => (formItem == null ? void 0 : formItem.validateState) || ""); const validateIcon = vue.computed(() => icon.ValidateComponentsMap[validateState.value]); const debounce = vue.computed(() => props.remote ? 300 : 0); const emptyText = vue.computed(() => { if (props.loading) { return props.loadingText || t("el.select.loading"); } else { if (props.remote && !states.inputValue && states.options.size === 0) return false; if (props.filterable && states.inputValue && states.options.size > 0 && filteredOptionsCount.value === 0) { return props.noMatchText || t("el.select.noMatch"); } if (states.options.size === 0) { return props.noDataText || t("el.select.noData"); } } return null; }); const filteredOptionsCount = vue.computed(() => optionsArray.value.filter((option) => option.visible).length); const optionsArray = vue.computed(() => { const list = Array.from(states.options.values()); const newList = []; states.optionValues.forEach((item) => { const index = list.findIndex((i) => i.value === item); if (index > -1) { newList.push(list[index]); } }); return newList.length >= list.length ? newList : list; }); const cachedOptionsArray = vue.computed(() => Array.from(states.cachedOptions.values())); const showNewOption = vue.computed(() => { const hasExistingOption = optionsArray.value.filter((option) => { return !option.created; }).some((option) => { return option.currentLabel === states.inputValue; }); return props.filterable && props.allowCreate && states.inputValue !== "" && !hasExistingOption; }); const updateOptions = () => { if (props.filterable && shared.isFunction(props.filterMethod)) return; if (props.filterable && props.remote && shared.isFunction(props.remoteMethod)) return; optionsArray.value.forEach((option) => { var _a; (_a = option.updateOption) == null ? void 0 : _a.call(option, states.inputValue); }); }; const selectSize = useFormCommonProps.useFormSize(); const collapseTagSize = vue.computed(() => ["small"].includes(selectSize.value) ? "small" : "default"); const dropdownMenuVisible = vue.computed({ get() { return expanded.value && emptyText.value !== false; }, set(val) { expanded.value = val; } }); const shouldShowPlaceholder = vue.computed(() => { if (props.multiple && !types.isUndefined(props.modelValue)) { return lodashUnified.castArray(props.modelValue).length === 0 && !states.inputValue; } const value = shared.isArray(props.modelValue) ? props.modelValue[0] : props.modelValue; return props.filterable || types.isUndefined(value) ? !states.inputValue : true; }); const currentPlaceholder = vue.computed(() => { var _a; const _placeholder = (_a = props.placeholder) != null ? _a : t("el.select.placeholder"); return props.multiple || !hasModelValue.value ? _placeholder : states.selectedLabel; }); const mouseEnterEventName = vue.computed(() => core.isIOS ? null : "mouseenter"); vue.watch(() => props.modelValue, (val, oldVal) => { if (props.multiple) { if (props.filterable && !props.reserveKeyword) { states.inputValue = ""; handleQueryChange(""); } } setSelected(); if (!lodashUnified.isEqual(val, oldVal) && props.validateEvent) { formItem == null ? void 0 : formItem.validate("change").catch((err) => error.debugWarn(err)); } }, { flush: "post", deep: true }); vue.watch(() => expanded.value, (val) => { if (val) { handleQueryChange(states.inputValue); } else { states.inputValue = ""; states.previousQuery = null; states.isBeforeHide = true; } emit("visible-change", val); }); vue.watch(() => states.options.entries(), () => { var _a; if (!core.isClient) return; const inputs = ((_a = selectRef.value) == null ? void 0 : _a.querySelectorAll("input")) || []; if (!props.filterable && !props.defaultFirstOption && !types.isUndefined(props.modelValue) || !Array.from(inputs).includes(document.activeElement)) { setSelected(); } if (props.defaultFirstOption && (props.filterable || props.remote) && filteredOptionsCount.value) { checkDefaultFirstOption(); } }, { flush: "post" }); vue.watch(() => states.hoveringIndex, (val) => { if (types.isNumber(val) && val > -1) { hoverOption.value = optionsArray.value[val] || {}; } else { hoverOption.value = {}; } optionsArray.value.forEach((option) => { option.hover = hoverOption.value === option; }); }); vue.watchEffect(() => { if (states.isBeforeHide) return; updateOptions(); }); const handleQueryChange = (val) => { if (states.previousQuery === val || isComposing.value) { return; } states.previousQuery = val; if (props.filterable && shared.isFunction(props.filterMethod)) { props.filterMethod(val); } else if (props.filterable && props.remote && shared.isFunction(props.remoteMethod)) { props.remoteMethod(val); } if (props.defaultFirstOption && (props.filterable || props.remote) && filteredOptionsCount.value) { vue.nextTick(checkDefaultFirstOption); } else { vue.nextTick(updateHoveringIndex); } }; const checkDefaultFirstOption = () => { const optionsInDropdown = optionsArray.value.filter((n) => n.visible && !n.disabled && !n.states.groupDisabled); const userCreatedOption = optionsInDropdown.find((n) => n.created); const firstOriginOption = optionsInDropdown[0]; states.hoveringIndex = getValueIndex(optionsArray.value, userCreatedOption || firstOriginOption); }; const setSelected = () => { if (!props.multiple) { const value = shared.isArray(props.modelValue) ? props.modelValue[0] : props.modelValue; const option = getOption(value); states.selectedLabel = option.currentLabel; states.selected = [option]; return; } else { states.selectedLabel = ""; } const result = []; if (!types.isUndefined(props.modelValue)) { lodashUnified.castArray(props.modelValue).forEach((value) => { result.push(getOption(value)); }); } states.selected = result; }; const getOption = (value) => { let option; const isObjectValue = shared.toRawType(value).toLowerCase() === "object"; const isNull = shared.toRawType(value).toLowerCase() === "null"; const isUndefined2 = shared.toRawType(value).toLowerCase() === "undefined"; for (let i = states.cachedOptions.size - 1; i >= 0; i--) { const cachedOption = cachedOptionsArray.value[i]; const isEqualValue = isObjectValue ? lodashUnified.get(cachedOption.value, props.valueKey) === lodashUnified.get(value, props.valueKey) : cachedOption.value === value; if (isEqualValue) { option = { value, currentLabel: cachedOption.currentLabel, get isDisabled() { return cachedOption.isDisabled; } }; break; } } if (option) return option; const label = isObjectValue ? value.label : !isNull && !isUndefined2 ? value : ""; const newOption = { value, currentLabel: label }; return newOption; }; const updateHoveringIndex = () => { states.hoveringIndex = optionsArray.value.findIndex((item) => states.selected.some((selected) => getValueKey(selected) === getValueKey(item))); }; const resetSelectionWidth = () => { states.selectionWidth = selectionRef.value.getBoundingClientRect().width; }; const resetCalculatorWidth = () => { states.calculatorWidth = calculatorRef.value.getBoundingClientRect().width; }; const resetCollapseItemWidth = () => { states.collapseItemWidth = collapseItemRef.value.getBoundingClientRect().width; }; const updateTooltip = () => { var _a, _b; (_b = (_a = tooltipRef.value) == null ? void 0 : _a.updatePopper) == null ? void 0 : _b.call(_a); }; const updateTagTooltip = () => { var _a, _b; (_b = (_a = tagTooltipRef.value) == null ? void 0 : _a.updatePopper) == null ? void 0 : _b.call(_a); }; const onInputChange = () => { if (states.inputValue.length > 0 && !expanded.value) { expanded.value = true; } handleQueryChange(states.inputValue); }; const onInput = (event) => { states.inputValue = event.target.value; if (props.remote) { debouncedOnInputChange(); } else { return onInputChange(); } }; const debouncedOnInputChange = lodashUnified.debounce(() => { onInputChange(); }, debounce.value); const emitChange = (val) => { if (!lodashUnified.isEqual(props.modelValue, val)) { emit(event.CHANGE_EVENT, val); } }; const getLastNotDisabledIndex = (value) => lodashUnified.findLastIndex(value, (it) => !states.disabledOptions.has(it)); const deletePrevTag = (e) => { if (!props.multiple) return; if (e.code === aria.EVENT_CODE.delete) return; if (e.target.value.length <= 0) { const value = lodashUnified.castArray(props.modelValue).slice(); const lastNotDisabledIndex = getLastNotDisabledIndex(value); if (lastNotDisabledIndex < 0) return; const removeTagValue = value[lastNotDisabledIndex]; value.splice(lastNotDisabledIndex, 1); emit(event.UPDATE_MODEL_EVENT, value); emitChange(value); emit("remove-tag", removeTagValue); } }; const deleteTag = (event$1, tag) => { const index = states.selected.indexOf(tag); if (index > -1 && !selectDisabled.value) { const value = lodashUnified.castArray(props.modelValue).slice(); value.splice(index, 1); emit(event.UPDATE_MODEL_EVENT, value); emitChange(value); emit("remove-tag", tag.value); } event$1.stopPropagation(); focus(); }; const deleteSelected = (event$1) => { event$1.stopPropagation(); const value = props.multiple ? [] : valueOnClear.value; if (props.multiple) { for (const item of states.selected) { if (item.isDisabled) value.push(item.value); } } emit(event.UPDATE_MODEL_EVENT, value); emitChange(value); states.hoveringIndex = -1; expanded.value = false; emit("clear"); focus(); }; const handleOptionSelect = (option) => { var _a; if (props.multiple) { const value = lodashUnified.castArray((_a = props.modelValue) != null ? _a : []).slice(); const optionIndex = getValueIndex(value, option.value); if (optionIndex > -1) { value.splice(optionIndex, 1); } else if (props.multipleLimit <= 0 || value.length < props.multipleLimit) { value.push(option.value); } emit(event.UPDATE_MODEL_EVENT, value); emitChange(value); if (option.created) { handleQueryChange(""); } if (props.filterable && !props.reserveKeyword) { states.inputValue = ""; } } else { emit(event.UPDATE_MODEL_EVENT, option.value); emitChange(option.value); expanded.value = false; } focus(); if (expanded.value) return; vue.nextTick(() => { scrollToOption(option); }); }; const getValueIndex = (arr = [], value) => { if (!shared.isObject(value)) return arr.indexOf(value); const valueKey = props.valueKey; let index = -1; arr.some((item, i) => { if (vue.toRaw(lodashUnified.get(item, valueKey)) === lodashUnified.get(value, valueKey)) { index = i; return true; } return false; }); return index; }; const scrollToOption = (option) => { var _a, _b, _c, _d, _e; const targetOption = shared.isArray(option) ? option[0] : option; let target = null; if (targetOption == null ? void 0 : targetOption.value) { const options = optionsArray.value.filter((item) => item.value === targetOption.value); if (options.length > 0) { target = options[0].$el; } } if (tooltipRef.value && target) { const menu = (_d = (_c = (_b = (_a = tooltipRef.value) == null ? void 0 : _a.popperRef) == null ? void 0 : _b.contentRef) == null ? void 0 : _c.querySelector) == null ? void 0 : _d.call(_c, `.${nsSelect.be("dropdown", "wrap")}`); if (menu) { scroll.scrollIntoView(menu, target); } } (_e = scrollbarRef.value) == null ? void 0 : _e.handleScroll(); }; const onOptionCreate = (vm) => { states.options.set(vm.value, vm); states.cachedOptions.set(vm.value, vm); vm.disabled && states.disabledOptions.set(vm.value, vm); }; const onOptionDestroy = (key, vm) => { if (states.options.get(key) === vm) { states.options.delete(key); } }; const popperRef = vue.computed(() => { var _a, _b; return (_b = (_a = tooltipRef.value) == null ? void 0 : _a.popperRef) == null ? void 0 : _b.contentRef; }); const handleMenuEnter = () => { states.isBeforeHide = false; vue.nextTick(() => scrollToOption(states.selected)); }; const focus = () => { var _a; (_a = inputRef.value) == null ? void 0 : _a.focus(); }; const blur = () => { var _a; (_a = inputRef.value) == null ? void 0 : _a.blur(); }; const handleClearClick = (event) => { deleteSelected(event); }; const handleClickOutside = () => { expanded.value = false; isFocused.value && blur(); }; const handleEsc = () => { if (states.inputValue.length > 0) { states.inputValue = ""; } else { expanded.value = false; } }; const toggleMenu = () => { if (selectDisabled.value) return; if (core.isIOS) states.inputHovering = true; if (states.menuVisibleOnFocus) { states.menuVisibleOnFocus = false; } else { expanded.value = !expanded.value; } }; const selectOption = () => { if (!expanded.value) { toggleMenu(); } else { if (optionsArray.value[states.hoveringIndex]) { handleOptionSelect(optionsArray.value[states.hoveringIndex]); } } }; const getValueKey = (item) => { return shared.isObject(item.value) ? lodashUnified.get(item.value, props.valueKey) : item.value; }; const optionsAllDisabled = vue.computed(() => optionsArray.value.filter((option) => option.visible).every((option) => option.disabled)); const showTagList = vue.computed(() => { if (!props.multiple) { return []; } return props.collapseTags ? states.selected.slice(0, props.maxCollapseTags) : states.selected; }); const collapseTagList = vue.computed(() => { if (!props.multiple) { return []; } return props.collapseTags ? states.selected.slice(props.maxCollapseTags) : []; }); const navigateOptions = (direction) => { if (!expanded.value) { expanded.value = true; return; } if (states.options.size === 0 || states.filteredOptionsCount === 0 || isComposing.value) return; if (!optionsAllDisabled.value) { if (direction === "next") { states.hoveringIndex++; if (states.hoveringIndex === states.options.size) { states.hoveringIndex = 0; } } else if (direction === "prev") { states.hoveringIndex--; if (states.hoveringIndex < 0) { states.hoveringIndex = states.options.size - 1; } } const option = optionsArray.value[states.hoveringIndex]; if (option.disabled === true || option.states.groupDisabled === true || !option.visible) { navigateOptions(direction); } vue.nextTick(() => scrollToOption(hoverOption.value)); } }; const getGapWidth = () => { if (!selectionRef.value) return 0; const style = window.getComputedStyle(selectionRef.value); return Number.parseFloat(style.gap || "6px"); }; const tagStyle = vue.computed(() => { const gapWidth = getGapWidth(); const maxWidth = collapseItemRef.value && props.maxCollapseTags === 1 ? states.selectionWidth - states.collapseItemWidth - gapWidth : states.selectionWidth; return { maxWidth: `${maxWidth}px` }; }); const collapseTagStyle = vue.computed(() => { return { maxWidth: `${states.selectionWidth}px` }; }); const inputStyle = vue.computed(() => ({ width: `${Math.max(states.calculatorWidth, MINIMUM_INPUT_WIDTH)}px` })); core.useResizeObserver(selectionRef, resetSelectionWidth); core.useResizeObserver(calculatorRef, resetCalculatorWidth); core.useResizeObserver(menuRef, updateTooltip); core.useResizeObserver(wrapperRef, updateTooltip); core.useResizeObserver(tagMenuRef, updateTagTooltip); core.useResizeObserver(collapseItemRef, resetCollapseItemWidth); vue.onMounted(() => { setSelected(); }); return { inputId, contentId, nsSelect, nsInput, states, isFocused, expanded, optionsArray, hoverOption, selectSize, filteredOptionsCount, resetCalculatorWidth, updateTooltip, updateTagTooltip, debouncedOnInputChange, onInput, deletePrevTag, deleteTag, deleteSelected, handleOptionSelect, scrollToOption, hasModelValue, shouldShowPlaceholder, currentPlaceholder, mouseEnterEventName, showClose, iconComponent, iconReverse, validateState, validateIcon, showNewOption, updateOptions, collapseTagSize, setSelected, selectDisabled, emptyText, handleCompositionStart, handleCompositionUpdate, handleCompositionEnd, onOptionCreate, onOptionDestroy, handleMenuEnter, focus, blur, handleClearClick, handleClickOutside, handleEsc, toggleMenu, selectOption, getValueKey, navigateOptions, dropdownMenuVisible, showTagList, collapseTagList, tagStyle, collapseTagStyle, inputStyle, popperRef, inputRef, tooltipRef, tagTooltipRef, calculatorRef, prefixRef, suffixRef, selectRef, wrapperRef, selectionRef, scrollbarRef, menuRef, tagMenuRef, collapseItemRef }; }; exports.useSelect = useSelect; //# sourceMappingURL=useSelect.js.map