@transferwise/components 0.0.0-experimental-4b360b4 → 0.0.0-experimental-0b0d7e6

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.
Files changed (110) hide show
  1. package/build/index.esm.js +115 -272
  2. package/build/index.esm.js.map +1 -1
  3. package/build/index.js +114 -271
  4. package/build/index.js.map +1 -1
  5. package/build/types/common/locale/index.d.ts +26 -43
  6. package/build/types/common/locale/index.d.ts.map +1 -1
  7. package/build/types/phoneNumberInput/PhoneNumberInput.d.ts +22 -27
  8. package/build/types/phoneNumberInput/PhoneNumberInput.d.ts.map +1 -1
  9. package/build/types/phoneNumberInput/data/countries.d.ts +5 -10
  10. package/build/types/phoneNumberInput/data/countries.d.ts.map +1 -1
  11. package/build/types/phoneNumberInput/index.d.ts +1 -1
  12. package/build/types/phoneNumberInput/index.d.ts.map +1 -1
  13. package/build/types/phoneNumberInput/utils/cleanNumber/cleanNumber.d.ts +1 -1
  14. package/build/types/phoneNumberInput/utils/cleanNumber/cleanNumber.d.ts.map +1 -1
  15. package/build/types/phoneNumberInput/utils/cleanNumber/index.d.ts +1 -1
  16. package/build/types/phoneNumberInput/utils/cleanNumber/index.d.ts.map +1 -1
  17. package/build/types/phoneNumberInput/utils/excludeCountries/excludeCountries.d.ts +8 -1
  18. package/build/types/phoneNumberInput/utils/excludeCountries/excludeCountries.d.ts.map +1 -1
  19. package/build/types/phoneNumberInput/utils/excludeCountries/index.d.ts +1 -1
  20. package/build/types/phoneNumberInput/utils/excludeCountries/index.d.ts.map +1 -1
  21. package/build/types/phoneNumberInput/utils/explodeNumberModel/index.d.ts +8 -4
  22. package/build/types/phoneNumberInput/utils/explodeNumberModel/index.d.ts.map +1 -1
  23. package/build/types/phoneNumberInput/utils/findCountryByCode/index.d.ts +1 -1
  24. package/build/types/phoneNumberInput/utils/findCountryByCode/index.d.ts.map +1 -1
  25. package/build/types/phoneNumberInput/utils/findCountryByPrefix/index.d.ts +1 -1
  26. package/build/types/phoneNumberInput/utils/findCountryByPrefix/index.d.ts.map +1 -1
  27. package/build/types/phoneNumberInput/utils/groupCountriesByPrefix/groupCountriesByPrefix.d.ts +2 -1
  28. package/build/types/phoneNumberInput/utils/groupCountriesByPrefix/groupCountriesByPrefix.d.ts.map +1 -1
  29. package/build/types/phoneNumberInput/utils/groupCountriesByPrefix/index.d.ts +1 -1
  30. package/build/types/phoneNumberInput/utils/groupCountriesByPrefix/index.d.ts.map +1 -1
  31. package/build/types/phoneNumberInput/utils/index.d.ts +11 -13
  32. package/build/types/phoneNumberInput/utils/index.d.ts.map +1 -1
  33. package/build/types/phoneNumberInput/utils/isStringNumeric/index.d.ts +1 -1
  34. package/build/types/phoneNumberInput/utils/isStringNumeric/index.d.ts.map +1 -1
  35. package/build/types/phoneNumberInput/utils/isStringNumeric/isStringNumeric.d.ts +1 -1
  36. package/build/types/phoneNumberInput/utils/isStringNumeric/isStringNumeric.d.ts.map +1 -1
  37. package/build/types/phoneNumberInput/utils/isValidPhoneNumber/index.d.ts +1 -1
  38. package/build/types/phoneNumberInput/utils/isValidPhoneNumber/index.d.ts.map +1 -1
  39. package/build/types/phoneNumberInput/utils/isValidPhoneNumber/isValidPhoneNumber.d.ts +6 -1
  40. package/build/types/phoneNumberInput/utils/isValidPhoneNumber/isValidPhoneNumber.d.ts.map +1 -1
  41. package/build/types/phoneNumberInput/utils/longestMatchingPrefix/index.d.ts +2 -1
  42. package/build/types/phoneNumberInput/utils/longestMatchingPrefix/index.d.ts.map +1 -1
  43. package/build/types/phoneNumberInput/utils/setDefaultPrefix/index.d.ts +7 -1
  44. package/build/types/phoneNumberInput/utils/setDefaultPrefix/index.d.ts.map +1 -1
  45. package/build/types/phoneNumberInput/utils/sortArrayByProperty/index.d.ts +1 -1
  46. package/build/types/phoneNumberInput/utils/sortArrayByProperty/index.d.ts.map +1 -1
  47. package/build/types/phoneNumberInput/utils/sortArrayByProperty/sortArrayByProperty.d.ts +1 -1
  48. package/build/types/phoneNumberInput/utils/sortArrayByProperty/sortArrayByProperty.d.ts.map +1 -1
  49. package/package.json +1 -1
  50. package/src/common/locale/{index.spec.js → index.spec.ts} +4 -4
  51. package/src/common/locale/index.ts +96 -0
  52. package/src/phoneNumberInput/PhoneNumberInput.spec.js +18 -22
  53. package/src/phoneNumberInput/PhoneNumberInput.tsx +193 -0
  54. package/src/phoneNumberInput/data/{countries.js → countries.ts} +9 -1
  55. package/src/phoneNumberInput/utils/cleanNumber/cleanNumber.ts +3 -0
  56. package/src/phoneNumberInput/utils/excludeCountries/{excludeCountries.spec.js → excludeCountries.spec.ts} +1 -1
  57. package/src/phoneNumberInput/utils/excludeCountries/{excludeCountries.js → excludeCountries.ts} +6 -5
  58. package/src/phoneNumberInput/utils/explodeNumberModel/{explodeNumberModel.spec.js → explodeNumberModel.spec.ts} +1 -1
  59. package/src/phoneNumberInput/utils/explodeNumberModel/index.ts +24 -0
  60. package/src/phoneNumberInput/utils/findCountryByCode/{findCountryByCode.spec.js → findCountryByCode.spec.ts} +0 -1
  61. package/src/phoneNumberInput/utils/findCountryByCode/index.ts +12 -0
  62. package/src/phoneNumberInput/utils/findCountryByPrefix/index.ts +12 -0
  63. package/src/phoneNumberInput/utils/groupCountriesByPrefix/groupCountriesByPrefix.spec.ts +102 -0
  64. package/src/phoneNumberInput/utils/groupCountriesByPrefix/groupCountriesByPrefix.ts +12 -0
  65. package/src/phoneNumberInput/utils/{index.js → index.ts} +0 -2
  66. package/src/phoneNumberInput/utils/isStringNumeric/{isStringNumeric.spec.js → isStringNumeric.spec.ts} +0 -1
  67. package/src/phoneNumberInput/utils/isStringNumeric/isStringNumeric.ts +1 -0
  68. package/src/phoneNumberInput/utils/isValidPhoneNumber/{isValidPhoneNumber.spec.js → isValidPhoneNumber.spec.ts} +1 -1
  69. package/src/phoneNumberInput/utils/isValidPhoneNumber/isValidPhoneNumber.ts +7 -0
  70. package/src/phoneNumberInput/utils/longestMatchingPrefix/index.ts +4 -0
  71. package/src/phoneNumberInput/utils/setDefaultPrefix/index.ts +20 -0
  72. package/src/phoneNumberInput/utils/sortArrayByProperty/sortArrayByProperty.ts +6 -0
  73. package/build/types/phoneNumberInput/utils/filterOptionsForQuery/index.d.ts +0 -2
  74. package/build/types/phoneNumberInput/utils/filterOptionsForQuery/index.d.ts.map +0 -1
  75. package/build/types/phoneNumberInput/utils/isOptionAndFitsQuery/index.d.ts +0 -2
  76. package/build/types/phoneNumberInput/utils/isOptionAndFitsQuery/index.d.ts.map +0 -1
  77. package/build/types/phoneNumberInput/utils/isOptionAndFitsQuery/isOptionAndFitsQuery.d.ts +0 -3
  78. package/build/types/phoneNumberInput/utils/isOptionAndFitsQuery/isOptionAndFitsQuery.d.ts.map +0 -1
  79. package/src/common/locale/index.js +0 -139
  80. package/src/phoneNumberInput/PhoneNumberInput.js +0 -210
  81. package/src/phoneNumberInput/data/countries.spec.js +0 -12
  82. package/src/phoneNumberInput/utils/cleanNumber/cleanNumber.js +0 -4
  83. package/src/phoneNumberInput/utils/explodeNumberModel/index.js +0 -27
  84. package/src/phoneNumberInput/utils/filterOptionsForQuery/filterOptionsForQuery.spec.js +0 -36
  85. package/src/phoneNumberInput/utils/filterOptionsForQuery/index.js +0 -11
  86. package/src/phoneNumberInput/utils/findCountryByCode/index.js +0 -10
  87. package/src/phoneNumberInput/utils/findCountryByPrefix/index.js +0 -11
  88. package/src/phoneNumberInput/utils/groupCountriesByPrefix/groupCountriesByPrefix.js +0 -26
  89. package/src/phoneNumberInput/utils/groupCountriesByPrefix/groupCountriesByPrefix.spec.js +0 -67
  90. package/src/phoneNumberInput/utils/isOptionAndFitsQuery/index.js +0 -1
  91. package/src/phoneNumberInput/utils/isOptionAndFitsQuery/isOptionAndFitsQuery.js +0 -25
  92. package/src/phoneNumberInput/utils/isOptionAndFitsQuery/isOptionAndFitsQuery.spec.js +0 -66
  93. package/src/phoneNumberInput/utils/isStringNumeric/isStringNumeric.js +0 -1
  94. package/src/phoneNumberInput/utils/isValidPhoneNumber/isValidPhoneNumber.js +0 -10
  95. package/src/phoneNumberInput/utils/longestMatchingPrefix/index.js +0 -2
  96. package/src/phoneNumberInput/utils/setDefaultPrefix/index.js +0 -25
  97. package/src/phoneNumberInput/utils/sortArrayByProperty/sortArrayByProperty.js +0 -3
  98. /package/src/phoneNumberInput/{PhoneNumberInput.story.js → PhoneNumberInput.story.tsx} +0 -0
  99. /package/src/phoneNumberInput/{index.js → index.ts} +0 -0
  100. /package/src/phoneNumberInput/utils/cleanNumber/{cleanNumber.spec.js → cleanNumber.spec.ts} +0 -0
  101. /package/src/phoneNumberInput/utils/cleanNumber/{index.js → index.ts} +0 -0
  102. /package/src/phoneNumberInput/utils/excludeCountries/{index.js → index.ts} +0 -0
  103. /package/src/phoneNumberInput/utils/findCountryByPrefix/{findCountryByPrefix.spec.js → findCountryByPrefix.spec.ts} +0 -0
  104. /package/src/phoneNumberInput/utils/groupCountriesByPrefix/{index.js → index.ts} +0 -0
  105. /package/src/phoneNumberInput/utils/isStringNumeric/{index.js → index.ts} +0 -0
  106. /package/src/phoneNumberInput/utils/isValidPhoneNumber/{index.js → index.ts} +0 -0
  107. /package/src/phoneNumberInput/utils/longestMatchingPrefix/{longestMatchingPrefix.spec.js → longestMatchingPrefix.spec.ts} +0 -0
  108. /package/src/phoneNumberInput/utils/setDefaultPrefix/{setDefaultPrefix.spec.js → setDefaultPrefix.spec.ts} +0 -0
  109. /package/src/phoneNumberInput/utils/sortArrayByProperty/{index.js → index.ts} +0 -0
  110. /package/src/phoneNumberInput/utils/sortArrayByProperty/{sortArrayByProperty.spec.js → sortArrayByProperty.spec.ts} +0 -0
