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

BREAKING: add customization options to CardForm on Android only #849

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
## Unreleased

- [#890](https://github.com/stripe/stripe-react-native/pull/890) BREAKING CHANGE: Changed parameters for: `createPaymentMethod`, `confirmPayment`, `confirmSetupIntent`, `collectBankAccountForPayment`, and `collectBankAccountForSetup`. Please read [this migration guide](./docs/upgrading-from-v0.7.0.md) for details.
- Renamed `type` field tp `paymentMethodType` on `PaymentMethod.Result`, `PaymentIntent.Result`, and `SetupIntent.Result` (result of `createPaymentMethod`, `retrieveSetupIntent`, `confirmSetupIntent`, `confirmPayment`, `collectBankAccountForPayment`, `collectBankAccountForSetup`, `verifyMicrodepositsForPayment`, and `verifyMicrodepositsForSetup`).
- Renamed `type` field to `paymentMethodType` on `PaymentMethod.Result`, `PaymentIntent.Result`, and `SetupIntent.Result` (result of `createPaymentMethod`, `retrieveSetupIntent`, `confirmSetupIntent`, `confirmPayment`, `collectBankAccountForPayment`, `collectBankAccountForSetup`, `verifyMicrodepositsForPayment`, and `verifyMicrodepositsForSetup`).
- [#849](https://github.com/stripe/stripe-react-native/pull/849) BREAKING CHANGE: Renamed `placeholder` prop on `<CardField />` and `<CardForm />` to `placeholders`.
- [#849](https://github.com/stripe/stripe-react-native/pull/849) Feat: Added customized styling options to `<CardForm />` on Android.

## 0.7.0

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export default function PaymentScreen() {
return (
<CardField
postalCodeEnabled={true}
placeholder={{
placeholders={{
number: '4242 4242 4242 4242',
}}
cardStyle={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ class CardFieldViewManager : SimpleViewManager<CardFieldView>() {
view.setCardStyle(cardStyle)
}

@ReactProp(name = "placeholder")
fun setPlaceHolders(view: CardFieldView, placeholder: ReadableMap) {
view.setPlaceHolders(placeholder)
@ReactProp(name = "placeholders")
fun setPlaceHolders(view: CardFieldView, placeholders: ReadableMap) {
view.setPlaceHolders(placeholders)
}

override fun createViewInstance(reactContext: ThemedReactContext): CardFieldView {
Expand Down
127 changes: 98 additions & 29 deletions android/src/main/java/com/reactnativestripesdk/CardFormView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ package com.reactnativestripesdk

import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.Typeface
import android.os.Build
import android.view.View
import android.view.View.OnFocusChangeListener
import android.widget.FrameLayout
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.UIManagerModule
import com.facebook.react.uimanager.events.EventDispatcher
import com.google.android.material.shape.CornerFamily
import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.shape.ShapeAppearanceModel
import com.stripe.android.databinding.CardMultilineWidgetBinding
import com.stripe.android.databinding.StripeCardFormViewBinding
import com.stripe.android.model.Address
Expand Down Expand Up @@ -38,35 +42,31 @@ class CardFormView(context: ThemedReactContext) : FrameLayout(context) {
}

fun setPostalCodeEnabled(value: Boolean) {
val cardFormView = StripeCardFormViewBinding.bind(cardForm)
val visibility = if (value) View.VISIBLE else View.GONE

cardFormView.cardMultilineWidget.postalCodeRequired = false
cardFormView.postalCodeContainer.visibility = visibility
cardFormViewBinding.cardMultilineWidget.postalCodeRequired = false
cardFormViewBinding.postalCodeContainer.visibility = visibility
}

// TODO: uncomment when ios-sdk allows for this
// fun setPlaceHolders(value: ReadableMap) {
// val cardFormView = StripeCardFormViewBinding.bind(cardForm)
//
// val numberPlaceholder = getValOr(value, "number", null)
// val expirationPlaceholder = getValOr(value, "expiration", null)
// val cvcPlaceholder = getValOr(value, "cvc", null)
// val postalCodePlaceholder = getValOr(value, "postalCode", null)
//
// numberPlaceholder?.let {
//// multilineWidgetBinding.tlCardNumber.hint = it
// }
// expirationPlaceholder?.let {
// multilineWidgetBinding.tlExpiry.hint = it
// }
// cvcPlaceholder?.let {
// multilineWidgetBinding.tlCvc.hint = it
// }
// postalCodePlaceholder?.let {
// cardFormView.postalCodeContainer.hint = it
// }
// }
fun setPlaceHolders(value: ReadableMap) {
val numberPlaceholder = getValOr(value, "number", null)
val expirationPlaceholder = getValOr(value, "expiration", null)
val cvcPlaceholder = getValOr(value, "cvc", null)
val postalCodePlaceholder = getValOr(value, "postalCode", null)

numberPlaceholder?.let {
multilineWidgetBinding.tlCardNumber.hint = it
}
expirationPlaceholder?.let {
multilineWidgetBinding.tlExpiry.hint = it
}
cvcPlaceholder?.let {
multilineWidgetBinding.tlCvc.hint = it
}
postalCodePlaceholder?.let {
cardFormViewBinding.postalCodeContainer.hint = it
}
}

fun setAutofocus(value: Boolean) {
if (value) {
Expand Down Expand Up @@ -101,11 +101,81 @@ class CardFormView(context: ThemedReactContext) : FrameLayout(context) {
}

fun setCardStyle(value: ReadableMap) {
val binding = StripeCardFormViewBinding.bind(cardForm)
val backgroundColor = getValOr(value, "backgroundColor", null)
val textColor = getValOr(value, "textColor", null)
val borderWidth = getIntOrNull(value, "borderWidth")
val borderColor = getValOr(value, "borderColor", null)
val borderRadius = getIntOrNull(value, "borderRadius") ?: 0
val fontSize = getIntOrNull(value, "fontSize")
val fontFamily = getValOr(value, "fontFamily")
val placeholderColor = getValOr(value, "placeholderColor", null)
val textErrorColor = getValOr(value, "textErrorColor", null)
val cursorColor = getValOr(value, "cursorColor", null)

val editTextBindings = setOf(
cardFormViewBinding.cardMultilineWidget.cardNumberEditText,
cardFormViewBinding.cardMultilineWidget.cvcEditText,
cardFormViewBinding.cardMultilineWidget.expiryDateEditText,
cardFormViewBinding.postalCode
)

textColor?.let {
for (binding in editTextBindings) {
binding.setTextColor(Color.parseColor(it))
}
cardFormViewBinding.countryLayout.countryAutocomplete.setTextColor(Color.parseColor(it))
}
textErrorColor?.let {
for (binding in editTextBindings) {
binding.setErrorColor(Color.parseColor(it))
cardFormViewBinding.postalCode.setErrorColor(Color.parseColor(it))
}
}
placeholderColor?.let {
multilineWidgetBinding.tlExpiry.defaultHintTextColor = ColorStateList.valueOf(Color.parseColor(it))
multilineWidgetBinding.tlCardNumber.defaultHintTextColor = ColorStateList.valueOf(Color.parseColor(it))
multilineWidgetBinding.tlCvc.defaultHintTextColor = ColorStateList.valueOf(Color.parseColor(it))
cardFormViewBinding.postalCodeContainer.defaultHintTextColor = ColorStateList.valueOf(Color.parseColor(it))
}
fontSize?.let {
for (binding in editTextBindings) {
binding.textSize = it.toFloat()
}
}
fontFamily?.let {
for (binding in editTextBindings) {
binding.typeface = Typeface.create(it, Typeface.NORMAL)
}
}
cursorColor?.let {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val color = Color.parseColor(it)
for (binding in editTextBindings) {
binding.textCursorDrawable?.setTint(color)
binding.textSelectHandle?.setTint(color)
binding.textSelectHandleLeft?.setTint(color)
binding.textSelectHandleRight?.setTint(color)
binding.highlightColor = color
}
}
}

binding.cardMultilineWidgetContainer.background = MaterialShapeDrawable().also { shape ->
cardFormViewBinding.cardMultilineWidgetContainer.setPadding(40, 0, 40, 0)
cardFormViewBinding.cardMultilineWidgetContainer.background = MaterialShapeDrawable(
ShapeAppearanceModel()
.toBuilder()
.setAllCorners(CornerFamily.ROUNDED, (borderRadius * 2).toFloat())
.build()
).also { shape ->
shape.strokeWidth = 0.0f
shape.strokeColor = ColorStateList.valueOf(Color.parseColor("#000000"))
shape.fillColor = ColorStateList.valueOf(Color.parseColor("#FFFFFF"))
borderWidth?.let {
shape.strokeWidth = (it * 2).toFloat()
}
borderColor?.let {
shape.strokeColor = ColorStateList.valueOf(Color.parseColor(it))
}
backgroundColor?.let {
shape.fillColor = ColorStateList.valueOf(Color.parseColor(it))
}
Expand Down Expand Up @@ -142,8 +212,7 @@ class CardFormView(context: ThemedReactContext) : FrameLayout(context) {
.setCountry(it.address?.country)
.build()

val binding = StripeCardFormViewBinding.bind(cardForm)
binding.cardMultilineWidget.paymentMethodCard?.let { params -> cardParams = params }
cardFormViewBinding.cardMultilineWidget.paymentMethodCard?.let { params -> cardParams = params }
}
} else {
cardParams = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ class CardFormViewManager : SimpleViewManager<CardFormView>() {
view.setPostalCodeEnabled(postalCodeEnabled)
}

// @ReactProp(name = "placeholder")
// fun setPlaceHolders(view: CardFormView, placeholder: ReadableMap) {
// view.setPlaceHolders(placeholder)
// }
@ReactProp(name = "placeholders")
fun setPlaceHolders(view: CardFormView, placeholders: ReadableMap) {
view.setPlaceHolders(placeholders);
}

@ReactProp(name = "autofocus")
fun setAutofocus(view: CardFormView, autofocus: Boolean = false) {
Expand Down
2 changes: 1 addition & 1 deletion docs/tipsi-stripe-migration-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ _after:_
<CardField
postalCodeEnabled={false}
autofocus
placeholder={{
placeholders={{
number: '4242 4242 4242 4242',
postalCode: '12345',
cvc: 'CVC',
Expand Down
16 changes: 15 additions & 1 deletion example/src/screens/MultilineWebhookPaymentScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ export default function MultilineWebhookPaymentScreen() {
style={styles.input}
/>
<CardForm
placeholders={{
number: '4242 4242 4242 4242',
postalCode: '12345',
cvc: 'CVC',
expiration: 'MM|YY',
}}
autofocus
cardStyle={inputStyles}
style={styles.cardField}
Expand Down Expand Up @@ -146,5 +152,13 @@ const styles = StyleSheet.create({
});

const inputStyles: CardFormView.Styles = {
backgroundColor: '#FFFFFF',
backgroundColor: '#D3D3D3',
textColor: '#A020F0',
borderColor: '#000000',
borderWidth: 2,
borderRadius: 10,
cursorColor: '#000000',
fontSize: 16,
placeholderColor: '#A020F0',
textErrorColor: '#ff0000',
};
4 changes: 2 additions & 2 deletions example/src/screens/WebhookPaymentScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export default function WebhookPaymentScreen() {
<CardField
postalCodeEnabled={false}
autofocus
placeholder={{
placeholders={{
number: '4242 4242 4242 4242',
postalCode: '12345',
cvc: 'CVC',
Expand Down Expand Up @@ -150,5 +150,5 @@ const inputStyles: CardFieldInput.Styles = {
borderColor: '#000000',
borderRadius: 8,
fontSize: 14,
placeholderColor: '#999999',
placeholderColor: '#A020F0',
};
2 changes: 1 addition & 1 deletion ios/CardFieldManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ @interface RCT_EXTERN_MODULE(CardFieldManager, RCTViewManager)
RCT_EXPORT_VIEW_PROPERTY(onCardChange, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onFocusChange, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(cardStyle, NSDictionary)
RCT_EXPORT_VIEW_PROPERTY(placeholder, NSDictionary)
RCT_EXPORT_VIEW_PROPERTY(placeholders, NSDictionary)
RCT_EXPORT_VIEW_PROPERTY(autofocus, BOOL)
RCT_EXPORT_VIEW_PROPERTY(dangerouslyGetFullCardDetails, BOOL)
RCT_EXTERN_METHOD(focus:(nonnull NSNumber*) reactTag)
Expand Down
10 changes: 5 additions & 5 deletions ios/CardFieldView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@ class CardFieldView: UIView, STPPaymentCardTextFieldDelegate {
}
}

@objc var placeholder: NSDictionary = NSDictionary() {
@objc var placeholders: NSDictionary = NSDictionary() {
didSet {
if let numberPlaceholder = placeholder["number"] as? String {
if let numberPlaceholder = placeholders["number"] as? String {
cardField.numberPlaceholder = numberPlaceholder
} else {
cardField.numberPlaceholder = "1234123412341234"
}
if let expirationPlaceholder = placeholder["expiration"] as? String {
if let expirationPlaceholder = placeholders["expiration"] as? String {
cardField.expirationPlaceholder = expirationPlaceholder
}
if let cvcPlaceholder = placeholder["cvc"] as? String {
if let cvcPlaceholder = placeholders["cvc"] as? String {
cardField.cvcPlaceholder = cvcPlaceholder
}
if let postalCodePlaceholder = placeholder["postalCode"] as? String {
if let postalCodePlaceholder = placeholders["postalCode"] as? String {
cardField.postalCodePlaceholder = postalCodePlaceholder
}
}
Expand Down
14 changes: 7 additions & 7 deletions src/components/CardField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export interface Props extends AccessibilityProps {
style?: StyleProp<ViewStyle>;
postalCodeEnabled?: boolean;
cardStyle?: CardFieldInput.Styles;
placeholder?: CardFieldInput.Placeholders;
placeholders?: CardFieldInput.Placeholders;
autofocus?: boolean;
onCardChange?(card: CardFieldInput.Details): void;
onBlur?(): void;
Expand Down Expand Up @@ -72,7 +72,7 @@ export const CardField = forwardRef<CardFieldInput.Methods, Props>(
onFocus,
onBlur,
cardStyle,
placeholder,
placeholders,
postalCodeEnabled,
...props
},
Expand Down Expand Up @@ -186,11 +186,11 @@ export const CardField = forwardRef<CardFieldInput.Methods, Props>(
textErrorColor: cardStyle?.textErrorColor,
fontFamily: cardStyle?.fontFamily,
}}
placeholder={{
number: placeholder?.number,
expiration: placeholder?.expiration,
cvc: placeholder?.cvc,
postalCode: placeholder?.postalCode,
placeholders={{
number: placeholders?.number,
expiration: placeholders?.expiration,
cvc: placeholders?.cvc,
postalCode: placeholders?.postalCode,
}}
{...props}
/>
Expand Down
Loading