react-native-international-phone-number 0.4.13 → 0.4.15

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.
package/README.md CHANGED
@@ -48,6 +48,7 @@
48
48
  - [With Function Component](#function-component)
49
49
  - [Custom Default Flag](#custom-default-flag)
50
50
  - [Default Phone Number Value](#default-phone-number-value)
51
+ - [Custom Phone Mask](#custom-phone-mask)
51
52
  - [Typescript](#typescript)
52
53
  - [Intermediate Usage](#intermediate-usage)
53
54
  - [Typescript + useRef](#typescript--useref)
@@ -293,6 +294,49 @@ export default function App() {
293
294
  > 1. You need to use a default value with the following format: `+(country callling code)(area code)(number phone)`
294
295
  > 2. The lib has the mechanism to set the flag and mask of the supplied `defaultValue`. However, if the supplied `defaultValue` does not match any international standard, the `input mask of the defaultValue` will be set to "BR" (please make sure that the default value is in the format mentioned above).
295
296
 
297
+ - ### Custom Phone Mask
298
+
299
+ ```tsx
300
+ import React, { useState } from 'react';
301
+ import { View, Text } from 'react-native';
302
+ import { PhoneInput } from 'react-native-international-phone-number';
303
+
304
+ export default function App() {
305
+ const [selectedCountry, setSelectedCountry] = useState(undefined);
306
+ const [inputValue, setInputValue] = useState('');
307
+
308
+ function handleInputValue(phoneNumber) {
309
+ setInputValue(phoneNumber);
310
+ }
311
+
312
+ function handleSelectedCountry(country) {
313
+ setSelectedCountry(country);
314
+ }
315
+
316
+ return (
317
+ <View style={{ width: '100%', flex: 1, padding: 24 }}>
318
+ <PhoneInput
319
+ customMask={['#### ####', '##### ####']}
320
+ value={inputValue}
321
+ onChangePhoneNumber={handleInputValue}
322
+ selectedCountry={selectedCountry}
323
+ onChangeSelectedCountry={handleSelectedCountry}
324
+ />
325
+ <View style={{ marginTop: 10 }}>
326
+ <Text>
327
+ Country:{' '}
328
+ {`${selectedCountry?.name} (${selectedCountry?.cca2})`}
329
+ </Text>
330
+ <Text>
331
+ Phone Number:{' '}
332
+ {`${selectedCountry?.callingCode} ${inputValue}`}
333
+ </Text>
334
+ </View>
335
+ </View>
336
+ );
337
+ }
338
+ ```
339
+
296
340
  - ### Typescript
297
341
 
298
342
  ```tsx
@@ -394,6 +438,8 @@ export default function App() {
394
438
  }
395
439
  ```
396
440
 
441
+ > Observation: Don't use the useRef hook combined with the useState hook to manage the phoneNumber and selectedCountry values. Instead, choose to use just one of them (useRef or useState).
442
+
397
443
  ## Advanced Usage
398
444
 
399
445
  - ### React-Hook-Form + Typescript + Default Phone Number Value
@@ -549,6 +595,7 @@ export default function App() {
549
595
 
550
596
  ## Component Props ([PhoneInputProps](https://github.com/AstrOOnauta/react-native-international-phone-number/blob/master/lib/interfaces/phoneInputProps.ts))
551
597
 
598
+ - `customMask?:` string[];
552
599
  - `defaultValue?:` string;
553
600
  - `value?:` string;
554
601
  - `onChangePhoneNumber?:` (phoneNumber: string) => void;
@@ -560,7 +607,7 @@ export default function App() {
560
607
  - `containerStyle?:` StyleProp<[ViewStyle](https://reactnative.dev/docs/view-style-props)>;
561
608
  - `flagContainerStyle?:` StyleProp<[ViewStyle](https://reactnative.dev/docs/view-style-props)>;
562
609
  - `inputStyle?:` StyleProp<[TextStyle](https://reactnative.dev/docs/text-style-props)>;
563
- - `ref?:` [Ref](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/663f439d11d78b65f1dfd38d120f3728ea2cc207/types/react/index.d.ts#L100)<[IPhoneInputRef](https://github.com/AstrOOnauta/react-native-international-phone-number/blob/master/lib/interfaces/phoneInputeRef.ts)>
610
+ - `ref?:` [Ref](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/663f439d11d78b65f1dfd38d120f3728ea2cc207/types/react/index.d.ts#L100)<[IPhoneInputRef](https://github.com/AstrOOnauta/react-native-international-phone-number/blob/master/lib/interfaces/phoneInputRef.ts)>
564
611
 
565
612
  <br>
566
613
 
package/lib/index.d.ts CHANGED
@@ -1,13 +1,8 @@
1
- import { Ref } from 'react';
2
-
3
1
  import { ICountry } from './interfaces/country';
4
2
  import { IPhoneInputRef } from './interfaces/phoneInputRef';
5
3
  import { PhoneInputProps } from './interfaces/phoneInputProps';
6
4
 
7
- declare function PhoneInput<IPhoneInputRef, PhoneInputProps>(
8
- props: PhoneInputProps,
9
- ref?: Ref<IPhoneInputRef>
10
- ): JSX.Element;
5
+ declare function PhoneInput(props: PhoneInputProps): JSX.Element;
11
6
 
12
7
  declare function getAllCountries(): ICountry[];
13
8
 
package/lib/index.js CHANGED
@@ -38,6 +38,7 @@ const PhoneInput = forwardRef(
38
38
  onChangePhoneNumber,
39
39
  selectedCountry,
40
40
  onChangeSelectedCountry,
41
+ customMask,
41
42
  ...rest
42
43
  },
43
44
  ref
@@ -122,7 +123,8 @@ const PhoneInput = forwardRef(
122
123
  const res = phoneMask(
123
124
  phoneNumber,
124
125
  callingCode ? callingCode : countryValue?.callingCode,
125
- countryValue?.cca2
126
+ countryValue?.cca2,
127
+ customMask ? customMask : null,
126
128
  );
127
129
 
128
130
  if (ref) {
@@ -245,79 +247,91 @@ const PhoneInput = forwardRef(
245
247
  }
246
248
  }, [selectedCountry]);
247
249
 
248
- return (
249
- <View
250
- style={[
251
- withDarkTheme
252
- ? {
253
- ...styles.darkContainer,
254
- backgroundColor: disabled
255
- ? '#858585'
256
- : styles.darkContainer.backgroundColor,
257
- }
258
- : {
259
- ...styles.lightContainer,
260
- backgroundColor: disabled
261
- ? '#E3E3E3'
262
- : styles.lightContainer.backgroundColor,
263
- },
264
- containerStyle ? containerStyle : {},
265
- ]}
266
- onLayout={(e) =>
267
- setContainerWidth(e.nativeEvent.layout.width)
268
- }
269
- >
270
- <CountryPicker
271
- containerButtonStyle={[
272
- flagContainerBase,
273
- countryValue?.cca2 === 'VA' ? { width: 140 } : {},
274
- flagContainerStyle ? flagContainerStyle : {},
275
- ]}
276
- onSelect={onSelect}
277
- withFilter
278
- withAlphaFilter
279
- withCallingCode
280
- withCallingCodeButton={countryValue || defaultCca2}
281
- theme={withDarkTheme ? DARK_THEME : DEFAULT_THEME}
282
- countryCode={
283
- countryValue ? countryValue?.cca2 : defaultCca2
284
- }
285
- modalProps={
286
- disabled || modalDisabled ? { visible: false } : {}
287
- }
288
- />
289
- <TextInput
250
+ if (
251
+ ref &&
252
+ (rest.value ||
253
+ onChangePhoneNumber ||
254
+ selectedCountry ||
255
+ onChangeSelectedCountry)
256
+ ) {
257
+ throw new Error(
258
+ "Error: Don't use the useRef hook combined with the useState hook to manage the phoneNumber and selectedCountry values. Instead, choose to use just one of them (useRef or useState)."
259
+ );
260
+ } else {
261
+ return (
262
+ <View
290
263
  style={[
291
- withDarkTheme ? styles.darkInput : styles.lightInput,
292
- { width: containerWidth - 100 },
293
- inputStyle ? inputStyle : {},
264
+ withDarkTheme
265
+ ? {
266
+ ...styles.darkContainer,
267
+ backgroundColor: disabled
268
+ ? '#858585'
269
+ : styles.darkContainer.backgroundColor,
270
+ }
271
+ : {
272
+ ...styles.lightContainer,
273
+ backgroundColor: disabled
274
+ ? '#E3E3E3'
275
+ : styles.lightContainer.backgroundColor,
276
+ },
277
+ containerStyle ? containerStyle : {},
294
278
  ]}
295
- placeholder={
296
- placeholder ? placeholder : 'Insert your phone number'
279
+ onLayout={(e) =>
280
+ setContainerWidth(e.nativeEvent.layout.width)
297
281
  }
298
- placeholderTextColor={
299
- placeholderTextColor
300
- ? placeholderTextColor
301
- : withDarkTheme
302
- ? '#CCCCCC'
303
- : '#DDDDDD'
304
- }
305
- selectionColor={
306
- selectionColor
307
- ? selectionColor
308
- : withDarkTheme
309
- ? 'rgba(255,255,255, .4)'
310
- : 'rgba(0 ,0 ,0 , .4)'
311
- }
312
- editable={!disabled}
313
- value={inputValue}
314
- onChangeText={onChangeText}
315
- keyboardType="numeric"
316
- ref={textInputRef}
317
- {...rest}
318
- />
319
- </View>
320
- );
282
+ >
283
+ <CountryPicker
284
+ containerButtonStyle={[
285
+ flagContainerBase,
286
+ countryValue?.cca2 === 'VA' ? { width: 140 } : {},
287
+ flagContainerStyle ? flagContainerStyle : {},
288
+ ]}
289
+ onSelect={onSelect}
290
+ withFilter
291
+ withAlphaFilter
292
+ withCallingCode
293
+ withCallingCodeButton={countryValue || defaultCca2}
294
+ theme={withDarkTheme ? DARK_THEME : DEFAULT_THEME}
295
+ countryCode={
296
+ countryValue ? countryValue?.cca2 : defaultCca2
297
+ }
298
+ modalProps={
299
+ disabled || modalDisabled ? { visible: false } : {}
300
+ }
301
+ />
302
+ <TextInput
303
+ style={[
304
+ withDarkTheme ? styles.darkInput : styles.lightInput,
305
+ { width: containerWidth - 100 },
306
+ inputStyle ? inputStyle : {},
307
+ ]}
308
+ placeholder={
309
+ placeholder ? placeholder : 'Insert your phone number'
310
+ }
311
+ placeholderTextColor={
312
+ placeholderTextColor
313
+ ? placeholderTextColor
314
+ : withDarkTheme
315
+ ? '#CCCCCC'
316
+ : '#DDDDDD'
317
+ }
318
+ selectionColor={
319
+ selectionColor
320
+ ? selectionColor
321
+ : withDarkTheme
322
+ ? 'rgba(255,255,255, .4)'
323
+ : 'rgba(0 ,0 ,0 , .4)'
324
+ }
325
+ editable={!disabled}
326
+ value={inputValue}
327
+ onChangeText={onChangeText}
328
+ keyboardType="numeric"
329
+ ref={textInputRef}
330
+ {...rest}
331
+ />
332
+ </View>
333
+ );
334
+ }
321
335
  }
322
336
  );
323
337
 
@@ -6,8 +6,10 @@ import {
6
6
  } from 'react-native';
7
7
 
8
8
  import { ICountry } from './country';
9
+ import { Ref } from 'react';
10
+ import { IPhoneInputRef } from './phoneInputRef';
9
11
 
10
- export interface PhoneInputProps extends TextInputProps {
12
+ interface IPhoneInputPropsWithoutRef extends TextInputProps {
11
13
  placeholder?: string;
12
14
  placeholderTextColor?: string;
13
15
  containerStyle?: StyleProp<ViewStyle>;
@@ -21,4 +23,28 @@ export interface PhoneInputProps extends TextInputProps {
21
23
  onChangePhoneNumber: (phoneNumber: string) => void;
22
24
  selectedCountry: undefined | ICountry;
23
25
  onChangeSelectedCountry: (country: ICountry) => void;
26
+ ref?: never;
27
+ customMask?:Array<string>;
24
28
  }
29
+
30
+ interface IPhoneInputPropsWithRef extends TextInputProps {
31
+ placeholder?: string;
32
+ placeholderTextColor?: string;
33
+ containerStyle?: StyleProp<ViewStyle>;
34
+ flagContainerStyle?: StyleProp<ViewStyle>;
35
+ inputStyle?: StyleProp<TextStyle>;
36
+ withDarkTheme?: boolean;
37
+ disabled?: boolean;
38
+ modalDisabled?: boolean;
39
+ defaultValue?: string;
40
+ value?: never;
41
+ onChangePhoneNumber?: never;
42
+ selectedCountry?: never;
43
+ onChangeSelectedCountry?: never;
44
+ ref: Ref<IPhoneInputRef>;
45
+ customMask?:Array<string>;
46
+ }
47
+
48
+ export type PhoneInputProps =
49
+ | IPhoneInputPropsWithRef
50
+ | IPhoneInputPropsWithoutRef;
@@ -1,22 +1,23 @@
1
1
  import { countries } from './countries';
2
2
 
3
- export default function phoneMask(phoneNumber, callingCode, cca2) {
3
+ export default function phoneMask(phoneNumber, callingCode, cca2, customMask) {
4
4
  let matrix = '';
5
5
 
6
6
  countries.forEach((item) => {
7
7
  const newCode = item.callingCode.replace(/[\s#]/g, '');
8
+ const phoneMask = Array.isArray(customMask) && customMask || item.phoneMasks;
8
9
 
9
10
  if (callingCode && callingCode.includes(newCode)) {
10
- if (item.phoneMasks.length === 1) {
11
+ if (phoneMask.length === 1) {
11
12
  if (cca2 !== 'CA' && cca2 !== 'US' && cca2 !== 'IT') {
12
- matrix = item.phoneMasks[0].replace(/[0-9]/g, '').trim();
13
+ matrix = phoneMask[0].replace(/[0-9]/g, '').trim();
13
14
  }
14
- } else if (item.phoneMasks.length > 1) {
15
+ } else if (phoneMask.length > 1) {
15
16
  let hasDifferentLengthsOfPhoneNumbers = false;
16
17
 
17
- for (let i = 0; i < item.phoneMasks.length; i++) {
18
+ for (let i = 0; i < phoneMask.length; i++) {
18
19
  if (
19
- phoneNumber.length > item.phoneMasks[0].length &&
20
+ phoneNumber.length > phoneMask[0].length &&
20
21
  newCode !== '+1'
21
22
  ) {
22
23
  hasDifferentLengthsOfPhoneNumbers = true;
@@ -25,17 +26,17 @@ export default function phoneMask(phoneNumber, callingCode, cca2) {
25
26
 
26
27
  if (!hasDifferentLengthsOfPhoneNumbers) {
27
28
  if (cca2 === 'CA' || cca2 === 'US') {
28
- matrix = item.phoneMasks[0].replace(/\d/g, '#').trim();
29
+ matrix = phoneMask[0].replace(/\d/g, '#').trim();
29
30
  } else {
30
- matrix = item.phoneMasks[0].replace(/[0-9]/g, '').trim();
31
+ matrix = phoneMask[0].replace(/[0-9]/g, '').trim();
31
32
  }
32
33
  } else {
33
- for (let i = 0; i < item.phoneMasks.length; i++) {
34
+ for (let i = 0; i < phoneMask.length; i++) {
34
35
  if (
35
- phoneNumber.length > item.phoneMasks[i].length &&
36
- item.phoneMasks[i + 1]
36
+ phoneNumber.length > phoneMask[i].length &&
37
+ phoneMask[i + 1]
37
38
  ) {
38
- matrix = item.phoneMasks[i + 1]
39
+ matrix = phoneMask[i + 1]
39
40
  .replace(/[0-9]/g, '')
40
41
  .trim();
41
42
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-native-international-phone-number",
3
3
  "author": "AstrOOnauta (https://github.com/AstrOOnauta)",
4
- "version": "0.4.13",
4
+ "version": "0.4.15",
5
5
  "description": "International mobile phone input component with mask for React Native",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/index.d.ts",