@input-kit/phone 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,2 +1,1136 @@
1
- import {forwardRef,useRef,useState,useId,useCallback,useEffect,useImperativeHandle,useMemo,useLayoutEffect}from'react';import {getCountries,getCountryCallingCode,getExampleNumber,parsePhoneNumberFromString,AsYouType,isValidPhoneNumber,isPossiblePhoneNumber,validatePhoneNumberLength}from'libphonenumber-js';import rn from'libphonenumber-js/mobile/examples';import on from'world-countries';import {jsxs,Fragment,jsx}from'react/jsx-runtime';var an=["US","GB","CA","AU","DE","FR","IT","ES","JP","CN","IN","BR","MX","KR","NL","CH","SE","AE","SG","ZA","NG","SA","TR","ID","PH","TH","VN","MY","NZ","AR"],sn=new Set(getCountries()),un=new Map(on.map(e=>[e.cca2,e])),ln={AC:{name:"Ascension Island",dialCode:"+247"},TA:{name:"Tristan da Cunha",dialCode:"+290"},BQ:{name:"Caribbean Netherlands",dialCode:"+599"}};function dn(e,n){let t=e.startsWith("+")?e:`+${e}`,r=n.replace(/\D/g,"");return `${t}${r}`}function cn(e){return e.toUpperCase().replace(/./g,n=>String.fromCodePoint(127397+n.charCodeAt(0)))}function pn(e,n){let t=e?.idd?.root;if(!t)return [n];let o=(e.idd?.suffixes?.length?e.idd.suffixes:[""]).map(s=>dn(t,s)).filter(s=>/^\+\d+$/.test(s));return Array.from(new Set([n,...o.length?o:[]]))}function fn(e){let n=getExampleNumber(e,rn);return n?n.formatNational().replace(/\d/g,"#"):void 0}function Ve(e){let n=an.indexOf(e);return n===-1?Number.MAX_SAFE_INTEGER:n}var Cn=Array.from(sn).map(e=>{let n=un.get(e),t=ln[e],r=t?.dialCode??`+${getCountryCallingCode(e)}`,o=pn(n,r);return {code:e,name:n?.name.common??t?.name??e,dialCode:r,dialCodes:o,flag:n?.flag||t?.flag||cn(e),format:fn(e)}}).sort((e,n)=>{let t=Ve(e.code)-Ve(n.code);return t!==0?t:e.name.localeCompare(n.name)}),S=Cn,gn=new Map(S.map(e=>[e.code,e])),yn=S.reduce((e,n)=>{for(let t of n.dialCodes){let r=e.get(t)??[];r.push(n),e.set(t,r);}return e},new Map),mn=S.flatMap(e=>e.dialCodes.map(n=>({dialCode:n,country:e}))).sort((e,n)=>n.dialCode.length-e.dialCode.length),$e=new Map;function hn(e){return Array.isArray(e)?[...e]:e?[e]:[]}function bn(e){let n=hn(e);if(n.length===0||typeof Intl>"u"||typeof Intl.DisplayNames>"u")return;let t=n.join("|"),r=$e.get(t);if(r)return r;try{let o=new Intl.DisplayNames(n,{type:"region"});return $e.set(t,o),o}catch{return}}function Pn(e){let n=e.replace(/\D/g,"");return n?`+${n}`:""}function T(e){return gn.get(e.toUpperCase())}function ke(e,n){return e?bn(n)?.of(e.code)??e.displayName??e.name:void 0}function Z(e,n){if(!e)return;let t=ke(e,n);return t?{...e,displayName:t}:e}function le(e,n){return n?e.map(t=>Z(t,n)??t):e}function ze(e){return yn.get(Pn(e))??[]}function Ln(e){return ze(e)[0]}function xn(e={}){let n=S;if(e.onlyCountries?.length){let t=new Set(e.onlyCountries.map(r=>r.toUpperCase()));n=n.filter(r=>t.has(r.code));}if(e.excludeCountries?.length){let t=new Set(e.excludeCountries.map(r=>r.toUpperCase()));n=n.filter(r=>!t.has(r.code));}if(n=le(n,e.locale),e.preferredCountries?.length){let t=e.preferredCountries.map(r=>r.toUpperCase());n=[...n].sort((r,o)=>{let s=t.indexOf(r.code),c=t.indexOf(o.code);return s!==-1&&c!==-1?s-c:s!==-1?-1:c!==-1?1:(r.displayName??r.name).localeCompare(o.displayName??o.name)});}return n.map(t=>({value:t.code,label:`${t.displayName??t.name} (${t.dialCode})`,dialCode:t.dialCode,flag:t.flag}))}function q(e){let n=e.trim();if(!n)return;let t=n.startsWith("+")?`+${n.replace(/\D/g,"")}`:n.startsWith("00")?`+${n.slice(2).replace(/\D/g,"")}`:"";if(!t)return;let r=parsePhoneNumberFromString(t);return r?.country?T(r.country):mn.find(o=>t.startsWith(o.dialCode))?.country}var De={selectCountry:"Select country",countrySearchPlaceholder:"Search countries...",noCountriesFound:"No countries found",searchCountriesAriaLabel:"Search countries",countryOptionsAriaLabel:"Country options",countryButtonAriaLabel:"Open country selector"},Nn={en:De,fr:{selectCountry:"Choisir un pays",countrySearchPlaceholder:"Rechercher un pays...",noCountriesFound:"Aucun pays trouv\xE9",searchCountriesAriaLabel:"Rechercher des pays",countryOptionsAriaLabel:"Options de pays",countryButtonAriaLabel:"Ouvrir le s\xE9lecteur de pays"},de:{selectCountry:"Land ausw\xE4hlen",countrySearchPlaceholder:"Land suchen...",noCountriesFound:"Keine L\xE4nder gefunden",searchCountriesAriaLabel:"L\xE4nder suchen",countryOptionsAriaLabel:"L\xE4nderoptionen",countryButtonAriaLabel:"L\xE4nderauswahl \xF6ffnen"},es:{selectCountry:"Seleccionar pa\xEDs",countrySearchPlaceholder:"Buscar pa\xEDs...",noCountriesFound:"No se encontraron pa\xEDses",searchCountriesAriaLabel:"Buscar pa\xEDses",countryOptionsAriaLabel:"Opciones de pa\xEDs",countryButtonAriaLabel:"Abrir selector de pa\xEDs"},pt:{selectCountry:"Selecionar pa\xEDs",countrySearchPlaceholder:"Pesquisar pa\xEDs...",noCountriesFound:"Nenhum pa\xEDs encontrado",searchCountriesAriaLabel:"Pesquisar pa\xEDses",countryOptionsAriaLabel:"Op\xE7\xF5es de pa\xEDs",countryButtonAriaLabel:"Abrir seletor de pa\xEDs"},it:{selectCountry:"Seleziona paese",countrySearchPlaceholder:"Cerca paese...",noCountriesFound:"Nessun paese trovato",searchCountriesAriaLabel:"Cerca paesi",countryOptionsAriaLabel:"Opzioni paese",countryButtonAriaLabel:"Apri selettore paese"},ja:{selectCountry:"\u56FD\u3092\u9078\u629E",countrySearchPlaceholder:"\u56FD\u3092\u691C\u7D22...",noCountriesFound:"\u56FD\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093",searchCountriesAriaLabel:"\u56FD\u3092\u691C\u7D22",countryOptionsAriaLabel:"\u56FD\u306E\u5019\u88DC",countryButtonAriaLabel:"\u56FD\u306E\u30BB\u30EC\u30AF\u30BF\u30FC\u3092\u958B\u304F"},ko:{selectCountry:"\uAD6D\uAC00 \uC120\uD0DD",countrySearchPlaceholder:"\uAD6D\uAC00 \uAC80\uC0C9...",noCountriesFound:"\uAD6D\uAC00\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",searchCountriesAriaLabel:"\uAD6D\uAC00 \uAC80\uC0C9",countryOptionsAriaLabel:"\uAD6D\uAC00 \uC635\uC158",countryButtonAriaLabel:"\uAD6D\uAC00 \uC120\uD0DD\uAE30 \uC5F4\uAE30"},zh:{selectCountry:"\u9009\u62E9\u56FD\u5BB6",countrySearchPlaceholder:"\u641C\u7D22\u56FD\u5BB6...",noCountriesFound:"\u672A\u627E\u5230\u56FD\u5BB6",searchCountriesAriaLabel:"\u641C\u7D22\u56FD\u5BB6",countryOptionsAriaLabel:"\u56FD\u5BB6\u9009\u9879",countryButtonAriaLabel:"\u6253\u5F00\u56FD\u5BB6\u9009\u62E9\u5668"},ar:{selectCountry:"\u0627\u062E\u062A\u0631 \u0627\u0644\u062F\u0648\u0644\u0629",countrySearchPlaceholder:"\u0627\u0628\u062D\u062B \u0639\u0646 \u062F\u0648\u0644\u0629...",noCountriesFound:"\u0644\u0645 \u064A\u062A\u0645 \u0627\u0644\u0639\u062B\u0648\u0631 \u0639\u0644\u0649 \u062F\u0648\u0644",searchCountriesAriaLabel:"\u0627\u0628\u062D\u062B \u0639\u0646 \u0627\u0644\u062F\u0648\u0644",countryOptionsAriaLabel:"\u062E\u064A\u0627\u0631\u0627\u062A \u0627\u0644\u062F\u0648\u0644",countryButtonAriaLabel:"\u0627\u0641\u062A\u062D \u0645\u062D\u062F\u062F \u0627\u0644\u062F\u0648\u0644\u0629"},hi:{selectCountry:"\u0926\u0947\u0936 \u091A\u0941\u0928\u0947\u0902",countrySearchPlaceholder:"\u0926\u0947\u0936 \u0916\u094B\u091C\u0947\u0902...",noCountriesFound:"\u0915\u094B\u0908 \u0926\u0947\u0936 \u0928\u0939\u0940\u0902 \u092E\u093F\u0932\u093E",searchCountriesAriaLabel:"\u0926\u0947\u0936 \u0916\u094B\u091C\u0947\u0902",countryOptionsAriaLabel:"\u0926\u0947\u0936 \u0935\u093F\u0915\u0932\u094D\u092A",countryButtonAriaLabel:"\u0926\u0947\u0936 \u091A\u092F\u0928 \u0916\u094B\u0932\u0947\u0902"}};function vn(e){let t=(Array.isArray(e)?e:e?[e]:[]).find(Boolean);return t?t.toLowerCase().split("-")[0]:void 0}function Ae(e,n){let t=vn(e),r=t?Nn[t]:void 0;return {...De,...r,...n}}function W(e){let n=e.trim(),t=p(n);return n.startsWith("+")&&!t?"+":t?n.startsWith("+")?`+${t}`:t:""}function ce(e){return e?.code}function He(e){return e?.format?.replace(/[^#]/g,"").length}function p(e){return e.replace(/\D/g,"")}function K(e,n){return e&&new AsYouType(ce(n)).input(W(e))}function pe(e){return W(e)}function Ge(e,n){return !e||!n?false:e.trim().startsWith("+")?validatePhoneNumberLength(W(e))===void 0:validatePhoneNumberLength(p(e),ce(n))===void 0}function qe(e,n,t){if(!e)return false;if(t)return t(e,n??void 0);let r=W(e),o=ce(n);return o?r.startsWith("+")?isValidPhoneNumber(r):isValidPhoneNumber(p(r),o):isPossiblePhoneNumber(r.startsWith("+")?r:`+${p(r)}`)}function B(e,n){if(!n)return e;let t=W(e);if(!t||t==="+")return "";if(t.startsWith("+"))return t;let r=p(t);return n.dialCodes.find(s=>r.startsWith(s.replace("+","")))?`+${r}`:`${n.dialCode}${r}`}function O(e,n){if(!n)return e;let t=W(e),r=p(t),o=p(n.dialCode);if(r.startsWith(o))return r.slice(o.length);for(let s of n.dialCodes){let c=s.replace("+","");if(r.startsWith(c))return r.slice(c.length)}return r}function we(e,n,t){let r=n.toLowerCase().trim();return r?e.filter(o=>o.name.toLowerCase().includes(r)||(o.displayName??"").toLowerCase().includes(r)||o.code.toLowerCase().includes(r)||o.dialCodes.some(s=>s.includes(r))):t?.length?[...e].sort((o,s)=>{let c=t.indexOf(o.code),y=t.indexOf(s.code);return c!==-1&&y!==-1?c-y:c!==-1?-1:y!==-1?1:(o.displayName??o.name).localeCompare(s.displayName??s.name)}):e}function fe(e){return e?.displayName??e?.name??""}function Re(e){return e?.format?e.format.replace(/#/g,"0"):e?.dialCode?`${e.dialCode} 000 000 0000`:"Phone number"}var An=p;function J(e){return e.trim().startsWith("+")||e.trim().startsWith("00")}function On(e){let n=p(e);if(!J(e))return {dialCode:null,nationalNumber:n};let t=S.map(o=>o.dialCode).sort((o,s)=>s.length-o.length).find(o=>n.startsWith(p(o)));if(!t)return {dialCode:null,nationalNumber:n};let r=p(t);return {dialCode:r,nationalNumber:n.slice(r.length)}}function wn(e){return q(e)??null}function Rn(e,n,t="national"){if(!e)return "";if(t==="e164")return B(e,n);let r=J(e)?O(e,n):e;if(!n&&t==="national")return p(r).slice(0,9).replace(/(\d{3})(?=\d)/g,"$1 ").trim();let o=K(r,n);return t==="international"?n?`${n.dialCode} ${o}`:B(e,n):o}function En(e,n){return B(e,n)}function Sn(e,n){if(n)return O(e,n);let t=q(e);return t?O(e,t):p(e)}function de(e,n){return {isValid:false,reason:e,message:n,error:n}}function _e(){return {isValid:true,reason:null,message:null,error:null}}function Ee(e,n,t=false,r){let o=p(e);if(!o)return t?de("required","Phone number is required"):_e();let s=He(n),c=n?p(O(e,n)):o;return c.length<7?de("too_short","Phone number is too short"):s&&c.length>s?de("too_long",`Phone number is too long (max ${s} digits)`):(r?r(e,n??void 0):qe(e,n))?_e():de("invalid","Invalid phone number")}function Bn(e,n){let t=ce(n),r=W(e),o=r.startsWith("+")?parsePhoneNumberFromString(r):parsePhoneNumberFromString(p(r),t);if(!o){let c=n?O(e,n):p(e);return {country:n??void 0,nationalNumber:c,e164:void 0,isValid:false}}return {country:o.country?T(o.country):n??void 0,nationalNumber:o.nationalNumber,e164:o.isValid()?o.number:void 0,isValid:o.isValid()}}function Mn(e,n){return n?Ge(e,n):p(e).length>=7}function Fn(e,n){return J(e)&&n?`${n.dialCode} ${K(O(e,n),n)}`:K(e,n)}var Oe=p;function Vn(e,n){return Oe(e)===Oe(n)}function $n(e,n=true){let t=`${e.flag} ${fe(e)}`;return n?`${t} (${e.dialCode})`:t}function kn(e,n){let t=He(n);if(!t)return e;let r=J(e),o=p(e),s=n?p(n.dialCode):"",c=r?s.length+t:t,y=o.slice(0,c);return r?`+${y}`:y}function Tn(e,n){return e.slice(0,n).replace(/\D/g,"").length}function Wn(e,n){if(n<=0)return e.startsWith("+")?1:0;let t=0;for(let r=0;r<e.length;r+=1)if(/\d/.test(e[r])&&(t+=1,t===n))return r+1;return e.length}function Me(e={}){let{value:n,defaultValue:t="",onChange:r,onCountryChange:o,onBlur:s,onFocus:c,defaultCountry:y="US",preferredCountries:ne,excludeCountries:ge,excludedCountries:ye,onlyCountries:me,allowedCountries:he,autoDetect:Y,autoDetectCountry:be,formatOnType:te=true,includeDialCode:L=false,required:re=false,validator:oe,onValidationChange:ie,locale:P,labels:U}=e,V=me??he,I=ge??ye,D=Y??be??true,w=n!==void 0,_=useRef(null),j=useRef(null),ae=useRef(y),C=useMemo(()=>{let i=S;return V?.length&&(i=i.filter(a=>V.includes(a.code))),I?.length&&(i=i.filter(a=>!I.includes(a.code))),i},[V,I]),N=useMemo(()=>le(C,P),[C,P]),R=useMemo(()=>Ae(P,U),[P,U]),Pe=C.find(i=>i.code===y)||C[0],[Le,se]=useState(t),[d,E]=useState(Pe),[$,H]=useState(false),[A,k]=useState(""),l=w?n:Le,f=useCallback(i=>Z(i,P),[P]);useEffect(()=>{let i=ae.current!==y;ae.current=y;let a=C.find(X=>X.code===y)||C[0],v=d?C.some(X=>X.code===d.code):false;a&&(i||!v)&&E(a);},[y,C,d]),useEffect(()=>{if(D&&l){let i=q(l);i&&C.some(a=>a.code===i.code)&&i.code!==d?.code&&(E(i),o?.(f(i)));}},[C,D,l,d?.code,o,f]);let G=useMemo(()=>te?K(L&&l.startsWith("+")?O(l,d):l,d):L&&l.startsWith("+")?O(l,d):l,[te,L,l,d]),xe=useMemo(()=>L&&d?B(l,d):l,[l,d,L]),M=useMemo(()=>Ee(l,d,re,oe),[l,d,re,oe]);useEffect(()=>{ie?.(M);},[M,ie]);let Ne=useMemo(()=>Z(d,P),[d,P]),ue=useMemo(()=>we(N,A,ne),[N,A,ne]);useLayoutEffect(()=>{let i=j.current,a=_.current;if(i===null||!a||typeof a.setSelectionRange!="function"||typeof document<"u"&&document.activeElement!==a)return;let v=Wn(G,i);a.setSelectionRange(v,v),j.current=null;},[G]);let z=useCallback(i=>{let a=pe(i);w||se(a),r?.(L?B(a,d):a,f(d));},[w,r,d,L,f]),ve=useCallback(i=>{let a=T(i);a&&(E(a),o?.(f(a)),r?.(L?B(l,a):l,f(a)));},[l,r,o,L,f]),u=useCallback(i=>{let a=T(i.code)??i;E(a),H(false),k(""),o?.(f(a)),r?.(L?B(l,a):l,f(a));},[l,r,o,L,f]),h=useCallback(()=>{H(i=>!i),$&&k("");},[$]),b=useCallback(()=>{H(true);},[]),m=useCallback(()=>{H(false),k("");},[]),Qe=useCallback(()=>{w||se(""),r?.("",f(d));},[w,r,d,f]),Ye=useCallback(i=>{let a=i.target.value,v=i.target.selectionStart??a.length,X=a.trim().startsWith("+")?`+${a.replace(/\D/g,"")}`:pe(a);j.current=Tn(a,v),z(X);},[z]),je=useCallback(()=>{c?.();},[c]),Xe=useCallback(()=>{s?.();},[s]),Ie=useCallback(i=>`phone-input-country-${i}`,[]),Ze=useCallback((i,a)=>({id:Ie(i.code),role:"option","aria-selected":i.code===d?.code,onClick:()=>u(i),onKeyDown:v=>{(v.key==="Enter"||v.key===" ")&&(v.preventDefault(),u(i)),v.key==="Escape"&&(v.preventDefault(),m());},tabIndex:a===0?0:-1}),[m,d?.code,Ie,u]);return {phone:l,value:l,fullPhone:xe,country:Ne,isValid:M.isValid,validationReason:M.reason,error:M.error,isOpen:$,searchQuery:A,labels:R,formattedValue:G,setPhone:z,setValue:z,setCountry:ve,toggleDropdown:h,toggle:h,openDropdown:b,open:b,closeDropdown:m,close:m,setSearchQuery:k,clear:Qe,inputProps:{ref:_,value:G,onChange:Ye,onFocus:je,onBlur:Xe,type:"tel",inputMode:"tel",autoComplete:"tel",placeholder:Re(d),"aria-invalid":l?!M.isValid:void 0},countryButtonProps:{onClick:h,"aria-expanded":$,"aria-haspopup":"listbox","aria-label":R.countryButtonAriaLabel},countrySelectorProps:{onClick:h,"aria-expanded":$,"aria-haspopup":"listbox","aria-label":R.countryButtonAriaLabel},dropdownProps:{role:"listbox","aria-label":R.countryOptionsAriaLabel},getCountryOptionId:Ie,filteredCountries:ue,countries:ue,selectCountry:u,getCountryOptionProps:Ze}}var qn=({size:e=12})=>jsx("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsx("polyline",{points:"18 15 12 9 6 15"})}),Kn=({size:e=12})=>jsx("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsx("polyline",{points:"6 9 12 15 18 9"})}),Qn=forwardRef(function(n,t){let{value:r,defaultValue:o,onChange:s,onBlur:c,onFocus:y,inputClassName:ne,selectorClassName:ge,containerClassName:ye,searchable:me=true,placeholder:he,disabled:Y,readOnly:be,name:te,id:L,"aria-label":re,"aria-labelledby":oe,...ie}=n,P=useRef(null),U=useRef(null),V=useRef([]),[I,D]=useState(0),w=useId(),{inputProps:_,countryButtonProps:j,dropdownProps:ae,country:C,filteredCountries:N,isOpen:R,isValid:Pe,searchQuery:Le,setSearchQuery:se,setCountry:d,selectCountry:E,clear:$,openDropdown:H,closeDropdown:A,getCountryOptionId:k,labels:l}=Me({value:r,defaultValue:o,onChange:s,onBlur:c,onFocus:y,...ie}),f=_.ref,G=useCallback(u=>{U.current=u,typeof f=="function"?f(u):f&&"current"in f&&(f.current=u);},[f]),xe=useCallback(()=>{U.current?.focus();},[]),M=useCallback(()=>{U.current?.blur();},[]),Ne=useCallback(u=>{E(u),D(0);},[E]),ue=useCallback((u,h,b)=>{switch(u.key){case "Enter":case " ":u.preventDefault(),E(h),D(0);break;case "ArrowDown":if(u.preventDefault(),b<N.length-1){let m=b+1;D(m),V.current[m]?.focus();}break;case "ArrowUp":if(u.preventDefault(),b>0){let m=b-1;D(m),V.current[m]?.focus();}break;case "Escape":u.preventDefault(),A();break}},[E,N.length,A]);useEffect(()=>{if(!R)return;let u=b=>{let m=b.target;P.current&&m&&!P.current.contains(m)&&A();},h=b=>{let m=b.target;P.current&&m&&!P.current.contains(m)&&A();};return document.addEventListener("mousedown",u),document.addEventListener("focusin",h),()=>{document.removeEventListener("mousedown",u),document.removeEventListener("focusin",h);}},[R,A]),useEffect(()=>{if(N.length===0){I!==0&&D(0);return}I>=N.length&&D(N.length-1);},[N.length,I]),useImperativeHandle(t,()=>({focus:xe,blur:M,clear:$,setCountry:d,getCountry:()=>C,open:H,close:A}));let z=N[I],ve=z?k(z.code):void 0;return jsxs("div",{ref:P,className:ye,"data-valid":Pe,children:[jsxs("button",{...j,type:"button",className:ge,disabled:Y,tabIndex:Y?-1:0,"aria-controls":w,children:[C?jsxs(Fragment,{children:[jsx("span",{className:"phone-input-flag",children:C.flag}),jsx("span",{className:"phone-input-dial-code",children:C.dialCode})]}):jsx("span",{className:"phone-input-placeholder",children:l.selectCountry}),jsx("span",{className:"phone-input-arrow","aria-hidden":"true",children:R?jsx(qn,{size:12}):jsx(Kn,{size:12})})]}),jsx("input",{..._,ref:G,id:L,name:te,className:ne,placeholder:he||_.placeholder,disabled:Y,readOnly:be,"aria-label":re,"aria-labelledby":oe}),R&&jsxs("div",{className:"phone-input-dropdown",children:[me&&jsx("div",{className:"phone-input-search",children:jsx("input",{type:"text",value:Le,onChange:u=>se(u.target.value),placeholder:l.countrySearchPlaceholder,autoFocus:true,"aria-controls":w,"aria-label":l.searchCountriesAriaLabel})}),jsxs("ul",{...ae,className:"phone-input-country-list",id:w,"aria-activedescendant":ve,children:[N.map((u,h)=>jsxs("li",{id:k(u.code),ref:b=>{V.current[h]=b;},role:"option","aria-selected":u.code===C?.code,className:`phone-input-country-option ${u.code===C?.code?"selected":""} ${h===I?"highlighted":""}`,onClick:()=>Ne(u),onKeyDown:b=>ue(b,u,h),onMouseEnter:()=>D(h),tabIndex:h===I?0:-1,children:[jsx("span",{className:"phone-input-flag",children:u.flag}),jsx("span",{className:"phone-input-country-name",children:fe(u)}),jsx("span",{className:"phone-input-dial-code",children:u.dialCode})]},u.code)),N.length===0&&jsx("li",{className:"phone-input-no-results",children:l.noCountriesFound})]})]})]})});export{De as DEFAULT_PHONE_INPUT_LABELS,Qn as PhoneInput,B as addDialCode,p as cleanPhone,S as countries,wn as detectCountry,q as detectCountryFromPhone,On as extractDialCode,we as filterCountries,Fn as formatAsYouType,K as formatPhone,Rn as formatPhoneNumber,ze as getCountriesByDialCode,T as getCountryByCode,Ln as getCountryByDialCode,$n as getCountryDisplayLabel,fe as getCountryDisplayName,xn as getCountryOptions,ke as getLocalizedCountryName,Sn as getNationalNumber,Re as getPlaceholder,J as isInternationalFormat,Mn as isPhoneNumberComplete,kn as limitInputLength,le as localizeCountries,Z as localizeCountry,Oe as normalizePhoneNumber,Bn as parsePhoneValue,En as parseToE164,Vn as phoneNumbersEqual,O as removeDialCode,Ae as resolvePhoneInputLabels,An as stripNonDigits,pe as unformatPhone,Me as usePhoneInput,qe as validatePhone,Ge as validatePhoneLength,Ee as validatePhoneNumber};//# sourceMappingURL=index.js.map
1
+ import { forwardRef, useRef, useState, useId, useCallback, useEffect, useImperativeHandle, useMemo, useLayoutEffect } from 'react';
2
+ import { getCountries, getCountryCallingCode, getExampleNumber, parsePhoneNumberFromString, AsYouType, validatePhoneNumberLength, isPossiblePhoneNumber, isValidPhoneNumber } from 'libphonenumber-js';
3
+ import examples from 'libphonenumber-js/mobile/examples';
4
+ import worldCountries from 'world-countries';
5
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
6
+
7
+ // src/usePhoneInput.ts
8
+ var PRIORITY_COUNTRIES = [
9
+ "US",
10
+ "GB",
11
+ "CA",
12
+ "AU",
13
+ "DE",
14
+ "FR",
15
+ "IT",
16
+ "ES",
17
+ "JP",
18
+ "CN",
19
+ "IN",
20
+ "BR",
21
+ "MX",
22
+ "KR",
23
+ "NL",
24
+ "CH",
25
+ "SE",
26
+ "AE",
27
+ "SG",
28
+ "ZA",
29
+ "NG",
30
+ "SA",
31
+ "TR",
32
+ "ID",
33
+ "PH",
34
+ "TH",
35
+ "VN",
36
+ "MY",
37
+ "NZ",
38
+ "AR"
39
+ ];
40
+ var supportedCountries = new Set(getCountries());
41
+ var worldCountryMap = new Map(worldCountries.map((country) => [country.cca2, country]));
42
+ var FALLBACK_COUNTRIES = {
43
+ AC: { name: "Ascension Island", dialCode: "+247" },
44
+ TA: { name: "Tristan da Cunha", dialCode: "+290" },
45
+ BQ: { name: "Caribbean Netherlands", dialCode: "+599" }
46
+ };
47
+ function normalizeDialCode(root, suffix) {
48
+ const normalizedRoot = root.startsWith("+") ? root : `+${root}`;
49
+ const digitsOnlySuffix = suffix.replace(/\D/g, "");
50
+ return `${normalizedRoot}${digitsOnlySuffix}`;
51
+ }
52
+ function codeToFlag(code) {
53
+ return code.toUpperCase().replace(/./g, (char) => String.fromCodePoint(127397 + char.charCodeAt(0)));
54
+ }
55
+ function buildDialCodes(country, fallbackDialCode) {
56
+ const root = country?.idd?.root;
57
+ if (!root) {
58
+ return [fallbackDialCode];
59
+ }
60
+ const suffixes = country.idd?.suffixes?.length ? country.idd.suffixes : [""];
61
+ const dialCodes = suffixes.map((suffix) => normalizeDialCode(root, suffix)).filter((dialCode) => /^\+\d+$/.test(dialCode));
62
+ return Array.from(/* @__PURE__ */ new Set([fallbackDialCode, ...dialCodes.length ? dialCodes : []]));
63
+ }
64
+ function getCountryFormat(code) {
65
+ const example = getExampleNumber(code, examples);
66
+ return example ? example.formatNational().replace(/\d/g, "#") : void 0;
67
+ }
68
+ function getCountryPriority(code) {
69
+ const index = PRIORITY_COUNTRIES.indexOf(code);
70
+ return index === -1 ? Number.MAX_SAFE_INTEGER : index;
71
+ }
72
+ var generatedCountries = Array.from(supportedCountries).map((code) => {
73
+ const country = worldCountryMap.get(code);
74
+ const fallback = FALLBACK_COUNTRIES[code];
75
+ const dialCode = fallback?.dialCode ?? `+${getCountryCallingCode(code)}`;
76
+ const dialCodes = buildDialCodes(country, dialCode);
77
+ return {
78
+ code,
79
+ name: country?.name.common ?? fallback?.name ?? code,
80
+ dialCode,
81
+ dialCodes,
82
+ flag: country?.flag || fallback?.flag || codeToFlag(code),
83
+ format: getCountryFormat(code)
84
+ };
85
+ }).sort((left, right) => {
86
+ const priorityDelta = getCountryPriority(left.code) - getCountryPriority(right.code);
87
+ return priorityDelta !== 0 ? priorityDelta : left.name.localeCompare(right.name);
88
+ });
89
+ var countries = generatedCountries;
90
+ var countryMap = new Map(countries.map((country) => [country.code, country]));
91
+ var countriesByDialCode = countries.reduce((map, country) => {
92
+ for (const dialCode of country.dialCodes) {
93
+ const matches = map.get(dialCode) ?? [];
94
+ matches.push(country);
95
+ map.set(dialCode, matches);
96
+ }
97
+ return map;
98
+ }, /* @__PURE__ */ new Map());
99
+ var dialCodeMatchers = countries.flatMap((country) => country.dialCodes.map((dialCode) => ({ dialCode, country }))).sort((left, right) => right.dialCode.length - left.dialCode.length);
100
+ var displayNameCache = /* @__PURE__ */ new Map();
101
+ function normalizeLocales(locale) {
102
+ return Array.isArray(locale) ? [...locale] : locale ? [locale] : [];
103
+ }
104
+ function getDisplayNames(locale) {
105
+ const locales = normalizeLocales(locale);
106
+ if (locales.length === 0 || typeof Intl === "undefined" || typeof Intl.DisplayNames === "undefined") {
107
+ return void 0;
108
+ }
109
+ const cacheKey = locales.join("|");
110
+ const cached = displayNameCache.get(cacheKey);
111
+ if (cached) {
112
+ return cached;
113
+ }
114
+ try {
115
+ const displayNames = new Intl.DisplayNames(locales, { type: "region" });
116
+ displayNameCache.set(cacheKey, displayNames);
117
+ return displayNames;
118
+ } catch {
119
+ return void 0;
120
+ }
121
+ }
122
+ function normalizeLookupDialCode(dialCode) {
123
+ const digits = dialCode.replace(/\D/g, "");
124
+ return digits ? `+${digits}` : "";
125
+ }
126
+ function getCountryByCode(code) {
127
+ return countryMap.get(code.toUpperCase());
128
+ }
129
+ function getLocalizedCountryName(country, locale) {
130
+ if (!country) {
131
+ return void 0;
132
+ }
133
+ const displayNames = getDisplayNames(locale);
134
+ return displayNames?.of(country.code) ?? country.displayName ?? country.name;
135
+ }
136
+ function localizeCountry(country, locale) {
137
+ if (!country) {
138
+ return void 0;
139
+ }
140
+ const displayName = getLocalizedCountryName(country, locale);
141
+ return displayName ? { ...country, displayName } : country;
142
+ }
143
+ function localizeCountries(list, locale) {
144
+ if (!locale) {
145
+ return list;
146
+ }
147
+ return list.map((country) => localizeCountry(country, locale) ?? country);
148
+ }
149
+ function getCountriesByDialCode(dialCode) {
150
+ return countriesByDialCode.get(normalizeLookupDialCode(dialCode)) ?? [];
151
+ }
152
+ function getCountryByDialCode(dialCode) {
153
+ return getCountriesByDialCode(dialCode)[0];
154
+ }
155
+ function getCountryOptions(params = {}) {
156
+ let list = countries;
157
+ if (params.onlyCountries?.length) {
158
+ const allowed = new Set(params.onlyCountries.map((code) => code.toUpperCase()));
159
+ list = list.filter((country) => allowed.has(country.code));
160
+ }
161
+ if (params.excludeCountries?.length) {
162
+ const excluded = new Set(params.excludeCountries.map((code) => code.toUpperCase()));
163
+ list = list.filter((country) => !excluded.has(country.code));
164
+ }
165
+ list = localizeCountries(list, params.locale);
166
+ if (params.preferredCountries?.length) {
167
+ const preferred = params.preferredCountries.map((code) => code.toUpperCase());
168
+ list = [...list].sort((left, right) => {
169
+ const leftIndex = preferred.indexOf(left.code);
170
+ const rightIndex = preferred.indexOf(right.code);
171
+ if (leftIndex !== -1 && rightIndex !== -1) {
172
+ return leftIndex - rightIndex;
173
+ }
174
+ if (leftIndex !== -1) {
175
+ return -1;
176
+ }
177
+ if (rightIndex !== -1) {
178
+ return 1;
179
+ }
180
+ return (left.displayName ?? left.name).localeCompare(right.displayName ?? right.name);
181
+ });
182
+ }
183
+ return list.map((country) => ({
184
+ value: country.code,
185
+ label: `${country.displayName ?? country.name} (${country.dialCode})`,
186
+ dialCode: country.dialCode,
187
+ flag: country.flag
188
+ }));
189
+ }
190
+ function detectCountryFromPhone(phone) {
191
+ const trimmed = phone.trim();
192
+ if (!trimmed) {
193
+ return void 0;
194
+ }
195
+ const normalized = trimmed.startsWith("+") ? `+${trimmed.replace(/\D/g, "")}` : trimmed.startsWith("00") ? `+${trimmed.slice(2).replace(/\D/g, "")}` : "";
196
+ if (!normalized) {
197
+ return void 0;
198
+ }
199
+ const parsedPhone = parsePhoneNumberFromString(normalized);
200
+ if (parsedPhone?.country) {
201
+ return getCountryByCode(parsedPhone.country);
202
+ }
203
+ return dialCodeMatchers.find((entry) => normalized.startsWith(entry.dialCode))?.country;
204
+ }
205
+
206
+ // src/labels.ts
207
+ var DEFAULT_PHONE_INPUT_LABELS = {
208
+ selectCountry: "Select country",
209
+ countrySearchPlaceholder: "Search countries...",
210
+ noCountriesFound: "No countries found",
211
+ searchCountriesAriaLabel: "Search countries",
212
+ countryOptionsAriaLabel: "Country options",
213
+ countryButtonAriaLabel: "Open country selector"
214
+ };
215
+ var LABELS_BY_LANGUAGE = {
216
+ en: DEFAULT_PHONE_INPUT_LABELS,
217
+ fr: {
218
+ selectCountry: "Choisir un pays",
219
+ countrySearchPlaceholder: "Rechercher un pays...",
220
+ noCountriesFound: "Aucun pays trouv\xE9",
221
+ searchCountriesAriaLabel: "Rechercher des pays",
222
+ countryOptionsAriaLabel: "Options de pays",
223
+ countryButtonAriaLabel: "Ouvrir le s\xE9lecteur de pays"
224
+ },
225
+ de: {
226
+ selectCountry: "Land ausw\xE4hlen",
227
+ countrySearchPlaceholder: "Land suchen...",
228
+ noCountriesFound: "Keine L\xE4nder gefunden",
229
+ searchCountriesAriaLabel: "L\xE4nder suchen",
230
+ countryOptionsAriaLabel: "L\xE4nderoptionen",
231
+ countryButtonAriaLabel: "L\xE4nderauswahl \xF6ffnen"
232
+ },
233
+ es: {
234
+ selectCountry: "Seleccionar pa\xEDs",
235
+ countrySearchPlaceholder: "Buscar pa\xEDs...",
236
+ noCountriesFound: "No se encontraron pa\xEDses",
237
+ searchCountriesAriaLabel: "Buscar pa\xEDses",
238
+ countryOptionsAriaLabel: "Opciones de pa\xEDs",
239
+ countryButtonAriaLabel: "Abrir selector de pa\xEDs"
240
+ },
241
+ pt: {
242
+ selectCountry: "Selecionar pa\xEDs",
243
+ countrySearchPlaceholder: "Pesquisar pa\xEDs...",
244
+ noCountriesFound: "Nenhum pa\xEDs encontrado",
245
+ searchCountriesAriaLabel: "Pesquisar pa\xEDses",
246
+ countryOptionsAriaLabel: "Op\xE7\xF5es de pa\xEDs",
247
+ countryButtonAriaLabel: "Abrir seletor de pa\xEDs"
248
+ },
249
+ it: {
250
+ selectCountry: "Seleziona paese",
251
+ countrySearchPlaceholder: "Cerca paese...",
252
+ noCountriesFound: "Nessun paese trovato",
253
+ searchCountriesAriaLabel: "Cerca paesi",
254
+ countryOptionsAriaLabel: "Opzioni paese",
255
+ countryButtonAriaLabel: "Apri selettore paese"
256
+ },
257
+ ja: {
258
+ selectCountry: "\u56FD\u3092\u9078\u629E",
259
+ countrySearchPlaceholder: "\u56FD\u3092\u691C\u7D22...",
260
+ noCountriesFound: "\u56FD\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093",
261
+ searchCountriesAriaLabel: "\u56FD\u3092\u691C\u7D22",
262
+ countryOptionsAriaLabel: "\u56FD\u306E\u5019\u88DC",
263
+ countryButtonAriaLabel: "\u56FD\u306E\u30BB\u30EC\u30AF\u30BF\u30FC\u3092\u958B\u304F"
264
+ },
265
+ ko: {
266
+ selectCountry: "\uAD6D\uAC00 \uC120\uD0DD",
267
+ countrySearchPlaceholder: "\uAD6D\uAC00 \uAC80\uC0C9...",
268
+ noCountriesFound: "\uAD6D\uAC00\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
269
+ searchCountriesAriaLabel: "\uAD6D\uAC00 \uAC80\uC0C9",
270
+ countryOptionsAriaLabel: "\uAD6D\uAC00 \uC635\uC158",
271
+ countryButtonAriaLabel: "\uAD6D\uAC00 \uC120\uD0DD\uAE30 \uC5F4\uAE30"
272
+ },
273
+ zh: {
274
+ selectCountry: "\u9009\u62E9\u56FD\u5BB6",
275
+ countrySearchPlaceholder: "\u641C\u7D22\u56FD\u5BB6...",
276
+ noCountriesFound: "\u672A\u627E\u5230\u56FD\u5BB6",
277
+ searchCountriesAriaLabel: "\u641C\u7D22\u56FD\u5BB6",
278
+ countryOptionsAriaLabel: "\u56FD\u5BB6\u9009\u9879",
279
+ countryButtonAriaLabel: "\u6253\u5F00\u56FD\u5BB6\u9009\u62E9\u5668"
280
+ },
281
+ ar: {
282
+ selectCountry: "\u0627\u062E\u062A\u0631 \u0627\u0644\u062F\u0648\u0644\u0629",
283
+ countrySearchPlaceholder: "\u0627\u0628\u062D\u062B \u0639\u0646 \u062F\u0648\u0644\u0629...",
284
+ noCountriesFound: "\u0644\u0645 \u064A\u062A\u0645 \u0627\u0644\u0639\u062B\u0648\u0631 \u0639\u0644\u0649 \u062F\u0648\u0644",
285
+ searchCountriesAriaLabel: "\u0627\u0628\u062D\u062B \u0639\u0646 \u0627\u0644\u062F\u0648\u0644",
286
+ countryOptionsAriaLabel: "\u062E\u064A\u0627\u0631\u0627\u062A \u0627\u0644\u062F\u0648\u0644",
287
+ countryButtonAriaLabel: "\u0627\u0641\u062A\u062D \u0645\u062D\u062F\u062F \u0627\u0644\u062F\u0648\u0644\u0629"
288
+ },
289
+ hi: {
290
+ selectCountry: "\u0926\u0947\u0936 \u091A\u0941\u0928\u0947\u0902",
291
+ countrySearchPlaceholder: "\u0926\u0947\u0936 \u0916\u094B\u091C\u0947\u0902...",
292
+ noCountriesFound: "\u0915\u094B\u0908 \u0926\u0947\u0936 \u0928\u0939\u0940\u0902 \u092E\u093F\u0932\u093E",
293
+ searchCountriesAriaLabel: "\u0926\u0947\u0936 \u0916\u094B\u091C\u0947\u0902",
294
+ countryOptionsAriaLabel: "\u0926\u0947\u0936 \u0935\u093F\u0915\u0932\u094D\u092A",
295
+ countryButtonAriaLabel: "\u0926\u0947\u0936 \u091A\u092F\u0928 \u0916\u094B\u0932\u0947\u0902"
296
+ }
297
+ };
298
+ function getPrimaryLanguage(locale) {
299
+ const locales = Array.isArray(locale) ? locale : locale ? [locale] : [];
300
+ const firstLocale = locales.find(Boolean);
301
+ return firstLocale ? firstLocale.toLowerCase().split("-")[0] : void 0;
302
+ }
303
+ function resolvePhoneInputLabels(locale, overrides) {
304
+ const language = getPrimaryLanguage(locale);
305
+ const localizedDefaults = language ? LABELS_BY_LANGUAGE[language] : void 0;
306
+ return {
307
+ ...DEFAULT_PHONE_INPUT_LABELS,
308
+ ...localizedDefaults,
309
+ ...overrides
310
+ };
311
+ }
312
+ function normalizePhoneInput(phone) {
313
+ const trimmed = phone.trim();
314
+ const digits = cleanPhone(trimmed);
315
+ if (trimmed.startsWith("+") && !digits) {
316
+ return "+";
317
+ }
318
+ if (!digits) {
319
+ return "";
320
+ }
321
+ return trimmed.startsWith("+") ? `+${digits}` : digits;
322
+ }
323
+ function getCountryCode(country) {
324
+ return country?.code;
325
+ }
326
+ function getMaxNationalDigits(country) {
327
+ return country?.format?.replace(/[^#]/g, "").length;
328
+ }
329
+ function getLengthValidationStatus(phone, country) {
330
+ const normalized = normalizePhoneInput(phone);
331
+ if (normalized.startsWith("+")) {
332
+ return validatePhoneNumberLength(normalized);
333
+ }
334
+ const countryCode = getCountryCode(country);
335
+ if (!countryCode) {
336
+ return void 0;
337
+ }
338
+ return validatePhoneNumberLength(cleanPhone(normalized), countryCode);
339
+ }
340
+ function isPhoneTooLong(phone, country) {
341
+ const normalized = normalizePhoneInput(phone);
342
+ const digits = cleanPhone(normalized);
343
+ if (!digits) {
344
+ return false;
345
+ }
346
+ if (getLengthValidationStatus(phone, country) === "TOO_LONG") {
347
+ return true;
348
+ }
349
+ const maxDigits = normalized.startsWith("+") ? 18 : 15;
350
+ return digits.length > maxDigits;
351
+ }
352
+ function cleanPhone(phone) {
353
+ return phone.replace(/\D/g, "");
354
+ }
355
+ function formatPhone(phone, country) {
356
+ if (!phone) return phone;
357
+ const formatter = new AsYouType(getCountryCode(country));
358
+ return formatter.input(normalizePhoneInput(phone));
359
+ }
360
+ function unformatPhone(formattedPhone) {
361
+ return normalizePhoneInput(formattedPhone);
362
+ }
363
+ function validatePhoneLength(phone, country) {
364
+ if (!phone || !country) return false;
365
+ if (phone.trim().startsWith("+")) {
366
+ return validatePhoneNumberLength(normalizePhoneInput(phone)) === void 0;
367
+ }
368
+ return validatePhoneNumberLength(cleanPhone(phone), getCountryCode(country)) === void 0;
369
+ }
370
+ function validatePhone(phone, country, customValidator) {
371
+ if (!phone) return false;
372
+ if (customValidator) {
373
+ return customValidator(phone, country ?? void 0);
374
+ }
375
+ const normalized = normalizePhoneInput(phone);
376
+ const countryCode = getCountryCode(country);
377
+ if (!countryCode) {
378
+ return isPossiblePhoneNumber(normalized.startsWith("+") ? normalized : `+${cleanPhone(normalized)}`);
379
+ }
380
+ if (normalized.startsWith("+")) {
381
+ return isValidPhoneNumber(normalized);
382
+ }
383
+ return isValidPhoneNumber(cleanPhone(normalized), countryCode);
384
+ }
385
+ function addDialCode(phone, country) {
386
+ if (!country) return phone;
387
+ const normalized = normalizePhoneInput(phone);
388
+ if (!normalized) return "";
389
+ if (normalized === "+") return "";
390
+ if (normalized.startsWith("+")) return normalized;
391
+ const digits = cleanPhone(normalized);
392
+ const matchingDialCode = country.dialCodes.find((dialCode) => digits.startsWith(dialCode.replace("+", "")));
393
+ return matchingDialCode ? `+${digits}` : `${country.dialCode}${digits}`;
394
+ }
395
+ function removeDialCode(phone, country) {
396
+ if (!country) return phone;
397
+ const normalized = normalizePhoneInput(phone);
398
+ const digits = cleanPhone(normalized);
399
+ const primaryDialDigits = cleanPhone(country.dialCode);
400
+ if (digits.startsWith(primaryDialDigits)) {
401
+ return digits.slice(primaryDialDigits.length);
402
+ }
403
+ for (const dialCode of country.dialCodes) {
404
+ const dialDigits = dialCode.replace("+", "");
405
+ if (digits.startsWith(dialDigits)) {
406
+ return digits.slice(dialDigits.length);
407
+ }
408
+ }
409
+ return digits;
410
+ }
411
+ function filterCountries(countries2, query, preferredCountries) {
412
+ const lowerQuery = query.toLowerCase().trim();
413
+ if (!lowerQuery) {
414
+ if (preferredCountries?.length) {
415
+ return [...countries2].sort((a, b) => {
416
+ const aPreferred = preferredCountries.indexOf(a.code);
417
+ const bPreferred = preferredCountries.indexOf(b.code);
418
+ if (aPreferred !== -1 && bPreferred !== -1) return aPreferred - bPreferred;
419
+ if (aPreferred !== -1) return -1;
420
+ if (bPreferred !== -1) return 1;
421
+ return (a.displayName ?? a.name).localeCompare(b.displayName ?? b.name);
422
+ });
423
+ }
424
+ return countries2;
425
+ }
426
+ return countries2.filter(
427
+ (country) => country.name.toLowerCase().includes(lowerQuery) || (country.displayName ?? "").toLowerCase().includes(lowerQuery) || country.code.toLowerCase().includes(lowerQuery) || country.dialCodes.some((dialCode) => dialCode.includes(lowerQuery))
428
+ );
429
+ }
430
+ function getCountryDisplayName(country) {
431
+ return country?.displayName ?? country?.name ?? "";
432
+ }
433
+ function getPlaceholder(country) {
434
+ if (!country?.format) return country?.dialCode ? `${country.dialCode} 000 000 0000` : "Phone number";
435
+ return country.format.replace(/#/g, "0");
436
+ }
437
+ var stripNonDigits = cleanPhone;
438
+ function isInternationalFormat(phone) {
439
+ return phone.trim().startsWith("+") || phone.trim().startsWith("00");
440
+ }
441
+ function extractDialCode(phone) {
442
+ const digits = cleanPhone(phone);
443
+ if (!isInternationalFormat(phone)) {
444
+ return { dialCode: null, nationalNumber: digits };
445
+ }
446
+ const match = countries.map((country) => country.dialCode).sort((left, right) => right.length - left.length).find((dialCode) => digits.startsWith(cleanPhone(dialCode)));
447
+ if (!match) {
448
+ return { dialCode: null, nationalNumber: digits };
449
+ }
450
+ const dialDigits = cleanPhone(match);
451
+ return {
452
+ dialCode: dialDigits,
453
+ nationalNumber: digits.slice(dialDigits.length)
454
+ };
455
+ }
456
+ function detectCountry(phone) {
457
+ return detectCountryFromPhone(phone) ?? null;
458
+ }
459
+ function formatPhoneNumber(phone, country, format = "national") {
460
+ if (!phone) return "";
461
+ if (format === "e164") {
462
+ return addDialCode(phone, country);
463
+ }
464
+ const nationalNumber = isInternationalFormat(phone) ? removeDialCode(phone, country) : phone;
465
+ if (!country && format === "national") {
466
+ return cleanPhone(nationalNumber).replace(/(\d{3})(?=\d)/g, "$1 ").trim();
467
+ }
468
+ const formattedNational = formatPhone(nationalNumber, country);
469
+ if (format === "international") {
470
+ return country ? `${country.dialCode} ${formattedNational}` : addDialCode(phone, country);
471
+ }
472
+ return formattedNational;
473
+ }
474
+ function parseToE164(phone, country) {
475
+ return addDialCode(phone, country);
476
+ }
477
+ function getNationalNumber(phone, country) {
478
+ if (country) {
479
+ return removeDialCode(phone, country);
480
+ }
481
+ const detectedCountry = detectCountryFromPhone(phone);
482
+ return detectedCountry ? removeDialCode(phone, detectedCountry) : cleanPhone(phone);
483
+ }
484
+ function validationFailure(reason, message) {
485
+ return { isValid: false, reason, message, error: message };
486
+ }
487
+ function validationSuccess() {
488
+ return { isValid: true, reason: null, message: null, error: null };
489
+ }
490
+ function validatePhoneNumber(phone, country, required = false, customValidator) {
491
+ const digits = cleanPhone(phone);
492
+ if (!digits) {
493
+ return required ? validationFailure("required", "Phone number is required") : validationSuccess();
494
+ }
495
+ const lengthStatus = getLengthValidationStatus(phone, country);
496
+ const nationalDigits = country ? cleanPhone(removeDialCode(phone, country)) : digits;
497
+ if (lengthStatus === "TOO_SHORT" || lengthStatus === void 0 && nationalDigits.length < 7) {
498
+ return validationFailure("too_short", "Phone number is too short");
499
+ }
500
+ if (lengthStatus === "TOO_LONG" || isPhoneTooLong(phone, country)) {
501
+ return validationFailure("too_long", "Phone number is too long");
502
+ }
503
+ const isValid = customValidator ? customValidator(phone, country ?? void 0) : validatePhone(phone, country);
504
+ return isValid ? validationSuccess() : validationFailure("invalid", "Invalid phone number");
505
+ }
506
+ function parsePhoneValue(phone, country) {
507
+ const countryCode = getCountryCode(country);
508
+ const normalized = normalizePhoneInput(phone);
509
+ const parsed = normalized.startsWith("+") ? parsePhoneNumberFromString(normalized) : parsePhoneNumberFromString(cleanPhone(normalized), countryCode);
510
+ if (!parsed) {
511
+ const nationalNumber = country ? removeDialCode(phone, country) : cleanPhone(phone);
512
+ return {
513
+ country: country ?? void 0,
514
+ nationalNumber,
515
+ e164: void 0,
516
+ isValid: false
517
+ };
518
+ }
519
+ const parsedCountry = parsed.country ? getCountryByCode(parsed.country) : country ?? void 0;
520
+ return {
521
+ country: parsedCountry,
522
+ nationalNumber: parsed.nationalNumber,
523
+ e164: parsed.isValid() ? parsed.number : void 0,
524
+ isValid: parsed.isValid()
525
+ };
526
+ }
527
+ function isPhoneNumberComplete(phone, country) {
528
+ if (!country) {
529
+ return cleanPhone(phone).length >= 7;
530
+ }
531
+ return validatePhoneLength(phone, country);
532
+ }
533
+ function formatAsYouType(phone, country) {
534
+ if (isInternationalFormat(phone) && country) {
535
+ return `${country.dialCode} ${formatPhone(removeDialCode(phone, country), country)}`;
536
+ }
537
+ return formatPhone(phone, country);
538
+ }
539
+ var normalizePhoneNumber = cleanPhone;
540
+ function phoneNumbersEqual(left, right) {
541
+ return normalizePhoneNumber(left) === normalizePhoneNumber(right);
542
+ }
543
+ function getCountryDisplayLabel(country, includeDialCode = true) {
544
+ const label = `${country.flag} ${getCountryDisplayName(country)}`;
545
+ return includeDialCode ? `${label} (${country.dialCode})` : label;
546
+ }
547
+ function limitInputLength(phone, country) {
548
+ const maxDigits = getMaxNationalDigits(country);
549
+ if (!maxDigits) {
550
+ return phone;
551
+ }
552
+ const isInternational = isInternationalFormat(phone);
553
+ const digits = cleanPhone(phone);
554
+ const dialDigits = country ? cleanPhone(country.dialCode) : "";
555
+ const maxLength = isInternational ? dialDigits.length + maxDigits : maxDigits;
556
+ const limited = digits.slice(0, maxLength);
557
+ return isInternational ? `+${limited}` : limited;
558
+ }
559
+
560
+ // src/usePhoneInput.ts
561
+ var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
562
+ function countDigitsBeforePosition(value, position) {
563
+ return value.slice(0, position).replace(/\D/g, "").length;
564
+ }
565
+ function getCaretPositionFromDigitCount(value, digitCount) {
566
+ if (digitCount <= 0) {
567
+ return value.startsWith("+") ? 1 : 0;
568
+ }
569
+ let seenDigits = 0;
570
+ for (let index = 0; index < value.length; index += 1) {
571
+ if (/\d/.test(value[index])) {
572
+ seenDigits += 1;
573
+ if (seenDigits === digitCount) {
574
+ return index + 1;
575
+ }
576
+ }
577
+ }
578
+ return value.length;
579
+ }
580
+ function usePhoneInput(options = {}) {
581
+ const {
582
+ value: controlledValue,
583
+ defaultValue = "",
584
+ onChange,
585
+ onCountryChange,
586
+ onBlur,
587
+ onFocus,
588
+ defaultCountry = "US",
589
+ preferredCountries,
590
+ excludeCountries,
591
+ excludedCountries,
592
+ onlyCountries,
593
+ allowedCountries,
594
+ autoDetect,
595
+ autoDetectCountry,
596
+ formatOnType = true,
597
+ includeDialCode = false,
598
+ required = false,
599
+ validator,
600
+ onValidationChange,
601
+ locale,
602
+ labels
603
+ } = options;
604
+ const resolvedOnlyCountries = onlyCountries ?? allowedCountries;
605
+ const resolvedExcludeCountries = excludeCountries ?? excludedCountries;
606
+ const resolvedAutoDetect = autoDetect ?? autoDetectCountry ?? true;
607
+ const isControlled = controlledValue !== void 0;
608
+ const inputRef = useRef(null);
609
+ const pendingCaretDigitIndexRef = useRef(null);
610
+ const previousDefaultCountryRef = useRef(defaultCountry);
611
+ const manualCountrySelectionRef = useRef(false);
612
+ const availableCountries = useMemo(() => {
613
+ let filtered = countries;
614
+ if (resolvedOnlyCountries?.length) {
615
+ filtered = filtered.filter((c) => resolvedOnlyCountries.includes(c.code));
616
+ }
617
+ if (resolvedExcludeCountries?.length) {
618
+ filtered = filtered.filter((c) => !resolvedExcludeCountries.includes(c.code));
619
+ }
620
+ return filtered;
621
+ }, [resolvedOnlyCountries, resolvedExcludeCountries]);
622
+ const localizedCountries = useMemo(
623
+ () => localizeCountries(availableCountries, locale),
624
+ [availableCountries, locale]
625
+ );
626
+ const resolvedLabels = useMemo(
627
+ () => resolvePhoneInputLabels(locale, labels),
628
+ [locale, labels]
629
+ );
630
+ const initialCountry = availableCountries.find((candidate) => candidate.code === defaultCountry) || availableCountries[0];
631
+ const [internalPhone, setInternalPhone] = useState(defaultValue);
632
+ const [country, setCountry] = useState(initialCountry);
633
+ const [isOpen, setIsOpen] = useState(false);
634
+ const [searchQuery, setSearchQuery] = useState("");
635
+ const phone = isControlled ? controlledValue : internalPhone;
636
+ const getOutputCountry = useCallback(
637
+ (nextCountry) => localizeCountry(nextCountry, locale),
638
+ [locale]
639
+ );
640
+ useEffect(() => {
641
+ const defaultCountryChanged = previousDefaultCountryRef.current !== defaultCountry;
642
+ previousDefaultCountryRef.current = defaultCountry;
643
+ const nextCountry = availableCountries.find((candidate) => candidate.code === defaultCountry) || availableCountries[0];
644
+ const countryStillAvailable = country ? availableCountries.some((candidate) => candidate.code === country.code) : false;
645
+ if (nextCountry && (defaultCountryChanged || !countryStillAvailable) && nextCountry.code !== country?.code) {
646
+ setCountry(nextCountry);
647
+ onCountryChange?.(getOutputCountry(nextCountry));
648
+ }
649
+ }, [defaultCountry, availableCountries, country, onCountryChange, getOutputCountry]);
650
+ useEffect(() => {
651
+ if (!resolvedAutoDetect || !phone) {
652
+ return;
653
+ }
654
+ const detected = detectCountryFromPhone(phone);
655
+ if (!detected || detected.code === country?.code) {
656
+ return;
657
+ }
658
+ if (!availableCountries.some((candidate) => candidate.code === detected.code)) {
659
+ return;
660
+ }
661
+ const digits = cleanPhone(phone);
662
+ const manualSelectionStillMatches = manualCountrySelectionRef.current && country?.dialCodes.some((dialCode) => digits.startsWith(dialCode.replace("+", "")));
663
+ if (manualSelectionStillMatches) {
664
+ return;
665
+ }
666
+ manualCountrySelectionRef.current = false;
667
+ setCountry(detected);
668
+ onCountryChange?.(getOutputCountry(detected));
669
+ }, [availableCountries, resolvedAutoDetect, phone, country, onCountryChange, getOutputCountry]);
670
+ const formattedPhone = useMemo(() => {
671
+ if (formatOnType) {
672
+ return formatPhone(includeDialCode && phone.startsWith("+") ? removeDialCode(phone, country) : phone, country);
673
+ }
674
+ return includeDialCode && phone.startsWith("+") ? removeDialCode(phone, country) : phone;
675
+ }, [formatOnType, includeDialCode, phone, country]);
676
+ const fullPhone = useMemo(() => {
677
+ if (includeDialCode && country) {
678
+ return addDialCode(phone, country);
679
+ }
680
+ return phone;
681
+ }, [phone, country, includeDialCode]);
682
+ const validation = useMemo(
683
+ () => validatePhoneNumber(phone, country, required, validator),
684
+ [phone, country, required, validator]
685
+ );
686
+ useEffect(() => {
687
+ onValidationChange?.(validation);
688
+ }, [validation, onValidationChange]);
689
+ const localizedCountry = useMemo(
690
+ () => localizeCountry(country, locale),
691
+ [country, locale]
692
+ );
693
+ const filteredCountries = useMemo(
694
+ () => filterCountries(localizedCountries, searchQuery, preferredCountries),
695
+ [localizedCountries, searchQuery, preferredCountries]
696
+ );
697
+ useIsomorphicLayoutEffect(() => {
698
+ const nextDigitIndex = pendingCaretDigitIndexRef.current;
699
+ const input = inputRef.current;
700
+ if (nextDigitIndex === null || !input || typeof input.setSelectionRange !== "function") {
701
+ return;
702
+ }
703
+ if (typeof document !== "undefined" && document.activeElement !== input) {
704
+ return;
705
+ }
706
+ const caretPosition = getCaretPositionFromDigitCount(formattedPhone, nextDigitIndex);
707
+ input.setSelectionRange(caretPosition, caretPosition);
708
+ pendingCaretDigitIndexRef.current = null;
709
+ }, [formattedPhone]);
710
+ const setPhone = useCallback(
711
+ (newPhone) => {
712
+ const unformatted = unformatPhone(newPhone);
713
+ if (!isControlled) {
714
+ setInternalPhone(unformatted);
715
+ }
716
+ onChange?.(
717
+ includeDialCode ? addDialCode(unformatted, country) : unformatted,
718
+ getOutputCountry(country)
719
+ );
720
+ },
721
+ [isControlled, onChange, country, includeDialCode, getOutputCountry]
722
+ );
723
+ const setCountryByCode = useCallback(
724
+ (code) => {
725
+ const newCountry = getCountryByCode(code);
726
+ if (newCountry) {
727
+ manualCountrySelectionRef.current = true;
728
+ setCountry(newCountry);
729
+ onCountryChange?.(getOutputCountry(newCountry));
730
+ onChange?.(
731
+ includeDialCode ? addDialCode(phone, newCountry) : phone,
732
+ getOutputCountry(newCountry)
733
+ );
734
+ }
735
+ },
736
+ [phone, onChange, onCountryChange, includeDialCode, getOutputCountry]
737
+ );
738
+ const selectCountry = useCallback(
739
+ (selectedCountry) => {
740
+ const rawCountry = getCountryByCode(selectedCountry.code) ?? selectedCountry;
741
+ manualCountrySelectionRef.current = true;
742
+ setCountry(rawCountry);
743
+ setIsOpen(false);
744
+ setSearchQuery("");
745
+ onCountryChange?.(getOutputCountry(rawCountry));
746
+ onChange?.(
747
+ includeDialCode ? addDialCode(phone, rawCountry) : phone,
748
+ getOutputCountry(rawCountry)
749
+ );
750
+ },
751
+ [phone, onChange, onCountryChange, includeDialCode, getOutputCountry]
752
+ );
753
+ const toggleDropdown = useCallback(() => {
754
+ setIsOpen((prev) => !prev);
755
+ if (isOpen) {
756
+ setSearchQuery("");
757
+ }
758
+ }, [isOpen]);
759
+ const openDropdown = useCallback(() => {
760
+ setIsOpen(true);
761
+ }, []);
762
+ const closeDropdown = useCallback(() => {
763
+ setIsOpen(false);
764
+ setSearchQuery("");
765
+ }, []);
766
+ const clear = useCallback(() => {
767
+ if (!isControlled) {
768
+ setInternalPhone("");
769
+ }
770
+ onChange?.("", getOutputCountry(country));
771
+ }, [isControlled, onChange, country, getOutputCountry]);
772
+ const handleInputChange = useCallback(
773
+ (event) => {
774
+ const rawValue = event.target.value;
775
+ const caretPosition = event.target.selectionStart ?? rawValue.length;
776
+ const unformatted = rawValue.trim().startsWith("+") ? `+${rawValue.replace(/\D/g, "")}` : unformatPhone(rawValue);
777
+ if (cleanPhone(unformatted).length > cleanPhone(phone).length && isPhoneTooLong(unformatted, country)) {
778
+ event.target.value = formattedPhone;
779
+ const restoredCaret = Math.min(Math.max(caretPosition - 1, 0), formattedPhone.length);
780
+ if (typeof event.target.setSelectionRange === "function") {
781
+ event.target.setSelectionRange(restoredCaret, restoredCaret);
782
+ }
783
+ return;
784
+ }
785
+ pendingCaretDigitIndexRef.current = countDigitsBeforePosition(rawValue, caretPosition);
786
+ setPhone(unformatted);
787
+ },
788
+ [setPhone, phone, country, formattedPhone]
789
+ );
790
+ const handleFocus = useCallback(() => {
791
+ onFocus?.();
792
+ }, [onFocus]);
793
+ const handleBlur = useCallback(() => {
794
+ onBlur?.();
795
+ }, [onBlur]);
796
+ const getCountryOptionId = useCallback(
797
+ (code) => `phone-input-country-${code}`,
798
+ []
799
+ );
800
+ const getCountryOptionProps = useCallback(
801
+ (optionCountry, index) => ({
802
+ id: getCountryOptionId(optionCountry.code),
803
+ role: "option",
804
+ "aria-selected": optionCountry.code === country?.code,
805
+ onClick: () => selectCountry(optionCountry),
806
+ onKeyDown: (event) => {
807
+ if (event.key === "Enter" || event.key === " ") {
808
+ event.preventDefault();
809
+ selectCountry(optionCountry);
810
+ }
811
+ if (event.key === "Escape") {
812
+ event.preventDefault();
813
+ closeDropdown();
814
+ }
815
+ },
816
+ tabIndex: index === 0 ? 0 : -1
817
+ }),
818
+ [closeDropdown, country?.code, getCountryOptionId, selectCountry]
819
+ );
820
+ return {
821
+ // State
822
+ phone,
823
+ value: phone,
824
+ fullPhone,
825
+ country: localizedCountry,
826
+ isValid: validation.isValid,
827
+ validationReason: validation.reason,
828
+ error: validation.error,
829
+ isOpen,
830
+ searchQuery,
831
+ labels: resolvedLabels,
832
+ formattedValue: formattedPhone,
833
+ // Actions
834
+ setPhone,
835
+ setValue: setPhone,
836
+ setCountry: setCountryByCode,
837
+ toggleDropdown,
838
+ toggle: toggleDropdown,
839
+ openDropdown,
840
+ open: openDropdown,
841
+ closeDropdown,
842
+ close: closeDropdown,
843
+ setSearchQuery,
844
+ clear,
845
+ // Props
846
+ inputProps: {
847
+ ref: inputRef,
848
+ value: formattedPhone,
849
+ onChange: handleInputChange,
850
+ onFocus: handleFocus,
851
+ onBlur: handleBlur,
852
+ type: "tel",
853
+ inputMode: "tel",
854
+ autoComplete: "tel",
855
+ placeholder: getPlaceholder(country),
856
+ "aria-invalid": validation.isValid ? void 0 : true
857
+ },
858
+ countryButtonProps: {
859
+ onClick: toggleDropdown,
860
+ "aria-expanded": isOpen,
861
+ "aria-haspopup": "listbox",
862
+ "aria-label": resolvedLabels.countryButtonAriaLabel
863
+ },
864
+ countrySelectorProps: {
865
+ onClick: toggleDropdown,
866
+ "aria-expanded": isOpen,
867
+ "aria-haspopup": "listbox",
868
+ "aria-label": resolvedLabels.countryButtonAriaLabel
869
+ },
870
+ dropdownProps: {
871
+ role: "listbox",
872
+ "aria-label": resolvedLabels.countryOptionsAriaLabel
873
+ },
874
+ getCountryOptionId,
875
+ filteredCountries,
876
+ countries: filteredCountries,
877
+ selectCountry,
878
+ getCountryOptionProps
879
+ };
880
+ }
881
+ var ChevronUpIcon = ({ size = 12 }) => /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("polyline", { points: "18 15 12 9 6 15" }) });
882
+ var ChevronDownIcon = ({ size = 12 }) => /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("polyline", { points: "6 9 12 15 18 9" }) });
883
+ var PhoneInput = forwardRef(
884
+ function PhoneInput2(props, ref) {
885
+ const {
886
+ value,
887
+ defaultValue,
888
+ onChange,
889
+ onBlur,
890
+ onFocus,
891
+ inputClassName,
892
+ selectorClassName,
893
+ containerClassName,
894
+ searchable = true,
895
+ placeholder,
896
+ disabled,
897
+ readOnly,
898
+ name,
899
+ id,
900
+ "aria-label": ariaLabel,
901
+ "aria-labelledby": ariaLabelledBy,
902
+ ...options
903
+ } = props;
904
+ const containerRef = useRef(null);
905
+ const inputRef = useRef(null);
906
+ const optionRefs = useRef([]);
907
+ const [highlightedIndex, setHighlightedIndex] = useState(0);
908
+ const listboxId = useId();
909
+ const {
910
+ inputProps,
911
+ countryButtonProps,
912
+ dropdownProps,
913
+ country,
914
+ filteredCountries,
915
+ isOpen,
916
+ isValid,
917
+ searchQuery,
918
+ setSearchQuery,
919
+ setCountry,
920
+ selectCountry,
921
+ clear,
922
+ openDropdown,
923
+ closeDropdown,
924
+ getCountryOptionId,
925
+ labels
926
+ } = usePhoneInput({
927
+ value,
928
+ defaultValue,
929
+ onChange,
930
+ onBlur,
931
+ onFocus,
932
+ ...options
933
+ });
934
+ const hookInputRef = inputProps.ref;
935
+ const mergedInputRef = useCallback((element) => {
936
+ inputRef.current = element;
937
+ if (typeof hookInputRef === "function") {
938
+ hookInputRef(element);
939
+ } else if (hookInputRef && "current" in hookInputRef) {
940
+ hookInputRef.current = element;
941
+ }
942
+ }, [hookInputRef]);
943
+ const focus = useCallback(() => {
944
+ inputRef.current?.focus();
945
+ }, []);
946
+ const blur = useCallback(() => {
947
+ inputRef.current?.blur();
948
+ }, []);
949
+ const handleCountryClick = useCallback((c) => {
950
+ selectCountry(c);
951
+ setHighlightedIndex(0);
952
+ }, [selectCountry]);
953
+ const handleCountryKeyDown = useCallback((e, c, index) => {
954
+ switch (e.key) {
955
+ case "Enter":
956
+ case " ":
957
+ e.preventDefault();
958
+ selectCountry(c);
959
+ setHighlightedIndex(0);
960
+ break;
961
+ case "ArrowDown":
962
+ e.preventDefault();
963
+ if (index < filteredCountries.length - 1) {
964
+ const nextIndex = index + 1;
965
+ setHighlightedIndex(nextIndex);
966
+ optionRefs.current[nextIndex]?.focus();
967
+ }
968
+ break;
969
+ case "ArrowUp":
970
+ e.preventDefault();
971
+ if (index > 0) {
972
+ const nextIndex = index - 1;
973
+ setHighlightedIndex(nextIndex);
974
+ optionRefs.current[nextIndex]?.focus();
975
+ }
976
+ break;
977
+ case "Home":
978
+ e.preventDefault();
979
+ setHighlightedIndex(0);
980
+ optionRefs.current[0]?.focus();
981
+ break;
982
+ case "End": {
983
+ e.preventDefault();
984
+ const lastIndex = filteredCountries.length - 1;
985
+ setHighlightedIndex(lastIndex);
986
+ optionRefs.current[lastIndex]?.focus();
987
+ break;
988
+ }
989
+ case "Escape":
990
+ e.preventDefault();
991
+ closeDropdown();
992
+ break;
993
+ }
994
+ }, [selectCountry, filteredCountries.length, closeDropdown]);
995
+ useEffect(() => {
996
+ if (!isOpen) {
997
+ return;
998
+ }
999
+ const handlePointerDown = (event) => {
1000
+ const target = event.target;
1001
+ if (containerRef.current && target && !containerRef.current.contains(target)) {
1002
+ closeDropdown();
1003
+ }
1004
+ };
1005
+ const handleFocusIn = (event) => {
1006
+ const target = event.target;
1007
+ if (containerRef.current && target && !containerRef.current.contains(target)) {
1008
+ closeDropdown();
1009
+ }
1010
+ };
1011
+ document.addEventListener("mousedown", handlePointerDown);
1012
+ document.addEventListener("focusin", handleFocusIn);
1013
+ return () => {
1014
+ document.removeEventListener("mousedown", handlePointerDown);
1015
+ document.removeEventListener("focusin", handleFocusIn);
1016
+ };
1017
+ }, [isOpen, closeDropdown]);
1018
+ useEffect(() => {
1019
+ if (filteredCountries.length === 0) {
1020
+ if (highlightedIndex !== 0) {
1021
+ setHighlightedIndex(0);
1022
+ }
1023
+ return;
1024
+ }
1025
+ if (highlightedIndex >= filteredCountries.length) {
1026
+ setHighlightedIndex(filteredCountries.length - 1);
1027
+ }
1028
+ }, [filteredCountries.length, highlightedIndex]);
1029
+ useImperativeHandle(ref, () => ({
1030
+ focus,
1031
+ blur,
1032
+ clear,
1033
+ setCountry,
1034
+ getCountry: () => country,
1035
+ open: openDropdown,
1036
+ close: closeDropdown
1037
+ }));
1038
+ const handleSearchKeyDown = useCallback((e) => {
1039
+ if (e.key === "ArrowDown") {
1040
+ e.preventDefault();
1041
+ setHighlightedIndex(0);
1042
+ optionRefs.current[0]?.focus();
1043
+ } else if (e.key === "Escape") {
1044
+ e.preventDefault();
1045
+ closeDropdown();
1046
+ }
1047
+ }, [closeDropdown]);
1048
+ return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: containerClassName, "data-valid": isValid, children: [
1049
+ /* @__PURE__ */ jsxs(
1050
+ "button",
1051
+ {
1052
+ ...countryButtonProps,
1053
+ type: "button",
1054
+ className: selectorClassName,
1055
+ disabled,
1056
+ tabIndex: disabled ? -1 : 0,
1057
+ "aria-controls": listboxId,
1058
+ children: [
1059
+ country ? /* @__PURE__ */ jsxs(Fragment, { children: [
1060
+ /* @__PURE__ */ jsx("span", { className: "phone-input-flag", children: country.flag }),
1061
+ /* @__PURE__ */ jsx("span", { className: "phone-input-dial-code", children: country.dialCode })
1062
+ ] }) : /* @__PURE__ */ jsx("span", { className: "phone-input-placeholder", children: labels.selectCountry }),
1063
+ /* @__PURE__ */ jsx("span", { className: "phone-input-arrow", "aria-hidden": "true", children: isOpen ? /* @__PURE__ */ jsx(ChevronUpIcon, { size: 12 }) : /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12 }) })
1064
+ ]
1065
+ }
1066
+ ),
1067
+ /* @__PURE__ */ jsx(
1068
+ "input",
1069
+ {
1070
+ ...inputProps,
1071
+ ref: mergedInputRef,
1072
+ id,
1073
+ name,
1074
+ className: inputClassName,
1075
+ placeholder: placeholder || inputProps.placeholder,
1076
+ disabled,
1077
+ readOnly,
1078
+ "aria-label": ariaLabel,
1079
+ "aria-labelledby": ariaLabelledBy
1080
+ }
1081
+ ),
1082
+ isOpen && /* @__PURE__ */ jsxs("div", { className: "phone-input-dropdown", children: [
1083
+ searchable && /* @__PURE__ */ jsx("div", { className: "phone-input-search", children: /* @__PURE__ */ jsx(
1084
+ "input",
1085
+ {
1086
+ type: "text",
1087
+ value: searchQuery,
1088
+ onChange: (e) => setSearchQuery(e.target.value),
1089
+ onKeyDown: handleSearchKeyDown,
1090
+ placeholder: labels.countrySearchPlaceholder,
1091
+ autoFocus: true,
1092
+ "aria-controls": listboxId,
1093
+ "aria-label": labels.searchCountriesAriaLabel
1094
+ }
1095
+ ) }),
1096
+ /* @__PURE__ */ jsxs(
1097
+ "ul",
1098
+ {
1099
+ ...dropdownProps,
1100
+ className: "phone-input-country-list",
1101
+ id: listboxId,
1102
+ children: [
1103
+ filteredCountries.map((c, index) => /* @__PURE__ */ jsxs(
1104
+ "li",
1105
+ {
1106
+ id: getCountryOptionId(c.code),
1107
+ ref: (element) => {
1108
+ optionRefs.current[index] = element;
1109
+ },
1110
+ role: "option",
1111
+ "aria-selected": c.code === country?.code,
1112
+ className: `phone-input-country-option ${c.code === country?.code ? "selected" : ""} ${index === highlightedIndex ? "highlighted" : ""}`,
1113
+ onClick: () => handleCountryClick(c),
1114
+ onKeyDown: (e) => handleCountryKeyDown(e, c, index),
1115
+ onMouseEnter: () => setHighlightedIndex(index),
1116
+ tabIndex: index === highlightedIndex ? 0 : -1,
1117
+ children: [
1118
+ /* @__PURE__ */ jsx("span", { className: "phone-input-flag", children: c.flag }),
1119
+ /* @__PURE__ */ jsx("span", { className: "phone-input-country-name", children: getCountryDisplayName(c) }),
1120
+ /* @__PURE__ */ jsx("span", { className: "phone-input-dial-code", children: c.dialCode })
1121
+ ]
1122
+ },
1123
+ c.code
1124
+ )),
1125
+ filteredCountries.length === 0 && /* @__PURE__ */ jsx("li", { className: "phone-input-no-results", children: labels.noCountriesFound })
1126
+ ]
1127
+ }
1128
+ )
1129
+ ] })
1130
+ ] });
1131
+ }
1132
+ );
1133
+
1134
+ export { DEFAULT_PHONE_INPUT_LABELS, PhoneInput, addDialCode, cleanPhone, countries, detectCountry, detectCountryFromPhone, extractDialCode, filterCountries, formatAsYouType, formatPhone, formatPhoneNumber, getCountriesByDialCode, getCountryByCode, getCountryByDialCode, getCountryDisplayLabel, getCountryDisplayName, getCountryOptions, getLocalizedCountryName, getNationalNumber, getPlaceholder, isInternationalFormat, isPhoneNumberComplete, isPhoneTooLong, limitInputLength, localizeCountries, localizeCountry, normalizePhoneNumber, parsePhoneValue, parseToE164, phoneNumbersEqual, removeDialCode, resolvePhoneInputLabels, stripNonDigits, unformatPhone, usePhoneInput, validatePhone, validatePhoneLength, validatePhoneNumber };
1135
+ //# sourceMappingURL=index.js.map
2
1136
  //# sourceMappingURL=index.js.map