lite-phone-input 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -45,6 +45,7 @@ interface PhoneInputOptions {
45
45
  initialValue?: string;
46
46
  containerClass?: string;
47
47
  dropdownContainer?: HTMLElement;
48
+ geoIpLookup?: (callback: (countryCode: string | null) => void) => void;
48
49
  onChange?: (e164: string, country: Country, validation: ValidationResult) => void;
49
50
  onCountryChange?: (country: Country) => void;
50
51
  onValidationChange?: (validation: ValidationResult) => void;
@@ -45,6 +45,7 @@ interface PhoneInputOptions {
45
45
  initialValue?: string;
46
46
  containerClass?: string;
47
47
  dropdownContainer?: HTMLElement;
48
+ geoIpLookup?: (callback: (countryCode: string | null) => void) => void;
48
49
  onChange?: (e164: string, country: Country, validation: ValidationResult) => void;
49
50
  onCountryChange?: (country: Country) => void;
50
51
  onValidationChange?: (validation: ValidationResult) => void;
@@ -2808,7 +2808,27 @@ var phone_countries_default = [
2808
2808
  // src/core/format.ts
2809
2809
  var TRAILING_SEP = /[\s\-]+$/;
2810
2810
  var FALLBACK_GROUP = /(.{4})(?=.)/g;
2811
- var NON_ASCII_DIGITS = /[\u0660-\u0669\u06F0-\u06F9]/g;
2811
+ var NUMERAL_BASES = [
2812
+ 1632,
2813
+ // Arabic-Indic ٠-٩
2814
+ 1776,
2815
+ // Persian ۰-۹
2816
+ 2406,
2817
+ // Devanagari ०-९
2818
+ 2534,
2819
+ // Bengali ০-৯
2820
+ 3664,
2821
+ // Thai ๐-๙
2822
+ 3792,
2823
+ // Lao ໐-໙
2824
+ 4160,
2825
+ // Myanmar ၀-၉
2826
+ 6112,
2827
+ // Khmer ០-៩
2828
+ 65296
2829
+ // Fullwidth 0-9
2830
+ ];
2831
+ var NON_ASCII_DIGITS = /[\u0660-\u0669\u06F0-\u06F9\u0966-\u096F\u09E6-\u09EF\u0E50-\u0E59\u0ED0-\u0ED9\u1040-\u1049\u17E0-\u17E9\uFF10-\uFF19]/g;
2812
2832
  function isRelevantChar(ch) {
2813
2833
  const c = ch.charCodeAt(0);
2814
2834
  return c >= 48 && c <= 57 || c === 43;
@@ -2858,9 +2878,18 @@ function extractDigits(value) {
2858
2878
  function normalizeNumerals(value) {
2859
2879
  return value.replace(NON_ASCII_DIGITS, (c) => {
2860
2880
  const code = c.charCodeAt(0);
2861
- return code <= 1641 ? String(code - 1632) : String(code - 1776);
2881
+ for (const base of NUMERAL_BASES) {
2882
+ if (code >= base && code <= base + 9) {
2883
+ return String(code - base);
2884
+ }
2885
+ }
2886
+ return c;
2862
2887
  });
2863
2888
  }
2889
+ function isNonAsciiDigit(ch) {
2890
+ const code = ch.charCodeAt(0);
2891
+ return NUMERAL_BASES.some((base) => code >= base && code <= base + 9);
2892
+ }
2864
2893
 
2865
2894
  // src/core/countries.ts
2866
2895
  function getFlag(code) {
@@ -3273,6 +3302,7 @@ var PhoneInput = class _PhoneInput {
3273
3302
  constructor(el, options) {
3274
3303
  this.nationalDigits = "";
3275
3304
  this.displayInternational = false;
3305
+ this.userHasInteracted = false;
3276
3306
  this.lastValidation = null;
3277
3307
  this.dropdown = null;
3278
3308
  this.dialCodeEl = null;
@@ -3290,6 +3320,7 @@ var PhoneInput = class _PhoneInput {
3290
3320
  if (this.opts.initialValue) {
3291
3321
  this.setValueInternal(this.opts.initialValue, true);
3292
3322
  }
3323
+ this.invokeGeoIpLookup();
3293
3324
  }
3294
3325
  }
3295
3326
  get isNationalInput() {
@@ -3327,8 +3358,9 @@ var PhoneInput = class _PhoneInput {
3327
3358
  return validatePhone(this.nationalDigits, this.selectedCountry);
3328
3359
  }
3329
3360
  setOptions(opts) {
3361
+ const { geoIpLookup: _, ...rest } = opts;
3330
3362
  const prev = { ...this.opts };
3331
- Object.assign(this.opts, opts);
3363
+ Object.assign(this.opts, rest);
3332
3364
  if (opts.allowedCountries !== void 0 || opts.excludedCountries !== void 0) {
3333
3365
  this.countries = this.filterCountries(getAllCountries());
3334
3366
  if (!this.countries.find((c) => c.code === this.selectedCountry.code)) {
@@ -3370,6 +3402,16 @@ var PhoneInput = class _PhoneInput {
3370
3402
  }
3371
3403
  this.el.innerHTML = "";
3372
3404
  }
3405
+ invokeGeoIpLookup() {
3406
+ const lookup = this.opts.geoIpLookup;
3407
+ if (!lookup) return;
3408
+ this.opts.geoIpLookup = void 0;
3409
+ const signal = this.ac.signal;
3410
+ lookup((countryCode) => {
3411
+ if (signal.aborted || this.userHasInteracted || !countryCode) return;
3412
+ this.setCountry(countryCode);
3413
+ });
3414
+ }
3373
3415
  // --- DOM Construction ---
3374
3416
  buildDOM() {
3375
3417
  this.containerEl = document.createElement("div");
@@ -3469,6 +3511,7 @@ var PhoneInput = class _PhoneInput {
3469
3511
  this.inputEl.addEventListener("paste", (e) => this.handlePaste(e), { signal });
3470
3512
  }
3471
3513
  handleInput(e) {
3514
+ this.userHasInteracted = true;
3472
3515
  if (this.opts.strict !== false && e.data === "+" && this.isNationalInput) {
3473
3516
  this.inputEl.value = this.inputEl.value.replace("+", "");
3474
3517
  }
@@ -3484,7 +3527,7 @@ var PhoneInput = class _PhoneInput {
3484
3527
  const formatted = this.formatNationalValue(digits);
3485
3528
  const np = this.shouldPrependPrefix ? this.selectedCountry.nationalPrefix : "";
3486
3529
  const display = !digits && np && extractDigits(raw).length > 0 ? np : digits && np ? np + formatted : formatted;
3487
- const newCursor = this.getNationalCursor(this.inputEl.value, oldCursor, formatted);
3530
+ const newCursor = this.getNationalCursor(raw, oldCursor, formatted);
3488
3531
  this.inputEl.value = display;
3489
3532
  this.inputEl.setSelectionRange(newCursor, newCursor);
3490
3533
  } else {
@@ -3511,7 +3554,7 @@ var PhoneInput = class _PhoneInput {
3511
3554
  } else {
3512
3555
  formatted = this.formatNationalValue(national);
3513
3556
  }
3514
- const newCursor = getCursorPosition(this.inputEl.value, oldCursor, formatted);
3557
+ const newCursor = getCursorPosition(raw, oldCursor, formatted);
3515
3558
  this.inputEl.value = formatted;
3516
3559
  this.inputEl.setSelectionRange(newCursor, newCursor);
3517
3560
  }
@@ -3526,14 +3569,12 @@ var PhoneInput = class _PhoneInput {
3526
3569
  if (!this.isNationalInput && e.key === "+" && this.inputEl.selectionStart === 0) {
3527
3570
  return;
3528
3571
  }
3529
- if (e.key.length === 1 && !/\d/.test(e.key)) {
3530
- const code = e.key.charCodeAt(0);
3531
- if (!(code >= 1632 && code <= 1641 || code >= 1776 && code <= 1785)) {
3532
- e.preventDefault();
3533
- }
3572
+ if (e.key.length === 1 && !/\d/.test(e.key) && !isNonAsciiDigit(e.key)) {
3573
+ e.preventDefault();
3534
3574
  }
3535
3575
  }
3536
3576
  handlePaste(e) {
3577
+ this.userHasInteracted = true;
3537
3578
  e.preventDefault();
3538
3579
  const text = e.clipboardData?.getData("text") ?? "";
3539
3580
  if (!text) return;
@@ -3572,6 +3613,7 @@ var PhoneInput = class _PhoneInput {
3572
3613
  // --- Dropdown ---
3573
3614
  openDropdown() {
3574
3615
  if (this.dropdown) return;
3616
+ this.userHasInteracted = true;
3575
3617
  this.dropdown = new Dropdown({
3576
3618
  countries: this.countries,
3577
3619
  preferredCountries: this.opts.preferredCountries ?? [],
@@ -3830,6 +3872,7 @@ var WIDGET_KEYS = /* @__PURE__ */ new Set([
3830
3872
  "initialValue",
3831
3873
  "containerClass",
3832
3874
  "dropdownContainer",
3875
+ "geoIpLookup",
3833
3876
  "onChange",
3834
3877
  "onCountryChange",
3835
3878
  "onValidationChange",
@@ -3887,6 +3930,7 @@ var PhoneInput2 = forwardRef(
3887
3930
  hiddenInput: p.hiddenInput,
3888
3931
  containerClass: p.containerClass,
3889
3932
  dropdownContainer: p.dropdownContainer,
3933
+ geoIpLookup: p.geoIpLookup,
3890
3934
  initialValue: p.initialValue,
3891
3935
  inputAttributes,
3892
3936
  // Callbacks read from ref so they always use the latest version