@whop/elements-react-native 0.1.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 (339) hide show
  1. package/README.md +179 -0
  2. package/android/build.gradle +64 -0
  3. package/android/consumer-rules.pro +3 -0
  4. package/android/gradle.properties +5 -0
  5. package/android/src/main/java/com/whop/elements/WhopAddressSuggestionsModule.kt +102 -0
  6. package/android/src/main/java/com/whop/elements/WhopAuthSessionModule.kt +126 -0
  7. package/android/src/main/java/com/whop/elements/WhopElementsPackage.kt +39 -0
  8. package/android/src/main/java/com/whop/elements/WhopPayButtonManager.kt +74 -0
  9. package/android/src/main/java/com/whop/elements/WhopPayButtonPressEvent.kt +17 -0
  10. package/android/src/main/java/com/whop/elements/WhopPayButtonView.kt +178 -0
  11. package/android/src/main/java/com/whop/elements/WhopPlatformPayModule.kt +212 -0
  12. package/assets/whop-wordmark-dark.png +0 -0
  13. package/assets/whop-wordmark-dark@2x.png +0 -0
  14. package/assets/whop-wordmark-dark@3x.png +0 -0
  15. package/assets/whop-wordmark-light.png +0 -0
  16. package/assets/whop-wordmark-light@2x.png +0 -0
  17. package/assets/whop-wordmark-light@3x.png +0 -0
  18. package/ios/Package.swift +59 -0
  19. package/ios/Sources/ElementsReactNative/WhopAddressSuggestionsImpl.swift +189 -0
  20. package/ios/Sources/ElementsReactNative/WhopAuthSessionImpl.swift +106 -0
  21. package/ios/Sources/ElementsReactNative/WhopPayButtonImpl.swift +89 -0
  22. package/ios/Sources/ElementsReactNative/WhopPlatformPayImpl.swift +181 -0
  23. package/ios/generated/WhopAddressSuggestionsModule.h +11 -0
  24. package/ios/generated/WhopAddressSuggestionsModule.mm +46 -0
  25. package/ios/generated/WhopAuthSessionModule.h +11 -0
  26. package/ios/generated/WhopAuthSessionModule.mm +45 -0
  27. package/ios/generated/WhopElementsShims.h +35 -0
  28. package/ios/generated/WhopPayButtonComponentView.h +12 -0
  29. package/ios/generated/WhopPayButtonComponentView.mm +82 -0
  30. package/ios/generated/WhopPlatformPayModule.h +11 -0
  31. package/ios/generated/WhopPlatformPayModule.mm +51 -0
  32. package/lib/module/api/client.js +139 -0
  33. package/lib/module/api/client.js.map +1 -0
  34. package/lib/module/api/client.test.js +137 -0
  35. package/lib/module/api/client.test.js.map +1 -0
  36. package/lib/module/api/types.js +2 -0
  37. package/lib/module/api/types.js.map +1 -0
  38. package/lib/module/controller/actions.js +148 -0
  39. package/lib/module/controller/actions.js.map +1 -0
  40. package/lib/module/controller/actions.test.js +102 -0
  41. package/lib/module/controller/actions.test.js.map +1 -0
  42. package/lib/module/controller/store.js +158 -0
  43. package/lib/module/controller/store.js.map +1 -0
  44. package/lib/module/core/address/country-data.js +1370 -0
  45. package/lib/module/core/address/country-data.js.map +1 -0
  46. package/lib/module/core/address/country-name.js +38 -0
  47. package/lib/module/core/address/country-name.js.map +1 -0
  48. package/lib/module/core/address/country-names.generated.js +249 -0
  49. package/lib/module/core/address/country-names.generated.js.map +1 -0
  50. package/lib/module/core/address/engine.js +245 -0
  51. package/lib/module/core/address/engine.js.map +1 -0
  52. package/lib/module/core/address/engine.test.js +216 -0
  53. package/lib/module/core/address/engine.test.js.map +1 -0
  54. package/lib/module/core/address/form-state.js +409 -0
  55. package/lib/module/core/address/form-state.js.map +1 -0
  56. package/lib/module/core/address/form-state.test.js +516 -0
  57. package/lib/module/core/address/form-state.test.js.map +1 -0
  58. package/lib/module/core/address/places.js +36 -0
  59. package/lib/module/core/address/places.js.map +1 -0
  60. package/lib/module/core/address/required-coverage.test.js +57 -0
  61. package/lib/module/core/address/required-coverage.test.js.map +1 -0
  62. package/lib/module/core/address/suggest.js +102 -0
  63. package/lib/module/core/address/suggest.js.map +1 -0
  64. package/lib/module/core/address/suggest.test.js +156 -0
  65. package/lib/module/core/address/suggest.test.js.map +1 -0
  66. package/lib/module/core/address/use-suggestions.js +33 -0
  67. package/lib/module/core/address/use-suggestions.js.map +1 -0
  68. package/lib/module/core/payments/address-change.js +91 -0
  69. package/lib/module/core/payments/address-change.js.map +1 -0
  70. package/lib/module/core/payments/billing-merge.js +62 -0
  71. package/lib/module/core/payments/billing-merge.js.map +1 -0
  72. package/lib/module/core/payments/browser-info.js +42 -0
  73. package/lib/module/core/payments/browser-info.js.map +1 -0
  74. package/lib/module/core/payments/bt.js +151 -0
  75. package/lib/module/core/payments/bt.js.map +1 -0
  76. package/lib/module/core/payments/bt.test.js +23 -0
  77. package/lib/module/core/payments/bt.test.js.map +1 -0
  78. package/lib/module/core/payments/currency.js +37 -0
  79. package/lib/module/core/payments/currency.js.map +1 -0
  80. package/lib/module/core/payments/detail.js +159 -0
  81. package/lib/module/core/payments/detail.js.map +1 -0
  82. package/lib/module/core/payments/detail.test.js +225 -0
  83. package/lib/module/core/payments/detail.test.js.map +1 -0
  84. package/lib/module/core/payments/errors.js +115 -0
  85. package/lib/module/core/payments/errors.js.map +1 -0
  86. package/lib/module/core/payments/mint.js +89 -0
  87. package/lib/module/core/payments/mint.js.map +1 -0
  88. package/lib/module/core/payments/plan.js +131 -0
  89. package/lib/module/core/payments/plan.js.map +1 -0
  90. package/lib/module/core/payments/refusals.js +17 -0
  91. package/lib/module/core/payments/refusals.js.map +1 -0
  92. package/lib/module/core/payments/secure-fields.js +87 -0
  93. package/lib/module/core/payments/secure-fields.js.map +1 -0
  94. package/lib/module/core/payments/tax-id-catalog.js +616 -0
  95. package/lib/module/core/payments/tax-id-catalog.js.map +1 -0
  96. package/lib/module/core/payments/wallet-contact.js +42 -0
  97. package/lib/module/core/payments/wallet-contact.js.map +1 -0
  98. package/lib/module/core/payments/wallet-contact.test.js +77 -0
  99. package/lib/module/core/payments/wallet-contact.test.js.map +1 -0
  100. package/lib/module/elements/address.js +467 -0
  101. package/lib/module/elements/address.js.map +1 -0
  102. package/lib/module/elements/branding.js +114 -0
  103. package/lib/module/elements/branding.js.map +1 -0
  104. package/lib/module/elements/card-fields/context.js +254 -0
  105. package/lib/module/elements/card-fields/context.js.map +1 -0
  106. package/lib/module/elements/card-fields/fields.js +309 -0
  107. package/lib/module/elements/card-fields/fields.js.map +1 -0
  108. package/lib/module/elements/card-fields/index.js +30 -0
  109. package/lib/module/elements/card-fields/index.js.map +1 -0
  110. package/lib/module/elements/card.js +107 -0
  111. package/lib/module/elements/card.js.map +1 -0
  112. package/lib/module/elements/email.js +84 -0
  113. package/lib/module/elements/email.js.map +1 -0
  114. package/lib/module/elements/payment/declared-fields.js +186 -0
  115. package/lib/module/elements/payment/declared-fields.js.map +1 -0
  116. package/lib/module/elements/payment/index.js +448 -0
  117. package/lib/module/elements/payment/index.js.map +1 -0
  118. package/lib/module/elements/payment/wallet.js +132 -0
  119. package/lib/module/elements/payment/wallet.js.map +1 -0
  120. package/lib/module/elements/tax-id.js +100 -0
  121. package/lib/module/elements/tax-id.js.map +1 -0
  122. package/lib/module/i18n/catalogs.js +103 -0
  123. package/lib/module/i18n/catalogs.js.map +1 -0
  124. package/lib/module/i18n/index.js +45 -0
  125. package/lib/module/i18n/index.js.map +1 -0
  126. package/lib/module/index.js +27 -0
  127. package/lib/module/index.js.map +1 -0
  128. package/lib/module/namespace.js +174 -0
  129. package/lib/module/namespace.js.map +1 -0
  130. package/lib/module/native/index.js +128 -0
  131. package/lib/module/native/index.js.map +1 -0
  132. package/lib/module/package.json +1 -0
  133. package/lib/module/provider.js +56 -0
  134. package/lib/module/provider.js.map +1 -0
  135. package/lib/module/specs/NativeWhopAddressSuggestions.js +6 -0
  136. package/lib/module/specs/NativeWhopAddressSuggestions.js.map +1 -0
  137. package/lib/module/specs/NativeWhopAuthSession.js +10 -0
  138. package/lib/module/specs/NativeWhopAuthSession.js.map +1 -0
  139. package/lib/module/specs/NativeWhopPlatformPay.js +10 -0
  140. package/lib/module/specs/NativeWhopPlatformPay.js.map +1 -0
  141. package/lib/module/specs/WhopPayButtonNativeComponent.ts +22 -0
  142. package/lib/module/theme/appearance.js +85 -0
  143. package/lib/module/theme/appearance.js.map +1 -0
  144. package/lib/module/theme/appearance.test.js +124 -0
  145. package/lib/module/theme/appearance.test.js.map +1 -0
  146. package/lib/module/theme/provider.js +25 -0
  147. package/lib/module/theme/provider.js.map +1 -0
  148. package/lib/module/theme/resolve.js +69 -0
  149. package/lib/module/theme/resolve.js.map +1 -0
  150. package/lib/module/theme/scales.generated.js +419 -0
  151. package/lib/module/theme/scales.generated.js.map +1 -0
  152. package/lib/module/ui/element-frame.js +83 -0
  153. package/lib/module/ui/element-frame.js.map +1 -0
  154. package/lib/module/ui/payment-method-icon.js +69 -0
  155. package/lib/module/ui/payment-method-icon.js.map +1 -0
  156. package/lib/module/ui/primitives.js +266 -0
  157. package/lib/module/ui/primitives.js.map +1 -0
  158. package/lib/module/ui/select.js +281 -0
  159. package/lib/module/ui/select.js.map +1 -0
  160. package/lib/module/ui/suggestions.js +71 -0
  161. package/lib/module/ui/suggestions.js.map +1 -0
  162. package/lib/module/ui/whop-logo.js +42 -0
  163. package/lib/module/ui/whop-logo.js.map +1 -0
  164. package/lib/typescript/package.json +1 -0
  165. package/lib/typescript/src/api/client.d.ts +87 -0
  166. package/lib/typescript/src/api/client.d.ts.map +1 -0
  167. package/lib/typescript/src/api/types.d.ts +175 -0
  168. package/lib/typescript/src/api/types.d.ts.map +1 -0
  169. package/lib/typescript/src/controller/actions.d.ts +42 -0
  170. package/lib/typescript/src/controller/actions.d.ts.map +1 -0
  171. package/lib/typescript/src/controller/store.d.ts +90 -0
  172. package/lib/typescript/src/controller/store.d.ts.map +1 -0
  173. package/lib/typescript/src/core/address/country-data.d.ts +4 -0
  174. package/lib/typescript/src/core/address/country-data.d.ts.map +1 -0
  175. package/lib/typescript/src/core/address/country-name.d.ts +2 -0
  176. package/lib/typescript/src/core/address/country-name.d.ts.map +1 -0
  177. package/lib/typescript/src/core/address/country-names.generated.d.ts +2 -0
  178. package/lib/typescript/src/core/address/country-names.generated.d.ts.map +1 -0
  179. package/lib/typescript/src/core/address/engine.d.ts +97 -0
  180. package/lib/typescript/src/core/address/engine.d.ts.map +1 -0
  181. package/lib/typescript/src/core/address/form-state.d.ts +144 -0
  182. package/lib/typescript/src/core/address/form-state.d.ts.map +1 -0
  183. package/lib/typescript/src/core/address/places.d.ts +23 -0
  184. package/lib/typescript/src/core/address/places.d.ts.map +1 -0
  185. package/lib/typescript/src/core/address/suggest.d.ts +47 -0
  186. package/lib/typescript/src/core/address/suggest.d.ts.map +1 -0
  187. package/lib/typescript/src/core/address/use-suggestions.d.ts +3 -0
  188. package/lib/typescript/src/core/address/use-suggestions.d.ts.map +1 -0
  189. package/lib/typescript/src/core/payments/address-change.d.ts +52 -0
  190. package/lib/typescript/src/core/payments/address-change.d.ts.map +1 -0
  191. package/lib/typescript/src/core/payments/billing-merge.d.ts +39 -0
  192. package/lib/typescript/src/core/payments/billing-merge.d.ts.map +1 -0
  193. package/lib/typescript/src/core/payments/browser-info.d.ts +12 -0
  194. package/lib/typescript/src/core/payments/browser-info.d.ts.map +1 -0
  195. package/lib/typescript/src/core/payments/bt.d.ts +55 -0
  196. package/lib/typescript/src/core/payments/bt.d.ts.map +1 -0
  197. package/lib/typescript/src/core/payments/currency.d.ts +7 -0
  198. package/lib/typescript/src/core/payments/currency.d.ts.map +1 -0
  199. package/lib/typescript/src/core/payments/detail.d.ts +53 -0
  200. package/lib/typescript/src/core/payments/detail.d.ts.map +1 -0
  201. package/lib/typescript/src/core/payments/errors.d.ts +62 -0
  202. package/lib/typescript/src/core/payments/errors.d.ts.map +1 -0
  203. package/lib/typescript/src/core/payments/mint.d.ts +74 -0
  204. package/lib/typescript/src/core/payments/mint.d.ts.map +1 -0
  205. package/lib/typescript/src/core/payments/plan.d.ts +69 -0
  206. package/lib/typescript/src/core/payments/plan.d.ts.map +1 -0
  207. package/lib/typescript/src/core/payments/refusals.d.ts +12 -0
  208. package/lib/typescript/src/core/payments/refusals.d.ts.map +1 -0
  209. package/lib/typescript/src/core/payments/secure-fields.d.ts +33 -0
  210. package/lib/typescript/src/core/payments/secure-fields.d.ts.map +1 -0
  211. package/lib/typescript/src/core/payments/tax-id-catalog.d.ts +481 -0
  212. package/lib/typescript/src/core/payments/tax-id-catalog.d.ts.map +1 -0
  213. package/lib/typescript/src/core/payments/wallet-contact.d.ts +40 -0
  214. package/lib/typescript/src/core/payments/wallet-contact.d.ts.map +1 -0
  215. package/lib/typescript/src/elements/address.d.ts +55 -0
  216. package/lib/typescript/src/elements/address.d.ts.map +1 -0
  217. package/lib/typescript/src/elements/branding.d.ts +18 -0
  218. package/lib/typescript/src/elements/branding.d.ts.map +1 -0
  219. package/lib/typescript/src/elements/card-fields/context.d.ts +67 -0
  220. package/lib/typescript/src/elements/card-fields/context.d.ts.map +1 -0
  221. package/lib/typescript/src/elements/card-fields/fields.d.ts +15 -0
  222. package/lib/typescript/src/elements/card-fields/fields.d.ts.map +1 -0
  223. package/lib/typescript/src/elements/card-fields/index.d.ts +21 -0
  224. package/lib/typescript/src/elements/card-fields/index.d.ts.map +1 -0
  225. package/lib/typescript/src/elements/card.d.ts +21 -0
  226. package/lib/typescript/src/elements/card.d.ts.map +1 -0
  227. package/lib/typescript/src/elements/email.d.ts +31 -0
  228. package/lib/typescript/src/elements/email.d.ts.map +1 -0
  229. package/lib/typescript/src/elements/payment/declared-fields.d.ts +43 -0
  230. package/lib/typescript/src/elements/payment/declared-fields.d.ts.map +1 -0
  231. package/lib/typescript/src/elements/payment/index.d.ts +37 -0
  232. package/lib/typescript/src/elements/payment/index.d.ts.map +1 -0
  233. package/lib/typescript/src/elements/payment/wallet.d.ts +39 -0
  234. package/lib/typescript/src/elements/payment/wallet.d.ts.map +1 -0
  235. package/lib/typescript/src/elements/tax-id.d.ts +41 -0
  236. package/lib/typescript/src/elements/tax-id.d.ts.map +1 -0
  237. package/lib/typescript/src/i18n/catalogs.d.ts +7 -0
  238. package/lib/typescript/src/i18n/catalogs.d.ts.map +1 -0
  239. package/lib/typescript/src/i18n/index.d.ts +17 -0
  240. package/lib/typescript/src/i18n/index.d.ts.map +1 -0
  241. package/lib/typescript/src/index.d.ts +42 -0
  242. package/lib/typescript/src/index.d.ts.map +1 -0
  243. package/lib/typescript/src/namespace.d.ts +36 -0
  244. package/lib/typescript/src/namespace.d.ts.map +1 -0
  245. package/lib/typescript/src/native/index.d.ts +62 -0
  246. package/lib/typescript/src/native/index.d.ts.map +1 -0
  247. package/lib/typescript/src/provider.d.ts +37 -0
  248. package/lib/typescript/src/provider.d.ts.map +1 -0
  249. package/lib/typescript/src/specs/NativeWhopAddressSuggestions.d.ts +13 -0
  250. package/lib/typescript/src/specs/NativeWhopAddressSuggestions.d.ts.map +1 -0
  251. package/lib/typescript/src/specs/NativeWhopAuthSession.d.ts +20 -0
  252. package/lib/typescript/src/specs/NativeWhopAuthSession.d.ts.map +1 -0
  253. package/lib/typescript/src/specs/NativeWhopPlatformPay.d.ts +24 -0
  254. package/lib/typescript/src/specs/NativeWhopPlatformPay.d.ts.map +1 -0
  255. package/lib/typescript/src/specs/WhopPayButtonNativeComponent.d.ts +21 -0
  256. package/lib/typescript/src/specs/WhopPayButtonNativeComponent.d.ts.map +1 -0
  257. package/lib/typescript/src/theme/appearance.d.ts +71 -0
  258. package/lib/typescript/src/theme/appearance.d.ts.map +1 -0
  259. package/lib/typescript/src/theme/provider.d.ts +11 -0
  260. package/lib/typescript/src/theme/provider.d.ts.map +1 -0
  261. package/lib/typescript/src/theme/resolve.d.ts +19 -0
  262. package/lib/typescript/src/theme/resolve.d.ts.map +1 -0
  263. package/lib/typescript/src/theme/scales.generated.d.ts +18 -0
  264. package/lib/typescript/src/theme/scales.generated.d.ts.map +1 -0
  265. package/lib/typescript/src/ui/element-frame.d.ts +32 -0
  266. package/lib/typescript/src/ui/element-frame.d.ts.map +1 -0
  267. package/lib/typescript/src/ui/payment-method-icon.d.ts +21 -0
  268. package/lib/typescript/src/ui/payment-method-icon.d.ts.map +1 -0
  269. package/lib/typescript/src/ui/primitives.d.ts +94 -0
  270. package/lib/typescript/src/ui/primitives.d.ts.map +1 -0
  271. package/lib/typescript/src/ui/select.d.ts +25 -0
  272. package/lib/typescript/src/ui/select.d.ts.map +1 -0
  273. package/lib/typescript/src/ui/suggestions.d.ts +15 -0
  274. package/lib/typescript/src/ui/suggestions.d.ts.map +1 -0
  275. package/lib/typescript/src/ui/whop-logo.d.ts +4 -0
  276. package/lib/typescript/src/ui/whop-logo.d.ts.map +1 -0
  277. package/package.json +121 -0
  278. package/scripts/check-swift.sh +27 -0
  279. package/scripts/codegen-shims.mjs +409 -0
  280. package/scripts/gen-country-names.mjs +58 -0
  281. package/scripts/gen-theme.mjs +124 -0
  282. package/scripts/gen-wordmark.mjs +68 -0
  283. package/scripts/mirror.mjs +112 -0
  284. package/src/api/client.ts +202 -0
  285. package/src/api/types.ts +166 -0
  286. package/src/controller/actions.ts +197 -0
  287. package/src/controller/store.ts +201 -0
  288. package/src/core/address/country-data.ts +927 -0
  289. package/src/core/address/country-name.ts +36 -0
  290. package/src/core/address/country-names.generated.ts +246 -0
  291. package/src/core/address/engine.ts +349 -0
  292. package/src/core/address/form-state.ts +479 -0
  293. package/src/core/address/places.ts +39 -0
  294. package/src/core/address/suggest.ts +153 -0
  295. package/src/core/address/use-suggestions.ts +37 -0
  296. package/src/core/payments/address-change.ts +121 -0
  297. package/src/core/payments/billing-merge.ts +91 -0
  298. package/src/core/payments/browser-info.ts +43 -0
  299. package/src/core/payments/bt.ts +176 -0
  300. package/src/core/payments/currency.ts +54 -0
  301. package/src/core/payments/detail.ts +204 -0
  302. package/src/core/payments/errors.ts +171 -0
  303. package/src/core/payments/mint.ts +130 -0
  304. package/src/core/payments/plan.ts +198 -0
  305. package/src/core/payments/refusals.ts +24 -0
  306. package/src/core/payments/secure-fields.ts +85 -0
  307. package/src/core/payments/tax-id-catalog.ts +320 -0
  308. package/src/core/payments/wallet-contact.ts +56 -0
  309. package/src/elements/address.tsx +570 -0
  310. package/src/elements/branding.tsx +87 -0
  311. package/src/elements/card-fields/context.tsx +310 -0
  312. package/src/elements/card-fields/fields.tsx +281 -0
  313. package/src/elements/card-fields/index.tsx +37 -0
  314. package/src/elements/card.tsx +101 -0
  315. package/src/elements/email.tsx +100 -0
  316. package/src/elements/payment/declared-fields.tsx +238 -0
  317. package/src/elements/payment/index.tsx +497 -0
  318. package/src/elements/payment/wallet.tsx +155 -0
  319. package/src/elements/tax-id.tsx +143 -0
  320. package/src/i18n/catalogs.ts +100 -0
  321. package/src/i18n/index.tsx +46 -0
  322. package/src/index.ts +68 -0
  323. package/src/namespace.tsx +231 -0
  324. package/src/native/index.ts +173 -0
  325. package/src/provider.tsx +76 -0
  326. package/src/specs/NativeWhopAddressSuggestions.ts +14 -0
  327. package/src/specs/NativeWhopAuthSession.ts +21 -0
  328. package/src/specs/NativeWhopPlatformPay.ts +25 -0
  329. package/src/specs/WhopPayButtonNativeComponent.ts +22 -0
  330. package/src/theme/appearance.ts +150 -0
  331. package/src/theme/provider.tsx +28 -0
  332. package/src/theme/resolve.ts +68 -0
  333. package/src/theme/scales.generated.ts +427 -0
  334. package/src/ui/element-frame.tsx +94 -0
  335. package/src/ui/payment-method-icon.tsx +55 -0
  336. package/src/ui/primitives.tsx +269 -0
  337. package/src/ui/select.tsx +255 -0
  338. package/src/ui/suggestions.tsx +69 -0
  339. package/src/ui/whop-logo.tsx +37 -0
