@userflow-tech/react-native 0.4.5 → 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 (417) hide show
  1. package/README.md +7 -2
  2. package/docs/anchoring.md +6 -1
  3. package/docs/troubleshooting.md +26 -0
  4. package/lib/commonjs/anchors/AutoAnchorRegistry.js +144 -34
  5. package/lib/commonjs/anchors/AutoAnchorRegistry.js.map +1 -1
  6. package/lib/commonjs/anchors/animationFrame.js +29 -1
  7. package/lib/commonjs/anchors/animationFrame.js.map +1 -1
  8. package/lib/commonjs/anchors/appActive.js +61 -0
  9. package/lib/commonjs/anchors/appActive.js.map +1 -0
  10. package/lib/commonjs/anchors/elementConditionEvaluator.js +25 -8
  11. package/lib/commonjs/anchors/elementConditionEvaluator.js.map +1 -1
  12. package/lib/commonjs/anchors/elementTapMonitor.js +67 -12
  13. package/lib/commonjs/anchors/elementTapMonitor.js.map +1 -1
  14. package/lib/commonjs/anchors/elementTargetMatch.js +33 -7
  15. package/lib/commonjs/anchors/elementTargetMatch.js.map +1 -1
  16. package/lib/commonjs/anchors/fiber/fiberInternals.js +66 -0
  17. package/lib/commonjs/anchors/fiber/fiberInternals.js.map +1 -1
  18. package/lib/commonjs/anchors/fiber/indexHostFibers.js +4 -3
  19. package/lib/commonjs/anchors/fiber/indexHostFibers.js.map +1 -1
  20. package/lib/commonjs/anchors/fiber/resolveFiberPath.js +30 -15
  21. package/lib/commonjs/anchors/fiber/resolveFiberPath.js.map +1 -1
  22. package/lib/commonjs/anchors/fiberAnchorCache.js +20 -0
  23. package/lib/commonjs/anchors/fiberAnchorCache.js.map +1 -1
  24. package/lib/commonjs/anchors/gestureHandlerHandoff.js +304 -0
  25. package/lib/commonjs/anchors/gestureHandlerHandoff.js.map +1 -0
  26. package/lib/commonjs/anchors/resolveAnchorHost.js +6 -0
  27. package/lib/commonjs/anchors/resolveAnchorHost.js.map +1 -1
  28. package/lib/commonjs/anchors/resolveAutoAnchorHost.js +11 -6
  29. package/lib/commonjs/anchors/resolveAutoAnchorHost.js.map +1 -1
  30. package/lib/commonjs/anchors/resolveElementTargets.js +63 -8
  31. package/lib/commonjs/anchors/resolveElementTargets.js.map +1 -1
  32. package/lib/commonjs/anchors/semanticMatcher.js +43 -21
  33. package/lib/commonjs/anchors/semanticMatcher.js.map +1 -1
  34. package/lib/commonjs/anchors/tapSlop.js +16 -0
  35. package/lib/commonjs/anchors/tapSlop.js.map +1 -0
  36. package/lib/commonjs/anchors/targetPressMonitor.js +66 -12
  37. package/lib/commonjs/anchors/targetPressMonitor.js.map +1 -1
  38. package/lib/commonjs/authoring/fingerprintFromInstance.js +5 -9
  39. package/lib/commonjs/authoring/fingerprintFromInstance.js.map +1 -1
  40. package/lib/commonjs/content/RichContentRenderer.js +3 -3
  41. package/lib/commonjs/content/RichContentRenderer.js.map +1 -1
  42. package/lib/commonjs/content/openSafeUrl.js +3 -1
  43. package/lib/commonjs/content/openSafeUrl.js.map +1 -1
  44. package/lib/commonjs/expo-router/useUserflowExpoRouter.js +6 -0
  45. package/lib/commonjs/expo-router/useUserflowExpoRouter.js.map +1 -1
  46. package/lib/commonjs/index.js +19 -5
  47. package/lib/commonjs/index.js.map +1 -1
  48. package/lib/commonjs/navigation/navigateUrlUtils.js +105 -0
  49. package/lib/commonjs/navigation/navigateUrlUtils.js.map +1 -0
  50. package/lib/commonjs/navigation/openExternalNavigateUrl.js +14 -0
  51. package/lib/commonjs/navigation/openExternalNavigateUrl.js.map +1 -0
  52. package/lib/commonjs/navigation/openFlowNavigateUrl.js +47 -41
  53. package/lib/commonjs/navigation/openFlowNavigateUrl.js.map +1 -1
  54. package/lib/commonjs/pairing/PairingController.js +3 -1
  55. package/lib/commonjs/pairing/PairingController.js.map +1 -1
  56. package/lib/commonjs/runtime/BannerHost.js +38 -29
  57. package/lib/commonjs/runtime/BannerHost.js.map +1 -1
  58. package/lib/commonjs/runtime/TargetPressBridge.js +55 -7
  59. package/lib/commonjs/runtime/TargetPressBridge.js.map +1 -1
  60. package/lib/commonjs/runtime/UserflowOverlay.js +5 -11
  61. package/lib/commonjs/runtime/UserflowOverlay.js.map +1 -1
  62. package/lib/commonjs/runtime/UserflowProvider.js +66 -40
  63. package/lib/commonjs/runtime/UserflowProvider.js.map +1 -1
  64. package/lib/commonjs/runtime/bannerEngine.js +8 -2
  65. package/lib/commonjs/runtime/bannerEngine.js.map +1 -1
  66. package/lib/commonjs/runtime/bannerFlowSpacer.js +71 -0
  67. package/lib/commonjs/runtime/bannerFlowSpacer.js.map +1 -0
  68. package/lib/commonjs/runtime/flowEngine.js +11 -0
  69. package/lib/commonjs/runtime/flowEngine.js.map +1 -1
  70. package/lib/commonjs/runtime/previewStart.js +39 -0
  71. package/lib/commonjs/runtime/previewStart.js.map +1 -0
  72. package/lib/commonjs/runtime/pushBannerLayoutContext.js +98 -0
  73. package/lib/commonjs/runtime/pushBannerLayoutContext.js.map +1 -0
  74. package/lib/commonjs/screenTracker.js +12 -0
  75. package/lib/commonjs/screenTracker.js.map +1 -1
  76. package/lib/commonjs/surfaces/BannerBar.js +79 -61
  77. package/lib/commonjs/surfaces/BannerBar.js.map +1 -1
  78. package/lib/commonjs/surfaces/BannerSurface.js +26 -0
  79. package/lib/commonjs/surfaces/BannerSurface.js.map +1 -1
  80. package/lib/commonjs/surfaces/TooltipSurface.js +43 -41
  81. package/lib/commonjs/surfaces/TooltipSurface.js.map +1 -1
  82. package/lib/commonjs/surfaces/bannerBarLayout.js +77 -10
  83. package/lib/commonjs/surfaces/bannerBarLayout.js.map +1 -1
  84. package/lib/commonjs/surfaces/bannerWebView/BannerWebViewBar.js +112 -63
  85. package/lib/commonjs/surfaces/bannerWebView/BannerWebViewBar.js.map +1 -1
  86. package/lib/commonjs/surfaces/bannerWebView/buildCustomBannerHtml.js +59 -11
  87. package/lib/commonjs/surfaces/bannerWebView/buildCustomBannerHtml.js.map +1 -1
  88. package/lib/commonjs/surfaces/hostAccessibilityTrap.js +28 -0
  89. package/lib/commonjs/surfaces/hostAccessibilityTrap.js.map +1 -0
  90. package/lib/commonjs/surfaces/resolveBannerTheme.js +6 -3
  91. package/lib/commonjs/surfaces/resolveBannerTheme.js.map +1 -1
  92. package/lib/commonjs/surfaces/tooltip/TooltipBubble.js +3 -2
  93. package/lib/commonjs/surfaces/tooltip/TooltipBubble.js.map +1 -1
  94. package/lib/commonjs/surfaces/tooltip/targetSearchSchedule.js +134 -0
  95. package/lib/commonjs/surfaces/tooltip/targetSearchSchedule.js.map +1 -0
  96. package/lib/commonjs/version.js +1 -1
  97. package/lib/module/anchors/AutoAnchorRegistry.js +145 -35
  98. package/lib/module/anchors/AutoAnchorRegistry.js.map +1 -1
  99. package/lib/module/anchors/animationFrame.js +29 -2
  100. package/lib/module/anchors/animationFrame.js.map +1 -1
  101. package/lib/module/anchors/appActive.js +57 -0
  102. package/lib/module/anchors/appActive.js.map +1 -0
  103. package/lib/module/anchors/elementConditionEvaluator.js +26 -9
  104. package/lib/module/anchors/elementConditionEvaluator.js.map +1 -1
  105. package/lib/module/anchors/elementTapMonitor.js +67 -12
  106. package/lib/module/anchors/elementTapMonitor.js.map +1 -1
  107. package/lib/module/anchors/elementTargetMatch.js +32 -7
  108. package/lib/module/anchors/elementTargetMatch.js.map +1 -1
  109. package/lib/module/anchors/fiber/fiberInternals.js +65 -0
  110. package/lib/module/anchors/fiber/fiberInternals.js.map +1 -1
  111. package/lib/module/anchors/fiber/indexHostFibers.js +4 -3
  112. package/lib/module/anchors/fiber/indexHostFibers.js.map +1 -1
  113. package/lib/module/anchors/fiber/resolveFiberPath.js +30 -15
  114. package/lib/module/anchors/fiber/resolveFiberPath.js.map +1 -1
  115. package/lib/module/anchors/fiberAnchorCache.js +19 -0
  116. package/lib/module/anchors/fiberAnchorCache.js.map +1 -1
  117. package/lib/module/anchors/gestureHandlerHandoff.js +298 -0
  118. package/lib/module/anchors/gestureHandlerHandoff.js.map +1 -0
  119. package/lib/module/anchors/resolveAnchorHost.js +1 -0
  120. package/lib/module/anchors/resolveAnchorHost.js.map +1 -1
  121. package/lib/module/anchors/resolveAutoAnchorHost.js +11 -6
  122. package/lib/module/anchors/resolveAutoAnchorHost.js.map +1 -1
  123. package/lib/module/anchors/resolveElementTargets.js +63 -8
  124. package/lib/module/anchors/resolveElementTargets.js.map +1 -1
  125. package/lib/module/anchors/semanticMatcher.js +43 -21
  126. package/lib/module/anchors/semanticMatcher.js.map +1 -1
  127. package/lib/module/anchors/tapSlop.js +11 -0
  128. package/lib/module/anchors/tapSlop.js.map +1 -0
  129. package/lib/module/anchors/targetPressMonitor.js +53 -8
  130. package/lib/module/anchors/targetPressMonitor.js.map +1 -1
  131. package/lib/module/authoring/fingerprintFromInstance.js +6 -10
  132. package/lib/module/authoring/fingerprintFromInstance.js.map +1 -1
  133. package/lib/module/content/RichContentRenderer.js +3 -3
  134. package/lib/module/content/RichContentRenderer.js.map +1 -1
  135. package/lib/module/content/openSafeUrl.js +3 -1
  136. package/lib/module/content/openSafeUrl.js.map +1 -1
  137. package/lib/module/expo-router/useUserflowExpoRouter.js +7 -1
  138. package/lib/module/expo-router/useUserflowExpoRouter.js.map +1 -1
  139. package/lib/module/index.js +22 -7
  140. package/lib/module/index.js.map +1 -1
  141. package/lib/module/navigation/navigateUrlUtils.js +94 -0
  142. package/lib/module/navigation/navigateUrlUtils.js.map +1 -0
  143. package/lib/module/navigation/openExternalNavigateUrl.js +11 -0
  144. package/lib/module/navigation/openExternalNavigateUrl.js.map +1 -0
  145. package/lib/module/navigation/openFlowNavigateUrl.js +22 -36
  146. package/lib/module/navigation/openFlowNavigateUrl.js.map +1 -1
  147. package/lib/module/pairing/PairingController.js +3 -1
  148. package/lib/module/pairing/PairingController.js.map +1 -1
  149. package/lib/module/runtime/BannerHost.js +38 -29
  150. package/lib/module/runtime/BannerHost.js.map +1 -1
  151. package/lib/module/runtime/TargetPressBridge.js +56 -8
  152. package/lib/module/runtime/TargetPressBridge.js.map +1 -1
  153. package/lib/module/runtime/UserflowOverlay.js +5 -11
  154. package/lib/module/runtime/UserflowOverlay.js.map +1 -1
  155. package/lib/module/runtime/UserflowProvider.js +66 -40
  156. package/lib/module/runtime/UserflowProvider.js.map +1 -1
  157. package/lib/module/runtime/bannerEngine.js +7 -2
  158. package/lib/module/runtime/bannerEngine.js.map +1 -1
  159. package/lib/module/runtime/bannerFlowSpacer.js +65 -0
  160. package/lib/module/runtime/bannerFlowSpacer.js.map +1 -0
  161. package/lib/module/runtime/flowEngine.js +11 -0
  162. package/lib/module/runtime/flowEngine.js.map +1 -1
  163. package/lib/module/runtime/previewStart.js +35 -0
  164. package/lib/module/runtime/previewStart.js.map +1 -0
  165. package/lib/module/runtime/pushBannerLayoutContext.js +91 -0
  166. package/lib/module/runtime/pushBannerLayoutContext.js.map +1 -0
  167. package/lib/module/screenTracker.js +11 -0
  168. package/lib/module/screenTracker.js.map +1 -1
  169. package/lib/module/surfaces/BannerBar.js +80 -62
  170. package/lib/module/surfaces/BannerBar.js.map +1 -1
  171. package/lib/module/surfaces/BannerSurface.js +26 -0
  172. package/lib/module/surfaces/BannerSurface.js.map +1 -1
  173. package/lib/module/surfaces/TooltipSurface.js +44 -42
  174. package/lib/module/surfaces/TooltipSurface.js.map +1 -1
  175. package/lib/module/surfaces/bannerBarLayout.js +72 -11
  176. package/lib/module/surfaces/bannerBarLayout.js.map +1 -1
  177. package/lib/module/surfaces/bannerWebView/BannerWebViewBar.js +113 -64
  178. package/lib/module/surfaces/bannerWebView/BannerWebViewBar.js.map +1 -1
  179. package/lib/module/surfaces/bannerWebView/buildCustomBannerHtml.js +59 -11
  180. package/lib/module/surfaces/bannerWebView/buildCustomBannerHtml.js.map +1 -1
  181. package/lib/module/surfaces/hostAccessibilityTrap.js +24 -0
  182. package/lib/module/surfaces/hostAccessibilityTrap.js.map +1 -0
  183. package/lib/module/surfaces/resolveBannerTheme.js +6 -3
  184. package/lib/module/surfaces/resolveBannerTheme.js.map +1 -1
  185. package/lib/module/surfaces/tooltip/TooltipBubble.js +3 -2
  186. package/lib/module/surfaces/tooltip/TooltipBubble.js.map +1 -1
  187. package/lib/module/surfaces/tooltip/targetSearchSchedule.js +128 -0
  188. package/lib/module/surfaces/tooltip/targetSearchSchedule.js.map +1 -0
  189. package/lib/module/version.js +1 -1
  190. package/lib/typescript/commonjs/src/anchors/AutoAnchorRegistry.d.ts +36 -2
  191. package/lib/typescript/commonjs/src/anchors/AutoAnchorRegistry.d.ts.map +1 -1
  192. package/lib/typescript/commonjs/src/anchors/animationFrame.d.ts +0 -4
  193. package/lib/typescript/commonjs/src/anchors/animationFrame.d.ts.map +1 -1
  194. package/lib/typescript/commonjs/src/anchors/appActive.d.ts +8 -0
  195. package/lib/typescript/commonjs/src/anchors/appActive.d.ts.map +1 -0
  196. package/lib/typescript/commonjs/src/anchors/elementTapMonitor.d.ts +17 -0
  197. package/lib/typescript/commonjs/src/anchors/elementTapMonitor.d.ts.map +1 -1
  198. package/lib/typescript/commonjs/src/anchors/elementTargetMatch.d.ts +7 -0
  199. package/lib/typescript/commonjs/src/anchors/elementTargetMatch.d.ts.map +1 -1
  200. package/lib/typescript/commonjs/src/anchors/fiber/fiberInternals.d.ts +7 -0
  201. package/lib/typescript/commonjs/src/anchors/fiber/fiberInternals.d.ts.map +1 -1
  202. package/lib/typescript/commonjs/src/anchors/fiber/indexHostFibers.d.ts +3 -2
  203. package/lib/typescript/commonjs/src/anchors/fiber/indexHostFibers.d.ts.map +1 -1
  204. package/lib/typescript/commonjs/src/anchors/fiber/resolveFiberPath.d.ts +3 -0
  205. package/lib/typescript/commonjs/src/anchors/fiber/resolveFiberPath.d.ts.map +1 -1
  206. package/lib/typescript/commonjs/src/anchors/fiberAnchorCache.d.ts +5 -0
  207. package/lib/typescript/commonjs/src/anchors/fiberAnchorCache.d.ts.map +1 -1
  208. package/lib/typescript/commonjs/src/anchors/gestureHandlerHandoff.d.ts +70 -0
  209. package/lib/typescript/commonjs/src/anchors/gestureHandlerHandoff.d.ts.map +1 -0
  210. package/lib/typescript/commonjs/src/anchors/resolveAnchorHost.d.ts +1 -0
  211. package/lib/typescript/commonjs/src/anchors/resolveAnchorHost.d.ts.map +1 -1
  212. package/lib/typescript/commonjs/src/anchors/resolveAutoAnchorHost.d.ts +11 -4
  213. package/lib/typescript/commonjs/src/anchors/resolveAutoAnchorHost.d.ts.map +1 -1
  214. package/lib/typescript/commonjs/src/anchors/resolveElementTargets.d.ts.map +1 -1
  215. package/lib/typescript/commonjs/src/anchors/semanticMatcher.d.ts +2 -0
  216. package/lib/typescript/commonjs/src/anchors/semanticMatcher.d.ts.map +1 -1
  217. package/lib/typescript/commonjs/src/anchors/tapSlop.d.ts +9 -0
  218. package/lib/typescript/commonjs/src/anchors/tapSlop.d.ts.map +1 -0
  219. package/lib/typescript/commonjs/src/anchors/targetPressMonitor.d.ts +13 -8
  220. package/lib/typescript/commonjs/src/anchors/targetPressMonitor.d.ts.map +1 -1
  221. package/lib/typescript/commonjs/src/authoring/fingerprintFromInstance.d.ts.map +1 -1
  222. package/lib/typescript/commonjs/src/content/RichContentRenderer.d.ts.map +1 -1
  223. package/lib/typescript/commonjs/src/content/openSafeUrl.d.ts.map +1 -1
  224. package/lib/typescript/commonjs/src/expo-router/useUserflowExpoRouter.d.ts.map +1 -1
  225. package/lib/typescript/commonjs/src/index.d.ts +6 -5
  226. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  227. package/lib/typescript/commonjs/src/navigation/navigateUrlUtils.d.ts +15 -0
  228. package/lib/typescript/commonjs/src/navigation/navigateUrlUtils.d.ts.map +1 -0
  229. package/lib/typescript/commonjs/src/navigation/openExternalNavigateUrl.d.ts +3 -0
  230. package/lib/typescript/commonjs/src/navigation/openExternalNavigateUrl.d.ts.map +1 -0
  231. package/lib/typescript/commonjs/src/navigation/openFlowNavigateUrl.d.ts +2 -5
  232. package/lib/typescript/commonjs/src/navigation/openFlowNavigateUrl.d.ts.map +1 -1
  233. package/lib/typescript/commonjs/src/pairing/PairingController.d.ts +6 -0
  234. package/lib/typescript/commonjs/src/pairing/PairingController.d.ts.map +1 -1
  235. package/lib/typescript/commonjs/src/runtime/BannerHost.d.ts.map +1 -1
  236. package/lib/typescript/commonjs/src/runtime/TargetPressBridge.d.ts +3 -0
  237. package/lib/typescript/commonjs/src/runtime/TargetPressBridge.d.ts.map +1 -1
  238. package/lib/typescript/commonjs/src/runtime/UserflowOverlay.d.ts.map +1 -1
  239. package/lib/typescript/commonjs/src/runtime/UserflowProvider.d.ts.map +1 -1
  240. package/lib/typescript/commonjs/src/runtime/bannerEngine.d.ts +5 -1
  241. package/lib/typescript/commonjs/src/runtime/bannerEngine.d.ts.map +1 -1
  242. package/lib/typescript/commonjs/src/runtime/bannerFlowSpacer.d.ts +15 -0
  243. package/lib/typescript/commonjs/src/runtime/bannerFlowSpacer.d.ts.map +1 -0
  244. package/lib/typescript/commonjs/src/runtime/flowEngine.d.ts.map +1 -1
  245. package/lib/typescript/commonjs/src/runtime/previewStart.d.ts +13 -0
  246. package/lib/typescript/commonjs/src/runtime/previewStart.d.ts.map +1 -0
  247. package/lib/typescript/commonjs/src/runtime/pushBannerLayoutContext.d.ts +17 -0
  248. package/lib/typescript/commonjs/src/runtime/pushBannerLayoutContext.d.ts.map +1 -0
  249. package/lib/typescript/commonjs/src/screenTracker.d.ts +6 -0
  250. package/lib/typescript/commonjs/src/screenTracker.d.ts.map +1 -1
  251. package/lib/typescript/commonjs/src/surfaces/BannerBar.d.ts +3 -1
  252. package/lib/typescript/commonjs/src/surfaces/BannerBar.d.ts.map +1 -1
  253. package/lib/typescript/commonjs/src/surfaces/BannerSurface.d.ts +5 -1
  254. package/lib/typescript/commonjs/src/surfaces/BannerSurface.d.ts.map +1 -1
  255. package/lib/typescript/commonjs/src/surfaces/TooltipSurface.d.ts +1 -1
  256. package/lib/typescript/commonjs/src/surfaces/TooltipSurface.d.ts.map +1 -1
  257. package/lib/typescript/commonjs/src/surfaces/bannerBarLayout.d.ts +17 -0
  258. package/lib/typescript/commonjs/src/surfaces/bannerBarLayout.d.ts.map +1 -1
  259. package/lib/typescript/commonjs/src/surfaces/bannerWebView/BannerWebViewBar.d.ts +3 -1
  260. package/lib/typescript/commonjs/src/surfaces/bannerWebView/BannerWebViewBar.d.ts.map +1 -1
  261. package/lib/typescript/commonjs/src/surfaces/bannerWebView/buildCustomBannerHtml.d.ts.map +1 -1
  262. package/lib/typescript/commonjs/src/surfaces/hostAccessibilityTrap.d.ts +14 -0
  263. package/lib/typescript/commonjs/src/surfaces/hostAccessibilityTrap.d.ts.map +1 -0
  264. package/lib/typescript/commonjs/src/surfaces/resolveBannerTheme.d.ts +4 -1
  265. package/lib/typescript/commonjs/src/surfaces/resolveBannerTheme.d.ts.map +1 -1
  266. package/lib/typescript/commonjs/src/surfaces/tooltip/TooltipBubble.d.ts +7 -1
  267. package/lib/typescript/commonjs/src/surfaces/tooltip/TooltipBubble.d.ts.map +1 -1
  268. package/lib/typescript/commonjs/src/surfaces/tooltip/targetSearchSchedule.d.ts +60 -0
  269. package/lib/typescript/commonjs/src/surfaces/tooltip/targetSearchSchedule.d.ts.map +1 -0
  270. package/lib/typescript/commonjs/src/version.d.ts +1 -1
  271. package/lib/typescript/module/src/anchors/AutoAnchorRegistry.d.ts +36 -2
  272. package/lib/typescript/module/src/anchors/AutoAnchorRegistry.d.ts.map +1 -1
  273. package/lib/typescript/module/src/anchors/animationFrame.d.ts +0 -4
  274. package/lib/typescript/module/src/anchors/animationFrame.d.ts.map +1 -1
  275. package/lib/typescript/module/src/anchors/appActive.d.ts +8 -0
  276. package/lib/typescript/module/src/anchors/appActive.d.ts.map +1 -0
  277. package/lib/typescript/module/src/anchors/elementTapMonitor.d.ts +17 -0
  278. package/lib/typescript/module/src/anchors/elementTapMonitor.d.ts.map +1 -1
  279. package/lib/typescript/module/src/anchors/elementTargetMatch.d.ts +7 -0
  280. package/lib/typescript/module/src/anchors/elementTargetMatch.d.ts.map +1 -1
  281. package/lib/typescript/module/src/anchors/fiber/fiberInternals.d.ts +7 -0
  282. package/lib/typescript/module/src/anchors/fiber/fiberInternals.d.ts.map +1 -1
  283. package/lib/typescript/module/src/anchors/fiber/indexHostFibers.d.ts +3 -2
  284. package/lib/typescript/module/src/anchors/fiber/indexHostFibers.d.ts.map +1 -1
  285. package/lib/typescript/module/src/anchors/fiber/resolveFiberPath.d.ts +3 -0
  286. package/lib/typescript/module/src/anchors/fiber/resolveFiberPath.d.ts.map +1 -1
  287. package/lib/typescript/module/src/anchors/fiberAnchorCache.d.ts +5 -0
  288. package/lib/typescript/module/src/anchors/fiberAnchorCache.d.ts.map +1 -1
  289. package/lib/typescript/module/src/anchors/gestureHandlerHandoff.d.ts +70 -0
  290. package/lib/typescript/module/src/anchors/gestureHandlerHandoff.d.ts.map +1 -0
  291. package/lib/typescript/module/src/anchors/resolveAnchorHost.d.ts +1 -0
  292. package/lib/typescript/module/src/anchors/resolveAnchorHost.d.ts.map +1 -1
  293. package/lib/typescript/module/src/anchors/resolveAutoAnchorHost.d.ts +11 -4
  294. package/lib/typescript/module/src/anchors/resolveAutoAnchorHost.d.ts.map +1 -1
  295. package/lib/typescript/module/src/anchors/resolveElementTargets.d.ts.map +1 -1
  296. package/lib/typescript/module/src/anchors/semanticMatcher.d.ts +2 -0
  297. package/lib/typescript/module/src/anchors/semanticMatcher.d.ts.map +1 -1
  298. package/lib/typescript/module/src/anchors/tapSlop.d.ts +9 -0
  299. package/lib/typescript/module/src/anchors/tapSlop.d.ts.map +1 -0
  300. package/lib/typescript/module/src/anchors/targetPressMonitor.d.ts +13 -8
  301. package/lib/typescript/module/src/anchors/targetPressMonitor.d.ts.map +1 -1
  302. package/lib/typescript/module/src/authoring/fingerprintFromInstance.d.ts.map +1 -1
  303. package/lib/typescript/module/src/content/RichContentRenderer.d.ts.map +1 -1
  304. package/lib/typescript/module/src/content/openSafeUrl.d.ts.map +1 -1
  305. package/lib/typescript/module/src/expo-router/useUserflowExpoRouter.d.ts.map +1 -1
  306. package/lib/typescript/module/src/index.d.ts +6 -5
  307. package/lib/typescript/module/src/index.d.ts.map +1 -1
  308. package/lib/typescript/module/src/navigation/navigateUrlUtils.d.ts +15 -0
  309. package/lib/typescript/module/src/navigation/navigateUrlUtils.d.ts.map +1 -0
  310. package/lib/typescript/module/src/navigation/openExternalNavigateUrl.d.ts +3 -0
  311. package/lib/typescript/module/src/navigation/openExternalNavigateUrl.d.ts.map +1 -0
  312. package/lib/typescript/module/src/navigation/openFlowNavigateUrl.d.ts +2 -5
  313. package/lib/typescript/module/src/navigation/openFlowNavigateUrl.d.ts.map +1 -1
  314. package/lib/typescript/module/src/pairing/PairingController.d.ts +6 -0
  315. package/lib/typescript/module/src/pairing/PairingController.d.ts.map +1 -1
  316. package/lib/typescript/module/src/runtime/BannerHost.d.ts.map +1 -1
  317. package/lib/typescript/module/src/runtime/TargetPressBridge.d.ts +3 -0
  318. package/lib/typescript/module/src/runtime/TargetPressBridge.d.ts.map +1 -1
  319. package/lib/typescript/module/src/runtime/UserflowOverlay.d.ts.map +1 -1
  320. package/lib/typescript/module/src/runtime/UserflowProvider.d.ts.map +1 -1
  321. package/lib/typescript/module/src/runtime/bannerEngine.d.ts +5 -1
  322. package/lib/typescript/module/src/runtime/bannerEngine.d.ts.map +1 -1
  323. package/lib/typescript/module/src/runtime/bannerFlowSpacer.d.ts +15 -0
  324. package/lib/typescript/module/src/runtime/bannerFlowSpacer.d.ts.map +1 -0
  325. package/lib/typescript/module/src/runtime/flowEngine.d.ts.map +1 -1
  326. package/lib/typescript/module/src/runtime/previewStart.d.ts +13 -0
  327. package/lib/typescript/module/src/runtime/previewStart.d.ts.map +1 -0
  328. package/lib/typescript/module/src/runtime/pushBannerLayoutContext.d.ts +17 -0
  329. package/lib/typescript/module/src/runtime/pushBannerLayoutContext.d.ts.map +1 -0
  330. package/lib/typescript/module/src/screenTracker.d.ts +6 -0
  331. package/lib/typescript/module/src/screenTracker.d.ts.map +1 -1
  332. package/lib/typescript/module/src/surfaces/BannerBar.d.ts +3 -1
  333. package/lib/typescript/module/src/surfaces/BannerBar.d.ts.map +1 -1
  334. package/lib/typescript/module/src/surfaces/BannerSurface.d.ts +5 -1
  335. package/lib/typescript/module/src/surfaces/BannerSurface.d.ts.map +1 -1
  336. package/lib/typescript/module/src/surfaces/TooltipSurface.d.ts +1 -1
  337. package/lib/typescript/module/src/surfaces/TooltipSurface.d.ts.map +1 -1
  338. package/lib/typescript/module/src/surfaces/bannerBarLayout.d.ts +17 -0
  339. package/lib/typescript/module/src/surfaces/bannerBarLayout.d.ts.map +1 -1
  340. package/lib/typescript/module/src/surfaces/bannerWebView/BannerWebViewBar.d.ts +3 -1
  341. package/lib/typescript/module/src/surfaces/bannerWebView/BannerWebViewBar.d.ts.map +1 -1
  342. package/lib/typescript/module/src/surfaces/bannerWebView/buildCustomBannerHtml.d.ts.map +1 -1
  343. package/lib/typescript/module/src/surfaces/hostAccessibilityTrap.d.ts +14 -0
  344. package/lib/typescript/module/src/surfaces/hostAccessibilityTrap.d.ts.map +1 -0
  345. package/lib/typescript/module/src/surfaces/resolveBannerTheme.d.ts +4 -1
  346. package/lib/typescript/module/src/surfaces/resolveBannerTheme.d.ts.map +1 -1
  347. package/lib/typescript/module/src/surfaces/tooltip/TooltipBubble.d.ts +7 -1
  348. package/lib/typescript/module/src/surfaces/tooltip/TooltipBubble.d.ts.map +1 -1
  349. package/lib/typescript/module/src/surfaces/tooltip/targetSearchSchedule.d.ts +60 -0
  350. package/lib/typescript/module/src/surfaces/tooltip/targetSearchSchedule.d.ts.map +1 -0
  351. package/lib/typescript/module/src/version.d.ts +1 -1
  352. package/package.json +1 -1
  353. package/src/anchors/AutoAnchorRegistry.ts +166 -35
  354. package/src/anchors/animationFrame.ts +31 -1
  355. package/src/anchors/appActive.ts +63 -0
  356. package/src/anchors/elementConditionEvaluator.ts +29 -12
  357. package/src/anchors/elementTapMonitor.ts +68 -10
  358. package/src/anchors/elementTargetMatch.ts +34 -7
  359. package/src/anchors/fiber/fiberInternals.ts +68 -0
  360. package/src/anchors/fiber/indexHostFibers.ts +8 -3
  361. package/src/anchors/fiber/resolveFiberPath.ts +25 -16
  362. package/src/anchors/fiberAnchorCache.ts +19 -0
  363. package/src/anchors/gestureHandlerHandoff.ts +356 -0
  364. package/src/anchors/resolveAnchorHost.ts +2 -0
  365. package/src/anchors/resolveAutoAnchorHost.ts +18 -8
  366. package/src/anchors/resolveElementTargets.ts +64 -7
  367. package/src/anchors/semanticMatcher.ts +48 -27
  368. package/src/anchors/tapSlop.ts +18 -0
  369. package/src/anchors/targetPressMonitor.ts +56 -19
  370. package/src/authoring/fingerprintFromInstance.ts +4 -5
  371. package/src/content/RichContentRenderer.tsx +4 -3
  372. package/src/content/openSafeUrl.ts +3 -1
  373. package/src/expo-router/useUserflowExpoRouter.ts +10 -1
  374. package/src/index.ts +20 -9
  375. package/src/navigation/navigateUrlUtils.ts +100 -0
  376. package/src/navigation/openExternalNavigateUrl.ts +9 -0
  377. package/src/navigation/openFlowNavigateUrl.ts +36 -36
  378. package/src/pairing/PairingController.ts +9 -1
  379. package/src/runtime/BannerHost.tsx +41 -23
  380. package/src/runtime/TargetPressBridge.tsx +66 -9
  381. package/src/runtime/UserflowOverlay.tsx +7 -9
  382. package/src/runtime/UserflowProvider.tsx +56 -32
  383. package/src/runtime/bannerEngine.ts +10 -2
  384. package/src/runtime/bannerFlowSpacer.tsx +70 -0
  385. package/src/runtime/flowEngine.ts +11 -0
  386. package/src/runtime/previewStart.ts +49 -0
  387. package/src/runtime/pushBannerLayoutContext.tsx +121 -0
  388. package/src/screenTracker.ts +11 -0
  389. package/src/surfaces/BannerBar.tsx +93 -55
  390. package/src/surfaces/BannerSurface.tsx +59 -3
  391. package/src/surfaces/TooltipSurface.tsx +63 -51
  392. package/src/surfaces/bannerBarLayout.ts +80 -7
  393. package/src/surfaces/bannerWebView/BannerWebViewBar.tsx +149 -57
  394. package/src/surfaces/bannerWebView/buildCustomBannerHtml.ts +63 -11
  395. package/src/surfaces/hostAccessibilityTrap.ts +25 -0
  396. package/src/surfaces/resolveBannerTheme.ts +14 -3
  397. package/src/surfaces/tooltip/TooltipBubble.tsx +8 -1
  398. package/src/surfaces/tooltip/targetSearchSchedule.ts +140 -0
  399. package/src/version.ts +1 -1
  400. package/vendor/core/dist/engine/BannerSessionEngine.d.ts +29 -2
  401. package/vendor/core/dist/engine/BannerSessionEngine.d.ts.map +1 -1
  402. package/vendor/core/dist/engine/BannerSessionEngine.js +87 -6
  403. package/vendor/core/dist/engine/BannerSessionEngine.js.map +1 -1
  404. package/vendor/core/dist/engine/ClientConditionEngine.d.ts.map +1 -1
  405. package/vendor/core/dist/engine/ClientConditionEngine.js +30 -7
  406. package/vendor/core/dist/engine/ClientConditionEngine.js.map +1 -1
  407. package/vendor/core/dist/engine/PairingEngine.d.ts +6 -1
  408. package/vendor/core/dist/engine/PairingEngine.d.ts.map +1 -1
  409. package/vendor/core/dist/engine/PairingEngine.js +23 -3
  410. package/vendor/core/dist/engine/PairingEngine.js.map +1 -1
  411. package/vendor/core/dist/engine/handleActions.d.ts.map +1 -1
  412. package/vendor/core/dist/engine/handleActions.js +67 -2
  413. package/vendor/core/dist/engine/handleActions.js.map +1 -1
  414. package/vendor/core/dist/version.d.ts +1 -1
  415. package/vendor/core/dist/version.js +1 -1
  416. package/vendor/core/package.json +1 -1
  417. package/vendor/protocol/package.json +1 -1
