Closed fbele closed 1 month ago
Thanks for your issue..I will investigate this case...
🚀 AstrOOnauta 🚀
I've also noticed that on iOS devices once a user clicks on the field and it's focused for the input of phone number, there is no way to "unfocus" or blur from the field.
It would be a nice feature for example to be able to tap anywhere out of the field and it would lose the focus from the field.
Running into this issue as well— any progress?
I think the real issue is this separation of a state implementation vs ref implementation, it doesn't really make sense and is sort of a misuse of the ref. The forwarded ref never touches the input, it's just being updated like a state object. The purpose of the ref is to have access to the element itself, so you can focus, blur, etc.
Will try to push up a PR with a fix if I have time, but it does seem like the most ideal fix would be to pass the ref straight through to the input and control the rest of the input with state
To anyone whos not using the ref implementation, use the following patch:
diff --git a/node_modules/react-native-international-phone-number/lib/index.js b/node_modules/react-native-international-phone-number/lib/index.js
index 9646316..5ce05e8 100644
--- a/node_modules/react-native-international-phone-number/lib/index.js
+++ b/node_modules/react-native-international-phone-number/lib/index.js
@@ -73,91 +73,18 @@ const PhoneInput = forwardRef(
const [inputValue, setInputValue] = useState(null);
const [countryValue, setCountryValue] = useState(null);
- const textInputRef = useRef(null);
-
- const refBase = {
- ...textInputRef.current,
- onFocus: textInputRef.current?.focus,
- focus: textInputRef.current?.focus,
- getValue: () => inputValue,
- value: inputValue,
- getFullPhoneNumber: () =>
- `${countryValue?.callingCode} ${inputValue}`,
- fullPhoneNumber: `${countryValue?.callingCode} ${inputValue}`,
- getSelectedCountry: () => countryValue,
- selectedCountry: countryValue,
- props: {
- theme,
- language,
- placeholder,
- placeholderTextColor,
- selectionColor,
- phoneInputStyles,
- modalStyles,
- disabled,
- modalDisabled,
- modalHeight,
- defaultCountry,
- defaultValue,
- onChangePhoneNumber,
- selectedCountry,
- onChangeSelectedCountry,
- customMask,
- showOnly,
- excludedCountries,
- popularCountries,
- modalSearchInputPlaceholder,
- modalSearchInputPlaceholderTextColor,
- modalSearchInputSelectionColor,
- modalNotFoundCountryMessage,
- customCaret,
- ...rest,
- },
- };
-
- function updateRef(phoneNumber, country) {
- if (ref) {
- ref.current = {
- ...refBase,
- getValue: () => phoneNumber,
- value: phoneNumber,
- getFullPhoneNumber: () =>
- `${country?.callingCode} ${phoneNumber}`,
- fullPhoneNumber: `${country?.callingCode} ${phoneNumber}`,
- getSelectedCountry: () => country,
- selectedCountry: country,
- props: {
- ...refBase.props,
- value: phoneNumber,
- selectedCountry: country,
- },
- };
- }
- }
-
function onSelect(country) {
setShow(false);
+ onChangePhoneNumber('');
- if (ref) {
- setInputValue('');
- } else {
- onChangePhoneNumber('');
- }
-
- if (onChangeSelectedCountry || ref) {
+ if (onChangeSelectedCountry) {
const newValue = {
name: country.name,
cca2: country.code,
flag: country.flag,
callingCode: country.dial_code,
};
-
- if (ref) {
- setCountryValue(newValue);
- updateRef('', newValue);
- } else {
- onChangeSelectedCountry(newValue);
- }
+ onChangeSelectedCountry(newValue);
}
}
@@ -167,13 +94,7 @@ const PhoneInput = forwardRef(
if (matchingCountry) {
setDefaultCca2(matchingCountry.cca2);
-
- if (ref) {
- setCountryValue(matchingCountry);
- updateRef('', matchingCountry);
- } else {
- onChangeSelectedCountry(matchingCountry);
- }
+ onChangeSelectedCountry(matchingCountry);
onChangeText(
phoneNumber.replace(matchingCountry.callingCode, ''),
@@ -191,71 +112,34 @@ const PhoneInput = forwardRef(
customMask ? customMask : null
);
- if (ref) {
- setInputValue(res);
- updateRef(res, countryValue);
- } else {
- onChangePhoneNumber(res);
- }
+ onChangePhoneNumber(res);
}
useEffect(() => {
if (!countryValue && !defaultCountry) {
const defaultCountry = getCountryByCca2('BR');
-
- if (ref) {
- setCountryValue(defaultCountry);
- updateRef('', defaultCountry);
- } else {
- onChangeSelectedCountry(defaultCountry);
- }
- } else {
- if (ref) {
- updateRef('', countryValue);
- }
+ onChangeSelectedCountry(defaultCountry);
}
}, []);
useEffect(() => {
if (defaultCountry) {
- if (ref) {
- setCountryValue(getCountryByCca2(defaultCountry));
- updateRef('', getCountryByCca2(defaultCountry));
- } else {
onChangeSelectedCountry(getCountryByCca2(defaultCountry));
- }
}
}, [defaultCountry]);
useEffect(() => {
- if (ref) {
- setInputValue('');
- } else {
- onChangePhoneNumber('');
- }
+ onChangePhoneNumber('');
if (defaultValue) {
const matchingCountry = getCountryByPhoneNumber(defaultValue);
if (matchingCountry) {
setDefaultCca2(matchingCountry.cca2);
-
- if (ref) {
- setCountryValue(matchingCountry);
- updateRef('', matchingCountry);
- } else {
- onChangeSelectedCountry(matchingCountry);
- }
+ onChangeSelectedCountry(matchingCountry);
} else {
setDefaultCca2(null);
-
- if (ref) {
- setCountryValue(null);
- updateRef('', null);
- } else {
- onChangeSelectedCountry(null);
- }
-
+ onChangeSelectedCountry(null);
onChangeText('', null);
console.warn(
@@ -302,158 +186,144 @@ const PhoneInput = forwardRef(
}, [countryValue]);
useEffect(() => {
- if (!ref) {
- setInputValue(rest.value);
- setCountryValue(selectedCountry);
- }
+ setInputValue(rest.value);
+ setCountryValue(selectedCountry);
}, [selectedCountry]);
- if (
- ref &&
- (rest.value ||
- onChangePhoneNumber ||
- selectedCountry ||
- onChangeSelectedCountry)
- ) {
- throw new Error(
- "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)."
- );
- } else {
- return (
- <>
- <View
- style={getContainerStyle(
+ return (
+ <>
+ <View
+ style={getContainerStyle(
+ theme,
+ phoneInputStyles?.container,
+ disabled
+ )}
+ >
+ <TouchableOpacity
+ activeOpacity={disabled || modalDisabled ? 1 : 0.6}
+ onPress={() =>
+ disabled || modalDisabled ? null : setShow(true)
+ }
+ style={getFlagContainerStyle(
theme,
- phoneInputStyles?.container,
- disabled
+ phoneInputStyles?.flagContainer
)}
>
- <TouchableOpacity
- activeOpacity={disabled || modalDisabled ? 1 : 0.6}
- onPress={() =>
- disabled || modalDisabled ? null : setShow(true)
- }
- style={getFlagContainerStyle(
- theme,
- phoneInputStyles?.flagContainer
- )}
- >
- <Text style={getFlagStyle(phoneInputStyles?.flag)}>
- {countryValue?.flag}
- </Text>
- {customCaret || (
- <View style={phoneInputStyles?.caret}>
+ <Text style={getFlagStyle(phoneInputStyles?.flag)}>
+ {countryValue?.flag}
+ </Text>
+ {customCaret || (
+ <View style={phoneInputStyles?.caret}>
+ <View
+ style={{
+ flexDirection: 'row',
+ justifyContent: 'center',
+ paddingTop: 4,
+ }}
+ >
<View
- style={{
- flexDirection: 'row',
- justifyContent: 'center',
- paddingTop: 4,
- }}
- >
- <View
- style={getCaretStyle(
- theme,
- phoneInputStyles?.caret
- )}
- />
- </View>
+ style={getCaretStyle(
+ theme,
+ phoneInputStyles?.caret
+ )}
+ />
</View>
+ </View>
+ )}
+ <View
+ style={getDividerStyle(
+ theme,
+ phoneInputStyles?.divider
)}
- <View
- style={getDividerStyle(
- theme,
- phoneInputStyles?.divider
- )}
- />
- <Text
- style={getFlagTextStyle(
- theme,
- phoneInputStyles?.callingCode
- )}
- >
- {countryValue?.callingCode}
- </Text>
- </TouchableOpacity>
- <TextInput
- style={getInputStyle(theme, phoneInputStyles?.input)}
- placeholder={
- placeholder === '' || placeholder
- ? placeholder
- : getPhoneNumberInputPlaceholder(language || 'en')
- }
- placeholderTextColor={
- placeholderTextColor ||
- (theme === 'dark' ? '#CCCCCC' : '#AAAAAA')
- }
- selectionColor={
- selectionColor ||
- (theme === 'dark'
- ? 'rgba(255,255,255, .4)'
- : 'rgba(0 ,0 ,0 , .4)')
- }
- editable={!disabled}
- value={inputValue}
- onChangeText={onChangeText}
- keyboardType="numeric"
- ref={textInputRef}
- {...rest}
/>
- </View>
- {!disabled && !modalDisabled && show ? (
- <CountryPicker
- show={show}
- lang={language}
- inputPlaceholder={
- modalSearchInputPlaceholder ||
- getSearchInputPlaceholder(language || 'en')
- }
- inputPlaceholderTextColor={
- modalSearchInputPlaceholderTextColor ||
- (theme === 'dark' ? '#CCCCCC' : '#AAAAAA')
- }
- selectionColor={
- modalSearchInputSelectionColor ||
- (theme === 'dark'
- ? 'rgba(255,255,255, .4)'
- : 'rgba(0 ,0 ,0 , .4)')
- }
- searchMessage={
- modalNotFoundCountryMessage ||
- getCountryNotFoundMessage(language || 'en')
- }
- enableModalAvoiding
- style={getCountryPickerStyle(
+ <Text
+ style={getFlagTextStyle(
theme,
- modalHeight,
- modalStyles
+ phoneInputStyles?.callingCode
)}
- pickerButtonOnPress={onSelect}
- onBackdropPress={() => setShow(false)}
- showOnly={showOnly}
- excludedCountries={excludedCountries}
- popularCountries={popularCountries}
- ListHeaderComponent={({ countries, lang, onPress }) => {
- return countries.map((country, index) => {
- return (
- <CountryButton
- key={index}
- item={country}
- name={country?.name?.[lang || 'en']}
- onPress={() => onPress(country)}
- style={getCountryPickerStyle(
- theme,
- modalHeight,
- modalStyles
- )}
- />
- );
- });
- }}
- />
- ) : null}
- </>
- );
- }
+ >
+ {countryValue?.callingCode}
+ </Text>
+ </TouchableOpacity>
+ <TextInput
+ style={getInputStyle(theme, phoneInputStyles?.input)}
+ placeholder={
+ placeholder === '' || placeholder
+ ? placeholder
+ : getPhoneNumberInputPlaceholder(language || 'en')
+ }
+ placeholderTextColor={
+ placeholderTextColor ||
+ (theme === 'dark' ? '#CCCCCC' : '#AAAAAA')
+ }
+ selectionColor={
+ selectionColor ||
+ (theme === 'dark'
+ ? 'rgba(255,255,255, .4)'
+ : 'rgba(0 ,0 ,0 , .4)')
+ }
+ editable={!disabled}
+ value={inputValue}
+ onChangeText={onChangeText}
+ keyboardType="numeric"
+ ref={ref}
+ {...rest}
+ />
+ </View>
+ {!disabled && !modalDisabled && show ? (
+ <CountryPicker
+ show={show}
+ lang={language}
+ inputPlaceholder={
+ modalSearchInputPlaceholder ||
+ getSearchInputPlaceholder(language || 'en')
+ }
+ inputPlaceholderTextColor={
+ modalSearchInputPlaceholderTextColor ||
+ (theme === 'dark' ? '#CCCCCC' : '#AAAAAA')
+ }
+ selectionColor={
+ modalSearchInputSelectionColor ||
+ (theme === 'dark'
+ ? 'rgba(255,255,255, .4)'
+ : 'rgba(0 ,0 ,0 , .4)')
+ }
+ searchMessage={
+ modalNotFoundCountryMessage ||
+ getCountryNotFoundMessage(language || 'en')
+ }
+ enableModalAvoiding
+ style={getCountryPickerStyle(
+ theme,
+ modalHeight,
+ modalStyles
+ )}
+ pickerButtonOnPress={onSelect}
+ onBackdropPress={() => setShow(false)}
+ showOnly={showOnly}
+ excludedCountries={excludedCountries}
+ popularCountries={popularCountries}
+ ListHeaderComponent={({ countries, lang, onPress }) => {
+ return countries.map((country, index) => {
+ return (
+ <CountryButton
+ key={index}
+ item={country}
+ name={country?.name?.[lang || 'en']}
+ onPress={() => onPress(country)}
+ style={getCountryPickerStyle(
+ theme,
+ modalHeight,
+ modalStyles
+ )}
+ />
+ );
+ });
+ }}
+ />
+ ) : null}
+ </>
+ );
}
);
diff --git a/node_modules/react-native-international-phone-number/lib/interfaces/phoneInputProps.ts b/node_modules/react-native-international-phone-number/lib/interfaces/phoneInputProps.ts
index 3dfa8f3..e5b762b 100644
--- a/node_modules/react-native-international-phone-number/lib/interfaces/phoneInputProps.ts
+++ b/node_modules/react-native-international-phone-number/lib/interfaces/phoneInputProps.ts
@@ -33,22 +33,10 @@ interface BasePhoneInput extends TextInputProps {
customCaret?: ReactNode;
}
-interface IPhoneInputPropsWithoutRef extends BasePhoneInput {
+export interface PhoneInputProps extends BasePhoneInput {
value: string;
onChangePhoneNumber: (phoneNumber: string) => void;
selectedCountry: ICountry | undefined | null;
onChangeSelectedCountry: (country: ICountry) => void;
- ref?: never;
-}
-
-interface IPhoneInputPropsWithRef extends BasePhoneInput {
- value?: never;
- onChangePhoneNumber?: never;
- selectedCountry?: never;
- onChangeSelectedCountry?: never;
ref?: Ref<IPhoneInputRef>;
}
-
-export type PhoneInputProps =
- | IPhoneInputPropsWithRef
- | IPhoneInputPropsWithoutRef;
Please check the new versio v0.8.0 and try again. Sorry for my late.
Let me know if this problem continues...
🚀AstrOOnauta 🚀
Hi,
I'm trying to use the module as intermediate usage in order to manually focus() or blur() the input but I am always getting an error that the methods do not exist:
The intellisense offers however suggestions as if these methods do exist in the module:
How can I manually trigger blur() or input() methods?
Thanks.