@transferwise/components 46.6.0 → 46.8.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.
Files changed (148) hide show
  1. package/build/index.esm.js +290 -346
  2. package/build/index.esm.js.map +1 -1
  3. package/build/index.js +290 -345
  4. package/build/index.js.map +1 -1
  5. package/build/main.css +107 -17
  6. package/build/styles/inputs/Input.css +0 -4
  7. package/build/styles/inputs/SelectInput.css +6 -1
  8. package/build/styles/inputs/TextArea.css +0 -4
  9. package/build/styles/main.css +107 -17
  10. package/build/styles/segmentedControl/SegmentedControl.css +101 -0
  11. package/build/styles/select/Select.css +0 -4
  12. package/build/types/common/locale/index.d.ts +26 -43
  13. package/build/types/common/locale/index.d.ts.map +1 -1
  14. package/build/types/index.d.ts +3 -0
  15. package/build/types/index.d.ts.map +1 -1
  16. package/build/types/inputs/SelectInput.d.ts +6 -5
  17. package/build/types/inputs/SelectInput.d.ts.map +1 -1
  18. package/build/types/phoneNumberInput/PhoneNumberInput.d.ts +22 -27
  19. package/build/types/phoneNumberInput/PhoneNumberInput.d.ts.map +1 -1
  20. package/build/types/phoneNumberInput/data/countries.d.ts +5 -10
  21. package/build/types/phoneNumberInput/data/countries.d.ts.map +1 -1
  22. package/build/types/phoneNumberInput/index.d.ts +1 -1
  23. package/build/types/phoneNumberInput/index.d.ts.map +1 -1
  24. package/build/types/phoneNumberInput/utils/cleanNumber/cleanNumber.d.ts +1 -1
  25. package/build/types/phoneNumberInput/utils/cleanNumber/cleanNumber.d.ts.map +1 -1
  26. package/build/types/phoneNumberInput/utils/cleanNumber/index.d.ts +1 -1
  27. package/build/types/phoneNumberInput/utils/cleanNumber/index.d.ts.map +1 -1
  28. package/build/types/phoneNumberInput/utils/excludeCountries/excludeCountries.d.ts +8 -1
  29. package/build/types/phoneNumberInput/utils/excludeCountries/excludeCountries.d.ts.map +1 -1
  30. package/build/types/phoneNumberInput/utils/excludeCountries/index.d.ts +1 -1
  31. package/build/types/phoneNumberInput/utils/excludeCountries/index.d.ts.map +1 -1
  32. package/build/types/phoneNumberInput/utils/explodeNumberModel/index.d.ts +8 -4
  33. package/build/types/phoneNumberInput/utils/explodeNumberModel/index.d.ts.map +1 -1
  34. package/build/types/phoneNumberInput/utils/findCountryByCode/index.d.ts +1 -1
  35. package/build/types/phoneNumberInput/utils/findCountryByCode/index.d.ts.map +1 -1
  36. package/build/types/phoneNumberInput/utils/findCountryByPrefix/index.d.ts +1 -1
  37. package/build/types/phoneNumberInput/utils/findCountryByPrefix/index.d.ts.map +1 -1
  38. package/build/types/phoneNumberInput/utils/groupCountriesByPrefix/groupCountriesByPrefix.d.ts +2 -1
  39. package/build/types/phoneNumberInput/utils/groupCountriesByPrefix/groupCountriesByPrefix.d.ts.map +1 -1
  40. package/build/types/phoneNumberInput/utils/groupCountriesByPrefix/index.d.ts +1 -1
  41. package/build/types/phoneNumberInput/utils/groupCountriesByPrefix/index.d.ts.map +1 -1
  42. package/build/types/phoneNumberInput/utils/index.d.ts +11 -13
  43. package/build/types/phoneNumberInput/utils/index.d.ts.map +1 -1
  44. package/build/types/phoneNumberInput/utils/isStringNumeric/index.d.ts +1 -1
  45. package/build/types/phoneNumberInput/utils/isStringNumeric/index.d.ts.map +1 -1
  46. package/build/types/phoneNumberInput/utils/isStringNumeric/isStringNumeric.d.ts +1 -1
  47. package/build/types/phoneNumberInput/utils/isStringNumeric/isStringNumeric.d.ts.map +1 -1
  48. package/build/types/phoneNumberInput/utils/isValidPhoneNumber/index.d.ts +1 -1
  49. package/build/types/phoneNumberInput/utils/isValidPhoneNumber/index.d.ts.map +1 -1
  50. package/build/types/phoneNumberInput/utils/isValidPhoneNumber/isValidPhoneNumber.d.ts +6 -1
  51. package/build/types/phoneNumberInput/utils/isValidPhoneNumber/isValidPhoneNumber.d.ts.map +1 -1
  52. package/build/types/phoneNumberInput/utils/longestMatchingPrefix/index.d.ts +2 -1
  53. package/build/types/phoneNumberInput/utils/longestMatchingPrefix/index.d.ts.map +1 -1
  54. package/build/types/phoneNumberInput/utils/setDefaultPrefix/index.d.ts +7 -1
  55. package/build/types/phoneNumberInput/utils/setDefaultPrefix/index.d.ts.map +1 -1
  56. package/build/types/phoneNumberInput/utils/sortArrayByProperty/index.d.ts +1 -1
  57. package/build/types/phoneNumberInput/utils/sortArrayByProperty/index.d.ts.map +1 -1
  58. package/build/types/phoneNumberInput/utils/sortArrayByProperty/sortArrayByProperty.d.ts +1 -1
  59. package/build/types/phoneNumberInput/utils/sortArrayByProperty/sortArrayByProperty.d.ts.map +1 -1
  60. package/build/types/segmentedControl/SegmentedControl.d.ts +31 -0
  61. package/build/types/segmentedControl/SegmentedControl.d.ts.map +1 -0
  62. package/build/types/segmentedControl/index.d.ts +3 -0
  63. package/build/types/segmentedControl/index.d.ts.map +1 -0
  64. package/package.json +7 -17
  65. package/src/common/locale/{index.spec.js → index.spec.ts} +4 -4
  66. package/src/common/locale/index.ts +96 -0
  67. package/src/index.ts +3 -0
  68. package/src/inputs/Input.css +0 -4
  69. package/src/inputs/SelectInput.css +6 -1
  70. package/src/inputs/SelectInput.less +8 -1
  71. package/src/inputs/SelectInput.spec.tsx +26 -0
  72. package/src/inputs/SelectInput.story.tsx +73 -1
  73. package/src/inputs/SelectInput.tsx +104 -85
  74. package/src/inputs/TextArea.css +0 -4
  75. package/src/main.css +107 -17
  76. package/src/main.less +1 -0
  77. package/src/phoneNumberInput/PhoneNumberInput.spec.js +18 -22
  78. package/src/phoneNumberInput/PhoneNumberInput.tsx +193 -0
  79. package/src/phoneNumberInput/data/{countries.js → countries.ts} +9 -1
  80. package/src/phoneNumberInput/utils/cleanNumber/cleanNumber.ts +3 -0
  81. package/src/phoneNumberInput/utils/excludeCountries/{excludeCountries.spec.js → excludeCountries.spec.ts} +1 -1
  82. package/src/phoneNumberInput/utils/excludeCountries/{excludeCountries.js → excludeCountries.ts} +6 -5
  83. package/src/phoneNumberInput/utils/explodeNumberModel/{explodeNumberModel.spec.js → explodeNumberModel.spec.ts} +1 -1
  84. package/src/phoneNumberInput/utils/explodeNumberModel/index.ts +24 -0
  85. package/src/phoneNumberInput/utils/findCountryByCode/{findCountryByCode.spec.js → findCountryByCode.spec.ts} +0 -1
  86. package/src/phoneNumberInput/utils/findCountryByCode/index.ts +12 -0
  87. package/src/phoneNumberInput/utils/findCountryByPrefix/index.ts +12 -0
  88. package/src/phoneNumberInput/utils/groupCountriesByPrefix/groupCountriesByPrefix.spec.ts +102 -0
  89. package/src/phoneNumberInput/utils/groupCountriesByPrefix/groupCountriesByPrefix.ts +12 -0
  90. package/src/phoneNumberInput/utils/{index.js → index.ts} +0 -2
  91. package/src/phoneNumberInput/utils/isStringNumeric/{isStringNumeric.spec.js → isStringNumeric.spec.ts} +0 -1
  92. package/src/phoneNumberInput/utils/isStringNumeric/isStringNumeric.ts +1 -0
  93. package/src/phoneNumberInput/utils/isValidPhoneNumber/{isValidPhoneNumber.spec.js → isValidPhoneNumber.spec.ts} +1 -1
  94. package/src/phoneNumberInput/utils/isValidPhoneNumber/isValidPhoneNumber.ts +7 -0
  95. package/src/phoneNumberInput/utils/longestMatchingPrefix/index.ts +4 -0
  96. package/src/phoneNumberInput/utils/setDefaultPrefix/index.ts +20 -0
  97. package/src/phoneNumberInput/utils/sortArrayByProperty/sortArrayByProperty.ts +6 -0
  98. package/src/segmentedControl/SegmentedControl.css +101 -0
  99. package/src/segmentedControl/SegmentedControl.less +101 -0
  100. package/src/segmentedControl/SegmentedControl.spec.tsx +106 -0
  101. package/src/segmentedControl/SegmentedControl.story.tsx +55 -0
  102. package/src/segmentedControl/SegmentedControl.tsx +175 -0
  103. package/src/segmentedControl/index.ts +2 -0
  104. package/src/select/Select.css +0 -4
  105. package/src/ssr.spec.js +17 -0
  106. package/src/withDisplayFormat/WithDisplayFormat.spec.js +1 -1
  107. package/src/withDisplayFormat/WithDisplayFormat.tsx +1 -1
  108. package/build/types/phoneNumberInput/utils/filterOptionsForQuery/index.d.ts +0 -2
  109. package/build/types/phoneNumberInput/utils/filterOptionsForQuery/index.d.ts.map +0 -1
  110. package/build/types/phoneNumberInput/utils/isOptionAndFitsQuery/index.d.ts +0 -2
  111. package/build/types/phoneNumberInput/utils/isOptionAndFitsQuery/index.d.ts.map +0 -1
  112. package/build/types/phoneNumberInput/utils/isOptionAndFitsQuery/isOptionAndFitsQuery.d.ts +0 -3
  113. package/build/types/phoneNumberInput/utils/isOptionAndFitsQuery/isOptionAndFitsQuery.d.ts.map +0 -1
  114. package/build/types/utilities/wrapInFragment.d.ts +0 -3
  115. package/build/types/utilities/wrapInFragment.d.ts.map +0 -1
  116. package/src/common/locale/index.js +0 -139
  117. package/src/phoneNumberInput/PhoneNumberInput.js +0 -210
  118. package/src/phoneNumberInput/data/countries.spec.js +0 -12
  119. package/src/phoneNumberInput/utils/cleanNumber/cleanNumber.js +0 -4
  120. package/src/phoneNumberInput/utils/explodeNumberModel/index.js +0 -27
  121. package/src/phoneNumberInput/utils/filterOptionsForQuery/filterOptionsForQuery.spec.js +0 -36
  122. package/src/phoneNumberInput/utils/filterOptionsForQuery/index.js +0 -11
  123. package/src/phoneNumberInput/utils/findCountryByCode/index.js +0 -10
  124. package/src/phoneNumberInput/utils/findCountryByPrefix/index.js +0 -11
  125. package/src/phoneNumberInput/utils/groupCountriesByPrefix/groupCountriesByPrefix.js +0 -26
  126. package/src/phoneNumberInput/utils/groupCountriesByPrefix/groupCountriesByPrefix.spec.js +0 -67
  127. package/src/phoneNumberInput/utils/isOptionAndFitsQuery/index.js +0 -1
  128. package/src/phoneNumberInput/utils/isOptionAndFitsQuery/isOptionAndFitsQuery.js +0 -25
  129. package/src/phoneNumberInput/utils/isOptionAndFitsQuery/isOptionAndFitsQuery.spec.js +0 -66
  130. package/src/phoneNumberInput/utils/isStringNumeric/isStringNumeric.js +0 -1
  131. package/src/phoneNumberInput/utils/isValidPhoneNumber/isValidPhoneNumber.js +0 -10
  132. package/src/phoneNumberInput/utils/longestMatchingPrefix/index.js +0 -2
  133. package/src/phoneNumberInput/utils/setDefaultPrefix/index.js +0 -25
  134. package/src/phoneNumberInput/utils/sortArrayByProperty/sortArrayByProperty.js +0 -3
  135. package/src/utilities/wrapInFragment.tsx +0 -3
  136. /package/src/phoneNumberInput/{PhoneNumberInput.story.js → PhoneNumberInput.story.tsx} +0 -0
  137. /package/src/phoneNumberInput/{index.js → index.ts} +0 -0
  138. /package/src/phoneNumberInput/utils/cleanNumber/{cleanNumber.spec.js → cleanNumber.spec.ts} +0 -0
  139. /package/src/phoneNumberInput/utils/cleanNumber/{index.js → index.ts} +0 -0
  140. /package/src/phoneNumberInput/utils/excludeCountries/{index.js → index.ts} +0 -0
  141. /package/src/phoneNumberInput/utils/findCountryByPrefix/{findCountryByPrefix.spec.js → findCountryByPrefix.spec.ts} +0 -0
  142. /package/src/phoneNumberInput/utils/groupCountriesByPrefix/{index.js → index.ts} +0 -0
  143. /package/src/phoneNumberInput/utils/isStringNumeric/{index.js → index.ts} +0 -0
  144. /package/src/phoneNumberInput/utils/isValidPhoneNumber/{index.js → index.ts} +0 -0
  145. /package/src/phoneNumberInput/utils/longestMatchingPrefix/{longestMatchingPrefix.spec.js → longestMatchingPrefix.spec.ts} +0 -0
  146. /package/src/phoneNumberInput/utils/setDefaultPrefix/{setDefaultPrefix.spec.js → setDefaultPrefix.spec.ts} +0 -0
  147. /package/src/phoneNumberInput/utils/sortArrayByProperty/{index.js → index.ts} +0 -0
  148. /package/src/phoneNumberInput/utils/sortArrayByProperty/{sortArrayByProperty.spec.js → sortArrayByProperty.spec.ts} +0 -0
