@datadog/mobile-react-native-session-replay 2.7.0 → 2.8.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 (86) hide show
  1. package/DatadogSDKReactNativeSessionReplay.podspec +11 -8
  2. package/android/build.gradle +9 -1
  3. package/android/gradle.properties +1 -0
  4. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/views/DdPrivacyView.kt +59 -0
  5. package/android/src/main/res/values/ids.xml +12 -0
  6. package/android/src/newarch/kotlin/com/datadog/reactnative/sessionreplay/views/DdPrivacyViewManager.kt +50 -0
  7. package/android/src/oldarch/kotlin/com/datadog/reactnative/sessionreplay/views/DdPrivacyViewManager.kt +43 -0
  8. package/android/src/rn76/kotlin/com/datadog/reactnative/sessionreplay/utils/ReactViewBackgroundDrawableUtils.kt +1 -1
  9. package/android/src/{main → rnpost74}/kotlin/com/datadog/reactnative/sessionreplay/DdSDKReactNativeSessionReplayPackage.kt +9 -2
  10. package/android/src/rnpre74/kotlin/com/datadog/reactnative/sessionreplay/DdSDKReactNativeSessionReplayPackage.kt +31 -0
  11. package/ios/Sources/DdPrivacyOverrider.swift +71 -0
  12. package/ios/Sources/DdPrivacyViewFabric.mm +54 -0
  13. package/ios/Sources/DdPrivacyViewPaper.m +58 -0
  14. package/ios/Sources/RCTFabricWrapper.mm +1 -2
  15. package/ios/Sources/RCTTextViewRecorder.swift +20 -5
  16. package/lib/commonjs/components/SessionReplayView/HideView.js +34 -0
  17. package/lib/commonjs/components/SessionReplayView/HideView.js.map +1 -0
  18. package/lib/commonjs/components/SessionReplayView/MaskAllView.js +44 -0
  19. package/lib/commonjs/components/SessionReplayView/MaskAllView.js.map +1 -0
  20. package/lib/commonjs/components/SessionReplayView/MaskNoneView.js +41 -0
  21. package/lib/commonjs/components/SessionReplayView/MaskNoneView.js.map +1 -0
  22. package/lib/commonjs/components/SessionReplayView/PrivacyView.js +46 -0
  23. package/lib/commonjs/components/SessionReplayView/PrivacyView.js.map +1 -0
  24. package/lib/commonjs/components/SessionReplayView/index.js +40 -0
  25. package/lib/commonjs/components/SessionReplayView/index.js.map +1 -0
  26. package/lib/commonjs/index.js +7 -0
  27. package/lib/commonjs/index.js.map +1 -1
  28. package/lib/commonjs/specs/DdPrivacyView.js +19 -0
  29. package/lib/commonjs/specs/DdPrivacyView.js.map +1 -0
  30. package/lib/commonjs/specs/DdPrivacyViewNativeComponent.js +17 -0
  31. package/lib/commonjs/specs/DdPrivacyViewNativeComponent.js.map +1 -0
  32. package/lib/commonjs/specs/DdPrivacyViewPaper.js +16 -0
  33. package/lib/commonjs/specs/DdPrivacyViewPaper.js.map +1 -0
  34. package/lib/commonjs/types/DdPrivacyView.js +6 -0
  35. package/lib/commonjs/types/DdPrivacyView.js.map +1 -0
  36. package/lib/module/components/SessionReplayView/HideView.js +28 -0
  37. package/lib/module/components/SessionReplayView/HideView.js.map +1 -0
  38. package/lib/module/components/SessionReplayView/MaskAllView.js +37 -0
  39. package/lib/module/components/SessionReplayView/MaskAllView.js.map +1 -0
  40. package/lib/module/components/SessionReplayView/MaskNoneView.js +35 -0
  41. package/lib/module/components/SessionReplayView/MaskNoneView.js.map +1 -0
  42. package/lib/module/components/SessionReplayView/PrivacyView.js +39 -0
  43. package/lib/module/components/SessionReplayView/PrivacyView.js.map +1 -0
  44. package/lib/module/components/SessionReplayView/index.js +35 -0
  45. package/lib/module/components/SessionReplayView/index.js.map +1 -0
  46. package/lib/module/index.js +2 -0
  47. package/lib/module/index.js.map +1 -1
  48. package/lib/module/specs/DdPrivacyView.js +12 -0
  49. package/lib/module/specs/DdPrivacyView.js.map +1 -0
  50. package/lib/module/specs/DdPrivacyViewNativeComponent.js +11 -0
  51. package/lib/module/specs/DdPrivacyViewNativeComponent.js.map +1 -0
  52. package/lib/module/specs/DdPrivacyViewPaper.js +10 -0
  53. package/lib/module/specs/DdPrivacyViewPaper.js.map +1 -0
  54. package/lib/module/types/DdPrivacyView.js +2 -0
  55. package/lib/module/types/DdPrivacyView.js.map +1 -0
  56. package/lib/typescript/components/SessionReplayView/HideView.d.ts +11 -0
  57. package/lib/typescript/components/SessionReplayView/HideView.d.ts.map +1 -0
  58. package/lib/typescript/components/SessionReplayView/MaskAllView.d.ts +23 -0
  59. package/lib/typescript/components/SessionReplayView/MaskAllView.d.ts.map +1 -0
  60. package/lib/typescript/components/SessionReplayView/MaskNoneView.d.ts +14 -0
  61. package/lib/typescript/components/SessionReplayView/MaskNoneView.d.ts.map +1 -0
  62. package/lib/typescript/components/SessionReplayView/PrivacyView.d.ts +36 -0
  63. package/lib/typescript/components/SessionReplayView/PrivacyView.d.ts.map +1 -0
  64. package/lib/typescript/components/SessionReplayView/index.d.ts +28 -0
  65. package/lib/typescript/components/SessionReplayView/index.d.ts.map +1 -0
  66. package/lib/typescript/index.d.ts +2 -0
  67. package/lib/typescript/index.d.ts.map +1 -1
  68. package/lib/typescript/specs/DdPrivacyView.d.ts +3 -0
  69. package/lib/typescript/specs/DdPrivacyView.d.ts.map +1 -0
  70. package/lib/typescript/specs/DdPrivacyViewNativeComponent.d.ts +10 -0
  71. package/lib/typescript/specs/DdPrivacyViewNativeComponent.d.ts.map +1 -0
  72. package/lib/typescript/specs/DdPrivacyViewPaper.d.ts +4 -0
  73. package/lib/typescript/specs/DdPrivacyViewPaper.d.ts.map +1 -0
  74. package/lib/typescript/types/DdPrivacyView.d.ts +8 -0
  75. package/lib/typescript/types/DdPrivacyView.d.ts.map +1 -0
  76. package/package.json +3 -3
  77. package/src/components/SessionReplayView/HideView.tsx +25 -0
  78. package/src/components/SessionReplayView/MaskAllView.tsx +53 -0
  79. package/src/components/SessionReplayView/MaskNoneView.tsx +40 -0
  80. package/src/components/SessionReplayView/PrivacyView.tsx +67 -0
  81. package/src/components/SessionReplayView/index.ts +34 -0
  82. package/src/index.ts +3 -0
  83. package/src/specs/DdPrivacyView.ts +17 -0
  84. package/src/specs/DdPrivacyViewNativeComponent.ts +19 -0
  85. package/src/specs/DdPrivacyViewPaper.ts +15 -0
  86. package/src/types/DdPrivacyView.ts +14 -0
