@stripe/stripe-react-native 0.65.0 → 0.66.0

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 (239) hide show
  1. package/README.md +2 -2
  2. package/android/detekt/detekt-baseline.xml +1 -76
  3. package/android/gradle.properties +4 -4
  4. package/android/src/main/java/com/reactnativestripesdk/AuBECSDebitFormView.kt +3 -1
  5. package/android/src/main/java/com/reactnativestripesdk/AuBECSDebitFormViewManager.kt +2 -1
  6. package/android/src/main/java/com/reactnativestripesdk/CardFieldView.kt +56 -58
  7. package/android/src/main/java/com/reactnativestripesdk/CurrencySelectorElementEvent.kt +26 -0
  8. package/android/src/main/java/com/reactnativestripesdk/CurrencySelectorElementView.kt +139 -0
  9. package/android/src/main/java/com/reactnativestripesdk/CurrencySelectorElementViewManager.kt +59 -0
  10. package/android/src/main/java/com/reactnativestripesdk/EmbeddedPaymentElementView.kt +105 -49
  11. package/android/src/main/java/com/reactnativestripesdk/EmbeddedPaymentElementViewManager.kt +72 -12
  12. package/android/src/main/java/com/reactnativestripesdk/EventEmitterCompat.kt +4 -0
  13. package/android/src/main/java/com/reactnativestripesdk/FinancialConnectionsSheetManager.kt +8 -4
  14. package/android/src/main/java/com/reactnativestripesdk/GooglePayButtonManager.kt +2 -1
  15. package/android/src/main/java/com/reactnativestripesdk/GooglePayButtonView.kt +26 -11
  16. package/android/src/main/java/com/reactnativestripesdk/GooglePayLauncherManager.kt +2 -1
  17. package/android/src/main/java/com/reactnativestripesdk/NavigationBarView.kt +14 -5
  18. package/android/src/main/java/com/reactnativestripesdk/PaymentElementConfig.kt +6 -2
  19. package/android/src/main/java/com/reactnativestripesdk/PaymentLauncherManager.kt +2 -1
  20. package/android/src/main/java/com/reactnativestripesdk/PaymentMethodCreateParamsFactory.kt +2 -1
  21. package/android/src/main/java/com/reactnativestripesdk/PaymentMethodMessagingElementConfig.kt +6 -2
  22. package/android/src/main/java/com/reactnativestripesdk/PaymentMethodMessagingElementViewManager.kt +2 -1
  23. package/android/src/main/java/com/reactnativestripesdk/PaymentOptionDisplayDataMapper.kt +8 -4
  24. package/android/src/main/java/com/reactnativestripesdk/PaymentSheetAppearance.kt +9 -3
  25. package/android/src/main/java/com/reactnativestripesdk/PaymentSheetManager.kt +118 -48
  26. package/android/src/main/java/com/reactnativestripesdk/StripeAbstractComposeView.kt +1 -0
  27. package/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +281 -46
  28. package/android/src/main/java/com/reactnativestripesdk/StripeSdkPackage.kt +2 -0
  29. package/android/src/main/java/com/reactnativestripesdk/addresssheet/AddressLauncherManager.kt +2 -1
  30. package/android/src/main/java/com/reactnativestripesdk/addresssheet/AddressSheetView.kt +3 -1
  31. package/android/src/main/java/com/reactnativestripesdk/customersheet/CustomerSheetManager.kt +8 -18
  32. package/android/src/main/java/com/reactnativestripesdk/customersheet/ReactNativeCustomerAdapter.kt +3 -1
  33. package/android/src/main/java/com/reactnativestripesdk/customersheet/ReactNativeCustomerSessionProvider.kt +2 -1
  34. package/android/src/main/java/com/reactnativestripesdk/pushprovisioning/AddToWalletButtonManager.kt +2 -1
  35. package/android/src/main/java/com/reactnativestripesdk/utils/CheckoutAddressUpdate.kt +45 -0
  36. package/android/src/main/java/com/reactnativestripesdk/utils/CheckoutMappers.kt +127 -0
  37. package/android/src/main/java/com/reactnativestripesdk/utils/DefaultActivityLifecycleCallbacks.kt +41 -0
  38. package/android/src/main/java/com/reactnativestripesdk/utils/Errors.kt +4 -2
  39. package/android/src/main/java/com/reactnativestripesdk/utils/Extensions.kt +5 -1
  40. package/android/src/main/java/com/reactnativestripesdk/utils/Mappers.kt +29 -13
  41. package/android/src/main/java/com/reactnativestripesdk/utils/PostalCodeUtilities.kt +2 -1
  42. package/android/src/oldarch/java/com/facebook/react/viewmanagers/EmbeddedPaymentElementViewManagerDelegate.java +6 -0
  43. package/android/src/oldarch/java/com/facebook/react/viewmanagers/EmbeddedPaymentElementViewManagerInterface.java +2 -0
  44. package/android/src/oldarch/java/com/facebook/react/viewmanagers/StripeCurrencySelectorElementManagerDelegate.java +35 -0
  45. package/android/src/oldarch/java/com/facebook/react/viewmanagers/StripeCurrencySelectorElementManagerInterface.java +18 -0
  46. package/android/src/oldarch/java/com/reactnativestripesdk/NativeOnrampSdkModuleSpec.java +17 -3
  47. package/android/src/oldarch/java/com/reactnativestripesdk/NativeStripeSdkModuleSpec.java +13 -1
  48. package/android/src/onramp/java/com/reactnativestripesdk/OnrampMappers.kt +116 -0
  49. package/android/src/onramp/java/com/reactnativestripesdk/OnrampSdkModule.kt +109 -1
  50. package/android/src/test/java/com/reactnativestripesdk/DrawableLoadingTest.kt +6 -2
  51. package/android/src/test/java/com/reactnativestripesdk/mappers/MappersTest.kt +60 -0
  52. package/android/src/test/java/com/reactnativestripesdk/mappers/OnrampMappersTest.kt +145 -0
  53. package/android/src/test/java/com/reactnativestripesdk/mappers/PaymentOptionDisplayDataMapperTest.kt +9 -4
  54. package/android/src/test/java/com/reactnativestripesdk/utils/CheckoutMappersTest.kt +98 -0
  55. package/android/src/test/java/com/reactnativestripesdk/utils/CheckoutTestFixtures.java +57 -0
  56. package/ios/ConnectAccountOnboarding/ConnectAccountOnboardingViewController.swift +6 -8
  57. package/ios/CurrencySelectorElementManager.m +16 -0
  58. package/ios/CurrencySelectorElementView.swift +159 -0
  59. package/ios/EmbeddedPaymentElementView.swift +1 -1
  60. package/ios/Mappers+Checkout.swift +337 -0
  61. package/ios/Mappers.swift +90 -2
  62. package/ios/NewArch/EmbeddedPaymentElementViewComponentView.mm +16 -2
  63. package/ios/NewArch/StripeCurrencySelectorElementComponentView.h +10 -0
  64. package/ios/NewArch/StripeCurrencySelectorElementComponentView.mm +89 -0
  65. package/ios/OldArch/StripeSdkEventEmitterCompat.h +1 -0
  66. package/ios/OldArch/StripeSdkEventEmitterCompat.m +6 -0
  67. package/ios/PaymentOptionDisplayData+ReactNative.swift +1 -1
  68. package/ios/PaymentSheetAppearance.swift +1 -1
  69. package/ios/StripeOnrampSdk.mm +19 -0
  70. package/ios/StripeSdk.mm +136 -0
  71. package/ios/StripeSdkEmitter.swift +1 -0
  72. package/ios/StripeSdkImpl+Checkout.swift +360 -0
  73. package/ios/StripeSdkImpl+CustomerSheet.swift +1 -1
  74. package/ios/StripeSdkImpl+Embedded.swift +108 -27
  75. package/ios/StripeSdkImpl+PaymentSheet.swift +18 -2
  76. package/ios/StripeSdkImpl.swift +89 -7
  77. package/jest/mock.js +13 -1
  78. package/lib/commonjs/components/AddToWalletButton.js +1 -1
  79. package/lib/commonjs/components/AddToWalletButton.js.map +1 -1
  80. package/lib/commonjs/components/AddressSheet.js +1 -1
  81. package/lib/commonjs/components/AddressSheet.js.map +1 -1
  82. package/lib/commonjs/components/AuBECSDebitForm.js +1 -1
  83. package/lib/commonjs/components/AuBECSDebitForm.js.map +1 -1
  84. package/lib/commonjs/components/CardField.js +1 -1
  85. package/lib/commonjs/components/CardField.js.map +1 -1
  86. package/lib/commonjs/components/CardForm.js +1 -1
  87. package/lib/commonjs/components/CardForm.js.map +1 -1
  88. package/lib/commonjs/components/CurrencySelectorElement.js +2 -0
  89. package/lib/commonjs/components/CurrencySelectorElement.js.map +1 -0
  90. package/lib/commonjs/components/PaymentMethodMessagingElement.js +1 -1
  91. package/lib/commonjs/components/PaymentMethodMessagingElement.js.map +1 -1
  92. package/lib/commonjs/components/PlatformPayButton.js +1 -1
  93. package/lib/commonjs/components/PlatformPayButton.js.map +1 -1
  94. package/lib/commonjs/components/StripeContainer.js +1 -1
  95. package/lib/commonjs/components/StripeContainer.js.map +1 -1
  96. package/lib/commonjs/connect/Components.js +1 -1
  97. package/lib/commonjs/connect/Components.js.map +1 -1
  98. package/lib/commonjs/connect/ConnectComponentsProvider.js +1 -1
  99. package/lib/commonjs/connect/ConnectComponentsProvider.js.map +1 -1
  100. package/lib/commonjs/connect/EmbeddedComponent.js +1 -1
  101. package/lib/commonjs/connect/EmbeddedComponent.js.map +1 -1
  102. package/lib/commonjs/connect/ModalCloseButton.js +1 -1
  103. package/lib/commonjs/connect/ModalCloseButton.js.map +1 -1
  104. package/lib/commonjs/connect/NavigationBar.js +1 -1
  105. package/lib/commonjs/connect/NavigationBar.js.map +1 -1
  106. package/lib/commonjs/events.js.map +1 -1
  107. package/lib/commonjs/functions.js +1 -1
  108. package/lib/commonjs/functions.js.map +1 -1
  109. package/lib/commonjs/helpers.js +1 -1
  110. package/lib/commonjs/hooks/useCheckout.js +1 -1
  111. package/lib/commonjs/hooks/useCheckout.js.map +1 -1
  112. package/lib/commonjs/hooks/useOnramp.js +1 -1
  113. package/lib/commonjs/hooks/useOnramp.js.map +1 -1
  114. package/lib/commonjs/specs/NativeAddToWalletButton.js +1 -1
  115. package/lib/commonjs/specs/NativeAddressSheet.js +1 -1
  116. package/lib/commonjs/specs/NativeApplePayButton.js +1 -1
  117. package/lib/commonjs/specs/NativeAuBECSDebitForm.js +1 -1
  118. package/lib/commonjs/specs/NativeCardField.js +1 -1
  119. package/lib/commonjs/specs/NativeCardField.js.map +1 -1
  120. package/lib/commonjs/specs/NativeCardForm.js +1 -1
  121. package/lib/commonjs/specs/NativeCardForm.js.map +1 -1
  122. package/lib/commonjs/specs/NativeConnectAccountOnboardingView.js +1 -1
  123. package/lib/commonjs/specs/NativeCurrencySelectorElement.js +2 -0
  124. package/lib/commonjs/specs/NativeCurrencySelectorElement.js.map +1 -0
  125. package/lib/commonjs/specs/NativeEmbeddedPaymentElement.js +1 -1
  126. package/lib/commonjs/specs/NativeEmbeddedPaymentElement.js.map +1 -1
  127. package/lib/commonjs/specs/NativeGooglePayButton.js +1 -1
  128. package/lib/commonjs/specs/NativeNavigationBar.js +1 -1
  129. package/lib/commonjs/specs/NativeOnrampSdkModule.js.map +1 -1
  130. package/lib/commonjs/specs/NativePaymentMethodMessagingElement.js +1 -1
  131. package/lib/commonjs/specs/NativeStripeContainer.js +1 -1
  132. package/lib/commonjs/specs/NativeStripeSdkModule.js.map +1 -1
  133. package/lib/commonjs/types/EmbeddedPaymentElement.js +1 -1
  134. package/lib/commonjs/types/EmbeddedPaymentElement.js.map +1 -1
  135. package/lib/module/components/AddToWalletButton.js +1 -1
  136. package/lib/module/components/AddToWalletButton.js.map +1 -1
  137. package/lib/module/components/AddressSheet.js +1 -1
  138. package/lib/module/components/AddressSheet.js.map +1 -1
  139. package/lib/module/components/AuBECSDebitForm.js +1 -1
  140. package/lib/module/components/AuBECSDebitForm.js.map +1 -1
  141. package/lib/module/components/CardField.js +1 -1
  142. package/lib/module/components/CardField.js.map +1 -1
  143. package/lib/module/components/CardForm.js +1 -1
  144. package/lib/module/components/CardForm.js.map +1 -1
  145. package/lib/module/components/CurrencySelectorElement.js +2 -0
  146. package/lib/module/components/CurrencySelectorElement.js.map +1 -0
  147. package/lib/module/components/PaymentMethodMessagingElement.js +1 -1
  148. package/lib/module/components/PaymentMethodMessagingElement.js.map +1 -1
  149. package/lib/module/components/PlatformPayButton.js +1 -1
  150. package/lib/module/components/PlatformPayButton.js.map +1 -1
  151. package/lib/module/components/StripeContainer.js +1 -1
  152. package/lib/module/components/StripeContainer.js.map +1 -1
  153. package/lib/module/connect/Components.js +1 -1
  154. package/lib/module/connect/Components.js.map +1 -1
  155. package/lib/module/connect/ConnectComponentsProvider.js +1 -1
  156. package/lib/module/connect/ConnectComponentsProvider.js.map +1 -1
  157. package/lib/module/connect/EmbeddedComponent.js +1 -1
  158. package/lib/module/connect/EmbeddedComponent.js.map +1 -1
  159. package/lib/module/connect/ModalCloseButton.js +1 -1
  160. package/lib/module/connect/ModalCloseButton.js.map +1 -1
  161. package/lib/module/connect/NavigationBar.js +1 -1
  162. package/lib/module/connect/NavigationBar.js.map +1 -1
  163. package/lib/module/events.js.map +1 -1
  164. package/lib/module/functions.js +1 -1
  165. package/lib/module/functions.js.map +1 -1
  166. package/lib/module/helpers.js +1 -1
  167. package/lib/module/hooks/useCheckout.js +1 -1
  168. package/lib/module/hooks/useCheckout.js.map +1 -1
  169. package/lib/module/hooks/useOnramp.js +1 -1
  170. package/lib/module/hooks/useOnramp.js.map +1 -1
  171. package/lib/module/specs/NativeAddToWalletButton.js +1 -1
  172. package/lib/module/specs/NativeAddressSheet.js +1 -1
  173. package/lib/module/specs/NativeApplePayButton.js +1 -1
  174. package/lib/module/specs/NativeAuBECSDebitForm.js +1 -1
  175. package/lib/module/specs/NativeCardField.js +1 -1
  176. package/lib/module/specs/NativeCardField.js.map +1 -1
  177. package/lib/module/specs/NativeCardForm.js +1 -1
  178. package/lib/module/specs/NativeCardForm.js.map +1 -1
  179. package/lib/module/specs/NativeConnectAccountOnboardingView.js +1 -1
  180. package/lib/module/specs/NativeCurrencySelectorElement.js +2 -0
  181. package/lib/module/specs/NativeCurrencySelectorElement.js.map +1 -0
  182. package/lib/module/specs/NativeEmbeddedPaymentElement.js +1 -1
  183. package/lib/module/specs/NativeEmbeddedPaymentElement.js.map +1 -1
  184. package/lib/module/specs/NativeGooglePayButton.js +1 -1
  185. package/lib/module/specs/NativeNavigationBar.js +1 -1
  186. package/lib/module/specs/NativeOnrampSdkModule.js.map +1 -1
  187. package/lib/module/specs/NativePaymentMethodMessagingElement.js +1 -1
  188. package/lib/module/specs/NativeStripeContainer.js +1 -1
  189. package/lib/module/specs/NativeStripeSdkModule.js.map +1 -1
  190. package/lib/module/types/EmbeddedPaymentElement.js +1 -1
  191. package/lib/module/types/EmbeddedPaymentElement.js.map +1 -1
  192. package/lib/typescript/src/components/CurrencySelectorElement.d.ts +62 -0
  193. package/lib/typescript/src/components/CurrencySelectorElement.d.ts.map +1 -0
  194. package/lib/typescript/src/components/PaymentMethodMessagingElement.d.ts +1 -1
  195. package/lib/typescript/src/components/PaymentMethodMessagingElement.d.ts.map +1 -1
  196. package/lib/typescript/src/events.d.ts +11 -0
  197. package/lib/typescript/src/events.d.ts.map +1 -1
  198. package/lib/typescript/src/functions.d.ts.map +1 -1
  199. package/lib/typescript/src/hooks/useCheckout.d.ts.map +1 -1
  200. package/lib/typescript/src/hooks/useOnramp.d.ts +22 -0
  201. package/lib/typescript/src/hooks/useOnramp.d.ts.map +1 -1
  202. package/lib/typescript/src/specs/NativeCurrencySelectorElement.d.ts +25 -0
  203. package/lib/typescript/src/specs/NativeCurrencySelectorElement.d.ts.map +1 -0
  204. package/lib/typescript/src/specs/NativeEmbeddedPaymentElement.d.ts +5 -1
  205. package/lib/typescript/src/specs/NativeEmbeddedPaymentElement.d.ts.map +1 -1
  206. package/lib/typescript/src/specs/NativeOnrampSdkModule.d.ts +3 -0
  207. package/lib/typescript/src/specs/NativeOnrampSdkModule.d.ts.map +1 -1
  208. package/lib/typescript/src/specs/NativeStripeSdkModule.d.ts +5 -2
  209. package/lib/typescript/src/specs/NativeStripeSdkModule.d.ts.map +1 -1
  210. package/lib/typescript/src/types/Checkout.d.ts +268 -86
  211. package/lib/typescript/src/types/Checkout.d.ts.map +1 -1
  212. package/lib/typescript/src/types/EmbeddedPaymentElement.d.ts +36 -1
  213. package/lib/typescript/src/types/EmbeddedPaymentElement.d.ts.map +1 -1
  214. package/lib/typescript/src/types/Onramp.d.ts +94 -0
  215. package/lib/typescript/src/types/Onramp.d.ts.map +1 -1
  216. package/package.json +16 -4
  217. package/src/components/CurrencySelectorElement.tsx +95 -0
  218. package/src/components/PaymentMethodMessagingElement.tsx +54 -52
  219. package/src/events.ts +11 -0
  220. package/src/functions.ts +30 -1
  221. package/src/hooks/useCheckout.tsx +129 -74
  222. package/src/hooks/useOnramp.tsx +44 -0
  223. package/src/specs/NativeCurrencySelectorElement.ts +35 -0
  224. package/src/specs/NativeEmbeddedPaymentElement.ts +12 -2
  225. package/src/specs/NativeOnrampSdkModule.ts +5 -0
  226. package/src/specs/NativeStripeSdkModule.ts +16 -2
  227. package/src/types/Checkout.ts +291 -86
  228. package/src/types/EmbeddedPaymentElement.tsx +117 -26
  229. package/src/types/Onramp.ts +109 -0
  230. package/stripe-react-native.podspec +1 -1
  231. package/android/.idea/AndroidProjectSystem.xml +0 -6
  232. package/android/.idea/caches/deviceStreaming.xml +0 -835
  233. package/android/.idea/compiler.xml +0 -6
  234. package/android/.idea/gradle.xml +0 -17
  235. package/android/.idea/migrations.xml +0 -10
  236. package/android/.idea/misc.xml +0 -10
  237. package/android/.idea/runConfigurations.xml +0 -17
  238. package/android/.idea/vcs.xml +0 -6
  239. package/android/local.properties +0 -8
