@stripe/stripe-react-native 0.49.0 → 0.50.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +1 -1
  3. package/android/.gradle/8.11.1/checksums/checksums.lock +0 -0
  4. package/android/.gradle/8.11.1/checksums/md5-checksums.bin +0 -0
  5. package/android/.gradle/8.11.1/checksums/sha1-checksums.bin +0 -0
  6. package/android/.gradle/8.11.1/executionHistory/executionHistory.lock +0 -0
  7. package/android/.gradle/8.11.1/fileChanges/last-build.bin +0 -0
  8. package/android/.gradle/8.11.1/fileHashes/fileHashes.lock +0 -0
  9. package/android/.gradle/8.11.1/gc.properties +0 -0
  10. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  11. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  12. package/android/.gradle/vcs-1/gc.properties +0 -0
  13. package/android/src/main/AndroidManifest.xml +10 -0
  14. package/android/src/main/java/com/reactnativestripesdk/CustomPaymentMethodActivity.kt +81 -0
  15. package/android/src/main/java/com/reactnativestripesdk/EmbeddedPaymentElementView.kt +96 -1
  16. package/android/src/main/java/com/reactnativestripesdk/EmbeddedPaymentElementViewManager.kt +26 -5
  17. package/android/src/main/java/com/reactnativestripesdk/PaymentMethodCreateParamsFactory.kt +0 -17
  18. package/android/src/main/java/com/reactnativestripesdk/PaymentSheetAppearance.kt +17 -6
  19. package/android/src/main/java/com/reactnativestripesdk/PaymentSheetFragment.kt +116 -20
  20. package/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +22 -0
  21. package/android/src/main/java/com/reactnativestripesdk/customersheet/CustomerSheetFragment.kt +1 -1
  22. package/android/src/main/java/com/reactnativestripesdk/pushprovisioning/AddToWalletButtonManager.kt +6 -2
  23. package/android/src/main/java/com/reactnativestripesdk/utils/Mappers.kt +52 -6
  24. package/android/src/main/res/values/styles.xml +27 -0
  25. package/android/src/oldarch/java/com/reactnativestripesdk/NativeStripeSdkModuleSpec.java +8 -0
  26. package/ios/ApplePayButtonManager.m +4 -0
  27. package/ios/ApplePayButtonView.swift +11 -4
  28. package/ios/Mappers.swift +0 -5
  29. package/ios/NewArch/ApplePayButtonComponentView.mm +6 -0
  30. package/ios/OldArch/StripeSdkEventEmitterCompat.h +1 -1
  31. package/ios/OldArch/StripeSdkEventEmitterCompat.m +7 -1
  32. package/ios/PaymentMethodFactory.swift +0 -17
  33. package/ios/PaymentSheetAppearance.swift +81 -67
  34. package/ios/StripeSdk.mm +7 -0
  35. package/ios/StripeSdkEmitter.swift +1 -0
  36. package/ios/StripeSdkImpl+Embedded.swift +39 -17
  37. package/ios/StripeSdkImpl+PaymentSheet.swift +114 -1
  38. package/ios/StripeSdkImpl.swift +38 -9
  39. package/lib/commonjs/components/AddToWalletButton.js +1 -1
  40. package/lib/commonjs/components/AddToWalletButton.js.map +1 -1
  41. package/lib/commonjs/components/AddressSheet.js +1 -1
  42. package/lib/commonjs/components/AddressSheet.js.map +1 -1
  43. package/lib/commonjs/components/AuBECSDebitForm.js +1 -1
  44. package/lib/commonjs/components/AuBECSDebitForm.js.map +1 -1
  45. package/lib/commonjs/components/CardField.js +1 -1
  46. package/lib/commonjs/components/CardField.js.map +1 -1
  47. package/lib/commonjs/components/CardForm.js +1 -1
  48. package/lib/commonjs/components/CardForm.js.map +1 -1
  49. package/lib/commonjs/components/PlatformPayButton.js +1 -1
  50. package/lib/commonjs/components/PlatformPayButton.js.map +1 -1
  51. package/lib/commonjs/components/StripeContainer.js +1 -1
  52. package/lib/commonjs/components/StripeContainer.js.map +1 -1
  53. package/lib/commonjs/events.js.map +1 -1
  54. package/lib/commonjs/functions.js +1 -1
  55. package/lib/commonjs/functions.js.map +1 -1
  56. package/lib/commonjs/specs/NativeApplePayButton.js +1 -1
  57. package/lib/commonjs/specs/NativeApplePayButton.js.map +1 -1
  58. package/lib/commonjs/specs/NativeStripeSdkModule.js.map +1 -1
  59. package/lib/commonjs/types/EmbeddedPaymentElement.js +1 -1
  60. package/lib/commonjs/types/EmbeddedPaymentElement.js.map +1 -1
  61. package/lib/commonjs/types/PaymentIntent.js.map +1 -1
  62. package/lib/commonjs/types/PaymentSheet.js +1 -1
  63. package/lib/commonjs/types/PaymentSheet.js.map +1 -1
  64. package/lib/module/components/AddToWalletButton.js +1 -1
  65. package/lib/module/components/AddToWalletButton.js.map +1 -1
  66. package/lib/module/components/AddressSheet.js +1 -1
  67. package/lib/module/components/AddressSheet.js.map +1 -1
  68. package/lib/module/components/AuBECSDebitForm.js +1 -1
  69. package/lib/module/components/AuBECSDebitForm.js.map +1 -1
  70. package/lib/module/components/CardField.js +1 -1
  71. package/lib/module/components/CardField.js.map +1 -1
  72. package/lib/module/components/CardForm.js +1 -1
  73. package/lib/module/components/CardForm.js.map +1 -1
  74. package/lib/module/components/PlatformPayButton.js +1 -1
  75. package/lib/module/components/PlatformPayButton.js.map +1 -1
  76. package/lib/module/components/StripeContainer.js +1 -1
  77. package/lib/module/components/StripeContainer.js.map +1 -1
  78. package/lib/module/events.js.map +1 -1
  79. package/lib/module/functions.js +1 -1
  80. package/lib/module/functions.js.map +1 -1
  81. package/lib/module/specs/NativeApplePayButton.js +1 -1
  82. package/lib/module/specs/NativeApplePayButton.js.map +1 -1
  83. package/lib/module/specs/NativeStripeSdkModule.js.map +1 -1
  84. package/lib/module/types/EmbeddedPaymentElement.js +1 -1
  85. package/lib/module/types/EmbeddedPaymentElement.js.map +1 -1
  86. package/lib/module/types/PaymentIntent.js.map +1 -1
  87. package/lib/module/types/PaymentSheet.js +1 -1
  88. package/lib/module/types/PaymentSheet.js.map +1 -1
  89. package/lib/typescript/src/components/PlatformPayButton.d.ts.map +1 -1
  90. package/lib/typescript/src/events.d.ts +1 -1
  91. package/lib/typescript/src/events.d.ts.map +1 -1
  92. package/lib/typescript/src/functions.d.ts.map +1 -1
  93. package/lib/typescript/src/specs/NativeApplePayButton.d.ts +4 -0
  94. package/lib/typescript/src/specs/NativeApplePayButton.d.ts.map +1 -1
  95. package/lib/typescript/src/specs/NativeStripeSdkModule.d.ts +2 -0
  96. package/lib/typescript/src/specs/NativeStripeSdkModule.d.ts.map +1 -1
  97. package/lib/typescript/src/types/EmbeddedPaymentElement.d.ts +2 -0
  98. package/lib/typescript/src/types/EmbeddedPaymentElement.d.ts.map +1 -1
  99. package/lib/typescript/src/types/PaymentIntent.d.ts +1 -10
  100. package/lib/typescript/src/types/PaymentIntent.d.ts.map +1 -1
  101. package/lib/typescript/src/types/PaymentMethod.d.ts +2 -13
  102. package/lib/typescript/src/types/PaymentMethod.d.ts.map +1 -1
  103. package/lib/typescript/src/types/PaymentSheet.d.ts +55 -0
  104. package/lib/typescript/src/types/PaymentSheet.d.ts.map +1 -1
  105. package/package.json +1 -1
  106. package/patches/README.md +55 -0
  107. package/patches/old-arch-codegen-fix.patch +87 -0
  108. package/src/components/PlatformPayButton.tsx +12 -4
  109. package/src/events.ts +2 -1
  110. package/src/functions.ts +36 -1
  111. package/src/specs/NativeApplePayButton.ts +5 -0
  112. package/src/specs/NativeStripeSdkModule.ts +4 -0
  113. package/src/types/EmbeddedPaymentElement.tsx +33 -0
  114. package/src/types/PaymentIntent.ts +0 -10
  115. package/src/types/PaymentMethod.ts +0 -14
  116. package/src/types/PaymentSheet.ts +59 -0
  117. package/.env +0 -19
  118. package/ios/StripeSdk.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  119. package/ios/StripeSdk.xcodeproj/project.xcworkspace/xcuserdata/wooj.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  120. package/ios/StripeSdk.xcodeproj/xcuserdata/wooj.xcuserdatad/xcschemes/xcschememanagement.plist +0 -19
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 0.50.1 - 2025-07-22
4
+
5
+ **Fixes**
6
+ - Fixed embedded payment element color support to accept both single color strings and light/dark color objects for `ThemedColor` properties (separatorColor, selectedColor, unselectedColor, checkmark color, chevron color).
7
+ - Fixed Android crash when providing partial `billingDetailsCollectionConfiguration` objects. Now gracefully handles missing fields like `attachDefaultsToPaymentMethod` by using safe accessor methods with default values.
8
+ - Fixed Android Kotlin compilation errors where nullable `ReadableMap?` was passed to functions expecting non-nullable `ReadableMap`. Added null checks in `EmbeddedPaymentElementViewManager` and `AddToWalletButtonManager`. [#1988](https://github.com/stripe/stripe-react-native/issues/1988)
9
+
10
+ ## 0.50.0 - 2025-07-17
11
+
12
+ **Features**
13
+ - Added support for Custom Payment Methods in PaymentSheet and Embedded Payment Element.
14
+
15
+ **Fixes**
16
+ - Removed Sofort from playground pages. Sofort is no longer support by Stripe.
17
+ - **Patches**
18
+ - Fixed codegen error when using React Native 0.74+ with old architecture by converting EventEmitter properties to callback functions in TurboModule interface. [#1977](https://github.com/stripe/stripe-react-native/issues/1977). See `patches/README.md` for more info.
19
+
3
20
  ## 0.49.0 - 2025-07-02
4
21
 
5
22
  **Features**
package/README.md CHANGED
@@ -23,7 +23,7 @@ Get started with our [📚 integration guides](https://stripe.com/docs/payments/
23
23
 
24
24
  **Native UI**: We provide native screens and elements to securely collect payment details on Android and iOS.
25
25
 
26
- **PaymentSheet**: [Learn how to integrate](https://stripe.com/docs/payments/accept-a-payment) PaymentSheet, our new pre-built payments UI for mobile apps. PaymentSheet lets you accept cards, Apple Pay, Google Pay, and much more out of the box and also supports saving & reusing payment methods. PaymentSheet currently accepts the following payment methods: Card, Apple Pay, Google Pay, SEPA Debit, Bancontact, iDEAL, EPS, P24, Afterpay/Clearpay, Klarna, Giropay, Sofort, and ACH.
26
+ **PaymentSheet**: [Learn how to integrate](https://stripe.com/docs/payments/accept-a-payment) PaymentSheet, our new pre-built payments UI for mobile apps. PaymentSheet lets you accept cards, Apple Pay, Google Pay, and much more out of the box and also supports saving & reusing payment methods. PaymentSheet currently accepts the following payment methods: Card, Apple Pay, Google Pay, SEPA Debit, Bancontact, iDEAL, EPS, P24, Afterpay/Clearpay, Klarna, Giropay, and ACH.
27
27
 
28
28
  #### Recommended usage
29
29
 
File without changes
@@ -0,0 +1,2 @@
1
+ #Thu Jul 17 13:09:27 MDT 2025
2
+ gradle.version=8.11.1
File without changes
@@ -1,3 +1,13 @@
1
1
  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
2
  package="com.reactnativestripesdk">
3
+
4
+ <application>
5
+ <activity
6
+ android:name=".CustomPaymentMethodActivity"
7
+ android:theme="@style/Theme.StripeReactNative.Transparent"
8
+ android:exported="false"
9
+ android:launchMode="singleTop"
10
+ android:excludeFromRecents="true"
11
+ android:noHistory="true" />
12
+ </application>
3
13
  </manifest>
@@ -0,0 +1,81 @@
1
+ package com.reactnativestripesdk
2
+
3
+ import android.os.Bundle
4
+ import android.view.MotionEvent
5
+ import com.facebook.react.ReactActivity
6
+ import java.lang.ref.WeakReference
7
+
8
+ /**
9
+ * A transparent activity that is launched when the Payment Element requests the
10
+ * `confirmCustomPaymentMethodCallback`.
11
+ *
12
+ * Its only purpose is to bring the app back to the foreground (the Stripe
13
+ * SDK launches its own proxy activity which pauses the host React Native
14
+ * activity). Having a React (transparent) activity on top ensures that React
15
+ * Native can display UI elements such as `Alert` dialogs coming from
16
+ * JavaScript.
17
+ *
18
+ * The activity uses a translucent theme to minimize visibility and is excluded
19
+ * from recents, though it may still be briefly visible to the end-user during
20
+ * certain operations.
21
+ */
22
+ class CustomPaymentMethodActivity : ReactActivity() {
23
+ override fun onCreate(savedInstanceState: Bundle?) {
24
+ // Disable the transition animation to make it truly invisible
25
+ overridePendingTransition(0, 0)
26
+ super.onCreate(savedInstanceState)
27
+ }
28
+
29
+ override fun getMainComponentName(): String? {
30
+ // We don't want to mount another React Native root – returning null is
31
+ // enough to make ReactActivity skip loading a JS component while still
32
+ // hooking into the lifecycle so that ReactContext is aware of this
33
+ // activity.
34
+ return null
35
+ }
36
+
37
+ override fun onTouchEvent(event: MotionEvent?): Boolean {
38
+ // Ensure touch events are properly handled by React Native
39
+ return super.onTouchEvent(event)
40
+ }
41
+
42
+ override fun dispatchTouchEvent(event: MotionEvent?): Boolean {
43
+ // Ensure touch events are properly dispatched to React Native
44
+ return super.dispatchTouchEvent(event)
45
+ }
46
+
47
+ override fun onResume() {
48
+ super.onResume()
49
+ // Ensure the activity is properly focused for touch events
50
+ currentFocus?.requestFocus()
51
+ }
52
+
53
+ override fun finish() {
54
+ super.finish()
55
+ // Disable the exit animation as well
56
+ overridePendingTransition(0, 0)
57
+
58
+ // Clear the weak reference when finished
59
+ if (currentActivityRef?.get() == this) {
60
+ currentActivityRef = null
61
+ }
62
+ }
63
+
64
+ companion object {
65
+ @Volatile
66
+ private var currentActivityRef: WeakReference<CustomPaymentMethodActivity>? = null
67
+
68
+ fun finishCurrent() {
69
+ currentActivityRef?.get()?.let { activity ->
70
+ activity.runOnUiThread {
71
+ activity.finish()
72
+ }
73
+ }
74
+ }
75
+ }
76
+
77
+ override fun onStart() {
78
+ super.onStart()
79
+ currentActivityRef = WeakReference(this)
80
+ }
81
+ }
@@ -1,6 +1,8 @@
1
1
  package com.reactnativestripesdk
2
2
 
3
3
  import android.content.Context
4
+ import android.content.Intent
5
+ import android.util.Log
4
6
  import androidx.compose.foundation.layout.Box
5
7
  import androidx.compose.foundation.layout.requiredHeight
6
8
  import androidx.compose.runtime.Composable
@@ -9,6 +11,7 @@ import androidx.compose.runtime.getValue
9
11
  import androidx.compose.runtime.mutableIntStateOf
10
12
  import androidx.compose.runtime.mutableStateOf
11
13
  import androidx.compose.runtime.remember
14
+ import androidx.compose.runtime.rememberCoroutineScope
12
15
  import androidx.compose.runtime.setValue
13
16
  import androidx.compose.ui.Modifier
14
17
  import androidx.compose.ui.layout.layout
@@ -19,14 +22,21 @@ import androidx.compose.ui.unit.dp
19
22
  import com.facebook.react.bridge.Arguments
20
23
  import com.facebook.react.uimanager.ThemedReactContext
21
24
  import com.reactnativestripesdk.utils.KeepJsAwakeTask
25
+ import com.reactnativestripesdk.utils.mapFromCustomPaymentMethod
22
26
  import com.reactnativestripesdk.utils.mapFromPaymentMethod
27
+ import com.stripe.android.model.PaymentMethod
28
+ import com.stripe.android.paymentelement.CustomPaymentMethodResult
29
+ import com.stripe.android.paymentelement.CustomPaymentMethodResultHandler
23
30
  import com.stripe.android.paymentelement.EmbeddedPaymentElement
31
+ import com.stripe.android.paymentelement.ExperimentalCustomPaymentMethodsApi
24
32
  import com.stripe.android.paymentelement.rememberEmbeddedPaymentElement
25
33
  import com.stripe.android.paymentsheet.CreateIntentResult
26
34
  import com.stripe.android.paymentsheet.PaymentSheet
27
35
  import kotlinx.coroutines.CompletableDeferred
28
36
  import kotlinx.coroutines.channels.Channel
37
+ import kotlinx.coroutines.delay
29
38
  import kotlinx.coroutines.flow.consumeAsFlow
39
+ import kotlinx.coroutines.launch
30
40
  import toWritableMap
31
41
 
32
42
  enum class RowSelectionBehaviorType {
@@ -34,6 +44,7 @@ enum class RowSelectionBehaviorType {
34
44
  ImmediateAction,
35
45
  }
36
46
 
47
+ @OptIn(ExperimentalCustomPaymentMethodsApi::class)
37
48
  class EmbeddedPaymentElementView(
38
49
  context: Context,
39
50
  ) : StripeAbstractComposeView(context) {
@@ -56,9 +67,92 @@ class EmbeddedPaymentElementView(
56
67
  private val reactContext get() = context as ThemedReactContext
57
68
  private val events = Channel<Event>(Channel.UNLIMITED)
58
69
 
70
+ @OptIn(ExperimentalCustomPaymentMethodsApi::class)
59
71
  @Composable
60
72
  override fun Content() {
61
73
  val type by remember { rowSelectionBehaviorType }
74
+ val coroutineScope = rememberCoroutineScope()
75
+
76
+ val confirmCustomPaymentMethodCallback =
77
+ remember(coroutineScope) {
78
+ {
79
+ customPaymentMethod: PaymentSheet.CustomPaymentMethod,
80
+ billingDetails: PaymentMethod.BillingDetails,
81
+ ->
82
+ // Launch a transparent Activity to ensure React Native UI can appear on top of the Stripe proxy activity.
83
+ try {
84
+ val intent =
85
+ Intent(reactContext, CustomPaymentMethodActivity::class.java).apply {
86
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
87
+ addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
88
+ }
89
+ reactContext.startActivity(intent)
90
+ } catch (e: Exception) {
91
+ Log.e("StripeReactNative", "Failed to start CustomPaymentMethodActivity", e)
92
+ }
93
+
94
+ val stripeSdkModule =
95
+ try {
96
+ requireStripeSdkModule()
97
+ } catch (ex: IllegalArgumentException) {
98
+ Log.e("StripeReactNative", "StripeSdkModule not found for CPM callback", ex)
99
+ CustomPaymentMethodActivity.finishCurrent()
100
+ return@remember
101
+ }
102
+
103
+ // Keep JS awake while React Native is backgrounded by Stripe SDK.
104
+ val keepJsAwakeTask =
105
+ KeepJsAwakeTask(reactContext.reactApplicationContext).apply { start() }
106
+
107
+ // Run on coroutine scope.
108
+ coroutineScope.launch {
109
+ try {
110
+ // Give the CustomPaymentMethodActivity a moment to fully initialize
111
+ delay(100)
112
+
113
+ // Emit event so JS can show the Alert and eventually respond via `customPaymentMethodResultCallback`.
114
+ stripeSdkModule.emitOnCustomPaymentMethodConfirmHandlerCallback(
115
+ mapFromCustomPaymentMethod(customPaymentMethod, billingDetails),
116
+ )
117
+
118
+ // Await JS result.
119
+ val resultFromJs = stripeSdkModule.customPaymentMethodResultCallback.await()
120
+
121
+ keepJsAwakeTask.stop()
122
+
123
+ val status = resultFromJs.getString("status")
124
+
125
+ val nativeResult =
126
+ when (status) {
127
+ "completed" ->
128
+ CustomPaymentMethodResult
129
+ .completed()
130
+ "canceled" ->
131
+ CustomPaymentMethodResult
132
+ .canceled()
133
+ "failed" -> {
134
+ val errMsg = resultFromJs.getString("error") ?: "Custom payment failed"
135
+ CustomPaymentMethodResult
136
+ .failed(displayMessage = errMsg)
137
+ }
138
+ else ->
139
+ CustomPaymentMethodResult
140
+ .failed(displayMessage = "Unknown status")
141
+ }
142
+
143
+ // Return result to Stripe SDK.
144
+ CustomPaymentMethodResultHandler.handleCustomPaymentMethodResult(
145
+ reactContext,
146
+ nativeResult,
147
+ )
148
+ } finally {
149
+ // Clean up the transparent activity
150
+ CustomPaymentMethodActivity.finishCurrent()
151
+ }
152
+ }
153
+ }
154
+ }
155
+
62
156
  val builder =
63
157
  remember(type) {
64
158
  EmbeddedPaymentElement
@@ -125,7 +219,8 @@ class EmbeddedPaymentElementView(
125
219
  }
126
220
  requireStripeSdkModule().emitEmbeddedPaymentElementFormSheetConfirmComplete(map)
127
221
  },
128
- ).rowSelectionBehavior(
222
+ ).confirmCustomPaymentMethodCallback(confirmCustomPaymentMethodCallback)
223
+ .rowSelectionBehavior(
129
224
  if (type == RowSelectionBehaviorType.Default) {
130
225
  EmbeddedPaymentElement.RowSelectionBehavior.default()
131
226
  } else {
@@ -17,10 +17,13 @@ import com.reactnativestripesdk.PaymentSheetFragment.Companion.buildGooglePayCon
17
17
  import com.reactnativestripesdk.addresssheet.AddressSheetView
18
18
  import com.reactnativestripesdk.utils.PaymentSheetAppearanceException
19
19
  import com.reactnativestripesdk.utils.PaymentSheetException
20
+ import com.reactnativestripesdk.utils.getBooleanOr
20
21
  import com.reactnativestripesdk.utils.mapToPreferredNetworks
22
+ import com.reactnativestripesdk.utils.parseCustomPaymentMethods
21
23
  import com.reactnativestripesdk.utils.toBundleObject
22
24
  import com.stripe.android.ExperimentalAllowsRemovalOfLastSavedPaymentMethodApi
23
25
  import com.stripe.android.paymentelement.EmbeddedPaymentElement
26
+ import com.stripe.android.paymentelement.ExperimentalCustomPaymentMethodsApi
24
27
  import com.stripe.android.paymentsheet.PaymentSheet
25
28
 
26
29
  @ReactModule(name = EmbeddedPaymentElementViewManager.NAME)
@@ -52,10 +55,13 @@ class EmbeddedPaymentElementViewManager :
52
55
  view: EmbeddedPaymentElementView,
53
56
  cfg: Dynamic,
54
57
  ) {
55
- val rowSelectionBehaviorType = parseRowSelectionBehavior(cfg.asMap())
58
+ val readableMap = cfg.asMap()
59
+ if (readableMap == null) return
60
+
61
+ val rowSelectionBehaviorType = parseRowSelectionBehavior(readableMap)
56
62
  view.rowSelectionBehaviorType.value = rowSelectionBehaviorType
57
63
 
58
- val elementConfig = parseElementConfiguration(cfg.asMap(), view.context)
64
+ val elementConfig = parseElementConfiguration(readableMap, view.context)
59
65
  view.latestElementConfig = elementConfig
60
66
  // if intentConfig is already set, configure immediately:
61
67
  view.latestIntentConfig?.let { intentCfg ->
@@ -72,7 +78,9 @@ class EmbeddedPaymentElementViewManager :
72
78
  view: EmbeddedPaymentElementView,
73
79
  cfg: Dynamic,
74
80
  ) {
75
- val intentConfig = parseIntentConfiguration(cfg.asMap())
81
+ val readableMap = cfg.asMap()
82
+ if (readableMap == null) return
83
+ val intentConfig = parseIntentConfiguration(readableMap)
76
84
  view.latestIntentConfig = intentConfig
77
85
  view.latestElementConfig?.let { elemCfg ->
78
86
  view.configure(elemCfg, intentConfig)
@@ -80,7 +88,10 @@ class EmbeddedPaymentElementViewManager :
80
88
  }
81
89
 
82
90
  @SuppressLint("RestrictedApi")
83
- @OptIn(ExperimentalAllowsRemovalOfLastSavedPaymentMethodApi::class)
91
+ @OptIn(
92
+ ExperimentalAllowsRemovalOfLastSavedPaymentMethodApi::class,
93
+ ExperimentalCustomPaymentMethodsApi::class,
94
+ )
84
95
  private fun parseElementConfiguration(
85
96
  map: ReadableMap,
86
97
  context: Context,
@@ -142,7 +153,7 @@ class EmbeddedPaymentElementViewManager :
142
153
  email = mapToCollectionMode(billingConfigParams?.getString("email")),
143
154
  address = mapToAddressCollectionMode(billingConfigParams?.getString("address")),
144
155
  attachDefaultsToPaymentMethod =
145
- billingConfigParams?.getBoolean("attachDefaultsToPaymentMethod") ?: false,
156
+ billingConfigParams?.getBooleanOr("attachDefaultsToPaymentMethod", false) ?: false,
146
157
  )
147
158
  val allowsRemovalOfLastSavedPaymentMethod =
148
159
  if (map.hasKey("allowsRemovalOfLastSavedPaymentMethod")) {
@@ -184,6 +195,16 @@ class EmbeddedPaymentElementViewManager :
184
195
  ),
185
196
  ).allowsRemovalOfLastSavedPaymentMethod(allowsRemovalOfLastSavedPaymentMethod)
186
197
  .cardBrandAcceptance(mapToCardBrandAcceptance(toBundleObject(map)))
198
+ // Serialize original ReadableMap because toBundleObject cannot keep arrays of objects
199
+ .customPaymentMethods(
200
+ parseCustomPaymentMethods(
201
+ toBundleObject(map.getMap("customPaymentMethodConfiguration")).apply {
202
+ map.getMap("customPaymentMethodConfiguration")?.let { readable ->
203
+ putSerializable("customPaymentMethodConfigurationReadableMap", readable.toHashMap())
204
+ }
205
+ },
206
+ ),
207
+ )
187
208
 
188
209
  primaryButtonLabel?.let { configurationBuilder.primaryButtonLabel(it) }
189
210
  paymentMethodOrder?.let { configurationBuilder.paymentMethodOrder(it) }
@@ -38,7 +38,6 @@ class PaymentMethodCreateParamsFactory(
38
38
  PaymentMethod.Type.Card -> createCardPaymentMethodParams()
39
39
  PaymentMethod.Type.Ideal -> createIDEALParams()
40
40
  PaymentMethod.Type.Alipay -> createAlipayParams()
41
- PaymentMethod.Type.Sofort -> createSofortParams()
42
41
  PaymentMethod.Type.Bancontact -> createBancontactParams()
43
42
  PaymentMethod.Type.SepaDebit -> createSepaParams()
44
43
  PaymentMethod.Type.Oxxo -> createOXXOParams()
@@ -79,21 +78,6 @@ class PaymentMethodCreateParamsFactory(
79
78
  @Throws(PaymentMethodCreateParamsException::class)
80
79
  private fun createAlipayParams(): PaymentMethodCreateParams = PaymentMethodCreateParams.createAlipay()
81
80
 
82
- @Throws(PaymentMethodCreateParamsException::class)
83
- private fun createSofortParams(): PaymentMethodCreateParams {
84
- val country =
85
- getValOr(paymentMethodData, "country", null)
86
- ?: run {
87
- throw PaymentMethodCreateParamsException("You must provide bank account country")
88
- }
89
-
90
- return PaymentMethodCreateParams.create(
91
- PaymentMethodCreateParams.Sofort(country = country),
92
- billingDetailsParams,
93
- metadata = metadataParams,
94
- )
95
- }
96
-
97
81
  @Throws(PaymentMethodCreateParamsException::class)
98
82
  private fun createBancontactParams(): PaymentMethodCreateParams {
99
83
  billingDetailsParams?.let {
@@ -271,7 +255,6 @@ class PaymentMethodCreateParamsFactory(
271
255
  PaymentMethod.Type.Affirm -> createAffirmStripeIntentParams(clientSecret, isPaymentIntent)
272
256
  PaymentMethod.Type.Ideal,
273
257
  PaymentMethod.Type.Alipay,
274
- PaymentMethod.Type.Sofort,
275
258
  PaymentMethod.Type.Bancontact,
276
259
  PaymentMethod.Type.SepaDebit,
277
260
  PaymentMethod.Type.Oxxo,
@@ -478,9 +478,11 @@ private fun buildFormInsets(insetParams: Bundle?): PaymentSheet.Insets {
478
478
  }
479
479
 
480
480
  /**
481
- * Pulls a light/dark hex‑string map out of [params],
482
- * chooses the right one based on the current UI mode,
483
- * and parses it (falling back to [defaultColor]).
481
+ * Parses a ThemedColor from [params] at [key]. Supports both:
482
+ * - Single hex string: "#RRGGBB"
483
+ * - Light/dark object: { "light": "#RRGGBB", "dark": "#RRGGBB" }
484
+ * For light/dark objects, chooses the appropriate color based on current UI mode.
485
+ * Falls back to [defaultColor] if no color is provided.
484
486
  */
485
487
  private fun dynamicColorFromParams(
486
488
  context: Context,
@@ -488,8 +490,12 @@ private fun dynamicColorFromParams(
488
490
  key: String,
489
491
  defaultColor: Int,
490
492
  ): Int {
491
- // Expect a nested Bundle { "light": "#RRGGBB", "dark": "#RRGGBB" }
492
- val colorBundle = params?.getBundle(key)
493
+ if (params == null) {
494
+ return defaultColor
495
+ }
496
+
497
+ // First check if it's a nested Bundle { "light": "#RRGGBB", "dark": "#RRGGBB" }
498
+ val colorBundle = params.getBundle(key)
493
499
  if (colorBundle != null) {
494
500
  val isDark =
495
501
  (
@@ -508,7 +514,12 @@ private fun dynamicColorFromParams(
508
514
  return colorFromHexOrDefault(hex, defaultColor)
509
515
  }
510
516
 
511
- // no override bundle just use default
517
+ // Check if it's a single color string
518
+ params.getString(key)?.let { colorString ->
519
+ return colorFromHexOrDefault(colorString, defaultColor)
520
+ }
521
+
522
+ // no override → just use default
512
523
  return defaultColor
513
524
  }
514
525