@@ -9,7 +9,7 @@ import type { AutoAnchorInstance } from './AutoAnchorRegistry';
9
9
  import type { AnyFiber } from './fiber/fiberInternals';
10
10
  import { fiberFromPublicInstance } from './fiber/fiberInternals';
11
11
  import { createFiberMeasureInWindow } from './fiber/measureHostFiber';
12
- import { resolveFiberPath } from './fiber/resolveFiberPath';
12
+ import { resolveFiberPath, type FiberPathMissReason } from './fiber/resolveFiberPath';
13
13
  import { createVisibleInstanceFilter } from './isInstanceOnVisibleScreen';
14
14
  import { resolveAnchorHost } from './resolveAnchorHost';
15
15
  import { matchFingerprint, type MatchResult } from './semanticMatcher';
@@ -28,7 +28,15 @@ export type AutoAnchorResolution =
28
28
  }
29
29
  | { status: 'ambiguous'; match?: MatchResult }
30
30
  | { status: 'absent'; match?: MatchResult }
31
- | { status: 'unknown'; match?: MatchResult };
31
+ | {
32
+ status: 'unknown';
33
+ match?: MatchResult;
34
+ /**
35
+ * Set when a fiber path did not resolve. Element conditions treat
36
+ * `no-match` as absent and `no-root` / `empty` as unknown.
37
+ */
38
+ fiberMiss?: FiberPathMissReason;
39
+ };
32
40
 
