UNPKG

element-plus

Version:

A Component Library for Vue 3

402 lines (397 loc) 13.7 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var vue = require('vue'); var shared = require('@vue/shared'); var lodashUnified = require('lodash-unified'); require('../../../hooks/index.js'); require('../../../directives/index.js'); require('../../../utils/index.js'); require('../../../constants/index.js'); var index$1 = require('../../input/index.js'); var index$2 = require('../../scrollbar/index.js'); var index = require('../../tooltip/index.js'); require('../../popper/index.js'); var index$3 = require('../../icon/index.js'); var iconsVue = require('@element-plus/icons-vue'); var pluginVue_exportHelper = require('../../../_virtual/plugin-vue_export-helper.js'); var index$4 = require('../../../directives/click-outside/index.js'); var tooltip = require('../../tooltip/src/tooltip.js'); var event = require('../../../constants/event.js'); var index$5 = require('../../../hooks/use-namespace/index.js'); var deprecation = require('../../popper/src/deprecation.js'); var index$6 = require('../../../hooks/use-attrs/index.js'); var rand = require('../../../utils/rand.js'); var error = require('../../../utils/error.js'); const COMPONENT_NAME = "ElAutocomplete"; const _sfc_main = vue.defineComponent({ name: COMPONENT_NAME, components: { ElTooltip: index.ElTooltip, ElInput: index$1.ElInput, ElScrollbar: index$2.ElScrollbar, ElIcon: index$3.ElIcon, Loading: iconsVue.Loading }, directives: { clickoutside: index$4["default"] }, inheritAttrs: false, props: { valueKey: { type: String, default: "value" }, modelValue: { type: [String, Number], default: "" }, debounce: { type: Number, default: 300 }, placement: { type: String, validator: (val) => { return [ "top", "top-start", "top-end", "bottom", "bottom-start", "bottom-end" ].includes(val); }, default: "bottom-start" }, fetchSuggestions: { type: Function, default: shared.NOOP }, popperClass: { type: String, default: "" }, triggerOnFocus: { type: Boolean, default: true }, selectWhenUnmatched: { type: Boolean, default: false }, hideLoading: { type: Boolean, default: false }, popperAppendToBody: { type: Boolean, default: void 0 }, teleported: tooltip.useTooltipContentProps.teleported, highlightFirstItem: { type: Boolean, default: false } }, emits: [ event.UPDATE_MODEL_EVENT, "input", "change", "focus", "blur", "clear", "select" ], setup(props, ctx) { const ns = index$5.useNamespace("autocomplete"); const { compatTeleported } = deprecation.useDeprecateAppendToBody(COMPONENT_NAME, "popperAppendToBody"); const attrs = index$6.useAttrs(); const suggestions = vue.ref([]); const highlightedIndex = vue.ref(-1); const dropdownWidth = vue.ref(""); const activated = vue.ref(false); const suggestionDisabled = vue.ref(false); const loading = vue.ref(false); const inputRef = vue.ref(null); const regionRef = vue.ref(null); const popper = vue.ref(null); const id = vue.computed(() => { return ns.b(String(rand.generateId())); }); const suggestionVisible = vue.computed(() => { const isValidData = shared.isArray(suggestions.value) && suggestions.value.length > 0; return (isValidData || loading.value) && activated.value; }); const suggestionLoading = vue.computed(() => { return !props.hideLoading && loading.value; }); const onSuggestionShow = () => { vue.nextTick(() => { if (suggestionVisible.value) { dropdownWidth.value = `${inputRef.value.$el.offsetWidth}px`; } }); }; vue.onMounted(() => { inputRef.value.inputOrTextarea.setAttribute("role", "textbox"); inputRef.value.inputOrTextarea.setAttribute("aria-autocomplete", "list"); inputRef.value.inputOrTextarea.setAttribute("aria-controls", "id"); inputRef.value.inputOrTextarea.setAttribute("aria-activedescendant", `${id.value}-item-${highlightedIndex.value}`); }); const getData = (queryString) => { if (suggestionDisabled.value) { return; } loading.value = true; props.fetchSuggestions(queryString, (suggestionsArg) => { loading.value = false; if (suggestionDisabled.value) { return; } if (shared.isArray(suggestionsArg)) { suggestions.value = suggestionsArg; highlightedIndex.value = props.highlightFirstItem ? 0 : -1; } else { error.throwError("ElAutocomplete", "autocomplete suggestions must be an array"); } }); }; const debouncedGetData = lodashUnified.debounce(getData, props.debounce); const handleInput = (value) => { ctx.emit("input", value); ctx.emit(event.UPDATE_MODEL_EVENT, value); suggestionDisabled.value = false; if (!props.triggerOnFocus && !value) { suggestionDisabled.value = true; suggestions.value = []; return; } debouncedGetData(value); }; const handleChange = (value) => { ctx.emit("change", value); }; const handleFocus = (e) => { activated.value = true; ctx.emit("focus", e); if (props.triggerOnFocus) { debouncedGetData(String(props.modelValue)); } }; const handleBlur = (e) => { ctx.emit("blur", e); }; const handleClear = () => { activated.value = false; ctx.emit(event.UPDATE_MODEL_EVENT, ""); ctx.emit("clear"); }; const handleKeyEnter = () => { if (suggestionVisible.value && highlightedIndex.value >= 0 && highlightedIndex.value < suggestions.value.length) { select(suggestions.value[highlightedIndex.value]); } else if (props.selectWhenUnmatched) { ctx.emit("select", { value: props.modelValue }); vue.nextTick(() => { suggestions.value = []; highlightedIndex.value = -1; }); } }; const close = () => { activated.value = false; }; const focus = () => { var _a; (_a = inputRef.value) == null ? void 0 : _a.focus(); }; const select = (item) => { ctx.emit("input", item[props.valueKey]); ctx.emit(event.UPDATE_MODEL_EVENT, item[props.valueKey]); ctx.emit("select", item); vue.nextTick(() => { suggestions.value = []; highlightedIndex.value = -1; }); }; const highlight = (index) => { if (!suggestionVisible.value || loading.value) { return; } if (index < 0) { highlightedIndex.value = -1; return; } if (index >= suggestions.value.length) { index = suggestions.value.length - 1; } const suggestion = regionRef.value.querySelector(`.${ns.be("suggestion", "wrap")}`); const suggestionList = suggestion.querySelectorAll(`.${ns.be("suggestion", "list")} li`); const highlightItem = suggestionList[index]; const scrollTop = suggestion.scrollTop; const { offsetTop, scrollHeight } = highlightItem; if (offsetTop + scrollHeight > scrollTop + suggestion.clientHeight) { suggestion.scrollTop += scrollHeight; } if (offsetTop < scrollTop) { suggestion.scrollTop -= scrollHeight; } highlightedIndex.value = index; inputRef.value.inputOrTextarea.setAttribute("aria-activedescendant", `${id.value}-item-${highlightedIndex.value}`); }; return { attrs, suggestions, highlightedIndex, dropdownWidth, activated, suggestionDisabled, loading, inputRef, regionRef, popper, id, suggestionVisible, suggestionLoading, compatTeleported, getData, handleInput, handleChange, handleFocus, handleBlur, handleClear, handleKeyEnter, close, focus, select, highlight, onSuggestionShow, ns }; } }); const _hoisted_1 = ["aria-expanded", "aria-owns"]; const _hoisted_2 = { key: 0 }; const _hoisted_3 = ["id", "aria-selected", "onClick"]; function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { const _component_el_input = vue.resolveComponent("el-input"); const _component_loading = vue.resolveComponent("loading"); const _component_el_icon = vue.resolveComponent("el-icon"); const _component_el_scrollbar = vue.resolveComponent("el-scrollbar"); const _component_el_tooltip = vue.resolveComponent("el-tooltip"); const _directive_clickoutside = vue.resolveDirective("clickoutside"); return vue.openBlock(), vue.createBlock(_component_el_tooltip, { ref: "popper", visible: _ctx.suggestionVisible, "onUpdate:visible": _cache[2] || (_cache[2] = ($event) => _ctx.suggestionVisible = $event), placement: _ctx.placement, "fallback-placements": ["bottom-start", "top-start"], "popper-class": `${_ctx.ns.e("popper")} ${_ctx.popperClass}`, teleported: _ctx.compatTeleported, "gpu-acceleration": false, pure: "", "manual-mode": "", effect: "light", trigger: "click", transition: `${_ctx.ns.namespace.value}-zoom-in-top`, persistent: "", onShow: _ctx.onSuggestionShow }, { content: vue.withCtx(() => [ vue.createElementVNode("div", { ref: "regionRef", class: vue.normalizeClass([_ctx.ns.b("suggestion"), _ctx.ns.is("loading", _ctx.suggestionLoading)]), style: vue.normalizeStyle({ minWidth: _ctx.dropdownWidth, outline: "none" }), role: "region" }, [ vue.createVNode(_component_el_scrollbar, { id: _ctx.id, tag: "ul", "wrap-class": _ctx.ns.be("suggestion", "wrap"), "view-class": _ctx.ns.be("suggestion", "list"), role: "listbox" }, { default: vue.withCtx(() => [ _ctx.suggestionLoading ? (vue.openBlock(), vue.createElementBlock("li", _hoisted_2, [ vue.createVNode(_component_el_icon, { class: "is-loading" }, { default: vue.withCtx(() => [ vue.createVNode(_component_loading) ]), _: 1 }) ])) : (vue.openBlock(true), vue.createElementBlock(vue.Fragment, { key: 1 }, vue.renderList(_ctx.suggestions, (item, index) => { return vue.openBlock(), vue.createElementBlock("li", { id: `${_ctx.id}-item-${index}`, key: index, class: vue.normalizeClass({ highlighted: _ctx.highlightedIndex === index }), role: "option", "aria-selected": _ctx.highlightedIndex === index, onClick: ($event) => _ctx.select(item) }, [ vue.renderSlot(_ctx.$slots, "default", { item }, () => [ vue.createTextVNode(vue.toDisplayString(item[_ctx.valueKey]), 1) ]) ], 10, _hoisted_3); }), 128)) ]), _: 3 }, 8, ["id", "wrap-class", "view-class"]) ], 6) ]), default: vue.withCtx(() => [ vue.withDirectives((vue.openBlock(), vue.createElementBlock("div", { class: vue.normalizeClass([_ctx.ns.b(), _ctx.$attrs.class]), style: vue.normalizeStyle(_ctx.$attrs.style), role: "combobox", "aria-haspopup": "listbox", "aria-expanded": _ctx.suggestionVisible, "aria-owns": _ctx.id }, [ vue.createVNode(_component_el_input, vue.mergeProps({ ref: "inputRef" }, _ctx.attrs, { "model-value": _ctx.modelValue, onInput: _ctx.handleInput, onChange: _ctx.handleChange, onFocus: _ctx.handleFocus, onBlur: _ctx.handleBlur, onClear: _ctx.handleClear, onKeydown: [ _cache[0] || (_cache[0] = vue.withKeys(vue.withModifiers(($event) => _ctx.highlight(_ctx.highlightedIndex - 1), ["prevent"]), ["up"])), _cache[1] || (_cache[1] = vue.withKeys(vue.withModifiers(($event) => _ctx.highlight(_ctx.highlightedIndex + 1), ["prevent"]), ["down"])), vue.withKeys(_ctx.handleKeyEnter, ["enter"]), vue.withKeys(_ctx.close, ["tab"]) ] }), vue.createSlots({ _: 2 }, [ _ctx.$slots.prepend ? { name: "prepend", fn: vue.withCtx(() => [ vue.renderSlot(_ctx.$slots, "prepend") ]) } : void 0, _ctx.$slots.append ? { name: "append", fn: vue.withCtx(() => [ vue.renderSlot(_ctx.$slots, "append") ]) } : void 0, _ctx.$slots.prefix ? { name: "prefix", fn: vue.withCtx(() => [ vue.renderSlot(_ctx.$slots, "prefix") ]) } : void 0, _ctx.$slots.suffix ? { name: "suffix", fn: vue.withCtx(() => [ vue.renderSlot(_ctx.$slots, "suffix") ]) } : void 0 ]), 1040, ["model-value", "onInput", "onChange", "onFocus", "onBlur", "onClear", "onKeydown"]) ], 14, _hoisted_1)), [ [_directive_clickoutside, _ctx.close] ]) ]), _: 3 }, 8, ["visible", "placement", "popper-class", "teleported", "transition", "onShow"]); } var Autocomplete = /* @__PURE__ */ pluginVue_exportHelper["default"](_sfc_main, [["render", _sfc_render]]); exports["default"] = Autocomplete; //# sourceMappingURL=index.js.map