react-native-klarna-inapp-sdk 2.4.9 → 2.5.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 (121) hide show
  1. package/README.md +2 -1
  2. package/android/build.gradle +3 -1
  3. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/KlarnaMobileSDKPackage.java +5 -1
  4. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/checkout/KlarnaCheckoutViewManager.java +4 -10
  5. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/WebViewResizeObserver.java +28 -0
  6. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/event/ComponentEventSender.java +5 -1
  7. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/ui/ResizeObserverWrapperView.java +2 -2
  8. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/ui/WrapperView.java +2 -2
  9. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/ui/YogaLayoutHelper.java +39 -0
  10. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/expresscheckout/KlarnaExpressCheckoutViewCallback.kt +30 -0
  11. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/expresscheckout/KlarnaExpressCheckoutViewEventSender.kt +80 -0
  12. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/expresscheckout/KlarnaExpressCheckoutViewManager.java +544 -0
  13. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/osm/KlarnaOSMViewEventHandler.java +30 -0
  14. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/osm/KlarnaOSMViewEventSender.java +64 -0
  15. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/osm/KlarnaOSMViewManager.java +356 -0
  16. package/android/src/newarch/java/com/klarna/mobile/sdk/reactnative/spec/RNKlarnaExpressCheckoutViewSpec.java +31 -0
  17. package/android/src/newarch/java/com/klarna/mobile/sdk/reactnative/spec/RNKlarnaOSMViewSpec.java +31 -0
  18. package/android/src/oldarch/java/com/klarna/mobile/sdk/reactnative/spec/RNKlarnaExpressCheckoutViewSpec.java +36 -0
  19. package/android/src/oldarch/java/com/klarna/mobile/sdk/reactnative/spec/RNKlarnaOSMViewSpec.java +32 -0
  20. package/android/src/test/java/com/klarna/mobile/sdk/reactnative/KlarnaMobileSDKPackageTest.java +5 -1
  21. package/android/src/test/java/com/klarna/mobile/sdk/reactnative/common/ui/YogaLayoutHelperTest.java +79 -0
  22. package/android/src/test/java/com/klarna/mobile/sdk/reactnative/expresscheckout/KlarnaExpressCheckoutViewManagerTest.java +259 -0
  23. package/android/src/test/java/com/klarna/mobile/sdk/reactnative/osm/KlarnaOSMViewEventHandlerTest.java +136 -0
  24. package/android/src/test/java/com/klarna/mobile/sdk/reactnative/osm/KlarnaOSMViewEventSenderTest.java +184 -0
  25. package/android/src/test/java/com/klarna/mobile/sdk/reactnative/osm/KlarnaOSMViewManagerTest.java +385 -0
  26. package/ios/RNKlarnaMobileSDK.xcodeproj/project.pbxproj +55 -1
  27. package/ios/Sources/KlarnaExpressCheckoutViewManager.h +5 -0
  28. package/ios/Sources/KlarnaExpressCheckoutViewManager.mm +39 -0
  29. package/ios/Sources/KlarnaOSMViewManager.h +5 -0
  30. package/ios/Sources/KlarnaOSMViewManager.mm +59 -0
  31. package/ios/Sources/view/KlarnaExpressCheckoutButtonDelegateProxy.swift +145 -0
  32. package/ios/Sources/view/KlarnaExpressCheckoutViewWrapper.h +41 -0
  33. package/ios/Sources/view/KlarnaOSMViewWrapper.h +48 -0
  34. package/ios/Sources/view/newarch/KlarnaExpressCheckoutViewWrapper.mm +228 -0
  35. package/ios/Sources/view/newarch/KlarnaOSMViewWrapper.mm +294 -0
  36. package/ios/Sources/view/newarch/KlarnaStandaloneWebViewWrapper.mm +20 -13
  37. package/ios/Sources/view/oldarch/KlarnaExpressCheckoutViewWrapper.mm +222 -0
  38. package/ios/Sources/view/oldarch/KlarnaOSMViewWrapper.mm +273 -0
  39. package/ios/Sources/view/oldarch/KlarnaStandaloneWebViewWrapper.mm +11 -13
  40. package/ios/Tests/KlarnaExpressCheckoutViewWrapperTests.m +391 -0
  41. package/ios/Tests/KlarnaOSMViewWrapperTests.m +450 -0
  42. package/ios/Tests/KlarnaStandaloneWebViewWrapperTests.m +105 -0
  43. package/lib/commonjs/KlarnaExpressCheckoutView.js +75 -0
  44. package/lib/commonjs/KlarnaExpressCheckoutView.js.map +1 -0
  45. package/lib/commonjs/KlarnaOSMView.js +94 -0
  46. package/lib/commonjs/KlarnaOSMView.js.map +1 -0
  47. package/lib/commonjs/index.js +99 -0
  48. package/lib/commonjs/index.js.map +1 -1
  49. package/lib/commonjs/specs/KlarnaExpressCheckoutViewNativeComponent.js +11 -0
  50. package/lib/commonjs/specs/KlarnaExpressCheckoutViewNativeComponent.js.map +1 -0
  51. package/lib/commonjs/specs/KlarnaOSMViewNativeComponent.js +16 -0
  52. package/lib/commonjs/specs/KlarnaOSMViewNativeComponent.js.map +1 -0
  53. package/lib/commonjs/types/button/KlarnaButtonShape.js +14 -0
  54. package/lib/commonjs/types/button/KlarnaButtonShape.js.map +1 -0
  55. package/lib/commonjs/types/button/KlarnaButtonStyle.js +13 -0
  56. package/lib/commonjs/types/button/KlarnaButtonStyle.js.map +1 -0
  57. package/lib/commonjs/types/button/KlarnaButtonTheme.js +14 -0
  58. package/lib/commonjs/types/button/KlarnaButtonTheme.js.map +1 -0
  59. package/lib/commonjs/types/common/KlarnaExpressCheckoutSessionOptions.js +9 -0
  60. package/lib/commonjs/types/common/KlarnaExpressCheckoutSessionOptions.js.map +1 -0
  61. package/lib/commonjs/types/common/KlarnaOSMPlacementKey.js +2 -0
  62. package/lib/commonjs/types/common/KlarnaOSMPlacementKey.js.map +1 -0
  63. package/lib/commonjs/types/common/KlarnaTheme.js +14 -0
  64. package/lib/commonjs/types/common/KlarnaTheme.js.map +1 -0
  65. package/lib/module/KlarnaExpressCheckoutView.js +64 -0
  66. package/lib/module/KlarnaExpressCheckoutView.js.map +1 -0
  67. package/lib/module/KlarnaOSMView.js +84 -0
  68. package/lib/module/KlarnaOSMView.js.map +1 -0
  69. package/lib/module/index.js +9 -0
  70. package/lib/module/index.js.map +1 -1
  71. package/lib/module/specs/KlarnaExpressCheckoutViewNativeComponent.js +3 -0
  72. package/lib/module/specs/KlarnaExpressCheckoutViewNativeComponent.js.map +1 -0
  73. package/lib/module/specs/KlarnaOSMViewNativeComponent.js +7 -0
  74. package/lib/module/specs/KlarnaOSMViewNativeComponent.js.map +1 -0
  75. package/lib/module/types/button/KlarnaButtonShape.js +7 -0
  76. package/lib/module/types/button/KlarnaButtonShape.js.map +1 -0
  77. package/lib/module/types/button/KlarnaButtonStyle.js +6 -0
  78. package/lib/module/types/button/KlarnaButtonStyle.js.map +1 -0
  79. package/lib/module/types/button/KlarnaButtonTheme.js +7 -0
  80. package/lib/module/types/button/KlarnaButtonTheme.js.map +1 -0
  81. package/lib/module/types/common/KlarnaExpressCheckoutSessionOptions.js +2 -0
  82. package/lib/module/types/common/KlarnaExpressCheckoutSessionOptions.js.map +1 -0
  83. package/lib/module/types/common/KlarnaOSMPlacementKey.js +2 -0
  84. package/lib/module/types/common/KlarnaOSMPlacementKey.js.map +1 -0
  85. package/lib/module/types/common/KlarnaTheme.js +7 -0
  86. package/lib/module/types/common/KlarnaTheme.js.map +1 -0
  87. package/lib/typescript/KlarnaExpressCheckoutView.d.ts +47 -0
  88. package/lib/typescript/KlarnaExpressCheckoutView.d.ts.map +1 -0
  89. package/lib/typescript/KlarnaOSMView.d.ts +36 -0
  90. package/lib/typescript/KlarnaOSMView.d.ts.map +1 -0
  91. package/lib/typescript/index.d.ts +9 -0
  92. package/lib/typescript/index.d.ts.map +1 -1
  93. package/lib/typescript/specs/KlarnaExpressCheckoutViewNativeComponent.d.ts +45 -0
  94. package/lib/typescript/specs/KlarnaExpressCheckoutViewNativeComponent.d.ts.map +1 -0
  95. package/lib/typescript/specs/KlarnaOSMViewNativeComponent.d.ts +35 -0
  96. package/lib/typescript/specs/KlarnaOSMViewNativeComponent.d.ts.map +1 -0
  97. package/lib/typescript/types/button/KlarnaButtonShape.d.ts +6 -0
  98. package/lib/typescript/types/button/KlarnaButtonShape.d.ts.map +1 -0
  99. package/lib/typescript/types/button/KlarnaButtonStyle.d.ts +5 -0
  100. package/lib/typescript/types/button/KlarnaButtonStyle.d.ts.map +1 -0
  101. package/lib/typescript/types/button/KlarnaButtonTheme.d.ts +6 -0
  102. package/lib/typescript/types/button/KlarnaButtonTheme.d.ts.map +1 -0
  103. package/lib/typescript/types/common/KlarnaExpressCheckoutSessionOptions.d.ts +10 -0
  104. package/lib/typescript/types/common/KlarnaExpressCheckoutSessionOptions.d.ts.map +1 -0
  105. package/lib/typescript/types/common/KlarnaOSMPlacementKey.d.ts +2 -0
  106. package/lib/typescript/types/common/KlarnaOSMPlacementKey.d.ts.map +1 -0
  107. package/lib/typescript/types/common/KlarnaTheme.d.ts +6 -0
  108. package/lib/typescript/types/common/KlarnaTheme.d.ts.map +1 -0
  109. package/package.json +8 -3
  110. package/react-native-klarna-inapp-sdk.podspec +2 -1
  111. package/src/KlarnaExpressCheckoutView.tsx +169 -0
  112. package/src/KlarnaOSMView.tsx +157 -0
  113. package/src/index.tsx +9 -0
  114. package/src/specs/KlarnaExpressCheckoutViewNativeComponent.ts +66 -0
  115. package/src/specs/KlarnaOSMViewNativeComponent.ts +50 -0
  116. package/src/types/button/KlarnaButtonShape.ts +5 -0
  117. package/src/types/button/KlarnaButtonStyle.ts +4 -0
  118. package/src/types/button/KlarnaButtonTheme.ts +5 -0
  119. package/src/types/common/KlarnaExpressCheckoutSessionOptions.ts +13 -0
  120. package/src/types/common/KlarnaOSMPlacementKey.ts +3 -0
  121. package/src/types/common/KlarnaTheme.ts +5 -0