@@ -1,6 +1,7 @@
1
1
  require "json"
2
2
 
3
3
  package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+ folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
4
5
 
5
6
  Pod::Spec.new do |s|
6
7
  s.name = "DatadogSDKReactNativeSessionReplay"
@@ -13,13 +14,12 @@ Pod::Spec.new do |s|
13
14
  s.platforms = { :ios => "12.0", :tvos => "12.0" }
14
15
  s.source = { :git => "https://github.com/DataDog/dd-sdk-reactnative.git", :tag => "#{s.version}" }
15
16
 
16
-
17
17
  s.source_files = "ios/Sources/*.{h,m,mm,swift}"
18
-
18
+
19
19
  s.dependency "React-Core"
20
20
 
21
21
  # /!\ Remember to keep the version in sync with DatadogSDKReactNative.podspec
22
- s.dependency 'DatadogSessionReplay', '~> 2.25.0'
22
+ s.dependency 'DatadogSessionReplay', '~> 2.27.0'
23
23
  s.dependency 'DatadogSDKReactNative'
24
24
 
25
25
  s.test_spec 'Tests' do |test_spec|
@@ -28,16 +28,19 @@ Pod::Spec.new do |s|
28
28
  test_spec.platforms = { :ios => "13.4", :tvos => "13.4" }
29
29
  end
30
30
 
31
-
32
- # This guard prevents installing the dependencies when we run `pod install` in the old architecture.
33
- # The `install_modules_dependencies` function is only available from RN 0.71, the new architecture is not
34
- # supported on earlier RN versions.
35
31
  if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
32
+ s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
33
+
36
34
  s.pod_target_xcconfig = {
37
35
  "DEFINES_MODULE" => "YES",
38
- "OTHER_CPLUSPLUSFLAGS" => "-DRCT_NEW_ARCH_ENABLED=1"
36
+ "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
39
37
  }
38
+ end
40
39
 
40
+ if respond_to?(:install_modules_dependencies, true)
41
41
  install_modules_dependencies(s)
