intl-tel-input 27.2.1 → 27.3.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/CHANGELOG.md +1 -1
- package/README.md +25 -14
- package/angular/dist/IntlTelInput.d.ts +3 -1
- package/angular/dist/IntlTelInput.js +157 -86
- package/angular/dist/IntlTelInputWithUtils.js +487 -393
- package/dist/css/intlTelInput-no-assets.css +1116 -1
- package/dist/css/intlTelInput-no-assets.min.css +1 -1
- package/dist/css/intlTelInput.css +1122 -1
- package/dist/css/intlTelInput.min.css +1 -1
- package/dist/js/data.d.ts +1 -4
- package/dist/js/data.js +2 -8
- package/dist/js/data.min.js +2 -2
- package/dist/js/data.mjs +1 -7
- package/dist/js/intlTelInput.d.ts +2 -4
- package/dist/js/intlTelInput.js +148 -85
- package/dist/js/intlTelInput.min.js +3 -3
- package/dist/js/intlTelInput.mjs +147 -84
- package/dist/js/intlTelInputWithUtils.js +478 -392
- package/dist/js/intlTelInputWithUtils.min.js +8 -8
- package/dist/js/intlTelInputWithUtils.mjs +477 -391
- package/dist/js/utils.js +50 -51
- package/package.json +3 -7
- package/react/dist/IntlTelInput.js +151 -84
- package/react/dist/IntlTelInputWithUtils.js +481 -391
- package/svelte/src/IntlTelInput.svelte +9 -2
- package/vue/dist/{IntlTelInput-CzuiSLVt.js → IntlTelInput-DWpqqgvZ.js} +463 -428
- package/vue/dist/IntlTelInput.js +1 -1
- package/vue/dist/IntlTelInputWithUtils.js +35 -14
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
See the Github Releases page for changelog: https://github.com/jackocnr/intl-tel-input/releases
|
|
2
2
|
|
|
3
|
-
Or to view a specific version, e.g. v27.
|
|
3
|
+
Or to view a specific version, e.g. v27.3.1, update the URL accordingly, e.g. https://github.com/jackocnr/intl-tel-input/releases/tag/v27.3.1
|
|
4
4
|
|
|
5
5
|
## Breaking changes
|
|
6
6
|
|
package/README.md
CHANGED
|
@@ -23,20 +23,31 @@ We provide React, Vue, Angular and Svelte (beta) components alongside the regula
|
|
|
23
23
|
We have a newly updated website, where you can find [a full set of docs](https://intl-tel-input.com/docs/integrations), a [live playground](https://intl-tel-input.com/playground/) where you can try out all of the options, as well as plenty of [examples](https://intl-tel-input.com/examples/validation-practical.html) of different setups.
|
|
24
24
|
|
|
25
25
|
## Features
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
|
|
39
|
-
|
|
26
|
+
|
|
27
|
+
🔍 **Fast country picking**
|
|
28
|
+
* Search by country name or dial code
|
|
29
|
+
* Full keyboard navigation
|
|
30
|
+
|
|
31
|
+
✨ **Smart defaults**
|
|
32
|
+
* Optionally auto-detect the user's country via IP lookup
|
|
33
|
+
* Example placeholders per country
|
|
34
|
+
|
|
35
|
+
📞 **Formatting & output**
|
|
36
|
+
* Formats the number as the user types
|
|
37
|
+
* Extract standard E.164 numbers to store
|
|
38
|
+
|
|
39
|
+
🛡️ **Validation**
|
|
40
|
+
* Validate numbers with specific error types
|
|
41
|
+
* Strict mode: only allow valid digits and enforce max length
|
|
42
|
+
|
|
43
|
+
🌍 **International & accessible**
|
|
44
|
+
* Translated into 40+ languages, with support for RTL and alternative numerals
|
|
45
|
+
* Screen reader-friendly ARIA markup
|
|
46
|
+
|
|
47
|
+
🎛️ **Customisable**
|
|
48
|
+
* Override CSS variables (e.g. dark mode)
|
|
49
|
+
* Optionally display the dial code next to the number
|
|
50
|
+
* Extensive initialisation options, methods, and events
|
|
40
51
|
|
|
41
52
|
## Contributing
|
|
42
53
|
See the [contributing guide](https://github.com/jackocnr/intl-tel-input/blob/master/.github/CONTRIBUTING.md) for instructions on setting up the project and making changes, and also on how to update the flag images, or how to add a new translation.
|
|
@@ -45,6 +45,7 @@ declare class IntlTelInput implements AfterViewInit, OnDestroy, OnChanges, Contr
|
|
|
45
45
|
separateDialCode?: AllOptions["separateDialCode"];
|
|
46
46
|
showFlags?: AllOptions["showFlags"];
|
|
47
47
|
strictMode?: AllOptions["strictMode"];
|
|
48
|
+
strictRejectAnimation?: AllOptions["strictRejectAnimation"];
|
|
48
49
|
useFullscreenPopup?: AllOptions["useFullscreenPopup"];
|
|
49
50
|
numberChange: EventEmitter<string>;
|
|
50
51
|
countryChange: EventEmitter<string>;
|
|
@@ -61,6 +62,7 @@ declare class IntlTelInput implements AfterViewInit, OnDestroy, OnChanges, Contr
|
|
|
61
62
|
click: EventEmitter<MouseEvent>;
|
|
62
63
|
private iti?;
|
|
63
64
|
private appliedInputAttrKeys;
|
|
65
|
+
private pluginInputClasses;
|
|
64
66
|
private lastEmittedNumber?;
|
|
65
67
|
private lastEmittedCountry?;
|
|
66
68
|
private lastEmittedValidity?;
|
|
@@ -103,6 +105,6 @@ declare class IntlTelInput implements AfterViewInit, OnDestroy, OnChanges, Contr
|
|
|
103
105
|
validate(_control: AbstractControl): ValidationErrors | null;
|
|
104
106
|
registerOnValidatorChange(fn: () => void): void;
|
|
105
107
|
static ɵfac: i0.ɵɵFactoryDeclaration<IntlTelInput, never>;
|
|
106
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<IntlTelInput, "intl-tel-input", never, { "initialValue": { "alias": "initialValue"; "required": false; }; "usePreciseValidation": { "alias": "usePreciseValidation"; "required": false; }; "inputAttributes": { "alias": "inputAttributes"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "allowDropdown": { "alias": "allowDropdown"; "required": false; }; "allowedNumberTypes": { "alias": "allowedNumberTypes"; "required": false; }; "allowNumberExtensions": { "alias": "allowNumberExtensions"; "required": false; }; "allowPhonewords": { "alias": "allowPhonewords"; "required": false; }; "autoPlaceholder": { "alias": "autoPlaceholder"; "required": false; }; "containerClass": { "alias": "containerClass"; "required": false; }; "countryNameLocale": { "alias": "countryNameLocale"; "required": false; }; "countryOrder": { "alias": "countryOrder"; "required": false; }; "countrySearch": { "alias": "countrySearch"; "required": false; }; "customPlaceholder": { "alias": "customPlaceholder"; "required": false; }; "dropdownAlwaysOpen": { "alias": "dropdownAlwaysOpen"; "required": false; }; "dropdownContainer": { "alias": "dropdownContainer"; "required": false; }; "excludeCountries": { "alias": "excludeCountries"; "required": false; }; "fixDropdownWidth": { "alias": "fixDropdownWidth"; "required": false; }; "formatAsYouType": { "alias": "formatAsYouType"; "required": false; }; "formatOnDisplay": { "alias": "formatOnDisplay"; "required": false; }; "geoIpLookup": { "alias": "geoIpLookup"; "required": false; }; "hiddenInput": { "alias": "hiddenInput"; "required": false; }; "i18n": { "alias": "i18n"; "required": false; }; "initialCountry": { "alias": "initialCountry"; "required": false; }; "loadUtils": { "alias": "loadUtils"; "required": false; }; "nationalMode": { "alias": "nationalMode"; "required": false; }; "onlyCountries": { "alias": "onlyCountries"; "required": false; }; "placeholderNumberType": { "alias": "placeholderNumberType"; "required": false; }; "searchInputClass": { "alias": "searchInputClass"; "required": false; }; "separateDialCode": { "alias": "separateDialCode"; "required": false; }; "showFlags": { "alias": "showFlags"; "required": false; }; "strictMode": { "alias": "strictMode"; "required": false; }; "useFullscreenPopup": { "alias": "useFullscreenPopup"; "required": false; }; }, { "numberChange": "numberChange"; "countryChange": "countryChange"; "validityChange": "validityChange"; "errorCodeChange": "errorCodeChange"; "openCountryDropdown": "openCountryDropdown"; "closeCountryDropdown": "closeCountryDropdown"; "strictReject": "strictReject"; "blur": "blur"; "focus": "focus"; "keydown": "keydown"; "keyup": "keyup"; "paste": "paste"; "click": "click"; }, never, never, true, never>;
|
|
108
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<IntlTelInput, "intl-tel-input", never, { "initialValue": { "alias": "initialValue"; "required": false; }; "usePreciseValidation": { "alias": "usePreciseValidation"; "required": false; }; "inputAttributes": { "alias": "inputAttributes"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "allowDropdown": { "alias": "allowDropdown"; "required": false; }; "allowedNumberTypes": { "alias": "allowedNumberTypes"; "required": false; }; "allowNumberExtensions": { "alias": "allowNumberExtensions"; "required": false; }; "allowPhonewords": { "alias": "allowPhonewords"; "required": false; }; "autoPlaceholder": { "alias": "autoPlaceholder"; "required": false; }; "containerClass": { "alias": "containerClass"; "required": false; }; "countryNameLocale": { "alias": "countryNameLocale"; "required": false; }; "countryOrder": { "alias": "countryOrder"; "required": false; }; "countrySearch": { "alias": "countrySearch"; "required": false; }; "customPlaceholder": { "alias": "customPlaceholder"; "required": false; }; "dropdownAlwaysOpen": { "alias": "dropdownAlwaysOpen"; "required": false; }; "dropdownContainer": { "alias": "dropdownContainer"; "required": false; }; "excludeCountries": { "alias": "excludeCountries"; "required": false; }; "fixDropdownWidth": { "alias": "fixDropdownWidth"; "required": false; }; "formatAsYouType": { "alias": "formatAsYouType"; "required": false; }; "formatOnDisplay": { "alias": "formatOnDisplay"; "required": false; }; "geoIpLookup": { "alias": "geoIpLookup"; "required": false; }; "hiddenInput": { "alias": "hiddenInput"; "required": false; }; "i18n": { "alias": "i18n"; "required": false; }; "initialCountry": { "alias": "initialCountry"; "required": false; }; "loadUtils": { "alias": "loadUtils"; "required": false; }; "nationalMode": { "alias": "nationalMode"; "required": false; }; "onlyCountries": { "alias": "onlyCountries"; "required": false; }; "placeholderNumberType": { "alias": "placeholderNumberType"; "required": false; }; "searchInputClass": { "alias": "searchInputClass"; "required": false; }; "separateDialCode": { "alias": "separateDialCode"; "required": false; }; "showFlags": { "alias": "showFlags"; "required": false; }; "strictMode": { "alias": "strictMode"; "required": false; }; "strictRejectAnimation": { "alias": "strictRejectAnimation"; "required": false; }; "useFullscreenPopup": { "alias": "useFullscreenPopup"; "required": false; }; }, { "numberChange": "numberChange"; "countryChange": "countryChange"; "validityChange": "validityChange"; "errorCodeChange": "errorCodeChange"; "openCountryDropdown": "openCountryDropdown"; "closeCountryDropdown": "closeCountryDropdown"; "strictReject": "strictReject"; "blur": "blur"; "focus": "focus"; "keydown": "keydown"; "keyup": "keyup"; "paste": "paste"; "click": "click"; }, never, never, true, never>;
|
|
107
109
|
}
|
|
108
110
|
export default IntlTelInput;
|
|
@@ -1743,13 +1743,7 @@ for (const c of rawCountryData) {
|
|
|
1743
1743
|
dialCode: c[1],
|
|
1744
1744
|
priority: c[2] || 0,
|
|
1745
1745
|
areaCodes: c[3] || null,
|
|
1746
|
-
nationalPrefix: c[4] || null
|
|
1747
|
-
normalisedName: "",
|
|
1748
|
-
// populated in the plugin
|
|
1749
|
-
initials: "",
|
|
1750
|
-
// populated in the plugin
|
|
1751
|
-
dialCodePlus: ""
|
|
1752
|
-
// populated in the plugin
|
|
1746
|
+
nationalPrefix: c[4] || null
|
|
1753
1747
|
});
|
|
1754
1748
|
}
|
|
1755
1749
|
var iso2Set = new Set(allCountries.map((c) => c.iso2));
|
|
@@ -1966,6 +1960,8 @@ var defaults = {
|
|
|
1966
1960
|
searchInputClass: "",
|
|
1967
1961
|
//* Display the international dial code next to the selected flag.
|
|
1968
1962
|
separateDialCode: false,
|
|
1963
|
+
//* When strictMode rejects a key (etc), play a short feedback animation
|
|
1964
|
+
strictRejectAnimation: false,
|
|
1969
1965
|
//* Show flags - for both the selected country, and in the country dropdown
|
|
1970
1966
|
showFlags: true,
|
|
1971
1967
|
//* Only allow certain chars e.g. a plus followed by numeric digits, and cap at max valid length.
|
|
@@ -2041,6 +2037,7 @@ var validateOptions = (customOptions) => {
|
|
|
2041
2037
|
case "showFlags":
|
|
2042
2038
|
case "separateDialCode":
|
|
2043
2039
|
case "strictMode":
|
|
2040
|
+
case "strictRejectAnimation":
|
|
2044
2041
|
case "useFullscreenPopup":
|
|
2045
2042
|
if (typeof value !== "boolean") {
|
|
2046
2043
|
warnOption(key, "a boolean", value);
|
|
@@ -2259,7 +2256,20 @@ var buildGlobeIcon = () => `
|
|
|
2259
2256
|
</svg>`;
|
|
2260
2257
|
|
|
2261
2258
|
// src/js/core/countrySearch.ts
|
|
2262
|
-
var
|
|
2259
|
+
var buildSearchTokens = (countries) => {
|
|
2260
|
+
const tokens = /* @__PURE__ */ new Map();
|
|
2261
|
+
for (const c of countries) {
|
|
2262
|
+
const normalisedName = normaliseString(c.name);
|
|
2263
|
+
const initials = normalisedName.split(/[^a-z]/).map((word) => word[0]).join("");
|
|
2264
|
+
tokens.set(c.iso2, {
|
|
2265
|
+
normalisedName,
|
|
2266
|
+
initials,
|
|
2267
|
+
dialCodePlus: `+${c.dialCode}`
|
|
2268
|
+
});
|
|
2269
|
+
}
|
|
2270
|
+
return tokens;
|
|
2271
|
+
};
|
|
2272
|
+
var getMatchedCountries = (countries, searchTokens, query) => {
|
|
2263
2273
|
const normalisedQuery = normaliseString(query);
|
|
2264
2274
|
const iso2Matches = [];
|
|
2265
2275
|
const nameStartsWith = [];
|
|
@@ -2268,17 +2278,18 @@ var getMatchedCountries = (countries, query) => {
|
|
|
2268
2278
|
const dialCodeContains = [];
|
|
2269
2279
|
const initialsMatches = [];
|
|
2270
2280
|
for (const c of countries) {
|
|
2281
|
+
const t = searchTokens.get(c.iso2);
|
|
2271
2282
|
if (c.iso2 === normalisedQuery) {
|
|
2272
2283
|
iso2Matches.push(c);
|
|
2273
|
-
} else if (
|
|
2284
|
+
} else if (t.normalisedName.startsWith(normalisedQuery)) {
|
|
2274
2285
|
nameStartsWith.push(c);
|
|
2275
|
-
} else if (
|
|
2286
|
+
} else if (t.normalisedName.includes(normalisedQuery)) {
|
|
2276
2287
|
nameContains.push(c);
|
|
2277
|
-
} else if (normalisedQuery === c.dialCode || normalisedQuery ===
|
|
2288
|
+
} else if (normalisedQuery === c.dialCode || normalisedQuery === t.dialCodePlus) {
|
|
2278
2289
|
dialCodeMatches.push(c);
|
|
2279
|
-
} else if (
|
|
2290
|
+
} else if (t.dialCodePlus.includes(normalisedQuery)) {
|
|
2280
2291
|
dialCodeContains.push(c);
|
|
2281
|
-
} else if (
|
|
2292
|
+
} else if (t.initials.includes(normalisedQuery)) {
|
|
2282
2293
|
initialsMatches.push(c);
|
|
2283
2294
|
}
|
|
2284
2295
|
}
|
|
@@ -2293,16 +2304,75 @@ var getMatchedCountries = (countries, query) => {
|
|
|
2293
2304
|
...initialsMatches
|
|
2294
2305
|
];
|
|
2295
2306
|
};
|
|
2296
|
-
var findFirstCountryStartingWith = (countries, query) => {
|
|
2307
|
+
var findFirstCountryStartingWith = (countries, searchTokens, query) => {
|
|
2297
2308
|
const normalisedQuery = normaliseString(query);
|
|
2298
2309
|
for (const c of countries) {
|
|
2299
|
-
|
|
2310
|
+
const { normalisedName } = searchTokens.get(c.iso2);
|
|
2311
|
+
if (normalisedName.startsWith(normalisedQuery)) {
|
|
2300
2312
|
return c;
|
|
2301
2313
|
}
|
|
2302
2314
|
}
|
|
2303
2315
|
return null;
|
|
2304
2316
|
};
|
|
2305
2317
|
|
|
2318
|
+
// src/js/core/numerals.ts
|
|
2319
|
+
var Numerals = class _Numerals {
|
|
2320
|
+
#userNumeralSet;
|
|
2321
|
+
//* Stateless conversion of any Arabic-Indic / Persian digits to ASCII 0-9.
|
|
2322
|
+
//* Use this when you need to normalise digits without affecting any instance's tracked numeral set (e.g. for the country-search query).
|
|
2323
|
+
static toAscii(str) {
|
|
2324
|
+
if (!str) {
|
|
2325
|
+
return "";
|
|
2326
|
+
}
|
|
2327
|
+
return str.replace(
|
|
2328
|
+
/[٠-٩]/g,
|
|
2329
|
+
(ch) => String.fromCharCode(48 + (ch.charCodeAt(0) - 1632))
|
|
2330
|
+
).replace(
|
|
2331
|
+
/[۰-۹]/g,
|
|
2332
|
+
(ch) => String.fromCharCode(48 + (ch.charCodeAt(0) - 1776))
|
|
2333
|
+
);
|
|
2334
|
+
}
|
|
2335
|
+
constructor(initialValue) {
|
|
2336
|
+
if (initialValue) {
|
|
2337
|
+
this.#updateNumeralSet(initialValue);
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
// If any Arabic-Indic digits, then label it as that set. Same for Persian. Otherwise assume ASCII.
|
|
2341
|
+
#updateNumeralSet(str) {
|
|
2342
|
+
if (/[٠-٩]/.test(str)) {
|
|
2343
|
+
this.#userNumeralSet = "arabic-indic";
|
|
2344
|
+
} else if (/[۰-۹]/.test(str)) {
|
|
2345
|
+
this.#userNumeralSet = "persian";
|
|
2346
|
+
} else {
|
|
2347
|
+
this.#userNumeralSet = "ascii";
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
// Denormalise ASCII 0-9 to the user's numeral set. If not yet known, return as-is.
|
|
2351
|
+
// NOTE: normalise is always called before this, so it should be impossible for the numeral set to be unknown at this point.
|
|
2352
|
+
denormalise(str) {
|
|
2353
|
+
if (!this.#userNumeralSet || this.#userNumeralSet === "ascii") {
|
|
2354
|
+
return str;
|
|
2355
|
+
}
|
|
2356
|
+
const base = this.#userNumeralSet === "arabic-indic" ? 1632 : 1776;
|
|
2357
|
+
return str.replace(/[0-9]/g, (d) => String.fromCharCode(base + Number(d)));
|
|
2358
|
+
}
|
|
2359
|
+
// Normalize Eastern Arabic (U+0660-0669) and Persian/Extended Arabic-Indic (U+06F0-06F9) numerals to ASCII 0-9.
|
|
2360
|
+
// Tracks the user's numeral set as a side effect so denormalise can mirror it back.
|
|
2361
|
+
normalise(str) {
|
|
2362
|
+
if (!str) {
|
|
2363
|
+
return "";
|
|
2364
|
+
}
|
|
2365
|
+
this.#updateNumeralSet(str);
|
|
2366
|
+
if (this.#userNumeralSet === "ascii") {
|
|
2367
|
+
return str;
|
|
2368
|
+
}
|
|
2369
|
+
return _Numerals.toAscii(str);
|
|
2370
|
+
}
|
|
2371
|
+
isAscii() {
|
|
2372
|
+
return !this.#userNumeralSet || this.#userNumeralSet === "ascii";
|
|
2373
|
+
}
|
|
2374
|
+
};
|
|
2375
|
+
|
|
2306
2376
|
// src/js/core/ui.ts
|
|
2307
2377
|
var UI = class _UI {
|
|
2308
2378
|
// private
|
|
@@ -2311,6 +2381,7 @@ var UI = class _UI {
|
|
|
2311
2381
|
#isRTL;
|
|
2312
2382
|
#originalPaddingLeft = "";
|
|
2313
2383
|
#countries;
|
|
2384
|
+
#searchTokens;
|
|
2314
2385
|
#searchDebounceTimer = null;
|
|
2315
2386
|
#inlineDropdownHeight;
|
|
2316
2387
|
#countryContainerEl;
|
|
@@ -2356,8 +2427,9 @@ var UI = class _UI {
|
|
|
2356
2427
|
}
|
|
2357
2428
|
}
|
|
2358
2429
|
//* Generate all of the markup for the plugin: the selected country overlay, and the dropdown.
|
|
2359
|
-
buildMarkup(countries) {
|
|
2430
|
+
buildMarkup(countries, searchTokens) {
|
|
2360
2431
|
this.#countries = countries;
|
|
2432
|
+
this.#searchTokens = searchTokens;
|
|
2361
2433
|
this.telInputEl.classList.add("iti__tel-input");
|
|
2362
2434
|
if (!this.telInputEl.hasAttribute("type")) {
|
|
2363
2435
|
this.telInputEl.setAttribute("type", "tel");
|
|
@@ -2725,7 +2797,12 @@ var UI = class _UI {
|
|
|
2725
2797
|
if (query === "") {
|
|
2726
2798
|
matchedCountries = this.#countries;
|
|
2727
2799
|
} else {
|
|
2728
|
-
|
|
2800
|
+
const normalisedQuery = Numerals.toAscii(query);
|
|
2801
|
+
matchedCountries = getMatchedCountries(
|
|
2802
|
+
this.#countries,
|
|
2803
|
+
this.#searchTokens,
|
|
2804
|
+
normalisedQuery
|
|
2805
|
+
);
|
|
2729
2806
|
}
|
|
2730
2807
|
this.#showFilteredCountries(matchedCountries);
|
|
2731
2808
|
}
|
|
@@ -3020,7 +3097,11 @@ var UI = class _UI {
|
|
|
3020
3097
|
}
|
|
3021
3098
|
//* Hidden search (countrySearch disabled): jump to the first list item whose name starts with the query.
|
|
3022
3099
|
#searchForCountry(query) {
|
|
3023
|
-
const match = findFirstCountryStartingWith(
|
|
3100
|
+
const match = findFirstCountryStartingWith(
|
|
3101
|
+
this.#countries,
|
|
3102
|
+
this.#searchTokens,
|
|
3103
|
+
query
|
|
3104
|
+
);
|
|
3024
3105
|
if (match) {
|
|
3025
3106
|
const listItem = this.#listItemByIso2.get(match.iso2);
|
|
3026
3107
|
this.#highlightListItem(listItem);
|
|
@@ -3332,13 +3413,6 @@ var sortCountries = (countries, options) => {
|
|
|
3332
3413
|
return a.name.localeCompare(b.name);
|
|
3333
3414
|
});
|
|
3334
3415
|
};
|
|
3335
|
-
var cacheSearchTokens = (countries) => {
|
|
3336
|
-
for (const c of countries) {
|
|
3337
|
-
c.normalisedName = normaliseString(c.name);
|
|
3338
|
-
c.initials = c.normalisedName.split(/[^a-z]/).map((word) => word[0]).join("");
|
|
3339
|
-
c.dialCodePlus = `+${c.dialCode}`;
|
|
3340
|
-
}
|
|
3341
|
-
};
|
|
3342
3416
|
|
|
3343
3417
|
// src/js/data/intl-regionless.ts
|
|
3344
3418
|
var regionlessDialCodes = /* @__PURE__ */ new Set([
|
|
@@ -3424,54 +3498,6 @@ var isRegionlessNanp = (number) => {
|
|
|
3424
3498
|
return false;
|
|
3425
3499
|
};
|
|
3426
3500
|
|
|
3427
|
-
// src/js/core/numerals.ts
|
|
3428
|
-
var Numerals = class {
|
|
3429
|
-
#userNumeralSet;
|
|
3430
|
-
constructor(initialValue) {
|
|
3431
|
-
if (initialValue) {
|
|
3432
|
-
this.#updateNumeralSet(initialValue);
|
|
3433
|
-
}
|
|
3434
|
-
}
|
|
3435
|
-
// If any Arabic-Indic digits, then label it as that set. Same for Persian. Otherwise assume ASCII.
|
|
3436
|
-
#updateNumeralSet(str) {
|
|
3437
|
-
if (/[\u0660-\u0669]/.test(str)) {
|
|
3438
|
-
this.#userNumeralSet = "arabic-indic";
|
|
3439
|
-
} else if (/[\u06F0-\u06F9]/.test(str)) {
|
|
3440
|
-
this.#userNumeralSet = "persian";
|
|
3441
|
-
} else {
|
|
3442
|
-
this.#userNumeralSet = "ascii";
|
|
3443
|
-
}
|
|
3444
|
-
}
|
|
3445
|
-
// Denormalise ASCII 0-9 to the user's numeral set. If not yet known, return as-is.
|
|
3446
|
-
// NOTE: normalise is always called before this, so it should be impossible for the numeral set to be unknown at this point.
|
|
3447
|
-
denormalise(str) {
|
|
3448
|
-
if (!this.#userNumeralSet || this.#userNumeralSet === "ascii") {
|
|
3449
|
-
return str;
|
|
3450
|
-
}
|
|
3451
|
-
const base = this.#userNumeralSet === "arabic-indic" ? 1632 : 1776;
|
|
3452
|
-
return str.replace(/[0-9]/g, (d) => String.fromCharCode(base + Number(d)));
|
|
3453
|
-
}
|
|
3454
|
-
// Normalize Eastern Arabic (U+0660-0669) and Persian/Extended Arabic-Indic (U+06F0-06F9) numerals to ASCII 0-9
|
|
3455
|
-
normalise(str) {
|
|
3456
|
-
if (!str) {
|
|
3457
|
-
return "";
|
|
3458
|
-
}
|
|
3459
|
-
this.#updateNumeralSet(str);
|
|
3460
|
-
if (this.#userNumeralSet === "ascii") {
|
|
3461
|
-
return str;
|
|
3462
|
-
}
|
|
3463
|
-
const base = this.#userNumeralSet === "arabic-indic" ? 1632 : 1776;
|
|
3464
|
-
const regex = this.#userNumeralSet === "arabic-indic" ? /[\u0660-\u0669]/g : /[\u06F0-\u06F9]/g;
|
|
3465
|
-
return str.replace(
|
|
3466
|
-
regex,
|
|
3467
|
-
(ch) => String.fromCharCode(48 + (ch.charCodeAt(0) - base))
|
|
3468
|
-
);
|
|
3469
|
-
}
|
|
3470
|
-
isAscii() {
|
|
3471
|
-
return !this.#userNumeralSet || this.#userNumeralSet === "ascii";
|
|
3472
|
-
}
|
|
3473
|
-
};
|
|
3474
|
-
|
|
3475
3501
|
// src/js/intlTelInput.ts
|
|
3476
3502
|
var nextId = 0;
|
|
3477
3503
|
var ensureUtils = (methodName) => {
|
|
@@ -3506,6 +3532,7 @@ var Iti = class _Iti {
|
|
|
3506
3532
|
#dialCodeToIso2Map;
|
|
3507
3533
|
#dialCodes;
|
|
3508
3534
|
#countryByIso2;
|
|
3535
|
+
#searchTokens;
|
|
3509
3536
|
#selectedCountry = null;
|
|
3510
3537
|
#maxCoreNumberLength = null;
|
|
3511
3538
|
#fallbackCountryIso2;
|
|
@@ -3529,9 +3556,7 @@ var Iti = class _Iti {
|
|
|
3529
3556
|
this.#numerals = new Numerals(input.value);
|
|
3530
3557
|
this.promise = this.#createInitPromise(this.#options);
|
|
3531
3558
|
this.#countries = processAllCountries(this.#options);
|
|
3532
|
-
const { dialCodes, dialCodeMaxLength, dialCodeToIso2Map } = processDialCodes(
|
|
3533
|
-
this.#countries
|
|
3534
|
-
);
|
|
3559
|
+
const { dialCodes, dialCodeMaxLength, dialCodeToIso2Map } = processDialCodes(this.#countries);
|
|
3535
3560
|
this.#dialCodes = dialCodes;
|
|
3536
3561
|
this.#dialCodeMaxLength = dialCodeMaxLength;
|
|
3537
3562
|
this.#dialCodeToIso2Map = dialCodeToIso2Map;
|
|
@@ -3564,7 +3589,7 @@ var Iti = class _Iti {
|
|
|
3564
3589
|
#init() {
|
|
3565
3590
|
this.#abortController = new AbortController();
|
|
3566
3591
|
this.#processCountryData();
|
|
3567
|
-
this.#ui.buildMarkup(this.#countries);
|
|
3592
|
+
this.#ui.buildMarkup(this.#countries, this.#searchTokens);
|
|
3568
3593
|
this.#setInitialState();
|
|
3569
3594
|
this.#initListeners();
|
|
3570
3595
|
this.#startAsyncLoads();
|
|
@@ -3579,7 +3604,7 @@ var Iti = class _Iti {
|
|
|
3579
3604
|
#processCountryData() {
|
|
3580
3605
|
generateCountryNames(this.#countries, this.#options);
|
|
3581
3606
|
sortCountries(this.#countries, this.#options);
|
|
3582
|
-
|
|
3607
|
+
this.#searchTokens = buildSearchTokens(this.#countries);
|
|
3583
3608
|
}
|
|
3584
3609
|
//* Set the initial state of the input value and the selected country by:
|
|
3585
3610
|
//* 1. Extracting a dial code from the given number
|
|
@@ -3702,7 +3727,7 @@ var Iti = class _Iti {
|
|
|
3702
3727
|
#bindAllTelInputListeners() {
|
|
3703
3728
|
this.#bindInputListener();
|
|
3704
3729
|
this.#bindKeydownListener();
|
|
3705
|
-
this.#
|
|
3730
|
+
this.#bindStrictPasteListener();
|
|
3706
3731
|
}
|
|
3707
3732
|
//* Android workaround for handling plus when separateDialCode enabled (as impossible to handle with keydown/keyup, for which e.key always returns "Unidentified", see https://stackoverflow.com/q/59584061/217866)
|
|
3708
3733
|
#handleAndroidPlusKey(inputValue) {
|
|
@@ -3713,6 +3738,7 @@ var Iti = class _Iti {
|
|
|
3713
3738
|
#handleAndroidStrictReject(inputValue, rejectedInput) {
|
|
3714
3739
|
const newCaretPos = this.#removeJustTypedChar(inputValue);
|
|
3715
3740
|
this.#ui.telInputEl.setSelectionRange(newCaretPos, newCaretPos);
|
|
3741
|
+
this.#playStrictRejectAnimation();
|
|
3716
3742
|
this.#dispatchEvent(EVENTS.STRICT_REJECT, {
|
|
3717
3743
|
source: "key",
|
|
3718
3744
|
rejectedInput,
|
|
@@ -3772,7 +3798,13 @@ var Iti = class _Iti {
|
|
|
3772
3798
|
//* On input event: (1) Update selected country, (2) Format-as-you-type.
|
|
3773
3799
|
//* Note that this fires AFTER the input is updated.
|
|
3774
3800
|
#handleInputEvent = (e) => {
|
|
3775
|
-
const {
|
|
3801
|
+
const {
|
|
3802
|
+
strictMode,
|
|
3803
|
+
formatAsYouType,
|
|
3804
|
+
separateDialCode,
|
|
3805
|
+
allowDropdown,
|
|
3806
|
+
countrySearch
|
|
3807
|
+
} = this.#options;
|
|
3776
3808
|
const detail = e?.detail;
|
|
3777
3809
|
if (detail?.["isCountryChange"]) {
|
|
3778
3810
|
return;
|
|
@@ -3854,6 +3886,7 @@ var Iti = class _Iti {
|
|
|
3854
3886
|
const newCountry = this.#resolveCountryChangeFromNumber(newFullNumber);
|
|
3855
3887
|
const isChangingDialCode = newCountry !== null;
|
|
3856
3888
|
if (!isAllowedChar || hasExceededMaxLength && !isChangingDialCode && !isInitialPlus) {
|
|
3889
|
+
this.#playStrictRejectAnimation();
|
|
3857
3890
|
this.#dispatchEvent(EVENTS.STRICT_REJECT, {
|
|
3858
3891
|
source: "key",
|
|
3859
3892
|
rejectedInput: e.key,
|
|
@@ -3862,15 +3895,16 @@ var Iti = class _Iti {
|
|
|
3862
3895
|
e.preventDefault();
|
|
3863
3896
|
}
|
|
3864
3897
|
};
|
|
3865
|
-
#
|
|
3898
|
+
#bindStrictPasteListener() {
|
|
3866
3899
|
if (!this.#options.strictMode) {
|
|
3867
3900
|
return;
|
|
3868
3901
|
}
|
|
3869
|
-
this.#ui.telInputEl.addEventListener("paste", this.#
|
|
3902
|
+
this.#ui.telInputEl.addEventListener("paste", this.#handleStrictPasteEvent, {
|
|
3870
3903
|
signal: this.#abortController.signal
|
|
3871
3904
|
});
|
|
3872
3905
|
}
|
|
3873
|
-
|
|
3906
|
+
// Handle paste events when strictMode is enabled by sanitising the pasted content before it's inserted into the input, and rejecting it entirely if it would result in an invalid number
|
|
3907
|
+
#handleStrictPasteEvent = (e) => {
|
|
3874
3908
|
e.preventDefault();
|
|
3875
3909
|
const input = this.#ui.telInputEl;
|
|
3876
3910
|
const selStart = input.selectionStart;
|
|
@@ -3889,6 +3923,15 @@ var Iti = class _Iti {
|
|
|
3889
3923
|
const sanitised = hasLeadingPlus && allowLeadingPlus ? `+${numerics}` : numerics;
|
|
3890
3924
|
let newValue = before + sanitised + after;
|
|
3891
3925
|
let rejectReason = sanitised !== pasted ? "invalid" : null;
|
|
3926
|
+
if (newValue.length > 30) {
|
|
3927
|
+
this.#playStrictRejectAnimation();
|
|
3928
|
+
this.#dispatchEvent(EVENTS.STRICT_REJECT, {
|
|
3929
|
+
source: "paste",
|
|
3930
|
+
rejectedInput: pastedRaw,
|
|
3931
|
+
reason: "max-length"
|
|
3932
|
+
});
|
|
3933
|
+
return;
|
|
3934
|
+
}
|
|
3892
3935
|
if (newValue.length > 5 && intlTelInput.utils) {
|
|
3893
3936
|
let coreNumber = intlTelInput.utils.getCoreNumber(newValue, iso2);
|
|
3894
3937
|
while (coreNumber.length === 0 && newValue.length > 0) {
|
|
@@ -3896,6 +3939,7 @@ var Iti = class _Iti {
|
|
|
3896
3939
|
coreNumber = intlTelInput.utils.getCoreNumber(newValue, iso2);
|
|
3897
3940
|
}
|
|
3898
3941
|
if (!coreNumber) {
|
|
3942
|
+
this.#playStrictRejectAnimation();
|
|
3899
3943
|
this.#dispatchEvent(EVENTS.STRICT_REJECT, {
|
|
3900
3944
|
source: "paste",
|
|
3901
3945
|
rejectedInput: pastedRaw,
|
|
@@ -3909,6 +3953,7 @@ var Iti = class _Iti {
|
|
|
3909
3953
|
newValue = newValue.slice(0, newValue.length - trimLength);
|
|
3910
3954
|
rejectReason = "max-length";
|
|
3911
3955
|
} else {
|
|
3956
|
+
this.#playStrictRejectAnimation();
|
|
3912
3957
|
this.#dispatchEvent(EVENTS.STRICT_REJECT, {
|
|
3913
3958
|
source: "paste",
|
|
3914
3959
|
rejectedInput: pastedRaw,
|
|
@@ -3923,6 +3968,9 @@ var Iti = class _Iti {
|
|
|
3923
3968
|
input.setSelectionRange(caretPos, caretPos);
|
|
3924
3969
|
input.dispatchEvent(new InputEvent("input", { bubbles: true }));
|
|
3925
3970
|
if (rejectReason) {
|
|
3971
|
+
if (pasted.length > 0 && sanitised.length === 0) {
|
|
3972
|
+
this.#playStrictRejectAnimation();
|
|
3973
|
+
}
|
|
3926
3974
|
this.#dispatchEvent(EVENTS.STRICT_REJECT, {
|
|
3927
3975
|
source: "paste",
|
|
3928
3976
|
rejectedInput: pastedRaw,
|
|
@@ -3935,6 +3983,21 @@ var Iti = class _Iti {
|
|
|
3935
3983
|
const max = Number(this.#ui.telInputEl.getAttribute("maxlength"));
|
|
3936
3984
|
return max && number.length > max ? number.substring(0, max) : number;
|
|
3937
3985
|
}
|
|
3986
|
+
//* Play the strict-reject animation (shake, or background-colour flash under prefers-reduced-motion) on the wrapper.
|
|
3987
|
+
//* Called when strictMode rejects the whole input (keystroke, or whole paste).
|
|
3988
|
+
//* Uses the wrapper (not the input) so any separateDialCode / country button move together with the input.
|
|
3989
|
+
#playStrictRejectAnimation() {
|
|
3990
|
+
if (!this.#options.strictRejectAnimation) {
|
|
3991
|
+
return;
|
|
3992
|
+
}
|
|
3993
|
+
const wrapperEl = this.#ui.telInputEl.parentElement;
|
|
3994
|
+
if (!wrapperEl) {
|
|
3995
|
+
return;
|
|
3996
|
+
}
|
|
3997
|
+
wrapperEl.classList.remove("iti__strict-reject-animation");
|
|
3998
|
+
void wrapperEl.offsetWidth;
|
|
3999
|
+
wrapperEl.classList.add("iti__strict-reject-animation");
|
|
4000
|
+
}
|
|
3938
4001
|
//* Trigger a custom event on the input (typed via ItiEventMap).
|
|
3939
4002
|
#dispatchEvent(name, detailProps = {}) {
|
|
3940
4003
|
const e = new CustomEvent(name, {
|
|
@@ -4571,7 +4634,7 @@ var intlTelInput = Object.assign(
|
|
|
4571
4634
|
attachUtils,
|
|
4572
4635
|
startedLoadingUtils: false,
|
|
4573
4636
|
startedLoadingAutoCountry: false,
|
|
4574
|
-
version: "27.
|
|
4637
|
+
version: "27.3.1"
|
|
4575
4638
|
}
|
|
4576
4639
|
);
|
|
4577
4640
|
var intlTelInput_default = intlTelInput;
|
|
@@ -4621,6 +4684,7 @@ var IntlTelInput = class _IntlTelInput {
|
|
|
4621
4684
|
separateDialCode;
|
|
4622
4685
|
showFlags;
|
|
4623
4686
|
strictMode;
|
|
4687
|
+
strictRejectAnimation;
|
|
4624
4688
|
useFullscreenPopup;
|
|
4625
4689
|
numberChange = new EventEmitter();
|
|
4626
4690
|
countryChange = new EventEmitter();
|
|
@@ -4637,6 +4701,8 @@ var IntlTelInput = class _IntlTelInput {
|
|
|
4637
4701
|
click = new EventEmitter();
|
|
4638
4702
|
iti;
|
|
4639
4703
|
appliedInputAttrKeys = /* @__PURE__ */ new Set();
|
|
4704
|
+
// Classes the plugin adds directly to the input (e.g. iti__tel-input)
|
|
4705
|
+
pluginInputClasses = "";
|
|
4640
4706
|
lastEmittedNumber;
|
|
4641
4707
|
lastEmittedCountry;
|
|
4642
4708
|
lastEmittedValidity;
|
|
@@ -4661,6 +4727,7 @@ var IntlTelInput = class _IntlTelInput {
|
|
|
4661
4727
|
};
|
|
4662
4728
|
ngAfterViewInit() {
|
|
4663
4729
|
this.iti = intlTelInput_default(this.inputRef.nativeElement, this.buildInitOptions());
|
|
4730
|
+
this.pluginInputClasses = this.inputRef.nativeElement.className;
|
|
4664
4731
|
this.inputRef.nativeElement.addEventListener("open:countrydropdown", this.handleOpenDropdown);
|
|
4665
4732
|
this.inputRef.nativeElement.addEventListener("close:countrydropdown", this.handleCloseDropdown);
|
|
4666
4733
|
this.inputRef.nativeElement.addEventListener("strict:reject", this.handleStrictReject);
|
|
@@ -4719,6 +4786,7 @@ var IntlTelInput = class _IntlTelInput {
|
|
|
4719
4786
|
separateDialCode: this.separateDialCode,
|
|
4720
4787
|
showFlags: this.showFlags,
|
|
4721
4788
|
strictMode: this.strictMode,
|
|
4789
|
+
strictRejectAnimation: this.strictRejectAnimation,
|
|
4722
4790
|
useFullscreenPopup: this.useFullscreenPopup
|
|
4723
4791
|
};
|
|
4724
4792
|
return Object.fromEntries(Object.entries(options).filter(([, value]) => value !== void 0));
|
|
@@ -4824,7 +4892,8 @@ var IntlTelInput = class _IntlTelInput {
|
|
|
4824
4892
|
warnInputAttr(key);
|
|
4825
4893
|
} else {
|
|
4826
4894
|
currentKeys.add(key);
|
|
4827
|
-
this.
|
|
4895
|
+
const next = key === "class" && this.pluginInputClasses ? `${this.pluginInputClasses} ${value}` : value;
|
|
4896
|
+
this.inputRef.nativeElement.setAttribute(key, next);
|
|
4828
4897
|
}
|
|
4829
4898
|
});
|
|
4830
4899
|
this.appliedInputAttrKeys.forEach((key) => {
|
|
@@ -4885,7 +4954,7 @@ var IntlTelInput = class _IntlTelInput {
|
|
|
4885
4954
|
let _t;
|
|
4886
4955
|
i0.\u0275\u0275queryRefresh(_t = i0.\u0275\u0275loadQuery()) && (ctx.inputRef = _t.first);
|
|
4887
4956
|
}
|
|
4888
|
-
}, inputs: { initialValue: "initialValue", usePreciseValidation: "usePreciseValidation", inputAttributes: "inputAttributes", disabled: "disabled", readonly: "readonly", allowDropdown: "allowDropdown", allowedNumberTypes: "allowedNumberTypes", allowNumberExtensions: "allowNumberExtensions", allowPhonewords: "allowPhonewords", autoPlaceholder: "autoPlaceholder", containerClass: "containerClass", countryNameLocale: "countryNameLocale", countryOrder: "countryOrder", countrySearch: "countrySearch", customPlaceholder: "customPlaceholder", dropdownAlwaysOpen: "dropdownAlwaysOpen", dropdownContainer: "dropdownContainer", excludeCountries: "excludeCountries", fixDropdownWidth: "fixDropdownWidth", formatAsYouType: "formatAsYouType", formatOnDisplay: "formatOnDisplay", geoIpLookup: "geoIpLookup", hiddenInput: "hiddenInput", i18n: "i18n", initialCountry: "initialCountry", loadUtils: "loadUtils", nationalMode: "nationalMode", onlyCountries: "onlyCountries", placeholderNumberType: "placeholderNumberType", searchInputClass: "searchInputClass", separateDialCode: "separateDialCode", showFlags: "showFlags", strictMode: "strictMode", useFullscreenPopup: "useFullscreenPopup" }, outputs: { numberChange: "numberChange", countryChange: "countryChange", validityChange: "validityChange", errorCodeChange: "errorCodeChange", openCountryDropdown: "openCountryDropdown", closeCountryDropdown: "closeCountryDropdown", strictReject: "strictReject", blur: "blur", focus: "focus", keydown: "keydown", keyup: "keyup", paste: "paste", click: "click" }, features: [i0.\u0275\u0275ProvidersFeature([
|
|
4957
|
+
}, inputs: { initialValue: "initialValue", usePreciseValidation: "usePreciseValidation", inputAttributes: "inputAttributes", disabled: "disabled", readonly: "readonly", allowDropdown: "allowDropdown", allowedNumberTypes: "allowedNumberTypes", allowNumberExtensions: "allowNumberExtensions", allowPhonewords: "allowPhonewords", autoPlaceholder: "autoPlaceholder", containerClass: "containerClass", countryNameLocale: "countryNameLocale", countryOrder: "countryOrder", countrySearch: "countrySearch", customPlaceholder: "customPlaceholder", dropdownAlwaysOpen: "dropdownAlwaysOpen", dropdownContainer: "dropdownContainer", excludeCountries: "excludeCountries", fixDropdownWidth: "fixDropdownWidth", formatAsYouType: "formatAsYouType", formatOnDisplay: "formatOnDisplay", geoIpLookup: "geoIpLookup", hiddenInput: "hiddenInput", i18n: "i18n", initialCountry: "initialCountry", loadUtils: "loadUtils", nationalMode: "nationalMode", onlyCountries: "onlyCountries", placeholderNumberType: "placeholderNumberType", searchInputClass: "searchInputClass", separateDialCode: "separateDialCode", showFlags: "showFlags", strictMode: "strictMode", strictRejectAnimation: "strictRejectAnimation", useFullscreenPopup: "useFullscreenPopup" }, outputs: { numberChange: "numberChange", countryChange: "countryChange", validityChange: "validityChange", errorCodeChange: "errorCodeChange", openCountryDropdown: "openCountryDropdown", closeCountryDropdown: "closeCountryDropdown", strictReject: "strictReject", blur: "blur", focus: "focus", keydown: "keydown", keyup: "keyup", paste: "paste", click: "click" }, features: [i0.\u0275\u0275ProvidersFeature([
|
|
4889
4958
|
{
|
|
4890
4959
|
provide: NG_VALUE_ACCESSOR,
|
|
4891
4960
|
useExisting: forwardRef(() => _IntlTelInput),
|
|
@@ -5019,6 +5088,8 @@ var IntlTelInput = class _IntlTelInput {
|
|
|
5019
5088
|
type: Input
|
|
5020
5089
|
}], strictMode: [{
|
|
5021
5090
|
type: Input
|
|
5091
|
+
}], strictRejectAnimation: [{
|
|
5092
|
+
type: Input
|
|
5022
5093
|
}], useFullscreenPopup: [{
|
|
5023
5094
|
type: Input
|
|
5024
5095
|
}], numberChange: [{
|