@@ -19,7 +19,7 @@ import { CSSTransition } from 'react-transition-group';
19
19
  import { usePopper } from 'react-popper';
20
20
  import throttle from 'lodash.throttle';
21
21
  import { createPortal } from 'react-dom';
22
- import { isUndefined, isKey, isNumber, isEmpty, isNull, isArray } from '@transferwise/neptune-validation';
22
+ import { isUndefined, isKey, isNumber, isEmpty, isNull } from '@transferwise/neptune-validation';
23
23
  import { Flag, Illustration } from '@wise/art';
24
24
  import clamp$2 from 'lodash.clamp';
25
25
  import debounce from 'lodash.debounce';
@@ -342,131 +342,76 @@ const Key = {
342
342
  COMMA: ','
343
343
  };
344
344
 
345
- /**
346
- * Default language
347
- *
348
- * @type {string}
349
- */
350
345
  const DEFAULT_LANG = 'en';
351
-
352
- /**
353
- * Default locale
354
- *
355
- * @type {string}
356
- */
357
346
  const DEFAULT_LOCALE = 'en-GB';
358
-
359
347
  /**
360
- * Array of languages that are written from the right to the left
361
- *
362
- * @type {string[]}
348
+ * Languages written right-to-left.
363
349
  */
364
350
  const RTL_LANGUAGES = ['ar', 'he'];
