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