@userflow-tech/react-native 0.4.4 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (431) hide show
  1. package/README.md +124 -34
  2. package/docs/anchoring.md +6 -1
  3. package/docs/deep-linking.md +26 -0
  4. package/docs/troubleshooting.md +50 -23
  5. package/expo-plugin/hostDependencyWarnings.d.ts +6 -4
  6. package/expo-plugin/hostDependencyWarnings.d.ts.map +1 -1
  7. package/expo-plugin/hostDependencyWarnings.js +8 -6
  8. package/expo-plugin/hostDependencyWarnings.js.map +1 -1
  9. package/lib/commonjs/anchors/AutoAnchorRegistry.js +144 -34
  10. package/lib/commonjs/anchors/AutoAnchorRegistry.js.map +1 -1
  11. package/lib/commonjs/anchors/animationFrame.js +29 -1
  12. package/lib/commonjs/anchors/animationFrame.js.map +1 -1
  13. package/lib/commonjs/anchors/appActive.js +61 -0
  14. package/lib/commonjs/anchors/appActive.js.map +1 -0
  15. package/lib/commonjs/anchors/elementConditionEvaluator.js +25 -8
  16. package/lib/commonjs/anchors/elementConditionEvaluator.js.map +1 -1
  17. package/lib/commonjs/anchors/elementTapMonitor.js +67 -12
  18. package/lib/commonjs/anchors/elementTapMonitor.js.map +1 -1
  19. package/lib/commonjs/anchors/elementTargetMatch.js +33 -7
  20. package/lib/commonjs/anchors/elementTargetMatch.js.map +1 -1
  21. package/lib/commonjs/anchors/fiber/fiberInternals.js +66 -0
  22. package/lib/commonjs/anchors/fiber/fiberInternals.js.map +1 -1
  23. package/lib/commonjs/anchors/fiber/indexHostFibers.js +4 -3
  24. package/lib/commonjs/anchors/fiber/indexHostFibers.js.map +1 -1
  25. package/lib/commonjs/anchors/fiber/resolveFiberPath.js +30 -15
  26. package/lib/commonjs/anchors/fiber/resolveFiberPath.js.map +1 -1
  27. package/lib/commonjs/anchors/fiberAnchorCache.js +20 -0
  28. package/lib/commonjs/anchors/fiberAnchorCache.js.map +1 -1
  29. package/lib/commonjs/anchors/gestureHandlerHandoff.js +304 -0
  30. package/lib/commonjs/anchors/gestureHandlerHandoff.js.map +1 -0
  31. package/lib/commonjs/anchors/resolveAnchorHost.js +6 -0
  32. package/lib/commonjs/anchors/resolveAnchorHost.js.map +1 -1
  33. package/lib/commonjs/anchors/resolveAutoAnchorHost.js +11 -6
  34. package/lib/commonjs/anchors/resolveAutoAnchorHost.js.map +1 -1
  35. package/lib/commonjs/anchors/resolveElementTargets.js +63 -8
  36. package/lib/commonjs/anchors/resolveElementTargets.js.map +1 -1
  37. package/lib/commonjs/anchors/semanticMatcher.js +43 -21
  38. package/lib/commonjs/anchors/semanticMatcher.js.map +1 -1
  39. package/lib/commonjs/anchors/tapSlop.js +16 -0
  40. package/lib/commonjs/anchors/tapSlop.js.map +1 -0
  41. package/lib/commonjs/anchors/targetPressMonitor.js +66 -12
  42. package/lib/commonjs/anchors/targetPressMonitor.js.map +1 -1
  43. package/lib/commonjs/authoring/fingerprintFromInstance.js +5 -9
  44. package/lib/commonjs/authoring/fingerprintFromInstance.js.map +1 -1
  45. package/lib/commonjs/content/RichContentRenderer.js +3 -3
  46. package/lib/commonjs/content/RichContentRenderer.js.map +1 -1
  47. package/lib/commonjs/content/openSafeUrl.js +3 -1
  48. package/lib/commonjs/content/openSafeUrl.js.map +1 -1
  49. package/lib/commonjs/expo-router/useUserflowExpoRouter.js +6 -0
  50. package/lib/commonjs/expo-router/useUserflowExpoRouter.js.map +1 -1
  51. package/lib/commonjs/index.js +19 -5
  52. package/lib/commonjs/index.js.map +1 -1
  53. package/lib/commonjs/installCheck.js +2 -2
  54. package/lib/commonjs/installCheck.js.map +1 -1
  55. package/lib/commonjs/navigation/navigateUrlUtils.js +105 -0
  56. package/lib/commonjs/navigation/navigateUrlUtils.js.map +1 -0
  57. package/lib/commonjs/navigation/openExternalNavigateUrl.js +14 -0
  58. package/lib/commonjs/navigation/openExternalNavigateUrl.js.map +1 -0
  59. package/lib/commonjs/navigation/openFlowNavigateUrl.js +47 -41
  60. package/lib/commonjs/navigation/openFlowNavigateUrl.js.map +1 -1
  61. package/lib/commonjs/pairing/PairingController.js +3 -1
  62. package/lib/commonjs/pairing/PairingController.js.map +1 -1
  63. package/lib/commonjs/runtime/BannerHost.js +38 -29
  64. package/lib/commonjs/runtime/BannerHost.js.map +1 -1
  65. package/lib/commonjs/runtime/TargetPressBridge.js +55 -7
  66. package/lib/commonjs/runtime/TargetPressBridge.js.map +1 -1
  67. package/lib/commonjs/runtime/UserflowOverlay.js +5 -11
  68. package/lib/commonjs/runtime/UserflowOverlay.js.map +1 -1
  69. package/lib/commonjs/runtime/UserflowProvider.js +66 -40
  70. package/lib/commonjs/runtime/UserflowProvider.js.map +1 -1
  71. package/lib/commonjs/runtime/bannerEngine.js +8 -2
  72. package/lib/commonjs/runtime/bannerEngine.js.map +1 -1
  73. package/lib/commonjs/runtime/bannerFlowSpacer.js +71 -0
  74. package/lib/commonjs/runtime/bannerFlowSpacer.js.map +1 -0
  75. package/lib/commonjs/runtime/flowEngine.js +11 -0
  76. package/lib/commonjs/runtime/flowEngine.js.map +1 -1
  77. package/lib/commonjs/runtime/previewStart.js +39 -0
  78. package/lib/commonjs/runtime/previewStart.js.map +1 -0
  79. package/lib/commonjs/runtime/pushBannerLayoutContext.js +98 -0
  80. package/lib/commonjs/runtime/pushBannerLayoutContext.js.map +1 -0
  81. package/lib/commonjs/screenTracker.js +12 -0
  82. package/lib/commonjs/screenTracker.js.map +1 -1
  83. package/lib/commonjs/surfaces/BannerBar.js +79 -61
  84. package/lib/commonjs/surfaces/BannerBar.js.map +1 -1
  85. package/lib/commonjs/surfaces/BannerSurface.js +26 -0
  86. package/lib/commonjs/surfaces/BannerSurface.js.map +1 -1
  87. package/lib/commonjs/surfaces/TooltipSurface.js +43 -41
  88. package/lib/commonjs/surfaces/TooltipSurface.js.map +1 -1
  89. package/lib/commonjs/surfaces/bannerBarLayout.js +77 -10
  90. package/lib/commonjs/surfaces/bannerBarLayout.js.map +1 -1
  91. package/lib/commonjs/surfaces/bannerWebView/BannerWebViewBar.js +112 -63
  92. package/lib/commonjs/surfaces/bannerWebView/BannerWebViewBar.js.map +1 -1
  93. package/lib/commonjs/surfaces/bannerWebView/buildCustomBannerHtml.js +59 -11
  94. package/lib/commonjs/surfaces/bannerWebView/buildCustomBannerHtml.js.map +1 -1
  95. package/lib/commonjs/surfaces/hostAccessibilityTrap.js +28 -0
  96. package/lib/commonjs/surfaces/hostAccessibilityTrap.js.map +1 -0
  97. package/lib/commonjs/surfaces/resolveBannerTheme.js +6 -3
  98. package/lib/commonjs/surfaces/resolveBannerTheme.js.map +1 -1
  99. package/lib/commonjs/surfaces/tooltip/TooltipBubble.js +3 -2
  100. package/lib/commonjs/surfaces/tooltip/TooltipBubble.js.map +1 -1
  101. package/lib/commonjs/surfaces/tooltip/targetSearchSchedule.js +134 -0
  102. package/lib/commonjs/surfaces/tooltip/targetSearchSchedule.js.map +1 -0
  103. package/lib/commonjs/version.js +1 -1
  104. package/lib/module/anchors/AutoAnchorRegistry.js +145 -35
  105. package/lib/module/anchors/AutoAnchorRegistry.js.map +1 -1
  106. package/lib/module/anchors/animationFrame.js +29 -2
  107. package/lib/module/anchors/animationFrame.js.map +1 -1
  108. package/lib/module/anchors/appActive.js +57 -0
  109. package/lib/module/anchors/appActive.js.map +1 -0
  110. package/lib/module/anchors/elementConditionEvaluator.js +26 -9
  111. package/lib/module/anchors/elementConditionEvaluator.js.map +1 -1
  112. package/lib/module/anchors/elementTapMonitor.js +67 -12
  113. package/lib/module/anchors/elementTapMonitor.js.map +1 -1
  114. package/lib/module/anchors/elementTargetMatch.js +32 -7
  115. package/lib/module/anchors/elementTargetMatch.js.map +1 -1
  116. package/lib/module/anchors/fiber/fiberInternals.js +65 -0
  117. package/lib/module/anchors/fiber/fiberInternals.js.map +1 -1
  118. package/lib/module/anchors/fiber/indexHostFibers.js +4 -3
  119. package/lib/module/anchors/fiber/indexHostFibers.js.map +1 -1
  120. package/lib/module/anchors/fiber/resolveFiberPath.js +30 -15
  121. package/lib/module/anchors/fiber/resolveFiberPath.js.map +1 -1
  122. package/lib/module/anchors/fiberAnchorCache.js +19 -0
  123. package/lib/module/anchors/fiberAnchorCache.js.map +1 -1
  124. package/lib/module/anchors/gestureHandlerHandoff.js +298 -0
  125. package/lib/module/anchors/gestureHandlerHandoff.js.map +1 -0
  126. package/lib/module/anchors/resolveAnchorHost.js +1 -0
  127. package/lib/module/anchors/resolveAnchorHost.js.map +1 -1
  128. package/lib/module/anchors/resolveAutoAnchorHost.js +11 -6
  129. package/lib/module/anchors/resolveAutoAnchorHost.js.map +1 -1
  130. package/lib/module/anchors/resolveElementTargets.js +63 -8
  131. package/lib/module/anchors/resolveElementTargets.js.map +1 -1
  132. package/lib/module/anchors/semanticMatcher.js +43 -21
  133. package/lib/module/anchors/semanticMatcher.js.map +1 -1
  134. package/lib/module/anchors/tapSlop.js +11 -0
  135. package/lib/module/anchors/tapSlop.js.map +1 -0
  136. package/lib/module/anchors/targetPressMonitor.js +53 -8
  137. package/lib/module/anchors/targetPressMonitor.js.map +1 -1
  138. package/lib/module/authoring/fingerprintFromInstance.js +6 -10
  139. package/lib/module/authoring/fingerprintFromInstance.js.map +1 -1
  140. package/lib/module/content/RichContentRenderer.js +3 -3
  141. package/lib/module/content/RichContentRenderer.js.map +1 -1
  142. package/lib/module/content/openSafeUrl.js +3 -1
  143. package/lib/module/content/openSafeUrl.js.map +1 -1
  144. package/lib/module/expo-router/useUserflowExpoRouter.js +7 -1
  145. package/lib/module/expo-router/useUserflowExpoRouter.js.map +1 -1
  146. package/lib/module/index.js +22 -7
  147. package/lib/module/index.js.map +1 -1
  148. package/lib/module/installCheck.js +2 -2
  149. package/lib/module/installCheck.js.map +1 -1
  150. package/lib/module/navigation/navigateUrlUtils.js +94 -0
  151. package/lib/module/navigation/navigateUrlUtils.js.map +1 -0
  152. package/lib/module/navigation/openExternalNavigateUrl.js +11 -0
  153. package/lib/module/navigation/openExternalNavigateUrl.js.map +1 -0
  154. package/lib/module/navigation/openFlowNavigateUrl.js +22 -36
  155. package/lib/module/navigation/openFlowNavigateUrl.js.map +1 -1
  156. package/lib/module/pairing/PairingController.js +3 -1
  157. package/lib/module/pairing/PairingController.js.map +1 -1
  158. package/lib/module/runtime/BannerHost.js +38 -29
  159. package/lib/module/runtime/BannerHost.js.map +1 -1
  160. package/lib/module/runtime/TargetPressBridge.js +56 -8
  161. package/lib/module/runtime/TargetPressBridge.js.map +1 -1
  162. package/lib/module/runtime/UserflowOverlay.js +5 -11
  163. package/lib/module/runtime/UserflowOverlay.js.map +1 -1
  164. package/lib/module/runtime/UserflowProvider.js +66 -40
  165. package/lib/module/runtime/UserflowProvider.js.map +1 -1
  166. package/lib/module/runtime/bannerEngine.js +7 -2
  167. package/lib/module/runtime/bannerEngine.js.map +1 -1
  168. package/lib/module/runtime/bannerFlowSpacer.js +65 -0
  169. package/lib/module/runtime/bannerFlowSpacer.js.map +1 -0
  170. package/lib/module/runtime/flowEngine.js +11 -0
  171. package/lib/module/runtime/flowEngine.js.map +1 -1
  172. package/lib/module/runtime/previewStart.js +35 -0
  173. package/lib/module/runtime/previewStart.js.map +1 -0
  174. package/lib/module/runtime/pushBannerLayoutContext.js +91 -0
  175. package/lib/module/runtime/pushBannerLayoutContext.js.map +1 -0
  176. package/lib/module/screenTracker.js +11 -0
  177. package/lib/module/screenTracker.js.map +1 -1
  178. package/lib/module/surfaces/BannerBar.js +80 -62
  179. package/lib/module/surfaces/BannerBar.js.map +1 -1
  180. package/lib/module/surfaces/BannerSurface.js +26 -0
  181. package/lib/module/surfaces/BannerSurface.js.map +1 -1
  182. package/lib/module/surfaces/TooltipSurface.js +44 -42
  183. package/lib/module/surfaces/TooltipSurface.js.map +1 -1
  184. package/lib/module/surfaces/bannerBarLayout.js +72 -11
  185. package/lib/module/surfaces/bannerBarLayout.js.map +1 -1
  186. package/lib/module/surfaces/bannerWebView/BannerWebViewBar.js +113 -64
  187. package/lib/module/surfaces/bannerWebView/BannerWebViewBar.js.map +1 -1
  188. package/lib/module/surfaces/bannerWebView/buildCustomBannerHtml.js +59 -11
  189. package/lib/module/surfaces/bannerWebView/buildCustomBannerHtml.js.map +1 -1
  190. package/lib/module/surfaces/hostAccessibilityTrap.js +24 -0
  191. package/lib/module/surfaces/hostAccessibilityTrap.js.map +1 -0
  192. package/lib/module/surfaces/resolveBannerTheme.js +6 -3
  193. package/lib/module/surfaces/resolveBannerTheme.js.map +1 -1
  194. package/lib/module/surfaces/tooltip/TooltipBubble.js +3 -2
  195. package/lib/module/surfaces/tooltip/TooltipBubble.js.map +1 -1
  196. package/lib/module/surfaces/tooltip/targetSearchSchedule.js +128 -0
  197. package/lib/module/surfaces/tooltip/targetSearchSchedule.js.map +1 -0
  198. package/lib/module/version.js +1 -1
  199. package/lib/typescript/commonjs/src/anchors/AutoAnchorRegistry.d.ts +36 -2
  200. package/lib/typescript/commonjs/src/anchors/AutoAnchorRegistry.d.ts.map +1 -1
  201. package/lib/typescript/commonjs/src/anchors/animationFrame.d.ts +0 -4
  202. package/lib/typescript/commonjs/src/anchors/animationFrame.d.ts.map +1 -1
  203. package/lib/typescript/commonjs/src/anchors/appActive.d.ts +8 -0
  204. package/lib/typescript/commonjs/src/anchors/appActive.d.ts.map +1 -0
  205. package/lib/typescript/commonjs/src/anchors/elementTapMonitor.d.ts +17 -0
  206. package/lib/typescript/commonjs/src/anchors/elementTapMonitor.d.ts.map +1 -1
  207. package/lib/typescript/commonjs/src/anchors/elementTargetMatch.d.ts +7 -0
  208. package/lib/typescript/commonjs/src/anchors/elementTargetMatch.d.ts.map +1 -1
  209. package/lib/typescript/commonjs/src/anchors/fiber/fiberInternals.d.ts +7 -0
  210. package/lib/typescript/commonjs/src/anchors/fiber/fiberInternals.d.ts.map +1 -1
  211. package/lib/typescript/commonjs/src/anchors/fiber/indexHostFibers.d.ts +3 -2
  212. package/lib/typescript/commonjs/src/anchors/fiber/indexHostFibers.d.ts.map +1 -1
  213. package/lib/typescript/commonjs/src/anchors/fiber/resolveFiberPath.d.ts +3 -0
  214. package/lib/typescript/commonjs/src/anchors/fiber/resolveFiberPath.d.ts.map +1 -1
  215. package/lib/typescript/commonjs/src/anchors/fiberAnchorCache.d.ts +5 -0
  216. package/lib/typescript/commonjs/src/anchors/fiberAnchorCache.d.ts.map +1 -1
  217. package/lib/typescript/commonjs/src/anchors/gestureHandlerHandoff.d.ts +70 -0
  218. package/lib/typescript/commonjs/src/anchors/gestureHandlerHandoff.d.ts.map +1 -0
  219. package/lib/typescript/commonjs/src/anchors/resolveAnchorHost.d.ts +1 -0
  220. package/lib/typescript/commonjs/src/anchors/resolveAnchorHost.d.ts.map +1 -1
  221. package/lib/typescript/commonjs/src/anchors/resolveAutoAnchorHost.d.ts +11 -4
  222. package/lib/typescript/commonjs/src/anchors/resolveAutoAnchorHost.d.ts.map +1 -1
  223. package/lib/typescript/commonjs/src/anchors/resolveElementTargets.d.ts.map +1 -1
  224. package/lib/typescript/commonjs/src/anchors/semanticMatcher.d.ts +2 -0
  225. package/lib/typescript/commonjs/src/anchors/semanticMatcher.d.ts.map +1 -1
  226. package/lib/typescript/commonjs/src/anchors/tapSlop.d.ts +9 -0
  227. package/lib/typescript/commonjs/src/anchors/tapSlop.d.ts.map +1 -0
  228. package/lib/typescript/commonjs/src/anchors/targetPressMonitor.d.ts +13 -8
  229. package/lib/typescript/commonjs/src/anchors/targetPressMonitor.d.ts.map +1 -1
  230. package/lib/typescript/commonjs/src/authoring/fingerprintFromInstance.d.ts.map +1 -1
  231. package/lib/typescript/commonjs/src/content/RichContentRenderer.d.ts.map +1 -1
  232. package/lib/typescript/commonjs/src/content/openSafeUrl.d.ts.map +1 -1
  233. package/lib/typescript/commonjs/src/expo-router/useUserflowExpoRouter.d.ts.map +1 -1
  234. package/lib/typescript/commonjs/src/index.d.ts +6 -5
  235. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  236. package/lib/typescript/commonjs/src/installCheck.d.ts +1 -1
  237. package/lib/typescript/commonjs/src/installCheck.d.ts.map +1 -1
  238. package/lib/typescript/commonjs/src/navigation/navigateUrlUtils.d.ts +15 -0
  239. package/lib/typescript/commonjs/src/navigation/navigateUrlUtils.d.ts.map +1 -0
  240. package/lib/typescript/commonjs/src/navigation/openExternalNavigateUrl.d.ts +3 -0
  241. package/lib/typescript/commonjs/src/navigation/openExternalNavigateUrl.d.ts.map +1 -0
  242. package/lib/typescript/commonjs/src/navigation/openFlowNavigateUrl.d.ts +2 -5
  243. package/lib/typescript/commonjs/src/navigation/openFlowNavigateUrl.d.ts.map +1 -1
  244. package/lib/typescript/commonjs/src/pairing/PairingController.d.ts +6 -0
  245. package/lib/typescript/commonjs/src/pairing/PairingController.d.ts.map +1 -1
  246. package/lib/typescript/commonjs/src/runtime/BannerHost.d.ts.map +1 -1
  247. package/lib/typescript/commonjs/src/runtime/TargetPressBridge.d.ts +3 -0
  248. package/lib/typescript/commonjs/src/runtime/TargetPressBridge.d.ts.map +1 -1
  249. package/lib/typescript/commonjs/src/runtime/UserflowOverlay.d.ts.map +1 -1
  250. package/lib/typescript/commonjs/src/runtime/UserflowProvider.d.ts.map +1 -1
  251. package/lib/typescript/commonjs/src/runtime/bannerEngine.d.ts +5 -1
  252. package/lib/typescript/commonjs/src/runtime/bannerEngine.d.ts.map +1 -1
  253. package/lib/typescript/commonjs/src/runtime/bannerFlowSpacer.d.ts +15 -0
  254. package/lib/typescript/commonjs/src/runtime/bannerFlowSpacer.d.ts.map +1 -0
  255. package/lib/typescript/commonjs/src/runtime/flowEngine.d.ts.map +1 -1
  256. package/lib/typescript/commonjs/src/runtime/previewStart.d.ts +13 -0
  257. package/lib/typescript/commonjs/src/runtime/previewStart.d.ts.map +1 -0
  258. package/lib/typescript/commonjs/src/runtime/pushBannerLayoutContext.d.ts +17 -0
  259. package/lib/typescript/commonjs/src/runtime/pushBannerLayoutContext.d.ts.map +1 -0
  260. package/lib/typescript/commonjs/src/screenTracker.d.ts +6 -0
  261. package/lib/typescript/commonjs/src/screenTracker.d.ts.map +1 -1
  262. package/lib/typescript/commonjs/src/surfaces/BannerBar.d.ts +3 -1
  263. package/lib/typescript/commonjs/src/surfaces/BannerBar.d.ts.map +1 -1
  264. package/lib/typescript/commonjs/src/surfaces/BannerSurface.d.ts +5 -1
  265. package/lib/typescript/commonjs/src/surfaces/BannerSurface.d.ts.map +1 -1
  266. package/lib/typescript/commonjs/src/surfaces/TooltipSurface.d.ts +1 -1
  267. package/lib/typescript/commonjs/src/surfaces/TooltipSurface.d.ts.map +1 -1
  268. package/lib/typescript/commonjs/src/surfaces/bannerBarLayout.d.ts +17 -0
  269. package/lib/typescript/commonjs/src/surfaces/bannerBarLayout.d.ts.map +1 -1
  270. package/lib/typescript/commonjs/src/surfaces/bannerWebView/BannerWebViewBar.d.ts +3 -1
  271. package/lib/typescript/commonjs/src/surfaces/bannerWebView/BannerWebViewBar.d.ts.map +1 -1
  272. package/lib/typescript/commonjs/src/surfaces/bannerWebView/buildCustomBannerHtml.d.ts.map +1 -1
  273. package/lib/typescript/commonjs/src/surfaces/hostAccessibilityTrap.d.ts +14 -0
  274. package/lib/typescript/commonjs/src/surfaces/hostAccessibilityTrap.d.ts.map +1 -0
  275. package/lib/typescript/commonjs/src/surfaces/resolveBannerTheme.d.ts +4 -1
  276. package/lib/typescript/commonjs/src/surfaces/resolveBannerTheme.d.ts.map +1 -1
  277. package/lib/typescript/commonjs/src/surfaces/tooltip/TooltipBubble.d.ts +7 -1
  278. package/lib/typescript/commonjs/src/surfaces/tooltip/TooltipBubble.d.ts.map +1 -1
  279. package/lib/typescript/commonjs/src/surfaces/tooltip/targetSearchSchedule.d.ts +60 -0
  280. package/lib/typescript/commonjs/src/surfaces/tooltip/targetSearchSchedule.d.ts.map +1 -0
  281. package/lib/typescript/commonjs/src/version.d.ts +1 -1
  282. package/lib/typescript/module/src/anchors/AutoAnchorRegistry.d.ts +36 -2
  283. package/lib/typescript/module/src/anchors/AutoAnchorRegistry.d.ts.map +1 -1
  284. package/lib/typescript/module/src/anchors/animationFrame.d.ts +0 -4
  285. package/lib/typescript/module/src/anchors/animationFrame.d.ts.map +1 -1
  286. package/lib/typescript/module/src/anchors/appActive.d.ts +8 -0
  287. package/lib/typescript/module/src/anchors/appActive.d.ts.map +1 -0
  288. package/lib/typescript/module/src/anchors/elementTapMonitor.d.ts +17 -0
  289. package/lib/typescript/module/src/anchors/elementTapMonitor.d.ts.map +1 -1
  290. package/lib/typescript/module/src/anchors/elementTargetMatch.d.ts +7 -0
  291. package/lib/typescript/module/src/anchors/elementTargetMatch.d.ts.map +1 -1
  292. package/lib/typescript/module/src/anchors/fiber/fiberInternals.d.ts +7 -0
  293. package/lib/typescript/module/src/anchors/fiber/fiberInternals.d.ts.map +1 -1
  294. package/lib/typescript/module/src/anchors/fiber/indexHostFibers.d.ts +3 -2
  295. package/lib/typescript/module/src/anchors/fiber/indexHostFibers.d.ts.map +1 -1
  296. package/lib/typescript/module/src/anchors/fiber/resolveFiberPath.d.ts +3 -0
  297. package/lib/typescript/module/src/anchors/fiber/resolveFiberPath.d.ts.map +1 -1
  298. package/lib/typescript/module/src/anchors/fiberAnchorCache.d.ts +5 -0
  299. package/lib/typescript/module/src/anchors/fiberAnchorCache.d.ts.map +1 -1
  300. package/lib/typescript/module/src/anchors/gestureHandlerHandoff.d.ts +70 -0
  301. package/lib/typescript/module/src/anchors/gestureHandlerHandoff.d.ts.map +1 -0
  302. package/lib/typescript/module/src/anchors/resolveAnchorHost.d.ts +1 -0
  303. package/lib/typescript/module/src/anchors/resolveAnchorHost.d.ts.map +1 -1
  304. package/lib/typescript/module/src/anchors/resolveAutoAnchorHost.d.ts +11 -4
  305. package/lib/typescript/module/src/anchors/resolveAutoAnchorHost.d.ts.map +1 -1
  306. package/lib/typescript/module/src/anchors/resolveElementTargets.d.ts.map +1 -1
  307. package/lib/typescript/module/src/anchors/semanticMatcher.d.ts +2 -0
  308. package/lib/typescript/module/src/anchors/semanticMatcher.d.ts.map +1 -1
  309. package/lib/typescript/module/src/anchors/tapSlop.d.ts +9 -0
  310. package/lib/typescript/module/src/anchors/tapSlop.d.ts.map +1 -0
  311. package/lib/typescript/module/src/anchors/targetPressMonitor.d.ts +13 -8
  312. package/lib/typescript/module/src/anchors/targetPressMonitor.d.ts.map +1 -1
  313. package/lib/typescript/module/src/authoring/fingerprintFromInstance.d.ts.map +1 -1
  314. package/lib/typescript/module/src/content/RichContentRenderer.d.ts.map +1 -1
  315. package/lib/typescript/module/src/content/openSafeUrl.d.ts.map +1 -1
  316. package/lib/typescript/module/src/expo-router/useUserflowExpoRouter.d.ts.map +1 -1
  317. package/lib/typescript/module/src/index.d.ts +6 -5
  318. package/lib/typescript/module/src/index.d.ts.map +1 -1
  319. package/lib/typescript/module/src/installCheck.d.ts +1 -1
  320. package/lib/typescript/module/src/installCheck.d.ts.map +1 -1
  321. package/lib/typescript/module/src/navigation/navigateUrlUtils.d.ts +15 -0
  322. package/lib/typescript/module/src/navigation/navigateUrlUtils.d.ts.map +1 -0
  323. package/lib/typescript/module/src/navigation/openExternalNavigateUrl.d.ts +3 -0
  324. package/lib/typescript/module/src/navigation/openExternalNavigateUrl.d.ts.map +1 -0
  325. package/lib/typescript/module/src/navigation/openFlowNavigateUrl.d.ts +2 -5
  326. package/lib/typescript/module/src/navigation/openFlowNavigateUrl.d.ts.map +1 -1
  327. package/lib/typescript/module/src/pairing/PairingController.d.ts +6 -0
  328. package/lib/typescript/module/src/pairing/PairingController.d.ts.map +1 -1
  329. package/lib/typescript/module/src/runtime/BannerHost.d.ts.map +1 -1
  330. package/lib/typescript/module/src/runtime/TargetPressBridge.d.ts +3 -0
  331. package/lib/typescript/module/src/runtime/TargetPressBridge.d.ts.map +1 -1
  332. package/lib/typescript/module/src/runtime/UserflowOverlay.d.ts.map +1 -1
  333. package/lib/typescript/module/src/runtime/UserflowProvider.d.ts.map +1 -1
  334. package/lib/typescript/module/src/runtime/bannerEngine.d.ts +5 -1
  335. package/lib/typescript/module/src/runtime/bannerEngine.d.ts.map +1 -1
  336. package/lib/typescript/module/src/runtime/bannerFlowSpacer.d.ts +15 -0
  337. package/lib/typescript/module/src/runtime/bannerFlowSpacer.d.ts.map +1 -0
  338. package/lib/typescript/module/src/runtime/flowEngine.d.ts.map +1 -1
  339. package/lib/typescript/module/src/runtime/previewStart.d.ts +13 -0
  340. package/lib/typescript/module/src/runtime/previewStart.d.ts.map +1 -0
  341. package/lib/typescript/module/src/runtime/pushBannerLayoutContext.d.ts +17 -0
  342. package/lib/typescript/module/src/runtime/pushBannerLayoutContext.d.ts.map +1 -0
  343. package/lib/typescript/module/src/screenTracker.d.ts +6 -0
  344. package/lib/typescript/module/src/screenTracker.d.ts.map +1 -1
  345. package/lib/typescript/module/src/surfaces/BannerBar.d.ts +3 -1
  346. package/lib/typescript/module/src/surfaces/BannerBar.d.ts.map +1 -1
  347. package/lib/typescript/module/src/surfaces/BannerSurface.d.ts +5 -1
  348. package/lib/typescript/module/src/surfaces/BannerSurface.d.ts.map +1 -1
  349. package/lib/typescript/module/src/surfaces/TooltipSurface.d.ts +1 -1
  350. package/lib/typescript/module/src/surfaces/TooltipSurface.d.ts.map +1 -1
  351. package/lib/typescript/module/src/surfaces/bannerBarLayout.d.ts +17 -0
  352. package/lib/typescript/module/src/surfaces/bannerBarLayout.d.ts.map +1 -1
  353. package/lib/typescript/module/src/surfaces/bannerWebView/BannerWebViewBar.d.ts +3 -1
  354. package/lib/typescript/module/src/surfaces/bannerWebView/BannerWebViewBar.d.ts.map +1 -1
  355. package/lib/typescript/module/src/surfaces/bannerWebView/buildCustomBannerHtml.d.ts.map +1 -1
  356. package/lib/typescript/module/src/surfaces/hostAccessibilityTrap.d.ts +14 -0
  357. package/lib/typescript/module/src/surfaces/hostAccessibilityTrap.d.ts.map +1 -0
  358. package/lib/typescript/module/src/surfaces/resolveBannerTheme.d.ts +4 -1
  359. package/lib/typescript/module/src/surfaces/resolveBannerTheme.d.ts.map +1 -1
  360. package/lib/typescript/module/src/surfaces/tooltip/TooltipBubble.d.ts +7 -1
  361. package/lib/typescript/module/src/surfaces/tooltip/TooltipBubble.d.ts.map +1 -1
  362. package/lib/typescript/module/src/surfaces/tooltip/targetSearchSchedule.d.ts +60 -0
  363. package/lib/typescript/module/src/surfaces/tooltip/targetSearchSchedule.d.ts.map +1 -0
  364. package/lib/typescript/module/src/version.d.ts +1 -1
  365. package/package.json +1 -1
  366. package/src/anchors/AutoAnchorRegistry.ts +166 -35
  367. package/src/anchors/animationFrame.ts +31 -1
  368. package/src/anchors/appActive.ts +63 -0
  369. package/src/anchors/elementConditionEvaluator.ts +29 -12
  370. package/src/anchors/elementTapMonitor.ts +68 -10
  371. package/src/anchors/elementTargetMatch.ts +34 -7
  372. package/src/anchors/fiber/fiberInternals.ts +68 -0
  373. package/src/anchors/fiber/indexHostFibers.ts +8 -3
  374. package/src/anchors/fiber/resolveFiberPath.ts +25 -16
  375. package/src/anchors/fiberAnchorCache.ts +19 -0
  376. package/src/anchors/gestureHandlerHandoff.ts +356 -0
  377. package/src/anchors/resolveAnchorHost.ts +2 -0
  378. package/src/anchors/resolveAutoAnchorHost.ts +18 -8
  379. package/src/anchors/resolveElementTargets.ts +64 -7
  380. package/src/anchors/semanticMatcher.ts +48 -27
  381. package/src/anchors/tapSlop.ts +18 -0
  382. package/src/anchors/targetPressMonitor.ts +56 -19
  383. package/src/authoring/fingerprintFromInstance.ts +4 -5
  384. package/src/content/RichContentRenderer.tsx +4 -3
  385. package/src/content/openSafeUrl.ts +3 -1
  386. package/src/expo-router/useUserflowExpoRouter.ts +10 -1
  387. package/src/index.ts +20 -9
  388. package/src/installCheck.ts +4 -4
  389. package/src/navigation/navigateUrlUtils.ts +100 -0
  390. package/src/navigation/openExternalNavigateUrl.ts +9 -0
  391. package/src/navigation/openFlowNavigateUrl.ts +36 -36
  392. package/src/pairing/PairingController.ts +9 -1
  393. package/src/runtime/BannerHost.tsx +41 -23
  394. package/src/runtime/TargetPressBridge.tsx +66 -9
  395. package/src/runtime/UserflowOverlay.tsx +7 -9
  396. package/src/runtime/UserflowProvider.tsx +56 -32
  397. package/src/runtime/bannerEngine.ts +10 -2
  398. package/src/runtime/bannerFlowSpacer.tsx +70 -0
  399. package/src/runtime/flowEngine.ts +11 -0
  400. package/src/runtime/previewStart.ts +49 -0
  401. package/src/runtime/pushBannerLayoutContext.tsx +121 -0
  402. package/src/screenTracker.ts +11 -0
  403. package/src/surfaces/BannerBar.tsx +93 -55
  404. package/src/surfaces/BannerSurface.tsx +59 -3
  405. package/src/surfaces/TooltipSurface.tsx +63 -51
  406. package/src/surfaces/bannerBarLayout.ts +80 -7
  407. package/src/surfaces/bannerWebView/BannerWebViewBar.tsx +149 -57
  408. package/src/surfaces/bannerWebView/buildCustomBannerHtml.ts +63 -11
  409. package/src/surfaces/hostAccessibilityTrap.ts +25 -0
  410. package/src/surfaces/resolveBannerTheme.ts +14 -3
  411. package/src/surfaces/tooltip/TooltipBubble.tsx +8 -1
  412. package/src/surfaces/tooltip/targetSearchSchedule.ts +140 -0
  413. package/src/version.ts +1 -1
  414. package/vendor/core/dist/engine/BannerSessionEngine.d.ts +29 -2
  415. package/vendor/core/dist/engine/BannerSessionEngine.d.ts.map +1 -1
  416. package/vendor/core/dist/engine/BannerSessionEngine.js +87 -6
  417. package/vendor/core/dist/engine/BannerSessionEngine.js.map +1 -1
  418. package/vendor/core/dist/engine/ClientConditionEngine.d.ts.map +1 -1
  419. package/vendor/core/dist/engine/ClientConditionEngine.js +30 -7
  420. package/vendor/core/dist/engine/ClientConditionEngine.js.map +1 -1
  421. package/vendor/core/dist/engine/PairingEngine.d.ts +6 -1
  422. package/vendor/core/dist/engine/PairingEngine.d.ts.map +1 -1
  423. package/vendor/core/dist/engine/PairingEngine.js +23 -3
  424. package/vendor/core/dist/engine/PairingEngine.js.map +1 -1
  425. package/vendor/core/dist/engine/handleActions.d.ts.map +1 -1
  426. package/vendor/core/dist/engine/handleActions.js +67 -2
  427. package/vendor/core/dist/engine/handleActions.js.map +1 -1
  428. package/vendor/core/dist/version.d.ts +1 -1
  429. package/vendor/core/dist/version.js +1 -1
  430. package/vendor/core/package.json +1 -1
  431. package/vendor/protocol/package.json +1 -1