365
-
366
351
  /**
367
352
  * @deprecated The source of truth for supported languages lives in Crab.
368
- * @type {string[]}
369
353
  */
370
354
  const SUPPORTED_LANGUAGES = [DEFAULT_LANG, 'de', 'es', 'fr', 'hu', 'id', 'it', 'ja', 'pl', 'pt', 'ro', 'ru', 'th', 'tr', 'uk', 'zh'];
371
-
372
355
  /**
373
- * Verifies and adjusts locale (replace `_` with `-`)
374
- * Returns null if locale is unrecognized by {Intl.Locale}
356
+ * Verifies and adjusts locale, replacing `_` with `-`.
375
357
  *
376
- * @param {string} locale (`es`, `es_ES`, `en-GB`, `en`, `ja`, `ja-JP` etc)
377
- * @returns {string|null}
358
+ * @param locale `es`, `es_ES`, `en-GB`, `en`, `ja`, `ja-JP`, etc.
359
+ * @returns `null` if locale is unrecognized by `Intl.Locale`.
378
360
  */
379
361
  function adjustLocale(locale) {
380
- if (!locale || locale.trim().length === 0) {
381
- return null;
382
- }
383
- try {
384
- const {
385
- baseName
386
- } = new Intl.Locale(locale.trim().replace('_', '-'));
387
- return baseName;
388
- } catch (error) {
389
- // eslint-disable-next-line no-console
390
- console.error(error);
391
- return null;
362
+ const localeTrimmed = locale?.trim();
363
+ if (localeTrimmed) {
364
+ try {
365
+ return new Intl.Locale(localeTrimmed.replace('_', '-')).baseName;
366
+ } catch (error) {
367
+ // eslint-disable-next-line no-console
368
+ console.error(error);
369
+ }
392
370
  }
371
+ return null;
393
372
  }
394
-
395
373
  /**
396
- * Provides corresponding lang (iso2) for provided locale
397
- * if locale is invalid or language is unsupported returns null
374
+ * Provides corresponding lang (iso2) for provided locale.
398
375
  *
399
376
  * @deprecated The use of this function almost always breaks language variants
400
377
  * e.g. Simplified and Traditional Chinese.
401
378
  * There should be no use case for this function.
402
379
  * To select the correct translations from a translations object, pass the
403
380
  * locale directly into Crab's getLocalisedMessages.
404
- * @param {string} locale (`es`, `es-ES`, `en-GB`, `en`, `ja`, `ja-JP` etc)
405
- * @returns {string|null} two-letter ISO639-1 language
381
+ * @param locale `es`, `es-ES`, `en-GB`, `en`, `ja`, `ja-JP`, etc.
382
+ * @returns Two-letter ISO 639-1 language code, falling back to `null` if locale is invalid or language is unsupported.
406
383
  */
407
384
  function getLangFromLocale(locale) {
408
385
  const adjustedLocale = adjustLocale(locale);
409
- if (adjustedLocale === null) {
410
- return null;
411
- }
412
- try {
386
+ if (adjustedLocale != null) {
413
387
  const {
414
388
  language
415
389
  } = new Intl.Locale(adjustedLocale);
416
390
  if (SUPPORTED_LANGUAGES.includes(language)) {
417
391
  return language;
418
392
  }
419
- return null;
420
- } catch (error) {
421
- // eslint-disable-next-line no-console
422
- console.error(error);
423
- return null;
424
393
  }
394
+ return null;
425
395
  }
426
-
427
396
  /**
428
- * Provides corresponding country code (iso2) for locales code with explicit region value (`es-ES`, `en-GB`, `ja-JP` etc.)
429
- * if the value is invalid or missing region it returns null
397
+ * Provides corresponding country code (iso2) for locales code with explicit region value.
430
398
  *
431
- * @param {string} locale
432
- * @returns {string|null}
399
+ * @param locale `es-ES`, `en-GB`, `ja-JP`, etc.
400
+ * @returns `null` if the locale is invalid or the region can‘t be identified.
433
401
  */
434
402
  function getCountryFromLocale(locale) {
435
403
  const adjustedLocale = adjustLocale(locale);
436
- if (adjustedLocale === null) {
437
- return null;
438
- }
439
- try {
440
- const {
441
- region
442
- } = new Intl.Locale(adjustedLocale);
443
- return region ?? null;
444
- } catch (error) {
445
- // eslint-disable-next-line no-console
446
- console.error(error);
447
- return null;
448
- }
404
+ return adjustedLocale != null ? new Intl.Locale(adjustedLocale).region ?? null : null;
449
405
  }
450
-
451
406
  /**
452
407
  * Provides the layout direction for a given locale.
453
- * If locale is invalid or language is unsupported returns Direction.LTR
454
408
  *
455
- * @param {string} locale (`es`, `es-ES`, `en-GB`, `en`, `ja`, `ja-JP` etc)
456
- * @returns {Direction} The layout direction based on the locale
409
+ * @param locale `es`, `es-ES`, `en-GB`, `en`, `ja`, `ja-JP`, etc.
410
+ * @returns The layout direction based on the locale, falling back to `Direction.LTR` if the locale is invalid or unsupported.
457
411
  */
458
412
  function getDirectionFromLocale(locale) {
459
- try {
460
- const adjustedLocale = adjustLocale(locale);
461
- const {
462
- language
463
- } = new Intl.Locale(adjustedLocale);
464
- return RTL_LANGUAGES.includes(language) ? Direction.RTL : Direction.LTR;
465
- } catch (error) {
466
- // eslint-disable-next-line no-console
467
- console.error(error);
468
- return Direction.LTR;
469
- }
413
+ const adjustedLocale = adjustLocale(locale);
414
+ return adjustedLocale != null && RTL_LANGUAGES.includes(new Intl.Locale(adjustedLocale).language) ? Direction.RTL : Direction.LTR;
470
415
  }
471
416
 
472
417
  /**
@@ -9567,111 +9512,79 @@ const countries = [{
9567
9512
  iso3: 'ZWE',
9568
9513
  phone: '+263'
9569
9514
  }];
9570
- var countries$1 = countries;
9571
9515
 
9572
9516
  const longestMatchingPrefix = matchingCodes => matchingCodes.reduce((a, b) => a.phone.length > b.phone.length ? a : b);
9573
9517
 
9574
9518
  const findCountryByCode = code => {
9575
- let matchingCodes;
9576
- if (code && code.length === 2) {
9577
- matchingCodes = countries$1.filter(country => code.toUpperCase() === country.iso2);
9519
+ if (code.length === 2) {
9520
+ const matchingCodes = countries.filter(country => code.toUpperCase() === country.iso2);
9521
+ if (matchingCodes.length > 0) {
9522
+ return longestMatchingPrefix(matchingCodes);
9523
+ }
9578
9524
  }
9579
- return matchingCodes && matchingCodes.length > 0 ? longestMatchingPrefix(matchingCodes) : null;
9525
+ return null;
9580
9526
  };
9581
9527
 
9582
9528
  /**
9583
9529
  * Default phone code, the UK one `+44`
9584
9530
  */
9585
9531
  const DEFAULT_PHONE_CODE = '+44';
9586
-
9587
9532
  /**
9588
9533
  * Given a valid locale it returns the correspondent prefix if found or +44 otherwise.
9589
9534
  *
9590
- * @param {string} locale - a string that represent the locale ex:'es-ES'
9591
- * @param countryCode
9592
- * @returns {string}
9535
+ * @param locale BCP 47 language tag of locale, e.g. `"es-ES"`.
9536
+ * @param countryCode Two-letter country code (ISO 3166-1 alpha-2).
9593
9537
  */
9594
9538
  const setDefaultPrefix = (locale, countryCode) => {
9595
- const country = findCountryByCode(countryCode) ||
9596
- // when `locale` code has explicit region: `en-GB`, `en-US`, `ar-AE`
9597
- findCountryByCode(getCountryFromLocale(locale)) ||
9598
- // when `locale` code is only two chars value: `fr`, `es`
9599
- findCountryByCode(locale);
9600
- return country?.phone || DEFAULT_PHONE_CODE;
9539
+ const country = (countryCode != null ? findCountryByCode(countryCode) : null) ?? findCountryByCode(getCountryFromLocale(locale) ?? locale);
9540
+ return country?.phone ?? DEFAULT_PHONE_CODE;
9601
9541
  };
9602
9542
 
9603
9543
  /**
9604
9544
  *
9605
9545
  * @param phoneNumber
9606
- * @returns {boolean} - returns true for number that starts with '+' and contains a mix of digits and spaces with
9607
- * at least 4 digits.
9546
+ * @returns True if number that starts with "+" and contains a mix of digits and spaces with at least 4 digits.
9608
9547
  */
9609
- const isValidPhoneNumber = phoneNumber => /^\+[\d-\s]+$/.test(phoneNumber) && phoneNumber.match(/\d+/g) && phoneNumber.match(/\d+/g).join('').length >= 4;
9548
+ const isValidPhoneNumber = phoneNumber => /^\+[\d-\s]+$/.test(phoneNumber) && (phoneNumber.match(/\d+/g)?.join('').length ?? 0) >= 4;
9610
9549
 
9611
9550
  const findCountryByPrefix = number => {
9612
- let matchingCodes = null;
9613
- if (number && number.length > 1) {
9614
- matchingCodes = countries$1.filter(country => number.indexOf(country.phone) === 0);
9551
+ if (number.length > 1) {
9552
+ const matchingCodes = countries.filter(country => number.startsWith(country.phone));
9553
+ if (matchingCodes.length > 0) {
9554
+ return longestMatchingPrefix(matchingCodes);
9555
+ }
9615
9556
  }
9616
- return matchingCodes && matchingCodes.length > 0 ? longestMatchingPrefix(matchingCodes) : null;
9557
+ return null;
9617
9558
  };
9618
9559
 
9619
9560
  /**
9620
- * Given a sting in a valid format ex:'+447573135343' it returns an object of shape
9621
- * {prefix=+44 ,suffix=7573135343}
9622
- *
9623
- * @param {string} number - a string that defines a phone number.
9624
- * @returns {{prefix: (string|*), suffix: string, format: string}}
9561
+ * @param number Phone number in a format like "+447573135343"
9625
9562
  */
9626
9563
  const explodeNumberModel = number => {
9627
- let prefix = '';
9628
- let suffix = '';
9629
- let format = '';
9630
9564
  const country = findCountryByPrefix(number);
9631
- if (country) {
9632
- prefix = country.phone;
9633
- suffix = number.slice(country.phone.length);
9634
- format = country.phoneFormat || '';
9635
- } else {
9636
- prefix = '';
9637
- suffix = number.slice(1);
9638
- format = '';
9639
- }
9640
- return {
9641
- prefix,
9642
- suffix,
9643
- format
9565
+ return country ? {
9566
+ prefix: country.phone,
9567
+ suffix: number.slice(country.phone.length),
9568
+ format: country.phoneFormat
9569
+ } : {
9570
+ prefix: null,
9571
+ suffix: number.slice(1)
9644
9572
  };
9645
9573
  };
9646
9574
 
9647
9575
  const DIGITS_MATCH = /^$|^(\+)|([\d]+)/g;
9648
- const cleanNumber = number => number.match(DIGITS_MATCH) && number.match(DIGITS_MATCH).join('') || '';
9576
+ const cleanNumber = number => number.match(DIGITS_MATCH)?.join('') ?? '';
9649
9577
 
9650
- // Reference fro localeCompare : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare
9651
- const sortArrayByProperty = (arrayToSort, property) => [...arrayToSort].sort((a, b) => a[property].localeCompare(b[property]));
9578
+ function sortArrayByProperty(arrayToSort, property) {
9579
+ return [...arrayToSort].sort((a, b) => a[property].localeCompare(b[property]));
9580
+ }
9652
9581
 
9653
9582
  const groupCountriesByPrefix = countries => {
9654
- const groupedArray = countries.reduce((accumulator, country) => {
9655
- const {
9656
- name,
9657
- iso2,
9658
- iso3,
9659
- phone
9660
- } = country;
9661
- if (accumulator[phone]) {
9662
- const previousValue = accumulator[phone];
9663
- accumulator[phone] = {
9664
- ...previousValue,
9665
- name: isArray(previousValue.name) ? [...previousValue.name, name] : [previousValue.name, name],
9666
- iso2: isArray(previousValue.iso2) ? [...previousValue.iso2, iso2] : [previousValue.iso2, iso2],
9667
- iso3: isArray(previousValue.iso3) ? [...previousValue.iso3, iso3] : [previousValue.iso3, iso3]
9668
- };
9669
- } else {
9670
- accumulator[phone] = country;
9671
- }
9672
- return accumulator;
9673
- }, {});
9674
- return Object.values(groupedArray);
9583
+ const countriesByPrefix = new Map();
9584
+ countries.forEach(country => {
9585
+ countriesByPrefix.set(country.phone, [...(countriesByPrefix.get(country.phone) ?? []), country]);
9586
+ });
9587
+ return countriesByPrefix;
9675
9588
  };
9676
9589
 
9677
9590
  // Reference fro localeCompare : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare
@@ -9679,41 +9592,38 @@ const filterCountriesByIso3 = (countries, iso3Codes) => {
9679
9592
  const iso3CodesSet = new Set(iso3Codes);
9680
9593
  return countries.filter(country => !iso3CodesSet.has(country.iso3));
9681
9594
  };
9682
-
9683
9595
  /**
9684
9596
  * Removes the countries sepecified in the second param
9685
9597
  *
9686
- * @param {Array} countries: list of country metadata objects
9687
- * @param {Array} disabledCountries: list of iso3 country codes to remove from the list
9688
- * @returns
9598
+ * @param countries list of country metadata objects
9599
+ * @param disabledCountries list of iso3 country codes to remove from the list
9689
9600
  */
9690
9601
  const excludeCountries = (countries, disabledCountries) => {
9691
9602
  return disabledCountries.length > 0 ? filterCountriesByIso3(countries, disabledCountries) : countries;
9692
9603
  };
9693
9604
 
9694
9605
  const ALLOWED_PHONE_CHARS = /^$|^[\d-\s]+$/;
9695
- const PhoneNumberInput = props => {
9696
- const {
9697
- id,
9698
- onChange,
9699
- searchPlaceholder,
9700
- disabled,
9701
- required,
9702
- size,
9703
- placeholder,
9704
- onFocus,
9705
- onBlur,
9706
- countryCode,
9707
- selectProps,
9708
- disabledCountries
9709
- } = props;
9606
+ const defaultSelectProps = {};
9607
+ const defaultDisabledCountries = [];
9608
+ const PhoneNumberInput = ({
9609
+ id,
9610
+ required,
9611
+ disabled,
9612
+ initialValue,
9613
+ onChange,
9614
+ onFocus,
9615
+ onBlur,
9616
+ countryCode,
9617
+ searchPlaceholder = 'Prefix',
9618
+ size = Size.MEDIUM,
9619
+ placeholder,
9620
+ selectProps = defaultSelectProps,
9621
+ disabledCountries = defaultDisabledCountries
9622
+ }) => {
9710
9623
  const {
9711
9624
  locale
9712
9625
  } = useIntl();
9713
- const getInitialValue = () => {
9714
- const {
9715
- initialValue
9716
- } = props;
9626
+ const [internalValue, setInternalValue] = useState(() => {
9717
9627
  const cleanValue = initialValue ? cleanNumber(initialValue) : null;
9718
9628
  if (!cleanValue || !isValidPhoneNumber(cleanValue)) {
9719
9629
  return {
@@ -9722,54 +9632,16 @@ const PhoneNumberInput = props => {
9722
9632
  };
9723
9633
  }
9724
9634
  return explodeNumberModel(cleanValue);
9725
- };
9726
- const [internalValue, setInternalValue] = useState(getInitialValue());
9635
+ });
9727
9636
  const [broadcastedValue, setBroadcastedValue] = useState(null);
9728
- const getSelectOptions = () => {
9729
- const countriesList = excludeCountries(countries$1, disabledCountries);
9730
- const listSortedByISO3 = groupCountriesByPrefix(sortArrayByProperty(countriesList, 'iso3'));
9731
- return listSortedByISO3.map(option => {
9732
- const {
9733
- phone,
9734
- iso3,
9735
- iso2,
9736
- name
9737
- } = option;
9738
- let note = '';
9739
- if (iso3) {
9740
- note = isArray(iso3) ? iso3.join(', ') : iso3;
9741
- } else if (iso2) {
9742
- note = isArray(iso2) ? iso2.join(', ') : iso2;
9743
- }
9744
- return {
9745
- type: 'option',
9746
- value: {
9747
- value: phone,
9748
- label: phone,
9749
- note: note
9750
- },
9751
- filterMatchers: [phone, note, name]
9752
- };
9753
- });
9754
- };
9755
- const options = getSelectOptions();
9756
- const onPrefixChange = ({
9757
- value
9758
- }) => {
9759
- setInternalValue({
9760
- prefix: value,
9761
- suffix: internalValue.suffix
9762
- });
9763
- };
9637
+ const countriesByPrefix = useMemo(() => groupCountriesByPrefix(sortArrayByProperty(excludeCountries(countries, disabledCountries), 'iso3')), [disabledCountries]);
9764
9638
  const onSuffixChange = event => {
9765
- const {
9766
- value = ''
9767
- } = event.target;
9768
- if (ALLOWED_PHONE_CHARS.test(value)) {
9769
- setInternalValue({
9770
- prefix: internalValue.prefix,
9771
- suffix: value
9772
- });
9639
+ const suffix = event.target.value;
9640
+ if (ALLOWED_PHONE_CHARS.test(suffix)) {
9641
+ setInternalValue(prev => ({
9642
+ ...prev,
9643
+ suffix
9644
+ }));
9773
9645
  }
9774
9646
  };
9775
9647
  const onPaste = event => {
@@ -9777,31 +9649,22 @@ const PhoneNumberInput = props => {
9777
9649
  return;
9778
9650
  }
9779
9651
  const pastedValue = (event.nativeEvent.clipboardData.getData('text/plain') || '').replace(/(\s|-)+/g, '');
9780
- const {
9781
- prefix: pastedPrefix,
9782
- suffix: pastedSuffix
9783
- } = explodeNumberModel(pastedValue);
9784
- const selectedPrefix = options.find(({
9785
- value
9786
- }) => value.value === pastedPrefix);
9787
- if (selectedPrefix && ALLOWED_PHONE_CHARS.test(pastedSuffix)) {
9788
- setInternalValue({
9789
- prefix: pastedPrefix,
9790
- suffix: pastedSuffix
9791
- });
9652
+ const pastedNumber = explodeNumberModel(pastedValue);
9653
+ if (pastedNumber.prefix != null && countriesByPrefix.has(pastedNumber.prefix) && ALLOWED_PHONE_CHARS.test(pastedNumber.suffix)) {
9654
+ setInternalValue(pastedNumber);
9792
9655
  }
9793
9656
  };
9794
9657
  useEffect(() => {
9795
9658
  if (broadcastedValue === null) {
9796
9659
  return setBroadcastedValue(internalValue);
9797
9660
  }
9798
- const internalPhoneNumber = internalValue.prefix + internalValue.suffix;
9799
- const broadcastedPhoneNumber = broadcastedValue.prefix + broadcastedValue.suffix;
9661
+ const internalPhoneNumber = `${internalValue.prefix ?? ''}${internalValue.suffix}`;
9662
+ const broadcastedPhoneNumber = `${broadcastedValue.prefix ?? ''}${broadcastedValue.suffix}`;
9800
9663
  if (internalPhoneNumber === broadcastedPhoneNumber) {
9801
9664
  return;
9802
9665
  }
9803
9666
  const newValue = isValidPhoneNumber(internalPhoneNumber) ? cleanNumber(internalPhoneNumber) : null;
9804
- onChange(newValue, internalValue.prefix);
9667
+ onChange(newValue, internalValue.prefix ?? '');
9805
9668
  setBroadcastedValue(internalValue);
9806
9669
  }, [onChange, broadcastedValue, internalValue]);
9807
9670
  return /*#__PURE__*/jsxs("div", {
@@ -9809,18 +9672,29 @@ const PhoneNumberInput = props => {
9809
9672
  children: [/*#__PURE__*/jsx("div", {
9810
9673
  className: "tw-telephone__country-select",
9811
9674
  children: /*#__PURE__*/jsx(SelectInput, {
9812
- placeholder: "Select an option...",
9813
- items: options,
9814
- value: options.find(item => item.value.value === internalValue.prefix)?.value,
9815
- renderValue: (option, withinTrigger) => /*#__PURE__*/jsx(SelectInputOptionContent, {
9816
- title: option.label,
9817
- note: withinTrigger ? undefined : option.note
9675
+ placeholder: "Select an option\u2026",
9676
+ items: [...countriesByPrefix].map(([prefix, countries]) => ({
9677
+ type: 'option',
9678
+ value: prefix,
9679
+ filterMatchers: [prefix, ...countries.map(country => country.name), ...countries.map(country => country.iso3)]
9680
+ })),
9681
+ value: internalValue.prefix,
9682
+ renderValue: (prefix, withinTrigger) => /*#__PURE__*/jsx(SelectInputOptionContent, {
9683
+ title: prefix,
9684
+ note: withinTrigger ? undefined : countriesByPrefix.get(prefix)?.map(country => country.iso3).join(', ')
9818
9685
  }),
9819
9686
  filterable: true,
9820
9687
  filterPlaceholder: searchPlaceholder,
9821
9688
  disabled: disabled,
9822
9689
  size: size,
9823
- onChange: onPrefixChange,
9690
+ onChange: prefix => {
9691
+ const country = prefix != null ? findCountryByPrefix(prefix) : null;
9692
+ setInternalValue(prev => ({
9693
+ ...prev,
9694
+ prefix,
9695
+ format: country?.phoneFormat
9696
+ }));
9697
+ },
9824
9698
  ...selectProps
9825
9699
  })
9826
9700
  }), /*#__PURE__*/jsx("div", {
@@ -9846,37 +9720,6 @@ const PhoneNumberInput = props => {
9846
9720
  })]
9847
9721
  });
9848
9722
  };
9849
- PhoneNumberInput.propTypes = {
9850
- id: PropTypes.string,
9851
- required: PropTypes.bool,
9852
- disabled: PropTypes.bool,
9853
- initialValue: PropTypes.string,
9854
- onChange: PropTypes.func.isRequired,
9855
- onFocus: PropTypes.func,
9856
- onBlur: PropTypes.func,
9857
- countryCode: PropTypes.string,
9858
- searchPlaceholder: PropTypes.string,
9859
- size: PropTypes.oneOf(['sm', 'md', 'lg']),
9860
- placeholder: PropTypes.string,
9861
- selectProps: PropTypes.object,
9862
- /** List of iso3 codes of countries to remove from the list */
9863
- disabledCountries: PropTypes.arrayOf(PropTypes.string)
9864
- };
9865
- PhoneNumberInput.defaultProps = {
9866
- id: null,
9867
- required: false,
9868
- disabled: false,
9869
- initialValue: null,
9870
- onFocus() {},
9871
- onBlur() {},
9872
- countryCode: null,
9873
- searchPlaceholder: 'Prefix',
9874
- size: Size.MEDIUM,
9875
- placeholder: '',
9876
- selectProps: {},
9877
- disabledCountries: []
9878
- };
9879
- var PhoneNumberInput$1 = PhoneNumberInput;
9880
9723
 
9881
9724
  const Progress = ({
9882
9725
  className,
@@ -15597,5 +15440,5 @@ const translations = {
15597
15440
  'zh-HK': zhHK
15598
15441
  };
15599
15442
 
15600
- export { Accordion, ActionButton, ActionOption, Alert$1 as Alert, ArrowPosition as AlertArrowPosition, Avatar, AvatarType, AvatarWrapper, Badge, Card as BaseCard, Body, BottomSheet$2 as BottomSheet, Breakpoint, Button, Card$2 as Card, Checkbox$1 as Checkbox, CheckboxButton$1 as CheckboxButton, CheckboxOption, Chevron, Chip, Chips, CircularButton$1 as CircularButton, ControlType, CriticalCommsBanner, DEFAULT_LANG, DEFAULT_LOCALE, DateInput$1 as DateInput, DateLookup$1 as DateLookup, DateMode, Decision$1 as Decision, Presentation as DecisionPresentation, Type as DecisionType, DefinitionList$1 as DefinitionList, Dimmer$1 as Dimmer, Direction, DirectionProvider, Display, Drawer$1 as Drawer, DropFade, DynamicFieldDefinitionList$1 as DynamicFieldDefinitionList, Emphasis, FileType, FlowNavigation, Header, Image, Info, InfoPresentation, InlineAlert, Input, InputGroup, InputWithDisplayFormat, InstructionsList$1 as InstructionsList, LanguageProvider, Layout$1 as Layout, Link, ListItem$1 as ListItem, Loader$1 as Loader, Logo$1 as Logo, LogoType, Markdown$1 as Markdown, MarkdownNodeType, Modal, Money$1 as Money, MoneyInput$1 as MoneyInput, MonthFormat, NavigationOption, NavigationOptionList$1 as NavigationOptionsList, Nudge, Option$2 as Option, OverlayHeader$1 as OverlayHeader, PhoneNumberInput$1 as PhoneNumberInput, Popover$2 as Popover, Position, Priority, ProcessIndicator$1 as ProcessIndicator, ProfileType, Progress, ProgressBar, PromoCard$1 as PromoCard, PromoCard$1 as PromoCardGroup, Provider$1 as Provider, RTL_LANGUAGES, Radio$1 as Radio, RadioGroup$1 as RadioGroup, RadioOption$1 as RadioOption, SUPPORTED_LANGUAGES, Scroll, SearchInput, Section, Select, SelectInput, SelectInputOptionContent, SelectInputTriggerButton, Sentiment, Size, SlidingPanel$1 as SlidingPanel, SnackbarConsumer, SnackbarContext, SnackbarPortal, SnackbarProvider$1 as SnackbarProvider, Status, StatusIcon, Stepper, Sticky$1 as Sticky, Summary, Switch, SwitchOption, Tabs$1 as Tabs, TextArea, TextareaWithDisplayFormat, Theme, Title, Tooltip$1 as Tooltip, Type$1 as Type, Typeahead, Typography, Upload$1 as Upload, UploadInput, UploadStep, Variant, Width, adjustLocale, getCountryFromLocale, getDirectionFromLocale, getLangFromLocale, isBrowser, isServerSide, translations, useDirection, useLayout, useScreenSize, useSnackbar };
15443
+ export { Accordion, ActionButton, ActionOption, Alert$1 as Alert, ArrowPosition as AlertArrowPosition, Avatar, AvatarType, AvatarWrapper, Badge, Card as BaseCard, Body, BottomSheet$2 as BottomSheet, Breakpoint, Button, Card$2 as Card, Checkbox$1 as Checkbox, CheckboxButton$1 as CheckboxButton, CheckboxOption, Chevron, Chip, Chips, CircularButton$1 as CircularButton, ControlType, CriticalCommsBanner, DEFAULT_LANG, DEFAULT_LOCALE, DateInput$1 as DateInput, DateLookup$1 as DateLookup, DateMode, Decision$1 as Decision, Presentation as DecisionPresentation, Type as DecisionType, DefinitionList$1 as DefinitionList, Dimmer$1 as Dimmer, Direction, DirectionProvider, Display, Drawer$1 as Drawer, DropFade, DynamicFieldDefinitionList$1 as DynamicFieldDefinitionList, Emphasis, FileType, FlowNavigation, Header, Image, Info, InfoPresentation, InlineAlert, Input, InputGroup, InputWithDisplayFormat, InstructionsList$1 as InstructionsList, LanguageProvider, Layout$1 as Layout, Link, ListItem$1 as ListItem, Loader$1 as Loader, Logo$1 as Logo, LogoType, Markdown$1 as Markdown, MarkdownNodeType, Modal, Money$1 as Money, MoneyInput$1 as MoneyInput, MonthFormat, NavigationOption, NavigationOptionList$1 as NavigationOptionsList, Nudge, Option$2 as Option, OverlayHeader$1 as OverlayHeader, PhoneNumberInput, Popover$2 as Popover, Position, Priority, ProcessIndicator$1 as ProcessIndicator, ProfileType, Progress, ProgressBar, PromoCard$1 as PromoCard, PromoCard$1 as PromoCardGroup, Provider$1 as Provider, RTL_LANGUAGES, Radio$1 as Radio, RadioGroup$1 as RadioGroup, RadioOption$1 as RadioOption, SUPPORTED_LANGUAGES, Scroll, SearchInput, Section, Select, SelectInput, SelectInputOptionContent, SelectInputTriggerButton, Sentiment, Size, SlidingPanel$1 as SlidingPanel, SnackbarConsumer, SnackbarContext, SnackbarPortal, SnackbarProvider$1 as SnackbarProvider, Status, StatusIcon, Stepper, Sticky$1 as Sticky, Summary, Switch, SwitchOption, Tabs$1 as Tabs, TextArea, TextareaWithDisplayFormat, Theme, Title, Tooltip$1 as Tooltip, Type$1 as Type, Typeahead, Typography, Upload$1 as Upload, UploadInput, UploadStep, Variant, Width, adjustLocale, getCountryFromLocale, getDirectionFromLocale, getLangFromLocale, isBrowser, isServerSide, translations, useDirection, useLayout, useScreenSize, useSnackbar };
15601
15444
  //# sourceMappingURL=index.esm.js.map