Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot use native TextInput methods #62

Open
fbele opened this issue Feb 6, 2024 · 4 comments
Open

Cannot use native TextInput methods #62

fbele opened this issue Feb 6, 2024 · 4 comments
Labels
bug Something isn't working

Comments

@fbele
Copy link

fbele commented Feb 6, 2024

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:

focus()

blur()

The intellisense offers however suggestions as if these methods do exist in the module:

intellisense

How can I manually trigger blur() or input() methods?

Thanks.

@AstrOOnauta AstrOOnauta added the bug Something isn't working label Feb 20, 2024
@AstrOOnauta
Copy link
Owner

Thanks for your issue..I will investigate this case...

🚀 AstrOOnauta 🚀

@fbele
Copy link
Author

fbele commented Feb 26, 2024

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.

@nickcarr51
Copy link

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

@relaxxpls
Copy link

relaxxpls commented May 17, 2024

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;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants