<!-- css -->
-<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/tomik23/autocomplete@1.8.1/dist/css/autocomplete.min.css"/>
+<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/tomik23/autocomplete@1.8.2/dist/css/autocomplete.min.css"/>
<!-- js -->
-<script src="https://cdn.jsdelivr.net/gh/tomik23/autocomplete@1.8.1/dist/js/autocomplete.min.js"></script>
+<script src="https://cdn.jsdelivr.net/gh/tomik23/autocomplete@1.8.2/dist/js/autocomplete.min.js"></script>
@@ -73,11 +73,11 @@
<!-- css -->
-<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/tomik23/autocomplete@1.8.1/dist/css/autocomplete.ie.min.css">
+<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/tomik23/autocomplete@1.8.2/dist/css/autocomplete.ie.min.css">
<!-- js -->
-<script src="https://cdn.jsdelivr.net/gh/tomik23/autocomplete@1.8.1/dist/js/polyfill.js"></script>
-<script src="https://cdn.jsdelivr.net/gh/tomik23/autocomplete@1.8.1/dist/js/autocomplete.ie.min.js"></script>
+<script src="https://cdn.jsdelivr.net/gh/tomik23/autocomplete@1.8.2/dist/js/polyfill.js"></script>
+<script src="https://cdn.jsdelivr.net/gh/tomik23/autocomplete@1.8.2/dist/js/autocomplete.ie.min.js"></script>
diff --git a/docs/js/autocomplete.min.js b/docs/js/autocomplete.min.js
index d7d7a5e..d00711a 100644
--- a/docs/js/autocomplete.min.js
+++ b/docs/js/autocomplete.min.js
@@ -1,2 +1,2 @@
-var Autocomplete=function(){"use strict";const t=(t,s)=>{for(let i in s)"addClass"===i?t.classList.add(s[i]):"removeClass"===i?t.classList.remove(s[i]):t.setAttribute(i,s[i])},s=(t,s)=>s.value=(t=>t.firstElementChild||t)(t).textContent.trim(),i=(t,s)=>{t.scrollTop=t.offsetTop-s.offsetHeight},h=(t,s)=>{t.setAttribute("aria-activedescendant",s||"")},e=(t,s,i,h)=>{const e=h.previousSibling,a=e?e.offsetHeight:0;if("0"==t.getAttribute("aria-posinset")&&(h.scrollTop=t.offsetTop-((t,s)=>{const i=document.querySelectorAll("#"+t+" > li:not(."+s+")");let h=0;return[].slice.call(i).map(t=>h+=t.offsetHeight),h})(s,i)),t.offsetTop-a
h.scrollTop+h.offsetHeight&&(h.scrollTop=s-h.offsetHeight)}},a=t=>document.createElement(t),l=27,n=13,o=38,r=40,c=9;return class{constructor(d,u){let{delay:m=500,clearButton:p=!0,howManyCharacters:b=1,selectFirst:v=!1,insertToInput:f=!1,showAllValues:x=!1,cache:C=!1,disableCloseOnSelect:y=!1,classGroup:k,classPreventClosing:w,classPrefix:j,ariaLabelClear:V,onSearch:g,onResults:S=(()=>{}),onSubmit:O=(()=>{}),onOpened:A=(()=>{}),onReset:I=(()=>{}),onRender:R=(()=>{}),onClose:P=(()=>{}),noResults:T=(()=>{}),onSelectedItem:B=(()=>{})}=u;var G;this.t=()=>{var s,i,h,e,a;this.s(),s=this.i,i=this.h,h=this.l,e=this.o,a=this.u,t(i,{id:h,tabIndex:"0",role:"listbox"}),t(e,{addClass:a+"-results-wrapper"}),e.insertAdjacentElement("beforeend",i),s.parentNode.insertBefore(e,s.nextSibling),this.i.addEventListener("input",this.m),this.p&&this.i.addEventListener("click",this.m),this.v({element:this.i,results:this.h})},this.C=(t,s)=>{this.k&&("update"===t?this.i.setAttribute(this.j,s.value):"remove"===t?this.i.removeAttribute(this.j):this.i.value=this.i.getAttribute(this.j))},this.m=t=>{let{target:s,type:i}=t;if("true"===this.i.getAttribute("aria-expanded")&&"click"===i)return;const h=s.value.replace(this.V,"\\$&");this.C("update",s);const e=this.p?0:this.g;clearTimeout(this.S),this.S=setTimeout(()=>{this.O(h.trim())},e)},this.A=()=>{var s;t(this.i,{"aria-owns":this.I+"-list","aria-expanded":"false","aria-autocomplete":"list","aria-activedescendant":"",role:"combobox",removeClass:"auto-expanded"}),this.o.classList.remove(this.R),(0==(null==(s=this.P)?void 0:s.length)&&!this.T||this.p)&&(this.h.innerHTML=""),this.B=this.G?0:-1,this.J()},this.O=t=>{this.N=t,this.$(!0),function(t,s){void 0===t&&(t=!1),t&&(t.classList.remove("hidden"),t.addEventListener("click",s))}(this.q,this.destroy),0==t.length&&this.F&&this.q.classList.add("hidden"),this.L>t.length&&!this.p?this.$():this.M({currentValue:t,element:this.i}).then(s=>{const i=this.i.value.length,h=s.length;this.P=Array.isArray(s)?[...s]:JSON.parse(JSON.stringify(s)),this.$(),this.D(),0==h&&0==i&&this.q.classList.add("hidden"),0==h&&i?(this.i.classList.remove("auto-expanded"),this.A(),this.H({element:this.i,currentValue:t,template:this.K}),this.U()):(h>0||(t=>t&&"object"==typeof t&&t.constructor===Object)(s))&&(this.B=this.G?0:-1,this.K(),this.U())}).catch(()=>{this.$(),this.A()})},this.$=t=>this.i.parentNode.classList[t?"add":"remove"](this.W),this.D=()=>this.i.classList.remove(this.X),this.U=()=>{this.i.addEventListener("keydown",this.Y),this.i.addEventListener("click",this.Z),["mousemove","click"].map(t=>{this.h.addEventListener(t,this._)}),document.addEventListener("click",this.tt)},this.K=s=>{t(this.i,{"aria-expanded":"true",addClass:this.u+"-expanded"}),this.h.innerHTML=0===this.P.length?this.st({currentValue:this.N,matches:0,template:s}):this.st({currentValue:this.N,matches:this.P,classGroup:this.it}),this.o.classList.add(this.R);const h=this.it?":not(."+this.it+")":"";this.ht=document.querySelectorAll("#"+this.l+" > li"+h),(s=>{for(let i=0;i{let{target:s}=t,i=null;(s.closest("ul")&&this.lt||s.closest("."+this.nt))&&(i=!0),s.id===this.I||i||this.A()},this.at=()=>{if(this.ot(document.querySelector("."+this.rt)),!this.G)return;const{firstElementChild:s}=this.h,i=this.it&&this.P.length>0&&this.G?s.nextElementSibling:s;this.ct({index:this.B,element:this.i,object:this.P[this.B]}),t(i,{id:this.dt+"-0",addClass:this.rt,"aria-selected":"true"}),h(this.i,this.dt+"-0")},this.Z=()=>{this.h.textContent.length>0&&!this.o.classList.contains(this.R)&&(t(this.i,{"aria-expanded":"true",addClass:this.u+"-expanded"}),this.o.classList.add(this.R),i(this.h,this.o),this.at(),this.et({type:"showItems",element:this.i,results:this.h}))},this._=t=>{t.preventDefault();const{target:s,type:i}=t,h=s.closest("li"),e=null==h?void 0:h.hasAttribute("role"),a=this.rt,l=document.querySelector("."+a);h&&e&&("click"===i&&this.ut(h),"mousemove"!==i||h.classList.contains(a)||(this.ot(l),this.pt(h),this.B=this.bt(h),this.ct({index:this.B,element:this.i,object:this.P[this.B]})))},this.ut=t=>{t&&0!==this.P.length?(s(t,this.i),this.vt({index:this.B,element:this.i,object:this.P[this.B],results:this.h}),this.lt||(this.ot(t),this.A()),this.F&&this.q.classList.remove("hidden"),this.C("remove")):!this.lt&&this.A()},this.bt=t=>Array.prototype.indexOf.call(this.ht,t),this.Y=t=>{const{keyCode:i}=t,e=this.o.classList.contains(this.R),a=this.P.length+1;switch(this.ft=document.querySelector("."+this.rt),i){case o:case r:if(t.preventDefault(),a<=1&&this.G||!e)return;i===o?(this.B<0&&(this.B=a-1),this.B-=1):(this.B+=1,this.B>=a&&(this.B=0)),this.ot(this.ft),a>0&&this.B>=0&&this.B{const i=this.dt+"-"+this.bt(s);t(s,{id:i,"aria-selected":"true",addClass:this.rt}),h(this.i,i),e(s,this.l,this.it,this.h)},this.ot=s=>{s&&t(s,{id:"",removeClass:this.rt,"aria-selected":"false"})},this.s=()=>{this.F&&(t(this.q,{class:this.u+"-clear hidden",type:"button",title:this.xt,"aria-label":this.xt}),this.i.insertAdjacentElement("afterend",this.q))},this.destroy=()=>{this.F&&this.q.classList.add("hidden"),this.i.value="",this.i.focus(),this.h.textContent="",this.A(),this.D(),this.Ct(this.i),this.i.removeEventListener("keydown",this.Y),this.i.removeEventListener("click",this.Z),document.removeEventListener("click",this.tt)},this.I=d,this.i=document.getElementById(d),this.M=(G=g,Boolean(G&&"function"==typeof G.then)?g:t=>{let{currentValue:s,element:i}=t;return Promise.resolve(g({currentValue:s,element:i}))}),this.st=S,this.v=R,this.vt=O,this.ct=B,this.et=A,this.Ct=I,this.H=T,this.J=P,this.g=m,this.L=b,this.F=p,this.G=v,this.T=f,this.p=x,this.it=k,this.nt=w,this.xt=V||"clear the search query",this.u=j?j+"-auto":"auto",this.lt=y,this.k=C,this.l=this.u+"-"+this.I+"-results",this.j="data-cache-auto-"+this.I,this.W=this.u+"-is-loading",this.R=this.u+"-is-active",this.rt=this.u+"-selected",this.dt=this.u+"-selected-option",this.X=this.u+"-error",this.V=/[|\\{}()[\]^$+*?.]/g,this.S=null,this.o=a("div"),this.h=a("ul"),this.q=a("button"),this.t()}}}();
+var Autocomplete=function(){"use strict";const t=(t,s)=>{for(let i in s)"addClass"===i?h(t,"add",s[i]):"removeClass"===i?h(t,"remove",s[i]):t.setAttribute(i,s[i])},s=t=>(t.firstElementChild||t).textContent.trim(),i=(t,s)=>{t.scrollTop=t.offsetTop-s.offsetHeight},h=(t,s,i)=>t.classList[s](i),e=(s,i)=>{t(s,{"aria-activedescendant":i||""})},a=(t,s,i,h)=>{const e=h.previousSibling,a=e?e.offsetHeight:0;if("0"==t.getAttribute("aria-posinset")&&(h.scrollTop=t.offsetTop-((t,s)=>{const i=document.querySelectorAll("#"+t+" > li:not(."+s+")");let h=0;return[].slice.call(i).map(t=>h+=t.offsetHeight),h})(s,i)),t.offsetTop-ah.scrollTop+h.offsetHeight&&(h.scrollTop=s-h.offsetHeight)}},n=t=>document.createElement(t),l=t=>document.querySelector(t),o=(t,s,i)=>{t.addEventListener(s,i)},r=(t,s,i)=>{t.removeEventListener(s,i)},c=27,d=13,u=38,m=40,p=9;return class{constructor(v,b){let{delay:f=500,clearButton:x=!0,howManyCharacters:C=1,selectFirst:y=!1,insertToInput:k=!1,showAllValues:w=!1,cache:g=!1,disableCloseOnSelect:j=!1,classGroup:V,classPreventClosing:S,classPrefix:O,ariaLabelClear:A,onSearch:I,onResults:R=(()=>{}),onSubmit:P=(()=>{}),onOpened:T=(()=>{}),onReset:B=(()=>{}),onRender:G=(()=>{}),onClose:J=(()=>{}),noResults:N=(()=>{}),onSelectedItem:$=(()=>{})}=b;var q;this.t=()=>{var s,i,h,e,a;this.s(),s=this.i,i=this.h,h=this.l,e=this.o,a=this.u,t(i,{id:h,tabIndex:"0",role:"listbox"}),t(e,{addClass:a+"-results-wrapper"}),e.insertAdjacentElement("beforeend",i),s.parentNode.insertBefore(e,s.nextSibling),o(this.i,"input",this.m),this.p&&o(this.i,"click",this.m),this.v({element:this.i,results:this.h})},this.C=(t,s)=>{this.k&&("update"===t?this.i.setAttribute(this.g,s.value):"remove"===t?this.i.removeAttribute(this.g):this.i.value=this.i.getAttribute(this.g))},this.m=t=>{let{target:s,type:i}=t;if("true"===this.i.getAttribute("aria-expanded")&&"click"===i)return;const h=s.value.replace(this.j,"\\$&");this.C("update",s);const e=this.p?0:this.V;clearTimeout(this.S),this.S=setTimeout(()=>{this.O(h.trim())},e)},this.A=()=>{t(this.i,{"aria-owns":this.I+"-list","aria-expanded":"false","aria-autocomplete":"list","aria-activedescendant":"",role:"combobox",removeClass:"auto-expanded"}),h(this.o,"remove",this.R),this.P=this.T?0:-1,this.B()},this.O=t=>{this.G=t,this.J(!0),function(t,s){void 0===t&&(t=!1),t&&(h(t,"remove","hidden"),o(t,"click",s))}(this.N,this.destroy),0==t.length&&this.$&&h(this.N,"add","hidden"),this.q>t.length&&!this.p?this.J():this.F({currentValue:t,element:this.i}).then(s=>{const i=this.i.value.length,e=s.length;this.L=Array.isArray(s)?s:JSON.parse(JSON.stringify(s)),this.J(),this.M(),0==e&&0==i&&h(this.N,"add","hidden"),0==e&&i?(h(this.i,"remove","auto-expanded"),this.A(),this.D({element:this.i,currentValue:t,template:this.H}),this.K()):(e>0||(t=>t&&"object"==typeof t&&t.constructor===Object)(s))&&(this.P=this.T?0:-1,this.H(),this.K())}).catch(()=>{this.J(),this.A()})},this.J=t=>this.i.parentNode.classList[t?"add":"remove"](this.U),this.M=()=>h(this.i,"remove",this.W),this.K=()=>{o(this.i,"keydown",this.X),o(this.i,"click",this.Y),["mousemove","click"].map(t=>{o(this.h,t,this.Z)}),o(document,"click",this._)},this.H=s=>{t(this.i,{"aria-expanded":"true",addClass:this.u+"-expanded"}),this.h.textContent="";const e=0===this.L.length?this.tt({currentValue:this.G,matches:0,template:s}):this.tt({currentValue:this.G,matches:this.L,classGroup:this.st});this.h.insertAdjacentHTML("afterbegin",e),h(this.o,"add",this.R);const a=this.st?":not(."+this.st+")":"";this.it=document.querySelectorAll("#"+this.l+" > li"+a),(s=>{for(let i=0;i{let{target:s}=t,i=null;(s.closest("ul")&&this.at||s.closest("."+this.nt))&&(i=!0),s.id===this.I||i||this.A()},this.et=()=>{if(this.lt(l("."+this.ot)),!this.T)return;const{firstElementChild:s}=this.h,i=this.st&&this.L.length>0&&this.T?s.nextElementSibling:s;this.rt({index:this.P,element:this.i,object:this.L[this.P]}),t(i,{id:this.ct+"-0",addClass:this.ot,"aria-selected":"true"}),e(this.i,this.ct+"-0")},this.Y=()=>{this.h.textContent.length>0&&!h(this.o,"contains",this.R)&&(t(this.i,{"aria-expanded":"true",addClass:this.u+"-expanded"}),h(this.o,"add",this.R),i(this.h,this.o),this.et(),this.ht({type:"showItems",element:this.i,results:this.h}))},this.Z=t=>{t.preventDefault();const{target:s,type:i}=t,e=s.closest("li"),a=null==e?void 0:e.hasAttribute("role"),n=this.ot,o=l("."+n);e&&a&&("click"===i&&this.dt(e),"mousemove"!==i||h(e,"contains",n)||(this.lt(o),this.ut(e),this.P=this.pt(e),this.rt({index:this.P,element:this.i,object:this.L[this.P]})))},this.dt=t=>{t&&0!==this.L.length?(this.i.value=s(t),this.vt({index:this.P,element:this.i,object:this.L[this.P],results:this.h}),this.at||(this.lt(t),this.A()),this.$&&h(this.N,"remove","hidden"),this.C("remove")):!this.at&&this.A()},this.pt=t=>Array.prototype.indexOf.call(this.it,t),this.X=t=>{const{keyCode:i}=t,a=h(this.o,"contains",this.R),n=this.L.length+1;switch(this.bt=l("."+this.ot),i){case u:case m:if(t.preventDefault(),n<=1&&this.T||!a)return;i===u?(this.P<0&&(this.P=n-1),this.P-=1):(this.P+=1,this.P>=n&&(this.P=0)),this.lt(this.bt),this.P>=0&&this.P{const i=this.ct+"-"+this.pt(s);t(s,{id:i,"aria-selected":"true",addClass:this.ot}),e(this.i,i),a(s,this.l,this.st,this.h)},this.lt=s=>{s&&t(s,{id:"",removeClass:this.ot,"aria-selected":"false"})},this.s=()=>{this.$&&(t(this.N,{class:this.u+"-clear hidden",type:"button",title:this.xt,"aria-label":this.xt}),this.i.insertAdjacentElement("afterend",this.N))},this.destroy=()=>{this.$&&h(this.N,"add","hidden"),this.i.value="",this.i.focus(),this.h.textContent="",this.A(),this.M(),this.Ct(this.i),r(this.i,"keydown",this.X),r(this.i,"click",this.Y),r(document,"click",this._)},this.I=v,this.i=document.getElementById(v),this.F=(q=I,Boolean(q&&"function"==typeof q.then)?I:t=>{let{currentValue:s,element:i}=t;return Promise.resolve(I({currentValue:s,element:i}))}),this.tt=R,this.v=G,this.vt=P,this.rt=$,this.ht=T,this.Ct=B,this.D=N,this.B=J,this.V=f,this.q=C,this.$=x,this.T=y,this.ft=k,this.p=w,this.st=V,this.nt=S,this.xt=A||"clear the search query",this.u=O?O+"-auto":"auto",this.at=j,this.k=g,this.l=this.u+"-"+this.I+"-results",this.g="data-cache-auto-"+this.I,this.U=this.u+"-is-loading",this.R=this.u+"-is-active",this.ot=this.u+"-selected",this.ct=this.u+"-selected-option",this.W=this.u+"-error",this.j=/[|\\{}()[\]^$+*?.]/g,this.S=null,this.o=n("div"),this.h=n("ul"),this.N=n("button"),this.t()}}}();
//# sourceMappingURL=autocomplete.min.js.map
diff --git a/docs/js/autocomplete.min.js.map b/docs/js/autocomplete.min.js.map
index c6f56cb..de896b4 100644
--- a/docs/js/autocomplete.min.js.map
+++ b/docs/js/autocomplete.min.js.map
@@ -1 +1 @@
-{"version":3,"file":"autocomplete.min.js","sources":["../../sources/js/utils/function.js","../../sources/js/utils/keyCodes.js","../../sources/js/script.js"],"sourcesContent":["/**\r\n * Check is a Object\r\n * @param {Object} value\r\n * @returns {Boolean}\r\n */\r\nconst isObject = (value) =>\r\n value && typeof value === \"object\" && value.constructor === Object;\r\n\r\n/**\r\n * Check if is a Promise\r\n * https://stackoverflow.com/a/53955664/10424385\r\n *\r\n * @param {Object} value\r\n * @returns {Boolean}\r\n */\r\nconst isPromise = (value) => Boolean(value && typeof value.then === \"function\");\r\n\r\n/**\r\n * Set attributes to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {Object} object\r\n */\r\nconst setAttributes = (el, object) => {\r\n for (let key in object) {\r\n if (key === \"addClass\") {\r\n el.classList.add(object[key]);\r\n } else if (key === \"removeClass\") {\r\n el.classList.remove(object[key]);\r\n } else {\r\n el.setAttribute(key, object[key]);\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Get first element from child\r\n *\r\n * @param {HTMLElement} element\r\n * @returns {HTMLELement}\r\n */\r\nconst getFirstElement = (element) => element.firstElementChild || element;\r\n\r\n/**\r\n * Set data from li to input\r\n *\r\n * @param {String} element\r\n * @param {HTMLElement} root\r\n * @returns {String}\r\n */\r\nconst getFirstElementFromLiAndAddToInput = (element, root) =>\r\n // get first element from li and add to input\r\n (root.value = getFirstElement(element).textContent.trim());\r\n\r\n/**\r\n * Scroll to top result-list\r\n * @param {HTMLElement} resultList\r\n * @param {HTMLElement} resultWrap\r\n */\r\nconst scrollResultsToTop = (resultList, resultWrap) => {\r\n // if there is an overflow of ul element, after\r\n // opening we always move ul to the top of the results\r\n resultList.scrollTop = resultList.offsetTop - resultWrap.offsetHeight;\r\n};\r\n\r\n/**\r\n * Adding role, tabindex, aria and call handleMouse\r\n *\r\n * @param {HTMLElement} itemsLi\r\n */\r\nconst addAriaToAllLiElements = (itemsLi) => {\r\n // add role to all li elements\r\n for (let i = 0; i < itemsLi.length; i++) {\r\n setAttributes(itemsLi[i], {\r\n role: \"option\",\r\n tabindex: \"-1\",\r\n \"aria-selected\": \"false\",\r\n \"aria-setsize\": itemsLi.length,\r\n \"aria-posinset\": i,\r\n });\r\n }\r\n};\r\n\r\n/**\r\n * Show btn to clear data\r\n *\r\n * @param {HTMLElement} clearButton - button to clear data\r\n * @param {Function} destroy - destroy function\r\n */\r\nconst showBtnToClearData = (clearButton = false, destroy) => {\r\n if (!clearButton) return;\r\n\r\n clearButton.classList.remove(\"hidden\");\r\n // add event to clear button\r\n clearButton.addEventListener(\"click\", destroy);\r\n};\r\n\r\n/**\r\n * Set aria-activedescendant\r\n *\r\n * @param {HTMLElement} root - search input\r\n * @param {String} type\r\n */\r\nconst setAriaActivedescendant = (root, type) => {\r\n root.setAttribute(\"aria-activedescendant\", type || \"\");\r\n};\r\n\r\n/**\r\n * Get height of ul without group class\r\n *\r\n * @param {String} outputUl\r\n * @param {String} classGroup\r\n * @returns {Number}\r\n */\r\nconst getClassGroupHeight = (outputUl, classGroup) => {\r\n // get height of ul without group class\r\n const allLi = document.querySelectorAll(\r\n `#${outputUl} > li:not(.${classGroup})`\r\n );\r\n let height = 0;\r\n [].slice.call(allLi).map((el) => (height += el.offsetHeight));\r\n\r\n // return height\r\n return height;\r\n};\r\n\r\n/**\r\n * Scroll into view when press up/down arrows\r\n *\r\n * @param {HTMLElement} target\r\n * @param {HTMLElement} outputUl\r\n * @param {String} classGroup\r\n * @param {HTMLElement} resultList\r\n */\r\nconst followActiveElement = (target, outputUl, classGroup, resultList) => {\r\n const previusElement = resultList.previousSibling;\r\n\r\n const previusElementHeight = previusElement ? previusElement.offsetHeight : 0;\r\n\r\n if (target.getAttribute(\"aria-posinset\") == \"0\") {\r\n resultList.scrollTop =\r\n target.offsetTop - getClassGroupHeight(outputUl, classGroup);\r\n }\r\n\r\n if (target.offsetTop - previusElementHeight < resultList.scrollTop) {\r\n resultList.scrollTop = target.offsetTop - previusElementHeight;\r\n } else {\r\n const offsetBottom =\r\n target.offsetTop + target.offsetHeight - previusElementHeight;\r\n const scrollBottom = resultList.scrollTop + resultList.offsetHeight;\r\n if (offsetBottom > scrollBottom) {\r\n resultList.scrollTop = offsetBottom - resultList.offsetHeight;\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Create output-list and put after search input\r\n *\r\n * @param {HTMLElement} root - search input\r\n * @param {HTMLElement} resultList - output-list ul\r\n * @param {String} outputUl - id name of output-list\r\n * @param {HTMLElement} resultWrap - wrapper ul element\r\n * @param {String} prefix - add prefix to all class auto\r\n */\r\nconst output = (root, resultList, outputUl, resultWrap, prefix) => {\r\n // set attribute to results-list\r\n setAttributes(resultList, {\r\n id: outputUl,\r\n tabIndex: \"0\",\r\n role: \"listbox\",\r\n });\r\n\r\n // add class to wrap element\r\n setAttributes(resultWrap, {\r\n addClass: `${prefix}-results-wrapper`,\r\n });\r\n\r\n // insert the results into the wrap element\r\n resultWrap.insertAdjacentElement(\"beforeend\", resultList);\r\n\r\n // insert the wrap element after the search input\r\n root.parentNode.insertBefore(resultWrap, root.nextSibling);\r\n};\r\n\r\n/**\r\n * Create element\r\n *\r\n * @param {String} type - type of element\r\n * @returns {HTMLDivElement}\r\n */\r\nconst createElement = (type) => document.createElement(type);\r\n\r\nexport {\r\n addAriaToAllLiElements,\r\n createElement,\r\n followActiveElement,\r\n getFirstElementFromLiAndAddToInput,\r\n isObject,\r\n isPromise,\r\n output,\r\n scrollResultsToTop,\r\n setAriaActivedescendant,\r\n setAttributes,\r\n showBtnToClearData,\r\n};\r\n","/**\r\n * Key codes\r\n */\r\nconst keyCodes = {\r\n ESC: 27,\r\n ENTER: 13,\r\n UP: 38,\r\n DOWN: 40,\r\n TAB: 9,\r\n};\r\n\r\nexport default keyCodes;\r\n","import {\r\n addAriaToAllLiElements,\r\n createElement,\r\n followActiveElement,\r\n getFirstElementFromLiAndAddToInput,\r\n isObject,\r\n isPromise,\r\n output,\r\n scrollResultsToTop,\r\n setAriaActivedescendant,\r\n setAttributes,\r\n showBtnToClearData,\r\n} from \"./utils/function\";\r\n\r\nimport keyCodes from \"./utils/keyCodes\";\r\n\r\n/**\r\n * @class Autocomplete\r\n */\r\nexport default class Autocomplete {\r\n /**\r\n * Constructor\r\n *\r\n * @param {String} element\r\n * @param {Object} object\r\n */\r\n constructor(\r\n element,\r\n {\r\n delay = 500,\r\n clearButton = true,\r\n howManyCharacters = 1,\r\n selectFirst = false,\r\n insertToInput = false,\r\n showAllValues = false,\r\n cache = false,\r\n disableCloseOnSelect = false,\r\n classGroup,\r\n classPreventClosing,\r\n classPrefix,\r\n ariaLabelClear,\r\n onSearch,\r\n onResults = () => {},\r\n onSubmit = () => {},\r\n onOpened = () => {},\r\n onReset = () => {},\r\n onRender = () => {},\r\n onClose = () => {},\r\n noResults = () => {},\r\n onSelectedItem = () => {},\r\n }\r\n ) {\r\n this._id = element;\r\n this._root = document.getElementById(element);\r\n this._onSearch = isPromise(onSearch)\r\n ? onSearch\r\n : ({ currentValue, element }) =>\r\n Promise.resolve(onSearch({ currentValue, element }));\r\n this._onResults = onResults;\r\n this._onRender = onRender;\r\n this._onSubmit = onSubmit;\r\n this._onSelected = onSelectedItem;\r\n this._onOpened = onOpened;\r\n this._onReset = onReset;\r\n this._noResults = noResults;\r\n this._onClose = onClose;\r\n\r\n this._delay = delay;\r\n this._characters = howManyCharacters;\r\n this._clearButton = clearButton;\r\n this._selectFirst = selectFirst;\r\n this._toInput = insertToInput;\r\n this._showAll = showAllValues;\r\n this._classGroup = classGroup;\r\n this._prevClosing = classPreventClosing;\r\n this._clearBtnAriLabel = ariaLabelClear\r\n ? ariaLabelClear\r\n : \"clear the search query\";\r\n this._prefix = classPrefix ? `${classPrefix}-auto` : \"auto\";\r\n this._disable = disableCloseOnSelect;\r\n\r\n // default config\r\n this._cache = cache;\r\n this._outputUl = `${this._prefix}-${this._id}-results`;\r\n this._cacheData = `data-cache-auto-${this._id}`;\r\n this._isLoading = `${this._prefix}-is-loading`;\r\n this._isActive = `${this._prefix}-is-active`;\r\n this._activeList = `${this._prefix}-selected`;\r\n this._selectedOption = `${this._prefix}-selected-option`;\r\n this._err = `${this._prefix}-error`;\r\n this._regex = /[|\\\\{}()[\\]^$+*?.]/g;\r\n this._timeout = null;\r\n\r\n this._resultWrap = createElement(\"div\");\r\n this._resultList = createElement(\"ul\");\r\n this._cBtn = createElement(\"button\");\r\n\r\n this._initial();\r\n }\r\n\r\n /**\r\n * Initial function\r\n */\r\n _initial = () => {\r\n this._clearbutton();\r\n\r\n output(\r\n this._root,\r\n this._resultList,\r\n this._outputUl,\r\n this._resultWrap,\r\n this._prefix\r\n );\r\n\r\n // default aria\r\n // this.reset();\r\n this._root.addEventListener(\"input\", this._handleInput);\r\n\r\n // show all values on click root input\r\n this._showAll && this._root.addEventListener(\"click\", this._handleInput);\r\n\r\n // calback functions\r\n this._onRender({\r\n element: this._root,\r\n results: this._resultList,\r\n });\r\n };\r\n\r\n /**\r\n * Actions on input\r\n *\r\n * @param {String} type - set attribute depending on type\r\n * @param {String} target\r\n */\r\n _cacheAct = (type, target) => {\r\n if (!this._cache) return;\r\n\r\n if (type === \"update\") {\r\n this._root.setAttribute(this._cacheData, target.value);\r\n } else if (type === \"remove\") {\r\n this._root.removeAttribute(this._cacheData);\r\n } else {\r\n this._root.value = this._root.getAttribute(this._cacheData);\r\n }\r\n };\r\n\r\n /**\r\n * Handle input\r\n *\r\n * @param {Event} object\r\n */\r\n _handleInput = ({ target, type }) => {\r\n if (\r\n this._root.getAttribute(\"aria-expanded\") === \"true\" &&\r\n type === \"click\"\r\n ) {\r\n return;\r\n }\r\n\r\n // replace all special characters\r\n const regex = target.value.replace(this._regex, \"\\\\$&\");\r\n\r\n // update data attribute cache\r\n this._cacheAct(\"update\", target);\r\n\r\n const delay = this._showAll ? 0 : this._delay;\r\n // clear timeout\r\n clearTimeout(this._timeout);\r\n this._timeout = setTimeout(() => {\r\n this._searchItem(regex.trim());\r\n }, delay);\r\n };\r\n\r\n /**\r\n * Default aria\r\n */\r\n _reset = () => {\r\n // set attributes to root - input\r\n setAttributes(this._root, {\r\n \"aria-owns\": `${this._id}-list`,\r\n \"aria-expanded\": \"false\",\r\n \"aria-autocomplete\": \"list\",\r\n \"aria-activedescendant\": \"\",\r\n role: \"combobox\",\r\n removeClass: \"auto-expanded\",\r\n });\r\n\r\n // remove class isActive\r\n this._resultWrap.classList.remove(this._isActive);\r\n\r\n // move the view item to the first item\r\n // this.resultList.scrollTop = 0;\r\n // scrollResultsToTop(this.resultList, this.resultWrap);\r\n\r\n // remove result when lengh = 0 and insertToInput is false\r\n if ((this._matches?.length == 0 && !this._toInput) || this._showAll) {\r\n this._resultList.innerHTML = \"\";\r\n }\r\n\r\n // set index\r\n this._index = this._selectFirst ? 0 : -1;\r\n\r\n // callback function\r\n this._onClose();\r\n };\r\n\r\n /**\r\n * The async function gets the text from the search\r\n * and returns the matching array\r\n *\r\n * @param {String} value\r\n */\r\n _searchItem = (value) => {\r\n this._value = value;\r\n\r\n // if searching show loading icon\r\n this._onLoading(true);\r\n\r\n // hide button clear\r\n showBtnToClearData(this._cBtn, this.destroy);\r\n\r\n // if there is no value and clearButton is true\r\n if (value.length == 0 && this._clearButton) {\r\n this._cBtn.classList.add(\"hidden\");\r\n }\r\n\r\n // if declare characters more then value.len and showAll is false\r\n // remove class isActive\r\n if (this._characters > value.length && !this._showAll) {\r\n this._onLoading();\r\n return;\r\n }\r\n\r\n // callblack function onSearch\r\n this._onSearch({ currentValue: value, element: this._root })\r\n .then((result) => {\r\n const rootValueLength = this._root.value.length;\r\n const resultLength = result.length;\r\n // set no result\r\n this._matches = Array.isArray(result)\r\n ? [...result]\r\n : JSON.parse(JSON.stringify(result));\r\n\r\n this._onLoading();\r\n this._error();\r\n\r\n // if use destroy() method\r\n if (resultLength == 0 && rootValueLength == 0) {\r\n this._cBtn.classList.add(\"hidden\");\r\n }\r\n\r\n if (resultLength == 0 && rootValueLength) {\r\n this._root.classList.remove(\"auto-expanded\");\r\n this._reset();\r\n this._noResults({\r\n element: this._root,\r\n currentValue: value,\r\n template: this._results,\r\n });\r\n this._events();\r\n } else if (resultLength > 0 || isObject(result)) {\r\n this._index = this._selectFirst ? 0 : -1;\r\n this._results();\r\n this._events();\r\n }\r\n })\r\n .catch(() => {\r\n this._onLoading();\r\n this._reset();\r\n });\r\n };\r\n\r\n /**\r\n * Set or remove loading class\r\n *\r\n * @param {Boolean} type\r\n */\r\n _onLoading = (type) =>\r\n this._root.parentNode.classList[type ? \"add\" : \"remove\"](this._isLoading);\r\n\r\n /**\r\n * Set error class to the root element\r\n */\r\n _error = () => this._root.classList.remove(this._err);\r\n\r\n /**\r\n * Events\r\n */\r\n _events = () => {\r\n // handle click on keydown [up, down, enter, tab, esc]\r\n this._root.addEventListener(\"keydown\", this._handleKeys);\r\n\r\n //\r\n this._root.addEventListener(\"click\", this._handleShowItems);\r\n\r\n // temporarily disabled mouseleave\r\n [\"mousemove\", \"click\"].map((eventType) => {\r\n this._resultList.addEventListener(eventType, this._handleMouse);\r\n });\r\n\r\n // close expanded items\r\n document.addEventListener(\"click\", this._handleDocClick);\r\n };\r\n\r\n /**\r\n * Results\r\n *\r\n * @param {HTMLElement|String} template - html or string returned from the function,\r\n * look at the example - https://github.com/tomik23/autocomplete/blob/master/docs/js/examples/no-results.js#L30\r\n */\r\n _results = (template) => {\r\n // set attribute to root\r\n setAttributes(this._root, {\r\n \"aria-expanded\": \"true\",\r\n addClass: `${this._prefix}-expanded`,\r\n });\r\n\r\n // add all found records to otput ul\r\n this._resultList.innerHTML =\r\n this._matches.length === 0\r\n ? this._onResults({\r\n currentValue: this._value,\r\n matches: 0,\r\n template,\r\n })\r\n : this._onResults({\r\n currentValue: this._value,\r\n matches: this._matches,\r\n classGroup: this._classGroup,\r\n });\r\n\r\n this._resultWrap.classList.add(this._isActive);\r\n\r\n const checkIfClassGroupExist = this._classGroup\r\n ? `:not(.${this._classGroup})`\r\n : \"\";\r\n\r\n this._itemsLi = document.querySelectorAll(\r\n `#${this._outputUl} > li${checkIfClassGroupExist}`\r\n );\r\n\r\n // adding role, tabindex and aria\r\n addAriaToAllLiElements(this._itemsLi);\r\n\r\n // action on open results\r\n this._onOpened({\r\n type: \"results\",\r\n element: this._root,\r\n results: this._resultList,\r\n });\r\n\r\n // select first element\r\n this._selectFirstEl();\r\n\r\n // move the view item to the first item\r\n // this.resultList.scrollTop = 0;\r\n scrollResultsToTop(this._resultList, this._resultWrap);\r\n };\r\n\r\n /**\r\n * Hangle click on document\r\n *\r\n * @param {Event} object\r\n */\r\n _handleDocClick = ({ target }) => {\r\n let disableClose = null;\r\n\r\n // if 'target' is a ul and 'disableCloseOnSelect'\r\n // is a 'true' set 'disableClose' on true\r\n if (\r\n (target.closest(\"ul\") && this._disable) ||\r\n // when class classDisableClose\r\n // then do not not close results\r\n target.closest(`.${this._prevClosing}`)\r\n ) {\r\n disableClose = true;\r\n }\r\n\r\n if (target.id !== this._id && !disableClose) {\r\n this._reset();\r\n return;\r\n }\r\n };\r\n\r\n /**\r\n * Select first element\r\n */\r\n _selectFirstEl = () => {\r\n this._remAria(document.querySelector(`.${this._activeList}`));\r\n\r\n if (!this._selectFirst) {\r\n return;\r\n }\r\n\r\n const { firstElementChild } = this._resultList;\r\n\r\n const classSelectFirst =\r\n this._classGroup && this._matches.length > 0 && this._selectFirst\r\n ? firstElementChild.nextElementSibling\r\n : firstElementChild;\r\n\r\n // calback function onSelect when first element is true\r\n this._onSelected({\r\n index: this._index,\r\n element: this._root,\r\n object: this._matches[this._index],\r\n });\r\n\r\n // set attribute to first element\r\n setAttributes(classSelectFirst, {\r\n id: `${this._selectedOption}-0`,\r\n addClass: this._activeList,\r\n \"aria-selected\": \"true\",\r\n });\r\n\r\n // set aria active descendant\r\n setAriaActivedescendant(this._root, `${this._selectedOption}-0`);\r\n };\r\n\r\n /**\r\n * show items when items.length > 0 and is not empty\r\n */\r\n _handleShowItems = () => {\r\n // if resultWrap is not active and resultList is not empty\r\n if (\r\n this._resultList.textContent.length > 0 &&\r\n !this._resultWrap.classList.contains(this._isActive)\r\n ) {\r\n // set attribute to root\r\n setAttributes(this._root, {\r\n \"aria-expanded\": \"true\",\r\n addClass: `${this._prefix}-expanded`,\r\n });\r\n\r\n // add isActive class to resultWrap\r\n this._resultWrap.classList.add(this._isActive);\r\n\r\n // move the view item to the first item\r\n // this.resultList.scrollTop = 0;\r\n scrollResultsToTop(this._resultList, this._resultWrap);\r\n\r\n // select first element\r\n this._selectFirstEl();\r\n\r\n // callback function\r\n this._onOpened({\r\n type: \"showItems\",\r\n element: this._root,\r\n results: this._resultList,\r\n });\r\n }\r\n };\r\n\r\n /**\r\n * Adding text from the list when li is clicking\r\n * or adding aria-selected to li elements\r\n *\r\n * @param {Event} event\r\n */\r\n _handleMouse = (event) => {\r\n event.preventDefault();\r\n\r\n const { target, type } = event;\r\n const targetClosest = target.closest(\"li\");\r\n const targetClosestRole = targetClosest?.hasAttribute(\"role\");\r\n const activeClass = this._activeList;\r\n const activeClassElement = document.querySelector(`.${activeClass}`);\r\n\r\n if (!targetClosest || !targetClosestRole) {\r\n return;\r\n }\r\n\r\n // click on li get element\r\n if (type === \"click\") {\r\n // get text from clicked li\r\n this._getTextFromLi(targetClosest);\r\n }\r\n\r\n if (\r\n type === \"mousemove\" &&\r\n !targetClosest.classList.contains(activeClass)\r\n ) {\r\n this._remAria(activeClassElement);\r\n\r\n // add aria to li\r\n this._setAria(targetClosest);\r\n this._index = this._indexLiSelected(targetClosest);\r\n\r\n this._onSelected({\r\n index: this._index,\r\n element: this._root,\r\n object: this._matches[this._index],\r\n });\r\n }\r\n };\r\n\r\n /**\r\n * Get text from li on enter or click\r\n *\r\n * @param {HTMLElement} element\r\n */\r\n _getTextFromLi = (element) => {\r\n if (!element || this._matches.length === 0) {\r\n // set default settings\r\n !this._disable && this._reset();\r\n\r\n return;\r\n }\r\n\r\n // get first element from li and set it to root\r\n getFirstElementFromLiAndAddToInput(element, this._root);\r\n\r\n // onSubmit passing text to function\r\n this._onSubmit({\r\n index: this._index,\r\n element: this._root,\r\n object: this._matches[this._index],\r\n results: this._resultList,\r\n });\r\n\r\n // set default settings\r\n if (!this._disable) {\r\n this._remAria(element);\r\n this._reset();\r\n }\r\n\r\n // show clearBtn when select element\r\n this._clearButton && this._cBtn.classList.remove(\"hidden\");\r\n\r\n // remove cache\r\n this._cacheAct(\"remove\");\r\n };\r\n\r\n /**\r\n * Return which li element was selected\r\n * by hovering the mouse over\r\n *\r\n * @param {HTMLElement} target\r\n * @returns {Number}\r\n */\r\n _indexLiSelected = (target) =>\r\n // get index of li element\r\n Array.prototype.indexOf.call(this._itemsLi, target);\r\n\r\n /**\r\n * Navigating the elements li and enter\r\n *\r\n * @param {Event} event\r\n */\r\n _handleKeys = (event) => {\r\n const { keyCode } = event;\r\n\r\n const resultList = this._resultWrap.classList.contains(this._isActive);\r\n\r\n const matchesLength = this._matches.length + 1;\r\n this._selectedLi = document.querySelector(`.${this._activeList}`);\r\n\r\n // switch between keys\r\n switch (keyCode) {\r\n case keyCodes.UP:\r\n case keyCodes.DOWN:\r\n // Wrong cursor position in the input field #62\r\n // Prevents the cursor from moving to the beginning\r\n // of input as the cursor hovers over the results.\r\n event.preventDefault();\r\n\r\n if ((matchesLength <= 1 && this._selectFirst) || !resultList) {\r\n return;\r\n }\r\n\r\n // if keyCode is up\r\n if (keyCode === keyCodes.UP) {\r\n if (this._index < 0) {\r\n this._index = matchesLength - 1;\r\n }\r\n this._index -= 1;\r\n } else {\r\n this._index += 1;\r\n if (this._index >= matchesLength) {\r\n this._index = 0;\r\n }\r\n }\r\n\r\n // remove aria-selected\r\n this._remAria(this._selectedLi);\r\n\r\n if (\r\n matchesLength > 0 &&\r\n this._index >= 0 &&\r\n this._index < matchesLength - 1\r\n ) {\r\n if (this._toInput && resultList) {\r\n getFirstElementFromLiAndAddToInput(\r\n this._itemsLi[this._index],\r\n this._root\r\n );\r\n }\r\n\r\n // callback function\r\n this._onSelected({\r\n index: this._index,\r\n element: this._root,\r\n object: this._matches[this._index],\r\n });\r\n\r\n // set aria-selected\r\n this._setAria(this._itemsLi[this._index]);\r\n } else {\r\n // catch action\r\n this._cacheAct();\r\n setAriaActivedescendant(this._root);\r\n\r\n this._onSelected({\r\n index: null,\r\n element: this._root,\r\n object: null,\r\n });\r\n }\r\n\r\n break;\r\n // keycode enter\r\n case keyCodes.ENTER:\r\n this._getTextFromLi(this._selectedLi);\r\n break;\r\n\r\n // keycode escape and keycode tab\r\n case keyCodes.TAB:\r\n case keyCodes.ESC:\r\n event.stopPropagation(); // #120\r\n this._reset();\r\n\r\n break;\r\n default:\r\n break;\r\n }\r\n };\r\n\r\n /**\r\n * Set aria label on item li\r\n *\r\n * @param {HTMLElement} target\r\n */\r\n _setAria = (target) => {\r\n const selectedOption = `${this._selectedOption}-${this._indexLiSelected(\r\n target\r\n )}`;\r\n\r\n // set aria to li\r\n setAttributes(target, {\r\n id: selectedOption,\r\n \"aria-selected\": \"true\",\r\n addClass: this._activeList,\r\n });\r\n\r\n setAriaActivedescendant(this._root, selectedOption);\r\n\r\n // scrollIntoView when press up/down arrows\r\n followActiveElement(\r\n target,\r\n this._outputUl,\r\n this._classGroup,\r\n this._resultList\r\n );\r\n };\r\n\r\n /**\r\n * Remove aria label from item li\r\n *\r\n * @param {HTMLElement} element\r\n */\r\n _remAria = (element) => {\r\n if (!element) return;\r\n\r\n // remove aria from li\r\n setAttributes(element, {\r\n id: \"\",\r\n removeClass: this._activeList,\r\n \"aria-selected\": \"false\",\r\n });\r\n };\r\n\r\n /**\r\n * Create clear button and\r\n * removing text from the input field\r\n */\r\n _clearbutton = () => {\r\n // stop when clear button is disabled\r\n if (!this._clearButton) return;\r\n\r\n // add aria to clear button\r\n setAttributes(this._cBtn, {\r\n class: `${this._prefix}-clear hidden`,\r\n type: \"button\",\r\n title: this._clearBtnAriLabel,\r\n \"aria-label\": this._clearBtnAriLabel,\r\n });\r\n\r\n // insert clear button after input - root\r\n this._root.insertAdjacentElement(\"afterend\", this._cBtn);\r\n };\r\n\r\n /**\r\n * Clicking on the clear button\r\n * publick destroy method\r\n */\r\n destroy = () => {\r\n // if clear button is true then add class hidden\r\n this._clearButton && this._cBtn.classList.add(\"hidden\");\r\n // clear value searchId\r\n this._root.value = \"\";\r\n // set focus\r\n this._root.focus();\r\n // remove li from ul\r\n this._resultList.textContent = \"\";\r\n // set default aria\r\n this._reset();\r\n // remove error if exist\r\n this._error();\r\n\r\n // callback function\r\n this._onReset(this._root);\r\n\r\n // remove listener\r\n this._root.removeEventListener(\"keydown\", this._handleKeys);\r\n this._root.removeEventListener(\"click\", this._handleShowItems);\r\n // remove listener on click on document\r\n document.removeEventListener(\"click\", this._handleDocClick);\r\n };\r\n}\r\n"],"names":["setAttributes","el","object","key","classList","add","remove","setAttribute","getFirstElementFromLiAndAddToInput","element","root","value","firstElementChild","getFirstElement","textContent","trim","scrollResultsToTop","resultList","resultWrap","scrollTop","offsetTop","offsetHeight","setAriaActivedescendant","type","followActiveElement","target","outputUl","classGroup","previusElement","previousSibling","previusElementHeight","getAttribute","allLi","document","querySelectorAll","height","slice","call","map","getClassGroupHeight","offsetBottom","createElement","keyCodes","constructor","delay","clearButton","howManyCharacters","selectFirst","insertToInput","showAllValues","cache","disableCloseOnSelect","classPreventClosing","classPrefix","ariaLabelClear","onSearch","onResults","onSubmit","onOpened","onReset","onRender","onClose","noResults","onSelectedItem","_initial","prefix","_clearbutton","this","_root","_resultList","_outputUl","_resultWrap","_prefix","id","tabIndex","role","addClass","insertAdjacentElement","parentNode","insertBefore","nextSibling","addEventListener","_handleInput","_showAll","_onRender","results","_cacheAct","_cache","_cacheData","removeAttribute","_ref2","regex","replace","_regex","_delay","clearTimeout","_timeout","setTimeout","_searchItem","_reset","_id","removeClass","_isActive","_matches","length","_toInput","innerHTML","_index","_selectFirst","_onClose","_value","_onLoading","destroy","showBtnToClearData","_cBtn","_clearButton","_characters","_onSearch","currentValue","then","result","rootValueLength","resultLength","Array","isArray","JSON","parse","stringify","_error","_noResults","template","_results","_events","Object","isObject","catch","_isLoading","_err","_handleKeys","_handleShowItems","eventType","_handleMouse","_handleDocClick","_onResults","matches","_classGroup","checkIfClassGroupExist","_itemsLi","itemsLi","i","tabindex","addAriaToAllLiElements","_onOpened","_selectFirstEl","_ref3","disableClose","closest","_disable","_prevClosing","_remAria","querySelector","_activeList","classSelectFirst","nextElementSibling","_onSelected","index","_selectedOption","contains","event","preventDefault","targetClosest","targetClosestRole","hasAttribute","activeClass","activeClassElement","_getTextFromLi","_setAria","_indexLiSelected","_onSubmit","prototype","indexOf","keyCode","matchesLength","_selectedLi","stopPropagation","selectedOption","class","title","_clearBtnAriLabel","focus","_onReset","removeEventListener","getElementById","Boolean","_ref4","Promise","resolve"],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"autocomplete.min.js","sources":["../../sources/js/utils/function.js","../../sources/js/utils/keyCodes.js","../../sources/js/script.js"],"sourcesContent":["/**\r\n * Check is a Object\r\n * @param {Object} value\r\n * @returns {Boolean}\r\n */\r\nconst isObject = (value) =>\r\n value && typeof value === \"object\" && value.constructor === Object;\r\n\r\n/**\r\n * Check if is a Promise\r\n * https://stackoverflow.com/a/53955664/10424385\r\n *\r\n * @param {Object} value\r\n * @returns {Boolean}\r\n */\r\nconst isPromise = (value) => Boolean(value && typeof value.then === \"function\");\r\n\r\n/**\r\n * Set attributes to element\r\n *\r\n * @param {HTMLElement} el\r\n * @param {Object} object\r\n */\r\nconst setAttributes = (el, object) => {\r\n for (let key in object) {\r\n if (key === \"addClass\") {\r\n classList(el, \"add\", object[key]);\r\n } else if (key === \"removeClass\") {\r\n classList(el, \"remove\", object[key]);\r\n } else {\r\n el.setAttribute(key, object[key]);\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Get first element from child\r\n *\r\n * @param {HTMLElement} element\r\n * @returns {HTMLELement}\r\n */\r\nconst getFirstElement = (element) =>\r\n (element.firstElementChild || element).textContent.trim();\r\n\r\n/**\r\n * Scroll to top result-list\r\n * @param {HTMLElement} resultList\r\n * @param {HTMLElement} resultWrap\r\n */\r\nconst scrollResultsToTop = (resultList, resultWrap) => {\r\n // if there is an overflow of ul element, after\r\n // opening we always move ul to the top of the results\r\n resultList.scrollTop = resultList.offsetTop - resultWrap.offsetHeight;\r\n};\r\n\r\n/**\r\n * Adding role, tabindex, aria and call handleMouse\r\n *\r\n * @param {HTMLElement} itemsLi\r\n */\r\nconst addAriaToAllLiElements = (itemsLi) => {\r\n // add role to all li elements\r\n for (let i = 0; i < itemsLi.length; i++) {\r\n setAttributes(itemsLi[i], {\r\n role: \"option\",\r\n tabindex: \"-1\",\r\n \"aria-selected\": \"false\",\r\n \"aria-setsize\": itemsLi.length,\r\n \"aria-posinset\": i,\r\n });\r\n }\r\n};\r\n\r\n/**\r\n * Show btn to clear data\r\n *\r\n * @param {HTMLElement} clearButton - button to clear data\r\n * @param {Function} destroy - destroy function\r\n */\r\nconst showBtnToClearData = (clearButton = false, destroy) => {\r\n if (!clearButton) return;\r\n\r\n classList(clearButton, \"remove\", \"hidden\");\r\n // add event to clear button\r\n onEvent(clearButton, \"click\", destroy);\r\n};\r\n\r\n/**\r\n * ClassList add/remove/contains\r\n *\r\n * @param {HTMLElement} element - html element\r\n * @param {String} action - add/remove/contains\r\n * @param {String} className - class name\r\n */\r\nconst classList = (element, action, className) =>\r\n element.classList[action](className);\r\n\r\n/**\r\n * Set aria-activedescendant\r\n *\r\n * @param {HTMLElement} root - search input\r\n * @param {String} type\r\n */\r\nconst setAriaActivedescendant = (root, type) => {\r\n setAttributes(root, {\r\n \"aria-activedescendant\": type || \"\",\r\n });\r\n};\r\n\r\n/**\r\n * Get height of ul without group class\r\n *\r\n * @param {String} outputUl\r\n * @param {String} classGroup\r\n * @returns {Number}\r\n */\r\nconst getClassGroupHeight = (outputUl, classGroup) => {\r\n // get height of ul without group class\r\n const allLiElements = document.querySelectorAll(\r\n `#${outputUl} > li:not(.${classGroup})`\r\n );\r\n let height = 0;\r\n [].slice.call(allLiElements).map((el) => (height += el.offsetHeight));\r\n\r\n // return height\r\n return height;\r\n};\r\n\r\n/**\r\n * Scroll into view when press up/down arrows\r\n *\r\n * @param {HTMLElement} target\r\n * @param {HTMLElement} outputUl\r\n * @param {String} classGroup\r\n * @param {HTMLElement} resultList\r\n */\r\nconst followActiveElement = (target, outputUl, classGroup, resultList) => {\r\n const previusElement = resultList.previousSibling;\r\n\r\n const previusElementHeight = previusElement ? previusElement.offsetHeight : 0;\r\n\r\n if (target.getAttribute(\"aria-posinset\") == \"0\") {\r\n resultList.scrollTop =\r\n target.offsetTop - getClassGroupHeight(outputUl, classGroup);\r\n }\r\n\r\n if (target.offsetTop - previusElementHeight < resultList.scrollTop) {\r\n resultList.scrollTop = target.offsetTop - previusElementHeight;\r\n } else {\r\n const offsetBottom =\r\n target.offsetTop + target.offsetHeight - previusElementHeight;\r\n const scrollBottom = resultList.scrollTop + resultList.offsetHeight;\r\n if (offsetBottom > scrollBottom) {\r\n resultList.scrollTop = offsetBottom - resultList.offsetHeight;\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Create output-list and put after search input\r\n *\r\n * @param {HTMLElement} root - search input\r\n * @param {HTMLElement} resultList - output-list ul\r\n * @param {String} outputUl - id name of output-list\r\n * @param {HTMLElement} resultWrap - wrapper ul element\r\n * @param {String} prefix - add prefix to all class auto\r\n */\r\nconst output = (root, resultList, outputUl, resultWrap, prefix) => {\r\n // set attribute to results-list\r\n setAttributes(resultList, {\r\n id: outputUl,\r\n tabIndex: \"0\",\r\n role: \"listbox\",\r\n });\r\n\r\n // add class to wrap element\r\n setAttributes(resultWrap, {\r\n addClass: `${prefix}-results-wrapper`,\r\n });\r\n\r\n // insert the results into the wrap element\r\n resultWrap.insertAdjacentElement(\"beforeend\", resultList);\r\n\r\n // insert the wrap element after the search input\r\n root.parentNode.insertBefore(resultWrap, root.nextSibling);\r\n};\r\n\r\n/**\r\n * Create element\r\n *\r\n * @param {String} type - type of element\r\n * @returns {HTMLDivElement}\r\n */\r\nconst createElement = (type) => document.createElement(type);\r\n\r\n/**\r\n * Get element\r\n *\r\n * @param {String} element\r\n * @returns {HTMLElement}\r\n */\r\nconst select = (element) => document.querySelector(element);\r\n\r\n/**\r\n * Event listeners\r\n *\r\n * @param {HTMLElement} element\r\n * @param {String} action\r\n * @param {Function} callback\r\n */\r\nconst onEvent = (element, action, callback) => {\r\n element.addEventListener(action, callback);\r\n};\r\n\r\n/**\r\n * Remove event listeners\r\n */\r\nconst offEvent = (element, action, callback) => {\r\n element.removeEventListener(action, callback);\r\n};\r\n\r\nexport {\r\n addAriaToAllLiElements,\r\n classList,\r\n createElement,\r\n followActiveElement,\r\n getFirstElement,\r\n isObject,\r\n isPromise,\r\n offEvent,\r\n onEvent,\r\n output,\r\n scrollResultsToTop,\r\n select,\r\n setAriaActivedescendant,\r\n setAttributes,\r\n showBtnToClearData,\r\n};\r\n","/**\r\n * Key codes\r\n */\r\nconst keyCodes = {\r\n ESC: 27,\r\n ENTER: 13,\r\n UP: 38,\r\n DOWN: 40,\r\n TAB: 9,\r\n};\r\n\r\nexport default keyCodes;\r\n","import {\r\n addAriaToAllLiElements,\r\n classList,\r\n createElement,\r\n followActiveElement,\r\n getFirstElement,\r\n isObject,\r\n isPromise,\r\n offEvent,\r\n onEvent,\r\n output,\r\n scrollResultsToTop,\r\n select,\r\n setAriaActivedescendant,\r\n setAttributes,\r\n showBtnToClearData,\r\n} from \"./utils/function\";\r\n\r\nimport keyCodes from \"./utils/keyCodes\";\r\n\r\n/**\r\n * @class Autocomplete\r\n */\r\nexport default class Autocomplete {\r\n /**\r\n * Constructor\r\n *\r\n * @param {String} element\r\n * @param {Object} object\r\n */\r\n constructor(\r\n element,\r\n {\r\n delay = 500,\r\n clearButton = true,\r\n howManyCharacters = 1,\r\n selectFirst = false,\r\n insertToInput = false,\r\n showAllValues = false,\r\n cache = false,\r\n disableCloseOnSelect = false,\r\n classGroup,\r\n classPreventClosing,\r\n classPrefix,\r\n ariaLabelClear,\r\n onSearch,\r\n onResults = () => {},\r\n onSubmit = () => {},\r\n onOpened = () => {},\r\n onReset = () => {},\r\n onRender = () => {},\r\n onClose = () => {},\r\n noResults = () => {},\r\n onSelectedItem = () => {},\r\n }\r\n ) {\r\n this._id = element;\r\n this._root = document.getElementById(element);\r\n this._onSearch = isPromise(onSearch)\r\n ? onSearch\r\n : ({ currentValue, element }) =>\r\n Promise.resolve(onSearch({ currentValue, element }));\r\n this._onResults = onResults;\r\n this._onRender = onRender;\r\n this._onSubmit = onSubmit;\r\n this._onSelected = onSelectedItem;\r\n this._onOpened = onOpened;\r\n this._onReset = onReset;\r\n this._noResults = noResults;\r\n this._onClose = onClose;\r\n\r\n this._delay = delay;\r\n this._characters = howManyCharacters;\r\n this._clearButton = clearButton;\r\n this._selectFirst = selectFirst;\r\n this._toInput = insertToInput;\r\n this._showAll = showAllValues;\r\n this._classGroup = classGroup;\r\n this._prevClosing = classPreventClosing;\r\n this._clearBtnAriLabel = ariaLabelClear\r\n ? ariaLabelClear\r\n : \"clear the search query\";\r\n this._prefix = classPrefix ? `${classPrefix}-auto` : \"auto\";\r\n this._disable = disableCloseOnSelect;\r\n\r\n // default config\r\n this._cache = cache;\r\n this._outputUl = `${this._prefix}-${this._id}-results`;\r\n this._cacheData = `data-cache-auto-${this._id}`;\r\n this._isLoading = `${this._prefix}-is-loading`;\r\n this._isActive = `${this._prefix}-is-active`;\r\n this._activeList = `${this._prefix}-selected`;\r\n this._selectedOption = `${this._prefix}-selected-option`;\r\n this._err = `${this._prefix}-error`;\r\n this._regex = /[|\\\\{}()[\\]^$+*?.]/g;\r\n this._timeout = null;\r\n\r\n this._resultWrap = createElement(\"div\");\r\n this._resultList = createElement(\"ul\");\r\n this._clearBtn = createElement(\"button\");\r\n\r\n this._initial();\r\n }\r\n\r\n /**\r\n * Initial function\r\n */\r\n _initial = () => {\r\n this._clearbutton();\r\n\r\n output(\r\n this._root,\r\n this._resultList,\r\n this._outputUl,\r\n this._resultWrap,\r\n this._prefix\r\n );\r\n\r\n // default aria\r\n onEvent(this._root, \"input\", this._handleInput);\r\n\r\n // show all values on click root input\r\n this._showAll && onEvent(this._root, \"click\", this._handleInput);\r\n\r\n // calback functions\r\n this._onRender({\r\n element: this._root,\r\n results: this._resultList,\r\n });\r\n };\r\n\r\n /**\r\n * Actions on input\r\n *\r\n * @param {String} type - set attribute depending on type\r\n * @param {String} target\r\n */\r\n _cacheAct = (type, target) => {\r\n if (!this._cache) return;\r\n\r\n if (type === \"update\") {\r\n this._root.setAttribute(this._cacheData, target.value);\r\n } else if (type === \"remove\") {\r\n this._root.removeAttribute(this._cacheData);\r\n } else {\r\n this._root.value = this._root.getAttribute(this._cacheData);\r\n }\r\n };\r\n\r\n /**\r\n * Handle input\r\n *\r\n * @param {Event} object\r\n */\r\n _handleInput = ({ target, type }) => {\r\n if (\r\n this._root.getAttribute(\"aria-expanded\") === \"true\" &&\r\n type === \"click\"\r\n ) {\r\n return;\r\n }\r\n\r\n // replace all special characters\r\n const regex = target.value.replace(this._regex, \"\\\\$&\");\r\n\r\n // update data attribute cache\r\n this._cacheAct(\"update\", target);\r\n\r\n const delay = this._showAll ? 0 : this._delay;\r\n // clear timeout\r\n clearTimeout(this._timeout);\r\n this._timeout = setTimeout(() => {\r\n this._searchItem(regex.trim());\r\n }, delay);\r\n };\r\n\r\n /**\r\n * Default aria\r\n */\r\n _reset = () => {\r\n // set attributes to root - input\r\n setAttributes(this._root, {\r\n \"aria-owns\": `${this._id}-list`,\r\n \"aria-expanded\": \"false\",\r\n \"aria-autocomplete\": \"list\",\r\n \"aria-activedescendant\": \"\",\r\n role: \"combobox\",\r\n removeClass: \"auto-expanded\",\r\n });\r\n\r\n // remove class isActive\r\n classList(this._resultWrap, \"remove\", this._isActive);\r\n\r\n // set index\r\n this._index = this._selectFirst ? 0 : -1;\r\n\r\n // callback function\r\n this._onClose();\r\n };\r\n\r\n /**\r\n * The async function gets the text from the search\r\n * and returns the matching array\r\n *\r\n * @param {String} value\r\n */\r\n _searchItem = (value) => {\r\n this._value = value;\r\n\r\n // if searching show loading icon\r\n this._onLoading(true);\r\n\r\n // hide button clear\r\n showBtnToClearData(this._clearBtn, this.destroy);\r\n\r\n // if there is no value and clearButton is true\r\n if (value.length == 0 && this._clearButton) {\r\n classList(this._clearBtn, \"add\", \"hidden\");\r\n }\r\n\r\n // if declare characters more then value.len and showAll is false\r\n // remove class isActive\r\n if (this._characters > value.length && !this._showAll) {\r\n this._onLoading();\r\n return;\r\n }\r\n\r\n // callblack function onSearch\r\n this._onSearch({ currentValue: value, element: this._root })\r\n .then((result) => {\r\n const rootValueLength = this._root.value.length;\r\n const resultLength = result.length;\r\n // set no result\r\n this._matches = Array.isArray(result)\r\n ? result\r\n : JSON.parse(JSON.stringify(result));\r\n\r\n this._onLoading();\r\n this._error();\r\n\r\n // if use destroy() method\r\n if (resultLength == 0 && rootValueLength == 0) {\r\n classList(this._clearBtn, \"add\", \"hidden\");\r\n }\r\n\r\n if (resultLength == 0 && rootValueLength) {\r\n classList(this._root, \"remove\", \"auto-expanded\");\r\n this._reset();\r\n this._noResults({\r\n element: this._root,\r\n currentValue: value,\r\n template: this._results,\r\n });\r\n this._events();\r\n } else if (resultLength > 0 || isObject(result)) {\r\n this._index = this._selectFirst ? 0 : -1;\r\n this._results();\r\n this._events();\r\n }\r\n })\r\n .catch(() => {\r\n this._onLoading();\r\n this._reset();\r\n });\r\n };\r\n\r\n /**\r\n * Set or remove loading class\r\n *\r\n * @param {Boolean} type\r\n */\r\n _onLoading = (type) =>\r\n this._root.parentNode.classList[type ? \"add\" : \"remove\"](this._isLoading);\r\n\r\n /**\r\n * Set error class to the root element\r\n */\r\n _error = () => classList(this._root, \"remove\", this._err);\r\n\r\n /**\r\n * Events\r\n */\r\n _events = () => {\r\n // handle click on keydown [up, down, enter, tab, esc]\r\n onEvent(this._root, \"keydown\", this._handleKeys);\r\n\r\n onEvent(this._root, \"click\", this._handleShowItems);\r\n\r\n // temporarily disabled mouseleave\r\n [\"mousemove\", \"click\"].map((eventType) => {\r\n onEvent(this._resultList, eventType, this._handleMouse);\r\n });\r\n\r\n // close expanded items\r\n onEvent(document, \"click\", this._handleDocClick);\r\n };\r\n\r\n /**\r\n * Results\r\n *\r\n * @param {HTMLElement|String} template - html or string returned from the function,\r\n * look at the example - https://github.com/tomik23/autocomplete/blob/master/docs/js/examples/no-results.js#L30\r\n */\r\n _results = (template) => {\r\n // set attribute to root\r\n setAttributes(this._root, {\r\n \"aria-expanded\": \"true\",\r\n addClass: `${this._prefix}-expanded`,\r\n });\r\n\r\n // clear result list\r\n this._resultList.textContent = \"\";\r\n\r\n // add all found records to otput ul\r\n const dataResults =\r\n this._matches.length === 0\r\n ? this._onResults({\r\n currentValue: this._value,\r\n matches: 0,\r\n template,\r\n })\r\n : this._onResults({\r\n currentValue: this._value,\r\n matches: this._matches,\r\n classGroup: this._classGroup,\r\n });\r\n\r\n // add data to ul\r\n this._resultList.insertAdjacentHTML(\"afterbegin\", dataResults);\r\n\r\n // add class isActive\r\n classList(this._resultWrap, \"add\", this._isActive);\r\n\r\n const checkIfClassGroupExist = this._classGroup\r\n ? `:not(.${this._classGroup})`\r\n : \"\";\r\n\r\n this._itemsLi = document.querySelectorAll(\r\n `#${this._outputUl} > li${checkIfClassGroupExist}`\r\n );\r\n\r\n // adding role, tabindex and aria\r\n addAriaToAllLiElements(this._itemsLi);\r\n\r\n // action on open results\r\n this._onOpened({\r\n type: \"results\",\r\n element: this._root,\r\n results: this._resultList,\r\n });\r\n\r\n // select first element\r\n this._selectFirstElement();\r\n\r\n // move the view item to the first item\r\n // this.resultList.scrollTop = 0;\r\n scrollResultsToTop(this._resultList, this._resultWrap);\r\n };\r\n\r\n /**\r\n * Hangle click on document\r\n *\r\n * @param {Event} object\r\n */\r\n _handleDocClick = ({ target }) => {\r\n let disableClose = null;\r\n\r\n // if 'target' is a ul and 'disableCloseOnSelect'\r\n // is a 'true' set 'disableClose' on true\r\n if (\r\n (target.closest(\"ul\") && this._disable) ||\r\n // when class classDisableClose\r\n // then do not not close results\r\n target.closest(`.${this._prevClosing}`)\r\n ) {\r\n disableClose = true;\r\n }\r\n\r\n if (target.id !== this._id && !disableClose) {\r\n this._reset();\r\n return;\r\n }\r\n };\r\n\r\n /**\r\n * Select first element\r\n */\r\n _selectFirstElement = () => {\r\n this._removeAria(select(`.${this._activeList}`));\r\n\r\n if (!this._selectFirst) {\r\n return;\r\n }\r\n\r\n const { firstElementChild } = this._resultList;\r\n\r\n const classSelectFirst =\r\n this._classGroup && this._matches.length > 0 && this._selectFirst\r\n ? firstElementChild.nextElementSibling\r\n : firstElementChild;\r\n\r\n // calback function onSelect when first element is true\r\n this._onSelected({\r\n index: this._index,\r\n element: this._root,\r\n object: this._matches[this._index],\r\n });\r\n\r\n // set attribute to first element\r\n setAttributes(classSelectFirst, {\r\n id: `${this._selectedOption}-0`,\r\n addClass: this._activeList,\r\n \"aria-selected\": \"true\",\r\n });\r\n\r\n // set aria active descendant\r\n setAriaActivedescendant(this._root, `${this._selectedOption}-0`);\r\n };\r\n\r\n /**\r\n * show items when items.length > 0 and is not empty\r\n */\r\n _handleShowItems = () => {\r\n // if resultWrap is not active and resultList is not empty\r\n if (\r\n this._resultList.textContent.length > 0 &&\r\n !classList(this._resultWrap, \"contains\", this._isActive)\r\n ) {\r\n // set attribute to root\r\n setAttributes(this._root, {\r\n \"aria-expanded\": \"true\",\r\n addClass: `${this._prefix}-expanded`,\r\n });\r\n\r\n // add isActive class to resultWrap\r\n classList(this._resultWrap, \"add\", this._isActive);\r\n\r\n // move the view item to the first item\r\n // this.resultList.scrollTop = 0;\r\n scrollResultsToTop(this._resultList, this._resultWrap);\r\n\r\n // select first element\r\n this._selectFirstElement();\r\n\r\n // callback function\r\n this._onOpened({\r\n type: \"showItems\",\r\n element: this._root,\r\n results: this._resultList,\r\n });\r\n }\r\n };\r\n\r\n /**\r\n * Adding text from the list when li is clicking\r\n * or adding aria-selected to li elements\r\n *\r\n * @param {Event} event\r\n */\r\n _handleMouse = (event) => {\r\n event.preventDefault();\r\n\r\n const { target, type } = event;\r\n const targetClosest = target.closest(\"li\");\r\n const targetClosestRole = targetClosest?.hasAttribute(\"role\");\r\n const activeClass = this._activeList;\r\n const activeClassElement = select(`.${activeClass}`);\r\n\r\n if (!targetClosest || !targetClosestRole) {\r\n return;\r\n }\r\n\r\n // click on li get element\r\n if (type === \"click\") {\r\n // get text from clicked li\r\n this._getTextFromLi(targetClosest);\r\n }\r\n\r\n if (\r\n type === \"mousemove\" &&\r\n !classList(targetClosest, \"contains\", activeClass)\r\n ) {\r\n this._removeAria(activeClassElement);\r\n\r\n // add aria to li\r\n this._setAria(targetClosest);\r\n this._index = this._indexLiSelected(targetClosest);\r\n\r\n this._onSelected({\r\n index: this._index,\r\n element: this._root,\r\n object: this._matches[this._index],\r\n });\r\n }\r\n };\r\n\r\n /**\r\n * Get text from li on enter or click\r\n *\r\n * @param {HTMLElement} element\r\n */\r\n _getTextFromLi = (element) => {\r\n if (!element || this._matches.length === 0) {\r\n // set default settings\r\n !this._disable && this._reset();\r\n\r\n return;\r\n }\r\n\r\n // get first element from li and set it to root\r\n this._root.value = getFirstElement(element);\r\n\r\n // onSubmit passing text to function\r\n this._onSubmit({\r\n index: this._index,\r\n element: this._root,\r\n object: this._matches[this._index],\r\n results: this._resultList,\r\n });\r\n\r\n // set default settings\r\n if (!this._disable) {\r\n this._removeAria(element);\r\n this._reset();\r\n }\r\n\r\n // show clearBtn when select element\r\n this._clearButton && classList(this._clearBtn, \"remove\", \"hidden\");\r\n\r\n // remove cache\r\n this._cacheAct(\"remove\");\r\n };\r\n\r\n /**\r\n * Return which li element was selected\r\n * by hovering the mouse over\r\n *\r\n * @param {HTMLElement} target\r\n * @returns {Number}\r\n */\r\n _indexLiSelected = (target) =>\r\n // get index of li element\r\n Array.prototype.indexOf.call(this._itemsLi, target);\r\n\r\n /**\r\n * Navigating the elements li and enter\r\n *\r\n * @param {Event} event\r\n */\r\n _handleKeys = (event) => {\r\n const { keyCode } = event;\r\n\r\n const resultList = classList(this._resultWrap, \"contains\", this._isActive);\r\n\r\n const matchesLength = this._matches.length + 1;\r\n this._selectedLi = select(`.${this._activeList}`);\r\n\r\n // switch between keys\r\n switch (keyCode) {\r\n case keyCodes.UP:\r\n case keyCodes.DOWN:\r\n // Wrong cursor position in the input field #62\r\n // Prevents the cursor from moving to the beginning\r\n // of input as the cursor hovers over the results.\r\n event.preventDefault();\r\n\r\n if ((matchesLength <= 1 && this._selectFirst) || !resultList) {\r\n return;\r\n }\r\n\r\n // if keyCode is up\r\n if (keyCode === keyCodes.UP) {\r\n if (this._index < 0) {\r\n this._index = matchesLength - 1;\r\n }\r\n this._index -= 1;\r\n } else {\r\n this._index += 1;\r\n if (this._index >= matchesLength) {\r\n this._index = 0;\r\n }\r\n }\r\n\r\n // remove aria-selected\r\n this._removeAria(this._selectedLi);\r\n\r\n if (this._index >= 0 && this._index < matchesLength - 1) {\r\n if (this._toInput && resultList) {\r\n this._root.value = getFirstElement(this._itemsLi[this._index]);\r\n }\r\n\r\n // callback function\r\n this._onSelected({\r\n index: this._index,\r\n element: this._root,\r\n object: this._matches[this._index],\r\n });\r\n\r\n // set aria-selected\r\n this._setAria(this._itemsLi[this._index]);\r\n } else {\r\n // catch action\r\n this._cacheAct();\r\n setAriaActivedescendant(this._root);\r\n\r\n this._onSelected({\r\n index: null,\r\n element: this._root,\r\n object: null,\r\n });\r\n }\r\n\r\n break;\r\n // keycode enter\r\n case keyCodes.ENTER:\r\n this._getTextFromLi(this._selectedLi);\r\n break;\r\n\r\n // keycode escape and keycode tab\r\n case keyCodes.TAB:\r\n case keyCodes.ESC:\r\n event.stopPropagation(); // #120\r\n this._reset();\r\n\r\n break;\r\n default:\r\n break;\r\n }\r\n };\r\n\r\n /**\r\n * Set aria label on item li\r\n *\r\n * @param {HTMLElement} target\r\n */\r\n _setAria = (target) => {\r\n const selectedOption = `${this._selectedOption}-${this._indexLiSelected(\r\n target\r\n )}`;\r\n\r\n // set aria to li\r\n setAttributes(target, {\r\n id: selectedOption,\r\n \"aria-selected\": \"true\",\r\n addClass: this._activeList,\r\n });\r\n\r\n setAriaActivedescendant(this._root, selectedOption);\r\n\r\n // scrollIntoView when press up/down arrows\r\n followActiveElement(\r\n target,\r\n this._outputUl,\r\n this._classGroup,\r\n this._resultList\r\n );\r\n };\r\n\r\n /**\r\n * Remove aria label from item li\r\n *\r\n * @param {HTMLElement} element\r\n */\r\n _removeAria = (element) => {\r\n if (!element) return;\r\n\r\n // remove aria from li\r\n setAttributes(element, {\r\n id: \"\",\r\n removeClass: this._activeList,\r\n \"aria-selected\": \"false\",\r\n });\r\n };\r\n\r\n /**\r\n * Create clear button and\r\n * removing text from the input field\r\n */\r\n _clearbutton = () => {\r\n // stop when clear button is disabled\r\n if (!this._clearButton) return;\r\n\r\n // add aria to clear button\r\n setAttributes(this._clearBtn, {\r\n class: `${this._prefix}-clear hidden`,\r\n type: \"button\",\r\n title: this._clearBtnAriLabel,\r\n \"aria-label\": this._clearBtnAriLabel,\r\n });\r\n\r\n // insert clear button after input - root\r\n this._root.insertAdjacentElement(\"afterend\", this._clearBtn);\r\n };\r\n\r\n /**\r\n * Clicking on the clear button\r\n * publick destroy method\r\n */\r\n destroy = () => {\r\n // if clear button is true then add class hidden\r\n this._clearButton && classList(this._clearBtn, \"add\", \"hidden\");\r\n // clear value searchId\r\n this._root.value = \"\";\r\n // set focus\r\n this._root.focus();\r\n // remove li from ul\r\n this._resultList.textContent = \"\";\r\n // set default aria\r\n this._reset();\r\n // remove error if exist\r\n this._error();\r\n\r\n // callback function\r\n this._onReset(this._root);\r\n\r\n // remove listener\r\n offEvent(this._root, \"keydown\", this._handleKeys);\r\n offEvent(this._root, \"click\", this._handleShowItems);\r\n // remove listener on click on document\r\n offEvent(document, \"click\", this._handleDocClick);\r\n };\r\n}\r\n"],"names":["setAttributes","el","object","key","classList","setAttribute","getFirstElement","element","firstElementChild","textContent","trim","scrollResultsToTop","resultList","resultWrap","scrollTop","offsetTop","offsetHeight","action","className","setAriaActivedescendant","root","type","followActiveElement","target","outputUl","classGroup","previusElement","previousSibling","previusElementHeight","getAttribute","allLiElements","document","querySelectorAll","height","slice","call","map","getClassGroupHeight","offsetBottom","createElement","select","querySelector","onEvent","callback","addEventListener","offEvent","removeEventListener","keyCodes","constructor","delay","clearButton","howManyCharacters","selectFirst","insertToInput","showAllValues","cache","disableCloseOnSelect","classPreventClosing","classPrefix","ariaLabelClear","onSearch","onResults","onSubmit","onOpened","onReset","onRender","onClose","noResults","onSelectedItem","value","_initial","prefix","_clearbutton","this","_root","_resultList","_outputUl","_resultWrap","_prefix","id","tabIndex","role","addClass","insertAdjacentElement","parentNode","insertBefore","nextSibling","_handleInput","_showAll","_onRender","results","_cacheAct","_cache","_cacheData","removeAttribute","_ref2","regex","replace","_regex","_delay","clearTimeout","_timeout","setTimeout","_searchItem","_reset","_id","removeClass","_isActive","_index","_selectFirst","_onClose","_value","_onLoading","destroy","showBtnToClearData","_clearBtn","length","_clearButton","_characters","_onSearch","currentValue","then","result","rootValueLength","resultLength","_matches","Array","isArray","JSON","parse","stringify","_error","_noResults","template","_results","_events","Object","isObject","catch","_isLoading","_err","_handleKeys","_handleShowItems","eventType","_handleMouse","_handleDocClick","dataResults","_onResults","matches","_classGroup","insertAdjacentHTML","checkIfClassGroupExist","_itemsLi","itemsLi","i","tabindex","addAriaToAllLiElements","_onOpened","_selectFirstElement","_ref3","disableClose","closest","_disable","_prevClosing","_removeAria","_activeList","classSelectFirst","nextElementSibling","_onSelected","index","_selectedOption","event","preventDefault","targetClosest","targetClosestRole","hasAttribute","activeClass","activeClassElement","_getTextFromLi","_setAria","_indexLiSelected","_onSubmit","prototype","indexOf","keyCode","matchesLength","_selectedLi","_toInput","stopPropagation","selectedOption","class","title","_clearBtnAriLabel","focus","_onReset","getElementById","Boolean","_ref4","Promise","resolve"],"mappings":"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"}
\ No newline at end of file
diff --git a/package.json b/package.json
index d279b48..899cec4 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@tomik23/autocomplete",
- "version": "1.8.1",
+ "version": "1.8.2",
"description": "Simple autocomplete component in vanilla JS",
"author": "Grzegorz Tomicki",
"main": "dist/js/autocomplete.js",
diff --git a/rollup.config.js b/rollup.config.js
index 6fa81b0..91fbea2 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -95,8 +95,8 @@ export default [
// umd
{
input,
- watch: false,
plugins: pluginsConfig(targets),
+ watch: false,
output: [
{
name: "Autocomplete",
@@ -122,8 +122,8 @@ export default [
// esm
{
input,
- watch: false,
plugins: pluginsConfig(targets),
+ watch: false,
output: [
{
name: "Autocomplete",
diff --git a/scripts/test-complex.js b/scripts/test-complex.js
index 2fc8d8d..e143ed1 100644
--- a/scripts/test-complex.js
+++ b/scripts/test-complex.js
@@ -14,6 +14,7 @@ createTestCafe()
runner
.src("./tests/Autocomplete.complex.test.js")
.browsers(browsers)
+ // .browsers("chrome:headless")
// .reporter([{ name: "spec", output: "reports/report-complex.txt" }])
.run()
);
diff --git a/sources/js/script.js b/sources/js/script.js
index 3314495..3aab642 100644
--- a/sources/js/script.js
+++ b/sources/js/script.js
@@ -1,12 +1,16 @@
import {
addAriaToAllLiElements,
+ classList,
createElement,
followActiveElement,
- getFirstElementFromLiAndAddToInput,
+ getFirstElement,
isObject,
isPromise,
+ offEvent,
+ onEvent,
output,
scrollResultsToTop,
+ select,
setAriaActivedescendant,
setAttributes,
showBtnToClearData,
@@ -93,7 +97,7 @@ export default class Autocomplete {
this._resultWrap = createElement("div");
this._resultList = createElement("ul");
- this._cBtn = createElement("button");
+ this._clearBtn = createElement("button");
this._initial();
}
@@ -113,11 +117,10 @@ export default class Autocomplete {
);
// default aria
- // this.reset();
- this._root.addEventListener("input", this._handleInput);
+ onEvent(this._root, "input", this._handleInput);
// show all values on click root input
- this._showAll && this._root.addEventListener("click", this._handleInput);
+ this._showAll && onEvent(this._root, "click", this._handleInput);
// calback functions
this._onRender({
@@ -186,16 +189,7 @@ export default class Autocomplete {
});
// remove class isActive
- this._resultWrap.classList.remove(this._isActive);
-
- // move the view item to the first item
- // this.resultList.scrollTop = 0;
- // scrollResultsToTop(this.resultList, this.resultWrap);
-
- // remove result when lengh = 0 and insertToInput is false
- if ((this._matches?.length == 0 && !this._toInput) || this._showAll) {
- this._resultList.innerHTML = "";
- }
+ classList(this._resultWrap, "remove", this._isActive);
// set index
this._index = this._selectFirst ? 0 : -1;
@@ -217,11 +211,11 @@ export default class Autocomplete {
this._onLoading(true);
// hide button clear
- showBtnToClearData(this._cBtn, this.destroy);
+ showBtnToClearData(this._clearBtn, this.destroy);
// if there is no value and clearButton is true
if (value.length == 0 && this._clearButton) {
- this._cBtn.classList.add("hidden");
+ classList(this._clearBtn, "add", "hidden");
}
// if declare characters more then value.len and showAll is false
@@ -238,7 +232,7 @@ export default class Autocomplete {
const resultLength = result.length;
// set no result
this._matches = Array.isArray(result)
- ? [...result]
+ ? result
: JSON.parse(JSON.stringify(result));
this._onLoading();
@@ -246,11 +240,11 @@ export default class Autocomplete {
// if use destroy() method
if (resultLength == 0 && rootValueLength == 0) {
- this._cBtn.classList.add("hidden");
+ classList(this._clearBtn, "add", "hidden");
}
if (resultLength == 0 && rootValueLength) {
- this._root.classList.remove("auto-expanded");
+ classList(this._root, "remove", "auto-expanded");
this._reset();
this._noResults({
element: this._root,
@@ -281,25 +275,24 @@ export default class Autocomplete {
/**
* Set error class to the root element
*/
- _error = () => this._root.classList.remove(this._err);
+ _error = () => classList(this._root, "remove", this._err);
/**
* Events
*/
_events = () => {
// handle click on keydown [up, down, enter, tab, esc]
- this._root.addEventListener("keydown", this._handleKeys);
+ onEvent(this._root, "keydown", this._handleKeys);
- //
- this._root.addEventListener("click", this._handleShowItems);
+ onEvent(this._root, "click", this._handleShowItems);
// temporarily disabled mouseleave
["mousemove", "click"].map((eventType) => {
- this._resultList.addEventListener(eventType, this._handleMouse);
+ onEvent(this._resultList, eventType, this._handleMouse);
});
// close expanded items
- document.addEventListener("click", this._handleDocClick);
+ onEvent(document, "click", this._handleDocClick);
};
/**
@@ -315,8 +308,11 @@ export default class Autocomplete {
addClass: `${this._prefix}-expanded`,
});
+ // clear result list
+ this._resultList.textContent = "";
+
// add all found records to otput ul
- this._resultList.innerHTML =
+ const dataResults =
this._matches.length === 0
? this._onResults({
currentValue: this._value,
@@ -329,7 +325,11 @@ export default class Autocomplete {
classGroup: this._classGroup,
});
- this._resultWrap.classList.add(this._isActive);
+ // add data to ul
+ this._resultList.insertAdjacentHTML("afterbegin", dataResults);
+
+ // add class isActive
+ classList(this._resultWrap, "add", this._isActive);
const checkIfClassGroupExist = this._classGroup
? `:not(.${this._classGroup})`
@@ -350,7 +350,7 @@ export default class Autocomplete {
});
// select first element
- this._selectFirstEl();
+ this._selectFirstElement();
// move the view item to the first item
// this.resultList.scrollTop = 0;
@@ -385,8 +385,8 @@ export default class Autocomplete {
/**
* Select first element
*/
- _selectFirstEl = () => {
- this._remAria(document.querySelector(`.${this._activeList}`));
+ _selectFirstElement = () => {
+ this._removeAria(select(`.${this._activeList}`));
if (!this._selectFirst) {
return;
@@ -424,7 +424,7 @@ export default class Autocomplete {
// if resultWrap is not active and resultList is not empty
if (
this._resultList.textContent.length > 0 &&
- !this._resultWrap.classList.contains(this._isActive)
+ !classList(this._resultWrap, "contains", this._isActive)
) {
// set attribute to root
setAttributes(this._root, {
@@ -433,14 +433,14 @@ export default class Autocomplete {
});
// add isActive class to resultWrap
- this._resultWrap.classList.add(this._isActive);
+ classList(this._resultWrap, "add", this._isActive);
// move the view item to the first item
// this.resultList.scrollTop = 0;
scrollResultsToTop(this._resultList, this._resultWrap);
// select first element
- this._selectFirstEl();
+ this._selectFirstElement();
// callback function
this._onOpened({
@@ -464,7 +464,7 @@ export default class Autocomplete {
const targetClosest = target.closest("li");
const targetClosestRole = targetClosest?.hasAttribute("role");
const activeClass = this._activeList;
- const activeClassElement = document.querySelector(`.${activeClass}`);
+ const activeClassElement = select(`.${activeClass}`);
if (!targetClosest || !targetClosestRole) {
return;
@@ -478,9 +478,9 @@ export default class Autocomplete {
if (
type === "mousemove" &&
- !targetClosest.classList.contains(activeClass)
+ !classList(targetClosest, "contains", activeClass)
) {
- this._remAria(activeClassElement);
+ this._removeAria(activeClassElement);
// add aria to li
this._setAria(targetClosest);
@@ -508,7 +508,7 @@ export default class Autocomplete {
}
// get first element from li and set it to root
- getFirstElementFromLiAndAddToInput(element, this._root);
+ this._root.value = getFirstElement(element);
// onSubmit passing text to function
this._onSubmit({
@@ -520,12 +520,12 @@ export default class Autocomplete {
// set default settings
if (!this._disable) {
- this._remAria(element);
+ this._removeAria(element);
this._reset();
}
// show clearBtn when select element
- this._clearButton && this._cBtn.classList.remove("hidden");
+ this._clearButton && classList(this._clearBtn, "remove", "hidden");
// remove cache
this._cacheAct("remove");
@@ -550,10 +550,10 @@ export default class Autocomplete {
_handleKeys = (event) => {
const { keyCode } = event;
- const resultList = this._resultWrap.classList.contains(this._isActive);
+ const resultList = classList(this._resultWrap, "contains", this._isActive);
const matchesLength = this._matches.length + 1;
- this._selectedLi = document.querySelector(`.${this._activeList}`);
+ this._selectedLi = select(`.${this._activeList}`);
// switch between keys
switch (keyCode) {
@@ -582,18 +582,11 @@ export default class Autocomplete {
}
// remove aria-selected
- this._remAria(this._selectedLi);
+ this._removeAria(this._selectedLi);
- if (
- matchesLength > 0 &&
- this._index >= 0 &&
- this._index < matchesLength - 1
- ) {
+ if (this._index >= 0 && this._index < matchesLength - 1) {
if (this._toInput && resultList) {
- getFirstElementFromLiAndAddToInput(
- this._itemsLi[this._index],
- this._root
- );
+ this._root.value = getFirstElement(this._itemsLi[this._index]);
}
// callback function
@@ -668,7 +661,7 @@ export default class Autocomplete {
*
* @param {HTMLElement} element
*/
- _remAria = (element) => {
+ _removeAria = (element) => {
if (!element) return;
// remove aria from li
@@ -688,7 +681,7 @@ export default class Autocomplete {
if (!this._clearButton) return;
// add aria to clear button
- setAttributes(this._cBtn, {
+ setAttributes(this._clearBtn, {
class: `${this._prefix}-clear hidden`,
type: "button",
title: this._clearBtnAriLabel,
@@ -696,7 +689,7 @@ export default class Autocomplete {
});
// insert clear button after input - root
- this._root.insertAdjacentElement("afterend", this._cBtn);
+ this._root.insertAdjacentElement("afterend", this._clearBtn);
};
/**
@@ -705,7 +698,7 @@ export default class Autocomplete {
*/
destroy = () => {
// if clear button is true then add class hidden
- this._clearButton && this._cBtn.classList.add("hidden");
+ this._clearButton && classList(this._clearBtn, "add", "hidden");
// clear value searchId
this._root.value = "";
// set focus
@@ -721,9 +714,9 @@ export default class Autocomplete {
this._onReset(this._root);
// remove listener
- this._root.removeEventListener("keydown", this._handleKeys);
- this._root.removeEventListener("click", this._handleShowItems);
+ offEvent(this._root, "keydown", this._handleKeys);
+ offEvent(this._root, "click", this._handleShowItems);
// remove listener on click on document
- document.removeEventListener("click", this._handleDocClick);
+ offEvent(document, "click", this._handleDocClick);
};
}
diff --git a/sources/js/utils/function.js b/sources/js/utils/function.js
index fc80a41..c16008c 100644
--- a/sources/js/utils/function.js
+++ b/sources/js/utils/function.js
@@ -24,9 +24,9 @@ const isPromise = (value) => Boolean(value && typeof value.then === "function");
const setAttributes = (el, object) => {
for (let key in object) {
if (key === "addClass") {
- el.classList.add(object[key]);
+ classList(el, "add", object[key]);
} else if (key === "removeClass") {
- el.classList.remove(object[key]);
+ classList(el, "remove", object[key]);
} else {
el.setAttribute(key, object[key]);
}
@@ -39,18 +39,8 @@ const setAttributes = (el, object) => {
* @param {HTMLElement} element
* @returns {HTMLELement}
*/
-const getFirstElement = (element) => element.firstElementChild || element;
-
-/**
- * Set data from li to input
- *
- * @param {String} element
- * @param {HTMLElement} root
- * @returns {String}
- */
-const getFirstElementFromLiAndAddToInput = (element, root) =>
- // get first element from li and add to input
- (root.value = getFirstElement(element).textContent.trim());
+const getFirstElement = (element) =>
+ (element.firstElementChild || element).textContent.trim();
/**
* Scroll to top result-list
@@ -90,11 +80,21 @@ const addAriaToAllLiElements = (itemsLi) => {
const showBtnToClearData = (clearButton = false, destroy) => {
if (!clearButton) return;
- clearButton.classList.remove("hidden");
+ classList(clearButton, "remove", "hidden");
// add event to clear button
- clearButton.addEventListener("click", destroy);
+ onEvent(clearButton, "click", destroy);
};
+/**
+ * ClassList add/remove/contains
+ *
+ * @param {HTMLElement} element - html element
+ * @param {String} action - add/remove/contains
+ * @param {String} className - class name
+ */
+const classList = (element, action, className) =>
+ element.classList[action](className);
+
/**
* Set aria-activedescendant
*
@@ -102,7 +102,9 @@ const showBtnToClearData = (clearButton = false, destroy) => {
* @param {String} type
*/
const setAriaActivedescendant = (root, type) => {
- root.setAttribute("aria-activedescendant", type || "");
+ setAttributes(root, {
+ "aria-activedescendant": type || "",
+ });
};
/**
@@ -114,11 +116,11 @@ const setAriaActivedescendant = (root, type) => {
*/
const getClassGroupHeight = (outputUl, classGroup) => {
// get height of ul without group class
- const allLi = document.querySelectorAll(
+ const allLiElements = document.querySelectorAll(
`#${outputUl} > li:not(.${classGroup})`
);
let height = 0;
- [].slice.call(allLi).map((el) => (height += el.offsetHeight));
+ [].slice.call(allLiElements).map((el) => (height += el.offsetHeight));
// return height
return height;
@@ -191,15 +193,45 @@ const output = (root, resultList, outputUl, resultWrap, prefix) => {
*/
const createElement = (type) => document.createElement(type);
+/**
+ * Get element
+ *
+ * @param {String} element
+ * @returns {HTMLElement}
+ */
+const select = (element) => document.querySelector(element);
+
+/**
+ * Event listeners
+ *
+ * @param {HTMLElement} element
+ * @param {String} action
+ * @param {Function} callback
+ */
+const onEvent = (element, action, callback) => {
+ element.addEventListener(action, callback);
+};
+
+/**
+ * Remove event listeners
+ */
+const offEvent = (element, action, callback) => {
+ element.removeEventListener(action, callback);
+};
+
export {
addAriaToAllLiElements,
+ classList,
createElement,
followActiveElement,
- getFirstElementFromLiAndAddToInput,
+ getFirstElement,
isObject,
isPromise,
+ offEvent,
+ onEvent,
output,
scrollResultsToTop,
+ select,
setAriaActivedescendant,
setAttributes,
showBtnToClearData,
diff --git a/tests/Autocomplete.complex.test.js b/tests/Autocomplete.complex.test.js
index 2f04017..56fa1f4 100644
--- a/tests/Autocomplete.complex.test.js
+++ b/tests/Autocomplete.complex.test.js
@@ -357,3 +357,46 @@ test("test 11: Press active-modal class exist", async (t) => {
// take screenshot
.takeScreenshot();
});
+
+// --------------------------------------------------
+// test 12
+
+test("test 12: Check input field when press arrow down", async (t) => {
+ await t
+ // .setTestSpeed(0.1)
+ // set value to input "wal"
+ .typeText(rootInput, "wal")
+
+ // wait 2 seconds
+ .wait(2000)
+
+ // press down arrow
+ // expect Walter White in input
+ .pressKey("down")
+ .expect(rootInput.value)
+ .eql("Walter White")
+
+ // take screenshot
+ .takeScreenshot()
+
+ // press down arrow
+ // now you on input filed
+ .pressKey("down")
+ // get value from input
+ // this time is get data from cache
+ .expect(rootInput.value)
+ .eql("wal")
+
+ // take screenshot
+ .takeScreenshot()
+
+ // press down arrow
+ // expect Walter White Jr. in input
+ // and li also have class active
+ .pressKey("down")
+ .expect(rootInput.value)
+ .eql("Walter White Jr.")
+
+ // take screenshot
+ .takeScreenshot();
+});
diff --git a/tests/complex-test.html b/tests/complex-test.html
index 549e4bc..112f40b 100644
--- a/tests/complex-test.html
+++ b/tests/complex-test.html
@@ -7,9 +7,10 @@
COMPLEX TEST