@@ -1,3 +1,8 @@
1
+ import { gestureHandlerHandoff } from './gestureHandlerHandoff';
2
+ import { TARGET_PRESS_TAP_SLOP, type TouchPoint, withinTapSlop } from './tapSlop';
3
+
4
+ export { TARGET_PRESS_TAP_SLOP, type TouchPoint, withinTapSlop };
5
+
1
6
  /**
2
7
  * Active tooltip target-press subscription.
3
8
  *
@@ -19,29 +24,10 @@ export interface TargetPressSubscription {
19
24
  onPress: () => void;
20
25
  }
21
26
 
22
- /** Max finger travel (px) between start and end to count as a tap, not a scroll. */
23
- export const TARGET_PRESS_TAP_SLOP = 10;
24
-
25
27
  export function pointInRect(x: number, y: number, rect: TargetPressRect): boolean {
26
28
  return x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height;
27
29
  }
28
30
 
29
- export interface TouchPoint {
30
- pageX: number;
31
- pageY: number;
32
- }
33
-
34
- /** True when the finger moved no more than `slop` between start and end. */
35
- export function withinTapSlop(
36
- start: TouchPoint,
37
- end: TouchPoint,
38
- slop: number = TARGET_PRESS_TAP_SLOP,
39
- ): boolean {
40
- const dx = end.pageX - start.pageX;
41
- const dy = end.pageY - start.pageY;
42
- return dx * dx + dy * dy <= slop * slop;
43
- }
44
-
45
31
  /**
46
32
  * True when start and end both land in `rect` and movement stays within tap
47
33
  * slop — mirrors a DOM click on the target without claiming the responder.
@@ -70,14 +56,25 @@ export type TouchIdentifier = number | string;
70
56
  export class TargetPressMonitor {
71
57
  private subscription: TargetPressSubscription | null = null;
72
58
  private touchStarts = new Map<TouchIdentifier, TouchPoint>();
59
+ private handoffStops = new Map<TouchIdentifier, () => void>();
73
60
 
74
61
  set(subscription: TargetPressSubscription | null): void {
75
62
  this.subscription = subscription;
76
63
  if (!subscription) {
77
64
  this.touchStarts.clear();
65
+ this.dropHandoffs();
78
66
  }
79
67
  }
80
68
 
69
+ /** Fingers with a recorded start that have not ended, cancelled, or been handed off. */
70
+ inProgressIdentifiers(): TouchIdentifier[] {
71
+ return [...this.touchStarts.keys()];
72
+ }
73
+
74
+ hasTouch(identifier: TouchIdentifier): boolean {
75
+ return this.touchStarts.has(identifier);
76
+ }
77
+
81
78
  clear(): void {
82
79
  this.set(null);
83
80
  }
