Skip to content

Instantly share code, notes, and snippets.

@aganov
Last active June 4, 2021 08:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aganov/eaffbb691848299458df449a58de3979 to your computer and use it in GitHub Desktop.
Save aganov/eaffbb691848299458df449a58de3979 to your computer and use it in GitHub Desktop.
stripe-react-native CardField focus blur clear
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()
+ }
}
// 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