@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
@@ -1,4 +1,5 @@
1
1
  import { BannerSessionEngine, type UserflowCore } from '@userflow-tech/core';
2
+ import type { EndFlowReasonInput } from '@userflow-tech/protocol';
2
3
 
3
4
  import { evalJsController } from '../evalJs/evalJsController';
4
5
  import { openFlowNavigateUrl } from '../navigation/openFlowNavigateUrl';
@@ -44,8 +45,15 @@ export function resetBannerSessionEngine(): void {
44
45
  }
45
46
 
46
47
  /** Drop the local banner without detaching (preview exit, user switch). */
47
- export function clearBannerSessionEngineLocalSession(): void {
48
- bannerEngine?.clearLocalSession();
48
+ export function clearBannerSessionEngineLocalSession(options?: {
49
+ rememberDraftForPreviewEnd?: boolean;
50
+ }): void {
51
+ bannerEngine?.clearLocalSession(options);
52
+ }
53
+
54
+ /** Best-effort end of a Builder preview banner draft (including after local clear). */
55
+ export async function endDraftBannerSession(): Promise<void> {
56
+ await bannerEngine?.endDraftBannerSession('USER_CLOSED' as EndFlowReasonInput);
49
57
  }
50
58
 
51
59
  /** Test helper: drop the singleton so the next get recreates it. */
@@ -0,0 +1,70 @@
1
+ import type { BannerSessionEngine } from '@userflow-tech/core';
2
+ import * as React from 'react';
3
+ import { View } from 'react-native';
4
+
5
+ import { bannerEdge } from './bannerPlacement';
6
+ import { useBannerSession } from './useBannerSession';
7
+
8
+ type SpacerEdge = 'top' | 'bottom';
9
+
10
+ const heights: Record<SpacerEdge, number> = { top: 0, bottom: 0 };
11
+ const listeners = new Set<() => void>();
12
+
13
+ function emit(): void {
14
+ for (const listener of listeners) {
15
+ listener();
16
+ }
17
+ }
18
+
19
+ /** @internal */
20
+ export function setBannerFlowSpacerHeight(edge: SpacerEdge, height: number): void {
21
+ const next = Math.max(0, Math.ceil(height));
22
+ if (heights[edge] === next) {
23
+ return;
24
+ }
25
+ heights[edge] = next;
26
+ emit();
27
+ }
28
+
29
+ function subscribe(listener: () => void): () => void {
30
+ listeners.add(listener);
31
+ return () => {
32
+ listeners.delete(listener);
33
+ };
34
+ }
35
+
36
+ function getHeight(edge: SpacerEdge): number {
37
+ return heights[edge];
38
+ }
39
+
40
+ /**
41
+ * Reserves layout space when a custom-css WebView banner is painted in the
42
+ * overlay host but the builder marked it `overlay: false` (push layout).
43
+ */
44
+ export function BannerWebViewFlowSpacer({
45
+ engine,
46
+ edge,
47
+ }: {
48
+ engine: BannerSessionEngine;
49
+ edge: SpacerEdge;
50
+ }): React.ReactElement | null {
51
+ const session = useBannerSession(engine);
52
+ const height = React.useSyncExternalStore(
53
+ subscribe,
54
+ () => getHeight(edge),
55
+ () => getHeight(edge),
56
+ );
57
+
58
+ if (!session?.version.banner || height <= 0) {
59
+ return null;
60
+ }
61
+ const pinnedEdge = bannerEdge(session.version.banner.embedMode);
62
+ if (pinnedEdge !== edge) {
63
+ return null;
64
+ }
65
+
66
+ // Layout-only: the painted banner lives in the overlay host (lower z-index).
67
+ return (
68
+ <View pointerEvents="none" testID={`userflow-banner-flow-spacer-${edge}`} style={{ height }} />
69
+ );
70
+ }
@@ -31,6 +31,17 @@ export function getFlowSessionEngine(core: UserflowCore): FlowSessionEngine {
31
31
  updateUser: (attributes) => core.updateUser(attributes),
32
32
  updateGroup: (attributes, options) => core.updateGroup(attributes, options),
33
33
  });
34
+ flowEngine.on((event) => {
35
+ if (event.type !== 'sessionChange' || event.session !== null) {
36
+ return;
37
+ }
38
+ // Drop a flow's eval page when the tour ends. A banner WebView reuses the
39
+ // same controller and must keep its page alive until the banner dismisses.
40
+ if (evalJsController.getSnapshot().bannerOwnsWebView) {
41
+ return;
42
+ }
43
+ evalJsController.reset();
44
+ });
34
45
  if (endDraftOnArrival) watchForRestoredDraft();
35
46
  }
36
47
  return flowEngine;
@@ -0,0 +1,49 @@
1
+ import type { UserflowCore } from '@userflow-tech/core';
2
+ import type { EndFlowReasonInput } from '@userflow-tech/protocol';
3
+
4
+ import { evalJsController } from '../evalJs/evalJsController';
5
+
6
+ import {
7
+ clearBannerSessionEngineLocalSession,
8
+ endDraftBannerSession,
9
+ getBannerSessionEngine,
10
+ } from './bannerEngine';
11
+ import {
12
+ cancelPendingDraftEnd,
13
+ clearFlowSessionEngineLocalSession,
14
+ endDraftFlowSession,
15
+ } from './flowEngine';
16
+
17
+ /**
18
+ * Drop local tour state and reset eval before a Builder `startFlowWithToken`.
19
+ *
20
+ * When a draft banner is still active, end it on the server first. The channel
21
+ * dedupes an unchanged `SetBannerSession`, so clearing the banner locally
22
+ * without ending the draft leaves nothing visible on a second preview of the
23
+ * same banner.
24
+ */
25
+ export async function prepareForBuilderPreviewStart(core: UserflowCore): Promise<void> {
26
+ cancelPendingDraftEnd();
27
+ clearFlowSessionEngineLocalSession();
28
+ core.setFlowSessionId(null);
29
+
30
+ const bannerEngine = getBannerSessionEngine(core);
31
+ const hasDraftBanner =
32
+ bannerEngine.getBannerSession()?.draftMode === true ||
33
+ bannerEngine.getDeferredDraftBannerSessionId() !== null;
34
+
35
+ if (hasDraftBanner) {
36
+ await bannerEngine.endDraftBannerForPreview('USER_CLOSED' as EndFlowReasonInput);
37
+ } else {
38
+ clearBannerSessionEngineLocalSession();
39
+ core.setBannerSessionId(null);
40
+ }
41
+
42
+ evalJsController.reset();
43
+ }
44
+
45
+ /** End tour and banner Builder drafts on the server (preview exit). */
46
+ export async function endDraftPreviewSessions(): Promise<void> {
47
+ await endDraftFlowSession();
48
+ await endDraftBannerSession();
49
+ }
@@ -0,0 +1,121 @@
1
+ import * as React from 'react';
2
+ import type { LayoutChangeEvent } from 'react-native';
3
+
4
+ export type PushBannerLayoutEdge = 'top' | 'bottom';
5
+
6
+ interface PushBannerLayoutContextValue {
7
+ /** Push-layout banner chrome mounted; host safe-area may follow this edge. */
8
+ register: (edge: PushBannerLayoutEdge, token: string) => void;
9
+ unregister: (token: string) => void;
10
+ }
11
+
12
+ const PushBannerLayoutContext = React.createContext<PushBannerLayoutContextValue | null>(null);
13
+
14
+ function pickEdge(registrations: Map<string, PushBannerLayoutEdge>): PushBannerLayoutEdge | null {
15
+ let top = false;
16
+ let bottom = false;
17
+ for (const edge of registrations.values()) {
18
+ if (edge === 'top') {
19
+ top = true;
20
+ }
21
+ if (edge === 'bottom') {
22
+ bottom = true;
23
+ }
24
+ }
25
+ if (top) {
26
+ return 'top';
27
+ }
28
+ if (bottom) {
29
+ return 'bottom';
30
+ }
31
+ return null;
32
+ }
33
+
34
+ export function PushBannerLayoutProvider({
35
+ children,
36
+ onActiveEdgeChange,
37
+ }: {
38
+ children: React.ReactNode;
39
+ onActiveEdgeChange: (edge: PushBannerLayoutEdge | null) => void;
40
+ }): React.ReactElement {
41
+ const registrations = React.useRef(new Map<string, PushBannerLayoutEdge>());
42
+ const onActiveEdgeChangeRef = React.useRef(onActiveEdgeChange);
43
+ onActiveEdgeChangeRef.current = onActiveEdgeChange;
44
+
45
+ const sync = React.useCallback(() => {
46
+ onActiveEdgeChangeRef.current(pickEdge(registrations.current));
47
+ }, []);
48
+
49
+ const value = React.useMemo<PushBannerLayoutContextValue>(
50
+ () => ({
51
+ register: (edge, token) => {
52
+ registrations.current.set(token, edge);
53
+ sync();
54
+ },
55
+ unregister: (token) => {
56
+ if (registrations.current.delete(token)) {
57
+ sync();
58
+ }
59
+ },
60
+ }),
61
+ [sync],
62
+ );
63
+
64
+ React.useLayoutEffect(() => {
65
+ sync();
66
+ }, [sync]);
67
+
68
+ return (
69
+ <PushBannerLayoutContext.Provider value={value}>{children}</PushBannerLayoutContext.Provider>
70
+ );
71
+ }
72
+
73
+ /** @internal */
74
+ export function usePushBannerLayoutRegistration(
75
+ edge: PushBannerLayoutEdge | null | undefined,
76
+ sessionId: string | undefined,
77
+ ): void {
78
+ const ctx = React.useContext(PushBannerLayoutContext);
79
+ React.useLayoutEffect(() => {
80
+ if (!ctx || !edge || !sessionId) {
81
+ return;
82
+ }
83
+ const token = `${sessionId}:${edge}`;
84
+ ctx.register(edge, token);
85
+ return () => {
86
+ ctx.unregister(token);
87
+ };
88
+ }, [ctx, edge, sessionId]);
89
+ }
90
+
91
+ /**
92
+ * Clears the host top/bottom safe-area override only after push-layout chrome
93
+ * has laid out, so a session without visible chrome cannot leave a white strip.
94
+ *
95
+ * @internal
96
+ */
97
+ export function usePushBannerHostInsetRegistration(
98
+ edge: PushBannerLayoutEdge | null | undefined,
99
+ sessionId: string,
100
+ enabled: boolean,
101
+ ): (event: LayoutChangeEvent) => void {
102
+ const [laidOut, setLaidOut] = React.useState(false);
103
+
104
+ React.useEffect(() => {
105
+ setLaidOut(false);
106
+ }, [edge, enabled]);
107
+
108
+ usePushBannerLayoutRegistration(enabled && laidOut && edge ? edge : null, sessionId);
109
+
110
+ return React.useCallback(
111
+ (event: LayoutChangeEvent) => {
112
+ if (!enabled || !edge) {
113
+ return;
114
+ }
115
+ if (event.nativeEvent.layout.height > 0) {
116
+ setLaidOut(true);
117
+ }
118
+ },
119
+ [edge, enabled],
120
+ );
121
+ }
@@ -24,6 +24,17 @@ function locationKey(location: ClientLocationUpdate): string {
24
24
  return 'path' in location ? `path:${location.path}` : `screen:${location.screen}`;
25
25
  }