package/README.md ADDED
@@ -0,0 +1,179 @@
1
+ # @whop/elements-react-native
2
+
3
+ Native React Native components for collecting payments with Whop.
4
+
5
+ No WebViews. The elements are real React Native views, card fields are PCI-isolated by Basis
6
+ Theory's React Native SDK, and the pieces that only the platform can do — the Apple Pay and Google
7
+ Pay sheets, their branded buttons, and the system browser a 3DS step opens in — are Swift and Kotlin
8
+ behind React Native Codegen.
9
+
10
+ ```tsx
11
+ import {
12
+ WhopElements, Payments, PaymentElement, AddressElement, EmailElement, BrandingElement,
13
+ } from '@whop/elements-react-native';
14
+
15
+ <WhopElements environment="production">
16
+ <Payments ref={payments} accountId="biz_…" plan="plan_…">
17
+ <EmailElement />
18
+ <AddressElement />
19
+ <PaymentElement onChange={(e) => setReady(e.complete)} />
20
+ <BrandingElement />
21
+ </Payments>
22
+ </WhopElements>;
23
+
24
+ const { confirmationToken } = await payments.current.createConfirmationToken();
25
+ ```
26
+
27
+ Confirm the token server-side, then hand any pending step to
28
+ `payments.current.handleNextAction({ clientSecret })`.
29
+
30
+ ## Requirements
31
+
32
+ | | |
33
+ | --- | --- |
34
+ | React Native | `>= 0.87`, New Architecture on |
35
+ | iOS | 15.1+, **Swift Package Manager** — this package ships no podspec |
36
+ | Android | minSdk 24, compileSdk 37 |
37
+ | Peers | `react` and `react-native` only — no native peer dependencies |
38
+
39
+ ## Elements
40
+
41
+ | Component | What it collects |
42
+ | --- | --- |
43
+ | `<PaymentElement />` | The offered payment methods and the selected one's required fields |
44
+ | `<AddressElement />` | A postal address, in the selected country's own format |
45
+ | `<CardElement />` | Card number, expiry, and security code, prearranged |
46
+ | `<CardFields>` + `<CardNumberElement />` `<CardExpiryElement />` `<CardCvcElement />` | The same three fields, placed individually |
47
+ | `<EmailElement />` | The buyer's email |
48
+ | `<TaxIdElement />` | A business tax registration |
49
+ | `<BrandingElement />` | Whop's merchant-of-record notice |
50
+
51
+ `<BrandingElement />` is required beside a payment surface: Whop is the merchant of record on these
52
+ sales, so `createConfirmationToken` refuses with `BRANDING_NOT_MOUNTED` without it.
53
+
54
+ `<AddressElement />` autocompletes by default from the **platform geocoder**, `MKLocalSearchCompleter`
55
+ on iOS and `android.location.Geocoder` on Android, so it needs no API key, no account, no location
56
+ permission and no extra dependency. Android resolves a complete address rather than predicting from a
57
+ fragment, so expect fewer and coarser suggestions there. A geocoder with no matches shows nothing and
58
+ the buyer types the address by hand, which is where they started: autocomplete never blocks a
59
+ checkout. Pass `autocomplete={false}` to turn it off.
60
+
61
+ ## `<Payments>`
62
+
63
+ | Prop | |
64
+ | --- | --- |
65
+ | `accountId` | The Whop company the sale belongs to |
66
+ | `plan` | The plan being sold, which resolves the currency, amount and offered methods. Pass `currency` and `amount` instead for an ad-hoc charge |
67
+ | `returnUrl` | Where the issuer returns after a redirect or 3DS step. Must be **https** and hosted by you, because the API refuses anything else, so a custom app scheme will not work. You do not register a deep link: `handleNextAction` polls the payment to rest and closes the browser itself |
68
+ | `applePayMerchantId` | Overrides the merchant identifier from the account's own Apple Pay registration. The Apple Pay tile is hidden only when neither exists |
69
+ | `googlePayMerchantName` | The name shown in the Google Pay sheet, defaulting to `Whop`. Google Pay needs nothing else from you |
70
+ | `order` | The method tile order, with Stripe's `paymentMethodOrder` semantics |
71
+
72
+ ## Appearance
73
+
74
+ One object, applied live — mounted elements restyle in place.
75
+
76
+ ```tsx
77
+ <WhopElements
78
+ appearance={{
79
+ theme: { appearance: 'dark', accentColor: 'blue' },
80
+ tokens: { radius: 12 },
81
+ parts: { 'whop-CardNumberField': { borderWidth: 2 } },
82
+ }}
83
+ >
84
+ ```
85
+
86
+ `theme` is identical to the web elements'. The two deltas are deliberate, because React Native has
87
+ no CSS:
88
+
89
+ - `tokens` replaces `variables` — a closed, typed map of **numbers**, not `"8px"` strings.
90
+ - `parts` replaces `classes` — the **same** `whop-*` part names, with React Native style objects
91
+ instead of CSS declarations. Flat per-part overrides: no cascade, no pseudo-classes.
92
+
93
+ Passing `variables` or `classes` throws by name rather than being silently ignored.
94
+
95
+ An unset `theme.appearance` follows the device's colour scheme.
96
+
97
+ ## Example app
98
+
99
+ ```bash
100
+ cd example
101
+ pnpm install
102
+ pnpm run setup # generates ios/ and android/, converts iOS to SwiftPM
103
+ pnpm run ios # or: pnpm run android
104
+ ```
105
+
106
+ Set your `accountId` and `plan` in `example/src/config.ts` first. It runs against
107
+ `production` by default — switch `environment` to `sandbox` there to point at the sandbox API.
108
+
109
+ `ios/` and `android/` are generated by `pnpm run setup` from the official React Native app template
110
+ rather than committed: they are several hundred files that belong to a React Native version, and
111
+ regenerating is how the example follows a version bump instead of drifting from it. The script also
112
+ converts the project to Swift Package Manager without ever invoking `pod` — it strips CocoaPods out
113
+ of the `.pbxproj` directly, because `react-native spm add --deintegrate` shells out to it.
114
+
115
+ One deliberate leftover: `ios/Podfile` stays as a pod-free stub. The React Native CLI locates the
116
+ iOS project by finding a Podfile, and `react-native spm` reads that location, so deleting it makes
117
+ `project.ios` resolve to `null` and the SPM setup fail. The example has three
118
+ screens: a realistic **Checkout**, a **Gallery** of each element with live prop controls, and
119
+ **Theming** applied to a live form.
120
+
121
+ The example is its own pnpm install root. React Native's `settings.gradle` does
122
+ `includeBuild("../node_modules/@react-native/gradle-plugin")`, which pnpm's isolated linker does not
123
+ expose, so `example/.npmrc` sets `node-linker=hoisted` — scoped there so the rest of the monorepo
124
+ stays isolated.
125
+
126
+ ## Native layer
127
+
128
+ Three units, all generated from `src/specs/` by React Native Codegen:
129
+
130
+ | Unit | Kind | iOS | Android |
131
+ | --- | --- | --- | --- |
132
+ | `WhopAuthSession` | Turbo Module | `ASWebAuthenticationSession` | Chrome Custom Tabs |
133
+ | `WhopPlatformPay` | Turbo Module | `PKPaymentAuthorizationController` | `PaymentsClient` |
134
+ | `WhopPayButton` | Fabric Component | `PKPaymentButton` | `PayButton` |
135
+
136
+ A redirect or 3DS step opens in the **system browser**, out of process — not a WebView the app can
137
+ read or script. `handleNextAction` then polls the payment to rest, because the API accepts only
138
+ https or loopback return URLs and a custom-scheme deep link back into the app is refused.
139
+
140
+ React Native cannot express a Fabric component or a Turbo Module in pure Swift: both need an
141
+ Objective-C++ class the C++ renderer can see. Nobody writes it here. `scripts/codegen-shims.mjs`
142
+ emits it from the same specs Codegen reads, into the gitignored `ios/generated/`, during `prepare`.
143
+ Every line a human writes on iOS is Swift and on Android is Kotlin.
144
+
145
+ The SDK has **no native peer dependencies**, deliberately: under Swift Package Manager, one peer
146
+ that ships no `Package.swift` makes the whole app unbuildable, and most of the React Native
147
+ ecosystem does not ship one yet. That is why the branding wordmark is drawn with plain views rather
148
+ than `react-native-svg`.
149
+
150
+ ## Not in this release
151
+
152
+ Absent entirely rather than half-present, so nothing renders that cannot work: saved payment
153
+ methods, the email code sign-in, installment tiers, ledger-balance payment, and the post-confirm
154
+ instruction panes.
155
+
156
+ ## Development
157
+
158
+ ```bash
159
+ pnpm install
160
+ pnpm build # emits ios/generated, then module + typescript targets
161
+ pnpm test
162
+ pnpm check-types
163
+ pnpm theme # regenerate src/theme/scales.generated.ts from frosted-ui's stylesheet
164
+ pnpm mirror # which files here mirror the web elements changed on this branch
165
+ pnpm check-swift # typecheck the Swift against the iOS SDK, no app build
166
+ ```
167
+
168
+ Nothing in `ios/Sources` imports React, so the whole Swift implementation typechecks standalone —
169
+ a wrong PassKit or AuthenticationServices symbol surfaces in seconds rather than one at a time
170
+ inside an Xcode build.
171
+
172
+ `pnpm mirror` answers the question a web author cannot otherwise ask, which files here implement the
173
+ same behaviour as the web elements they just changed. `scripts/mirror.mjs` derives the ported files
174
+ from their own headers and keeps an explicit table for the element components; `pnpm mirror:validate`
175
+ fails if either side of a pair has moved. Add a row when you add an element.
176
+
177
+ `src/core/` is ported verbatim from `frontend/apps/web/src/elements/`. Each file names its source in
178
+ a header, and the address engine's own test suite is ported with it, so the port is proved against
179
+ the same assertions the web elements pass.
@@ -0,0 +1,64 @@
1
+ buildscript {
2
+ ext.WhopElements = [
3
+ kotlinVersion: "2.2.0",
4
+ minSdkVersion: 24,
5
+ compileSdkVersion: 37,
6
+ buildToolsVersion: "37.0.0",
7
+ ndkVersion: "27.1.12297006",
8
+ ]
9
+
10
+ ext.getExtOrDefault = { prop ->
11
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : WhopElements[prop]
12
+ }
13
+
14
+ repositories {
15
+ google()
16
+ mavenCentral()
17
+ }
18
+
19
+ dependencies {
20
+ classpath "com.android.tools.build:gradle:9.0.0"
21
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
22
+ }
23
+ }
24
+
25
+ apply plugin: "com.android.library"
26
+ apply plugin: "kotlin-android"
27
+ apply plugin: "com.facebook.react"
28
+
29
+ android {
30
+ namespace "com.whop.elements"
31
+ compileSdkVersion getExtOrDefault("compileSdkVersion")
32
+ buildToolsVersion getExtOrDefault("buildToolsVersion")
33
+
34
+ defaultConfig {
35
+ minSdkVersion getExtOrDefault("minSdkVersion")
36
+ consumerProguardFiles "consumer-rules.pro"
37
+ }
38
+
39
+ compileOptions {
40
+ sourceCompatibility JavaVersion.VERSION_17
41
+ targetCompatibility JavaVersion.VERSION_17
42
+ }
43
+
44
+ kotlinOptions {
45
+ jvmTarget = "17"
46
+ }
47
+
48
+ sourceSets {
49
+ main {
50
+ java.srcDirs += "src/main/java"
51
+ }
52
+ }
53
+ }
54
+
55
+ repositories {
56
+ google()
57
+ mavenCentral()
58
+ }
59
+
60
+ dependencies {
61
+ implementation "com.facebook.react:react-android"
62
+ implementation "androidx.browser:browser:1.8.0"
63
+ implementation "com.google.android.gms:play-services-wallet:19.4.0"
64
+ }
@@ -0,0 +1,3 @@
1
+ # Codegen looks these up reflectively, and R8 has no reference to them from Kotlin.
2
+ -keep class com.whop.elements.** { *; }
3
+ -keep class com.facebook.react.viewmanagers.WhopPayButton** { *; }
@@ -0,0 +1,5 @@
1
+ # AGP 9 defaults the built-in Kotlin plugin and the new DSL on; react-native's gradle plugin
2
+ # is not compatible with either yet, and the 0.87 app template carries the same two opt-outs.
3
+ android.builtInKotlin=false
4
+ android.newDsl=false
5
+ android.useAndroidX=true
@@ -0,0 +1,102 @@
1
+ package com.whop.elements
2
+
3
+ import android.location.Address
4
+ import android.location.Geocoder
5
+ import com.facebook.react.bridge.Promise
6
+ import com.facebook.react.bridge.ReactApplicationContext
7
+ import com.facebook.react.module.annotations.ReactModule
8
+ import java.util.concurrent.Executors
9
+ import org.json.JSONArray
10
+ import org.json.JSONObject
11
+
12
+ /**
13
+ * Street suggestions, through the platform geocoder.
14
+ *
15
+ * `android.location.Geocoder` rather than the Google Places SDK: Places adds ~8 MB of dex that R8
16
+ * cannot shrink, merges ACCESS_FINE_LOCATION and three more permissions into every consuming app,
17
+ * and holds its API key in one process-global that the host app and this SDK would silently
18
+ * overwrite for each other. Geocoder is in the framework — no dependency, no key, no permission,
19
+ * no manifest entry, and nothing for a consumer to provision.
20
+ *
21
+ * Unlike MapKit, one geocode already returns full components for every candidate, so `resolve`
22
+ * reads the row this module cached rather than making a second call. The two-step shape is kept
23
+ * because the spec is shared with iOS, where it is not optional.
24
+ */
25
+ @ReactModule(name = WhopAddressSuggestionsModule.NAME)
26
+ class WhopAddressSuggestionsModule(reactContext: ReactApplicationContext) :
27
+ NativeWhopAddressSuggestionsSpec(reactContext) {
28
+
29
+ private val executor = Executors.newSingleThreadExecutor()
30
+
31
+ /** Content-keyed like the iOS port, so a resolve that lands after a newer query still finds its row. */
32
+ private val cache = object : LinkedHashMap<String, Address>(16, 0.75f, true) {
33
+ override fun removeEldestEntry(eldest: MutableMap.MutableEntry<String, Address>?): Boolean = size > CACHE_LIMIT
34
+ }
35
+
36
+ /** Not every device ships a geocoder backend, and a device without one answers nothing forever. */
37
+ override fun isAvailable(): Boolean = Geocoder.isPresent()
38
+
39
+ override fun suggest(query: String?, promise: Promise) {
40
+ val trimmed = query?.trim().orEmpty()
41
+ if (trimmed.length < MIN_QUERY_LENGTH) {
42
+ promise.resolve(EMPTY)
43
+ return
44
+ }
45
+ executor.execute {
46
+ // The blocking overload deliberately: the GeocodeListener form is API 33+, this module ships
47
+ // to minSdk 24, and one code path off the main thread beats two guarded by a version check.
48
+ @Suppress("DEPRECATION")
49
+ val results = runCatching { Geocoder(reactApplicationContext).getFromLocationName(trimmed, RESULT_LIMIT) }
50
+ .getOrNull()
51
+ .orEmpty()
52
+
53
+ val rows = JSONArray()
54
+ for (address in results) {
55
+ val label = label(address) ?: continue
56
+ synchronized(cache) { cache[label] = address }
57
+ rows.put(JSONObject().put("id", label).put("label", label))
58
+ }
59
+ promise.resolve(rows.toString())
60
+ }
61
+ }
62
+
63
+ override fun details(suggestionId: String?, promise: Promise) {
64
+ val address = suggestionId?.let { key -> synchronized(cache) { cache[key] } }
65
+ if (address == null) {
66
+ promise.resolve(EMPTY_OBJECT)
67
+ return
68
+ }
69
+ promise.resolve(components(address).toString())
70
+ }
71
+
72
+ /** The one-line form Geocoder already formats, falling back to the components it did return. */
73
+ private fun label(address: Address): String? {
74
+ val line = runCatching { address.getAddressLine(0) }.getOrNull()
75
+ if (!line.isNullOrBlank()) return line
76
+ val parts = listOfNotNull(
77
+ listOfNotNull(address.subThoroughfare, address.thoroughfare).joinToString(" ").ifBlank { null },
78
+ address.locality,
79
+ address.adminArea,
80
+ )
81
+ return parts.joinToString(", ").ifBlank { null }
82
+ }
83
+
84
+ /** Raw components only. `line1` composition is per-country and lives on the JS side. */
85
+ private fun components(address: Address): JSONObject =
86
+ JSONObject()
87
+ .put("streetNumber", address.subThoroughfare.orEmpty())
88
+ .put("street", address.thoroughfare.orEmpty())
89
+ .put("city", address.locality.orEmpty())
90
+ .put("state", address.adminArea.orEmpty())
91
+ .put("postalCode", address.postalCode.orEmpty())
92
+ .put("country", address.countryCode?.uppercase().orEmpty())
93
+
94
+ companion object {
95
+ const val NAME = "WhopAddressSuggestions"
96
+ private const val MIN_QUERY_LENGTH = 3
97
+ private const val RESULT_LIMIT = 5
98
+ private const val CACHE_LIMIT = 100
99
+ private const val EMPTY = "[]"
100
+ private const val EMPTY_OBJECT = "{}"
101
+ }
102
+ }
@@ -0,0 +1,126 @@
1
+ package com.whop.elements
2
+
3
+ import android.app.Activity
4
+ import android.content.Intent
5
+ import android.net.Uri
6
+ import androidx.browser.customtabs.CustomTabsIntent
7
+ import com.facebook.react.bridge.ActivityEventListener
8
+ import com.facebook.react.bridge.LifecycleEventListener
9
+ import com.facebook.react.bridge.Promise
10
+ import com.facebook.react.bridge.ReactApplicationContext
11
+ import com.facebook.react.module.annotations.ReactModule
12
+
13
+ /**
14
+ * The redirect and 3DS surface.
15
+ *
16
+ * A Custom Tab is Chrome rendering the page in its own process, so the host app can neither read the
17
+ * issuer's 3DS challenge nor script it. That is the difference between this and the `WebView` +
18
+ * `javaScriptEnabled` pattern, and it is the whole reason this module exists.
19
+ */
20
+ @ReactModule(name = WhopAuthSessionModule.NAME)
21
+ class WhopAuthSessionModule(reactContext: ReactApplicationContext) :
22
+ NativeWhopAuthSessionSpec(reactContext), ActivityEventListener, LifecycleEventListener {
23
+
24
+ private var pending: Promise? = null
25
+ private var browserTookOver = false
26
+
27
+ init {
28
+ reactContext.addActivityEventListener(this)
29
+ reactContext.addLifecycleEventListener(this)
30
+ }
31
+
32
+ override fun getName(): String = NAME
33
+
34
+ override fun isAvailable(): Boolean = true
35
+
36
+ override fun present(url: String?, callbackScheme: String?, prefersEphemeral: Boolean, promise: Promise) {
37
+ val target = url?.let(Uri::parse)
38
+ if (target == null || !target.scheme.equals("https", ignoreCase = true)) {
39
+ promise.reject("INVALID_URL", "whop elements: an https URL is required")
40
+ return
41
+ }
42
+ val activity: Activity? = reactApplicationContext.currentActivity
43
+ if (activity == null) {
44
+ promise.reject("NO_ACTIVITY", "whop elements: no activity is attached")
45
+ return
46
+ }
47
+
48
+ settle(null)
49
+ pending = promise
50
+ browserTookOver = false
51
+
52
+ val intent = CustomTabsIntent.Builder()
53
+ .setShowTitle(true)
54
+ .setUrlBarHidingEnabled(true)
55
+ .build()
56
+ if (prefersEphemeral) {
57
+ intent.intent.putExtra("com.android.browser.incognito", true)
58
+ }
59
+ intent.intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
60
+ runCatching { intent.launchUrl(activity, target) }
61
+ .onFailure {
62
+ pending = null
63
+ promise.reject("BROWSER_UNAVAILABLE", "whop elements: no browser could present the page")
64
+ }
65
+ }
66
+
67
+ /**
68
+ * A Custom Tab cannot be closed programmatically the way ASWebAuthenticationSession can, so
69
+ * settling the promise alone left the buyer looking at the return URL in Chrome while the app's
70
+ * result screen sat hidden behind it. The tab is an activity in this task, so relaunching the
71
+ * host activity on top of it pops it — REORDER_TO_FRONT alone would not, since the tab is above
72
+ * us and CLEAR_TOP is what removes it.
73
+ */
74
+ override fun dismiss() {
75
+ settle(null)
76
+ val activity = reactApplicationContext.currentActivity ?: return
77
+ activity.startActivity(
78
+ Intent(activity, activity.javaClass).addFlags(
79
+ Intent.FLAG_ACTIVITY_REORDER_TO_FRONT or
80
+ Intent.FLAG_ACTIVITY_CLEAR_TOP or
81
+ Intent.FLAG_ACTIVITY_SINGLE_TOP,
82
+ ),
83
+ )
84
+ }
85
+
86
+ /**
87
+ * A Custom Tab has no completion callback: the app simply comes back to the foreground. So the
88
+ * signal is a PAUSE followed by a RESUME — launching the tab pauses this activity, and coming
89
+ * back resumes it. Counting resumes instead would never settle, because the launch produces no
90
+ * resume of its own to skip.
91
+ *
92
+ * Resolving null is correct: a dismissal is an outcome, not a failure, and handleNextAction's
93
+ * poll is the authority on what actually happened to the payment. A completed redirect arrives
94
+ * as `onNewIntent` first and settles with the URL.
95
+ */
96
+ override fun onHostResume() {
97
+ if (pending == null || !browserTookOver) return
98
+ settle(null)
99
+ }
100
+
101
+ override fun onHostPause() {
102
+ if (pending != null) browserTookOver = true
103
+ }
104
+
105
+ override fun onHostDestroy() {
106
+ settle(null)
107
+ }
108
+
109
+ override fun onNewIntent(intent: Intent) {
110
+ val data = intent.data ?: return
111
+ settle(data.toString())
112
+ }
113
+
114
+ override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) = Unit
115
+
116
+ private fun settle(value: String?) {
117
+ val promise = pending ?: return
118
+ pending = null
119
+ browserTookOver = false
120
+ promise.resolve(value)
121
+ }
122
+
123
+ companion object {
124
+ const val NAME = "WhopAuthSession"
125
+ }
126
+ }
@@ -0,0 +1,39 @@
1
+ package com.whop.elements
2
+
3
+ import com.facebook.react.BaseReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.module.model.ReactModuleInfo
7
+ import com.facebook.react.module.model.ReactModuleInfoProvider
8
+ import com.facebook.react.uimanager.ViewManager
9
+
10
+ class WhopElementsPackage : BaseReactPackage() {
11
+
12
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? =
13
+ when (name) {
14
+ WhopAuthSessionModule.NAME -> WhopAuthSessionModule(reactContext)
15
+ WhopPlatformPayModule.NAME -> WhopPlatformPayModule(reactContext)
16
+ WhopAddressSuggestionsModule.NAME -> WhopAddressSuggestionsModule(reactContext)
17
+ else -> null
18
+ }
19
+
20
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> =
21
+ listOf(WhopPayButtonManager())
22
+
23
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider = ReactModuleInfoProvider {
24
+ listOf(
25
+ WhopAuthSessionModule.NAME,
26
+ WhopPlatformPayModule.NAME,
27
+ WhopAddressSuggestionsModule.NAME,
28
+ ).associateWith { name ->
29
+ ReactModuleInfo(
30
+ name,
31
+ name,
32
+ false,
33
+ false,
34
+ false,
35
+ true,
36
+ )
37
+ }
38
+ }
39
+ }
@@ -0,0 +1,74 @@
1
+ package com.whop.elements
2
+
3
+ import com.facebook.react.module.annotations.ReactModule
4
+ import com.facebook.react.uimanager.SimpleViewManager
5
+ import com.facebook.react.uimanager.ThemedReactContext
6
+ import com.facebook.react.uimanager.UIManagerHelper
7
+ import com.facebook.react.uimanager.common.UIManagerType
8
+ import com.facebook.react.uimanager.ViewManagerDelegate
9
+ import com.facebook.react.uimanager.annotations.ReactProp
10
+ import com.facebook.react.viewmanagers.WhopPayButtonManagerDelegate
11
+ import com.facebook.react.viewmanagers.WhopPayButtonManagerInterface
12
+
13
+ /**
14
+ * Google Pay's brand guidelines require the supplied control rather than a drawn imitation, which is
15
+ * why this is the one element surface that is a native view on Android.
16
+ *
17
+ * The interface and delegate this implements are Codegen output from
18
+ * `src/specs/WhopPayButtonNativeComponent.ts` — nothing here is hand-written Java.
19
+ */
20
+ @ReactModule(name = WhopPayButtonManager.NAME)
21
+ class WhopPayButtonManager :
22
+ SimpleViewManager<WhopPayButtonView>(), WhopPayButtonManagerInterface<WhopPayButtonView> {
23
+
24
+ private val delegate: ViewManagerDelegate<WhopPayButtonView> = WhopPayButtonManagerDelegate(this)
25
+
26
+ override fun getDelegate(): ViewManagerDelegate<WhopPayButtonView> = delegate
27
+
28
+ override fun getName(): String = NAME
29
+
30
+ public override fun createViewInstance(context: ThemedReactContext): WhopPayButtonView {
31
+ val button = WhopPayButtonView(context)
32
+ button.setOnPressListener {
33
+ val dispatcher = UIManagerHelper.getEventDispatcher(context, UIManagerType.FABRIC)
34
+ // Never dispatch a Fabric event from inside a layout or composition pass.
35
+ button.post {
36
+ dispatcher?.dispatchEvent(
37
+ WhopPayButtonPressEvent(UIManagerHelper.getSurfaceId(context), button.id),
38
+ )
39
+ }
40
+ }
41
+ return button
42
+ }
43
+
44
+ /** A direct event reaches JS only if the manager maps its native name to the prop that receives
45
+ * it. Without this the press is dispatched and silently dropped. */
46
+ override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> =
47
+ mutableMapOf(
48
+ WhopPayButtonPressEvent.EVENT_NAME to mutableMapOf("registrationName" to "onPayPress"),
49
+ )
50
+
51
+ @ReactProp(name = "variant")
52
+ override fun setVariant(view: WhopPayButtonView?, value: String?) {
53
+ view?.setVariant(value)
54
+ }
55
+
56
+ @ReactProp(name = "buttonAppearance")
57
+ override fun setButtonAppearance(view: WhopPayButtonView?, value: String?) {
58
+ view?.setButtonAppearance(value)
59
+ }
60
+
61
+ @ReactProp(name = "cornerRadius")
62
+ override fun setCornerRadius(view: WhopPayButtonView?, value: Double) {
63
+ view?.setCornerRadius(value)
64
+ }
65
+
66
+ @ReactProp(name = "disabled")
67
+ override fun setDisabled(view: WhopPayButtonView?, value: Boolean) {
68
+ view?.setDisabledState(value)
69
+ }
70
+
71
+ companion object {
72
+ const val NAME = "WhopPayButton"
73
+ }
74
+ }
@@ -0,0 +1,17 @@
1
+ package com.whop.elements
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.WritableMap
5
+ import com.facebook.react.uimanager.events.Event
6
+
7
+ class WhopPayButtonPressEvent(surfaceId: Int, viewId: Int) :
8
+ Event<WhopPayButtonPressEvent>(surfaceId, viewId) {
9
+
10
+ override fun getEventName(): String = EVENT_NAME
11
+
12
+ override fun getEventData(): WritableMap = Arguments.createMap()
13
+
14
+ companion object {
15
+ const val EVENT_NAME = "topPayPress"
16
+ }
17
+ }