UNPKG

@wfrog/vc

Version:

vue3 组件库 vc

1,586 lines (1,567 loc) 67.2 kB
import { shallowRef, ref, computed, inject, getCurrentInstance, toRaw, watch, defineComponent, withDirectives, createElementBlock, openBlock, withModifiers, normalizeClass, renderSlot, createElementVNode, toDisplayString, vShow, unref, toRefs, reactive, onBeforeUnmount, nextTick, normalizeStyle, createCommentVNode, onMounted, watchEffect, provide, isVNode, resolveComponent, resolveDirective, toHandlerKey, createVNode, withCtx, createBlock, Fragment, renderList, mergeProps, normalizeProps, createTextVNode, vModelText, resolveDynamicComponent } from 'vue'; import { u as useTooltipContentProps, E as Ee, a as ElTooltip } from './DUd8IaU9.mjs'; import { s as scrollbarEmits, E as ElScrollbar } from './CJQcPuNK.mjs'; import { t as tagProps, E as ElTag } from './Bm4zCpG6.mjs'; import { E as ElIcon } from './m2vp1CCf.mjs'; import { g as get, u as useLocale } from './-m34CPRn.mjs'; import { c as buildProps, t as throwError, s as isObject, u as useNamespace, e as debugWarn, i as isArray$1, a as isEmpty, g as isUndefined, v as isIOS, o as isClient, f as isNumber, j as isFunction, l as isPlainObject, w as useDebounceFn, k as isNil, h as isString, d as definePropType } from './E_WRn0OP.mjs'; import { b as isArray } from './Spa-JKB4.mjs'; import { i as isEqual } from './-EkpfdcW.mjs'; import { _ as _export_sfc, w as withInstall, a as withNoopInstall } from './D389hx_T.mjs'; import { u as useId } from './8rLUmOVR.mjs'; import { e as useResizeObserver, f as useMutationObserver } from './CEClY-_T.mjs'; import { u as useFormItem, a as useFormItemInputId, c as useFormSize } from './BOAz6rgm.mjs'; import { a as useEmptyValues, u as useEmptyValuesProps } from './C5hWsUfD.mjs'; import { a as useComposition, u as useFocusController } from './JCIyOUEY.mjs'; import { V as ValidateComponentsMap, i as iconPropType } from '../components/icon/icon2.mjs'; import { g as getEventCode, E as EVENT_CODE } from './BJS5Pdfp.mjs'; import { U as UPDATE_MODEL_EVENT, C as CHANGE_EVENT } from './Ct6q2FXg.mjs'; import { s as scrollIntoView } from './DBO1MWUI.mjs'; import { b as baseIteratee } from './DFKOIp_Z.mjs'; import { c as clamp } from './Dqz1zvKN.mjs'; import { ArrowDown, CircleClose } from '@element-plus/icons-vue'; import { u as useSizeProp } from './CS4VKsqy.mjs'; import { u as useAriaProps } from './C2LgraHx.mjs'; import { C as ClickOutside } from './HSv8BL8o.mjs'; import { f as flattedChildren } from './B_tU9Nax.mjs'; /** * The base implementation of `_.findIndex` and `_.findLastIndex` without * support for iteratee shorthands. * * @private * @param {Array} array The array to inspect. * @param {Function} predicate The function invoked per iteration. * @param {number} fromIndex The index to search from. * @param {boolean} [fromRight] Specify iterating from right to left. * @returns {number} Returns the index of the matched value, else `-1`. */ function baseFindIndex(array, predicate, fromIndex, fromRight) { array.length; var index = fromIndex + (1 ); while ((index-- )) { if (predicate(array[index], index, array)) { return index; } } return -1; } /** * Casts `value` as an array if it's not one. * * @static * @memberOf _ * @since 4.4.0 * @category Lang * @param {*} value The value to inspect. * @returns {Array} Returns the cast array. * @example * * _.castArray(1); * // => [1] * * _.castArray({ 'a': 1 }); * // => [{ 'a': 1 }] * * _.castArray('abc'); * // => ['abc'] * * _.castArray(null); * // => [null] * * _.castArray(undefined); * // => [undefined] * * _.castArray(); * // => [] * * var array = [1, 2, 3]; * console.log(_.castArray(array) === array); * // => true */ function castArray() { if (!arguments.length) { return []; } var value = arguments[0]; return isArray(value) ? value : [value]; } /** * This method is like `_.findIndex` except that it iterates over elements * of `collection` from right to left. * * @static * @memberOf _ * @since 2.0.0 * @category Array * @param {Array} array The array to inspect. * @param {Function} [predicate=_.identity] The function invoked per iteration. * @param {number} [fromIndex=array.length-1] The index to search from. * @returns {number} Returns the index of the found element, else `-1`. * @example * * var users = [ * { 'user': 'barney', 'active': true }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': false } * ]; * * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; }); * // => 2 * * // The `_.matches` iteratee shorthand. * _.findLastIndex(users, { 'user': 'barney', 'active': true }); * // => 0 * * // The `_.matchesProperty` iteratee shorthand. * _.findLastIndex(users, ['active', false]); * // => 2 * * // The `_.property` iteratee shorthand. * _.findLastIndex(users, 'active'); * // => 0 */ function findLastIndex(array, predicate, fromIndex) { var length = array == null ? 0 : array.length; if (!length) { return -1; } var index = length - 1; return baseFindIndex(array, baseIteratee(predicate), index); } const MINIMUM_INPUT_WIDTH = 11; const BORDER_HORIZONTAL_WIDTH = 2; function useCalcInputWidth() { const calculatorRef = shallowRef(); const calculatorWidth = ref(0); const inputStyle = computed(() => ({ minWidth: `${Math.max(calculatorWidth.value, MINIMUM_INPUT_WIDTH)}px` })); const resetCalculatorWidth = () => { var _a, _b; calculatorWidth.value = (_b = (_a = calculatorRef.value) == null ? void 0 : _a.getBoundingClientRect().width) != null ? _b : 0; }; useResizeObserver(calculatorRef, resetCalculatorWidth); return { calculatorRef, calculatorWidth, inputStyle }; } const defaultProps = { label: "label", value: "value", disabled: "disabled", options: "options" }; function useProps(props) { const aliasProps = computed(() => ({ ...defaultProps, ...props.props })); const getLabel = (option) => get(option, aliasProps.value.label); const getValue = (option) => get(option, aliasProps.value.value); const getDisabled = (option) => get(option, aliasProps.value.disabled); const getOptions = (option) => get(option, aliasProps.value.options); return { aliasProps, getLabel, getValue, getDisabled, getOptions }; } const selectGroupKey = Symbol("ElSelectGroup"); const selectKey = Symbol("ElSelect"); const COMPONENT_NAME$1 = "ElOption"; const optionProps = buildProps({ value: { type: [String, Number, Boolean, Object], required: true }, label: { type: [String, Number] }, created: Boolean, disabled: Boolean }); const escapeStringRegexp = (string = "") => string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d"); function useOption(props, states) { const select = inject(selectKey); if (!select) { throwError(COMPONENT_NAME$1, "usage: <el-select><el-option /></el-select/>"); } const selectGroup = inject(selectGroupKey, { disabled: false }); const itemSelected = computed(() => { return contains(castArray(select.props.modelValue), props.value); }); const limitReached = computed(() => { var _a; if (select.props.multiple) { const modelValue = castArray((_a = select.props.modelValue) != null ? _a : []); return !itemSelected.value && modelValue.length >= select.props.multipleLimit && select.props.multipleLimit > 0; } else { return false; } }); const currentLabel = computed(() => { var _a; return (_a = props.label) != null ? _a : isObject(props.value) ? "" : props.value; }); const currentValue = computed(() => { return props.value || props.label || ""; }); const isDisabled = computed(() => { return props.disabled || states.groupDisabled || limitReached.value; }); const instance = getCurrentInstance(); const contains = (arr = [], target) => { if (!isObject(props.value)) { return arr && arr.includes(target); } else { const valueKey = select.props.valueKey; return arr && arr.some((item) => { return toRaw(get(item, valueKey)) === get(target, valueKey); }); } }; const hoverItem = () => { if (!props.disabled && !selectGroup.disabled) { select.states.hoveringIndex = select.optionsArray.indexOf(instance.proxy); } }; const updateOption = (query) => { const regexp = new RegExp(escapeStringRegexp(query), "i"); states.visible = regexp.test(String(currentLabel.value)) || props.created; }; watch(() => currentLabel.value, () => { if (!props.created && !select.props.remote) select.setSelected(); }); watch(() => props.value, (val, oldVal) => { const { remote, valueKey } = select.props; const shouldUpdate = remote ? val !== oldVal : !isEqual(val, oldVal); if (shouldUpdate) { select.onOptionDestroy(oldVal, instance.proxy); select.onOptionCreate(instance.proxy); } if (!props.created && !remote) { if (valueKey && isObject(val) && isObject(oldVal) && val[valueKey] === oldVal[valueKey]) { return; } select.setSelected(); } }); watch(() => selectGroup.disabled, () => { states.groupDisabled = selectGroup.disabled; }, { immediate: true }); return { select, currentLabel, currentValue, itemSelected, isDisabled, hoverItem, updateOption }; } const _sfc_main$3 = defineComponent({ name: COMPONENT_NAME$1, componentName: COMPONENT_NAME$1, props: optionProps, setup(props) { const ns = useNamespace("select"); const id = useId(); const containerKls = computed(() => [ ns.be("dropdown", "item"), ns.is("disabled", unref(isDisabled)), ns.is("selected", unref(itemSelected)), ns.is("hovering", unref(hover)) ]); const states = reactive({ index: -1, groupDisabled: false, visible: true, hover: false }); const { currentLabel, itemSelected, isDisabled, select, hoverItem, updateOption } = useOption(props, states); const { visible, hover } = toRefs(states); const vm = getCurrentInstance().proxy; select.onOptionCreate(vm); onBeforeUnmount(() => { const key = vm.value; nextTick(() => { const { selected: selectedOptions } = select.states; const doesSelected = selectedOptions.some((item) => { return item.value === vm.value; }); if (select.states.cachedOptions.get(key) === vm && !doesSelected) { select.states.cachedOptions.delete(key); } }); select.onOptionDestroy(key, vm); }); function selectOptionClick() { if (!isDisabled.value) { select.handleOptionSelect(vm); } } return { ns, id, containerKls, currentLabel, itemSelected, isDisabled, select, visible, hover, states, hoverItem, updateOption, selectOptionClick }; } }); function _sfc_render$3(_ctx, _cache) { return withDirectives((openBlock(), createElementBlock("li", { id: _ctx.id, class: normalizeClass(_ctx.containerKls), role: "option", "aria-disabled": _ctx.isDisabled || void 0, "aria-selected": _ctx.itemSelected, onMousemove: _ctx.hoverItem, onClick: withModifiers(_ctx.selectOptionClick, ["stop"]) }, [ renderSlot(_ctx.$slots, "default", {}, () => [ createElementVNode("span", null, toDisplayString(_ctx.currentLabel), 1) ]) ], 42, ["id", "aria-disabled", "aria-selected", "onMousemove", "onClick"])), [ [vShow, _ctx.visible] ]); } var Option = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["render", _sfc_render$3], ["__file", "option.vue"]]); const _sfc_main$2 = defineComponent({ name: "ElSelectDropdown", componentName: "ElSelectDropdown", setup() { const select = inject(selectKey); const ns = useNamespace("select"); const popperClass = computed(() => select.props.popperClass); const isMultiple = computed(() => select.props.multiple); const isFitInputWidth = computed(() => select.props.fitInputWidth); const minWidth = ref(""); function updateMinWidth() { var _a; const offsetWidth = (_a = select.selectRef) == null ? void 0 : _a.offsetWidth; if (offsetWidth) { minWidth.value = `${offsetWidth - BORDER_HORIZONTAL_WIDTH}px`; } else { minWidth.value = ""; } } onMounted(() => { updateMinWidth(); useResizeObserver(select.selectRef, updateMinWidth); }); return { ns, minWidth, popperClass, isMultiple, isFitInputWidth }; } }); function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) { return openBlock(), createElementBlock("div", { class: normalizeClass([_ctx.ns.b("dropdown"), _ctx.ns.is("multiple", _ctx.isMultiple), _ctx.popperClass]), style: normalizeStyle({ [_ctx.isFitInputWidth ? "width" : "minWidth"]: _ctx.minWidth }) }, [ _ctx.$slots.header ? (openBlock(), createElementBlock("div", { key: 0, class: normalizeClass(_ctx.ns.be("dropdown", "header")) }, [ renderSlot(_ctx.$slots, "header") ], 2)) : createCommentVNode("v-if", true), renderSlot(_ctx.$slots, "default"), _ctx.$slots.footer ? (openBlock(), createElementBlock("div", { key: 1, class: normalizeClass(_ctx.ns.be("dropdown", "footer")) }, [ renderSlot(_ctx.$slots, "footer") ], 2)) : createCommentVNode("v-if", true) ], 6); } var ElSelectMenu = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["render", _sfc_render$2], ["__file", "select-dropdown.vue"]]); const useSelect = (props, emit) => { const { t } = useLocale(); const contentId = useId(); const nsSelect = useNamespace("select"); const nsInput = useNamespace("input"); const states = reactive({ inputValue: "", options: /* @__PURE__ */ new Map(), cachedOptions: /* @__PURE__ */ new Map(), optionValues: [], selected: [], selectionWidth: 0, collapseItemWidth: 0, selectedLabel: "", hoveringIndex: -1, previousQuery: null, inputHovering: false, menuVisibleOnFocus: false, isBeforeHide: false }); const selectRef = ref(); const selectionRef = ref(); const tooltipRef = ref(); const tagTooltipRef = ref(); const inputRef = ref(); const prefixRef = ref(); const suffixRef = ref(); const menuRef = ref(); const tagMenuRef = ref(); const collapseItemRef = ref(); const scrollbarRef = ref(); const expanded = ref(false); const hoverOption = ref(); const debouncing = ref(false); const { form, formItem } = useFormItem(); const { inputId } = useFormItemInputId(props, { formItemContext: formItem }); const { valueOnClear, isEmptyValue } = useEmptyValues(props); const { isComposing, handleCompositionStart, handleCompositionUpdate, handleCompositionEnd } = useComposition({ afterComposition: (e) => onInput(e) }); const selectDisabled = computed(() => props.disabled || !!(form == null ? void 0 : form.disabled)); const { wrapperRef, isFocused, handleBlur } = useFocusController(inputRef, { disabled: selectDisabled, 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() { var _a; expanded.value = false; states.menuVisibleOnFocus = false; if (props.validateEvent) { (_a = formItem == null ? void 0 : formItem.validate) == null ? void 0 : _a.call(formItem, "blur").catch((err) => debugWarn(err)); } } }); const hasModelValue = computed(() => { return isArray$1(props.modelValue) ? props.modelValue.length > 0 : !isEmptyValue(props.modelValue); }); const needStatusIcon = computed(() => { var _a; return (_a = form == null ? void 0 : form.statusIcon) != null ? _a : false; }); const showClearBtn = computed(() => { return props.clearable && !selectDisabled.value && hasModelValue.value && (isFocused.value || states.inputHovering); }); const iconComponent = computed(() => props.remote && props.filterable && !props.remoteShowSuffix ? "" : props.suffixIcon); const iconReverse = computed(() => nsSelect.is("reverse", !!(iconComponent.value && expanded.value))); const validateState = computed(() => (formItem == null ? void 0 : formItem.validateState) || ""); const validateIcon = computed(() => validateState.value && ValidateComponentsMap[validateState.value]); const debounce = computed(() => props.remote ? props.debounce : 0); const isRemoteSearchEmpty = computed(() => props.remote && !states.inputValue && states.options.size === 0); const emptyText = computed(() => { if (props.loading) { return props.loadingText || t("el.select.loading"); } else { 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 = computed(() => optionsArray.value.filter((option) => option.visible).length); const optionsArray = 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 = computed(() => Array.from(states.cachedOptions.values())); const showNewOption = 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 && isFunction(props.filterMethod)) return; if (props.filterable && props.remote && isFunction(props.remoteMethod)) return; optionsArray.value.forEach((option) => { var _a; (_a = option.updateOption) == null ? void 0 : _a.call(option, states.inputValue); }); }; const selectSize = useFormSize(); const collapseTagSize = computed(() => ["small"].includes(selectSize.value) ? "small" : "default"); const dropdownMenuVisible = computed({ get() { return expanded.value && (props.loading || !isRemoteSearchEmpty.value) && (!debouncing.value || !isEmpty(states.previousQuery)); }, set(val) { expanded.value = val; } }); const shouldShowPlaceholder = computed(() => { if (props.multiple && !isUndefined(props.modelValue)) { return castArray(props.modelValue).length === 0 && !states.inputValue; } const value = isArray$1(props.modelValue) ? props.modelValue[0] : props.modelValue; return props.filterable || isUndefined(value) ? !states.inputValue : true; }); const currentPlaceholder = computed(() => { var _a; const _placeholder = (_a = props.placeholder) != null ? _a : t("el.select.placeholder"); return props.multiple || !hasModelValue.value ? _placeholder : states.selectedLabel; }); const mouseEnterEventName = computed(() => isIOS ? null : "mouseenter"); watch(() => props.modelValue, (val, oldVal) => { if (props.multiple) { if (props.filterable && !props.reserveKeyword) { states.inputValue = ""; handleQueryChange(""); } } setSelected(); if (!isEqual(val, oldVal) && props.validateEvent) { formItem == null ? void 0 : formItem.validate("change").catch((err) => debugWarn(err)); } }, { flush: "post", deep: true }); watch(() => expanded.value, (val) => { if (val) { handleQueryChange(states.inputValue); } else { states.inputValue = ""; states.previousQuery = null; states.isBeforeHide = true; } emit("visible-change", val); }); watch(() => states.options.entries(), () => { if (!isClient) return; setSelected(); if (props.defaultFirstOption && (props.filterable || props.remote) && filteredOptionsCount.value) { checkDefaultFirstOption(); } }, { flush: "post" }); watch([() => states.hoveringIndex, optionsArray], ([val]) => { if (isNumber(val) && val > -1) { hoverOption.value = optionsArray.value[val] || {}; } else { hoverOption.value = {}; } optionsArray.value.forEach((option) => { option.hover = hoverOption.value === option; }); }); watchEffect(() => { if (states.isBeforeHide) return; updateOptions(); }); const handleQueryChange = (val) => { if (states.previousQuery === val || isComposing.value) { return; } states.previousQuery = val; if (props.filterable && isFunction(props.filterMethod)) { props.filterMethod(val); } else if (props.filterable && props.remote && isFunction(props.remoteMethod)) { props.remoteMethod(val); } if (props.defaultFirstOption && (props.filterable || props.remote) && filteredOptionsCount.value) { nextTick(checkDefaultFirstOption); } else { 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]; const valueList = optionsArray.value.map((item) => item.value); states.hoveringIndex = getValueIndex(valueList, userCreatedOption || firstOriginOption); }; const setSelected = () => { if (!props.multiple) { const value = isArray$1(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 (!isUndefined(props.modelValue)) { castArray(props.modelValue).forEach((value) => { result.push(getOption(value)); }); } states.selected = result; }; const getOption = (value) => { let option; const isObjectValue = isPlainObject(value); for (let i = states.cachedOptions.size - 1; i >= 0; i--) { const cachedOption = cachedOptionsArray.value[i]; const isEqualValue = isObjectValue ? get(cachedOption.value, props.valueKey) === get(value, props.valueKey) : cachedOption.value === value; if (isEqualValue) { option = { index: optionsArray.value.filter((opt) => !opt.created).indexOf(cachedOption), value, currentLabel: cachedOption.currentLabel, get isDisabled() { return cachedOption.isDisabled; } }; break; } } if (option) return option; const label = isObjectValue ? value.label : value != null ? value : ""; const newOption = { index: -1, 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 = Number.parseFloat(window.getComputedStyle(selectionRef.value).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) { debouncing.value = true; debouncedOnInputChange(); } else { return onInputChange(); } }; const debouncedOnInputChange = useDebounceFn(() => { onInputChange(); debouncing.value = false; }, debounce); const emitChange = (val) => { if (!isEqual(props.modelValue, val)) { emit(CHANGE_EVENT, val); } }; const getLastNotDisabledIndex = (value) => findLastIndex(value, (it) => { const option = states.cachedOptions.get(it); return !(option == null ? void 0 : option.disabled) && !(option == null ? void 0 : option.states.groupDisabled); }); const deletePrevTag = (e) => { const code = getEventCode(e); if (!props.multiple) return; if (code === EVENT_CODE.delete) return; if (e.target.value.length <= 0) { const value = castArray(props.modelValue).slice(); const lastNotDisabledIndex = getLastNotDisabledIndex(value); if (lastNotDisabledIndex < 0) return; const removeTagValue = value[lastNotDisabledIndex]; value.splice(lastNotDisabledIndex, 1); emit(UPDATE_MODEL_EVENT, value); emitChange(value); emit("remove-tag", removeTagValue); } }; const deleteTag = (event, tag) => { const index = states.selected.indexOf(tag); if (index > -1 && !selectDisabled.value) { const value = castArray(props.modelValue).slice(); value.splice(index, 1); emit(UPDATE_MODEL_EVENT, value); emitChange(value); emit("remove-tag", tag.value); } event.stopPropagation(); focus(); }; const deleteSelected = (event) => { event.stopPropagation(); const value = props.multiple ? [] : valueOnClear.value; if (props.multiple) { for (const item of states.selected) { if (item.isDisabled) value.push(item.value); } } emit(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 = castArray((_a = props.modelValue) != null ? _a : []).slice(); const optionIndex = getValueIndex(value, option); if (optionIndex > -1) { value.splice(optionIndex, 1); } else if (props.multipleLimit <= 0 || value.length < props.multipleLimit) { value.push(option.value); } emit(UPDATE_MODEL_EVENT, value); emitChange(value); if (option.created) { handleQueryChange(""); } if (props.filterable && !props.reserveKeyword) { states.inputValue = ""; } } else { !isEqual(props.modelValue, option.value) && emit(UPDATE_MODEL_EVENT, option.value); emitChange(option.value); expanded.value = false; } focus(); if (expanded.value) return; nextTick(() => { scrollToOption(option); }); }; const getValueIndex = (arr, option) => { if (isUndefined(option)) return -1; if (!isObject(option.value)) return arr.indexOf(option.value); return arr.findIndex((item) => { return isEqual(get(item, props.valueKey), getValueKey(option)); }); }; const scrollToOption = (option) => { var _a, _b, _c, _d, _e; const targetOption = isArray$1(option) ? option[0] : option; let target = null; if (!isNil(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) { 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); }; const onOptionDestroy = (key, vm) => { if (states.options.get(key) === vm) { states.options.delete(key); } }; const popperRef = computed(() => { var _a, _b; return (_b = (_a = tooltipRef.value) == null ? void 0 : _a.popperRef) == null ? void 0 : _b.contentRef; }); const handleMenuEnter = () => { states.isBeforeHide = false; nextTick(() => { var _a; (_a = scrollbarRef.value) == null ? void 0 : _a.update(); scrollToOption(states.selected); }); }; const focus = () => { var _a; (_a = inputRef.value) == null ? void 0 : _a.focus(); }; const blur = () => { var _a; if (expanded.value) { expanded.value = false; nextTick(() => { var _a2; return (_a2 = inputRef.value) == null ? void 0 : _a2.blur(); }); return; } (_a = inputRef.value) == null ? void 0 : _a.blur(); }; const handleClearClick = (event) => { deleteSelected(event); }; const handleClickOutside = (event) => { expanded.value = false; if (isFocused.value) { const _event = new FocusEvent("blur", event); nextTick(() => handleBlur(_event)); } }; const handleEsc = () => { if (states.inputValue.length > 0) { states.inputValue = ""; } else { expanded.value = false; } }; const toggleMenu = () => { if (selectDisabled.value) return; if (isIOS) states.inputHovering = true; if (states.menuVisibleOnFocus) { states.menuVisibleOnFocus = false; } else { expanded.value = !expanded.value; } }; const selectOption = () => { if (!expanded.value) { toggleMenu(); } else { const option = optionsArray.value[states.hoveringIndex]; if (option && !option.isDisabled) { handleOptionSelect(option); } } }; const getValueKey = (item) => { return isObject(item.value) ? get(item.value, props.valueKey) : item.value; }; const optionsAllDisabled = computed(() => optionsArray.value.filter((option) => option.visible).every((option) => option.isDisabled)); const showTagList = computed(() => { if (!props.multiple) { return []; } return props.collapseTags ? states.selected.slice(0, props.maxCollapseTags) : states.selected; }); const collapseTagList = 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 || filteredOptionsCount.value === 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.isDisabled || !option.visible) { navigateOptions(direction); } nextTick(() => scrollToOption(hoverOption.value)); } }; const findFocusableIndex = (arr, start, step, len) => { for (let i = start; i >= 0 && i < len; i += step) { const obj = arr[i]; if (!(obj == null ? void 0 : obj.isDisabled) && (obj == null ? void 0 : obj.visible)) { return i; } } return null; }; const focusOption = (targetIndex, mode) => { var _a; const len = states.options.size; if (len === 0) return; const start = clamp(targetIndex, 0, len - 1); const options = optionsArray.value; const direction = mode === "up" ? -1 : 1; const newIndex = (_a = findFocusableIndex(options, start, direction, len)) != null ? _a : findFocusableIndex(options, start - direction, -direction, len); if (newIndex != null) { states.hoveringIndex = newIndex; nextTick(() => scrollToOption(hoverOption.value)); } }; const handleKeydown = (e) => { const code = getEventCode(e); let isPreventDefault = true; switch (code) { case EVENT_CODE.up: navigateOptions("prev"); break; case EVENT_CODE.down: navigateOptions("next"); break; case EVENT_CODE.enter: case EVENT_CODE.numpadEnter: selectOption(); break; case EVENT_CODE.esc: handleEsc(); break; case EVENT_CODE.backspace: isPreventDefault = false; deletePrevTag(e); return; case EVENT_CODE.home: if (!expanded.value) return; focusOption(0, "down"); break; case EVENT_CODE.end: if (!expanded.value) return; focusOption(states.options.size - 1, "up"); break; case EVENT_CODE.pageUp: if (!expanded.value) return; focusOption(states.hoveringIndex - 10, "up"); break; case EVENT_CODE.pageDown: if (!expanded.value) return; focusOption(states.hoveringIndex + 10, "down"); break; default: isPreventDefault = false; break; } if (isPreventDefault) { e.preventDefault(); e.stopPropagation(); } }; const getGapWidth = () => { if (!selectionRef.value) return 0; const style = window.getComputedStyle(selectionRef.value); return Number.parseFloat(style.gap || "6px"); }; const tagStyle = computed(() => { const gapWidth = getGapWidth(); const inputSlotWidth = props.filterable ? gapWidth + MINIMUM_INPUT_WIDTH : 0; const maxWidth = collapseItemRef.value && props.maxCollapseTags === 1 ? states.selectionWidth - states.collapseItemWidth - gapWidth - inputSlotWidth : states.selectionWidth - inputSlotWidth; return { maxWidth: `${maxWidth}px` }; }); const collapseTagStyle = computed(() => { return { maxWidth: `${states.selectionWidth}px` }; }); const popupScroll = (data) => { emit("popup-scroll", data); }; useResizeObserver(selectionRef, resetSelectionWidth); useResizeObserver(wrapperRef, updateTooltip); useResizeObserver(tagMenuRef, updateTagTooltip); useResizeObserver(collapseItemRef, resetCollapseItemWidth); let stop; watch(() => dropdownMenuVisible.value, (newVal) => { if (newVal) { stop = useResizeObserver(menuRef, updateTooltip).stop; } else { stop == null ? void 0 : stop(); stop = void 0; } }); onMounted(() => { setSelected(); }); return { inputId, contentId, nsSelect, nsInput, states, isFocused, expanded, optionsArray, hoverOption, selectSize, filteredOptionsCount, updateTooltip, updateTagTooltip, debouncedOnInputChange, onInput, deletePrevTag, deleteTag, deleteSelected, handleOptionSelect, scrollToOption, hasModelValue, shouldShowPlaceholder, currentPlaceholder, mouseEnterEventName, needStatusIcon, showClearBtn, iconComponent, iconReverse, validateState, validateIcon, showNewOption, updateOptions, collapseTagSize, setSelected, selectDisabled, emptyText, handleCompositionStart, handleCompositionUpdate, handleCompositionEnd, handleKeydown, onOptionCreate, onOptionDestroy, handleMenuEnter, focus, blur, handleClearClick, handleClickOutside, handleEsc, toggleMenu, selectOption, getValueKey, navigateOptions, dropdownMenuVisible, showTagList, collapseTagList, popupScroll, getOption, tagStyle, collapseTagStyle, popperRef, inputRef, tooltipRef, tagTooltipRef, prefixRef, suffixRef, selectRef, wrapperRef, selectionRef, scrollbarRef, menuRef, tagMenuRef, collapseItemRef }; }; var ElOptions = defineComponent({ name: "ElOptions", setup(_, { slots }) { const select = inject(selectKey); let cachedValueList = []; return () => { var _a, _b; const children = (_a = slots.default) == null ? void 0 : _a.call(slots); const valueList = []; function filterOptions(children2) { if (!isArray$1(children2)) return; children2.forEach((item) => { var _a2, _b2, _c, _d; const name = (_a2 = (item == null ? void 0 : item.type) || {}) == null ? void 0 : _a2.name; if (name === "ElOptionGroup") { filterOptions(!isString(item.children) && !isArray$1(item.children) && isFunction((_b2 = item.children) == null ? void 0 : _b2.default) ? (_c = item.children) == null ? void 0 : _c.default() : item.children); } else if (name === "ElOption") { valueList.push((_d = item.props) == null ? void 0 : _d.value); } else if (isArray$1(item.children)) { filterOptions(item.children); } }); } if (children.length) { filterOptions((_b = children[0]) == null ? void 0 : _b.children); } if (!isEqual(valueList, cachedValueList)) { cachedValueList = valueList; if (select) { select.states.optionValues = valueList; } } return children; }; } }); const selectProps = buildProps({ name: String, id: String, modelValue: { type: definePropType([ Array, String, Number, Boolean, Object ]), default: void 0 }, autocomplete: { type: String, default: "off" }, automaticDropdown: Boolean, size: useSizeProp, effect: { type: definePropType(String), default: "light" }, disabled: Boolean, clearable: Boolean, filterable: Boolean, allowCreate: Boolean, loading: Boolean, popperClass: { type: String, default: "" }, popperStyle: { type: definePropType([String, Object]) }, popperOptions: { type: definePropType(Object), default: () => ({}) }, remote: Boolean, debounce: { type: Number, default: 300 }, loadingText: String, noMatchText: String, noDataText: String, remoteMethod: { type: definePropType(Function) }, filterMethod: { type: definePropType(Function) }, multiple: Boolean, multipleLimit: { type: Number, default: 0 }, placeholder: { type: String }, defaultFirstOption: Boolean, reserveKeyword: { type: Boolean, default: true }, valueKey: { type: String, default: "value" }, collapseTags: Boolean, collapseTagsTooltip: Boolean, maxCollapseTags: { type: Number, default: 1 }, teleported: useTooltipContentProps.teleported, persistent: { type: Boolean, default: true }, clearIcon: { type: iconPropType, default: CircleClose }, fitInputWidth: Boolean, suffixIcon: { type: iconPropType, default: ArrowDown }, tagType: { ...tagProps.type, default: "info" }, tagEffect: { ...tagProps.effect, default: "light" }, validateEvent: { type: Boolean, default: true }, remoteShowSuffix: Boolean, showArrow: { type: Boolean, default: true }, offset: { type: Number, default: 12 }, placement: { type: definePropType(String), values: Ee, default: "bottom-start" }, fallbackPlacements: { type: definePropType(Array), default: ["bottom-start", "top-start", "right", "left"] }, tabindex: { type: [String, Number], default: 0 }, appendTo: useTooltipContentProps.appendTo, options: { type: definePropType(Array) }, props: { type: definePropType(Object), default: () => defaultProps }, ...useEmptyValuesProps, ...useAriaProps(["ariaLabel"]) }); ({ "popup-scroll": scrollbarEmits.scroll}); const _sfc_main$1 = defineComponent({ name: "ElOptionGroup", componentName: "ElOptionGroup", props: { label: String, disabled: Boolean }, setup(props) { const ns = useNamespace("select"); const groupRef = ref(); const instance = getCurrentInstance(); const children = ref([]); provide(selectGroupKey, reactive({ ...toRefs(props) })); const visible = computed(() => children.value.some((option) => option.visible === true)); const isOption = (node) => { var _a; return node.type.name === "ElOption" && !!((_a = node.component) == null ? void 0 : _a.proxy); }; const flattedChildren = (node) => { const nodes = castArray(node); const children2 = []; nodes.forEach((child) => { var _a; if (!isVNode(child)) return; if (isOption(child)) { children2.push(child.component.proxy); } else if (isArray$1(child.children) && child.children.length) { children2.push(...flattedChildren(child.children)); } else if ((_a = child.component) == null ? void 0 : _a.subTree) { children2.push(...flattedChildren(child.component.subTree)); } }); return children2; }; const updateChildren = () => { children.value = flattedChildren(instance.subTree); }; onMounted(() => { updateChildren(); }); useMutationObserver(groupRef, updateChildren, { attributes: true, subtree: true, childList: true }); return { groupRef, visible, ns }; } }); function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) { return withDirectives((openBlock(), createElementBlock("ul", { ref: "groupRef", class: normalizeClass(_ctx.ns.be("group", "wrap")) }, [ createElementVNode("li", { class: normalizeClass(_ctx.ns.be("group", "title")) }, toDisplayString(_ctx.label), 3), createElementVNode("li", null, [ createElementVNode("ul", { class: normalizeClass(_ctx.ns.b("group")) }, [ renderSlot(_ctx.$slots, "default") ], 2) ]) ], 2)), [ [vShow, _ctx.visible] ]); } var OptionGroup = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["render", _sfc_render$1], ["__file", "option-group.vue"]]); const COMPONENT_NAME = "ElSelect"; const warnHandlerMap = /* @__PURE__ */ new WeakMap(); const createSelectWarnHandler = (appContext) => { return (...args) => { var _a, _b; const message = args[0]; if (!message || message.includes('Slot "default" invoked outside of the render function') && ((_a = args[2]) == null ? void 0 : _a.includes("ElTreeSelect"))) return; const original = (_b = warnHandlerMap.get(appContext)) == null ? void 0 : _b.originalWarnHandler; if (original) { original(...args); return; } console.warn(...args); }; }; const getWarnHandlerRecord = (appContext) => { let record = warnHandlerMap.get(appContext); if (!record) { record = { originalWarnHandler: appContext.config.warnHandler, handler: createSelectWarnHandler(appContext), count: 0 }; warnHandlerMap.set(appContext, record); } return record; }; const _sfc_main = defineComponent({ name: COMPONENT_NAME, componentName: COMPONENT_NAME, components: { ElSelectMenu, ElOption: Option, ElOptions, ElOptionGroup: OptionGroup, ElTag, ElScrollbar, ElTooltip, ElIcon }, directives: { ClickOutside }, props: selectProps, emits: [ UPDATE_MODEL_EVENT, CHANGE_EVENT, "remove-tag", "clear", "visible-change", "focus", "blur", "popup-scroll" ], setup(props, { emit, slots }) { const instance = getCurrentInstance(); const warnRecord = getWarnHandlerRecord(instance.appContext); warnRecord.count += 1; instance.appContext.config.warnHandler = warnRecord.handler; const modelValue = computed(() => { const { modelValue: rawModelValue, multiple } = props; const fallback = multiple ? [] : void 0; if (isArray$1(rawModelValue)) { return multiple ? rawModelValue : fallback; } return multiple ? fallback : rawModelValue; }); const _props = reactive({ ...toRefs(props), modelValue }); const API = useSelect(_props, emit); const { calculatorRef, inputStyle } = useCalcInputWidth(); const { getLabel, getValue, getOptions, getDisabled } = useProps(props); const getOptionProps = (option) => ({ label: getLabel(option), value: getValue(option), disabled: getDisabled(option) }); const flatTreeSelectData = (data) => { return data.reduce((acc, item) => { acc.push(item); if (item.children && item.children.length > 0) { acc.push(...flatTreeSelectData(item.children)); } return acc; }, []); }; const manuallyRenderSlots = (vnodes) => { const children = flattedChildren(vnodes || []); children.forEach((item) => { var _a; if (isObject(item) && (item.type.name === "ElOption" || item.type.name === "ElTree")) { const _name = item.type.name; if (_name === "ElTree") { const treeData = ((_a = item.props) == null ? void 0 : _a.data) || []; const flatData = flatTreeSelectData(treeData); flatData.forEach((treeItem) => { treeItem.currentLabel = treeItem.label || (isObject(treeItem.value) ? "" : treeItem.value); API.onOptionCreate(treeItem); }); } else if (_name === "ElOption") { const obj = { ...item.props }; obj.currentLabel = obj.label || (isObject(obj.value) ? "" : obj.value); API.onOptionCreate(obj); } } }); }; watch(() => { var _a; return [(_a = slots.default) == null ? void 0 : _a.call(slots), modelValue.value]; }, () => { var _a; if (props.persistent || API.expanded.value) { return; } API.states.options.clear(); manuallyRenderSlots((_a = slots.default) == null ? void 0 : _a.call(slots)); }, { immediate: true }); provide(selectKey, reactive({ props: _props, states: API.states, selectRef: API.selectRef, optionsArray: API.optionsArray, setSelected: API.setSelected, handleOptionSelect: API.handleOptionSelect, onOptionCreate: API.onOptionCreate, onOptionDestroy: API.onOptionDestroy })); const selectedLabel = computed(() => { if (!props.multiple) { return API.states.selectedLabel; } return API.states.selected.map((i) => i.currentLabel); }); onBeforeUnmount(() => { const record = warnHandlerMap.get(instance.appContext); if (!record) return; record.count -= 1; if (record.count <= 0) { instance.appContext.config.warnHandler = record.originalWarnHandler; warnHandlerMap.delete(instance.appContext); } }); return { ...API, modelValue, selectedLabel, calculatorRef, inputStyle, getLabel, getValue, getOptions, getDisabled, getOptionProps }; } }); function _sfc_render(_ctx, _cache) { const _component_el_tag = resolveComponent("el-tag"); const _component_el_tooltip = resolveComponent("el-tooltip"); const _component_el_icon = resolveComponent("el-icon"); const _component_el_option = resolveComponent("el-option"); const _component_el_option_group = resolveComponent("el-option-group"); const _component_el_options = resolveComponent("el-options"); const _component_el_scrollbar = resolveComponent("el-scrollbar"); const _component_el_select_menu = resolveComponent("el-select-menu"); const _directive_click_outside = resolveDirective("click-outside"); return withDirectives((openBlock(), createElementBlock("div", { ref: "selectRef", class: normalizeClass([_ctx.nsSelect.b(), _ctx.nsSelect.m(_ctx.selectSize)]), [toHandlerKey(_ctx.mouseEnterEventName)]: ($event) => _ctx.states.inputHovering = true, onMouseleave: ($event) => _ctx.states.inputHovering = false }, [ createVNode(_component_el_tooltip, { ref: "tooltipRef", visible: _ctx.dropdownMenuVisible, placement: _ctx.placement, teleported: _ctx.teleported, "popper-class": [_ctx.nsSelect.e("popper"), _ctx.popperClass], "popper-style": _ctx.popperStyle, "popper-options": _ctx.popperOptions, "fallback-placements": _ctx.fallbackPlacements, effect: _ctx.effect, pure: "", trigger: "click", transition: `${_ctx.nsSelect.namespace.value}-zoom-in-top`, "stop-popper-mouse-event": false, "gpu-acceleration": false, persistent: _ctx.persistent, "append-to": _ctx.appendTo, "show-arrow": _ctx.showArrow, offset: _ctx.offset, onBeforeShow: _ctx.handleMenuEnter, onHide: ($event) => _ctx.states.isBeforeHide = false }, { default: withCtx(() => { var _a; return [ createElementVNode("div", { ref: "wrapperRef", class: normalizeClass([ _ctx.nsSelect.e("wrapper"), _ctx.nsSelect.is("focused", _ctx.isFocused),