@@ -1,139 +0,0 @@
1
- import { Direction } from '..';
2
-
3
- /**
4
- * Default language
5
- *
6
- * @type {string}
7
- */
8
- export const DEFAULT_LANG = 'en';
9
-
10
- /**
11
- * Default locale
12
- *
13
- * @type {string}
14
- */
15
- export const DEFAULT_LOCALE = 'en-GB';
16
-
17
- /**
18
- * Array of languages that are written from the right to the left
19
- *
20
- * @type {string[]}
21
- */
22
- export const RTL_LANGUAGES = ['ar', 'he'];
23
-
24
- /**
25
- * @deprecated The source of truth for supported languages lives in Crab.
26
- * @type {string[]}
27
- */
28
- export const SUPPORTED_LANGUAGES = [
29
- DEFAULT_LANG,
30
- 'de',
31
- 'es',
32
- 'fr',
33
- 'hu',
34
- 'id',
35
- 'it',
36
- 'ja',
37
- 'pl',
38
- 'pt',
39
- 'ro',
40
- 'ru',
41
- 'th',
42
- 'tr',
43
- 'uk',
44
- 'zh',
45
- ];
46
-
47
- /**
48
- * Verifies and adjusts locale (replace `_` with `-`)
49
- * Returns null if locale is unrecognized by {Intl.Locale}
50
- *
51
- * @param {string} locale (`es`, `es_ES`, `en-GB`, `en`, `ja`, `ja-JP` etc)
52
- * @returns {string|null}
53
- */
54
- export function adjustLocale(locale) {
55
- if (!locale || locale.trim().length === 0) {
56
- return null;
57
- }
58
- try {
59
- const { baseName } = new Intl.Locale(locale.trim().replace('_', '-'));
60
- return baseName;
61
- } catch (error) {
62
- // eslint-disable-next-line no-console
63
- console.error(error);
64
- return null;
65
- }
66
- }
67
-
68
- /**
69
- * Provides corresponding lang (iso2) for provided locale
70
- * if locale is invalid or language is unsupported returns null
71
- *
72
- * @deprecated The use of this function almost always breaks language variants
73
- * e.g. Simplified and Traditional Chinese.
74
- * There should be no use case for this function.
75
- * To select the correct translations from a translations object, pass the
76
- * locale directly into Crab's getLocalisedMessages.
77
- * @param {string} locale (`es`, `es-ES`, `en-GB`, `en`, `ja`, `ja-JP` etc)
78
- * @returns {string|null} two-letter ISO639-1 language
79
- */
80
- export function getLangFromLocale(locale) {
81
- const adjustedLocale = adjustLocale(locale);
82
- if (adjustedLocale === null) {
83
- return null;
84
- }
85
- try {
86
- const { language } = new Intl.Locale(adjustedLocale);
87
-
88
- if (SUPPORTED_LANGUAGES.includes(language)) {
89
- return language;
90
- }
91
- return null;
92
- } catch (error) {
93
- // eslint-disable-next-line no-console
94
- console.error(error);
95
- return null;
96
- }
97
- }
98
-
99
- /**
100
- * Provides corresponding country code (iso2) for locales code with explicit region value (`es-ES`, `en-GB`, `ja-JP` etc.)
101
- * if the value is invalid or missing region it returns null
102
- *
103
- * @param {string} locale
104
- * @returns {string|null}
105
- */
106
- export function getCountryFromLocale(locale) {
107
- const adjustedLocale = adjustLocale(locale);
108
- if (adjustedLocale === null) {
109
- return null;
110
- }
111
- try {
112
- const { region } = new Intl.Locale(adjustedLocale);
113
- return region ?? null;
114
- } catch (error) {
115
- // eslint-disable-next-line no-console
116
- console.error(error);
117
- return null;
118
- }
119
- }
120
-
121
- /**
122
- * Provides the layout direction for a given locale.
123
- * If locale is invalid or language is unsupported returns Direction.LTR
124
- *
125
- * @param {string} locale (`es`, `es-ES`, `en-GB`, `en`, `ja`, `ja-JP` etc)
126
- * @returns {Direction} The layout direction based on the locale
127
- */
128
- export function getDirectionFromLocale(locale) {
129
- try {
130
- const adjustedLocale = adjustLocale(locale);
131
- const { language } = new Intl.Locale(adjustedLocale);
132
-
133
- return RTL_LANGUAGES.includes(language) ? Direction.RTL : Direction.LTR;
134
- } catch (error) {
135
- // eslint-disable-next-line no-console
136
- console.error(error);
137
- return Direction.LTR;
138
- }
139
- }
@@ -1,210 +0,0 @@
1
- import { isArray } from '@transferwise/neptune-validation';
2
- import PropTypes from 'prop-types';
3
- import { useState, useEffect } from 'react';
4
- import { useIntl } from 'react-intl';
5
-
6
- import { Size } from '../common';
7
- import { SelectInput, SelectInputOptionContent } from '../inputs/SelectInput';
8
-
9
- import countries from './data/countries';
10
- import {
11
- explodeNumberModel,
12
- isValidPhoneNumber,
13
- cleanNumber,
14
- setDefaultPrefix,
15
- sortArrayByProperty,
16
- groupCountriesByPrefix,
17
- excludeCountries,
18
- } from './utils';
19
-
20
- const ALLOWED_PHONE_CHARS = /^$|^[\d-\s]+$/;
21
-
22
- const PhoneNumberInput = (props) => {
23
- const {
24
- id,
25
- onChange,
26
- searchPlaceholder,
27
- disabled,
28
- required,
29
- size,
30
- placeholder,
31
- onFocus,
32
- onBlur,
33
- countryCode,
34
- selectProps,
35
- disabledCountries,
36
- } = props;
37
- const { locale } = useIntl();
38
-
39
- const getInitialValue = () => {
40
- const { initialValue } = props;
41
-
42
- const cleanValue = initialValue ? cleanNumber(initialValue) : null;
43
-
44
- if (!cleanValue || !isValidPhoneNumber(cleanValue)) {
45
- return {
46
- prefix: setDefaultPrefix(locale, countryCode),
47
- suffix: '',
48
- };
49
- }
50
-
51
- return explodeNumberModel(cleanValue);
52
- };
53
-
54
- const [internalValue, setInternalValue] = useState(getInitialValue());
55
- const [broadcastedValue, setBroadcastedValue] = useState(null);
56
-
57
- const getSelectOptions = () => {
58
- const countriesList = excludeCountries(countries, disabledCountries);
59
- const listSortedByISO3 = groupCountriesByPrefix(sortArrayByProperty(countriesList, 'iso3'));
60
-
61
- return listSortedByISO3.map((option) => {
62
- const { phone, iso3, iso2, name } = option;
63
- let note = '';
64
-
65
- if (iso3) {
66
- note = isArray(iso3) ? iso3.join(', ') : iso3;
67
- } else if (iso2) {
68
- note = isArray(iso2) ? iso2.join(', ') : iso2;
69
- }
70
-
71
- return {
72
- type: 'option',
73
- value: {
74
- value: phone,
75
- label: phone,
76
- note: note,
77
- },
78
- filterMatchers: [phone, note, name],
79
- };
80
- });
81
- };
82
-
83
- const options = getSelectOptions();
84
-
85
- const onPrefixChange = ({ value }) => {
86
- setInternalValue({ prefix: value, suffix: internalValue.suffix });
87
- };
88
-
89
- const onSuffixChange = (event) => {
90
- const { value = '' } = event.target;
91
-
92
- if (ALLOWED_PHONE_CHARS.test(value)) {
93
- setInternalValue({ prefix: internalValue.prefix, suffix: value });
94
- }
95
- };
96
-
97
- const onPaste = (event) => {
98
- if (!event.nativeEvent.clipboardData) {
99
- return;
100
- }
101
-
102
- const pastedValue = (event.nativeEvent.clipboardData.getData('text/plain') || '').replace(
103
- /(\s|-)+/g,
104
- '',
105
- );
106
- const { prefix: pastedPrefix, suffix: pastedSuffix } = explodeNumberModel(pastedValue);
107
- const selectedPrefix = options.find(({ value }) => value.value === pastedPrefix);
108
-
109
- if (selectedPrefix && ALLOWED_PHONE_CHARS.test(pastedSuffix)) {
110
- setInternalValue({ prefix: pastedPrefix, suffix: pastedSuffix });
111
- }
112
- };
113
-
114
- useEffect(() => {
115
- if (broadcastedValue === null) {
116
- return setBroadcastedValue(internalValue);
117
- }
118
-
119
- const internalPhoneNumber = internalValue.prefix + internalValue.suffix;
120
- const broadcastedPhoneNumber = broadcastedValue.prefix + broadcastedValue.suffix;
121
-
122
- if (internalPhoneNumber === broadcastedPhoneNumber) {
123
- return;
124
- }
125
-
126
- const newValue = isValidPhoneNumber(internalPhoneNumber)
127
- ? cleanNumber(internalPhoneNumber)
128
- : null;
129
-
130
- onChange(newValue, internalValue.prefix);
131
- setBroadcastedValue(internalValue);
132
- }, [onChange, broadcastedValue, internalValue]);
133
-
134
- return (
135
- <div className="tw-telephone">
136
- <div className="tw-telephone__country-select">
137
- <SelectInput
138
- placeholder="Select an option..."
139
- items={options}
140
- value={options.find((item) => item.value.value === internalValue.prefix)?.value}
141
- renderValue={(option, withinTrigger) => (
142
- <SelectInputOptionContent
143
- title={option.label}
144
- note={withinTrigger ? undefined : option.note}
145
- />
146
- )}
147
- filterable
148
- filterPlaceholder={searchPlaceholder}
149
- disabled={disabled}
150
- size={size}
151
- onChange={onPrefixChange}
152
- {...selectProps}
153
- />
154
- </div>
155
- <div className="tw-telephone__number-input">
156
- <div className={`input-group input-group-${size}`}>
157
- <input
158
- id={id}
159
- autoComplete="tel-national"
160
- name="phoneNumber"
161
- inputMode="numeric"
162
- value={internalValue.suffix}
163
- className="form-control"
164
- disabled={disabled}
165
- required={required}
166
- placeholder={placeholder}
167
- onChange={onSuffixChange}
168
- onPaste={onPaste}
169
- onFocus={onFocus}
170
- onBlur={onBlur}
171
- />
172
- </div>
173
- </div>
174
- </div>
175
- );
176
- };
177
-
178
- PhoneNumberInput.propTypes = {
179
- id: PropTypes.string,
180
- required: PropTypes.bool,
181
- disabled: PropTypes.bool,
182
- initialValue: PropTypes.string,
183
- onChange: PropTypes.func.isRequired,
184
- onFocus: PropTypes.func,
185
- onBlur: PropTypes.func,
186
- countryCode: PropTypes.string,
187
- searchPlaceholder: PropTypes.string,
188
- size: PropTypes.oneOf(['sm', 'md', 'lg']),
189
- placeholder: PropTypes.string,
190
- selectProps: PropTypes.object,
191
- /** List of iso3 codes of countries to remove from the list */
192
- disabledCountries: PropTypes.arrayOf(PropTypes.string),
193
- };
194
-
195
- PhoneNumberInput.defaultProps = {
196
- id: null,
197
- required: false,
198
- disabled: false,
199
- initialValue: null,
200
- onFocus() {},
201
- onBlur() {},
202
- countryCode: null,
203
- searchPlaceholder: 'Prefix',
204
- size: Size.MEDIUM,
205
- placeholder: '',
206
- selectProps: {},
207
- disabledCountries: [],
208
- };
209
-
210
- export default PhoneNumberInput;
@@ -1,12 +0,0 @@
1
- import countries from './countries';
2
-
3
- describe('Given a list of countries', () => {
4
- countries.forEach((country) => {
5
- it('each country should have a valid format', () => {
6
- expect(country).toHaveProperty('phone');
7
- expect(country).toHaveProperty('name');
8
- expect(country).toHaveProperty('iso3');
9
- expect(country).toHaveProperty('iso2');
10
- });
11
- });
12
- });
@@ -1,4 +0,0 @@
1
- const DIGITS_MATCH = /^$|^(\+)|([\d]+)/g;
2
-
3
- export const cleanNumber = (number) =>
4
- (number.match(DIGITS_MATCH) && number.match(DIGITS_MATCH).join('')) || '';
@@ -1,27 +0,0 @@
1
- import { findCountryByPrefix } from '../findCountryByPrefix';
2
-
3
- /**
4
- * Given a sting in a valid format ex:'+447573135343' it returns an object of shape
5
- * {prefix=+44 ,suffix=7573135343}
6
- *
7
- * @param {string} number - a string that defines a phone number.
8
- * @returns {{prefix: (string|*), suffix: string, format: string}}
9
- */
10
- export const explodeNumberModel = (number) => {
11
- let prefix = '';
12
- let suffix = '';
13
- let format = '';
14
- const country = findCountryByPrefix(number);
15
-
16
- if (country) {
17
- prefix = country.phone;
18
- suffix = number.slice(country.phone.length);
19
- format = country.phoneFormat || '';
20
- } else {
21
- prefix = '';
22
- suffix = number.slice(1);
23
- format = '';
24
- }
25
-
26
- return { prefix, suffix, format };
27
- };
@@ -1,36 +0,0 @@
1
- import { filterOptionsForQuery } from '..';
2
-
3
- const OPTIONS = [
4
- {
5
- name: 'test1',
6
- iso2: 'TT',
7
- iso3: 'TT1',
8
- phone: '+93',
9
- },
10
- {
11
- name: 'something',
12
- iso2: 'ST',
13
- iso3: 'SMT',
14
- phone: '+33',
15
- },
16
- ];
17
-
18
- describe('filterOptionsForQuery', () => {
19
- it('filters options based on all properties', () => {
20
- const option1 = OPTIONS[0];
21
- const option2 = OPTIONS[1];
22
-
23
- expect(filterOptionsForQuery(OPTIONS, option1.name)).toStrictEqual([option1]);
24
- expect(filterOptionsForQuery(OPTIONS, option1.iso2)).toStrictEqual([option1]);
25
- expect(filterOptionsForQuery(OPTIONS, option1.iso3)).toStrictEqual([option1]);
26
- expect(filterOptionsForQuery(OPTIONS, option1.phone)).toStrictEqual([option1]);
27
- expect(filterOptionsForQuery(OPTIONS, option2.name)).toStrictEqual([option2]);
28
- expect(filterOptionsForQuery(OPTIONS, option2.iso2)).toStrictEqual([option2]);
29
- expect(filterOptionsForQuery(OPTIONS, option2.iso3)).toStrictEqual([option2]);
30
- expect(filterOptionsForQuery(OPTIONS, option2.phone)).toStrictEqual([option2]);
31
- });
32
-
33
- it('should return an emtpy array if option cannot be found', () => {
34
- expect(filterOptionsForQuery(OPTIONS, 'AA')).toStrictEqual([]);
35
- });
36
- });
@@ -1,11 +0,0 @@
1
- import { isOptionAndFitsQuery } from '../isOptionAndFitsQuery';
2
-
3
- /**
4
- * Filters a set of options based on search string
5
- *
6
- * @param options
7
- * @param query
8
- * @returns {*}
9
- */
10
- export const filterOptionsForQuery = (options, query) =>
11
- options.filter((option) => isOptionAndFitsQuery(option, query));
@@ -1,10 +0,0 @@
1
- import countries from '../../data/countries';
2
- import { longestMatchingPrefix } from '../longestMatchingPrefix';
3
-
4
- export const findCountryByCode = (code) => {
5
- let matchingCodes;
6
- if (code && code.length === 2) {
7
- matchingCodes = countries.filter((country) => code.toUpperCase() === country.iso2);
8
- }
9
- return matchingCodes && matchingCodes.length > 0 ? longestMatchingPrefix(matchingCodes) : null;
10
- };
@@ -1,11 +0,0 @@
1
- import countries from '../../data/countries';
2
- import { longestMatchingPrefix } from '../longestMatchingPrefix';
3
-
4
- export const findCountryByPrefix = (number) => {
5
- let matchingCodes = null;
6
- if (number && number.length > 1) {
7
- matchingCodes = countries.filter((country) => number.indexOf(country.phone) === 0);
8
- }
9
-
10
- return matchingCodes && matchingCodes.length > 0 ? longestMatchingPrefix(matchingCodes) : null;
11
- };
@@ -1,26 +0,0 @@
1
- import { isArray } from '@transferwise/neptune-validation';
2
-
3
- export const groupCountriesByPrefix = (countries) => {
4
- const groupedArray = countries.reduce((accumulator, country) => {
5
- const { name, iso2, iso3, phone } = country;
6
- if (accumulator[phone]) {
7
- const previousValue = accumulator[phone];
8
- accumulator[phone] = {
9
- ...previousValue,
10
- name: isArray(previousValue.name)
11
- ? [...previousValue.name, name]
12
- : [previousValue.name, name],
13
- iso2: isArray(previousValue.iso2)
14
- ? [...previousValue.iso2, iso2]
15
- : [previousValue.iso2, iso2],
16
- iso3: isArray(previousValue.iso3)
17
- ? [...previousValue.iso3, iso3]
18
- : [previousValue.iso3, iso3],
19
- };
20
- } else {
21
- accumulator[phone] = country;
22
- }
23
- return accumulator;
24
- }, {});
25
- return Object.values(groupedArray);
26
- };
@@ -1,67 +0,0 @@
1
- import { groupCountriesByPrefix } from '.';
2
-
3
- const countries = [
4
- {
5
- name: 'Canada',
6
- iso2: 'CA',
7
- iso3: 'CAN',
8
- phone: '+1',
9
- },
10
- {
11
- name: 'United States of America',
12
- iso2: 'US',
13
- iso3: 'USA',
14
- phone: '+1',
15
- },
16
- {
17
- name: 'United States Minor Outlying Islands',
18
- iso2: 'UM',
19
- iso3: 'UMI',
20
- phone: '+1',
21
- },
22
- {
23
- name: 'United Kingdom',
24
- iso2: 'GB',
25
- iso3: 'GBR',
26
- phone: '+44',
27
- },
28
- {
29
- name: 'Guernsey',
30
- iso2: 'GG',
31
- iso3: 'GGY',
32
- phone: '+44',
33
- },
34
- {
35
- name: 'Guinea',
36
- iso2: 'GN',
37
- iso3: 'GIN',
38
- phone: '+224',
39
- },
40
- ];
41
-
42
- const groupedCountries = [
43
- {
44
- name: ['Canada', 'United States of America', 'United States Minor Outlying Islands'],
45
- iso2: ['CA', 'US', 'UM'],
46
- iso3: ['CAN', 'USA', 'UMI'],
47
- phone: '+1',
48
- },
49
- {
50
- name: ['United Kingdom', 'Guernsey'],
51
- iso2: ['GB', 'GG'],
52
- iso3: ['GBR', 'GGY'],
53
- phone: '+44',
54
- },
55
- {
56
- name: 'Guinea',
57
- iso2: 'GN',
58
- iso3: 'GIN',
59
- phone: '+224',
60
- },
61
- ];
62
-
63
- describe('groupCountriesByPrefix', () => {
64
- it('groups countries by prefix', () => {
65
- expect(groupCountriesByPrefix(countries)).toStrictEqual(groupedCountries);
66
- });
67
- });
@@ -1 +0,0 @@
1
- export { isOptionAndFitsQuery, startsWith } from './isOptionAndFitsQuery';
@@ -1,25 +0,0 @@
1
- import { isArray } from '@transferwise/neptune-validation';
2
- /**
3
- * Checks if query is contained into object properties.
4
- *
5
- * @param {object} option - the select option
6
- * @param {string} query - the current search query
7
- * @returns {boolean}
8
- */
9
- export const isOptionAndFitsQuery = (option, query) =>
10
- startsWith(option.iso3, query) ||
11
- startsWith(option.iso2, query) ||
12
- startsWith(option.name, query) ||
13
- startsWith(option.phone, query);
14
-
15
- export const startsWith = (property, query) => {
16
- if (isArray(property)) {
17
- return (
18
- property.filter((proper) => normalizeValue(proper).indexOf(normalizeValue(query)) === 0)
19
- .length > 0
20
- );
21
- }
22
- return normalizeValue(property).indexOf(normalizeValue(query)) === 0;
23
- };
24
-
25
- const normalizeValue = (value) => value.toLowerCase().replace('+', '');
@@ -1,66 +0,0 @@
1
- import { startsWith, isOptionAndFitsQuery } from '.';
2
-
3
- const DATA_TEST = [
4
- {
5
- name: 'test1',
6
- iso2: 'TT',
7
- iso3: 'TT1',
8
- phone: '+93',
9
- },
10
- {
11
- name: 'test1',
12
- iso2: ['TT', 'AA'],
13
- iso3: 'TT1',
14
- phone: '+93',
15
- },
16
- {
17
- name: 'something',
18
- iso2: 'ST',
19
- iso3: 'SMT',
20
- phone: '+33',
21
- },
22
- ];
23
-
24
- describe('isOptionAndFitsQuery', () => {
25
- describe('when option is given', () => {
26
- it('should return true if query is relevant', () => {
27
- expect(isOptionAndFitsQuery(DATA_TEST[0], 'TT')).toBe(true);
28
- });
29
-
30
- it('should return true if query is relevant and one of the array values', () => {
31
- expect(isOptionAndFitsQuery(DATA_TEST[1], 'TT')).toBe(true);
32
- });
33
-
34
- it('should return false if query is not relevant and not one of the array values', () => {
35
- expect(isOptionAndFitsQuery(DATA_TEST[1], 'BB')).toBe(false);
36
- });
37
-
38
- it('should return false if query is not relevant', () => {
39
- expect(isOptionAndFitsQuery(DATA_TEST[0], 'AA')).toBe(false);
40
- });
41
- });
42
- });
43
-
44
- describe('startWith', () => {
45
- describe('when property is given', () => {
46
- it('returns true if any of the values starts with the query', () => {
47
- expect(startsWith('AA', 'AA')).toBe(true);
48
- });
49
-
50
- it(`returns false if value doesn't start with`, () => {
51
- expect(startsWith('AABB', 'BB')).toBe(false);
52
- });
53
-
54
- it('should return true if query is contained in grouped options', () => {
55
- expect(startsWith(['AA', 'BB'], 'BB')).toBe(true);
56
- });
57
-
58
- it("returns false if any value in an array doesn't start with", () => {
59
- expect(startsWith(['CCAA', 'CCBB'], 'BB')).toBe(false);
60
- });
61
-
62
- it('returns false for an empty value', () => {
63
- expect(startsWith('', 'BB')).toBe(false);
64
- });
65
- });
66
- });
@@ -1 +0,0 @@
1
- export const isStringNumeric = (value) => /^\+?[\d-\s]+$/.test(value);
@@ -1,10 +0,0 @@
1
- /**
2
- *
3
- * @param phoneNumber
4
- * @returns {boolean} - returns true for number that starts with '+' and contains a mix of digits and spaces with
5
- * at least 4 digits.
6
- */
7
- export const isValidPhoneNumber = (phoneNumber) =>
8
- /^\+[\d-\s]+$/.test(phoneNumber) &&
9
- phoneNumber.match(/\d+/g) &&
10
- phoneNumber.match(/\d+/g).join('').length >= 4;
@@ -1,2 +0,0 @@
1
- export const longestMatchingPrefix = (matchingCodes) =>
2
- matchingCodes.reduce((a, b) => (a.phone.length > b.phone.length ? a : b));