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

Issue with Stripe card component on RN v0.74 #775

Open
Andrerm124 opened this issue Jan 23, 2025 · 15 comments · May be fixed by #777
Open

Issue with Stripe card component on RN v0.74 #775

Andrerm124 opened this issue Jan 23, 2025 · 15 comments · May be fixed by #777
Assignees
Labels
🤖 android Android specific 🐛 bug Something isn't working 🍎 iOS iOS specific KeyboardAwareScrollView 📜 Anything related to KeyboardAwareScrollView component

Comments

@Andrerm124
Copy link

Andrerm124 commented Jan 23, 2025

Describe the bug
I've attempted to use this library to improve our keyboard handling in a production application running React Native 0.74.5 and all was going well until I encountered a Stripe card input field . It seems the Keyboard Aware Scroll View isn't detecting focus on this input, and thus not scrolling to ensure it's still visible. This specific input is a Native input, so I thought that was the reason, however I noticed that it was multiple inputs living inside of a horizontal scroll view, so did some testing with a regular input inside a horizontal scroll view which turns out it doesn't seem to be working, so may be the root cause.

I did a bit more digging, and both the native Stripe input and an input within a horizontal scrollview seems to be working on RN v0.77, so I created a new barebones project with the same RN version of my main project and found that it no longer works.
I know React Native 0.74 is an older version and may no longer be receiving any love, but currently we don't have the capacity to upgrade our project (It's rather large) and so far this library has been excellent at fitting our needs!

From my testing, this issue seems present on both only iOS and Android

Edit: This issue is affecting iOS only. There was a bug with my underlying code that caused Android to behave incorrectly. This issue is present for iOS.

Code snippet
Repo below

Repo for reproducing
Example repo

To Reproduce
Steps to reproduce the behaviour:

  1. Install NPM packages
  2. Install Pods
  3. Run the app (npx react-native run:ios)
  4. Scroll down and notice how the 3 different inputs differ (First input detects focus, bottom two do not)

Expected behavior
I would expect all inputs to have their focus detected, and thus have the Keyboard Aware Scroll View move to show them

Screenshots
Video example

Screen.Recording.2025-01-23.at.18.32.20.mov

Smartphone (please complete the following information):

  • Desktop OS: MacOS 14.6.1
  • Device: iPhone 13 Pro Max. Samsung Galaxy S10+
  • OS: iOS 17.5 + Android (Not sure version)
  • RN version: 0.74.5
  • RN architecture: old
  • JS engine: Hermes
  • Library version: 1.15.2
@Andrerm124
Copy link
Author

I also just wanted to put a sidenote: I've noticed your responsiveness to activity on this project and love how dedicated you are. You've made a brilliant library and should be proud 🙌

@kirillzyusko
Copy link
Owner

@Andrerm124 I think I just don't detect a ScrollView as a horizontal one and treat it as a vertical one and send a wrong parentScrollViewTarget and ignore those events: https://github.com/kirillzyusko/react-native-keyboard-controller/blob/main/ios/extensions/UIResponder.swift#L67

Let me check your reproduction and I will come back to you 👀 Thank you for preparing a reproduction example 😊

Issue is reproducible on Android as well?

@kirillzyusko kirillzyusko added KeyboardAwareScrollView 📜 Anything related to KeyboardAwareScrollView component 🐛 bug Something isn't working 🤖 android Android specific 🍎 iOS iOS specific labels Jan 23, 2025
@Andrerm124
Copy link
Author

Thanks for the quick reply!
Yeah it’s reproducible on Android, though I only tested it with my main project, not specifically with that example repo I provided

@kirillzyusko
Copy link
Owner

@Andrerm124 okay, alright, will try to look into it 👀

@Andrerm124
Copy link
Author

Andrerm124 commented Jan 23, 2025

@kirillzyusko I'm awfully sorry, it seems there was a different issue in my main project causing Android to fail.
I've just done a sanity check and it seems the Keyboard Aware Scroll View works as intended on Android!

I will update the opening issue to correct this! Sorry for the confusion

Edit: Doing more research into this, as it may still be an issue

@Andrerm124
Copy link
Author

Andrerm124 commented Jan 23, 2025

Seems my sanity check wasn't thorough enough - While Android is able to detect focus on Horizontal ScrollViews, it doesn't seem to detect focus for the Stripe CardField component.

From my research, it seems like the Stripe library is extending the native EditText component with these custom inputs, which aren't detecting focus:

  • CardNumberEditText
  • ExpiryDateEditText
  • CvcEditText
  • PostalCodeEditText

Some potentially useful data:
Stripe native android Card Widget (The component that holds the multiple inputs)
Stripe native android Card Number Edit Text

Screen recording:

Screen.Recording.2025-01-23.at.20.16.17.mov

@kirillzyusko kirillzyusko removed the 🤖 android Android specific label Jan 23, 2025
@kirillzyusko
Copy link
Owner

kirillzyusko commented Jan 24, 2025

Android

Well @Andrerm124 Since stripe uses its own subclasses of EditText, then it's highly likely that my casting to ReactEditText fails and the filed becomes "invisible". But in a reality it's not needed and I removed that overcasting in #776 - hopefully it can resolve the problem on Android 🤞

I can not verify the fix, because in your example project on Android I'm constantly getting:

Image

Have you seen this error? Can you try to use my PR and check if it solves the problem?

Looks like I'm getting this error when try to render <CardField style={{width: '100%', height: 50, borderWidth: 1}} /> 🤔

