framepayments-react-native 2.0.4 → 2.0.7
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.
- package/README.md +81 -0
- package/android/build.gradle +3 -3
- package/android/src/main/java/com/framepayments/reactnativeframe/FrameOnboardingActivity.kt +4 -1
- package/android/src/main/java/com/framepayments/reactnativeframe/FrameSDKModule.kt +2 -0
- package/ios/FrameRNTheme.swift +119 -0
- package/ios/FrameSDKBridge.m +25 -0
- package/ios/FrameSDKBridge.swift +48 -24
- package/lib/index.d.ts +5 -4
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +4 -3
- package/lib/native.d.ts +12 -1
- package/lib/native.d.ts.map +1 -1
- package/lib/native.js +21 -2
- package/lib/types.d.ts +55 -0
- package/lib/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/native.test.ts +33 -3
- package/src/index.ts +10 -1
- package/src/native.ts +31 -2
- package/src/types.ts +62 -0
package/README.md
CHANGED
|
@@ -191,6 +191,7 @@ if (result.status === 'completed') {
|
|
|
191
191
|
|---|---|---|---|
|
|
192
192
|
| `accountId` | `string` | No | The Frame account to onboard |
|
|
193
193
|
| `capabilities` | `OnboardingCapability[]` | No | Which onboarding steps to include (see below) |
|
|
194
|
+
| `applePayMerchantId` | `string` | No | Apple Pay merchant ID. When set, the onboarding flow includes an Apple Pay setup step. iOS only — ignored on Android. Same prerequisites as `presentApplePay`. |
|
|
194
195
|
|
|
195
196
|
**`capabilities` values:**
|
|
196
197
|
|
|
@@ -298,6 +299,86 @@ On non-Android platforms `Frame.presentGooglePay` rejects synchronously with a n
|
|
|
298
299
|
|
|
299
300
|
---
|
|
300
301
|
|
|
302
|
+
### `Frame.setTheme(theme)` (iOS)
|
|
303
|
+
|
|
304
|
+
Customizes colors, fonts, and corner radii on Frame's reusable components — checkout, cart, and the onboarding flow. Backed by `FrameTheme` introduced in Frame-iOS 2.1.2.
|
|
305
|
+
|
|
306
|
+
Call once at app startup (after `Frame.initialize`). The theme applies to every subsequent `present*` call. Modals already on screen are not re-themed mid-flow. Pass `null` or `{}` to reset to defaults; pass a partial dict to override only specific tokens.
|
|
307
|
+
|
|
308
|
+
```ts
|
|
309
|
+
import Frame from 'framepayments-react-native';
|
|
310
|
+
|
|
311
|
+
await Frame.setTheme({
|
|
312
|
+
colors: {
|
|
313
|
+
primaryButton: '#5B2DFF',
|
|
314
|
+
primaryButtonText: '#FFFFFF',
|
|
315
|
+
surface: '#0A0A0A',
|
|
316
|
+
textPrimary: '#FFFFFF',
|
|
317
|
+
error: '#E53935',
|
|
318
|
+
},
|
|
319
|
+
fonts: {
|
|
320
|
+
title: { name: 'Inter-Bold', size: 24 },
|
|
321
|
+
button: { name: 'Inter-SemiBold', size: 16 },
|
|
322
|
+
},
|
|
323
|
+
radii: { medium: 16 },
|
|
324
|
+
});
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**Android**: `setTheme()` resolves immediately and has no effect — `frame-android` does not yet have a matching theme API.
|
|
328
|
+
|
|
329
|
+
#### Tokens
|
|
330
|
+
|
|
331
|
+
**Colors** — hex strings (`#RGB`, `#RRGGBB`, or `#RRGGBBAA`, with or without leading `#`):
|
|
332
|
+
|
|
333
|
+
| Key | Used by |
|
|
334
|
+
|-----|---------|
|
|
335
|
+
| `primaryButton` / `primaryButtonText` | Primary CTAs |
|
|
336
|
+
| `secondaryButton` / `secondaryButtonText` | Secondary CTAs |
|
|
337
|
+
| `disabledButton` / `disabledButtonStroke` / `disabledButtonText` | Disabled CTAs |
|
|
338
|
+
| `surface` / `surfaceStroke` | Cards, sheets, input backgrounds |
|
|
339
|
+
| `textPrimary` / `textSecondary` | Body and supporting text |
|
|
340
|
+
| `error` | Validation messages |
|
|
341
|
+
| `onboardingHeaderBackground` | Onboarding header bar |
|
|
342
|
+
| `onboardingProgressFilledOnBrand` / `onboardingProgressEmptyOnBrand` | Onboarding progress indicator |
|
|
343
|
+
|
|
344
|
+
**Fonts** — `{ name: string; size: number }` objects. `name` must match a PostScript font name registered in your app's `Info.plist` (`UIAppFonts`) and bundled as a resource. Use `name: 'system'` for the system font.
|
|
345
|
+
|
|
346
|
+
| Key | Default | Used by |
|
|
347
|
+
|-----|---------|---------|
|
|
348
|
+
| `title` | `.title` | Page titles |
|
|
349
|
+
| `heading` | 18pt semibold | Section headers |
|
|
350
|
+
| `headline` | `.headline` | Card headlines |
|
|
351
|
+
| `body` | `.body` | Body text |
|
|
352
|
+
| `bodySmall` | 14pt | Smaller body |
|
|
353
|
+
| `label` | `.subheadline` | Field labels |
|
|
354
|
+
| `caption` | `.caption` | Captions, footnotes |
|
|
355
|
+
| `button` | `.headline` | Button text |
|
|
356
|
+
|
|
357
|
+
**Radii** — numbers (in points):
|
|
358
|
+
|
|
359
|
+
| Key | Default | Used by |
|
|
360
|
+
|-----|---------|---------|
|
|
361
|
+
| `small` | 8 | Small chips |
|
|
362
|
+
| `medium` | 10 | Buttons, inputs |
|
|
363
|
+
| `large` | 16 | Cards, sheets |
|
|
364
|
+
|
|
365
|
+
#### Custom fonts
|
|
366
|
+
|
|
367
|
+
Custom fonts are passed through to SwiftUI's `Font.custom(name:size:)`. Two requirements on the host iOS app:
|
|
368
|
+
|
|
369
|
+
1. Add the font file to your app's bundle (Xcode → Build Phases → Copy Bundle Resources).
|
|
370
|
+
2. Register it in your app's `Info.plist`:
|
|
371
|
+
```xml
|
|
372
|
+
<key>UIAppFonts</key>
|
|
373
|
+
<array>
|
|
374
|
+
<string>Inter-Bold.ttf</string>
|
|
375
|
+
</array>
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
If a font name doesn't resolve, iOS silently falls back to the system font.
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
301
382
|
### Rendering wallet buttons
|
|
302
383
|
|
|
303
384
|
Apple and Google both require their official button artwork (with light/dark variants) — custom-styled buttons can be rejected. Download the assets from [Apple's marketing page](https://developer.apple.com/apple-pay/marketing/) and [Google's brand guidelines page](https://developers.google.com/pay/api/android/guides/brand-guidelines), bundle them in your app, and pick a variant based on the active color scheme:
|
package/android/build.gradle
CHANGED
|
@@ -31,9 +31,9 @@ android {
|
|
|
31
31
|
dependencies {
|
|
32
32
|
implementation 'com.facebook.react:react-native:+'
|
|
33
33
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:2.1.0"
|
|
34
|
-
implementation 'com.framepayments:framesdk:2.0.
|
|
35
|
-
implementation 'com.framepayments:framesdk_ui:2.0.
|
|
36
|
-
implementation 'com.framepayments:framesdk_onboarding:2.0.
|
|
34
|
+
implementation 'com.framepayments:framesdk:2.0.4'
|
|
35
|
+
implementation 'com.framepayments:framesdk_ui:2.0.4'
|
|
36
|
+
implementation 'com.framepayments:framesdk_onboarding:2.0.4'
|
|
37
37
|
// Required by FrameGooglePayButton (PaymentsClient, WalletConstants).
|
|
38
38
|
// framesdk_ui declares this as `implementation`, so it is not exposed transitively.
|
|
39
39
|
implementation 'com.google.android.gms:play-services-wallet:19.4.0'
|
|
@@ -18,10 +18,12 @@ class FrameOnboardingActivity : ComponentActivity() {
|
|
|
18
18
|
val accountId = intent.getStringExtra(EXTRA_ACCOUNT_ID)
|
|
19
19
|
val capabilitiesJson = intent.getStringExtra(EXTRA_CAPABILITIES_JSON) ?: "[]"
|
|
20
20
|
val capabilities = parseCapabilities(capabilitiesJson)
|
|
21
|
+
val googlePayMerchantId = intent.getStringExtra(EXTRA_GOOGLE_PAY_MERCHANT_ID)
|
|
21
22
|
|
|
22
23
|
val config = OnboardingConfig(
|
|
23
24
|
accountId = accountId,
|
|
24
|
-
requiredCapabilities = capabilities
|
|
25
|
+
requiredCapabilities = capabilities,
|
|
26
|
+
googlePayMerchantId = googlePayMerchantId
|
|
25
27
|
)
|
|
26
28
|
|
|
27
29
|
setContent {
|
|
@@ -62,6 +64,7 @@ class FrameOnboardingActivity : ComponentActivity() {
|
|
|
62
64
|
companion object {
|
|
63
65
|
const val EXTRA_ACCOUNT_ID = "account_id"
|
|
64
66
|
const val EXTRA_CAPABILITIES_JSON = "capabilities_json"
|
|
67
|
+
const val EXTRA_GOOGLE_PAY_MERCHANT_ID = "google_pay_merchant_id"
|
|
65
68
|
const val EXTRA_PAYMENT_METHOD_ID = "payment_method_id"
|
|
66
69
|
const val REQUEST_CODE = 9003
|
|
67
70
|
}
|
|
@@ -119,6 +119,7 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
|
|
|
119
119
|
fun presentOnboarding(
|
|
120
120
|
accountId: String?,
|
|
121
121
|
capabilities: com.facebook.react.bridge.ReadableArray,
|
|
122
|
+
googlePayMerchantId: String?,
|
|
122
123
|
promise: Promise
|
|
123
124
|
) {
|
|
124
125
|
val activity = reactApplicationContext.currentActivity ?: run {
|
|
@@ -131,6 +132,7 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
|
|
|
131
132
|
val intent = Intent(activity, FrameOnboardingActivity::class.java).apply {
|
|
132
133
|
putExtra(FrameOnboardingActivity.EXTRA_ACCOUNT_ID, accountId)
|
|
133
134
|
putExtra(FrameOnboardingActivity.EXTRA_CAPABILITIES_JSON, capabilitiesJson)
|
|
135
|
+
putExtra(FrameOnboardingActivity.EXTRA_GOOGLE_PAY_MERCHANT_ID, googlePayMerchantId)
|
|
134
136
|
}
|
|
135
137
|
activity.startActivityForResult(intent, FrameOnboardingActivity.REQUEST_CODE)
|
|
136
138
|
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
//
|
|
2
|
+
// FrameRNTheme.swift
|
|
3
|
+
// FrameReactNative
|
|
4
|
+
//
|
|
5
|
+
// Bridges JS theme dictionaries to Frame-iOS's FrameTheme and applies it to
|
|
6
|
+
// every SwiftUI root view we present. Read/written only on the main thread.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Foundation
|
|
10
|
+
import SwiftUI
|
|
11
|
+
import Frame
|
|
12
|
+
|
|
13
|
+
enum FrameRNTheme {
|
|
14
|
+
// Main-thread only: written by FrameSDKBridge.setTheme (dispatched to main),
|
|
15
|
+
// read by present* methods (already on main).
|
|
16
|
+
static var current: FrameTheme? = nil
|
|
17
|
+
|
|
18
|
+
static func resolved() -> FrameTheme { current ?? .default }
|
|
19
|
+
|
|
20
|
+
static func parse(_ dict: [String: Any]) -> FrameTheme {
|
|
21
|
+
var theme = FrameTheme.default
|
|
22
|
+
|
|
23
|
+
if let colorsDict = dict["colors"] as? [String: Any] {
|
|
24
|
+
applyColor(colorsDict, "primaryButton") { theme.colors.primaryButton = $0 }
|
|
25
|
+
applyColor(colorsDict, "primaryButtonText") { theme.colors.primaryButtonText = $0 }
|
|
26
|
+
applyColor(colorsDict, "secondaryButton") { theme.colors.secondaryButton = $0 }
|
|
27
|
+
applyColor(colorsDict, "secondaryButtonText") { theme.colors.secondaryButtonText = $0 }
|
|
28
|
+
applyColor(colorsDict, "disabledButton") { theme.colors.disabledButton = $0 }
|
|
29
|
+
applyColor(colorsDict, "disabledButtonStroke") { theme.colors.disabledButtonStroke = $0 }
|
|
30
|
+
applyColor(colorsDict, "disabledButtonText") { theme.colors.disabledButtonText = $0 }
|
|
31
|
+
applyColor(colorsDict, "surface") { theme.colors.surface = $0 }
|
|
32
|
+
applyColor(colorsDict, "surfaceStroke") { theme.colors.surfaceStroke = $0 }
|
|
33
|
+
applyColor(colorsDict, "textPrimary") { theme.colors.textPrimary = $0 }
|
|
34
|
+
applyColor(colorsDict, "textSecondary") { theme.colors.textSecondary = $0 }
|
|
35
|
+
applyColor(colorsDict, "error") { theme.colors.error = $0 }
|
|
36
|
+
applyColor(colorsDict, "onboardingHeaderBackground") { theme.colors.onboardingHeaderBackground = $0 }
|
|
37
|
+
applyColor(colorsDict, "onboardingProgressFilledOnBrand") { theme.colors.onboardingProgressFilledOnBrand = $0 }
|
|
38
|
+
applyColor(colorsDict, "onboardingProgressEmptyOnBrand") { theme.colors.onboardingProgressEmptyOnBrand = $0 }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if let fontsDict = dict["fonts"] as? [String: Any] {
|
|
42
|
+
applyFont(fontsDict, "title") { theme.fonts.title = $0 }
|
|
43
|
+
applyFont(fontsDict, "heading") { theme.fonts.heading = $0 }
|
|
44
|
+
applyFont(fontsDict, "headline") { theme.fonts.headline = $0 }
|
|
45
|
+
applyFont(fontsDict, "body") { theme.fonts.body = $0 }
|
|
46
|
+
applyFont(fontsDict, "bodySmall") { theme.fonts.bodySmall = $0 }
|
|
47
|
+
applyFont(fontsDict, "label") { theme.fonts.label = $0 }
|
|
48
|
+
applyFont(fontsDict, "caption") { theme.fonts.caption = $0 }
|
|
49
|
+
applyFont(fontsDict, "button") { theme.fonts.button = $0 }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if let radiiDict = dict["radii"] as? [String: Any] {
|
|
53
|
+
if let v = radiiDict["small"] as? Double { theme.radii.small = CGFloat(v) }
|
|
54
|
+
if let v = radiiDict["medium"] as? Double { theme.radii.medium = CGFloat(v) }
|
|
55
|
+
if let v = radiiDict["large"] as? Double { theme.radii.large = CGFloat(v) }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return theme
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private static func applyColor(_ dict: [String: Any], _ key: String, _ set: (Color) -> Void) {
|
|
62
|
+
guard let hex = dict[key] as? String, let color = Color(rnHex: hex) else { return }
|
|
63
|
+
set(color)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private static func applyFont(_ dict: [String: Any], _ key: String, _ set: (Font) -> Void) {
|
|
67
|
+
guard let entry = dict[key] as? [String: Any],
|
|
68
|
+
let name = entry["name"] as? String,
|
|
69
|
+
let size = entry["size"] as? Double else { return }
|
|
70
|
+
if name.lowercased() == "system" {
|
|
71
|
+
set(.system(size: CGFloat(size)))
|
|
72
|
+
} else {
|
|
73
|
+
set(.custom(name, size: CGFloat(size)))
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Applies the supplied FrameTheme to a single root view. Captured at present
|
|
79
|
+
// time so each UIHostingController has a stable, concrete rootView type.
|
|
80
|
+
struct ThemedRoot<Content: View>: View {
|
|
81
|
+
let theme: FrameTheme
|
|
82
|
+
let content: Content
|
|
83
|
+
|
|
84
|
+
init(_ content: Content, theme: FrameTheme) {
|
|
85
|
+
self.content = content
|
|
86
|
+
self.theme = theme
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
var body: some View {
|
|
90
|
+
content.frameTheme(theme)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
extension Color {
|
|
95
|
+
// Accepts "#RGB", "#RRGGBB", "#RRGGBBAA" with or without the leading '#'.
|
|
96
|
+
init?(rnHex hex: String) {
|
|
97
|
+
var s = hex.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
98
|
+
if s.hasPrefix("#") { s.removeFirst() }
|
|
99
|
+
if s.count == 3 {
|
|
100
|
+
s = s.map { "\($0)\($0)" }.joined()
|
|
101
|
+
}
|
|
102
|
+
guard s.count == 6 || s.count == 8 else { return nil }
|
|
103
|
+
var v: UInt64 = 0
|
|
104
|
+
guard Scanner(string: s).scanHexInt64(&v) else { return nil }
|
|
105
|
+
let r, g, b, a: Double
|
|
106
|
+
if s.count == 6 {
|
|
107
|
+
r = Double((v >> 16) & 0xff) / 255
|
|
108
|
+
g = Double((v >> 8) & 0xff) / 255
|
|
109
|
+
b = Double( v & 0xff) / 255
|
|
110
|
+
a = 1
|
|
111
|
+
} else {
|
|
112
|
+
r = Double((v >> 24) & 0xff) / 255
|
|
113
|
+
g = Double((v >> 16) & 0xff) / 255
|
|
114
|
+
b = Double((v >> 8) & 0xff) / 255
|
|
115
|
+
a = Double( v & 0xff) / 255
|
|
116
|
+
}
|
|
117
|
+
self = Color(.sRGB, red: r, green: g, blue: b, opacity: a)
|
|
118
|
+
}
|
|
119
|
+
}
|
package/ios/FrameSDKBridge.m
CHANGED
|
@@ -31,6 +31,10 @@ RCT_EXTERN_METHOD(initialize:(NSString *)secretKey
|
|
|
31
31
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
32
32
|
rejecter:(RCTPromiseRejectBlock)reject)
|
|
33
33
|
|
|
34
|
+
RCT_EXTERN_METHOD(setTheme:(NSDictionary *)theme
|
|
35
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
36
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
37
|
+
|
|
34
38
|
RCT_EXTERN_METHOD(presentCheckout:(id)customerId
|
|
35
39
|
amount:(nonnull NSNumber *)amount
|
|
36
40
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
@@ -47,6 +51,12 @@ RCT_EXTERN_METHOD(presentOnboarding:(id)accountId
|
|
|
47
51
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
48
52
|
rejecter:(RCTPromiseRejectBlock)reject)
|
|
49
53
|
|
|
54
|
+
RCT_EXTERN_METHOD(presentOnboardingWithApplePay:(id)accountId
|
|
55
|
+
capabilities:(NSArray *)capabilities
|
|
56
|
+
applePayMerchantId:(id)applePayMerchantId
|
|
57
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
58
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
59
|
+
|
|
50
60
|
RCT_EXTERN_METHOD(presentApplePay:(NSString *)ownerType
|
|
51
61
|
ownerId:(NSString *)ownerId
|
|
52
62
|
amount:(nonnull NSNumber *)amount
|
|
@@ -70,6 +80,10 @@ RCT_EXTERN_METHOD(presentApplePay:(NSString *)ownerType
|
|
|
70
80
|
[[[ObjCFrameSDKBridge alloc] init] initialize:secretKey publishableKey:publishableKey debugMode:debugMode resolver:resolve rejecter:reject];
|
|
71
81
|
}
|
|
72
82
|
|
|
83
|
+
- (void)setTheme:(NSDictionary *)theme resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
|
|
84
|
+
[[[ObjCFrameSDKBridge alloc] init] setTheme:theme resolver:resolve rejecter:reject];
|
|
85
|
+
}
|
|
86
|
+
|
|
73
87
|
- (void)presentCheckout:(id)customerId amount:(NSNumber *)amount resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
|
|
74
88
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
75
89
|
UIViewController *topVC = FrameGetTopViewController();
|
|
@@ -104,6 +118,17 @@ RCT_EXTERN_METHOD(presentApplePay:(NSString *)ownerType
|
|
|
104
118
|
});
|
|
105
119
|
}
|
|
106
120
|
|
|
121
|
+
- (void)presentOnboardingWithApplePay:(id)accountId capabilities:(NSArray *)capabilities applePayMerchantId:(id)applePayMerchantId resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
|
|
122
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
123
|
+
UIViewController *topVC = FrameGetTopViewController();
|
|
124
|
+
if (!topVC) {
|
|
125
|
+
reject(@"NO_ROOT_VC", @"Could not find root view controller to present onboarding", nil);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
[[[ObjCFrameSDKBridge alloc] init] presentOnboardingWithApplePayFrom:topVC accountId:accountId capabilities:capabilities applePayMerchantId:applePayMerchantId resolver:resolve rejecter:reject];
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
107
132
|
- (void)presentApplePay:(NSString *)ownerType ownerId:(NSString *)ownerId amount:(NSNumber *)amount currency:(NSString *)currency merchantId:(NSString *)merchantId resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
|
|
108
133
|
[[[ObjCFrameSDKBridge alloc] init] presentApplePay:ownerType ownerId:ownerId amount:amount.intValue currency:currency merchantId:merchantId resolver:resolve rejecter:reject];
|
|
109
134
|
}
|
package/ios/FrameSDKBridge.swift
CHANGED
|
@@ -27,6 +27,15 @@ public class FrameSDKBridge: NSObject {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
@objc public
|
|
31
|
+
func setTheme(_ theme: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
32
|
+
DispatchQueue.main.async {
|
|
33
|
+
let dict = theme as? [String: Any] ?? [:]
|
|
34
|
+
FrameRNTheme.current = dict.isEmpty ? nil : FrameRNTheme.parse(dict)
|
|
35
|
+
resolve(nil)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
30
39
|
@objc public
|
|
31
40
|
func presentCheckout(from viewController: UIViewController, customerId: String?, amount: Int, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
32
41
|
presentCheckoutOnMain(from: viewController, customerId: customerId, amount: amount, resolve: resolve, reject: reject)
|
|
@@ -45,7 +54,15 @@ public class FrameSDKBridge: NSObject {
|
|
|
45
54
|
func presentOnboarding(from viewController: UIViewController, accountId: NSObject?, capabilities: NSArray, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
46
55
|
let parsedCapabilities = parseCapabilities(capabilities)
|
|
47
56
|
let accountIdString = accountId as? String
|
|
48
|
-
presentOnboardingOnMain(from: viewController, accountId: accountIdString, capabilities: parsedCapabilities, resolve: resolve, reject: reject)
|
|
57
|
+
presentOnboardingOnMain(from: viewController, accountId: accountIdString, capabilities: parsedCapabilities, applePayMerchantId: nil, resolve: resolve, reject: reject)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@objc public
|
|
61
|
+
func presentOnboardingWithApplePay(from viewController: UIViewController, accountId: NSObject?, capabilities: NSArray, applePayMerchantId: NSObject?, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
62
|
+
let parsedCapabilities = parseCapabilities(capabilities)
|
|
63
|
+
let accountIdString = accountId as? String
|
|
64
|
+
let merchantIdString = applePayMerchantId as? String
|
|
65
|
+
presentOnboardingOnMain(from: viewController, accountId: accountIdString, capabilities: parsedCapabilities, applePayMerchantId: merchantIdString, resolve: resolve, reject: reject)
|
|
49
66
|
}
|
|
50
67
|
|
|
51
68
|
@objc public
|
|
@@ -96,20 +113,23 @@ public class FrameSDKBridge: NSObject {
|
|
|
96
113
|
|
|
97
114
|
private func presentCheckoutOnMain(from top: UIViewController, customerId: String?, amount: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
98
115
|
var hosting: CheckoutHostingController!
|
|
99
|
-
hosting = CheckoutHostingController(rootView:
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
hosting
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
116
|
+
hosting = CheckoutHostingController(rootView: ThemedRoot(
|
|
117
|
+
FrameCheckoutView(
|
|
118
|
+
customerId: customerId,
|
|
119
|
+
paymentAmount: amount,
|
|
120
|
+
checkoutCallback: { [weak hosting] chargeIntent in
|
|
121
|
+
hosting?.didComplete = true
|
|
122
|
+
top.dismiss(animated: true)
|
|
123
|
+
DispatchQueue.main.async {
|
|
124
|
+
if let dict = Self.encodeChargeIntent(chargeIntent) {
|
|
125
|
+
resolve(dict)
|
|
126
|
+
} else {
|
|
127
|
+
reject("ENCODE_ERROR", "Failed to encode charge intent", nil)
|
|
128
|
+
}
|
|
110
129
|
}
|
|
111
130
|
}
|
|
112
|
-
|
|
131
|
+
),
|
|
132
|
+
theme: FrameRNTheme.resolved()
|
|
113
133
|
))
|
|
114
134
|
hosting.onCancel = {
|
|
115
135
|
DispatchQueue.main.async {
|
|
@@ -166,7 +186,7 @@ public class FrameSDKBridge: NSObject {
|
|
|
166
186
|
cartItems: cartItems,
|
|
167
187
|
shippingAmountInCents: shippingAmountInCents
|
|
168
188
|
)
|
|
169
|
-
let hosting = UIHostingController(rootView: cartView)
|
|
189
|
+
let hosting = UIHostingController(rootView: ThemedRoot(cartView, theme: FrameRNTheme.resolved()))
|
|
170
190
|
hosting.modalPresentationStyle = UIModalPresentationStyle.pageSheet
|
|
171
191
|
if let sheet = hosting.sheetPresentationController {
|
|
172
192
|
sheet.detents = [UISheetPresentationController.Detent.large()]
|
|
@@ -179,17 +199,21 @@ public class FrameSDKBridge: NSObject {
|
|
|
179
199
|
}
|
|
180
200
|
}
|
|
181
201
|
|
|
182
|
-
private func presentOnboardingOnMain(from top: UIViewController, accountId: String?, capabilities: [FrameObjects.Capabilities], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
183
|
-
var hosting: OnboardingHostingController<OnboardingContainerView
|
|
202
|
+
private func presentOnboardingOnMain(from top: UIViewController, accountId: String?, capabilities: [FrameObjects.Capabilities], applePayMerchantId: String?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
203
|
+
var hosting: OnboardingHostingController<ThemedRoot<OnboardingContainerView>>!
|
|
184
204
|
var delegate: OnboardingDismissDelegate!
|
|
185
205
|
hosting = OnboardingHostingController(
|
|
186
|
-
rootView:
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
206
|
+
rootView: ThemedRoot(
|
|
207
|
+
OnboardingContainerView(
|
|
208
|
+
accountId: accountId,
|
|
209
|
+
requiredCapabilities: capabilities,
|
|
210
|
+
applePayMerchantId: applePayMerchantId,
|
|
211
|
+
onComplete: { [weak hosting] in
|
|
212
|
+
delegate?.finish(completed: true)
|
|
213
|
+
hosting?.dismiss(animated: true)
|
|
214
|
+
}
|
|
215
|
+
),
|
|
216
|
+
theme: FrameRNTheme.resolved()
|
|
193
217
|
)
|
|
194
218
|
)
|
|
195
219
|
// Embed in a UINavigationController so the outer sheet is a UIKit container,
|
|
@@ -218,7 +242,7 @@ public class FrameSDKBridge: NSObject {
|
|
|
218
242
|
|
|
219
243
|
// MARK: - CheckoutHostingController
|
|
220
244
|
|
|
221
|
-
private final class CheckoutHostingController: UIHostingController<FrameCheckoutView
|
|
245
|
+
private final class CheckoutHostingController: UIHostingController<ThemedRoot<FrameCheckoutView>>, UIAdaptivePresentationControllerDelegate {
|
|
222
246
|
var didComplete = false
|
|
223
247
|
var onCancel: (() -> Void)?
|
|
224
248
|
private var cancelled = false
|
package/lib/index.d.ts
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
* - Use presentApplePay / presentGooglePay to launch the platform wallet sheet from your own button UI.
|
|
8
8
|
* - For API calls (customers, charge intents, refunds), use the framepayments (frame-node) package from JS.
|
|
9
9
|
*/
|
|
10
|
-
import { initialize, presentCheckout, presentCart, presentOnboarding, presentApplePay, presentGooglePay } from './native';
|
|
11
|
-
export { initialize, presentCheckout, presentCart, presentOnboarding, presentApplePay, presentGooglePay, } from './native';
|
|
12
|
-
export type { FrameCartItem, ChargeIntent, ChargeIntentStatus, AuthorizationMode, FrameError, BillingAddress, PaymentCard, BankAccount, PaymentMethod, OnboardingCapability, OnboardingResult, OnboardingResultStatus, ApplePayOwner, PresentApplePayOptions, PresentGooglePayOptions, } from './types';
|
|
10
|
+
import { initialize, presentCheckout, presentCart, presentOnboarding, presentApplePay, presentGooglePay, setTheme } from './native';
|
|
11
|
+
export { initialize, presentCheckout, presentCart, presentOnboarding, presentApplePay, presentGooglePay, setTheme, } from './native';
|
|
12
|
+
export type { FrameCartItem, ChargeIntent, ChargeIntentStatus, AuthorizationMode, FrameError, BillingAddress, PaymentCard, BankAccount, PaymentMethod, OnboardingCapability, OnboardingResult, OnboardingResultStatus, ApplePayOwner, PresentApplePayOptions, PresentGooglePayOptions, FrameTheme, FrameThemeColor, FrameThemeFont, FrameThemeColors, FrameThemeFonts, FrameThemeRadii, } from './types';
|
|
13
13
|
export { ErrorCodes } from './errors';
|
|
14
14
|
export type { FrameErrorShape, FrameErrorCode } from './errors';
|
|
15
|
-
/** Default export for Frame.initialize(), Frame.presentCheckout(), Frame.presentCart(), Frame.presentOnboarding(), Frame.presentApplePay(), Frame.presentGooglePay() */
|
|
15
|
+
/** Default export for Frame.initialize(), Frame.presentCheckout(), Frame.presentCart(), Frame.presentOnboarding(), Frame.presentApplePay(), Frame.presentGooglePay(), Frame.setTheme() */
|
|
16
16
|
declare const _default: {
|
|
17
17
|
initialize: typeof initialize;
|
|
18
18
|
presentCheckout: typeof presentCheckout;
|
|
@@ -20,6 +20,7 @@ declare const _default: {
|
|
|
20
20
|
presentOnboarding: typeof presentOnboarding;
|
|
21
21
|
presentApplePay: typeof presentApplePay;
|
|
22
22
|
presentGooglePay: typeof presentGooglePay;
|
|
23
|
+
setTheme: typeof setTheme;
|
|
23
24
|
};
|
|
24
25
|
export default _default;
|
|
25
26
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,UAAU,EACV,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,gBAAgB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,UAAU,EACV,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,QAAQ,EACT,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,UAAU,EACV,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,QAAQ,GACT,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,WAAW,EACX,WAAW,EACX,aAAa,EACb,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,EACtB,aAAa,EACb,sBAAsB,EACtB,uBAAuB,EACvB,UAAU,EACV,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,eAAe,GAChB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAEhE,0LAA0L;;;;;;;;;;AAC1L,wBAQE"}
|
package/lib/index.js
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
* - Use presentApplePay / presentGooglePay to launch the platform wallet sheet from your own button UI.
|
|
8
8
|
* - For API calls (customers, charge intents, refunds), use the framepayments (frame-node) package from JS.
|
|
9
9
|
*/
|
|
10
|
-
import { initialize, presentCheckout, presentCart, presentOnboarding, presentApplePay, presentGooglePay, } from './native';
|
|
11
|
-
export { initialize, presentCheckout, presentCart, presentOnboarding, presentApplePay, presentGooglePay, } from './native';
|
|
10
|
+
import { initialize, presentCheckout, presentCart, presentOnboarding, presentApplePay, presentGooglePay, setTheme, } from './native';
|
|
11
|
+
export { initialize, presentCheckout, presentCart, presentOnboarding, presentApplePay, presentGooglePay, setTheme, } from './native';
|
|
12
12
|
export { ErrorCodes } from './errors';
|
|
13
|
-
/** Default export for Frame.initialize(), Frame.presentCheckout(), Frame.presentCart(), Frame.presentOnboarding(), Frame.presentApplePay(), Frame.presentGooglePay() */
|
|
13
|
+
/** Default export for Frame.initialize(), Frame.presentCheckout(), Frame.presentCart(), Frame.presentOnboarding(), Frame.presentApplePay(), Frame.presentGooglePay(), Frame.setTheme() */
|
|
14
14
|
export default {
|
|
15
15
|
initialize,
|
|
16
16
|
presentCheckout,
|
|
@@ -18,4 +18,5 @@ export default {
|
|
|
18
18
|
presentOnboarding,
|
|
19
19
|
presentApplePay,
|
|
20
20
|
presentGooglePay,
|
|
21
|
+
setTheme,
|
|
21
22
|
};
|
package/lib/native.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Native module bridge. Uses NativeModules for classic React Native bridge.
|
|
3
3
|
*/
|
|
4
|
-
import type { ChargeIntent, FrameCartItem, OnboardingCapability, OnboardingResult, PresentApplePayOptions, PresentGooglePayOptions } from './types';
|
|
4
|
+
import type { ChargeIntent, FrameCartItem, FrameTheme, OnboardingCapability, OnboardingResult, PresentApplePayOptions, PresentGooglePayOptions } from './types';
|
|
5
5
|
export declare function initialize(options: {
|
|
6
6
|
secretKey: string;
|
|
7
7
|
publishableKey: string;
|
|
@@ -19,7 +19,18 @@ export declare function presentCart(options: {
|
|
|
19
19
|
export declare function presentOnboarding(options: {
|
|
20
20
|
accountId?: string | null;
|
|
21
21
|
capabilities?: OnboardingCapability[];
|
|
22
|
+
applePayMerchantId?: string | null;
|
|
23
|
+
googlePayMerchantId?: string | null;
|
|
22
24
|
}): Promise<OnboardingResult>;
|
|
23
25
|
export declare function presentApplePay(options: PresentApplePayOptions): Promise<ChargeIntent>;
|
|
24
26
|
export declare function presentGooglePay(options: PresentGooglePayOptions): Promise<ChargeIntent>;
|
|
27
|
+
/**
|
|
28
|
+
* Configure colors, fonts, and corner radii for Frame's reusable iOS
|
|
29
|
+
* components. Applied to every subsequent `present*` call; an in-flight modal
|
|
30
|
+
* is not re-themed mid-flow.
|
|
31
|
+
*
|
|
32
|
+
* Pass `null` or `{}` to reset to SDK defaults. Android is a no-op until
|
|
33
|
+
* frame-android ships a matching theme API.
|
|
34
|
+
*/
|
|
35
|
+
export declare function setTheme(theme: FrameTheme | null): Promise<void>;
|
|
25
36
|
//# sourceMappingURL=native.d.ts.map
|
package/lib/native.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACxB,MAAM,SAAS,CAAC;AAmBjB,wBAAgB,UAAU,CAAC,OAAO,EAAE;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBhB;AAwBD,wBAAgB,eAAe,CAAC,OAAO,EAAE;IACvC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,YAAY,CAAC,CAKxB;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE;IACnC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;CAC/B,GAAG,OAAO,CAAC,YAAY,CAAC,CASxB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,oBAAoB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,UAAU,EACV,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACxB,MAAM,SAAS,CAAC;AAmBjB,wBAAgB,UAAU,CAAC,OAAO,EAAE;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBhB;AAwBD,wBAAgB,eAAe,CAAC,OAAO,EAAE;IACvC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,YAAY,CAAC,CAKxB;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE;IACnC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;CAC/B,GAAG,OAAO,CAAC,YAAY,CAAC,CASxB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACtC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAkB5B;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,YAAY,CAAC,CAoBtF;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,YAAY,CAAC,CAUxF;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAMhE"}
|
package/lib/native.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Native module bridge. Uses NativeModules for classic React Native bridge.
|
|
3
3
|
*/
|
|
4
|
-
import { NativeModules } from 'react-native';
|
|
4
|
+
import { NativeModules, Platform } from 'react-native';
|
|
5
5
|
import { ErrorCodes } from './errors';
|
|
6
6
|
const LINKING_ERROR = `The package 'framepayments-react-native' doesn't seem to be linked. Make sure you have run 'pod install' (iOS) or rebuilt the app (Android).`;
|
|
7
7
|
const FrameSDK = NativeModules.FrameSDK
|
|
@@ -53,7 +53,10 @@ export function presentCart(options) {
|
|
|
53
53
|
}
|
|
54
54
|
export function presentOnboarding(options) {
|
|
55
55
|
guardInitialized();
|
|
56
|
-
|
|
56
|
+
if (Platform.OS === 'ios' && options.applePayMerchantId) {
|
|
57
|
+
return wrapPromise(FrameSDK.presentOnboardingWithApplePay(options.accountId ?? null, options.capabilities ?? [], options.applePayMerchantId));
|
|
58
|
+
}
|
|
59
|
+
return wrapPromise(FrameSDK.presentOnboarding(options.accountId ?? null, options.capabilities ?? [], options.googlePayMerchantId ?? null));
|
|
57
60
|
}
|
|
58
61
|
export function presentApplePay(options) {
|
|
59
62
|
guardInitialized();
|
|
@@ -72,3 +75,19 @@ export function presentGooglePay(options) {
|
|
|
72
75
|
guardInitialized();
|
|
73
76
|
return wrapPromise(FrameSDK.presentGooglePay(options.amountCents, options.customerId ?? null, options.currencyCode ?? 'USD', options.googlePayMerchantId ?? null));
|
|
74
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Configure colors, fonts, and corner radii for Frame's reusable iOS
|
|
80
|
+
* components. Applied to every subsequent `present*` call; an in-flight modal
|
|
81
|
+
* is not re-themed mid-flow.
|
|
82
|
+
*
|
|
83
|
+
* Pass `null` or `{}` to reset to SDK defaults. Android is a no-op until
|
|
84
|
+
* frame-android ships a matching theme API.
|
|
85
|
+
*/
|
|
86
|
+
export function setTheme(theme) {
|
|
87
|
+
if (theme !== null && (typeof theme !== 'object' || Array.isArray(theme))) {
|
|
88
|
+
throw new Error('Frame.setTheme requires a theme object or null');
|
|
89
|
+
}
|
|
90
|
+
if (Platform.OS !== 'ios')
|
|
91
|
+
return Promise.resolve();
|
|
92
|
+
return wrapPromise(FrameSDK.setTheme(theme ?? {}));
|
|
93
|
+
}
|
package/lib/types.d.ts
CHANGED
|
@@ -128,4 +128,59 @@ export interface PresentGooglePayOptions {
|
|
|
128
128
|
/** Optional override for the Google Pay merchant ID. */
|
|
129
129
|
googlePayMerchantId?: string;
|
|
130
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Theming for Frame's reusable iOS components (checkout, cart, onboarding).
|
|
133
|
+
* iOS-only: on Android, Frame.setTheme() resolves immediately and has no effect
|
|
134
|
+
* until frame-android ships a matching theme API.
|
|
135
|
+
*
|
|
136
|
+
* Pass any subset — unspecified tokens fall back to SDK defaults.
|
|
137
|
+
*/
|
|
138
|
+
/** Hex color: '#RGB', '#RRGGBB', or '#RRGGBBAA' (with or without leading '#'). */
|
|
139
|
+
export type FrameThemeColor = string;
|
|
140
|
+
/**
|
|
141
|
+
* Custom font reference. `name` must be a PostScript font name registered in
|
|
142
|
+
* the host app's Info.plist `UIAppFonts` and bundled as a resource. Pass
|
|
143
|
+
* `name: 'system'` to use the system font at the given size.
|
|
144
|
+
*/
|
|
145
|
+
export interface FrameThemeFont {
|
|
146
|
+
name: string;
|
|
147
|
+
size: number;
|
|
148
|
+
}
|
|
149
|
+
export interface FrameThemeColors {
|
|
150
|
+
primaryButton?: FrameThemeColor;
|
|
151
|
+
primaryButtonText?: FrameThemeColor;
|
|
152
|
+
secondaryButton?: FrameThemeColor;
|
|
153
|
+
secondaryButtonText?: FrameThemeColor;
|
|
154
|
+
disabledButton?: FrameThemeColor;
|
|
155
|
+
disabledButtonStroke?: FrameThemeColor;
|
|
156
|
+
disabledButtonText?: FrameThemeColor;
|
|
157
|
+
surface?: FrameThemeColor;
|
|
158
|
+
surfaceStroke?: FrameThemeColor;
|
|
159
|
+
textPrimary?: FrameThemeColor;
|
|
160
|
+
textSecondary?: FrameThemeColor;
|
|
161
|
+
error?: FrameThemeColor;
|
|
162
|
+
onboardingHeaderBackground?: FrameThemeColor;
|
|
163
|
+
onboardingProgressFilledOnBrand?: FrameThemeColor;
|
|
164
|
+
onboardingProgressEmptyOnBrand?: FrameThemeColor;
|
|
165
|
+
}
|
|
166
|
+
export interface FrameThemeFonts {
|
|
167
|
+
title?: FrameThemeFont;
|
|
168
|
+
heading?: FrameThemeFont;
|
|
169
|
+
headline?: FrameThemeFont;
|
|
170
|
+
body?: FrameThemeFont;
|
|
171
|
+
bodySmall?: FrameThemeFont;
|
|
172
|
+
label?: FrameThemeFont;
|
|
173
|
+
caption?: FrameThemeFont;
|
|
174
|
+
button?: FrameThemeFont;
|
|
175
|
+
}
|
|
176
|
+
export interface FrameThemeRadii {
|
|
177
|
+
small?: number;
|
|
178
|
+
medium?: number;
|
|
179
|
+
large?: number;
|
|
180
|
+
}
|
|
181
|
+
export interface FrameTheme {
|
|
182
|
+
colors?: FrameThemeColors;
|
|
183
|
+
fonts?: FrameThemeFonts;
|
|
184
|
+
radii?: FrameThemeRadii;
|
|
185
|
+
}
|
|
131
186
|
//# sourceMappingURL=types.d.ts.map
|
package/lib/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,2CAA2C;AAC3C,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,kBAAkB,GAC1B,UAAU,GACV,UAAU,GACV,QAAQ,GACR,YAAY,GACZ,SAAS,GACT,UAAU,GACV,UAAU,GACV,WAAW,CAAC;AAEhB,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,QAAQ,CAAC;AAEvD,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,GAAG,CAAC,EAAE,WAAW,CAAC;IAClB,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,gEAAgE;AAChE,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,sFAAsF;AACtF,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,+DAA+D;AAC/D,MAAM,MAAM,oBAAoB,GAC5B,KAAK,GACL,aAAa,GACb,oBAAoB,GACpB,gBAAgB,GAChB,mBAAmB,GACnB,WAAW,GACX,cAAc,GACd,sBAAsB,GACtB,2BAA2B,GAC3B,mBAAmB,GACnB,sBAAsB,GACtB,gBAAgB,GAChB,kBAAkB,CAAC;AAEvB,MAAM,MAAM,sBAAsB,GAAG,WAAW,GAAG,WAAW,CAAC;AAE/D,6CAA6C;AAC7C,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,sBAAsB,CAAC;IAC/B,oFAAoF;IACpF,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,8DAA8D;AAC9D,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpC,yCAAyC;AACzC,MAAM,WAAW,sBAAsB;IACrC,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,KAAK,EAAE,aAAa,CAAC;IACrB,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,0CAA0C;AAC1C,MAAM,WAAW,uBAAuB;IACtC,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wDAAwD;IACxD,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -7,6 +7,9 @@ const mockInitialize = jest.fn((_secretKey: string, _publishableKey: string, _de
|
|
|
7
7
|
const mockPresentCheckout = jest.fn((_customerId: unknown, _amount: number) => Promise.resolve({ id: 'ci_1', amount: 10000 }));
|
|
8
8
|
const mockPresentCart = jest.fn((_customerId: unknown, _items: unknown[], _shipping: number) => Promise.resolve({ id: 'ci_2', amount: 15000 }));
|
|
9
9
|
const mockPresentOnboarding = jest.fn((_accountId: unknown, _capabilities: unknown[]) => Promise.resolve({ status: 'completed', paymentMethodId: 'pm_1' }));
|
|
10
|
+
const mockPresentOnboardingWithApplePay = jest.fn((_accountId: unknown, _capabilities: unknown[], _merchantId: string) => Promise.resolve({ status: 'completed', paymentMethodId: 'pm_2' }));
|
|
11
|
+
|
|
12
|
+
const mockPlatform = { OS: 'ios' as 'ios' | 'android' };
|
|
10
13
|
|
|
11
14
|
jest.mock('react-native', () => ({
|
|
12
15
|
NativeModules: {
|
|
@@ -15,8 +18,10 @@ jest.mock('react-native', () => ({
|
|
|
15
18
|
presentCheckout: mockPresentCheckout,
|
|
16
19
|
presentCart: mockPresentCart,
|
|
17
20
|
presentOnboarding: mockPresentOnboarding,
|
|
21
|
+
presentOnboardingWithApplePay: mockPresentOnboardingWithApplePay,
|
|
18
22
|
},
|
|
19
23
|
},
|
|
24
|
+
Platform: mockPlatform,
|
|
20
25
|
}));
|
|
21
26
|
|
|
22
27
|
// Re-import after mock so we get the mocked NativeModules
|
|
@@ -27,7 +32,7 @@ let presentCart: (opts: {
|
|
|
27
32
|
items: Array<{ id: string; title: string; amountInCents: number; imageUrl: string }>;
|
|
28
33
|
shippingAmountInCents: number;
|
|
29
34
|
}) => Promise<unknown>;
|
|
30
|
-
let presentOnboarding: (opts: { accountId?: string | null; capabilities?: string[] }) => Promise<unknown>;
|
|
35
|
+
let presentOnboarding: (opts: { accountId?: string | null; capabilities?: string[]; applePayMerchantId?: string | null; googlePayMerchantId?: string | null }) => Promise<unknown>;
|
|
31
36
|
|
|
32
37
|
beforeEach(() => {
|
|
33
38
|
jest.resetModules();
|
|
@@ -35,6 +40,8 @@ beforeEach(() => {
|
|
|
35
40
|
mockPresentCheckout.mockClear();
|
|
36
41
|
mockPresentCart.mockClear();
|
|
37
42
|
mockPresentOnboarding.mockClear();
|
|
43
|
+
mockPresentOnboardingWithApplePay.mockClear();
|
|
44
|
+
mockPlatform.OS = 'ios';
|
|
38
45
|
const native = require('../native');
|
|
39
46
|
initialize = native.initialize;
|
|
40
47
|
presentCheckout = native.presentCheckout;
|
|
@@ -141,13 +148,36 @@ describe('presentOnboarding', () => {
|
|
|
141
148
|
it('calls native presentOnboarding with accountId and capabilities after initialize', async () => {
|
|
142
149
|
await initialize({ secretKey: 'sk_xxx', publishableKey: 'pk_xxx' });
|
|
143
150
|
const result = await presentOnboarding({ accountId: 'acct_1', capabilities: ['kyc', 'bank_account_verification'] });
|
|
144
|
-
expect(mockPresentOnboarding).toHaveBeenCalledWith('acct_1', ['kyc', 'bank_account_verification']);
|
|
151
|
+
expect(mockPresentOnboarding).toHaveBeenCalledWith('acct_1', ['kyc', 'bank_account_verification'], null);
|
|
145
152
|
expect(result).toEqual({ status: 'completed', paymentMethodId: 'pm_1' });
|
|
146
153
|
});
|
|
147
154
|
|
|
148
155
|
it('passes null for accountId and empty array for capabilities when not provided', async () => {
|
|
149
156
|
await initialize({ secretKey: 'sk_xxx', publishableKey: 'pk_xxx' });
|
|
150
157
|
await presentOnboarding({});
|
|
151
|
-
expect(mockPresentOnboarding).toHaveBeenCalledWith(null, []);
|
|
158
|
+
expect(mockPresentOnboarding).toHaveBeenCalledWith(null, [], null);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('routes to presentOnboardingWithApplePay on iOS when applePayMerchantId is set', async () => {
|
|
162
|
+
mockPlatform.OS = 'ios';
|
|
163
|
+
await initialize({ secretKey: 'sk_xxx', publishableKey: 'pk_xxx' });
|
|
164
|
+
await presentOnboarding({ accountId: 'acct_1', capabilities: ['kyc'], applePayMerchantId: 'merchant.com.example' });
|
|
165
|
+
expect(mockPresentOnboardingWithApplePay).toHaveBeenCalledWith('acct_1', ['kyc'], 'merchant.com.example');
|
|
166
|
+
expect(mockPresentOnboarding).not.toHaveBeenCalled();
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('still routes to presentOnboarding on Android even when applePayMerchantId is set', async () => {
|
|
170
|
+
mockPlatform.OS = 'android';
|
|
171
|
+
await initialize({ secretKey: 'sk_xxx', publishableKey: 'pk_xxx' });
|
|
172
|
+
await presentOnboarding({ accountId: 'acct_1', capabilities: ['kyc'], applePayMerchantId: 'merchant.com.example' });
|
|
173
|
+
expect(mockPresentOnboarding).toHaveBeenCalledWith('acct_1', ['kyc'], null);
|
|
174
|
+
expect(mockPresentOnboardingWithApplePay).not.toHaveBeenCalled();
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('forwards googlePayMerchantId to native presentOnboarding on Android', async () => {
|
|
178
|
+
mockPlatform.OS = 'android';
|
|
179
|
+
await initialize({ secretKey: 'sk_xxx', publishableKey: 'pk_xxx' });
|
|
180
|
+
await presentOnboarding({ accountId: 'acct_1', capabilities: ['kyc'], googlePayMerchantId: 'BCR2DN4T...' });
|
|
181
|
+
expect(mockPresentOnboarding).toHaveBeenCalledWith('acct_1', ['kyc'], 'BCR2DN4T...');
|
|
152
182
|
});
|
|
153
183
|
});
|
package/src/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
presentOnboarding,
|
|
16
16
|
presentApplePay,
|
|
17
17
|
presentGooglePay,
|
|
18
|
+
setTheme,
|
|
18
19
|
} from './native';
|
|
19
20
|
|
|
20
21
|
export {
|
|
@@ -24,6 +25,7 @@ export {
|
|
|
24
25
|
presentOnboarding,
|
|
25
26
|
presentApplePay,
|
|
26
27
|
presentGooglePay,
|
|
28
|
+
setTheme,
|
|
27
29
|
} from './native';
|
|
28
30
|
export type {
|
|
29
31
|
FrameCartItem,
|
|
@@ -41,11 +43,17 @@ export type {
|
|
|
41
43
|
ApplePayOwner,
|
|
42
44
|
PresentApplePayOptions,
|
|
43
45
|
PresentGooglePayOptions,
|
|
46
|
+
FrameTheme,
|
|
47
|
+
FrameThemeColor,
|
|
48
|
+
FrameThemeFont,
|
|
49
|
+
FrameThemeColors,
|
|
50
|
+
FrameThemeFonts,
|
|
51
|
+
FrameThemeRadii,
|
|
44
52
|
} from './types';
|
|
45
53
|
export { ErrorCodes } from './errors';
|
|
46
54
|
export type { FrameErrorShape, FrameErrorCode } from './errors';
|
|
47
55
|
|
|
48
|
-
/** Default export for Frame.initialize(), Frame.presentCheckout(), Frame.presentCart(), Frame.presentOnboarding(), Frame.presentApplePay(), Frame.presentGooglePay() */
|
|
56
|
+
/** Default export for Frame.initialize(), Frame.presentCheckout(), Frame.presentCart(), Frame.presentOnboarding(), Frame.presentApplePay(), Frame.presentGooglePay(), Frame.setTheme() */
|
|
49
57
|
export default {
|
|
50
58
|
initialize,
|
|
51
59
|
presentCheckout,
|
|
@@ -53,4 +61,5 @@ export default {
|
|
|
53
61
|
presentOnboarding,
|
|
54
62
|
presentApplePay,
|
|
55
63
|
presentGooglePay,
|
|
64
|
+
setTheme,
|
|
56
65
|
};
|
package/src/native.ts
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
* Native module bridge. Uses NativeModules for classic React Native bridge.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { NativeModules } from 'react-native';
|
|
5
|
+
import { NativeModules, Platform } from 'react-native';
|
|
6
6
|
import type {
|
|
7
7
|
ChargeIntent,
|
|
8
8
|
FrameCartItem,
|
|
9
|
+
FrameTheme,
|
|
9
10
|
OnboardingCapability,
|
|
10
11
|
OnboardingResult,
|
|
11
12
|
PresentApplePayOptions,
|
|
@@ -101,12 +102,24 @@ export function presentCart(options: {
|
|
|
101
102
|
export function presentOnboarding(options: {
|
|
102
103
|
accountId?: string | null;
|
|
103
104
|
capabilities?: OnboardingCapability[];
|
|
105
|
+
applePayMerchantId?: string | null;
|
|
106
|
+
googlePayMerchantId?: string | null;
|
|
104
107
|
}): Promise<OnboardingResult> {
|
|
105
108
|
guardInitialized();
|
|
109
|
+
if (Platform.OS === 'ios' && options.applePayMerchantId) {
|
|
110
|
+
return wrapPromise(
|
|
111
|
+
FrameSDK.presentOnboardingWithApplePay(
|
|
112
|
+
options.accountId ?? null,
|
|
113
|
+
options.capabilities ?? [],
|
|
114
|
+
options.applePayMerchantId
|
|
115
|
+
)
|
|
116
|
+
);
|
|
117
|
+
}
|
|
106
118
|
return wrapPromise(
|
|
107
119
|
FrameSDK.presentOnboarding(
|
|
108
120
|
options.accountId ?? null,
|
|
109
|
-
options.capabilities ?? []
|
|
121
|
+
options.capabilities ?? [],
|
|
122
|
+
options.googlePayMerchantId ?? null
|
|
110
123
|
)
|
|
111
124
|
);
|
|
112
125
|
}
|
|
@@ -144,3 +157,19 @@ export function presentGooglePay(options: PresentGooglePayOptions): Promise<Char
|
|
|
144
157
|
)
|
|
145
158
|
);
|
|
146
159
|
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Configure colors, fonts, and corner radii for Frame's reusable iOS
|
|
163
|
+
* components. Applied to every subsequent `present*` call; an in-flight modal
|
|
164
|
+
* is not re-themed mid-flow.
|
|
165
|
+
*
|
|
166
|
+
* Pass `null` or `{}` to reset to SDK defaults. Android is a no-op until
|
|
167
|
+
* frame-android ships a matching theme API.
|
|
168
|
+
*/
|
|
169
|
+
export function setTheme(theme: FrameTheme | null): Promise<void> {
|
|
170
|
+
if (theme !== null && (typeof theme !== 'object' || Array.isArray(theme))) {
|
|
171
|
+
throw new Error('Frame.setTheme requires a theme object or null');
|
|
172
|
+
}
|
|
173
|
+
if (Platform.OS !== 'ios') return Promise.resolve();
|
|
174
|
+
return wrapPromise(FrameSDK.setTheme(theme ?? {}));
|
|
175
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -162,3 +162,65 @@ export interface PresentGooglePayOptions {
|
|
|
162
162
|
/** Optional override for the Google Pay merchant ID. */
|
|
163
163
|
googlePayMerchantId?: string;
|
|
164
164
|
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Theming for Frame's reusable iOS components (checkout, cart, onboarding).
|
|
168
|
+
* iOS-only: on Android, Frame.setTheme() resolves immediately and has no effect
|
|
169
|
+
* until frame-android ships a matching theme API.
|
|
170
|
+
*
|
|
171
|
+
* Pass any subset — unspecified tokens fall back to SDK defaults.
|
|
172
|
+
*/
|
|
173
|
+
|
|
174
|
+
/** Hex color: '#RGB', '#RRGGBB', or '#RRGGBBAA' (with or without leading '#'). */
|
|
175
|
+
export type FrameThemeColor = string;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Custom font reference. `name` must be a PostScript font name registered in
|
|
179
|
+
* the host app's Info.plist `UIAppFonts` and bundled as a resource. Pass
|
|
180
|
+
* `name: 'system'` to use the system font at the given size.
|
|
181
|
+
*/
|
|
182
|
+
export interface FrameThemeFont {
|
|
183
|
+
name: string;
|
|
184
|
+
size: number;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export interface FrameThemeColors {
|
|
188
|
+
primaryButton?: FrameThemeColor;
|
|
189
|
+
primaryButtonText?: FrameThemeColor;
|
|
190
|
+
secondaryButton?: FrameThemeColor;
|
|
191
|
+
secondaryButtonText?: FrameThemeColor;
|
|
192
|
+
disabledButton?: FrameThemeColor;
|
|
193
|
+
disabledButtonStroke?: FrameThemeColor;
|
|
194
|
+
disabledButtonText?: FrameThemeColor;
|
|
195
|
+
surface?: FrameThemeColor;
|
|
196
|
+
surfaceStroke?: FrameThemeColor;
|
|
197
|
+
textPrimary?: FrameThemeColor;
|
|
198
|
+
textSecondary?: FrameThemeColor;
|
|
199
|
+
error?: FrameThemeColor;
|
|
200
|
+
onboardingHeaderBackground?: FrameThemeColor;
|
|
201
|
+
onboardingProgressFilledOnBrand?: FrameThemeColor;
|
|
202
|
+
onboardingProgressEmptyOnBrand?: FrameThemeColor;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export interface FrameThemeFonts {
|
|
206
|
+
title?: FrameThemeFont;
|
|
207
|
+
heading?: FrameThemeFont;
|
|
208
|
+
headline?: FrameThemeFont;
|
|
209
|
+
body?: FrameThemeFont;
|
|
210
|
+
bodySmall?: FrameThemeFont;
|
|
211
|
+
label?: FrameThemeFont;
|
|
212
|
+
caption?: FrameThemeFont;
|
|
213
|
+
button?: FrameThemeFont;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export interface FrameThemeRadii {
|
|
217
|
+
small?: number;
|
|
218
|
+
medium?: number;
|
|
219
|
+
large?: number;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export interface FrameTheme {
|
|
223
|
+
colors?: FrameThemeColors;
|
|
224
|
+
fonts?: FrameThemeFonts;
|
|
225
|
+
radii?: FrameThemeRadii;
|
|
226
|
+
}
|