@alikhalilll/a-tel-input 1.0.2 → 1.1.1
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/.media/README.md +3 -0
- package/.media/hero.png +0 -0
- package/README.md +597 -72
- package/dist/_chunks/types.d.ts +661 -0
- package/dist/_chunks/types.js +52 -0
- package/dist/_chunks/types.js.map +1 -0
- package/dist/_chunks/usePhoneValidation.js +539 -0
- package/dist/_chunks/usePhoneValidation.js.map +1 -0
- package/dist/index.cjs +471 -695
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +122 -587
- package/dist/index.d.ts +122 -587
- package/dist/index.js +454 -658
- package/dist/index.js.map +1 -1
- package/dist/styles.css +20 -5
- package/dist/vee-validate/index.cjs +113 -0
- package/dist/vee-validate/index.cjs.map +1 -0
- package/dist/vee-validate/index.d.cts +86 -0
- package/dist/vee-validate/index.d.ts +86 -0
- package/dist/vee-validate/index.js +112 -0
- package/dist/vee-validate/index.js.map +1 -0
- package/dist/zod/index.cjs +211 -0
- package/dist/zod/index.cjs.map +1 -0
- package/dist/zod/index.d.cts +65 -0
- package/dist/zod/index.d.ts +65 -0
- package/dist/zod/index.js +208 -0
- package/dist/zod/index.js.map +1 -0
- package/package.json +34 -3
- package/src/components/ACountrySelect.vue +17 -3
- package/src/components/ATelInput.vue +206 -66
- package/src/composables/useCountryDetection.ts +28 -11
- package/src/composables/useCountryMatching.ts +160 -20
- package/src/composables/useCountrySelection.ts +71 -0
- package/src/composables/usePhoneValidation.ts +81 -18
- package/src/composables/useSyncedModel.ts +80 -0
- package/src/composables/useTelInputValidation.ts +50 -11
- package/src/index.ts +2 -0
- package/src/types.ts +80 -0
- package/src/vee-validate/index.ts +2 -0
- package/src/vee-validate/useTelField.ts +202 -0
- package/src/zod/index.ts +259 -0
- package/web-types.json +44 -1
package/dist/index.cjs
CHANGED
|
@@ -1,33 +1,10 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var __defProp$1 = Object.defineProperty;
|
|
5
|
-
var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
|
|
6
|
-
var __getOwnPropNames$1 = Object.getOwnPropertyNames;
|
|
7
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
-
var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
|
|
9
|
-
var __copyProps$1 = (to, from, except, desc) => {
|
|
10
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames$1(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
-
key = keys[i];
|
|
12
|
-
if (!__hasOwnProp$1.call(to, key) && key !== except) __defProp$1(to, key, {
|
|
13
|
-
get: ((k) => from[k]).bind(null, key),
|
|
14
|
-
enumerable: !(desc = __getOwnPropDesc$1(from, key)) || desc.enumerable
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps$1(isNodeMode || !mod || !mod.__esModule ? __defProp$1(target, "default", {
|
|
20
|
-
value: mod,
|
|
21
|
-
enumerable: true
|
|
22
|
-
}) : target, mod));
|
|
23
|
-
//#endregion
|
|
2
|
+
const require_usePhoneValidation = require("./_chunks/usePhoneValidation.js");
|
|
3
|
+
const require_types = require("./_chunks/types.js");
|
|
24
4
|
let vue = require("vue");
|
|
25
|
-
vue = __toESM(vue, 1);
|
|
5
|
+
vue = require_usePhoneValidation.__toESM(vue, 1);
|
|
26
6
|
let libphonenumber_js = require("libphonenumber-js");
|
|
27
|
-
let libphonenumber_js_examples_mobile_json = require("libphonenumber-js/examples.mobile.json");
|
|
28
|
-
libphonenumber_js_examples_mobile_json = __toESM(libphonenumber_js_examples_mobile_json, 1);
|
|
29
7
|
let _vueuse_core = require("@vueuse/core");
|
|
30
|
-
let class_variance_authority = require("class-variance-authority");
|
|
31
8
|
let aria_hidden = require("aria-hidden");
|
|
32
9
|
//#region ../../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
|
|
33
10
|
function r$2(e) {
|
|
@@ -3428,508 +3405,6 @@ function cn$2(...inputs) {
|
|
|
3428
3405
|
return twMerge$2(clsx$2(inputs));
|
|
3429
3406
|
}
|
|
3430
3407
|
//#endregion
|
|
3431
|
-
//#region src/utils/digits.ts
|
|
3432
|
-
/**
|
|
3433
|
-
* Alternative-numeral support. Phone numbers are routinely entered with the digits of the
|
|
3434
|
-
* user's own script — Arabic-Indic, Persian/Urdu, Devanagari, Bengali. `libphonenumber-js`
|
|
3435
|
-
* and our own `\d` cleanup only understand ASCII `0-9`, so anything else silently becomes
|
|
3436
|
-
* an empty number. `normalizeDigits` folds those scripts down to ASCII before validation.
|
|
3437
|
-
*/
|
|
3438
|
-
/**
|
|
3439
|
-
* Base code points of contiguous decimal-digit blocks. Each block runs `base`‥`base+9`
|
|
3440
|
-
* for digit `0`‥`9`, so the ASCII digit is `codePoint - base`. Add a script by appending
|
|
3441
|
-
* one entry here.
|
|
3442
|
-
*/
|
|
3443
|
-
const LOCALE_DIGIT_RANGES = [
|
|
3444
|
-
{
|
|
3445
|
-
name: "arabic-indic",
|
|
3446
|
-
base: 1632
|
|
3447
|
-
},
|
|
3448
|
-
{
|
|
3449
|
-
name: "extended-arabic",
|
|
3450
|
-
base: 1776
|
|
3451
|
-
},
|
|
3452
|
-
{
|
|
3453
|
-
name: "devanagari",
|
|
3454
|
-
base: 2406
|
|
3455
|
-
},
|
|
3456
|
-
{
|
|
3457
|
-
name: "bengali",
|
|
3458
|
-
base: 2534
|
|
3459
|
-
}
|
|
3460
|
-
];
|
|
3461
|
-
/** Lookup of every non-ASCII digit code point → its ASCII character. */
|
|
3462
|
-
const DIGIT_MAP = (() => {
|
|
3463
|
-
const map = /* @__PURE__ */ new Map();
|
|
3464
|
-
for (const { base } of LOCALE_DIGIT_RANGES) for (let d = 0; d <= 9; d++) map.set(base + d, String(d));
|
|
3465
|
-
return map;
|
|
3466
|
-
})();
|
|
3467
|
-
/**
|
|
3468
|
-
* Replace any supported non-ASCII decimal digit with its ASCII equivalent. Every other
|
|
3469
|
-
* character (spaces, `+`, separators, letters) is left untouched — callers still run their
|
|
3470
|
-
* own `\D` cleanup afterwards.
|
|
3471
|
-
*/
|
|
3472
|
-
function normalizeDigits(input) {
|
|
3473
|
-
const str = String(input ?? "");
|
|
3474
|
-
let out = "";
|
|
3475
|
-
for (const ch of str) {
|
|
3476
|
-
const cp = ch.codePointAt(0);
|
|
3477
|
-
out += cp != null && DIGIT_MAP.get(cp) || ch;
|
|
3478
|
-
}
|
|
3479
|
-
return out;
|
|
3480
|
-
}
|
|
3481
|
-
//#endregion
|
|
3482
|
-
//#region src/composables/usePhoneValidation.ts
|
|
3483
|
-
/**
|
|
3484
|
-
* Country list + phone validation, framework-agnostic.
|
|
3485
|
-
*
|
|
3486
|
-
* Ported from the reference @pkgs/ui ATelInput composable with these cleanups:
|
|
3487
|
-
* - Drop Nuxt-only `process.client` checks → use plain `typeof window !== 'undefined'`.
|
|
3488
|
-
* - Drop Arabic default placeholder; let consumers pass their own.
|
|
3489
|
-
* - Expand the offline fallback list from 2 → ~20 of the most-populated countries.
|
|
3490
|
-
* - Keep REST Countries fetch + localStorage cache + libphonenumber-js examples + fast `search_key`.
|
|
3491
|
-
*/
|
|
3492
|
-
const STORAGE_KEY = "ali_ui_phone_countries_v1";
|
|
3493
|
-
const REST_COUNTRIES_URL = "https://restcountries.com/v3.1/all?fields=name,cca2,idd,flags";
|
|
3494
|
-
const EX = libphonenumber_js_examples_mobile_json.default;
|
|
3495
|
-
const isBrowser$1 = () => typeof window !== "undefined";
|
|
3496
|
-
function toDigits(v) {
|
|
3497
|
-
return normalizeDigits(String(v ?? "")).replace(/\D/g, "");
|
|
3498
|
-
}
|
|
3499
|
-
/**
|
|
3500
|
-
* Render an ASCII digit string in a locale's numeral system (e.g. `'ar'` → `٠-٩`).
|
|
3501
|
-
* Used only for display hints — falls back to ASCII if the locale is unknown.
|
|
3502
|
-
*/
|
|
3503
|
-
function localizeDigits(digits, locale) {
|
|
3504
|
-
if (!locale) return digits;
|
|
3505
|
-
try {
|
|
3506
|
-
const fmt = new Intl.NumberFormat(locale, { useGrouping: false });
|
|
3507
|
-
return digits.replace(/[0-9]/g, (d) => fmt.format(Number(d)));
|
|
3508
|
-
} catch {
|
|
3509
|
-
return digits;
|
|
3510
|
-
}
|
|
3511
|
-
}
|
|
3512
|
-
function ensurePlusDial(dial) {
|
|
3513
|
-
const d = toDigits(dial);
|
|
3514
|
-
return d ? `+${d}` : "";
|
|
3515
|
-
}
|
|
3516
|
-
function normalizeIso2(iso2) {
|
|
3517
|
-
return String(iso2 ?? "").trim().toUpperCase();
|
|
3518
|
-
}
|
|
3519
|
-
function dropLeadingZeros(digits) {
|
|
3520
|
-
return String(digits ?? "").replace(/^0+/, "");
|
|
3521
|
-
}
|
|
3522
|
-
function buildFullE164(dial, digits) {
|
|
3523
|
-
const dialClean = ensurePlusDial(dial);
|
|
3524
|
-
const nsn = dropLeadingZeros(toDigits(digits));
|
|
3525
|
-
return dialClean && nsn ? `${dialClean}${nsn}` : null;
|
|
3526
|
-
}
|
|
3527
|
-
function inferLengthFromExample(national) {
|
|
3528
|
-
const d = toDigits(national);
|
|
3529
|
-
if (!d) return {
|
|
3530
|
-
min: null,
|
|
3531
|
-
max: null
|
|
3532
|
-
};
|
|
3533
|
-
const n = d.length;
|
|
3534
|
-
return {
|
|
3535
|
-
min: Math.max(4, n - 2),
|
|
3536
|
-
max: n + 2
|
|
3537
|
-
};
|
|
3538
|
-
}
|
|
3539
|
-
function buildDialCode(idd) {
|
|
3540
|
-
const root = idd?.root?.trim();
|
|
3541
|
-
if (!root || !root.startsWith("+")) return null;
|
|
3542
|
-
const out = `${root}${idd?.suffixes?.[0]?.trim() ?? ""}`;
|
|
3543
|
-
return out.startsWith("+") ? out : null;
|
|
3544
|
-
}
|
|
3545
|
-
function normalizeSearchKey(input) {
|
|
3546
|
-
return String(input ?? "").toLowerCase().replace(/\s+/g, " ").trim().replace(/[^\p{L}\p{N}+ ]/gu, "");
|
|
3547
|
-
}
|
|
3548
|
-
/**
|
|
3549
|
-
* Return a copy of the country list with display names localized to `locale` via
|
|
3550
|
-
* `Intl.DisplayNames`. `search_key` is rebuilt (keeping the English name too) so search
|
|
3551
|
-
* still matches either spelling. Unknown locales / regions fall back to the English name.
|
|
3552
|
-
*/
|
|
3553
|
-
function localizeCountries(list, locale) {
|
|
3554
|
-
if (!locale) return list;
|
|
3555
|
-
let display;
|
|
3556
|
-
try {
|
|
3557
|
-
display = new Intl.DisplayNames([locale], { type: "region" });
|
|
3558
|
-
} catch {
|
|
3559
|
-
return list;
|
|
3560
|
-
}
|
|
3561
|
-
return list.map((c) => {
|
|
3562
|
-
let localized = c.raw_data.name;
|
|
3563
|
-
try {
|
|
3564
|
-
localized = display.of(c.raw_data.iso2) || c.raw_data.name;
|
|
3565
|
-
} catch {}
|
|
3566
|
-
if (localized === c.raw_data.name) return c;
|
|
3567
|
-
const dial = c.raw_data.dial_code;
|
|
3568
|
-
return {
|
|
3569
|
-
...c,
|
|
3570
|
-
label: `${localized} (${dial})`,
|
|
3571
|
-
search_key: normalizeSearchKey(`${localized} ${c.raw_data.name} ${dial} ${c.raw_data.iso2} ${c.raw_data.dial_digits}`),
|
|
3572
|
-
raw_data: {
|
|
3573
|
-
...c.raw_data,
|
|
3574
|
-
name: localized
|
|
3575
|
-
}
|
|
3576
|
-
};
|
|
3577
|
-
});
|
|
3578
|
-
}
|
|
3579
|
-
function makeFallback(iso2, name, dial) {
|
|
3580
|
-
const dialDigits = toDigits(dial);
|
|
3581
|
-
return {
|
|
3582
|
-
label: `${name} (+${dialDigits})`,
|
|
3583
|
-
value: iso2,
|
|
3584
|
-
search_key: normalizeSearchKey(`${name} +${dialDigits} ${iso2}`),
|
|
3585
|
-
raw_data: {
|
|
3586
|
-
iso2,
|
|
3587
|
-
dial_code: `+${dialDigits}`,
|
|
3588
|
-
dial_digits: dialDigits,
|
|
3589
|
-
name,
|
|
3590
|
-
flag: `https://flagcdn.com/w40/${iso2.toLowerCase()}.png`,
|
|
3591
|
-
source: "fallback",
|
|
3592
|
-
original: {}
|
|
3593
|
-
}
|
|
3594
|
-
};
|
|
3595
|
-
}
|
|
3596
|
-
const FALLBACK_COUNTRIES = [
|
|
3597
|
-
makeFallback("SA", "Saudi Arabia", "+966"),
|
|
3598
|
-
makeFallback("EG", "Egypt", "+20"),
|
|
3599
|
-
makeFallback("AE", "United Arab Emirates", "+971"),
|
|
3600
|
-
makeFallback("US", "United States", "+1"),
|
|
3601
|
-
makeFallback("GB", "United Kingdom", "+44"),
|
|
3602
|
-
makeFallback("DE", "Germany", "+49"),
|
|
3603
|
-
makeFallback("FR", "France", "+33"),
|
|
3604
|
-
makeFallback("ES", "Spain", "+34"),
|
|
3605
|
-
makeFallback("IT", "Italy", "+39"),
|
|
3606
|
-
makeFallback("TR", "Turkey", "+90"),
|
|
3607
|
-
makeFallback("RU", "Russia", "+7"),
|
|
3608
|
-
makeFallback("CN", "China", "+86"),
|
|
3609
|
-
makeFallback("IN", "India", "+91"),
|
|
3610
|
-
makeFallback("JP", "Japan", "+81"),
|
|
3611
|
-
makeFallback("KR", "South Korea", "+82"),
|
|
3612
|
-
makeFallback("BR", "Brazil", "+55"),
|
|
3613
|
-
makeFallback("MX", "Mexico", "+52"),
|
|
3614
|
-
makeFallback("CA", "Canada", "+1"),
|
|
3615
|
-
makeFallback("AU", "Australia", "+61"),
|
|
3616
|
-
makeFallback("NG", "Nigeria", "+234"),
|
|
3617
|
-
makeFallback("PK", "Pakistan", "+92"),
|
|
3618
|
-
makeFallback("ID", "Indonesia", "+62")
|
|
3619
|
-
];
|
|
3620
|
-
function usePhoneValidation() {
|
|
3621
|
-
const countries = (0, vue.ref)([]);
|
|
3622
|
-
const isCountriesLoading = (0, vue.ref)(false);
|
|
3623
|
-
const byValue = (0, vue.ref)(/* @__PURE__ */ new Map());
|
|
3624
|
-
const byDialDigits = (0, vue.ref)(/* @__PURE__ */ new Map());
|
|
3625
|
-
function rebuildIndexes(list) {
|
|
3626
|
-
const valueMap = /* @__PURE__ */ new Map();
|
|
3627
|
-
const dialMap = /* @__PURE__ */ new Map();
|
|
3628
|
-
for (const item of list) {
|
|
3629
|
-
valueMap.set(item.value, item);
|
|
3630
|
-
const dial = item.raw_data.dial_digits;
|
|
3631
|
-
if (dial) {
|
|
3632
|
-
const bucket = dialMap.get(dial) ?? [];
|
|
3633
|
-
bucket.push(item);
|
|
3634
|
-
dialMap.set(dial, bucket);
|
|
3635
|
-
}
|
|
3636
|
-
}
|
|
3637
|
-
byValue.value = valueMap;
|
|
3638
|
-
byDialDigits.value = dialMap;
|
|
3639
|
-
}
|
|
3640
|
-
function upsertCountries(list) {
|
|
3641
|
-
countries.value = list;
|
|
3642
|
-
rebuildIndexes(list);
|
|
3643
|
-
}
|
|
3644
|
-
function normalizeRestCountries(list) {
|
|
3645
|
-
const out = [];
|
|
3646
|
-
for (const c of list) {
|
|
3647
|
-
const name = c?.name?.common?.trim();
|
|
3648
|
-
const iso2 = normalizeIso2(c?.cca2);
|
|
3649
|
-
const dial = buildDialCode(c?.idd);
|
|
3650
|
-
const flag = c?.flags?.png?.trim() || c?.flags?.svg?.trim() || null;
|
|
3651
|
-
if (!name || !iso2 || !dial) continue;
|
|
3652
|
-
const dialDigits = toDigits(dial);
|
|
3653
|
-
const search_key = normalizeSearchKey(`${name} ${dial} ${iso2} ${dialDigits}`);
|
|
3654
|
-
out.push({
|
|
3655
|
-
label: `${name} (${dial})`,
|
|
3656
|
-
value: iso2,
|
|
3657
|
-
search_key,
|
|
3658
|
-
raw_data: {
|
|
3659
|
-
iso2,
|
|
3660
|
-
dial_code: dial,
|
|
3661
|
-
dial_digits: dialDigits,
|
|
3662
|
-
name,
|
|
3663
|
-
flag,
|
|
3664
|
-
source: "restcountries",
|
|
3665
|
-
original: c
|
|
3666
|
-
}
|
|
3667
|
-
});
|
|
3668
|
-
}
|
|
3669
|
-
const map = /* @__PURE__ */ new Map();
|
|
3670
|
-
for (const item of out) {
|
|
3671
|
-
const prev = map.get(item.value);
|
|
3672
|
-
if (!prev) {
|
|
3673
|
-
map.set(item.value, item);
|
|
3674
|
-
continue;
|
|
3675
|
-
}
|
|
3676
|
-
const prevScore = (prev.raw_data.flag ? 1 : 0) + (prev.raw_data.dial_code ? 1 : 0);
|
|
3677
|
-
if ((item.raw_data.flag ? 1 : 0) + (item.raw_data.dial_code ? 1 : 0) > prevScore) map.set(item.value, item);
|
|
3678
|
-
}
|
|
3679
|
-
return Array.from(map.values()).sort((a, b) => a.raw_data.name.localeCompare(b.raw_data.name));
|
|
3680
|
-
}
|
|
3681
|
-
async function getCountries(options) {
|
|
3682
|
-
const force = Boolean(options?.force);
|
|
3683
|
-
if (!force && countries.value.length) return countries.value;
|
|
3684
|
-
if (!force && isBrowser$1()) try {
|
|
3685
|
-
const cached = localStorage.getItem(STORAGE_KEY);
|
|
3686
|
-
if (cached) {
|
|
3687
|
-
const parsed = JSON.parse(cached);
|
|
3688
|
-
if (Array.isArray(parsed) && parsed.length) {
|
|
3689
|
-
upsertCountries(parsed);
|
|
3690
|
-
return countries.value;
|
|
3691
|
-
}
|
|
3692
|
-
}
|
|
3693
|
-
} catch {}
|
|
3694
|
-
isCountriesLoading.value = true;
|
|
3695
|
-
try {
|
|
3696
|
-
const res = await fetch(REST_COUNTRIES_URL);
|
|
3697
|
-
if (!res.ok) throw new Error(`Failed to fetch countries: ${res.status}`);
|
|
3698
|
-
const normalized = normalizeRestCountries(await res.json());
|
|
3699
|
-
upsertCountries(normalized.length ? normalized : FALLBACK_COUNTRIES);
|
|
3700
|
-
if (isBrowser$1()) try {
|
|
3701
|
-
localStorage.setItem(STORAGE_KEY, JSON.stringify(countries.value));
|
|
3702
|
-
} catch {}
|
|
3703
|
-
return countries.value;
|
|
3704
|
-
} catch {
|
|
3705
|
-
upsertCountries(FALLBACK_COUNTRIES);
|
|
3706
|
-
return countries.value;
|
|
3707
|
-
} finally {
|
|
3708
|
-
isCountriesLoading.value = false;
|
|
3709
|
-
}
|
|
3710
|
-
}
|
|
3711
|
-
function searchCountries(keyword, limit = 50) {
|
|
3712
|
-
const q = normalizeSearchKey(keyword);
|
|
3713
|
-
if (!q) return countries.value.slice(0, limit);
|
|
3714
|
-
const res = [];
|
|
3715
|
-
for (const item of countries.value) if (item.search_key.includes(q)) {
|
|
3716
|
-
res.push(item);
|
|
3717
|
-
if (res.length >= limit) break;
|
|
3718
|
-
}
|
|
3719
|
-
return res;
|
|
3720
|
-
}
|
|
3721
|
-
function getCountryByValue(value) {
|
|
3722
|
-
return byValue.value.get(normalizeIso2(value)) ?? null;
|
|
3723
|
-
}
|
|
3724
|
-
function getCountriesByDial(dial) {
|
|
3725
|
-
return byDialDigits.value.get(toDigits(dial)) ?? [];
|
|
3726
|
-
}
|
|
3727
|
-
function getRequiredInfo(country, locale) {
|
|
3728
|
-
const iso2 = normalizeIso2(country.iso2);
|
|
3729
|
-
if (!iso2) return null;
|
|
3730
|
-
try {
|
|
3731
|
-
const example = (0, libphonenumber_js.getExampleNumber)(iso2, EX);
|
|
3732
|
-
const exampleNational = example?.formatNational?.() ?? "";
|
|
3733
|
-
const exampleE164 = example?.format?.("E.164") ?? "";
|
|
3734
|
-
const inferred = inferLengthFromExample(exampleNational);
|
|
3735
|
-
const dial_code = country.dial_code ? ensurePlusDial(country.dial_code) : exampleE164 ? `+${example?.countryCallingCode}` : "";
|
|
3736
|
-
const digitsExample = toDigits(exampleNational);
|
|
3737
|
-
return {
|
|
3738
|
-
iso2,
|
|
3739
|
-
dial_code,
|
|
3740
|
-
placeholder: "",
|
|
3741
|
-
example_national: exampleNational,
|
|
3742
|
-
example_e164: exampleE164,
|
|
3743
|
-
national_number_length: inferred,
|
|
3744
|
-
format_hint: digitsExample ? `e.g. ${localizeDigits(digitsExample, locale)}` : ""
|
|
3745
|
-
};
|
|
3746
|
-
} catch {
|
|
3747
|
-
return null;
|
|
3748
|
-
}
|
|
3749
|
-
}
|
|
3750
|
-
function validate(input) {
|
|
3751
|
-
const country = input.country ?? null;
|
|
3752
|
-
if (!country?.iso2) return {
|
|
3753
|
-
ok: false,
|
|
3754
|
-
reason: "missing_country",
|
|
3755
|
-
country: null,
|
|
3756
|
-
phone: {
|
|
3757
|
-
raw: ("phone" in input ? input.phone : null) ?? null,
|
|
3758
|
-
digits: ""
|
|
3759
|
-
},
|
|
3760
|
-
full_phone: null,
|
|
3761
|
-
required: null
|
|
3762
|
-
};
|
|
3763
|
-
const iso2 = normalizeIso2(country.iso2);
|
|
3764
|
-
const required = getRequiredInfo({
|
|
3765
|
-
iso2,
|
|
3766
|
-
dial_code: country.dial_code
|
|
3767
|
-
}, input.locale);
|
|
3768
|
-
if (!required) return {
|
|
3769
|
-
ok: false,
|
|
3770
|
-
reason: "country_not_supported",
|
|
3771
|
-
country: {
|
|
3772
|
-
iso2,
|
|
3773
|
-
dial_code: ensurePlusDial(country.dial_code)
|
|
3774
|
-
},
|
|
3775
|
-
phone: {
|
|
3776
|
-
raw: ("phone" in input ? input.phone : null) ?? null,
|
|
3777
|
-
digits: ""
|
|
3778
|
-
},
|
|
3779
|
-
full_phone: null,
|
|
3780
|
-
required: null
|
|
3781
|
-
};
|
|
3782
|
-
if (!("phone" in input)) return {
|
|
3783
|
-
ok: true,
|
|
3784
|
-
reason: null,
|
|
3785
|
-
country: {
|
|
3786
|
-
iso2: required.iso2,
|
|
3787
|
-
dial_code: required.dial_code
|
|
3788
|
-
},
|
|
3789
|
-
phone: {
|
|
3790
|
-
raw: null,
|
|
3791
|
-
digits: ""
|
|
3792
|
-
},
|
|
3793
|
-
full_phone: null,
|
|
3794
|
-
required
|
|
3795
|
-
};
|
|
3796
|
-
const raw = input.phone;
|
|
3797
|
-
const digits = toDigits(raw);
|
|
3798
|
-
if (!raw || !String(raw).trim()) return {
|
|
3799
|
-
ok: true,
|
|
3800
|
-
reason: null,
|
|
3801
|
-
country: {
|
|
3802
|
-
iso2: required.iso2,
|
|
3803
|
-
dial_code: required.dial_code
|
|
3804
|
-
},
|
|
3805
|
-
phone: {
|
|
3806
|
-
raw: raw ?? null,
|
|
3807
|
-
digits: ""
|
|
3808
|
-
},
|
|
3809
|
-
full_phone: null,
|
|
3810
|
-
required
|
|
3811
|
-
};
|
|
3812
|
-
if (String(raw).replace(/\s+/g, "").match(/[^\d+]/)) return {
|
|
3813
|
-
ok: false,
|
|
3814
|
-
reason: "phone_has_non_digits",
|
|
3815
|
-
country: {
|
|
3816
|
-
iso2: required.iso2,
|
|
3817
|
-
dial_code: required.dial_code
|
|
3818
|
-
},
|
|
3819
|
-
phone: {
|
|
3820
|
-
raw,
|
|
3821
|
-
digits
|
|
3822
|
-
},
|
|
3823
|
-
full_phone: buildFullE164(required.dial_code, digits),
|
|
3824
|
-
required
|
|
3825
|
-
};
|
|
3826
|
-
const nsn = dropLeadingZeros(digits);
|
|
3827
|
-
const { min, max } = required.national_number_length;
|
|
3828
|
-
if (min !== null && nsn.length < min) return {
|
|
3829
|
-
ok: false,
|
|
3830
|
-
reason: "too_short",
|
|
3831
|
-
country: {
|
|
3832
|
-
iso2: required.iso2,
|
|
3833
|
-
dial_code: required.dial_code
|
|
3834
|
-
},
|
|
3835
|
-
phone: {
|
|
3836
|
-
raw,
|
|
3837
|
-
digits
|
|
3838
|
-
},
|
|
3839
|
-
full_phone: buildFullE164(required.dial_code, digits),
|
|
3840
|
-
required,
|
|
3841
|
-
details: {
|
|
3842
|
-
min,
|
|
3843
|
-
actual: nsn.length
|
|
3844
|
-
}
|
|
3845
|
-
};
|
|
3846
|
-
if (max !== null && nsn.length > max) return {
|
|
3847
|
-
ok: false,
|
|
3848
|
-
reason: "too_long",
|
|
3849
|
-
country: {
|
|
3850
|
-
iso2: required.iso2,
|
|
3851
|
-
dial_code: required.dial_code
|
|
3852
|
-
},
|
|
3853
|
-
phone: {
|
|
3854
|
-
raw,
|
|
3855
|
-
digits
|
|
3856
|
-
},
|
|
3857
|
-
full_phone: buildFullE164(required.dial_code, digits),
|
|
3858
|
-
required,
|
|
3859
|
-
details: {
|
|
3860
|
-
max,
|
|
3861
|
-
actual: nsn.length
|
|
3862
|
-
}
|
|
3863
|
-
};
|
|
3864
|
-
const full = buildFullE164(required.dial_code, digits) ?? String(raw);
|
|
3865
|
-
try {
|
|
3866
|
-
if (!(0, libphonenumber_js.isValidPhoneNumber)(full, iso2)) {
|
|
3867
|
-
const parsed = (0, libphonenumber_js.parsePhoneNumberFromString)(full, iso2);
|
|
3868
|
-
return {
|
|
3869
|
-
ok: false,
|
|
3870
|
-
reason: "invalid_phone",
|
|
3871
|
-
country: {
|
|
3872
|
-
iso2: required.iso2,
|
|
3873
|
-
dial_code: required.dial_code
|
|
3874
|
-
},
|
|
3875
|
-
phone: {
|
|
3876
|
-
raw,
|
|
3877
|
-
digits
|
|
3878
|
-
},
|
|
3879
|
-
full_phone: parsed?.number ?? null,
|
|
3880
|
-
required,
|
|
3881
|
-
details: {
|
|
3882
|
-
type: parsed?.getType?.() ?? null,
|
|
3883
|
-
possible: parsed?.isPossible?.() ?? null,
|
|
3884
|
-
country: parsed?.country ?? null
|
|
3885
|
-
}
|
|
3886
|
-
};
|
|
3887
|
-
}
|
|
3888
|
-
const parsed = (0, libphonenumber_js.parsePhoneNumberFromString)(full, iso2);
|
|
3889
|
-
return {
|
|
3890
|
-
ok: true,
|
|
3891
|
-
reason: null,
|
|
3892
|
-
country: {
|
|
3893
|
-
iso2: required.iso2,
|
|
3894
|
-
dial_code: required.dial_code
|
|
3895
|
-
},
|
|
3896
|
-
phone: {
|
|
3897
|
-
raw,
|
|
3898
|
-
digits
|
|
3899
|
-
},
|
|
3900
|
-
full_phone: parsed?.number ?? full,
|
|
3901
|
-
required
|
|
3902
|
-
};
|
|
3903
|
-
} catch (e) {
|
|
3904
|
-
return {
|
|
3905
|
-
ok: false,
|
|
3906
|
-
reason: "parse_failed",
|
|
3907
|
-
country: {
|
|
3908
|
-
iso2: required.iso2,
|
|
3909
|
-
dial_code: required.dial_code
|
|
3910
|
-
},
|
|
3911
|
-
phone: {
|
|
3912
|
-
raw,
|
|
3913
|
-
digits
|
|
3914
|
-
},
|
|
3915
|
-
full_phone: buildFullE164(required.dial_code, digits),
|
|
3916
|
-
required,
|
|
3917
|
-
details: { error: e?.message ?? String(e) }
|
|
3918
|
-
};
|
|
3919
|
-
}
|
|
3920
|
-
}
|
|
3921
|
-
return {
|
|
3922
|
-
countries,
|
|
3923
|
-
isCountriesLoading,
|
|
3924
|
-
getCountries,
|
|
3925
|
-
searchCountries,
|
|
3926
|
-
getCountryByValue,
|
|
3927
|
-
getCountriesByDial,
|
|
3928
|
-
getRequiredInfo,
|
|
3929
|
-
validate
|
|
3930
|
-
};
|
|
3931
|
-
}
|
|
3932
|
-
//#endregion
|
|
3933
3408
|
//#region src/composables/useCountryDetection.ts
|
|
3934
3409
|
/**
|
|
3935
3410
|
* Best-effort country detection chain: IP geolocation → timezone → navigator.language → fallback.
|
|
@@ -4039,24 +3514,32 @@ function tryLocale() {
|
|
|
4039
3514
|
return null;
|
|
4040
3515
|
}
|
|
4041
3516
|
}
|
|
3517
|
+
const inflightIpFetch = /* @__PURE__ */ new Map();
|
|
4042
3518
|
async function tryIp(endpoint, timeoutMs) {
|
|
4043
3519
|
if (!isBrowser() || typeof fetch !== "function") return null;
|
|
3520
|
+
const existing = inflightIpFetch.get(endpoint);
|
|
3521
|
+
if (existing) return existing;
|
|
4044
3522
|
const controller = new AbortController();
|
|
4045
3523
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
3524
|
+
const promise = (async () => {
|
|
3525
|
+
try {
|
|
3526
|
+
const res = await fetch(endpoint, {
|
|
3527
|
+
signal: controller.signal,
|
|
3528
|
+
credentials: "omit"
|
|
3529
|
+
});
|
|
3530
|
+
if (!res.ok) return null;
|
|
3531
|
+
const data = await res.json();
|
|
3532
|
+
const code = (data.country_code ?? data.country ?? "").toString().toUpperCase();
|
|
3533
|
+
return /^[A-Z]{2}$/.test(code) ? code : null;
|
|
3534
|
+
} catch {
|
|
3535
|
+
return null;
|
|
3536
|
+
} finally {
|
|
3537
|
+
clearTimeout(timer);
|
|
3538
|
+
inflightIpFetch.delete(endpoint);
|
|
3539
|
+
}
|
|
3540
|
+
})();
|
|
3541
|
+
inflightIpFetch.set(endpoint, promise);
|
|
3542
|
+
return promise;
|
|
4060
3543
|
}
|
|
4061
3544
|
function readCache() {
|
|
4062
3545
|
if (!isBrowser()) return null;
|
|
@@ -4122,6 +3605,11 @@ function useCountryDetection(opts = {}) {
|
|
|
4122
3605
|
}
|
|
4123
3606
|
//#endregion
|
|
4124
3607
|
//#region src/composables/useCountryMatching.ts
|
|
3608
|
+
/** Cached snapshot of every country libphonenumber knows about (~250 ISO2 codes).
|
|
3609
|
+
* Used by tier 2 of `matchLeadingDialCode` as the last-resort iteration so detection
|
|
3610
|
+
* works for *every* country, not just the popular ones in the bundled fallback list.
|
|
3611
|
+
* Cached at module load — `getCountries()` is a static metadata table, no I/O. */
|
|
3612
|
+
const ALL_LIBPHONENUMBER_ISO2 = (0, libphonenumber_js.getCountries)();
|
|
4125
3613
|
/** Synchronous dial-digit → ISO2 fallback for common countries, used when the async
|
|
4126
3614
|
* REST Countries fetch hasn't populated `getCountriesByDial`'s index yet at setup. */
|
|
4127
3615
|
const DIAL_TO_ISO2_FALLBACK = {
|
|
@@ -4188,6 +3676,58 @@ const DIAL_TO_ISO2_FALLBACK = {
|
|
|
4188
3676
|
/** localStorage key for the user's most recently picked countries. Used as a
|
|
4189
3677
|
* tie-breaker when multiple countries share a dial code (e.g. all NANP). */
|
|
4190
3678
|
const COUNTRY_RECENTS_KEY = "ali_ui_country_recents_v1";
|
|
3679
|
+
/** ISO2 codes iterated by tier 2 of `matchLeadingDialCode` when looking for a country
|
|
3680
|
+
* that accepts a local-format input as valid. Mirrors the `FALLBACK_COUNTRIES` list in
|
|
3681
|
+
* {@link usePhoneValidation} (kept in sync by tests + by being short and obvious).
|
|
3682
|
+
* Order matters — earlier entries get priority when multiple countries would each
|
|
3683
|
+
* validate the same input. Built around the most-populated / most-likely countries. */
|
|
3684
|
+
const FALLBACK_ISO2_LIST = [
|
|
3685
|
+
"SA",
|
|
3686
|
+
"EG",
|
|
3687
|
+
"AE",
|
|
3688
|
+
"US",
|
|
3689
|
+
"GB",
|
|
3690
|
+
"DE",
|
|
3691
|
+
"FR",
|
|
3692
|
+
"ES",
|
|
3693
|
+
"IT",
|
|
3694
|
+
"TR",
|
|
3695
|
+
"RU",
|
|
3696
|
+
"CN",
|
|
3697
|
+
"IN",
|
|
3698
|
+
"JP",
|
|
3699
|
+
"KR",
|
|
3700
|
+
"BR",
|
|
3701
|
+
"MX",
|
|
3702
|
+
"CA",
|
|
3703
|
+
"AU",
|
|
3704
|
+
"NG",
|
|
3705
|
+
"PK",
|
|
3706
|
+
"ID"
|
|
3707
|
+
];
|
|
3708
|
+
/** Build a minimal `CountryOption` from libphonenumber metadata when the async REST
|
|
3709
|
+
* Countries list hasn't loaded the entry yet. Used so country **detection** works
|
|
3710
|
+
* generically for any libphonenumber country, not just the ~22 in the offline
|
|
3711
|
+
* fallback list. The picker will overwrite this synthetic record with the real one
|
|
3712
|
+
* (with localized name + flag) as soon as `getCountries()` resolves. */
|
|
3713
|
+
function buildSyntheticCountry(iso2, dialDigits) {
|
|
3714
|
+
const ISO2 = iso2.toUpperCase();
|
|
3715
|
+
const digits = String(dialDigits).replace(/\D/g, "");
|
|
3716
|
+
return {
|
|
3717
|
+
label: `${ISO2} (+${digits})`,
|
|
3718
|
+
value: ISO2,
|
|
3719
|
+
search_key: `${ISO2.toLowerCase()} +${digits} ${digits}`,
|
|
3720
|
+
raw_data: {
|
|
3721
|
+
iso2: ISO2,
|
|
3722
|
+
dial_code: `+${digits}`,
|
|
3723
|
+
dial_digits: digits,
|
|
3724
|
+
name: ISO2,
|
|
3725
|
+
flag: `https://flagcdn.com/w40/${ISO2.toLowerCase()}.png`,
|
|
3726
|
+
source: "fallback",
|
|
3727
|
+
original: {}
|
|
3728
|
+
}
|
|
3729
|
+
};
|
|
3730
|
+
}
|
|
4191
3731
|
function readRecents() {
|
|
4192
3732
|
if (typeof window === "undefined") return [];
|
|
4193
3733
|
try {
|
|
@@ -4233,38 +3773,75 @@ function useCountryMatching(deps) {
|
|
|
4233
3773
|
const n = Number(digits);
|
|
4234
3774
|
return Number.isFinite(n) ? n : null;
|
|
4235
3775
|
}
|
|
3776
|
+
const MATCHER_CACHE_MAX = 128;
|
|
3777
|
+
const matcherCache = /* @__PURE__ */ new Map();
|
|
3778
|
+
function readMatcherCache(key) {
|
|
3779
|
+
if (!matcherCache.has(key)) return void 0;
|
|
3780
|
+
const value = matcherCache.get(key);
|
|
3781
|
+
matcherCache.delete(key);
|
|
3782
|
+
matcherCache.set(key, value);
|
|
3783
|
+
return value;
|
|
3784
|
+
}
|
|
3785
|
+
function writeMatcherCache(key, value) {
|
|
3786
|
+
if (matcherCache.size >= MATCHER_CACHE_MAX) {
|
|
3787
|
+
const oldest = matcherCache.keys().next().value;
|
|
3788
|
+
if (oldest !== void 0) matcherCache.delete(oldest);
|
|
3789
|
+
}
|
|
3790
|
+
matcherCache.set(key, value);
|
|
3791
|
+
}
|
|
4236
3792
|
/** Three-tier match of the leading digits to a country:
|
|
4237
3793
|
* 1. libphonenumber international parse (handles NANP disambiguation).
|
|
4238
|
-
* 2. libphonenumber national-format parse
|
|
4239
|
-
* formats like Egyptian `01066105963` with no
|
|
3794
|
+
* 2. libphonenumber national-format parse, iterating through candidate hint
|
|
3795
|
+
* countries (handles local formats like Egyptian `01066105963` with no
|
|
3796
|
+
* dial-code prefix). Universal coverage via `getCountries()`.
|
|
4240
3797
|
* 3. Longest-prefix match against the dial-digits index, with the current
|
|
4241
|
-
* selection / recents as tie-breakers when multiple countries share a code.
|
|
3798
|
+
* selection / recents as tie-breakers when multiple countries share a code.
|
|
3799
|
+
*
|
|
3800
|
+
* Results are LRU-cached per input + context to avoid re-paying tier-2 iteration
|
|
3801
|
+
* cost when the user backspaces and retypes the same prefix. */
|
|
4242
3802
|
function matchLeadingDialCode(digits, options = {}) {
|
|
4243
3803
|
if (!digits) return null;
|
|
4244
3804
|
const { hintCountry, currentIso2 } = options;
|
|
3805
|
+
const cacheKey = `${digits}|${hintCountry ?? ""}|${currentIso2 ?? ""}`;
|
|
3806
|
+
const cached = readMatcherCache(cacheKey);
|
|
3807
|
+
if (cached !== void 0) return cached;
|
|
3808
|
+
const result = runMatch(digits, hintCountry, currentIso2);
|
|
3809
|
+
writeMatcherCache(cacheKey, result);
|
|
3810
|
+
return result;
|
|
3811
|
+
}
|
|
3812
|
+
function runMatch(digits, hintCountry, currentIso2) {
|
|
4245
3813
|
try {
|
|
4246
3814
|
const parsed = (0, libphonenumber_js.parsePhoneNumberFromString)(`+${digits}`);
|
|
4247
|
-
if (parsed?.country && parsed.countryCallingCode) {
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
nationalNumber: String(parsed.nationalNumber ?? "")
|
|
4252
|
-
};
|
|
4253
|
-
}
|
|
4254
|
-
} catch {}
|
|
4255
|
-
if (hintCountry && digits.length >= 4) try {
|
|
4256
|
-
const parsed = (0, libphonenumber_js.parsePhoneNumberFromString)(digits, hintCountry);
|
|
4257
|
-
if (parsed?.isValid()) {
|
|
4258
|
-
const matched = getCountryByValue(parsed.country || hintCountry);
|
|
4259
|
-
if (matched) return {
|
|
4260
|
-
country: matched,
|
|
4261
|
-
nationalNumber: String(parsed.nationalNumber ?? "")
|
|
4262
|
-
};
|
|
4263
|
-
}
|
|
3815
|
+
if (parsed?.country && parsed.countryCallingCode) return {
|
|
3816
|
+
country: getCountryByValue(parsed.country) ?? buildSyntheticCountry(parsed.country, String(parsed.countryCallingCode)),
|
|
3817
|
+
nationalNumber: String(parsed.nationalNumber ?? "")
|
|
3818
|
+
};
|
|
4264
3819
|
} catch {}
|
|
3820
|
+
if (digits.length >= 4) {
|
|
3821
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
3822
|
+
if (hintCountry) candidates.add(hintCountry.toUpperCase());
|
|
3823
|
+
if (currentIso2) candidates.add(currentIso2.toUpperCase());
|
|
3824
|
+
for (const recent of readRecents()) candidates.add(recent.toUpperCase());
|
|
3825
|
+
for (const fallback of FALLBACK_ISO2_LIST) candidates.add(fallback);
|
|
3826
|
+
for (const all of ALL_LIBPHONENUMBER_ISO2) candidates.add(all);
|
|
3827
|
+
for (const iso2 of candidates) try {
|
|
3828
|
+
const parsed = (0, libphonenumber_js.parsePhoneNumberFromString)(digits, iso2);
|
|
3829
|
+
if (parsed?.isValid()) {
|
|
3830
|
+
const resolvedIso2 = parsed.country || iso2;
|
|
3831
|
+
return {
|
|
3832
|
+
country: getCountryByValue(resolvedIso2) ?? buildSyntheticCountry(resolvedIso2, String(parsed.countryCallingCode ?? "")),
|
|
3833
|
+
nationalNumber: String(parsed.nationalNumber ?? "")
|
|
3834
|
+
};
|
|
3835
|
+
}
|
|
3836
|
+
} catch {}
|
|
3837
|
+
}
|
|
4265
3838
|
for (let len = Math.min(3, digits.length); len >= 1; len--) {
|
|
4266
3839
|
const prefix = digits.slice(0, len);
|
|
4267
|
-
|
|
3840
|
+
let group = getCountriesByDial(prefix);
|
|
3841
|
+
if (!group.length) {
|
|
3842
|
+
const iso2 = DIAL_TO_ISO2_FALLBACK[prefix];
|
|
3843
|
+
if (iso2) group = [getCountryByValue(iso2) ?? buildSyntheticCountry(iso2, prefix)];
|
|
3844
|
+
}
|
|
4268
3845
|
if (!group.length) continue;
|
|
4269
3846
|
const nationalNumber = digits.slice(prefix.length);
|
|
4270
3847
|
if (group.length === 1) return {
|
|
@@ -4336,18 +3913,36 @@ function useTelInputValidation(deps, inputs, config) {
|
|
|
4336
3913
|
phone: inputs.phone.value ?? "",
|
|
4337
3914
|
locale: config.locale()
|
|
4338
3915
|
}));
|
|
3916
|
+
const externalErrorActive = (0, vue.computed)(() => {
|
|
3917
|
+
const e = config.externalError();
|
|
3918
|
+
return typeof e === "string" && e.length > 0;
|
|
3919
|
+
});
|
|
4339
3920
|
const validationState = (0, vue.computed)(() => {
|
|
3921
|
+
if (externalErrorActive.value) return "error";
|
|
4340
3922
|
if (!inputs.phone.value) return "idle";
|
|
4341
3923
|
return validation.value.ok ? "valid" : "error";
|
|
4342
3924
|
});
|
|
4343
|
-
const visibleValidationState = (0, vue.computed)(() =>
|
|
3925
|
+
const visibleValidationState = (0, vue.computed)(() => {
|
|
3926
|
+
if (externalErrorActive.value) return "error";
|
|
3927
|
+
const mode = config.validateOn() ?? "change";
|
|
3928
|
+
if (mode === "eager") return validationState.value;
|
|
3929
|
+
if (mode === "blur" && !inputs.hasBlurred.value) return "idle";
|
|
3930
|
+
return inputs.hasFinishedTyping.value ? validationState.value : "idle";
|
|
3931
|
+
});
|
|
4344
3932
|
const errorMessage = (0, vue.computed)(() => {
|
|
3933
|
+
const ext = config.externalError();
|
|
3934
|
+
if (typeof ext === "string" && ext.length > 0) return ext;
|
|
4345
3935
|
const v = validation.value;
|
|
4346
3936
|
if (v.ok || !v.reason) return null;
|
|
4347
3937
|
if (!inputs.phone.value) return null;
|
|
4348
3938
|
return config.errorMessages()?.[v.reason] ?? inputs.messages.value.errorMessages[v.reason];
|
|
4349
3939
|
});
|
|
4350
|
-
const showError = (0, vue.computed)(() =>
|
|
3940
|
+
const showError = (0, vue.computed)(() => {
|
|
3941
|
+
if (!errorMessage.value) return false;
|
|
3942
|
+
if (externalErrorActive.value) return true;
|
|
3943
|
+
if (!config.showValidation()) return false;
|
|
3944
|
+
return visibleValidationState.value === "error";
|
|
3945
|
+
});
|
|
4351
3946
|
return {
|
|
4352
3947
|
validation,
|
|
4353
3948
|
required,
|
|
@@ -4363,54 +3958,88 @@ function useTelInputValidation(deps, inputs, config) {
|
|
|
4363
3958
|
};
|
|
4364
3959
|
}
|
|
4365
3960
|
//#endregion
|
|
4366
|
-
//#region src/
|
|
4367
|
-
const aTelInputVariants = (0, class_variance_authority.cva)("a-tel-input__field", {
|
|
4368
|
-
variants: { size: {
|
|
4369
|
-
xs: "",
|
|
4370
|
-
sm: "",
|
|
4371
|
-
md: "",
|
|
4372
|
-
lg: "",
|
|
4373
|
-
xl: ""
|
|
4374
|
-
} },
|
|
4375
|
-
defaultVariants: { size: "md" }
|
|
4376
|
-
});
|
|
4377
|
-
const DEFAULT_ERROR_MESSAGES = {
|
|
4378
|
-
missing_country: "Please select a country.",
|
|
4379
|
-
country_not_supported: "This country is not supported.",
|
|
4380
|
-
phone_has_non_digits: "Phone number can only contain digits.",
|
|
4381
|
-
too_short: "Phone number is too short.",
|
|
4382
|
-
too_long: "Phone number is too long.",
|
|
4383
|
-
invalid_phone: "Phone number is invalid.",
|
|
4384
|
-
parse_failed: "Could not parse phone number."
|
|
4385
|
-
};
|
|
4386
|
-
/** English defaults for every {@link TelInputMessages} key. */
|
|
4387
|
-
const DEFAULT_MESSAGES = {
|
|
4388
|
-
searchPlaceholder: "Search country or +code…",
|
|
4389
|
-
emptyText: "No countries found.",
|
|
4390
|
-
loadingText: "Loading countries…",
|
|
4391
|
-
suggestedLabel: "Suggested",
|
|
4392
|
-
allCountriesLabel: "All countries",
|
|
4393
|
-
errorMessages: DEFAULT_ERROR_MESSAGES,
|
|
4394
|
-
countryLabel: "Country",
|
|
4395
|
-
selectCountryLabel: "Select country",
|
|
4396
|
-
phoneInputLabel: "Phone number"
|
|
4397
|
-
};
|
|
3961
|
+
//#region src/composables/useCountrySelection.ts
|
|
4398
3962
|
/**
|
|
4399
|
-
*
|
|
4400
|
-
*
|
|
3963
|
+
* The picker selection state machine for {@link ATelInput}, consolidated into a
|
|
3964
|
+
* single composable so the component doesn't have to juggle three boolean flags
|
|
3965
|
+
* (`userPickedCountry` / `autoSettingCountry` / `inputDetectionApplied`) and
|
|
3966
|
+
* reason about their pairwise interactions.
|
|
3967
|
+
*
|
|
3968
|
+
* Every write to the selection goes through {@link UseCountrySelectionReturn.set},
|
|
3969
|
+
* which records both the new ISO2 and the *origin* of the change. That makes the
|
|
3970
|
+
* downstream decision — should detection re-route the picker on the next typed-input
|
|
3971
|
+
* burst? — a one-liner: `if (detectionLocked.value) return;`.
|
|
4401
3972
|
*/
|
|
4402
|
-
function
|
|
4403
|
-
|
|
3973
|
+
function useCountrySelection() {
|
|
3974
|
+
const iso2 = (0, vue.ref)("");
|
|
3975
|
+
const source = (0, vue.ref)("none");
|
|
3976
|
+
function set(nextIso2, nextSource) {
|
|
3977
|
+
iso2.value = nextIso2;
|
|
3978
|
+
source.value = nextSource;
|
|
3979
|
+
}
|
|
3980
|
+
function clear() {
|
|
3981
|
+
iso2.value = "";
|
|
3982
|
+
source.value = "none";
|
|
3983
|
+
}
|
|
4404
3984
|
return {
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
}
|
|
3985
|
+
iso2,
|
|
3986
|
+
source,
|
|
3987
|
+
set,
|
|
3988
|
+
clear,
|
|
3989
|
+
detectionLocked: (0, vue.computed)(() => source.value === "picker" || source.value === "input")
|
|
4411
3990
|
};
|
|
4412
3991
|
}
|
|
4413
3992
|
//#endregion
|
|
3993
|
+
//#region src/composables/useSyncedModel.ts
|
|
3994
|
+
/**
|
|
3995
|
+
* Two-way bidirectional sync between a `defineModel` ref and internal component
|
|
3996
|
+
* state — with the **echo-loop guard** built in. Solves a recurring class of
|
|
3997
|
+
* bugs in this component where two watchers (external→internal and
|
|
3998
|
+
* internal→external) would fight each other and rewrite values the user just
|
|
3999
|
+
* typed.
|
|
4000
|
+
*
|
|
4001
|
+
* Mechanics:
|
|
4002
|
+
*
|
|
4003
|
+
* 1. When any of `triggers` change AND we're not currently applying an
|
|
4004
|
+
* external write, recompute the model value via `compose()` and write it
|
|
4005
|
+
* into `model`. Stamp `lastEmitted` first so we recognise the echo.
|
|
4006
|
+
* 2. When `model` changes AND the new value isn't the echo of our last emit,
|
|
4007
|
+
* apply it into internal state via `apply()`. The `applying` flag is held
|
|
4008
|
+
* for the duration of `apply()` so step (1) skips while we mutate.
|
|
4009
|
+
*
|
|
4010
|
+
* Used for:
|
|
4011
|
+
* - `modelValue` (E.164 string) ↔ `phone` + `selectedIso2`.
|
|
4012
|
+
* - `country` (dial-number) ↔ `selectedIso2`.
|
|
4013
|
+
*
|
|
4014
|
+
* The hand-rolled equivalents (`applyingModelValue` / `lastEmittedModelValue`
|
|
4015
|
+
* plus the country↔iso2 watcher pair with `autoSettingCountry`) collapse into
|
|
4016
|
+
* two calls to this helper.
|
|
4017
|
+
*/
|
|
4018
|
+
function useSyncedModel(options) {
|
|
4019
|
+
const { model, triggers, compose, apply } = options;
|
|
4020
|
+
const isEqual = options.isEqual ?? Object.is;
|
|
4021
|
+
let applying = false;
|
|
4022
|
+
let lastEmitted = { __unset: true };
|
|
4023
|
+
const isEcho = (v) => typeof lastEmitted === "object" && lastEmitted !== null && "__unset" in lastEmitted ? false : isEqual(v, lastEmitted);
|
|
4024
|
+
(0, vue.watch)(model, (next) => {
|
|
4025
|
+
if (isEcho(next)) return;
|
|
4026
|
+
applying = true;
|
|
4027
|
+
try {
|
|
4028
|
+
apply(next);
|
|
4029
|
+
} finally {
|
|
4030
|
+
applying = false;
|
|
4031
|
+
}
|
|
4032
|
+
}, { immediate: true });
|
|
4033
|
+
(0, vue.watch)(triggers, () => {
|
|
4034
|
+
if (applying) return;
|
|
4035
|
+
const next = compose();
|
|
4036
|
+
if (!isEqual(next, model.value)) {
|
|
4037
|
+
lastEmitted = next;
|
|
4038
|
+
model.value = next;
|
|
4039
|
+
}
|
|
4040
|
+
}, { flush: "post" });
|
|
4041
|
+
}
|
|
4042
|
+
//#endregion
|
|
4414
4043
|
//#region ../AResponsivePopover/dist/index.js
|
|
4415
4044
|
var __defProp = Object.defineProperty;
|
|
4416
4045
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -16975,11 +16604,6 @@ const _sfc_main$2$2 = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
16975
16604
|
const open = (0, vue.useModel)(__props, "open");
|
|
16976
16605
|
const isDesktop = (0, _vueuse_core.useMediaQuery)(() => props.breakpoint);
|
|
16977
16606
|
/**
|
|
16978
|
-
* Pre-imported on both branches — do NOT lazy-load. Switching the component identity at runtime
|
|
16979
|
-
* means we still hydrate the right tree client-side.
|
|
16980
|
-
*/
|
|
16981
|
-
const Root = (0, vue.computed)(() => isDesktop.value ? APopover_default : ADrawer_default);
|
|
16982
|
-
/**
|
|
16983
16607
|
* Per-branch `modal` resolution — the two roots interpret the prop differently:
|
|
16984
16608
|
*
|
|
16985
16609
|
* APopover (desktop, reka-ui): `modal=true` triggers `PopoverContentModal` + its
|
|
@@ -16996,7 +16620,7 @@ const _sfc_main$2$2 = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
16996
16620
|
return props.scrollLock === "body";
|
|
16997
16621
|
});
|
|
16998
16622
|
const drawerModal = (0, vue.computed)(() => props.modal !== false);
|
|
16999
|
-
const
|
|
16623
|
+
const drawerNoBodyStyles = (0, vue.computed)(() => props.scrollLock !== "body");
|
|
17000
16624
|
provideResponsivePopoverContext({
|
|
17001
16625
|
open: (0, vue.computed)(() => open.value ?? false),
|
|
17002
16626
|
isDesktop: (0, vue.computed)(() => isDesktop.value),
|
|
@@ -17006,10 +16630,15 @@ const _sfc_main$2$2 = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
17006
16630
|
props,
|
|
17007
16631
|
open,
|
|
17008
16632
|
isDesktop,
|
|
17009
|
-
Root,
|
|
17010
16633
|
rekaModal,
|
|
17011
16634
|
drawerModal,
|
|
17012
|
-
|
|
16635
|
+
drawerNoBodyStyles,
|
|
16636
|
+
get APopover() {
|
|
16637
|
+
return APopover_default;
|
|
16638
|
+
},
|
|
16639
|
+
get ADrawer() {
|
|
16640
|
+
return ADrawer_default;
|
|
16641
|
+
}
|
|
17013
16642
|
};
|
|
17014
16643
|
Object.defineProperty(__returned__, "__isScriptSetup", {
|
|
17015
16644
|
enumerable: false,
|
|
@@ -17019,15 +16648,30 @@ const _sfc_main$2$2 = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
17019
16648
|
}
|
|
17020
16649
|
});
|
|
17021
16650
|
function _sfc_render$2$2(_ctx, _cache, $props, $setup, $data, $options) {
|
|
17022
|
-
return (0, vue.openBlock)(), (0, vue.createBlock)(
|
|
16651
|
+
return $setup.isDesktop ? ((0, vue.openBlock)(), (0, vue.createBlock)($setup["APopover"], {
|
|
16652
|
+
key: 0,
|
|
17023
16653
|
open: $setup.open,
|
|
17024
16654
|
"onUpdate:open": _cache[0] || (_cache[0] = ($event) => $setup.open = $event),
|
|
17025
|
-
modal: $setup.
|
|
16655
|
+
modal: $setup.rekaModal,
|
|
16656
|
+
"data-slot": "responsive-popover"
|
|
16657
|
+
}, {
|
|
16658
|
+
default: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "default", { isDesktop: true })]),
|
|
16659
|
+
_: 3
|
|
16660
|
+
}, 8, ["open", "modal"])) : ((0, vue.openBlock)(), (0, vue.createBlock)($setup["ADrawer"], {
|
|
16661
|
+
key: 1,
|
|
16662
|
+
open: $setup.open,
|
|
16663
|
+
"onUpdate:open": _cache[1] || (_cache[1] = ($event) => $setup.open = $event),
|
|
16664
|
+
modal: $setup.drawerModal,
|
|
16665
|
+
"no-body-styles": $setup.drawerNoBodyStyles,
|
|
17026
16666
|
"data-slot": "responsive-popover"
|
|
17027
16667
|
}, {
|
|
17028
|
-
default: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "default", { isDesktop:
|
|
16668
|
+
default: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "default", { isDesktop: false })]),
|
|
17029
16669
|
_: 3
|
|
17030
|
-
},
|
|
16670
|
+
}, 8, [
|
|
16671
|
+
"open",
|
|
16672
|
+
"modal",
|
|
16673
|
+
"no-body-styles"
|
|
16674
|
+
]));
|
|
17031
16675
|
}
|
|
17032
16676
|
var AResponsivePopover_default = /* @__PURE__ */ export_helper_default$3(_sfc_main$2$2, [["render", _sfc_render$2$2], ["__file", "/Users/alikhalill/Desktop/my-projects/ali-nuxt-toolkit/packages/ui-components/AResponsivePopover/src/components/AResponsivePopover.vue"]]);
|
|
17033
16677
|
const _sfc_main$1$2 = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
@@ -17140,7 +16784,7 @@ const _sfc_main$9 = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
17140
16784
|
if (typeof document === "undefined") return [];
|
|
17141
16785
|
return Array.from(document.querySelectorAll("[data-responsive-popover-scroll-container=\"true\"]"));
|
|
17142
16786
|
},
|
|
17143
|
-
active: (0, vue.computed)(() => !!ctx?.open.value &&
|
|
16787
|
+
active: (0, vue.computed)(() => !!ctx?.open.value && scrollLockMode.value === "events")
|
|
17144
16788
|
});
|
|
17145
16789
|
const __returned__ = {
|
|
17146
16790
|
props,
|
|
@@ -17186,7 +16830,8 @@ function _sfc_render$9(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
17186
16830
|
])) : ((0, vue.openBlock)(), (0, vue.createBlock)($setup["ADrawerContent"], {
|
|
17187
16831
|
key: 1,
|
|
17188
16832
|
class: (0, vue.normalizeClass)($setup.mergedClass),
|
|
17189
|
-
"data-slot": "responsive-popover-content"
|
|
16833
|
+
"data-slot": "responsive-popover-content",
|
|
16834
|
+
"data-responsive-popover-scroll-container": "true"
|
|
17190
16835
|
}, {
|
|
17191
16836
|
default: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "default")]),
|
|
17192
16837
|
_: 3
|
|
@@ -17597,11 +17242,11 @@ const _sfc_main$1 = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
17597
17242
|
setup(__props, { expose: __expose }) {
|
|
17598
17243
|
const props = __props;
|
|
17599
17244
|
const selected = (0, vue.useModel)(__props, "selected");
|
|
17600
|
-
const { countries: internalCountries, isCountriesLoading, getCountries, searchCountries: defaultSearch, getCountryByValue: lookupInternal } = usePhoneValidation();
|
|
17245
|
+
const { countries: internalCountries, isCountriesLoading, getCountries, searchCountries: defaultSearch, getCountryByValue: lookupInternal } = require_usePhoneValidation.usePhoneValidation();
|
|
17601
17246
|
const open = (0, vue.ref)(false);
|
|
17602
17247
|
const search = (0, vue.ref)("");
|
|
17603
17248
|
getCountries();
|
|
17604
|
-
const effectiveCountries = (0, vue.computed)(() => props.countries && props.countries.length ? props.countries : localizeCountries(internalCountries.value, props.locale));
|
|
17249
|
+
const effectiveCountries = (0, vue.computed)(() => props.countries && props.countries.length ? props.countries : require_usePhoneValidation.localizeCountries(internalCountries.value, props.locale));
|
|
17605
17250
|
const effectiveByValue = (0, vue.computed)(() => new Map(effectiveCountries.value.map((c) => [c.value, c])));
|
|
17606
17251
|
function lookup(iso2) {
|
|
17607
17252
|
if (!iso2) return null;
|
|
@@ -17845,7 +17490,7 @@ const _hoisted_6$1 = {
|
|
|
17845
17490
|
};
|
|
17846
17491
|
const _hoisted_7$1 = { class: "a-country-select__list" };
|
|
17847
17492
|
const _hoisted_8$1 = { class: "a-country-select__loading" };
|
|
17848
|
-
const _hoisted_9 = { class: "a-country-select__empty" };
|
|
17493
|
+
const _hoisted_9$1 = { class: "a-country-select__empty" };
|
|
17849
17494
|
const _hoisted_10 = {
|
|
17850
17495
|
key: 0,
|
|
17851
17496
|
"data-slot": "country-select-group",
|
|
@@ -17943,7 +17588,7 @@ function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
17943
17588
|
(0, vue.createElementVNode)("div", _hoisted_7$1, [$setup.isCountriesLoading && $setup.effectiveCountries.length === 0 ? (0, vue.renderSlot)(_ctx.$slots, "loading", { key: 0 }, () => [(0, vue.createElementVNode)("div", _hoisted_8$1, (0, vue.toDisplayString)($setup.props.loadingText), 1)], true) : $setup.isSearching && $setup.filtered.length === 0 ? (0, vue.renderSlot)(_ctx.$slots, "empty", {
|
|
17944
17589
|
key: 1,
|
|
17945
17590
|
query: $setup.search
|
|
17946
|
-
}, () => [(0, vue.createElementVNode)("div", _hoisted_9, (0, vue.toDisplayString)($setup.props.emptyText), 1)], true) : ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 2 }, [
|
|
17591
|
+
}, () => [(0, vue.createElementVNode)("div", _hoisted_9$1, (0, vue.toDisplayString)($setup.props.emptyText), 1)], true) : ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 2 }, [
|
|
17947
17592
|
(0, vue.createCommentVNode)(" Suggested group "),
|
|
17948
17593
|
$setup.suggested.length > 0 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("section", _hoisted_10, [(0, vue.renderSlot)(_ctx.$slots, "group-header", {
|
|
17949
17594
|
label: $setup.props.suggestedLabel,
|
|
@@ -18072,6 +17717,27 @@ const _sfc_main = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
18072
17717
|
required: false,
|
|
18073
17718
|
skipCheck: true
|
|
18074
17719
|
},
|
|
17720
|
+
modelValue: {
|
|
17721
|
+
type: String,
|
|
17722
|
+
required: false
|
|
17723
|
+
},
|
|
17724
|
+
name: {
|
|
17725
|
+
type: String,
|
|
17726
|
+
required: false
|
|
17727
|
+
},
|
|
17728
|
+
error: {
|
|
17729
|
+
type: [String, null],
|
|
17730
|
+
required: false
|
|
17731
|
+
},
|
|
17732
|
+
validating: {
|
|
17733
|
+
type: Boolean,
|
|
17734
|
+
required: false
|
|
17735
|
+
},
|
|
17736
|
+
validateOn: {
|
|
17737
|
+
type: String,
|
|
17738
|
+
required: false,
|
|
17739
|
+
default: "change"
|
|
17740
|
+
},
|
|
18075
17741
|
placeholder: {
|
|
18076
17742
|
type: String,
|
|
18077
17743
|
required: false,
|
|
@@ -18214,28 +17880,65 @@ const _sfc_main = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
18214
17880
|
type: [Number, null],
|
|
18215
17881
|
default: null
|
|
18216
17882
|
},
|
|
18217
|
-
"countryModifiers": {}
|
|
17883
|
+
"countryModifiers": {},
|
|
17884
|
+
"modelValue": {
|
|
17885
|
+
type: String,
|
|
17886
|
+
default: ""
|
|
17887
|
+
},
|
|
17888
|
+
"modelModifiers": {}
|
|
18218
17889
|
}),
|
|
18219
|
-
emits:
|
|
18220
|
-
|
|
17890
|
+
emits: /* @__PURE__ */ (0, vue.mergeModels)([
|
|
17891
|
+
"update:modelValue",
|
|
17892
|
+
"update:phone",
|
|
17893
|
+
"update:country",
|
|
17894
|
+
"blur",
|
|
17895
|
+
"focus"
|
|
17896
|
+
], [
|
|
17897
|
+
"update:phone",
|
|
17898
|
+
"update:country",
|
|
17899
|
+
"update:modelValue"
|
|
17900
|
+
]),
|
|
17901
|
+
setup(__props, { expose: __expose, emit: __emit }) {
|
|
18221
17902
|
const props = __props;
|
|
17903
|
+
const emit = __emit;
|
|
18222
17904
|
const phone = (0, vue.useModel)(__props, "phone");
|
|
18223
17905
|
/** Public `v-model:country` — the **dial number** (e.g. `20` for Egypt, `44` for the UK,
|
|
18224
17906
|
* `1` for the NANP block). `null` means no country selected. Internally the component
|
|
18225
17907
|
* tracks a richer ISO2 code (`selectedIso2`) because dial codes alone can't disambiguate
|
|
18226
17908
|
* NANP (`+1` covers 25+ countries) — the picker still needs an exact country. */
|
|
18227
17909
|
const country = (0, vue.useModel)(__props, "country");
|
|
18228
|
-
/**
|
|
18229
|
-
*
|
|
18230
|
-
|
|
18231
|
-
|
|
17910
|
+
/**
|
|
17911
|
+
* Default v-model — the canonical **E.164** string (e.g. `'+201066105963'`).
|
|
17912
|
+
*
|
|
17913
|
+
* Single-string contract for VeeValidate's `<Field v-slot="{ field }">` pattern
|
|
17914
|
+
* (`v-bind="field"`), native `<form>` submission, or any `v-model="phoneE164"`
|
|
17915
|
+
* consumer. Bind it with:
|
|
17916
|
+
*
|
|
17917
|
+
* <ATelInput v-model="phoneE164" />
|
|
17918
|
+
*
|
|
17919
|
+
* <VeeField v-slot="{ field, errors }" name="phone">
|
|
17920
|
+
* <ATelInput v-bind="field" :error="errors[0]" />
|
|
17921
|
+
* </VeeField>
|
|
17922
|
+
*
|
|
17923
|
+
* When set externally, the value is parsed via libphonenumber-js → the country
|
|
17924
|
+
* picker and the digits-only `phone` model are derived from it. When the user
|
|
17925
|
+
* types or picks a country, the composed E.164 is written back out. Stays in
|
|
17926
|
+
* sync with `v-model:phone` / `v-model:country` — you can use either contract.
|
|
17927
|
+
*/
|
|
17928
|
+
const modelValue = (0, vue.useModel)(__props, "modelValue");
|
|
17929
|
+
/** The picker selection state machine — `iso2` is the internal source of truth, `source`
|
|
17930
|
+
* records where the current selection came from, `detectionLocked` answers "should
|
|
17931
|
+
* typed-input detection re-route the picker on the next burst?". Single mutator: `set`.
|
|
17932
|
+
* Replaces the historical flag soup (`userPickedCountry` / `autoSettingCountry` /
|
|
17933
|
+
* `inputDetectionApplied`). */
|
|
17934
|
+
const selection = useCountrySelection();
|
|
17935
|
+
const selectedIso2 = selection.iso2;
|
|
17936
|
+
const { getCountries, validate, getRequiredInfo, getCountryByValue, getCountriesByDial } = require_usePhoneValidation.usePhoneValidation();
|
|
18232
17937
|
const { resolveCountryIdentifier, dialNumberFor, matchLeadingDialCode } = useCountryMatching({
|
|
18233
17938
|
getCountryByValue,
|
|
18234
17939
|
getCountriesByDial
|
|
18235
17940
|
});
|
|
18236
17941
|
getCountries();
|
|
18237
|
-
const userPickedCountry = (0, vue.ref)(false);
|
|
18238
|
-
const autoSettingCountry = (0, vue.ref)(false);
|
|
18239
17942
|
/** Silently resolved via IP/timezone/locale when `detectFromInput` is on — used as a hint
|
|
18240
17943
|
* so local-format numbers (e.g. Egyptian `01066105963`) can be parsed without a `+` prefix.
|
|
18241
17944
|
* Seeded from `defaultCountry` so it has a usable value before async detection resolves. */
|
|
@@ -18249,18 +17952,28 @@ const _sfc_main = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
18249
17952
|
currentIso2: selectedIso2.value
|
|
18250
17953
|
});
|
|
18251
17954
|
}
|
|
17955
|
+
/** User explicitly picked a country from the picker — locks the selection so subsequent
|
|
17956
|
+
* typed-input detection cannot churn the picker. */
|
|
17957
|
+
function onPickerPick(iso2) {
|
|
17958
|
+
selection.set(iso2, "picker");
|
|
17959
|
+
}
|
|
18252
17960
|
const typing = useTypingPhase({
|
|
18253
17961
|
debounceMs: (0, vue.computed)(() => Math.max(0, props.detectDebounceMs)),
|
|
18254
17962
|
onSettle: () => {
|
|
18255
17963
|
if (!props.detectFromInput) return;
|
|
18256
|
-
if (
|
|
17964
|
+
if (selection.detectionLocked.value) return;
|
|
18257
17965
|
const current = phone.value;
|
|
18258
17966
|
if (!current) return;
|
|
17967
|
+
const typedInternational = (displayValue.value ?? "").trimStart().startsWith("+");
|
|
17968
|
+
if (selectedIso2.value && !typedInternational) return;
|
|
18259
17969
|
typing.markDetectionAttempt();
|
|
18260
17970
|
const match = tryMatchPhone(current);
|
|
18261
17971
|
if (!match) return;
|
|
18262
|
-
|
|
18263
|
-
|
|
17972
|
+
if (match.country.value === selectedIso2.value && match.nationalNumber === phone.value) {
|
|
17973
|
+
selection.source.value = "input";
|
|
17974
|
+
return;
|
|
17975
|
+
}
|
|
17976
|
+
selection.set(match.country.value, "input");
|
|
18264
17977
|
phone.value = match.nationalNumber;
|
|
18265
17978
|
}
|
|
18266
17979
|
});
|
|
@@ -18271,8 +17984,7 @@ const _sfc_main = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
18271
17984
|
const seed = resolveCountryIdentifier(props.defaultCountry);
|
|
18272
17985
|
if (seed) {
|
|
18273
17986
|
inferredCountry.value = seed;
|
|
18274
|
-
|
|
18275
|
-
selectedIso2.value = seed;
|
|
17987
|
+
selection.set(seed, "default");
|
|
18276
17988
|
return;
|
|
18277
17989
|
}
|
|
18278
17990
|
}
|
|
@@ -18291,43 +18003,31 @@ const _sfc_main = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
18291
18003
|
const iso2 = detected ? detected.toUpperCase() : "";
|
|
18292
18004
|
if (props.detectFromInput) {
|
|
18293
18005
|
inferredCountry.value = iso2;
|
|
18294
|
-
if (phone.value && !
|
|
18006
|
+
if (phone.value && !selection.detectionLocked.value && !selectedIso2.value) {
|
|
18295
18007
|
const match = tryMatchPhone(phone.value);
|
|
18296
18008
|
if (match) {
|
|
18297
|
-
|
|
18298
|
-
selectedIso2.value = match.country.value;
|
|
18009
|
+
selection.set(match.country.value, "input");
|
|
18299
18010
|
phone.value = match.nationalNumber;
|
|
18300
18011
|
}
|
|
18301
18012
|
}
|
|
18302
18013
|
return;
|
|
18303
18014
|
}
|
|
18304
|
-
if (!selectedIso2.value && iso2)
|
|
18305
|
-
autoSettingCountry.value = true;
|
|
18306
|
-
selectedIso2.value = iso2;
|
|
18307
|
-
}
|
|
18015
|
+
if (!selectedIso2.value && iso2) selection.set(iso2, "env");
|
|
18308
18016
|
});
|
|
18309
|
-
|
|
18310
|
-
|
|
18311
|
-
|
|
18312
|
-
|
|
18313
|
-
|
|
18314
|
-
if (
|
|
18315
|
-
|
|
18017
|
+
useSyncedModel({
|
|
18018
|
+
model: country,
|
|
18019
|
+
triggers: [selectedIso2],
|
|
18020
|
+
compose: () => selectedIso2.value ? dialNumberFor(selectedIso2.value) : null,
|
|
18021
|
+
apply: (next) => {
|
|
18022
|
+
if (next == null) {
|
|
18023
|
+
selection.clear();
|
|
18024
|
+
return;
|
|
18025
|
+
}
|
|
18026
|
+
if (dialNumberFor(selectedIso2.value) === next) return;
|
|
18027
|
+
const iso2 = resolveCountryIdentifier(String(next));
|
|
18028
|
+
if (iso2) selection.set(iso2, "external");
|
|
18316
18029
|
}
|
|
18317
|
-
|
|
18318
|
-
const iso2 = resolveCountryIdentifier(String(next));
|
|
18319
|
-
if (iso2) selectedIso2.value = iso2;
|
|
18320
|
-
}, { immediate: true });
|
|
18321
|
-
/** Internal → external: keep `country` (dial number) in lockstep with `selectedIso2`, and
|
|
18322
|
-
* flag "user manually picked from picker" when the change isn't one we initiated.
|
|
18323
|
-
* `flush: 'sync'` so the `autoSettingCountry` guard is reliable. */
|
|
18324
|
-
(0, vue.watch)(selectedIso2, (iso2, prev) => {
|
|
18325
|
-
const wasAutoSet = autoSettingCountry.value;
|
|
18326
|
-
autoSettingCountry.value = false;
|
|
18327
|
-
const nextDial = dialNumberFor(iso2);
|
|
18328
|
-
if (country.value !== nextDial) country.value = nextDial;
|
|
18329
|
-
if (!wasAutoSet && props.detectFromInput && iso2 && prev !== iso2) userPickedCountry.value = true;
|
|
18330
|
-
}, { flush: "sync" });
|
|
18030
|
+
});
|
|
18331
18031
|
/** The string shown in the `<input>`. Deliberately decoupled from `phone` (the digits-only
|
|
18332
18032
|
* model) so the visible field is NOT rewritten mid-edit — non-digits / alternative numerals
|
|
18333
18033
|
* are normalized into `phone` immediately, but the displayed value is only cleaned up once
|
|
@@ -18336,6 +18036,29 @@ const _sfc_main = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
18336
18036
|
/** Set when the in-flight `phone` change came from the user typing — tells the `phone`
|
|
18337
18037
|
* watcher to leave `displayValue` alone (the user is still editing it). */
|
|
18338
18038
|
let phoneEditedByInput = false;
|
|
18039
|
+
useSyncedModel({
|
|
18040
|
+
model: modelValue,
|
|
18041
|
+
triggers: [phone, selectedIso2],
|
|
18042
|
+
compose: () => {
|
|
18043
|
+
if (!selectedIso2.value || !phone.value) return "";
|
|
18044
|
+
return validate({
|
|
18045
|
+
country: { iso2: selectedIso2.value },
|
|
18046
|
+
phone: phone.value
|
|
18047
|
+
}).full_phone ?? "";
|
|
18048
|
+
},
|
|
18049
|
+
apply: (next) => {
|
|
18050
|
+
const trimmed = String(next ?? "").trim();
|
|
18051
|
+
if (!trimmed) {
|
|
18052
|
+
if (phone.value !== "") phone.value = "";
|
|
18053
|
+
if (selectedIso2.value !== "") selection.clear();
|
|
18054
|
+
return;
|
|
18055
|
+
}
|
|
18056
|
+
const parsed = (0, libphonenumber_js.parsePhoneNumberFromString)(trimmed.startsWith("+") ? trimmed : `+${trimmed.replace(/^\+/, "")}`);
|
|
18057
|
+
if (!parsed || !parsed.country) return;
|
|
18058
|
+
if (selectedIso2.value !== parsed.country) selection.set(parsed.country, "external");
|
|
18059
|
+
if (phone.value !== parsed.nationalNumber) phone.value = parsed.nationalNumber;
|
|
18060
|
+
}
|
|
18061
|
+
});
|
|
18339
18062
|
function commitPhone(value) {
|
|
18340
18063
|
phoneEditedByInput = true;
|
|
18341
18064
|
phone.value = value;
|
|
@@ -18343,14 +18066,10 @@ const _sfc_main = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
18343
18066
|
function handlePhoneInput(e) {
|
|
18344
18067
|
const target = e.target;
|
|
18345
18068
|
displayValue.value = target.value;
|
|
18346
|
-
const cleaned = normalizeDigits(target.value).replace(/\D/g, "");
|
|
18069
|
+
const cleaned = require_usePhoneValidation.normalizeDigits(target.value).replace(/\D/g, "");
|
|
18347
18070
|
if (!cleaned) {
|
|
18348
18071
|
typing.reset();
|
|
18349
|
-
if (props.detectFromInput)
|
|
18350
|
-
autoSettingCountry.value = true;
|
|
18351
|
-
selectedIso2.value = "";
|
|
18352
|
-
userPickedCountry.value = false;
|
|
18353
|
-
}
|
|
18072
|
+
if (props.detectFromInput) selection.clear();
|
|
18354
18073
|
commitPhone("");
|
|
18355
18074
|
return;
|
|
18356
18075
|
}
|
|
@@ -18361,10 +18080,10 @@ const _sfc_main = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
18361
18080
|
* value — fold alternative numerals to ASCII and drop any stray non-digits. */
|
|
18362
18081
|
function handlePhoneChange(e) {
|
|
18363
18082
|
const target = e.target;
|
|
18364
|
-
displayValue.value = normalizeDigits(target.value).replace(/\D/g, "");
|
|
18083
|
+
displayValue.value = require_usePhoneValidation.normalizeDigits(target.value).replace(/\D/g, "");
|
|
18365
18084
|
}
|
|
18366
18085
|
(0, vue.watch)(() => phone.value, (next) => {
|
|
18367
|
-
const cleaned = normalizeDigits(String(next ?? "")).replace(/\D/g, "");
|
|
18086
|
+
const cleaned = require_usePhoneValidation.normalizeDigits(String(next ?? "")).replace(/\D/g, "");
|
|
18368
18087
|
if (cleaned !== next) {
|
|
18369
18088
|
phone.value = cleaned;
|
|
18370
18089
|
return;
|
|
@@ -18377,12 +18096,14 @@ const _sfc_main = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
18377
18096
|
}, { flush: "post" });
|
|
18378
18097
|
/** Resolved UI strings — `messages` prop merged onto English defaults. The individual
|
|
18379
18098
|
* string props still win when both are set (see `errorMessage` / template bindings). */
|
|
18380
|
-
const messages = (0, vue.computed)(() => resolveMessages(props.messages));
|
|
18099
|
+
const messages = (0, vue.computed)(() => require_types.resolveMessages(props.messages));
|
|
18381
18100
|
/** `dir` of the outer wrapper — drives the hint/error text alignment and the country
|
|
18382
18101
|
* picker popover. Explicit `'ltr'`/`'rtl'` is applied; `'auto'` or an omitted prop yields
|
|
18383
18102
|
* `undefined` so it inherits from the page. The field row itself is always LTR so the
|
|
18384
18103
|
* dial prefix / digits / flag trigger keep a consistent order. */
|
|
18385
18104
|
const dirAttr = (0, vue.computed)(() => props.dir === "ltr" || props.dir === "rtl" ? props.dir : void 0);
|
|
18105
|
+
/** Set to `true` the first time the input is blurred. Drives `validateOn: 'blur'`. */
|
|
18106
|
+
const hasBlurred = (0, vue.ref)(false);
|
|
18386
18107
|
const { validation, required, validationState, visibleValidationState, errorMessage, showError, showHint, selectedDialCode } = useTelInputValidation({
|
|
18387
18108
|
validate,
|
|
18388
18109
|
getRequiredInfo,
|
|
@@ -18391,15 +18112,35 @@ const _sfc_main = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
18391
18112
|
phone,
|
|
18392
18113
|
selectedIso2,
|
|
18393
18114
|
hasFinishedTyping,
|
|
18115
|
+
hasBlurred,
|
|
18394
18116
|
messages
|
|
18395
18117
|
}, {
|
|
18396
18118
|
locale: () => props.locale,
|
|
18397
18119
|
showValidation: () => props.showValidation,
|
|
18398
|
-
errorMessages: () => props.errorMessages
|
|
18120
|
+
errorMessages: () => props.errorMessages,
|
|
18121
|
+
validateOn: () => props.validateOn,
|
|
18122
|
+
externalError: () => props.error
|
|
18399
18123
|
});
|
|
18400
18124
|
const effectivePlaceholder = (0, vue.computed)(() => props.placeholder || required.value?.format_hint || messages.value.phoneInputLabel);
|
|
18401
18125
|
const helperId = (0, vue.useId)();
|
|
18402
18126
|
const describedBy = (0, vue.computed)(() => showError.value || showHint.value ? helperId : void 0);
|
|
18127
|
+
const inputRef = (0, vue.ref)(null);
|
|
18128
|
+
function handleBlur(e) {
|
|
18129
|
+
hasBlurred.value = true;
|
|
18130
|
+
emit("blur", e);
|
|
18131
|
+
}
|
|
18132
|
+
function handleFocus(e) {
|
|
18133
|
+
emit("focus", e);
|
|
18134
|
+
}
|
|
18135
|
+
function focus(options) {
|
|
18136
|
+
inputRef.value?.focus(options);
|
|
18137
|
+
}
|
|
18138
|
+
function blur() {
|
|
18139
|
+
inputRef.value?.blur();
|
|
18140
|
+
}
|
|
18141
|
+
function select() {
|
|
18142
|
+
inputRef.value?.select();
|
|
18143
|
+
}
|
|
18403
18144
|
__expose({
|
|
18404
18145
|
validation,
|
|
18405
18146
|
required,
|
|
@@ -18408,12 +18149,18 @@ const _sfc_main = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
18408
18149
|
visibleValidationState,
|
|
18409
18150
|
isDetecting,
|
|
18410
18151
|
hasFinishedTyping,
|
|
18411
|
-
detectionAttempted
|
|
18152
|
+
detectionAttempted,
|
|
18153
|
+
focus,
|
|
18154
|
+
blur,
|
|
18155
|
+
select
|
|
18412
18156
|
});
|
|
18413
18157
|
const __returned__ = {
|
|
18414
18158
|
props,
|
|
18159
|
+
emit,
|
|
18415
18160
|
phone,
|
|
18416
18161
|
country,
|
|
18162
|
+
modelValue,
|
|
18163
|
+
selection,
|
|
18417
18164
|
selectedIso2,
|
|
18418
18165
|
getCountries,
|
|
18419
18166
|
validate,
|
|
@@ -18423,10 +18170,9 @@ const _sfc_main = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
18423
18170
|
resolveCountryIdentifier,
|
|
18424
18171
|
dialNumberFor,
|
|
18425
18172
|
matchLeadingDialCode,
|
|
18426
|
-
userPickedCountry,
|
|
18427
|
-
autoSettingCountry,
|
|
18428
18173
|
inferredCountry,
|
|
18429
18174
|
tryMatchPhone,
|
|
18175
|
+
onPickerPick,
|
|
18430
18176
|
typing,
|
|
18431
18177
|
isDetecting,
|
|
18432
18178
|
hasFinishedTyping,
|
|
@@ -18443,6 +18189,7 @@ const _sfc_main = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
18443
18189
|
handlePhoneChange,
|
|
18444
18190
|
messages,
|
|
18445
18191
|
dirAttr,
|
|
18192
|
+
hasBlurred,
|
|
18446
18193
|
validation,
|
|
18447
18194
|
required,
|
|
18448
18195
|
validationState,
|
|
@@ -18454,6 +18201,12 @@ const _sfc_main = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
18454
18201
|
effectivePlaceholder,
|
|
18455
18202
|
helperId,
|
|
18456
18203
|
describedBy,
|
|
18204
|
+
inputRef,
|
|
18205
|
+
handleBlur,
|
|
18206
|
+
handleFocus,
|
|
18207
|
+
focus,
|
|
18208
|
+
blur,
|
|
18209
|
+
select,
|
|
18457
18210
|
get cn() {
|
|
18458
18211
|
return cn$2;
|
|
18459
18212
|
},
|
|
@@ -18495,25 +18248,34 @@ const _hoisted_4 = {
|
|
|
18495
18248
|
};
|
|
18496
18249
|
const _hoisted_5 = [
|
|
18497
18250
|
"value",
|
|
18251
|
+
"name",
|
|
18498
18252
|
"disabled",
|
|
18499
18253
|
"placeholder",
|
|
18500
18254
|
"aria-label",
|
|
18501
18255
|
"aria-invalid",
|
|
18502
18256
|
"aria-describedby",
|
|
18257
|
+
"aria-errormessage",
|
|
18258
|
+
"aria-busy",
|
|
18503
18259
|
"data-has-dial"
|
|
18504
18260
|
];
|
|
18505
18261
|
const _hoisted_6 = {
|
|
18262
|
+
key: 0,
|
|
18263
|
+
class: "a-tel-input__validating",
|
|
18264
|
+
"data-slot": "tel-input-validating",
|
|
18265
|
+
"aria-hidden": "true"
|
|
18266
|
+
};
|
|
18267
|
+
const _hoisted_7 = {
|
|
18506
18268
|
key: 0,
|
|
18507
18269
|
class: "a-tel-input__detecting",
|
|
18508
18270
|
"aria-hidden": "true",
|
|
18509
18271
|
"data-slot": "tel-input-detecting"
|
|
18510
18272
|
};
|
|
18511
|
-
const
|
|
18273
|
+
const _hoisted_8 = {
|
|
18512
18274
|
key: 0,
|
|
18513
18275
|
class: "a-tel-input__country-wrapper",
|
|
18514
18276
|
"data-slot": "tel-input-country-wrapper"
|
|
18515
18277
|
};
|
|
18516
|
-
const
|
|
18278
|
+
const _hoisted_9 = ["id"];
|
|
18517
18279
|
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
18518
18280
|
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
|
|
18519
18281
|
class: (0, vue.normalizeClass)($setup.cn("a-tel-input", _ctx.$attrs.class)),
|
|
@@ -18531,31 +18293,41 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
18531
18293
|
(0, vue.renderSlot)(_ctx.$slots, "prefix", {}, void 0, true),
|
|
18532
18294
|
$setup.selectedDialCode ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_4, (0, vue.toDisplayString)($setup.selectedDialCode), 1)) : (0, vue.createCommentVNode)("v-if", true),
|
|
18533
18295
|
(0, vue.createElementVNode)("input", {
|
|
18296
|
+
ref: "inputRef",
|
|
18534
18297
|
value: $setup.displayValue,
|
|
18535
18298
|
type: "tel",
|
|
18536
18299
|
inputmode: "numeric",
|
|
18537
18300
|
autocomplete: "tel",
|
|
18538
18301
|
dir: "ltr",
|
|
18539
18302
|
"data-slot": "tel-input-field",
|
|
18303
|
+
name: $setup.props.name,
|
|
18540
18304
|
disabled: $setup.props.disabled || $setup.props.loading,
|
|
18541
18305
|
placeholder: $setup.effectivePlaceholder,
|
|
18542
18306
|
"aria-label": $setup.messages.phoneInputLabel,
|
|
18543
18307
|
"aria-invalid": $setup.visibleValidationState === "error" || void 0,
|
|
18544
18308
|
"aria-describedby": $setup.describedBy,
|
|
18309
|
+
"aria-errormessage": $setup.visibleValidationState === "error" ? $setup.helperId : void 0,
|
|
18310
|
+
"aria-busy": $setup.props.validating || void 0,
|
|
18545
18311
|
class: (0, vue.normalizeClass)($setup.cn("a-tel-input__input", $setup.props.inputClass)),
|
|
18546
18312
|
"data-has-dial": $setup.selectedDialCode ? "" : void 0,
|
|
18547
18313
|
onInput: $setup.handlePhoneInput,
|
|
18548
|
-
onChange: $setup.handlePhoneChange
|
|
18314
|
+
onChange: $setup.handlePhoneChange,
|
|
18315
|
+
onBlur: $setup.handleBlur,
|
|
18316
|
+
onFocus: $setup.handleFocus
|
|
18549
18317
|
}, null, 42, _hoisted_5),
|
|
18318
|
+
(0, vue.createCommentVNode)(" Async-validation spinner (e.g. server-side \"phone exists?\" check). Independent\n of `isDetecting` (which is for country detection) so both can be shown without\n interfering. Lives next to the input and never disables it. "),
|
|
18319
|
+
(0, vue.createVNode)(vue.Transition, { name: "a-tell-detect" }, {
|
|
18320
|
+
default: (0, vue.withCtx)(() => [$setup.props.validating ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_6, [(0, vue.renderSlot)(_ctx.$slots, "validating", {}, () => [(0, vue.createVNode)($setup["SpinnerIcon"], { class: "a-tel-input__detecting-icon" })], true)])) : (0, vue.createCommentVNode)("v-if", true)]),
|
|
18321
|
+
_: 3
|
|
18322
|
+
}),
|
|
18550
18323
|
(0, vue.createCommentVNode)(" Detection-in-flight spinner — shown only during the first debounce window,\n before the picker has appeared. Once the picker is visible (success OR a failed\n attempt that revealed the empty picker) we stop re-flashing on every keystroke. "),
|
|
18551
18324
|
(0, vue.createVNode)(vue.Transition, { name: "a-tell-detect" }, {
|
|
18552
|
-
default: (0, vue.withCtx)(() => [$setup.isDetecting && !$setup.selectedIso2 && !$setup.detectionAttempted ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div",
|
|
18325
|
+
default: (0, vue.withCtx)(() => [$setup.isDetecting && !$setup.selectedIso2 && !$setup.detectionAttempted ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_7, [(0, vue.renderSlot)(_ctx.$slots, "detecting", {}, () => [(0, vue.createVNode)($setup["SpinnerIcon"], { class: "a-tel-input__detecting-icon" })], true)])) : (0, vue.createCommentVNode)("v-if", true)]),
|
|
18553
18326
|
_: 3
|
|
18554
18327
|
}),
|
|
18555
18328
|
(0, vue.createVNode)(vue.Transition, { name: "a-tell-country" }, {
|
|
18556
|
-
default: (0, vue.withCtx)(() => [!$setup.props.detectFromInput || $setup.selectedIso2 || $setup.detectionAttempted ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div",
|
|
18329
|
+
default: (0, vue.withCtx)(() => [!$setup.props.detectFromInput || $setup.selectedIso2 || $setup.detectionAttempted ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_8, [(0, vue.createVNode)($setup["ACountrySelect"], {
|
|
18557
18330
|
selected: $setup.selectedIso2,
|
|
18558
|
-
"onUpdate:selected": _cache[0] || (_cache[0] = ($event) => $setup.selectedIso2 = $event),
|
|
18559
18331
|
"allowed-dial-codes": $setup.props.allowedDialCodes,
|
|
18560
18332
|
disabled: $setup.props.disabled || $setup.props.loading,
|
|
18561
18333
|
size: $setup.props.size,
|
|
@@ -18566,6 +18338,7 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
18566
18338
|
"suggested-label": $setup.messages.suggestedLabel,
|
|
18567
18339
|
"all-countries-label": $setup.messages.allCountriesLabel,
|
|
18568
18340
|
"country-label": $setup.messages.countryLabel,
|
|
18341
|
+
"onUpdate:selected": $setup.onPickerPick,
|
|
18569
18342
|
"select-country-label": $setup.messages.selectCountryLabel,
|
|
18570
18343
|
"flag-url": $setup.props.flagUrl,
|
|
18571
18344
|
searcher: $setup.props.searcher,
|
|
@@ -18672,7 +18445,7 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
18672
18445
|
}, () => [(0, vue.createElementVNode)("p", {
|
|
18673
18446
|
"data-slot": "tel-input-hint",
|
|
18674
18447
|
class: (0, vue.normalizeClass)($setup.cn("a-tel-input__hint", $setup.props.hintClass))
|
|
18675
|
-
}, (0, vue.toDisplayString)($setup.required.format_hint), 3)], true) : (0, vue.createCommentVNode)("v-if", true)], 8,
|
|
18448
|
+
}, (0, vue.toDisplayString)($setup.required.format_hint), 3)], true) : (0, vue.createCommentVNode)("v-if", true)], 8, _hoisted_9)
|
|
18676
18449
|
], 10, _hoisted_1);
|
|
18677
18450
|
}
|
|
18678
18451
|
var ATelInput_default = /* @__PURE__ */ export_helper_default(_sfc_main, [
|
|
@@ -18685,19 +18458,22 @@ exports.ACountryFlag = ACountryFlag_default;
|
|
|
18685
18458
|
exports.ACountrySelect = ACountrySelect_default;
|
|
18686
18459
|
exports.ATelInput = ATelInput_default;
|
|
18687
18460
|
exports.COUNTRY_RECENTS_KEY = COUNTRY_RECENTS_KEY;
|
|
18688
|
-
exports.DEFAULT_ERROR_MESSAGES = DEFAULT_ERROR_MESSAGES;
|
|
18689
|
-
exports.DEFAULT_MESSAGES = DEFAULT_MESSAGES;
|
|
18461
|
+
exports.DEFAULT_ERROR_MESSAGES = require_types.DEFAULT_ERROR_MESSAGES;
|
|
18462
|
+
exports.DEFAULT_MESSAGES = require_types.DEFAULT_MESSAGES;
|
|
18690
18463
|
exports.DIAL_TO_ISO2_FALLBACK = DIAL_TO_ISO2_FALLBACK;
|
|
18691
|
-
exports.
|
|
18692
|
-
exports.
|
|
18464
|
+
exports.FALLBACK_ISO2_LIST = FALLBACK_ISO2_LIST;
|
|
18465
|
+
exports.LOCALE_DIGIT_RANGES = require_usePhoneValidation.LOCALE_DIGIT_RANGES;
|
|
18466
|
+
exports.aTelInputVariants = require_types.aTelInputVariants;
|
|
18693
18467
|
exports.defaultFlagUrl = defaultFlagUrl;
|
|
18694
18468
|
exports.detectCountry = detectCountry;
|
|
18695
|
-
exports.localizeCountries = localizeCountries;
|
|
18696
|
-
exports.normalizeDigits = normalizeDigits;
|
|
18697
|
-
exports.resolveMessages = resolveMessages;
|
|
18469
|
+
exports.localizeCountries = require_usePhoneValidation.localizeCountries;
|
|
18470
|
+
exports.normalizeDigits = require_usePhoneValidation.normalizeDigits;
|
|
18471
|
+
exports.resolveMessages = require_types.resolveMessages;
|
|
18698
18472
|
exports.useCountryDetection = useCountryDetection;
|
|
18699
18473
|
exports.useCountryMatching = useCountryMatching;
|
|
18700
|
-
exports.
|
|
18474
|
+
exports.useCountrySelection = useCountrySelection;
|
|
18475
|
+
exports.usePhoneValidation = require_usePhoneValidation.usePhoneValidation;
|
|
18476
|
+
exports.useSyncedModel = useSyncedModel;
|
|
18701
18477
|
exports.useTelInputValidation = useTelInputValidation;
|
|
18702
18478
|
exports.useTypingPhase = useTypingPhase;
|
|
18703
18479
|
|