UNPKG

vue-typeahead3

Version:

A super lightweight typeahead / autocompletion component for Vue.js 3. It's written in TypeScript using Vue.js 3 Composition API.

162 lines (161 loc) 6.32 kB
import { defineComponent, ref, toRefs, computed, watch, openBlock, createElementBlock, createElementVNode, withDirectives, normalizeClass, withKeys, vModelText, Fragment, renderList, toDisplayString, createTextVNode, unref, createCommentVNode, pushScopeId, popScopeId } from "vue"; var Typeahead_vue_vue_type_style_index_0_scoped_true_lang = ""; var _export_sfc = (sfc, props) => { const target = sfc.__vccOpts || sfc; for (const [key, val] of props) { target[key] = val; } return target; }; const _withScopeId = (n) => (pushScopeId("data-v-9737757a"), n = n(), popScopeId(), n); const _hoisted_1 = { class: "typeahead-container" }; const _hoisted_2 = { class: "search-container" }; const _hoisted_3 = ["placeholder"]; const _hoisted_4 = { key: 0, class: "results-container" }; const _hoisted_5 = { class: "results" }; const _hoisted_6 = ["onClick", "onMouseover"]; const _hoisted_7 = { class: "category" }; const _hoisted_8 = { key: 1 }; const _hoisted_9 = { key: 1, class: "results-container" }; const _hoisted_10 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ createElementVNode("ul", { class: "results" }, [ /* @__PURE__ */ createElementVNode("li", null, "No results found!") ], -1)); const _hoisted_11 = [ _hoisted_10 ]; const _sfc_main = defineComponent({ __name: "Typeahead", props: { modelValue: {}, suggestions: {}, placeholder: { default: "Type to search..." }, searchKey: { default: "value" }, categoryKey: { default: "category" }, valueKey: { default: "value" }, maxResults: { default: 5 } }, emits: ["update:modelValue"], setup(__props, { expose: __expose, emit: __emit }) { const props = __props; const emit = __emit; const searchTerm = ref(""); const selected = ref(false); const focused = ref(-1); const { valueKey, suggestions, searchKey, modelValue } = toRefs(props); const results = computed( () => { var _a; if (!((_a = searchTerm == null ? void 0 : searchTerm.value) == null ? void 0 : _a.length) || (selected == null ? void 0 : selected.value)) return []; return suggestions.value.filter( (entry) => entry[searchKey.value].toLowerCase().includes(searchTerm.value.toLowerCase()) ); } ); const select = (result) => { searchTerm.value = result[valueKey.value]; selected.value = true; return emit("update:modelValue", result); }; __expose({ select }); const handleArrow = (dir) => { if (dir < 0) { if (focused.value > 0) { focused.value--; } } else if (dir > 0 && focused.value < results.value.length - 1) { focused.value++; } }; const handleEsc = () => { searchTerm.value = ""; selected.value = false; focused.value = -1; return emit("update:modelValue", void 0); }; const handleClear = () => { if (!searchTerm.value) { handleEsc(); } }; const handleSelect = () => { const result = results.value[focused.value]; select(result); }; const focus = (index) => { focused.value = index; }; const isFocused = (index) => { return index === focused.value; }; watch(modelValue, (newVal, oldVal) => { if (newVal === oldVal) { return; } if (newVal && newVal[props.valueKey] !== (searchTerm == null ? void 0 : searchTerm.value)) { select(newVal); } if (!newVal && searchTerm.value && newVal[props.valueKey] !== searchTerm.value) { handleClear(); } }); watch(searchTerm, (newVal, oldVal) => { if (newVal !== oldVal && (!newVal || newVal.length === 0)) { selected.value = false; focused.value = -1; return emit("update:modelValue", void 0); } }); return (_ctx, _cache) => { return openBlock(), createElementBlock("div", _hoisted_1, [ createElementVNode("div", _hoisted_2, [ withDirectives(createElementVNode("input", { "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => searchTerm.value = $event), type: "search", placeholder: props.placeholder, class: normalizeClass({ "has-results": results.value.length }), onSearch: handleClear, onKeyup: [ _cache[1] || (_cache[1] = withKeys(($event) => handleArrow(-1), ["up"])), _cache[2] || (_cache[2] = withKeys(($event) => handleArrow(1), ["down"])), withKeys(handleEsc, ["esc"]), withKeys(handleSelect, ["enter"]) ] }, null, 42, _hoisted_3), [ [vModelText, searchTerm.value] ]) ]), results.value.length && !selected.value ? (openBlock(), createElementBlock("div", _hoisted_4, [ createElementVNode("ul", _hoisted_5, [ (openBlock(true), createElementBlock(Fragment, null, renderList(results.value, (result, index) => { return openBlock(), createElementBlock(Fragment, { key: index }, [ index < _ctx.maxResults ? (openBlock(), createElementBlock("li", { key: 0, class: normalizeClass({ focused: isFocused(index) }), onClick: ($event) => select(result), onMouseover: ($event) => focus(index), onMouseleave: _cache[3] || (_cache[3] = ($event) => focus(-1)) }, [ createElementVNode("h5", _hoisted_7, toDisplayString(result[_ctx.categoryKey]), 1), createTextVNode(" " + toDisplayString(result[unref(valueKey)]), 1) ], 42, _hoisted_6)) : createCommentVNode("", true), results.value.length === 0 ? (openBlock(), createElementBlock("li", _hoisted_8, "Test")) : createCommentVNode("", true) ], 64); }), 128)) ]) ])) : searchTerm.value && !results.value.length && !selected.value ? (openBlock(), createElementBlock("div", _hoisted_9, _hoisted_11)) : createCommentVNode("", true) ]); }; } }); var Typeahead = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-9737757a"]]); Typeahead.install = function(app) { app.component(Typeahead.name, Typeahead); }; export { Typeahead as default };