@@ -113,6 +110,38 @@ export class TargetPressMonitor {
113
110
  }
114
111
  }
115
112
 
113
+ /**
114
+ * Gesture-handler cancelled this finger. Press if that handler later ends as
115
+ * a tap and the start (and the end, when the payload has one) is inside the
116
+ * current target rect.
117
+ */
118
+ handOffTouch(identifier: TouchIdentifier, handlerTags: readonly number[]): void {
119
+ const start = this.touchStarts.get(identifier);
120
+ if (!start) return;
121
+ this.touchStarts.delete(identifier);
122
+ this.handoffStops.get(identifier)?.();
123
+ if (!this.subscription || handlerTags.length === 0) return;
124
+ const stop = gestureHandlerHandoff.track({
125
+ identifier,
126
+ pageX: start.pageX,
127
+ pageY: start.pageY,
128
+ handlerTags,
129
+ onResolve: (end) => {
130
+ const sub = this.subscription;
131
+ if (!sub) return;
132
+ const rect = sub.getRect();
133
+ if (!rect || rect.width <= 0 || rect.height <= 0) return;
134
+ if (!pointInRect(start.pageX, start.pageY, rect)) return;
135
+ if (end && !pointInRect(end.pageX, end.pageY, rect)) return;
136
+ sub.onPress();
137
+ },
138
+ });
139
+ this.handoffStops.set(identifier, () => {
140
+ stop();
141
+ this.handoffStops.delete(identifier);
142
+ });
143
+ }
144
+
116
145
  /**
117
146
  * Drop in-progress gesture(s). With `identifier`, cancels that finger only;
118
147
  * otherwise clears all (e.g. blanket `onTouchCancel`).
@@ -120,15 +149,23 @@ export class TargetPressMonitor {
120
149
  cancelTouch(identifier?: TouchIdentifier): void {
121
150
  if (identifier == null) {
122
151
  this.touchStarts.clear();
152
+ this.dropHandoffs();
123
153
  return;
124
154
  }
125
155
  this.touchStarts.delete(identifier);
156
+ this.handoffStops.get(identifier)?.();
126
157
  }
127
158
 
128
159
  /** Test helper. */