33
41
  type MeasureInWindowCallback = (x: number, y: number, width: number, height: number) => void;
34
42
 
@@ -121,7 +129,8 @@ export function resolveScoredAutoAnchor(fp: MobileFingerprint): AutoAnchorResolu
121
129
  if (visible.instance) return mapMatch(visible);
122
130
 
123
131
  if (visible.reason === 'no-candidates') {
124
- const any = matchFingerprint(fp);
132
+ // Nothing can commit between the two matches, so the first read stands.
133
+ const any = matchFingerprint(fp, { liveContentFresh: true });
125
134
  if (any.instance) return { status: 'absent', match: any };
126
135
  if (any.reason === 'all-contradicted') return mapMatch(any);
127
136
  }
@@ -136,10 +145,11 @@ export function resolveScoredAutoAnchor(fp: MobileFingerprint): AutoAnchorResolu
136
145
  * carries a real `testID` / `userflowId` / non-`uf_` `nativeID` still resolves
137
146
  * under Babel `stampOnly: true` (no auto-registry population).
138
147
  *
139
- * Scored matches run over `autoAnchorRegistry` and fail closed: weak or
140
- * non-unique evidence is `unknown`, not `absent`, so ELEMENT gates stay blocked
141
- * rather than inventing a truth value. Hosts on a covered navigator screen
142
- * are skipped the same way the fiber scan skips them.
148
+ * Scored matches run over `autoAnchorRegistry`. A covered screen and a
149
+ * contradicted fingerprint are `absent`. Weak, missing, or tied evidence stays
150
+ * `unknown` here; element conditions decide which of those count as absent.
151
+ * Hosts on a covered navigator screen are skipped the same way the fiber scan
152
+ * skips them.
143
153
  */
144
154
  export function resolveAutoAnchorHost(
145
155
  autoData: string | MobileAutoData | null | undefined,
@@ -159,7 +169,7 @@ export function resolveAutoAnchorHost(
159
169
  };
160
170
  }
161
171
  if (fiberHit.status === 'ambiguous') return { status: 'ambiguous' };
162
- return { status: 'unknown' };
172
+ return { status: 'unknown', fiberMiss: fiberHit.reason };
163
173
  }
164
174
 
165
175
  const exactId = exactIdFromFingerprint(fp);
@@ -6,9 +6,16 @@
6
6
  * `testID`, then a real `nativeID`) use that same multi-host lookup, and fall
7
7
  * through to scoring only when nothing matched.
8
8
  */
9
- import { decodeMobileAutoData, type FlowSelectorFragment } from '@userflow-tech/protocol';
9
+ import {
10
+ decodeMobileAutoData,
11
+ type FlowSelectorFragment,
12
+ type MobileAutoData,
13
+ } from '@userflow-tech/protocol';
14
+
15
+ import { screenIdFromLocation, getCurrentScreenLocation } from '../screenTracker';
10
16
 
11
17
  import { type AnchorHost, anchorRegistry } from './AnchorRegistry';
18
+ import { autoAnchorRegistry } from './AutoAnchorRegistry';
12
19
  import type { ElementTap } from './elementTapMonitor';
