UNPKG

element-plus

Version:

A Component Library for Vue3.0

384 lines (373 loc) 13 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var vue = require('vue'); var hooks = require('../hooks'); var debounce = require('lodash/debounce'); var directives = require('../directives'); var util = require('../utils/util'); var constants = require('../utils/constants'); var throwError = require('../utils/error'); var ElInput = require('../el-input'); var ElScrollbar = require('../el-scrollbar'); var ElPopper = require('../el-popper'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var debounce__default = /*#__PURE__*/_interopDefaultLegacy(debounce); var throwError__default = /*#__PURE__*/_interopDefaultLegacy(throwError); var ElInput__default = /*#__PURE__*/_interopDefaultLegacy(ElInput); var ElScrollbar__default = /*#__PURE__*/_interopDefaultLegacy(ElScrollbar); var ElPopper__default = /*#__PURE__*/_interopDefaultLegacy(ElPopper); /** * Make a map and return a function for checking if a key * is in that map. * IMPORTANT: all calls of this function must be prefixed with * \/\*#\_\_PURE\_\_\*\/ * So that rollup can tree-shake them if necessary. */ const EMPTY_OBJ = (process.env.NODE_ENV !== 'production') ? Object.freeze({}) : {}; const EMPTY_ARR = (process.env.NODE_ENV !== 'production') ? Object.freeze([]) : []; const NOOP = () => { }; var script = vue.defineComponent({ name: "ElAutocomplete", components: { ElPopper: ElPopper__default['default'], ElInput: ElInput__default['default'], ElScrollbar: ElScrollbar__default['default'] }, directives: { clickoutside: directives.ClickOutside }, 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: NOOP }, popperClass: { type: String, default: "" }, triggerOnFocus: { type: Boolean, default: true }, selectWhenUnmatched: { type: Boolean, default: false }, hideLoading: { type: Boolean, default: false }, popperAppendToBody: { type: Boolean, default: true }, highlightFirstItem: { type: Boolean, default: false } }, emits: [constants.UPDATE_MODEL_EVENT, "input", "change", "focus", "blur", "clear", "select"], setup(props, ctx) { const attrs = hooks.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 `el-autocomplete-${util.generateId()}`; }); const suggestionVisible = vue.computed(() => { const isValidData = util.isArray(suggestions.value) && suggestions.value.length > 0; return (isValidData || loading.value) && activated.value; }); const suggestionLoading = vue.computed(() => { return !props.hideLoading && loading.value; }); const updatePopperPosition = () => { vue.nextTick(popper.value.update); }; vue.watch(suggestionVisible, () => { 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 $ul = regionRef.value.querySelector(".el-autocomplete-suggestion__list"); $ul.setAttribute("role", "listbox"); $ul.setAttribute("id", id.value); }); vue.onUpdated(updatePopperPosition); const getData = (queryString) => { if (suggestionDisabled.value) { return; } loading.value = true; updatePopperPosition(); props.fetchSuggestions(queryString, (suggestionsArg) => { loading.value = false; if (suggestionDisabled.value) { return; } if (util.isArray(suggestionsArg)) { suggestions.value = suggestionsArg; highlightedIndex.value = props.highlightFirstItem ? 0 : -1; } else { throwError__default['default']("ElAutocomplete", "autocomplete suggestions must be an array"); } }); }; const debouncedGetData = debounce__default['default'](getData, props.debounce); const handleInput = (value) => { ctx.emit("input", value); ctx.emit(constants.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(props.modelValue); } }; const handleBlur = (e) => { ctx.emit("blur", e); }; const handleClear = () => { activated.value = false; ctx.emit(constants.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 = () => { inputRef.value.focus(); }; const select = (item) => { ctx.emit("input", item[props.valueKey]); ctx.emit(constants.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(".el-autocomplete-suggestion__wrap"); const suggestionList = suggestion.querySelectorAll(".el-autocomplete-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, getData, handleInput, handleChange, handleFocus, handleBlur, handleClear, handleKeyEnter, close, focus, select, highlight }; } }); const _hoisted_1 = { key: 0 }; const _hoisted_2 = /* @__PURE__ */ vue.createVNode("i", { class: "el-icon-loading" }, null, -1); function render(_ctx, _cache, $props, $setup, $data, $options) { const _component_el_input = vue.resolveComponent("el-input"); const _component_el_scrollbar = vue.resolveComponent("el-scrollbar"); const _component_el_popper = vue.resolveComponent("el-popper"); const _directive_clickoutside = vue.resolveDirective("clickoutside"); return vue.openBlock(), vue.createBlock(_component_el_popper, { ref: "popper", visible: _ctx.suggestionVisible, "onUpdate:visible": _cache[3] || (_cache[3] = ($event) => _ctx.suggestionVisible = $event), placement: _ctx.placement, "popper-class": `el-autocomplete__popper ${_ctx.popperClass}`, "append-to-body": _ctx.popperAppendToBody, pure: "", "manual-mode": "", effect: "light", trigger: "click", transition: "el-zoom-in-top", "gpu-acceleration": false }, { trigger: vue.withCtx(() => [ vue.withDirectives(vue.createVNode("div", { class: ["el-autocomplete", _ctx.$attrs.class], style: _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[1] || (_cache[1] = vue.withKeys(vue.withModifiers(($event) => _ctx.highlight(_ctx.highlightedIndex - 1), ["prevent"]), ["up"])), _cache[2] || (_cache[2] = 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, ["aria-expanded", "aria-owns"]), [ [_directive_clickoutside, _ctx.close] ]) ]), default: vue.withCtx(() => [ vue.createVNode("div", { ref: "regionRef", class: ["el-autocomplete-suggestion", _ctx.suggestionLoading && "is-loading"], style: { width: _ctx.dropdownWidth, outline: "none" }, role: "region" }, [ vue.createVNode(_component_el_scrollbar, { tag: "ul", "wrap-class": "el-autocomplete-suggestion__wrap", "view-class": "el-autocomplete-suggestion__list" }, { default: vue.withCtx(() => [ _ctx.suggestionLoading ? (vue.openBlock(), vue.createBlock("li", _hoisted_1, [ _hoisted_2 ])) : (vue.openBlock(true), vue.createBlock(vue.Fragment, { key: 1 }, vue.renderList(_ctx.suggestions, (item, index) => { return vue.openBlock(), vue.createBlock("li", { id: `${_ctx.id}-item-${index}`, key: index, class: { "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, ["id", "aria-selected", "onClick"]); }), 128)) ]), _: 3 }) ], 6) ]), _: 1 }, 8, ["visible", "placement", "popper-class", "append-to-body"]); } script.render = render; script.__file = "packages/autocomplete/src/index.vue"; script.install = (app) => { app.component(script.name, script); }; const _Autocomplete = script; exports.default = _Autocomplete;