UNPKG

element-plus

Version:

A Component Library for Vue 3

727 lines (722 loc) 24.3 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var vue = require('vue'); var shared = require('@vue/shared'); var lodashUnified = require('lodash-unified'); var core = require('@vueuse/core'); require('../../../constants/index.js'); require('../../../utils/index.js'); require('../../../hooks/index.js'); var index = require('../../../hooks/use-locale/index.js'); var index$1 = require('../../../hooks/use-namespace/index.js'); var index$2 = require('../../../hooks/use-deprecated/index.js'); var index$3 = require('../../../hooks/use-form-item/index.js'); var index$4 = require('../../../hooks/use-common-props/index.js'); var error = require('../../../utils/error.js'); var size = require('../../../utils/vue/size.js'); var event = require('../../../constants/event.js'); var scroll = require('../../../utils/dom/scroll.js'); var aria = require('../../../constants/aria.js'); var i18n = require('../../../utils/i18n.js'); function useSelectStates(props) { const { t } = index.useLocale(); return vue.reactive({ options: /* @__PURE__ */ new Map(), cachedOptions: /* @__PURE__ */ new Map(), createdLabel: null, createdSelected: false, selected: props.multiple ? [] : {}, inputLength: 20, inputWidth: 0, optionsCount: 0, filteredOptionsCount: 0, visible: false, softFocus: false, selectedLabel: "", hoverIndex: -1, query: "", previousQuery: null, inputHovering: false, cachedPlaceHolder: "", currentPlaceholder: t("el.select.placeholder"), menuVisibleOnFocus: false, isOnComposition: false, isSilentBlur: false, prefixWidth: 11, tagInMultiLine: false, mouseEnter: false }); } const useSelect = (props, states, ctx) => { const { t } = index.useLocale(); const ns = index$1.useNamespace("select"); index$2.useDeprecated({ from: "suffixTransition", replacement: "override style scheme", version: "2.3.0", scope: "props", ref: "https://element-plus.org/en-US/component/select.html#select-attributes" }, vue.computed(() => props.suffixTransition === false)); const reference = vue.ref(null); const input = vue.ref(null); const tooltipRef = vue.ref(null); const tags = vue.ref(null); const selectWrapper = vue.ref(null); const scrollbar = vue.ref(null); const hoverOption = vue.ref(-1); const queryChange = vue.shallowRef({ query: "" }); const groupQueryChange = vue.shallowRef(""); const { form, formItem } = index$3.useFormItem(); const readonly = vue.computed(() => !props.filterable || props.multiple || !states.visible); const selectDisabled = vue.computed(() => props.disabled || (form == null ? void 0 : form.disabled)); const showClose = vue.computed(() => { const hasValue = props.multiple ? Array.isArray(props.modelValue) && props.modelValue.length > 0 : props.modelValue !== void 0 && props.modelValue !== null && props.modelValue !== ""; const criteria = props.clearable && !selectDisabled.value && states.inputHovering && hasValue; return criteria; }); const iconComponent = vue.computed(() => props.remote && props.filterable && !props.remoteShowSuffix ? "" : props.suffixIcon); const iconReverse = vue.computed(() => ns.is("reverse", iconComponent.value && states.visible && props.suffixTransition)); 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.query === "" && states.options.size === 0) return false; if (props.filterable && states.query && states.options.size > 0 && states.filteredOptionsCount === 0) { return props.noMatchText || t("el.select.noMatch"); } if (states.options.size === 0) { return props.noDataText || t("el.select.noData"); } } return null; }); const optionsArray = vue.computed(() => Array.from(states.options.values())); 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.query; }); return props.filterable && props.allowCreate && states.query !== "" && !hasExistingOption; }); const selectSize = index$4.useSize(); const collapseTagSize = vue.computed(() => ["small"].includes(selectSize.value) ? "small" : "default"); const dropMenuVisible = vue.computed({ get() { return states.visible && emptyText.value !== false; }, set(val) { states.visible = val; } }); vue.watch([() => selectDisabled.value, () => selectSize.value, () => form == null ? void 0 : form.size], () => { vue.nextTick(() => { resetInputHeight(); }); }); vue.watch(() => props.placeholder, (val) => { states.cachedPlaceHolder = states.currentPlaceholder = val; }); vue.watch(() => props.modelValue, (val, oldVal) => { if (props.multiple) { resetInputHeight(); if (val && val.length > 0 || input.value && states.query !== "") { states.currentPlaceholder = ""; } else { states.currentPlaceholder = states.cachedPlaceHolder; } if (props.filterable && !props.reserveKeyword) { states.query = ""; handleQueryChange(states.query); } } setSelected(); if (props.filterable && !props.multiple) { states.inputLength = 20; } 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(() => states.visible, (val) => { var _a, _b, _c; if (!val) { if (props.filterable) { if (shared.isFunction(props.filterMethod)) { props.filterMethod(); } if (shared.isFunction(props.remoteMethod)) { props.remoteMethod(); } } input.value && input.value.blur(); states.query = ""; states.previousQuery = null; states.selectedLabel = ""; states.inputLength = 20; states.menuVisibleOnFocus = false; resetHoverIndex(); vue.nextTick(() => { if (input.value && input.value.value === "" && states.selected.length === 0) { states.currentPlaceholder = states.cachedPlaceHolder; } }); if (!props.multiple) { if (states.selected) { if (props.filterable && props.allowCreate && states.createdSelected && states.createdLabel) { states.selectedLabel = states.createdLabel; } else { states.selectedLabel = states.selected.currentLabel; } if (props.filterable) states.query = states.selectedLabel; } if (props.filterable) { states.currentPlaceholder = states.cachedPlaceHolder; } } } else { (_b = (_a = tooltipRef.value) == null ? void 0 : _a.updatePopper) == null ? void 0 : _b.call(_a); if (props.filterable) { states.filteredOptionsCount = states.optionsCount; states.query = props.remote ? "" : states.selectedLabel; if (props.multiple) { (_c = input.value) == null ? void 0 : _c.focus(); } else { if (states.selectedLabel) { states.currentPlaceholder = `${states.selectedLabel}`; states.selectedLabel = ""; } } handleQueryChange(states.query); if (!props.multiple && !props.remote) { queryChange.value.query = ""; vue.triggerRef(queryChange); vue.triggerRef(groupQueryChange); } } } ctx.emit("visible-change", val); }); vue.watch(() => states.options.entries(), () => { var _a, _b, _c; if (!core.isClient) return; (_b = (_a = tooltipRef.value) == null ? void 0 : _a.updatePopper) == null ? void 0 : _b.call(_a); if (props.multiple) { resetInputHeight(); } const inputs = ((_c = selectWrapper.value) == null ? void 0 : _c.querySelectorAll("input")) || []; if (!Array.from(inputs).includes(document.activeElement)) { setSelected(); } if (props.defaultFirstOption && (props.filterable || props.remote) && states.filteredOptionsCount) { checkDefaultFirstOption(); } }, { flush: "post" }); vue.watch(() => states.hoverIndex, (val) => { if (typeof val === "number" && val > -1) { hoverOption.value = optionsArray.value[val] || {}; } else { hoverOption.value = {}; } optionsArray.value.forEach((option) => { option.hover = hoverOption.value === option; }); }); const resetInputHeight = () => { if (props.collapseTags && !props.filterable) return; vue.nextTick(() => { var _a, _b; if (!reference.value) return; const input2 = reference.value.$el.querySelector("input"); const _tags = tags.value; const sizeInMap = size.getComponentSize(selectSize.value || (form == null ? void 0 : form.size)); input2.style.height = `${(states.selected.length === 0 ? sizeInMap : Math.max(_tags ? _tags.clientHeight + (_tags.clientHeight > sizeInMap ? 6 : 0) : 0, sizeInMap)) - 2}px`; states.tagInMultiLine = Number.parseFloat(input2.style.height) >= sizeInMap; if (states.visible && emptyText.value !== false) { (_b = (_a = tooltipRef.value) == null ? void 0 : _a.updatePopper) == null ? void 0 : _b.call(_a); } }); }; const handleQueryChange = async (val) => { if (states.previousQuery === val || states.isOnComposition) return; if (states.previousQuery === null && (typeof props.filterMethod === "function" || typeof props.remoteMethod === "function")) { states.previousQuery = val; return; } states.previousQuery = val; vue.nextTick(() => { var _a, _b; if (states.visible) (_b = (_a = tooltipRef.value) == null ? void 0 : _a.updatePopper) == null ? void 0 : _b.call(_a); }); states.hoverIndex = -1; if (props.multiple && props.filterable) { vue.nextTick(() => { const length = input.value.value.length * 15 + 20; states.inputLength = props.collapseTags ? Math.min(50, length) : length; managePlaceholder(); resetInputHeight(); }); } if (props.remote && typeof props.remoteMethod === "function") { states.hoverIndex = -1; props.remoteMethod(val); } else if (typeof props.filterMethod === "function") { props.filterMethod(val); vue.triggerRef(groupQueryChange); } else { states.filteredOptionsCount = states.optionsCount; queryChange.value.query = val; vue.triggerRef(queryChange); vue.triggerRef(groupQueryChange); } if (props.defaultFirstOption && (props.filterable || props.remote) && states.filteredOptionsCount) { await vue.nextTick(); checkDefaultFirstOption(); } }; const managePlaceholder = () => { if (states.currentPlaceholder !== "") { states.currentPlaceholder = input.value.value ? "" : states.cachedPlaceHolder; } }; 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.hoverIndex = getValueIndex(optionsArray.value, userCreatedOption || firstOriginOption); }; const setSelected = () => { var _a; if (!props.multiple) { const option = getOption(props.modelValue); if ((_a = option.props) == null ? void 0 : _a.created) { states.createdLabel = option.props.value; states.createdSelected = true; } else { states.createdSelected = false; } states.selectedLabel = option.currentLabel; states.selected = option; if (props.filterable) states.query = states.selectedLabel; return; } else { states.selectedLabel = ""; } const result = []; if (Array.isArray(props.modelValue)) { props.modelValue.forEach((value) => { result.push(getOption(value)); }); } states.selected = result; vue.nextTick(() => { resetInputHeight(); }); }; const getOption = (value) => { let option; const isObjectValue = shared.toRawType(value).toLowerCase() === "object"; const isNull = shared.toRawType(value).toLowerCase() === "null"; const isUndefined = 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, isDisabled: cachedOption.isDisabled }; break; } } if (option) return option; const label = isObjectValue ? value.label : !isNull && !isUndefined ? value : ""; const newOption = { value, currentLabel: label }; if (props.multiple) { ; newOption.hitState = false; } return newOption; }; const resetHoverIndex = () => { setTimeout(() => { const valueKey = props.valueKey; if (!props.multiple) { states.hoverIndex = optionsArray.value.findIndex((item) => { return getValueKey(item) === getValueKey(states.selected); }); } else { if (states.selected.length > 0) { states.hoverIndex = Math.min.apply(null, states.selected.map((selected) => { return optionsArray.value.findIndex((item) => { return lodashUnified.get(item, valueKey) === lodashUnified.get(selected, valueKey); }); })); } else { states.hoverIndex = -1; } } }, 300); }; const handleResize = () => { var _a, _b; resetInputWidth(); (_b = (_a = tooltipRef.value) == null ? void 0 : _a.updatePopper) == null ? void 0 : _b.call(_a); if (props.multiple && !props.filterable) resetInputHeight(); }; const resetInputWidth = () => { var _a; states.inputWidth = (_a = reference.value) == null ? void 0 : _a.$el.getBoundingClientRect().width; }; const onInputChange = () => { if (props.filterable && states.query !== states.selectedLabel) { states.query = states.selectedLabel; handleQueryChange(states.query); } }; const debouncedOnInputChange = lodashUnified.debounce(() => { onInputChange(); }, debounce.value); const debouncedQueryChange = lodashUnified.debounce((e) => { handleQueryChange(e.target.value); }, debounce.value); const emitChange = (val) => { if (!lodashUnified.isEqual(props.modelValue, val)) { ctx.emit(event.CHANGE_EVENT, val); } }; const deletePrevTag = (e) => { if (e.target.value.length <= 0 && !toggleLastOptionHitState()) { const value = props.modelValue.slice(); value.pop(); ctx.emit(event.UPDATE_MODEL_EVENT, value); emitChange(value); } if (e.target.value.length === 1 && props.modelValue.length === 0) { states.currentPlaceholder = states.cachedPlaceHolder; } }; const deleteTag = (event$1, tag) => { const index = states.selected.indexOf(tag); if (index > -1 && !selectDisabled.value) { const value = props.modelValue.slice(); value.splice(index, 1); ctx.emit(event.UPDATE_MODEL_EVENT, value); emitChange(value); ctx.emit("remove-tag", tag.value); } event$1.stopPropagation(); }; const deleteSelected = (event$1) => { event$1.stopPropagation(); const value = props.multiple ? [] : ""; if (typeof value !== "string") { for (const item of states.selected) { if (item.isDisabled) value.push(item.value); } } ctx.emit(event.UPDATE_MODEL_EVENT, value); emitChange(value); states.hoverIndex = -1; states.visible = false; ctx.emit("clear"); }; const handleOptionSelect = (option, byClick) => { var _a; if (props.multiple) { const value = (props.modelValue || []).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); } ctx.emit(event.UPDATE_MODEL_EVENT, value); emitChange(value); if (option.created) { states.query = ""; handleQueryChange(""); states.inputLength = 20; } if (props.filterable) (_a = input.value) == null ? void 0 : _a.focus(); } else { ctx.emit(event.UPDATE_MODEL_EVENT, option.value); emitChange(option.value); states.visible = false; } states.isSilentBlur = byClick; setSoftFocus(); if (states.visible) 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 setSoftFocus = () => { states.softFocus = true; const _input = input.value || reference.value; if (_input) { _input == null ? void 0 : _input.focus(); } }; const scrollToOption = (option) => { var _a, _b, _c, _d, _e; const targetOption = Array.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, `.${ns.be("dropdown", "wrap")}`); if (menu) { scroll.scrollIntoView(menu, target); } } (_e = scrollbar.value) == null ? void 0 : _e.handleScroll(); }; const onOptionCreate = (vm) => { states.optionsCount++; states.filteredOptionsCount++; states.options.set(vm.value, vm); states.cachedOptions.set(vm.value, vm); }; const onOptionDestroy = (key, vm) => { if (states.options.get(key) === vm) { states.optionsCount--; states.filteredOptionsCount--; states.options.delete(key); } }; const resetInputState = (e) => { if (e.code !== aria.EVENT_CODE.backspace) toggleLastOptionHitState(false); states.inputLength = input.value.value.length * 15 + 20; resetInputHeight(); }; const toggleLastOptionHitState = (hit) => { if (!Array.isArray(states.selected)) return; const option = states.selected[states.selected.length - 1]; if (!option) return; if (hit === true || hit === false) { option.hitState = hit; return hit; } option.hitState = !option.hitState; return option.hitState; }; const handleComposition = (event) => { const text = event.target.value; if (event.type === "compositionend") { states.isOnComposition = false; vue.nextTick(() => handleQueryChange(text)); } else { const lastCharacter = text[text.length - 1] || ""; states.isOnComposition = !i18n.isKorean(lastCharacter); } }; const handleMenuEnter = () => { vue.nextTick(() => scrollToOption(states.selected)); }; const handleFocus = (event) => { if (!states.softFocus) { if (props.automaticDropdown || props.filterable) { if (props.filterable && !states.visible) { states.menuVisibleOnFocus = true; } states.visible = true; } ctx.emit("focus", event); } else { states.softFocus = false; } }; const blur = () => { var _a; states.visible = false; (_a = reference.value) == null ? void 0 : _a.blur(); }; const handleBlur = (event) => { vue.nextTick(() => { if (states.isSilentBlur) { states.isSilentBlur = false; } else { ctx.emit("blur", event); } }); states.softFocus = false; }; const handleClearClick = (event) => { deleteSelected(event); }; const handleClose = () => { states.visible = false; }; const handleKeydownEscape = (event) => { if (states.visible) { event.preventDefault(); event.stopPropagation(); states.visible = false; } }; const toggleMenu = (e) => { var _a; if (e && !states.mouseEnter) { return; } if (!selectDisabled.value) { if (states.menuVisibleOnFocus) { states.menuVisibleOnFocus = false; } else { if (!tooltipRef.value || !tooltipRef.value.isFocusInsideContent()) { states.visible = !states.visible; } } if (states.visible) { ; (_a = input.value || reference.value) == null ? void 0 : _a.focus(); } } }; const selectOption = () => { if (!states.visible) { toggleMenu(); } else { if (optionsArray.value[states.hoverIndex]) { handleOptionSelect(optionsArray.value[states.hoverIndex], void 0); } } }; 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 navigateOptions = (direction) => { if (!states.visible) { states.visible = true; return; } if (states.options.size === 0 || states.filteredOptionsCount === 0) return; if (states.isOnComposition) return; if (!optionsAllDisabled.value) { if (direction === "next") { states.hoverIndex++; if (states.hoverIndex === states.options.size) { states.hoverIndex = 0; } } else if (direction === "prev") { states.hoverIndex--; if (states.hoverIndex < 0) { states.hoverIndex = states.options.size - 1; } } const option = optionsArray.value[states.hoverIndex]; if (option.disabled === true || option.states.groupDisabled === true || !option.visible) { navigateOptions(direction); } vue.nextTick(() => scrollToOption(hoverOption.value)); } }; const handleMouseEnter = () => { states.mouseEnter = true; }; const handleMouseLeave = () => { states.mouseEnter = false; }; return { optionsArray, selectSize, handleResize, debouncedOnInputChange, debouncedQueryChange, deletePrevTag, deleteTag, deleteSelected, handleOptionSelect, scrollToOption, readonly, resetInputHeight, showClose, iconComponent, iconReverse, showNewOption, collapseTagSize, setSelected, managePlaceholder, selectDisabled, emptyText, toggleLastOptionHitState, resetInputState, handleComposition, onOptionCreate, onOptionDestroy, handleMenuEnter, handleFocus, blur, handleBlur, handleClearClick, handleClose, handleKeydownEscape, toggleMenu, selectOption, getValueKey, navigateOptions, dropMenuVisible, queryChange, groupQueryChange, reference, input, tooltipRef, tags, selectWrapper, scrollbar, handleMouseEnter, handleMouseLeave }; }; exports.useSelect = useSelect; exports.useSelectStates = useSelectStates; //# sourceMappingURL=useSelect.js.map