@desource/phone-mask-vue 1.1.1 → 1.2.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 DELETED
@@ -1,1301 +0,0 @@
1
- var lib = (function(exports, vue) {
2
- "use strict";
3
- const M = { AC: "+247 #####", AD: ["+376 ### ###", "+376 #### ####"], AE: ["+971 # ### ####", "+971 ## ### ####", "+971 ### ######", "+971 ### # #####"], AF: "+93 ## ### ####", AG: "+1 ###-###-####", AI: "+1 ###-###-####", AL: ["+355 ## ### ###", "+355 ## ### ####", "+355 ### ####", "+355 ### ###", "+355 ### #####"], AM: ["+374 ## ######", "+374 ### ## ###"], AO: "+244 ### ### ###", AR: ["+54 ## ####-####", "+54 # ## ####-####", "+54 ###-###-####"], AS: "+1 ###-###-####", AT: ["+43 # #########", "+43 ### ######"], AU: ["+61 # #### ####", "+61 ### ### ###", "+61 #### ### ###", "+61 ## ### ##"], AW: "+297 ### ####", AX: ["+358 ## #######", "+358 ### ######"], AZ: ["+994 ## ### ## ##", "+994 ### ## ## ##"], BA: ["+387 ## ###-###", "+387 ## ### ###"], BB: "+1 ###-###-####", BD: ["+880 #-#######", "+880 ####-######", "+880 ###-#######"], BE: ["+32 ## ## ## ##", "+32 ### ## ## ##", "+32 ### ## ###"], BF: "+226 ## ## ## ##", BG: ["+359 # ### ###", "+359 ## ### ###", "+359 ### ## ###"], BH: "+973 #### ####", BI: "+257 ## ## ## ##", BJ: ["+229 ## ## ## ## ##", "+229 ## ## ## ##"], BL: "+590 ### ## ## ##", BM: "+1 ###-###-####", BN: "+673 ### ####", BO: ["+591 # #######", "+591 ########", "+591 ### ## ####"], BQ: "+599 ### ####", BR: ["+55 ## ####-####", "+55 ## #####-####", "+55 ### ## ####", "+55 ####-####"], BS: "+1 ###-###-####", BT: ["+975 # ### ###", "+975 ## ## ## ##"], BW: ["+267 ### ####", "+267 ## ### ###", "+267 #### ### ###", "+267 ## #####"], BY: ["+375 ### ##-##-##", "+375 ## ###-##-##", "+375 ### ### ####"], BZ: ["+501 ###-####", "+501 #-###-####-###"], CA: "+1 ###-###-####", CC: ["+61 # #### ####", "+61 ### ### ###", "+61 #### ### ###"], CD: ["+243 ## #####", "+243 ### ### ###"], CF: "+236 ## ## ## ##", CG: ["+242 ## ### ####", "+242 # #### ####"], CH: ["+41 ## ### ## ##", "+41 ### ### ###"], CI: ["+225 ## ## # #####", "+225 ## ## ## ####"], CK: "+682 ## ###", CL: ["+56 ### ### ###", "+56 # #### ####", "+56 ### ### ####", "+56 ## ### ####"], CM: ["+237 # ## ## ## ##", "+237 ## ## ## ##"], CN: ["+86 ## #### ####", "+86 ### #### ####", "+86 ### ### ####", "+86 ########"], CO: ["+57 ### #######", "+57 # ### #######"], CR: ["+506 #### ####", "+506 ###-###-####"], CU: ["+53 # #######", "+53 ### #######"], CV: "+238 ### ## ##", CW: ["+599 # ### ####", "+599 ### ####"], CX: ["+61 # #### ####", "+61 ### ### ###", "+61 #### ### ###"], CY: "+357 ## ######", CZ: "+420 ### ### ###", DE: ["+49 ## ######", "+49 #### #######", "+49 ### ##########", "+49 ### # ######", "+49 ### # ####", "+49 ### #### ####", "+49 ########"], DJ: "+253 ## ## ## ##", DK: "+45 ## ## ## ##", DM: "+1 ###-###-####", DO: "+1 ###-###-####", DZ: ["+213 ## ## ## ##", "+213 ### ## ## ##", "+213 ## ### ## ##"], EC: ["+593 #-###-####", "+593 ## ### ####", "+593 #### ### ####"], EE: ["+372 ### ####", "+372 #### ####", "+372 ## ## ####"], EG: ["+20 # ########", "+20 ## ########", "+20 ### ### ####"], EH: ["+212 # ## ## ## ##", "+212 ##-#######"], ER: "+291 # ### ###", ES: ["+34 ### ## ## ##", "+34 ### ### ###"], ET: "+251 ## ### ####", FI: ["+358 ## #######", "+358 ### ######"], FJ: ["+679 ### ####", "+679 #### ### ####"], FK: "+500 #####", FM: "+691 ### ####", FO: "+298 ######", FR: ["+33 # ## ## ## ##", "+33 ### ## ## ##"], GA: "+241 ## ## ## ##", GB: ["+44 ### ### ####", "+44 #### ######", "+44 ## #### ####"], GD: "+1 ###-###-####", GE: ["+995 ## ### ## ##", "+995 ### ## ## ##", "+995 ### ### ###"], GF: "+594 ### ## ## ##", GG: ["+44 #### ######", "+44 ### ### ####", "+44 ## #### ####"], GH: ["+233 ## ### ####", "+233 ### #####"], GI: ["+350 ### #####", "+350 ########"], GL: "+299 ## ## ##", GM: "+220 ### ####", GN: ["+224 ## ## ## ##", "+224 ### ## ## ##"], GP: "+590 ### ## ## ##", GQ: ["+240 ### ### ###", "+240 ### ######"], GR: ["+30 ## #### ####", "+30 ### ### ####"], GT: ["+502 #### ####", "+502 #### ### ####"], GU: "+1 ###-###-####", GW: ["+245 ### ### ###", "+245 ### ####"], GY: "+592 ### ####", HK: ["+852 #### ####", "+852 ### ### ###", "+852 ### ## ### ###"], HN: ["+504 ####-####", "+504 ###########"], HR: ["+385 # #### ###", "+385 ## ### ####", "+385 ### ### ###", "+385 ## ## ###", "+385 ## ### ###"], HT: "+509 ## ## ####", HU: ["+36 # ### ####", "+36 ## ### ####", "+36 ## ### ###"], ID: ["+62 ## #######", "+62 ###-###-###", "+62 ### #######", "+62 ### # ### ###", "+62 ### ### ####"], IE: ["+353 ## #####", "+353 ## ### ####", "+353 #### ### ###", "+353 ### ### ###"], IL: ["+972 #-###-####", "+972 ##-###-####", "+972 #-###-###-###"], IM: ["+44 #### ######", "+44 ### ### ####", "+44 ## #### ####"], IN: ["+91 ##### #####", "+91 #### ## ####", "+91 #### ### ### ###", "+91 #### ### ####"], IO: "+246 ### ####", IQ: ["+964 # ### ####", "+964 ### ### ####"], IR: ["+98 ## #### ####", "+98 ### ### ####"], IS: "+354 ### ####", IT: ["+39 ## #### ####", "+39 ### ### ####", "+39 ### ### ###"], JE: ["+44 #### ######", "+44 ### ### ####", "+44 ## #### ####"], JM: "+1 ###-###-####", JO: ["+962 # ### ####", "+962 # #### ####", "+962 ### #####", "+962 ## #######"], JP: ["+81 #-####-####", "+81 ##-####-####", "+81 ###-###-###", "+81 ##-###-####"], KE: ["+254 ## #######", "+254 ### ######", "+254 ### ### ###"], KG: ["+996 ### ### ###", "+996 ### ### # ##"], KH: ["+855 ## ### ###", "+855 #### ### ###"], KI: ["+686 #####", "+686 ########"], KM: "+269 ### ## ##", KN: "+1 ###-###-####", KP: ["+850 # ### ####", "+850 ### ### ####"], KR: ["+82 #-###-####", "+82 ##-####-####", "+82 ##-###-####"], KW: ["+965 #### ####", "+965 ### #####", "+965 #### ###"], KY: "+1 ###-###-####", KZ: ["+7 ##### # ## ##", "+7 ### ### ####", "+7 ### ###-##-##"], LA: ["+856 ## ### ###", "+856 ## ## ### ###"], LB: ["+961 # ### ###", "+961 ## ### ###"], LC: "+1 ###-###-####", LI: ["+423 ### ## ##", "+423 ### ### ###"], LK: ["+94 ### ### ###", "+94 ## ### ####"], LR: ["+231 ## ### ###", "+231 ## ### ####"], LS: "+266 #### ####", LT: ["+370 ### #####", "+370 ### ## ###"], LU: ["+352 ## ## ## ##", "+352 ### ### ###", "+352 ### ## ###"], LV: "+371 ## ### ###", LY: "+218 ##-#######", MA: ["+212 # ## ## ## ##", "+212 ##-#######"], MC: ["+377 ## ## ## ##", "+377 # ## ## ## ##"], MD: ["+373 ## ### ###", "+373 ### ## ###", "+373 ### #####"], ME: "+382 ## ### ###", MF: "+590 ### ## ## ##", MG: "+261 ## ## ### ##", MH: "+692 ###-####", MK: ["+389 # ### ####", "+389 ## ### ###", "+389 ### # ## ##"], ML: "+223 ## ## ## ##", MM: ["+95 # ### ###", "+95 # ### ####", "+95 ### ### ####"], MN: "+976 #### ####", MO: ["+853 #### ####", "+853 #### ###"], MP: "+1 ###-###-####", MQ: "+596 ### ## ## ##", MR: "+222 ## ## ## ##", MS: "+1 ###-###-####", MT: "+356 #### ####", MU: ["+230 #### ####", "+230 ### ####"], MV: ["+960 ###-####", "+960 ### ### ####"], MW: ["+265 # ### ###", "+265 ### ## ## ##"], MX: "+52 ### ### ####", MY: ["+60 #-#### ####", "+60 ##-### ####", "+60 #-###-##-####", "+60 ###-### ####"], MZ: ["+258 ## ### ###", "+258 ## ### ####", "+258 ### ### ###"], NA: ["+264 ## ### ###", "+264 ## ### ####", "+264 ### ### ###"], NC: "+687 ##.##.##", NE: ["+227 ## ## ## ##", "+227 ## ### ###"], NF: ["+672 ## ####", "+672 # #####"], NG: ["+234 #### ## ####", "+234 ### ### ####", "+234 ### #### ####"], NI: "+505 #### ####", NL: ["+31 ## ### ####", "+31 # ########", "+31 ### ####", "+31 ## #######"], NO: ["+47 ## ## ## ##", "+47 ### ## ###"], NP: ["+977 #-#######", "+977 ###-#######", "+977 ###########"], NR: "+674 ### ####", NU: ["+683 ####", "+683 ### ####"], NZ: ["+64 # ### ####", "+64 ## ### ####", "+64 ### ### ###"], OM: ["+968 ## ######", "+968 #### ####", "+968 ### #####"], PA: ["+507 ###-####", "+507 ####-####"], PE: ["+51 # #######", "+51 ### ### ###", "+51 ### #####"], PF: ["+689 ## ## ## ##", "+689 ### ## ## ##"], PG: ["+675 ### ####", "+675 #### ####"], PH: ["+63 # #### ####", "+63 ### ### ####", "+63 #### # ### ####"], PK: ["+92 ## ########", "+92 ### #######", "+92 ### ### ##", "+92 #### #####"], PL: ["+48 ## ### ## ##", "+48 ### ### ###"], PM: ["+508 ## ## ##", "+508 ### ## ## ##"], PR: "+1 ###-###-####", PS: ["+970 # ### ####", "+970 ### ### ###", "+970 #### ### ###"], PT: ["+351 ## ### ####", "+351 ### ### ###"], PW: "+680 ### ####", PY: ["+595 ## ### ####", "+595 ### ######", "+595 #### ### ####"], QA: ["+974 #### ####", "+974 ### ####"], RE: "+262 ### ## ## ##", RO: ["+40 ## ### ####", "+40 ### ### ###"], RS: ["+381 ## ######", "+381 ## #######", "+381 ### #####"], RU: "+7 ### ###-##-##", RW: "+250 ### ### ###", SA: ["+966 ## ### ####", "+966 ### ### ####", "+966 #### #####"], SB: ["+677 #####", "+677 ## #####"], SC: ["+248 # ### ###", "+248 #######"], SD: "+249 ## ### ####", SE: ["+46 # ## ## ##", "+46 ## ### ## ##", "+46 ## ## ## ##", "+46 ### ## ## ###"], SG: ["+65 #### ####", "+65 #### ### ####"], SH: "+290 #####", SI: ["+386 # ### ## ##", "+386 ## ### ###", "+386 ## ######", "+386 ### #####"], SJ: ["+47 ## ## ## ##", "+47 ### ## ###"], SK: ["+421 #/### ### ##", "+421 ### ### ###", "+421 #######"], SL: "+232 ## ######", SM: ["+378 #### ######", "+378 ## ## ## ##"], SN: ["+221 ## ### ## ##", "+221 ### ## ## ##"], SO: ["+252 # ######", "+252 # #######"], SR: ["+597 ###-###", "+597 ###-####", "+597 ##-##-##"], SS: "+211 ### ### ###", ST: "+239 ### ####", SV: ["+503 #### ####", "+503 ### ####"], SX: "+1 ###-###-####", SY: ["+963 ## ### ####", "+963 ### ### ###"], SZ: ["+268 #### ####", "+268 ##### ####"], TA: "+290 ####", TC: "+1 ###-###-####", TD: "+235 ## ## ## ##", TG: "+228 ## ## ## ##", TH: ["+66 # ### ####", "+66 ## ### ####", "+66 #### ### ###"], TJ: ["+992 ### ## ####", "+992 ## ### ####"], TK: "+690 ####", TL: ["+670 ### ####", "+670 #### ####"], TM: ["+993 ## ##-##-##", "+993 ## ######"], TN: "+216 ## ### ###", TO: ["+676 ##-###", "+676 ### ####", "+676 #### ###"], TR: ["+90 ### ### ## ##", "+90 ### ### ####"], TT: "+1 ###-###-####", TV: ["+688 ## ###", "+688 ## ####"], TW: ["+886 # #### ####", "+886 ### ### ###", "+886 ## ### ####", "+886 ## #### ####"], TZ: ["+255 ## ### ####", "+255 ### ### ###", "+255 ### ## ####"], UA: ["+380 #### #####", "+380 ## ### ####", "+380 ### ### ###"], UG: ["+256 ## #######", "+256 ### ######"], US: "+1 ###-###-####", UY: ["+598 #### ####", "+598 ## ### ###", "+598 ### ####"], UZ: "+998 ## ### ## ##", VA: ["+39 ## #### ####", "+39 ### ### ####", "+39 ### ### ###"], VC: "+1 ###-###-####", VE: "+58 ###-#######", VG: "+1 ###-###-####", VI: "+1 ###-###-####", VN: ["+84 ### #### ###", "+84 ### ### ###", "+84 #### ######", "+84 ## ### ## ##"], VU: ["+678 #####", "+678 ### ####"], WF: ["+681 ## ## ##", "+681 ### ## ## ##"], WS: ["+685 #####", "+685 ## #####", "+685 ### ###"], XK: ["+383 ## ### ###", "+383 ### #####"], YE: ["+967 # ### ###", "+967 ### ### ###"], YT: "+262 ### ## ## ##", ZA: ["+27 ## ### ####", "+27 ### ### ###"], ZM: ["+260 ### ### ###", "+260 ## #######", "+260 #########"], ZW: ["+263 ## #####", "+263 ## ### ####", "+263 ### ####", "+263 #### ######"] };
4
- const t$1 = /^[a-z]{2}$/i, countryCodeEmoji = (o2) => {
5
- if (!t$1.test(o2)) {
6
- const t2 = typeof o2;
7
- throw new TypeError(`cc argument must be an ISO 3166-1 alpha-2 string, but got '${"string" === t2 ? o2 : t2}' instead.`);
8
- }
9
- const e2 = [...o2.toUpperCase()].map((t2) => (t2.codePointAt(0) ?? 0) + 127397);
10
- return String.fromCodePoint(...e2);
11
- };
12
- const o$1 = "en", n$1 = /* @__PURE__ */ new Map(), getDisplayNames = (e2) => {
13
- const t2 = e2.toLowerCase(), s2 = n$1.get(t2);
14
- if (s2) return s2;
15
- const r = new Intl.DisplayNames([e2], { type: "region" });
16
- if (n$1.size >= 10) {
17
- for (const e3 of n$1.keys()) if (e3 !== o$1) {
18
- n$1.delete(e3);
19
- break;
20
- }
21
- }
22
- return n$1.set(t2, r), r;
23
- }, s$1 = Object.entries(M), divideMask = (e2) => e2.split(/ (.*)/s);
24
- function getCodeAndMask(e2) {
25
- let t2 = "", o2 = "";
26
- if (Array.isArray(e2)) {
27
- const n2 = [];
28
- for (const o3 of e2) {
29
- const [e3, s2] = divideMask(o3);
30
- t2 || (t2 = e3), n2.push(s2);
31
- }
32
- o2 = n2;
33
- } else {
34
- const [n2, s2] = divideMask(e2);
35
- t2 = n2, o2 = s2;
36
- }
37
- return [t2, o2];
38
- }
39
- s$1.map(([e2, t2]) => ({ id: e2, mask: t2 }));
40
- s$1.reduce((e2, [t2, o2]) => {
41
- const [n2, s2] = getCodeAndMask(o2);
42
- return e2[t2] = { code: n2, mask: s2 }, e2;
43
- }, {});
44
- s$1.map(([e2, t2]) => {
45
- const [o2, n2] = getCodeAndMask(t2);
46
- return { id: e2, code: o2, mask: n2 };
47
- });
48
- s$1.reduce((e2, [o2, n2]) => {
49
- const [s2, r] = getCodeAndMask(n2);
50
- return e2[o2] = { code: s2, mask: r, flag: countryCodeEmoji(o2) }, e2;
51
- }, {});
52
- s$1.map(([e2, o2]) => {
53
- const [n2, s2] = getCodeAndMask(o2);
54
- return { id: e2, code: n2, mask: s2, flag: countryCodeEmoji(e2) };
55
- });
56
- const MasksFullMap = (e2) => {
57
- const o2 = getDisplayNames(e2);
58
- return s$1.reduce((e3, [n2, s2]) => {
59
- const [r, a] = getCodeAndMask(s2), d = o2.of(n2) ?? "";
60
- return e3[n2] = { code: r, mask: a, name: d, flag: countryCodeEmoji(n2) }, e3;
61
- }, {});
62
- }, MasksFull = (e2) => {
63
- const o2 = getDisplayNames(e2);
64
- return s$1.map(([e3, n2]) => {
65
- const [s2, r] = getCodeAndMask(n2);
66
- return { id: e3, code: s2, mask: r, name: o2.of(e3) ?? "", flag: countryCodeEmoji(e3) };
67
- });
68
- }, f = MasksFullMap(o$1);
69
- MasksFull(o$1);
70
- const k = countryCodeEmoji;
71
- function getNavigatorLang() {
72
- return globalThis.navigator?.language || "en";
73
- }
74
- function detectCountryFromLocale() {
75
- try {
76
- const t2 = getNavigatorLang();
77
- try {
78
- const r2 = new Intl.Locale(t2);
79
- if (r2.region) return r2.region.toUpperCase();
80
- } catch {
81
- }
82
- const r = t2.split(/[-_]/);
83
- if (r.length > 1) return r[1]?.toUpperCase() || null;
84
- } catch {
85
- }
86
- return null;
87
- }
88
- function hasCountry(t2) {
89
- const e2 = f;
90
- return t2.toUpperCase() in e2;
91
- }
92
- function getCountry(r, e2) {
93
- const n2 = MasksFullMap(e2), o2 = r.toUpperCase();
94
- return o2 in n2 ? { id: o2, ...n2[o2] } : { id: "US", ...n2.US };
95
- }
96
- function parseCountryCode(t2, r) {
97
- return t2 && hasCountry(t2) ? t2.toUpperCase() : r || "";
98
- }
99
- function toArray(t2) {
100
- return Array.isArray(t2) ? t2 : [t2];
101
- }
102
- function countPlaceholders(t2) {
103
- return (t2.match(/#/g) || []).length;
104
- }
105
- function removeCountryCodePrefix(t2) {
106
- return t2.replace(/^\+\d+\s?/, "");
107
- }
108
- function pickMaskVariant(t2, r) {
109
- if (!t2.length) return "";
110
- if (1 === t2.length) return t2[0];
111
- const e2 = t2.map((t3) => ({ mask: t3, count: countPlaceholders(t3) })), n2 = e2.filter((t3) => t3.count >= r).sort((t3, r2) => t3.count - r2.count);
112
- if (n2.length > 0) return n2[0].mask;
113
- const o2 = e2.sort((t3, r2) => r2.count - t3.count)[0];
114
- return o2 ? o2.mask : t2[0];
115
- }
116
- function formatDigitsWithMap(t2, r) {
117
- let e2 = "";
118
- const n2 = [];
119
- let o2 = 0;
120
- const a = r.length, s2 = t2.length;
121
- for (let c = 0; c < s2; c++) {
122
- const s3 = t2[c];
123
- if ("#" === s3) {
124
- if (!(o2 < a)) break;
125
- e2 += r[o2], n2.push(o2), o2++;
126
- } else {
127
- const r2 = -1 !== t2.indexOf("#", c + 1) && o2 < a;
128
- (e2.length > 0 || r2) && (e2 += s3, n2.push(-1));
129
- }
130
- }
131
- return { display: e2, map: n2 };
132
- }
133
- function filterCountries(t2, r) {
134
- const e2 = r.trim().toUpperCase();
135
- if (!e2) return t2;
136
- const n2 = e2.replace(/\D/g, ""), o2 = n2.length > 0;
137
- return t2.map((t3) => {
138
- const r2 = t3.name.toUpperCase(), a = t3.id.toUpperCase(), s2 = t3.code.toUpperCase(), c = t3.code.replace(/\D/g, "");
139
- let i = 0;
140
- return r2.startsWith(e2) ? i = 1e3 : r2.includes(e2) && (i = 500), s2.startsWith(e2) ? i += 100 : s2.includes(e2) && (i += 50), a === e2 ? i += 200 : a.startsWith(e2) && (i += 150), o2 && c.startsWith(n2) ? i += 80 : o2 && c.includes(n2) && (i += 40), { country: t3, score: i };
141
- }).filter((t3) => t3.score > 0).sort((t3, r2) => r2.score === t3.score ? t3.country.name.localeCompare(r2.country.name) : r2.score - t3.score).map((t3) => t3.country);
142
- }
143
- const e$1 = [" ", "-", "(", ")"], t = ["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End", "Tab"], n = /[^\d\s\-()]/;
144
- function removeDigitsRange(e2, t2, n2) {
145
- return { newDigits: e2.slice(0, t2) + e2.slice(n2), caretDigitIndex: t2 };
146
- }
147
- function removeSelectedDigits(e2, t2, n2, i) {
148
- if (n2 === i) return;
149
- const r = t2.getDigitRange(e2, n2, i);
150
- if (!r) return;
151
- const [s2, g] = r;
152
- return removeDigitsRange(e2, s2, g);
153
- }
154
- function extractDigits(e2, t2) {
155
- const n2 = e2.replace(/\D/g, "");
156
- return t2 ? n2.slice(0, t2) : n2;
157
- }
158
- function getSelection(e2) {
159
- return e2 ? [e2.selectionStart ?? 0, e2.selectionEnd ?? 0] : [0, 0];
160
- }
161
- function setCaret(e2, t2) {
162
- if (e2) try {
163
- e2.setSelectionRange(t2, t2);
164
- } catch {
165
- }
166
- }
167
- function processBeforeInput(e2) {
168
- if (!e2.target) return;
169
- const t2 = e2.target, i = e2.data;
170
- "insertText" === e2.inputType && i && (n.test(i) || " " === i && t2.value.endsWith(" ")) && e2.preventDefault();
171
- }
172
- function processInput(e2, t2) {
173
- if (!e2.target) return;
174
- const n2 = e2.target, { formatter: i } = t2, r = i.getMaxDigits(), s2 = extractDigits(n2.value, r);
175
- return { newDigits: s2, caretDigitIndex: s2.length };
176
- }
177
- function processKeydown(n2, i) {
178
- if (!n2.target) return;
179
- const r = n2.target, { digits: s2, formatter: g } = i;
180
- if ((function shouldIgnoreKeydown(e2) {
181
- return e2.ctrlKey || e2.metaKey || e2.altKey || t.includes(e2.key);
182
- })(n2)) return;
183
- const [o2, c] = getSelection(r), a = r.value;
184
- return "Backspace" === n2.key ? (n2.preventDefault(), removeSelectedDigits(s2, g, o2, c) ?? (function removePreviousDigit(t2, n3, i2, r2) {
185
- if (r2 <= 0) return;
186
- let s3 = r2 - 1;
187
- for (; s3 >= 0 && e$1.includes(i2[s3]); ) s3--;
188
- if (s3 < 0) return;
189
- const g2 = n3.getDigitRange(t2, s3, s3 + 1);
190
- if (!g2) return;
191
- const [o3] = g2;
192
- return removeDigitsRange(t2, o3, o3 + 1);
193
- })(s2, g, a, o2)) : "Delete" === n2.key ? (n2.preventDefault(), removeSelectedDigits(s2, g, o2, c) ?? (function removeNextDigit(e2, t2, n3, i2) {
194
- if (i2 >= n3.length) return;
195
- const r2 = t2.getDigitRange(e2, i2, n3.length);
196
- if (!r2) return;
197
- const [s3] = r2;
198
- return removeDigitsRange(e2, s3, s3 + 1);
199
- })(s2, g, a, o2)) : void (/^\d$/.test(n2.key) ? s2.length >= g.getMaxDigits() && n2.preventDefault() : 1 === n2.key.length && n2.preventDefault());
200
- }
201
- function processPaste(e2, t2) {
202
- if (!e2.target) return;
203
- e2.preventDefault();
204
- const n2 = e2.target, { digits: i, formatter: r } = t2, s2 = e2.clipboardData?.getData("text") || "", g = r.getMaxDigits(), o2 = extractDigits(s2, g);
205
- if (0 === o2.length) return;
206
- const [c, a] = getSelection(n2);
207
- if (c !== a) {
208
- const e3 = r.getDigitRange(i, c, a);
209
- if (e3) {
210
- const [t3, n3] = e3;
211
- return { newDigits: extractDigits(i.slice(0, t3) + o2 + i.slice(n3), g), caretDigitIndex: t3 + o2.length };
212
- }
213
- }
214
- const u = r.getDigitRange(i, 0, c), l = u ? u[1] : 0;
215
- return { newDigits: extractDigits(i.slice(0, l) + o2 + i.slice(l), g), caretDigitIndex: l + o2.length };
216
- }
217
- function createPhoneFormatter(o2) {
218
- const i = toArray(o2.mask), l = i.map((n2) => countPlaceholders(removeCountryCodePrefix(n2))), s2 = Math.max(...l), getMask = (t2) => {
219
- const n2 = pickMaskVariant(i, t2);
220
- return removeCountryCodePrefix(n2);
221
- };
222
- return { formatDisplay: (t2) => {
223
- const e2 = getMask(t2.length);
224
- return formatDigitsWithMap(e2, t2).display;
225
- }, getMaxDigits: () => s2, getPlaceholder: () => getMask(0), getCaretPosition: (t2) => {
226
- const e2 = Math.max(0, t2);
227
- if (0 === e2) return 0;
228
- const r = getMask(e2), { display: a } = formatDigitsWithMap(r, "0".repeat(e2));
229
- return a.length;
230
- }, getDigitRange: (t2, e2, r) => {
231
- const a = getMask(t2.length), { map: o3 } = formatDigitsWithMap(a, t2);
232
- let i2 = 1 / 0, l2 = -1 / 0;
233
- for (let t3 = e2; t3 < r && t3 < o3.length; t3++) {
234
- const e3 = o3[t3];
235
- void 0 !== e3 && e3 >= 0 && (i2 = Math.min(i2, e3), l2 = Math.max(l2, e3));
236
- }
237
- return i2 === 1 / 0 ? null : [i2, l2 + 1];
238
- }, isComplete: (t2) => l.includes(t2.length) };
239
- }
240
- const o = "https://ipapi.co/json/", e = 1500, p = "@desource/phone-mask:geo", s = 864e5;
241
- async function detectCountryFromGeoIP(t2 = o, r = e) {
242
- const n2 = new AbortController(), c = setTimeout(() => n2.abort(), r);
243
- try {
244
- const o2 = await fetch(t2, { signal: n2.signal, headers: { Accept: "application/json" } });
245
- if (clearTimeout(c), !o2.ok) return null;
246
- const e2 = await o2.json();
247
- return (e2.country || e2.country_code || e2.countryCode || e2.country_code2 || "").toString().toUpperCase() || null;
248
- } catch {
249
- return clearTimeout(c), null;
250
- }
251
- }
252
- async function detectByGeoIp() {
253
- try {
254
- const o3 = localStorage.getItem(p);
255
- if (o3) {
256
- const e3 = JSON.parse(o3), c = Date.now() - e3.ts > s, a = parseCountryCode(e3.country_code);
257
- if (a && !c) return a;
258
- localStorage.removeItem(p);
259
- }
260
- } catch {
261
- }
262
- const o2 = await detectCountryFromGeoIP(), e2 = parseCountryCode(o2);
263
- if (e2) {
264
- try {
265
- const t2 = JSON.stringify({ country_code: e2, ts: Date.now() });
266
- localStorage.setItem(p, t2);
267
- } catch {
268
- }
269
- return e2;
270
- }
271
- return null;
272
- }
273
- function useCountry({
274
- country: countryOption,
275
- locale: localeOption,
276
- detect,
277
- onCountryChange
278
- } = {}) {
279
- const locale = vue.computed(() => vue.toValue(localeOption) || getNavigatorLang());
280
- const countryCode = vue.ref(parseCountryCode(vue.toValue(countryOption), "US"));
281
- const country = vue.computed(() => getCountry(countryCode.value, locale.value));
282
- const setCountry2 = (code) => {
283
- const parsed = parseCountryCode(code);
284
- if (parsed) {
285
- countryCode.value = parsed;
286
- return true;
287
- }
288
- return false;
289
- };
290
- const detectCountry = async () => {
291
- const geoCountry = await detectByGeoIp();
292
- if (setCountry2(geoCountry)) return;
293
- const localeCountry = detectCountryFromLocale();
294
- setCountry2(localeCountry);
295
- };
296
- vue.watchEffect(() => {
297
- const newCountry = vue.toValue(countryOption);
298
- if (newCountry && newCountry !== countryCode.value) {
299
- setCountry2(newCountry);
300
- }
301
- });
302
- vue.watchEffect(() => {
303
- if (vue.toValue(detect) && !vue.toValue(countryOption)) {
304
- detectCountry();
305
- }
306
- });
307
- vue.watchEffect(() => {
308
- onCountryChange?.(country.value);
309
- });
310
- return { country, setCountry: setCountry2, locale };
311
- }
312
- function useFormatter({
313
- country,
314
- value,
315
- onChange,
316
- onPhoneChange,
317
- onValidationChange
318
- }) {
319
- const formatter = vue.computed(() => createPhoneFormatter(vue.toValue(country)));
320
- const maxDigits = vue.computed(() => formatter.value.getMaxDigits());
321
- const digits = vue.computed(() => extractDigits(vue.toValue(value), maxDigits.value));
322
- const displayPlaceholder = vue.computed(() => formatter.value.getPlaceholder());
323
- const displayValue = vue.computed(() => formatter.value.formatDisplay(digits.value));
324
- const full = vue.computed(() => digits.value ? `${vue.toValue(country).code}${digits.value}` : "");
325
- const fullFormatted = vue.computed(() => displayValue.value ? `${vue.toValue(country).code} ${displayValue.value}` : "");
326
- const isComplete = vue.computed(() => formatter.value.isComplete(digits.value));
327
- const isEmpty = vue.computed(() => digits.value.length === 0);
328
- const shouldShowWarn = vue.computed(() => !isEmpty.value && !isComplete.value);
329
- const phoneData = vue.computed(() => ({
330
- full: full.value,
331
- fullFormatted: fullFormatted.value,
332
- digits: digits.value
333
- }));
334
- vue.watchEffect(() => {
335
- if (vue.toValue(value) !== digits.value) {
336
- onChange(digits.value);
337
- }
338
- });
339
- vue.watchEffect(() => {
340
- onPhoneChange?.(phoneData.value);
341
- });
342
- vue.watchEffect(() => {
343
- onValidationChange?.(isComplete.value);
344
- });
345
- return {
346
- digits,
347
- formatter,
348
- displayPlaceholder,
349
- displayValue,
350
- full,
351
- fullFormatted,
352
- isComplete,
353
- isEmpty,
354
- shouldShowWarn
355
- };
356
- }
357
- function useTimer() {
358
- let timerRef = null;
359
- const clear = () => {
360
- if (timerRef) {
361
- clearTimeout(timerRef);
362
- timerRef = null;
363
- }
364
- };
365
- const set = (callback, delay) => {
366
- clear();
367
- timerRef = setTimeout(callback, delay);
368
- };
369
- vue.onUnmounted(clear);
370
- return { set, clear };
371
- }
372
- function useValidationHint() {
373
- const showValidationHint = vue.ref(false);
374
- const validationTimer = useTimer();
375
- const clearValidationHint = (hideHint = true) => {
376
- if (hideHint) showValidationHint.value = false;
377
- validationTimer.clear();
378
- };
379
- const scheduleValidationHint = (delay) => {
380
- showValidationHint.value = false;
381
- validationTimer.set(() => {
382
- showValidationHint.value = true;
383
- }, delay);
384
- };
385
- return { showValidationHint, clearValidationHint, scheduleValidationHint };
386
- }
387
- const HINT_DELAY_INPUT = 500;
388
- const HINT_DELAY_ACTION = 300;
389
- function useInputHandlers(options) {
390
- const { formatter, digits, inactive, onChange, scheduleValidationHint } = options;
391
- const scheduleCaretUpdate = (el, digitIndex) => {
392
- vue.nextTick(() => {
393
- if (!el) return;
394
- const pos = vue.toValue(formatter).getCaretPosition(digitIndex);
395
- setCaret(el, pos);
396
- });
397
- };
398
- const handleBeforeInput = (e2) => {
399
- processBeforeInput(e2);
400
- };
401
- const handleInput = (e2) => {
402
- if (vue.toValue(inactive)) return;
403
- const result = processInput(e2, { formatter: vue.toValue(formatter) });
404
- if (!result) return;
405
- onChange?.(result.newDigits);
406
- scheduleCaretUpdate(e2.target, result.caretDigitIndex);
407
- scheduleValidationHint?.(HINT_DELAY_INPUT);
408
- };
409
- const handleKeydown = (e2) => {
410
- if (vue.toValue(inactive)) return;
411
- const result = processKeydown(e2, { digits: vue.toValue(digits), formatter: vue.toValue(formatter) });
412
- if (!result) return;
413
- onChange?.(result.newDigits);
414
- scheduleCaretUpdate(e2.target, result.caretDigitIndex);
415
- scheduleValidationHint?.(HINT_DELAY_ACTION);
416
- };
417
- const handlePaste = (e2) => {
418
- if (vue.toValue(inactive)) return;
419
- const result = processPaste(e2, { digits: vue.toValue(digits), formatter: vue.toValue(formatter) });
420
- if (!result) return;
421
- onChange?.(result.newDigits);
422
- scheduleCaretUpdate(e2.target, result.caretDigitIndex);
423
- scheduleValidationHint?.(HINT_DELAY_ACTION);
424
- };
425
- return {
426
- handleBeforeInput,
427
- handleInput,
428
- handleKeydown,
429
- handlePaste
430
- };
431
- }
432
- function useCountrySelector({
433
- rootRef,
434
- dropdownRef,
435
- searchRef,
436
- selectorRef,
437
- locale,
438
- countryOption,
439
- inactive,
440
- onSelectCountry,
441
- onAfterSelect
442
- }) {
443
- const search = vue.ref("");
444
- const dropdownOpen = vue.ref(false);
445
- const dropdownStyle = vue.shallowRef({});
446
- const focusedIndex = vue.ref(0);
447
- const countries = vue.computed(() => MasksFull(vue.toValue(locale)));
448
- const filteredCountries = vue.computed(() => filterCountries(countries.value, search.value));
449
- const hasDropdown = vue.computed(() => !vue.toValue(countryOption) && countries.value.length > 1);
450
- const setFocusedIndex = (index2) => {
451
- focusedIndex.value = index2;
452
- };
453
- const focusSearch = () => {
454
- vue.nextTick(() => searchRef.value?.focus({ preventScroll: true }));
455
- };
456
- const closeDropdown = () => {
457
- dropdownOpen.value = false;
458
- };
459
- const openDropdown = () => {
460
- dropdownOpen.value = true;
461
- setFocusedIndex(0);
462
- focusSearch();
463
- };
464
- const toggleDropdown = () => {
465
- if (vue.toValue(inactive) || !hasDropdown.value) return;
466
- if (dropdownOpen.value) {
467
- closeDropdown();
468
- } else {
469
- openDropdown();
470
- }
471
- };
472
- const selectCountry = (code) => {
473
- onSelectCountry(code);
474
- closeDropdown();
475
- search.value = "";
476
- setFocusedIndex(0);
477
- onAfterSelect?.();
478
- };
479
- const handleSearchChange = (e2) => {
480
- search.value = e2.target.value;
481
- setFocusedIndex(0);
482
- };
483
- const onDocClick = (ev) => {
484
- const target = ev.target;
485
- const dropdownEl = dropdownRef.value;
486
- const selectorEl = selectorRef.value;
487
- if (!target) return;
488
- if (dropdownEl?.contains(target)) return;
489
- if (selectorEl?.contains(target)) return;
490
- closeDropdown();
491
- };
492
- const positionDropdown = (e2) => {
493
- if (e2?.type === "scroll" && e2.target && dropdownRef.value?.contains(e2.target)) return;
494
- if (!rootRef.value) return;
495
- const rect = rootRef.value.getBoundingClientRect();
496
- dropdownStyle.value = {
497
- top: `${rect.bottom + globalThis.scrollY + 8}px`,
498
- left: `${rect.left + globalThis.scrollX}px`,
499
- width: `${rect.width}px`
500
- };
501
- };
502
- const scrollFocusedIntoView = () => {
503
- vue.nextTick(() => {
504
- const list = dropdownRef.value?.lastElementChild;
505
- const option = list?.children[focusedIndex.value];
506
- if (!list || !option) return;
507
- const listRect = list.getBoundingClientRect();
508
- const optionRect = option.getBoundingClientRect();
509
- let scrollAmount = 0;
510
- if (optionRect.top < listRect.top) {
511
- scrollAmount = list.scrollTop - (listRect.top - optionRect.top);
512
- } else if (optionRect.bottom > listRect.bottom) {
513
- scrollAmount = list.scrollTop + (optionRect.bottom - listRect.bottom);
514
- } else {
515
- return;
516
- }
517
- list.scrollTo({ top: scrollAmount, behavior: "smooth" });
518
- });
519
- };
520
- const handleSearchKeydown = (e2) => {
521
- if (e2.key === "ArrowDown") {
522
- e2.preventDefault();
523
- setFocusedIndex(Math.min(focusedIndex.value + 1, filteredCountries.value.length - 1));
524
- scrollFocusedIntoView();
525
- } else if (e2.key === "ArrowUp") {
526
- e2.preventDefault();
527
- setFocusedIndex(Math.max(focusedIndex.value - 1, 0));
528
- scrollFocusedIntoView();
529
- } else if (e2.key === "Enter" && filteredCountries.value[focusedIndex.value]) {
530
- e2.preventDefault();
531
- selectCountry(filteredCountries.value[focusedIndex.value].id);
532
- } else if (e2.key === "Escape") {
533
- closeDropdown();
534
- }
535
- };
536
- const removeListeners = () => {
537
- globalThis.removeEventListener("resize", positionDropdown);
538
- globalThis.removeEventListener("scroll", positionDropdown, true);
539
- globalThis.removeEventListener("click", onDocClick, true);
540
- };
541
- vue.watch(hasDropdown, (dropdownExists) => {
542
- if (!dropdownExists && dropdownOpen.value) {
543
- closeDropdown();
544
- }
545
- });
546
- vue.watch(dropdownOpen, (isOpen) => {
547
- if (!isOpen) {
548
- removeListeners();
549
- return;
550
- }
551
- positionDropdown();
552
- globalThis.addEventListener("resize", positionDropdown);
553
- globalThis.addEventListener("scroll", positionDropdown, true);
554
- globalThis.addEventListener("click", onDocClick, true);
555
- });
556
- vue.onBeforeUnmount(removeListeners);
557
- return {
558
- // State
559
- dropdownOpen,
560
- search,
561
- focusedIndex,
562
- dropdownStyle,
563
- // Derived
564
- filteredCountries,
565
- hasDropdown,
566
- // Actions
567
- openDropdown,
568
- closeDropdown,
569
- toggleDropdown,
570
- selectCountry,
571
- setFocusedIndex,
572
- handleSearchChange,
573
- handleSearchKeydown
574
- };
575
- }
576
- function useClipboard(delay = 1800) {
577
- const copied = vue.ref(false);
578
- const isCopying = vue.ref(false);
579
- const copyTimer = useTimer();
580
- const copy = async (text) => {
581
- if (isCopying.value) return false;
582
- const trimmedText = text.trim();
583
- if (!trimmedText) return false;
584
- isCopying.value = true;
585
- try {
586
- await navigator.clipboard.writeText(trimmedText);
587
- copied.value = true;
588
- copyTimer.set(() => {
589
- copied.value = false;
590
- }, delay);
591
- return true;
592
- } catch (err) {
593
- console.warn("Copy failed", err);
594
- return false;
595
- } finally {
596
- isCopying.value = false;
597
- }
598
- };
599
- return { copied, isCopying, copy };
600
- }
601
- const DELAY = 1800;
602
- function useCopyAction({ liveRef, fullFormatted, onCopy }) {
603
- const liveTimer = useTimer();
604
- const { copied, copy } = useClipboard(DELAY);
605
- const copyAriaLabel = vue.computed(() => copied.value ? "Copied" : `Copy ${fullFormatted.value}`);
606
- const copyButtonTitle = vue.computed(() => copied.value ? "Copied" : "Copy phone number");
607
- const announceToScreenReader = (message) => {
608
- if (!liveRef?.value) return;
609
- liveRef.value.textContent = message;
610
- liveTimer.set(() => {
611
- if (liveRef.value) liveRef.value.textContent = "";
612
- }, DELAY);
613
- };
614
- const onCopyClick = async () => {
615
- const valueToCopy = fullFormatted.value.trim();
616
- const success = await copy(valueToCopy);
617
- if (success) {
618
- onCopy?.(valueToCopy);
619
- announceToScreenReader("Phone number copied to clipboard");
620
- }
621
- };
622
- return {
623
- copied,
624
- copyAriaLabel,
625
- copyButtonTitle,
626
- onCopyClick
627
- };
628
- }
629
- function useTheme({ theme }) {
630
- const systemDark = vue.ref(false);
631
- const themeClass = vue.computed(() => {
632
- const resolvedTheme = vue.toValue(theme);
633
- if (resolvedTheme === "auto") {
634
- return systemDark.value ? "theme-dark" : "theme-light";
635
- }
636
- return `theme-${resolvedTheme}`;
637
- });
638
- let mq = null;
639
- const handler = (e2) => {
640
- systemDark.value = e2.matches;
641
- };
642
- vue.onBeforeMount(() => {
643
- mq = globalThis.matchMedia?.("(prefers-color-scheme: dark)") ?? null;
644
- if (!mq) return;
645
- systemDark.value = mq.matches;
646
- mq.addEventListener("change", handler);
647
- });
648
- vue.onBeforeUnmount(() => {
649
- mq?.removeEventListener("change", handler);
650
- });
651
- return {
652
- themeClass
653
- };
654
- }
655
- const _hoisted_1 = ["disabled", "tabindex", "aria-label", "aria-expanded", "aria-haspopup"];
656
- const _hoisted_2 = ["aria-label"];
657
- const _hoisted_3 = { class: "pi-code" };
658
- const _hoisted_4 = { class: "pi-input-wrap" };
659
- const _hoisted_5 = ["placeholder", "value", "disabled", "readonly", "aria-invalid"];
660
- const _hoisted_6 = {
661
- class: "pi-actions",
662
- role: "toolbar",
663
- "aria-label": "Phone input actions"
664
- };
665
- const _hoisted_7 = ["aria-label", "title"];
666
- const _hoisted_8 = {
667
- key: 1,
668
- width: "16",
669
- height: "16",
670
- viewBox: "0 0 16 16",
671
- fill: "none",
672
- "aria-hidden": "true"
673
- };
674
- const _hoisted_9 = {
675
- key: 2,
676
- width: "16",
677
- height: "16",
678
- viewBox: "0 0 16 16",
679
- fill: "none",
680
- "aria-hidden": "true"
681
- };
682
- const _hoisted_10 = ["aria-label", "title"];
683
- const _hoisted_11 = {
684
- key: 0,
685
- width: "11",
686
- height: "11",
687
- viewBox: "0 0 14 14",
688
- fill: "none",
689
- "aria-hidden": "true"
690
- };
691
- const _hoisted_12 = { class: "pi-search-wrap" };
692
- const _hoisted_13 = ["value", "aria-activedescendant", "placeholder"];
693
- const _hoisted_14 = ["id", "aria-selected", "title", "onClick", "onMouseenter"];
694
- const _hoisted_15 = ["aria-label"];
695
- const _hoisted_16 = { class: "pi-opt-name" };
696
- const _hoisted_17 = { class: "pi-opt-code" };
697
- const _hoisted_18 = {
698
- key: 0,
699
- class: "pi-empty"
700
- };
701
- const _sfc_main = /* @__PURE__ */ vue.defineComponent({
702
- __name: "PhoneInput",
703
- props: /* @__PURE__ */ vue.mergeModels({
704
- country: {},
705
- detect: { type: Boolean, default: true },
706
- locale: {},
707
- size: { default: "normal" },
708
- theme: { default: "auto" },
709
- disabled: { type: Boolean, default: false },
710
- readonly: { type: Boolean, default: false },
711
- showCopy: { type: Boolean, default: true },
712
- showClear: { type: Boolean, default: false },
713
- withValidity: { type: Boolean, default: true },
714
- searchPlaceholder: { default: "Search country or code..." },
715
- noResultsText: { default: "No countries found" },
716
- clearButtonLabel: { default: "Clear phone number" },
717
- dropdownClass: {},
718
- disableDefaultStyles: { type: Boolean, default: false }
719
- }, {
720
- "modelValue": { default: "" },
721
- "modelModifiers": {}
722
- }),
723
- emits: /* @__PURE__ */ vue.mergeModels(["change", "country-change", "validation-change", "focus", "blur", "copy", "clear"], ["update:modelValue"]),
724
- setup(__props, { expose: __expose, emit: __emit }) {
725
- const props = __props;
726
- const slots = vue.useSlots();
727
- const emit = __emit;
728
- const model = vue.useModel(__props, "modelValue");
729
- const onChange = (v) => {
730
- model.value = v;
731
- };
732
- const { country, setCountry: setCountry2, locale } = useCountry({
733
- country: () => props.country,
734
- locale: () => props.locale,
735
- detect: () => props.detect,
736
- onCountryChange: (c) => emit("country-change", c)
737
- });
738
- const {
739
- digits,
740
- formatter,
741
- displayPlaceholder,
742
- displayValue,
743
- full,
744
- fullFormatted,
745
- isComplete,
746
- isEmpty,
747
- shouldShowWarn
748
- } = useFormatter({
749
- country,
750
- value: model,
751
- onChange,
752
- onPhoneChange: (data) => emit("change", data),
753
- onValidationChange: (complete) => emit("validation-change", complete)
754
- });
755
- const { showValidationHint, clearValidationHint, scheduleValidationHint } = useValidationHint();
756
- const rootRef = vue.useTemplateRef("rootRef");
757
- const telRef = vue.useTemplateRef("telRef");
758
- const liveRef = vue.useTemplateRef("liveRef");
759
- const dropdownRef = vue.useTemplateRef("dropdownRef");
760
- const searchRef = vue.useTemplateRef("searchRef");
761
- const selectorRef = vue.useTemplateRef("selectorRef");
762
- const dropdownId = vue.getCurrentInstance()?.uid ?? 0;
763
- const listboxId = `pi-options-${dropdownId}`;
764
- const getOptionId = (idx) => `pi-option-${dropdownId}-${idx}`;
765
- const inactive = vue.computed(() => props.disabled || props.readonly);
766
- const incomplete = vue.computed(() => showValidationHint.value && shouldShowWarn.value);
767
- const showCopyButton = vue.computed(() => props.showCopy && !isEmpty.value && !props.disabled);
768
- const showClearButton = vue.computed(() => props.showClear && !isEmpty.value && !inactive.value);
769
- const { copied, copyAriaLabel, copyButtonTitle, onCopyClick } = useCopyAction({
770
- liveRef,
771
- fullFormatted,
772
- onCopy: (v) => emit("copy", v)
773
- });
774
- const focusInput = () => vue.nextTick(() => telRef.value?.focus());
775
- const {
776
- dropdownOpen,
777
- search,
778
- focusedIndex,
779
- dropdownStyle,
780
- filteredCountries,
781
- hasDropdown,
782
- closeDropdown,
783
- toggleDropdown,
784
- selectCountry,
785
- setFocusedIndex,
786
- handleSearchChange,
787
- handleSearchKeydown
788
- } = useCountrySelector({
789
- rootRef,
790
- dropdownRef,
791
- searchRef,
792
- selectorRef,
793
- locale,
794
- countryOption: () => props.country,
795
- inactive,
796
- onSelectCountry: setCountry2,
797
- onAfterSelect: focusInput
798
- });
799
- const activeOptionId = vue.computed(
800
- () => dropdownOpen.value && filteredCountries.value[focusedIndex.value] ? getOptionId(focusedIndex.value) : void 0
801
- );
802
- const { handleBeforeInput, handleInput, handleKeydown, handlePaste } = useInputHandlers({
803
- formatter,
804
- digits,
805
- inactive,
806
- onChange,
807
- scheduleValidationHint
808
- });
809
- const handleFocus = (e2) => {
810
- clearValidationHint(false);
811
- closeDropdown();
812
- emit("focus", e2);
813
- };
814
- const handleBlur = (e2) => emit("blur", e2);
815
- const clear = () => {
816
- onChange("");
817
- clearValidationHint();
818
- emit("clear");
819
- };
820
- const onClearClick = () => {
821
- clear();
822
- focusInput();
823
- };
824
- __expose({
825
- focus: focusInput,
826
- blur: () => telRef.value?.blur(),
827
- clear,
828
- selectCountry,
829
- getFullNumber: () => full.value,
830
- getFullFormattedNumber: () => fullFormatted.value,
831
- getDigits: () => digits.value,
832
- isValid: () => isComplete.value,
833
- isComplete: () => isComplete.value
834
- });
835
- const { themeClass } = useTheme({
836
- theme: () => props.theme
837
- });
838
- const rootClasses = vue.computed(() => [
839
- "phone-input",
840
- `size-${props.size}`,
841
- themeClass.value,
842
- {
843
- "is-disabled": props.disabled,
844
- "is-readonly": props.readonly,
845
- "is-unstyled": props.disableDefaultStyles,
846
- "is-incomplete": props.withValidity && incomplete.value,
847
- "is-complete": props.withValidity && isComplete.value
848
- }
849
- ]);
850
- const rootStyles = vue.computed(() => ({
851
- "--pi-actions-count": +showCopyButton.value + +showClearButton.value + (slots["actions-before"] ? 1 : 0)
852
- }));
853
- return (_ctx, _cache) => {
854
- return vue.openBlock(), vue.createElementBlock("div", {
855
- ref_key: "rootRef",
856
- ref: rootRef,
857
- "aria-label": "Phone input with country selector",
858
- role: "group",
859
- class: vue.normalizeClass(rootClasses.value),
860
- style: vue.normalizeStyle(rootStyles.value)
861
- }, [
862
- vue.createElementVNode("div", {
863
- ref_key: "selectorRef",
864
- ref: selectorRef,
865
- class: "pi-selector"
866
- }, [
867
- vue.createElementVNode("button", {
868
- type: "button",
869
- class: vue.normalizeClass(["pi-selector-btn", { "no-dropdown": !vue.unref(hasDropdown) || __props.readonly }]),
870
- disabled: __props.disabled,
871
- tabindex: inactive.value || !vue.unref(hasDropdown) ? -1 : void 0,
872
- "aria-label": `Selected country: ${vue.unref(country).name}`,
873
- "aria-expanded": vue.unref(dropdownOpen),
874
- "aria-haspopup": vue.unref(hasDropdown) ? "listbox" : void 0,
875
- onClick: _cache[0] || (_cache[0] = //@ts-ignore
876
- (...args) => vue.unref(toggleDropdown) && vue.unref(toggleDropdown)(...args))
877
- }, [
878
- vue.createElementVNode("span", {
879
- class: "pi-flag",
880
- role: "img",
881
- "aria-label": `${vue.unref(country).name} flag`
882
- }, [
883
- vue.renderSlot(_ctx.$slots, "flag", { country: vue.unref(country) }, () => [
884
- vue.createTextVNode(vue.toDisplayString(vue.unref(country).flag), 1)
885
- ], true)
886
- ], 8, _hoisted_2),
887
- vue.createElementVNode("span", _hoisted_3, vue.toDisplayString(vue.unref(country).code), 1),
888
- !inactive.value && vue.unref(hasDropdown) ? (vue.openBlock(), vue.createElementBlock("svg", {
889
- key: 0,
890
- class: vue.normalizeClass(["pi-chevron", { "is-open": vue.unref(dropdownOpen) }]),
891
- width: "12",
892
- height: "12",
893
- viewBox: "0 0 12 12",
894
- fill: "none",
895
- "aria-hidden": "true"
896
- }, [..._cache[8] || (_cache[8] = [
897
- vue.createElementVNode("path", {
898
- d: "M2.5 4.5L6 8L9.5 4.5",
899
- stroke: "currentColor",
900
- "stroke-width": "1.5",
901
- "stroke-linecap": "round",
902
- "stroke-linejoin": "round"
903
- }, null, -1)
904
- ])], 2)) : vue.createCommentVNode("", true)
905
- ], 10, _hoisted_1)
906
- ], 512),
907
- vue.createElementVNode("div", _hoisted_4, [
908
- vue.createElementVNode("input", {
909
- ref_key: "telRef",
910
- ref: telRef,
911
- type: "tel",
912
- inputmode: "tel",
913
- autocomplete: "tel-national",
914
- autocorrect: "off",
915
- autocapitalize: "off",
916
- spellcheck: "false",
917
- class: "pi-input",
918
- placeholder: vue.unref(displayPlaceholder),
919
- value: vue.unref(displayValue),
920
- disabled: __props.disabled,
921
- readonly: __props.readonly,
922
- "aria-invalid": incomplete.value,
923
- onBeforeinput: _cache[1] || (_cache[1] = //@ts-ignore
924
- (...args) => vue.unref(handleBeforeInput) && vue.unref(handleBeforeInput)(...args)),
925
- onInput: _cache[2] || (_cache[2] = //@ts-ignore
926
- (...args) => vue.unref(handleInput) && vue.unref(handleInput)(...args)),
927
- onKeydown: _cache[3] || (_cache[3] = //@ts-ignore
928
- (...args) => vue.unref(handleKeydown) && vue.unref(handleKeydown)(...args)),
929
- onPaste: _cache[4] || (_cache[4] = //@ts-ignore
930
- (...args) => vue.unref(handlePaste) && vue.unref(handlePaste)(...args)),
931
- onFocus: handleFocus,
932
- onBlur: handleBlur
933
- }, null, 40, _hoisted_5),
934
- vue.createElementVNode("div", _hoisted_6, [
935
- vue.createVNode(vue.Transition, { name: "fade-scale" }, {
936
- default: vue.withCtx(() => [
937
- vue.renderSlot(_ctx.$slots, "actions-before", {}, void 0, true)
938
- ]),
939
- _: 3
940
- }),
941
- vue.createVNode(vue.Transition, { name: "fade-scale" }, {
942
- default: vue.withCtx(() => [
943
- showCopyButton.value ? (vue.openBlock(), vue.createElementBlock("button", {
944
- key: 0,
945
- type: "button",
946
- class: vue.normalizeClass(["pi-btn", "pi-btn-copy", { "is-copied": vue.unref(copied) }]),
947
- "aria-label": vue.unref(copyAriaLabel),
948
- title: vue.unref(copyButtonTitle),
949
- onClick: _cache[5] || (_cache[5] = //@ts-ignore
950
- (...args) => vue.unref(onCopyClick) && vue.unref(onCopyClick)(...args))
951
- }, [
952
- slots["copy-svg"] ? vue.renderSlot(_ctx.$slots, "copy-svg", {
953
- key: 0,
954
- copied: vue.unref(copied)
955
- }, void 0, true) : !vue.unref(copied) ? (vue.openBlock(), vue.createElementBlock("svg", _hoisted_8, [..._cache[9] || (_cache[9] = [
956
- vue.createElementVNode("path", {
957
- d: "M13.5 5.5V13.5H5.5V5.5H13.5ZM13.5 4H5.5C4.67 4 4 4.67 4 5.5V13.5C4 14.33 4.67 15 5.5 15H13.5C14.33 15 15 14.33 15 13.5V5.5C15 4.67 14.33 4 13.5 4ZM10.5 1H2.5V11H4V2.5H10.5V1Z",
958
- fill: "currentColor"
959
- }, null, -1)
960
- ])])) : (vue.openBlock(), vue.createElementBlock("svg", _hoisted_9, [..._cache[10] || (_cache[10] = [
961
- vue.createElementVNode("path", {
962
- d: "M6.5 11.5L3 8L4.06 6.94L6.5 9.38L11.94 3.94L13 5L6.5 11.5Z",
963
- fill: "currentColor"
964
- }, null, -1)
965
- ])]))
966
- ], 10, _hoisted_7)) : vue.createCommentVNode("", true)
967
- ]),
968
- _: 3
969
- }),
970
- vue.createVNode(vue.Transition, { name: "fade-scale" }, {
971
- default: vue.withCtx(() => [
972
- showClearButton.value ? (vue.openBlock(), vue.createElementBlock("button", {
973
- key: 0,
974
- type: "button",
975
- class: "pi-btn pi-btn-clear",
976
- "aria-label": __props.clearButtonLabel,
977
- title: __props.clearButtonLabel,
978
- onClick: onClearClick
979
- }, [
980
- !slots["clear-svg"] ? (vue.openBlock(), vue.createElementBlock("svg", _hoisted_11, [..._cache[11] || (_cache[11] = [
981
- vue.createElementVNode("path", {
982
- d: "M14 1.41L12.59 0L7 5.59L1.41 0L0 1.41L5.59 7L0 12.59L1.41 14L7 8.41L12.59 14L14 12.59L8.41 7L14 1.41Z",
983
- fill: "currentColor"
984
- }, null, -1)
985
- ])])) : vue.renderSlot(_ctx.$slots, "clear-svg", { key: 1 }, void 0, true)
986
- ], 8, _hoisted_10)) : vue.createCommentVNode("", true)
987
- ]),
988
- _: 3
989
- })
990
- ])
991
- ]),
992
- (vue.openBlock(), vue.createBlock(vue.Teleport, { to: "body" }, [
993
- vue.createVNode(vue.Transition, { name: "dropdown" }, {
994
- default: vue.withCtx(() => [
995
- vue.unref(dropdownOpen) ? (vue.openBlock(), vue.createElementBlock("div", {
996
- key: 0,
997
- ref_key: "dropdownRef",
998
- ref: dropdownRef,
999
- class: vue.normalizeClass(["phone-dropdown", [__props.dropdownClass, vue.unref(themeClass)]]),
1000
- role: "dialog",
1001
- "aria-modal": "false",
1002
- "aria-label": "Select country",
1003
- style: vue.normalizeStyle(vue.unref(dropdownStyle))
1004
- }, [
1005
- vue.createElementVNode("div", _hoisted_12, [
1006
- vue.createElementVNode("input", {
1007
- ref_key: "searchRef",
1008
- ref: searchRef,
1009
- value: vue.unref(search),
1010
- type: "search",
1011
- class: "pi-search",
1012
- "aria-label": "Search countries",
1013
- "aria-controls": listboxId,
1014
- "aria-activedescendant": activeOptionId.value,
1015
- placeholder: __props.searchPlaceholder,
1016
- onKeydown: _cache[6] || (_cache[6] = //@ts-ignore
1017
- (...args) => vue.unref(handleSearchKeydown) && vue.unref(handleSearchKeydown)(...args)),
1018
- onInput: _cache[7] || (_cache[7] = //@ts-ignore
1019
- (...args) => vue.unref(handleSearchChange) && vue.unref(handleSearchChange)(...args))
1020
- }, null, 40, _hoisted_13)
1021
- ]),
1022
- vue.createElementVNode("ul", {
1023
- id: listboxId,
1024
- class: "pi-options",
1025
- role: "listbox",
1026
- tabindex: "-1"
1027
- }, [
1028
- (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(filteredCountries), (c, idx) => {
1029
- return vue.openBlock(), vue.createElementBlock("li", {
1030
- id: getOptionId(idx),
1031
- key: c.id,
1032
- role: "option",
1033
- class: vue.normalizeClass([
1034
- "pi-option",
1035
- {
1036
- "is-focused": idx === vue.unref(focusedIndex),
1037
- "is-selected": c.id === vue.unref(country).id
1038
- }
1039
- ]),
1040
- "aria-selected": c.id === vue.unref(country).id,
1041
- title: c.name,
1042
- onClick: ($event) => vue.unref(selectCountry)(c.id),
1043
- onMouseenter: ($event) => vue.unref(setFocusedIndex)(idx)
1044
- }, [
1045
- vue.createElementVNode("span", {
1046
- class: "pi-flag",
1047
- role: "img",
1048
- "aria-label": `${c.name} flag`
1049
- }, [
1050
- vue.renderSlot(_ctx.$slots, "flag", { country: c }, () => [
1051
- vue.createTextVNode(vue.toDisplayString(c.flag), 1)
1052
- ], true)
1053
- ], 8, _hoisted_15),
1054
- vue.createElementVNode("span", _hoisted_16, vue.toDisplayString(c.name), 1),
1055
- vue.createElementVNode("span", _hoisted_17, vue.toDisplayString(c.code), 1)
1056
- ], 42, _hoisted_14);
1057
- }), 128)),
1058
- vue.unref(filteredCountries).length === 0 ? (vue.openBlock(), vue.createElementBlock("li", _hoisted_18, vue.toDisplayString(__props.noResultsText), 1)) : vue.createCommentVNode("", true)
1059
- ])
1060
- ], 6)) : vue.createCommentVNode("", true)
1061
- ]),
1062
- _: 3
1063
- })
1064
- ])),
1065
- vue.createElementVNode("div", {
1066
- ref_key: "liveRef",
1067
- ref: liveRef,
1068
- class: "sr-only",
1069
- role: "status",
1070
- "aria-live": "polite",
1071
- "aria-atomic": "true"
1072
- }, null, 512)
1073
- ], 6);
1074
- };
1075
- }
1076
- });
1077
- const _export_sfc = (sfc, props) => {
1078
- const target = sfc.__vccOpts || sfc;
1079
- for (const [key, val] of props) {
1080
- target[key] = val;
1081
- }
1082
- return target;
1083
- };
1084
- const PhoneInput = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-d730aa54"]]);
1085
- function parseParams(params) {
1086
- if (typeof params === "string") return { country: params };
1087
- if (params && typeof params === "object") return params;
1088
- return {};
1089
- }
1090
- function updateDigits(el, state, digits) {
1091
- state.digits = digits;
1092
- el.value = state.formatter.formatDisplay(state.digits);
1093
- if (state.options.onChange) {
1094
- const fullNumberFormatted = el.value ? `${state.country.code} ${el.value}` : "";
1095
- const fullNumber = state.digits ? `${state.country.code}${state.digits}` : "";
1096
- state.options.onChange({
1097
- full: fullNumber,
1098
- fullFormatted: fullNumberFormatted,
1099
- digits: state.digits
1100
- });
1101
- }
1102
- }
1103
- function checkDigitsUpdate(el, state) {
1104
- const maxDigits = state.formatter.getMaxDigits();
1105
- const digits = extractDigits(el.value, maxDigits);
1106
- const displayValue = state.formatter.formatDisplay(digits);
1107
- if (digits !== state.digits || el.value !== displayValue) {
1108
- updateDigits(el, state, digits);
1109
- }
1110
- }
1111
- function checkCountryUpdate(el, state) {
1112
- const oldCountry = state.country.id;
1113
- const newCountry = parseCountryCode(state.options.country);
1114
- if (newCountry && newCountry !== oldCountry) {
1115
- setCountry(el, state, newCountry);
1116
- }
1117
- }
1118
- function createHandler(el, state, handler) {
1119
- return (e2) => {
1120
- const result = handler(e2, state);
1121
- if (!result) return;
1122
- updateDigits(el, state, result.newDigits);
1123
- vue.nextTick(() => {
1124
- const pos = state.formatter.getCaretPosition(result.caretDigitIndex);
1125
- setCaret(el, pos);
1126
- });
1127
- };
1128
- }
1129
- async function detectInitialCountry(options) {
1130
- const countryOption = parseCountryCode(options.country);
1131
- if (countryOption) return countryOption;
1132
- if (options.detect) {
1133
- const geoCountry = parseCountryCode(await detectByGeoIp());
1134
- if (geoCountry) return geoCountry;
1135
- const localeCountry = parseCountryCode(detectCountryFromLocale());
1136
- if (localeCountry) return localeCountry;
1137
- }
1138
- return "US";
1139
- }
1140
- function setCountry(el, state, newCountryCode) {
1141
- const parsed = parseCountryCode(newCountryCode);
1142
- if (!parsed) return;
1143
- const newCountry = getCountry(parsed, state.locale);
1144
- state.country = newCountry;
1145
- state.options.onCountryChange?.(newCountry);
1146
- state.formatter = createPhoneFormatter(newCountry);
1147
- el.placeholder = state.formatter.getPlaceholder();
1148
- checkDigitsUpdate(el, state);
1149
- }
1150
- const vPhoneMask = {
1151
- mounted(el, binding) {
1152
- if (el.tagName !== "INPUT") {
1153
- console.warn("[v-phone-mask] Directive can only be used on input elements");
1154
- return;
1155
- }
1156
- el.setAttribute("type", "tel");
1157
- el.setAttribute("inputmode", "tel");
1158
- el.setAttribute("placeholder", "");
1159
- const options = parseParams(binding.value);
1160
- const locale = options.locale || getNavigatorLang();
1161
- const country = getCountry(parseCountryCode(options.country, "US"), locale);
1162
- const state = {
1163
- country,
1164
- formatter: createPhoneFormatter(country),
1165
- digits: "",
1166
- locale,
1167
- options
1168
- };
1169
- el.__phoneMaskState = state;
1170
- state.inputHandler = createHandler(el, state, processInput);
1171
- state.keydownHandler = createHandler(el, state, processKeydown);
1172
- state.pasteHandler = createHandler(el, state, processPaste);
1173
- state.beforeInputHandler = processBeforeInput;
1174
- el.addEventListener("beforeinput", state.beforeInputHandler);
1175
- el.addEventListener("input", state.inputHandler);
1176
- el.addEventListener("keydown", state.keydownHandler);
1177
- el.addEventListener("paste", state.pasteHandler);
1178
- detectInitialCountry(options).then((countryCode) => {
1179
- if (el.__phoneMaskState !== state) return;
1180
- setCountry(el, state, countryCode);
1181
- });
1182
- },
1183
- updated(el, binding) {
1184
- const state = el.__phoneMaskState;
1185
- if (!state) return;
1186
- state.options = parseParams(binding.value);
1187
- checkCountryUpdate(el, state);
1188
- checkDigitsUpdate(el, state);
1189
- },
1190
- unmounted(el) {
1191
- const state = el.__phoneMaskState;
1192
- if (!state) return;
1193
- if (state.beforeInputHandler) el.removeEventListener("beforeinput", state.beforeInputHandler);
1194
- if (state.inputHandler) el.removeEventListener("input", state.inputHandler);
1195
- if (state.keydownHandler) el.removeEventListener("keydown", state.keydownHandler);
1196
- if (state.pasteHandler) el.removeEventListener("paste", state.pasteHandler);
1197
- delete el.__phoneMaskState;
1198
- }
1199
- };
1200
- function usePhoneMask(options) {
1201
- const inputRef = vue.shallowRef(null);
1202
- const { country, setCountry: setCountry2 } = useCountry({
1203
- country: options.country,
1204
- locale: options.locale,
1205
- detect: options.detect,
1206
- onCountryChange: options.onCountryChange
1207
- });
1208
- const {
1209
- digits,
1210
- formatter,
1211
- displayPlaceholder,
1212
- displayValue,
1213
- full,
1214
- fullFormatted,
1215
- isComplete,
1216
- isEmpty,
1217
- shouldShowWarn
1218
- } = useFormatter({
1219
- country,
1220
- value: options.value,
1221
- onChange: options.onChange,
1222
- onPhoneChange: options.onPhoneChange
1223
- });
1224
- const { handleBeforeInput, handleInput, handleKeydown, handlePaste } = useInputHandlers({
1225
- formatter,
1226
- digits,
1227
- onChange: options.onChange
1228
- });
1229
- vue.onMounted(() => {
1230
- const el = inputRef.value;
1231
- if (!el) return;
1232
- el.setAttribute("type", "tel");
1233
- el.setAttribute("inputmode", "tel");
1234
- });
1235
- vue.watchEffect(
1236
- () => {
1237
- const el = inputRef.value;
1238
- if (!el) return;
1239
- el.value = displayValue.value;
1240
- el.setAttribute("placeholder", displayPlaceholder.value);
1241
- },
1242
- { flush: "post" }
1243
- );
1244
- vue.onMounted(() => {
1245
- const el = inputRef.value;
1246
- if (!el) return;
1247
- el.addEventListener("beforeinput", handleBeforeInput);
1248
- el.addEventListener("input", handleInput);
1249
- el.addEventListener("keydown", handleKeydown);
1250
- el.addEventListener("paste", handlePaste);
1251
- });
1252
- vue.onUnmounted(() => {
1253
- const el = inputRef.value;
1254
- if (!el) return;
1255
- el.removeEventListener("beforeinput", handleBeforeInput);
1256
- el.removeEventListener("input", handleInput);
1257
- el.removeEventListener("keydown", handleKeydown);
1258
- el.removeEventListener("paste", handlePaste);
1259
- });
1260
- const clear = () => {
1261
- options.onChange("");
1262
- };
1263
- return {
1264
- inputRef,
1265
- digits,
1266
- formatter,
1267
- full,
1268
- fullFormatted,
1269
- isComplete,
1270
- isEmpty,
1271
- shouldShowWarn,
1272
- country,
1273
- setCountry: setCountry2,
1274
- clear
1275
- };
1276
- }
1277
- function install(app) {
1278
- app.component("PhoneInput", PhoneInput);
1279
- app.directive("phone-mask", vPhoneMask);
1280
- }
1281
- const index = {
1282
- install
1283
- };
1284
- const PMaskHelpers = {
1285
- getFlagEmoji: k,
1286
- countPlaceholders,
1287
- formatDigitsWithMap,
1288
- pickMaskVariant,
1289
- removeCountryCodePrefix,
1290
- toArray
1291
- };
1292
- exports.PMaskHelpers = PMaskHelpers;
1293
- exports.PhoneInput = PhoneInput;
1294
- exports.default = index;
1295
- exports.install = install;
1296
- exports.usePhoneMask = usePhoneMask;
1297
- exports.vPhoneMask = vPhoneMask;
1298
- exports.vPhoneMaskSetCountry = setCountry;
1299
- Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
1300
- return exports;
1301
- })({}, Vue);