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.
@@ -46,6 +46,7 @@ interface PhoneInputOptions {
46
46
  initialValue?: string;
47
47
  containerClass?: string;
48
48
  dropdownContainer?: HTMLElement;
49
+ geoIpLookup?: (callback: (countryCode: string | null) => void) => void;
49
50
  onChange?: (e164: string, country: Country, validation: ValidationResult) => void;
50
51
  onCountryChange?: (country: Country) => void;
51
52
  onValidationChange?: (validation: ValidationResult) => void;
@@ -46,6 +46,7 @@ interface PhoneInputOptions {
46
46
  initialValue?: string;
47
47
  containerClass?: string;
48
48
  dropdownContainer?: HTMLElement;
49
+ geoIpLookup?: (callback: (countryCode: string | null) => void) => void;
49
50
  onChange?: (e164: string, country: Country, validation: ValidationResult) => void;
50
51
  onCountryChange?: (country: Country) => void;
51
52
  onValidationChange?: (validation: ValidationResult) => void;
@@ -2810,7 +2810,27 @@ var phone_countries_default = [
2810
2810
  // src/core/format.ts
2811
2811
  var TRAILING_SEP = /[\s\-]+$/;
2812
2812
  var FALLBACK_GROUP = /(.{4})(?=.)/g;
2813
- var NON_ASCII_DIGITS = /[\u0660-\u0669\u06F0-\u06F9]/g;
2813
+ var NUMERAL_BASES = [
2814
+ 1632,
2815
+ // Arabic-Indic ٠-٩
2816
+ 1776,
2817
+ // Persian ۰-۹
2818
+ 2406,
2819
+ // Devanagari ०-९
2820
+ 2534,
2821
+ // Bengali ০-৯
2822
+ 3664,
2823
+ // Thai ๐-๙
2824
+ 3792,
2825
+ // Lao ໐-໙
2826
+ 4160,
2827
+ // Myanmar ၀-၉
2828
+ 6112,
2829
+ // Khmer ០-៩
2830
+ 65296
2831
+ // Fullwidth 0-9
2832
+ ];
2833
+ var NON_ASCII_DIGITS = /[\u0660-\u0669\u06F0-\u06F9\u0966-\u096F\u09E6-\u09EF\u0E50-\u0E59\u0ED0-\u0ED9\u1040-\u1049\u17E0-\u17E9\uFF10-\uFF19]/g;
2814
2834
  function isRelevantChar(ch) {
2815
2835
  const c = ch.charCodeAt(0);
2816
2836
  return c >= 48 && c <= 57 || c === 43;
@@ -2860,9 +2880,18 @@ function extractDigits(value) {
2860
2880
  function normalizeNumerals(value) {
2861
2881
  return value.replace(NON_ASCII_DIGITS, (c) => {
2862
2882
  const code = c.charCodeAt(0);
2863
- return code <= 1641 ? String(code - 1632) : String(code - 1776);
2883
+ for (const base of NUMERAL_BASES) {
2884
+ if (code >= base && code <= base + 9) {
2885
+ return String(code - base);
2886
+ }
2887
+ }
2888
+ return c;
2864
2889
  });
2865
2890
  }
2891
+ function isNonAsciiDigit(ch) {
2892
+ const code = ch.charCodeAt(0);
2893
+ return NUMERAL_BASES.some((base) => code >= base && code <= base + 9);
2894
+ }
2866
2895
 
2867
2896
  // src/core/countries.ts
2868
2897
  function getFlag(code) {
@@ -3275,6 +3304,7 @@ var PhoneInput = class _PhoneInput {
3275
3304
  constructor(el, options) {
3276
3305
  this.nationalDigits = "";
3277
3306
  this.displayInternational = false;
3307
+ this.userHasInteracted = false;
3278
3308
  this.lastValidation = null;
3279
3309
  this.dropdown = null;
3280
3310
  this.dialCodeEl = null;
@@ -3292,6 +3322,7 @@ var PhoneInput = class _PhoneInput {
3292
3322
  if (this.opts.initialValue) {
3293
3323
  this.setValueInternal(this.opts.initialValue, true);
3294
3324
  }
3325
+ this.invokeGeoIpLookup();
3295
3326
  }
3296
3327
  }
3297
3328
  get isNationalInput() {
@@ -3329,8 +3360,9 @@ var PhoneInput = class _PhoneInput {
3329
3360
  return validatePhone(this.nationalDigits, this.selectedCountry);
3330
3361
  }
3331
3362
  setOptions(opts) {
3363
+ const { geoIpLookup: _, ...rest } = opts;
3332
3364
  const prev = { ...this.opts };
3333
- Object.assign(this.opts, opts);
3365
+ Object.assign(this.opts, rest);
3334
3366
  if (opts.allowedCountries !== void 0 || opts.excludedCountries !== void 0) {
3335
3367
  this.countries = this.filterCountries(getAllCountries());
3336
3368
  if (!this.countries.find((c) => c.code === this.selectedCountry.code)) {
@@ -3372,6 +3404,16 @@ var PhoneInput = class _PhoneInput {
3372
3404
  }
3373
3405
  this.el.innerHTML = "";
3374
3406
  }
3407
+ invokeGeoIpLookup() {
3408
+ const lookup = this.opts.geoIpLookup;
3409
+ if (!lookup) return;
3410
+ this.opts.geoIpLookup = void 0;
3411
+ const signal = this.ac.signal;
3412
+ lookup((countryCode) => {
3413
+ if (signal.aborted || this.userHasInteracted || !countryCode) return;
3414
+ this.setCountry(countryCode);
3415
+ });
3416
+ }
3375
3417
  // --- DOM Construction ---
3376
3418
  buildDOM() {
3377
3419
  this.containerEl = document.createElement("div");
@@ -3471,6 +3513,7 @@ var PhoneInput = class _PhoneInput {
3471
3513
  this.inputEl.addEventListener("paste", (e) => this.handlePaste(e), { signal });
3472
3514
  }
3473
3515
  handleInput(e) {
3516
+ this.userHasInteracted = true;
3474
3517
  if (this.opts.strict !== false && e.data === "+" && this.isNationalInput) {
3475
3518
  this.inputEl.value = this.inputEl.value.replace("+", "");
3476
3519
  }
@@ -3486,7 +3529,7 @@ var PhoneInput = class _PhoneInput {
3486
3529
  const formatted = this.formatNationalValue(digits);
3487
3530
  const np = this.shouldPrependPrefix ? this.selectedCountry.nationalPrefix : "";
3488
3531
  const display = !digits && np && extractDigits(raw).length > 0 ? np : digits && np ? np + formatted : formatted;
3489
- const newCursor = this.getNationalCursor(this.inputEl.value, oldCursor, formatted);
3532
+ const newCursor = this.getNationalCursor(raw, oldCursor, formatted);
3490
3533
  this.inputEl.value = display;
3491
3534
  this.inputEl.setSelectionRange(newCursor, newCursor);
3492
3535
  } else {
@@ -3513,7 +3556,7 @@ var PhoneInput = class _PhoneInput {
3513
3556
  } else {
3514
3557
  formatted = this.formatNationalValue(national);
3515
3558
  }
3516
- const newCursor = getCursorPosition(this.inputEl.value, oldCursor, formatted);
3559
+ const newCursor = getCursorPosition(raw, oldCursor, formatted);
3517
3560
  this.inputEl.value = formatted;
3518
3561
  this.inputEl.setSelectionRange(newCursor, newCursor);
3519
3562
  }
@@ -3528,14 +3571,12 @@ var PhoneInput = class _PhoneInput {
3528
3571
  if (!this.isNationalInput && e.key === "+" && this.inputEl.selectionStart === 0) {
3529
3572
  return;
3530
3573
  }
3531
- if (e.key.length === 1 && !/\d/.test(e.key)) {
3532
- const code = e.key.charCodeAt(0);
3533
- if (!(code >= 1632 && code <= 1641 || code >= 1776 && code <= 1785)) {
3534
- e.preventDefault();
3535
- }
3574
+ if (e.key.length === 1 && !/\d/.test(e.key) && !isNonAsciiDigit(e.key)) {
3575
+ e.preventDefault();
3536
3576
  }
3537
3577
  }
3538
3578
  handlePaste(e) {
3579
+ this.userHasInteracted = true;
3539
3580
  e.preventDefault();
3540
3581
  const text = e.clipboardData?.getData("text") ?? "";
3541
3582
  if (!text) return;
@@ -3574,6 +3615,7 @@ var PhoneInput = class _PhoneInput {
3574
3615
  // --- Dropdown ---
3575
3616
  openDropdown() {
3576
3617
  if (this.dropdown) return;
3618
+ this.userHasInteracted = true;
3577
3619
  this.dropdown = new Dropdown({
3578
3620
  countries: this.countries,
3579
3621
  preferredCountries: this.opts.preferredCountries ?? [],
@@ -3831,6 +3873,7 @@ var WIDGET_KEYS = /* @__PURE__ */ new Set([
3831
3873
  "initialValue",
3832
3874
  "containerClass",
3833
3875
  "dropdownContainer",
3876
+ "geoIpLookup",
3834
3877
  "onChange",
3835
3878
  "onCountryChange",
3836
3879
  "onValidationChange",
@@ -3888,6 +3931,7 @@ var PhoneInput2 = forwardRef(
3888
3931
  hiddenInput: p.hiddenInput,
3889
3932
  containerClass: p.containerClass,
3890
3933
  dropdownContainer: p.dropdownContainer,
3934
+ geoIpLookup: p.geoIpLookup,
3891
3935
  initialValue: p.initialValue,
3892
3936
  inputAttributes,
3893
3937
  onChange: (e164, country, validation) => propsRef.current.onChange?.(e164, country, validation),