@@ -0,0 +1,57 @@
1
+ package com.reactnativestripesdk.utils;
2
+
3
+ import com.stripe.android.checkout.CheckoutSession;
4
+ import com.stripe.android.paymentsheet.verticalmode.CurrencySelectorOptions;
5
+ import java.util.Arrays;
6
+ import java.util.Collections;
7
+
8
+ public final class CheckoutTestFixtures {
9
+ private CheckoutTestFixtures() {}
10
+
11
+ public static CheckoutSession fullSession() {
12
+ CheckoutSession.TotalSummary totals =
13
+ new CheckoutSession.TotalSummary(
14
+ 5000L,
15
+ 4044L,
16
+ 4044L,
17
+ Arrays.asList(
18
+ new CheckoutSession.DiscountAmount(500L, "SUMMER10"),
19
+ new CheckoutSession.DiscountAmount(250L, "LOYALTY5")),
20
+ Collections.singletonList(
21
+ new CheckoutSession.TaxAmount(294L, false, "Sales Tax", 6.875d)),
22
+ new CheckoutSession.ShippingRate(
23
+ "shr_standard", 500L, "Standard Shipping", "5-7 business days"),
24
+ null);
25
+
26
+ return new CheckoutSession(
27
+ "cs_test_123",
28
+ CheckoutSession.Status.Open,
29
+ false,
30
+ "usd",
31
+ null,
32
+ new CheckoutSession.Tax(CheckoutSession.Tax.Status.Ready),
33
+ totals,
34
+ Arrays.asList(
35
+ new CheckoutSession.LineItem("li_item1", "Llama Figure", 2, null, 1998L, 1998L),
36
+ new CheckoutSession.LineItem("li_item2", "Alpaca Plushie", 1, 2499L, 2499L, 2499L)),
37
+ Arrays.asList(
38
+ new CheckoutSession.ShippingRate("shr_standard", 500L, "Standard Shipping", null),
39
+ new CheckoutSession.ShippingRate(
40
+ "shr_express", 1500L, "Express Shipping", "1-2 business days")),
41
+ (CurrencySelectorOptions) null);
42
+ }
43
+
44
+ public static CheckoutSession blankCurrencySession() {
45
+ return new CheckoutSession(
46
+ "cs_test_blank_currency",
47
+ CheckoutSession.Status.Open,
48
+ false,
49
+ "",
50
+ null,
51
+ new CheckoutSession.Tax(CheckoutSession.Tax.Status.Ready),
52
+ null,
53
+ Collections.<CheckoutSession.LineItem>emptyList(),
54
+ Collections.<CheckoutSession.ShippingRate>emptyList(),
55
+ (CurrencySelectorOptions) null);
56
+ }
57
+ }
@@ -122,12 +122,10 @@ class ConnectAccountOnboardingViewController: UIViewController {
122
122
  reactContentView?.layoutIfNeeded()
123
123
  }
