react-native-acoustic-connect 19.0.11 → 19.0.34

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 (380) hide show
  1. package/CHANGELOG.md +111 -0
  2. package/ConnectConfig.example.json +1 -1
  3. package/README.md +426 -3
  4. package/android/build.gradle +119 -3
  5. package/android/config.gradle +123 -13
  6. package/android/src/main/assets/ConnectAdvancedConfig.json +1 -1
  7. package/android/src/main/assets/EOCoreAdvancedConfig.json +1 -1
  8. package/android/src/main/assets/TealeafAdvancedConfig.json +1 -1
  9. package/android/src/main/java/com/acousticconnectrn/HybridAcousticConnectRN.kt +457 -37
  10. package/app.plugin.js +2 -2
  11. package/ios/AcousticConnectRNConfig.json +2 -2
  12. package/ios/ConnectRNParsing.swift +229 -0
  13. package/ios/HybridAcousticConnectRN.swift +290 -30
  14. package/lib/commonjs/TLTRN.js +116 -3
  15. package/lib/commonjs/TLTRN.js.map +1 -1
  16. package/lib/commonjs/components/Connect.js +145 -27
  17. package/lib/commonjs/components/Connect.js.map +1 -1
  18. package/lib/commonjs/index.js +3 -0
  19. package/lib/commonjs/index.js.map +1 -1
  20. package/lib/module/TLTRN.js +116 -3
  21. package/lib/module/TLTRN.js.map +1 -1
  22. package/lib/module/components/Connect.js +146 -28
  23. package/lib/module/components/Connect.js.map +1 -1
  24. package/lib/module/index.js +5 -0
  25. package/lib/module/index.js.map +1 -1
  26. package/lib/typescript/src/TLTRN.d.ts +85 -1
  27. package/lib/typescript/src/TLTRN.d.ts.map +1 -1
  28. package/lib/typescript/src/components/Connect.d.ts.map +1 -1
  29. package/lib/typescript/src/index.d.ts +1 -0
  30. package/lib/typescript/src/index.d.ts.map +1 -1
  31. package/lib/typescript/src/specs/react-native-acoustic-connect.nitro.d.ts +190 -10
  32. package/lib/typescript/src/specs/react-native-acoustic-connect.nitro.d.ts.map +1 -1
  33. package/nitrogen/generated/android/c++/JHybridAcousticConnectRNSpec.cpp +5 -9
  34. package/nitrogen/generated/android/c++/JHybridAcousticConnectRNSpec.hpp +1 -1
  35. package/nitrogen/generated/android/kotlin/com/margelo/nitro/acousticconnectrn/HybridAcousticConnectRNSpec.kt +2 -1
  36. package/nitrogen/generated/ios/AcousticConnectRN-Swift-Cxx-Umbrella.hpp +1 -0
  37. package/nitrogen/generated/ios/c++/HybridAcousticConnectRNSpecSwift.hpp +2 -1
  38. package/nitrogen/generated/ios/swift/HybridAcousticConnectRNSpec.swift +1 -1
  39. package/nitrogen/generated/ios/swift/HybridAcousticConnectRNSpec_cxx.swift +2 -25
  40. package/nitrogen/generated/shared/c++/HybridAcousticConnectRNSpec.hpp +2 -1
  41. package/package.json +6 -8
  42. package/plugin/build/withConnectAndroidConfig.d.ts +2 -2
  43. package/plugin/build/withConnectAndroidConfig.js +2 -2
  44. package/plugin/build/withConnectIosSigning.d.ts +1 -1
  45. package/plugin/build/withConnectIosSigning.js +1 -1
  46. package/plugin/src/withConnectAndroidConfig.ts +2 -2
  47. package/plugin/src/withConnectIosSigning.ts +1 -1
  48. package/scripts/gradleParser.js +1 -1
  49. package/src/TLTRN.ts +125 -4
  50. package/src/components/Connect.tsx +150 -27
  51. package/src/index.ts +5 -0
  52. package/src/specs/react-native-acoustic-connect.nitro.ts +192 -10
  53. package/Examples/SampleUI/.bundle/config +0 -2
  54. package/Examples/SampleUI/.detoxrc.js +0 -83
  55. package/Examples/SampleUI/.eslintrc.js +0 -4
  56. package/Examples/SampleUI/.prettierrc.js +0 -7
  57. package/Examples/SampleUI/.watchmanconfig +0 -1
  58. package/Examples/SampleUI/App.js +0 -1
  59. package/Examples/SampleUI/Gemfile +0 -10
  60. package/Examples/SampleUI/Gemfile.lock +0 -121
  61. package/Examples/SampleUI/README.md +0 -79
  62. package/Examples/SampleUI/__tests__/App.test.tsx +0 -17
  63. package/Examples/SampleUI/android/app/build.gradle +0 -129
  64. package/Examples/SampleUI/android/app/debug.keystore +0 -0
  65. package/Examples/SampleUI/android/app/proguard-rules.pro +0 -10
  66. package/Examples/SampleUI/android/app/src/debug/AndroidManifest.xml +0 -9
  67. package/Examples/SampleUI/android/app/src/main/AndroidManifest.xml +0 -31
  68. package/Examples/SampleUI/android/app/src/main/java/com/sampleui/MainActivity.kt +0 -30
  69. package/Examples/SampleUI/android/app/src/main/java/com/sampleui/MainApplication.kt +0 -53
  70. package/Examples/SampleUI/android/app/src/main/res/drawable/rn_edit_text_material.xml +0 -37
  71. package/Examples/SampleUI/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  72. package/Examples/SampleUI/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  73. package/Examples/SampleUI/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  74. package/Examples/SampleUI/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  75. package/Examples/SampleUI/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  76. package/Examples/SampleUI/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  77. package/Examples/SampleUI/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  78. package/Examples/SampleUI/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  79. package/Examples/SampleUI/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  80. package/Examples/SampleUI/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  81. package/Examples/SampleUI/android/app/src/main/res/values/strings.xml +0 -3
  82. package/Examples/SampleUI/android/app/src/main/res/values/styles.xml +0 -9
  83. package/Examples/SampleUI/android/build.gradle +0 -21
  84. package/Examples/SampleUI/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  85. package/Examples/SampleUI/android/gradle/wrapper/gradle-wrapper.properties +0 -7
  86. package/Examples/SampleUI/android/gradle.properties +0 -39
  87. package/Examples/SampleUI/android/gradlew +0 -252
  88. package/Examples/SampleUI/android/gradlew.bat +0 -94
  89. package/Examples/SampleUI/android/settings.gradle +0 -21
  90. package/Examples/SampleUI/app.json +0 -51
  91. package/Examples/SampleUI/assets/fonts/Abel-Regular.ttf +0 -0
  92. package/Examples/SampleUI/assets/fonts/NotoSans-Regular.ttf +0 -0
  93. package/Examples/SampleUI/assets/images/android-icon.png +0 -0
  94. package/Examples/SampleUI/assets/images/artist-1.jpg +0 -0
  95. package/Examples/SampleUI/assets/images/artist-2.jpg +0 -0
  96. package/Examples/SampleUI/assets/images/avatar.png +0 -0
  97. package/Examples/SampleUI/assets/images/beach.jpg +0 -0
  98. package/Examples/SampleUI/assets/images/bridge.jpg +0 -0
  99. package/Examples/SampleUI/assets/images/chameleon.jpg +0 -0
  100. package/Examples/SampleUI/assets/images/city.jpg +0 -0
  101. package/Examples/SampleUI/assets/images/email-icon.png +0 -0
  102. package/Examples/SampleUI/assets/images/favorite.png +0 -0
  103. package/Examples/SampleUI/assets/images/forest.jpg +0 -0
  104. package/Examples/SampleUI/assets/images/paper-icon.png +0 -0
  105. package/Examples/SampleUI/assets/images/players-2.jpg +0 -0
  106. package/Examples/SampleUI/assets/images/players.jpg +0 -0
  107. package/Examples/SampleUI/assets/images/restaurant-1.jpg +0 -0
  108. package/Examples/SampleUI/assets/images/restaurant-2.jpg +0 -0
  109. package/Examples/SampleUI/assets/images/song-1.jpg +0 -0
  110. package/Examples/SampleUI/assets/images/song-2.jpg +0 -0
  111. package/Examples/SampleUI/assets/images/splash.png +0 -0
  112. package/Examples/SampleUI/assets/images/strawberries.jpg +0 -0
  113. package/Examples/SampleUI/assets/images/wrecked-ship.jpg +0 -0
  114. package/Examples/SampleUI/assets/styles/fonts.css +0 -47
  115. package/Examples/SampleUI/babel.config.js +0 -22
  116. package/Examples/SampleUI/index.js +0 -9
  117. package/Examples/SampleUI/ios/.xcode.env +0 -11
  118. package/Examples/SampleUI/ios/Podfile +0 -71
  119. package/Examples/SampleUI/ios/Podfile.lock +0 -2276
  120. package/Examples/SampleUI/ios/SampleUI/AppDelegate.h +0 -7
  121. package/Examples/SampleUI/ios/SampleUI/AppDelegate.mm +0 -31
  122. package/Examples/SampleUI/ios/SampleUI/Images.xcassets/AppIcon.appiconset/Contents.json +0 -53
  123. package/Examples/SampleUI/ios/SampleUI/Images.xcassets/Contents.json +0 -6
  124. package/Examples/SampleUI/ios/SampleUI/Info.plist +0 -52
  125. package/Examples/SampleUI/ios/SampleUI/LaunchScreen.storyboard +0 -47
  126. package/Examples/SampleUI/ios/SampleUI/PrivacyInfo.xcprivacy +0 -48
  127. package/Examples/SampleUI/ios/SampleUI/main.m +0 -10
  128. package/Examples/SampleUI/ios/SampleUI.xcodeproj/project.pbxproj +0 -785
  129. package/Examples/SampleUI/ios/SampleUI.xcodeproj/xcshareddata/xcschemes/SampleUI.xcscheme +0 -105
  130. package/Examples/SampleUI/ios/SampleUI.xcworkspace/contents.xcworkspacedata +0 -10
  131. package/Examples/SampleUI/ios/SampleUITests/Info.plist +0 -24
  132. package/Examples/SampleUI/ios/SampleUITests/SampleUITests.m +0 -66
  133. package/Examples/SampleUI/jest.config.js +0 -3
  134. package/Examples/SampleUI/metro.config.js +0 -54
  135. package/Examples/SampleUI/package.json +0 -65
  136. package/Examples/SampleUI/scripts/integration-test-android.sh +0 -292
  137. package/Examples/SampleUI/src/DrawerItems.tsx +0 -322
  138. package/Examples/SampleUI/src/ExampleList.tsx +0 -175
  139. package/Examples/SampleUI/src/Examples/ActivityIndicatorExample.tsx +0 -73
  140. package/Examples/SampleUI/src/Examples/AnimatedFABExample/AnimatedFABExample.tsx +0 -220
  141. package/Examples/SampleUI/src/Examples/AnimatedFABExample/CustomFAB.tsx +0 -70
  142. package/Examples/SampleUI/src/Examples/AnimatedFABExample/CustomFABControls.tsx +0 -146
  143. package/Examples/SampleUI/src/Examples/AnimatedFABExample/index.ts +0 -1
  144. package/Examples/SampleUI/src/Examples/AppbarExample.tsx +0 -263
  145. package/Examples/SampleUI/src/Examples/AvatarExample.tsx +0 -76
  146. package/Examples/SampleUI/src/Examples/BadgeExample.tsx +0 -97
  147. package/Examples/SampleUI/src/Examples/BannerExample.tsx +0 -152
  148. package/Examples/SampleUI/src/Examples/BottomNavigationBarExample.tsx +0 -94
  149. package/Examples/SampleUI/src/Examples/BottomNavigationExample.tsx +0 -205
  150. package/Examples/SampleUI/src/Examples/ButtonExample.tsx +0 -405
  151. package/Examples/SampleUI/src/Examples/CardExample.tsx +0 -245
  152. package/Examples/SampleUI/src/Examples/CheckboxExample.tsx +0 -87
  153. package/Examples/SampleUI/src/Examples/CheckboxItemExample.tsx +0 -72
  154. package/Examples/SampleUI/src/Examples/ChipExample.tsx +0 -432
  155. package/Examples/SampleUI/src/Examples/DataTableExample.tsx +0 -128
  156. package/Examples/SampleUI/src/Examples/DialogExample.tsx +0 -217
  157. package/Examples/SampleUI/src/Examples/Dialogs/DialogTextComponent.tsx +0 -31
  158. package/Examples/SampleUI/src/Examples/Dialogs/DialogTrackingTest.tsx +0 -307
  159. package/Examples/SampleUI/src/Examples/Dialogs/DialogWithCustomColors.tsx +0 -57
  160. package/Examples/SampleUI/src/Examples/Dialogs/DialogWithDismissableBackButton.tsx +0 -38
  161. package/Examples/SampleUI/src/Examples/Dialogs/DialogWithIcon.tsx +0 -42
  162. package/Examples/SampleUI/src/Examples/Dialogs/DialogWithLoadingIndicator.tsx +0 -48
  163. package/Examples/SampleUI/src/Examples/Dialogs/DialogWithLongText.tsx +0 -81
  164. package/Examples/SampleUI/src/Examples/Dialogs/DialogWithRadioBtns.tsx +0 -111
  165. package/Examples/SampleUI/src/Examples/Dialogs/UndismissableDialog.tsx +0 -30
  166. package/Examples/SampleUI/src/Examples/Dialogs/index.tsx +0 -44
  167. package/Examples/SampleUI/src/Examples/DividerExample.tsx +0 -30
  168. package/Examples/SampleUI/src/Examples/FABExample.tsx +0 -226
  169. package/Examples/SampleUI/src/Examples/IconButtonExample.tsx +0 -230
  170. package/Examples/SampleUI/src/Examples/IconExample.tsx +0 -50
  171. package/Examples/SampleUI/src/Examples/ListAccordionExample.tsx +0 -65
  172. package/Examples/SampleUI/src/Examples/ListAccordionGroupExample.tsx +0 -80
  173. package/Examples/SampleUI/src/Examples/ListItemExample.tsx +0 -310
  174. package/Examples/SampleUI/src/Examples/ListSectionExample.tsx +0 -159
  175. package/Examples/SampleUI/src/Examples/MaterialBottomTabNavigatorExample.tsx +0 -87
  176. package/Examples/SampleUI/src/Examples/MenuExample.tsx +0 -211
  177. package/Examples/SampleUI/src/Examples/ProgressBarExample.tsx +0 -142
  178. package/Examples/SampleUI/src/Examples/RadioButtonExample.tsx +0 -104
  179. package/Examples/SampleUI/src/Examples/RadioButtonGroupExample.tsx +0 -67
  180. package/Examples/SampleUI/src/Examples/RadioButtonItemExample.tsx +0 -77
  181. package/Examples/SampleUI/src/Examples/SearchbarExample.tsx +0 -249
  182. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonCustomColorCheck.tsx +0 -93
  183. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonDefault.tsx +0 -49
  184. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonDisabled.tsx +0 -47
  185. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonMultiselect.tsx +0 -50
  186. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonMultiselectIcons.tsx +0 -49
  187. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonMultiselectRealCase.tsx +0 -114
  188. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonOnlyIcons.tsx +0 -40
  189. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonOnlyIconsWithCheck.tsx +0 -43
  190. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonRealCase.tsx +0 -97
  191. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonWithDensity.tsx +0 -47
  192. package/Examples/SampleUI/src/Examples/SegmentedButtons/SegmentedButtonWithSelectedCheck.tsx +0 -52
  193. package/Examples/SampleUI/src/Examples/SegmentedButtons/index.ts +0 -9
  194. package/Examples/SampleUI/src/Examples/SegmentedButtonsExample.tsx +0 -57
  195. package/Examples/SampleUI/src/Examples/SnackbarExample.tsx +0 -141
  196. package/Examples/SampleUI/src/Examples/SurfaceExample.tsx +0 -130
  197. package/Examples/SampleUI/src/Examples/SwitchExample.tsx +0 -105
  198. package/Examples/SampleUI/src/Examples/TeamDetails.tsx +0 -291
  199. package/Examples/SampleUI/src/Examples/TeamsList.tsx +0 -57
  200. package/Examples/SampleUI/src/Examples/TextExample.tsx +0 -132
  201. package/Examples/SampleUI/src/Examples/TextInputExample.tsx +0 -914
  202. package/Examples/SampleUI/src/Examples/ThemeExample.tsx +0 -41
  203. package/Examples/SampleUI/src/Examples/ThemingWithReactNavigation.tsx +0 -75
  204. package/Examples/SampleUI/src/Examples/ToggleButtonExample.tsx +0 -128
  205. package/Examples/SampleUI/src/Examples/TooltipExample.tsx +0 -191
  206. package/Examples/SampleUI/src/Examples/TouchableRippleExample.tsx +0 -37
  207. package/Examples/SampleUI/src/RootNavigator.tsx +0 -95
  208. package/Examples/SampleUI/src/ScreenWrapper.tsx +0 -67
  209. package/Examples/SampleUI/src/components/ActivityIndicator.tsx +0 -254
  210. package/Examples/SampleUI/src/components/Appbar/Appbar.tsx +0 -364
  211. package/Examples/SampleUI/src/components/Appbar/AppbarAction.tsx +0 -132
  212. package/Examples/SampleUI/src/components/Appbar/AppbarBackAction.tsx +0 -77
  213. package/Examples/SampleUI/src/components/Appbar/AppbarBackIcon.tsx +0 -52
  214. package/Examples/SampleUI/src/components/Appbar/AppbarContent.tsx +0 -249
  215. package/Examples/SampleUI/src/components/Appbar/AppbarHeader.tsx +0 -174
  216. package/Examples/SampleUI/src/components/Appbar/index.ts +0 -22
  217. package/Examples/SampleUI/src/components/Appbar/utils.ts +0 -188
  218. package/Examples/SampleUI/src/components/Avatar/Avatar.tsx +0 -8
  219. package/Examples/SampleUI/src/components/Avatar/AvatarIcon.tsx +0 -87
  220. package/Examples/SampleUI/src/components/Avatar/AvatarImage.tsx +0 -128
  221. package/Examples/SampleUI/src/components/Avatar/AvatarText.tsx +0 -127
  222. package/Examples/SampleUI/src/components/Badge.tsx +0 -138
  223. package/Examples/SampleUI/src/components/Banner.tsx +0 -302
  224. package/Examples/SampleUI/src/components/BottomNavigation/BottomNavigation.tsx +0 -643
  225. package/Examples/SampleUI/src/components/BottomNavigation/BottomNavigationBar.tsx +0 -1039
  226. package/Examples/SampleUI/src/components/BottomNavigation/BottomNavigationRouteScreen.tsx +0 -31
  227. package/Examples/SampleUI/src/components/BottomNavigation/utils.ts +0 -70
  228. package/Examples/SampleUI/src/components/Button/Button.tsx +0 -503
  229. package/Examples/SampleUI/src/components/Button/utils.tsx +0 -272
  230. package/Examples/SampleUI/src/components/Card/Card.tsx +0 -373
  231. package/Examples/SampleUI/src/components/Card/CardActions.tsx +0 -74
  232. package/Examples/SampleUI/src/components/Card/CardContent.tsx +0 -99
  233. package/Examples/SampleUI/src/components/Card/CardCover.tsx +0 -96
  234. package/Examples/SampleUI/src/components/Card/CardTitle.tsx +0 -236
  235. package/Examples/SampleUI/src/components/Card/utils.tsx +0 -110
  236. package/Examples/SampleUI/src/components/Checkbox/Checkbox.tsx +0 -78
  237. package/Examples/SampleUI/src/components/Checkbox/CheckboxAndroid.tsx +0 -180
  238. package/Examples/SampleUI/src/components/Checkbox/CheckboxIOS.tsx +0 -104
  239. package/Examples/SampleUI/src/components/Checkbox/CheckboxItem.tsx +0 -236
  240. package/Examples/SampleUI/src/components/Checkbox/index.ts +0 -19
  241. package/Examples/SampleUI/src/components/Checkbox/utils.ts +0 -183
  242. package/Examples/SampleUI/src/components/Chip/Chip.tsx +0 -513
  243. package/Examples/SampleUI/src/components/Chip/helpers.tsx +0 -322
  244. package/Examples/SampleUI/src/components/CrossFadeIcon.tsx +0 -140
  245. package/Examples/SampleUI/src/components/DataTable/DataTable.tsx +0 -138
  246. package/Examples/SampleUI/src/components/DataTable/DataTableCell.tsx +0 -132
  247. package/Examples/SampleUI/src/components/DataTable/DataTableHeader.tsx +0 -82
  248. package/Examples/SampleUI/src/components/DataTable/DataTablePagination.tsx +0 -407
  249. package/Examples/SampleUI/src/components/DataTable/DataTableRow.tsx +0 -107
  250. package/Examples/SampleUI/src/components/DataTable/DataTableTitle.tsx +0 -208
  251. package/Examples/SampleUI/src/components/Dialog/Dialog.tsx +0 -191
  252. package/Examples/SampleUI/src/components/Dialog/DialogActions.tsx +0 -94
  253. package/Examples/SampleUI/src/components/Dialog/DialogContent.tsx +0 -54
  254. package/Examples/SampleUI/src/components/Dialog/DialogIcon.tsx +0 -100
  255. package/Examples/SampleUI/src/components/Dialog/DialogScrollArea.tsx +0 -88
  256. package/Examples/SampleUI/src/components/Dialog/DialogTitle.tsx +0 -94
  257. package/Examples/SampleUI/src/components/Divider.tsx +0 -102
  258. package/Examples/SampleUI/src/components/Drawer/Drawer.tsx +0 -8
  259. package/Examples/SampleUI/src/components/Drawer/DrawerCollapsedItem.tsx +0 -282
  260. package/Examples/SampleUI/src/components/Drawer/DrawerItem.tsx +0 -209
  261. package/Examples/SampleUI/src/components/Drawer/DrawerSection.tsx +0 -138
  262. package/Examples/SampleUI/src/components/FAB/AnimatedFAB.tsx +0 -619
  263. package/Examples/SampleUI/src/components/FAB/FAB.tsx +0 -371
  264. package/Examples/SampleUI/src/components/FAB/FABGroup.tsx +0 -532
  265. package/Examples/SampleUI/src/components/FAB/index.ts +0 -13
  266. package/Examples/SampleUI/src/components/FAB/utils.ts +0 -474
  267. package/Examples/SampleUI/src/components/HelperText/HelperText.tsx +0 -168
  268. package/Examples/SampleUI/src/components/HelperText/utils.ts +0 -30
  269. package/Examples/SampleUI/src/components/Icon.tsx +0 -170
  270. package/Examples/SampleUI/src/components/IconButton/IconButton.tsx +0 -234
  271. package/Examples/SampleUI/src/components/IconButton/utils.ts +0 -190
  272. package/Examples/SampleUI/src/components/List/List.tsx +0 -20
  273. package/Examples/SampleUI/src/components/List/ListAccordion.tsx +0 -391
  274. package/Examples/SampleUI/src/components/List/ListAccordionGroup.tsx +0 -88
  275. package/Examples/SampleUI/src/components/List/ListIcon.tsx +0 -79
  276. package/Examples/SampleUI/src/components/List/ListImage.tsx +0 -89
  277. package/Examples/SampleUI/src/components/List/ListItem.tsx +0 -313
  278. package/Examples/SampleUI/src/components/List/ListSection.tsx +0 -87
  279. package/Examples/SampleUI/src/components/List/ListSubheader.tsx +0 -79
  280. package/Examples/SampleUI/src/components/List/utils.ts +0 -113
  281. package/Examples/SampleUI/src/components/MaterialCommunityIcon.tsx +0 -121
  282. package/Examples/SampleUI/src/components/Menu/Menu.tsx +0 -711
  283. package/Examples/SampleUI/src/components/Menu/MenuItem.tsx +0 -257
  284. package/Examples/SampleUI/src/components/Menu/utils.ts +0 -110
  285. package/Examples/SampleUI/src/components/Modal.tsx +0 -245
  286. package/Examples/SampleUI/src/components/Portal/Portal.tsx +0 -69
  287. package/Examples/SampleUI/src/components/Portal/PortalConsumer.tsx +0 -44
  288. package/Examples/SampleUI/src/components/Portal/PortalHost.tsx +0 -143
  289. package/Examples/SampleUI/src/components/Portal/PortalManager.tsx +0 -54
  290. package/Examples/SampleUI/src/components/ProgressBar.tsx +0 -292
  291. package/Examples/SampleUI/src/components/RadioButton/RadioButton.tsx +0 -86
  292. package/Examples/SampleUI/src/components/RadioButton/RadioButtonAndroid.tsx +0 -202
  293. package/Examples/SampleUI/src/components/RadioButton/RadioButtonGroup.tsx +0 -67
  294. package/Examples/SampleUI/src/components/RadioButton/RadioButtonIOS.tsx +0 -130
  295. package/Examples/SampleUI/src/components/RadioButton/RadioButtonItem.tsx +0 -268
  296. package/Examples/SampleUI/src/components/RadioButton/index.ts +0 -22
  297. package/Examples/SampleUI/src/components/RadioButton/utils.ts +0 -37
  298. package/Examples/SampleUI/src/components/Searchbar.tsx +0 -459
  299. package/Examples/SampleUI/src/components/SegmentedButtons/SegmentedButtonItem.tsx +0 -271
  300. package/Examples/SampleUI/src/components/SegmentedButtons/SegmentedButtons.tsx +0 -197
  301. package/Examples/SampleUI/src/components/SegmentedButtons/utils.ts +0 -179
  302. package/Examples/SampleUI/src/components/Snackbar.tsx +0 -430
  303. package/Examples/SampleUI/src/components/Surface.tsx +0 -376
  304. package/Examples/SampleUI/src/components/Switch/Switch.tsx +0 -108
  305. package/Examples/SampleUI/src/components/Switch/utils.ts +0 -113
  306. package/Examples/SampleUI/src/components/TextInput/Addons/Outline.tsx +0 -64
  307. package/Examples/SampleUI/src/components/TextInput/Addons/Underline.tsx +0 -78
  308. package/Examples/SampleUI/src/components/TextInput/Adornment/TextInputAdornment.tsx +0 -208
  309. package/Examples/SampleUI/src/components/TextInput/Adornment/TextInputAffix.tsx +0 -212
  310. package/Examples/SampleUI/src/components/TextInput/Adornment/TextInputIcon.tsx +0 -195
  311. package/Examples/SampleUI/src/components/TextInput/Adornment/enums.tsx +0 -12
  312. package/Examples/SampleUI/src/components/TextInput/Adornment/types.tsx +0 -11
  313. package/Examples/SampleUI/src/components/TextInput/Adornment/utils.ts +0 -48
  314. package/Examples/SampleUI/src/components/TextInput/Label/InputLabel.tsx +0 -217
  315. package/Examples/SampleUI/src/components/TextInput/Label/LabelBackground.tsx +0 -100
  316. package/Examples/SampleUI/src/components/TextInput/TextInput.tsx +0 -572
  317. package/Examples/SampleUI/src/components/TextInput/TextInputFlat.tsx +0 -475
  318. package/Examples/SampleUI/src/components/TextInput/TextInputOutlined.tsx +0 -450
  319. package/Examples/SampleUI/src/components/TextInput/constants.tsx +0 -48
  320. package/Examples/SampleUI/src/components/TextInput/helpers.tsx +0 -612
  321. package/Examples/SampleUI/src/components/TextInput/types.tsx +0 -155
  322. package/Examples/SampleUI/src/components/ToggleButton/ToggleButton.tsx +0 -187
  323. package/Examples/SampleUI/src/components/ToggleButton/ToggleButtonGroup.tsx +0 -72
  324. package/Examples/SampleUI/src/components/ToggleButton/ToggleButtonRow.tsx +0 -107
  325. package/Examples/SampleUI/src/components/ToggleButton/index.ts +0 -16
  326. package/Examples/SampleUI/src/components/ToggleButton/utils.ts +0 -26
  327. package/Examples/SampleUI/src/components/Tooltip/Tooltip.tsx +0 -249
  328. package/Examples/SampleUI/src/components/Tooltip/utils.ts +0 -129
  329. package/Examples/SampleUI/src/components/TouchableRipple/Pressable.tsx +0 -41
  330. package/Examples/SampleUI/src/components/TouchableRipple/TouchableRipple.native.tsx +0 -145
  331. package/Examples/SampleUI/src/components/TouchableRipple/TouchableRipple.tsx +0 -317
  332. package/Examples/SampleUI/src/components/TouchableRipple/utils.ts +0 -66
  333. package/Examples/SampleUI/src/components/Typography/AnimatedText.tsx +0 -107
  334. package/Examples/SampleUI/src/components/Typography/Text.tsx +0 -184
  335. package/Examples/SampleUI/src/components/Typography/types.tsx +0 -5
  336. package/Examples/SampleUI/src/components/Typography/v2/Caption.tsx +0 -50
  337. package/Examples/SampleUI/src/components/Typography/v2/Headline.tsx +0 -52
  338. package/Examples/SampleUI/src/components/Typography/v2/Paragraph.tsx +0 -49
  339. package/Examples/SampleUI/src/components/Typography/v2/StyledText.tsx +0 -56
  340. package/Examples/SampleUI/src/components/Typography/v2/Subheading.tsx +0 -50
  341. package/Examples/SampleUI/src/components/Typography/v2/Text.tsx +0 -62
  342. package/Examples/SampleUI/src/components/Typography/v2/Title.tsx +0 -49
  343. package/Examples/SampleUI/src/components/Typography/v2/index.ts +0 -5
  344. package/Examples/SampleUI/src/core/PaperProvider.tsx +0 -122
  345. package/Examples/SampleUI/src/core/SafeAreaProviderCompat.tsx +0 -65
  346. package/Examples/SampleUI/src/core/settings.tsx +0 -23
  347. package/Examples/SampleUI/src/core/theming.tsx +0 -170
  348. package/Examples/SampleUI/src/index.native.tsx +0 -285
  349. package/Examples/SampleUI/src/index.tsx +0 -226
  350. package/Examples/SampleUI/src/react-navigation/index.tsx +0 -19
  351. package/Examples/SampleUI/src/react-navigation/navigators/createMaterialBottomTabNavigator.tsx +0 -72
  352. package/Examples/SampleUI/src/react-navigation/types.tsx +0 -126
  353. package/Examples/SampleUI/src/react-navigation/views/MaterialBottomTabView.tsx +0 -140
  354. package/Examples/SampleUI/src/styles/__tests__/fonts.test.js +0 -290
  355. package/Examples/SampleUI/src/styles/fonts.tsx +0 -143
  356. package/Examples/SampleUI/src/styles/overlay.tsx +0 -70
  357. package/Examples/SampleUI/src/styles/shadow.tsx +0 -109
  358. package/Examples/SampleUI/src/styles/themes/index.ts +0 -4
  359. package/Examples/SampleUI/src/styles/themes/v2/DarkTheme.tsx +0 -30
  360. package/Examples/SampleUI/src/styles/themes/v2/LightTheme.tsx +0 -30
  361. package/Examples/SampleUI/src/styles/themes/v2/colors.tsx +0 -277
  362. package/Examples/SampleUI/src/styles/themes/v3/DarkTheme.tsx +0 -66
  363. package/Examples/SampleUI/src/styles/themes/v3/LightTheme.tsx +0 -69
  364. package/Examples/SampleUI/src/styles/themes/v3/tokens.tsx +0 -230
  365. package/Examples/SampleUI/src/utils/BackHandler/BackHandler.native.tsx +0 -3
  366. package/Examples/SampleUI/src/utils/BackHandler/BackHandler.tsx +0 -11
  367. package/Examples/SampleUI/src/utils/addEventListener.tsx +0 -56
  368. package/Examples/SampleUI/src/utils/forwardRef.tsx +0 -23
  369. package/Examples/SampleUI/src/utils/getContrastingColor.tsx +0 -15
  370. package/Examples/SampleUI/src/utils/hasTouchHandler.tsx +0 -23
  371. package/Examples/SampleUI/src/utils/roundLayoutSize.ts +0 -2
  372. package/Examples/SampleUI/src/utils/splitStyles.ts +0 -60
  373. package/Examples/SampleUI/src/utils/useAnimatedValue.tsx +0 -9
  374. package/Examples/SampleUI/src/utils/useAnimatedValueArray.tsx +0 -13
  375. package/Examples/SampleUI/src/utils/useIsKeyboardShown.tsx +0 -55
  376. package/Examples/SampleUI/src/utils/useLayout.tsx +0 -29
  377. package/Examples/SampleUI/src/utils/useLazyRef.tsx +0 -11
  378. package/Examples/SampleUI/tsconfig.json +0 -3
  379. package/Examples/SampleUI/utils/index.ts +0 -1426
  380. package/cli/__tests__/doctor.test.mjs +0 -88
package/src/TLTRN.ts CHANGED
@@ -54,7 +54,7 @@ class TLTRN {
54
54
  static displayDebug = false;
55
55
 
56
56
  static myTimer = {
57
- handle: null as NodeJS.Timeout | null,
57
+ handle: null as ReturnType<typeof setInterval> | null,
58
58
  started: 0,
59
59
  time: 1000,
60
60
  /**
@@ -110,11 +110,44 @@ class TLTRN {
110
110
  return result;
111
111
  };
112
112
 
113
- static logScreenLayout = (name: string | undefined) => {
113
+ /**
114
+ * Sentinel for the native `delay` argument meaning "use the
115
+ * `CaptureLayoutDelay` configured for this screen". Both bridges resolve it
116
+ * from the layout config; anything >= 0 is an explicit delay in
117
+ * milliseconds.
118
+ */
119
+ static USE_CONFIGURED_CAPTURE_DELAY = -1;
120
+
121
+ /**
122
+ * Captures the layout of the current screen.
123
+ *
124
+ * @param name Screen name to associate with the capture.
125
+ * @param delayMs Milliseconds to wait before capturing. Omit it to use the
126
+ * `CaptureLayoutDelay` from `ConnectConfig.json` — that is the setting to
127
+ * reach for when a screen transition animation is still running and the
128
+ * capture would otherwise catch a half-rendered screen. Pass `0` to
129
+ * capture immediately.
130
+ *
131
+ * Passing no delay used to send a hardcoded `0`, which made
132
+ * `CaptureLayoutDelay` inert for React Native apps and fired the capture at
133
+ * the *start* of the transition rather than after it.
134
+ *
135
+ * @returns With no `delayMs` — the normal case — only that the capture was
136
+ * **scheduled**, not that it produced a layout message. The native
137
+ * deferred overload dispatches and returns immediately, so anything that
138
+ * goes wrong once it runs (no view controller resolved, layout capture
139
+ * gated off by config) cannot be reflected here; those surface in logcat
140
+ * / os_log instead. Pass `0` and the value describes the capture itself,
141
+ * at the cost of capturing mid-transition.
142
+ */
143
+ static logScreenLayout = (name: string | undefined, delayMs?: number) => {
114
144
  TLTRN.currentScreen = name || '';
115
145
  let result = false
116
146
  try {
117
- result = AcousticConnectRN.logScreenLayout(TLTRN.currentScreen, 0);
147
+ result = AcousticConnectRN.logScreenLayout(
148
+ TLTRN.currentScreen,
149
+ delayMs === undefined ? TLTRN.USE_CONFIGURED_CAPTURE_DELAY : delayMs
150
+ );
118
151
  } catch (error: Error | any) {
119
152
  console.log('LogScreenLayout error: ', error.message);
120
153
  }
@@ -168,8 +201,86 @@ class TLTRN {
168
201
  return result;
169
202
  };
170
203
 
204
+ /**
205
+ * Keys already warned about, so a call site inside a render or a list loop
206
+ * warns once rather than on every pass.
207
+ */
208
+ static warnedNestedValueSites = new Set<string>();
209
+
210
+ /**
211
+ * Cap on {@link warnedNestedValueSites}.
212
+ *
213
+ * The site key includes the nested keys' names, so a payload built from an
214
+ * API response — per-record ids, timestamps — makes every call a distinct
215
+ * site, and the set would then grow for the life of the session. By the
216
+ * hundredth distinct shape the warning has made its point, so it stops
217
+ * instead of accumulating: bounded memory matters more than warning about
218
+ * shape 101.
219
+ */
220
+ static WARNED_NESTED_VALUE_SITES_MAX = 100;
221
+
222
+ /**
223
+ * Warns when a flat-values payload carries a nested object or array.
224
+ *
225
+ * `logCustomEvent`/`logDialogCustomEvent` are typed for flat scalars, but
226
+ * TypeScript types are erased at runtime: a payload built from an API
227
+ * response, widened through `any`, or passed from untyped JS reaches the
228
+ * bridge with its nesting intact. Both platforms then reshape it silently —
229
+ * Android's SDK chain is typed `HashMap<String, String>` end to end, so a
230
+ * nested value is stringified into whatever its `toString()` yields — and
231
+ * the call still returns `true`. `logSignal` is the API that carries nested
232
+ * JSON on both platforms.
233
+ *
234
+ * Warning only: the payload is passed through untouched, so this changes no
235
+ * behaviour and cannot break a caller who is relying on today's reshaping.
236
+ *
237
+ * @param api Name of the calling API, for the message.
238
+ * @param values The payload about to cross the bridge.
239
+ */
240
+ static warnOnNestedValues = (api: string, values: Record<string, unknown>) => {
241
+ if (values == null || typeof values !== 'object') {
242
+ return;
243
+ }
244
+ const nested = Object.keys(values).filter((key) => {
245
+ const value = (values as Record<string, unknown>)[key];
246
+ return typeof value === 'object' && value !== null;
247
+ });
248
+ if (nested.length === 0) {
249
+ return;
250
+ }
251
+ const site = `${api}:${nested.sort().join(',')}`;
252
+ if (TLTRN.warnedNestedValueSites.has(site)) {
253
+ return;
254
+ }
255
+ if (TLTRN.warnedNestedValueSites.size >= TLTRN.WARNED_NESTED_VALUE_SITES_MAX) {
256
+ return;
257
+ }
258
+ TLTRN.warnedNestedValueSites.add(site);
259
+ console.warn(
260
+ `TLTRN.${api}: nested value(s) [${nested.sort().join(', ')}] will be flattened — ` +
261
+ `${api} carries flat scalars only, and the native SDKs reshape anything else ` +
262
+ `without reporting it. Use logSignal for nested JSON; it is carried intact on ` +
263
+ `both platforms.`
264
+ );
265
+ };
266
+
267
+ /**
268
+ * Logs a custom event.
269
+ *
270
+ * @param eventName Event name, as it appears in the posted JSON.
271
+ * @param values Flat key/value pairs. Nested objects and arrays are NOT
272
+ * supported here and are reshaped by the native SDKs — use `logSignal`
273
+ * for nested JSON.
274
+ * @param level Monitoring level for this event.
275
+ * @returns Whether the native SDK **accepted the event for delivery** —
276
+ * not whether the collector received it. The event is queued locally and
277
+ * posted later, so no return value from this call can attest to delivery;
278
+ * a `true` here means only that the SDK took the event. A `false` is also
279
+ * logged natively (logcat / os_log) so the rejection is visible.
280
+ */
171
281
  static logCustomEvent = async (eventName: string, values: Record<string, string | number | boolean>, level: number) => {
172
282
  let result = false
283
+ TLTRN.warnOnNestedValues('logCustomEvent', values);
173
284
  try {
174
285
  result = AcousticConnectRN.logCustomEvent(eventName, values, level);
175
286
  } catch (error: Error | any) {
@@ -209,8 +320,15 @@ class TLTRN {
209
320
  return result;
210
321
  };
211
322
 
323
+ /**
324
+ * Logs a custom event tied to a dialog.
325
+ *
326
+ * Same flat-values contract and same return-value meaning as
327
+ * {@link logCustomEvent} — it routes to the same native API.
328
+ */
212
329
  static logDialogCustomEvent = async (dialogId: string, eventName: string, values: Record<string, string | number | boolean>) => {
213
330
  let result = false
331
+ TLTRN.warnOnNestedValues('logDialogCustomEvent', values);
214
332
  try {
215
333
  result = AcousticConnectRN.logDialogCustomEvent(dialogId, eventName, values);
216
334
  } catch (error: Error | any) {
@@ -356,7 +474,10 @@ class TLTRN {
356
474
  static logTeal = async () => {
357
475
  try {
358
476
  TLTRN.isLoggingData = 1;
359
- var res = await AcousticConnectRN.logScreenLayout(TLTRN.currentScreen, -1);
477
+ var res = await AcousticConnectRN.logScreenLayout(
478
+ TLTRN.currentScreen,
479
+ TLTRN.USE_CONFIGURED_CAPTURE_DELAY
480
+ );
360
481
  var dict = { ReactLayoutTime: TLTRN.totalRenderTime };
361
482
  var result = await AcousticConnectRN.logCustomEvent("ReactPlugin", dict, 1);
362
483
  if (TLTRN.displayDebug) {
@@ -8,7 +8,7 @@
8
8
  * prohibited.
9
9
  ********************************************************************************************/
10
10
  import React, { useCallback, useEffect, useRef, useState } from "react";
11
- import { View, StyleSheet, Platform } from "react-native";
11
+ import { View, StyleSheet } from "react-native";
12
12
  import type { LayoutChangeEvent } from "react-native"; // Use type-only import for LayoutChangeEvent
13
13
  import TLTRN from '../TLTRN';
14
14
 
@@ -76,14 +76,13 @@ const Connect: React.FC<ConnectProps> = ({
76
76
  // ref is usable, then flip `navReady` to subscribe. The direct-child case
77
77
  // resolves on the first synchronous check (no polling, no warning). If the
78
78
  // ref never attaches within the grace window we warn once, as before.
79
- // See CA-144314.
80
79
  useEffect(() => {
81
80
  // Reset readiness whenever the resolved ref changes. Without this, a
82
81
  // `navigationRef` prop swap leaves `navReady` stale-true, so the
83
82
  // subscription effect below re-runs and attaches `addListener` to the
84
83
  // old container (whose `.current` is still non-null mid-transition)
85
84
  // before the new ref is validated. Resetting forces re-validation
86
- // through `isUsable()` before tracking re-enables. See CA-144314.
85
+ // through `isUsable()` before tracking re-enables.
87
86
  setNavReady(false);
88
87
 
89
88
  const isUsable = () =>
@@ -132,14 +131,28 @@ const Connect: React.FC<ConnectProps> = ({
132
131
 
133
132
  // Listen for the 'state' event to track navigation state changes
134
133
  const unsubscribeState = navigation.current.addListener("state", () => {
135
- currentRoute.current = extractName(navigation) || navigation.current.getCurrentRoute()?.name;
134
+ // extractName resolves the focused route through the nested
135
+ // navigators itself, so there is no outer-level fallback to chain
136
+ // here — one used to be appended, which reported the tab name for
137
+ // every push inside that tab.
138
+ currentRoute.current = extractName(navigation);
136
139
 
137
- if (Platform.OS === "ios" && currentRoute && currentRoute.current) {
138
- TLTRN.logScreenViewPageName(currentRoute.current);
139
- } else if (Platform.OS === "android") {
140
- TLTRN.logScreenViewPageName(currentRoute.current);
141
- TLTRN.logScreenLayout(currentRoute.current);
140
+ // Both platforms take the same path. iOS used to be excluded from
141
+ // the layout call, which left the wrapper with no layout trigger
142
+ // at all there: the one remaining bridge caller was TLTRN's
143
+ // render-settle timer, so a plain navigation captured nothing.
144
+ if (!currentRoute.current) {
145
+ return;
142
146
  }
147
+ TLTRN.logScreenViewPageName(currentRoute.current);
148
+ // Deliberately no delay argument. TLTRN then sends its
149
+ // "use the configured CaptureLayoutDelay" sentinel, so the capture
150
+ // is deferred past the transition. Passing 0 would select the
151
+ // native synchronous overload instead, which captures on the
152
+ // calling thread at the *start* of the transition — React
153
+ // Navigation fires 'state' before the animation runs — and makes
154
+ // CaptureLayoutDelay inert.
155
+ TLTRN.logScreenLayout(currentRoute.current);
143
156
  });
144
157
 
145
158
  // Cleanup listeners when the component unmounts or dependencies change
@@ -149,12 +162,9 @@ const Connect: React.FC<ConnectProps> = ({
149
162
  }, [navReady, navigation]);
150
163
 
151
164
  const onStartShouldSetResponderCapture = useCallback((event: any) => {
152
- if (navigation?.current?.getCurrentRoute) {
153
- currentRoute.current =
154
- extractName(navigation) || navigation.current.getCurrentRoute()?.name;
155
- if (currentRoute.current) {
156
- TLTRN.logScreenViewPageName(currentRoute.current);
157
- }
165
+ currentRoute.current = extractName(navigation);
166
+ if (currentRoute.current) {
167
+ TLTRN.logScreenViewPageName(currentRoute.current);
158
168
  }
159
169
  TLTRN.logClickEvent(event);
160
170
  return false; // Must remain false so events bubble to the host app's handlers
@@ -166,13 +176,18 @@ const Connect: React.FC<ConnectProps> = ({
166
176
  }
167
177
  initial.current = true;
168
178
 
169
- if (navigation?.current?.getCurrentRoute) {
170
- currentRoute.current = navigation.current.getCurrentRoute()?.name;
171
- if (Platform.OS === "ios" && currentRoute.current) {
172
- TLTRN.logScreenViewPageName(currentRoute.current);
173
- } else if (Platform.OS === "android") {
174
- TLTRN.logScreenLayout(currentRoute.current);
175
- }
179
+ // Resolved through extractName like the other two triggers. This site
180
+ // used to read `getCurrentRoute()?.name` directly, so a `params.name`
181
+ // override was honoured on navigation but silently ignored for the
182
+ // first-paint screen — the same screen reported under two names.
183
+ currentRoute.current = extractName(navigation);
184
+ // Same unification as the 'state' listener above: the split sent
185
+ // only a screenview on iOS and only a layout on Android, so
186
+ // neither platform got both from the first-paint trigger. No delay
187
+ // argument, for the reason given there.
188
+ if (currentRoute.current) {
189
+ TLTRN.logScreenViewPageName(currentRoute.current);
190
+ TLTRN.logScreenLayout(currentRoute.current);
176
191
  }
177
192
  return true;
178
193
  }, [navigation]);
@@ -190,13 +205,121 @@ const Connect: React.FC<ConnectProps> = ({
190
205
  );
191
206
  };
192
207
 
208
+ /**
209
+ * Walks a React Navigation state down to the deepest **focused** route.
210
+ *
211
+ * Nested navigators are the default architecture of production RN apps: a tab
212
+ * navigator whose tabs each hold a stack. The container's root state then
213
+ * describes only the outer level, and the route that the user is actually
214
+ * looking at lives in `routes[index].state`, recursively. Reading the outer
215
+ * level alone reports the *tab* name for every push inside that tab, so screen
216
+ * changes below the first level are invisible to analytics and replay.
217
+ *
218
+ * `index` can legitimately be absent on a partial/rehydrated state, in which
219
+ * case React Navigation treats the last route as focused — matched here.
220
+ *
221
+ * A depth cap guards against a malformed state whose nesting cycles; 32 is far
222
+ * past any real navigator tree.
223
+ */
224
+ function findFocusedRoute(state: any): any {
225
+ let current = state;
226
+ let depth = 0;
227
+ while (current?.routes?.length && depth++ < 32) {
228
+ const index = current.index ?? current.routes.length - 1;
229
+ const route = current.routes[index];
230
+ if (!route?.state?.routes?.length) {
231
+ return route;
232
+ }
233
+ current = route.state;
234
+ }
235
+ return undefined;
236
+ }
237
+
238
+ /**
239
+ * Containers already reported by {@link warnExtractNameFailed}.
240
+ *
241
+ * Keyed by the container itself, so a ref that throws on every navigation
242
+ * produces one line rather than one per transition, while a genuinely
243
+ * different container still gets its own. A `WeakSet` holds no strong
244
+ * reference, so remembering a container cannot keep it alive.
245
+ */
246
+ const extractNameErrorReported = new WeakSet<object>();
247
+
248
+ /**
249
+ * Reports, once per container, that resolving the current route threw.
250
+ *
251
+ * A throw here is expected and harmless during teardown, which is why
252
+ * ``extractName`` swallows it. A ref that keeps throwing is a different
253
+ * matter: every screen view goes unnamed, and without a line here that looks
254
+ * exactly like a ref that never attached. One warning separates the two
255
+ * without flooding a listener that fires per navigation.
256
+ */
257
+ function warnExtractNameFailed(container: unknown, error: unknown) {
258
+ if (typeof container === "object" && container !== null) {
259
+ if (extractNameErrorReported.has(container)) {
260
+ return;
261
+ }
262
+ extractNameErrorReported.add(container);
263
+ }
264
+ console.warn(
265
+ "Connect: could not resolve the current route — the navigation container ref threw. " +
266
+ "Screen views stay unnamed while this persists (harmless if the container is unmounting). " +
267
+ "Cause:",
268
+ error
269
+ );
270
+ }
271
+
272
+ /**
273
+ * The screen name to report for the navigation container's current position.
274
+ *
275
+ * Resolution order:
276
+ *
277
+ * 1. The focused route resolved from `getRootState()` by ``findFocusedRoute``.
278
+ * Taking the state and walking it here — rather than trusting a single
279
+ * accessor — keeps the wrapper correct regardless of whether the host app's
280
+ * navigation library resolves nesting inside `getCurrentRoute()`, and works
281
+ * for a custom container ref that exposes state but not that helper.
282
+ * 2. `getCurrentRoute()`, for refs that expose no `getRootState`.
283
+ *
284
+ * Either way `params.name` wins over the route's own `name` when the host app
285
+ * supplies it — the documented override for giving a route a human-readable
286
+ * analytics name. Only a non-empty string counts, so `params: { name: '' }`
287
+ * falls through to the route name instead of blanking the screenview.
288
+ *
289
+ * Returns `""` when nothing resolves, which both callers treat as "skip".
290
+ */
193
291
  function extractName(navigation: any): string {
194
- const routeParams = navigation?.current?.getCurrentRoute?.()?.params;
195
- if (routeParams) {
196
- const { name } = routeParams;
197
- return name ? name : navigation.current?.getCurrentRoute()?.name || "";
292
+ const container = navigation?.current;
293
+ if (!container) {
294
+ return "";
295
+ }
296
+
297
+ let route: any;
298
+ try {
299
+ route = findFocusedRoute(container.getRootState?.());
300
+ } catch (error) {
301
+ // A container mid-teardown can throw out of getRootState(). Screen
302
+ // naming is not worth taking the host app's navigation down for.
303
+ warnExtractNameFailed(container, error);
304
+ route = undefined;
305
+ }
306
+ if (!route) {
307
+ try {
308
+ route = container.getCurrentRoute?.();
309
+ } catch (error) {
310
+ warnExtractNameFailed(container, error);
311
+ route = undefined;
312
+ }
313
+ }
314
+ if (!route) {
315
+ return "";
316
+ }
317
+
318
+ const overridden = route.params?.name;
319
+ if (typeof overridden === "string" && overridden.length > 0) {
320
+ return overridden;
198
321
  }
199
- return "";
322
+ return typeof route.name === "string" ? route.name : "";
200
323
  }
201
324
 
202
325
  export default Connect;
package/src/index.ts CHANGED
@@ -41,4 +41,9 @@ try {
41
41
  }
42
42
 
43
43
  export { Connect, TLTRN, KeyboardListener, DialogListener, useDialogTracking, DialogDebugger, withAcousticAutoDialog }
44
+
45
+ // Re-exported so callers can name a `logSignal` payload without importing
46
+ // from `react-native-nitro-modules` — the spec aliases nitro's AnyMap only
47
+ // because that is the one type nitrogen accepts for arbitrary JSON.
48
+ export type { SignalValues } from './specs/react-native-acoustic-connect.nitro'
44
49
  export default AcousticConnectRN
@@ -10,7 +10,7 @@
10
10
  // Created on 5/9/25.
11
11
  //
12
12
 
13
- import { type HybridObject } from 'react-native-nitro-modules'
13
+ import { type AnyMap, type HybridObject } from 'react-native-nitro-modules'
14
14
 
15
15
  // Define a named type for the anonymous object
16
16
  export type KeyValueObject = {
@@ -18,6 +18,32 @@ export type KeyValueObject = {
18
18
  [key: string]: unknown;
19
19
  };
20
20
 
21
+ /**
22
+ * Payload accepted by {@link AcousticConnectRN.logSignal} — any JSON-shaped
23
+ * object. Nested objects and arrays are allowed, so this is a superset of a
24
+ * flat `Record<string, string | number | boolean>`.
25
+ *
26
+ * You do not need this type to call `logSignal`: an object literal is enough.
27
+ * It exists for the times you want to name the payload — a helper parameter, a
28
+ * shared constant — and is re-exported from the package root so you never have
29
+ * to reach into `react-native-nitro-modules` for it:
30
+ *
31
+ * ```ts
32
+ * import AcousticConnectRN, { type SignalValues } from 'react-native-acoustic-connect'
33
+ *
34
+ * const payload: SignalValues = { signalContent: { signalType: 'pageview' } }
35
+ * AcousticConnectRN.logSignal(payload, 1)
36
+ * ```
37
+ *
38
+ * @remarks
39
+ * Aliases nitro's `AnyMap`, which is the only way to express arbitrary JSON in
40
+ * a Nitro spec — a hand-rolled recursive type is rejected by nitrogen, which
41
+ * tries to generate a struct for it. Nitrogen resolves the alias, so the
42
+ * generated native bindings are identical either way; the indirection exists
43
+ * purely to keep a third-party type name off our public API.
44
+ */
45
+ export type SignalValues = AnyMap
46
+
21
47
  export type ConnectMonitoringLevelType = 'Ignore' | 'CellularAndWiFi' | 'WiFi'
22
48
 
23
49
  /**
@@ -123,21 +149,138 @@ export interface AcousticConnectRN extends HybridObject<{ ios: 'swift', android:
123
149
  getBooleanConfigItemForKey(theDefault: boolean, key: string, moduleName: string): boolean
124
150
  getStringItemForKey(theDefault: string, key: string, moduleName: string): string | null | undefined
125
151
  getNumberItemForKey(theDefault: number, key: string, moduleName: string): number
152
+ /**
153
+ * Logs a named custom event with a flat set of key/value pairs.
154
+ *
155
+ * `values` is deliberately **flat** (scalars only), unlike
156
+ * {@link logSignal}. The Android SDK's custom-event path is typed
157
+ * `HashMap<String, String>` end to end (`Connect.logCustomEvent` →
158
+ * `Tealeaf.logCustomEvent`), so there is no native route for nested
159
+ * JSON. Widening this signature would compile but silently drop the
160
+ * nesting on Android while preserving it on iOS — a cross-platform
161
+ * divergence worse than the restriction. Use {@link logSignal} when the
162
+ * payload needs structure.
163
+ *
164
+ * @param eventName Event name; appears in the posted JSON.
165
+ * @param values Flat key/value pairs to attach to the event.
166
+ * @param level Monitoring level for this event.
167
+ * @returns `true` if the SDK **accepted the event for delivery** — not
168
+ * that the collector received it. Events are queued on device and posted
169
+ * in batches later, so nothing this call can return attests to delivery
170
+ * or to server-side acceptance. A `false` means the SDK rejected the
171
+ * event outright and nothing was queued; the bridge also logs that to
172
+ * logcat / os_log so it is visible without inspecting the return value.
173
+ */
126
174
  logCustomEvent(eventName: string, values: Record<string, string | number | boolean>, level: number): boolean
127
- logSignal(values: Record<string, string | number | boolean>, level: number): boolean
175
+
176
+ /**
177
+ * Logs a signal payload.
178
+ *
179
+ * `values` accepts **arbitrary JSON** — nested objects and arrays, not
180
+ * just scalars — because both native SDKs embed the payload verbatim:
181
+ * iOS `CTSignalMessage` gates only on `NSJSONSerialization
182
+ * isValidJSONObject:`, and Android `Connect.logSignal` takes an untyped
183
+ * `HashMap<String, Any?>`. The bridge converts the map to each
184
+ * platform's JSON representation without flattening or reshaping it.
185
+ *
186
+ * Scalar-only callers are unaffected: {@link SignalValues} is a superset
187
+ * of `Record<string, string | number | boolean>`.
188
+ *
189
+ * @param values Signal payload. Objects, arrays, strings, numbers,
190
+ * booleans and `null` are all carried through.
191
+ * @param level Monitoring level for this signal.
192
+ * @returns `true` if the SDK **accepted the signal for delivery** — not
193
+ * that the collector received it, and not that it passed server-side
194
+ * schema validation. Signals are queued on device and posted later, so
195
+ * nothing this call can return attests to delivery. A `false` means the
196
+ * SDK rejected it and nothing was queued; the bridge logs that to
197
+ * logcat / os_log.
198
+ *
199
+ * @remarks
200
+ * **Android version boundary — top-level numbers.** The Android SDK's
201
+ * `JsonUtil.getHashValues` gained a `Number` branch in Connect Android
202
+ * **11.0.24-beta**, so from that version a top-level numeric value is
203
+ * carried. Earlier versions serialised only `String`, `Boolean`,
204
+ * `JSONObject`, `JSONArray` and `byte[]` at the top level of the signal
205
+ * map and dropped a top-level number. Numbers nested *inside* an object
206
+ * or array were never affected, because the bridge builds those
207
+ * `JSONObject`/`JSONArray` values itself, and iOS has always carried
208
+ * top-level numbers normally. Both versions sit inside the
209
+ * `[11.0.11, 12.0.0)` range this package accepts, so nest the number if
210
+ * your integration pins a Connect Android version below 11.0.24-beta.
211
+ *
212
+ * @example Nested payload
213
+ * ```ts
214
+ * import AcousticConnectRN from 'react-native-acoustic-connect'
215
+ *
216
+ * AcousticConnectRN.logSignal(
217
+ * {
218
+ * signalContent: {
219
+ * signalType: 'pageview',
220
+ * url: 'https://app.example.com/dashboard',
221
+ * pageCategory: 'dashboard',
222
+ * },
223
+ * audience: [
224
+ * { name: 'Account Name', value: 'Acme Corp' },
225
+ * { name: 'Account ID', value: '4815162342' },
226
+ * ],
227
+ * },
228
+ * 1
229
+ * )
230
+ * ```
231
+ */
232
+ logSignal(values: SignalValues, level: number): boolean
128
233
  logExceptionEvent(message: string, stackInfo: string, unhandled: boolean): boolean
129
234
  logLocation(): boolean
130
235
  logLocationWithLatitudeLongitude(latitude: number, longitude: number, level: number): boolean
131
236
  logClickEvent(target: number, controlId: string): boolean
132
237
  logTextChangeEvent(target: number, controlId: string, text: string | null | undefined): boolean
238
+ /**
239
+ * Sets the logical screen name subsequent events are attributed to.
240
+ *
241
+ * Sets the name and nothing else — no screenview, no layout capture — on
242
+ * both platforms. `<Connect>` calls this on every touch so the click that
243
+ * follows lands on the right screen, so it has to stay cheap.
244
+ *
245
+ * Android used to route it through `Connect.resumeConnect`, which also
246
+ * emitted a screenview and captured a full layout, putting tens to hundreds
247
+ * of KB on the wire per tap where iOS sent none. Use `logScreenLayout` when
248
+ * a layout capture is what you want.
249
+ */
133
250
  setCurrentScreenName(logicalPageName: string): boolean
134
251
  logScreenViewContextLoad(logicalPageName: string | null | undefined, referrer:string | null | undefined): boolean
135
252
  logScreenViewContextUnload(logicalPageName: string | null | undefined, referrer:string | null | undefined): boolean
253
+ /**
254
+ * Captures the layout of the current screen.
255
+ *
256
+ * @param name Screen name to associate with the capture.
257
+ * @param delay Milliseconds to wait before capturing — the same unit as
258
+ * `CaptureLayoutDelay` in the layout config, on both platforms. A
259
+ * negative value means "use the `CaptureLayoutDelay` configured for this
260
+ * screen"; `0` captures immediately.
261
+ *
262
+ * Prefer `TLTRN.logScreenLayout`, which defaults to the configured delay.
263
+ *
264
+ * @returns For a `delay` of `0`, whether the capture itself succeeded. For
265
+ * any positive or configured delay, only that the capture was
266
+ * **scheduled** — the native deferred overload dispatches and returns
267
+ * immediately, so a `true` says nothing about what the capture found
268
+ * when it eventually ran. Failures after that point (no view controller
269
+ * resolved, config gating the capture off) surface in logcat / os_log,
270
+ * not here.
271
+ */
136
272
  logScreenLayout(name: string, delay: number): boolean
137
273
  // New dialog event handling methods
138
274
  logDialogShowEvent(dialogId: string, dialogTitle: string, dialogType: string): boolean
139
275
  logDialogDismissEvent(dialogId: string, dismissReason: string): boolean
140
276
  logDialogButtonClickEvent(dialogId: string, buttonText: string, buttonIndex: number): boolean
277
+ /**
278
+ * Logs a custom event against a tracked dialog.
279
+ *
280
+ * `values` is flat for the same reason as {@link logCustomEvent} — this
281
+ * routes to the native custom-event API, whose Android path carries string
282
+ * values only.
283
+ */
141
284
  logDialogCustomEvent(dialogId: string, eventName: string, values: Record<string, string | number | boolean>): boolean
142
285
 
143
286
  /**
@@ -161,23 +304,62 @@ export interface AcousticConnectRN extends HybridObject<{ ios: 'swift', android:
161
304
  * `'loggedIn'` when omitted (identity logging typically marks a sign-in),
162
305
  * overriding the native SDKs' own `'pageView'` default.
163
306
  * @param additionalParameters Optional extra key/value pairs merged into the
164
- * signal payload. Only when omitted (`undefined`) does the bridge supply
165
- * the default `{ registrationMethod: 'email' }`; an explicitly-provided
166
- * map is used as-is, so passing an empty `{}` sends no extra parameters
167
- * (the default is not merged in). A `'url'` entry is honoured uniformly on
168
- * both platforms: on Android it is routed to the SDK's explicit `url`
169
- * parameter, on iOS it rides inside the parameter map (where the native
170
- * API expects it).
307
+ * signal payload. Only when omitted (`undefined`) does the bridge supply a
308
+ * default, and that default follows the resolved `signalType` — see
309
+ * **Required method attribute** below. An explicitly-provided map is used
310
+ * as-is, so passing an empty `{}` sends no extra parameters (the default is
311
+ * not merged in). A `'url'` entry is honoured uniformly on both platforms:
312
+ * on Android it is routed to the SDK's explicit `url` parameter, on iOS it
313
+ * rides inside the parameter map (where the native API expects it).
171
314
  * @returns A promise resolving to `true` if the identity signal was
172
315
  * dispatched, `false` otherwise (including the blank-identifier case).
173
316
  * Never rejects.
174
317
  *
175
- * @example
318
+ * ### Required method attribute
319
+ *
320
+ * Identity signals must carry a *method* attribute, and the key Connect
321
+ * requires depends on the signal type:
322
+ *
323
+ * | `signalType` | Required attribute |
324
+ * | -------------------- | -------------------- |
325
+ * | `'loggedIn'` | `loginMethod` |
326
+ * | `'accountRegistered'`| `registrationMethod` |
327
+ *
328
+ * Send the wrong key and the signal fails schema validation and is
329
+ * discarded server-side — while this promise still resolves `true`, because
330
+ * the native SDKs report only that the signal was queued. If you pass
331
+ * `additionalParameters` explicitly, you own supplying the right key.
332
+ *
333
+ * @example Sign-in — `loginMethod` is required
176
334
  * ```ts
177
335
  * import AcousticConnectRN from 'react-native-acoustic-connect'
178
336
  *
337
+ * await AcousticConnectRN.logIdentity('Email', 'user@example.com', 'loggedIn', {
338
+ * loginMethod: 'sso',
339
+ * })
340
+ *
341
+ * // Omitting both arguments is equivalent to the above with
342
+ * // `{ loginMethod: 'email' }` — the bridge defaults to a `loggedIn` signal.
179
343
  * await AcousticConnectRN.logIdentity('Email', 'user@example.com')
180
344
  * ```
345
+ *
346
+ * @example Registration — `registrationMethod` is required
347
+ * ```ts
348
+ * await AcousticConnectRN.logIdentity(
349
+ * 'Email',
350
+ * 'user@example.com',
351
+ * 'accountRegistered',
352
+ * { registrationMethod: 'email' }
353
+ * )
354
+ * ```
355
+ *
356
+ * @returns `true` if the SDK **accepted the identity signal for
357
+ * delivery**. It does not mean the signal reached the collector, and it
358
+ * does not mean the collector kept it — a schema-invalid signal (the
359
+ * wrong method key above) is discarded server-side after resolving
360
+ * `true` here. Never rejects. A `false` means the SDK rejected the call
361
+ * locally, e.g. a blank identifier; the bridge logs that to logcat /
362
+ * os_log.
181
363
  */
182
364
  logIdentity(
183
365
  identifierName: string,
@@ -1,2 +0,0 @@
1
- BUNDLE_PATH: "vendor/bundle"
2
- BUNDLE_FORCE_RUBY_PLATFORM: 1