26
26
 
27
+ /**
28
+ * The screen id stored on an AUTO envelope (`path` for Expo Router, `screen`
29
+ * otherwise). Missing or blank locations are `'unknown'`, the same sentinel
30
+ * the element picker writes when it has not seen a screen yet.
31
+ */
32
+ export function screenIdFromLocation(location: ClientLocationUpdate | null | undefined): string {
33
+ if (!location) return 'unknown';
34
+ const id = 'path' in location ? location.path : location.screen;
35
+ return id || 'unknown';
36
+ }
37
+
27
38
  /** Event attributes for `screen_viewed`, or `null` when the location has no identity. */
28
39
  export function screenViewedAttributes(
29
40
  location: ClientLocationUpdate,
@@ -11,14 +11,18 @@ import { Animated, Pressable, StyleSheet, Text, View } from 'react-native';
11
11
  import { BannerStepButton } from '../content/BannerStepButton';
12
12
  import { RichContentRenderer } from '../content/RichContentRenderer';
13
13
  import { mixThemeColors } from '../content/themeColor';
14
+ import { usePushBannerHostInsetRegistration } from '../runtime/pushBannerLayoutContext';
14
15
 
15
16
  import {
16
17
  BANNER_CLOSE_SLOT_SIZE,
17
18
  BANNER_ROOT_PADDING,
19
+ bannerBarRootStyle,
18
20
  bannerFrameStyle,
19
21
  bannerInnerStyle,
22
+ bannerPushLayoutChrome,
20
23
  resolveBannerBarBorderRadius,
21
24
  } from './bannerBarLayout';
25
+ import { useUserflowSafeAreaInsets } from './safeArea';
22
26
  import {
23
27
  BANNER_BUTTON_GAP,
24
28
  BANNER_CLOSE_BORDER_RADIUS,
@@ -28,6 +32,8 @@ import { resolveBannerBackgroundColor, resolveBannerForegroundColor } from './re
28
32
 
29
33
  export interface BannerBarProps {
30
34
  session: BannerSessionFragment;
35
+ pushLayoutEdge?: 'top' | 'bottom' | null;
36
+ overlaySafeEdge?: 'top' | 'bottom' | null;
31
37
  onActions: (actions: FlowActionFragment[]) => void;
32
38
  onDismiss: (endReason: EndFlowReasonInput) => void;
33
39
  }
@@ -38,6 +44,8 @@ export interface BannerBarProps {
38
44
  */
39
45
  export function BannerBar({
40
46
  session,
47
+ pushLayoutEdge = null,
48
+ overlaySafeEdge = null,
41
49
  onActions,
42
50
  onDismiss,
43
51
  }: BannerBarProps): React.ReactElement | null {
@@ -50,10 +58,20 @@ export function BannerBar({
50
58
  [theme, backgroundColor, foregroundColor],
51
59
  );
52
60
  const lookupAttribute = React.useMemo(() => genSessionDataLookup(session.data), [session.data]);
53
- const opacity = React.useRef(new Animated.Value(banner?.animate ? 0 : 1)).current;
61
+ const insets = useUserflowSafeAreaInsets();
62
+ const overlay = banner?.overlay !== false;
63
+ const hostInsetEdge = !overlay && pushLayoutEdge ? pushLayoutEdge : null;
64
+ const safeAreaEdge = hostInsetEdge ?? overlaySafeEdge ?? null;
65
+ const onPushChromeLayout = usePushBannerHostInsetRegistration(
66
+ hostInsetEdge,
67
+ session.id,
68
+ hostInsetEdge != null,
69
+ );
70
+ const fadeIn = banner?.animate === true && hostInsetEdge == null;
71
+ const opacity = React.useRef(new Animated.Value(fadeIn ? 0 : 1)).current;
54
72
 
55
73
  React.useEffect(() => {
56
- if (!banner?.animate) {
74
+ if (!fadeIn) {
57
75
  opacity.setValue(1);
58
76
  return;
59
77
  }
@@ -67,73 +85,93 @@ export function BannerBar({
67
85
  return () => {
68
86
  animation.stop();
69
87
  };
70
- }, [banner?.animate, opacity, session.id]);
88
+ }, [fadeIn, opacity, session.id]);
71
89
 
72
90
  if (!banner) return null;
73
91
 
74
- const overlay = banner.overlay !== false;
75
92
  const frameStyle = bannerFrameStyle(banner);
93
+ const rootStyle = bannerBarRootStyle(banner);
76
94
  const innerStyle = bannerInnerStyle(banner);
77
95
  const closePressedBackground = mixThemeColors(backgroundColor, foregroundColor, 0.12);
78
96
  const overlayEdge = banner.embedMode === BannerEmbedMode.BODY_LAST ? 'bottom' : 'top';
79
97
  const barRadius = resolveBannerBarBorderRadius(banner);
98
+ const insetChrome = safeAreaEdge
99
+ ? bannerPushLayoutChrome(safeAreaEdge, insets, backgroundColor)
100
+ : null;
101
+ const insetChromeOutsideFade = insetChrome != null && fadeIn;
80
102
 
81
- return (
82
- <View testID="userflow-banner-frame" style={frameStyle}>
83
- <Animated.View style={[{ opacity }, overlay ? bannerOverlayShadowStyle(overlayEdge) : null]}>
84
- <View
85
- testID="userflow-banner"
86
- style={[
87
- styles.root,
88
- { backgroundColor },
89
- barRadius != null ? { borderRadius: barRadius, overflow: 'hidden' as const } : null,
90
- ]}
91
- >
92
- <View style={styles.startSpacer} />
93
- <View style={innerStyle}>
94
- <View style={styles.content}>
95
- <RichContentRenderer
96
- content={banner.content}
97
- buttons={[]}
103
+ const bar = (
104
+ <View
105
+ testID="userflow-banner"
106
+ style={[
107
+ styles.root,
108
+ rootStyle,
109
+ { backgroundColor },
110
+ barRadius != null ? { borderRadius: barRadius, overflow: 'hidden' as const } : null,
111
+ ]}
112
+ >
113
+ <View style={styles.startSpacer} />
114
+ <View style={innerStyle}>
115
+ <View style={styles.content}>
116
+ <RichContentRenderer
117
+ content={banner.content}
118
+ buttons={[]}
119
+ theme={bannerTheme}
120
+ sessionData={session.data}
121
+ lookupAttribute={lookupAttribute}
122
+ onActions={onActions}
123
+ />
124
+ </View>
125
+ {banner.buttons.length > 0 ? (
126
+ <View style={styles.buttons}>
127
+ {banner.buttons.map((button) => (
128
+ <BannerStepButton
129
+ key={button.id}
130
+ button={button}
98
131
  theme={bannerTheme}
99
132
  sessionData={session.data}
100
- lookupAttribute={lookupAttribute}
101
133
  onActions={onActions}
102
134
  />
103
- </View>
104
- {banner.buttons.length > 0 ? (
105
- <View style={styles.buttons}>
106
- {banner.buttons.map((button) => (
107
- <BannerStepButton
108
- key={button.id}
109
- button={button}
110
- theme={bannerTheme}
111
- sessionData={session.data}
112
- onActions={onActions}
113
- />
114
- ))}
115
- </View>
116
- ) : null}
135
+ ))}
117
136
  </View>
118
- {session.version.closeDisabled ? (
119
- <View style={styles.startSpacer} />
120
- ) : (
121
- <Pressable
122
- testID="userflow-banner-dismiss"
123
- accessibilityRole="button"
124
- accessibilityLabel="Dismiss"
125
- hitSlop={8}
126
- onPress={() => onDismiss(EndFlowReasonInput.USER_CLOSED)}
127
- style={({ pressed }) => [
128
- styles.close,
129
- pressed ? { backgroundColor: closePressedBackground } : null,
130
- ]}
131
- >
132
- <Text style={[styles.dismissIcon, { color: foregroundColor }]}>×</Text>
133
- </Pressable>
134
- )}
135
- </View>
136
- </Animated.View>
137
+ ) : null}
138
+ </View>
139
+ {session.version.closeDisabled ? (
140
+ <View style={styles.startSpacer} />
141
+ ) : (
142
+ <Pressable
143
+ testID="userflow-banner-dismiss"
144
+ accessibilityRole="button"
145
+ accessibilityLabel="Dismiss"
146
+ hitSlop={8}
147
+ onPress={() => onDismiss(EndFlowReasonInput.USER_CLOSED)}
148
+ style={({ pressed }) => [
149
+ styles.close,
150
+ pressed ? { backgroundColor: closePressedBackground } : null,
151
+ ]}
152
+ >
153
+ <Text style={[styles.dismissIcon, { color: foregroundColor }]}>×</Text>
154
+ </Pressable>
155
+ )}
156
+ </View>
157
+ );
158
+
159
+ const animatedBar = (
160
+ <Animated.View
161
+ onLayout={hostInsetEdge ? onPushChromeLayout : undefined}
162
+ style={[
163
+ { opacity },
164
+ overlay ? bannerOverlayShadowStyle(overlayEdge) : null,
165
+ insetChromeOutsideFade ? null : insetChrome,
166
+ ]}
167
+ >
168
+ {bar}
169
+ </Animated.View>
170
+ );
171
+
172
+ return (
173
+ <View testID="userflow-banner-frame" style={frameStyle}>
174
+ {insetChromeOutsideFade ? <View style={insetChrome}>{animatedBar}</View> : animatedBar}
137
175
  </View>
138
176
  );
139
177
  }
@@ -15,6 +15,10 @@ import { bannerNeedsWebView } from './bannerWebView/bannerNeedsWebView';
15
15
 
16
16
  export interface BannerSurfaceProps {
17
17
  session: BannerSessionFragment;
18
+ /** When set, the banner pushes host layout and fills the safe-area inset on this edge. */
19
+ pushLayoutEdge?: 'top' | 'bottom' | null;
20
+ /** Overlay host edge — paints safe-area padding without pushing layout. */
21
+ overlaySafeEdge?: 'top' | 'bottom' | null;
18
22
  onActions: (actions: FlowActionFragment[]) => void | Promise<void>;
19
23
  onDismiss: (endReason: EndFlowReasonInput) => void;
20
24
  }
@@ -27,6 +31,8 @@ let warnedMissingWebView = false;
27
31
  */
28
32
  export function BannerSurface({
29
33
  session,
34
+ pushLayoutEdge = null,
35
+ overlaySafeEdge = null,
30
36
  onActions,
31
37
  onDismiss,
32
38
  }: BannerSurfaceProps): React.ReactElement | null {
@@ -35,6 +41,34 @@ export function BannerSurface({
35
41
  const needsWebView = banner != null && bannerNeedsWebView(banner, theme);
36
42
  const webView = needsWebView ? getEvalJsWebView() : null;
37
43
 
44
+ React.useEffect(() => {
45
+ if (!banner || !__DEV__) {
46
+ return;
47
+ }
48
+ // eslint-disable-next-line no-console -- intentional development diagnostic
49
+ console.log('[Userflow] banner shown', {
50
+ flowId: session.flow.id,
51
+ flowName: session.flow.name,
52
+ bannerSessionId: session.id,
53
+ versionId: session.version.id,
54
+ embedMode: banner.embedMode,
55
+ overlay: banner.overlay !== false,
56
+ webView: needsWebView,
57
+ pushLayoutEdge: pushLayoutEdge ?? null,
58
+ overlaySafeEdge: overlaySafeEdge ?? null,
59
+ hostAsOverlay: banner.overlay !== false || needsWebView,
60
+ });
61
+ }, [
62
+ banner,
63
+ needsWebView,
64
+ overlaySafeEdge,
65
+ pushLayoutEdge,
66
+ session.flow.id,
67
+ session.flow.name,
68
+ session.id,
69
+ session.version.id,
70
+ ]);
71
+
38
72
  React.useLayoutEffect(() => {
39
73
  if (!needsWebView || !webView) {
40
74
  return;
@@ -69,13 +103,35 @@ export function BannerSurface({
69
103
  );
70
104
  }
71
105
  }
72
- return <BannerBar session={session} onActions={onActions} onDismiss={onDismiss} />;
106
+ return (
107
+ <BannerBar
108
+ session={session}
109
+ pushLayoutEdge={pushLayoutEdge}
110
+ overlaySafeEdge={overlaySafeEdge}
111
+ onActions={onActions}
112
+ onDismiss={onDismiss}
113
+ />
114
+ );
73
115
  }
74
116
  return (
75
- <BannerWebViewBar session={session} onActions={onActions} onDismiss={dismissWebViewBanner} />
117
+ <BannerWebViewBar
118
+ session={session}
119
+ pushLayoutEdge={pushLayoutEdge}
120
+ overlaySafeEdge={overlaySafeEdge}
121
+ onActions={onActions}
122
+ onDismiss={dismissWebViewBanner}
123
+ />
76
124
  );
77
125
  }
78
- return <BannerBar session={session} onActions={onActions} onDismiss={onDismiss} />;
126
+ return (
127
+ <BannerBar
128
+ session={session}
129
+ pushLayoutEdge={pushLayoutEdge}
130
+ overlaySafeEdge={overlaySafeEdge}
131
+ onActions={onActions}
132
+ onDismiss={onDismiss}
133
+ />
134
+ );
79
135
  }
80
136
 
81
137
  /** @internal */