42
+ # else
43
+ # s.dependency "React-Core"
42
44
  end
45
+
43
46
  end
@@ -120,7 +120,7 @@ android {
120
120
  }
121
121
 
122
122
  defaultConfig {
123
- minSdkVersion 21
123
+ minSdkVersion getExtOrIntegerDefault('minSdkVersion')
124
124
  targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
125
125
  versionCode 1
126
126
  versionName "1.0"
@@ -146,6 +146,14 @@ android {
146
146
  } else {
147
147
  java.srcDirs += ['src/rnlegacy/kotlin']
148
148
  }
149
+
150
+
151
+ if (reactNativeMinorVersion >= 74) {
152
+ java.srcDirs += ['src/rnpost74/kotlin']
153
+ } else {
154
+ java.srcDirs += ['src/rnpre74/kotlin']
155
+ }
156
+
149
157
  }
150
158
  test {
151
159
  java.srcDir("src/test/kotlin")
@@ -1,5 +1,6 @@
1
1
  DatadogSDKReactNativeSessionReplay_kotlinVersion=1.8.21
2
2
  DatadogSDKReactNativeSessionReplay_compileSdkVersion=33
3
+ DatadogSDKReactNativeSessionReplay_minSdkVersion=21
3
4
  DatadogSDKReactNativeSessionReplay_buildToolsVersion=33.0.0
4
5
  DatadogSDKReactNativeSessionReplay_targetSdkVersion=33
5
6
  android.useAndroidX=true
@@ -0,0 +1,59 @@
1
+ /*
2
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
4
+ * Copyright 2016-Present Datadog, Inc.
5
+ */
6
+
7
+ package com.datadog.reactnative.sessionreplay.views
8
+
9
+ import android.content.Context
10
+ import com.datadog.reactnative.sessionreplay.R
11
+ import com.facebook.react.views.view.ReactViewGroup
12
+
13
+ /**
14
+ * Native React Native UI element that inherits from ReactViewGroup and exposes extra properties.
15
+ */
16
+ class DdPrivacyView(context: Context) : ReactViewGroup(context) {
17
+ /**
18
+ * Defines the way text and input should be masked.
19
+ */
20
+ var textAndInputPrivacy: String? = null
21
+ set(value) {
22
+ field = value
23
+ this.setTag(R.id.datadog_text_and_input_privacy, value)
24
+ }
25
+
26
+ /**
27
+ * Defines the way images should be masked.
28
+ */
29
+ var imagePrivacy: String? = null
30
+ set(value) {
31
+ field = value
32
+ this.setTag(R.id.datadog_image_privacy, value)
33
+ }
34
+
35
+ /**
36
+ * Defines the way user touches should be masked.
37
+ */
38
+ var touchPrivacy: String? = null
39
+ set(value) {
40
+ field = value
41
+ this.setTag(R.id.datadog_touch_privacy, value)
42
+ }
43
+
44
+ /**
45
+ * Defines the way certain parts of the UI can be set to hidden.
46
+ */
47
+ var hide: Boolean = false
48
+ set(value) {
49
+ field = value
50
+ this.setTag(R.id.datadog_hidden, value)
51
+ }
52
+
53
+ init {
54
+ this.setTag(R.id.datadog_hidden, this.hide)
55
+ this.setTag(R.id.datadog_image_privacy, this.imagePrivacy)
56
+ this.setTag(R.id.datadog_text_and_input_privacy, this.textAndInputPrivacy)
57
+ this.setTag(R.id.datadog_touch_privacy, this.touchPrivacy)
58
+ }
59
+ }
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="utf-8"?><!--
2
+ ~ Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3
+ ~ This product includes software developed at Datadog (https://www.datadoghq.com/).
4
+ ~ Copyright 2016-Present Datadog, Inc.
5
+ -->
6
+
7
+ <resources>
8
+ <item name="datadog_hidden" type="id"/>
9
+ <item name="datadog_image_privacy" type="id"/>
10
+ <item name="datadog_text_and_input_privacy" type="id"/>
11
+ <item name="datadog_touch_privacy" type="id"/>
12
+ </resources>
@@ -0,0 +1,50 @@
1
+ /*
2
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
4
+ * Copyright 2016-Present Datadog, Inc.
5
+ */
6
+
7
+ package com.datadog.reactnative.sessionreplay.views
8
+
9
+ import com.facebook.react.bridge.ReactApplicationContext
10
+ import com.facebook.react.uimanager.ThemedReactContext
11
+ import com.facebook.react.uimanager.ViewGroupManager
12
+ import com.facebook.react.uimanager.ViewManagerDelegate
13
+ import com.facebook.react.uimanager.annotations.ReactProp
14
+ import com.facebook.react.viewmanagers.DdPrivacyViewManagerDelegate
15
+ import com.facebook.react.viewmanagers.DdPrivacyViewManagerInterface
16
+
17
+ class DdPrivacyViewManager(context: ReactApplicationContext) : ViewGroupManager<DdPrivacyView>(),
18
+ DdPrivacyViewManagerInterface<DdPrivacyView> {
19
+ companion object {
20
+ const val REACT_CLASS = "DdPrivacyView"
21
+ }
22
+
23
+ private val delegate: DdPrivacyViewManagerDelegate<DdPrivacyView, DdPrivacyViewManager> = DdPrivacyViewManagerDelegate(this)
24
+
25
+ override fun getDelegate(): ViewManagerDelegate<DdPrivacyView> = delegate
26
+
27
+ override fun getName(): String = REACT_CLASS
28
+
29
+ override fun createViewInstance(context: ThemedReactContext): DdPrivacyView = DdPrivacyView(context)
30
+
31
+ @ReactProp(name = "hide")
32
+ override fun setHide(view: DdPrivacyView?, value: Boolean) {
33
+ view?.let { view.hide = value }
34
+ }
35
+
36
+ @ReactProp(name = "textAndInputPrivacy")
37
+ override fun setTextAndInputPrivacy(view: DdPrivacyView?, value: String?) {
38
+ view?.let { view.textAndInputPrivacy = value }
39
+ }
40
+
41
+ @ReactProp(name = "imagePrivacy")
42
+ override fun setImagePrivacy(view: DdPrivacyView?, value: String?) {
43
+ view?.let { view.imagePrivacy = value }
44
+ }
45
+
46
+ @ReactProp(name = "touchPrivacy")
47
+ override fun setTouchPrivacy(view: DdPrivacyView?, value: String?) {
48
+ view?.let { view.touchPrivacy = value }
49
+ }
50
+ }
@@ -0,0 +1,43 @@
1
+ /*
2
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
4
+ * Copyright 2016-Present Datadog, Inc.
5
+ */
6
+ package com.datadog.reactnative.sessionreplay.views
7
+
8
+ import com.facebook.react.bridge.ReactApplicationContext
9
+ import com.facebook.react.uimanager.ThemedReactContext
10
+ import com.facebook.react.uimanager.ViewGroupManager
11
+ import com.facebook.react.uimanager.annotations.ReactProp
12
+
13
+ class DdPrivacyViewManager(context: ReactApplicationContext) : ViewGroupManager<DdPrivacyView>() {
14
+ companion object {
15
+ const val REACT_CLASS = "DdPrivacyView"
16
+ }
17
+
18
+ override fun getName(): String = REACT_CLASS
19
+
20
+ override fun createViewInstance(context: ThemedReactContext): DdPrivacyView {
21
+ return DdPrivacyView(context)
22
+ }
23
+
24
+ @ReactProp(name = "hide")
25
+ fun setHide(view: DdPrivacyView?, value: Boolean) {
26
+ view?.let { view.hide = value }
27
+ }
28
+
29
+ @ReactProp(name = "textAndInputPrivacy")
30
+ fun setTextAndInputPrivacy(view: DdPrivacyView?, value: String?) {
31
+ view?.let { view.textAndInputPrivacy = value }
32
+ }
33
+
34
+ @ReactProp(name = "imagePrivacy")
35
+ fun setImagePrivacy(view: DdPrivacyView?, value: String?) {
36
+ view?.let { view.imagePrivacy = value }
37
+ }
38
+
39
+ @ReactProp(name = "touchPrivacy")
40
+ fun setTouchPrivacy(view: DdPrivacyView?, value: String?) {
41
+ view?.let { view.touchPrivacy = value }
42
+ }
43
+ }
@@ -42,7 +42,7 @@ internal class ReactViewBackgroundDrawableUtils : DrawableUtils() {
42
42
 
43
43
  @OptIn(UnstableReactNativeAPI::class)
44
44
  override fun getReactBackgroundFromDrawable(drawable: Drawable?): Drawable? {
45
- return when(drawable) {
45
+ return when (drawable) {
46
46
  is CSSBackgroundDrawable -> drawable
47
47
  is InsetDrawable -> getReactBackgroundFromDrawable(drawable.drawable)
48
48
  is LayerDrawable -> getDrawableFromLayerDrawable(drawable)
@@ -6,16 +6,22 @@
6
6
 
7
7
  package com.datadog.reactnative.sessionreplay
8
8
 
9
- import com.facebook.react.TurboReactPackage
9
+ import com.datadog.reactnative.sessionreplay.views.DdPrivacyViewManager
10
+ import com.facebook.react.BaseReactPackage
10
11
  import com.facebook.react.bridge.NativeModule
11
12
  import com.facebook.react.bridge.ReactApplicationContext
12
13
  import com.facebook.react.module.model.ReactModuleInfo
13
14
  import com.facebook.react.module.model.ReactModuleInfoProvider
15
+ import com.facebook.react.uimanager.ViewManager
14
16
 
15
17
  /**
16
18
  * Package of native dd-sdk-reactnative native modules.
17
19
  */
18
- class DdSDKReactNativeSessionReplayPackage : TurboReactPackage() {
20
+ class DdSDKReactNativeSessionReplayPackage : BaseReactPackage() {
21
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
22
+ return listOf(DdPrivacyViewManager(reactContext))
23
+ }
24
+
19
25
  override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
20
26
  return when (name) {
21
27
  DdSessionReplayImplementation.NAME -> DdSessionReplay(reactContext)
@@ -43,4 +49,5 @@ class DdSDKReactNativeSessionReplayPackage : TurboReactPackage() {
43
49
  moduleInfos
44
50
  }
45
51
  }
52
+
46
53
  }
@@ -0,0 +1,31 @@
1
+ /*
2
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
4
+ * Copyright 2016-Present Datadog, Inc.
5
+ */
6
+
7
+ package com.datadog.reactnative.sessionreplay
8
+
9
+ import com.datadog.reactnative.sessionreplay.views.DdPrivacyViewManager
10
+ import com.facebook.react.ReactPackage
11
+ import com.facebook.react.bridge.NativeModule
12
+ import com.facebook.react.bridge.ReactApplicationContext
13
+ import com.facebook.react.uimanager.ViewManager
14
+
15
+ /**
16
+ * Package of native dd-sdk-reactnative native modules.
17
+ */
18
+ class DdSDKReactNativeSessionReplayPackage : ReactPackage {
19
+
20
+ override fun createViewManagers(
21
+ reactContext: ReactApplicationContext
22
+ ): List<ViewManager<*, *>> {
23
+ return listOf(DdPrivacyViewManager(reactContext))
24
+ }
25
+
26
+ override fun createNativeModules(
27
+ reactContext: ReactApplicationContext
28
+ ): List<NativeModule> {
29
+ return listOf(DdSessionReplay(reactContext))
30
+ }
31
+ }
@@ -0,0 +1,71 @@
1
+ import ObjectiveC
2
+ import UIKit
3
+ @_spi(objc) import DatadogSessionReplay
4
+
5
+ @objc public class DdPrivacyOverrider: NSObject {
6
+ @objc public static func setOverrides(
7
+ for view: UIView,
8
+ textPrivacy: NSString?,
9
+ imagePrivacy: NSString?,
10
+ touchPrivacy: NSString?,
11
+ hide: Bool
12
+ ) {
13
+ let wrapper = objc_SessionReplayPrivacyOverrides(view: view)
14
+
15
+ if let raw = textPrivacy as String?,
16
+ let val = mapTextPrivacy(raw)
17
+ {
18
+ wrapper.textAndInputPrivacy = val
19
+ }
20
+
21
+ if let raw = imagePrivacy as String?,
22
+ let val = mapImagePrivacy(raw)
23
+ {
24
+ wrapper.imagePrivacy = val
25
+ }
26
+
27
+ if let raw = touchPrivacy as String?,
28
+ let val = mapTouchPrivacy(raw)
29
+ {
30
+ wrapper.touchPrivacy = val
31
+ }
32
+
33
+ wrapper.hide = NSNumber(value: hide)
34
+ }
35
+
36
+ private static func mapTextPrivacy(_ string: String) -> objc_TextAndInputPrivacyLevelOverride? {
37
+ switch string.uppercased() {
38
+ case "MASK_SENSITIVE_INPUTS": return .maskSensitiveInputs
39
+ case "MASK_ALL_INPUTS": return .maskAllInputs
40
+ case "MASK_ALL": return .maskAll
41
+ default: return objc_TextAndInputPrivacyLevelOverride.none
42
+ }
43
+ }
44
+
45
+ private static func mapImagePrivacy(_ string: String) -> objc_ImagePrivacyLevelOverride? {
46
+ switch string.uppercased() {
47
+ case "MASK_NONE": return .maskNone
48
+ case "MASK_NON_BUNDLED_ONLY": return .maskNonBundledOnly
49
+ case "MASK_ALL": return .maskAll
50
+ default: return objc_ImagePrivacyLevelOverride.none
51
+ }
52
+ }
53
+
54
+ private static func mapTouchPrivacy(_ string: String) -> objc_TouchPrivacyLevelOverride? {
55
+ switch string.uppercased() {
56
+ case "SHOW": return .show
57
+ case "HIDE": return .hide
58
+ default: return objc_TouchPrivacyLevelOverride.none
59
+ }
60
+ }
61
+
62
+ @objc public static func debugPrint(for view: UIView) {
63
+ let wrapper = objc_SessionReplayPrivacyOverrides(view: view)
64
+ print("""
65
+ - text: \(wrapper.textAndInputPrivacy)
66
+ - image: \(wrapper.imagePrivacy)
67
+ - touch: \(wrapper.touchPrivacy)
68
+ - hide: \(String(describing: wrapper.hide))
69
+ """)
70
+ }
71
+ }
@@ -0,0 +1,54 @@
1
+ /*
2
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
4
+ * Copyright 2016-Present Datadog, Inc.
5
+ */
6
+
7
+ #if RCT_NEW_ARCH_ENABLED
8
+ #import <React/RCTViewComponentView.h>
9
+ #import <react/renderer/components/DdSDKReactNativeSessionReplay/ComponentDescriptors.h>
10
+ #import <react/renderer/components/DdSDKReactNativeSessionReplay/EventEmitters.h>
11
+ #import <react/renderer/components/DdSDKReactNativeSessionReplay/Props.h>
12
+ #import <react/renderer/components/DdSDKReactNativeSessionReplay/RCTComponentViewHelpers.h>
13
+ #import <React/RCTFabricComponentsPlugins.h>
14
+ #import "DatadogSDKReactNativeSessionReplay-Swift.h"
15
+
16
+ using namespace facebook::react;
17
+
18
+ @interface DdPrivacyViewFabric : RCTViewComponentView <RCTDdPrivacyViewViewProtocol>
19
+ @end
20
+
21
+ @implementation DdPrivacyViewFabric {
22
+ UIView * _view;
23
+ }
24
+
25
+ + (ComponentDescriptorProvider)componentDescriptorProvider {
26
+ return concreteComponentDescriptorProvider<DdPrivacyViewComponentDescriptor>();
27
+ }
28
+
29
+ - (instancetype)initWithFrame:(CGRect)frame {
30
+ if (self = [super initWithFrame:frame]) {
31
+ static const auto defaultProps = std::make_shared<const DdPrivacyViewProps>();
32
+ _props = defaultProps;
33
+ }
34
+ return self;
35
+ }
36
+
37
+ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps {
38
+ const auto &newProps = *std::static_pointer_cast<DdPrivacyViewProps const>(props);
39
+
40
+ NSString *text = [NSString stringWithUTF8String:newProps.textAndInputPrivacy.c_str()];
41
+ NSString *image = [NSString stringWithUTF8String:newProps.imagePrivacy.c_str()];
42
+ NSString *touch = [NSString stringWithUTF8String:newProps.touchPrivacy.c_str()];
43
+
44
+ [DdPrivacyOverrider setOverridesFor:self textPrivacy:text imagePrivacy:image touchPrivacy:touch hide:newProps.hide];
45
+
46
+ [super updateProps:props oldProps:oldProps];
47
+ }
48
+
49
+ @end
50
+
51
+ Class<RCTComponentViewProtocol> DdPrivacyViewCls(void) {
52
+ return DdPrivacyViewFabric.class;
53
+ }
54
+ #endif
@@ -0,0 +1,58 @@
1
+ /*
2
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
4
+ * Copyright 2016-Present Datadog, Inc.
5
+ */
6
+
7
+ #import <React/RCTViewManager.h>
8
+ #import "DatadogSDKReactNativeSessionReplay-Swift.h"
9
+
10
+ @interface DdPrivacyView : UIView
11
+
12
+ @property (nonatomic, strong) NSString *textPrivacy;
13
+ @property (nonatomic, strong) NSString *imagePrivacy;
14
+ @property (nonatomic, strong) NSString *touchPrivacy;
15
+ @property (nonatomic, assign) BOOL hide;
16
+
17
+ @end
18
+
19
+ @implementation DdPrivacyView
20
+ @end
21
+
22
+
23
+ @interface DdPrivacyViewPaper : RCTViewManager
24
+ @end
25
+
26
+ @implementation DdPrivacyViewPaper
27
+
28
+ RCT_EXPORT_MODULE(DdPrivacyView)
29
+
30
+ - (UIView *) view {
31
+ return [[DdPrivacyView alloc] init];
32
+ }
33
+
34
+ RCT_CUSTOM_VIEW_PROPERTY(textAndInputPrivacy, NSString, DdPrivacyView) {
35
+ view.textPrivacy = [RCTConvert NSString:json];
36
+ [self setPrivacyOverridesFor:view];
37
+ }
38
+
39
+ RCT_CUSTOM_VIEW_PROPERTY(imagePrivacy, NSString, DdPrivacyView) {
40
+ view.imagePrivacy = [RCTConvert NSString:json];
41
+ [self setPrivacyOverridesFor:view];
42
+ }
43
+
44
+ RCT_CUSTOM_VIEW_PROPERTY(touchPrivacy, NSString, DdPrivacyView) {
45
+ view.touchPrivacy = [RCTConvert NSString:json];
46
+ [self setPrivacyOverridesFor:view];
47
+ }
48
+
49
+ RCT_CUSTOM_VIEW_PROPERTY(hide, BOOL, DdPrivacyView) {
50
+ view.hide = json ? [json boolValue] : NO;
51
+ [self setPrivacyOverridesFor:view];
52
+ }
53
+
54
+ - (void) setPrivacyOverridesFor:(DdPrivacyView *) view {
55
+ [DdPrivacyOverrider setOverridesFor:view textPrivacy:view.textPrivacy imagePrivacy:view.imagePrivacy touchPrivacy:view.touchPrivacy hide:view.hide];
56
+ }
57
+
58
+ @end
@@ -12,13 +12,12 @@
12
12
  #import <React-RCTFabric/React/RCTParagraphComponentView.h>
13
13
  #import <React-RCTFabric/React/RCTConversions.h>
14
14
 
15
- #if RCT_VERSION_MINOR > 74
15
+ #if __has_include(<React-FabricComponents/react/renderer/components/text/ParagraphProps.h>)
16
16
  #import <React-FabricComponents/react/renderer/components/text/ParagraphProps.h>
17
17
  #else
18
18
  #import <React-Fabric/react/renderer/components/text/ParagraphProps.h>
19
19
  #endif
20
20
 
21
-
22
21
  namespace rct = facebook::react;
23
22
  #endif
24
23
 
@@ -10,8 +10,8 @@ import DatadogSessionReplay
10
10
  import React
11
11
 
12
12
  internal class RCTTextViewRecorder: SessionReplayNodeRecorder {
13
- internal var textObfuscator: (SessionReplayViewTreeRecordingContext) -> SessionReplayTextObfuscating = { context in
14
- return context.recorder.textAndInputPrivacy.staticTextObfuscator
13
+ internal var textObfuscator: (SessionReplayViewTreeRecordingContext, SessionReplayViewAttributes) -> SessionReplayTextObfuscating = { context, viewAttributes in
14
+ return viewAttributes.resolveTextAndInputPrivacyLevel(in: context).staticTextObfuscator
15
15
  }
16
16
 
17
17
  internal var identifier = UUID()
@@ -41,7 +41,7 @@ internal class RCTTextViewRecorder: SessionReplayNodeRecorder {
41
41
  text: textProperties.text,
42
42
  textAlignment: textProperties.alignment,
43
43
  textColor: textProperties.foregroundColor,
44
- textObfuscator: textObfuscator(context),
44
+ textObfuscator: textObfuscator(context, attributes),
45
45
  fontSize: textProperties.fontSize,
46
46
  contentRect: textProperties.contentRect
47
47
  )
@@ -78,8 +78,23 @@ internal class RCTTextViewRecorder: SessionReplayNodeRecorder {
78
78
  var shadowView: RCTTextShadowView? = nil
79
79
  let tag = textView.reactTag
80
80
 
81
- RCTGetUIManagerQueue().sync {
82
- shadowView = uiManager.shadowView(forReactTag: tag) as? RCTTextShadowView
81
+ let timeout: TimeInterval = 0.2
82
+ let semaphore = DispatchSemaphore(value: 0)
83
+
84
+ // We need to access the shadow view from the UIManager queue, but we're currently on the main thread.
85
+ // Calling `.sync` from the main thread to the UIManager queue is unsafe, because the UIManager queue
86
+ // may already be executing a layout operation that in turn requires the main thread (e.g. measuring a native view).
87
+ // That would create a circular dependency and deadlock the app.
88
+ // To avoid this, we dispatch the work asynchronously to the UIManager queue and wait with a timeout.
89
+ // This ensures we block only if absolutely necessary, and can fail gracefully if the queue is busy.
90
+ RCTGetUIManagerQueue().async {
91
+ shadowView = self.uiManager.shadowView(forReactTag: tag) as? RCTTextShadowView
92
+ semaphore.signal()
93
+ }
94
+
95
+ let waitResult = semaphore.wait(timeout: .now() + timeout)
96
+ if waitResult == .timedOut {
97
+ return nil
83
98
  }
84
99
 
85
100
  guard let shadow = shadowView else {
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.HideView = HideView;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _PrivacyView = require("./PrivacyView");
9
+ var _jsxRuntime = require("react/jsx-runtime");
10
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
+ /*
12
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
13
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
14
+ * Copyright 2016-Present Datadog, Inc.
15
+ */
16
+
17
+ /**
18
+ * A wrapper component that hides all of its content from session replays.
19
+ *
20
+ * When used, none of the children within this view will appear in the replay recording.
21
+ * This is useful for UI areas that contain sensitive or confidential information that should
22
+ * be completely excluded from visibility, not just masked.
23
+ */
24
+ function HideView({
25
+ children,
26
+ ...props
27
+ }) {
28
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_PrivacyView.PrivacyView, {
29
+ ...props,
30
+ hide: true,
31
+ children: children
32
+ });
33
+ }
34
+ //# sourceMappingURL=HideView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_react","_interopRequireDefault","require","_PrivacyView","_jsxRuntime","e","__esModule","default","HideView","children","props","jsx","PrivacyView","hide"],"sourceRoot":"../../../../src","sources":["components/SessionReplayView/HideView.tsx"],"mappings":";;;;;;AAOA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AAEA,IAAAC,YAAA,GAAAD,OAAA;AAA4C,IAAAE,WAAA,GAAAF,OAAA;AAAA,SAAAD,uBAAAI,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAT5C;AACA;AACA;AACA;AACA;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASG,QAAQA,CAAC;EAAEC,QAAQ;EAAE,GAAGC;AAAiB,CAAC,EAAE;EACxD,oBACI,IAAAN,WAAA,CAAAO,GAAA,EAACR,YAAA,CAAAS,WAAW;IAAA,GAAKF,KAAK;IAAEG,IAAI,EAAE,IAAK;IAAAJ,QAAA,EAC9BA;EAAQ,CACA,CAAC;AAEtB","ignoreList":[]}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.MaskAllView = MaskAllView;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _SessionReplay = require("../../SessionReplay");
9
+ var _PrivacyView = require("./PrivacyView");
10
+ var _jsxRuntime = require("react/jsx-runtime");
11
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
+ /*
13
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
14
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
15
+ * Copyright 2016-Present Datadog, Inc.
16
+ */
17
+
18
+ /**
19
+ * A wrapper component that enforces full masking on all content within it.
20
+ *
21
+ * This includes:
22
+ * - Masking all text and input values (e.g., replacing them with asterisks)
23
+ * - Masking all images
24
+ * - Hiding or optionally showing touch interactions, depending on `showTouch`
25
+ *
26
+ * This component is useful for marking sensitive UI sections that should not be visible
27
+ * in session replays.
28
+ */
29
+ function MaskAllView({
30
+ children,
31
+ showTouch,
32
+ ...props
33
+ }) {
34
+ const touchPrivacy = showTouch ? _SessionReplay.TouchPrivacyLevel.SHOW : _SessionReplay.TouchPrivacyLevel.HIDE;
35
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_PrivacyView.PrivacyView, {
36
+ ...props,
37
+ textAndInputPrivacy: _SessionReplay.TextAndInputPrivacyLevel.MASK_ALL,
38
+ imagePrivacy: _SessionReplay.ImagePrivacyLevel.MASK_ALL,
39
+ touchPrivacy: touchPrivacy,
40
+ hide: false,
41
+ children: children
42
+ });
43
+ }
44
+ //# sourceMappingURL=MaskAllView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_react","_interopRequireDefault","require","_SessionReplay","_PrivacyView","_jsxRuntime","e","__esModule","default","MaskAllView","children","showTouch","props","touchPrivacy","TouchPrivacyLevel","SHOW","HIDE","jsx","PrivacyView","textAndInputPrivacy","TextAndInputPrivacyLevel","MASK_ALL","imagePrivacy","ImagePrivacyLevel","hide"],"sourceRoot":"../../../../src","sources":["components/SessionReplayView/MaskAllView.tsx"],"mappings":";;;;;;AAOA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AAEA,IAAAC,cAAA,GAAAD,OAAA;AAMA,IAAAE,YAAA,GAAAF,OAAA;AAA4C,IAAAG,WAAA,GAAAH,OAAA;AAAA,SAAAD,uBAAAK,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAf5C;AACA;AACA;AACA;AACA;;AAqBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASG,WAAWA,CAAC;EAAEC,QAAQ;EAAEC,SAAS;EAAE,GAAGC;AAAa,CAAC,EAAE;EAClE,MAAMC,YAAY,GAAGF,SAAS,GACxBG,gCAAiB,CAACC,IAAI,GACtBD,gCAAiB,CAACE,IAAI;EAE5B,oBACI,IAAAX,WAAA,CAAAY,GAAA,EAACb,YAAA,CAAAc,WAAW;IAAA,GACJN,KAAK;IACTO,mBAAmB,EAAEC,uCAAwB,CAACC,QAAS;IACvDC,YAAY,EAAEC,gCAAiB,CAACF,QAAS;IACzCR,YAAY,EAAEA,YAAa;IAC3BW,IAAI,EAAE,KAAM;IAAAd,QAAA,EAEXA;EAAQ,CACA,CAAC;AAEtB","ignoreList":[]}