@desource/phone-mask-vue 0.2.3 → 1.0.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/CHANGELOG.md +46 -0
- package/LICENSE +1 -1
- package/README.md +154 -11
- package/dist/index.cjs +858 -961
- package/dist/index.js +858 -961
- package/dist/index.mjs +859 -962
- package/dist/phone-mask-vue.css +64 -64
- package/dist/types/components/PhoneInput.vue.d.ts +7 -7
- package/dist/types/components/PhoneInput.vue.d.ts.map +1 -1
- package/dist/types/composables/internal/useCopyAction.d.ts +14 -0
- package/dist/types/composables/internal/useCopyAction.d.ts.map +1 -0
- package/dist/types/composables/internal/useCountry.d.ts +22 -0
- package/dist/types/composables/internal/useCountry.d.ts.map +1 -0
- package/dist/types/composables/internal/useCountrySelector.d.ts +30 -0
- package/dist/types/composables/internal/useCountrySelector.d.ts.map +1 -0
- package/dist/types/composables/internal/useFormatter.d.ts +46 -0
- package/dist/types/composables/internal/useFormatter.d.ts.map +1 -0
- package/dist/types/composables/internal/useInputHandlers.d.ts +20 -0
- package/dist/types/composables/internal/useInputHandlers.d.ts.map +1 -0
- package/dist/types/composables/internal/useTheme.d.ts +10 -0
- package/dist/types/composables/internal/useTheme.d.ts.map +1 -0
- package/dist/types/composables/internal/useValidationHint.d.ts +6 -0
- package/dist/types/composables/internal/useValidationHint.d.ts.map +1 -0
- package/dist/types/composables/usePhoneMask.d.ts +8 -0
- package/dist/types/composables/usePhoneMask.d.ts.map +1 -0
- package/dist/types/composables/{useClipboard.d.ts → utility/useClipboard.d.ts} +1 -2
- package/dist/types/composables/utility/useClipboard.d.ts.map +1 -0
- package/dist/types/composables/utility/useTimer.d.ts +9 -0
- package/dist/types/composables/utility/useTimer.d.ts.map +1 -0
- package/dist/types/directives/vPhoneMask.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/types.d.ts +31 -13
- package/dist/types/types.d.ts.map +1 -1
- package/package.json +18 -12
- package/dist/types/composables/useClipboard.d.ts.map +0 -1
- package/dist/types/composables/useCountrySelector.d.ts +0 -21
- package/dist/types/composables/useCountrySelector.d.ts.map +0 -1
- package/dist/types/composables/useMask.d.ts +0 -20
- package/dist/types/composables/useMask.d.ts.map +0 -1
- package/dist/types/composables/usePhoneFormatter.d.ts +0 -16
- package/dist/types/composables/usePhoneFormatter.d.ts.map +0 -1
- package/dist/types/consts.d.ts +0 -8
- package/dist/types/consts.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -2,66 +2,101 @@
|
|
|
2
2
|
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
3
|
const vue = require("vue");
|
|
4
4
|
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 #### ######"] };
|
|
5
|
-
const t$1 = /^[a-z]{2}$/i, countryCodeEmoji = (
|
|
6
|
-
if (!t$1.test(
|
|
7
|
-
const t2 = typeof
|
|
8
|
-
throw new TypeError(`cc argument must be an ISO 3166-1 alpha-2 string, but got '${"string" === t2 ?
|
|
5
|
+
const t$1 = /^[a-z]{2}$/i, countryCodeEmoji = (o2) => {
|
|
6
|
+
if (!t$1.test(o2)) {
|
|
7
|
+
const t2 = typeof o2;
|
|
8
|
+
throw new TypeError(`cc argument must be an ISO 3166-1 alpha-2 string, but got '${"string" === t2 ? o2 : t2}' instead.`);
|
|
9
9
|
}
|
|
10
|
-
const
|
|
11
|
-
return String.fromCodePoint(...
|
|
10
|
+
const e2 = [...o2.toUpperCase()].map((t2) => (t2.codePointAt(0) ?? 0) + 127397);
|
|
11
|
+
return String.fromCodePoint(...e2);
|
|
12
12
|
};
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
for (const
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
const o$1 = "en", n = /* @__PURE__ */ new Map(), getDisplayNames = (e2) => {
|
|
14
|
+
const t2 = e2.toLowerCase(), s2 = n.get(t2);
|
|
15
|
+
if (s2) return s2;
|
|
16
|
+
const r = new Intl.DisplayNames([e2], { type: "region" });
|
|
17
|
+
if (n.size >= 10) {
|
|
18
|
+
for (const e3 of n.keys()) if (e3 !== o$1) {
|
|
19
|
+
n.delete(e3);
|
|
20
|
+
break;
|
|
21
21
|
}
|
|
22
|
-
|
|
22
|
+
}
|
|
23
|
+
return n.set(t2, r), r;
|
|
24
|
+
}, s$1 = Object.entries(M), divideMask = (e2) => e2.split(/ (.*)/s);
|
|
25
|
+
function getCodeAndMask(e2) {
|
|
26
|
+
let t2 = "", o2 = "";
|
|
27
|
+
if (Array.isArray(e2)) {
|
|
28
|
+
const n2 = [];
|
|
29
|
+
for (const o3 of e2) {
|
|
30
|
+
const [e3, s2] = divideMask(o3);
|
|
31
|
+
t2 || (t2 = e3), n2.push(s2);
|
|
32
|
+
}
|
|
33
|
+
o2 = n2;
|
|
23
34
|
} else {
|
|
24
|
-
const [
|
|
25
|
-
|
|
35
|
+
const [n2, s2] = divideMask(e2);
|
|
36
|
+
t2 = n2, o2 = s2;
|
|
26
37
|
}
|
|
27
|
-
return [
|
|
38
|
+
return [t2, o2];
|
|
28
39
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const [
|
|
32
|
-
return
|
|
40
|
+
s$1.map(([e2, t2]) => ({ id: e2, mask: t2 }));
|
|
41
|
+
s$1.reduce((e2, [t2, o2]) => {
|
|
42
|
+
const [n2, s2] = getCodeAndMask(o2);
|
|
43
|
+
return e2[t2] = { code: n2, mask: s2 }, e2;
|
|
33
44
|
}, {});
|
|
34
|
-
|
|
35
|
-
const [
|
|
36
|
-
return { id:
|
|
45
|
+
s$1.map(([e2, t2]) => {
|
|
46
|
+
const [o2, n2] = getCodeAndMask(t2);
|
|
47
|
+
return { id: e2, code: o2, mask: n2 };
|
|
37
48
|
});
|
|
38
|
-
|
|
39
|
-
const [
|
|
40
|
-
return
|
|
49
|
+
s$1.reduce((e2, [o2, n2]) => {
|
|
50
|
+
const [s2, r] = getCodeAndMask(n2);
|
|
51
|
+
return e2[o2] = { code: s2, mask: r, flag: countryCodeEmoji(o2) }, e2;
|
|
41
52
|
}, {});
|
|
42
|
-
|
|
43
|
-
const [
|
|
44
|
-
return { id:
|
|
53
|
+
s$1.map(([e2, o2]) => {
|
|
54
|
+
const [n2, s2] = getCodeAndMask(o2);
|
|
55
|
+
return { id: e2, code: n2, mask: s2, flag: countryCodeEmoji(e2) };
|
|
45
56
|
});
|
|
46
|
-
const MasksFullMap = (
|
|
47
|
-
const
|
|
48
|
-
return
|
|
49
|
-
const [
|
|
50
|
-
return
|
|
57
|
+
const MasksFullMap = (e2) => {
|
|
58
|
+
const o2 = getDisplayNames(e2);
|
|
59
|
+
return s$1.reduce((e3, [n2, s2]) => {
|
|
60
|
+
const [r, a] = getCodeAndMask(s2), d = o2.of(n2) ?? "";
|
|
61
|
+
return e3[n2] = { code: r, mask: a, name: d, flag: countryCodeEmoji(n2) }, e3;
|
|
51
62
|
}, {});
|
|
52
|
-
}, MasksFull = (
|
|
53
|
-
const
|
|
54
|
-
return
|
|
55
|
-
const [
|
|
56
|
-
return { id:
|
|
63
|
+
}, MasksFull = (e2) => {
|
|
64
|
+
const o2 = getDisplayNames(e2);
|
|
65
|
+
return s$1.map(([e3, n2]) => {
|
|
66
|
+
const [s2, r] = getCodeAndMask(n2);
|
|
67
|
+
return { id: e3, code: s2, mask: r, name: o2.of(e3) ?? "", flag: countryCodeEmoji(e3) };
|
|
57
68
|
});
|
|
58
|
-
},
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
69
|
+
}, f = MasksFullMap(o$1);
|
|
70
|
+
MasksFull(o$1);
|
|
71
|
+
const k = countryCodeEmoji;
|
|
72
|
+
function getNavigatorLang() {
|
|
73
|
+
return "undefined" != typeof navigator && navigator.language || "en";
|
|
74
|
+
}
|
|
75
|
+
function detectCountryFromLocale() {
|
|
76
|
+
try {
|
|
77
|
+
const t2 = getNavigatorLang();
|
|
78
|
+
try {
|
|
79
|
+
const e3 = new Intl.Locale(t2);
|
|
80
|
+
if (e3.region) return e3.region.toUpperCase();
|
|
81
|
+
} catch {
|
|
82
|
+
}
|
|
83
|
+
const e2 = t2.split(/[-_]/);
|
|
84
|
+
if (e2.length > 1) return e2[1]?.toUpperCase() || null;
|
|
85
|
+
} catch {
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
function hasCountry(t2) {
|
|
90
|
+
const r = f;
|
|
91
|
+
return t2.toUpperCase() in r;
|
|
92
|
+
}
|
|
93
|
+
function getCountry(e2, r) {
|
|
94
|
+
const n2 = MasksFullMap(r), o2 = e2.toUpperCase();
|
|
95
|
+
return o2 in n2 ? { id: o2, ...n2[o2] } : { id: "US", ...n2.US };
|
|
96
|
+
}
|
|
97
|
+
function parseCountryCode(t2, e2) {
|
|
98
|
+
return t2 && hasCountry(t2) ? t2.toUpperCase() : e2 || "";
|
|
99
|
+
}
|
|
65
100
|
function toArray(t2) {
|
|
66
101
|
return Array.isArray(t2) ? t2 : [t2];
|
|
67
102
|
}
|
|
@@ -71,492 +106,488 @@ function countPlaceholders(t2) {
|
|
|
71
106
|
function removeCountryCodePrefix(t2) {
|
|
72
107
|
return t2.replace(/^\+\d+\s?/, "");
|
|
73
108
|
}
|
|
74
|
-
function pickMaskVariant(t2,
|
|
109
|
+
function pickMaskVariant(t2, e2) {
|
|
75
110
|
if (1 === t2.length) return t2[0];
|
|
76
|
-
const r = t2.map((t3) => ({ mask: t3, count: countPlaceholders(t3) })),
|
|
77
|
-
if (
|
|
78
|
-
const
|
|
79
|
-
return
|
|
111
|
+
const r = t2.map((t3) => ({ mask: t3, count: countPlaceholders(t3) })), n2 = r.filter((t3) => t3.count >= e2).sort((t3, e3) => t3.count - e3.count);
|
|
112
|
+
if (n2.length > 0) return n2[0].mask;
|
|
113
|
+
const o2 = r.sort((t3, e3) => e3.count - t3.count)[0];
|
|
114
|
+
return o2 ? o2.mask : t2[0];
|
|
80
115
|
}
|
|
81
|
-
function formatDigitsWithMap(t2,
|
|
116
|
+
function formatDigitsWithMap(t2, e2) {
|
|
82
117
|
let r = "";
|
|
83
|
-
const
|
|
84
|
-
let
|
|
85
|
-
const
|
|
86
|
-
for (let
|
|
87
|
-
const
|
|
88
|
-
if ("#" ===
|
|
89
|
-
if (!(
|
|
90
|
-
r +=
|
|
118
|
+
const n2 = [];
|
|
119
|
+
let o2 = 0;
|
|
120
|
+
const a = e2.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
|
+
r += e2[o2], n2.push(o2), o2++;
|
|
91
126
|
} else {
|
|
92
|
-
const
|
|
93
|
-
(r.length > 0 ||
|
|
127
|
+
const e3 = -1 !== t2.indexOf("#", c + 1) && o2 < a;
|
|
128
|
+
(r.length > 0 || e3) && (r += s3, n2.push(-1));
|
|
94
129
|
}
|
|
95
130
|
}
|
|
96
|
-
return { display: r, map:
|
|
131
|
+
return { display: r, map: n2 };
|
|
97
132
|
}
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if (b.score !== a.score) return b.score - a.score;
|
|
145
|
-
return a.country.name.localeCompare(b.country.name);
|
|
146
|
-
}).map(({ country }) => country);
|
|
147
|
-
});
|
|
148
|
-
const selectCountry = (id) => {
|
|
149
|
-
selectedId.value = id;
|
|
150
|
-
closeDropdown();
|
|
151
|
-
};
|
|
152
|
-
const toggleDropdown = async (searchRef) => {
|
|
153
|
-
dropdownOpened.value = !dropdownOpened.value;
|
|
154
|
-
if (!dropdownOpened.value) return;
|
|
155
|
-
await vue.nextTick();
|
|
156
|
-
searchRef.value?.focus({ preventScroll: true });
|
|
157
|
-
focusedIndex.value = 0;
|
|
158
|
-
};
|
|
159
|
-
const closeDropdown = () => {
|
|
160
|
-
dropdownOpened.value = false;
|
|
161
|
-
};
|
|
162
|
-
const focusNextOption = (scrollFn) => {
|
|
163
|
-
if (filteredCountries.value.length === 0) return;
|
|
164
|
-
focusedIndex.value = Math.min(filteredCountries.value.length - 1, focusedIndex.value + 1);
|
|
165
|
-
scrollFn?.();
|
|
166
|
-
};
|
|
167
|
-
const focusPrevOption = (scrollFn) => {
|
|
168
|
-
if (filteredCountries.value.length === 0) return;
|
|
169
|
-
focusedIndex.value = Math.max(0, focusedIndex.value - 1);
|
|
170
|
-
scrollFn?.();
|
|
171
|
-
};
|
|
172
|
-
const chooseFocusedOption = () => {
|
|
173
|
-
const item = filteredCountries.value[focusedIndex.value];
|
|
174
|
-
if (item) selectCountry(item.id);
|
|
175
|
-
};
|
|
176
|
-
const detectFromLocale = () => {
|
|
177
|
-
try {
|
|
178
|
-
const lang = navigator.language || "";
|
|
179
|
-
try {
|
|
180
|
-
const loc = new Intl.Locale(lang);
|
|
181
|
-
if (loc.region && hasCountry(loc.region)) return loc.region.toUpperCase();
|
|
182
|
-
} catch {
|
|
133
|
+
function filterCountries(t2, e2) {
|
|
134
|
+
const r = e2.trim().toUpperCase();
|
|
135
|
+
if (!r) return t2;
|
|
136
|
+
const n2 = r.replace(/\D/g, ""), o2 = n2.length > 0;
|
|
137
|
+
return t2.map((t3) => {
|
|
138
|
+
const e3 = t3.name.toUpperCase(), a = t3.id.toUpperCase(), s2 = t3.code.toUpperCase(), c = t3.code.replace(/\D/g, "");
|
|
139
|
+
let i2 = 0;
|
|
140
|
+
return e3.startsWith(r) ? i2 = 1e3 : e3.includes(r) && (i2 = 500), s2.startsWith(r) ? i2 += 100 : s2.includes(r) && (i2 += 50), a === r ? i2 += 200 : a.startsWith(r) && (i2 += 150), o2 && c.startsWith(n2) ? i2 += 80 : o2 && c.includes(n2) && (i2 += 40), { country: t3, score: i2 };
|
|
141
|
+
}).filter((t3) => t3.score > 0).sort((t3, e3) => e3.score !== t3.score ? e3.score - t3.score : t3.country.name.localeCompare(e3.country.name)).map((t3) => t3.country);
|
|
142
|
+
}
|
|
143
|
+
const t = [" ", "-", "(", ")"], e$1 = ["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End", "Tab"], i = /[^\d\s\-()]/;
|
|
144
|
+
function extractDigits(t2, e2) {
|
|
145
|
+
const i2 = t2.replace(/\D/g, "");
|
|
146
|
+
return e2 ? i2.slice(0, e2) : i2;
|
|
147
|
+
}
|
|
148
|
+
function getSelection(t2) {
|
|
149
|
+
return t2 ? [t2.selectionStart ?? 0, t2.selectionEnd ?? 0] : [0, 0];
|
|
150
|
+
}
|
|
151
|
+
function setCaret(t2, e2) {
|
|
152
|
+
if (t2) try {
|
|
153
|
+
t2.setSelectionRange(e2, e2);
|
|
154
|
+
} catch {
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function processBeforeInput(t2) {
|
|
158
|
+
if (!t2.target) return;
|
|
159
|
+
const e2 = t2.target, n2 = t2.data;
|
|
160
|
+
"insertText" === t2.inputType && n2 && (i.test(n2) || " " === n2 && e2.value.endsWith(" ")) && t2.preventDefault();
|
|
161
|
+
}
|
|
162
|
+
function processInput(t2, e2) {
|
|
163
|
+
if (!t2.target) return;
|
|
164
|
+
const i2 = t2.target, { formatter: n2 } = e2, r = n2.getMaxDigits(), s2 = extractDigits(i2.value, r);
|
|
165
|
+
return { newDigits: s2, caretDigitIndex: s2.length };
|
|
166
|
+
}
|
|
167
|
+
function processKeydown(i2, n2) {
|
|
168
|
+
if (!i2.target) return;
|
|
169
|
+
const r = i2.target, { digits: s2, formatter: c } = n2;
|
|
170
|
+
if (i2.ctrlKey || i2.metaKey || i2.altKey || e$1.includes(i2.key)) return;
|
|
171
|
+
const [g, a] = getSelection(r);
|
|
172
|
+
if ("Backspace" !== i2.key) if ("Delete" !== i2.key) /^[0-9]$/.test(i2.key) ? s2.length >= c.getMaxDigits() && i2.preventDefault() : 1 === i2.key.length && i2.preventDefault();
|
|
173
|
+
else {
|
|
174
|
+
if (i2.preventDefault(), g !== a) {
|
|
175
|
+
const t2 = c.getDigitRange(s2, g, a);
|
|
176
|
+
if (t2) {
|
|
177
|
+
const [e2, i3] = t2;
|
|
178
|
+
return { newDigits: s2.slice(0, e2) + s2.slice(i3), caretDigitIndex: e2 };
|
|
183
179
|
}
|
|
184
|
-
const parts = lang.split(/[-_]/);
|
|
185
|
-
if (parts.length > 1 && hasCountry(parts[1])) return parts[1].toUpperCase();
|
|
186
|
-
} catch {
|
|
187
180
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
if (cached) {
|
|
194
|
-
const parsed = JSON.parse(cached);
|
|
195
|
-
const isExpired = Date.now() - parsed.ts > CACHE_EXPIRY_MS;
|
|
196
|
-
if (!isExpired && parsed.country_code && hasCountry(parsed.country_code)) {
|
|
197
|
-
return parsed.country_code.toUpperCase();
|
|
198
|
-
}
|
|
199
|
-
if (isExpired) {
|
|
200
|
-
localStorage.removeItem(CACHE_KEY);
|
|
201
|
-
}
|
|
181
|
+
if (g < r.value.length) {
|
|
182
|
+
const t2 = c.getDigitRange(s2, g, r.value.length);
|
|
183
|
+
if (t2) {
|
|
184
|
+
const [e2] = t2;
|
|
185
|
+
return { newDigits: s2.slice(0, e2) + s2.slice(e2 + 1), caretDigitIndex: e2 };
|
|
202
186
|
}
|
|
203
|
-
} catch {
|
|
204
187
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (!res.ok) {
|
|
213
|
-
return null;
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
if (i2.preventDefault(), g !== a) {
|
|
191
|
+
const t2 = c.getDigitRange(s2, g, a);
|
|
192
|
+
if (t2) {
|
|
193
|
+
const [e2, i3] = t2;
|
|
194
|
+
return { newDigits: s2.slice(0, e2) + s2.slice(i3), caretDigitIndex: e2 };
|
|
214
195
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
196
|
+
}
|
|
197
|
+
if (g > 0) {
|
|
198
|
+
const e2 = r.value;
|
|
199
|
+
let i3 = g - 1;
|
|
200
|
+
for (; i3 >= 0 && t.includes(e2[i3]); ) i3--;
|
|
201
|
+
if (i3 >= 0) {
|
|
202
|
+
const t2 = c.getDigitRange(s2, i3, i3 + 1);
|
|
203
|
+
if (t2) {
|
|
204
|
+
const [e3] = t2;
|
|
205
|
+
return { newDigits: s2.slice(0, e3) + s2.slice(e3 + 1), caretDigitIndex: e3 };
|
|
221
206
|
}
|
|
222
|
-
return code;
|
|
223
207
|
}
|
|
224
|
-
} catch {
|
|
225
|
-
} finally {
|
|
226
|
-
clearTimeout(timeoutId);
|
|
227
208
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
if (!detect) return;
|
|
242
|
-
const geo = await detectByGeoIp();
|
|
243
|
-
if (geo) {
|
|
244
|
-
selectInitialCountry(geo, emitFn);
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
const loc = detectFromLocale();
|
|
248
|
-
if (loc) {
|
|
249
|
-
selectInitialCountry(loc, emitFn);
|
|
250
|
-
return;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function processPaste(t2, e2) {
|
|
212
|
+
if (!t2.target) return;
|
|
213
|
+
t2.preventDefault();
|
|
214
|
+
const i2 = t2.target, { digits: n2, formatter: r } = e2, s2 = t2.clipboardData?.getData("text") || "", c = r.getMaxDigits(), g = extractDigits(s2, c);
|
|
215
|
+
if (0 === g.length) return;
|
|
216
|
+
const [a, o2] = getSelection(i2);
|
|
217
|
+
if (a !== o2) {
|
|
218
|
+
const t3 = r.getDigitRange(n2, a, o2);
|
|
219
|
+
if (t3) {
|
|
220
|
+
const [e3, i3] = t3;
|
|
221
|
+
return { newDigits: extractDigits(n2.slice(0, e3) + g + n2.slice(i3), c), caretDigitIndex: e3 + g.length };
|
|
251
222
|
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
selectedId,
|
|
256
|
-
selected,
|
|
257
|
-
hasCountry,
|
|
258
|
-
// Dropdown
|
|
259
|
-
hasDropdown,
|
|
260
|
-
dropdownOpened,
|
|
261
|
-
search,
|
|
262
|
-
focusedIndex,
|
|
263
|
-
filteredCountries,
|
|
264
|
-
selectCountry,
|
|
265
|
-
toggleDropdown,
|
|
266
|
-
closeDropdown,
|
|
267
|
-
focusNextOption,
|
|
268
|
-
focusPrevOption,
|
|
269
|
-
chooseFocusedOption,
|
|
270
|
-
// Country Detection
|
|
271
|
-
initCountry
|
|
272
|
-
};
|
|
223
|
+
}
|
|
224
|
+
const l = r.getDigitRange(n2, 0, a), f2 = l ? l[1] : 0;
|
|
225
|
+
return { newDigits: extractDigits(n2.slice(0, f2) + g + n2.slice(f2), c), caretDigitIndex: f2 + g.length };
|
|
273
226
|
}
|
|
274
|
-
function createPhoneFormatter(
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
const getMask = (digitLength) => {
|
|
279
|
-
const mask = pickMaskVariant(variants, digitLength);
|
|
280
|
-
return removeCountryCodePrefix(mask);
|
|
227
|
+
function createPhoneFormatter(o2) {
|
|
228
|
+
const a = toArray(o2.mask), i2 = a.map((n2) => countPlaceholders(removeCountryCodePrefix(n2))), g = Math.max(...i2), getMask = (t2) => {
|
|
229
|
+
const n2 = pickMaskVariant(a, t2);
|
|
230
|
+
return removeCountryCodePrefix(n2);
|
|
281
231
|
};
|
|
282
|
-
return {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
},
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
298
|
-
if (digitIndex >= map.length) return display.length;
|
|
299
|
-
for (let i2 = 0; i2 < map.length; i2++) {
|
|
300
|
-
if (map[i2] > digitIndex) return i2;
|
|
301
|
-
}
|
|
302
|
-
return display.length;
|
|
303
|
-
},
|
|
304
|
-
getDigitRange: (digits, selStart, selEnd) => {
|
|
305
|
-
const template = getMask(digits.length);
|
|
306
|
-
const { map } = formatDigitsWithMap(template, digits);
|
|
307
|
-
let min = Infinity;
|
|
308
|
-
let max = -Infinity;
|
|
309
|
-
for (let i2 = selStart; i2 < selEnd && i2 < map.length; i2++) {
|
|
310
|
-
const digitIdx = map[i2];
|
|
311
|
-
if (digitIdx !== void 0 && digitIdx >= 0) {
|
|
312
|
-
min = Math.min(min, digitIdx);
|
|
313
|
-
max = Math.max(max, digitIdx);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
return min === Infinity ? null : [min, max + 1];
|
|
317
|
-
},
|
|
318
|
-
isComplete: (digits) => {
|
|
319
|
-
return variantsDigits.includes(digits.length);
|
|
232
|
+
return { formatDisplay: (t2) => {
|
|
233
|
+
const e2 = getMask(t2.length);
|
|
234
|
+
return formatDigitsWithMap(e2, t2).display;
|
|
235
|
+
}, getMaxDigits: () => g, getPlaceholder: () => getMask(0), getCaretPosition: (t2) => {
|
|
236
|
+
const e2 = getMask(t2), { display: r, map: l } = formatDigitsWithMap(e2, "0".repeat(t2));
|
|
237
|
+
for (let e3 = 0; e3 < l.length; e3++) if (l[e3] === t2) return e3;
|
|
238
|
+
if (t2 >= l.length) return r.length;
|
|
239
|
+
for (let e3 = 0; e3 < l.length; e3++) if (l[e3] > t2) return e3;
|
|
240
|
+
return r.length;
|
|
241
|
+
}, getDigitRange: (t2, e2, r) => {
|
|
242
|
+
const l = getMask(t2.length), { map: o3 } = formatDigitsWithMap(l, t2);
|
|
243
|
+
let a2 = 1 / 0, i3 = -1 / 0;
|
|
244
|
+
for (let t3 = e2; t3 < r && t3 < o3.length; t3++) {
|
|
245
|
+
const e3 = o3[t3];
|
|
246
|
+
void 0 !== e3 && e3 >= 0 && (a2 = Math.min(a2, e3), i3 = Math.max(i3, e3));
|
|
320
247
|
}
|
|
321
|
-
|
|
248
|
+
return a2 === 1 / 0 ? null : [a2, i3 + 1];
|
|
249
|
+
}, isComplete: (t2) => i2.includes(t2.length) };
|
|
322
250
|
}
|
|
323
|
-
|
|
324
|
-
|
|
251
|
+
const o = "https://ipapi.co/json/", e = 1500, p = "@desource/phone-mask:geo", s = 864e5;
|
|
252
|
+
async function detectCountryFromGeoIP(t2 = o, r = e) {
|
|
253
|
+
const n2 = new AbortController(), c = setTimeout(() => n2.abort(), r);
|
|
325
254
|
try {
|
|
326
|
-
|
|
255
|
+
const o2 = await fetch(t2, { signal: n2.signal, headers: { Accept: "application/json" } });
|
|
256
|
+
if (clearTimeout(c), !o2.ok) return null;
|
|
257
|
+
const e2 = await o2.json();
|
|
258
|
+
return (e2.country || e2.country_code || e2.countryCode || e2.country_code2 || "").toString().toUpperCase() || null;
|
|
327
259
|
} catch {
|
|
260
|
+
return clearTimeout(c), null;
|
|
328
261
|
}
|
|
329
262
|
}
|
|
330
|
-
function
|
|
331
|
-
|
|
332
|
-
|
|
263
|
+
async function detectByGeoIp() {
|
|
264
|
+
try {
|
|
265
|
+
const o3 = localStorage.getItem(p);
|
|
266
|
+
if (o3) {
|
|
267
|
+
const e3 = JSON.parse(o3), c = Date.now() - e3.ts > s, a = parseCountryCode(e3.country_code);
|
|
268
|
+
if (a && !c) return a;
|
|
269
|
+
localStorage.removeItem(p);
|
|
270
|
+
}
|
|
271
|
+
} catch {
|
|
272
|
+
}
|
|
273
|
+
const o2 = await detectCountryFromGeoIP(), e2 = parseCountryCode(o2);
|
|
274
|
+
if (e2) {
|
|
275
|
+
try {
|
|
276
|
+
const t2 = JSON.stringify({ country_code: e2, ts: Date.now() });
|
|
277
|
+
localStorage.setItem(p, t2);
|
|
278
|
+
} catch {
|
|
279
|
+
}
|
|
280
|
+
return e2;
|
|
281
|
+
}
|
|
282
|
+
return null;
|
|
333
283
|
}
|
|
334
|
-
function
|
|
335
|
-
|
|
336
|
-
|
|
284
|
+
function useCountry({
|
|
285
|
+
country: countryOption,
|
|
286
|
+
locale: localeOption,
|
|
287
|
+
detect,
|
|
288
|
+
onCountryChange
|
|
289
|
+
} = {}) {
|
|
290
|
+
const locale = vue.computed(() => vue.toValue(localeOption) || getNavigatorLang());
|
|
291
|
+
const countryCode = vue.ref(parseCountryCode(vue.toValue(countryOption), "US"));
|
|
292
|
+
const country = vue.computed(() => getCountry(countryCode.value, locale.value));
|
|
293
|
+
const setCountry = (code) => {
|
|
294
|
+
const parsed = parseCountryCode(code);
|
|
295
|
+
if (parsed) {
|
|
296
|
+
countryCode.value = parsed;
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
return false;
|
|
300
|
+
};
|
|
301
|
+
const detectCountry = async () => {
|
|
302
|
+
const geoCountry = await detectByGeoIp();
|
|
303
|
+
if (setCountry(geoCountry)) return;
|
|
304
|
+
const localeCountry = detectCountryFromLocale();
|
|
305
|
+
setCountry(localeCountry);
|
|
306
|
+
};
|
|
307
|
+
vue.watchEffect(() => {
|
|
308
|
+
const newCountry = vue.toValue(countryOption);
|
|
309
|
+
if (newCountry && newCountry !== countryCode.value) {
|
|
310
|
+
setCountry(newCountry);
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
vue.watchEffect(() => {
|
|
314
|
+
if (vue.toValue(detect) && !vue.toValue(countryOption)) {
|
|
315
|
+
detectCountry();
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
vue.watchEffect(() => {
|
|
319
|
+
onCountryChange?.(country.value);
|
|
320
|
+
});
|
|
321
|
+
return { country, setCountry, locale };
|
|
337
322
|
}
|
|
338
|
-
function
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
323
|
+
function useFormatter({
|
|
324
|
+
country,
|
|
325
|
+
value,
|
|
326
|
+
onChange,
|
|
327
|
+
onPhoneChange,
|
|
328
|
+
onValidationChange
|
|
329
|
+
}) {
|
|
330
|
+
const formatter = vue.computed(() => createPhoneFormatter(vue.toValue(country)));
|
|
331
|
+
const maxDigits = vue.computed(() => formatter.value.getMaxDigits());
|
|
332
|
+
const digits = vue.computed(() => extractDigits(vue.toValue(value), maxDigits.value));
|
|
344
333
|
const displayPlaceholder = vue.computed(() => formatter.value.getPlaceholder());
|
|
334
|
+
const displayValue = vue.computed(() => formatter.value.formatDisplay(digits.value));
|
|
335
|
+
const full = vue.computed(() => digits.value ? `${vue.toValue(country).code}${digits.value}` : "");
|
|
336
|
+
const fullFormatted = vue.computed(() => displayValue.value ? `${vue.toValue(country).code} ${displayValue.value}` : "");
|
|
345
337
|
const isComplete = vue.computed(() => formatter.value.isComplete(digits.value));
|
|
346
338
|
const isEmpty = vue.computed(() => digits.value.length === 0);
|
|
347
|
-
const
|
|
348
|
-
const
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
339
|
+
const shouldShowWarn = vue.computed(() => !isEmpty.value && !isComplete.value);
|
|
340
|
+
const phoneData = vue.computed(() => ({
|
|
341
|
+
full: full.value,
|
|
342
|
+
fullFormatted: fullFormatted.value,
|
|
343
|
+
digits: digits.value
|
|
344
|
+
}));
|
|
345
|
+
vue.watchEffect(() => {
|
|
346
|
+
if (vue.toValue(value) !== digits.value) {
|
|
347
|
+
onChange(digits.value);
|
|
348
|
+
}
|
|
352
349
|
});
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
return `${selected.value.code}${digits.value}`;
|
|
350
|
+
vue.watchEffect(() => {
|
|
351
|
+
onPhoneChange?.(phoneData.value);
|
|
356
352
|
});
|
|
357
|
-
|
|
358
|
-
|
|
353
|
+
vue.watchEffect(() => {
|
|
354
|
+
onValidationChange?.(isComplete.value);
|
|
355
|
+
});
|
|
356
|
+
return {
|
|
357
|
+
digits,
|
|
358
|
+
formatter,
|
|
359
|
+
displayPlaceholder,
|
|
360
|
+
displayValue,
|
|
361
|
+
full,
|
|
362
|
+
fullFormatted,
|
|
363
|
+
isComplete,
|
|
364
|
+
isEmpty,
|
|
365
|
+
shouldShowWarn
|
|
359
366
|
};
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
367
|
+
}
|
|
368
|
+
function useTimer() {
|
|
369
|
+
let timerRef = null;
|
|
370
|
+
const clear = () => {
|
|
371
|
+
if (timerRef) {
|
|
372
|
+
clearTimeout(timerRef);
|
|
373
|
+
timerRef = null;
|
|
374
|
+
}
|
|
363
375
|
};
|
|
364
|
-
const
|
|
365
|
-
|
|
366
|
-
|
|
376
|
+
const set = (callback, delay) => {
|
|
377
|
+
clear();
|
|
378
|
+
timerRef = setTimeout(callback, delay);
|
|
367
379
|
};
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
380
|
+
vue.onUnmounted(clear);
|
|
381
|
+
return { set, clear };
|
|
382
|
+
}
|
|
383
|
+
function useValidationHint() {
|
|
384
|
+
const showValidationHint = vue.ref(false);
|
|
385
|
+
const validationTimer = useTimer();
|
|
386
|
+
const clearValidationHint = (hideHint = true) => {
|
|
387
|
+
if (hideHint) showValidationHint.value = false;
|
|
388
|
+
validationTimer.clear();
|
|
376
389
|
};
|
|
377
|
-
const
|
|
378
|
-
const el = e.target;
|
|
379
|
-
if (!el) return;
|
|
380
|
-
const newDigits = extractDigits(el.value, maxDigits.value);
|
|
390
|
+
const scheduleValidationHint = (delay) => {
|
|
381
391
|
showValidationHint.value = false;
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
+
validationTimer.set(() => {
|
|
393
|
+
showValidationHint.value = true;
|
|
394
|
+
}, delay);
|
|
395
|
+
};
|
|
396
|
+
return { showValidationHint, clearValidationHint, scheduleValidationHint };
|
|
397
|
+
}
|
|
398
|
+
const HINT_DELAY_INPUT = 500;
|
|
399
|
+
const HINT_DELAY_ACTION = 300;
|
|
400
|
+
function useInputHandlers(options) {
|
|
401
|
+
const { formatter, digits, inactive, onChange, scheduleValidationHint } = options;
|
|
402
|
+
const scheduleCaretUpdate = (el, digitIndex) => {
|
|
392
403
|
vue.nextTick(() => {
|
|
393
|
-
|
|
404
|
+
if (!el) return;
|
|
405
|
+
const pos = vue.toValue(formatter).getCaretPosition(digitIndex);
|
|
406
|
+
setCaret(el, pos);
|
|
394
407
|
});
|
|
395
408
|
};
|
|
396
|
-
const
|
|
397
|
-
|
|
398
|
-
if (!el) return;
|
|
399
|
-
if (e.ctrlKey || e.metaKey || e.altKey || NavigationKeys.includes(e.key)) return;
|
|
400
|
-
const [selStart, selEnd] = getSelection(el);
|
|
401
|
-
if (e.key === "Backspace") {
|
|
402
|
-
e.preventDefault();
|
|
403
|
-
if (selStart !== selEnd) {
|
|
404
|
-
const range = formatter.value.getDigitRange(digits.value, selStart, selEnd);
|
|
405
|
-
if (range) {
|
|
406
|
-
const [start, end] = range;
|
|
407
|
-
removeDigitsRange(start, end);
|
|
408
|
-
updateDisplay2();
|
|
409
|
-
vue.nextTick(() => setCaretToDigitPosition(start));
|
|
410
|
-
}
|
|
411
|
-
return;
|
|
412
|
-
}
|
|
413
|
-
if (selStart > 0) {
|
|
414
|
-
const displayStr = displayValue.value;
|
|
415
|
-
let prevPos = selStart - 1;
|
|
416
|
-
while (prevPos >= 0 && Delimiters.includes(displayStr[prevPos])) {
|
|
417
|
-
prevPos--;
|
|
418
|
-
}
|
|
419
|
-
if (prevPos >= 0) {
|
|
420
|
-
const range = formatter.value.getDigitRange(digits.value, prevPos, prevPos + 1);
|
|
421
|
-
if (range) {
|
|
422
|
-
const [start] = range;
|
|
423
|
-
removeDigitsRange(start, start + 1);
|
|
424
|
-
updateDisplay2();
|
|
425
|
-
vue.nextTick(() => setCaretToDigitPosition(start));
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
return;
|
|
430
|
-
}
|
|
431
|
-
if (e.key === "Delete") {
|
|
432
|
-
e.preventDefault();
|
|
433
|
-
if (selStart !== selEnd) {
|
|
434
|
-
const range = formatter.value.getDigitRange(digits.value, selStart, selEnd);
|
|
435
|
-
if (range) {
|
|
436
|
-
const [start, end] = range;
|
|
437
|
-
removeDigitsRange(start, end);
|
|
438
|
-
updateDisplay2();
|
|
439
|
-
vue.nextTick(() => setCaretToDigitPosition(start));
|
|
440
|
-
}
|
|
441
|
-
return;
|
|
442
|
-
}
|
|
443
|
-
if (selStart < displayValue.value.length) {
|
|
444
|
-
const range = formatter.value.getDigitRange(digits.value, selStart, selStart + 1);
|
|
445
|
-
if (range) {
|
|
446
|
-
const [start] = range;
|
|
447
|
-
removeDigitsRange(start, start + 1);
|
|
448
|
-
updateDisplay2();
|
|
449
|
-
vue.nextTick(() => setCaretToDigitPosition(start));
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
return;
|
|
453
|
-
}
|
|
454
|
-
if (/^[0-9]$/.test(e.key)) {
|
|
455
|
-
if (digits.value.length >= maxDigits.value) {
|
|
456
|
-
e.preventDefault();
|
|
457
|
-
}
|
|
458
|
-
return;
|
|
459
|
-
}
|
|
460
|
-
if (e.key.length === 1) {
|
|
461
|
-
e.preventDefault();
|
|
462
|
-
}
|
|
409
|
+
const handleBeforeInput = (e2) => {
|
|
410
|
+
processBeforeInput(e2);
|
|
463
411
|
};
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
412
|
+
const handleInput = (e2) => {
|
|
413
|
+
if (vue.toValue(inactive)) return;
|
|
414
|
+
const result = processInput(e2, { formatter: vue.toValue(formatter) });
|
|
415
|
+
if (!result) return;
|
|
416
|
+
onChange?.(result.newDigits);
|
|
417
|
+
scheduleCaretUpdate(e2.target, result.caretDigitIndex);
|
|
418
|
+
scheduleValidationHint?.(HINT_DELAY_INPUT);
|
|
419
|
+
};
|
|
420
|
+
const handleKeydown = (e2) => {
|
|
421
|
+
if (vue.toValue(inactive)) return;
|
|
422
|
+
const result = processKeydown(e2, { digits: vue.toValue(digits), formatter: vue.toValue(formatter) });
|
|
423
|
+
if (!result) return;
|
|
424
|
+
onChange?.(result.newDigits);
|
|
425
|
+
scheduleCaretUpdate(e2.target, result.caretDigitIndex);
|
|
426
|
+
scheduleValidationHint?.(HINT_DELAY_ACTION);
|
|
427
|
+
};
|
|
428
|
+
const handlePaste = (e2) => {
|
|
429
|
+
if (vue.toValue(inactive)) return;
|
|
430
|
+
const result = processPaste(e2, { digits: vue.toValue(digits), formatter: vue.toValue(formatter) });
|
|
431
|
+
if (!result) return;
|
|
432
|
+
onChange?.(result.newDigits);
|
|
433
|
+
scheduleCaretUpdate(e2.target, result.caretDigitIndex);
|
|
434
|
+
scheduleValidationHint?.(HINT_DELAY_ACTION);
|
|
435
|
+
};
|
|
436
|
+
return {
|
|
437
|
+
handleBeforeInput,
|
|
438
|
+
handleInput,
|
|
439
|
+
handleKeydown,
|
|
440
|
+
handlePaste
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
function useCountrySelector({
|
|
444
|
+
rootRef,
|
|
445
|
+
dropdownRef,
|
|
446
|
+
searchRef,
|
|
447
|
+
selectorRef,
|
|
448
|
+
locale,
|
|
449
|
+
countryOption,
|
|
450
|
+
inactive,
|
|
451
|
+
onSelectCountry,
|
|
452
|
+
onAfterSelect
|
|
453
|
+
}) {
|
|
454
|
+
const search = vue.ref("");
|
|
455
|
+
const dropdownOpen = vue.ref(false);
|
|
456
|
+
const dropdownStyle = vue.shallowRef({});
|
|
457
|
+
const focusedIndex = vue.ref(0);
|
|
458
|
+
const countries = vue.computed(() => MasksFull(vue.toValue(locale)));
|
|
459
|
+
const filteredCountries = vue.computed(() => filterCountries(countries.value, search.value));
|
|
460
|
+
const hasDropdown = vue.computed(() => !vue.toValue(countryOption) && countries.value.length > 1);
|
|
461
|
+
const setFocusedIndex = (index2) => {
|
|
462
|
+
focusedIndex.value = index2;
|
|
463
|
+
};
|
|
464
|
+
const focusSearch = () => {
|
|
465
|
+
vue.nextTick(() => searchRef.value?.focus({ preventScroll: true }));
|
|
466
|
+
};
|
|
467
|
+
const closeDropdown = () => {
|
|
468
|
+
dropdownOpen.value = false;
|
|
469
|
+
};
|
|
470
|
+
const openDropdown = () => {
|
|
471
|
+
dropdownOpen.value = true;
|
|
472
|
+
setFocusedIndex(0);
|
|
473
|
+
focusSearch();
|
|
474
|
+
};
|
|
475
|
+
const toggleDropdown = () => {
|
|
476
|
+
if (vue.toValue(inactive) || !hasDropdown.value) return;
|
|
477
|
+
if (dropdownOpen.value) {
|
|
478
|
+
closeDropdown();
|
|
479
|
+
} else {
|
|
480
|
+
openDropdown();
|
|
468
481
|
}
|
|
469
|
-
handleKeydownInternal(e);
|
|
470
|
-
if (validationTimer.value) clearTimeout(validationTimer.value);
|
|
471
|
-
validationTimer.value = setTimeout(() => {
|
|
472
|
-
if (!isComplete.value && !isEmpty.value) showValidationHint.value = true;
|
|
473
|
-
}, 300);
|
|
474
482
|
};
|
|
475
|
-
const
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
483
|
+
const selectCountry = (code) => {
|
|
484
|
+
onSelectCountry(code);
|
|
485
|
+
closeDropdown();
|
|
486
|
+
search.value = "";
|
|
487
|
+
setFocusedIndex(0);
|
|
488
|
+
onAfterSelect?.();
|
|
489
|
+
};
|
|
490
|
+
const handleSearchChange = (e2) => {
|
|
491
|
+
search.value = e2.target.value;
|
|
492
|
+
setFocusedIndex(0);
|
|
493
|
+
};
|
|
494
|
+
const onDocClick = (ev) => {
|
|
495
|
+
const target = ev.target;
|
|
496
|
+
const dropdownEl = dropdownRef.value;
|
|
497
|
+
const selectorEl = selectorRef.value;
|
|
498
|
+
if (!target) return;
|
|
499
|
+
if (dropdownEl?.contains(target)) return;
|
|
500
|
+
if (selectorEl?.contains(target)) return;
|
|
501
|
+
closeDropdown();
|
|
502
|
+
};
|
|
503
|
+
const positionDropdown = (e2) => {
|
|
504
|
+
if (e2?.type === "scroll" && e2.target && dropdownRef.value?.contains(e2.target)) return;
|
|
505
|
+
if (!rootRef.value) return;
|
|
506
|
+
const rect = rootRef.value.getBoundingClientRect();
|
|
507
|
+
dropdownStyle.value = {
|
|
508
|
+
top: `${rect.bottom + window.scrollY + 8}px`,
|
|
509
|
+
left: `${rect.left + window.scrollX}px`,
|
|
510
|
+
width: `${rect.width}px`
|
|
511
|
+
};
|
|
512
|
+
};
|
|
513
|
+
const scrollFocusedIntoView = () => {
|
|
514
|
+
vue.nextTick(() => {
|
|
515
|
+
const list = dropdownRef.value?.lastElementChild;
|
|
516
|
+
const option = list?.children[focusedIndex.value];
|
|
517
|
+
if (!list || !option) return;
|
|
518
|
+
const listRect = list.getBoundingClientRect();
|
|
519
|
+
const optionRect = option.getBoundingClientRect();
|
|
520
|
+
let scrollAmount = 0;
|
|
521
|
+
if (optionRect.top < listRect.top) {
|
|
522
|
+
scrollAmount = list.scrollTop - (listRect.top - optionRect.top);
|
|
523
|
+
} else if (optionRect.bottom > listRect.bottom) {
|
|
524
|
+
scrollAmount = list.scrollTop + (optionRect.bottom - listRect.bottom);
|
|
525
|
+
} else {
|
|
492
526
|
return;
|
|
493
527
|
}
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
const insertIndex = range ? range[0] : digits.value.length;
|
|
497
|
-
const left = digits.value.slice(0, insertIndex);
|
|
498
|
-
const right = digits.value.slice(insertIndex);
|
|
499
|
-
digits.value = extractDigits(left + pastedDigits + right, maxDigits.value);
|
|
500
|
-
updateDisplay2();
|
|
501
|
-
if (validationTimer.value) clearTimeout(validationTimer.value);
|
|
502
|
-
validationTimer.value = setTimeout(() => {
|
|
503
|
-
if (!isComplete.value && !isEmpty.value) showValidationHint.value = true;
|
|
504
|
-
}, 300);
|
|
505
|
-
vue.nextTick(() => setCaretToDigitPosition(insertIndex + pastedDigits.length));
|
|
528
|
+
list.scrollTo({ top: scrollAmount, behavior: "smooth" });
|
|
529
|
+
});
|
|
506
530
|
};
|
|
507
|
-
const
|
|
508
|
-
if (
|
|
509
|
-
|
|
531
|
+
const handleSearchKeydown = (e2) => {
|
|
532
|
+
if (e2.key === "ArrowDown") {
|
|
533
|
+
e2.preventDefault();
|
|
534
|
+
setFocusedIndex(Math.min(focusedIndex.value + 1, filteredCountries.value.length - 1));
|
|
535
|
+
scrollFocusedIntoView();
|
|
536
|
+
} else if (e2.key === "ArrowUp") {
|
|
537
|
+
e2.preventDefault();
|
|
538
|
+
setFocusedIndex(Math.max(focusedIndex.value - 1, 0));
|
|
539
|
+
scrollFocusedIntoView();
|
|
540
|
+
} else if (e2.key === "Enter" && filteredCountries.value[focusedIndex.value]) {
|
|
541
|
+
e2.preventDefault();
|
|
542
|
+
selectCountry(filteredCountries.value[focusedIndex.value].id);
|
|
543
|
+
} else if (e2.key === "Escape") {
|
|
544
|
+
closeDropdown();
|
|
510
545
|
}
|
|
511
546
|
};
|
|
512
|
-
const
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
if (validationTimer.value) {
|
|
517
|
-
clearTimeout(validationTimer.value);
|
|
518
|
-
validationTimer.value = null;
|
|
519
|
-
}
|
|
547
|
+
const removeListeners = () => {
|
|
548
|
+
window.removeEventListener("resize", positionDropdown);
|
|
549
|
+
window.removeEventListener("scroll", positionDropdown, true);
|
|
550
|
+
window.removeEventListener("click", onDocClick, true);
|
|
520
551
|
};
|
|
521
|
-
vue.watch(
|
|
522
|
-
if (
|
|
523
|
-
|
|
552
|
+
vue.watch(hasDropdown, (dropdownExists) => {
|
|
553
|
+
if (!dropdownExists && dropdownOpen.value) {
|
|
554
|
+
closeDropdown();
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
vue.watch(dropdownOpen, (isOpen) => {
|
|
558
|
+
if (!isOpen) {
|
|
559
|
+
removeListeners();
|
|
560
|
+
return;
|
|
524
561
|
}
|
|
525
|
-
|
|
562
|
+
positionDropdown();
|
|
563
|
+
window.addEventListener("resize", positionDropdown);
|
|
564
|
+
window.addEventListener("scroll", positionDropdown, true);
|
|
565
|
+
window.addEventListener("click", onDocClick, true);
|
|
526
566
|
});
|
|
527
|
-
|
|
567
|
+
vue.onBeforeUnmount(removeListeners);
|
|
528
568
|
return {
|
|
529
569
|
// State
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
// Methods
|
|
546
|
-
updateDisplayFromDigits: updateDisplay2,
|
|
547
|
-
clear
|
|
570
|
+
dropdownOpen,
|
|
571
|
+
search,
|
|
572
|
+
focusedIndex,
|
|
573
|
+
dropdownStyle,
|
|
574
|
+
// Derived
|
|
575
|
+
filteredCountries,
|
|
576
|
+
hasDropdown,
|
|
577
|
+
// Actions
|
|
578
|
+
openDropdown,
|
|
579
|
+
closeDropdown,
|
|
580
|
+
toggleDropdown,
|
|
581
|
+
selectCountry,
|
|
582
|
+
setFocusedIndex,
|
|
583
|
+
handleSearchChange,
|
|
584
|
+
handleSearchKeydown
|
|
548
585
|
};
|
|
549
586
|
}
|
|
550
|
-
function useClipboard() {
|
|
587
|
+
function useClipboard(delay = 1800) {
|
|
551
588
|
const copied = vue.ref(false);
|
|
552
589
|
const isCopying = vue.ref(false);
|
|
553
|
-
|
|
554
|
-
const clearTimer = () => {
|
|
555
|
-
if (copyTimer) {
|
|
556
|
-
clearTimeout(copyTimer);
|
|
557
|
-
copyTimer = null;
|
|
558
|
-
}
|
|
559
|
-
};
|
|
590
|
+
const copyTimer = useTimer();
|
|
560
591
|
const copy = async (text) => {
|
|
561
592
|
if (isCopying.value) return false;
|
|
562
593
|
const trimmedText = text.trim();
|
|
@@ -565,11 +596,9 @@ function useClipboard() {
|
|
|
565
596
|
try {
|
|
566
597
|
await navigator.clipboard.writeText(trimmedText);
|
|
567
598
|
copied.value = true;
|
|
568
|
-
|
|
569
|
-
copyTimer = setTimeout(() => {
|
|
599
|
+
copyTimer.set(() => {
|
|
570
600
|
copied.value = false;
|
|
571
|
-
|
|
572
|
-
}, 1800);
|
|
601
|
+
}, delay);
|
|
573
602
|
return true;
|
|
574
603
|
} catch (err) {
|
|
575
604
|
console.warn("Copy failed", err);
|
|
@@ -578,24 +607,71 @@ function useClipboard() {
|
|
|
578
607
|
isCopying.value = false;
|
|
579
608
|
}
|
|
580
609
|
};
|
|
581
|
-
|
|
582
|
-
|
|
610
|
+
return { copied, isCopying, copy };
|
|
611
|
+
}
|
|
612
|
+
const DELAY = 1800;
|
|
613
|
+
function useCopyAction({ liveRef, fullFormatted, onCopy }) {
|
|
614
|
+
const liveTimer = useTimer();
|
|
615
|
+
const { copied, copy } = useClipboard(DELAY);
|
|
616
|
+
const copyAriaLabel = vue.computed(() => copied.value ? "Copied" : `Copy ${fullFormatted.value}`);
|
|
617
|
+
const copyButtonTitle = vue.computed(() => copied.value ? "Copied" : "Copy phone number");
|
|
618
|
+
const announceToScreenReader = (message) => {
|
|
619
|
+
if (!liveRef?.value) return;
|
|
620
|
+
liveRef.value.textContent = message;
|
|
621
|
+
liveTimer.set(() => {
|
|
622
|
+
if (liveRef.value) liveRef.value.textContent = "";
|
|
623
|
+
}, DELAY);
|
|
624
|
+
};
|
|
625
|
+
const onCopyClick = async () => {
|
|
626
|
+
const valueToCopy = fullFormatted.value.trim();
|
|
627
|
+
const success = await copy(valueToCopy);
|
|
628
|
+
if (success) {
|
|
629
|
+
onCopy?.(valueToCopy);
|
|
630
|
+
announceToScreenReader("Phone number copied to clipboard");
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
return {
|
|
634
|
+
copied,
|
|
635
|
+
copyAriaLabel,
|
|
636
|
+
copyButtonTitle,
|
|
637
|
+
onCopyClick
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
function useTheme({ theme }) {
|
|
641
|
+
const systemDark = vue.ref(false);
|
|
642
|
+
const themeClass = vue.computed(() => {
|
|
643
|
+
return vue.toValue(theme) !== "auto" ? `theme-${vue.toValue(theme)}` : systemDark.value ? "theme-dark" : "theme-light";
|
|
644
|
+
});
|
|
645
|
+
let mq = null;
|
|
646
|
+
const handler = (e2) => {
|
|
647
|
+
systemDark.value = e2.matches;
|
|
648
|
+
};
|
|
649
|
+
vue.onBeforeMount(() => {
|
|
650
|
+
if (typeof window === "undefined") return;
|
|
651
|
+
mq = window.matchMedia?.("(prefers-color-scheme: dark)") ?? null;
|
|
652
|
+
if (!mq) return;
|
|
653
|
+
systemDark.value = mq.matches;
|
|
654
|
+
mq.addEventListener("change", handler);
|
|
655
|
+
});
|
|
656
|
+
vue.onBeforeUnmount(() => {
|
|
657
|
+
mq?.removeEventListener("change", handler);
|
|
658
|
+
});
|
|
659
|
+
return {
|
|
660
|
+
themeClass
|
|
583
661
|
};
|
|
584
|
-
return { copied, isCopying, copy, onUnmount };
|
|
585
662
|
}
|
|
586
|
-
const _hoisted_1 =
|
|
587
|
-
const _hoisted_2 = ["
|
|
588
|
-
const _hoisted_3 =
|
|
589
|
-
const _hoisted_4 = { class: "pi-
|
|
590
|
-
const _hoisted_5 =
|
|
591
|
-
const _hoisted_6 =
|
|
592
|
-
const _hoisted_7 = {
|
|
663
|
+
const _hoisted_1 = ["disabled", "tabindex", "aria-label", "aria-expanded", "aria-haspopup"];
|
|
664
|
+
const _hoisted_2 = ["aria-label"];
|
|
665
|
+
const _hoisted_3 = { class: "pi-code" };
|
|
666
|
+
const _hoisted_4 = { class: "pi-input-wrap" };
|
|
667
|
+
const _hoisted_5 = ["placeholder", "value", "disabled", "readonly", "aria-invalid"];
|
|
668
|
+
const _hoisted_6 = {
|
|
593
669
|
class: "pi-actions",
|
|
594
670
|
role: "toolbar",
|
|
595
671
|
"aria-label": "Phone input actions"
|
|
596
672
|
};
|
|
597
|
-
const
|
|
598
|
-
const
|
|
673
|
+
const _hoisted_7 = ["aria-label", "title"];
|
|
674
|
+
const _hoisted_8 = {
|
|
599
675
|
key: 1,
|
|
600
676
|
width: "16",
|
|
601
677
|
height: "16",
|
|
@@ -603,7 +679,7 @@ const _hoisted_9 = {
|
|
|
603
679
|
fill: "none",
|
|
604
680
|
"aria-hidden": "true"
|
|
605
681
|
};
|
|
606
|
-
const
|
|
682
|
+
const _hoisted_9 = {
|
|
607
683
|
key: 2,
|
|
608
684
|
width: "16",
|
|
609
685
|
height: "16",
|
|
@@ -611,8 +687,8 @@ const _hoisted_10 = {
|
|
|
611
687
|
fill: "none",
|
|
612
688
|
"aria-hidden": "true"
|
|
613
689
|
};
|
|
614
|
-
const
|
|
615
|
-
const
|
|
690
|
+
const _hoisted_10 = ["aria-label", "title"];
|
|
691
|
+
const _hoisted_11 = {
|
|
616
692
|
key: 0,
|
|
617
693
|
width: "11",
|
|
618
694
|
height: "11",
|
|
@@ -620,14 +696,14 @@ const _hoisted_12 = {
|
|
|
620
696
|
fill: "none",
|
|
621
697
|
"aria-hidden": "true"
|
|
622
698
|
};
|
|
623
|
-
const
|
|
624
|
-
const
|
|
625
|
-
const
|
|
626
|
-
const
|
|
627
|
-
const
|
|
628
|
-
const
|
|
629
|
-
const
|
|
630
|
-
const
|
|
699
|
+
const _hoisted_12 = { class: "pi-search-wrap" };
|
|
700
|
+
const _hoisted_13 = ["value", "placeholder"];
|
|
701
|
+
const _hoisted_14 = ["aria-activedescendant"];
|
|
702
|
+
const _hoisted_15 = ["id", "aria-selected", "title", "onClick", "onMouseenter"];
|
|
703
|
+
const _hoisted_16 = ["aria-label"];
|
|
704
|
+
const _hoisted_17 = { class: "pi-opt-name" };
|
|
705
|
+
const _hoisted_18 = { class: "pi-opt-code" };
|
|
706
|
+
const _hoisted_19 = {
|
|
631
707
|
key: 0,
|
|
632
708
|
class: "pi-empty"
|
|
633
709
|
};
|
|
@@ -650,242 +726,133 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
650
726
|
dropdownClass: {},
|
|
651
727
|
disableDefaultStyles: { type: Boolean, default: false }
|
|
652
728
|
}, {
|
|
653
|
-
"modelValue": {},
|
|
729
|
+
"modelValue": { default: "" },
|
|
654
730
|
"modelModifiers": {}
|
|
655
731
|
}),
|
|
656
732
|
emits: /* @__PURE__ */ vue.mergeModels(["change", "country-change", "validation-change", "focus", "blur", "copy", "clear"], ["update:modelValue"]),
|
|
657
733
|
setup(__props, { expose: __expose, emit: __emit }) {
|
|
658
734
|
const props = __props;
|
|
659
735
|
const slots = vue.useSlots();
|
|
660
|
-
const model = vue.useModel(__props, "modelValue");
|
|
661
736
|
const emit = __emit;
|
|
737
|
+
const model = vue.useModel(__props, "modelValue");
|
|
738
|
+
const onChange = (v) => {
|
|
739
|
+
model.value = v;
|
|
740
|
+
};
|
|
741
|
+
const { country, setCountry, locale } = useCountry({
|
|
742
|
+
country: () => props.country,
|
|
743
|
+
locale: () => props.locale,
|
|
744
|
+
detect: () => props.detect,
|
|
745
|
+
onCountryChange: (c) => emit("country-change", c)
|
|
746
|
+
});
|
|
747
|
+
const {
|
|
748
|
+
digits,
|
|
749
|
+
formatter,
|
|
750
|
+
displayPlaceholder,
|
|
751
|
+
displayValue,
|
|
752
|
+
full,
|
|
753
|
+
fullFormatted,
|
|
754
|
+
isComplete,
|
|
755
|
+
isEmpty,
|
|
756
|
+
shouldShowWarn
|
|
757
|
+
} = useFormatter({
|
|
758
|
+
country,
|
|
759
|
+
value: model,
|
|
760
|
+
onChange,
|
|
761
|
+
onPhoneChange: (data) => emit("change", data),
|
|
762
|
+
onValidationChange: (complete) => emit("validation-change", complete)
|
|
763
|
+
});
|
|
764
|
+
const { showValidationHint, clearValidationHint, scheduleValidationHint } = useValidationHint();
|
|
662
765
|
const rootRef = vue.useTemplateRef("rootRef");
|
|
663
766
|
const telRef = vue.useTemplateRef("telRef");
|
|
664
|
-
const searchRef = vue.useTemplateRef("searchRef");
|
|
665
767
|
const liveRef = vue.useTemplateRef("liveRef");
|
|
666
768
|
const dropdownRef = vue.useTemplateRef("dropdownRef");
|
|
667
|
-
const
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
769
|
+
const searchRef = vue.useTemplateRef("searchRef");
|
|
770
|
+
const selectorRef = vue.useTemplateRef("selectorRef");
|
|
771
|
+
const inactive = vue.computed(() => props.disabled || props.readonly);
|
|
772
|
+
const incomplete = vue.computed(() => showValidationHint.value && shouldShowWarn.value);
|
|
773
|
+
const showCopyButton = vue.computed(() => props.showCopy && !isEmpty.value && !props.disabled);
|
|
774
|
+
const showClearButton = vue.computed(() => props.showClear && !isEmpty.value && !inactive.value);
|
|
775
|
+
const { copied, copyAriaLabel, copyButtonTitle, onCopyClick } = useCopyAction({
|
|
776
|
+
liveRef,
|
|
777
|
+
fullFormatted,
|
|
778
|
+
onCopy: (v) => emit("copy", v)
|
|
673
779
|
});
|
|
674
|
-
const
|
|
675
|
-
const countrySelector = useCountrySelector(usedLocale);
|
|
780
|
+
const focusInput = () => vue.nextTick(() => telRef.value?.focus());
|
|
676
781
|
const {
|
|
782
|
+
dropdownOpen,
|
|
677
783
|
search,
|
|
678
|
-
filteredCountries,
|
|
679
784
|
focusedIndex,
|
|
680
|
-
|
|
681
|
-
|
|
785
|
+
dropdownStyle,
|
|
786
|
+
filteredCountries,
|
|
682
787
|
hasDropdown,
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
788
|
+
closeDropdown,
|
|
789
|
+
toggleDropdown,
|
|
790
|
+
selectCountry,
|
|
791
|
+
setFocusedIndex,
|
|
792
|
+
handleSearchChange,
|
|
793
|
+
handleSearchKeydown
|
|
794
|
+
} = useCountrySelector({
|
|
795
|
+
rootRef,
|
|
796
|
+
dropdownRef,
|
|
797
|
+
searchRef,
|
|
798
|
+
selectorRef,
|
|
799
|
+
locale,
|
|
800
|
+
countryOption: () => props.country,
|
|
801
|
+
inactive,
|
|
802
|
+
onSelectCountry: setCountry,
|
|
803
|
+
onAfterSelect: focusInput
|
|
804
|
+
});
|
|
805
|
+
const { handleBeforeInput, handleInput, handleKeydown, handlePaste } = useInputHandlers({
|
|
806
|
+
formatter,
|
|
807
|
+
digits,
|
|
808
|
+
inactive,
|
|
809
|
+
onChange,
|
|
810
|
+
scheduleValidationHint
|
|
811
|
+
});
|
|
812
|
+
const handleFocus = (e2) => {
|
|
813
|
+
clearValidationHint(false);
|
|
814
|
+
closeDropdown();
|
|
815
|
+
emit("focus", e2);
|
|
816
|
+
};
|
|
817
|
+
const handleBlur = (e2) => emit("blur", e2);
|
|
818
|
+
const clear = () => {
|
|
819
|
+
onChange("");
|
|
820
|
+
clearValidationHint();
|
|
821
|
+
emit("clear");
|
|
822
|
+
};
|
|
823
|
+
const onClearClick = () => {
|
|
824
|
+
clear();
|
|
825
|
+
focusInput();
|
|
826
|
+
};
|
|
827
|
+
__expose({
|
|
828
|
+
focus: focusInput,
|
|
829
|
+
blur: () => telRef.value?.blur(),
|
|
830
|
+
clear,
|
|
831
|
+
selectCountry,
|
|
832
|
+
getFullNumber: () => full.value,
|
|
833
|
+
getFullFormattedNumber: () => fullFormatted.value,
|
|
834
|
+
getDigits: () => digits.value,
|
|
835
|
+
isValid: () => isComplete.value,
|
|
836
|
+
isComplete: () => isComplete.value
|
|
837
|
+
});
|
|
838
|
+
const { themeClass } = useTheme({
|
|
839
|
+
theme: () => props.theme
|
|
704
840
|
});
|
|
705
841
|
const rootClasses = vue.computed(() => [
|
|
706
842
|
"phone-input",
|
|
707
|
-
|
|
843
|
+
`size-${props.size}`,
|
|
708
844
|
themeClass.value,
|
|
709
845
|
{
|
|
710
846
|
"is-disabled": props.disabled,
|
|
711
847
|
"is-readonly": props.readonly,
|
|
712
848
|
"is-unstyled": props.disableDefaultStyles,
|
|
713
|
-
"is-incomplete": props.withValidity &&
|
|
849
|
+
"is-incomplete": props.withValidity && incomplete.value,
|
|
714
850
|
"is-complete": props.withValidity && isComplete.value
|
|
715
851
|
}
|
|
716
852
|
]);
|
|
717
853
|
const rootStyles = vue.computed(() => ({
|
|
718
854
|
"--pi-actions-count": +showCopyButton.value + +showClearButton.value + (slots["actions-before"] ? 1 : 0)
|
|
719
855
|
}));
|
|
720
|
-
const emitModelUpdate = () => {
|
|
721
|
-
if (model.value === digits.value) return;
|
|
722
|
-
model.value = digits.value;
|
|
723
|
-
emit("change", {
|
|
724
|
-
full: full.value,
|
|
725
|
-
fullFormatted: fullFormatted.value,
|
|
726
|
-
digits: digits.value
|
|
727
|
-
});
|
|
728
|
-
};
|
|
729
|
-
const onInput = async (e) => {
|
|
730
|
-
if (inactive.value) return;
|
|
731
|
-
mask.handleInput(e);
|
|
732
|
-
await vue.nextTick();
|
|
733
|
-
emitModelUpdate();
|
|
734
|
-
};
|
|
735
|
-
const onKeydown = async (e) => {
|
|
736
|
-
if (inactive.value) return;
|
|
737
|
-
mask.handleKeydown(e);
|
|
738
|
-
await vue.nextTick();
|
|
739
|
-
emitModelUpdate();
|
|
740
|
-
};
|
|
741
|
-
const onPaste = async (e) => {
|
|
742
|
-
if (inactive.value) return;
|
|
743
|
-
mask.handlePaste(e);
|
|
744
|
-
await vue.nextTick();
|
|
745
|
-
emitModelUpdate();
|
|
746
|
-
};
|
|
747
|
-
const onFocus = (e) => {
|
|
748
|
-
mask.handleFocus();
|
|
749
|
-
dropdownOpened.value = false;
|
|
750
|
-
emit("focus", e);
|
|
751
|
-
};
|
|
752
|
-
const onBlur = (e) => emit("blur", e);
|
|
753
|
-
const onSelectCountry = async (countryId) => {
|
|
754
|
-
countrySelector.selectCountry(countryId);
|
|
755
|
-
emit("country-change", selected.value);
|
|
756
|
-
await vue.nextTick();
|
|
757
|
-
telRef.value?.focus();
|
|
758
|
-
};
|
|
759
|
-
const onCopyClick = async () => {
|
|
760
|
-
const valueToCopy = fullFormatted.value;
|
|
761
|
-
const success = await copy(valueToCopy);
|
|
762
|
-
if (success) {
|
|
763
|
-
emit("copy", valueToCopy);
|
|
764
|
-
}
|
|
765
|
-
};
|
|
766
|
-
const onClearClick = async () => {
|
|
767
|
-
mask.clear();
|
|
768
|
-
model.value = "";
|
|
769
|
-
emit("change", {
|
|
770
|
-
full: "",
|
|
771
|
-
fullFormatted: "",
|
|
772
|
-
digits: ""
|
|
773
|
-
});
|
|
774
|
-
emit("clear");
|
|
775
|
-
await vue.nextTick();
|
|
776
|
-
telRef.value?.focus();
|
|
777
|
-
};
|
|
778
|
-
const positionDropdown = (e) => {
|
|
779
|
-
if (e?.type === "scroll" && e.target && dropdownRef.value?.contains(e.target)) return;
|
|
780
|
-
const root = rootRef.value;
|
|
781
|
-
if (!root) return;
|
|
782
|
-
const rect = root.getBoundingClientRect();
|
|
783
|
-
dropdownStyle.value = {
|
|
784
|
-
top: `${rect.bottom + window.scrollY + 8}px`,
|
|
785
|
-
left: `${rect.left + window.scrollX}px`,
|
|
786
|
-
width: `${rect.width}px`
|
|
787
|
-
};
|
|
788
|
-
};
|
|
789
|
-
const removeDropdownListeners = () => {
|
|
790
|
-
window.removeEventListener("scroll", positionDropdown, true);
|
|
791
|
-
window.removeEventListener("click", onDocClick, true);
|
|
792
|
-
window.removeEventListener("resize", positionDropdown);
|
|
793
|
-
};
|
|
794
|
-
const toggleDropdown = async () => {
|
|
795
|
-
if (inactive.value || !hasDropdown.value) return;
|
|
796
|
-
await countrySelector.toggleDropdown(searchRef);
|
|
797
|
-
if (dropdownOpened.value) {
|
|
798
|
-
positionDropdown();
|
|
799
|
-
window.addEventListener("scroll", positionDropdown, true);
|
|
800
|
-
window.addEventListener("click", onDocClick, true);
|
|
801
|
-
window.addEventListener("resize", positionDropdown);
|
|
802
|
-
} else {
|
|
803
|
-
removeDropdownListeners();
|
|
804
|
-
}
|
|
805
|
-
};
|
|
806
|
-
const scrollFocusedIntoView = async () => {
|
|
807
|
-
await vue.nextTick();
|
|
808
|
-
const list = dropdownRef.value?.lastElementChild;
|
|
809
|
-
if (!list) return;
|
|
810
|
-
const option = list.children[focusedIndex.value];
|
|
811
|
-
if (!option) return;
|
|
812
|
-
const listRect = list.getBoundingClientRect();
|
|
813
|
-
const optionRect = option.getBoundingClientRect();
|
|
814
|
-
let scrollAmount = 0;
|
|
815
|
-
if (optionRect.top < listRect.top) {
|
|
816
|
-
scrollAmount = list.scrollTop - (listRect.top - optionRect.top);
|
|
817
|
-
} else if (optionRect.bottom > listRect.bottom) {
|
|
818
|
-
scrollAmount = list.scrollTop + (optionRect.bottom - listRect.bottom);
|
|
819
|
-
} else {
|
|
820
|
-
return;
|
|
821
|
-
}
|
|
822
|
-
list.scrollTo({ top: scrollAmount, behavior: "smooth" });
|
|
823
|
-
};
|
|
824
|
-
const onDocClick = (ev) => {
|
|
825
|
-
const dropdown = dropdownRef.value;
|
|
826
|
-
const selector = rootRef.value?.firstChild;
|
|
827
|
-
if (!(dropdown || selector)) return;
|
|
828
|
-
const target = ev.target;
|
|
829
|
-
if (!target || dropdown?.contains(target) || selector?.contains(target)) return;
|
|
830
|
-
dropdownOpened.value = false;
|
|
831
|
-
};
|
|
832
|
-
vue.watch(
|
|
833
|
-
model,
|
|
834
|
-
(newValue) => {
|
|
835
|
-
if (!newValue) {
|
|
836
|
-
if (!isEmpty.value) mask.clear();
|
|
837
|
-
return;
|
|
838
|
-
}
|
|
839
|
-
const currentDigits = digits.value;
|
|
840
|
-
if (newValue !== currentDigits) {
|
|
841
|
-
const incomingDigits = newValue.replace(/\D/g, "");
|
|
842
|
-
if (incomingDigits !== currentDigits) {
|
|
843
|
-
digits.value = incomingDigits;
|
|
844
|
-
mask.updateDisplayFromDigits();
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
},
|
|
848
|
-
{ immediate: true }
|
|
849
|
-
);
|
|
850
|
-
vue.watch(
|
|
851
|
-
[() => props.country, () => props.detect],
|
|
852
|
-
async ([country, detect]) => {
|
|
853
|
-
await vue.nextTick();
|
|
854
|
-
await countrySelector.initCountry(country, detect, () => emit("country-change", selected.value));
|
|
855
|
-
},
|
|
856
|
-
{ immediate: true }
|
|
857
|
-
);
|
|
858
|
-
vue.watch(
|
|
859
|
-
copyMessage,
|
|
860
|
-
(val) => {
|
|
861
|
-
if (liveRef.value && val) {
|
|
862
|
-
liveRef.value.textContent = val;
|
|
863
|
-
}
|
|
864
|
-
},
|
|
865
|
-
{ flush: "post" }
|
|
866
|
-
);
|
|
867
|
-
vue.watch(
|
|
868
|
-
isComplete,
|
|
869
|
-
(valid) => {
|
|
870
|
-
emit("validation-change", valid);
|
|
871
|
-
},
|
|
872
|
-
{ flush: "post" }
|
|
873
|
-
);
|
|
874
|
-
vue.onBeforeUnmount(() => {
|
|
875
|
-
removeDropdownListeners();
|
|
876
|
-
onClipboardUnmount();
|
|
877
|
-
});
|
|
878
|
-
__expose({
|
|
879
|
-
focus: () => telRef.value?.focus(),
|
|
880
|
-
blur: () => telRef.value?.blur(),
|
|
881
|
-
clear: mask.clear,
|
|
882
|
-
selectCountry: countrySelector.selectCountry,
|
|
883
|
-
getFullNumber: () => full.value,
|
|
884
|
-
getFullFormattedNumber: () => fullFormatted.value,
|
|
885
|
-
getDigits: () => digits.value,
|
|
886
|
-
isValid: () => isComplete.value,
|
|
887
|
-
isComplete: () => isComplete.value
|
|
888
|
-
});
|
|
889
856
|
return (_ctx, _cache) => {
|
|
890
857
|
return vue.openBlock(), vue.createElementBlock("div", {
|
|
891
858
|
ref_key: "rootRef",
|
|
@@ -895,36 +862,41 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
895
862
|
class: vue.normalizeClass(rootClasses.value),
|
|
896
863
|
style: vue.normalizeStyle(rootStyles.value)
|
|
897
864
|
}, [
|
|
898
|
-
vue.createElementVNode("div",
|
|
865
|
+
vue.createElementVNode("div", {
|
|
866
|
+
ref_key: "selectorRef",
|
|
867
|
+
ref: selectorRef,
|
|
868
|
+
class: "pi-selector"
|
|
869
|
+
}, [
|
|
899
870
|
vue.createElementVNode("button", {
|
|
900
871
|
type: "button",
|
|
901
872
|
class: vue.normalizeClass(["pi-selector-btn", { "no-dropdown": !vue.unref(hasDropdown) || __props.readonly }]),
|
|
902
873
|
disabled: __props.disabled,
|
|
903
874
|
tabindex: inactive.value || !vue.unref(hasDropdown) ? -1 : void 0,
|
|
904
|
-
"aria-label": `Selected country: ${vue.unref(
|
|
905
|
-
"aria-expanded": vue.unref(
|
|
875
|
+
"aria-label": `Selected country: ${vue.unref(country).name}`,
|
|
876
|
+
"aria-expanded": vue.unref(dropdownOpen),
|
|
906
877
|
"aria-haspopup": vue.unref(hasDropdown) ? "listbox" : void 0,
|
|
907
|
-
onClick:
|
|
878
|
+
onClick: _cache[0] || (_cache[0] = //@ts-ignore
|
|
879
|
+
(...args) => vue.unref(toggleDropdown) && vue.unref(toggleDropdown)(...args))
|
|
908
880
|
}, [
|
|
909
881
|
vue.createElementVNode("span", {
|
|
910
882
|
class: "pi-flag",
|
|
911
883
|
role: "img",
|
|
912
|
-
"aria-label": `${vue.unref(
|
|
884
|
+
"aria-label": `${vue.unref(country).name} flag`
|
|
913
885
|
}, [
|
|
914
|
-
vue.renderSlot(_ctx.$slots, "flag", { country: vue.unref(
|
|
915
|
-
vue.createTextVNode(vue.toDisplayString(vue.unref(
|
|
886
|
+
vue.renderSlot(_ctx.$slots, "flag", { country: vue.unref(country) }, () => [
|
|
887
|
+
vue.createTextVNode(vue.toDisplayString(vue.unref(country).flag), 1)
|
|
916
888
|
], true)
|
|
917
|
-
], 8,
|
|
918
|
-
vue.createElementVNode("span",
|
|
889
|
+
], 8, _hoisted_2),
|
|
890
|
+
vue.createElementVNode("span", _hoisted_3, vue.toDisplayString(vue.unref(country).code), 1),
|
|
919
891
|
!inactive.value && vue.unref(hasDropdown) ? (vue.openBlock(), vue.createElementBlock("svg", {
|
|
920
892
|
key: 0,
|
|
921
|
-
class: vue.normalizeClass(["pi-chevron", { "is-open": vue.unref(
|
|
893
|
+
class: vue.normalizeClass(["pi-chevron", { "is-open": vue.unref(dropdownOpen) }]),
|
|
922
894
|
width: "12",
|
|
923
895
|
height: "12",
|
|
924
896
|
viewBox: "0 0 12 12",
|
|
925
897
|
fill: "none",
|
|
926
898
|
"aria-hidden": "true"
|
|
927
|
-
}, [..._cache[
|
|
899
|
+
}, [..._cache[8] || (_cache[8] = [
|
|
928
900
|
vue.createElementVNode("path", {
|
|
929
901
|
d: "M2.5 4.5L6 8L9.5 4.5",
|
|
930
902
|
stroke: "currentColor",
|
|
@@ -933,9 +905,9 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
933
905
|
"stroke-linejoin": "round"
|
|
934
906
|
}, null, -1)
|
|
935
907
|
])], 2)) : vue.createCommentVNode("", true)
|
|
936
|
-
], 10,
|
|
937
|
-
]),
|
|
938
|
-
vue.createElementVNode("div",
|
|
908
|
+
], 10, _hoisted_1)
|
|
909
|
+
], 512),
|
|
910
|
+
vue.createElementVNode("div", _hoisted_4, [
|
|
939
911
|
vue.createElementVNode("input", {
|
|
940
912
|
ref_key: "telRef",
|
|
941
913
|
ref: telRef,
|
|
@@ -950,16 +922,19 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
950
922
|
value: vue.unref(displayValue),
|
|
951
923
|
disabled: __props.disabled,
|
|
952
924
|
readonly: __props.readonly,
|
|
953
|
-
"aria-invalid":
|
|
954
|
-
onBeforeinput: _cache[
|
|
955
|
-
(...args) => vue.unref(
|
|
956
|
-
onInput
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
925
|
+
"aria-invalid": incomplete.value,
|
|
926
|
+
onBeforeinput: _cache[1] || (_cache[1] = //@ts-ignore
|
|
927
|
+
(...args) => vue.unref(handleBeforeInput) && vue.unref(handleBeforeInput)(...args)),
|
|
928
|
+
onInput: _cache[2] || (_cache[2] = //@ts-ignore
|
|
929
|
+
(...args) => vue.unref(handleInput) && vue.unref(handleInput)(...args)),
|
|
930
|
+
onKeydown: _cache[3] || (_cache[3] = //@ts-ignore
|
|
931
|
+
(...args) => vue.unref(handleKeydown) && vue.unref(handleKeydown)(...args)),
|
|
932
|
+
onPaste: _cache[4] || (_cache[4] = //@ts-ignore
|
|
933
|
+
(...args) => vue.unref(handlePaste) && vue.unref(handlePaste)(...args)),
|
|
934
|
+
onFocus: handleFocus,
|
|
935
|
+
onBlur: handleBlur
|
|
936
|
+
}, null, 40, _hoisted_5),
|
|
937
|
+
vue.createElementVNode("div", _hoisted_6, [
|
|
963
938
|
vue.createVNode(vue.Transition, { name: "fade-scale" }, {
|
|
964
939
|
default: vue.withCtx(() => [
|
|
965
940
|
vue.renderSlot(_ctx.$slots, "actions-before", {}, void 0, true)
|
|
@@ -971,26 +946,27 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
971
946
|
showCopyButton.value ? (vue.openBlock(), vue.createElementBlock("button", {
|
|
972
947
|
key: 0,
|
|
973
948
|
type: "button",
|
|
974
|
-
class: vue.normalizeClass(["pi-btn", { "is-copied": vue.unref(copied) }]),
|
|
975
|
-
"aria-label": copyAriaLabel
|
|
976
|
-
title: copyButtonTitle
|
|
977
|
-
onClick:
|
|
949
|
+
class: vue.normalizeClass(["pi-btn", "pi-btn-copy", { "is-copied": vue.unref(copied) }]),
|
|
950
|
+
"aria-label": vue.unref(copyAriaLabel),
|
|
951
|
+
title: vue.unref(copyButtonTitle),
|
|
952
|
+
onClick: _cache[5] || (_cache[5] = //@ts-ignore
|
|
953
|
+
(...args) => vue.unref(onCopyClick) && vue.unref(onCopyClick)(...args))
|
|
978
954
|
}, [
|
|
979
955
|
slots["copy-svg"] ? vue.renderSlot(_ctx.$slots, "copy-svg", {
|
|
980
956
|
key: 0,
|
|
981
957
|
copied: vue.unref(copied)
|
|
982
|
-
}, void 0, true) : !vue.unref(copied) ? (vue.openBlock(), vue.createElementBlock("svg",
|
|
958
|
+
}, void 0, true) : !vue.unref(copied) ? (vue.openBlock(), vue.createElementBlock("svg", _hoisted_8, [..._cache[9] || (_cache[9] = [
|
|
983
959
|
vue.createElementVNode("path", {
|
|
984
960
|
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",
|
|
985
961
|
fill: "currentColor"
|
|
986
962
|
}, null, -1)
|
|
987
|
-
])])) : (vue.openBlock(), vue.createElementBlock("svg",
|
|
963
|
+
])])) : (vue.openBlock(), vue.createElementBlock("svg", _hoisted_9, [..._cache[10] || (_cache[10] = [
|
|
988
964
|
vue.createElementVNode("path", {
|
|
989
965
|
d: "M6.5 11.5L3 8L4.06 6.94L6.5 9.38L11.94 3.94L13 5L6.5 11.5Z",
|
|
990
966
|
fill: "currentColor"
|
|
991
967
|
}, null, -1)
|
|
992
968
|
])]))
|
|
993
|
-
], 10,
|
|
969
|
+
], 10, _hoisted_7)) : vue.createCommentVNode("", true)
|
|
994
970
|
]),
|
|
995
971
|
_: 3
|
|
996
972
|
}),
|
|
@@ -999,18 +975,18 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
999
975
|
showClearButton.value ? (vue.openBlock(), vue.createElementBlock("button", {
|
|
1000
976
|
key: 0,
|
|
1001
977
|
type: "button",
|
|
1002
|
-
class: "pi-btn",
|
|
978
|
+
class: "pi-btn pi-btn-clear",
|
|
1003
979
|
"aria-label": __props.clearButtonLabel,
|
|
1004
980
|
title: __props.clearButtonLabel,
|
|
1005
981
|
onClick: onClearClick
|
|
1006
982
|
}, [
|
|
1007
|
-
!slots["clear-svg"] ? (vue.openBlock(), vue.createElementBlock("svg",
|
|
983
|
+
!slots["clear-svg"] ? (vue.openBlock(), vue.createElementBlock("svg", _hoisted_11, [..._cache[11] || (_cache[11] = [
|
|
1008
984
|
vue.createElementVNode("path", {
|
|
1009
985
|
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",
|
|
1010
986
|
fill: "currentColor"
|
|
1011
987
|
}, null, -1)
|
|
1012
988
|
])])) : vue.renderSlot(_ctx.$slots, "clear-svg", { key: 1 }, void 0, true)
|
|
1013
|
-
], 8,
|
|
989
|
+
], 8, _hoisted_10)) : vue.createCommentVNode("", true)
|
|
1014
990
|
]),
|
|
1015
991
|
_: 3
|
|
1016
992
|
})
|
|
@@ -1019,42 +995,30 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
1019
995
|
(vue.openBlock(), vue.createBlock(vue.Teleport, { to: "body" }, [
|
|
1020
996
|
vue.createVNode(vue.Transition, { name: "dropdown" }, {
|
|
1021
997
|
default: vue.withCtx(() => [
|
|
1022
|
-
vue.unref(
|
|
998
|
+
vue.unref(dropdownOpen) ? (vue.openBlock(), vue.createElementBlock("div", {
|
|
1023
999
|
key: 0,
|
|
1024
1000
|
ref_key: "dropdownRef",
|
|
1025
1001
|
ref: dropdownRef,
|
|
1026
|
-
class: vue.normalizeClass(["phone-dropdown", [__props.dropdownClass, themeClass
|
|
1002
|
+
class: vue.normalizeClass(["phone-dropdown", [__props.dropdownClass, vue.unref(themeClass)]]),
|
|
1027
1003
|
role: "dialog",
|
|
1028
1004
|
"aria-modal": "false",
|
|
1029
1005
|
"aria-label": "Select country",
|
|
1030
|
-
style: vue.normalizeStyle(dropdownStyle
|
|
1006
|
+
style: vue.normalizeStyle(vue.unref(dropdownStyle))
|
|
1031
1007
|
}, [
|
|
1032
|
-
vue.createElementVNode("div",
|
|
1033
|
-
vue.
|
|
1008
|
+
vue.createElementVNode("div", _hoisted_12, [
|
|
1009
|
+
vue.createElementVNode("input", {
|
|
1034
1010
|
ref_key: "searchRef",
|
|
1035
1011
|
ref: searchRef,
|
|
1036
|
-
|
|
1012
|
+
value: vue.unref(search),
|
|
1037
1013
|
type: "search",
|
|
1038
1014
|
class: "pi-search",
|
|
1039
1015
|
"aria-label": "Search countries",
|
|
1040
1016
|
placeholder: __props.searchPlaceholder,
|
|
1041
|
-
onKeydown: [
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
(...args) => vue.unref(chooseFocusedOption) && vue.unref(chooseFocusedOption)(...args),
|
|
1047
|
-
["prevent"]
|
|
1048
|
-
), ["enter"])),
|
|
1049
|
-
_cache[5] || (_cache[5] = vue.withKeys(
|
|
1050
|
-
//@ts-ignore
|
|
1051
|
-
(...args) => vue.unref(closeDropdown) && vue.unref(closeDropdown)(...args),
|
|
1052
|
-
["escape"]
|
|
1053
|
-
))
|
|
1054
|
-
]
|
|
1055
|
-
}, null, 40, _hoisted_14), [
|
|
1056
|
-
[vue.vModelText, vue.unref(search)]
|
|
1057
|
-
])
|
|
1017
|
+
onKeydown: _cache[6] || (_cache[6] = //@ts-ignore
|
|
1018
|
+
(...args) => vue.unref(handleSearchKeydown) && vue.unref(handleSearchKeydown)(...args)),
|
|
1019
|
+
onInput: _cache[7] || (_cache[7] = //@ts-ignore
|
|
1020
|
+
(...args) => vue.unref(handleSearchChange) && vue.unref(handleSearchChange)(...args))
|
|
1021
|
+
}, null, 40, _hoisted_13)
|
|
1058
1022
|
]),
|
|
1059
1023
|
vue.createElementVNode("ul", {
|
|
1060
1024
|
class: "pi-options",
|
|
@@ -1071,13 +1035,13 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
1071
1035
|
"pi-option",
|
|
1072
1036
|
{
|
|
1073
1037
|
"is-focused": idx === vue.unref(focusedIndex),
|
|
1074
|
-
"is-selected": c.id === vue.unref(
|
|
1038
|
+
"is-selected": c.id === vue.unref(country).id
|
|
1075
1039
|
}
|
|
1076
1040
|
]),
|
|
1077
|
-
"aria-selected": c.id === vue.unref(
|
|
1041
|
+
"aria-selected": c.id === vue.unref(country).id,
|
|
1078
1042
|
title: c.name,
|
|
1079
|
-
onClick: ($event) =>
|
|
1080
|
-
onMouseenter: ($event) =>
|
|
1043
|
+
onClick: ($event) => vue.unref(selectCountry)(c.id),
|
|
1044
|
+
onMouseenter: ($event) => vue.unref(setFocusedIndex)(idx)
|
|
1081
1045
|
}, [
|
|
1082
1046
|
vue.createElementVNode("span", {
|
|
1083
1047
|
class: "pi-flag",
|
|
@@ -1087,13 +1051,13 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
1087
1051
|
vue.renderSlot(_ctx.$slots, "flag", { country: c }, () => [
|
|
1088
1052
|
vue.createTextVNode(vue.toDisplayString(c.flag), 1)
|
|
1089
1053
|
], true)
|
|
1090
|
-
], 8,
|
|
1091
|
-
vue.createElementVNode("span",
|
|
1092
|
-
vue.createElementVNode("span",
|
|
1093
|
-
], 42,
|
|
1054
|
+
], 8, _hoisted_16),
|
|
1055
|
+
vue.createElementVNode("span", _hoisted_17, vue.toDisplayString(c.name), 1),
|
|
1056
|
+
vue.createElementVNode("span", _hoisted_18, vue.toDisplayString(c.code), 1)
|
|
1057
|
+
], 42, _hoisted_15);
|
|
1094
1058
|
}), 128)),
|
|
1095
|
-
vue.unref(filteredCountries).length === 0 ? (vue.openBlock(), vue.createElementBlock("li",
|
|
1096
|
-
], 8,
|
|
1059
|
+
vue.unref(filteredCountries).length === 0 ? (vue.openBlock(), vue.createElementBlock("li", _hoisted_19, vue.toDisplayString(__props.noResultsText), 1)) : vue.createCommentVNode("", true)
|
|
1060
|
+
], 8, _hoisted_14)
|
|
1097
1061
|
], 6)) : vue.createCommentVNode("", true)
|
|
1098
1062
|
]),
|
|
1099
1063
|
_: 3
|
|
@@ -1118,56 +1082,7 @@ const _export_sfc = (sfc, props) => {
|
|
|
1118
1082
|
}
|
|
1119
1083
|
return target;
|
|
1120
1084
|
};
|
|
1121
|
-
const PhoneInput = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
1122
|
-
function getNavigatorLang() {
|
|
1123
|
-
if (typeof navigator !== "undefined") {
|
|
1124
|
-
return navigator.language || "";
|
|
1125
|
-
}
|
|
1126
|
-
return "";
|
|
1127
|
-
}
|
|
1128
|
-
function getCountry(countryCode, locale) {
|
|
1129
|
-
const isEn = locale.toLowerCase().startsWith("en");
|
|
1130
|
-
const countriesMap = isEn ? m : MasksFullMap(locale);
|
|
1131
|
-
const id = countryCode.toUpperCase();
|
|
1132
|
-
const found = countriesMap[id];
|
|
1133
|
-
return found ? { id, ...found } : null;
|
|
1134
|
-
}
|
|
1135
|
-
function getDefaultCountry(locale) {
|
|
1136
|
-
const isEn = locale.toLowerCase().startsWith("en");
|
|
1137
|
-
const countries = isEn ? m : MasksFullMap(locale);
|
|
1138
|
-
return { id: "US", ...countries.US };
|
|
1139
|
-
}
|
|
1140
|
-
async function detectCountryFromGeoIP() {
|
|
1141
|
-
try {
|
|
1142
|
-
const controller = new AbortController();
|
|
1143
|
-
const timeoutId = setTimeout(() => controller.abort(), GEO_IP_TIMEOUT);
|
|
1144
|
-
const res = await fetch(GEO_IP_URL, {
|
|
1145
|
-
signal: controller.signal,
|
|
1146
|
-
headers: { Accept: "application/json" }
|
|
1147
|
-
});
|
|
1148
|
-
clearTimeout(timeoutId);
|
|
1149
|
-
if (!res.ok) return null;
|
|
1150
|
-
const json = await res.json();
|
|
1151
|
-
const code = (json.country || json.country_code || json.countryCode || json.country_code2 || "").toString().toUpperCase();
|
|
1152
|
-
return code || null;
|
|
1153
|
-
} catch {
|
|
1154
|
-
return null;
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
function detectCountryFromLocale() {
|
|
1158
|
-
try {
|
|
1159
|
-
const lang = getNavigatorLang();
|
|
1160
|
-
try {
|
|
1161
|
-
const loc = new Intl.Locale(lang);
|
|
1162
|
-
if (loc.region) return loc.region.toUpperCase();
|
|
1163
|
-
} catch {
|
|
1164
|
-
}
|
|
1165
|
-
const parts = lang.split(/[-_]/);
|
|
1166
|
-
if (parts.length > 1) return parts[1]?.toUpperCase() || null;
|
|
1167
|
-
} catch {
|
|
1168
|
-
}
|
|
1169
|
-
return null;
|
|
1170
|
-
}
|
|
1085
|
+
const PhoneInput = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-33134720"]]);
|
|
1171
1086
|
async function initState(binding) {
|
|
1172
1087
|
const value = binding.value;
|
|
1173
1088
|
let options = {};
|
|
@@ -1176,24 +1091,24 @@ async function initState(binding) {
|
|
|
1176
1091
|
} else if (typeof value === "object" && value !== null) {
|
|
1177
1092
|
options = value;
|
|
1178
1093
|
}
|
|
1179
|
-
const locale = options.locale || getNavigatorLang()
|
|
1180
|
-
let country
|
|
1094
|
+
const locale = options.locale || getNavigatorLang();
|
|
1095
|
+
let country;
|
|
1181
1096
|
if (options.country) {
|
|
1182
1097
|
country = getCountry(options.country, locale);
|
|
1183
1098
|
} else if (options.detect) {
|
|
1184
1099
|
const geoCountry = await detectCountryFromGeoIP();
|
|
1185
1100
|
if (geoCountry) {
|
|
1186
1101
|
country = getCountry(geoCountry, locale);
|
|
1187
|
-
}
|
|
1188
|
-
if (!country) {
|
|
1102
|
+
} else {
|
|
1189
1103
|
const localeCountry = detectCountryFromLocale();
|
|
1190
1104
|
if (localeCountry) {
|
|
1191
1105
|
country = getCountry(localeCountry, locale);
|
|
1106
|
+
} else {
|
|
1107
|
+
country = getCountry("US", locale);
|
|
1192
1108
|
}
|
|
1193
1109
|
}
|
|
1194
|
-
}
|
|
1195
|
-
|
|
1196
|
-
country = getDefaultCountry(locale);
|
|
1110
|
+
} else {
|
|
1111
|
+
country = getCountry("US", locale);
|
|
1197
1112
|
}
|
|
1198
1113
|
return {
|
|
1199
1114
|
country,
|
|
@@ -1215,147 +1130,50 @@ function updateDisplay(el, state) {
|
|
|
1215
1130
|
});
|
|
1216
1131
|
}
|
|
1217
1132
|
}
|
|
1218
|
-
function createBeforeInputHandler(el) {
|
|
1219
|
-
return (e) => {
|
|
1220
|
-
const data = e.data;
|
|
1221
|
-
if (e.inputType !== "insertText" || !data) return;
|
|
1222
|
-
if (InvalidPattern.test(data) || data === " " && el.value.endsWith(" ")) {
|
|
1223
|
-
e.preventDefault();
|
|
1224
|
-
}
|
|
1225
|
-
};
|
|
1226
|
-
}
|
|
1227
1133
|
function createInputHandler(el, state) {
|
|
1228
|
-
return (
|
|
1229
|
-
const
|
|
1230
|
-
if (!
|
|
1231
|
-
|
|
1232
|
-
const maxDigits = state.formatter.getMaxDigits();
|
|
1233
|
-
state.digits = extractDigits(raw, maxDigits);
|
|
1134
|
+
return (e2) => {
|
|
1135
|
+
const result = processInput(e2, { formatter: state.formatter });
|
|
1136
|
+
if (!result) return;
|
|
1137
|
+
state.digits = result.newDigits;
|
|
1234
1138
|
updateDisplay(el, state);
|
|
1235
1139
|
vue.nextTick(() => {
|
|
1236
|
-
const pos = state.formatter.getCaretPosition(
|
|
1140
|
+
const pos = state.formatter.getCaretPosition(result.caretDigitIndex);
|
|
1237
1141
|
setCaret(el, pos);
|
|
1238
1142
|
});
|
|
1239
1143
|
};
|
|
1240
1144
|
}
|
|
1241
1145
|
function createKeydownHandler(el, state) {
|
|
1242
|
-
return (
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
const pos = state.formatter.getCaretPosition(start);
|
|
1255
|
-
setCaret(el, pos);
|
|
1256
|
-
});
|
|
1257
|
-
}
|
|
1258
|
-
return;
|
|
1259
|
-
}
|
|
1260
|
-
if (selStart > 0) {
|
|
1261
|
-
const displayStr = el.value;
|
|
1262
|
-
let prevPos = selStart - 1;
|
|
1263
|
-
while (prevPos >= 0 && Delimiters.includes(displayStr[prevPos])) {
|
|
1264
|
-
prevPos--;
|
|
1265
|
-
}
|
|
1266
|
-
if (prevPos >= 0) {
|
|
1267
|
-
const range = state.formatter.getDigitRange(state.digits, prevPos, prevPos + 1);
|
|
1268
|
-
if (range) {
|
|
1269
|
-
const [start] = range;
|
|
1270
|
-
state.digits = state.digits.slice(0, start) + state.digits.slice(start + 1);
|
|
1271
|
-
updateDisplay(el, state);
|
|
1272
|
-
vue.nextTick(() => {
|
|
1273
|
-
const pos = state.formatter.getCaretPosition(start);
|
|
1274
|
-
setCaret(el, pos);
|
|
1275
|
-
});
|
|
1276
|
-
}
|
|
1277
|
-
}
|
|
1278
|
-
}
|
|
1279
|
-
return;
|
|
1280
|
-
}
|
|
1281
|
-
if (e.key === "Delete") {
|
|
1282
|
-
e.preventDefault();
|
|
1283
|
-
if (selStart !== selEnd) {
|
|
1284
|
-
const range = state.formatter.getDigitRange(state.digits, selStart, selEnd);
|
|
1285
|
-
if (range) {
|
|
1286
|
-
const [start, end] = range;
|
|
1287
|
-
state.digits = state.digits.slice(0, start) + state.digits.slice(end);
|
|
1288
|
-
updateDisplay(el, state);
|
|
1289
|
-
vue.nextTick(() => {
|
|
1290
|
-
const pos = state.formatter.getCaretPosition(start);
|
|
1291
|
-
setCaret(el, pos);
|
|
1292
|
-
});
|
|
1293
|
-
}
|
|
1294
|
-
return;
|
|
1295
|
-
}
|
|
1296
|
-
if (selStart < el.value.length) {
|
|
1297
|
-
const range = state.formatter.getDigitRange(state.digits, selStart, selStart + 1);
|
|
1298
|
-
if (range) {
|
|
1299
|
-
const [start] = range;
|
|
1300
|
-
state.digits = state.digits.slice(0, start) + state.digits.slice(start + 1);
|
|
1301
|
-
updateDisplay(el, state);
|
|
1302
|
-
vue.nextTick(() => {
|
|
1303
|
-
const pos = state.formatter.getCaretPosition(start);
|
|
1304
|
-
setCaret(el, pos);
|
|
1305
|
-
});
|
|
1306
|
-
}
|
|
1307
|
-
}
|
|
1308
|
-
return;
|
|
1309
|
-
}
|
|
1310
|
-
if (/^[0-9]$/.test(e.key)) {
|
|
1311
|
-
if (state.digits.length >= state.formatter.getMaxDigits()) {
|
|
1312
|
-
e.preventDefault();
|
|
1313
|
-
}
|
|
1314
|
-
return;
|
|
1315
|
-
}
|
|
1316
|
-
if (e.key.length === 1) {
|
|
1317
|
-
e.preventDefault();
|
|
1318
|
-
}
|
|
1146
|
+
return (e2) => {
|
|
1147
|
+
const result = processKeydown(e2, {
|
|
1148
|
+
digits: state.digits,
|
|
1149
|
+
formatter: state.formatter
|
|
1150
|
+
});
|
|
1151
|
+
if (!result) return;
|
|
1152
|
+
state.digits = result.newDigits;
|
|
1153
|
+
updateDisplay(el, state);
|
|
1154
|
+
vue.nextTick(() => {
|
|
1155
|
+
const pos = state.formatter.getCaretPosition(result.caretDigitIndex);
|
|
1156
|
+
setCaret(el, pos);
|
|
1157
|
+
});
|
|
1319
1158
|
};
|
|
1320
1159
|
}
|
|
1321
1160
|
function createPasteHandler(el, state) {
|
|
1322
|
-
return (
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
if (
|
|
1328
|
-
|
|
1329
|
-
if (selStart !== selEnd) {
|
|
1330
|
-
const range2 = state.formatter.getDigitRange(state.digits, selStart, selEnd);
|
|
1331
|
-
if (range2) {
|
|
1332
|
-
const [start, end] = range2;
|
|
1333
|
-
const left2 = state.digits.slice(0, start);
|
|
1334
|
-
const right2 = state.digits.slice(end);
|
|
1335
|
-
state.digits = extractDigits(left2 + pastedDigits + right2, maxDigits);
|
|
1336
|
-
updateDisplay(el, state);
|
|
1337
|
-
vue.nextTick(() => {
|
|
1338
|
-
const pos = state.formatter.getCaretPosition(start + pastedDigits.length);
|
|
1339
|
-
setCaret(el, pos);
|
|
1340
|
-
});
|
|
1341
|
-
return;
|
|
1342
|
-
}
|
|
1343
|
-
}
|
|
1344
|
-
const range = state.formatter.getDigitRange(state.digits, selStart, selStart);
|
|
1345
|
-
const insertIndex = range ? range[0] : state.digits.length;
|
|
1346
|
-
const left = state.digits.slice(0, insertIndex);
|
|
1347
|
-
const right = state.digits.slice(insertIndex);
|
|
1348
|
-
state.digits = extractDigits(left + pastedDigits + right, maxDigits);
|
|
1161
|
+
return (e2) => {
|
|
1162
|
+
const result = processPaste(e2, {
|
|
1163
|
+
digits: state.digits,
|
|
1164
|
+
formatter: state.formatter
|
|
1165
|
+
});
|
|
1166
|
+
if (!result) return;
|
|
1167
|
+
state.digits = result.newDigits;
|
|
1349
1168
|
updateDisplay(el, state);
|
|
1350
1169
|
vue.nextTick(() => {
|
|
1351
|
-
const pos = state.formatter.getCaretPosition(
|
|
1170
|
+
const pos = state.formatter.getCaretPosition(result.caretDigitIndex);
|
|
1352
1171
|
setCaret(el, pos);
|
|
1353
1172
|
});
|
|
1354
1173
|
};
|
|
1355
1174
|
}
|
|
1356
1175
|
async function updateCountry(el, state, newCountryCode) {
|
|
1357
1176
|
const newCountry = getCountry(newCountryCode, state.locale);
|
|
1358
|
-
if (!newCountry) return;
|
|
1359
1177
|
state.country = newCountry;
|
|
1360
1178
|
state.formatter = createPhoneFormatter(newCountry);
|
|
1361
1179
|
el.placeholder = state.formatter.getPlaceholder();
|
|
@@ -1381,7 +1199,7 @@ const vPhoneMask = {
|
|
|
1381
1199
|
state.inputHandler = createInputHandler(el, state);
|
|
1382
1200
|
state.keydownHandler = createKeydownHandler(el, state);
|
|
1383
1201
|
state.pasteHandler = createPasteHandler(el, state);
|
|
1384
|
-
state.beforeInputHandler =
|
|
1202
|
+
state.beforeInputHandler = processBeforeInput;
|
|
1385
1203
|
el.addEventListener("beforeinput", state.beforeInputHandler);
|
|
1386
1204
|
el.addEventListener("input", state.inputHandler);
|
|
1387
1205
|
el.addEventListener("keydown", state.keydownHandler);
|
|
@@ -1412,8 +1230,10 @@ const vPhoneMask = {
|
|
|
1412
1230
|
if (newCountry && newCountry !== oldCountry) {
|
|
1413
1231
|
await updateCountry(el, state, newCountry);
|
|
1414
1232
|
}
|
|
1415
|
-
const
|
|
1416
|
-
|
|
1233
|
+
const maxDigits = state.formatter.getMaxDigits();
|
|
1234
|
+
const newDigits = extractDigits(el.value, maxDigits);
|
|
1235
|
+
const normalizedDisplay = state.formatter.formatDisplay(newDigits);
|
|
1236
|
+
if (newDigits !== state.digits || el.value !== normalizedDisplay) {
|
|
1417
1237
|
state.digits = newDigits;
|
|
1418
1238
|
updateDisplay(el, state);
|
|
1419
1239
|
}
|
|
@@ -1428,6 +1248,82 @@ const vPhoneMask = {
|
|
|
1428
1248
|
delete el.__phoneMaskState;
|
|
1429
1249
|
}
|
|
1430
1250
|
};
|
|
1251
|
+
function usePhoneMask(options) {
|
|
1252
|
+
const inputRef = vue.shallowRef(null);
|
|
1253
|
+
const { country, setCountry } = useCountry({
|
|
1254
|
+
country: options.country,
|
|
1255
|
+
locale: options.locale,
|
|
1256
|
+
detect: options.detect,
|
|
1257
|
+
onCountryChange: options.onCountryChange
|
|
1258
|
+
});
|
|
1259
|
+
const {
|
|
1260
|
+
digits,
|
|
1261
|
+
formatter,
|
|
1262
|
+
displayPlaceholder,
|
|
1263
|
+
displayValue,
|
|
1264
|
+
full,
|
|
1265
|
+
fullFormatted,
|
|
1266
|
+
isComplete,
|
|
1267
|
+
isEmpty,
|
|
1268
|
+
shouldShowWarn
|
|
1269
|
+
} = useFormatter({
|
|
1270
|
+
country,
|
|
1271
|
+
value: options.value,
|
|
1272
|
+
onChange: options.onChange,
|
|
1273
|
+
onPhoneChange: options.onPhoneChange
|
|
1274
|
+
});
|
|
1275
|
+
const { handleBeforeInput, handleInput, handleKeydown, handlePaste } = useInputHandlers({
|
|
1276
|
+
formatter,
|
|
1277
|
+
digits,
|
|
1278
|
+
onChange: options.onChange
|
|
1279
|
+
});
|
|
1280
|
+
vue.onMounted(() => {
|
|
1281
|
+
const el = inputRef.value;
|
|
1282
|
+
if (!el) return;
|
|
1283
|
+
el.setAttribute("type", "tel");
|
|
1284
|
+
el.setAttribute("inputmode", "tel");
|
|
1285
|
+
});
|
|
1286
|
+
vue.watchEffect(
|
|
1287
|
+
() => {
|
|
1288
|
+
const el = inputRef.value;
|
|
1289
|
+
if (!el) return;
|
|
1290
|
+
el.value = displayValue.value;
|
|
1291
|
+
el.setAttribute("placeholder", displayPlaceholder.value);
|
|
1292
|
+
},
|
|
1293
|
+
{ flush: "post" }
|
|
1294
|
+
);
|
|
1295
|
+
vue.onMounted(() => {
|
|
1296
|
+
const el = inputRef.value;
|
|
1297
|
+
if (!el) return;
|
|
1298
|
+
el.addEventListener("beforeinput", handleBeforeInput);
|
|
1299
|
+
el.addEventListener("input", handleInput);
|
|
1300
|
+
el.addEventListener("keydown", handleKeydown);
|
|
1301
|
+
el.addEventListener("paste", handlePaste);
|
|
1302
|
+
});
|
|
1303
|
+
vue.onUnmounted(() => {
|
|
1304
|
+
const el = inputRef.value;
|
|
1305
|
+
if (!el) return;
|
|
1306
|
+
el.removeEventListener("beforeinput", handleBeforeInput);
|
|
1307
|
+
el.removeEventListener("input", handleInput);
|
|
1308
|
+
el.removeEventListener("keydown", handleKeydown);
|
|
1309
|
+
el.removeEventListener("paste", handlePaste);
|
|
1310
|
+
});
|
|
1311
|
+
const clear = () => {
|
|
1312
|
+
options.onChange("");
|
|
1313
|
+
};
|
|
1314
|
+
return {
|
|
1315
|
+
inputRef,
|
|
1316
|
+
digits,
|
|
1317
|
+
full,
|
|
1318
|
+
fullFormatted,
|
|
1319
|
+
isComplete,
|
|
1320
|
+
isEmpty,
|
|
1321
|
+
shouldShowWarn,
|
|
1322
|
+
country,
|
|
1323
|
+
setCountry,
|
|
1324
|
+
clear
|
|
1325
|
+
};
|
|
1326
|
+
}
|
|
1431
1327
|
function install(app) {
|
|
1432
1328
|
app.component("PhoneInput", PhoneInput);
|
|
1433
1329
|
app.directive("phone-mask", vPhoneMask);
|
|
@@ -1436,7 +1332,7 @@ const index = {
|
|
|
1436
1332
|
install
|
|
1437
1333
|
};
|
|
1438
1334
|
const PMaskHelpers = {
|
|
1439
|
-
getFlagEmoji:
|
|
1335
|
+
getFlagEmoji: k,
|
|
1440
1336
|
countPlaceholders,
|
|
1441
1337
|
formatDigitsWithMap,
|
|
1442
1338
|
pickMaskVariant,
|
|
@@ -1447,5 +1343,6 @@ exports.PMaskHelpers = PMaskHelpers;
|
|
|
1447
1343
|
exports.PhoneInput = PhoneInput;
|
|
1448
1344
|
exports.default = index;
|
|
1449
1345
|
exports.install = install;
|
|
1346
|
+
exports.usePhoneMask = usePhoneMask;
|
|
1450
1347
|
exports.vPhoneMask = vPhoneMask;
|
|
1451
1348
|
exports.vPhoneMaskSetCountry = updateCountry;
|