Last active
June 4, 2021 08:11
-
-
Save aganov/eaffbb691848299458df449a58de3979 to your computer and use it in GitHub Desktop.
stripe-react-native CardField focus blur clear
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/node_modules/@stripe/stripe-react-native/android/src/main/java/com/reactnativestripesdk/StripeSdkCardView.kt b/node_modules/@stripe/stripe-react-native/android/src/main/java/com/reactnativestripesdk/StripeSdkCardView.kt | |
index f13b188..37568f9 100644 | |
--- a/node_modules/@stripe/stripe-react-native/android/src/main/java/com/reactnativestripesdk/StripeSdkCardView.kt | |
+++ b/node_modules/@stripe/stripe-react-native/android/src/main/java/com/reactnativestripesdk/StripeSdkCardView.kt | |
@@ -51,6 +51,27 @@ class StripeSdkCardView(private val context: ThemedReactContext) : FrameLayout(c | |
} | |
} | |
+ fun requestFocusFromJS() { | |
+ val binding = CardInputWidgetBinding.bind(mCardWidget) | |
+ binding.cardNumberEditText.requestFocus() | |
+ binding.cardNumberEditText.showSoftKeyboard() | |
+ } | |
+ | |
+ fun requestBlurFromJS() { | |
+ val binding = CardInputWidgetBinding.bind(mCardWidget) | |
+ binding.cardNumberEditText.hideSoftKeyboard() | |
+ binding.cardNumberEditText.clearFocus() | |
+ } | |
+ | |
+ fun requestClearFromJS() { | |
+ val binding = CardInputWidgetBinding.bind(mCardWidget) | |
+ binding.cardNumberEditText.setText("") | |
+ binding.cvcEditText.setText("") | |
+ binding.expiryDateEditText.setText("") | |
+ if (mCardWidget.postalCodeEnabled) { | |
+ binding.postalCodeEditText.setText("") | |
+ } | |
+ } | |
fun setCardStyle(value: ReadableMap) { | |
val binding = CardInputWidgetBinding.bind(mCardWidget) | |
@@ -237,3 +258,12 @@ fun View.showSoftKeyboard() { | |
} | |
} | |
} | |
+ | |
+fun View.hideSoftKeyboard() { | |
+ post { | |
+ if (this.requestFocus()) { | |
+ val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager? | |
+ imm?.hideSoftInputFromWindow(windowToken, 0) | |
+ } | |
+ } | |
+} | |
\ No newline at end of file | |
diff --git a/node_modules/@stripe/stripe-react-native/android/src/main/java/com/reactnativestripesdk/StripeSdkCardViewManager.kt b/node_modules/@stripe/stripe-react-native/android/src/main/java/com/reactnativestripesdk/StripeSdkCardViewManager.kt | |
index 0f54799..cd60feb 100644 | |
--- a/node_modules/@stripe/stripe-react-native/android/src/main/java/com/reactnativestripesdk/StripeSdkCardViewManager.kt | |
+++ b/node_modules/@stripe/stripe-react-native/android/src/main/java/com/reactnativestripesdk/StripeSdkCardViewManager.kt | |
@@ -1,5 +1,6 @@ | |
package com.reactnativestripesdk | |
+import com.facebook.react.bridge.ReadableArray | |
import com.facebook.react.bridge.ReadableMap | |
import com.facebook.react.bridge.ReadableNativeMap | |
import com.facebook.react.bridge.WritableMap | |
@@ -63,6 +64,14 @@ class StripeSdkCardViewManager : SimpleViewManager<StripeSdkCardView>() { | |
this.cardViewInstanceMap[CARD_FIELD_INSTANCE_NAME] = null | |
} | |
+ override fun receiveCommand(root: StripeSdkCardView, commandId: String?, args: ReadableArray?) { | |
+ when (commandId) { | |
+ "focus" -> root.requestFocusFromJS() | |
+ "blur" -> root.requestBlurFromJS() | |
+ "clear" -> root.requestClearFromJS() | |
+ } | |
+ } | |
+ | |
fun getCardViewInstance(): StripeSdkCardView? { | |
if (cardViewInstanceMap[CARD_FIELD_INSTANCE_NAME] != null) { | |
return cardViewInstanceMap[CARD_FIELD_INSTANCE_NAME] as StripeSdkCardView | |
diff --git a/node_modules/@stripe/stripe-react-native/ios/CardFieldManager.m b/node_modules/@stripe/stripe-react-native/ios/CardFieldManager.m | |
index 449f92d..afd0575 100644 | |
--- a/node_modules/@stripe/stripe-react-native/ios/CardFieldManager.m | |
+++ b/node_modules/@stripe/stripe-react-native/ios/CardFieldManager.m | |
@@ -3,6 +3,10 @@ | |
#import <React/RCTViewManager.h> | |
@interface RCT_EXTERN_MODULE(CardFieldManager, RCTViewManager) | |
+RCT_EXTERN_METHOD(focus:(nonnull NSNumber*) reactTag) | |
+RCT_EXTERN_METHOD(blur:(nonnull NSNumber*) reactTag) | |
+RCT_EXTERN_METHOD(clear:(nonnull NSNumber*) reactTag) | |
+ | |
RCT_EXPORT_VIEW_PROPERTY(postalCodeEnabled, BOOL) | |
RCT_EXPORT_VIEW_PROPERTY(onCardChange, RCTDirectEventBlock) | |
RCT_EXPORT_VIEW_PROPERTY(onFocusChange, RCTDirectEventBlock) | |
diff --git a/node_modules/@stripe/stripe-react-native/ios/CardFieldManager.swift b/node_modules/@stripe/stripe-react-native/ios/CardFieldManager.swift | |
index a7938f6..c9a8d90 100644 | |
--- a/node_modules/@stripe/stripe-react-native/ios/CardFieldManager.swift | |
+++ b/node_modules/@stripe/stripe-react-native/ios/CardFieldManager.swift | |
@@ -27,4 +27,26 @@ class CardFieldManager: RCTViewManager, CardFieldDelegate { | |
override class func requiresMainQueueSetup() -> Bool { | |
return false | |
} | |
+ | |
+ @objc func focus(_ reactTag: NSNumber) { | |
+ // self.bridge!.uiManager.addUIBlock { (uiManager: RCTUIManager?, viewRegistry: [NSNumber: UIView]?) in | |
+ self.bridge!.uiManager.addUIBlock { (_: RCTUIManager?, viewRegistry: [NSNumber: UIView]?) in | |
+ let view: CardFieldView = (viewRegistry![reactTag] as? CardFieldView)! | |
+ view.focus() | |
+ } | |
+ } | |
+ | |
+ @objc func blur(_ reactTag: NSNumber) { | |
+ self.bridge!.uiManager.addUIBlock { (_: RCTUIManager?, viewRegistry: [NSNumber: UIView]?) in | |
+ let view: CardFieldView = (viewRegistry![reactTag] as? CardFieldView)! | |
+ view.blur() | |
+ } | |
+ } | |
+ | |
+ @objc func clear(_ reactTag: NSNumber) { | |
+ self.bridge!.uiManager.addUIBlock { (_: RCTUIManager?, viewRegistry: [NSNumber: UIView]?) in | |
+ let view: CardFieldView = (viewRegistry![reactTag] as? CardFieldView)! | |
+ view.clear() | |
+ } | |
+ } | |
} | |
diff --git a/node_modules/@stripe/stripe-react-native/ios/CardFieldView.swift b/node_modules/@stripe/stripe-react-native/ios/CardFieldView.swift | |
index a514b31..bfc33a8 100644 | |
--- a/node_modules/@stripe/stripe-react-native/ios/CardFieldView.swift | |
+++ b/node_modules/@stripe/stripe-react-native/ios/CardFieldView.swift | |
@@ -121,6 +121,10 @@ class CardFieldView: UIView, STPPaymentCardTextFieldDelegate { | |
onFocusChange?(["focusedField": "PostalCode"]) | |
} | |
+ func paymentCardTextFieldDidEndEditing(_ textField: STPPaymentCardTextField) { | |
+ onFocusChange?(["focusedField": NSNull()]) | |
+ } | |
+ | |
func paymentCardTextFieldDidChange(_ textField: STPPaymentCardTextField) { | |
if onCardChange != nil { | |
let brand = STPCardValidator.brand(forNumber: textField.cardParams.number ?? "") | |
@@ -167,4 +171,15 @@ class CardFieldView: UIView, STPPaymentCardTextFieldDelegate { | |
// | |
} | |
+ func focus() { | |
+ cardField.becomeFirstResponder() | |
+ } | |
+ | |
+ func blur() { | |
+ cardField.resignFirstResponder() | |
+ } | |
+ | |
+ func clear() { | |
+ cardField.clear() | |
+ } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Based on https://github.com/Agaweb/react-native-stripe | |
import React, { useCallback, useRef, forwardRef, useLayoutEffect, useImperativeHandle } from "react"; | |
import { UIManager, requireNativeComponent } from "react-native"; | |
const CardFieldNative = requireNativeComponent("CardField"); | |
const TextInputState = require("react-native/Libraries/Components/TextInput/TextInputState"); | |
const CardField = forwardRef( | |
({ onCardChange, onFocus, onBlur, cardStyle, placeholder, postalCodeEnabled, ...props }, ref) => { | |
const inputRef = useRef(null); | |
const onCardChangeHandler = useCallback( | |
event => { | |
const card = event.nativeEvent; | |
const data = { | |
last4: card.last4, | |
expiryMonth: card.expiryMonth, | |
expiryYear: card.expiryYear, | |
complete: card.complete, | |
brand: card.brand, | |
}; | |
if (card.hasOwnProperty("postalCode")) { | |
data.postalCode = card.postalCode || ""; | |
} | |
onCardChange?.(data); | |
}, | |
[onCardChange], | |
); | |
const onFocusHandler = useCallback( | |
event => { | |
const { focusedField } = event.nativeEvent; | |
if (focusedField) { | |
TextInputState.focusInput(inputRef.current); | |
onFocus?.(focusedField); | |
} else { | |
onBlur?.(); | |
} | |
}, | |
[onFocus, onBlur], | |
); | |
const focus = () => { | |
UIManager.dispatchViewManagerCommand(findNodeHandle(inputRef.current), "focus", []); | |
}; | |
const blur = () => { | |
UIManager.dispatchViewManagerCommand(findNodeHandle(inputRef.current), "blur", []); | |
}; | |
const clear = () => { | |
UIManager.dispatchViewManagerCommand(findNodeHandle(inputRef.current), "clear", []); | |
}; | |
useImperativeHandle(ref, () => ({ | |
focus, | |
blur, | |
clear, | |
})); | |
useLayoutEffect(() => { | |
const inputRefValue = inputRef.current; | |
if (inputRefValue !== null) { | |
TextInputState.registerInput(inputRefValue); | |
return () => { | |
TextInputState.unregisterInput(inputRefValue); | |
if (TextInputState.currentlyFocusedInput() === inputRefValue) { | |
inputRefValue.blur(); | |
} | |
}; | |
} | |
}, [inputRef]); | |
return ( | |
<CardFieldNative | |
ref={inputRef} | |
onCardChange={onCardChangeHandler} | |
onFocusChange={onFocusHandler} | |
postalCodeEnabled={postalCodeEnabled ?? true} | |
cardStyle={{ | |
backgroundColor: cardStyle?.backgroundColor, | |
borderColor: cardStyle?.borderColor, | |
borderWidth: cardStyle?.borderWidth, | |
borderRadius: cardStyle?.borderRadius, | |
cursorColor: cardStyle?.cursorColor, | |
fontSize: cardStyle?.fontSize, | |
placeholderColor: cardStyle?.placeholderColor, | |
textColor: cardStyle?.textColor, | |
textErrorColor: cardStyle?.textErrorColor, | |
fontFamily: cardStyle?.fontFamily, | |
}} | |
placeholder={{ | |
number: placeholder?.number, | |
expiration: placeholder?.expiration, | |
cvc: placeholder?.cvc, | |
postalCode: placeholder?.postalCode, | |
}} | |
{...props} | |
/> | |
); | |
}, | |
); | |
export default CardField; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment