@multiplayer-app/session-recorder-react-native 1.0.1-beta.3 → 1.0.1-beta.5

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 (463) hide show
  1. package/LICENSE +1 -2
  2. package/README.md +216 -155
  3. package/SessionRecorderNative.podspec +9 -14
  4. package/android/build.gradle +21 -44
  5. package/android/gradle.properties +4 -4
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativeConfig.kt +52 -0
  8. package/android/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativeModule.kt +860 -0
  9. package/android/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativePackage.kt +33 -0
  10. package/android/src/main/java/com/multiplayer/sessionrecordernative/model/TargetInfo.kt +9 -0
  11. package/android/src/main/java/com/multiplayer/sessionrecordernative/util/ViewUtils.kt +72 -0
  12. package/ios/SessionRecorderNative.podspec +4 -2
  13. package/ios/SessionRecorderNative.swift +1 -1
  14. package/ios/SessionRecorderNativeSpec.swift +3 -3
  15. package/lib/module/components/ScreenRecorderView/ScreenRecorderView.js +23 -0
  16. package/lib/module/components/ScreenRecorderView/ScreenRecorderView.js.map +1 -0
  17. package/lib/module/components/ScreenRecorderView/index.js +4 -0
  18. package/lib/module/components/ScreenRecorderView/index.js.map +1 -0
  19. package/lib/module/components/SessionRecorderWidget/ErrorBanner.js +64 -0
  20. package/lib/module/components/SessionRecorderWidget/ErrorBanner.js.map +1 -0
  21. package/lib/module/components/SessionRecorderWidget/FinalPopover.js +74 -0
  22. package/lib/module/components/SessionRecorderWidget/FinalPopover.js.map +1 -0
  23. package/lib/module/components/SessionRecorderWidget/FloatingButton.js +191 -0
  24. package/lib/module/components/SessionRecorderWidget/FloatingButton.js.map +1 -0
  25. package/lib/module/components/SessionRecorderWidget/InitialPopover.js +138 -0
  26. package/lib/module/components/SessionRecorderWidget/InitialPopover.js.map +1 -0
  27. package/lib/module/components/SessionRecorderWidget/ModalContainer.js +177 -0
  28. package/lib/module/components/SessionRecorderWidget/ModalContainer.js.map +1 -0
  29. package/lib/module/components/SessionRecorderWidget/ModalHeader.js +27 -0
  30. package/lib/module/components/SessionRecorderWidget/ModalHeader.js.map +1 -0
  31. package/lib/module/components/SessionRecorderWidget/SessionRecorderWidget.js +133 -0
  32. package/lib/module/components/SessionRecorderWidget/SessionRecorderWidget.js.map +1 -0
  33. package/lib/module/components/SessionRecorderWidget/icons.js +93 -0
  34. package/lib/module/components/SessionRecorderWidget/icons.js.map +1 -0
  35. package/lib/module/components/SessionRecorderWidget/index.js +5 -0
  36. package/lib/module/components/SessionRecorderWidget/index.js.map +1 -0
  37. package/lib/module/components/SessionRecorderWidget/styles.js +173 -0
  38. package/lib/module/components/SessionRecorderWidget/styles.js.map +1 -0
  39. package/lib/module/components/index.js +5 -0
  40. package/lib/module/components/index.js.map +1 -0
  41. package/lib/module/config/constants.js +42 -0
  42. package/lib/module/config/constants.js.map +1 -0
  43. package/lib/module/config/defaults.js +81 -0
  44. package/lib/module/config/defaults.js.map +1 -0
  45. package/lib/module/config/index.js +9 -0
  46. package/lib/module/config/index.js.map +1 -0
  47. package/lib/module/config/masking.js +35 -0
  48. package/lib/module/config/masking.js.map +1 -0
  49. package/lib/module/config/session-recorder.js +44 -0
  50. package/lib/module/config/session-recorder.js.map +1 -0
  51. package/lib/module/config/validators.js +28 -0
  52. package/lib/module/config/validators.js.map +1 -0
  53. package/lib/module/config/widget.js +35 -0
  54. package/lib/module/config/widget.js.map +1 -0
  55. package/lib/module/context/SessionRecorderContext.js +93 -0
  56. package/lib/module/context/SessionRecorderContext.js.map +1 -0
  57. package/lib/module/context/SessionRecorderStore.js +12 -0
  58. package/lib/module/context/SessionRecorderStore.js.map +1 -0
  59. package/lib/module/context/useSessionRecorderStore.js +20 -0
  60. package/lib/module/context/useSessionRecorderStore.js.map +1 -0
  61. package/lib/module/context/useStoreSelector.js +27 -0
  62. package/lib/module/context/useStoreSelector.js.map +1 -0
  63. package/lib/module/index.js +13 -0
  64. package/lib/module/index.js.map +1 -0
  65. package/lib/module/native/SessionRecorderNative.js +74 -0
  66. package/lib/module/native/SessionRecorderNative.js.map +1 -0
  67. package/lib/module/native/index.js +4 -0
  68. package/lib/module/native/index.js.map +1 -0
  69. package/lib/module/otel/helpers.js +218 -0
  70. package/lib/module/otel/helpers.js.map +1 -0
  71. package/lib/module/otel/index.js +95 -0
  72. package/lib/module/otel/index.js.map +1 -0
  73. package/lib/module/otel/instrumentations/index.js +102 -0
  74. package/lib/module/otel/instrumentations/index.js.map +1 -0
  75. package/lib/module/package.json +1 -0
  76. package/lib/module/patch/index.js +4 -0
  77. package/lib/module/patch/index.js.map +1 -0
  78. package/lib/module/patch/xhr.js +116 -0
  79. package/lib/module/patch/xhr.js.map +1 -0
  80. package/lib/module/recorder/eventExporter.js +130 -0
  81. package/lib/module/recorder/eventExporter.js.map +1 -0
  82. package/lib/module/recorder/gestureRecorder.js +641 -0
  83. package/lib/module/recorder/gestureRecorder.js.map +1 -0
  84. package/lib/module/recorder/index.js +168 -0
  85. package/lib/module/recorder/index.js.map +1 -0
  86. package/lib/module/recorder/navigationTracker.js +228 -0
  87. package/lib/module/recorder/navigationTracker.js.map +1 -0
  88. package/lib/module/recorder/screenRecorder.js +495 -0
  89. package/lib/module/recorder/screenRecorder.js.map +1 -0
  90. package/lib/module/services/api.service.js +149 -0
  91. package/lib/module/services/api.service.js.map +1 -0
  92. package/lib/module/services/network.service.js +178 -0
  93. package/lib/module/services/network.service.js.map +1 -0
  94. package/lib/module/services/screenMaskingService.js +107 -0
  95. package/lib/module/services/screenMaskingService.js.map +1 -0
  96. package/lib/module/services/storage.service.js +179 -0
  97. package/lib/module/services/storage.service.js.map +1 -0
  98. package/lib/module/session-recorder.js +541 -0
  99. package/lib/module/session-recorder.js.map +1 -0
  100. package/lib/module/types/configs.js +4 -0
  101. package/lib/module/types/configs.js.map +1 -0
  102. package/lib/module/types/expo-constants.d.js +2 -0
  103. package/lib/module/types/expo-constants.d.js.map +1 -0
  104. package/lib/module/types/index.js +11 -0
  105. package/lib/module/types/index.js.map +1 -0
  106. package/lib/module/types/session-recorder.js +68 -0
  107. package/lib/module/types/session-recorder.js.map +1 -0
  108. package/lib/module/types/session.js +9 -0
  109. package/lib/module/types/session.js.map +1 -0
  110. package/lib/module/utils/app-metadata.js +28 -0
  111. package/lib/module/utils/app-metadata.js.map +1 -0
  112. package/lib/module/utils/constants.optional.expo.js +6 -0
  113. package/lib/module/utils/constants.optional.expo.js.map +1 -0
  114. package/lib/module/utils/constants.optional.js +8 -0
  115. package/lib/module/utils/constants.optional.js.map +1 -0
  116. package/lib/module/utils/createStore.js +27 -0
  117. package/lib/module/utils/createStore.js.map +1 -0
  118. package/lib/module/utils/index.js +11 -0
  119. package/lib/module/utils/index.js.map +1 -0
  120. package/lib/module/utils/logger.js +185 -0
  121. package/lib/module/utils/logger.js.map +1 -0
  122. package/lib/module/utils/platform.js +340 -0
  123. package/lib/module/utils/platform.js.map +1 -0
  124. package/lib/module/utils/request-utils.js +58 -0
  125. package/lib/module/utils/request-utils.js.map +1 -0
  126. package/lib/module/utils/rrweb-events.js +276 -0
  127. package/lib/module/utils/rrweb-events.js.map +1 -0
  128. package/lib/module/utils/session.js +21 -0
  129. package/lib/module/utils/session.js.map +1 -0
  130. package/lib/module/utils/shallowEqual.js +17 -0
  131. package/lib/module/utils/shallowEqual.js.map +1 -0
  132. package/lib/module/utils/time.js +17 -0
  133. package/lib/module/utils/time.js.map +1 -0
  134. package/lib/module/utils/type-utils.js +69 -0
  135. package/lib/module/utils/type-utils.js.map +1 -0
  136. package/lib/module/version.js +4 -0
  137. package/lib/module/version.js.map +1 -0
  138. package/lib/typescript/package.json +1 -0
  139. package/lib/typescript/src/components/ScreenRecorderView/ScreenRecorderView.d.ts +6 -0
  140. package/lib/typescript/src/components/ScreenRecorderView/ScreenRecorderView.d.ts.map +1 -0
  141. package/lib/typescript/src/components/ScreenRecorderView/index.d.ts +2 -0
  142. package/lib/typescript/src/components/ScreenRecorderView/index.d.ts.map +1 -0
  143. package/{dist → lib/typescript/src}/components/SessionRecorderWidget/ErrorBanner.d.ts +1 -0
  144. package/lib/typescript/src/components/SessionRecorderWidget/ErrorBanner.d.ts.map +1 -0
  145. package/{dist → lib/typescript/src}/components/SessionRecorderWidget/FinalPopover.d.ts +2 -1
  146. package/lib/typescript/src/components/SessionRecorderWidget/FinalPopover.d.ts.map +1 -0
  147. package/{dist → lib/typescript/src}/components/SessionRecorderWidget/FloatingButton.d.ts +1 -0
  148. package/lib/typescript/src/components/SessionRecorderWidget/FloatingButton.d.ts.map +1 -0
  149. package/{dist → lib/typescript/src}/components/SessionRecorderWidget/InitialPopover.d.ts +2 -1
  150. package/lib/typescript/src/components/SessionRecorderWidget/InitialPopover.d.ts.map +1 -0
  151. package/{dist → lib/typescript/src}/components/SessionRecorderWidget/ModalContainer.d.ts +1 -0
  152. package/lib/typescript/src/components/SessionRecorderWidget/ModalContainer.d.ts.map +1 -0
  153. package/{dist → lib/typescript/src}/components/SessionRecorderWidget/ModalHeader.d.ts +1 -0
  154. package/lib/typescript/src/components/SessionRecorderWidget/ModalHeader.d.ts.map +1 -0
  155. package/{dist → lib/typescript/src}/components/SessionRecorderWidget/SessionRecorderWidget.d.ts +1 -0
  156. package/lib/typescript/src/components/SessionRecorderWidget/SessionRecorderWidget.d.ts.map +1 -0
  157. package/{dist → lib/typescript/src}/components/SessionRecorderWidget/icons.d.ts +1 -0
  158. package/lib/typescript/src/components/SessionRecorderWidget/icons.d.ts.map +1 -0
  159. package/lib/typescript/src/components/SessionRecorderWidget/index.d.ts +3 -0
  160. package/lib/typescript/src/components/SessionRecorderWidget/index.d.ts.map +1 -0
  161. package/{dist → lib/typescript/src}/components/SessionRecorderWidget/styles.d.ts +4 -3
  162. package/lib/typescript/src/components/SessionRecorderWidget/styles.d.ts.map +1 -0
  163. package/lib/typescript/src/components/index.d.ts +3 -0
  164. package/lib/typescript/src/components/index.d.ts.map +1 -0
  165. package/{dist → lib/typescript/src}/config/constants.d.ts +1 -0
  166. package/lib/typescript/src/config/constants.d.ts.map +1 -0
  167. package/{dist → lib/typescript/src}/config/defaults.d.ts +2 -1
  168. package/lib/typescript/src/config/defaults.d.ts.map +1 -0
  169. package/{dist → lib/typescript/src}/config/index.d.ts +1 -0
  170. package/lib/typescript/src/config/index.d.ts.map +1 -0
  171. package/lib/typescript/src/config/masking.d.ts +3 -0
  172. package/lib/typescript/src/config/masking.d.ts.map +1 -0
  173. package/lib/typescript/src/config/session-recorder.d.ts +3 -0
  174. package/lib/typescript/src/config/session-recorder.d.ts.map +1 -0
  175. package/{dist → lib/typescript/src}/config/validators.d.ts +1 -0
  176. package/lib/typescript/src/config/validators.d.ts.map +1 -0
  177. package/{dist → lib/typescript/src}/config/widget.d.ts +2 -1
  178. package/lib/typescript/src/config/widget.d.ts.map +1 -0
  179. package/{dist → lib/typescript/src}/context/SessionRecorderContext.d.ts +3 -2
  180. package/lib/typescript/src/context/SessionRecorderContext.d.ts.map +1 -0
  181. package/{dist → lib/typescript/src}/context/SessionRecorderStore.d.ts +2 -1
  182. package/lib/typescript/src/context/SessionRecorderStore.d.ts.map +1 -0
  183. package/{dist → lib/typescript/src}/context/useSessionRecorderStore.d.ts +4 -3
  184. package/lib/typescript/src/context/useSessionRecorderStore.d.ts.map +1 -0
  185. package/{dist → lib/typescript/src}/context/useStoreSelector.d.ts +2 -1
  186. package/lib/typescript/src/context/useStoreSelector.d.ts.map +1 -0
  187. package/{dist → lib/typescript/src}/index.d.ts +1 -0
  188. package/lib/typescript/src/index.d.ts.map +1 -0
  189. package/{dist → lib/typescript/src}/native/SessionRecorderNative.d.ts +21 -3
  190. package/lib/typescript/src/native/SessionRecorderNative.d.ts.map +1 -0
  191. package/lib/typescript/src/native/index.d.ts +2 -0
  192. package/lib/typescript/src/native/index.d.ts.map +1 -0
  193. package/{dist → lib/typescript/src}/otel/helpers.d.ts +3 -2
  194. package/lib/typescript/src/otel/helpers.d.ts.map +1 -0
  195. package/{dist → lib/typescript/src}/otel/index.d.ts +2 -2
  196. package/lib/typescript/src/otel/index.d.ts.map +1 -0
  197. package/{dist → lib/typescript/src}/otel/instrumentations/index.d.ts +2 -1
  198. package/lib/typescript/src/otel/instrumentations/index.d.ts.map +1 -0
  199. package/lib/typescript/src/patch/index.d.ts +2 -0
  200. package/lib/typescript/src/patch/index.d.ts.map +1 -0
  201. package/{dist → lib/typescript/src}/patch/xhr.d.ts +1 -0
  202. package/lib/typescript/src/patch/xhr.d.ts.map +1 -0
  203. package/{dist → lib/typescript/src}/recorder/eventExporter.d.ts +2 -1
  204. package/lib/typescript/src/recorder/eventExporter.d.ts.map +1 -0
  205. package/{dist → lib/typescript/src}/recorder/gestureRecorder.d.ts +3 -2
  206. package/lib/typescript/src/recorder/gestureRecorder.d.ts.map +1 -0
  207. package/{dist → lib/typescript/src}/recorder/index.d.ts +3 -2
  208. package/lib/typescript/src/recorder/index.d.ts.map +1 -0
  209. package/{dist → lib/typescript/src}/recorder/navigationTracker.d.ts +2 -1
  210. package/lib/typescript/src/recorder/navigationTracker.d.ts.map +1 -0
  211. package/{dist → lib/typescript/src}/recorder/screenRecorder.d.ts +4 -4
  212. package/lib/typescript/src/recorder/screenRecorder.d.ts.map +1 -0
  213. package/{dist → lib/typescript/src}/services/api.service.d.ts +2 -1
  214. package/lib/typescript/src/services/api.service.d.ts.map +1 -0
  215. package/{dist → lib/typescript/src}/services/network.service.d.ts +1 -0
  216. package/lib/typescript/src/services/network.service.d.ts.map +1 -0
  217. package/{dist → lib/typescript/src}/services/screenMaskingService.d.ts +2 -1
  218. package/lib/typescript/src/services/screenMaskingService.d.ts.map +1 -0
  219. package/{dist → lib/typescript/src}/services/storage.service.d.ts +2 -1
  220. package/lib/typescript/src/services/storage.service.d.ts.map +1 -0
  221. package/{dist → lib/typescript/src}/session-recorder.d.ts +3 -2
  222. package/lib/typescript/src/session-recorder.d.ts.map +1 -0
  223. package/{dist → lib/typescript/src}/types/configs.d.ts +3 -2
  224. package/lib/typescript/src/types/configs.d.ts.map +1 -0
  225. package/{dist → lib/typescript/src}/types/index.d.ts +1 -0
  226. package/lib/typescript/src/types/index.d.ts.map +1 -0
  227. package/{dist → lib/typescript/src}/types/session-recorder.d.ts +7 -6
  228. package/lib/typescript/src/types/session-recorder.d.ts.map +1 -0
  229. package/{dist → lib/typescript/src}/types/session.d.ts +1 -0
  230. package/lib/typescript/src/types/session.d.ts.map +1 -0
  231. package/{dist → lib/typescript/src}/utils/app-metadata.d.ts +1 -0
  232. package/lib/typescript/src/utils/app-metadata.d.ts.map +1 -0
  233. package/{dist → lib/typescript/src}/utils/constants.optional.d.ts +1 -0
  234. package/lib/typescript/src/utils/constants.optional.d.ts.map +1 -0
  235. package/{dist → lib/typescript/src}/utils/constants.optional.expo.d.ts +1 -0
  236. package/lib/typescript/src/utils/constants.optional.expo.d.ts.map +1 -0
  237. package/{dist → lib/typescript/src}/utils/createStore.d.ts +1 -0
  238. package/lib/typescript/src/utils/createStore.d.ts.map +1 -0
  239. package/lib/typescript/src/utils/index.d.ts +8 -0
  240. package/lib/typescript/src/utils/index.d.ts.map +1 -0
  241. package/{dist → lib/typescript/src}/utils/logger.d.ts +2 -1
  242. package/lib/typescript/src/utils/logger.d.ts.map +1 -0
  243. package/{dist → lib/typescript/src}/utils/platform.d.ts +2 -1
  244. package/lib/typescript/src/utils/platform.d.ts.map +1 -0
  245. package/{dist → lib/typescript/src}/utils/request-utils.d.ts +1 -0
  246. package/lib/typescript/src/utils/request-utils.d.ts.map +1 -0
  247. package/{dist → lib/typescript/src}/utils/rrweb-events.d.ts +2 -1
  248. package/lib/typescript/src/utils/rrweb-events.d.ts.map +1 -0
  249. package/{dist → lib/typescript/src}/utils/session.d.ts +1 -0
  250. package/lib/typescript/src/utils/session.d.ts.map +1 -0
  251. package/{dist → lib/typescript/src}/utils/shallowEqual.d.ts +1 -0
  252. package/lib/typescript/src/utils/shallowEqual.d.ts.map +1 -0
  253. package/{dist → lib/typescript/src}/utils/time.d.ts +1 -0
  254. package/lib/typescript/src/utils/time.d.ts.map +1 -0
  255. package/{dist → lib/typescript/src}/utils/type-utils.d.ts +1 -0
  256. package/lib/typescript/src/utils/type-utils.d.ts.map +1 -0
  257. package/{dist → lib/typescript/src}/version.d.ts +1 -0
  258. package/lib/typescript/src/version.d.ts.map +1 -0
  259. package/package.json +133 -44
  260. package/src/components/ScreenRecorderView/ScreenRecorderView.tsx +20 -0
  261. package/src/components/ScreenRecorderView/index.ts +1 -0
  262. package/src/components/SessionRecorderWidget/ErrorBanner.tsx +58 -0
  263. package/src/components/SessionRecorderWidget/FinalPopover.tsx +96 -0
  264. package/src/components/SessionRecorderWidget/FloatingButton.tsx +176 -0
  265. package/src/components/SessionRecorderWidget/InitialPopover.tsx +167 -0
  266. package/src/components/SessionRecorderWidget/ModalContainer.tsx +189 -0
  267. package/src/components/SessionRecorderWidget/ModalHeader.tsx +26 -0
  268. package/src/components/SessionRecorderWidget/SessionRecorderWidget.tsx +150 -0
  269. package/src/components/SessionRecorderWidget/icons.tsx +80 -0
  270. package/src/components/SessionRecorderWidget/index.ts +3 -0
  271. package/src/components/SessionRecorderWidget/styles.ts +168 -0
  272. package/src/config/constants.ts +67 -0
  273. package/src/config/defaults.ts +105 -0
  274. package/src/config/index.ts +6 -0
  275. package/src/config/masking.ts +60 -0
  276. package/src/config/session-recorder.ts +87 -0
  277. package/src/config/validators.ts +54 -0
  278. package/src/config/widget.ts +47 -0
  279. package/src/context/SessionRecorderContext.tsx +138 -0
  280. package/src/context/SessionRecorderStore.ts +22 -0
  281. package/src/context/useSessionRecorderStore.ts +34 -0
  282. package/src/context/useStoreSelector.ts +36 -0
  283. package/src/index.ts +10 -0
  284. package/src/native/SessionRecorderNative.ts +180 -0
  285. package/src/native/index.ts +5 -0
  286. package/src/otel/helpers.ts +290 -0
  287. package/src/otel/index.ts +132 -0
  288. package/src/otel/instrumentations/index.ts +118 -0
  289. package/src/patch/xhr.ts +148 -0
  290. package/src/recorder/eventExporter.ts +150 -0
  291. package/src/recorder/gestureRecorder.ts +828 -0
  292. package/src/recorder/index.ts +203 -0
  293. package/src/recorder/navigationTracker.ts +268 -0
  294. package/src/recorder/screenRecorder.ts +600 -0
  295. package/src/services/api.service.ts +216 -0
  296. package/src/services/network.service.ts +191 -0
  297. package/src/services/screenMaskingService.ts +153 -0
  298. package/src/services/storage.service.ts +248 -0
  299. package/src/session-recorder.ts +647 -0
  300. package/src/types/configs.ts +118 -0
  301. package/src/types/expo-constants.d.ts +7 -0
  302. package/src/types/index.ts +27 -0
  303. package/src/types/session-recorder.ts +381 -0
  304. package/src/types/session.ts +65 -0
  305. package/src/utils/app-metadata.ts +31 -0
  306. package/src/utils/constants.optional.expo.ts +5 -0
  307. package/src/utils/constants.optional.ts +18 -0
  308. package/src/utils/createStore.ts +32 -0
  309. package/{dist/utils/index.d.ts → src/utils/index.ts} +1 -0
  310. package/src/utils/logger.ts +245 -0
  311. package/src/utils/platform.ts +401 -0
  312. package/src/utils/request-utils.ts +61 -0
  313. package/src/utils/rrweb-events.ts +329 -0
  314. package/src/utils/session.ts +22 -0
  315. package/src/utils/shallowEqual.ts +20 -0
  316. package/src/utils/time.ts +20 -0
  317. package/src/utils/type-utils.ts +75 -0
  318. package/src/version.ts +1 -0
  319. package/REACT_NATIVE_SETUP.md +0 -91
  320. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  321. package/android/gradle/wrapper/gradle-wrapper.properties +0 -7
  322. package/android/gradlew +0 -249
  323. package/android/gradlew.bat +0 -92
  324. package/copy-react-native-dist.sh +0 -56
  325. package/dist/components/ScreenRecorderView/ScreenRecorderView.d.ts +0 -5
  326. package/dist/components/ScreenRecorderView/ScreenRecorderView.js +0 -1
  327. package/dist/components/ScreenRecorderView/ScreenRecorderView.js.map +0 -1
  328. package/dist/components/ScreenRecorderView/index.d.ts +0 -1
  329. package/dist/components/ScreenRecorderView/index.js +0 -1
  330. package/dist/components/ScreenRecorderView/index.js.map +0 -1
  331. package/dist/components/SessionRecorderWidget/ErrorBanner.js +0 -1
  332. package/dist/components/SessionRecorderWidget/ErrorBanner.js.map +0 -1
  333. package/dist/components/SessionRecorderWidget/FinalPopover.js +0 -1
  334. package/dist/components/SessionRecorderWidget/FinalPopover.js.map +0 -1
  335. package/dist/components/SessionRecorderWidget/FloatingButton.js +0 -1
  336. package/dist/components/SessionRecorderWidget/FloatingButton.js.map +0 -1
  337. package/dist/components/SessionRecorderWidget/InitialPopover.js +0 -1
  338. package/dist/components/SessionRecorderWidget/InitialPopover.js.map +0 -1
  339. package/dist/components/SessionRecorderWidget/ModalContainer.js +0 -1
  340. package/dist/components/SessionRecorderWidget/ModalContainer.js.map +0 -1
  341. package/dist/components/SessionRecorderWidget/ModalHeader.js +0 -1
  342. package/dist/components/SessionRecorderWidget/ModalHeader.js.map +0 -1
  343. package/dist/components/SessionRecorderWidget/SessionRecorderWidget.js +0 -1
  344. package/dist/components/SessionRecorderWidget/SessionRecorderWidget.js.map +0 -1
  345. package/dist/components/SessionRecorderWidget/icons.js +0 -1
  346. package/dist/components/SessionRecorderWidget/icons.js.map +0 -1
  347. package/dist/components/SessionRecorderWidget/index.d.ts +0 -2
  348. package/dist/components/SessionRecorderWidget/index.js +0 -1
  349. package/dist/components/SessionRecorderWidget/index.js.map +0 -1
  350. package/dist/components/SessionRecorderWidget/styles.js +0 -1
  351. package/dist/components/SessionRecorderWidget/styles.js.map +0 -1
  352. package/dist/components/index.js +0 -1
  353. package/dist/components/index.js.map +0 -1
  354. package/dist/config/constants.js +0 -1
  355. package/dist/config/constants.js.map +0 -1
  356. package/dist/config/defaults.js +0 -1
  357. package/dist/config/defaults.js.map +0 -1
  358. package/dist/config/index.js +0 -1
  359. package/dist/config/index.js.map +0 -1
  360. package/dist/config/masking.d.ts +0 -2
  361. package/dist/config/masking.js +0 -1
  362. package/dist/config/masking.js.map +0 -1
  363. package/dist/config/session-recorder.d.ts +0 -2
  364. package/dist/config/session-recorder.js +0 -1
  365. package/dist/config/session-recorder.js.map +0 -1
  366. package/dist/config/validators.js +0 -1
  367. package/dist/config/validators.js.map +0 -1
  368. package/dist/config/widget.js +0 -1
  369. package/dist/config/widget.js.map +0 -1
  370. package/dist/context/SessionRecorderContext.js +0 -1
  371. package/dist/context/SessionRecorderContext.js.map +0 -1
  372. package/dist/context/SessionRecorderStore.js +0 -1
  373. package/dist/context/SessionRecorderStore.js.map +0 -1
  374. package/dist/context/useSessionRecorderStore.js +0 -1
  375. package/dist/context/useSessionRecorderStore.js.map +0 -1
  376. package/dist/context/useStoreSelector.js +0 -1
  377. package/dist/context/useStoreSelector.js.map +0 -1
  378. package/dist/index.js +0 -1
  379. package/dist/index.js.map +0 -1
  380. package/dist/native/GestureRecorderNative.d.ts +0 -57
  381. package/dist/native/GestureRecorderNative.js +0 -1
  382. package/dist/native/GestureRecorderNative.js.map +0 -1
  383. package/dist/native/GestureRecorderNativeTurboSpec.d.ts +0 -31
  384. package/dist/native/GestureRecorderNativeTurboSpec.js +0 -1
  385. package/dist/native/GestureRecorderNativeTurboSpec.js.map +0 -1
  386. package/dist/native/SessionRecorderNative.js +0 -1
  387. package/dist/native/SessionRecorderNative.js.map +0 -1
  388. package/dist/native/SessionRecorderNativeTurboSpec.d.ts +0 -17
  389. package/dist/native/SessionRecorderNativeTurboSpec.js +0 -1
  390. package/dist/native/SessionRecorderNativeTurboSpec.js.map +0 -1
  391. package/dist/native/index.d.ts +0 -1
  392. package/dist/native/index.js +0 -1
  393. package/dist/native/index.js.map +0 -1
  394. package/dist/otel/helpers.js +0 -1
  395. package/dist/otel/helpers.js.map +0 -1
  396. package/dist/otel/index.js +0 -1
  397. package/dist/otel/index.js.map +0 -1
  398. package/dist/otel/instrumentations/index.js +0 -1
  399. package/dist/otel/instrumentations/index.js.map +0 -1
  400. package/dist/patch/index.js +0 -1
  401. package/dist/patch/index.js.map +0 -1
  402. package/dist/patch/xhr.js +0 -1
  403. package/dist/patch/xhr.js.map +0 -1
  404. package/dist/recorder/eventExporter.js +0 -1
  405. package/dist/recorder/eventExporter.js.map +0 -1
  406. package/dist/recorder/gestureRecorder.js +0 -1
  407. package/dist/recorder/gestureRecorder.js.map +0 -1
  408. package/dist/recorder/index.js +0 -1
  409. package/dist/recorder/index.js.map +0 -1
  410. package/dist/recorder/navigationTracker.js +0 -1
  411. package/dist/recorder/navigationTracker.js.map +0 -1
  412. package/dist/recorder/screenRecorder.js +0 -1
  413. package/dist/recorder/screenRecorder.js.map +0 -1
  414. package/dist/services/api.service.js +0 -1
  415. package/dist/services/api.service.js.map +0 -1
  416. package/dist/services/network.service.js +0 -1
  417. package/dist/services/network.service.js.map +0 -1
  418. package/dist/services/screenMaskingService.js +0 -1
  419. package/dist/services/screenMaskingService.js.map +0 -1
  420. package/dist/services/storage.service.js +0 -1
  421. package/dist/services/storage.service.js.map +0 -1
  422. package/dist/session-recorder.js +0 -1
  423. package/dist/session-recorder.js.map +0 -1
  424. package/dist/types/configs.js +0 -1
  425. package/dist/types/configs.js.map +0 -1
  426. package/dist/types/index.js +0 -1
  427. package/dist/types/index.js.map +0 -1
  428. package/dist/types/session-recorder.js +0 -1
  429. package/dist/types/session-recorder.js.map +0 -1
  430. package/dist/types/session.js +0 -1
  431. package/dist/types/session.js.map +0 -1
  432. package/dist/utils/app-metadata.js +0 -1
  433. package/dist/utils/app-metadata.js.map +0 -1
  434. package/dist/utils/constants.optional.expo.js +0 -1
  435. package/dist/utils/constants.optional.expo.js.map +0 -1
  436. package/dist/utils/constants.optional.js +0 -1
  437. package/dist/utils/constants.optional.js.map +0 -1
  438. package/dist/utils/createStore.js +0 -1
  439. package/dist/utils/createStore.js.map +0 -1
  440. package/dist/utils/index.js +0 -1
  441. package/dist/utils/index.js.map +0 -1
  442. package/dist/utils/logger.js +0 -1
  443. package/dist/utils/logger.js.map +0 -1
  444. package/dist/utils/platform.js +0 -1
  445. package/dist/utils/platform.js.map +0 -1
  446. package/dist/utils/request-utils.js +0 -1
  447. package/dist/utils/request-utils.js.map +0 -1
  448. package/dist/utils/rrweb-events.js +0 -1
  449. package/dist/utils/rrweb-events.js.map +0 -1
  450. package/dist/utils/session.js +0 -1
  451. package/dist/utils/session.js.map +0 -1
  452. package/dist/utils/shallowEqual.js +0 -1
  453. package/dist/utils/shallowEqual.js.map +0 -1
  454. package/dist/utils/time.js +0 -1
  455. package/dist/utils/time.js.map +0 -1
  456. package/dist/utils/type-utils.js +0 -1
  457. package/dist/utils/type-utils.js.map +0 -1
  458. package/dist/version.js +0 -1
  459. package/dist/version.js.map +0 -1
  460. package/docs/AUTO_METADATA_DETECTION.md +0 -108
  461. package/react-native.config.js +0 -13
  462. /package/{dist/components/index.d.ts → src/components/index.ts} +0 -0
  463. /package/{dist/patch/index.d.ts → src/patch/index.ts} +0 -0