iOS

I was right in thinking that the condition is not working in your case. I'm trying to come up with a better solution, but basically the problem is that in your case scroll view size is actually smaller, than screen width (scroll view layout). So I treat it as a vertical scroll view (because content is not exceeding layout width). And then condition:

        // input belongs to ScrollView
        if (layout.value?.parentScrollViewTarget !== scrollViewTarget.value) {
          return 0;
        }

Prevents scrolling of a ScrollView (you can remove this condition and I'm pretty sure it will start working. But I'll spend more time investigating this!

@Andrerm124
Copy link
Author

@kirillzyusko I've updated my reproduction repository to fix the Android issue, so you should hopefully be able to test that properly if you pull the latest main 🙂

Will do some testing in an hour or two to see if your PR fixes the problem on Android, and will test whether removing that code block fixes iOS 🙂

@kirillzyusko kirillzyusko changed the title Issue with Horizontal ScrollView on RN v0.74 Issue with Stripe card component on RN v0.74 Jan 24, 2025
@kirillzyusko kirillzyusko added the 🤖 android Android specific label Jan 24, 2025
@kirillzyusko
Copy link
Owner

Okay, on iOS problem is a little bit different 🤔
On iOS stripe input field is also a native component, and .reactViewTag doesn't exist there. On RN 0.77 you most likely run a new architecture, and you read tag property (instead of reactViewTag) and because of that it probably works.
Need to think how that issue can be fixed on paper architecture 🙂

I tested Android and now it's working, but if you can double test - it would be awesome!

@kirillzyusko
Copy link
Owner

Okay, another update. The problem is that first responder (UIView in this case) is double nested:

Image

However in react-native a manager view has only one level nesting. So it seems like it can be any distance (sometimes it's 0 if contextMenuHidden is specified for plain inputs).

I think I have to re-work that traversal algorithm and make it it working with any depth (not strictly 1 or 0) 👀 Will try to look into it today evening!

@kirillzyusko kirillzyusko linked a pull request Jan 24, 2025 that will close this issue
2 tasks
@Andrerm124
Copy link
Author

Andrerm124 commented Jan 24, 2025

On Android I seem to be getting the following error when using the branch your PR is on (Native error):

IllegalArgumentException: Expected receiver of type com.facebook.react.views.textinput.ReactEditText, but got com.stripe.android.view.CardNumberEditText

Key stack trace:
at com.reactnativekeyboardcontroller.extensions.EditTextKt.addOnTextChangedListener(EditText.kt:64)
at > com.reactnativekeyboardcontroller.listeners.FocusedInputObserver.focusListener$lambda$2(FocusedInputObserver.kt:112)
at com.reactnativekeyboardcontroller.listeners.FocusedInputObserver.$r8$lambda$moq4fpwglA5MuwphX7JaNaqI7bk(Unknown Source:0)

Edit: Seems there was an update to the branch - Testing now

@Andrerm124
Copy link
Author

^ Updated branch seems to fix the problem. Working as expected on Android now! 🎉

@kirillzyusko
Copy link
Owner

Cool, then I'll merge Android PR 🎉

kirillzyusko added a commit that referenced this issue Jan 24, 2025
## 📜 Description

Cast to base `EditText` class whenever it's possible.

## 💡 Motivation and Context

If you deal with native SDKs (i. e. Stripe), then in such SDKs they may
inherit their component from native `EditText` and simply expose them to
JS layer. Casting to `ReactEditText` will eventually fail and part of
this library will not be working (everything about tracking focused
input).

So in this PR I decided to cast everything to `EditText`. Conditional
casting will be only in two places `focus` method and in reflection in
`addTextChangedListener`. But in the last method I still can get a
crash: `Expected receiver of type
com.facebook.react.views.textinput.ReactEditText, but got
com.stripe.android.view.CardNumberEditText`, so to overcome this problem
I decided to handle that exception and call original method.

Resolves android issue in
#775

## 📢 Changelog

<!-- High level overview of important changes -->
<!-- For example: fixed status bar manipulation; added new types
declarations; -->
<!-- If your changes don't affect one of platform/language below - then
remove this platform/language -->

### Android

- cast to `EditText` instead of `ReactEditText` whenever it's possible;
- handle `IllegalArgumentException` in `addOnTextChangedListener`. 

## 🤔 How Has This Been Tested?

Tested on Medium Phone API 35 emulator.

## 📸 Screenshots (if appropriate):

Sorry, but emulator is really laggy 😬 


https://github.com/user-attachments/assets/08024fcc-6233-4fca-97f9-d5c6dfdfc479

## 📝 Checklist

- [x] CI successfully passed
- [x] I added new mocks and corresponding unit-tests if library API was
changed
@kirillzyusko
Copy link
Owner

I found a solution for this problem on iOS in: #777

But the problem is that KeyboardController.dismiss doesn't work, which means that I don't detect the input correctly. While the PR from above solves the problem (with KeyboardAwareScrollView), I still would like to spend a little bit more time and try to find out potentially better solutions 👀

@Andrerm124
Copy link
Author

This is amazing news! Thank you for spending so much time on this problem. If there’s anything I can do to help out with alternative solutions do let me know (Though I’m not particular good with iOS development 😅)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🤖 android Android specific 🐛 bug Something isn't working 🍎 iOS iOS specific KeyboardAwareScrollView 📜 Anything related to KeyboardAwareScrollView component
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants