telpick 2.0.0 → 2.0.2

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.
@@ -554,70 +554,86 @@ const S = [
554
554
  ];
555
555
  (function() {
556
556
  if (typeof document < "u" && document.currentScript && document.currentScript.src) {
557
- const i = document.currentScript.src.replace(/\/[^/]*$/, "");
558
- typeof globalThis < "u" ? globalThis.__TELPICK_SCRIPT_BASE__ = i : typeof window < "u" && (window.__TELPICK_SCRIPT_BASE__ = i);
557
+ const d = document.currentScript.src.replace(/\/[^/]*$/, "");
558
+ typeof globalThis < "u" ? globalThis.__TELPICK_SCRIPT_BASE__ = d : typeof window < "u" && (window.__TELPICK_SCRIPT_BASE__ = d);
559
559
  }
560
560
  })();
561
561
  function P() {
562
- const i = typeof globalThis < "u" && globalThis.__TELPICK_SCRIPT_BASE__ ? globalThis.__TELPICK_SCRIPT_BASE__ : typeof window < "u" && window.__TELPICK_SCRIPT_BASE__ || "";
563
- return i ? `${i.replace(/\/$/, "")}/assets/flags` : "";
562
+ const d = typeof globalThis < "u" && globalThis.__TELPICK_SCRIPT_BASE__ ? globalThis.__TELPICK_SCRIPT_BASE__ : typeof window < "u" && window.__TELPICK_SCRIPT_BASE__ || "";
563
+ return d ? `${d.replace(/\/$/, "")}/assets/flags` : typeof import.meta < "u" && import.meta.url ? new URL("./assets/flags/", self.location).href : "";
564
564
  }
565
565
  class T {
566
- constructor({ code: a = null, onChange: n = () => {
567
- }, styleOverrides: o = {}, baseFlagUrl: s = "" } = {}) {
568
- this.code = a, this.onChange = n, this.styleOverrides = o, this.baseFlagUrl = s || P(), this.codes = [], this.selectedCode = a, this.isDropdownOpen = !1, this.searchQuery = "", this.container = null, this.dropdown = null, this._outsideHandler = null, this._getFlagUrl = this._getFlagUrl.bind(this);
566
+ constructor({ code: n = null, onChange: r = () => {
567
+ }, styleOverrides: o = {}, baseFlagUrl: t = "" } = {}) {
568
+ this.code = n, this.onChange = r, this.styleOverrides = o, this.baseFlagUrl = t || P(), this.codes = [], this.selectedCode = n, this.isDropdownOpen = !1, this.searchQuery = "", this.container = null, this.dropdown = null, this._outsideHandler = null, this._scrollResizeCleanup = null, this._boundUpdatePosition = () => this._updateDropdownPosition(), this._getFlagUrl = this._getFlagUrl.bind(this);
569
569
  }
570
- _getFlagUrl(a, n) {
571
- const o = a ? a.replace(/^.*\//, "") : n ? `${String(n).toLowerCase()}.webp` : "";
572
- return o ? this.baseFlagUrl ? `${this.baseFlagUrl.replace(/\/$/, "")}/${o}` : a || (n ? `/flags/${String(n).toLowerCase()}.webp` : "") : "";
570
+ _updateDropdownPosition() {
571
+ if (!this.dropdown || !this.container)
572
+ return;
573
+ const n = this.container.getBoundingClientRect();
574
+ this.dropdown.style.position = "fixed", this.dropdown.style.top = `${n.bottom + 4}px`, this.dropdown.style.left = `${n.left}px`, this.dropdown.style.marginTop = "0";
573
575
  }
574
- async init(a) {
575
- if (this.container = a, this.codes = [...S].sort((o, s) => o.country.localeCompare(s.country, "es")), this.code) {
576
- const o = this.codes.find((s) => s.country_code === this.code);
576
+ _getFlagUrl(n, r) {
577
+ const o = n ? n.replace(/^.*\//, "") : r ? `${String(r).toLowerCase()}.webp` : "";
578
+ if (!o && !r)
579
+ return "";
580
+ if (this.baseFlagUrl) {
581
+ const t = this.baseFlagUrl.replace(/\/$/, "");
582
+ if (t.includes("flagcdn.com")) {
583
+ const i = String(r || o && o.replace(/\.[^.]+$/, "") || "").toLowerCase();
584
+ return i ? `${t}/${i}.png` : "";
585
+ }
586
+ return `${t}/${o}`;
587
+ }
588
+ return "";
589
+ }
590
+ async init(n) {
591
+ if (this.container = n, this.codes = [...S].sort((o, t) => o.country.localeCompare(t.country, "es")), this.code) {
592
+ const o = this.codes.find((t) => t.country_code === this.code);
577
593
  o && (this.selectedCode = o.country_code);
578
594
  } else {
579
595
  const o = [
580
596
  async () => {
581
597
  try {
582
- const r = await (await fetch("https://ip-api.com/json/?fields=countryCode")).json();
583
- if (r.countryCode)
584
- return this.codes.find((e) => e.country_code === r.countryCode);
598
+ const s = await (await fetch("https://ip-api.com/json/?fields=countryCode")).json();
599
+ if (s.countryCode)
600
+ return this.codes.find((e) => e.country_code === s.countryCode);
585
601
  } catch {
586
602
  }
587
603
  return null;
588
604
  },
589
605
  async () => {
590
606
  try {
591
- const r = await (await fetch("https://get.geojs.io/v1/ip/country.json")).json();
592
- if (r.country)
593
- return this.codes.find((e) => e.country_code === r.country);
607
+ const s = await (await fetch("https://get.geojs.io/v1/ip/country.json")).json();
608
+ if (s.country)
609
+ return this.codes.find((e) => e.country_code === s.country);
594
610
  } catch {
595
611
  }
596
612
  return null;
597
613
  },
598
614
  async () => {
599
615
  try {
600
- const r = await (await fetch("https://ipapi.co/json/")).json();
601
- if (r.country_code)
602
- return this.codes.find((e) => e.country_code === r.country_code);
616
+ const s = await (await fetch("https://ipapi.co/json/")).json();
617
+ if (s.country_code)
618
+ return this.codes.find((e) => e.country_code === s.country_code);
603
619
  } catch {
604
620
  }
605
621
  return null;
606
622
  }
607
623
  ];
608
- let s = null;
609
- for (const l of o)
624
+ let t = null;
625
+ for (const i of o)
610
626
  try {
611
- if (s = await Promise.race([
612
- l(),
613
- new Promise((r) => setTimeout(() => r(null), 3e3))
614
- ]), s)
627
+ if (t = await Promise.race([
628
+ i(),
629
+ new Promise((s) => setTimeout(() => s(null), 3e3))
630
+ ]), t)
615
631
  break;
616
632
  } catch {
617
633
  }
618
- if (!s)
634
+ if (!t)
619
635
  try {
620
- const l = Intl.DateTimeFormat().resolvedOptions().timeZone, e = {
636
+ const i = Intl.DateTimeFormat().resolvedOptions().timeZone, e = {
621
637
  "America/Lima": "PE",
622
638
  "America/Bogota": "CO",
623
639
  "America/Mexico_City": "MX",
@@ -679,106 +695,108 @@ class T {
679
695
  "Africa/Johannesburg": "ZA",
680
696
  "Africa/Nairobi": "KE",
681
697
  "Africa/Lagos": "NG"
682
- }[l];
683
- e && (s = this.codes.find((u) => u.country_code === e));
698
+ }[i];
699
+ e && (t = this.codes.find((u) => u.country_code === e));
684
700
  } catch {
685
701
  }
686
- if (s)
687
- this.selectedCode = s.country_code;
702
+ if (t)
703
+ this.selectedCode = t.country_code;
688
704
  else {
689
- const l = this.codes.find((r) => r.country_code === "CO");
690
- l && (this.selectedCode = l.country_code);
705
+ const i = this.codes.find((s) => s.country_code === "CO");
706
+ i && (this.selectedCode = i.country_code);
691
707
  }
692
708
  }
693
709
  this.render();
694
- const n = this.codes.find((o) => o.country_code === this.selectedCode);
695
- n && this.onChange(n), this._setupOutsideClick();
710
+ const r = this.codes.find((o) => o.country_code === this.selectedCode);
711
+ r && this.onChange(r), this._setupOutsideClick();
696
712
  }
697
713
  render() {
698
- this.container.innerHTML = "";
699
- const a = document.createElement("button");
700
- a.className = "telpick-btn", Object.assign(a.style, this.styleOverrides), a.onclick = () => {
714
+ this._scrollResizeCleanup && (this._scrollResizeCleanup(), this._scrollResizeCleanup = null), this.dropdown && this.dropdown.parentNode && (this.dropdown.parentNode.removeChild(this.dropdown), this.dropdown = null), this.container.innerHTML = "";
715
+ const n = document.createElement("button");
716
+ n.className = "telpick-btn", Object.assign(n.style, this.styleOverrides), n.onclick = () => {
701
717
  this.isDropdownOpen = !this.isDropdownOpen, this.render();
702
718
  };
703
- const n = document.createElement("div");
704
- n.className = "telpick-flag";
705
- const o = this.codes.find((e) => e.country_code === this.selectedCode) || { country_code: "", code: "", country: "", flag: "" }, s = this._getFlagUrl(o.flag, o.country_code);
706
- if (s) {
719
+ const r = document.createElement("div");
720
+ r.className = "telpick-flag";
721
+ const o = this.codes.find((e) => e.country_code === this.selectedCode) || { country_code: "", code: "", country: "", flag: "" }, t = this._getFlagUrl(o.flag, o.country_code);
722
+ if (t) {
707
723
  const e = document.createElement("img");
708
- e.src = s, e.className = "w-full h-full object-cover", e.alt = o.country || "flag", e.loading = "lazy", e.referrerPolicy = "no-referrer", n.appendChild(e);
724
+ e.src = t, e.className = "w-full h-full object-cover", e.alt = o.country || "flag", e.loading = "lazy", e.referrerPolicy = "no-referrer", r.appendChild(e);
709
725
  }
710
- a.appendChild(n);
711
- const l = document.createElement("span");
712
- l.textContent = o.code, a.appendChild(l);
713
- const r = document.createElement("span");
714
- if (r.className = "ml-auto", r.textContent = "▼", a.appendChild(r), this.container.appendChild(a), this.isDropdownOpen) {
726
+ n.appendChild(r);
727
+ const i = document.createElement("span");
728
+ i.textContent = o.code, n.appendChild(i);
729
+ const s = document.createElement("span");
730
+ if (s.className = "ml-auto", s.textContent = "▼", n.appendChild(s), this.container.appendChild(n), this.isDropdownOpen) {
715
731
  this.dropdown = document.createElement("div"), this.dropdown.className = "telpick-dropdown", this.dropdown.onclick = (c) => c.stopPropagation(), this.dropdown.onmousedown = (c) => c.stopPropagation();
716
732
  const e = document.createElement("input");
717
733
  e.className = "telpick-search", e.type = "text", e.placeholder = "Buscar país...", e.value = this.searchQuery, e.oninput = (c) => {
718
734
  var h;
719
735
  c.stopPropagation();
720
- const d = c.target, _ = d.selectionStart || 0, g = d.value;
721
- this.searchQuery = g;
722
- const f = (h = this.dropdown) == null ? void 0 : h.querySelector("ul");
723
- f ? (f.innerHTML = "", (this.searchQuery ? this.codes.filter((t) => t.country.toLowerCase().includes(this.searchQuery.toLowerCase())) : this.codes).forEach((t) => {
724
- const y = document.createElement("li"), E = t.country_code === this.selectedCode && this.selectedCode !== null && this.selectedCode !== void 0;
725
- y.className = `telpick-item ${E ? "telpick-item-selected" : ""}`, y.onclick = () => {
726
- this.selectedCode = t.country_code, this.onChange(t), this.isDropdownOpen = !1, this.searchQuery = "", this.render();
736
+ const l = c.target, _ = l.selectionStart || 0, f = l.value;
737
+ this.searchQuery = f;
738
+ const p = (h = this.dropdown) == null ? void 0 : h.querySelector("ul");
739
+ p ? (p.innerHTML = "", (this.searchQuery ? this.codes.filter((a) => a.country.toLowerCase().includes(this.searchQuery.toLowerCase())) : this.codes).forEach((a) => {
740
+ const g = document.createElement("li"), E = a.country_code === this.selectedCode && this.selectedCode !== null && this.selectedCode !== void 0;
741
+ g.className = `telpick-item ${E ? "telpick-item-selected" : ""}`, g.onclick = () => {
742
+ this.selectedCode = a.country_code, this.onChange(a), this.isDropdownOpen = !1, this.searchQuery = "", this.render();
727
743
  };
728
744
  const b = document.createElement("div");
729
745
  b.className = "telpick-flag";
730
- const C = this._getFlagUrl(t.flag, t.country_code);
746
+ const C = this._getFlagUrl(a.flag, a.country_code);
731
747
  if (C) {
732
- const p = document.createElement("img");
733
- p.src = C, p.className = "w-full h-full object-cover", p.alt = t.country || "flag", p.loading = "lazy", p.referrerPolicy = "no-referrer", b.appendChild(p);
748
+ const y = document.createElement("img");
749
+ y.src = C, y.className = "w-full h-full object-cover", y.alt = a.country || "flag", y.loading = "lazy", y.referrerPolicy = "no-referrer", b.appendChild(y);
734
750
  }
735
- y.appendChild(b);
751
+ g.appendChild(b);
736
752
  const A = document.createElement("span");
737
- A.textContent = t.country, y.appendChild(A);
753
+ A.textContent = a.country, g.appendChild(A);
738
754
  const m = document.createElement("span");
739
- m.className = "ml-auto", m.textContent = t.code, y.appendChild(m), f.appendChild(y);
755
+ m.className = "ml-auto", m.textContent = a.code, g.appendChild(m), p.appendChild(g);
740
756
  }), requestAnimationFrame(() => {
741
757
  if (e) {
742
758
  e.focus();
743
- const t = Math.min(_ + 1, g.length);
744
- e.setSelectionRange(t, t);
759
+ const a = Math.min(_ + 1, f.length);
760
+ e.setSelectionRange(a, a);
745
761
  }
746
762
  })) : this.render();
747
763
  }, e.onclick = (c) => c.stopPropagation(), e.onmousedown = (c) => c.stopPropagation(), this.dropdown.appendChild(e);
748
764
  const u = document.createElement("ul");
749
765
  u.style.maxHeight = "130px", u.style.overflowY = "auto", (this.searchQuery ? this.codes.filter((c) => c.country.toLowerCase().includes(this.searchQuery.toLowerCase())) : this.codes).forEach((c) => {
750
- const d = document.createElement("li"), _ = c.country_code === this.selectedCode && this.selectedCode !== null && this.selectedCode !== void 0;
751
- d.className = `telpick-item ${_ ? "telpick-item-selected" : ""}`, d.setAttribute("aria-selected", _), d.onclick = () => {
766
+ const l = document.createElement("li"), _ = c.country_code === this.selectedCode && this.selectedCode !== null && this.selectedCode !== void 0;
767
+ l.className = `telpick-item ${_ ? "telpick-item-selected" : ""}`, l.setAttribute("aria-selected", _), l.onclick = () => {
752
768
  this.selectedCode = c.country_code, this.onChange(c), this.isDropdownOpen = !1, this.searchQuery = "", this.render();
753
769
  };
754
- const g = document.createElement("div");
755
- g.className = "telpick-flag";
756
- const f = this._getFlagUrl(c.flag, c.country_code);
757
- if (f) {
758
- const t = document.createElement("img");
759
- t.src = f, t.className = "w-full h-full object-cover", t.alt = c.country || "flag", t.loading = "lazy", t.referrerPolicy = "no-referrer", g.appendChild(t);
770
+ const f = document.createElement("div");
771
+ f.className = "telpick-flag";
772
+ const p = this._getFlagUrl(c.flag, c.country_code);
773
+ if (p) {
774
+ const a = document.createElement("img");
775
+ a.src = p, a.className = "w-full h-full object-cover", a.alt = c.country || "flag", a.loading = "lazy", a.referrerPolicy = "no-referrer", f.appendChild(a);
760
776
  }
761
- d.appendChild(g);
777
+ l.appendChild(f);
762
778
  const h = document.createElement("span");
763
- h.textContent = c.country, d.appendChild(h);
779
+ h.textContent = c.country, l.appendChild(h);
764
780
  const w = document.createElement("span");
765
- w.className = "ml-auto", w.textContent = c.code, d.appendChild(w), u.appendChild(d);
766
- }), this.dropdown.appendChild(u), this.container.appendChild(this.dropdown), requestAnimationFrame(() => {
781
+ w.className = "ml-auto", w.textContent = c.code, l.appendChild(w), u.appendChild(l);
782
+ }), this.dropdown.appendChild(u), document.body.appendChild(this.dropdown), this._updateDropdownPosition(), this._scrollResizeCleanup = () => {
783
+ window.removeEventListener("scroll", this._boundUpdatePosition, !0), window.removeEventListener("resize", this._boundUpdatePosition);
784
+ }, window.addEventListener("scroll", this._boundUpdatePosition, !0), window.addEventListener("resize", this._boundUpdatePosition), requestAnimationFrame(() => {
767
785
  e && e.focus();
768
786
  });
769
787
  }
770
788
  }
771
789
  _setupOutsideClick() {
772
- this._outsideHandler && document.removeEventListener("click", this._outsideHandler), this._outsideHandler = (a) => {
773
- const n = a.target;
774
- if (this.isDropdownOpen && this.container && n) {
775
- const o = this.container.querySelector(".telpick-dropdown");
776
- !this.container.contains(n) && (!o || !o.contains(n)) && (this.isDropdownOpen = !1, this.render());
790
+ this._outsideHandler && document.removeEventListener("click", this._outsideHandler), this._outsideHandler = (n) => {
791
+ const r = n.target;
792
+ if (this.isDropdownOpen && this.container && r) {
793
+ const o = this.container.contains(r), t = this.dropdown && this.dropdown.contains(r);
794
+ !o && !t && (this.isDropdownOpen = !1, this.render());
777
795
  }
778
796
  }, document.addEventListener("click", this._outsideHandler, !0);
779
797
  }
780
798
  destroy() {
781
- this._outsideHandler && document.removeEventListener("mousedown", this._outsideHandler), this.container.innerHTML = "";
799
+ this._outsideHandler && document.removeEventListener("click", this._outsideHandler), this._scrollResizeCleanup && (this._scrollResizeCleanup(), this._scrollResizeCleanup = null), this.dropdown && this.dropdown.parentNode && (this.dropdown.parentNode.removeChild(this.dropdown), this.dropdown = null), this.container.innerHTML = "";
782
800
  }
783
801
  }
784
802
  window.Telpick = T;
@@ -1 +1 @@
1
- (function(i,w){typeof exports=="object"&&typeof module<"u"?w(exports):typeof define=="function"&&define.amd?define(["exports"],w):(i=typeof globalThis<"u"?globalThis:i||self,w(i.Telpick={}))})(this,function(i){"use strict";const w="",P=[{country:"Afganistán",code:"+93",flag:"/flags/af.png",country_code:"AF"},{country:"Albania",code:"+355",flag:"/flags/al.webp",country_code:"AL"},{country:"Alemania",code:"+49",flag:"/flags/de.webp",country_code:"DE"},{country:"Andorra",code:"+376",flag:"/flags/ad.webp",country_code:"AD"},{country:"Antigua y Barbuda",code:"+1",flag:"/flags/ag.webp",country_code:"AG"},{country:"Arabia Saudita",code:"+966",flag:"/flags/sa.webp",country_code:"SA"},{country:"Argentina",code:"+54",flag:"/flags/ar.webp",country_code:"AR"},{country:"Australia",code:"+61",flag:"/flags/au.webp",country_code:"AU"},{country:"Austria",code:"+43",flag:"/flags/at.webp",country_code:"AT"},{country:"Bahamas",code:"+1",flag:"/flags/bs.webp",country_code:"BS"},{country:"Bangladés",code:"+880",flag:"/flags/bd.webp",country_code:"BD"},{country:"Barbados",code:"+1",flag:"/flags/bb.webp",country_code:"BB"},{country:"Bélgica",code:"+32",flag:"/flags/be.webp",country_code:"BE"},{country:"Belice",code:"+501",flag:"/flags/bz.webp",country_code:"BZ"},{country:"Bielorrusia",code:"+375",flag:"/flags/by.webp",country_code:"BY"},{country:"Bolivia",code:"+591",flag:"/flags/bo.webp",country_code:"BO"},{country:"Bosnia y Herzegovina",code:"+387",flag:"/flags/ba.webp",country_code:"BA"},{country:"Brasil",code:"+55",flag:"/flags/br.webp",country_code:"BR"},{country:"Bulgaria",code:"+359",flag:"/flags/bg.webp",country_code:"BG"},{country:"Canadá",code:"+1",flag:"/flags/ca.webp",country_code:"CA"},{country:"Chile",code:"+56",flag:"/flags/cl.webp",country_code:"CL"},{country:"China",code:"+86",flag:"/flags/cn.webp",country_code:"CN"},{country:"Colombia",code:"+57",flag:"/flags/co.webp",country_code:"CO"},{country:"Corea del Sur",code:"+82",flag:"/flags/kr.webp",country_code:"KR"},{country:"Costa Rica",code:"+506",flag:"/flags/cr.webp",country_code:"CR"},{country:"Croacia",code:"+385",flag:"/flags/hr.webp",country_code:"HR"},{country:"Cuba",code:"+53",flag:"/flags/cu.webp",country_code:"CU"},{country:"Dinamarca",code:"+45",flag:"/flags/dk.webp",country_code:"DK"},{country:"Dominica",code:"+1",flag:"/flags/dm.webp",country_code:"DM"},{country:"Ecuador",code:"+593",flag:"/flags/ec.webp",country_code:"EC"},{country:"Egipto",code:"+20",flag:"/flags/eg.webp",country_code:"EG"},{country:"El Salvador",code:"+503",flag:"/flags/sv.webp",country_code:"SV"},{country:"España",code:"+34",flag:"/flags/es.webp",country_code:"ES"},{country:"Estados Unidos",code:"+1",flag:"/flags/us.webp",country_code:"US"},{country:"Estonia",code:"+372",flag:"/flags/ee.webp",country_code:"EE"},{country:"Filipinas",code:"+63",flag:"/flags/ph.webp",country_code:"PH"},{country:"Finlandia",code:"+358",flag:"/flags/fi.webp",country_code:"FI"},{country:"Francia",code:"+33",flag:"/flags/fr.webp",country_code:"FR"},{country:"Granada",code:"+1",flag:"/flags/gd.webp",country_code:"GD"},{country:"Grecia",code:"+30",flag:"/flags/gr.webp",country_code:"GR"},{country:"Guatemala",code:"+502",flag:"/flags/gt.webp",country_code:"GT"},{country:"Guyana",code:"+592",flag:"/flags/gy.webp",country_code:"GY"},{country:"Haití",code:"+509",flag:"/flags/ht.webp",country_code:"HT"},{country:"Honduras",code:"+504",flag:"/flags/hn.webp",country_code:"HN"},{country:"Hungría",code:"+36",flag:"/flags/hu.webp",country_code:"HU"},{country:"India",code:"+91",flag:"/flags/in.webp",country_code:"IN"},{country:"Indonesia",code:"+62",flag:"/flags/id.webp",country_code:"ID"},{country:"Irak",code:"+964",flag:"/flags/iq.webp",country_code:"IQ"},{country:"Irlanda",code:"+353",flag:"/flags/ie.webp",country_code:"IE"},{country:"Islandia",code:"+354",flag:"/flags/is.webp",country_code:"IS"},{country:"Israel",code:"+972",flag:"/flags/il.webp",country_code:"IL"},{country:"Italia",code:"+39",flag:"/flags/it.webp",country_code:"IT"},{country:"Jamaica",code:"+1",flag:"/flags/jm.webp",country_code:"JM"},{country:"Japón",code:"+81",flag:"/flags/jp.webp",country_code:"JP"},{country:"Kenia",code:"+254",flag:"/flags/ke.webp",country_code:"KE"},{country:"Letonia",code:"+371",flag:"/flags/lv.webp",country_code:"LV"},{country:"Lituania",code:"+370",flag:"/flags/lt.webp",country_code:"LT"},{country:"Luxemburgo",code:"+352",flag:"/flags/lu.webp",country_code:"LU"},{country:"Malasia",code:"+60",flag:"/flags/my.webp",country_code:"MY"},{country:"Malta",code:"+356",flag:"/flags/mt.webp",country_code:"MT"},{country:"México",code:"+52",flag:"/flags/mx.webp",country_code:"MX"},{country:"Mónaco",code:"+377",flag:"/flags/mc.webp",country_code:"MC"},{country:"Nicaragua",code:"+505",flag:"/flags/ni.webp",country_code:"NI"},{country:"Nigeria",code:"+234",flag:"/flags/ng.webp",country_code:"NG"},{country:"Noruega",code:"+47",flag:"/flags/no.webp",country_code:"NO"},{country:"Nueva Zelanda",code:"+64",flag:"/flags/nz.webp",country_code:"NZ"},{country:"Países Bajos",code:"+31",flag:"/flags/nl.webp",country_code:"NL"},{country:"Pakistán",code:"+92",flag:"/flags/pk.webp",country_code:"PK"},{country:"Panamá",code:"+507",flag:"/flags/pa.webp",country_code:"PA"},{country:"Paraguay",code:"+595",flag:"/flags/py.webp",country_code:"PY"},{country:"Perú",code:"+51",flag:"/flags/pe.webp",country_code:"PE"},{country:"Polonia",code:"+48",flag:"/flags/pl.webp",country_code:"PL"},{country:"Portugal",code:"+351",flag:"/flags/pt.webp",country_code:"PT"},{country:"Reino Unido",code:"+44",flag:"/flags/gb.webp",country_code:"GB"},{country:"República Checa",code:"+420",flag:"/flags/cz.webp",country_code:"CZ"},{country:"República Dominicana",code:"+1",flag:"/flags/do.webp",country_code:"DO"},{country:"Rumanía",code:"+40",flag:"/flags/ro.webp",country_code:"RO"},{country:"Rusia",code:"+7",flag:"/flags/ru.webp",country_code:"RU"},{country:"San Cristóbal y Nieves",code:"+1",flag:"/flags/kn.webp",country_code:"KN"},{country:"San Vicente y las Granadinas",code:"+1",flag:"/flags/vc.webp",country_code:"VC"},{country:"Santa Lucía",code:"+1",flag:"/flags/lc.webp",country_code:"LC"},{country:"Singapur",code:"+65",flag:"/flags/sg.webp",country_code:"SG"},{country:"Sudáfrica",code:"+27",flag:"/flags/za.webp",country_code:"ZA"},{country:"Suecia",code:"+46",flag:"/flags/se.webp",country_code:"SE"},{country:"Suiza",code:"+41",flag:"/flags/ch.webp",country_code:"CH"},{country:"Surinam",code:"+597",flag:"/flags/sr.webp",country_code:"SR"},{country:"Tailandia",code:"+66",flag:"/flags/th.webp",country_code:"TH"},{country:"Trinidad y Tobago",code:"+1",flag:"/flags/tt.webp",country_code:"TT"},{country:"Ucrania",code:"+380",flag:"/flags/ua.webp",country_code:"UA"},{country:"Uruguay",code:"+598",flag:"/flags/uy.webp",country_code:"UY"},{country:"Venezuela",code:"+58",flag:"/flags/ve.webp",country_code:"VE"},{country:"Vietnam",code:"+84",flag:"/flags/vn.webp",country_code:"VN"}];(function(){if(typeof document<"u"&&document.currentScript&&document.currentScript.src){const u=document.currentScript.src.replace(/\/[^/]*$/,"");typeof globalThis<"u"?globalThis.__TELPICK_SCRIPT_BASE__=u:typeof window<"u"&&(window.__TELPICK_SCRIPT_BASE__=u)}})();function k(){const u=typeof globalThis<"u"&&globalThis.__TELPICK_SCRIPT_BASE__?globalThis.__TELPICK_SCRIPT_BASE__:typeof window<"u"&&window.__TELPICK_SCRIPT_BASE__||"";return u?`${u.replace(/\/$/,"")}/assets/flags`:""}class E{constructor({code:a=null,onChange:n=()=>{},styleOverrides:o={},baseFlagUrl:s=""}={}){this.code=a,this.onChange=n,this.styleOverrides=o,this.baseFlagUrl=s||k(),this.codes=[],this.selectedCode=a,this.isDropdownOpen=!1,this.searchQuery="",this.container=null,this.dropdown=null,this._outsideHandler=null,this._getFlagUrl=this._getFlagUrl.bind(this)}_getFlagUrl(a,n){const o=a?a.replace(/^.*\//,""):n?`${String(n).toLowerCase()}.webp`:"";return o?this.baseFlagUrl?`${this.baseFlagUrl.replace(/\/$/,"")}/${o}`:a||(n?`/flags/${String(n).toLowerCase()}.webp`:""):""}async init(a){if(this.container=a,this.codes=[...P].sort((o,s)=>o.country.localeCompare(s.country,"es")),this.code){const o=this.codes.find(s=>s.country_code===this.code);o&&(this.selectedCode=o.country_code)}else{const o=[async()=>{try{const r=await(await fetch("https://ip-api.com/json/?fields=countryCode")).json();if(r.countryCode)return this.codes.find(e=>e.country_code===r.countryCode)}catch{}return null},async()=>{try{const r=await(await fetch("https://get.geojs.io/v1/ip/country.json")).json();if(r.country)return this.codes.find(e=>e.country_code===r.country)}catch{}return null},async()=>{try{const r=await(await fetch("https://ipapi.co/json/")).json();if(r.country_code)return this.codes.find(e=>e.country_code===r.country_code)}catch{}return null}];let s=null;for(const l of o)try{if(s=await Promise.race([l(),new Promise(r=>setTimeout(()=>r(null),3e3))]),s)break}catch{}if(!s)try{const l=Intl.DateTimeFormat().resolvedOptions().timeZone,e={"America/Lima":"PE","America/Bogota":"CO","America/Mexico_City":"MX","America/Argentina/Buenos_Aires":"AR","America/Santiago":"CL","America/Caracas":"VE","America/Montevideo":"UY","America/Asuncion":"PY","America/La_Paz":"BO","America/Guayaquil":"EC","America/Panama":"PA","America/Costa_Rica":"CR","America/Managua":"NI","America/Tegucigalpa":"HN","America/Guatemala":"GT","America/El_Salvador":"SV","America/Havana":"CU","America/Santo_Domingo":"DO","America/Jamaica":"JM","America/Port-au-Prince":"HT","Europe/Madrid":"ES","Europe/London":"GB","Europe/Paris":"FR","Europe/Berlin":"DE","Europe/Rome":"IT","Europe/Amsterdam":"NL","Europe/Brussels":"BE","Europe/Vienna":"AT","Europe/Zurich":"CH","Europe/Stockholm":"SE","Europe/Oslo":"NO","Europe/Copenhagen":"DK","Europe/Helsinki":"FI","Europe/Warsaw":"PL","Europe/Prague":"CZ","Europe/Bucharest":"RO","Europe/Moscow":"RU","America/New_York":"US","America/Chicago":"US","America/Denver":"US","America/Los_Angeles":"US","America/Toronto":"CA","America/Vancouver":"CA","Asia/Tokyo":"JP","Asia/Shanghai":"CN","Asia/Hong_Kong":"CN","Asia/Seoul":"KR","Asia/Singapore":"SG","Asia/Bangkok":"TH","Asia/Jakarta":"ID","Asia/Manila":"PH","Asia/Kolkata":"IN","Asia/Dubai":"AE","Asia/Riyadh":"SA","Australia/Sydney":"AU","Australia/Melbourne":"AU","Pacific/Auckland":"NZ","Africa/Cairo":"EG","Africa/Johannesburg":"ZA","Africa/Nairobi":"KE","Africa/Lagos":"NG"}[l];e&&(s=this.codes.find(f=>f.country_code===e))}catch{}if(s)this.selectedCode=s.country_code;else{const l=this.codes.find(r=>r.country_code==="CO");l&&(this.selectedCode=l.country_code)}}this.render();const n=this.codes.find(o=>o.country_code===this.selectedCode);n&&this.onChange(n),this._setupOutsideClick()}render(){this.container.innerHTML="";const a=document.createElement("button");a.className="telpick-btn",Object.assign(a.style,this.styleOverrides),a.onclick=()=>{this.isDropdownOpen=!this.isDropdownOpen,this.render()};const n=document.createElement("div");n.className="telpick-flag";const o=this.codes.find(e=>e.country_code===this.selectedCode)||{country_code:"",code:"",country:"",flag:""},s=this._getFlagUrl(o.flag,o.country_code);if(s){const e=document.createElement("img");e.src=s,e.className="w-full h-full object-cover",e.alt=o.country||"flag",e.loading="lazy",e.referrerPolicy="no-referrer",n.appendChild(e)}a.appendChild(n);const l=document.createElement("span");l.textContent=o.code,a.appendChild(l);const r=document.createElement("span");if(r.className="ml-auto",r.textContent="▼",a.appendChild(r),this.container.appendChild(a),this.isDropdownOpen){this.dropdown=document.createElement("div"),this.dropdown.className="telpick-dropdown",this.dropdown.onclick=c=>c.stopPropagation(),this.dropdown.onmousedown=c=>c.stopPropagation();const e=document.createElement("input");e.className="telpick-search",e.type="text",e.placeholder="Buscar país...",e.value=this.searchQuery,e.oninput=c=>{var _;c.stopPropagation();const d=c.target,b=d.selectionStart||0,g=d.value;this.searchQuery=g;const y=(_=this.dropdown)==null?void 0:_.querySelector("ul");y?(y.innerHTML="",(this.searchQuery?this.codes.filter(t=>t.country.toLowerCase().includes(this.searchQuery.toLowerCase())):this.codes).forEach(t=>{const p=document.createElement("li"),B=t.country_code===this.selectedCode&&this.selectedCode!==null&&this.selectedCode!==void 0;p.className=`telpick-item ${B?"telpick-item-selected":""}`,p.onclick=()=>{this.selectedCode=t.country_code,this.onChange(t),this.isDropdownOpen=!1,this.searchQuery="",this.render()};const C=document.createElement("div");C.className="telpick-flag";const S=this._getFlagUrl(t.flag,t.country_code);if(S){const h=document.createElement("img");h.src=S,h.className="w-full h-full object-cover",h.alt=t.country||"flag",h.loading="lazy",h.referrerPolicy="no-referrer",C.appendChild(h)}p.appendChild(C);const T=document.createElement("span");T.textContent=t.country,p.appendChild(T);const A=document.createElement("span");A.className="ml-auto",A.textContent=t.code,p.appendChild(A),y.appendChild(p)}),requestAnimationFrame(()=>{if(e){e.focus();const t=Math.min(b+1,g.length);e.setSelectionRange(t,t)}})):this.render()},e.onclick=c=>c.stopPropagation(),e.onmousedown=c=>c.stopPropagation(),this.dropdown.appendChild(e);const f=document.createElement("ul");f.style.maxHeight="130px",f.style.overflowY="auto",(this.searchQuery?this.codes.filter(c=>c.country.toLowerCase().includes(this.searchQuery.toLowerCase())):this.codes).forEach(c=>{const d=document.createElement("li"),b=c.country_code===this.selectedCode&&this.selectedCode!==null&&this.selectedCode!==void 0;d.className=`telpick-item ${b?"telpick-item-selected":""}`,d.setAttribute("aria-selected",b),d.onclick=()=>{this.selectedCode=c.country_code,this.onChange(c),this.isDropdownOpen=!1,this.searchQuery="",this.render()};const g=document.createElement("div");g.className="telpick-flag";const y=this._getFlagUrl(c.flag,c.country_code);if(y){const t=document.createElement("img");t.src=y,t.className="w-full h-full object-cover",t.alt=c.country||"flag",t.loading="lazy",t.referrerPolicy="no-referrer",g.appendChild(t)}d.appendChild(g);const _=document.createElement("span");_.textContent=c.country,d.appendChild(_);const m=document.createElement("span");m.className="ml-auto",m.textContent=c.code,d.appendChild(m),f.appendChild(d)}),this.dropdown.appendChild(f),this.container.appendChild(this.dropdown),requestAnimationFrame(()=>{e&&e.focus()})}}_setupOutsideClick(){this._outsideHandler&&document.removeEventListener("click",this._outsideHandler),this._outsideHandler=a=>{const n=a.target;if(this.isDropdownOpen&&this.container&&n){const o=this.container.querySelector(".telpick-dropdown");!this.container.contains(n)&&(!o||!o.contains(n))&&(this.isDropdownOpen=!1,this.render())}},document.addEventListener("click",this._outsideHandler,!0)}destroy(){this._outsideHandler&&document.removeEventListener("mousedown",this._outsideHandler),this.container.innerHTML=""}}window.Telpick=E,i.Telpick=E,Object.defineProperty(i,Symbol.toStringTag,{value:"Module"})});
1
+ (function(u,d){typeof exports=="object"&&typeof module<"u"?d(exports):typeof define=="function"&&define.amd?define(["exports"],d):(u=typeof globalThis<"u"?globalThis:u||self,d(u.Telpick={}))})(this,function(u){"use strict";var d=typeof document<"u"?document.currentScript:null;const v="",T=[{country:"Afganistán",code:"+93",flag:"/flags/af.png",country_code:"AF"},{country:"Albania",code:"+355",flag:"/flags/al.webp",country_code:"AL"},{country:"Alemania",code:"+49",flag:"/flags/de.webp",country_code:"DE"},{country:"Andorra",code:"+376",flag:"/flags/ad.webp",country_code:"AD"},{country:"Antigua y Barbuda",code:"+1",flag:"/flags/ag.webp",country_code:"AG"},{country:"Arabia Saudita",code:"+966",flag:"/flags/sa.webp",country_code:"SA"},{country:"Argentina",code:"+54",flag:"/flags/ar.webp",country_code:"AR"},{country:"Australia",code:"+61",flag:"/flags/au.webp",country_code:"AU"},{country:"Austria",code:"+43",flag:"/flags/at.webp",country_code:"AT"},{country:"Bahamas",code:"+1",flag:"/flags/bs.webp",country_code:"BS"},{country:"Bangladés",code:"+880",flag:"/flags/bd.webp",country_code:"BD"},{country:"Barbados",code:"+1",flag:"/flags/bb.webp",country_code:"BB"},{country:"Bélgica",code:"+32",flag:"/flags/be.webp",country_code:"BE"},{country:"Belice",code:"+501",flag:"/flags/bz.webp",country_code:"BZ"},{country:"Bielorrusia",code:"+375",flag:"/flags/by.webp",country_code:"BY"},{country:"Bolivia",code:"+591",flag:"/flags/bo.webp",country_code:"BO"},{country:"Bosnia y Herzegovina",code:"+387",flag:"/flags/ba.webp",country_code:"BA"},{country:"Brasil",code:"+55",flag:"/flags/br.webp",country_code:"BR"},{country:"Bulgaria",code:"+359",flag:"/flags/bg.webp",country_code:"BG"},{country:"Canadá",code:"+1",flag:"/flags/ca.webp",country_code:"CA"},{country:"Chile",code:"+56",flag:"/flags/cl.webp",country_code:"CL"},{country:"China",code:"+86",flag:"/flags/cn.webp",country_code:"CN"},{country:"Colombia",code:"+57",flag:"/flags/co.webp",country_code:"CO"},{country:"Corea del Sur",code:"+82",flag:"/flags/kr.webp",country_code:"KR"},{country:"Costa Rica",code:"+506",flag:"/flags/cr.webp",country_code:"CR"},{country:"Croacia",code:"+385",flag:"/flags/hr.webp",country_code:"HR"},{country:"Cuba",code:"+53",flag:"/flags/cu.webp",country_code:"CU"},{country:"Dinamarca",code:"+45",flag:"/flags/dk.webp",country_code:"DK"},{country:"Dominica",code:"+1",flag:"/flags/dm.webp",country_code:"DM"},{country:"Ecuador",code:"+593",flag:"/flags/ec.webp",country_code:"EC"},{country:"Egipto",code:"+20",flag:"/flags/eg.webp",country_code:"EG"},{country:"El Salvador",code:"+503",flag:"/flags/sv.webp",country_code:"SV"},{country:"España",code:"+34",flag:"/flags/es.webp",country_code:"ES"},{country:"Estados Unidos",code:"+1",flag:"/flags/us.webp",country_code:"US"},{country:"Estonia",code:"+372",flag:"/flags/ee.webp",country_code:"EE"},{country:"Filipinas",code:"+63",flag:"/flags/ph.webp",country_code:"PH"},{country:"Finlandia",code:"+358",flag:"/flags/fi.webp",country_code:"FI"},{country:"Francia",code:"+33",flag:"/flags/fr.webp",country_code:"FR"},{country:"Granada",code:"+1",flag:"/flags/gd.webp",country_code:"GD"},{country:"Grecia",code:"+30",flag:"/flags/gr.webp",country_code:"GR"},{country:"Guatemala",code:"+502",flag:"/flags/gt.webp",country_code:"GT"},{country:"Guyana",code:"+592",flag:"/flags/gy.webp",country_code:"GY"},{country:"Haití",code:"+509",flag:"/flags/ht.webp",country_code:"HT"},{country:"Honduras",code:"+504",flag:"/flags/hn.webp",country_code:"HN"},{country:"Hungría",code:"+36",flag:"/flags/hu.webp",country_code:"HU"},{country:"India",code:"+91",flag:"/flags/in.webp",country_code:"IN"},{country:"Indonesia",code:"+62",flag:"/flags/id.webp",country_code:"ID"},{country:"Irak",code:"+964",flag:"/flags/iq.webp",country_code:"IQ"},{country:"Irlanda",code:"+353",flag:"/flags/ie.webp",country_code:"IE"},{country:"Islandia",code:"+354",flag:"/flags/is.webp",country_code:"IS"},{country:"Israel",code:"+972",flag:"/flags/il.webp",country_code:"IL"},{country:"Italia",code:"+39",flag:"/flags/it.webp",country_code:"IT"},{country:"Jamaica",code:"+1",flag:"/flags/jm.webp",country_code:"JM"},{country:"Japón",code:"+81",flag:"/flags/jp.webp",country_code:"JP"},{country:"Kenia",code:"+254",flag:"/flags/ke.webp",country_code:"KE"},{country:"Letonia",code:"+371",flag:"/flags/lv.webp",country_code:"LV"},{country:"Lituania",code:"+370",flag:"/flags/lt.webp",country_code:"LT"},{country:"Luxemburgo",code:"+352",flag:"/flags/lu.webp",country_code:"LU"},{country:"Malasia",code:"+60",flag:"/flags/my.webp",country_code:"MY"},{country:"Malta",code:"+356",flag:"/flags/mt.webp",country_code:"MT"},{country:"México",code:"+52",flag:"/flags/mx.webp",country_code:"MX"},{country:"Mónaco",code:"+377",flag:"/flags/mc.webp",country_code:"MC"},{country:"Nicaragua",code:"+505",flag:"/flags/ni.webp",country_code:"NI"},{country:"Nigeria",code:"+234",flag:"/flags/ng.webp",country_code:"NG"},{country:"Noruega",code:"+47",flag:"/flags/no.webp",country_code:"NO"},{country:"Nueva Zelanda",code:"+64",flag:"/flags/nz.webp",country_code:"NZ"},{country:"Países Bajos",code:"+31",flag:"/flags/nl.webp",country_code:"NL"},{country:"Pakistán",code:"+92",flag:"/flags/pk.webp",country_code:"PK"},{country:"Panamá",code:"+507",flag:"/flags/pa.webp",country_code:"PA"},{country:"Paraguay",code:"+595",flag:"/flags/py.webp",country_code:"PY"},{country:"Perú",code:"+51",flag:"/flags/pe.webp",country_code:"PE"},{country:"Polonia",code:"+48",flag:"/flags/pl.webp",country_code:"PL"},{country:"Portugal",code:"+351",flag:"/flags/pt.webp",country_code:"PT"},{country:"Reino Unido",code:"+44",flag:"/flags/gb.webp",country_code:"GB"},{country:"República Checa",code:"+420",flag:"/flags/cz.webp",country_code:"CZ"},{country:"República Dominicana",code:"+1",flag:"/flags/do.webp",country_code:"DO"},{country:"Rumanía",code:"+40",flag:"/flags/ro.webp",country_code:"RO"},{country:"Rusia",code:"+7",flag:"/flags/ru.webp",country_code:"RU"},{country:"San Cristóbal y Nieves",code:"+1",flag:"/flags/kn.webp",country_code:"KN"},{country:"San Vicente y las Granadinas",code:"+1",flag:"/flags/vc.webp",country_code:"VC"},{country:"Santa Lucía",code:"+1",flag:"/flags/lc.webp",country_code:"LC"},{country:"Singapur",code:"+65",flag:"/flags/sg.webp",country_code:"SG"},{country:"Sudáfrica",code:"+27",flag:"/flags/za.webp",country_code:"ZA"},{country:"Suecia",code:"+46",flag:"/flags/se.webp",country_code:"SE"},{country:"Suiza",code:"+41",flag:"/flags/ch.webp",country_code:"CH"},{country:"Surinam",code:"+597",flag:"/flags/sr.webp",country_code:"SR"},{country:"Tailandia",code:"+66",flag:"/flags/th.webp",country_code:"TH"},{country:"Trinidad y Tobago",code:"+1",flag:"/flags/tt.webp",country_code:"TT"},{country:"Ucrania",code:"+380",flag:"/flags/ua.webp",country_code:"UA"},{country:"Uruguay",code:"+598",flag:"/flags/uy.webp",country_code:"UY"},{country:"Venezuela",code:"+58",flag:"/flags/ve.webp",country_code:"VE"},{country:"Vietnam",code:"+84",flag:"/flags/vn.webp",country_code:"VN"}];(function(){if(typeof document<"u"&&document.currentScript&&document.currentScript.src){const f=document.currentScript.src.replace(/\/[^/]*$/,"");typeof globalThis<"u"?globalThis.__TELPICK_SCRIPT_BASE__=f:typeof window<"u"&&(window.__TELPICK_SCRIPT_BASE__=f)}})();function R(){const f=typeof globalThis<"u"&&globalThis.__TELPICK_SCRIPT_BASE__?globalThis.__TELPICK_SCRIPT_BASE__:typeof window<"u"&&window.__TELPICK_SCRIPT_BASE__||"";return f?`${f.replace(/\/$/,"")}/assets/flags`:typeof{url:typeof document>"u"&&typeof location>"u"?require("url").pathToFileURL(__filename).href:typeof document>"u"?location.href:d&&d.tagName.toUpperCase()==="SCRIPT"&&d.src||new URL("telpick.umd.js",document.baseURI).href}<"u"&&(typeof document>"u"&&typeof location>"u"?require("url").pathToFileURL(__filename).href:typeof document>"u"?location.href:d&&d.tagName.toUpperCase()==="SCRIPT"&&d.src||new URL("telpick.umd.js",document.baseURI).href)?new URL("./assets/flags/",self.location).href:""}class E{constructor({code:n=null,onChange:r=()=>{},styleOverrides:o={},baseFlagUrl:t=""}={}){this.code=n,this.onChange=r,this.styleOverrides=o,this.baseFlagUrl=t||R(),this.codes=[],this.selectedCode=n,this.isDropdownOpen=!1,this.searchQuery="",this.container=null,this.dropdown=null,this._outsideHandler=null,this._scrollResizeCleanup=null,this._boundUpdatePosition=()=>this._updateDropdownPosition(),this._getFlagUrl=this._getFlagUrl.bind(this)}_updateDropdownPosition(){if(!this.dropdown||!this.container)return;const n=this.container.getBoundingClientRect();this.dropdown.style.position="fixed",this.dropdown.style.top=`${n.bottom+4}px`,this.dropdown.style.left=`${n.left}px`,this.dropdown.style.marginTop="0"}_getFlagUrl(n,r){const o=n?n.replace(/^.*\//,""):r?`${String(r).toLowerCase()}.webp`:"";if(!o&&!r)return"";if(this.baseFlagUrl){const t=this.baseFlagUrl.replace(/\/$/,"");if(t.includes("flagcdn.com")){const i=String(r||o&&o.replace(/\.[^.]+$/,"")||"").toLowerCase();return i?`${t}/${i}.png`:""}return`${t}/${o}`}return""}async init(n){if(this.container=n,this.codes=[...T].sort((o,t)=>o.country.localeCompare(t.country,"es")),this.code){const o=this.codes.find(t=>t.country_code===this.code);o&&(this.selectedCode=o.country_code)}else{const o=[async()=>{try{const s=await(await fetch("https://ip-api.com/json/?fields=countryCode")).json();if(s.countryCode)return this.codes.find(e=>e.country_code===s.countryCode)}catch{}return null},async()=>{try{const s=await(await fetch("https://get.geojs.io/v1/ip/country.json")).json();if(s.country)return this.codes.find(e=>e.country_code===s.country)}catch{}return null},async()=>{try{const s=await(await fetch("https://ipapi.co/json/")).json();if(s.country_code)return this.codes.find(e=>e.country_code===s.country_code)}catch{}return null}];let t=null;for(const i of o)try{if(t=await Promise.race([i(),new Promise(s=>setTimeout(()=>s(null),3e3))]),t)break}catch{}if(!t)try{const i=Intl.DateTimeFormat().resolvedOptions().timeZone,e={"America/Lima":"PE","America/Bogota":"CO","America/Mexico_City":"MX","America/Argentina/Buenos_Aires":"AR","America/Santiago":"CL","America/Caracas":"VE","America/Montevideo":"UY","America/Asuncion":"PY","America/La_Paz":"BO","America/Guayaquil":"EC","America/Panama":"PA","America/Costa_Rica":"CR","America/Managua":"NI","America/Tegucigalpa":"HN","America/Guatemala":"GT","America/El_Salvador":"SV","America/Havana":"CU","America/Santo_Domingo":"DO","America/Jamaica":"JM","America/Port-au-Prince":"HT","Europe/Madrid":"ES","Europe/London":"GB","Europe/Paris":"FR","Europe/Berlin":"DE","Europe/Rome":"IT","Europe/Amsterdam":"NL","Europe/Brussels":"BE","Europe/Vienna":"AT","Europe/Zurich":"CH","Europe/Stockholm":"SE","Europe/Oslo":"NO","Europe/Copenhagen":"DK","Europe/Helsinki":"FI","Europe/Warsaw":"PL","Europe/Prague":"CZ","Europe/Bucharest":"RO","Europe/Moscow":"RU","America/New_York":"US","America/Chicago":"US","America/Denver":"US","America/Los_Angeles":"US","America/Toronto":"CA","America/Vancouver":"CA","Asia/Tokyo":"JP","Asia/Shanghai":"CN","Asia/Hong_Kong":"CN","Asia/Seoul":"KR","Asia/Singapore":"SG","Asia/Bangkok":"TH","Asia/Jakarta":"ID","Asia/Manila":"PH","Asia/Kolkata":"IN","Asia/Dubai":"AE","Asia/Riyadh":"SA","Australia/Sydney":"AU","Australia/Melbourne":"AU","Pacific/Auckland":"NZ","Africa/Cairo":"EG","Africa/Johannesburg":"ZA","Africa/Nairobi":"KE","Africa/Lagos":"NG"}[i];e&&(t=this.codes.find(p=>p.country_code===e))}catch{}if(t)this.selectedCode=t.country_code;else{const i=this.codes.find(s=>s.country_code==="CO");i&&(this.selectedCode=i.country_code)}}this.render();const r=this.codes.find(o=>o.country_code===this.selectedCode);r&&this.onChange(r),this._setupOutsideClick()}render(){this._scrollResizeCleanup&&(this._scrollResizeCleanup(),this._scrollResizeCleanup=null),this.dropdown&&this.dropdown.parentNode&&(this.dropdown.parentNode.removeChild(this.dropdown),this.dropdown=null),this.container.innerHTML="";const n=document.createElement("button");n.className="telpick-btn",Object.assign(n.style,this.styleOverrides),n.onclick=()=>{this.isDropdownOpen=!this.isDropdownOpen,this.render()};const r=document.createElement("div");r.className="telpick-flag";const o=this.codes.find(e=>e.country_code===this.selectedCode)||{country_code:"",code:"",country:"",flag:""},t=this._getFlagUrl(o.flag,o.country_code);if(t){const e=document.createElement("img");e.src=t,e.className="w-full h-full object-cover",e.alt=o.country||"flag",e.loading="lazy",e.referrerPolicy="no-referrer",r.appendChild(e)}n.appendChild(r);const i=document.createElement("span");i.textContent=o.code,n.appendChild(i);const s=document.createElement("span");if(s.className="ml-auto",s.textContent="▼",n.appendChild(s),this.container.appendChild(n),this.isDropdownOpen){this.dropdown=document.createElement("div"),this.dropdown.className="telpick-dropdown",this.dropdown.onclick=c=>c.stopPropagation(),this.dropdown.onmousedown=c=>c.stopPropagation();const e=document.createElement("input");e.className="telpick-search",e.type="text",e.placeholder="Buscar país...",e.value=this.searchQuery,e.oninput=c=>{var w;c.stopPropagation();const l=c.target,m=l.selectionStart||0,g=l.value;this.searchQuery=g;const y=(w=this.dropdown)==null?void 0:w.querySelector("ul");y?(y.innerHTML="",(this.searchQuery?this.codes.filter(a=>a.country.toLowerCase().includes(this.searchQuery.toLowerCase())):this.codes).forEach(a=>{const h=document.createElement("li"),U=a.country_code===this.selectedCode&&this.selectedCode!==null&&this.selectedCode!==void 0;h.className=`telpick-item ${U?"telpick-item-selected":""}`,h.onclick=()=>{this.selectedCode=a.country_code,this.onChange(a),this.isDropdownOpen=!1,this.searchQuery="",this.render()};const C=document.createElement("div");C.className="telpick-flag";const S=this._getFlagUrl(a.flag,a.country_code);if(S){const _=document.createElement("img");_.src=S,_.className="w-full h-full object-cover",_.alt=a.country||"flag",_.loading="lazy",_.referrerPolicy="no-referrer",C.appendChild(_)}h.appendChild(C);const P=document.createElement("span");P.textContent=a.country,h.appendChild(P);const A=document.createElement("span");A.className="ml-auto",A.textContent=a.code,h.appendChild(A),y.appendChild(h)}),requestAnimationFrame(()=>{if(e){e.focus();const a=Math.min(m+1,g.length);e.setSelectionRange(a,a)}})):this.render()},e.onclick=c=>c.stopPropagation(),e.onmousedown=c=>c.stopPropagation(),this.dropdown.appendChild(e);const p=document.createElement("ul");p.style.maxHeight="130px",p.style.overflowY="auto",(this.searchQuery?this.codes.filter(c=>c.country.toLowerCase().includes(this.searchQuery.toLowerCase())):this.codes).forEach(c=>{const l=document.createElement("li"),m=c.country_code===this.selectedCode&&this.selectedCode!==null&&this.selectedCode!==void 0;l.className=`telpick-item ${m?"telpick-item-selected":""}`,l.setAttribute("aria-selected",m),l.onclick=()=>{this.selectedCode=c.country_code,this.onChange(c),this.isDropdownOpen=!1,this.searchQuery="",this.render()};const g=document.createElement("div");g.className="telpick-flag";const y=this._getFlagUrl(c.flag,c.country_code);if(y){const a=document.createElement("img");a.src=y,a.className="w-full h-full object-cover",a.alt=c.country||"flag",a.loading="lazy",a.referrerPolicy="no-referrer",g.appendChild(a)}l.appendChild(g);const w=document.createElement("span");w.textContent=c.country,l.appendChild(w);const b=document.createElement("span");b.className="ml-auto",b.textContent=c.code,l.appendChild(b),p.appendChild(l)}),this.dropdown.appendChild(p),document.body.appendChild(this.dropdown),this._updateDropdownPosition(),this._scrollResizeCleanup=()=>{window.removeEventListener("scroll",this._boundUpdatePosition,!0),window.removeEventListener("resize",this._boundUpdatePosition)},window.addEventListener("scroll",this._boundUpdatePosition,!0),window.addEventListener("resize",this._boundUpdatePosition),requestAnimationFrame(()=>{e&&e.focus()})}}_setupOutsideClick(){this._outsideHandler&&document.removeEventListener("click",this._outsideHandler),this._outsideHandler=n=>{const r=n.target;if(this.isDropdownOpen&&this.container&&r){const o=this.container.contains(r),t=this.dropdown&&this.dropdown.contains(r);!o&&!t&&(this.isDropdownOpen=!1,this.render())}},document.addEventListener("click",this._outsideHandler,!0)}destroy(){this._outsideHandler&&document.removeEventListener("click",this._outsideHandler),this._scrollResizeCleanup&&(this._scrollResizeCleanup(),this._scrollResizeCleanup=null),this.dropdown&&this.dropdown.parentNode&&(this.dropdown.parentNode.removeChild(this.dropdown),this.dropdown=null),this.container.innerHTML=""}}window.Telpick=E,u.Telpick=E,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "telpick",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Multi-platform country and phone code selector with a modern design, smooth animations, and automatic IP detection.",
5
5
  "main": "dist/telpick.es.js",
6
6
  "module": "dist/telpick.es.js",
package/src/demo-init.js CHANGED
@@ -6,12 +6,16 @@ import Telpick from './telpick.js'
6
6
 
7
7
  window.Telpick = Telpick
8
8
 
9
+ // Base para banderas: en build (GitHub Pages) están en /telpick/src/assets/flags; en dev en /src/assets/flags.
10
+ const flagsBase = `${(import.meta.env.BASE_URL || '/').replace(/([^/])$/, '$1/')}src/assets/flags`
11
+
9
12
  function initDemo() {
10
13
  const container = document.getElementById('telpick-container')
11
14
  if (!container) return
12
15
 
13
16
  const telpick = new Telpick({
14
17
  code: null,
18
+ baseFlagUrl: flagsBase,
15
19
  onChange: (country) => {
16
20
  const infoEl = document.getElementById('selected-info')
17
21
  if (infoEl) {
package/src/telpick.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import countryCodesData from './assets/country-code.json'
2
2
 
3
- // Al cargar por <script src="...">, guardar la URL base para resolver assets (banderas) en CDN
3
+
4
4
  ;(function () {
5
5
  if (typeof document !== 'undefined' && document.currentScript && document.currentScript.src) {
6
6
  const base = document.currentScript.src.replace(/\/[^/]*$/, '')
@@ -10,10 +10,14 @@ import countryCodesData from './assets/country-code.json'
10
10
  })()
11
11
 
12
12
  function _getDefaultBaseFlagUrl() {
13
- const base = typeof globalThis !== 'undefined' && globalThis.__TELPICK_SCRIPT_BASE__
13
+ const scriptBase = typeof globalThis !== 'undefined' && globalThis.__TELPICK_SCRIPT_BASE__
14
14
  ? globalThis.__TELPICK_SCRIPT_BASE__
15
15
  : (typeof window !== 'undefined' && window.__TELPICK_SCRIPT_BASE__) || ''
16
- return base ? `${base.replace(/\/$/, '')}/assets/flags` : ''
16
+ if (scriptBase) return `${scriptBase.replace(/\/$/, '')}/assets/flags`
17
+ if (typeof import.meta !== 'undefined' && import.meta.url) {
18
+ return new URL('./assets/flags/', import.meta.url).href
19
+ }
20
+ return ''
17
21
  }
18
22
 
19
23
  class Telpick {
@@ -29,17 +33,33 @@ class Telpick {
29
33
  this.container = null
30
34
  this.dropdown = null
31
35
  this._outsideHandler = null
36
+ this._scrollResizeCleanup = null
37
+ this._boundUpdatePosition = () => this._updateDropdownPosition()
32
38
  this._getFlagUrl = this._getFlagUrl.bind(this)
33
39
  }
34
40
 
41
+ _updateDropdownPosition() {
42
+ if (!this.dropdown || !this.container) return
43
+ const rect = this.container.getBoundingClientRect()
44
+ this.dropdown.style.position = 'fixed'
45
+ this.dropdown.style.top = `${rect.bottom + 4}px`
46
+ this.dropdown.style.left = `${rect.left}px`
47
+ this.dropdown.style.marginTop = '0'
48
+ }
49
+
35
50
  _getFlagUrl(flagPathFromJson, countryCode) {
36
51
  const filename = flagPathFromJson ? flagPathFromJson.replace(/^.*\//, '') : (countryCode ? `${String(countryCode).toLowerCase()}.webp` : '')
37
- if (!filename) return ''
52
+ if (!filename && !countryCode) return ''
38
53
  if (this.baseFlagUrl) {
39
54
  const base = this.baseFlagUrl.replace(/\/$/, '')
55
+ if (base.includes('flagcdn.com')) {
56
+ const code = String(countryCode || (filename && filename.replace(/\.[^.]+$/, '')) || '').toLowerCase()
57
+ return code ? `${base}/${code}.png` : ''
58
+ }
40
59
  return `${base}/${filename}`
41
60
  }
42
- return flagPathFromJson || (countryCode ? `/flags/${String(countryCode).toLowerCase()}.webp` : '')
61
+
62
+ return ''
43
63
  }
44
64
 
45
65
  async init(container) {
@@ -141,6 +161,14 @@ class Telpick {
141
161
  }
142
162
 
143
163
  render() {
164
+ if (this._scrollResizeCleanup) {
165
+ this._scrollResizeCleanup()
166
+ this._scrollResizeCleanup = null
167
+ }
168
+ if (this.dropdown && this.dropdown.parentNode) {
169
+ this.dropdown.parentNode.removeChild(this.dropdown)
170
+ this.dropdown = null
171
+ }
144
172
  this.container.innerHTML = ''
145
173
  const btn = document.createElement('button')
146
174
  btn.className = 'telpick-btn'
@@ -279,8 +307,15 @@ class Telpick {
279
307
  ul.appendChild(li)
280
308
  })
281
309
  this.dropdown.appendChild(ul)
282
- this.container.appendChild(this.dropdown)
283
-
310
+ document.body.appendChild(this.dropdown)
311
+ this._updateDropdownPosition()
312
+ this._scrollResizeCleanup = () => {
313
+ window.removeEventListener('scroll', this._boundUpdatePosition, true)
314
+ window.removeEventListener('resize', this._boundUpdatePosition)
315
+ }
316
+ window.addEventListener('scroll', this._boundUpdatePosition, true)
317
+ window.addEventListener('resize', this._boundUpdatePosition)
318
+
284
319
  requestAnimationFrame(() => {
285
320
  if (input) {
286
321
  input.focus()
@@ -294,8 +329,9 @@ class Telpick {
294
329
  this._outsideHandler = e => {
295
330
  const target = e.target
296
331
  if (this.isDropdownOpen && this.container && target) {
297
- const dropdown = this.container.querySelector('.telpick-dropdown')
298
- if (!this.container.contains(target) && (!dropdown || !dropdown.contains(target))) {
332
+ const inContainer = this.container.contains(target)
333
+ const inDropdown = this.dropdown && this.dropdown.contains(target)
334
+ if (!inContainer && !inDropdown) {
299
335
  this.isDropdownOpen = false
300
336
  this.render()
301
337
  }
@@ -305,7 +341,15 @@ class Telpick {
305
341
  }
306
342
 
307
343
  destroy() {
308
- if (this._outsideHandler) document.removeEventListener('mousedown', this._outsideHandler)
344
+ if (this._outsideHandler) document.removeEventListener('click', this._outsideHandler)
345
+ if (this._scrollResizeCleanup) {
346
+ this._scrollResizeCleanup()
347
+ this._scrollResizeCleanup = null
348
+ }
349
+ if (this.dropdown && this.dropdown.parentNode) {
350
+ this.dropdown.parentNode.removeChild(this.dropdown)
351
+ this.dropdown = null
352
+ }
309
353
  this.container.innerHTML = ''
310
354
  }
311
355
  }
File without changes
Binary file
File without changes
Binary file
@@ -1,7 +0,0 @@
1
- // Telpick CDN loader
2
- // <script src="https://unpkg.com/telpick/dist/telpick.umd.js"></script>
3
- // window.Telpick disponible
4
-
5
- // Ejemplo de uso:
6
- // const telpick = new Telpick({ code: null, onChange: (country) => console.log(country) })
7
- // telpick.init(document.getElementById('telpick-container'))
@@ -1,140 +0,0 @@
1
- import React, { useState, useEffect, useRef, useMemo } from 'react'
2
- import { getDefaultCountry, useClickOutside, CountryCode, TelpickProps } from './telpick'
3
- import './telpick.css'
4
-
5
- export function TelpickReact({ code, onChange, styleOverrides }: TelpickProps) {
6
- const [codes, setCodes] = useState<CountryCode[]>([])
7
- const [selectedCode, setSelectedCode] = useState(code)
8
- const [isDropdownOpen, setDropdownOpen] = useState(false)
9
- const [searchQuery, setSearchQuery] = useState('')
10
- const dropdownRef = useRef<HTMLDivElement>(null)
11
- const searchInputRef = useRef<HTMLInputElement>(null)
12
-
13
- useEffect(() => {
14
- fetch('/resources/api/country-codes.json')
15
- .then(res => res.json())
16
- .then(data => {
17
- const sorted = data.sort((a, b) => a.country.localeCompare(b.country, 'es'))
18
- setCodes(sorted)
19
- if (!code) {
20
- getDefaultCountry(data).then(def => {
21
- if (def) {
22
- setSelectedCode(def.country_code)
23
- onChange && onChange(def)
24
- }
25
- })
26
- } else {
27
- setSelectedCode(code)
28
- }
29
- })
30
- }, [code, onChange])
31
-
32
- useEffect(() => {
33
- if (code !== undefined && code !== selectedCode) {
34
- setSelectedCode(code)
35
- }
36
- }, [code])
37
-
38
- useEffect(() => {
39
- if (dropdownRef.current) {
40
- const remove = useClickOutside(dropdownRef.current, () => setDropdownOpen(false))
41
- return remove
42
- }
43
- }, [dropdownRef])
44
-
45
- useEffect(() => {
46
- if (isDropdownOpen && searchInputRef.current) {
47
- searchInputRef.current.focus()
48
- }
49
- }, [isDropdownOpen])
50
-
51
- const selectCode = (item: CountryCode) => {
52
- setSelectedCode(item.country_code)
53
- onChange && onChange(item)
54
- setDropdownOpen(false)
55
- setSearchQuery('')
56
- }
57
-
58
- const selectedCountry = codes.find(c => c.country_code === selectedCode) || {
59
- country_code: selectedCode,
60
- flag: '',
61
- country: '',
62
- code: '',
63
- }
64
-
65
- const filteredCodes = useMemo(() => {
66
- if (!searchQuery) return codes
67
- return codes.filter(c => c.country.toLowerCase().includes(searchQuery.toLowerCase()))
68
- }, [codes, searchQuery])
69
-
70
- const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
71
- const cursorPosition = e.target.selectionStart || 0
72
- const newValue = e.target.value
73
- setSearchQuery(newValue)
74
- requestAnimationFrame(() => {
75
- if (searchInputRef.current) {
76
- searchInputRef.current.focus()
77
- const newCursorPos = Math.min(cursorPosition + 1, newValue.length)
78
- searchInputRef.current.setSelectionRange(newCursorPos, newCursorPos)
79
- }
80
- })
81
- }
82
-
83
- return (
84
- <div className="telpick-wrapper relative" ref={dropdownRef}>
85
- <button
86
- onClick={() => setDropdownOpen(!isDropdownOpen)}
87
- className="telpick-btn"
88
- style={styleOverrides}
89
- aria-expanded={isDropdownOpen}
90
- aria-haspopup="listbox"
91
- >
92
- <div className="telpick-flag">
93
- {selectedCountry.flag && <img src={selectedCountry.flag} alt={selectedCountry.country || 'flag'} />}
94
- </div>
95
- <span>{selectedCountry.code}</span>
96
- <span className="telpick-arrow ml-auto">▼</span>
97
- </button>
98
- {isDropdownOpen && (
99
- <div
100
- className="telpick-dropdown"
101
- role="listbox"
102
- onClick={(e) => e.stopPropagation()}
103
- onMouseDown={(e) => e.stopPropagation()}
104
- >
105
- <input
106
- ref={searchInputRef}
107
- value={searchQuery}
108
- onChange={handleSearchChange}
109
- onClick={(e) => e.stopPropagation()}
110
- onMouseDown={(e) => e.stopPropagation()}
111
- type="text"
112
- placeholder="Buscar país..."
113
- className="telpick-search"
114
- autoFocus
115
- />
116
- <ul>
117
- {filteredCodes.map((item, index) => {
118
- const isSelected = item.country_code === selectedCode && selectedCode !== null && selectedCode !== undefined
119
- return (
120
- <li
121
- key={`${item.country_code}-${index}`}
122
- onClick={() => selectCode(item)}
123
- className={`telpick-item ${isSelected ? 'telpick-item-selected' : ''}`}
124
- role="option"
125
- aria-selected={isSelected}
126
- >
127
- <div className="telpick-flag">
128
- <img src={item.flag} alt={item.country} />
129
- </div>
130
- <span>{item.country}</span>
131
- <span className="ml-auto">{item.code}</span>
132
- </li>
133
- )
134
- })}
135
- </ul>
136
- </div>
137
- )}
138
- </div>
139
- )
140
- }
package/src/telpick.ts DELETED
@@ -1,157 +0,0 @@
1
- export interface CountryCode {
2
- country_code: string;
3
- flag: string;
4
- country: string;
5
- code: string;
6
- }
7
-
8
- export interface TelpickProps {
9
- code?: string;
10
- onChange?: (country: CountryCode) => void;
11
- styleOverrides?: Partial<Record<string, string>>;
12
- }
13
-
14
- export async function getDefaultCountry(codes: CountryCode[]): Promise<CountryCode | null> {
15
- const services = [
16
- async () => {
17
- try {
18
- const res = await fetch('https://ip-api.com/json/?fields=countryCode')
19
- const data = await res.json()
20
- if (data.countryCode) {
21
- return codes.find(c => c.country_code === data.countryCode) || null
22
- }
23
- } catch {}
24
- return null
25
- },
26
- async () => {
27
- try {
28
- const res = await fetch('https://get.geojs.io/v1/ip/country.json')
29
- const data = await res.json()
30
- if (data.country) {
31
- return codes.find(c => c.country_code === data.country) || null
32
- }
33
- } catch {}
34
- return null
35
- },
36
- async () => {
37
- try {
38
- const res = await fetch('https://ipapi.co/json/')
39
- const data = await res.json()
40
- if (data.country_code) {
41
- return codes.find(c => c.country_code === data.country_code) || null
42
- }
43
- } catch {}
44
- return null
45
- },
46
- async () => {
47
- try {
48
- const res = await fetch('https://ip-api.io/json/')
49
- const data = await res.json()
50
- if (data.country_code) {
51
- return codes.find(c => c.country_code === data.country_code) || null
52
- }
53
- } catch {}
54
- return null
55
- }
56
- ]
57
-
58
- for (const service of services) {
59
- try {
60
- const result = await Promise.race([
61
- service(),
62
- new Promise<null>((resolve) => setTimeout(() => resolve(null), 3000))
63
- ])
64
- if (result) return result
65
- } catch {
66
- continue
67
- }
68
- }
69
-
70
- try {
71
- const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone
72
- const timezoneToCountry: Record<string, string> = {
73
- 'America/Lima': 'PE',
74
- 'America/Bogota': 'CO',
75
- 'America/Mexico_City': 'MX',
76
- 'America/Argentina/Buenos_Aires': 'AR',
77
- 'America/Santiago': 'CL',
78
- 'America/Caracas': 'VE',
79
- 'America/Montevideo': 'UY',
80
- 'America/Asuncion': 'PY',
81
- 'America/La_Paz': 'BO',
82
- 'America/Guayaquil': 'EC',
83
- 'America/Panama': 'PA',
84
- 'America/Costa_Rica': 'CR',
85
- 'America/Managua': 'NI',
86
- 'America/Tegucigalpa': 'HN',
87
- 'America/Guatemala': 'GT',
88
- 'America/El_Salvador': 'SV',
89
- 'America/Havana': 'CU',
90
- 'America/Santo_Domingo': 'DO',
91
- 'America/Jamaica': 'JM',
92
- 'America/Port-au-Prince': 'HT',
93
- 'Europe/Madrid': 'ES',
94
- 'Europe/London': 'GB',
95
- 'Europe/Paris': 'FR',
96
- 'Europe/Berlin': 'DE',
97
- 'Europe/Rome': 'IT',
98
- 'Europe/Amsterdam': 'NL',
99
- 'Europe/Brussels': 'BE',
100
- 'Europe/Vienna': 'AT',
101
- 'Europe/Zurich': 'CH',
102
- 'Europe/Stockholm': 'SE',
103
- 'Europe/Oslo': 'NO',
104
- 'Europe/Copenhagen': 'DK',
105
- 'Europe/Helsinki': 'FI',
106
- 'Europe/Warsaw': 'PL',
107
- 'Europe/Prague': 'CZ',
108
- 'Europe/Bucharest': 'RO',
109
- 'Europe/Moscow': 'RU',
110
- 'America/New_York': 'US',
111
- 'America/Chicago': 'US',
112
- 'America/Denver': 'US',
113
- 'America/Los_Angeles': 'US',
114
- 'America/Toronto': 'CA',
115
- 'America/Vancouver': 'CA',
116
- 'Asia/Tokyo': 'JP',
117
- 'Asia/Shanghai': 'CN',
118
- 'Asia/Hong_Kong': 'CN',
119
- 'Asia/Seoul': 'KR',
120
- 'Asia/Singapore': 'SG',
121
- 'Asia/Bangkok': 'TH',
122
- 'Asia/Jakarta': 'ID',
123
- 'Asia/Manila': 'PH',
124
- 'Asia/Kolkata': 'IN',
125
- 'Asia/Dubai': 'AE',
126
- 'Asia/Riyadh': 'SA',
127
- 'Australia/Sydney': 'AU',
128
- 'Australia/Melbourne': 'AU',
129
- 'Pacific/Auckland': 'NZ',
130
- 'Africa/Cairo': 'EG',
131
- 'Africa/Johannesburg': 'ZA',
132
- 'Africa/Nairobi': 'KE',
133
- 'Africa/Lagos': 'NG'
134
- }
135
-
136
- const countryCode = timezoneToCountry[timezone]
137
- if (countryCode) {
138
- return codes.find(c => c.country_code === countryCode) || null
139
- }
140
- } catch {}
141
-
142
- return codes.find(c => c.country_code === 'CO') || null
143
- }
144
-
145
- export function useClickOutside(ref: HTMLElement, cb: () => void) {
146
- function handler(e: MouseEvent) {
147
- const target = e.target as Node
148
- if (ref && target && !ref.contains(target)) {
149
- const dropdown = ref.querySelector('.telpick-dropdown')
150
- if (!dropdown || !dropdown.contains(target)) {
151
- cb()
152
- }
153
- }
154
- }
155
- document.addEventListener('click', handler, true)
156
- return () => document.removeEventListener('click', handler, true)
157
- }
@@ -1,199 +0,0 @@
1
- import { getDefaultCountry, useClickOutside, CountryCode, TelpickProps } from './telpick'
2
- import './telpick.css'
3
-
4
- export class TelpickVanilla {
5
- constructor(options = {}) {
6
- this.code = options.code || null
7
- this.onChange = options.onChange || (() => {})
8
- this.styleOverrides = options.styleOverrides || {}
9
- this.codes = []
10
- this.selectedCode = this.code
11
- this.isDropdownOpen = false
12
- this.searchQuery = ''
13
- this.container = null
14
- this.dropdown = null
15
- this.searchInput = null
16
- }
17
-
18
- async init(container) {
19
- this.container = container
20
- const res = await fetch('/resources/api/country-codes.json')
21
- const data = await res.json()
22
- this.codes = data.sort((a, b) => a.country.localeCompare(b.country, 'es'))
23
- if (!this.code) {
24
- const def = await getDefaultCountry(this.codes)
25
- if (def) this.selectedCode = def.country_code
26
- }
27
- this.render()
28
- useClickOutside(this.container, () => {
29
- this.closeDropdown()
30
- })
31
- }
32
-
33
- render() {
34
- if (this.isDropdownOpen && this.dropdown && this.searchInput) {
35
- const ul = this.dropdown.querySelector('ul')
36
- if (ul) {
37
- ul.innerHTML = ''
38
- const filtered = !this.searchQuery
39
- ? this.codes
40
- : this.codes.filter(c => c.country.toLowerCase().includes(this.searchQuery.toLowerCase()))
41
-
42
- filtered.forEach((item, index) => {
43
- const li = document.createElement('li')
44
- const isSelected = item.country_code === this.selectedCode && this.selectedCode !== null && this.selectedCode !== undefined
45
- li.className = `telpick-item ${isSelected ? 'telpick-item-selected' : ''}`
46
- li.setAttribute('role', 'option')
47
- li.setAttribute('aria-selected', isSelected)
48
- li.onclick = () => {
49
- this.selectedCode = item.country_code
50
- this.onChange(item)
51
- this.isDropdownOpen = false
52
- this.searchQuery = ''
53
- this.render()
54
- }
55
-
56
- const flag = document.createElement('div')
57
- flag.className = 'telpick-flag'
58
- const img = document.createElement('img')
59
- img.src = item.flag
60
- img.alt = item.country
61
- flag.appendChild(img)
62
- li.appendChild(flag)
63
-
64
- const countrySpan = document.createElement('span')
65
- countrySpan.textContent = item.country
66
- li.appendChild(countrySpan)
67
-
68
- const codeSpan = document.createElement('span')
69
- codeSpan.className = 'ml-auto'
70
- codeSpan.textContent = item.code
71
- li.appendChild(codeSpan)
72
-
73
- ul.appendChild(li)
74
- })
75
- }
76
- return
77
- }
78
-
79
- this.container.innerHTML = ''
80
- this.container.className = 'telpick-wrapper relative'
81
-
82
- const btn = document.createElement('button')
83
- btn.className = 'telpick-btn'
84
- btn.setAttribute('aria-expanded', this.isDropdownOpen)
85
- btn.setAttribute('aria-haspopup', 'listbox')
86
- Object.assign(btn.style, this.styleOverrides)
87
- btn.onclick = () => {
88
- this.isDropdownOpen = !this.isDropdownOpen
89
- this.render()
90
- }
91
-
92
- const flagDiv = document.createElement('div')
93
- flagDiv.className = 'telpick-flag'
94
- const selectedCountry = this.codes.find(c => c.country_code === this.selectedCode) || { flag: '', code: '', country: '' }
95
- if (selectedCountry.flag) {
96
- const img = document.createElement('img')
97
- img.src = selectedCountry.flag
98
- img.alt = selectedCountry.country || 'flag'
99
- flagDiv.appendChild(img)
100
- }
101
- btn.appendChild(flagDiv)
102
-
103
- const codeSpan = document.createElement('span')
104
- codeSpan.textContent = selectedCountry.code
105
- btn.appendChild(codeSpan)
106
-
107
- const arrowSpan = document.createElement('span')
108
- arrowSpan.className = 'telpick-arrow ml-auto'
109
- arrowSpan.textContent = '▼'
110
- btn.appendChild(arrowSpan)
111
- this.container.appendChild(btn)
112
-
113
- if (this.isDropdownOpen) {
114
- this.dropdown = document.createElement('div')
115
- this.dropdown.className = 'telpick-dropdown'
116
- this.dropdown.setAttribute('role', 'listbox')
117
- this.dropdown.onclick = e => e.stopPropagation()
118
- this.dropdown.onmousedown = e => e.stopPropagation()
119
-
120
- const input = document.createElement('input')
121
- input.className = 'telpick-search'
122
- input.type = 'text'
123
- input.placeholder = 'Buscar país...'
124
- input.value = this.searchQuery
125
- input.autofocus = true
126
- this.searchInput = input
127
- input.oninput = e => {
128
- e.stopPropagation()
129
- const inputEl = e.target
130
- const cursorPos = inputEl.selectionStart || 0
131
- const newValue = inputEl.value
132
- this.searchQuery = newValue
133
- this.render()
134
- requestAnimationFrame(() => {
135
- if (this.searchInput) {
136
- this.searchInput.focus()
137
- const newCursorPos = Math.min(cursorPos + 1, newValue.length)
138
- this.searchInput.setSelectionRange(newCursorPos, newCursorPos)
139
- }
140
- })
141
- }
142
- input.onclick = e => e.stopPropagation()
143
- input.onmousedown = e => e.stopPropagation()
144
- this.dropdown.appendChild(input)
145
-
146
- const ul = document.createElement('ul')
147
- const filtered = !this.searchQuery
148
- ? this.codes
149
- : this.codes.filter(c => c.country.toLowerCase().includes(this.searchQuery.toLowerCase()))
150
-
151
- filtered.forEach((item, index) => {
152
- const li = document.createElement('li')
153
- const isSelected = item.country_code === this.selectedCode && this.selectedCode !== null && this.selectedCode !== undefined
154
- li.className = `telpick-item ${isSelected ? 'telpick-item-selected' : ''}`
155
- li.setAttribute('role', 'option')
156
- li.setAttribute('aria-selected', isSelected)
157
- li.onclick = () => {
158
- this.selectedCode = item.country_code
159
- this.onChange(item)
160
- this.isDropdownOpen = false
161
- this.searchQuery = ''
162
- this.render()
163
- }
164
-
165
- const flag = document.createElement('div')
166
- flag.className = 'telpick-flag'
167
- const img = document.createElement('img')
168
- img.src = item.flag
169
- img.alt = item.country
170
- flag.appendChild(img)
171
- li.appendChild(flag)
172
-
173
- const countrySpan = document.createElement('span')
174
- countrySpan.textContent = item.country
175
- li.appendChild(countrySpan)
176
-
177
- const codeSpan = document.createElement('span')
178
- codeSpan.className = 'ml-auto'
179
- codeSpan.textContent = item.code
180
- li.appendChild(codeSpan)
181
-
182
- ul.appendChild(li)
183
- })
184
- this.dropdown.appendChild(ul)
185
- this.container.appendChild(this.dropdown)
186
-
187
- requestAnimationFrame(() => {
188
- if (this.searchInput) {
189
- this.searchInput.focus()
190
- }
191
- })
192
- }
193
- }
194
-
195
- closeDropdown() {
196
- this.isDropdownOpen = false
197
- this.render()
198
- }
199
- }
@@ -1,144 +0,0 @@
1
- import { defineComponent, ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'
2
- import { getDefaultCountry, useClickOutside, CountryCode, TelpickProps } from './telpick'
3
- import './telpick.css'
4
-
5
- export const TelpickVue = defineComponent({
6
- name: 'TelpickVue',
7
- props: {
8
- code: { type: String, default: null },
9
- styleOverrides: { type: Object, default: () => ({}) }
10
- },
11
- emits: ['update:code'],
12
- setup(props, { emit }) {
13
- const codes = ref<CountryCode[]>([])
14
- const selectedCode = ref(props.code)
15
- const isDropdownOpen = ref(false)
16
- const searchQuery = ref('')
17
- const dropdownRef = ref<HTMLElement | null>(null)
18
- const searchInputRef = ref<HTMLInputElement | null>(null)
19
-
20
- const handleSearchInput = (e: Event) => {
21
- const input = e.target as HTMLInputElement
22
- const cursorPos = input.selectionStart || 0
23
- const newValue = input.value
24
- searchQuery.value = newValue
25
- requestAnimationFrame(() => {
26
- if (searchInputRef.value) {
27
- searchInputRef.value.focus()
28
- const newCursorPos = Math.min(cursorPos + 1, newValue.length)
29
- searchInputRef.value.setSelectionRange(newCursorPos, newCursorPos)
30
- }
31
- })
32
- }
33
-
34
- const selectCode = (item: CountryCode) => {
35
- selectedCode.value = item.country_code
36
- emit('update:code', item)
37
- isDropdownOpen.value = false
38
- searchQuery.value = ''
39
- }
40
-
41
- const selectedCountry = computed(() => {
42
- return (
43
- codes.value.find((c) => c.country_code === selectedCode.value) || {
44
- country_code: selectedCode.value,
45
- flag: '',
46
- country: '',
47
- code: '',
48
- }
49
- )
50
- })
51
-
52
- const filteredCodes = computed(() => {
53
- if (!searchQuery.value) return codes.value
54
- return codes.value.filter((c) =>
55
- c.country.toLowerCase().includes(searchQuery.value.toLowerCase())
56
- )
57
- })
58
-
59
- watch(() => props.code, (newCode) => {
60
- if (newCode !== undefined && newCode !== null) {
61
- selectedCode.value = newCode
62
- }
63
- })
64
-
65
- watch(isDropdownOpen, async () => {
66
- if (isDropdownOpen.value) {
67
- await nextTick()
68
- if (searchInputRef.value) {
69
- searchInputRef.value.focus()
70
- }
71
- }
72
- })
73
-
74
- onMounted(async () => {
75
- const response = await fetch('/resources/api/country-codes.json')
76
- const data = await response.json()
77
- codes.value = data.sort((a, b) => a.country.localeCompare(b.country, 'es'))
78
- if (!props.code) {
79
- const def = await getDefaultCountry(codes.value)
80
- if (def) selectCode(def)
81
- }
82
- if (dropdownRef.value) {
83
- const remove = useClickOutside(dropdownRef.value, () => {
84
- isDropdownOpen.value = false
85
- })
86
- onUnmounted(remove)
87
- }
88
- })
89
-
90
- return {
91
- codes,
92
- selectedCode,
93
- isDropdownOpen,
94
- searchQuery,
95
- selectCode,
96
- selectedCountry,
97
- filteredCodes,
98
- dropdownRef,
99
- searchInputRef,
100
- handleSearchInput
101
- }
102
- },
103
- template: `
104
- <div class="telpick-wrapper relative" ref="dropdownRef">
105
- <button
106
- @click="isDropdownOpen = !isDropdownOpen"
107
- class="telpick-btn"
108
- :style="styleOverrides"
109
- :aria-expanded="isDropdownOpen"
110
- aria-haspopup="listbox"
111
- >
112
- <div class="telpick-flag">
113
- <img v-if="selectedCountry.flag" :src="selectedCountry.flag" :alt="selectedCountry.country || 'flag'" />
114
- </div>
115
- <span>{{ selectedCountry.code }}</span>
116
- <span class="telpick-arrow ml-auto">▼</span>
117
- </button>
118
- <Transition name="telpick-dropdown">
119
- <div v-if="isDropdownOpen" class="telpick-dropdown" role="listbox" @click.stop @mousedown.stop>
120
- <input
121
- ref="searchInputRef"
122
- v-model="searchQuery"
123
- type="text"
124
- placeholder="Buscar país..."
125
- class="telpick-search"
126
- @input="handleSearchInput"
127
- @click.stop
128
- @mousedown.stop
129
- autofocus
130
- />
131
- <ul>
132
- <li v-for="(item, index) in filteredCodes" :key="\`\${item.country_code}-\${index}\`" @click="selectCode(item)" :class="['telpick-item', { 'telpick-item-selected': item.country_code === selectedCode && selectedCode !== null && selectedCode !== undefined }]" role="option" :aria-selected="item.country_code === selectedCode && selectedCode !== null && selectedCode !== undefined">
133
- <div class="telpick-flag">
134
- <img :src="item.flag" :alt="item.country" />
135
- </div>
136
- <span>{{ item.country }}</span>
137
- <span class="ml-auto">{{ item.code }}</span>
138
- </li>
139
- </ul>
140
- </div>
141
- </Transition>
142
- </div>
143
- `
144
- })
@@ -1,37 +0,0 @@
1
- // Wrapper para Vue, React y CDN usando Vanilla JS
2
- // Vue y React pueden usar el componente vanilla vía ref
3
-
4
- // Vue wrapper
5
- export function TelpickVue(props, { emit }) {
6
- let telpickInstance = null
7
- return {
8
- mounted() {
9
- telpickInstance = new window.Telpick({
10
- code: props.code,
11
- onChange: country => emit('update:code', country),
12
- styleOverrides: props.styleOverrides || {}
13
- })
14
- telpickInstance.init(this.$el)
15
- },
16
- beforeUnmount() {
17
- telpickInstance && telpickInstance.destroy()
18
- },
19
- render() {
20
- return null // Render handled by vanilla
21
- }
22
- }
23
- }
24
-
25
- // React wrapper
26
- import React, { useRef, useEffect } from 'react'
27
- export function TelpickReact({ code, onChange, styleOverrides }) {
28
- const ref = useRef()
29
- useEffect(() => {
30
- const telpickInstance = new window.Telpick({ code, onChange, styleOverrides })
31
- telpickInstance.init(ref.current)
32
- return () => telpickInstance.destroy()
33
- }, [code, onChange, styleOverrides])
34
- return <div ref={ref}></div>
35
- }
36
-
37
- // CDN usage: window.Telpick