@@ -0,0 +1,450 @@
1
+ #import <XCTest/XCTest.h>
2
+ #import <OCMock/OCMock.h>
3
+ #import <React/RCTComponent.h>
4
+ #import <KlarnaMobileSDK/KlarnaMobileSDK.h>
5
+ #import <KlarnaMobileSDK/KlarnaMobileSDK-Swift.h>
6
+
7
+ #import "../Sources/view/KlarnaOSMViewWrapper.h"
8
+
9
+ @interface KlarnaOSMViewWrapper () <KlarnaEventHandler, KlarnaSizingDelegate>
10
+
11
+ // Expose private properties and methods for testing
12
+ @property (nonatomic, strong) KlarnaOSMView* klarnaOSMView;
13
+ @property (nonatomic, assign) BOOL isOSMViewReadyEventSent;
14
+
15
+ - (void)initializeActualOSMView;
16
+ - (void)updateStyleConfiguration;
17
+ - (UIColor *)colorFromHexString:(NSString *)hexString;
18
+ - (void)sendOSMViewReadyEvent;
19
+
20
+ @end
21
+
22
+ @interface KlarnaOSMViewWrapperTests : XCTestCase
23
+
24
+ @property (nonatomic, strong) KlarnaOSMViewWrapper *wrapper;
25
+ @property (nonatomic, strong) id osmViewMock;
26
+
27
+ @end
28
+
29
+ @implementation KlarnaOSMViewWrapperTests
30
+
31
+ - (void)setUp {
32
+ // Stub initializeActualOSMView on the partial mock BEFORE init runs,
33
+ // preventing the real KlarnaOSMView SDK from being instantiated.
34
+ KlarnaOSMViewWrapper *wrapper = [KlarnaOSMViewWrapper alloc];
35
+ id partialMock = OCMPartialMock(wrapper);
36
+ OCMStub([partialMock initializeActualOSMView]);
37
+ [wrapper initWithFrame:CGRectZero];
38
+ self.wrapper = partialMock;
39
+
40
+ // Assign a class mock as the klarnaOSMView for verification
41
+ id mockOSMView = OCMClassMock([KlarnaOSMView class]);
42
+ self.osmViewMock = mockOSMView;
43
+ self.wrapper.klarnaOSMView = mockOSMView;
44
+ }
45
+
46
+ - (void)tearDown {
47
+ self.wrapper = nil;
48
+ self.osmViewMock = nil;
49
+ }
50
+
51
+ #pragma mark - Initialization Tests
52
+
53
+ - (void)test_initializesOSMViewOnCreation {
54
+ // The OSM view should be created during initWithFrame
55
+ XCTAssertNotNil(self.wrapper.klarnaOSMView);
56
+ }
57
+
58
+ - (void)test_wrapperHasClearBackground {
59
+ XCTAssertNotNil(self.wrapper.backgroundColor);
60
+ }
61
+
62
+ - (void)test_osmViewReadyEventNotSentInitially {
63
+ XCTAssertFalse(self.wrapper.isOSMViewReadyEventSent);
64
+ }
65
+
66
+ #pragma mark - Property Setter Tests: clientId
67
+
68
+ - (void)test_setClientId {
69
+ [self.wrapper setClientId:@"test-client-id"];
70
+ XCTAssertEqualObjects(self.wrapper.clientId, @"test-client-id");
71
+ }
72
+
73
+ - (void)test_setClientIdPassesToOSMView {
74
+ [self.wrapper setClientId:@"test-client-id"];
75
+ OCMVerify([self.osmViewMock setClientId:@"test-client-id"]);
76
+ }
77
+
78
+ #pragma mark - Property Setter Tests: placementKey
79
+
80
+ - (void)test_setPlacementKey {
81
+ [self.wrapper setPlacementKey:@"test-placement-key"];
82
+ XCTAssertEqualObjects(self.wrapper.placementKey, @"test-placement-key");
83
+ }
84
+
85
+ - (void)test_setPlacementKeyPassesToOSMView {
86
+ [self.wrapper setPlacementKey:@"test-placement-key"];
87
+ OCMVerify([self.osmViewMock setPlacementKey:@"test-placement-key"]);
88
+ }
89
+
90
+ #pragma mark - Property Setter Tests: locale
91
+
92
+ - (void)test_setLocale {
93
+ [self.wrapper setLocale:@"en-US"];
94
+ XCTAssertEqualObjects(self.wrapper.locale, @"en-US");
95
+ }
96
+
97
+ - (void)test_setLocalePassesToOSMView {
98
+ [self.wrapper setLocale:@"en-US"];
99
+ OCMVerify([self.osmViewMock setLocale:@"en-US"]);
100
+ }
101
+
102
+ - (void)test_setLocaleEmptyStringDoesNotPassToOSMView {
103
+ OCMReject([self.osmViewMock setLocale:OCMOCK_ANY]);
104
+ [self.wrapper setLocale:@""];
105
+ XCTAssertEqualObjects(self.wrapper.locale, @"");
106
+ }
107
+
108
+ #pragma mark - Property Setter Tests: purchaseAmount
109
+
110
+ - (void)test_setPurchaseAmount {
111
+ [self.wrapper setPurchaseAmount:@"9999"];
112
+ XCTAssertEqualObjects(self.wrapper.purchaseAmount, @"9999");
113
+ }
114
+
115
+ - (void)test_setPurchaseAmountPassesNumberToOSMView {
116
+ [self.wrapper setPurchaseAmount:@"9999"];
117
+ OCMVerify([self.osmViewMock setPurchaseAmount:[OCMArg checkWithBlock:^BOOL(NSNumber *amount) {
118
+ return [amount longValue] == 9999;
119
+ }]]);
120
+ }
121
+
122
+ - (void)test_setPurchaseAmountEmptyStringDoesNotPassToOSMView {
123
+ OCMReject([self.osmViewMock setPurchaseAmount:OCMOCK_ANY]);
124
+ [self.wrapper setPurchaseAmount:@""];
125
+ }
126
+
127
+ - (void)test_setPurchaseAmountInvalidStringDoesNotPassToOSMView {
128
+ OCMReject([self.osmViewMock setPurchaseAmount:OCMOCK_ANY]);
129
+ [self.wrapper setPurchaseAmount:@"not-a-number"];
130
+ }
131
+
132
+ #pragma mark - Property Setter Tests: environment
133
+
134
+ - (void)test_setEnvironmentPlayground {
135
+ [self.wrapper setEnvironment:@"playground"];
136
+ XCTAssertEqualObjects(self.wrapper.environment, @"playground");
137
+ OCMVerify([self.osmViewMock setEnvironment:KlarnaEnvironment.playground]);
138
+ }
139
+
140
+ - (void)test_setEnvironmentProduction {
141
+ [self.wrapper setEnvironment:@"production"];
142
+ OCMVerify([self.osmViewMock setEnvironment:KlarnaEnvironment.production]);
143
+ }
144
+
145
+ - (void)test_setEnvironmentStaging {
146
+ [self.wrapper setEnvironment:@"staging"];
147
+ OCMVerify([self.osmViewMock setEnvironment:KlarnaEnvironment.staging]);
148
+ }
149
+
150
+ - (void)test_setEnvironmentUnknown {
151
+ OCMReject([self.osmViewMock setEnvironment:OCMOCK_ANY]);
152
+ [self.wrapper setEnvironment:@"unknown"];
153
+ }
154
+
155
+ - (void)test_setEnvironmentEmpty {
156
+ OCMReject([self.osmViewMock setEnvironment:OCMOCK_ANY]);
157
+ [self.wrapper setEnvironment:@""];
158
+ }
159
+
160
+ #pragma mark - Property Setter Tests: region
161
+
162
+ - (void)test_setRegionEu {
163
+ [self.wrapper setRegion:@"eu"];
164
+ XCTAssertEqualObjects(self.wrapper.region, @"eu");
165
+ OCMVerify([self.osmViewMock setRegion:KlarnaRegion.eu]);
166
+ }
167
+
168
+ - (void)test_setRegionNa {
169
+ [self.wrapper setRegion:@"na"];
170
+ OCMVerify([self.osmViewMock setRegion:KlarnaRegion.na]);
171
+ }
172
+
173
+ - (void)test_setRegionOc {
174
+ [self.wrapper setRegion:@"oc"];
175
+ OCMVerify([self.osmViewMock setRegion:KlarnaRegion.oc]);
176
+ }
177
+
178
+ - (void)test_setRegionUnknown {
179
+ OCMReject([self.osmViewMock setRegion:OCMOCK_ANY]);
180
+ [self.wrapper setRegion:@"unknown"];
181
+ }
182
+
183
+ - (void)test_setRegionEmpty {
184
+ OCMReject([self.osmViewMock setRegion:OCMOCK_ANY]);
185
+ [self.wrapper setRegion:@""];
186
+ }
187
+
188
+ #pragma mark - Property Setter Tests: theme
189
+
190
+ - (void)test_setThemeLight {
191
+ [self.wrapper setTheme:@"light"];
192
+ XCTAssertEqualObjects(self.wrapper.theme, @"light");
193
+ OCMVerify([(KlarnaOSMView *)self.osmViewMock setTheme:KlarnaThemeLight]);
194
+ }
195
+
196
+ - (void)test_setThemeDark {
197
+ [self.wrapper setTheme:@"dark"];
198
+ OCMVerify([(KlarnaOSMView *)self.osmViewMock setTheme:KlarnaThemeDark]);
199
+ }
200
+
201
+ - (void)test_setThemeAutomatic {
202
+ [self.wrapper setTheme:@"automatic"];
203
+ OCMVerify([(KlarnaOSMView *)self.osmViewMock setTheme:KlarnaThemeAutomatic]);
204
+ }
205
+
206
+ - (void)test_setThemeUnknown {
207
+ OCMReject([(KlarnaOSMView *)self.osmViewMock setTheme:KlarnaThemeLight]);
208
+ OCMReject([(KlarnaOSMView *)self.osmViewMock setTheme:KlarnaThemeDark]);
209
+ OCMReject([(KlarnaOSMView *)self.osmViewMock setTheme:KlarnaThemeAutomatic]);
210
+ [self.wrapper setTheme:@"unknown"];
211
+ }
212
+
213
+ - (void)test_setThemeEmpty {
214
+ OCMReject([(KlarnaOSMView *)self.osmViewMock setTheme:KlarnaThemeLight]);
215
+ OCMReject([(KlarnaOSMView *)self.osmViewMock setTheme:KlarnaThemeDark]);
216
+ OCMReject([(KlarnaOSMView *)self.osmViewMock setTheme:KlarnaThemeAutomatic]);
217
+ [self.wrapper setTheme:@""];
218
+ }
219
+
220
+ #pragma mark - Property Setter Tests: returnUrl (no-op on native side)
221
+
222
+ - (void)test_setReturnUrlIsNoOp {
223
+ // OSM ignores returnUrl - the value is stored but not forwarded to the native SDK
224
+ [self.wrapper setReturnUrl:@"https://return.example.com"];
225
+ XCTAssertEqualObjects(self.wrapper.returnUrl, @"https://return.example.com");
226
+ }
227
+
228
+ - (void)test_setReturnUrlNil {
229
+ [self.wrapper setReturnUrl:nil];
230
+ XCTAssertNil(self.wrapper.returnUrl);
231
+ }
232
+
233
+ #pragma mark - Style Configuration Tests
234
+
235
+ - (void)test_setOsmBackgroundColorTriggersStyleUpdate {
236
+ [self.wrapper setOsmBackgroundColor:@"#FF0000"];
237
+ XCTAssertEqualObjects(self.wrapper.osmBackgroundColor, @"#FF0000");
238
+ OCMVerify([self.osmViewMock setStyleConfiguration:OCMOCK_ANY]);
239
+ }
240
+
241
+ - (void)test_setTextColorTriggersStyleUpdate {
242
+ [self.wrapper setTextColor:@"#00FF00"];
243
+ XCTAssertEqualObjects(self.wrapper.textColor, @"#00FF00");
244
+ OCMVerify([self.osmViewMock setStyleConfiguration:OCMOCK_ANY]);
245
+ }
246
+
247
+ - (void)test_setNilColorsResetsStyleConfiguration {
248
+ [self.wrapper setOsmBackgroundColor:nil];
249
+ [self.wrapper setTextColor:nil];
250
+ // With both colors nil, styleConfiguration should be set to nil
251
+ OCMVerify([self.osmViewMock setStyleConfiguration:[OCMArg isNil]]);
252
+ }
253
+
254
+ - (void)test_setInvalidColorResetsStyleConfiguration {
255
+ [self.wrapper setOsmBackgroundColor:@"invalid"];
256
+ // Invalid color should result in nil style configuration
257
+ OCMVerify([self.osmViewMock setStyleConfiguration:[OCMArg isNil]]);
258
+ }
259
+
260
+ #pragma mark - Color Parsing Tests
261
+
262
+ - (void)test_colorFromHexStringRGB {
263
+ UIColor *color = [self.wrapper colorFromHexString:@"#FF0000"];
264
+ XCTAssertNotNil(color);
265
+ CGFloat r, g, b, a;
266
+ [color getRed:&r green:&g blue:&b alpha:&a];
267
+ XCTAssertEqualWithAccuracy(r, 1.0, 0.01);
268
+ XCTAssertEqualWithAccuracy(g, 0.0, 0.01);
269
+ XCTAssertEqualWithAccuracy(b, 0.0, 0.01);
270
+ XCTAssertEqualWithAccuracy(a, 1.0, 0.01);
271
+ }
272
+
273
+ - (void)test_colorFromHexStringRGBA {
274
+ UIColor *color = [self.wrapper colorFromHexString:@"#FF000080"];
275
+ XCTAssertNotNil(color);
276
+ CGFloat r, g, b, a;
277
+ [color getRed:&r green:&g blue:&b alpha:&a];
278
+ XCTAssertEqualWithAccuracy(r, 1.0, 0.01);
279
+ XCTAssertEqualWithAccuracy(g, 0.0, 0.01);
280
+ XCTAssertEqualWithAccuracy(b, 0.0, 0.01);
281
+ XCTAssertEqualWithAccuracy(a, 128.0 / 255.0, 0.01);
282
+ }
283
+
284
+ - (void)test_colorFromHexStringWithoutHash {
285
+ UIColor *color = [self.wrapper colorFromHexString:@"00FF00"];
286
+ XCTAssertNotNil(color);
287
+ CGFloat r, g, b, a;
288
+ [color getRed:&r green:&g blue:&b alpha:&a];
289
+ XCTAssertEqualWithAccuracy(r, 0.0, 0.01);
290
+ XCTAssertEqualWithAccuracy(g, 1.0, 0.01);
291
+ XCTAssertEqualWithAccuracy(b, 0.0, 0.01);
292
+ }
293
+
294
+ - (void)test_colorFromHexStringNil {
295
+ UIColor *color = [self.wrapper colorFromHexString:nil];
296
+ XCTAssertNil(color);
297
+ }
298
+
299
+ - (void)test_colorFromHexStringEmpty {
300
+ UIColor *color = [self.wrapper colorFromHexString:@""];
301
+ XCTAssertNil(color);
302
+ }
303
+
304
+ - (void)test_colorFromHexStringInvalidLength {
305
+ UIColor *color = [self.wrapper colorFromHexString:@"#FFF"];
306
+ XCTAssertNil(color);
307
+ }
308
+
309
+ - (void)test_colorFromHexStringTooLong {
310
+ UIColor *color = [self.wrapper colorFromHexString:@"#FF0000FF00"];
311
+ XCTAssertNil(color);
312
+ }
313
+
314
+ #pragma mark - Render Tests
315
+
316
+ - (void)test_renderCallsOSMViewRender {
317
+ [self.wrapper render];
318
+ OCMVerify([self.osmViewMock render]);
319
+ }
320
+
321
+ #pragma mark - KlarnaEventHandler Tests
322
+
323
+ - (void)test_onErrorCallbackFired {
324
+ __block NSDictionary *receivedBody = nil;
325
+ [self.wrapper setOnError:^(NSDictionary *body) {
326
+ receivedBody = body;
327
+ }];
328
+
329
+ id mockError = OCMClassMock([KlarnaError class]);
330
+ OCMStub([mockError name]).andReturn(@"TestError");
331
+ OCMStub([mockError message]).andReturn(@"Test error message");
332
+ OCMStub([mockError isFatal]).andReturn(YES);
333
+
334
+ [(id<KlarnaEventHandler>)self.wrapper klarnaComponent:self.osmViewMock encounteredError:mockError];
335
+
336
+ XCTAssertNotNil(receivedBody);
337
+ NSDictionary *errorDict = receivedBody[@"error"];
338
+ XCTAssertEqualObjects(errorDict[@"name"], @"TestError");
339
+ XCTAssertEqualObjects(errorDict[@"message"], @"Test error message");
340
+ XCTAssertEqualObjects(errorDict[@"isFatal"], @YES);
341
+ }
342
+
343
+ - (void)test_onErrorCallbackNotFatal {
344
+ __block NSDictionary *receivedBody = nil;
345
+ [self.wrapper setOnError:^(NSDictionary *body) {
346
+ receivedBody = body;
347
+ }];
348
+
349
+ id mockError = OCMClassMock([KlarnaError class]);
350
+ OCMStub([mockError name]).andReturn(@"MinorError");
351
+ OCMStub([mockError message]).andReturn(@"Non-fatal error");
352
+ OCMStub([mockError isFatal]).andReturn(NO);
353
+
354
+ [(id<KlarnaEventHandler>)self.wrapper klarnaComponent:self.osmViewMock encounteredError:mockError];
355
+
356
+ XCTAssertNotNil(receivedBody);
357
+ NSDictionary *errorDict = receivedBody[@"error"];
358
+ XCTAssertEqualObjects(errorDict[@"isFatal"], @NO);
359
+ }
360
+
361
+ - (void)test_onErrorWithoutCallbackDoesNotCrash {
362
+ id mockError = OCMClassMock([KlarnaError class]);
363
+ OCMStub([mockError name]).andReturn(@"TestError");
364
+ OCMStub([mockError message]).andReturn(@"Test error message");
365
+ OCMStub([mockError isFatal]).andReturn(NO);
366
+
367
+ XCTAssertNoThrow([(id<KlarnaEventHandler>)self.wrapper klarnaComponent:self.osmViewMock encounteredError:mockError]);
368
+ }
369
+
370
+ - (void)test_dispatchedEventIsNoOp {
371
+ id mockEvent = OCMClassMock([KlarnaProductEvent class]);
372
+ XCTAssertNoThrow([(id<KlarnaEventHandler>)self.wrapper klarnaComponent:self.osmViewMock dispatchedEvent:mockEvent]);
373
+ }
374
+
375
+ #pragma mark - KlarnaSizingDelegate Tests
376
+
377
+ - (void)test_onResizedCallbackFired {
378
+ __block NSDictionary *receivedBody = nil;
379
+ [self.wrapper setOnResized:^(NSDictionary *body) {
380
+ receivedBody = body;
381
+ }];
382
+
383
+ [(id<KlarnaSizingDelegate>)self.wrapper klarnaComponent:self.osmViewMock resizedToHeight:150.0];
384
+
385
+ XCTAssertNotNil(receivedBody);
386
+ XCTAssertEqualObjects(receivedBody[@"height"], @"150");
387
+ }
388
+
389
+ - (void)test_onResizedWithZeroHeight {
390
+ __block NSDictionary *receivedBody = nil;
391
+ [self.wrapper setOnResized:^(NSDictionary *body) {
392
+ receivedBody = body;
393
+ }];
394
+
395
+ [(id<KlarnaSizingDelegate>)self.wrapper klarnaComponent:self.osmViewMock resizedToHeight:0.0];
396
+
397
+ XCTAssertNotNil(receivedBody);
398
+ XCTAssertEqualObjects(receivedBody[@"height"], @"0");
399
+ }
400
+
401
+ - (void)test_onResizedWithoutCallbackDoesNotCrash {
402
+ XCTAssertNoThrow([(id<KlarnaSizingDelegate>)self.wrapper klarnaComponent:self.osmViewMock resizedToHeight:100.0]);
403
+ }
404
+
405
+ #pragma mark - OSM View Ready Event Tests
406
+
407
+ - (void)test_sendOSMViewReadyEventFires {
408
+ __block BOOL eventFired = NO;
409
+ [self.wrapper setOnOSMViewReady:^(NSDictionary *body) {
410
+ eventFired = YES;
411
+ }];
412
+
413
+ // Simulate the event being ready to send
414
+ self.wrapper.isOSMViewReadyEventSent = NO;
415
+ [self.wrapper sendOSMViewReadyEvent];
416
+
417
+ XCTAssertTrue(eventFired);
418
+ XCTAssertTrue(self.wrapper.isOSMViewReadyEventSent);
419
+ }
420
+
421
+ - (void)test_sendOSMViewReadyEventOnlyFiresOnce {
422
+ __block int fireCount = 0;
423
+ [self.wrapper setOnOSMViewReady:^(NSDictionary *body) {
424
+ fireCount++;
425
+ }];
426
+
427
+ self.wrapper.isOSMViewReadyEventSent = NO;
428
+ [self.wrapper sendOSMViewReadyEvent];
429
+ [self.wrapper sendOSMViewReadyEvent];
430
+
431
+ XCTAssertEqual(fireCount, 1);
432
+ }
433
+
434
+ - (void)test_sendOSMViewReadyEventWithoutCallbackDoesNotCrash {
435
+ self.wrapper.isOSMViewReadyEventSent = NO;
436
+ XCTAssertNoThrow([self.wrapper sendOSMViewReadyEvent]);
437
+ }
438
+
439
+ - (void)test_didMoveToWindowResetsReadyEventFlag {
440
+ self.wrapper.isOSMViewReadyEventSent = YES;
441
+
442
+ // Simulate removal from window (window becomes nil)
443
+ id wrapperMock = self.wrapper;
444
+ OCMStub([wrapperMock window]).andReturn(nil);
445
+ [self.wrapper didMoveToWindow];
446
+
447
+ XCTAssertFalse(self.wrapper.isOSMViewReadyEventSent);
448
+ }
449
+
450
+ @end
@@ -0,0 +1,105 @@
1
+ #import <XCTest/XCTest.h>
2
+ #import <OCMock/OCMock.h>
3
+ #import <KlarnaMobileSDK/KlarnaMobileSDK.h>
4
+ #import <KlarnaMobileSDK/KlarnaMobileSDK-Swift.h>
5
+
6
+ #import "../Sources/view/KlarnaStandaloneWebViewWrapper.h"
7
+
8
+ @interface KlarnaStandaloneWebViewWrapper ()
9
+
10
+ // Expose private properties and methods for testing
11
+ @property (nonatomic, strong) KlarnaStandaloneWebView* klarnaStandaloneWebView;
12
+ - (void) initializeKlarnaStandaloneWebView;
13
+
14
+ @end
15
+
16
+ @interface KlarnaStandaloneWebViewWrapperTests : XCTestCase
17
+
18
+ @property (nonatomic, strong) id wrapper;
19
+
20
+ @end
21
+
22
+ @implementation KlarnaStandaloneWebViewWrapperTests
23
+
24
+ - (void)setUp {
25
+ // Create wrapper with a partial mock, stubbing initializeKlarnaStandaloneWebView
26
+ // to prevent the real SDK from being instantiated (it crashes in test env).
27
+ KlarnaStandaloneWebViewWrapper *wrapper = [KlarnaStandaloneWebViewWrapper alloc];
28
+ id partialMock = OCMPartialMock(wrapper);
29
+ OCMStub([partialMock initializeKlarnaStandaloneWebView]);
30
+ [wrapper init];
31
+ self.wrapper = partialMock;
32
+ }
33
+
34
+ - (void)tearDown {
35
+ self.wrapper = nil;
36
+ }
37
+
38
+ #pragma mark - Deferred Initialization Tests
39
+
40
+ - (void)test_doesNotInitializeViewOnInit {
41
+ // KlarnaStandaloneWebView requires returnURL in its designated initializer
42
+ // (init(frame:) is unavailable). The wrapper defers creation until returnUrl
43
+ // is delivered as a React Native prop.
44
+ OCMReject([self.wrapper initializeKlarnaStandaloneWebView]);
45
+
46
+ KlarnaStandaloneWebViewWrapper *freshWrapper = [KlarnaStandaloneWebViewWrapper alloc];
47
+ id freshMock = OCMPartialMock(freshWrapper);
48
+ OCMStub([freshMock initializeKlarnaStandaloneWebView]);
49
+ [freshWrapper init];
50
+
51
+ OCMVerifyAll(freshMock);
52
+ XCTAssertNil(((KlarnaStandaloneWebViewWrapper *)freshMock).klarnaStandaloneWebView);
53
+ }
54
+
55
+ - (void)test_initializesViewWhenReturnUrlIsSet {
56
+ // The native view is created once a valid returnUrl arrives from React Native.
57
+ // WHEN
58
+ [self.wrapper setReturnUrl:@"testapp://return"];
59
+
60
+ // THEN
61
+ OCMVerify([self.wrapper initializeKlarnaStandaloneWebView]);
62
+ }
63
+
64
+ - (void)test_doesNotInitializeViewWithEmptyReturnUrl {
65
+ // An empty returnUrl should not trigger initialization — the SDK requires
66
+ // a valid URL in initWithReturnURL:.
67
+ // WHEN
68
+ [self.wrapper setReturnUrl:@""];
69
+
70
+ // THEN
71
+ XCTAssertNil(((KlarnaStandaloneWebViewWrapper *)self.wrapper).klarnaStandaloneWebView);
72
+ }
73
+
74
+ - (void)test_doesNotInitializeViewWithNilReturnUrl {
75
+ // A nil returnUrl should not trigger initialization.
76
+ // WHEN
77
+ [self.wrapper setReturnUrl:nil];
78
+
79
+ // THEN
80
+ XCTAssertNil(((KlarnaStandaloneWebViewWrapper *)self.wrapper).klarnaStandaloneWebView);
81
+ }
82
+
83
+ #pragma mark - Prop Ordering Tests
84
+
85
+ - (void)test_bouncesCanBeSetBeforeReturnUrl {
86
+ // React Native does not guarantee prop ordering. Setting bounces before
87
+ // returnUrl should not crash, even though the native view doesn't exist yet.
88
+ // WHEN
89
+ XCTAssertNoThrow([self.wrapper setBounces:NO]);
90
+ [self.wrapper setReturnUrl:@"testapp://return"];
91
+
92
+ // THEN
93
+ OCMVerify([self.wrapper initializeKlarnaStandaloneWebView]);
94
+ }
95
+
96
+ - (void)test_returnUrlCanBeSetBeforeBounces {
97
+ // WHEN
98
+ [self.wrapper setReturnUrl:@"testapp://return"];
99
+ XCTAssertNoThrow([self.wrapper setBounces:YES]);
100
+
101
+ // THEN
102
+ OCMVerify([self.wrapper initializeKlarnaStandaloneWebView]);
103
+ }
104
+
105
+ @end
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.KlarnaExpressCheckoutView = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _KlarnaExpressCheckoutViewNativeComponent = _interopRequireDefault(require("./specs/KlarnaExpressCheckoutViewNativeComponent"));
9
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
11
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
12
+ const normalizeSessionData = sessionData => {
13
+ if (sessionData !== null && sessionData !== void 0 && sessionData.trim()) {
14
+ return sessionData;
15
+ }
16
+ return '';
17
+ };
18
+ class KlarnaExpressCheckoutView extends _react.Component {
19
+ constructor(props) {
20
+ super(props);
21
+ this.state = {
22
+ nativeViewHeight: 0
23
+ };
24
+ this.viewRef = /*#__PURE__*/_react.default.createRef();
25
+ }
26
+ render() {
27
+ return /*#__PURE__*/_react.default.createElement(_KlarnaExpressCheckoutViewNativeComponent.default, {
28
+ ref: this.viewRef
29
+ /* eslint-disable-next-line react-native/no-inline-styles */,
30
+ style: {
31
+ width: '100%',
32
+ height: this.state.nativeViewHeight > 0 ? this.state.nativeViewHeight : 48,
33
+ ...this.props.style
34
+ },
35
+ sessionType: 'clientId' in this.props.sessionOptions ? 'clientId' : 'clientToken',
36
+ clientId: 'clientId' in this.props.sessionOptions ? this.props.sessionOptions.clientId : '',
37
+ clientToken: 'clientToken' in this.props.sessionOptions ? this.props.sessionOptions.clientToken : '',
38
+ locale: this.props.locale,
39
+ environment: this.props.environment,
40
+ region: this.props.region,
41
+ returnUrl: this.props.returnUrl,
42
+ theme: this.props.theme ?? '',
43
+ shape: this.props.shape ?? '',
44
+ buttonStyle: this.props.buttonStyle ?? '',
45
+ autoFinalize: this.props.autoFinalize ?? true,
46
+ collectShippingAddress: this.props.collectShippingAddress ?? false,
47
+ sessionData: normalizeSessionData(this.props.sessionData),
48
+ onAuthorized: event => {
49
+ var _this$props$onAuthori, _this$props;
50
+ (_this$props$onAuthori = (_this$props = this.props).onAuthorized) === null || _this$props$onAuthori === void 0 || _this$props$onAuthori.call(_this$props, event.nativeEvent.authorizationResponse);
51
+ },
52
+ onError: event => {
53
+ var _this$props$onError, _this$props2;
54
+ const mobileSdkError = {
55
+ isFatal: event.nativeEvent.error.isFatal,
56
+ message: event.nativeEvent.error.message,
57
+ name: event.nativeEvent.error.name
58
+ };
59
+ (_this$props$onError = (_this$props2 = this.props).onError) === null || _this$props$onError === void 0 || _this$props$onError.call(_this$props2, mobileSdkError);
60
+ },
61
+ onResized: event => {
62
+ const newHeight = Number(event.nativeEvent.height);
63
+ if (newHeight !== this.state.nativeViewHeight) {
64
+ this.setState({
65
+ nativeViewHeight: newHeight
66
+ });
67
+ }
68
+ }
69
+ });
70
+ }
71
+ }
72
+ exports.KlarnaExpressCheckoutView = KlarnaExpressCheckoutView;
73
+ var _default = KlarnaExpressCheckoutView;
74
+ exports.default = _default;
75
+ //# sourceMappingURL=KlarnaExpressCheckoutView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_react","_interopRequireWildcard","require","_KlarnaExpressCheckoutViewNativeComponent","_interopRequireDefault","obj","__esModule","default","_getRequireWildcardCache","nodeInterop","WeakMap","cacheBabelInterop","cacheNodeInterop","cache","has","get","newObj","hasPropertyDescriptor","Object","defineProperty","getOwnPropertyDescriptor","key","prototype","hasOwnProperty","call","desc","set","normalizeSessionData","sessionData","trim","KlarnaExpressCheckoutView","Component","constructor","props","state","nativeViewHeight","viewRef","React","createRef","render","createElement","ref","style","width","height","sessionType","sessionOptions","clientId","clientToken","locale","environment","region","returnUrl","theme","shape","buttonStyle","autoFinalize","collectShippingAddress","onAuthorized","event","_this$props$onAuthori","_this$props","nativeEvent","authorizationResponse","onError","_this$props$onError","_this$props2","mobileSdkError","isFatal","error","message","name","onResized","newHeight","Number","setState","exports","_default"],"sourceRoot":"../../src","sources":["KlarnaExpressCheckoutView.tsx"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,uBAAA,CAAAC,OAAA;AAaA,IAAAC,yCAAA,GAAAC,sBAAA,CAAAF,OAAA;AAE0D,SAAAE,uBAAAC,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,KAAAE,OAAA,EAAAF,GAAA;AAAA,SAAAG,yBAAAC,WAAA,eAAAC,OAAA,kCAAAC,iBAAA,OAAAD,OAAA,QAAAE,gBAAA,OAAAF,OAAA,YAAAF,wBAAA,YAAAA,CAAAC,WAAA,WAAAA,WAAA,GAAAG,gBAAA,GAAAD,iBAAA,KAAAF,WAAA;AAAA,SAAAR,wBAAAI,GAAA,EAAAI,WAAA,SAAAA,WAAA,IAAAJ,GAAA,IAAAA,GAAA,CAAAC,UAAA,WAAAD,GAAA,QAAAA,GAAA,oBAAAA,GAAA,wBAAAA,GAAA,4BAAAE,OAAA,EAAAF,GAAA,UAAAQ,KAAA,GAAAL,wBAAA,CAAAC,WAAA,OAAAI,KAAA,IAAAA,KAAA,CAAAC,GAAA,CAAAT,GAAA,YAAAQ,KAAA,CAAAE,GAAA,CAAAV,GAAA,SAAAW,MAAA,WAAAC,qBAAA,GAAAC,MAAA,CAAAC,cAAA,IAAAD,MAAA,CAAAE,wBAAA,WAAAC,GAAA,IAAAhB,GAAA,QAAAgB,GAAA,kBAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAnB,GAAA,EAAAgB,GAAA,SAAAI,IAAA,GAAAR,qBAAA,GAAAC,MAAA,CAAAE,wBAAA,CAAAf,GAAA,EAAAgB,GAAA,cAAAI,IAAA,KAAAA,IAAA,CAAAV,GAAA,IAAAU,IAAA,CAAAC,GAAA,KAAAR,MAAA,CAAAC,cAAA,CAAAH,MAAA,EAAAK,GAAA,EAAAI,IAAA,YAAAT,MAAA,CAAAK,GAAA,IAAAhB,GAAA,CAAAgB,GAAA,SAAAL,MAAA,CAAAT,OAAA,GAAAF,GAAA,MAAAQ,KAAA,IAAAA,KAAA,CAAAa,GAAA,CAAArB,GAAA,EAAAW,MAAA,YAAAA,MAAA;AA0C1D,MAAMW,oBAAoB,GAAIC,WAAoB,IAAa;EAC7D,IAAIA,WAAW,aAAXA,WAAW,eAAXA,WAAW,CAAEC,IAAI,CAAC,CAAC,EAAE;IACvB,OAAOD,WAAW;EACpB;EACA,OAAO,EAAE;AACX,CAAC;AAEM,MAAME,yBAAyB,SAASC,gBAAS,CAGtD;EAKAC,WAAWA,CAACC,KAAqC,EAAE;IACjD,KAAK,CAACA,KAAK,CAAC;IACZ,IAAI,CAACC,KAAK,GAAG;MACXC,gBAAgB,EAAE;IACpB,CAAC;IACD,IAAI,CAACC,OAAO,gBAAGC,cAAK,CAACC,SAAS,CAAC,CAAC;EAClC;EAEAC,MAAMA,CAAA,EAAG;IACP,oBACEvC,MAAA,CAAAO,OAAA,CAAAiC,aAAA,CAACrC,yCAAA,CAAAI,OAA2B;MAC1BkC,GAAG,EAAE,IAAI,CAACL;MACV;MACAM,KAAK,EAAE;QACLC,KAAK,EAAE,MAAM;QACbC,MAAM,EACJ,IAAI,CAACV,KAAK,CAACC,gBAAgB,GAAG,CAAC,GAAG,IAAI,CAACD,KAAK,CAACC,gBAAgB,GAAG,EAAE;QACpE,GAAG,IAAI,CAACF,KAAK,CAACS;MAChB,CAAE;MACFG,WAAW,EACT,UAAU,IAAI,IAAI,CAACZ,KAAK,CAACa,cAAc,GAAG,UAAU,GAAG,aACxD;MACDC,QAAQ,EACN,UAAU,IAAI,IAAI,CAACd,KAAK,CAACa,cAAc,GACnC,IAAI,CAACb,KAAK,CAACa,cAAc,CAACC,QAAQ,GAClC,EACL;MACDC,WAAW,EACT,aAAa,IAAI,IAAI,CAACf,KAAK,CAACa,cAAc,GACtC,IAAI,CAACb,KAAK,CAACa,cAAc,CAACE,WAAW,GACrC,EACL;MACDC,MAAM,EAAE,IAAI,CAAChB,KAAK,CAACgB,MAAO;MAC1BC,WAAW,EAAE,IAAI,CAACjB,KAAK,CAACiB,WAAY;MACpCC,MAAM,EAAE,IAAI,CAAClB,KAAK,CAACkB,MAAO;MAC1BC,SAAS,EAAE,IAAI,CAACnB,KAAK,CAACmB,SAAU;MAChCC,KAAK,EAAE,IAAI,CAACpB,KAAK,CAACoB,KAAK,IAAI,EAAG;MAC9BC,KAAK,EAAE,IAAI,CAACrB,KAAK,CAACqB,KAAK,IAAI,EAAG;MAC9BC,WAAW,EAAE,IAAI,CAACtB,KAAK,CAACsB,WAAW,IAAI,EAAG;MAC1CC,YAAY,EAAE,IAAI,CAACvB,KAAK,CAACuB,YAAY,IAAI,IAAK;MAC9CC,sBAAsB,EAAE,IAAI,CAACxB,KAAK,CAACwB,sBAAsB,IAAI,KAAM;MACnE7B,WAAW,EAAED,oBAAoB,CAAC,IAAI,CAACM,KAAK,CAACL,WAAW,CAAE;MAC1D8B,YAAY,EACVC,KAcC,IACE;QAAA,IAAAC,qBAAA,EAAAC,WAAA;QACH,CAAAD,qBAAA,IAAAC,WAAA,OAAI,CAAC5B,KAAK,EAACyB,YAAY,cAAAE,qBAAA,eAAvBA,qBAAA,CAAApC,IAAA,CAAAqC,WAAA,EAA0BF,KAAK,CAACG,WAAW,CAACC,qBAAqB,CAAC;MACpE,CAAE;MACFC,OAAO,EACLL,KAQC,IACE;QAAA,IAAAM,mBAAA,EAAAC,YAAA;QACH,MAAMC,cAAoC,GAAG;UAC3CC,OAAO,EAAET,KAAK,CAACG,WAAW,CAACO,KAAK,CAACD,OAAO;UACxCE,OAAO,EAAEX,KAAK,CAACG,WAAW,CAACO,KAAK,CAACC,OAAO;UACxCC,IAAI,EAAEZ,KAAK,CAACG,WAAW,CAACO,KAAK,CAACE;QAChC,CAAC;QACD,CAAAN,mBAAA,IAAAC,YAAA,OAAI,CAACjC,KAAK,EAAC+B,OAAO,cAAAC,mBAAA,eAAlBA,mBAAA,CAAAzC,IAAA,CAAA0C,YAAA,EAAqBC,cAAc,CAAC;MACtC,CAAE;MACFK,SAAS,EACPb,KAIC,IACE;QACH,MAAMc,SAAS,GAAGC,MAAM,CAACf,KAAK,CAACG,WAAW,CAAClB,MAAM,CAAC;QAClD,IAAI6B,SAAS,KAAK,IAAI,CAACvC,KAAK,CAACC,gBAAgB,EAAE;UAC7C,IAAI,CAACwC,QAAQ,CAAC;YAAExC,gBAAgB,EAAEsC;UAAU,CAAC,CAAC;QAChD;MACF;IAAE,CACH,CAAC;EAEN;AACF;AAACG,OAAA,CAAA9C,yBAAA,GAAAA,yBAAA;AAAA,IAAA+C,QAAA,GAEc/C,yBAAyB;AAAA8C,OAAA,CAAArE,OAAA,GAAAsE,QAAA"}