
Security News
/Research
Wallet-Draining npm Package Impersonates Nodemailer to Hijack Crypto Transactions
Malicious npm package impersonates Nodemailer and drains wallets by hijacking crypto transactions across multiple blockchains.
react-native-international-phone-number
Advanced tools
International mobile phone input component with mask for React Native
$ npm i --save react-native-international-phone-number
OR
$ yarn add react-native-international-phone-number
Create a react-native.config.js
file at the root of your react-native project with:
module.exports = {
project: {
ios: {},
android: {},
},
assets: [
'./node_modules/react-native-country-select/lib/assets/fonts',
],
};
Then link the font to your native projects with:
npx react-native-asset
npx expo install expo-font
;expo-font
: import { useFonts } from 'expo-font';
...
useFonts({
'TwemojiMozilla': require('./node_modules/react-native-country-select/lib/assets/fonts/TwemojiMozilla.woff2'),
});
...
Observation: you need to recompile your project after adding new fonts.
import React from 'react';
import { View, Text } from 'react-native';
import PhoneInput, { isValidPhoneNumber } from 'react-native-international-phone-number';
export class App extends React.Component {
constructor(props) {
super(props)
this.state = {
selectedCountry: null,
inputValue: ''
}
}
function handleSelectedCountry(country) {
this.setState({
selectedCountry: country
})
}
function handleInputValue(phoneNumber) {
this.setState({
inputValue: phoneNumber
})
}
render(){
return (
<View style={{ width: '100%', flex: 1, padding: 24 }}>
<PhoneInput
value={this.state.inputValue}
onChangePhoneNumber={this.handleInputValue}
selectedCountry={this.state.selectedCountry}
onChangeSelectedCountry={this.handleSelectedCountry}
/>
<View style={{ marginTop: 10 }}>
<Text>
Country:{' '}
{`${this.state.selectedCountry?.translations?.eng?.common} (${this.state.selectedCountry?.cca2})`}
</Text>
<Text>
Phone Number: {`${this.state.selectedCountry?.idd?.root} ${this.state.inputValue}`}
</Text>
<Text>
isValid:{' '}
{isValidPhoneNumber(this.state.inputValue, this.state.selectedCountry)
? 'true'
: 'false'}
</Text>
</View>
</View>
);
}
}
import React, {useState} from 'react';
import {View, Text} from 'react-native';
import PhoneInput, {
isValidPhoneNumber,
} from 'react-native-international-phone-number';
export default function App() {
const [selectedCountry, setSelectedCountry] = useState(null);
const [inputValue, setInputValue] = useState('');
function handleInputValue(phoneNumber) {
setInputValue(phoneNumber);
}
function handleSelectedCountry(country) {
setSelectedCountry(country);
}
return (
<View style={{width: '100%', flex: 1, padding: 24}}>
<PhoneInput
value={inputValue}
onChangePhoneNumber={handleInputValue}
selectedCountry={selectedCountry}
onChangeSelectedCountry={handleSelectedCountry}
/>
<View style={{marginTop: 10}}>
<Text>
Country:{' '}
{`${selectedCountry?.translations?.eng?.common} (${selectedCountry?.cca2})`}
</Text>
<Text>
Phone Number: {`${selectedCountry?.idd?.root} ${inputValue}`}
</Text>
<Text>
isValid:{' '}
{isValidPhoneNumber(inputValue, selectedCountry) ? 'true' : 'false'}
</Text>
</View>
</View>
);
}
import React, {useState} from 'react';
import {View, Text} from 'react-native';
import PhoneInput, {
ICountry,
isValidPhoneNumber,
} from 'react-native-international-phone-number';
export default function App() {
const [selectedCountry, setSelectedCountry] = useState<null | ICountry>(null);
const [inputValue, setInputValue] = useState<string>('');
function handleInputValue(phoneNumber: string) {
setInputValue(phoneNumber);
}
function handleSelectedCountry(country: ICountry) {
setSelectedCountry(country);
}
return (
<View style={{width: '100%', flex: 1, padding: 24}}>
<PhoneInput
value={inputValue}
onChangePhoneNumber={handleInputValue}
selectedCountry={selectedCountry}
onChangeSelectedCountry={handleSelectedCountry}
/>
<View style={{marginTop: 10}}>
<Text>
Country:{' '}
{`${selectedCountry?.translations?.eng?.common} (${selectedCountry?.cca2})`}
</Text>
<Text>
Phone Number: {`${selectedCountry?.idd?.root} ${inputValue}`}
</Text>
<Text>
isValid:{' '}
{isValidPhoneNumber(inputValue, selectedCountry) ? 'true' : 'false'}
</Text>
</View>
</View>
);
}
import React, {useRef} from 'react';
import {View, Text} from 'react-native';
import PhoneInput, {
ICountry,
IPhoneInputRef,
} from 'react-native-international-phone-number';
export default function App() {
const phoneInputRef = useRef<IPhoneInputRef>(null);
function onSubmitRef() {
Alert.alert(
'Intermediate Result',
`Country: ${inputRef.current?.selectedCountry?.translations?.eng?.common} \nPhone Number: ${inputRef.current?.fullPhoneNumber} \nisValid: ${inputRef.current?.isValid}`,
);
}
return (
<View style={{width: '100%', flex: 1, padding: 24}}>
<PhoneInput ref={phoneInputRef} />
<TouchableOpacity
style={{
width: '100%',
paddingVertical: 12,
backgroundColor: '#2196F3',
borderRadius: 4,
marginTop: 10,
}}
onPress={onSubmit}>
<Text
style={{
color: '#F3F3F3',
textAlign: 'center',
fontSize: 16,
fontWeight: 'bold',
}}>
Submit
</Text>
</TouchableOpacity>
</View>
);
}
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).
import React, {useState, useEffect} from 'react';
import {View, Text, TouchableOpacity, Alert} from 'react-native';
import PhoneInput, {
ICountry,
isValidPhoneNumber,
} from 'react-native-international-phone-number';
import {Controller, FieldValues} from 'react-hook-form';
interface FormProps extends FieldValues {
phoneNumber: string;
}
export default function App() {
const [selectedCountry, setSelectedCountry] = useState<undefined | ICountry>(
undefined,
);
function handleSelectedCountry(country: ICountry) {
setSelectedCountry(country);
}
function onSubmit(form: FormProps) {
const phoneNumber = `${selectedCountry?.idd?.root} ${form.phoneNumber}`;
const isValid = isValidPhoneNumber(
form.phoneNumber,
selectedCountry as ICountry,
);
Alert.alert(
'Advanced Result',
`Country: ${selectedCountry?.translations?.eng?.common} \nPhone Number: ${phoneNumber} \nisValid: ${isValid}`,
);
}
return (
<View style={{width: '100%', flex: 1, padding: 24}}>
<Controller
name="phoneNumber"
control={control}
render={({field: {onChange, value}}) => (
<PhoneInput
defaultValue="+12505550199"
value={value}
onChangePhoneNumber={onChange}
selectedCountry={selectedCountry}
onChangeSelectedCountry={handleSelectedCountry}
/>
)}
/>
<TouchableOpacity
style={{
width: '100%',
paddingVertical: 12,
backgroundColor: '#2196F3',
borderRadius: 4,
}}
onPress={handleSubmit(onSubmit)}>
<Text
style={{
color: '#F3F3F3',
textAlign: 'center',
fontSize: 16,
fontWeight: 'bold',
}}>
Submit
</Text>
</TouchableOpacity>
</View>
);
}
Observations:
- You need to use a default value with the following format:
+(country callling code)(area code)(number phone)
- The lib has the mechanism to set the flag and mask of the supplied
defaultValue
. However, if the supplieddefaultValue
does not match any international standard, theinput mask of the defaultValue
will be set to "BR" (please make sure that the default value is in the format mentioned above).
Property | Type | Description |
---|---|---|
container | ViewStyle | Main input container |
flagContainer | ViewStyle | Flag and dropdown container |
flag | TextStyle | Flag emoji styling |
caret | TextStyle | Dropdown arrow |
divider | ViewStyle | Separator line |
callingCode | TextStyle | Country calling code |
input | TextStyle | Phone number input |
Property | Type | Description |
---|---|---|
backdrop | ViewStyle | Modal background overlay |
container | ViewStyle | Modal main container |
content | ViewStyle | Modal content area |
dragHandleContainer | ViewStyle | Drag Handle area |
dragHandleIndicator | ViewStyle | Drag Handle Indicator |
searchContainer | ViewStyle | Search input wrapper |
searchInput | TextStyle | Search input field |
list | ViewStyle | Countries list container |
countryItem | ViewStyle | Individual country row |
flag | TextStyle | Country flag in list |
countryInfo | ViewStyle | Country details container |
callingCode | TextStyle | Calling code in list |
countryName | TextStyle | Country name in list |
sectionTitle | TextStyle | Section headers |
closeButton | ViewStyle | Close button container |
closeButtonText | TextStyle | Close button text |
countryNotFoundContainer | ViewStyle | No results container |
countryNotFoundMessage | TextStyle | No results message |
Prop | Type | Description |
---|---|---|
theme | ITheme | Theme configuration for the component |
language | ILanguage | Language for country names and UI |
defaultValue | string | Default phone number value (format: +(country code)(area code)(number) ) |
value | string | Controlled phone number value |
onChangePhoneNumber | (phoneNumber: string) => void | Callback when phone number changes |
defaultCountry | ICountryCca2 | Default selected country (ISO 3166-1 alpha-2) |
selectedCountry | ICountry | Currently selected country object |
onChangeSelectedCountry | (country: ICountry) => void | Callback when country selection changes |
placeholder | string | Placeholder text for phone input |
phoneInputPlaceholderTextColor | string | Color of placeholder text |
phoneInputSelectionColor | string | Color of text selection |
phoneInputStyles | IPhoneInputStyles | Custom styles for phone input component |
modalStyles | ICountrySelectStyles | Custom styles for country selection modal |
disabled | boolean | Disable the entire phone input |
modalDisabled | boolean | Disable only the country selection modal |
customMask | string | Custom phone number mask (format like this: (###) ###-#### ) |
visibleCountries | ICountryCca2[] | Array of country codes to show in modal |
hiddenCountries | ICountryCca2[] | Array of country codes to hide from modal |
popularCountries | ICountryCca2[] | Array of country codes to show in popular section |
customCaret | () => ReactNode | Custom dropdown arrow component |
rtl | boolean | Enable right-to-left layout |
isFullScreen | boolean | Show modal in full screen mode |
modalType | 'bottomSheet' | 'popup' | Type of modal presentation |
modalDragHandleIndicatorComponent | () => ReactNode | Custom drag handle indicator component |
modalSearchInputPlaceholderTextColor | string | Color of modal search placeholder text |
modalSearchInputPlaceholder | string | Placeholder text for modal search input |
modalSearchInputSelectionColor | string | Color of modal search text selection |
modalPopularCountriesTitle | string | Title for popular countries section |
modalAllCountriesTitle | string | Title for all countries section |
modalSectionTitleComponent | () => ReactNode | Custom section title component |
modalCountryItemComponent | () => ReactNode | Custom country item component |
modalCloseButtonComponent | () => ReactNode | Custom close button component |
modalSectionTitleDisabled | boolean | Disable section titles in modal |
modalNotFoundCountryMessage | string | Message when no countries found |
disabledModalBackdropPress | boolean | Disable modal close on backdrop press |
removedModalBackdrop | boolean | Remove modal backdrop entirely |
onModalBackdropPress | () => void | Callback when modal backdrop is pressed |
onModalRequestClose | () => void | Callback when modal close is requested |
showModalSearchInput | boolean | Show search input in modal |
showModalCloseButton | boolean | Show close button in modal |
showModalScrollIndicator | boolean | Show scroll indicator in modal |
ref | Ref<IPhoneInputRef> | Ref to access component methods |
Function | Parameters | Return Type | Description |
---|---|---|---|
getAllCountries | () | ICountry[] | Returns an array of all available countries |
getCountriesByCallingCode | (callingCode: string) | ICountry[] | undefined | Returns countries that match the given calling code |
getCountryByCca2 | (cca2: string) | ICountry | undefined | Returns a country by its ISO 3166-1 alpha-2 code |
getCountriesByName | (name: string, language: ILanguage) | ICountry[] | undefined | Returns countries that match the given name in the specified language |
getCountryByPhoneNumber | (phoneNumber: string) | ICountry | undefined | Returns the country that matches the given phone number |
isValidPhoneNumber | (phoneNumber: string, country: ICountry) | boolean | Validates if a phone number is valid for the given country |
The language
prop supports the following values:
Code | Language |
---|---|
ara | Arabic |
bel | Belarusian |
bre | Breton |
bul | Bulgarian |
ces | Czech |
deu | German |
ell | Greek |
eng | English |
est | Estonian |
fin | Finnish |
fra | French |
heb | Hebrew |
hrv | Croatian |
hun | Hungarian |
ita | Italian |
jpn | Japanese |
kor | Korean |
nld | Dutch |
per | Persian |
pol | Polish |
por | Portuguese |
ron | Romanian |
rus | Russian |
slk | Slovak |
spa | Spanish |
srp | Serbian |
swe | Swedish |
tur | Turkish |
ukr | Ukrainian |
urd | Urdu |
zho | Chinese |
zho-Hans | Simplified Chinese |
zho-Hant | Traditional Chinese |
When utilizing this package, you may need to target the PhoneInput component in your automated tests. To facilitate this, we provide a testID props for the PhoneInput component. The testID can be integrated with popular testing libraries such as @testing-library/react-native or Maestro. This enables you to efficiently locate and interact with PhoneInput elements within your tests, ensuring a robust and reliable testing experience.
const phoneInput = getByTestId('countryPickerPhoneInput');
const flagContainerButton = getByTestId('countryPickerFlagContainerButton');
const countrySelect = getByTestId('countrySelectSearchInput');
const countrySelectBackdrop = getByTestId('countrySelectBackdrop');
const countrySelectList = getByTestId('countrySelectList');
const countrySelectSearchInput = getByTestId('countrySelectSearchInput');
const countrySelectItem = getByTestId('countrySelectItem');
const countrySelectCloseButton = getByTestId('countrySelectCloseButton');
Ensure your app is inclusive and usable by everyone by leveraging built-in React Native accessibility features. The accessibility props are covered by this package.
$ git clone https://github.com/AstrOOnauta/react-native-international-phone-number.git
Repair, Update and Enjoy ๐ ๏ธ๐งโ๏ธ
Create a new PR to this repository
FAQs
International mobile phone input component with mask for React Native
We found that react-native-international-phone-number demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.ย It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
/Research
Malicious npm package impersonates Nodemailer and drains wallets by hijacking crypto transactions across multiple blockchains.
Security News
This episode explores the hard problem of reachability analysis, from static analysis limits to handling dynamic languages and massive dependency trees.
Security News
/Research
Malicious Nx npm versions stole secrets and wallet info using AI CLI tools; Socketโs AI scanner detected the supply chain attack and flagged the malware.