react-native-phone-country-input 1.0.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 (172) hide show
  1. package/README.md +477 -0
  2. package/lib/commonjs/CountrySelector/CountrySelector.js +74 -0
  3. package/lib/commonjs/CountrySelector/CountrySelector.js.map +1 -0
  4. package/lib/commonjs/CountrySelector/CountrySelectorModal.js +267 -0
  5. package/lib/commonjs/CountrySelector/CountrySelectorModal.js.map +1 -0
  6. package/lib/commonjs/Keyboard/Keyboard.js +316 -0
  7. package/lib/commonjs/Keyboard/Keyboard.js.map +1 -0
  8. package/lib/commonjs/Keyboard/KeyboardToolbar.js +70 -0
  9. package/lib/commonjs/Keyboard/KeyboardToolbar.js.map +1 -0
  10. package/lib/commonjs/Keyboard/KeypadButton.js +66 -0
  11. package/lib/commonjs/Keyboard/KeypadButton.js.map +1 -0
  12. package/lib/commonjs/Keyboard/KeypadButtonContainer.js +65 -0
  13. package/lib/commonjs/Keyboard/KeypadButtonContainer.js.map +1 -0
  14. package/lib/commonjs/Keyboard/KeypadRow.js +34 -0
  15. package/lib/commonjs/Keyboard/KeypadRow.js.map +1 -0
  16. package/lib/commonjs/PhoneCountryInput/PhoneCountryInput.js +86 -0
  17. package/lib/commonjs/PhoneCountryInput/PhoneCountryInput.js.map +1 -0
  18. package/lib/commonjs/PhoneNumberField.js +36 -0
  19. package/lib/commonjs/PhoneNumberField.js.map +1 -0
  20. package/lib/commonjs/Styling/Colors.js +197 -0
  21. package/lib/commonjs/Styling/Colors.js.map +1 -0
  22. package/lib/commonjs/Styling/Sizing.js +111 -0
  23. package/lib/commonjs/Styling/Sizing.js.map +1 -0
  24. package/lib/commonjs/consts/KEYBOARD_LAYOUT.js +45 -0
  25. package/lib/commonjs/consts/KEYBOARD_LAYOUT.js.map +1 -0
  26. package/lib/commonjs/consts/regions.js +1503 -0
  27. package/lib/commonjs/consts/regions.js.map +1 -0
  28. package/lib/commonjs/enum/CountryIds.js +264 -0
  29. package/lib/commonjs/enum/CountryIds.js.map +1 -0
  30. package/lib/commonjs/hooks/UsePhoneFieldState.js +237 -0
  31. package/lib/commonjs/hooks/UsePhoneFieldState.js.map +1 -0
  32. package/lib/commonjs/index.js +56 -0
  33. package/lib/commonjs/index.js.map +1 -0
  34. package/lib/commonjs/package.json +1 -0
  35. package/lib/commonjs/utils/characterDeletion.js +20 -0
  36. package/lib/commonjs/utils/characterDeletion.js.map +1 -0
  37. package/lib/commonjs/utils/characterInsert.js +20 -0
  38. package/lib/commonjs/utils/characterInsert.js.map +1 -0
  39. package/lib/commonjs/utils/fromMaskedNumberToUnmaskedSelection.js +14 -0
  40. package/lib/commonjs/utils/fromMaskedNumberToUnmaskedSelection.js.map +1 -0
  41. package/lib/commonjs/utils/fromUnmaskedToMaskedPosition.js +20 -0
  42. package/lib/commonjs/utils/fromUnmaskedToMaskedPosition.js.map +1 -0
  43. package/lib/commonjs/utils/generateCountryCodeList.js +23 -0
  44. package/lib/commonjs/utils/generateCountryCodeList.js.map +1 -0
  45. package/lib/commonjs/utils/getDefaultRegion.js +33 -0
  46. package/lib/commonjs/utils/getDefaultRegion.js.map +1 -0
  47. package/lib/commonjs/utils/maskToPhoneNumber.js +23 -0
  48. package/lib/commonjs/utils/maskToPhoneNumber.js.map +1 -0
  49. package/lib/commonjs/utils/matchCountryCode.js +27 -0
  50. package/lib/commonjs/utils/matchCountryCode.js.map +1 -0
  51. package/lib/module/CountrySelector/CountrySelector.js +70 -0
  52. package/lib/module/CountrySelector/CountrySelector.js.map +1 -0
  53. package/lib/module/CountrySelector/CountrySelectorModal.js +262 -0
  54. package/lib/module/CountrySelector/CountrySelectorModal.js.map +1 -0
  55. package/lib/module/Keyboard/Keyboard.js +310 -0
  56. package/lib/module/Keyboard/Keyboard.js.map +1 -0
  57. package/lib/module/Keyboard/KeyboardToolbar.js +65 -0
  58. package/lib/module/Keyboard/KeyboardToolbar.js.map +1 -0
  59. package/lib/module/Keyboard/KeypadButton.js +61 -0
  60. package/lib/module/Keyboard/KeypadButton.js.map +1 -0
  61. package/lib/module/Keyboard/KeypadButtonContainer.js +59 -0
  62. package/lib/module/Keyboard/KeypadButtonContainer.js.map +1 -0
  63. package/lib/module/Keyboard/KeypadRow.js +30 -0
  64. package/lib/module/Keyboard/KeypadRow.js.map +1 -0
  65. package/lib/module/PhoneCountryInput/PhoneCountryInput.js +80 -0
  66. package/lib/module/PhoneCountryInput/PhoneCountryInput.js.map +1 -0
  67. package/lib/module/PhoneNumberField.js +31 -0
  68. package/lib/module/PhoneNumberField.js.map +1 -0
  69. package/lib/module/Styling/Colors.js +193 -0
  70. package/lib/module/Styling/Colors.js.map +1 -0
  71. package/lib/module/Styling/Sizing.js +107 -0
  72. package/lib/module/Styling/Sizing.js.map +1 -0
  73. package/lib/module/consts/KEYBOARD_LAYOUT.js +41 -0
  74. package/lib/module/consts/KEYBOARD_LAYOUT.js.map +1 -0
  75. package/lib/module/consts/regions.js +1498 -0
  76. package/lib/module/consts/regions.js.map +1 -0
  77. package/lib/module/enum/CountryIds.js +260 -0
  78. package/lib/module/enum/CountryIds.js.map +1 -0
  79. package/lib/module/hooks/UsePhoneFieldState.js +232 -0
  80. package/lib/module/hooks/UsePhoneFieldState.js.map +1 -0
  81. package/lib/module/index.js +16 -0
  82. package/lib/module/index.js.map +1 -0
  83. package/lib/module/package.json +1 -0
  84. package/lib/module/utils/characterDeletion.js +16 -0
  85. package/lib/module/utils/characterDeletion.js.map +1 -0
  86. package/lib/module/utils/characterInsert.js +16 -0
  87. package/lib/module/utils/characterInsert.js.map +1 -0
  88. package/lib/module/utils/fromMaskedNumberToUnmaskedSelection.js +10 -0
  89. package/lib/module/utils/fromMaskedNumberToUnmaskedSelection.js.map +1 -0
  90. package/lib/module/utils/fromUnmaskedToMaskedPosition.js +16 -0
  91. package/lib/module/utils/fromUnmaskedToMaskedPosition.js.map +1 -0
  92. package/lib/module/utils/generateCountryCodeList.js +19 -0
  93. package/lib/module/utils/generateCountryCodeList.js.map +1 -0
  94. package/lib/module/utils/getDefaultRegion.js +28 -0
  95. package/lib/module/utils/getDefaultRegion.js.map +1 -0
  96. package/lib/module/utils/maskToPhoneNumber.js +19 -0
  97. package/lib/module/utils/maskToPhoneNumber.js.map +1 -0
  98. package/lib/module/utils/matchCountryCode.js +23 -0
  99. package/lib/module/utils/matchCountryCode.js.map +1 -0
  100. package/lib/typescript/CountrySelector/CountrySelector.d.ts +19 -0
  101. package/lib/typescript/CountrySelector/CountrySelector.d.ts.map +1 -0
  102. package/lib/typescript/CountrySelector/CountrySelectorModal.d.ts +12 -0
  103. package/lib/typescript/CountrySelector/CountrySelectorModal.d.ts.map +1 -0
  104. package/lib/typescript/Keyboard/Keyboard.d.ts +25 -0
  105. package/lib/typescript/Keyboard/Keyboard.d.ts.map +1 -0
  106. package/lib/typescript/Keyboard/KeyboardToolbar.d.ts +9 -0
  107. package/lib/typescript/Keyboard/KeyboardToolbar.d.ts.map +1 -0
  108. package/lib/typescript/Keyboard/KeypadButton.d.ts +10 -0
  109. package/lib/typescript/Keyboard/KeypadButton.d.ts.map +1 -0
  110. package/lib/typescript/Keyboard/KeypadButtonContainer.d.ts +12 -0
  111. package/lib/typescript/Keyboard/KeypadButtonContainer.d.ts.map +1 -0
  112. package/lib/typescript/Keyboard/KeypadRow.d.ts +9 -0
  113. package/lib/typescript/Keyboard/KeypadRow.d.ts.map +1 -0
  114. package/lib/typescript/PhoneCountryInput/PhoneCountryInput.d.ts +16 -0
  115. package/lib/typescript/PhoneCountryInput/PhoneCountryInput.d.ts.map +1 -0
  116. package/lib/typescript/PhoneNumberField.d.ts +17 -0
  117. package/lib/typescript/PhoneNumberField.d.ts.map +1 -0
  118. package/lib/typescript/Styling/Colors.d.ts +189 -0
  119. package/lib/typescript/Styling/Colors.d.ts.map +1 -0
  120. package/lib/typescript/Styling/Sizing.d.ts +214 -0
  121. package/lib/typescript/Styling/Sizing.d.ts.map +1 -0
  122. package/lib/typescript/consts/KEYBOARD_LAYOUT.d.ts +18 -0
  123. package/lib/typescript/consts/KEYBOARD_LAYOUT.d.ts.map +1 -0
  124. package/lib/typescript/consts/regions.d.ts +10 -0
  125. package/lib/typescript/consts/regions.d.ts.map +1 -0
  126. package/lib/typescript/enum/CountryIds.d.ts +249 -0
  127. package/lib/typescript/enum/CountryIds.d.ts.map +1 -0
  128. package/lib/typescript/hooks/UsePhoneFieldState.d.ts +34 -0
  129. package/lib/typescript/hooks/UsePhoneFieldState.d.ts.map +1 -0
  130. package/lib/typescript/index.d.ts +15 -0
  131. package/lib/typescript/index.d.ts.map +1 -0
  132. package/lib/typescript/utils/characterDeletion.d.ts +3 -0
  133. package/lib/typescript/utils/characterDeletion.d.ts.map +1 -0
  134. package/lib/typescript/utils/characterInsert.d.ts +3 -0
  135. package/lib/typescript/utils/characterInsert.d.ts.map +1 -0
  136. package/lib/typescript/utils/fromMaskedNumberToUnmaskedSelection.d.ts +2 -0
  137. package/lib/typescript/utils/fromMaskedNumberToUnmaskedSelection.d.ts.map +1 -0
  138. package/lib/typescript/utils/fromUnmaskedToMaskedPosition.d.ts +2 -0
  139. package/lib/typescript/utils/fromUnmaskedToMaskedPosition.d.ts.map +1 -0
  140. package/lib/typescript/utils/generateCountryCodeList.d.ts +3 -0
  141. package/lib/typescript/utils/generateCountryCodeList.d.ts.map +1 -0
  142. package/lib/typescript/utils/getDefaultRegion.d.ts +4 -0
  143. package/lib/typescript/utils/getDefaultRegion.d.ts.map +1 -0
  144. package/lib/typescript/utils/maskToPhoneNumber.d.ts +2 -0
  145. package/lib/typescript/utils/maskToPhoneNumber.d.ts.map +1 -0
  146. package/lib/typescript/utils/matchCountryCode.d.ts +3 -0
  147. package/lib/typescript/utils/matchCountryCode.d.ts.map +1 -0
  148. package/package.json +92 -0
  149. package/src/CountrySelector/CountrySelector.tsx +77 -0
  150. package/src/CountrySelector/CountrySelectorModal.tsx +280 -0
  151. package/src/Keyboard/Keyboard.tsx +322 -0
  152. package/src/Keyboard/KeyboardToolbar.tsx +53 -0
  153. package/src/Keyboard/KeypadButton.tsx +58 -0
  154. package/src/Keyboard/KeypadButtonContainer.tsx +67 -0
  155. package/src/Keyboard/KeypadRow.tsx +29 -0
  156. package/src/PhoneCountryInput/PhoneCountryInput.tsx +98 -0
  157. package/src/PhoneNumberField.tsx +46 -0
  158. package/src/Styling/Colors.ts +206 -0
  159. package/src/Styling/Sizing.ts +110 -0
  160. package/src/consts/KEYBOARD_LAYOUT.ts +34 -0
  161. package/src/consts/regions.ts +268 -0
  162. package/src/enum/CountryIds.ts +256 -0
  163. package/src/hooks/UsePhoneFieldState.tsx +268 -0
  164. package/src/index.ts +27 -0
  165. package/src/utils/characterDeletion.ts +16 -0
  166. package/src/utils/characterInsert.ts +20 -0
  167. package/src/utils/fromMaskedNumberToUnmaskedSelection.ts +10 -0
  168. package/src/utils/fromUnmaskedToMaskedPosition.ts +13 -0
  169. package/src/utils/generateCountryCodeList.ts +22 -0
  170. package/src/utils/getDefaultRegion.ts +30 -0
  171. package/src/utils/maskToPhoneNumber.ts +30 -0
  172. package/src/utils/matchCountryCode.ts +23 -0