124
124
 
125
- override func viewWillDisappear(_ animated: Bool) {
126
- super.viewWillDisappear(animated)
127
-
128
- // If being dismissed (not just going to background), notify
129
- if isBeingDismissed {
130
- onClose?()
131
- }
132
- }
125
+ // No viewWillDisappear/isBeingDismissed handler here. The modal uses .fullScreen
126
+ // presentation which prevents swipe-to-dismiss, so the only user-initiated exit path
127
+ // is the close button (handleCloseButtonPressed). Adding isBeingDismissed here would
128
+ // cause spurious onExit events when iOS presents a child VC (e.g. ASWebAuthenticationSession
129
+ // for identity verification) over this modal — UIKit calls viewWillDisappear and reports
130
+ // isBeingDismissed = true even though the user didn't close the modal.
133
131
  }
@@ -0,0 +1,16 @@
1
+ //
2
+ // CurrencySelectorElementManager.m
3
+ // stripe-react-native
4
+ //
5
+ // Created by Nick Porter on 5/7/26.
6
+ //
7
+
8
+ #import <Foundation/Foundation.h>
9
+ #import <React/RCTBridgeModule.h>
10
+ #import <React/RCTViewManager.h>
11
+
12
+ @interface RCT_EXTERN_MODULE(StripeCurrencySelectorElementManager, RCTViewManager)
13
+ RCT_EXPORT_VIEW_PROPERTY(sessionKey, NSString)
14
+ RCT_EXPORT_VIEW_PROPERTY(disabled, BOOL)
15
+ RCT_EXPORT_VIEW_PROPERTY(onHeightChange, RCTDirectEventBlock)
16
+ @end
@@ -0,0 +1,159 @@
1
+ //
2
+ // CurrencySelectorElementView.swift
3
+ // stripe-react-native
4
+ //
5
+ // Created by Nick Porter on 5/7/26.
6
+ //
7
+
8
+ import Combine
9
+ import Foundation
10
+ @_spi(ReactNativeSDK) import StripePaymentSheet
11
+ import UIKit
12
+
13
+ @objc(StripeCurrencySelectorElementManager)
14
+ class StripeCurrencySelectorElementManager: RCTViewManager {
15
+ override static func requiresMainQueueSetup() -> Bool {
16
+ return true
17
+ }
18
+
19
+ override func view() -> UIView! {
20
+ return StripeCurrencySelectorElementContainerView(frame: .zero)
21
+ }
22
+ }
23
+
24
+ @objc(StripeCurrencySelectorElementContainerView)
25
+ public class StripeCurrencySelectorElementContainerView: UIView {
26
+
27
+ // MARK: - Bridge-exposed Props
28
+
29
+ @objc public var sessionKey: String? {
30
+ didSet {
31
+ guard sessionKey != oldValue else { return }
32
+ attachToSessionIfPossible()
33
+ }
34
+ }
35
+
36
+ @objc public var disabled: Bool = false {
37
+ didSet {
38
+ selectorView?.isEnabled = !disabled
39
+ }
40
+ }
41
+
42
+ /// Fired whenever the inner selector's intrinsic height changes so RN
43
+ /// can match it. Session-state changes flow through the central
44
+ /// `checkoutSessionDidChangeState` event on `StripeSdk` (see
45
+ /// `CheckoutStateBridge`), so this view does not need to push state.
46
+ @objc public var onHeightChange: RCTDirectEventBlock?
47
+
48
+ // MARK: - Private Properties
49
+
50
+ private var selectorView: Checkout.CurrencySelectorView?
51
+ private var sessionCancellable: AnyCancellable?
52
+ private var lastReportedHeight: CGFloat = -1
53
+
54
+ // MARK: - Init
55
+
56
+ override public init(frame: CGRect) {
57
+ super.init(frame: frame)
58
+ backgroundColor = .clear
59
+ clipsToBounds = true
60
+ }
61
+
62
+ @available(*, unavailable)
63
+ required init?(coder _: NSCoder) {
64
+ fatalError("init(coder:) has not been implemented")
65
+ }
66
+
67
+ // MARK: - Layout
68
+
69
+ public override func layoutSubviews() {
70
+ super.layoutSubviews()
71
+ reportHeightIfNeeded()
72
+ }
73
+
74
+ // MARK: - Setup
75
+
76
+ private func attachToSessionIfPossible() {
77
+ Task { @MainActor in
78
+ guard let key = self.sessionKey,
79
+ let checkout = StripeSdkImpl.shared.checkoutInstances[key] else {
80
+ self.detach()
81
+ return
82
+ }
83
+
84
+ // Already showing a selector — leave it in place. Re-creating
85
+ // would interrupt the inner view's loading animation and reset
86
+ // its enabled state mid-API-call.
87
+ if self.selectorView != nil {
88
+ return
89
+ }
90
+
91
+ self.installSelectorView(for: checkout)
92
+ self.subscribeForLayoutUpdates(on: checkout)
93
+ }
94
+ }
95
+
96
+ /// We don't push state to JS here — `CheckoutStateBridge` already does
97
+ /// that for the whole session. This subscription only nudges Auto Layout
98
+ /// so the caption-text changes after a currency selection are reflected
99
+ /// in our reported height back to RN.
100
+ private func subscribeForLayoutUpdates(on checkout: Checkout) {
101
+ sessionCancellable = checkout.$state
102
+ .dropFirst()
103
+ .receive(on: DispatchQueue.main)
104
+ .sink { [weak self] _ in
105
+ guard let self else { return }
106
+ self.setNeedsLayout()
107
+ self.layoutIfNeeded()
108
+ self.reportHeightIfNeeded()
109
+ }
110
+ }
111
+
112
+ private func installSelectorView(for checkout: Checkout) {
113
+ let view = Checkout.CurrencySelectorView(checkout: checkout)
114
+ view.translatesAutoresizingMaskIntoConstraints = false
115
+ view.isEnabled = !disabled
116
+ addSubview(view)
117
+
118
+ NSLayoutConstraint.activate([
119
+ view.topAnchor.constraint(equalTo: topAnchor),
120
+ view.leadingAnchor.constraint(equalTo: leadingAnchor),
121
+ view.trailingAnchor.constraint(equalTo: trailingAnchor),
122
+ view.bottomAnchor.constraint(equalTo: bottomAnchor),
123
+ ])
124
+
125
+ selectorView = view
126
+
127
+ // Force an initial height report so RN can lay us out at zero
128
+ // when Adaptive Pricing is unavailable.
129
+ setNeedsLayout()
130
+ layoutIfNeeded()
131
+ }
132
+
133
+ private func detach() {
134
+ sessionCancellable?.cancel()
135
+ sessionCancellable = nil
136
+ selectorView?.removeFromSuperview()
137
+ selectorView = nil
138
+ lastReportedHeight = -1
139
+ }
140
+
141
+ // MARK: - Events
142
+
143
+ private func reportHeightIfNeeded() {
144
+ let desiredHeight: CGFloat
145
+ if let selectorView, !selectorView.isHidden {
146
+ desiredHeight = selectorView.systemLayoutSizeFitting(
147
+ CGSize(width: bounds.width, height: UIView.layoutFittingCompressedSize.height),
148
+ withHorizontalFittingPriority: .required,
149
+ verticalFittingPriority: .fittingSizeLevel
150
+ ).height
151
+ } else {
152
+ desiredHeight = 0
153
+ }
154
+
155
+ guard desiredHeight != lastReportedHeight else { return }
156
+ lastReportedHeight = desiredHeight
157
+ onHeightChange?(["height": desiredHeight])
158
+ }
159
+ }
@@ -6,7 +6,7 @@
6
6
  //