13
20
  import { anchorIdsAboveTap } from './elementTargetMatch';
14
21
  import { fiberScanRoot } from './fiber/FiberScanRoot';
@@ -85,21 +92,38 @@ function resolveAutoTargets(autoData: string | null): ElementTargetResolution {
85
92
  if (!decoded || !fingerprint) return { status: 'unknown' };
86
93
 
87
94
  if (decoded.resolver === 'fiber' && decoded.fiberPath) {
88
- return fromAutoResolution(resolveAutoAnchorHost(decoded));
95
+ return conditionVerdict(resolveAutoAnchorHost(decoded), decoded);
89
96
  }
90
97
 
91
98
  const exactId = exactIdFromFingerprint(fingerprint);
99
+ let exactIdAbsent = false;
92
100
  if (exactId) {
93
101
  const manual = resolveManualTargets(exactId);
94
102
  if (manual.status === 'found') return manual;
103
+ // "Absent" before a scan root exists only means we have not looked yet.
104
+ exactIdAbsent = fiberScanRoot.getFiber() != null;
95
105
  }
96
106
 
97
107
  // The exact id already missed above, so go straight to scoring rather than
98
108
  // letting resolveAutoAnchorHost scan for it again.
99
- return fromAutoResolution(resolveScoredAutoAnchor(fingerprint));
109
+ return conditionVerdict(resolveScoredAutoAnchor(fingerprint), decoded, exactIdAbsent);
100
110
  }
101
111
 
102
- function fromAutoResolution(resolution: AutoAnchorResolution): ElementTargetResolution {
112
+ /**
113
+ * Turn an AUTO resolution into the value an element condition can report.
114
+ *
115
+ * A miss (nothing scored, or an exact id that a scan did not find) is absent,
116
+ * matching web. A tie stays unknown on the screen where the element was picked,
117
+ * because the target may be one of the look-alikes, and is absent on any other
118
+ * screen. An empty registry with no exact id, a missing scan root, and a
119
+ * missing fingerprint stay unknown so `stampOnly` cannot open a "not present"
120
+ * gate.
121
+ */
122
+ function conditionVerdict(
123
+ resolution: AutoAnchorResolution,
124
+ decoded: MobileAutoData,
125
+ exactIdAbsent = false,
126
+ ): ElementTargetResolution {
103
127
  if (resolution.status === 'found') {
104
128
  // Scored matches only try the direct ref pointer, which Paper release
105
129
  // builds null out. Without the index fallback a tap could never match.
@@ -112,12 +136,45 @@ function fromAutoResolution(resolution: AutoAnchorResolution): ElementTargetReso
112
136
  };
113
137
  }
114
138
  if (resolution.status === 'absent') return { status: 'absent' };
115
- // Ambiguous and unknown both fail closed. Ambiguous is a real tie, not a
116
- // broken selector, so it does not warn.
117
- if (resolution.status === 'ambiguous') return { status: 'unknown', silent: true };
139
+
140
+ if (resolution.status === 'unknown') {
141
+ if (resolution.fiberMiss === 'no-root' || resolution.fiberMiss === 'empty') {
142
+ return { status: 'unknown' };
143
+ }
144
+ if (resolution.fiberMiss === 'no-match') return { status: 'absent' };
145
+ }
146
+
147
+ const reason = resolution.match?.reason;
148
+ const tie =
149
+ resolution.status === 'ambiguous' ||
150
+ reason === 'not-unique' ||
151
+ reason === 'ambiguous-explicit-id';
152
+ if (tie) {
153
+ if (offPickedScreen(decoded.screenId)) return { status: 'absent' };
154
+ // A real tie is not a broken selector, so it does not warn. A weak
155
+ // not-unique miss still does, matching the previous unknown report.
156
+ return reason === 'not-unique' ? { status: 'unknown' } : { status: 'unknown', silent: true };
157
+ }
158
+
159
+ if (reason === 'below-threshold') return { status: 'absent' };
160
+
161
+ if (reason === 'no-candidates') {
162
+ const nothingToMatch = autoAnchorRegistry.allInstances().length === 0 && !exactIdAbsent;
163
+ if (nothingToMatch) return { status: 'unknown' };
164
+ return { status: 'absent' };
165
+ }
166
+
118
167
  return { status: 'unknown' };
119
168
  }
