@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
@@ -6,10 +6,14 @@
6
6
  * tooltip target-press monitor uses. The host fiber is the one captured at
7
7
  * touch start, before the press's setState commits a new tree.
8
8
  *
9
+ * A touch that gesture-handler cancels is handed off instead of dropped: the
10
+ * same fiber is emitted if that handler later ends as a tap.
11
+ *
9
12
  * With no subscribers the monitor stores nothing, so the bridge can skip the
10
13
  * fiber lookup entirely.
11
14
  */
12
15
  import type { AnyFiber } from './fiber/fiberInternals';
16
+ import { gestureHandlerHandoff } from './gestureHandlerHandoff';
13
17
  import { type TouchIdentifier, type TouchPoint, withinTapSlop } from './targetPressMonitor';
14
18
 
15
19
  export interface ElementTap {
@@ -25,6 +29,7 @@ interface TouchStart extends TouchPoint {
25
29
  export class ElementTapMonitor {
26
30
  private readonly listeners = new Set<ElementTapListener>();
27
31
  private readonly touchStarts = new Map<TouchIdentifier, TouchStart>();
32
+ private readonly handoffStops = new Map<TouchIdentifier, () => void>();
28
33
 
29
34
  get subscriberCount(): number {
30
35
  return this.listeners.size;
@@ -36,10 +41,25 @@ export class ElementTapMonitor {
36
41
  this.listeners.delete(listener);
37
42
  if (this.listeners.size === 0) {
38
43
  this.touchStarts.clear();
44
+ this.dropHandoffs();
39
45
  }
40
46
  };
41
47
  }
42
48
 
49
+ /** Fingers with a recorded start that have not ended, cancelled, or been handed off. */
50
+ inProgressIdentifiers(): TouchIdentifier[] {
51
+ return [...this.touchStarts.keys()];
52
+ }
53
+
54
+ hasTouch(identifier: TouchIdentifier): boolean {
55
+ return this.touchStarts.has(identifier);
56
+ }
57
+
58
+ /** Fiber captured at touch start, or null when this finger is not in progress. */
59
+ startFiber(identifier: TouchIdentifier): AnyFiber | null {
60
+ return this.touchStarts.get(identifier)?.targetFiber ?? null;
61
+ }
62
+
43
63
  handleTouchStart(
44
64
  identifier: TouchIdentifier,
45
65
  pageX: number,
@@ -63,31 +83,69 @@ export class ElementTapMonitor {
63
83
  if (!start || this.listeners.size === 0 || !start.targetFiber) return;
64
84
  if (!withinTapSlop(start, { pageX, pageY })) return;
65
85
 
66
- const tap: ElementTap = { targetFiber: start.targetFiber };
67
- for (const listener of this.listeners) {
68
- // One condition's failure must not cost the others this tap, or abort
69
- // the bridge's handling of the event's remaining touches.
70
- try {
71
- listener(tap);
72
- } catch {
73
- // The condition stays at its current value.
74
- }
75
- }
86
+ this.emit(start.targetFiber);
87
+ }
88
+
89
+ /**
90
+ * Gesture-handler cancelled this finger. Forget the RN touch and emit the
91
+ * start fiber if that handler later ends as a tap. A start with no fiber
92
+ * cannot latch, so it is dropped.
93
+ */
94
+ handOffTouch(identifier: TouchIdentifier, handlerTags: readonly number[]): void {
95
+ const start = this.touchStarts.get(identifier);
96
+ if (!start) return;
97
+ this.touchStarts.delete(identifier);
98
+ this.handoffStops.get(identifier)?.();
99
+ if (!start.targetFiber || handlerTags.length === 0 || this.listeners.size === 0) return;
100
+ const fiber = start.targetFiber;
101
+ const stop = gestureHandlerHandoff.track({
102
+ identifier,
103
+ pageX: start.pageX,
104
+ pageY: start.pageY,
105
+ handlerTags,
106
+ onResolve: () => this.emit(fiber),
107
+ });
108
+ this.handoffStops.set(identifier, () => {
109
+ stop();
110
+ this.handoffStops.delete(identifier);
111
+ });
76
112
  }
77
113
 
78
114
  /** Drop in-progress gesture(s). Omit `identifier` to clear every finger. */
79
115
  cancelTouch(identifier?: TouchIdentifier): void {
80
116
  if (identifier == null) {
81
117
  this.touchStarts.clear();
118
+ this.dropHandoffs();
82
119
  return;
83
120
  }
84
121
  this.touchStarts.delete(identifier);
122
+ this.handoffStops.get(identifier)?.();
85
123
  }
86
124
 
87
125
  /** Test helper. */
88
126
  resetForTests(): void {
89
127
  this.listeners.clear();
90
128
  this.touchStarts.clear();
129
+ this.dropHandoffs();
130
+ }
131
+
132
+ private emit(targetFiber: AnyFiber): void {
133
+ if (this.listeners.size === 0) return;
134
+ const tap: ElementTap = { targetFiber };
135
+ for (const listener of this.listeners) {
136
+ // One condition's failure must not cost the others this tap, or abort
137
+ // the bridge's handling of the event's remaining touches.
138
+ try {
139
+ listener(tap);
140
+ } catch {
141
+ // The condition stays at its current value.
142
+ }
143
+ }
144
+ }
145
+
146
+ private dropHandoffs(): void {
147
+ for (const stop of this.handoffStops.values()) stop();
148
+ this.handoffStops.clear();
91
149
  }
92
150
  }
93
151
 
@@ -26,19 +26,46 @@ export function anchorIdsAboveTap(tap: ElementTap): ReadonlySet<string> {
26
26
  const ids = new Set<string>();
27
27
  let current: AnyFiber = tap.targetFiber;
28
28
  for (let depth = 0; current && depth < MAX_ANCESTOR_WALK; depth += 1) {
29
- const props = getMemoizedProps(current);
30
- if (props) {
31
- for (const tier of ANCHOR_PROP_TIERS) {
32
- const value = props[tier];
33
- if (typeof value === 'string') ids.add(value);
34
- }
35
- }
29
+ collectAnchorIds(current, ids);
36
30
  current = getReturn(current);
37
31
  }
38
32
  anchorIdsByTap.set(tap, ids);
39
33
  return ids;
40
34
  }
41
35
 
36
+ /**
37
+ * The fiber on `start` (or an ancestor) that carries `anchorId`.
38
+ *
39
+ * The touch-start fiber is kept after the press navigates away, so a click can
40
+ * still match when a live scan of the new screen no longer finds the id.
41
+ */
42
+ export function fiberBearingAnchorId(start: AnyFiber, anchorId: string): AnyFiber | null {
43
+ let current: AnyFiber = start;
44
+ for (let depth = 0; current && depth < MAX_ANCESTOR_WALK; depth += 1) {
45
+ if (fiberHasAnchorId(current, anchorId)) return current;
46
+ current = getReturn(current);
47
+ }
48
+ return null;
49
+ }
50
+
51
+ function fiberHasAnchorId(fiber: AnyFiber, anchorId: string): boolean {
52
+ const props = getMemoizedProps(fiber);
53
+ if (!props) return false;
54
+ for (const tier of ANCHOR_PROP_TIERS) {
55
+ if (props[tier] === anchorId) return true;
56
+ }
57
+ return false;
58
+ }
59
+
60
+ function collectAnchorIds(fiber: AnyFiber, ids: Set<string>): void {
61
+ const props = getMemoizedProps(fiber);
62
+ if (!props) return;
63
+ for (const tier of ANCHOR_PROP_TIERS) {
64
+ const value = props[tier];
65
+ if (typeof value === 'string') ids.add(value);
66
+ }
67
+ }
68
+
42
69
  export function sameFiber(a: AnyFiber, b: AnyFiber): boolean {
43
70
  if (a == null || b == null) return false;
44
71
  if (a === b) return true;
@@ -319,6 +319,74 @@ export function resolveCurrentFiber(fiber: AnyFiber): AnyFiber {
319
319
  return fiber;
320
320
  }
321
321
 
322
+ /** Where a fiber sits: its tree's current fiber, and whether it is under it. */
323
+ interface TreePlace {
324
+ current: AnyFiber;
325
+ inTree: boolean;
326
+ }
327
+
328
+ /**
329
+ * {@link resolveCurrentFiber} for many fibers in one synchronous pass. Where
330
+ * each ancestor sits is remembered, so the pass walks every ancestor once
331
+ * instead of once per fiber below it. Discard it when the pass ends: a render
332
+ * moves `return` pointers.
333
+ */
334
+ export function createCurrentFiberResolver(): (fiber: AnyFiber) => AnyFiber {
335
+ const placeOf = new Map<object, TreePlace | null>();
336
+
337
+ const locate = (fiber: AnyFiber): TreePlace | null => {
338
+ const path: AnyFiber[] = [];
339
+ let above: TreePlace | null = null;
340
+ let cur: AnyFiber = fiber;
341
+ for (let depth = 0; cur && depth < MAX_ANCESTOR_WALK; depth += 1) {
342
+ const known = placeOf.get(cur);
343
+ if (known !== undefined) {
344
+ above = known;
345
+ break;
346
+ }
347
+ path.push(cur);
348
+ // Only a HostRoot (or a detached fiber) has no parent, so the tag is
349
+ // read once, at the top, not at every step.
350
+ const parent = getReturn(cur);
351
+ if (!parent) {
352
+ const rootState =
353
+ getFiberTag(cur) === HOST_ROOT_TAG
354
+ ? (getStateNode(cur) as { current?: AnyFiber } | null)
355
+ : null;
356
+ above = rootState?.current ? { current: rootState.current, inTree: false } : null;
357
+ break;
358
+ }
359
+ cur = parent;
360
+ }
361
+ // Top down: a fiber is in the current tree when the current fiber is it
362
+ // or one of its ancestors.
363
+ let place = above;
364
+ for (let i = path.length - 1; i >= 0; i -= 1) {
365
+ if (place && !place.inTree && path[i] === place.current) {
366
+ place = { current: place.current, inTree: true };
367
+ }
368
+ placeOf.set(path[i], place);
369
+ }
370
+ return place;
371
+ };
372
+
373
+ return (fiber) => {
374
+ if (!fiber) return fiber;
375
+ try {
376
+ const alternate = getAlternate(fiber);
377
+ if (!alternate) return fiber;
378
+ const own = locate(fiber);
379
+ if (!own || own.inTree) return fiber;
380
+ const other = locate(alternate);
381
+ // Two trees for one pair only happens on a corrupt graph.
382
+ if (!other || other.current !== own.current) return resolveCurrentFiber(fiber);
383
+ return other.inTree ? alternate : fiber;
384
+ } catch {
385
+ return fiber;
386
+ }
387
+ };
388
+ }
389
+
322
390
  function isInTree(fiber: AnyFiber, root: AnyFiber): boolean {
323
391
  let cur: AnyFiber = fiber;
324
392
  for (let depth = 0; cur && depth < MAX_ANCESTOR_WALK; depth += 1) {
@@ -111,13 +111,18 @@ export function createLazyHostFiberIndex(
111
111
 
112
112
  /**
113
113
  * Fiber for a public instance: direct pointer first, then the scan-root index
114
- * by identity / native tag.
114
+ * by identity / native tag. Pass a `createCurrentFiberResolver()` resolver when
115
+ * looking up many instances in one pass.
115
116
  */
116
- export function lookupHostFiber(index: HostFiberIndexSource, instance: unknown): AnyFiber | null {
117
+ export function lookupHostFiber(
118
+ index: HostFiberIndexSource,
119
+ instance: unknown,
120
+ resolveCurrent: (fiber: AnyFiber) => AnyFiber = resolveCurrentFiber,
121
+ ): AnyFiber | null {
117
122
  const direct = fiberFromPublicInstance(instance);
118
123
  if (direct) {
119
124
  try {
120
- return resolveCurrentFiber(direct);
125
+ return resolveCurrent(direct);
121
126
  } catch {
122
127
  return direct;
123
128
  }
@@ -31,10 +31,13 @@ import { walkVisibleFibers } from './walkVisibleFibers';
31
31
  const MIN_SCORE = 40;
32
32
  const UNIQUENESS_MARGIN = 12;
33
33
 
34
+ /** Why a fiber path did not resolve. Element conditions map these differently. */
35
+ export type FiberPathMissReason = 'empty' | 'no-root' | 'no-match';
36
+
34
37
  export type FiberPathResolution =
35
38
  | { status: 'found'; fiber: AnyFiber; cacheId: string; textDisagreed?: boolean }
36
39
  | { status: 'ambiguous' }
37
- | { status: 'unknown' };
40
+ | { status: 'unknown'; reason: FiberPathMissReason };
38
41
 
39
42
  function stringProp(value: unknown): string | undefined {
40
43
  return typeof value === 'string' && value.trim() ? value.trim() : undefined;
@@ -50,18 +53,13 @@ function sameFiber(a: AnyFiber, b: AnyFiber): boolean {
50
53
  return alt != null && alt === b;
51
54
  }
52
55
 
53
- function liveSegment(fiber: AnyFiber): MobileFiberSegment {
56
+ /** The live segment without its text, which needs a subtree walk. */
57
+ function liveIdentity(fiber: AnyFiber): MobileFiberSegment {
54
58
  const props = getLiveHostProps(fiber);
55
59
  const role = stringProp(props?.accessibilityRole) ?? stringProp(props?.role);
56
60
  const testID = stringProp(props?.testID);
57
61
  const accessibilityLabel =
58
62
  stringProp(props?.accessibilityLabel) ?? stringProp(props?.['aria-label']);
59
- let text: string | undefined;
60
- try {
61
- text = readHostText(fiber, 1);
62
- } catch {
63
- text = undefined;
64
- }
65
63
  const hostKind = getHostTypeName(fiber);
66
64
  return {
67
65
  displayName: typeof fiber?.type === 'string' ? fiber.type : '',
@@ -69,10 +67,19 @@ function liveSegment(fiber: AnyFiber): MobileFiberSegment {
69
67
  ...(role ? { role } : {}),
70
68
  ...(testID ? { testID } : {}),
71
69
  ...(accessibilityLabel ? { accessibilityLabel } : {}),
72
- ...(text ? { text } : {}),
73
70
  };
74
71
  }
75
72
 
73
+ function liveSegment(fiber: AnyFiber): MobileFiberSegment {
74
+ let text: string | undefined;
75
+ try {
76
+ text = readHostText(fiber, 1);
77
+ } catch {
78
+ text = undefined;
79
+ }
80
+ return { ...liveIdentity(fiber), ...(text ? { text } : {}) };
81
+ }
82
+
76
83
  function ancestorsOf(fiber: AnyFiber): AnyFiber[] {
77
84
  const chain: AnyFiber[] = [];
78
85
  let current: AnyFiber | null = fiber;
@@ -90,7 +97,8 @@ function scoreAlignment(expected: MobileFiberSegment[], actual: AnyFiber[]): num
90
97
  let kindAligned = 0;
91
98
  for (let i = 0; i < n; i += 1) {
92
99
  const exp = expected[expected.length - 1 - i]!;
93
- const live = liveSegment(actual[actual.length - 1 - i]!);
100
+ // Alignment never compares text, so skip the subtree walk for every ancestor.
101
+ const live = liveIdentity(actual[actual.length - 1 - i]!);
94
102
  const expKind = exp.hostKind ?? exp.displayName;
95
103
  const liveKind = live.hostKind ?? live.displayName;
96
104
  if (expKind && liveKind && expKind !== liveKind) break;
@@ -107,13 +115,14 @@ function scoreHost(
107
115
  path: MobileFiberPath,
108
116
  fiber: AnyFiber,
109
117
  ): { score: number; textDisagreed: boolean } {
110
- const live = liveSegment(fiber);
111
118
  const leaf = path.segments[path.segments.length - 1];
112
119
  const leafKind = leaf?.hostKind ?? path.leafKind;
113
- const liveKind = live.hostKind ?? '';
120
+ // Kind first: most hosts fail here, before any props or text are read.
121
+ const liveKind = getHostTypeName(fiber) ?? '';
114
122
  if (leafKind && liveKind && leafKind !== liveKind) {
115
123
  return { score: -Infinity, textDisagreed: false };
116
124
  }
125
+ const live = liveSegment(fiber);
117
126
 
118
127
  let score = 20;
119
128
  if (leaf?.role && live.role === leaf.role) score += 15;
@@ -151,15 +160,15 @@ function scoreHost(
151
160
 
152
161
  function resolveScored(path: MobileFiberPath, root: AnyFiber): FiberPathResolution {
153
162
  const scored: Array<{ fiber: AnyFiber; score: number; textDisagreed: boolean }> = [];
163
+ // The walk already skips covered screens, so no per-host visibility walk.
154
164
  walkVisibleFibers(root, (fiber) => {
155
165
  if (!isHostFiber(fiber)) return;
156
- if (!isFiberOnVisibleScreen(fiber)) return;
157
166
  const { score, textDisagreed } = scoreHost(path, fiber);
158
167
  if (score > -Infinity) scored.push({ fiber, score, textDisagreed });
159
168
  });
160
169
  scored.sort((a, b) => b.score - a.score);
161
170
  const best = scored[0];
162
- if (!best || best.score < MIN_SCORE) return { status: 'unknown' };
171
+ if (!best || best.score < MIN_SCORE) return { status: 'unknown', reason: 'no-match' };
163
172
  const second = scored[1];
164
173
  if (second && best.score - second.score < UNIQUENESS_MARGIN) return { status: 'ambiguous' };
165
174
  return {
@@ -175,7 +184,7 @@ function resolveScored(path: MobileFiberPath, root: AnyFiber): FiberPathResoluti
175
184
  * and reuses the manual fiber scan.
176
185
  */
177
186
  export function resolveFiberPath(path: MobileFiberPath | null | undefined): FiberPathResolution {
178
- if (!path || path.segments.length === 0) return { status: 'unknown' };
187
+ if (!path || path.segments.length === 0) return { status: 'unknown', reason: 'empty' };
179
188
 
180
189
  const leaf = path.segments[path.segments.length - 1];
181
190
  const exactId = leaf?.testID;
@@ -200,7 +209,7 @@ export function resolveFiberPath(path: MobileFiberPath | null | undefined): Fibe
200
209
  }
201
210
 
202
211
  const root = fiberScanRoot.getFiber();
203
- if (!root) return { status: 'unknown' };
212
+ if (!root) return { status: 'unknown', reason: 'no-root' };
204
213
 
205
214
  const resolved = resolveScored(path, root);
206
215
  if (resolved.status === 'found') {
@@ -7,6 +7,7 @@ interface FiberCacheEntry {
7
7
 
8
8
  const fiberCache = new Map<string, FiberCacheEntry>();
9
9
  let currentScreenKey: string | null = null;
10
+ const screenChangeListeners = new Set<() => void>();
10
11
 
11
12
  export function getFiberAnchorScreenKey(): string | null {
12
13
  return currentScreenKey;
@@ -17,6 +18,24 @@ export function notifyAnchorScreenChange(screenKey: string | null): void {
17
18
  if (screenKey === currentScreenKey) return;
18
19
  currentScreenKey = screenKey;
19
20
  fiberCache.clear();
21
+ for (const listener of Array.from(screenChangeListeners)) {
22
+ try {
23
+ listener();
24
+ } catch {
25
+ // A listener must not break screen tracking.
26
+ }
27
+ }
28
+ }
29
+
30
+ /**
31
+ * `listener` runs after the active screen changes, once the cache above is
32
+ * cleared. Searches that back off while a target is missing restart from here.
33
+ */
34
+ export function subscribeAnchorScreenChange(listener: () => void): () => void {
35
+ screenChangeListeners.add(listener);
36
+ return () => {
37
+ screenChangeListeners.delete(listener);
38
+ };
20
39
  }
21
40
 
22
41
  /** Drop the fiber cache (preview restart / tests). */