@@ -0,0 +1,176 @@
1
+ import React, { useRef, useEffect, useMemo } from 'react';
2
+ import {
3
+ StyleSheet,
4
+ Platform,
5
+ Animated,
6
+ PanResponder,
7
+ View,
8
+ Dimensions,
9
+ } from 'react-native';
10
+ import { SessionState } from '../../types';
11
+ import { StorageService } from '../../services/storage.service';
12
+ import { RecordIcon, CapturingIcon, PausedIcon } from './icons';
13
+
14
+ interface FloatingButtonProps {
15
+ sessionState: SessionState | null;
16
+ onPress: () => void;
17
+ }
18
+
19
+ const buttonSize = 52;
20
+ const rightOffset = 20;
21
+ const topOffset = Platform.OS === 'ios' ? 60 : 40;
22
+
23
+ const FloatingButton: React.FC<FloatingButtonProps> = ({
24
+ sessionState,
25
+ onPress,
26
+ }) => {
27
+ const position = useRef(new Animated.ValueXY({ x: 0, y: 0 })).current;
28
+ const lastPosition = useRef({ top: topOffset, right: rightOffset });
29
+ const storageService = useRef(StorageService.getInstance()).current;
30
+
31
+ const screenBounds = useMemo(() => {
32
+ const { width, height } = Dimensions.get('window');
33
+
34
+ return {
35
+ minTop: topOffset,
36
+ maxTop: height - buttonSize,
37
+ minRight: 0,
38
+ maxRight: width - buttonSize,
39
+ };
40
+ }, []);
41
+
42
+ // Load saved position on component mount
43
+ useEffect(() => {
44
+ const savedPosition = storageService.getFloatingButtonPosition();
45
+ if (savedPosition) {
46
+ const { width } = Dimensions.get('window');
47
+ const top = savedPosition.y;
48
+ const right = width - savedPosition.x - buttonSize;
49
+ lastPosition.current = { top, right };
50
+ position.setValue({ x: right, y: top });
51
+ } else {
52
+ position.setValue({
53
+ x: lastPosition.current.right,
54
+ y: lastPosition.current.top,
55
+ });
56
+ }
57
+ }, []);
58
+
59
+ const panResponder = useRef(
60
+ PanResponder.create({
61
+ onStartShouldSetPanResponder: () => true,
62
+ onMoveShouldSetPanResponder: (_, gestureState) => {
63
+ const distance = Math.sqrt(
64
+ gestureState.dx * gestureState.dx + gestureState.dy * gestureState.dy
65
+ );
66
+ return distance > 5;
67
+ },
68
+ onPanResponderGrant: () => {
69
+ // Set the initial position for this gesture
70
+ position.setValue({
71
+ x: lastPosition.current.right,
72
+ y: lastPosition.current.top,
73
+ });
74
+ },
75
+ onPanResponderMove: (_, gestureState) => {
76
+ // Calculate new position based on gesture movement
77
+ const newTop = lastPosition.current.top + gestureState.dy;
78
+ const newRight = lastPosition.current.right - gestureState.dx;
79
+
80
+ // Update position during drag
81
+ position.setValue({ x: newRight, y: newTop });
82
+ },
83
+ onPanResponderRelease: (_, gestureState) => {
84
+ // Check if this was actually a drag (significant movement)
85
+ const distance = Math.sqrt(
86
+ gestureState.dx * gestureState.dx + gestureState.dy * gestureState.dy
87
+ );
88
+
89
+ // If it was a tap (no significant movement), trigger onPress
90
+ if (distance <= 5) {
91
+ onPress();
92
+ } else {
93
+ // Calculate new position after dragging
94
+ const newTop = lastPosition.current.top + gestureState.dy;
95
+ const newRight = lastPosition.current.right - gestureState.dx;
96
+
97
+ // Clamp to screen bounds
98
+ const clampedTop = Math.max(
99
+ screenBounds.minTop,
100
+ Math.min(screenBounds.maxTop, newTop)
101
+ );
102
+ const clampedRight = Math.max(
103
+ screenBounds.minRight,
104
+ Math.min(screenBounds.maxRight, newRight)
105
+ );
106
+
107
+ // Update position
108
+ lastPosition.current = { top: clampedTop, right: clampedRight };
109
+ position.setValue({ x: clampedRight, y: clampedTop });
110
+
111
+ // Convert back to x,y coordinates for storage
112
+ const { width } = Dimensions.get('window');
113
+ const storagePosition = {
114
+ x: width - clampedRight - buttonSize,
115
+ y: clampedTop,
116
+ };
117
+
118
+ // Persist position to AsyncStorage (debounced)
119
+ storageService.saveFloatingButtonPosition(storagePosition);
120
+ }
121
+ },
122
+ })
123
+ ).current;
124
+
125
+ // Memoized button icon and color for performance
126
+ const content = useMemo(() => {
127
+ switch (sessionState) {
128
+ case SessionState.started:
129
+ return {
130
+ icon: <CapturingIcon size={28} color="white" />,
131
+ color: '#FF4444',
132
+ };
133
+ case SessionState.paused:
134
+ return {
135
+ icon: <PausedIcon size={28} color="white" />,
136
+ color: '#FFA500',
137
+ };
138
+ default:
139
+ return {
140
+ icon: <RecordIcon size={28} color="#718096" />,
141
+ color: '#ffffff',
142
+ };
143
+ }
144
+ }, [sessionState]);
145
+
146
+ return (
147
+ <Animated.View
148
+ style={[styles.draggableButton, { top: position.y, right: position.x }]}
149
+ {...panResponder.panHandlers}
150
+ >
151
+ <View style={[styles.floatingButton, { backgroundColor: content.color }]}>
152
+ {content.icon}
153
+ </View>
154
+ </Animated.View>
155
+ );
156
+ };
157
+
158
+ const styles = StyleSheet.create({
159
+ draggableButton: {
160
+ position: 'absolute',
161
+ },
162
+ floatingButton: {
163
+ elevation: 8,
164
+ shadowRadius: 4,
165
+ width: buttonSize,
166
+ shadowColor: '#000',
167
+ height: buttonSize,
168
+ shadowOpacity: 0.25,
169
+ alignItems: 'center',
170
+ justifyContent: 'center',
171
+ borderRadius: buttonSize / 2,
172
+ shadowOffset: { width: 0, height: 2 },
173
+ },
174
+ });
175
+
176
+ export default FloatingButton;
@@ -0,0 +1,167 @@
1
+ import React, { useMemo, useState } from 'react';
2
+ import { View, Text, Pressable, Switch } from 'react-native';
3
+ import { SessionType } from '@multiplayer-app/session-recorder-common';
4
+ import { type TextOverridesOptions } from '../../types';
5
+ import { sharedStyles } from './styles';
6
+ import ModalHeader from './ModalHeader';
7
+ import { CapturingIcon } from './icons';
8
+ import { logger } from '../../utils';
9
+
10
+ interface InitialPopoverProps extends React.PropsWithChildren {
11
+ isContinuous: boolean;
12
+ showContinuousRecording: boolean;
13
+ textOverrides: TextOverridesOptions;
14
+ onStartRecording: (sessionType: SessionType) => void;
15
+ onStopRecording: (comment?: string) => void;
16
+ onSaveContinuousSession: () => void;
17
+ onClose: () => void;
18
+ isSubmitting: boolean;
19
+ isOnline: boolean;
20
+ }
21
+
22
+ const InitialPopover: React.FC<InitialPopoverProps> = ({
23
+ isContinuous,
24
+ textOverrides,
25
+ showContinuousRecording,
26
+ onStartRecording,
27
+ onStopRecording,
28
+ onSaveContinuousSession,
29
+ isOnline,
30
+ children,
31
+ }) => {
32
+ const [saving, setSaving] = useState(false);
33
+ const [loading, setLoading] = useState(false);
34
+ const [continuousRecording, setContinuousRecording] = useState(isContinuous);
35
+
36
+ const handleStartRecording = async () => {
37
+ try {
38
+ setLoading(true);
39
+ await onStartRecording(SessionType.PLAIN);
40
+ } catch (error) {
41
+ logger.error('InitialPopover', 'Failed to start recording', error);
42
+ } finally {
43
+ setLoading(false);
44
+ }
45
+ };
46
+
47
+ const handleToggleContinuousRecording = async (value: boolean) => {
48
+ try {
49
+ setLoading(true);
50
+ setContinuousRecording(value);
51
+ if (value) {
52
+ await onStartRecording(SessionType.CONTINUOUS);
53
+ } else {
54
+ await onStopRecording();
55
+ }
56
+ } catch (error) {
57
+ logger.error(
58
+ 'InitialPopover',
59
+ 'Failed to toggle continuous recording',
60
+ error
61
+ );
62
+ } finally {
63
+ setLoading(false);
64
+ }
65
+ };
66
+
67
+ const handleSaveContinuousSession = async () => {
68
+ try {
69
+ setSaving(true);
70
+ await onSaveContinuousSession();
71
+ } catch (error) {
72
+ logger.error(
73
+ 'InitialPopover',
74
+ 'Failed to save continuous session',
75
+ error
76
+ );
77
+ } finally {
78
+ setSaving(false);
79
+ }
80
+ };
81
+
82
+ const textContent = useMemo(() => {
83
+ return {
84
+ label: textOverrides.continuousRecordingLabel,
85
+ title: showContinuousRecording
86
+ ? textOverrides.initialTitleWithContinuous
87
+ : textOverrides.initialTitleWithoutContinuous,
88
+ description: showContinuousRecording
89
+ ? textOverrides.initialDescriptionWithContinuous
90
+ : textOverrides.initialDescriptionWithoutContinuous,
91
+ };
92
+ }, [showContinuousRecording, textOverrides]);
93
+
94
+ return (
95
+ <View style={sharedStyles.popoverContent}>
96
+ <ModalHeader />
97
+ <View style={sharedStyles.popoverBody}>
98
+ {children}
99
+ {showContinuousRecording && (
100
+ <View style={sharedStyles.continuousRecordingSection}>
101
+ <Text style={sharedStyles.continuousRecordingLabel}>
102
+ {textContent.label}
103
+ </Text>
104
+ <Switch
105
+ disabled={loading || !isOnline}
106
+ value={continuousRecording}
107
+ ios_backgroundColor="#e2e8f0"
108
+ onValueChange={handleToggleContinuousRecording}
109
+ trackColor={{ false: '#e2e8f0', true: '#493bff' }}
110
+ thumbColor={'#ffffff'}
111
+ />
112
+ </View>
113
+ )}
114
+ {!continuousRecording ? (
115
+ <>
116
+ <Text style={sharedStyles.title}>{textContent.title}</Text>
117
+ <Text style={sharedStyles.description}>
118
+ {textContent.description}
119
+ </Text>
120
+ <View style={sharedStyles.popoverFooter}>
121
+ <Pressable
122
+ disabled={loading || !isOnline}
123
+ onPress={handleStartRecording}
124
+ style={[sharedStyles.actionButton, sharedStyles.startButton]}
125
+ >
126
+ <Text style={sharedStyles.actionButtonText}>
127
+ {loading
128
+ ? 'Starting to record...'
129
+ : textOverrides.startRecordingButtonText}
130
+ </Text>
131
+ </Pressable>
132
+ </View>
133
+ </>
134
+ ) : (
135
+ <>
136
+ <View style={sharedStyles.continuousOverlay}>
137
+ <View style={sharedStyles.continuousOverlayHeader}>
138
+ <CapturingIcon size={20} color="red" />
139
+ <Text style={sharedStyles.continuousOverlayTitle}>
140
+ {textOverrides.continuousOverlayTitle}
141
+ </Text>
142
+ </View>
143
+ <Text style={sharedStyles.continuousOverlayDescription}>
144
+ {textOverrides.continuousOverlayDescription}
145
+ </Text>
146
+ </View>
147
+ <View style={sharedStyles.popoverFooter}>
148
+ <Pressable
149
+ disabled={saving || !isOnline}
150
+ onPress={handleSaveContinuousSession}
151
+ style={[sharedStyles.actionButton, sharedStyles.saveButton]}
152
+ >
153
+ <Text style={sharedStyles.actionButtonText}>
154
+ {saving
155
+ ? 'Saving...'
156
+ : textOverrides.saveLastSnapshotButtonText}
157
+ </Text>
158
+ </Pressable>
159
+ </View>
160
+ </>
161
+ )}
162
+ </View>
163
+ </View>
164
+ );
165
+ };
166
+
167
+ export default InitialPopover;
@@ -0,0 +1,189 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import {
3
+ Animated,
4
+ Pressable,
5
+ StyleSheet,
6
+ Dimensions,
7
+ Modal,
8
+ PanResponder,
9
+ Platform,
10
+ } from 'react-native';
11
+ import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
12
+
13
+ const { height: SCREEN_HEIGHT } = Dimensions.get('window');
14
+ const MODAL_HEIGHT = SCREEN_HEIGHT * 0.7;
15
+
16
+ interface ModalContainerProps {
17
+ isVisible: boolean;
18
+ onClose: () => void;
19
+ children: React.ReactNode;
20
+ }
21
+
22
+ const ModalContainer: React.FC<ModalContainerProps> = ({
23
+ isVisible,
24
+ onClose,
25
+ children,
26
+ }) => {
27
+ const fadeAnim = useRef(new Animated.Value(0)).current;
28
+ const translateY = useRef(new Animated.Value(0)).current;
29
+ const [visible, setVisible] = useState<boolean>(isVisible);
30
+
31
+ const SWIPE_THRESHOLD = 100; // Distance to trigger close
32
+
33
+ const animateClose = () => {
34
+ Animated.parallel([
35
+ Animated.timing(fadeAnim, {
36
+ toValue: 0,
37
+ duration: 250,
38
+ useNativeDriver: true,
39
+ }),
40
+ Animated.timing(translateY, {
41
+ toValue: MODAL_HEIGHT,
42
+ duration: 250,
43
+ useNativeDriver: true,
44
+ }),
45
+ ]).start(() => {
46
+ setVisible(false);
47
+ onClose();
48
+ });
49
+ };
50
+
51
+ useEffect(() => {
52
+ if (isVisible) {
53
+ setVisible(true);
54
+ // Start from bottom and animate to position
55
+ translateY.setValue(MODAL_HEIGHT);
56
+ Animated.parallel([
57
+ Animated.timing(fadeAnim, {
58
+ toValue: 1,
59
+ duration: 300,
60
+ useNativeDriver: true,
61
+ }),
62
+ Animated.timing(translateY, {
63
+ toValue: 0,
64
+ duration: 300,
65
+ useNativeDriver: true,
66
+ }),
67
+ ]).start();
68
+ } else if (visible) {
69
+ // If external isVisible turned false, animate close then hide
70
+ Animated.parallel([
71
+ Animated.timing(fadeAnim, {
72
+ toValue: 0,
73
+ duration: 250,
74
+ useNativeDriver: true,
75
+ }),
76
+ Animated.timing(translateY, {
77
+ toValue: MODAL_HEIGHT,
78
+ duration: 250,
79
+ useNativeDriver: true,
80
+ }),
81
+ ]).start(() => {
82
+ setVisible(false);
83
+ });
84
+ }
85
+ }, [isVisible, fadeAnim, translateY, visible]);
86
+
87
+ // PanResponder for swipe-to-dismiss functionality
88
+ const panResponder = useRef(
89
+ PanResponder.create({
90
+ onStartShouldSetPanResponder: () => true,
91
+ onMoveShouldSetPanResponder: (_, gestureState) => {
92
+ // Only respond to downward swipes
93
+ return gestureState.dy > 10;
94
+ },
95
+ onPanResponderGrant: () => {
96
+ // Reset any ongoing animations
97
+ translateY.stopAnimation();
98
+ },
99
+ onPanResponderMove: (_, gestureState) => {
100
+ // Only allow downward movement
101
+ if (gestureState.dy > 0) {
102
+ translateY.setValue(gestureState.dy);
103
+ }
104
+ },
105
+ onPanResponderRelease: (_, gestureState) => {
106
+ const { dy, vy } = gestureState;
107
+
108
+ // If swiped down with sufficient distance or velocity, close modal
109
+ if (dy > SWIPE_THRESHOLD || vy > 500) {
110
+ animateClose();
111
+ } else {
112
+ // Snap back to original position
113
+ Animated.spring(translateY, {
114
+ toValue: 0,
115
+ useNativeDriver: true,
116
+ tension: 100,
117
+ friction: 8,
118
+ }).start();
119
+ }
120
+ },
121
+ })
122
+ ).current;
123
+
124
+ return (
125
+ <Modal
126
+ visible={visible}
127
+ transparent
128
+ animationType="none"
129
+ onRequestClose={onClose}
130
+ >
131
+ <SafeAreaProvider>
132
+ <Animated.View style={{ ...styles.backdrop, opacity: fadeAnim }}>
133
+ <Pressable style={styles.backdropPressable} onPress={animateClose} />
134
+ <Animated.View
135
+ style={[styles.modal, { transform: [{ translateY }] }]}
136
+ {...panResponder.panHandlers}
137
+ >
138
+ <SafeAreaView style={styles.safeArea} edges={['bottom']}>
139
+ {children}
140
+ </SafeAreaView>
141
+ </Animated.View>
142
+ </Animated.View>
143
+ </SafeAreaProvider>
144
+ </Modal>
145
+ );
146
+ };
147
+
148
+ const styles = StyleSheet.create({
149
+ backdrop: {
150
+ position: 'absolute',
151
+ top: 0,
152
+ left: 0,
153
+ right: 0,
154
+ bottom: 0,
155
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
156
+ },
157
+ backdropPressable: {
158
+ flex: 1,
159
+ },
160
+ safeArea: {
161
+ flex: 1,
162
+ backgroundColor: 'white',
163
+ borderTopLeftRadius: 20,
164
+ borderTopRightRadius: 20,
165
+ },
166
+ modal: {
167
+ position: 'absolute',
168
+ bottom: 0,
169
+ left: 0,
170
+ right: 0,
171
+ maxHeight: MODAL_HEIGHT,
172
+ backgroundColor: 'white',
173
+ borderTopLeftRadius: 20,
174
+ borderTopRightRadius: 20,
175
+ ...Platform.select({
176
+ ios: {
177
+ shadowColor: '#000',
178
+ shadowOffset: { width: 0, height: -2 },
179
+ shadowOpacity: 0.1,
180
+ shadowRadius: 8,
181
+ },
182
+ android: {
183
+ elevation: 8,
184
+ },
185
+ }),
186
+ },
187
+ });
188
+
189
+ export default ModalContainer;
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import { View, Pressable, Linking } from 'react-native';
3
+ import { sharedStyles } from './styles';
4
+ import { LogoIcon } from './icons';
5
+
6
+ interface ModalHeaderProps {
7
+ children?: React.ReactNode;
8
+ }
9
+
10
+ const ModalHeader: React.FC<ModalHeaderProps> = ({ children }) => {
11
+ return (
12
+ <View style={sharedStyles.popoverHeader}>
13
+ <View style={sharedStyles.modalHandle} />
14
+ <View style={sharedStyles.popoverHeaderContent}>
15
+ <Pressable
16
+ onPress={() => Linking.openURL('https://www.multiplayer.app')}
17
+ >
18
+ <LogoIcon size={42} />
19
+ </Pressable>
20
+ {children}
21
+ </View>
22
+ </View>
23
+ );
24
+ };
25
+
26
+ export default ModalHeader;
@@ -0,0 +1,150 @@
1
+ import React, { useState, useCallback, memo } from 'react';
2
+ import { View, StyleSheet } from 'react-native';
3
+ import { SessionState } from '../../types';
4
+ import { SessionType } from '@multiplayer-app/session-recorder-common';
5
+ import { useSessionRecorder } from '../../context/SessionRecorderContext';
6
+
7
+ import FinalPopover from './FinalPopover';
8
+ import ModalContainer from './ModalContainer';
9
+ import InitialPopover from './InitialPopover';
10
+ import FloatingButton from './FloatingButton';
11
+ import ErrorBanner from './ErrorBanner';
12
+ import { logger } from '../../utils';
13
+ import { useSessionRecorderStore } from '../../context/useSessionRecorderStore';
14
+ import { sessionRecorderStore } from '../../context/SessionRecorderStore';
15
+
16
+ interface SessionRecorderWidgetProps {}
17
+
18
+ const SessionRecorderWidget: React.FC<SessionRecorderWidgetProps> = memo(() => {
19
+ const { instance, openWidgetModal, closeWidgetModal } = useSessionRecorder();
20
+ const isOnline = useSessionRecorderStore<boolean>((s) => s.isOnline);
21
+ const sessionType = useSessionRecorderStore<SessionType | null>(
22
+ (s) => s.sessionType
23
+ );
24
+ const isModalVisible = useSessionRecorderStore<boolean>(
25
+ (s) => s.isWidgetModalVisible
26
+ );
27
+ const sessionState = useSessionRecorderStore<SessionState | null>(
28
+ (s) => s.sessionState
29
+ );
30
+ const error = useSessionRecorderStore<string | null>((s) => s.error);
31
+ const [isSubmitting, setIsSubmitting] = useState(false);
32
+
33
+ // Get configuration from instance
34
+ const { widget, showContinuousRecording } = instance.config;
35
+
36
+ const dismissError = useCallback(() => {
37
+ sessionRecorderStore.setState({ error: null });
38
+ }, []);
39
+
40
+ const handleError = useCallback((error: any, message: string) => {
41
+ const errorMessage = error instanceof Error ? error.message : message;
42
+ logger.error('SessionRecorderWidget', message, error);
43
+ sessionRecorderStore.setState({ error: errorMessage });
44
+ }, []);
45
+
46
+ const onStartRecording = useCallback(
47
+ async (sessionType: SessionType) => {
48
+ if (!isOnline) {
49
+ handleError(
50
+ new Error('Cannot start recording while offline'),
51
+ 'Cannot start recording while offline'
52
+ );
53
+ return;
54
+ }
55
+ try {
56
+ await instance.start(sessionType);
57
+ closeWidgetModal();
58
+ } catch (error) {
59
+ handleError(error, 'Failed to start recording');
60
+ }
61
+ },
62
+ [isOnline, handleError]
63
+ );
64
+
65
+ const onStopRecording = useCallback(
66
+ async (comment?: string) => {
67
+ try {
68
+ setIsSubmitting(true);
69
+ await instance.stop(comment);
70
+ closeWidgetModal();
71
+ } catch (error) {
72
+ handleError(error, 'Failed to stop recording');
73
+ } finally {
74
+ setIsSubmitting(false);
75
+ }
76
+ },
77
+ [handleError]
78
+ );
79
+
80
+ const onCancelSession = useCallback(async () => {
81
+ try {
82
+ await instance.cancel();
83
+ closeWidgetModal();
84
+ } catch (error) {
85
+ handleError(error, 'Failed to cancel session');
86
+ }
87
+ }, [handleError]);
88
+
89
+ const onSaveContinuousSession = useCallback(async () => {
90
+ try {
91
+ await instance.save();
92
+ } catch (error) {
93
+ handleError(error, 'Failed to save continuous session');
94
+ }
95
+ }, [handleError]);
96
+
97
+ const isStarted =
98
+ sessionState === SessionState.started ||
99
+ sessionState === SessionState.paused;
100
+ const isContinuous = sessionType === SessionType.CONTINUOUS;
101
+
102
+ return (
103
+ <>
104
+ {widget.button?.visible && (
105
+ <View pointerEvents="box-none" style={styles.overlayContainer}>
106
+ <FloatingButton
107
+ sessionState={sessionState}
108
+ onPress={openWidgetModal}
109
+ />
110
+ </View>
111
+ )}
112
+ <ModalContainer isVisible={isModalVisible} onClose={closeWidgetModal}>
113
+ {isStarted && !isContinuous ? (
114
+ <FinalPopover
115
+ isOnline={isOnline}
116
+ isSubmitting={isSubmitting}
117
+ textOverrides={widget.textOverrides}
118
+ onClose={closeWidgetModal}
119
+ onStopRecording={onStopRecording}
120
+ onCancelSession={onCancelSession}
121
+ >
122
+ {error && <ErrorBanner error={error} onDismiss={dismissError} />}
123
+ </FinalPopover>
124
+ ) : (
125
+ <InitialPopover
126
+ isOnline={isOnline}
127
+ isSubmitting={isSubmitting}
128
+ textOverrides={widget.textOverrides}
129
+ isContinuous={isStarted && isContinuous}
130
+ showContinuousRecording={showContinuousRecording}
131
+ onClose={closeWidgetModal}
132
+ onStopRecording={onStopRecording}
133
+ onStartRecording={onStartRecording}
134
+ onSaveContinuousSession={onSaveContinuousSession}
135
+ >
136
+ {error && <ErrorBanner error={error} onDismiss={dismissError} />}
137
+ </InitialPopover>
138
+ )}
139
+ </ModalContainer>
140
+ </>
141
+ );
142
+ });
143
+
144
+ export default SessionRecorderWidget;
145
+
146
+ const styles = StyleSheet.create({
147
+ overlayContainer: {
148
+ ...StyleSheet.absoluteFillObject,
149
+ },
150
+ });