129
160
  resetForTests(): void {
130
161
  this.subscription = null;
131
162
  this.touchStarts.clear();
163
+ this.dropHandoffs();
164
+ }
165
+
166
+ private dropHandoffs(): void {
167
+ for (const stop of this.handoffStops.values()) stop();
168
+ this.handoffStops.clear();
132
169
  }
133
170
  }
134
171
 
@@ -16,7 +16,7 @@ import { fibersMatch, resolveFiberPath } from '../anchors/fiber/resolveFiberPath
16
16
  import { createVisibleInstanceFilter } from '../anchors/isInstanceOnVisibleScreen';
17
17
  import * as semanticMatcher from '../anchors/semanticMatcher';
18
18
  import type { MatchMissReason } from '../anchors/semanticMatcher';
19
- import { getCurrentScreenLocation } from '../screenTracker';
19
+ import { getCurrentScreenLocation, screenIdFromLocation } from '../screenTracker';
20
20
 
21
21
  import type { PickTarget } from './hitTest';
22
22
 
@@ -35,10 +35,9 @@ function deriveIdentityStrength(inst: AutoAnchorInstance): IdentityStrength {
35
35
  }
36
36
 
37
37
  function screenFromLocation(): { screenId: string; screenName?: string } {
38
- const location = getCurrentScreenLocation();
39
- if (!location) return { screenId: 'unknown' };
40
- if ('path' in location) return { screenId: location.path, screenName: location.path };
41
- return { screenId: location.screen, screenName: location.screen };
38
+ const screenId = screenIdFromLocation(getCurrentScreenLocation());
39
+ if (screenId === 'unknown') return { screenId };
40
+ return { screenId, screenName: screenId };
42
41
  }
