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