@@ -0,0 +1,256 @@
1
+ export enum CountryId {
2
+ // Zone 1 - North American Numbering Plan (NANP)
3
+ UNITED_STATES = 'US',
4
+ CANADA = 'CA',
5
+ ANTIGUA_AND_BARBUDA = 'AG',
6
+ ANGUILLA = 'AI',
7
+ AMERICAN_SAMOA = 'AS',
8
+ BAHAMAS = 'BS',
9
+ BARBADOS = 'BB',
10
+ BERMUDA = 'BM',
11
+ BRITISH_VIRGIN_ISLANDS = 'VG',
12
+ CAYMAN_ISLANDS = 'KY',
13
+ DOMINICA = 'DM',
14
+ DOMINICAN_REPUBLIC = 'DO',
15
+ GRENADA = 'GD',
16
+ GUAM = 'GU',
17
+ JAMAICA = 'JM',
18
+ MONTSERRAT = 'MS',
19
+ NORTHERN_MARIANA_ISLANDS = 'MP',
20
+ PUERTO_RICO = 'PR',
21
+ SAINT_KITTS_AND_NEVIS = 'KN',
22
+ SAINT_LUCIA = 'LC',
23
+ SAINT_VINCENT_AND_THE_GRENADINES = 'VC',
24
+ SINT_MAARTEN = 'SX',
25
+ TRINIDAD_AND_TOBAGO = 'TT',
26
+ TURKS_AND_CAICOS_ISLANDS = 'TC',
27
+ UNITED_STATES_VIRGIN_ISLANDS = 'VI',
28
+ // Zone 2 - Africa
29
+ EGYPT = 'EG',
30
+ SOUTH_SUDAN = 'SS',
31
+ MOROCCO = 'MA',
32
+ WESTERN_SAHARA = 'EH',
33
+ ALGERIA = 'DZ',
34
+ TUNISIA = 'TN',
35
+ LIBYA = 'LY',
36
+ GAMBIA = 'GM',
37
+ SENEGAL = 'SN',
38
+ MAURITANIA = 'MR',
39
+ MALI = 'ML',
40
+ GUINEA = 'GN',
41
+ IVORY_COAST = 'CI',
42
+ BURKINA_FASO = 'BF',
43
+ NIGER = 'NE',
44
+ TOGO = 'TG',
45
+ BENIN = 'BJ',
46
+ MAURITIUS = 'MU',
47
+ LIBERIA = 'LR',
48
+ SIERRA_LEONE = 'SL',
49
+ GHANA = 'GH',
50
+ NIGERIA = 'NG',
51
+ CHAD = 'TD',
52
+ CENTRAL_AFRICAN_REPUBLIC = 'CF',
53
+ CAMEROON = 'CM',
54
+ CAPE_VERDE = 'CV',
55
+ SAO_TOME_AND_PRINCIPE = 'ST',
56
+ EQUATORIAL_GUINEA = 'GQ',
57
+ GABON = 'GA',
58
+ REPUBLIC_OF_THE_CONGO = 'CG',
59
+ DEMOCRATIC_REPUBLIC_OF_THE_CONGO = 'CD',
60
+ ANGOLA = 'AO',
61
+ GUINEA_BISSAU = 'GW',
62
+ BRITISH_INDIAN_OCEAN_TERRITORY = 'IO',
63
+ ASCENSION_ISLAND = 'AC',
64
+ SEYCHELLES = 'SC',
65
+ SUDAN = 'SD',
66
+ RWANDA = 'RW',
67
+ ETHIOPIA = 'ET',
68
+ SOMALIA = 'SO',
69
+ DJIBOUTI = 'DJ',
70
+ KENYA = 'KE',
71
+ TANZANIA = 'TZ',
72
+ UGANDA = 'UG',
73
+ BURUNDI = 'BI',
74
+ MOZAMBIQUE = 'MZ',
75
+ ZAMBIA = 'ZM',
76
+ MADAGASCAR = 'MG',
77
+ REUNION = 'RE',
78
+ MAYOTTE = 'YT',
79
+ ZIMBABWE = 'ZW',
80
+ NAMIBIA = 'NA',
81
+ MALAWI = 'MW',
82
+ LESOTHO = 'LS',
83
+ BOTSWANA = 'BW',
84
+ ESWATINI = 'SZ',
85
+ COMOROS = 'KM',
86
+ SOUTH_AFRICA = 'ZA',
87
+ SAINT_HELENA = 'SH',
88
+ ERITREA = 'ER',
89
+ ARUBA = 'AW',
90
+ FAROE_ISLANDS = 'FO',
91
+ GREENLAND = 'GL',
92
+ // Zone 3 - Europe
93
+ GREECE = 'GR',
94
+ NETHERLANDS = 'NL',
95
+ BELGIUM = 'BE',
96
+ FRANCE = 'FR',
97
+ SPAIN = 'ES',
98
+ GIBRALTAR = 'GI',
99
+ PORTUGAL = 'PT',
100
+ LUXEMBOURG = 'LU',
101
+ IRELAND = 'IE',
102
+ ICELAND = 'IS',
103
+ ALBANIA = 'AL',
104
+ MALTA = 'MT',
105
+ CYPRUS = 'CY',
106
+ FINLAND = 'FI',
107
+ ALAND_ISLANDS = 'AX',
108
+ BULGARIA = 'BG',
109
+ HUNGARY = 'HU',
110
+ LITHUANIA = 'LT',
111
+ LATVIA = 'LV',
112
+ ESTONIA = 'EE',
113
+ MOLDOVA = 'MD',
114
+ ARMENIA = 'AM',
115
+ BELARUS = 'BY',
116
+ ANDORRA = 'AD',
117
+ MONACO = 'MC',
118
+ SAN_MARINO = 'SM',
119
+ UKRAINE = 'UA',
120
+ SERBIA = 'RS',
121
+ MONTENEGRO = 'ME',
122
+ KOSOVO = 'XK',
123
+ CROATIA = 'HR',
124
+ SLOVENIA = 'SI',
125
+ BOSNIA_AND_HERZEGOVINA = 'BA',
126
+ NORTH_MACEDONIA = 'MK',
127
+ ITALY = 'IT',
128
+ VATICAN_CITY = 'VA',
129
+ ROMANIA = 'RO',
130
+ SWITZERLAND = 'CH',
131
+ CZECH_REPUBLIC = 'CZ',
132
+ SLOVAKIA = 'SK',
133
+ LIECHTENSTEIN = 'LI',
134
+ AUSTRIA = 'AT',
135
+ UNITED_KINGDOM = 'GB',
136
+ GUERNSEY = 'GG',
137
+ ISLE_OF_MAN = 'IM',
138
+ JERSEY = 'JE',
139
+ DENMARK = 'DK',
140
+ SWEDEN = 'SE',
141
+ NORWAY = 'NO',
142
+ SVALBARD_AND_JAN_MAYEN = 'SJ',
143
+ POLAND = 'PL',
144
+ GERMANY = 'DE',
145
+ // Zone 5 - Central & South America, Caribbean
146
+ FALKLAND_ISLANDS = 'FK',
147
+ SOUTH_GEORGIA_AND_THE_SOUTH_SANDWICH_ISLANDS = 'GS',
148
+ BELIZE = 'BZ',
149
+ GUATEMALA = 'GT',
150
+ EL_SALVADOR = 'SV',
151
+ HONDURAS = 'HN',
152
+ NICARAGUA = 'NI',
153
+ COSTA_RICA = 'CR',
154
+ PANAMA = 'PA',
155
+ SAINT_PIERRE_AND_MIQUELON = 'PM',
156
+ HAITI = 'HT',
157
+ PERU = 'PE',
158
+ MEXICO = 'MX',
159
+ CUBA = 'CU',
160
+ ARGENTINA = 'AR',
161
+ BRAZIL = 'BR',
162
+ CHILE = 'CL',
163
+ COLOMBIA = 'CO',
164
+ VENEZUELA = 'VE',
165
+ GUADELOUPE = 'GP',
166
+ SAINT_BARTHELEMY = 'BL',
167
+ SAINT_MARTIN = 'MF',
168
+ BOLIVIA = 'BO',
169
+ GUYANA = 'GY',
170
+ ECUADOR = 'EC',
171
+ FRENCH_GUIANA = 'GF',
172
+ PARAGUAY = 'PY',
173
+ MARTINIQUE = 'MQ',
174
+ SURINAME = 'SR',
175
+ URUGUAY = 'UY',
176
+ CURACAO = 'CW',
177
+ CARIBBEAN_NETHERLANDS = 'BQ',
178
+ // Zone 6 - Southeast Asia & Oceania
179
+ MALAYSIA = 'MY',
180
+ AUSTRALIA = 'AU',
181
+ CHRISTMAS_ISLAND = 'CX',
182
+ COCOS_KEELING_ISLANDS = 'CC',
183
+ INDONESIA = 'ID',
184
+ PHILIPPINES = 'PH',
185
+ NEW_ZEALAND = 'NZ',
186
+ PITCAIRN_ISLANDS = 'PN',
187
+ SINGAPORE = 'SG',
188
+ THAILAND = 'TH',
189
+ TIMOR_LESTE = 'TL',
190
+ NORFOLK_ISLAND = 'NF',
191
+ BRUNEI = 'BN',
192
+ NAURU = 'NR',
193
+ PAPUA_NEW_GUINEA = 'PG',
194
+ TONGA = 'TO',
195
+ SOLOMON_ISLANDS = 'SB',
196
+ VANUATU = 'VU',
197
+ FIJI = 'FJ',
198
+ PALAU = 'PW',
199
+ WALLIS_AND_FUTUNA = 'WF',
200
+ COOK_ISLANDS = 'CK',
201
+ NIUE = 'NU',
202
+ SAMOA = 'WS',
203
+ KIRIBATI = 'KI',
204
+ NEW_CALEDONIA = 'NC',
205
+ TUVALU = 'TV',
206
+ FRENCH_POLYNESIA = 'PF',
207
+ TOKELAU = 'TK',
208
+ MICRONESIA = 'FM',
209
+ MARSHALL_ISLANDS = 'MH',
210
+ // Zone 7 - Russia & Kazakhstan
211
+ RUSSIA = 'RU',
212
+ KAZAKHSTAN = 'KZ',
213
+ // Zone 8 - East Asia
214
+ JAPAN = 'JP',
215
+ SOUTH_KOREA = 'KR',
216
+ VIETNAM = 'VN',
217
+ NORTH_KOREA = 'KP',
218
+ HONG_KONG = 'HK',
219
+ MACAU = 'MO',
220
+ CAMBODIA = 'KH',
221
+ LAOS = 'LA',
222
+ CHINA = 'CN',
223
+ BANGLADESH = 'BD',
224
+ TAIWAN = 'TW',
225
+ // Zone 9 - South Asia, Middle East & Central Asia
226
+ TURKEY = 'TR',
227
+ INDIA = 'IN',
228
+ PAKISTAN = 'PK',
229
+ AFGHANISTAN = 'AF',
230
+ SRI_LANKA = 'LK',
231
+ MYANMAR = 'MM',
232
+ MALDIVES = 'MV',
233
+ LEBANON = 'LB',
234
+ JORDAN = 'JO',
235
+ SYRIA = 'SY',
236
+ IRAQ = 'IQ',
237
+ KUWAIT = 'KW',
238
+ SAUDI_ARABIA = 'SA',
239
+ YEMEN = 'YE',
240
+ OMAN = 'OM',
241
+ PALESTINIAN_TERRITORIES = 'PS',
242
+ UNITED_ARAB_EMIRATES = 'AE',
243
+ ISRAEL = 'IL',
244
+ BAHRAIN = 'BH',
245
+ QATAR = 'QA',
246
+ BHUTAN = 'BT',
247
+ MONGOLIA = 'MN',
248
+ NEPAL = 'NP',
249
+ IRAN = 'IR',
250
+ TAJIKISTAN = 'TJ',
251
+ TURKMENISTAN = 'TM',
252
+ AZERBAIJAN = 'AZ',
253
+ GEORGIA = 'GE',
254
+ KYRGYZSTAN = 'KG',
255
+ UZBEKISTAN = 'UZ',
256
+ }
@@ -0,0 +1,268 @@
1
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
+ import { CountryCode } from '../consts/regions';
3
+ import { CountryId } from '../enum/CountryIds';
4
+ import { generateCountryCodeList } from '../utils/generateCountryCodeList';
5
+ import { getDefaultRegion } from '../utils/getDefaultRegion';
6
+ import { PhoneFieldOutcome } from '../PhoneNumberField';
7
+ import { maskToPhoneNumber } from '../utils/maskToPhoneNumber';
8
+ import { matchCountryCode } from '../utils/matchCountryCode';
9
+ import Clipboard from '@react-native-clipboard/clipboard';
10
+ import {
11
+ BACK_BUTTON,
12
+ CLEAR_BUTTON,
13
+ GLOBE_BUTTON,
14
+ KEYPAD_KEY,
15
+ SELECTION_TYPE,
16
+ } from '../consts/KEYBOARD_LAYOUT';
17
+ import { NativeSyntheticEvent, TextInputSelectionChangeEventData } from 'react-native';
18
+ import { characterDeletion } from '../utils/characterDeletion';
19
+ import { characterInsert } from '../utils/characterInsert';
20
+ import { fromMaskedNumberToUnmaskedSelection } from '../utils/fromMaskedNumberToUnmaskedSelection';
21
+ import { fromUnmaskedToMaskedPosition } from '../utils/fromUnmaskedToMaskedPosition';
22
+
23
+ export interface usePhoneFieldStateParams {
24
+ allowedCountryCodes?: CountryId[] | null;
25
+ disallowedCountryCodes?: CountryId[] | null;
26
+ }
27
+
28
+ export interface usePhoneFieldStateReturn {
29
+ country?: CountryCode;
30
+ filteredCountryCodes?: CountryCode[];
31
+ phoneNumber?: string;
32
+ outcome?: PhoneFieldOutcome;
33
+ onChangeText: (phoneNumber: string) => void;
34
+ onChangeFlag: (newCountry: CountryCode) => void;
35
+ onKeyPress: (_key: KEYPAD_KEY) => void;
36
+ onCopy: () => void;
37
+ onPaste: () => Promise<boolean>;
38
+ isKeyboardOpen: boolean;
39
+ openKeyboard: () => void;
40
+ closeKeyboard: () => void;
41
+ isCountrySelectorOpen: boolean;
42
+ openCountrySelector: () => void;
43
+ closeCountrySelector: () => void;
44
+ onTextSelection: (e: NativeSyntheticEvent<TextInputSelectionChangeEventData>) => void;
45
+ onClearText: () => void;
46
+ cursorPosition: { start: number; end: number };
47
+ }
48
+
49
+ export function usePhoneFieldState({
50
+ allowedCountryCodes,
51
+ disallowedCountryCodes,
52
+ }: usePhoneFieldStateParams): usePhoneFieldStateReturn {
53
+ const [country, setCountry] = useState<CountryCode | undefined>(undefined);
54
+ const [phoneNumber, setPhoneNumber] = useState<string | undefined>(undefined);
55
+ const phoneNumberRef = useRef(phoneNumber);
56
+ const [outcome, setOutcome] = useState<PhoneFieldOutcome | undefined>(undefined);
57
+ const [isKeyboardOpen, setIsKeyboardOpen] = useState(false);
58
+ const [cursorPosition, setCursorPosition] = useState<{ start: number; end: number }>({
59
+ start: 1,
60
+ end: 1,
61
+ });
62
+ const selectionRef = useRef<SELECTION_TYPE>({
63
+ start: 1,
64
+ end: 1,
65
+ hasBeenSelected: false,
66
+ hasBeenConsumed: true,
67
+ });
68
+
69
+ const openKeyboard = useCallback(() => setIsKeyboardOpen(true), []);
70
+ const closeKeyboard = useCallback(() => setIsKeyboardOpen(false), []);
71
+
72
+ const [isCountrySelectorOpen, setIsCountrySelectorOpen] = useState(false);
73
+ const openCountrySelector = useCallback(() => setIsCountrySelectorOpen(true), []);
74
+ const closeCountrySelector = useCallback(() => setIsCountrySelectorOpen(false), []);
75
+
76
+ const filteredCountryCodes = useMemo(() => {
77
+ return generateCountryCodeList(
78
+ allowedCountryCodes ?? undefined,
79
+ disallowedCountryCodes ?? undefined
80
+ );
81
+ }, [allowedCountryCodes, disallowedCountryCodes]);
82
+
83
+ const onChangeText = useCallback(
84
+ (_value: string) => {
85
+ const cleanedValue = _value.replace(/\D\s*/g, '').trim(); // remove non-digit characters
86
+
87
+ // parse the country code from the phone number and set the country state
88
+ let matchedCountry = matchCountryCode(filteredCountryCodes, cleanedValue);
89
+ console.debug('matchedCountry', matchedCountry);
90
+ setCountry(matchedCountry || undefined);
91
+
92
+ if (!!matchedCountry && cleanedValue.length >= 2) {
93
+ // apply masking to the phone number based on the matched country code
94
+ const output = maskToPhoneNumber(
95
+ cleanedValue,
96
+ matchedCountry?.code.replace('+', ''),
97
+ matchedCountry?.mask
98
+ );
99
+ setPhoneNumber(output);
100
+ phoneNumberRef.current = output;
101
+ const ouputWthOutMask = output.replace(/\D/g, '');
102
+ console.debug(output, ouputWthOutMask);
103
+
104
+ const correctLength = (matchedCountry.code + matchedCountry.mask).length;
105
+ const expectedDigitCount =
106
+ matchedCountry.code.replace(/\D/g, '').length +
107
+ matchedCountry.mask.replace(/[^#]/g, '').length;
108
+ setOutcome({
109
+ countryDetails: matchedCountry || null,
110
+ phoneNumber: ouputWthOutMask,
111
+ isValid: ouputWthOutMask.length === expectedDigitCount,
112
+ correctLength,
113
+ });
114
+ } else {
115
+ setPhoneNumber(cleanedValue);
116
+ phoneNumberRef.current = cleanedValue;
117
+ const correctLength = ((matchedCountry?.code ?? '') + (matchedCountry?.mask ?? '')).length;
118
+ setOutcome({
119
+ countryDetails: matchedCountry || null,
120
+ phoneNumber: cleanedValue,
121
+ isValid: false,
122
+ correctLength,
123
+ });
124
+ }
125
+ },
126
+ [filteredCountryCodes]
127
+ );
128
+
129
+ const onClearText = useCallback(() => {
130
+ console.debug('Refreshing....');
131
+ if (!outcome) {
132
+ console.error('Outcome is not defined, so cannot clear text');
133
+ return;
134
+ }
135
+ const current_outcome = outcome;
136
+ setPhoneNumber(current_outcome?.countryDetails?.code);
137
+ phoneNumberRef.current = current_outcome?.countryDetails?.code;
138
+
139
+ setOutcome({ ...current_outcome, phoneNumber: current_outcome?.countryDetails?.code ?? '' });
140
+ }, [outcome]);
141
+
142
+ const onChangeFlag = useCallback((newCountry: CountryCode) => {
143
+ const _phoneNumber = newCountry.code.replace('+', '');
144
+
145
+ setOutcome({
146
+ countryDetails: newCountry,
147
+ phoneNumber: _phoneNumber,
148
+ isValid: false,
149
+ correctLength: (newCountry.code + newCountry.mask).length,
150
+ });
151
+ setPhoneNumber(_phoneNumber);
152
+ phoneNumberRef.current = _phoneNumber;
153
+ setCountry(newCountry);
154
+
155
+ const newMasked = '+' + _phoneNumber;
156
+ const unmaskedEnd = _phoneNumber.replace(/\D/g, '').length;
157
+ selectionRef.current = {
158
+ start: unmaskedEnd,
159
+ end: unmaskedEnd,
160
+ hasBeenSelected: true,
161
+ hasBeenConsumed: false,
162
+ };
163
+ const maskedEnd = fromUnmaskedToMaskedPosition(newMasked, unmaskedEnd);
164
+ setCursorPosition({ start: maskedEnd, end: maskedEnd });
165
+ }, []);
166
+
167
+ const onKeyPress = useCallback(
168
+ (_key: KEYPAD_KEY) => {
169
+ const current = phoneNumberRef.current;
170
+ const existing_number = '+' + (current ?? '').replace(/\D/g, '');
171
+ const { start, end } = selectionRef.current;
172
+
173
+ if (_key.main === BACK_BUTTON) {
174
+ const isRange = start !== end;
175
+ if (start > 0 || isRange) {
176
+ const outcome = characterDeletion(existing_number, selectionRef.current);
177
+ onChangeText(outcome);
178
+ if (start > 0) {
179
+ selectionRef.current = { start: start - 1, end: start - 1, hasBeenSelected: true };
180
+ }
181
+ }
182
+ } else if (_key.main === CLEAR_BUTTON) {
183
+ onChangeText('');
184
+ selectionRef.current = { start: 0, end: 0, hasBeenSelected: false };
185
+ } else if (_key.main === GLOBE_BUTTON) {
186
+ openCountrySelector();
187
+ } else {
188
+ const outcome = characterInsert(existing_number, _key.main, selectionRef.current);
189
+ onChangeText(outcome);
190
+ if (phoneNumberRef.current && selectionRef.current.start < phoneNumberRef.current.length) {
191
+ selectionRef.current = { start: start + 1, end: start + 1, hasBeenSelected: true };
192
+ }
193
+ }
194
+
195
+ const newMasked = '+' + (phoneNumberRef.current ?? '');
196
+ const maskedStart = fromUnmaskedToMaskedPosition(newMasked, selectionRef.current.start);
197
+ setCursorPosition({ start: maskedStart, end: maskedStart });
198
+ },
199
+ [onChangeText, openCountrySelector]
200
+ );
201
+
202
+ const onCopy = useCallback(async () => {
203
+ console.debug('copying phone number: ', outcome?.phoneNumber);
204
+ Clipboard.setString(outcome?.phoneNumber ?? '');
205
+ }, [outcome?.phoneNumber]);
206
+
207
+ const onPaste = useCallback(async (): Promise<boolean> => {
208
+ const clipBoardContents = (await Clipboard.getString()).trim();
209
+ if (clipBoardContents.replace(/\D\s*/g, '').length < 1) {
210
+ return false;
211
+ }
212
+ onChangeText(clipBoardContents);
213
+ const newMasked = '+' + (phoneNumberRef.current ?? '');
214
+ const unmaskedEnd = (phoneNumberRef.current ?? '').replace(/\D/g, '').length;
215
+ selectionRef.current = {
216
+ start: unmaskedEnd,
217
+ end: unmaskedEnd,
218
+ hasBeenSelected: true,
219
+ hasBeenConsumed: false,
220
+ };
221
+ const maskedEnd = fromUnmaskedToMaskedPosition(newMasked, unmaskedEnd);
222
+ setCursorPosition({ start: maskedEnd, end: maskedEnd });
223
+ return true;
224
+ }, [onChangeText]);
225
+
226
+ const onTextSelection = useCallback(
227
+ (e: NativeSyntheticEvent<TextInputSelectionChangeEventData>) => {
228
+ const next = e.nativeEvent.selection;
229
+ // Include '+' so maskedPoint indexes align with the displayed string
230
+ const maskedValue = '+' + (phoneNumberRef.current ?? '');
231
+ const start = fromMaskedNumberToUnmaskedSelection(maskedValue, next.start);
232
+ const end = fromMaskedNumberToUnmaskedSelection(maskedValue, next.end);
233
+ selectionRef.current = { start, end, hasBeenSelected: true, hasBeenConsumed: false };
234
+ setCursorPosition({ start: next.start, end: next.end });
235
+ },
236
+ []
237
+ );
238
+
239
+ useEffect(() => {
240
+ const defaultRegion = getDefaultRegion(filteredCountryCodes);
241
+ console.debug(defaultRegion);
242
+ setCountry(defaultRegion);
243
+ onChangeText(defaultRegion?.code ?? ''); // set the default country code in the input field on load
244
+
245
+ // eslint-disable-next-line react-hooks/exhaustive-deps
246
+ }, []);
247
+
248
+ return {
249
+ country,
250
+ filteredCountryCodes,
251
+ phoneNumber,
252
+ outcome,
253
+ onChangeText,
254
+ onChangeFlag,
255
+ onKeyPress,
256
+ onCopy,
257
+ onPaste,
258
+ isKeyboardOpen,
259
+ openKeyboard,
260
+ closeKeyboard,
261
+ isCountrySelectorOpen,
262
+ openCountrySelector,
263
+ closeCountrySelector,
264
+ onTextSelection,
265
+ onClearText,
266
+ cursorPosition,
267
+ };
268
+ }
package/src/index.ts ADDED
@@ -0,0 +1,27 @@
1
+ // Opinionated all-in-one component
2
+ export { PhoneCountryInput } from './PhoneCountryInput/PhoneCountryInput';
3
+ export type { PhoneCountryInputProps } from './PhoneCountryInput/PhoneCountryInput';
4
+
5
+ // Individual pieces
6
+ export { PhoneNumberField } from './PhoneNumberField';
7
+ export type { PhoneNumberFieldProps, PhoneFieldOutcome } from './PhoneNumberField';
8
+
9
+ export { CountrySelector } from './CountrySelector/CountrySelector';
10
+ export type { CountrySelectorProps } from './CountrySelector/CountrySelector';
11
+
12
+ export { CountrySelectorModal } from './CountrySelector/CountrySelectorModal';
13
+ export type { CountrySelectorModalProps } from './CountrySelector/CountrySelectorModal';
14
+
15
+ export { default as Keyboard } from './Keyboard/Keyboard';
16
+ export type { KeyboardProps, PasteErrorModalProps, CopySuccessModalProps } from './Keyboard/Keyboard';
17
+
18
+ // State management hook
19
+ export { usePhoneFieldState } from './hooks/UsePhoneFieldState';
20
+ export type {
21
+ usePhoneFieldStateParams,
22
+ usePhoneFieldStateReturn,
23
+ } from './hooks/UsePhoneFieldState';
24
+
25
+ // Types for advanced users
26
+ export type { CountryCode } from './consts/regions';
27
+ export { CountryId } from './enum/CountryIds';
@@ -0,0 +1,16 @@
1
+ import { SELECTION_TYPE } from '../consts/KEYBOARD_LAYOUT';
2
+
3
+ export function characterDeletion(phoneNumber: string, selection: SELECTION_TYPE): string {
4
+ const isRange = selection.start !== selection.end;
5
+
6
+ if (!selection.hasBeenSelected && !isRange && selection.start === 0) {
7
+ return phoneNumber.slice(0, -1);
8
+ }
9
+ if (isRange) {
10
+ // selection.start digits are before the selection; first selected char is at index start+1
11
+ return phoneNumber.slice(0, selection.start + 1) + phoneNumber.slice(selection.end + 1);
12
+ }
13
+ // backspace: delete the digit immediately to the left of cursor (at index start); clamp to protect '+'
14
+ const start = Math.max(selection.start, 1);
15
+ return phoneNumber.slice(0, start) + phoneNumber.slice(start + 1);
16
+ }
@@ -0,0 +1,20 @@
1
+ import { SELECTION_TYPE } from '../consts/KEYBOARD_LAYOUT';
2
+
3
+ export function characterInsert(
4
+ phoneNumber: string,
5
+ newChar: string,
6
+ selection: SELECTION_TYPE
7
+ ): string {
8
+ const isARange = selection.start !== selection.end;
9
+
10
+ if (isARange) {
11
+ // selection.start digits are before the selection; first selected char is at index start+1
12
+ return phoneNumber.slice(0, selection.start + 1) + newChar + phoneNumber.slice(selection.end + 1);
13
+ } else if (selection.start === 0 && !selection.hasBeenSelected) {
14
+ return phoneNumber + newChar;
15
+ } else {
16
+ // cursor is after `start` digits; insert before char at index start+1; clamp to protect '+'
17
+ const start = Math.max(selection.start, 1);
18
+ return phoneNumber.slice(0, start + 1) + newChar + phoneNumber.slice(start + 1);
19
+ }
20
+ }
@@ -0,0 +1,10 @@
1
+ export function fromMaskedNumberToUnmaskedSelection(
2
+ maskedValue: string,
3
+ maskedPoint: number
4
+ ): number {
5
+ let count = 0;
6
+ for (let i = 0; i < maskedPoint && i < maskedValue.length; i++) {
7
+ if (/\d/.test(maskedValue[i])) count++;
8
+ }
9
+ return count;
10
+ }
@@ -0,0 +1,13 @@
1
+ export function fromUnmaskedToMaskedPosition(maskedValue: string, unmaskedPos: number): number {
2
+ if (unmaskedPos <= 0) return 1;
3
+ let digitCount = 0;
4
+ for (let i = 0; i < maskedValue.length; i++) {
5
+ if (/\d/.test(maskedValue[i])) {
6
+ digitCount++;
7
+ if (digitCount === unmaskedPos) {
8
+ return i + 1;
9
+ }
10
+ }
11
+ }
12
+ return maskedValue.length;
13
+ }
@@ -0,0 +1,22 @@
1
+ import { countryCodeList } from '../consts/regions';
2
+ import { CountryId } from '../enum/CountryIds';
3
+
4
+ export function generateCountryCodeList(
5
+ allowedCountryCodes?: CountryId[],
6
+ disallowedCountryCodes?: CountryId[]
7
+ ) {
8
+ return (
9
+ countryCodeList
10
+ .filter(({ id }) => {
11
+ if (allowedCountryCodes && !allowedCountryCodes.includes(id)) {
12
+ return false;
13
+ }
14
+ if (disallowedCountryCodes && disallowedCountryCodes.includes(id)) {
15
+ return false;
16
+ }
17
+ return true;
18
+ })
19
+ // sort by longer country codes first to ensure that we match the most specific country code when parsing the phone number
20
+ .sort((a, b) => b.code.length - a.code.length)
21
+ );
22
+ }
@@ -0,0 +1,30 @@
1
+ import { getLocales } from 'expo-localization';
2
+ import { CountryCode } from '../consts/regions';
3
+
4
+ export function getDefaultRegion(filteredCountryCodes: CountryCode[]): CountryCode {
5
+ const localization = getLocales();
6
+ // console.debug('localization', JSON.stringify(localization, null, 2));
7
+ const id = localization?.[0]?.regionCode;
8
+ if (id) {
9
+ const matchedCountry = filteredCountryCodes.find((country) => country.id === id);
10
+ if (matchedCountry) {
11
+ return matchedCountry;
12
+ }
13
+ }
14
+ return filteredCountryCodes[0];
15
+ }
16
+
17
+ export function getDefaultRegionWithNullableState(
18
+ filteredCountryCodes: CountryCode[]
19
+ ): CountryCode | null {
20
+ const localization = getLocales();
21
+ // console.debug('localization', JSON.stringify(localization, null, 2));
22
+ const id = localization?.[0]?.regionCode;
23
+ if (id) {
24
+ const matchedCountry = filteredCountryCodes.find((country) => country.id === id);
25
+ if (matchedCountry) {
26
+ return matchedCountry;
27
+ }
28
+ }
29
+ return null;
30
+ }