43
42
 
44
43
  function deviceMetadata(): DeviceMetadata | undefined {
@@ -8,6 +8,8 @@ import * as React from 'react';
8
8
  import type { TextStyle, ViewStyle } from 'react-native';
9
9
  import { Image, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
10
10
 
11
+ import { openFlowNavigateUrl } from '../navigation/openFlowNavigateUrl';
12
+
11
13
  import { StepButton } from './StepButton';
12
14
  import {
13
15
  deserializeRichContentDoc,
@@ -17,7 +19,6 @@ import {
17
19
  } from './deserialize';
18
20
  import { resolveImageFrame } from './imageLayout';
19
21
  import { migrateFlowBlocksIntoContent } from './migrateFlowBlocks';
20
- import { openSafeUrl } from './openSafeUrl';
21
22
  import {
22
23
  ROOT_CONTENT_GAP,
23
24
  WEB_CODE_BG_ALPHA,
@@ -401,7 +402,7 @@ function RenderedLink({
401
402
  accessibilityRole="link"
402
403
  accessibilityHint={href || undefined}
403
404
  onPress={() => {
404
- void openSafeUrl(href);
405
+ void openFlowNavigateUrl(href);
405
406
  }}
406
407
  >
407
408
  <InlineChildren
@@ -480,7 +481,7 @@ function RenderedImage({
480
481
  accessibilityRole="link"
481
482
  accessibilityLabel="Image link"
482
483
  onPress={() => {
483
- void openSafeUrl(href);
484
+ void openFlowNavigateUrl(href);
484
485
  }}
485
486
  >
486
487
  {framed}
@@ -15,7 +15,9 @@ export function isSafeUrl(url: string | null | undefined): boolean {
15
15
  const parsed = new URL(trimmed);
16
16
  return ALLOWED_PROTOCOLS.has(parsed.protocol);
17
17
  } catch {
18
- return false;
18
+ // Hermes / older runtimes can lack a full URL implementation; still allow
19
+ // obvious http(s) strings so NAVIGATE does not fall through to Expo Router.
20
+ return /^https?:\/\//i.test(trimmed);
19
21
  }
20
22
  }
21
23
 
@@ -6,7 +6,11 @@ import {
6
6
  readNavigationPresentation,
7
7
  subscribeNavigationState,
8
8
  } from '../navigation/isOverlayPresentation';
9
- import { setExpoRouterNavigator } from '../navigation/openFlowNavigateUrl';
9
+ import {
10
+ mustNotUseExpoRouterPush,
11
+ shouldOpenExternalNavigateUrl,
12
+ } from '../navigation/navigateUrlUtils';
13
+ import { openFlowNavigateUrl, setExpoRouterNavigator } from '../navigation/openFlowNavigateUrl';
10
14
  import { handleScreenChange } from '../screenTracker';
11
15
 
12
16
  /**
@@ -73,6 +77,11 @@ export function useUserflowExpoRouter(): void {
73
77
  useEffect(() => {
74
78
  setExpoRouterNavigator({
75
79
  push: (href) => {
80
+ const trimmed = String(href).trim();
81
+ if (mustNotUseExpoRouterPush(trimmed) || shouldOpenExternalNavigateUrl(trimmed)) {
82
+ void openFlowNavigateUrl(trimmed);
83
+ return;
84
+ }
76
85
  router.push(href as never);
77
86
  },
78
87
  });
package/src/index.ts CHANGED
@@ -80,13 +80,13 @@ import {
80
80
  attachFlowSessionEngine,
81
81
  cancelPendingDraftEnd,
82
82
  clearFlowSessionEngineLocalSession,
83
- endDraftFlowSession,
84
83
  endEvalJsFlowSession,
85
84
  getFlowSessionEngine,
86
85
  hasActiveFlowSession,
87
86
  resetFlowSessionEngine,
88
87
  } from './runtime/flowEngine';
89
88
  import { isolateAsync, isolateSync } from './runtime/isolateCall';
89
+ import { endDraftPreviewSessions, prepareForBuilderPreviewStart } from './runtime/previewStart';
90
90
  import { getUserflowCore } from './runtime/userflowCore';
91
91
  import {
92
92
  disableScreenTracking,
@@ -100,7 +100,9 @@ import {
100
100
  } from './screenTracker';
101
101
  import { setSurfaceInteractionBlocking as setSurfaceInteractionBlockingConfig } from './surfaces/surfaceInteractionConfig';
102
102
 
103
- export { SDK_VERSION } from './version';
103
+ import { SDK_VERSION } from './version';
104
+
105
+ export { SDK_VERSION };
104
106
  export type { DeviceContext, DeviceOs, DeviceType, SdkPlatform } from './deviceContext';
105
107
  export type { HostAppVersion, HostAppVersionSource } from './hostAppVersion';
106
108
  export { EmbedBannerPlaceholder } from './runtime/EmbedBannerPlaceholder';
@@ -141,8 +143,8 @@ export type {
141
143
  /** Configuration passed to {@link Userflow.init}. */
142
144
  export type UserflowInitConfig = UserflowInitOptions & {
143
145
  /**
144
- * Optional host handler for flow NAVIGATE actions. When set, wins over
145
- * React Navigation / Expo Router / Linking.
146
+ * Optional host handler for flow and banner NAVIGATE actions. When set, wins
147
+ * over React Navigation / Expo Router / Linking.
146
148
  */
147
149
  onNavigate?: FlowNavigateHandler;
148
150
  /**
@@ -297,6 +299,10 @@ export const Userflow = {
297
299
  ...(config.appBuild !== undefined ? { appBuild: config.appBuild } : {}),
298
300
  });
299
301
  warnIfInstallIncomplete();
302
+ if (__DEV__) {
303
+ // eslint-disable-next-line no-console -- intentional development diagnostic
304
+ console.log(`[Userflow] react-native SDK ${SDK_VERSION} (source)`);
305
+ }
300
306
  cacheDeviceContextAtInit();
301
307
  setHostOnNavigate(config.onNavigate);
302
308
  lifecycle.start();
@@ -311,6 +317,7 @@ export const Userflow = {
311
317
  // the success path makes a failed init look like a broken deep link.
312
318
  const pairing = installPairingController(core, {
313
319
  ...(config.pairingEndpoint !== undefined ? { pairingEndpoint: config.pairingEndpoint } : {}),
320
+ prepareForBuilderPreviewStart: () => prepareForBuilderPreviewStart(core),
314
321
  clearLocalSession: () => {
315
322
  clearFlowSessionEngineLocalSession();
316
323
  core.setFlowSessionId(null);
@@ -318,7 +325,7 @@ export const Userflow = {
318
325
  core.setBannerSessionId(null);
319
326
  evalJsController.reset();
320
327
  },
321
- endDraftSession: endDraftFlowSession,
328
+ endDraftSession: endDraftPreviewSessions,
322
329
  cancelPendingDraftEnd,
323
330
  });
324
331
  pairing.notifyInitStarted();
@@ -354,8 +361,8 @@ export const Userflow = {
354
361
  return getPairingController(core).exitPreview();
355
362
  },
356
363
  /**
357
- * Override or clear the host NAVIGATE handler (same as `init({ onNavigate })`).
358
- * Wins over React Navigation / Expo Router / Linking when set.
364
+ * Override or clear the host NAVIGATE handler for flows and banners (same as
365
+ * `init({ onNavigate })`). Wins over React Navigation / Expo Router / Linking.
359
366
  */
360
367
  setOnNavigate(handler: FlowNavigateHandler | null | undefined): void {
361
368
  setHostOnNavigate(handler);
@@ -372,7 +379,9 @@ export const Userflow = {
372
379
  if (previousId != null && previousId !== userId) {
373
380
  resetClientConditionEngine();
374
381
  core.setClientConditions([]);
375
- clearBannerSessionEngineLocalSession();
382
+ clearFlowSessionEngineLocalSession();
383
+ clearBannerSessionEngineLocalSession({ rememberDraftForPreviewEnd: false });
384
+ core.setFlowSessionId(null);
376
385
  core.setBannerSessionId(null);
377
386
  evalJsController.reset();
378
387
  await clearAnonymousId();
@@ -391,7 +400,9 @@ export const Userflow = {
391
400
  if (previousId != null && previousId !== anonymousId) {
392
401
  resetClientConditionEngine();
393
402
  core.setClientConditions([]);
394
- clearBannerSessionEngineLocalSession();
403
+ clearFlowSessionEngineLocalSession();
404
+ clearBannerSessionEngineLocalSession({ rememberDraftForPreviewEnd: false });
405
+ core.setFlowSessionId(null);
395
406
  core.setBannerSessionId(null);
396
407
  evalJsController.reset();
397
408
  armScreenViewedForNextIdentify();
@@ -10,7 +10,7 @@ export const INSTALL_ASYNC_STORAGE_LINE =
10
10
  '- @react-native-async-storage/async-storage is not linked. Anonymous users and Builder pairing will not persist. Add it to the app package.json (npx expo install @react-native-async-storage/async-storage), run pod install on iOS, and rebuild.';
11
11
 
12
12
  export const INSTALL_VIEW_SHOT_LINE =
13
- '- react-native-view-shot is not linked, so Builder element selection gets no screenshot. Install react-native-view-shot@^5.0.0 and rebuild. On Expo SDK 54, pin ^5.0.0; an unpinned npx expo install resolves 4.0.3.';
13
+ '- react-native-view-shot is not linked, so Builder element selection gets no screenshot. Install it and rebuild. On Expo SDK 56 and 57, run npx expo install react-native-view-shot unpinned, with no expo.install.exclude entry for it. Otherwise install react-native-view-shot@^5.0.0; on Expo SDK 55 and older, an unpinned npx expo install resolves 4.0.3.';
14
14
 
15
15
  export const INSTALL_WEBVIEW_LINE =
16
16
  '- react-native-webview is not linked. Evaluate JavaScript and WebView banners will not run. Install it (npx expo install react-native-webview) and rebuild.';
@@ -36,9 +36,9 @@ export const INSTALL_SAFE_AREA_WARNING =
36
36
  export function formatViewShotVersionWarning(version: string): string {
37
37
  return (
38
38
  `[Userflow] react-native-view-shot@${version} is older than 5.0.0, so Builder element selection may not get a screenshot. ` +
39
- 'Install react-native-view-shot@^5.0.0 in the same command as the SDK and rebuild. ' +
40
- 'Do not retry the install with --force or --legacy-peer-deps; that leaves this version in place. ' +
41
- 'On Expo SDK 54, pin ^5.0.0 and add "react-native-view-shot" to expo.install.exclude.\n' +
39
+ 'On Expo SDK 56 and 57, run npx expo install react-native-view-shot unpinned, with no expo.install.exclude entry for it, and rebuild. ' +
40
+ 'Otherwise install react-native-view-shot@^5.0.0 in the same command as the SDK and rebuild; on Expo SDK 55 and older, also add "react-native-view-shot" to expo.install.exclude. ' +
41
+ 'Do not retry the install with --force or --legacy-peer-deps; that leaves this version in place.\n' +
42
42
  INSTALL_CHECK_FOOTER
43
43
  );
44
44
  }
@@ -0,0 +1,100 @@
1
+ const ABSOLUTE_WEB_URL = /^https?:\/\//i;
2
+
3
+ /** Hostname.tld with optional port, path, query, or hash — not an in-app screen name like `Profile`. */
4
+ const BARE_EXTERNAL_HOST =
5
+ /^[\w.-]+\.[a-z]{2,}(?::\d+)?(?:\/[^\s?#]*)?(?:\?[^\s#]*)?(?:#[^\s]*)?$/i;
6
+
7
+ function isAllowlistedWebUrl(url: string): boolean {
8
+ const trimmed = url.trim();
9
+ if (!trimmed) {
10
+ return false;
11
+ }
12
+ if (!ABSOLUTE_WEB_URL.test(trimmed) && !/^mailto:/i.test(trimmed) && !/^tel:/i.test(trimmed)) {
13
+ return false;
14
+ }
15
+ try {
16
+ const parsed = new URL(trimmed);
17
+ return (
18
+ parsed.protocol === 'http:' ||
19
+ parsed.protocol === 'https:' ||
20
+ parsed.protocol === 'mailto:' ||
21
+ parsed.protocol === 'tel:'
22
+ );
23
+ } catch {
24
+ return ABSOLUTE_WEB_URL.test(trimmed);
25
+ }
26
+ }
27
+
28
+ /** Fix common builder typos before classification (`https:/google.com`). */
29
+ export function normalizeNavigateUrlInput(url: string): string {
30
+ const trimmed = url.trim();
31
+ return trimmed.replace(/^(https?):\/(?!\/)/i, '$1://');
32
+ }
33
+
34
+ /** Prefix `https://` when the builder URL omitted the scheme (e.g. `google.com`). */
35
+ export function normalizeExternalNavigateUrl(url: string): string {
36
+ const trimmed = normalizeNavigateUrlInput(url);
37
+ if (ABSOLUTE_WEB_URL.test(trimmed)) {
38
+ return trimmed;
39
+ }
40
+ if (BARE_EXTERNAL_HOST.test(trimmed) && !trimmed.startsWith('/')) {
41
+ return `https://${trimmed}`;
42
+ }
43
+ return trimmed;
44
+ }
45
+
46
+ /** True when the URL should open outside the app (browser / mail / tel). */
47
+ export function shouldOpenExternalNavigateUrl(url: string): boolean {
48
+ const trimmed = normalizeNavigateUrlInput(url);
49
+ if (!trimmed) {
50
+ return false;
51
+ }
52
+ if (isAllowlistedWebUrl(trimmed)) {
53
+ return true;
54
+ }
55
+ if (ABSOLUTE_WEB_URL.test(trimmed)) {
56
+ return true;
57
+ }
58
+ if (/^mailto:/i.test(trimmed) || /^tel:/i.test(trimmed)) {
59
+ return true;
60
+ }
61
+ if (BARE_EXTERNAL_HOST.test(trimmed) && !trimmed.startsWith('/')) {
62
+ return true;
63
+ }
64
+ return false;
65
+ }
66
+
67
+ /** True for http(s) / mailto / tel (external). */
68
+ export function isExternalNavigateUrl(url: string): boolean {
69
+ return shouldOpenExternalNavigateUrl(url);
70
+ }
71
+
72
+ /** Path-like in-app URL: leading slash, or no scheme. */
73
+ export function isInAppNavigateUrl(url: string): boolean {
74
+ const trimmed = normalizeNavigateUrlInput(url);
75
+ if (!trimmed) return false;
76
+ if (shouldOpenExternalNavigateUrl(trimmed)) return false;
77
+ if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed)) return false;
78
+ return true;
79
+ }
80
+
81
+ /** Never pass absolute / external URLs to Expo Router `push`. */
82
+ export function mustNotUseExpoRouterPush(url: string): boolean {
83
+ const trimmed = normalizeNavigateUrlInput(url);
84
+ if (!trimmed) return false;
85
+ if (shouldOpenExternalNavigateUrl(trimmed)) return true;
86
+ if (trimmed.includes('://')) return true;
87
+ return false;
88
+ }
89
+
90
+ export function normalizeInAppPath(url: string): string {
91
+ const trimmed = normalizeNavigateUrlInput(url);
92
+ if (trimmed.startsWith('/')) return trimmed;
93
+ return `/${trimmed}`;
94
+ }
95
+
96
+ export function routeNameFromPath(path: string): string {
97
+ const normalized = normalizeInAppPath(path).replace(/^\//, '');
98
+ const [first] = normalized.split(/[/?#]/);
99
+ return first || normalized;
100
+ }
@@ -0,0 +1,9 @@
1
+ import { openSafeUrl } from '../content/openSafeUrl';
2
+
3
+ import { normalizeExternalNavigateUrl } from './navigateUrlUtils';
4
+
5
+ /** Open http(s)/mailto/tel via Linking (documented SDK behavior). */
6
+ export async function openExternalNavigateUrl(url: string): Promise<void> {
7
+ const external = normalizeExternalNavigateUrl(url);
8
+ await openSafeUrl(external);
9
+ }
@@ -1,9 +1,18 @@
1
1
  import type { NavigationContainerRef, ParamListBase } from '@react-navigation/native';
2
- import { Linking } from 'react-native';
3
2
 
4
- import { isSafeUrl, openSafeUrl } from '../content/openSafeUrl';
3
+ import { isSafeUrl } from '../content/openSafeUrl';
5
4
  import { isolateAsync, isolateSync } from '../runtime/isolateCall';
6
5
 
6
+ import {
7
+ isInAppNavigateUrl,
8
+ mustNotUseExpoRouterPush,
9
+ normalizeInAppPath,
10
+ normalizeNavigateUrlInput,
11
+ routeNameFromPath,
12
+ shouldOpenExternalNavigateUrl,
13
+ } from './navigateUrlUtils';
14
+ import { openExternalNavigateUrl } from './openExternalNavigateUrl';
15
+
7
16
  export type FlowNavigateHandler = (url: string) => void | boolean | Promise<void | boolean>;
8
17
 
9
18
  export type ExpoRouterLike = {
@@ -31,38 +40,19 @@ export function setExpoRouterNavigator(router: ExpoRouterLike | null | undefined
31
40
  expoRouter = router ?? null;
32
41
  }
33
42
 
34
- /** True for http(s) / mailto / tel (external). */
35
- export function isExternalNavigateUrl(url: string): boolean {
36
- return isSafeUrl(url);
37
- }
38
-
39
- /** Path-like in-app URL: leading slash, or no scheme. */
40
- export function isInAppNavigateUrl(url: string): boolean {
41
- const trimmed = url.trim();
42
- if (!trimmed) return false;
43
- if (isExternalNavigateUrl(trimmed)) return false;
44
- if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed)) return false;
45
- return true;
46
- }
47
-
48
- function normalizeInAppPath(url: string): string {
49
- const trimmed = url.trim();
50
- if (trimmed.startsWith('/')) return trimmed;
51
- return `/${trimmed}`;
52
- }
53
-
54
- function routeNameFromPath(path: string): string {
55
- const normalized = normalizeInAppPath(path).replace(/^\//, '');
56
- const [first] = normalized.split(/[/?#]/);
57
- return first || normalized;
58
- }
43
+ export {
44
+ isExternalNavigateUrl,
45
+ isInAppNavigateUrl,
46
+ normalizeExternalNavigateUrl,
47
+ shouldOpenExternalNavigateUrl,
48
+ } from './navigateUrlUtils';
59
49
 
60
50
  /**
61
51
  * Open a flow NAVIGATE url.
62
52
  *
63
53
  * Priority:
64
54
  * 1. Host `onNavigate` (custom schemes / exotic routing)
65
- * 2. External allowlisted schemes → Linking / `openSafeUrl`
55
+ * 2. External allowlisted schemes → in-app browser / Linking
66
56
  * 3. Path-like → Expo Router `push` or React Navigation `navigate`
67
57
  * 4. Fallback → Linking (best-effort)
68
58
  *
@@ -72,9 +62,18 @@ function routeNameFromPath(path: string): string {
72
62
  * `@userflow-tech/react-native/expo-router` under `UserflowProvider`.
73
63
  */
74
64
  export async function openFlowNavigateUrl(url: string): Promise<void> {
75
- const trimmed = url.trim();
65
+ const trimmed = normalizeNavigateUrlInput(url);
76
66
  if (!trimmed) return;
77
67
 
68
+ if (__DEV__) {
69
+ // eslint-disable-next-line no-console -- intentional development diagnostic
70
+ console.log('[Userflow] NAVIGATE openFlowNavigateUrl', {
71
+ url: trimmed,
72
+ external: shouldOpenExternalNavigateUrl(trimmed),
73
+ inApp: isInAppNavigateUrl(trimmed),
74
+ });
75
+ }
76
+
78
77
  if (hostOnNavigate) {
79
78
  await isolateAsync('onNavigate', async () => {
80
79
  await hostOnNavigate!(trimmed);
@@ -82,13 +81,17 @@ export async function openFlowNavigateUrl(url: string): Promise<void> {
82
81
  return;
83
82
  }
84
83
 
85
- if (isExternalNavigateUrl(trimmed)) {
86
- await openSafeUrl(trimmed);
84
+ if (shouldOpenExternalNavigateUrl(trimmed)) {
85
+ await openExternalNavigateUrl(trimmed);
87
86
  return;
88
87
  }
89
88
 
90
89
  if (isInAppNavigateUrl(trimmed)) {
91
90
  if (expoRouter) {
91
+ if (mustNotUseExpoRouterPush(trimmed)) {
92
+ await openExternalNavigateUrl(trimmed);
93
+ return;
94
+ }
92
95
  isolateSync('onNavigate', () => {
93
96
  expoRouter!.push(normalizeInAppPath(trimmed));
94
97
  });
@@ -104,11 +107,8 @@ export async function openFlowNavigateUrl(url: string): Promise<void> {
104
107
  }
105
108
  }
106
109
 
107
- // Last resort — may fail for custom schemes; hosts should set onNavigate.
108
- try {
109
- await Linking.openURL(trimmed);
110
- } catch {
111
- // Best-effort.
110
+ if (isSafeUrl(trimmed) || /^https?:\/\//i.test(trimmed)) {
111
+ await openExternalNavigateUrl(trimmed);
112
112
  }
113
113
  }
114
114
 
@@ -46,6 +46,11 @@ export interface PairingControllerOptions {
46
46
  tokenStore?: PairingTokenStore;
47
47
  /** Clear mid-flow session when exiting preview. */
48
48
  clearLocalSession?: () => void;
49
+ /**
50
+ * Runs before a Builder preview start is sent on the end-user channel.
51
+ * Defaults to {@link clearLocalSession} when omitted.
52
+ */
53
+ prepareForBuilderPreviewStart?: () => void | Promise<void>;
49
54
  /** End the previewed draft on the server when exiting preview. */
50
55
  endDraftSession?: () => Promise<void>;
51
56
  /**
@@ -84,6 +89,7 @@ export class PairingController {
84
89
  private readonly LinkingModule: NonNullable<PairingControllerOptions['LinkingModule']>;
85
90
  private readonly AppStateModule: NonNullable<PairingControllerOptions['AppStateModule']>;
86
91
  private readonly clearLocalSession: (() => void) | undefined;
92
+ private readonly prepareForBuilderPreviewStart: (() => void | Promise<void>) | undefined;
87
93
  private readonly endDraftSession: (() => Promise<void>) | undefined;
88
94
  private readonly cancelPendingDraftEnd: (() => void) | undefined;
89
95
  private readonly core: UserflowCore;
@@ -122,6 +128,7 @@ export class PairingController {
122
128
  this.LinkingModule = options.LinkingModule ?? Linking;
123
129
  this.AppStateModule = options.AppStateModule ?? AppState;
124
130
  this.clearLocalSession = options.clearLocalSession ?? undefined;
131
+ this.prepareForBuilderPreviewStart = options.prepareForBuilderPreviewStart ?? undefined;
125
132
  this.endDraftSession = options.endDraftSession ?? undefined;
126
133
  this.cancelPendingDraftEnd = options.cancelPendingDraftEnd ?? undefined;
127
134
  this.logger = options.logger ?? defaultPairingLogger;
@@ -596,7 +603,8 @@ export class PairingController {
596
603
  ...(this.pairingDeviceId !== null ? { device_id: this.pairingDeviceId } : {}),
597
604
  }),
598
605
  onBeforePreviewStart: () => {
599
- this.clearLocalSession?.();
606
+ const run = this.prepareForBuilderPreviewStart ?? this.clearLocalSession;
607
+ return run?.();
600
608
  },
601
609
  });
602
610