UNPKG

places-autocomplete-js

Version:

Google Maps Platform Awards 2025 Winner - A flexible, accessible, and secure vanilla JavaScript library that brings the power of Google's address search to your application in minutes.

3 lines (2 loc) 14.4 kB
(function(p,f){typeof exports=="object"&&typeof module<"u"?f(exports):typeof define=="function"&&define.amd?define(["exports"],f):(p=typeof globalThis<"u"?globalThis:p||self,f(p.PlacesAutocomplete={}))})(this,(function(p){"use strict";class f{#u;#d;#_;#f;#t;#a;#e;#n;#s;#l;#c;#h;#o=[];#i=-1;#b;#r;#p;#y={autofocus:!1,autocomplete:"off",placeholder:"Start typing your address ...",distance:!0,distance_units:"km",label:"",debounce:100,clear_input:!0,debug:!1};#m={section:"",container:"pac-container",icon_container:"pac-icon-container",icon:'<svg xmlns="http://www.w3.org/2000/svg" class="pac-w-5 pac-h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8" /><path d="m21 21-4.3-4.3" /></svg>',input:"pac-input",kbd_container:"pac-kbd-container",kbd_escape:"pac-kbd-escape",kbd_up:"pac-kbd-up",kbd_down:"pac-kbd-down",kbd_active:"pac-kbd-active",ul:"pac-ul",li:"pac-li",li_current:"pac-li-current",li_a:"pac-li-a",li_button:"pac-li-button",li_button_current:"pac-li-button-current",li_div_container:"pac-li-div-container",li_div_p_container:"pac-li-div-p-container",li_div_one:"pac-li-div-one",li_div_one_p:"pac-li-div-one-p",map_icon_svg:"pac-map-icon-svg",map_pin_icon:'<path d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"/><circle cx="12" cy="10" r="3"/>',li_div_one_p_secondaryText:"pac-li-div-one-p-secondaryText",li_div_two:"pac-li-div-two",li_div_two_p:"pac-li-div-two-p",highlight:"pac-highlight"};#v={input:"",includedRegionCodes:["GB"],language:"en-gb",region:"GB"};#g=["formattedAddress","addressComponents"];#E=["formattedAddress","addressComponents"];constructor(t){if(!t||!t.containerId||!t.googleMapsApiKey)throw new Error("PacAutocomplete: Missing required configuration (containerId, googleMapsApiKey).");if(this.#u=t.containerId,this.#d=document.getElementById(t.containerId),!this.#d)throw new Error(`PacAutocomplete: Container element with ID "${t.containerId}" not found.`);this.#_=t.googleMapsApiKey,this.#f=t.googleMapsApiVersion||"weekly",this.#t={...this.#y,...t.options},t.options&&t.options.classes?this.#t.classes={...this.#m,...t.options.classes}:this.#t.classes=this.#m,this.#t.debug&&(console.log("___debug constructor options:"),console.log(this.#t)),t.fetchFields&&Array.isArray(t.fetchFields)&&this._setFetchFields(t.fetchFields),this.#b=t.onResponse||(e=>{console.info("---------Default onResponse not provided---------"),console.info("Selected Place:",JSON.stringify(e,null,2))}),this.#r=t.onError||(e=>{console.error("---------Default onError not provided---------"),console.error("PAC Error:",e)}),t.requestParams&&Object.keys(t.requestParams).length>0?this.#a={...this.#v,...t.requestParams}:this.#a={...this.#v},this.#t.debug&&console.log("___debug constructor requestParams:",this.#a),this._initialiseDebouncedRequest(),this._init()}async _init(){try{(typeof google>"u"||!google.maps)&&await this._loadGoogleMapsApi({key:this.#_,v:this.#f}),this._createPACStructure(),await this._initializeAutocomplete()}catch(t){this.#r(t)}}_initialiseDebouncedRequest(){this.#p=this._debounce(async()=>{if(!this.#e||!this.#e.value){this._reset(),this.#e&&this.#e.setAttribute("aria-expanded","false");return}this.#a.input=this.#e.value;try{const{suggestions:t}=await google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions(this.#a);if(t&&t.length>0){const e=await Promise.all(this._createSuggestionElements(t));this.#s.replaceChildren(...e),this.#s.style.display="block",this.#e.setAttribute("aria-expanded","true")}else this._reset(),this.#e.setAttribute("aria-expanded","false")}catch(t){this.#r(t),this._reset()}},this.#t.debounce)}_setFetchFields(t){Array.isArray(t)&&t.length>0&&(this.#g=[...new Set([...this.#E,...t])].filter(e=>e))}_debounce(t,e){let s=null;return function(...n){const a=()=>{s=null,t(...n)};s!==null&&clearTimeout(s),s=setTimeout(a,e??100)}}_formatDistance(t,e){if(typeof t!="number"||!this.#t.distance)return null;let s,i;return e==="km"?(s=(t/1e3).toFixed(2),i="km"):(s=(t/1609.34).toFixed(2),i="miles"),s=s.replace(/\.00$/,""),`${s} ${i}`}async _loadGoogleMapsApi(t){var e,s,i,n="The Google Maps JavaScript API",a="google",c="importLibrary",m="__ib__",_=document,h=window;h=h[a]||(h[a]={});var r=h.maps||(h.maps={}),b=new Set,d=new URLSearchParams,v=()=>e||(e=new Promise(async(u,l)=>{s=_.createElement("script"),d.set("libraries",[...b].join(","));for(i in t)d.set(i.replace(/[A-Z]/g,g=>"_"+g[0].toLowerCase()),t[i]);d.set("callback",a+".maps."+m),s.src=`https://maps.${a}apis.com/maps/api/js?`+d,r[m]=u,s.onerror=()=>e=l(new Error(`${n} could not load. Check your API key and network connection.`)),s.nonce=_.querySelector("script[nonce]")?.nonce||"",_.head.append(s)}));r[c]?console.warn(n+" only loads once. Ignoring:",t):r[c]=(u,...l)=>b.add(u)&&v().then(()=>r[c](u,...l))}_createPACStructure(){const t=document.createElement("section");t.className=this.#t.classes.section,this.#n=document.createElement("div"),this.#n.className=this.#t.classes.container,this.#n.setAttribute("id",this.#u+"-div"),t.appendChild(this.#n);const e=document.createElement("div");e.className=this.#t.classes.icon_container,this.#n.appendChild(e);const s=document.createElement("div");if(s.innerHTML=this.#t.classes.icon,e.appendChild(s.firstElementChild),this.#e=document.createElement("input"),this.#e.id=this.#u+"-input",this.#e.type="text",this.#e.name="search",this.#e.placeholder=this.#t.placeholder,this.#e.autocomplete=this.#t.autocomplete,this.#e.className=this.#t.classes.input,this.#e.setAttribute("role","combobox"),this.#e.setAttribute("aria-autocomplete","list"),this.#e.setAttribute("aria-expanded","false"),this.#e.setAttribute("aria-controls","pacSuggestions"),this.#e.setAttribute("aria-activedescendant",""),this.#t.autofocus&&(this.#e.autofocus=!0),this.#t.label){const n=document.createElement("label");n.htmlFor=this.#e.id,n.textContent=this.#t.label,t.prepend(n)}this.#n.appendChild(this.#e);const i=document.createElement("div");i.className=this.#t.classes.kbd_container,this.#l=document.createElement("kbd"),this.#l.className=this.#t.classes.kbd_escape,this.#l.textContent="Esc",i.appendChild(this.#l),this.#c=document.createElement("kbd"),this.#c.className=this.#t.classes.kbd_up,this.#c.innerHTML="&#8593;",i.appendChild(this.#c),this.#h=document.createElement("kbd"),this.#h.className=this.#t.classes.kbd_down,this.#h.innerHTML="&#8595;",i.appendChild(this.#h),this.#n.appendChild(i),this.#s=document.createElement("ul"),this.#s.id="pacSuggestions",this.#s.className=this.#t.classes.ul,this.#s.style.display="none",this.#s.setAttribute("role","listbox"),this.#s.setAttribute("aria-labelledby",this.#e.id),this.#n.appendChild(this.#s),this.#d.appendChild(t),t.addEventListener("keydown",this._onKeyDown.bind(this))}_attachedEventListeners(){this.#e.addEventListener("input",this.#p),this.#e.addEventListener("blur",()=>{setTimeout(()=>{this.#s&&!this.#s.contains(document.activeElement)&&(this.#s.style.display="none",this.#e.setAttribute("aria-expanded","false"))},200)}),this.#e.addEventListener("focus",()=>{this.#e.value&&this.#o.length>0&&(this.#s.style.display="block",this.#e.setAttribute("aria-expanded","true"))})}_detachEventListeners(){this.#e&&this.#e.removeEventListener("input",this.#p),this.#d&&this.#n&&this.#d.removeChild(this.#n.parentElement)}async _initializeAutocomplete(){try{await google.maps.importLibrary("places"),this._refreshToken(),this.#e?this._attachedEventListeners():this.#r(new Error("Input element not found during initialization."))}catch(t){console.error("Error initializing Google Places Autocomplete:",t),this.#r(new Error("Google Maps Places library not available."))}}_reset(t=!1,e=null){this.#i=-1,this.#e&&this.#t.clear_input==!1&&e&&e.formattedAddress?this.#e.value=e.formattedAddress:this.#e&&(this.#e.value=""),this.#e&&(this.#e.setAttribute("aria-expanded","false"),this.#e.setAttribute("aria-activedescendant",""),this.#e.blur()),this.#o=[],this.#i=-1,this.#s&&(this.#s.innerHTML="",this.#s.style.display="none"),t&&this._refreshToken()}_resetLiClasses(){this.#s&&Array.from(this.#s.children).forEach(t=>{this.#t.classes.li_current.split(" ").forEach(s=>t.classList.remove(s));const e=t.querySelector("button");e&&this.#t.classes.li_button_current.split(" ").forEach(s=>e.classList.remove(s))})}_onKeyDown(t){if(this._resetLiClasses(),t.key==="Escape"&&(t.preventDefault(),this.#t.classes.kbd_active.split(" ").forEach(e=>this.#l?.classList.add(e)),setTimeout(()=>this.#t.classes.kbd_active.split(" ").forEach(e=>this.#l?.classList.remove(e)),300),this._reset(!0)),!(!this.#o.length||!this.#s||this.#s.style.display==="none"))if(t.key==="ArrowDown"){t.preventDefault(),this.#i=Math.min(this.#i+1,this.#o.length-1),this.#i<0&&(this.#i=0);const e=this.#s.children.item(this.#i);if(e){const s=e.querySelector("button");this.#t.classes.li_current.split(" ").forEach(i=>e.classList.add(i)),s&&this.#t.classes.li_button_current.split(" ").forEach(i=>s.classList.add(i)),e.scrollIntoView({block:"nearest"}),this.#e.setAttribute("aria-activedescendant",e.id)}this.#t.classes.kbd_active.split(" ").forEach(s=>this.#h?.classList.add(s)),setTimeout(()=>this.#t.classes.kbd_active.split(" ").forEach(s=>this.#h?.classList.remove(s)),300)}else if(t.key==="ArrowUp"){t.preventDefault(),this.#i=Math.max(this.#i-1,0);const e=this.#s.children.item(this.#i);if(e){const s=e.querySelector("button");this.#t.classes.li_current.split(" ").forEach(i=>e.classList.add(i)),s&&this.#t.classes.li_button_current.split(" ").forEach(i=>s.classList.add(i)),e.scrollIntoView({block:"nearest"})}this.#t.classes.kbd_active.split(" ").forEach(s=>this.#c?.classList.add(s)),setTimeout(()=>this.#t.classes.kbd_active.split(" ").forEach(s=>this.#c?.classList.remove(s)),300)}else t.key==="Enter"&&(t.preventDefault(),this.#i>=0&&this.#i<this.#o.length&&this._onPlaceSelected(this.#o[this.#i].place))}_getAddressComponent(t,e){return t.addressComponents?.find(s=>s.types.includes(e))?.longText||""}_getSecondaryText(t){const e=this._getAddressComponent(t,"locality"),s=this._getAddressComponent(t,"administrative_area_level_1"),i=this._getAddressComponent(t,"postal_code"),n=this._getAddressComponent(t,"country");return[e,s,n,i].filter(Boolean).join(", ")}_createButtonElement(t){const e=document.createElement("button");return e.tabIndex=t+1,e.className=this.#t.classes.li_button,e}_createDivElement(t){const e=document.createElement("div");return t&&(e.className=t),e}_createMapPinIconElement(){const t=document.createElementNS("http://www.w3.org/2000/svg","svg");return t.setAttribute("xmlns","http://www.w3.org/2000/svg"),t.setAttribute("width","24"),t.setAttribute("height","24"),t.setAttribute("viewBox","0 0 24 24"),t.setAttribute("fill","none"),t.setAttribute("stroke","currentColor"),t.setAttribute("stroke-width","2"),t.setAttribute("stroke-linecap","round"),t.setAttribute("stroke-linejoin","round"),t.setAttribute("class",this.#t.classes.map_icon_svg),t.innerHTML=this.#t.classes.map_pin_icon,t}_createPElement(t){const e=document.createElement("p");return t&&(e.className=t),e}_createSuggestionElements(t){return this.#o=[],t.map(async(e,s)=>{let i=e.placePrediction.toPlace();await i.fetchFields({fields:["addressComponents"]});const n=document.createElement("li");n.id=`option-${s+1}`,n.className=this.#t.classes.li;const a=this._createButtonElement(s);a.addEventListener("click",o=>{o.preventDefault(),this._onPlaceSelected(e.placePrediction.toPlace())});const c=this._createDivElement(this.#t.classes.li_div_container),m=this._createDivElement(this.#t.classes.li_div_one),_=this._createDivElement(this.#t.classes.li_div_two),h=this._createMapPinIconElement();m.appendChild(h);const r=this._createDivElement(this.#t.classes.li_div_p_container);m.appendChild(r);const b=this._createPElement(this.#t.classes.li_div_one_p),d=this._createPElement(this.#t.classes.li_div_one_p_secondaryText),v=this._createPElement(this.#t.classes.li_div_two_p);v.textContent=this._formatDistance(e.placePrediction.distanceMeters,this.#t.distance_units??"km"),r.appendChild(b),r.appendChild(d),_.appendChild(v),c.appendChild(m),c.appendChild(_),a.appendChild(c),n.appendChild(a);const u=e.placePrediction.mainText,l=u.text,g=u.matches;let A=0;g.sort((o,C)=>o.startOffset-C.startOffset);const y=document.createElement("span"),E=document.createElement("span");E.classList=this.#t.classes.highlight??"font-bold";for(const o of g)y.textContent+=l.substring(A,o.startOffset),o.startOffset>0&&l.charAt(o.startOffset-1)==" "&&(E.textContent+=" "),E.textContent+=l.substring(o.startOffset,o.endOffset),A=o.endOffset;const w=document.createTextNode(l.substring(A));y.appendChild(E),y.appendChild(w),b.appendChild(y);const k=this._getSecondaryText(i);return k&&(d.textContent=k),this.#o.push({id:s+1,place:i,mainText:e.placePrediction.mainText.text,secondaryText:this._getSecondaryText(i),description:e.placePrediction.toString()}),n.appendChild(a),n})}async _onPlaceSelected(t){let e=null;try{await t.fetchFields({fields:this.#g}),e=t.toJSON(),this.#b(e)}catch(s){console.error("Error fetching place details:",s),this.#r(s)}finally{this._reset(!0,e)}}_refreshToken(){try{this.#a.sessionToken=new google.maps.places.AutocompleteSessionToken}catch(t){console.error("Error creating session token:",t),this.#r(t)}}setFetchFields(t){this._setFetchFields(t)}getFetchFields(){return this.#g}setRequestParams(t){typeof t=="object"&&!Array.isArray(t)&&t!==null&&(t.input&&typeof t.input=="string"&&(this.#e.value=t.input),this.#a={...this.#v,...t})}getRequestParams(){return this.#a}setOptions(t){if(typeof t=="object"&&!Array.isArray(t)&&t!==null){this._detachEventListeners();const e=t.classes||{};delete t.classes,this.#t={...this.#y,...t},e&&typeof e=="object"&&Object.keys(e).length>0?this.#t.classes={...this.#m,...e}:this.#t.classes={...this.#m},this._initialiseDebouncedRequest(),this._createPACStructure(),this.#e&&this._attachedEventListeners()}}getOptions(){return this.#t}clear(){this._reset(!0)}destroy(){this._detachEventListeners(),this.#u=null,this.#d=null,this.#_=null,this.#f=null,this.#t=null,this.#a=null,this.#e=null,this.#n=null,this.#s=null,this.#l=null,this.#c=null,this.#h=null,this.#o=null,this.#i=-1,this.#b=null,this.#r=null,this.#p=null}}p.PlacesAutocomplete=f,Object.defineProperty(p,Symbol.toStringTag,{value:"Module"})})); //# sourceMappingURL=places-autocomplete.umd.cjs.map