UNPKG

element-plus

Version:

A Component Library for Vue 3

669 lines (666 loc) 26.3 kB
import { defineComponent, toRefs, computed, unref, provide, reactive, onMounted, nextTick, resolveComponent, resolveDirective, withDirectives, openBlock, createElementBlock, normalizeClass, withModifiers, createVNode, withCtx, createElementVNode, normalizeStyle, toDisplayString, createBlock, Fragment, renderList, createCommentVNode, Transition, withKeys, vModelText, createSlots, resolveDynamicComponent, renderSlot, vShow } from 'vue'; import { useResizeObserver } from '@vueuse/core'; import { placements } from '@popperjs/core'; import '../../../directives/index.mjs'; import '../../../hooks/index.mjs'; import { ElInput } from '../../input/index.mjs'; import { ElTooltip } from '../../tooltip/index.mjs'; import { ElScrollbar } from '../../scrollbar/index.mjs'; import { ElTag } from '../../tag/index.mjs'; import { ElIcon } from '../../icon/index.mjs'; import '../../../constants/index.mjs'; import '../../../utils/index.mjs'; import { CircleClose, ArrowDown } from '@element-plus/icons-vue'; import Option from './option.mjs'; import ElSelectMenu from './select-dropdown.mjs'; import { useSelectStates, useSelect } from './useSelect.mjs'; import { selectKey } from './token.mjs'; import _export_sfc from '../../../_virtual/plugin-vue_export-helper.mjs'; import ClickOutside from '../../../directives/click-outside/index.mjs'; import { isValidComponentSize } from '../../../utils/vue/validator.mjs'; import { useTooltipContentProps } from '../../tooltip/src/content.mjs'; import { iconPropType } from '../../../utils/vue/icon.mjs'; import { tagProps } from '../../tag/src/tag.mjs'; import { UPDATE_MODEL_EVENT, CHANGE_EVENT } from '../../../constants/event.mjs'; import { useNamespace } from '../../../hooks/use-namespace/index.mjs'; import { useLocale } from '../../../hooks/use-locale/index.mjs'; import { useFocus } from '../../../hooks/use-focus/index.mjs'; const COMPONENT_NAME = "ElSelect"; const _sfc_main = defineComponent({ name: COMPONENT_NAME, componentName: COMPONENT_NAME, components: { ElInput, ElSelectMenu, ElOption: Option, ElTag, ElScrollbar, ElTooltip, ElIcon }, directives: { ClickOutside }, props: { name: String, id: String, modelValue: { type: [Array, String, Number, Boolean, Object], default: void 0 }, autocomplete: { type: String, default: "off" }, automaticDropdown: Boolean, size: { type: String, validator: isValidComponentSize }, effect: { type: String, default: "light" }, disabled: Boolean, clearable: Boolean, filterable: Boolean, allowCreate: Boolean, loading: Boolean, popperClass: { type: String, default: "" }, remote: Boolean, loadingText: String, noMatchText: String, noDataText: String, remoteMethod: Function, filterMethod: 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: { type: Boolean, default: false }, teleported: useTooltipContentProps.teleported, persistent: { type: Boolean, default: true }, clearIcon: { type: iconPropType, default: CircleClose }, fitInputWidth: { type: Boolean, default: false }, suffixIcon: { type: iconPropType, default: ArrowDown }, tagType: { ...tagProps.type, default: "info" }, validateEvent: { type: Boolean, default: true }, remoteShowSuffix: { type: Boolean, default: false }, suffixTransition: { type: Boolean, default: true }, placement: { type: String, values: placements, default: "bottom-start" } }, emits: [ UPDATE_MODEL_EVENT, CHANGE_EVENT, "remove-tag", "clear", "visible-change", "focus", "blur" ], setup(props, ctx) { const nsSelect = useNamespace("select"); const nsInput = useNamespace("input"); const { t } = useLocale(); const states = useSelectStates(props); const { optionsArray, selectSize, readonly, handleResize, collapseTagSize, debouncedOnInputChange, debouncedQueryChange, deletePrevTag, deleteTag, deleteSelected, handleOptionSelect, scrollToOption, setSelected, resetInputHeight, managePlaceholder, showClose, selectDisabled, iconComponent, iconReverse, showNewOption, emptyText, toggleLastOptionHitState, resetInputState, handleComposition, onOptionCreate, onOptionDestroy, handleMenuEnter, handleFocus, blur, handleBlur, handleClearClick, handleClose, handleKeydownEscape, toggleMenu, selectOption, getValueKey, navigateOptions, dropMenuVisible, reference, input, tooltipRef, tags, selectWrapper, scrollbar, queryChange, groupQueryChange, handleMouseEnter, handleMouseLeave } = useSelect(props, states, ctx); const { focus } = useFocus(reference); const { inputWidth, selected, inputLength, filteredOptionsCount, visible, softFocus, selectedLabel, hoverIndex, query, inputHovering, currentPlaceholder, menuVisibleOnFocus, isOnComposition, isSilentBlur, options, cachedOptions, optionsCount, prefixWidth, tagInMultiLine } = toRefs(states); const wrapperKls = computed(() => { const classList = [nsSelect.b()]; const _selectSize = unref(selectSize); if (_selectSize) { classList.push(nsSelect.m(_selectSize)); } if (props.disabled) { classList.push(nsSelect.m("disabled")); } return classList; }); const selectTagsStyle = computed(() => ({ maxWidth: `${unref(inputWidth) - 32}px`, width: "100%" })); const tagTextStyle = computed(() => { const maxWidth = unref(inputWidth) > 123 ? unref(inputWidth) - 123 : unref(inputWidth) - 75; return { maxWidth: `${maxWidth}px` }; }); provide(selectKey, reactive({ props, options, optionsArray, cachedOptions, optionsCount, filteredOptionsCount, hoverIndex, handleOptionSelect, onOptionCreate, onOptionDestroy, selectWrapper, selected, setSelected, queryChange, groupQueryChange })); onMounted(() => { states.cachedPlaceHolder = currentPlaceholder.value = props.placeholder || t("el.select.placeholder"); if (props.multiple && Array.isArray(props.modelValue) && props.modelValue.length > 0) { currentPlaceholder.value = ""; } useResizeObserver(selectWrapper, handleResize); if (props.remote && props.multiple) { resetInputHeight(); } nextTick(() => { const refEl = reference.value && reference.value.$el; if (!refEl) return; inputWidth.value = refEl.getBoundingClientRect().width; if (ctx.slots.prefix) { const prefix = refEl.querySelector(`.${nsInput.e("prefix")}`); prefixWidth.value = Math.max(prefix.getBoundingClientRect().width + 5, 30); } }); setSelected(); }); if (props.multiple && !Array.isArray(props.modelValue)) { ctx.emit(UPDATE_MODEL_EVENT, []); } if (!props.multiple && Array.isArray(props.modelValue)) { ctx.emit(UPDATE_MODEL_EVENT, ""); } const popperPaneRef = computed(() => { var _a, _b; return (_b = (_a = tooltipRef.value) == null ? void 0 : _a.popperRef) == null ? void 0 : _b.contentRef; }); return { tagInMultiLine, prefixWidth, selectSize, readonly, handleResize, collapseTagSize, debouncedOnInputChange, debouncedQueryChange, deletePrevTag, deleteTag, deleteSelected, handleOptionSelect, scrollToOption, inputWidth, selected, inputLength, filteredOptionsCount, visible, softFocus, selectedLabel, hoverIndex, query, inputHovering, currentPlaceholder, menuVisibleOnFocus, isOnComposition, isSilentBlur, options, resetInputHeight, managePlaceholder, showClose, selectDisabled, iconComponent, iconReverse, showNewOption, emptyText, toggleLastOptionHitState, resetInputState, handleComposition, handleMenuEnter, handleFocus, blur, handleBlur, handleClearClick, handleClose, handleKeydownEscape, toggleMenu, selectOption, getValueKey, navigateOptions, dropMenuVisible, focus, reference, input, tooltipRef, popperPaneRef, tags, selectWrapper, scrollbar, wrapperKls, selectTagsStyle, nsSelect, tagTextStyle, handleMouseEnter, handleMouseLeave }; } }); const _hoisted_1 = ["disabled", "autocomplete"]; const _hoisted_2 = { style: { "height": "100%", "display": "flex", "justify-content": "center", "align-items": "center" } }; function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { const _component_el_tag = resolveComponent("el-tag"); const _component_el_tooltip = resolveComponent("el-tooltip"); const _component_el_icon = resolveComponent("el-icon"); const _component_el_input = resolveComponent("el-input"); const _component_el_option = resolveComponent("el-option"); 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: "selectWrapper", class: normalizeClass(_ctx.wrapperKls), onMouseenter: _cache[22] || (_cache[22] = (...args) => _ctx.handleMouseEnter && _ctx.handleMouseEnter(...args)), onMouseleave: _cache[23] || (_cache[23] = (...args) => _ctx.handleMouseLeave && _ctx.handleMouseLeave(...args)), onClick: _cache[24] || (_cache[24] = withModifiers((...args) => _ctx.toggleMenu && _ctx.toggleMenu(...args), ["stop"])) }, [ createVNode(_component_el_tooltip, { ref: "tooltipRef", visible: _ctx.dropMenuVisible, placement: _ctx.placement, teleported: _ctx.teleported, "popper-class": [_ctx.nsSelect.e("popper"), _ctx.popperClass], "fallback-placements": ["bottom-start", "top-start", "right", "left"], 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, onShow: _ctx.handleMenuEnter }, { default: withCtx(() => [ createElementVNode("div", { class: "select-trigger", onMouseenter: _cache[20] || (_cache[20] = ($event) => _ctx.inputHovering = true), onMouseleave: _cache[21] || (_cache[21] = ($event) => _ctx.inputHovering = false) }, [ _ctx.multiple ? (openBlock(), createElementBlock("div", { key: 0, ref: "tags", class: normalizeClass(_ctx.nsSelect.e("tags")), style: normalizeStyle(_ctx.selectTagsStyle) }, [ _ctx.collapseTags && _ctx.selected.length ? (openBlock(), createElementBlock("span", { key: 0, class: normalizeClass([ _ctx.nsSelect.b("tags-wrapper"), { "has-prefix": _ctx.prefixWidth && _ctx.selected.length } ]) }, [ createVNode(_component_el_tag, { closable: !_ctx.selectDisabled && !_ctx.selected[0].isDisabled, size: _ctx.collapseTagSize, hit: _ctx.selected[0].hitState, type: _ctx.tagType, "disable-transitions": "", onClose: _cache[0] || (_cache[0] = ($event) => _ctx.deleteTag($event, _ctx.selected[0])) }, { default: withCtx(() => [ createElementVNode("span", { class: normalizeClass(_ctx.nsSelect.e("tags-text")), style: normalizeStyle(_ctx.tagTextStyle) }, toDisplayString(_ctx.selected[0].currentLabel), 7) ]), _: 1 }, 8, ["closable", "size", "hit", "type"]), _ctx.selected.length > 1 ? (openBlock(), createBlock(_component_el_tag, { key: 0, closable: false, size: _ctx.collapseTagSize, type: _ctx.tagType, "disable-transitions": "" }, { default: withCtx(() => [ _ctx.collapseTagsTooltip ? (openBlock(), createBlock(_component_el_tooltip, { key: 0, disabled: _ctx.dropMenuVisible, "fallback-placements": ["bottom", "top", "right", "left"], effect: _ctx.effect, placement: "bottom", teleported: _ctx.teleported }, { default: withCtx(() => [ createElementVNode("span", { class: normalizeClass(_ctx.nsSelect.e("tags-text")) }, "+ " + toDisplayString(_ctx.selected.length - 1), 3) ]), content: withCtx(() => [ createElementVNode("div", { class: normalizeClass(_ctx.nsSelect.e("collapse-tags")) }, [ (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.selected.slice(1), (item, idx) => { return openBlock(), createElementBlock("div", { key: idx, class: normalizeClass(_ctx.nsSelect.e("collapse-tag")) }, [ (openBlock(), createBlock(_component_el_tag, { key: _ctx.getValueKey(item), class: "in-tooltip", closable: !_ctx.selectDisabled && !item.isDisabled, size: _ctx.collapseTagSize, hit: item.hitState, type: _ctx.tagType, "disable-transitions": "", style: { margin: "2px" }, onClose: ($event) => _ctx.deleteTag($event, item) }, { default: withCtx(() => [ createElementVNode("span", { class: normalizeClass(_ctx.nsSelect.e("tags-text")), style: normalizeStyle({ maxWidth: _ctx.inputWidth - 75 + "px" }) }, toDisplayString(item.currentLabel), 7) ]), _: 2 }, 1032, ["closable", "size", "hit", "type", "onClose"])) ], 2); }), 128)) ], 2) ]), _: 1 }, 8, ["disabled", "effect", "teleported"])) : (openBlock(), createElementBlock("span", { key: 1, class: normalizeClass(_ctx.nsSelect.e("tags-text")) }, "+ " + toDisplayString(_ctx.selected.length - 1), 3)) ]), _: 1 }, 8, ["size", "type"])) : createCommentVNode("v-if", true) ], 2)) : createCommentVNode("v-if", true), createCommentVNode(" <div> "), !_ctx.collapseTags ? (openBlock(), createBlock(Transition, { key: 1, onAfterLeave: _ctx.resetInputHeight }, { default: withCtx(() => [ createElementVNode("span", { class: normalizeClass([ _ctx.nsSelect.b("tags-wrapper"), { "has-prefix": _ctx.prefixWidth && _ctx.selected.length } ]) }, [ (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.selected, (item) => { return openBlock(), createBlock(_component_el_tag, { key: _ctx.getValueKey(item), closable: !_ctx.selectDisabled && !item.isDisabled, size: _ctx.collapseTagSize, hit: item.hitState, type: _ctx.tagType, "disable-transitions": "", onClose: ($event) => _ctx.deleteTag($event, item) }, { default: withCtx(() => [ createElementVNode("span", { class: normalizeClass(_ctx.nsSelect.e("tags-text")), style: normalizeStyle({ maxWidth: _ctx.inputWidth - 75 + "px" }) }, toDisplayString(item.currentLabel), 7) ]), _: 2 }, 1032, ["closable", "size", "hit", "type", "onClose"]); }), 128)) ], 2) ]), _: 1 }, 8, ["onAfterLeave"])) : createCommentVNode("v-if", true), createCommentVNode(" </div> "), _ctx.filterable ? withDirectives((openBlock(), createElementBlock("input", { key: 2, ref: "input", "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => _ctx.query = $event), type: "text", class: normalizeClass([_ctx.nsSelect.e("input"), _ctx.nsSelect.is(_ctx.selectSize)]), disabled: _ctx.selectDisabled, autocomplete: _ctx.autocomplete, style: normalizeStyle({ marginLeft: _ctx.prefixWidth && !_ctx.selected.length || _ctx.tagInMultiLine ? `${_ctx.prefixWidth}px` : "", flexGrow: 1, width: `${_ctx.inputLength / (_ctx.inputWidth - 32)}%`, maxWidth: `${_ctx.inputWidth - 42}px` }), onFocus: _cache[2] || (_cache[2] = (...args) => _ctx.handleFocus && _ctx.handleFocus(...args)), onBlur: _cache[3] || (_cache[3] = (...args) => _ctx.handleBlur && _ctx.handleBlur(...args)), onKeyup: _cache[4] || (_cache[4] = (...args) => _ctx.managePlaceholder && _ctx.managePlaceholder(...args)), onKeydown: [ _cache[5] || (_cache[5] = (...args) => _ctx.resetInputState && _ctx.resetInputState(...args)), _cache[6] || (_cache[6] = withKeys(withModifiers(($event) => _ctx.navigateOptions("next"), ["prevent"]), ["down"])), _cache[7] || (_cache[7] = withKeys(withModifiers(($event) => _ctx.navigateOptions("prev"), ["prevent"]), ["up"])), _cache[8] || (_cache[8] = withKeys((...args) => _ctx.handleKeydownEscape && _ctx.handleKeydownEscape(...args), ["esc"])), _cache[9] || (_cache[9] = withKeys(withModifiers((...args) => _ctx.selectOption && _ctx.selectOption(...args), ["stop", "prevent"]), ["enter"])), _cache[10] || (_cache[10] = withKeys((...args) => _ctx.deletePrevTag && _ctx.deletePrevTag(...args), ["delete"])), _cache[11] || (_cache[11] = withKeys(($event) => _ctx.visible = false, ["tab"])) ], onCompositionstart: _cache[12] || (_cache[12] = (...args) => _ctx.handleComposition && _ctx.handleComposition(...args)), onCompositionupdate: _cache[13] || (_cache[13] = (...args) => _ctx.handleComposition && _ctx.handleComposition(...args)), onCompositionend: _cache[14] || (_cache[14] = (...args) => _ctx.handleComposition && _ctx.handleComposition(...args)), onInput: _cache[15] || (_cache[15] = (...args) => _ctx.debouncedQueryChange && _ctx.debouncedQueryChange(...args)) }, null, 46, _hoisted_1)), [ [vModelText, _ctx.query] ]) : createCommentVNode("v-if", true) ], 6)) : createCommentVNode("v-if", true), createVNode(_component_el_input, { id: _ctx.id, ref: "reference", modelValue: _ctx.selectedLabel, "onUpdate:modelValue": _cache[16] || (_cache[16] = ($event) => _ctx.selectedLabel = $event), type: "text", placeholder: _ctx.currentPlaceholder, name: _ctx.name, autocomplete: _ctx.autocomplete, size: _ctx.selectSize, disabled: _ctx.selectDisabled, readonly: _ctx.readonly, "validate-event": false, class: normalizeClass([_ctx.nsSelect.is("focus", _ctx.visible)]), tabindex: _ctx.multiple && _ctx.filterable ? -1 : void 0, onFocus: _ctx.handleFocus, onBlur: _ctx.handleBlur, onInput: _ctx.debouncedOnInputChange, onPaste: _ctx.debouncedOnInputChange, onCompositionstart: _ctx.handleComposition, onCompositionupdate: _ctx.handleComposition, onCompositionend: _ctx.handleComposition, onKeydown: [ _cache[17] || (_cache[17] = withKeys(withModifiers(($event) => _ctx.navigateOptions("next"), ["stop", "prevent"]), ["down"])), _cache[18] || (_cache[18] = withKeys(withModifiers(($event) => _ctx.navigateOptions("prev"), ["stop", "prevent"]), ["up"])), withKeys(withModifiers(_ctx.selectOption, ["stop", "prevent"]), ["enter"]), withKeys(_ctx.handleKeydownEscape, ["esc"]), _cache[19] || (_cache[19] = withKeys(($event) => _ctx.visible = false, ["tab"])) ] }, createSlots({ suffix: withCtx(() => [ _ctx.iconComponent && !_ctx.showClose ? (openBlock(), createBlock(_component_el_icon, { key: 0, class: normalizeClass([_ctx.nsSelect.e("caret"), _ctx.nsSelect.e("icon"), _ctx.iconReverse]) }, { default: withCtx(() => [ (openBlock(), createBlock(resolveDynamicComponent(_ctx.iconComponent))) ]), _: 1 }, 8, ["class"])) : createCommentVNode("v-if", true), _ctx.showClose && _ctx.clearIcon ? (openBlock(), createBlock(_component_el_icon, { key: 1, class: normalizeClass([_ctx.nsSelect.e("caret"), _ctx.nsSelect.e("icon")]), onClick: _ctx.handleClearClick }, { default: withCtx(() => [ (openBlock(), createBlock(resolveDynamicComponent(_ctx.clearIcon))) ]), _: 1 }, 8, ["class", "onClick"])) : createCommentVNode("v-if", true) ]), _: 2 }, [ _ctx.$slots.prefix ? { name: "prefix", fn: withCtx(() => [ createElementVNode("div", _hoisted_2, [ renderSlot(_ctx.$slots, "prefix") ]) ]) } : void 0 ]), 1032, ["id", "modelValue", "placeholder", "name", "autocomplete", "size", "disabled", "readonly", "class", "tabindex", "onFocus", "onBlur", "onInput", "onPaste", "onCompositionstart", "onCompositionupdate", "onCompositionend", "onKeydown"]) ], 32) ]), content: withCtx(() => [ createVNode(_component_el_select_menu, null, { default: withCtx(() => [ withDirectives(createVNode(_component_el_scrollbar, { ref: "scrollbar", tag: "ul", "wrap-class": _ctx.nsSelect.be("dropdown", "wrap"), "view-class": _ctx.nsSelect.be("dropdown", "list"), class: normalizeClass([ _ctx.nsSelect.is("empty", !_ctx.allowCreate && Boolean(_ctx.query) && _ctx.filteredOptionsCount === 0) ]) }, { default: withCtx(() => [ _ctx.showNewOption ? (openBlock(), createBlock(_component_el_option, { key: 0, value: _ctx.query, created: true }, null, 8, ["value"])) : createCommentVNode("v-if", true), renderSlot(_ctx.$slots, "default") ]), _: 3 }, 8, ["wrap-class", "view-class", "class"]), [ [vShow, _ctx.options.size > 0 && !_ctx.loading] ]), _ctx.emptyText && (!_ctx.allowCreate || _ctx.loading || _ctx.allowCreate && _ctx.options.size === 0) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [ _ctx.$slots.empty ? renderSlot(_ctx.$slots, "empty", { key: 0 }) : (openBlock(), createElementBlock("p", { key: 1, class: normalizeClass(_ctx.nsSelect.be("dropdown", "empty")) }, toDisplayString(_ctx.emptyText), 3)) ], 64)) : createCommentVNode("v-if", true) ]), _: 3 }) ]), _: 3 }, 8, ["visible", "placement", "teleported", "popper-class", "effect", "transition", "persistent", "onShow"]) ], 34)), [ [_directive_click_outside, _ctx.handleClose, _ctx.popperPaneRef] ]); } var Select = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__file", "/home/runner/work/element-plus/element-plus/packages/components/select/src/select.vue"]]); export { Select as default }; //# sourceMappingURL=select.mjs.map