7
7
 
8
8
  import Foundation
9
- @_spi(EmbeddedPaymentElementPrivateBeta) import StripePaymentSheet
9
+ import StripePaymentSheet
10
10
  import UIKit
11
11
 
12
12
  @objc(EmbeddedPaymentElementView)
@@ -0,0 +1,337 @@
1
+ //
2
+ // Mappers+Checkout.swift
3
+ // stripe-react-native
4
+ //
5
+ // Created by Nick Porter on 4/29/26.
6
+ //
7
+
8
+ import Foundation
9
+ @_spi(ReactNativeSDK) import StripePaymentSheet
10
+
11
+ extension Mappers {
12
+
13
+ // MARK: - State & Session
14
+
15
+ class func mapFromCheckoutState(_ state: Checkout.State) -> NSDictionary {
16
+ [
17
+ "status": state.isLoading ? "loading" : "loaded",
18
+ "session": mapFromCheckoutSession(state.session),
19
+ ]
20
+ }
21
+
22
+ class func mapFromCheckoutSession(_ session: Checkout.Session) -> NSDictionary {
23
+ let result = NSMutableDictionary()
24
+ result["id"] = session.id
25
+ result["livemode"] = session.livemode
26
+ result["lineItems"] = session.lineItems.map(mapFromLineItem)
27
+ result["shippingOptions"] = session.shippingOptions.map(mapFromShippingOption)
28
+ result["discountAmounts"] = session.discountAmounts.map(mapFromDiscountAmount)
29
+ result["currencyOptions"] = session.currencyOptions.map(mapFromCurrencyOption)
30
+ result["tax"] = mapFromTax(session.tax)
31
+
32
+ if let businessName = session.businessName {
33
+ result["businessName"] = businessName
34
+ }
35
+ if let currency = session.currency {
36
+ result["currency"] = currency
37
+ }
38
+ if let email = session.email {
39
+ result["email"] = email
40
+ }
41
+ if let minorUnitsAmountDivisor = session.minorUnitsAmountDivisor {
42
+ result["minorUnitsAmountDivisor"] = minorUnitsAmountDivisor
43
+ }
44
+ if let status = session.status {
45
+ result["status"] = mapFromStatus(status)
46
+ }
47
+ if let total = session.total {
48
+ result["total"] = mapFromTotal(total)
49
+ }
50
+ if let shipping = session.shipping {
51
+ result["shipping"] = mapFromSelectedShipping(shipping)
52
+ }
53
+ if let billingAddress = session.billingAddress {
54
+ result["billingAddress"] = mapFromContactAddress(billingAddress)
55
+ }
56
+ if let shippingAddress = session.shippingAddress {
57
+ result["shippingAddress"] = mapFromContactAddress(shippingAddress)
58
+ }
59
+
60
+ return result
61
+ }
62
+
63
+ // MARK: - Amount
64
+
65
+ class func mapFromAmount(_ amount: Checkout.Amount) -> NSDictionary {
66
+ [
67
+ "amount": amount.amount,
68
+ "minorUnitsAmount": amount.minorUnitsAmount,
69
+ ]
70
+ }
71
+
72
+ class func mapFromDecimalAmount(_ decimalAmount: Checkout.DecimalAmount) -> NSDictionary {
73
+ [
74
+ "amount": decimalAmount.amount,
75
+ "minorUnitsAmount": NSDecimalNumber(decimal: decimalAmount.minorUnitsAmount).doubleValue,
76
+ ]
77
+ }
78
+
79
+ // MARK: - Status
80
+
81
+ class func mapFromStatus(_ status: Checkout.Status) -> NSDictionary {
82
+ let result = NSMutableDictionary()
83
+ result["type"] = mapFromStatusType(status.type)
84
+
85
+ if let paymentStatus = status.paymentStatus {
86
+ result["paymentStatus"] = mapFromPaymentStatus(paymentStatus)
87
+ }
88
+
89
+ return result
90
+ }
91
+
92
+ private class func mapFromStatusType(_ type: Checkout.StatusType) -> String {
93
+ switch type {
94
+ case .open: return "open"
95
+ case .complete: return "complete"
96
+ case .expired: return "expired"
97
+ case .unknown: return "unknown"
98
+ @unknown default: return "unknown"
99
+ }
100
+ }
101
+
102
+ private class func mapFromPaymentStatus(_ paymentStatus: Checkout.PaymentStatus) -> String {
103
+ switch paymentStatus {
104
+ case .paid: return "paid"
105
+ case .unpaid: return "unpaid"
106
+ case .noPaymentRequired: return "noPaymentRequired"
107
+ case .unknown: return "unknown"
108
+ @unknown default: return "unknown"
109
+ }
110
+ }
111
+
112
+ // MARK: - Total
113
+
114
+ class func mapFromTotal(_ total: Checkout.Total) -> NSDictionary {
115
+ [
116
+ "subtotal": mapFromAmount(total.subtotal),
117
+ "taxExclusive": mapFromAmount(total.taxExclusive),
118
+ "taxInclusive": mapFromAmount(total.taxInclusive),
119
+ "shippingRate": mapFromAmount(total.shippingRate),
120
+ "discount": mapFromAmount(total.discount),
121
+ "total": mapFromAmount(total.total),
122
+ "appliedBalance": mapFromAmount(total.appliedBalance),
123
+ "balanceAppliedToNextInvoice": total.balanceAppliedToNextInvoice,
124
+ ]
125
+ }
126
+
127
+ // MARK: - Tax
128
+
129
+ class func mapFromTax(_ tax: Checkout.Tax) -> NSDictionary {
130
+ let result = NSMutableDictionary()
131
+ result["status"] = mapFromTaxStatus(tax.status)
132
+
133
+ if let taxAmounts = tax.taxAmounts {
134
+ result["taxAmounts"] = taxAmounts.map(mapFromTaxAmount)
135
+ }
136
+
137
+ return result
138
+ }
139
+
140
+ private class func mapFromTaxStatus(_ status: Checkout.TaxStatus) -> String {
141
+ switch status {
142
+ case .ready: return "ready"
143
+ case .requiresShippingAddress: return "requiresShippingAddress"
144
+ case .requiresBillingAddress: return "requiresBillingAddress"
145
+ case .unknown: return "unknown"
146
+ @unknown default: return "unknown"
147
+ }
148
+ }
149
+
150
+ private class func mapFromTaxAmount(_ taxAmount: Checkout.TaxAmount) -> NSDictionary {
151
+ [
152
+ "amount": mapFromAmount(taxAmount.amount),
153
+ "inclusive": taxAmount.inclusive,
154
+ "displayName": taxAmount.displayName,
155
+ ]
156
+ }
157
+
158
+ // MARK: - Line Items
159
+
160
+ class func mapFromLineItem(_ lineItem: Checkout.LineItem) -> NSDictionary {
161
+ let result = NSMutableDictionary()
162
+ result["id"] = lineItem.id
163
+ result["name"] = lineItem.name
164
+ result["images"] = lineItem.images
165
+ result["quantity"] = lineItem.quantity
166
+ result["discountAmounts"] = lineItem.discountAmounts.map(mapFromDiscountAmount)
167
+ result["taxAmounts"] = lineItem.taxAmounts.map(mapFromTaxAmount)
168
+
169
+ if let description = lineItem.description {
170
+ result["description"] = description
171
+ }
172
+ if let unitAmount = lineItem.unitAmount {
173
+ result["unitAmount"] = mapFromAmount(unitAmount)
174
+ }
175
+ if let unitAmountDecimal = lineItem.unitAmountDecimal {
176
+ result["unitAmountDecimal"] = mapFromDecimalAmount(unitAmountDecimal)
177
+ }
178
+ if let subtotal = lineItem.subtotal {
179
+ result["subtotal"] = mapFromAmount(subtotal)
180
+ }
181
+ if let discount = lineItem.discount {
182
+ result["discount"] = mapFromAmount(discount)
183
+ }
184
+ if let taxExclusive = lineItem.taxExclusive {
185
+ result["taxExclusive"] = mapFromAmount(taxExclusive)
186
+ }
187
+ if let taxInclusive = lineItem.taxInclusive {
188
+ result["taxInclusive"] = mapFromAmount(taxInclusive)
189
+ }
190
+ if let total = lineItem.total {
191
+ result["total"] = mapFromAmount(total)
192
+ }
193
+ if let adjustableQuantity = lineItem.adjustableQuantity {
194
+ result["adjustableQuantity"] = mapFromAdjustableQuantity(adjustableQuantity)
195
+ }
196
+
197
+ return result
198
+ }
199
+
200
+ private class func mapFromAdjustableQuantity(_ adjustableQuantity: Checkout.AdjustableQuantity) -> NSDictionary {
201
+ [
202
+ "minimum": adjustableQuantity.minimum,
203
+ "maximum": adjustableQuantity.maximum,
204
+ ]
205
+ }
206
+
207
+ // MARK: - Shipping
208
+
209
+ class func mapFromShippingOption(_ shippingOption: Checkout.ShippingOption) -> NSDictionary {
210
+ let result = NSMutableDictionary()
211
+ result["id"] = shippingOption.id
212
+ result["amount"] = mapFromAmount(shippingOption.amount)
213
+ result["currency"] = shippingOption.currency
214
+
215
+ if let displayName = shippingOption.displayName {
216
+ result["displayName"] = displayName
217
+ }
218
+ if let deliveryEstimate = shippingOption.deliveryEstimate {
219
+ result["deliveryEstimate"] = mapFromDeliveryEstimate(deliveryEstimate)
220
+ }
221
+
222
+ return result
223
+ }
224
+
225
+ private class func mapFromDeliveryEstimate(_ estimate: Checkout.DeliveryEstimate) -> NSDictionary {
226
+ let result = NSMutableDictionary()
227
+
228
+ if let minimum = estimate.minimum {
229
+ result["minimum"] = mapFromDeliveryEstimateBound(minimum)
230
+ }
231
+ if let maximum = estimate.maximum {
232
+ result["maximum"] = mapFromDeliveryEstimateBound(maximum)
233
+ }
234
+
235
+ return result
236
+ }
237
+
238
+ private class func mapFromDeliveryEstimateBound(_ bound: Checkout.DeliveryEstimate.Bound) -> NSDictionary {
239
+ [
240
+ "unit": mapFromDeliveryEstimateUnit(bound.unit),
241
+ "value": bound.value,
242
+ ]
243
+ }
244
+
245
+ private class func mapFromDeliveryEstimateUnit(_ unit: Checkout.DeliveryEstimate.Bound.Unit) -> String {
246
+ switch unit {
247
+ case .hour: return "hour"
248
+ case .day: return "day"
249
+ case .businessDay: return "businessDay"
250
+ case .week: return "week"
251
+ case .month: return "month"
252
+ case .unknown: return "unknown"
253
+ @unknown default: return "unknown"
254
+ }
255
+ }
256
+
257
+ class func mapFromSelectedShipping(_ selectedShipping: Checkout.SelectedShipping) -> NSDictionary {
258
+ [
259
+ "shippingOption": mapFromShippingOption(selectedShipping.shippingOption),
260
+ "taxAmounts": selectedShipping.taxAmounts.map(mapFromTaxAmount),
261
+ ]
262
+ }
263
+
264
+ // MARK: - Discounts
265
+
266
+ class func mapFromDiscountAmount(_ discountAmount: Checkout.DiscountAmount) -> NSDictionary {
267
+ let result = NSMutableDictionary()
268
+ result["amount"] = mapFromAmount(discountAmount.amount)
269
+ result["displayName"] = discountAmount.displayName
270
+
271
+ if let promotionCode = discountAmount.promotionCode {
272
+ result["promotionCode"] = promotionCode
273
+ }
274
+
275
+ return result
276
+ }
277
+
278
+ // MARK: - Currency Options
279
+
280
+ class func mapFromCurrencyOption(_ currencyOption: Checkout.CurrencyOption) -> NSDictionary {
281
+ let result = NSMutableDictionary()
282
+ result["amount"] = mapFromAmount(currencyOption.amount)
283
+ result["currency"] = currencyOption.currency
284
+
285
+ if let currencyConversion = currencyOption.currencyConversion {
286
+ result["currencyConversion"] = mapFromCurrencyConversion(currencyConversion)
287
+ }
288
+
289
+ return result
290
+ }
291
+
292
+ private class func mapFromCurrencyConversion(_ conversion: Checkout.CurrencyConversion) -> NSDictionary {
293
+ [
294
+ "fxRate": conversion.fxRate,
295
+ "sourceCurrency": conversion.sourceCurrency,
296
+ ]
297
+ }
298
+
299
+ // MARK: - Address
300
+
301
+ class func mapFromContactAddress(_ contactAddress: Checkout.ContactAddress) -> NSDictionary {
302
+ let result = NSMutableDictionary()
303
+ result["address"] = mapFromCheckoutAddress(contactAddress.address)
304
+
305
+ if let name = contactAddress.name {
306
+ result["name"] = name
307
+ }
308
+ if let phone = contactAddress.phone {
309
+ result["phone"] = phone
310
+ }
311
+
312
+ return result
313
+ }
314
+
315
+ private class func mapFromCheckoutAddress(_ address: Checkout.Address) -> NSDictionary {
316
+ let result = NSMutableDictionary()
317
+ result["country"] = address.country
318
+
319
+ if let line1 = address.line1 {
320
+ result["line1"] = line1
321
+ }
322
+ if let line2 = address.line2 {
323
+ result["line2"] = line2
324
+ }
325
+ if let city = address.city {
326
+ result["city"] = city
327
+ }
328
+ if let state = address.state {
329
+ result["state"] = state
330
+ }
331
+ if let postalCode = address.postalCode {
332
+ result["postalCode"] = postalCode
333
+ }
334
+
335
+ return result
336
+ }
337
+ }