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