@wfrog/vc
Version:
vue3 组件库 vc
1,586 lines (1,567 loc) • 67.2 kB
JavaScript
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),