120
169
 
170
+ /** True when the picked screen is known and the app is on a different one. */
171
+ function offPickedScreen(pickedScreenId: string | undefined): boolean {
172
+ if (!pickedScreenId || pickedScreenId === 'unknown') return false;
173
+ const current = screenIdFromLocation(getCurrentScreenLocation());
174
+ if (current === 'unknown') return false;
175
+ return current !== pickedScreenId;
176
+ }
177
+
121
178
  function resolveManualTargets(id: string): ElementTargetResolution {
122
179
  const registered = anchorRegistry.getAll(id);
123
180
  if (registered.length > 0) {
@@ -190,18 +190,21 @@ function intrinsicNonTextAgrees(fp: MobileFingerprint, inst: AutoAnchorInstance)
190
190
  );
191
191
  }
192
192
 
193
+ /**
194
+ * An id or kind conflict, or a childText disagreement no text-independent
195
+ * identity (authoritative id, matching icon/image) vouches for.
196
+ */
197
+ function isContradicted(fp: MobileFingerprint, inst: AutoAnchorInstance): boolean {
198
+ if (contradictsStrong(fp, inst)) return true;
199
+ return childTextDisagrees(fp, inst) && !idAgrees(fp, inst) && !intrinsicNonTextAgrees(fp, inst);
200
+ }
201
+
193
202
  function scoreInstance(
194
203
  fp: MobileFingerprint,
195
204
  inst: AutoAnchorInstance,
196
205
  ambiguous: boolean,
197
206
  ): number {
198
- if (contradictsStrong(fp, inst)) return -Infinity;
199
-
200
- // A childText disagreement is disqualifying unless a text-independent identity
201
- // vouches for the element (authoritative id, or matching icon/image).
202
- if (childTextDisagrees(fp, inst) && !idAgrees(fp, inst) && !intrinsicNonTextAgrees(fp, inst)) {
203
- return -Infinity;
204
- }
207
+ if (isContradicted(fp, inst)) return -Infinity;
205
208
 
206
209
  let score = 0;
207
210
 
@@ -231,11 +234,14 @@ function scoreInstance(
231
234
 
232
235
  score += scoreAncestors(fp.ancestors ?? [], inst.ancestors ?? []);
233
236
 
234
- const window = autoAnchorRegistry.siblingWindow(inst.instanceId, 2);
235
- score += scoreSiblingWindow(fp.previousSiblings ?? [], window.previous);
236
- // Score next siblings once. The POC added a reversed pass *and* a direct pass,
237
- // which double-counted the next window.
238
- score += scoreSiblingWindow(fp.nextSiblings ?? [], window.next);
237
+ // The window scans the registry, so skip it when there is nothing to compare.
238
+ if (fp.previousSiblings?.length || fp.nextSiblings?.length) {
239
+ const window = autoAnchorRegistry.siblingWindow(inst.instanceId, 2);
240
+ score += scoreSiblingWindow(fp.previousSiblings ?? [], window.previous);
241
+ // Score next siblings once. The POC added a reversed pass *and* a direct pass,
242
+ // which double-counted the next window.
243
+ score += scoreSiblingWindow(fp.nextSiblings ?? [], window.next);
244
+ }
239
245
 
240
246
  if (ambiguous && !inst.manualId) score -= 40;
241
247
 
@@ -246,6 +252,8 @@ type InstanceFilter = (inst: AutoAnchorInstance) => boolean;
246
252
 
247
253
  interface MatchOptions {
248
254
  instanceFilter?: InstanceFilter;
255
+ /** The caller refreshed live content earlier in this same synchronous call. */
256
+ liveContentFresh?: boolean;
249
257
  }
250
258
 
251
259
  /** Each instance's visibility is computed once per match. */
@@ -260,10 +268,7 @@ function memoizeFilter(filter: InstanceFilter): InstanceFilter {
260
268
  };
261
269
  }
262
270
 
263
- function candidatePool(
264
- fp: MobileFingerprint,
265
- instanceFilter?: InstanceFilter,
266
- ): AutoAnchorInstance[] {
271
+ function candidatePool(fp: MobileFingerprint): AutoAnchorInstance[] {
267
272
  // Explicit ids are authoritative: a miss is no-candidates, not a full-registry search.
268
273
  let pool: AutoAnchorInstance[];
269
274
  if (fp.manualId) {
@@ -286,29 +291,45 @@ function candidatePool(
286
291
  if (filtered.length > 0) pool = filtered;
287
292
  }
288
293
  }
289
- return instanceFilter ? pool.filter(instanceFilter) : pool;
294
+ return pool;
290
295
  }
291
296
 
292
297
  function miss(reason: MatchMissReason, score = 0, secondScore = 0): MatchResult {
293
298
  return { instance: null, score, secondScore, reason };
294
299
  }
295
300
 
296
- function matchFingerprintCore(fp: MobileFingerprint, instanceFilter?: InstanceFilter): MatchResult {
301
+ function matchFingerprintCore(
302
+ fp: MobileFingerprint,
303
+ instanceFilter?: InstanceFilter,
304
+ liveContentFresh = false,
305
+ ): MatchResult {
297
306
  // Live text / testID must be applied *before* pooling. A shared Babel helper
298
307
  // (`const field = () => <TextInput testID={id} />`) reuses one auto-anchor
299
308
  // callback, so the runtime bag is last-writer-wins until we read the host.
309
+ // An unchanged host is a fiber and props-identity check after one shared
310
+ // ancestor walk per pass, so refreshing every instance stays cheap; the
311
+ // per-instance screen walk is what is not, and it only runs for the pool
312
+ // below.
313
+ const all = autoAnchorRegistry.allInstances();
314
+ if (all.length > 0 && !liveContentFresh) {
315
+ autoAnchorRegistry.refreshLiveContent(all);
316
+ }
317
+
300
318
  // A filter's verdict is memoized so covered-screen checks run once per instance.
301
319
  const filter = instanceFilter ? memoizeFilter(instanceFilter) : undefined;
302
- const broad = filter
303
- ? autoAnchorRegistry.allInstances().filter(filter)
304
- : autoAnchorRegistry.allInstances();
305
- if (broad.length > 0) {
306
- autoAnchorRegistry.refreshLiveContent(broad);
320
+ const candidates = candidatePool(fp);
321
+ // A contradiction does not depend on visibility, so settle it before the
322
+ // covered-screen check. Visibility of contradicted instances only matters to
323
+ // tell `all-contradicted` from `no-candidates` when nothing else is left.
324
+ const viable: AutoAnchorInstance[] = [];
325
+ const contradicted: AutoAnchorInstance[] = [];
326
+ for (const inst of candidates) {
327
+ (isContradicted(fp, inst) ? contradicted : viable).push(inst);
307
328
  }
308
-
309
- const pool = candidatePool(fp, filter);
329
+ const pool = filter ? viable.filter(filter) : viable;
310
330
  if (pool.length === 0) {
311
- return miss('no-candidates');
331
+ const anyContradictedCandidate = filter ? contradicted.some(filter) : contradicted.length > 0;
332
+ return miss(anyContradictedCandidate ? 'all-contradicted' : 'no-candidates');
312
333
  }
313
334
 
314
335
  // Visibility can clear a registry-wide ambiguous flag (a covered twin) but
@@ -367,7 +388,7 @@ function matchFingerprintCore(fp: MobileFingerprint, instanceFilter?: InstanceFi
367
388
  * can flag weak (`structural`) targets.
368
389
  */
369
390
  export function matchFingerprint(fp: MobileFingerprint, opts?: MatchOptions): MatchResult {
370
- const result = matchFingerprintCore(fp, opts?.instanceFilter);
391
+ const result = matchFingerprintCore(fp, opts?.instanceFilter, opts?.liveContentFresh);
371
392
  if (fp.identityStrength) result.identityStrength = fp.identityStrength;
372
393
  return result;
373
394
  }
@@ -0,0 +1,18 @@
1
+ /** Max finger travel (px) between start and end to count as a tap, not a scroll. */
2
+ export const TARGET_PRESS_TAP_SLOP = 10;
3
+
4
+ export interface TouchPoint {
5
+ pageX: number;
6
+ pageY: number;
7
+ }
8
+
9
+ /** True when the finger moved no more than `slop` between start and end. */
10
+ export function withinTapSlop(
11
+ start: TouchPoint,
12
+ end: TouchPoint,
13
+ slop: number = TARGET_PRESS_TAP_SLOP,
14
+ ): boolean {
15
+ const dx = end.pageX - start.pageX;
16
+ const dy = end.pageY - start.pageY;
17
+ return dx * dx + dy * dy <= slop * slop;
18
+ }
@@ -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();