react-native-userleap 2.21.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -76,6 +76,6 @@ dependencies {
76
76
  if (findProject(':userleap-android-sdk') != null) {
77
77
  implementation project(':userleap-android-sdk')
78
78
  } else {
79
- implementation ("com.userleap:userleap-android-sdk:2.23.0") // update this version on android updates
79
+ implementation ("com.userleap:userleap-android-sdk:2.24.0") // update this version on android updates
80
80
  }
81
81
  }
@@ -13,8 +13,6 @@ import com.facebook.react.bridge.ReactMethod;
13
13
  import com.facebook.react.bridge.ReadableArray;
14
14
  import com.facebook.react.bridge.ReadableMap;
15
15
  import com.facebook.react.bridge.WritableMap;
16
- import com.facebook.react.modules.core.DeviceEventManagerModule;
17
-
18
16
  import com.userleap.EventListener;
19
17
  import com.userleap.EventName;
20
18
  import com.userleap.EventPayload;
@@ -22,17 +20,16 @@ import com.userleap.SprigEvent;
22
20
  import com.userleap.SprigSurveyResult;
23
21
  import com.userleap.SurveyState;
24
22
  import com.userleap.UserLeap;
23
+ import com.userleap.SprigUserInterfaceMode;
25
24
 
26
25
  import org.json.JSONException;
27
26
  import org.json.JSONObject;
28
27
 
29
- import java.util.EnumSet;
30
28
  import java.util.HashMap;
31
29
  import java.util.Iterator;
32
30
  import java.util.List;
33
31
  import java.util.Map;
34
32
  import java.util.Objects;
35
- import java.util.Set;
36
33
  import java.util.stream.Collectors;
37
34
 
38
35
  import javax.annotation.Nullable;
@@ -44,34 +41,6 @@ public class UserLeapModule extends ReactContextBaseJavaModule {
44
41
 
45
42
  private static final String TAG = "UserLeapModule";
46
43
 
47
- /**
48
- * Lifecycle events we forward to React Native via DeviceEventEmitter.
49
- * Excluded:
50
- * - LOGGING_EVENT: handled separately via logcat
51
- * - REPLAY_CAPTURE: internal Web SDK plumbing, not meaningful to RN consumers
52
- * - REPLAY_EVENTS_UPLOADED_COMPLETED: deprecated alias for REPLAY_EVENTS_UPLOAD_COMPLETED
53
- */
54
- private static final Set<EventName> FORWARDED_EVENTS = EnumSet.of(
55
- EventName.SDK_READY,
56
- EventName.VISITOR_ID_UPDATED,
57
- EventName.SURVEY_HEIGHT,
58
- EventName.SURVEY_STATE_RETURNED,
59
- EventName.SURVEY_WILL_PRESENT,
60
- EventName.SURVEY_PRESENTED,
61
- EventName.SURVEY_APPEARED,
62
- EventName.QUESTION_ANSWERED,
63
- EventName.SURVEY_CLOSE_REQUESTED,
64
- EventName.SURVEY_WILL_CLOSE,
65
- EventName.SURVEY_CLOSED,
66
- EventName.SURVEY_COMPLETED,
67
- EventName.REPLAY_CAPTURE_STARTED,
68
- EventName.REPLAY_CAPTURE_STOPPED,
69
- EventName.REPLAY_CAPTURE_COMPLETED,
70
- EventName.REPLAY_RENDERING_COMPLETED,
71
- EventName.REPLAY_UPLOAD_COMPLETED,
72
- EventName.REPLAY_EVENTS_UPLOAD_COMPLETED
73
- );
74
-
75
44
  private final ReactApplicationContext reactContext;
76
45
 
77
46
  public UserLeapModule(ReactApplicationContext reactContext) {
@@ -84,48 +53,6 @@ public class UserLeapModule extends ReactContextBaseJavaModule {
84
53
  return "UserLeapBindings";
85
54
  }
86
55
 
87
- // ---------------------------------------------------------------------------
88
- // Required stubs for RN's NativeEventEmitter on the JS side.
89
- // ---------------------------------------------------------------------------
90
-
91
- @ReactMethod
92
- public void addListener(String eventName) {
93
- // No-op: listeners are registered once in configure() for the SDK lifetime.
94
- }
95
-
96
- @ReactMethod
97
- public void removeListeners(int count) {
98
- // No-op: listeners are registered once in configure() for the SDK lifetime.
99
- }
100
-
101
- // ---------------------------------------------------------------------------
102
- // Lifecycle event registration
103
- // ---------------------------------------------------------------------------
104
-
105
- private void registerForAllLifecycleEvents() {
106
- for (EventName eventName : FORWARDED_EVENTS) {
107
- UserLeap.INSTANCE.addEventListener(eventName, new EventListener() {
108
- @Override
109
- public void onEvent(SprigEvent event) {
110
- sendSprigEvent(event);
111
- }
112
- });
113
- }
114
- }
115
-
116
- private void sendSprigEvent(SprigEvent event) {
117
- if (!reactContext.hasActiveCatalystInstance()) {
118
- return;
119
- }
120
-
121
- WritableMap params = jsonObjectToWritableMap(event.getData());
122
- String eventName = toCamelCase(event.getName().name());
123
-
124
- reactContext
125
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
126
- .emit(eventName, params);
127
- }
128
-
129
56
  // ---------------------------------------------------------------------------
130
57
  // Bridge helpers
131
58
  // ---------------------------------------------------------------------------
@@ -187,11 +114,7 @@ public class UserLeapModule extends ReactContextBaseJavaModule {
187
114
  private WritableMap surveyResultToWritableMap(SprigSurveyResult surveyResult) {
188
115
  WritableMap resultMap = Arguments.createMap();
189
116
  resultMap.putString("surveyState", surveyResult.getSurveyState().name());
190
- if (surveyResult.getSurveyId() != null) {
191
- resultMap.putInt("surveyId", surveyResult.getSurveyId());
192
- } else {
193
- resultMap.putInt("surveyId", 0);
194
- }
117
+ resultMap.putInt("surveyId", surveyResult.getSurveyId());
195
118
  return resultMap;
196
119
  }
197
120
 
@@ -280,8 +203,6 @@ public class UserLeapModule extends ReactContextBaseJavaModule {
280
203
  }
281
204
  });
282
205
 
283
- registerForAllLifecycleEvents();
284
-
285
206
  UserLeap.INSTANCE.configure(
286
207
  reactContext,
287
208
  environment,
@@ -448,6 +369,17 @@ public class UserLeapModule extends ReactContextBaseJavaModule {
448
369
  UserLeap.INSTANCE.setUserIdentifier(identifier);
449
370
  }
450
371
 
372
+ @ReactMethod
373
+ public void overrideUserInterfaceMode(double mode) {
374
+ int modeInt = (int) mode;
375
+ for (SprigUserInterfaceMode m : SprigUserInterfaceMode.values()) {
376
+ if (m.getValue() == modeInt) {
377
+ UserLeap.INSTANCE.overrideUserInterfaceMode(m);
378
+ return;
379
+ }
380
+ }
381
+ }
382
+
451
383
  @ReactMethod
452
384
  public void logout() {
453
385
  UserLeap.INSTANCE.logout();
package/index.d.ts CHANGED
@@ -5,31 +5,13 @@ declare namespace UserLeap {
5
5
  NO_SURVEY: string;
6
6
  };
7
7
 
8
- const LifecycleEvent: {
9
- sdkReady: number;
10
- visitorIdUpdated: number;
11
- surveyHeight: number;
12
- surveyWillPresent: number;
13
- surveyPresented: number;
14
- surveyAppeared: number;
15
- surveyCloseRequested: number;
16
- surveyWillClose: number;
17
- surveyClosed: number;
18
- replayCapture: number;
19
- replayCaptureStarted: number;
20
- replayCaptureStopped: number;
21
- replayCaptureCompleted: number;
22
- replayRenderingCompleted: number;
23
- replayUploadCompleted: number;
24
- replayEventsUploadCompleted: number;
25
- loggingEvent: number;
26
- surveyCompleted: number;
27
- surveyStateReturned: number;
8
+ const SprigUserInterfaceMode: {
9
+ unspecified: number;
10
+ light: number;
11
+ dark: number;
28
12
  };
29
13
 
30
- // Usage: UserLeap.EventEmitter.addListener('surveyPresented', callback)
31
- const EventEmitter: any;
32
-
14
+ function overrideUserInterfaceMode(mode: SprigUserInterfaceMode): void;
33
15
  function visitorIdentifier(): number;
34
16
  function visitorIdentifierString(): string;
35
17
  function sdkVersion(): string;
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Platform, NativeModules, NativeEventEmitter } from "react-native";
1
+ import { Platform, NativeModules } from "react-native";
2
2
 
3
3
  import { version } from "./package.json";
4
4
 
@@ -8,29 +8,13 @@ const SurveyState = {
8
8
  NO_SURVEY: "NO_SURVEY",
9
9
  };
10
10
 
11
- const LifecycleEvent = {
12
- sdkReady: 0,
13
- visitorIdUpdated: 1,
14
- surveyHeight: 2,
15
- surveyWillPresent: 3,
16
- surveyPresented: 4,
17
- surveyAppeared: 5,
18
- surveyCloseRequested: 6,
19
- surveyWillClose: 7,
20
- surveyClosed: 8,
21
- replayCapture: 9,
22
- replayCaptureStarted: 10,
23
- replayCaptureStopped: 11,
24
- replayCaptureCompleted: 12,
25
- replayRenderingCompleted: 13,
26
- replayUploadCompleted: 14,
27
- replayEventsUploadCompleted: 15,
28
- loggingEvent: 16,
29
- surveyCompleted: 17,
30
- surveyStateReturned: 18
31
- }
32
11
 
33
- const UserLeapEventEmitter = new NativeEventEmitter(NativeModules.UserLeapBindings);
12
+ const SprigUserInterfaceMode = {
13
+ unspecified: 0,
14
+ light: 1,
15
+ dark: 2,
16
+ };
17
+
34
18
 
35
19
  const stringifyAttributes = (attributes) => {
36
20
  if (!(attributes instanceof Object && attributes.constructor === Object))
@@ -45,7 +29,7 @@ const isValidPlatform = () => {
45
29
  //Platform.Version is a number for android and string for ios
46
30
  return (
47
31
  (Platform.OS === "android" && String(Platform.Version) >= "21") ||
48
- (Platform.OS === "ios" && String(Platform.Version) >= "10.3")
32
+ (Platform.OS === "ios" && String(Platform.Version) >= "15.0")
49
33
  );
50
34
  };
51
35
 
@@ -280,6 +264,14 @@ const trackIdentifyAndPresent = (event, userId, partnerAnonynmousId) => {
280
264
  }
281
265
  };
282
266
 
267
+
268
+ const overrideUserInterfaceMode = (mode) => {
269
+ if (isValidPlatform()) {
270
+ NativeModules.UserLeapBindings.overrideUserInterfaceMode(mode);
271
+ }
272
+ }
273
+
274
+
283
275
  const UserLeap = {
284
276
  visitorIdentifier,
285
277
  visitorIdentifierString,
@@ -305,10 +297,10 @@ const UserLeap = {
305
297
  dismissActiveSurvey,
306
298
  pauseDisplayingSurveys,
307
299
  unpauseDisplayingSurveys,
300
+ overrideUserInterfaceMode,
308
301
  };
309
302
 
310
- UserLeap.LifecycleEvent = LifecycleEvent;
311
303
  UserLeap.SurveyState = SurveyState;
312
- UserLeap.EventEmitter = UserLeapEventEmitter;
304
+ UserLeap.SprigUserInterfaceMode = SprigUserInterfaceMode;
313
305
 
314
306
  export default UserLeap;
@@ -1,7 +1,6 @@
1
1
  #import <React/RCTBridgeModule.h>
2
- #import <React/RCTEventEmitter.h>
3
2
  @import UserLeapKit;
4
3
 
5
- @interface UserLeapBindings : RCTEventEmitter <RCTBridgeModule, _SGRNExtractor>
4
+ @interface UserLeapBindings : NSObject <RCTBridgeModule, _SGRNExtractor>
6
5
  @property (nonatomic, weak) RCTBridge *bridge;
7
6
  @end
@@ -45,11 +45,6 @@
45
45
  return surveyStateBinding;
46
46
  }
47
47
 
48
- /// These are required by RCTEventEmitter.
49
- - (NSArray<NSString *> *)supportedEvents {
50
- return [LifecycleEventUtil allNameStrings];
51
- }
52
-
53
48
  RCT_EXPORT_MODULE()
54
49
 
55
50
  RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(visitorIdentifier)
@@ -71,32 +66,6 @@ RCT_EXPORT_METHOD(configure:(NSString *)environmentId configuration:(NSDictionar
71
66
  {
72
67
  [[UserLeap shared] configureWithEnvironment:environmentId configuration:configuration];
73
68
  [[UserLeap shared] _passWithRnExtractor:self];
74
-
75
- /// Register for all the LifeCycle events.
76
- [self registerForAllLifecycleEvents];
77
- }
78
-
79
- - (void)registerForAllLifecycleEvents {
80
-
81
- for (NSNumber *eventVal in [LifecycleEventUtil all]) {
82
- [[UserLeap shared] registerEventListenerFor:[eventVal intValue] listener:^(NSDictionary<NSString *,id> * eventData) {
83
-
84
- NSString *type = eventData[LifecycleEventDataKey.eventType];
85
- if (!type) {
86
- return;
87
- }
88
-
89
- LifecycleEvent lifecycleEvent = [LifecycleEventUtil fromString:type];
90
- if (lifecycleEvent != LifecycleEventUnknown) {
91
-
92
- /// Always make sure the type exists in the supportedEvents; sending an unsupported event will crash the app.
93
- NSString *lifecycleEventName = [LifecycleEventUtil stringName:lifecycleEvent];
94
- if ([[self supportedEvents] containsObject: lifecycleEventName]) {
95
- [self sendEventWithName:lifecycleEventName body:eventData];
96
- }
97
- }
98
- }];
99
- }
100
69
  }
101
70
 
102
71
 
@@ -245,21 +214,54 @@ RCT_EXPORT_METHOD(trackIdentifyAndPresent:(NSString *)eventName userId:(NSString
245
214
  }
246
215
 
247
216
  - (_SGRNTextProperties *)textPropertiesFromView:(UIView * _Nonnull)passedView {
248
- if (![passedView isKindOfClass:[RCTTextView class]]) { return nil;}
249
- RCTUIManager* uiManager = [self.bridge moduleForClass:[RCTUIManager class]];
250
- RCTTextView *textView = (RCTTextView *)passedView;
251
- __block _SGRNTextProperties *textProperties = [[_SGRNTextProperties alloc] init];
252
- dispatch_sync(RCTGetUIManagerQueue(), ^{
253
- RCTShadowView *shadowView = [uiManager shadowViewForReactTag:textView.reactTag];
254
- if ([shadowView isKindOfClass:[RCTTextShadowView class]]) {
255
- RCTTextShadowView *textShadowView = (RCTTextShadowView *)shadowView;
256
- textProperties.text = [self extractText: textShadowView.reactSubviews];
257
- textProperties.color = textShadowView.textAttributes.foregroundColor;
258
- textProperties.alignment = textShadowView.textAttributes.alignment;
259
- textProperties.font = textShadowView.textAttributes.effectiveFont;
217
+
218
+ // Legacy for pre new arch.
219
+ if ([passedView isKindOfClass:[RCTTextView class]]) {
220
+ RCTUIManager* uiManager = [self.bridge moduleForClass:[RCTUIManager class]];
221
+ RCTTextView *textView = (RCTTextView *)passedView;
222
+ __block _SGRNTextProperties *textProperties = [[_SGRNTextProperties alloc] init];
223
+ dispatch_sync(RCTGetUIManagerQueue(), ^{
224
+ RCTShadowView *shadowView = [uiManager shadowViewForReactTag:textView.reactTag];
225
+ if ([shadowView isKindOfClass:[RCTTextShadowView class]]) {
226
+ RCTTextShadowView *textShadowView = (RCTTextShadowView *)shadowView;
227
+ NSString *text = [self extractText: textShadowView.reactSubviews];
228
+ if (text.length == 0) return;
229
+ textProperties.text = text;
230
+ textProperties.color = textShadowView.textAttributes.foregroundColor;
231
+ textProperties.alignment = textShadowView.textAttributes.alignment;
232
+ textProperties.font = textShadowView.textAttributes.effectiveFont;
233
+ }
234
+ });
235
+ if (textProperties.text.length == 0) return nil;
236
+ return textProperties;
237
+ }
238
+
239
+ // Text under new arch.
240
+ Class ParagraphComponentView = NSClassFromString(@"RCTParagraphComponentView");
241
+ if (ParagraphComponentView && [passedView isKindOfClass:ParagraphComponentView]) {
242
+ NSString *text = [self extractTextFromParagraphComponentView:passedView];
243
+ if (text.length == 0) return nil;
244
+ _SGRNTextProperties *textProperties = [[_SGRNTextProperties alloc] init];
245
+ textProperties.text = text;
246
+ if ([passedView respondsToSelector:@selector(attributedText)]) {
247
+ NSAttributedString *attrText = [passedView performSelector:@selector(attributedText)];
248
+ if (attrText.length > 0) {
249
+ NSDictionary *attrs = [attrText attributesAtIndex:0 effectiveRange:nil];
250
+ if (!textProperties.color && attrs[NSForegroundColorAttributeName]) {
251
+ textProperties.color = attrs[NSForegroundColorAttributeName];
252
+ }
253
+ if (!textProperties.font && attrs[NSFontAttributeName]) {
254
+ textProperties.font = attrs[NSFontAttributeName];
255
+ }
256
+ NSParagraphStyle *style = attrs[NSParagraphStyleAttributeName];
257
+ if (style) {
258
+ textProperties.alignment = style.alignment;
259
+ }
260
+ }
260
261
  }
261
- });
262
- return textProperties;
262
+ return textProperties;
263
+ }
264
+ return nil;
263
265
  }
264
266
 
265
267
  RCT_EXPORT_METHOD(dismissActiveSurvey)
@@ -277,6 +279,11 @@ RCT_EXPORT_METHOD(unpauseDisplayingSurveys)
277
279
  [[UserLeap shared] unpauseDisplayingSurveys];
278
280
  }
279
281
 
282
+ RCT_EXPORT_METHOD(overrideUserInterfaceMode:(NSInteger)mode)
283
+ {
284
+ [[UserLeap shared] overrideUserInterfaceModeWithMode:mode];
285
+ }
286
+
280
287
  - (_SGRNViewProperties * _Nullable)propertiesFromView:(UIView * _Nonnull)passedView {
281
288
  if ([passedView isKindOfClass:[RCTView class]]) {
282
289
  RCTView *rView = (RCTView *) passedView;
@@ -302,4 +309,22 @@ RCT_EXPORT_METHOD(unpauseDisplayingSurveys)
302
309
  }
303
310
  return text;
304
311
  }
312
+
313
+ - (NSString *)extractTextFromParagraphComponentView:(UIView *)view {
314
+ if ([view respondsToSelector:@selector(attributedText)]) {
315
+ NSAttributedString *attrText = [view performSelector:@selector(attributedText)];
316
+ return attrText.string;
317
+ }
318
+ if ([view respondsToSelector:@selector(text)]) {
319
+ NSString *text = [view performSelector:@selector(text)];
320
+ return text;
321
+ }
322
+ NSMutableString *result = [NSMutableString string];
323
+ for (UIView *subview in view.subviews) {
324
+ NSString *subText = [self extractTextFromParagraphComponentView:subview];
325
+ if (subText) [result appendString:subText];
326
+ }
327
+ return result;
328
+ }
329
+
305
330
  @end
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-userleap",
3
- "version": "2.21.0",
3
+ "version": "3.1.0",
4
4
  "description": "React Native module for UserLeap",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -17,11 +17,6 @@
17
17
  "scripts": {
18
18
  "test": "echo \"Error: no test specified\" && exit 1"
19
19
  },
20
- "repository": {
21
- "type": "git",
22
- "url": "git+https://github.com/UserLeap/react-native-userleap.git",
23
- "baseUrl": "https://github.com/UserLeap/react-native-userleap"
24
- },
25
20
  "keywords": [
26
21
  "userleap",
27
22
  "react-native",
@@ -38,9 +33,12 @@
38
33
  "babel-jest": "29.7.0",
39
34
  "eslint": "7.32.0",
40
35
  "jest": "29.7.0",
41
- "metro-react-native-babel-preset": "0.67.0",
42
- "react": "18.2.0",
43
- "react-native": "0.74.7",
36
+ "@react-native/babel-preset": "^0.81.0",
37
+ "react": "19.1.0",
38
+ "react-native": "0.81.0",
44
39
  "react-test-renderer": "18.2.0"
40
+ },
41
+ "overrides": {
42
+ "js-yaml": "3.14.2"
45
43
  }
46
44
  }
@@ -19,5 +19,5 @@ Pod::Spec.new do |s|
19
19
  s.requires_arc = true
20
20
 
21
21
  s.dependency "React"
22
- s.dependency "UserLeapKit", "4.29.0"
22
+ s.dependency "UserLeapKit", "4.30.0"
23
23
  end