@userflow-tech/react-native 0.5.0 → 0.7.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 (328) hide show
  1. package/README.md +65 -33
  2. package/docs/custom-fonts.md +36 -0
  3. package/docs/troubleshooting.md +45 -44
  4. package/expo-plugin/hostDependencyWarnings.d.ts +5 -5
  5. package/expo-plugin/hostDependencyWarnings.js +7 -7
  6. package/expo-plugin/hostDependencyWarnings.js.map +1 -1
  7. package/lib/commonjs/anchors/AnchorRegistry.js +5 -0
  8. package/lib/commonjs/anchors/AnchorRegistry.js.map +1 -1
  9. package/lib/commonjs/anchors/ScrollContainerRegistry.js +8 -0
  10. package/lib/commonjs/anchors/ScrollContainerRegistry.js.map +1 -1
  11. package/lib/commonjs/anchors/fiber/FiberScanRootStore.js +8 -0
  12. package/lib/commonjs/anchors/fiber/FiberScanRootStore.js.map +1 -1
  13. package/lib/commonjs/anchors/fiber/detectAppFontFamily.js +341 -0
  14. package/lib/commonjs/anchors/fiber/detectAppFontFamily.js.map +1 -0
  15. package/lib/commonjs/anchors/fiber/presentedModal.js +215 -0
  16. package/lib/commonjs/anchors/fiber/presentedModal.js.map +1 -0
  17. package/lib/commonjs/anchors/fiber/touchTargetFiber.js +1 -0
  18. package/lib/commonjs/anchors/fiber/touchTargetFiber.js.map +1 -1
  19. package/lib/commonjs/anchors/fiber/visibleRect.js +12 -3
  20. package/lib/commonjs/anchors/fiber/visibleRect.js.map +1 -1
  21. package/lib/commonjs/anchors/fiber/visibleScreens.js +6 -0
  22. package/lib/commonjs/anchors/fiber/visibleScreens.js.map +1 -1
  23. package/lib/commonjs/anchors/useUserflowAnchor.js.map +1 -1
  24. package/lib/commonjs/anchors/useUserflowScrollContainer.js.map +1 -1
  25. package/lib/commonjs/authoring/ElementPickerOverlay.js +197 -138
  26. package/lib/commonjs/authoring/ElementPickerOverlay.js.map +1 -1
  27. package/lib/commonjs/authoring/hitTest.js +67 -10
  28. package/lib/commonjs/authoring/hitTest.js.map +1 -1
  29. package/lib/commonjs/authoring/hostAtPoint.js +45 -21
  30. package/lib/commonjs/authoring/hostAtPoint.js.map +1 -1
  31. package/lib/commonjs/content/BannerStepButton.js +2 -1
  32. package/lib/commonjs/content/BannerStepButton.js.map +1 -1
  33. package/lib/commonjs/content/RichContentRenderer.js +27 -9
  34. package/lib/commonjs/content/RichContentRenderer.js.map +1 -1
  35. package/lib/commonjs/content/StepButton.js +2 -1
  36. package/lib/commonjs/content/StepButton.js.map +1 -1
  37. package/lib/commonjs/content/resolveContentFontFamily.js +96 -0
  38. package/lib/commonjs/content/resolveContentFontFamily.js.map +1 -0
  39. package/lib/commonjs/deepLinking.js.map +1 -1
  40. package/lib/commonjs/deviceContext.js +39 -19
  41. package/lib/commonjs/deviceContext.js.map +1 -1
  42. package/lib/commonjs/index.js +13 -5
  43. package/lib/commonjs/index.js.map +1 -1
  44. package/lib/commonjs/installCheck.js +3 -3
  45. package/lib/commonjs/installCheck.js.map +1 -1
  46. package/lib/commonjs/lifecycle.js +2 -0
  47. package/lib/commonjs/lifecycle.js.map +1 -1
  48. package/lib/commonjs/pairing/PairingController.js.map +1 -1
  49. package/lib/commonjs/runtime/BannerHost.js +3 -3
  50. package/lib/commonjs/runtime/BannerHost.js.map +1 -1
  51. package/lib/commonjs/runtime/UserflowOverlay.js +17 -13
  52. package/lib/commonjs/runtime/UserflowOverlay.js.map +1 -1
  53. package/lib/commonjs/runtime/WindowOverlayHost.js +83 -0
  54. package/lib/commonjs/runtime/WindowOverlayHost.js.map +1 -0
  55. package/lib/commonjs/runtime/pushBannerLayoutContext.js +11 -8
  56. package/lib/commonjs/runtime/pushBannerLayoutContext.js.map +1 -1
  57. package/lib/commonjs/runtime/userflowCore.js +9 -2
  58. package/lib/commonjs/runtime/userflowCore.js.map +1 -1
  59. package/lib/commonjs/surfaces/BannerSurface.js +2 -6
  60. package/lib/commonjs/surfaces/BannerSurface.js.map +1 -1
  61. package/lib/commonjs/surfaces/ProgressBar.js +2 -1
  62. package/lib/commonjs/surfaces/ProgressBar.js.map +1 -1
  63. package/lib/commonjs/surfaces/TooltipSurface.js +114 -51
  64. package/lib/commonjs/surfaces/TooltipSurface.js.map +1 -1
  65. package/lib/commonjs/surfaces/bannerWebView/BannerWebViewBar.js +6 -4
  66. package/lib/commonjs/surfaces/bannerWebView/BannerWebViewBar.js.map +1 -1
  67. package/lib/commonjs/surfaces/bannerWebView/bannerNeedsWebView.js +3 -33
  68. package/lib/commonjs/surfaces/bannerWebView/bannerNeedsWebView.js.map +1 -1
  69. package/lib/commonjs/surfaces/bannerWebView/bannerThemeStyles.js +2 -1
  70. package/lib/commonjs/surfaces/bannerWebView/bannerThemeStyles.js.map +1 -1
  71. package/lib/commonjs/surfaces/bannerWebView/bannerWebViewHeight.js +33 -0
  72. package/lib/commonjs/surfaces/bannerWebView/bannerWebViewHeight.js.map +1 -0
  73. package/lib/commonjs/surfaces/bannerWebView/buildCustomBannerHtml.js +45 -12
  74. package/lib/commonjs/surfaces/bannerWebView/buildCustomBannerHtml.js.map +1 -1
  75. package/lib/commonjs/surfaces/tooltip/TooltipHighlight.js +6 -6
  76. package/lib/commonjs/surfaces/tooltip/TooltipHighlight.js.map +1 -1
  77. package/lib/commonjs/surfaces/tooltip/targetOrigin.js +74 -0
  78. package/lib/commonjs/surfaces/tooltip/targetOrigin.js.map +1 -0
  79. package/lib/commonjs/version.js +1 -1
  80. package/lib/module/anchors/AnchorRegistry.js +5 -0
  81. package/lib/module/anchors/AnchorRegistry.js.map +1 -1
  82. package/lib/module/anchors/ScrollContainerRegistry.js +8 -0
  83. package/lib/module/anchors/ScrollContainerRegistry.js.map +1 -1
  84. package/lib/module/anchors/fiber/FiberScanRootStore.js +8 -0
  85. package/lib/module/anchors/fiber/FiberScanRootStore.js.map +1 -1
  86. package/lib/module/anchors/fiber/detectAppFontFamily.js +330 -0
  87. package/lib/module/anchors/fiber/detectAppFontFamily.js.map +1 -0
  88. package/lib/module/anchors/fiber/presentedModal.js +206 -0
  89. package/lib/module/anchors/fiber/presentedModal.js.map +1 -0
  90. package/lib/module/anchors/fiber/touchTargetFiber.js +1 -0
  91. package/lib/module/anchors/fiber/touchTargetFiber.js.map +1 -1
  92. package/lib/module/anchors/fiber/visibleRect.js +12 -3
  93. package/lib/module/anchors/fiber/visibleRect.js.map +1 -1
  94. package/lib/module/anchors/fiber/visibleScreens.js +5 -0
  95. package/lib/module/anchors/fiber/visibleScreens.js.map +1 -1
  96. package/lib/module/anchors/useUserflowAnchor.js.map +1 -1
  97. package/lib/module/anchors/useUserflowScrollContainer.js.map +1 -1
  98. package/lib/module/authoring/ElementPickerOverlay.js +199 -140
  99. package/lib/module/authoring/ElementPickerOverlay.js.map +1 -1
  100. package/lib/module/authoring/hitTest.js +67 -11
  101. package/lib/module/authoring/hitTest.js.map +1 -1
  102. package/lib/module/authoring/hostAtPoint.js +45 -21
  103. package/lib/module/authoring/hostAtPoint.js.map +1 -1
  104. package/lib/module/content/BannerStepButton.js +2 -1
  105. package/lib/module/content/BannerStepButton.js.map +1 -1
  106. package/lib/module/content/RichContentRenderer.js +27 -9
  107. package/lib/module/content/RichContentRenderer.js.map +1 -1
  108. package/lib/module/content/StepButton.js +2 -1
  109. package/lib/module/content/StepButton.js.map +1 -1
  110. package/lib/module/content/resolveContentFontFamily.js +89 -0
  111. package/lib/module/content/resolveContentFontFamily.js.map +1 -0
  112. package/lib/module/deepLinking.js.map +1 -1
  113. package/lib/module/deviceContext.js +38 -17
  114. package/lib/module/deviceContext.js.map +1 -1
  115. package/lib/module/index.js +13 -5
  116. package/lib/module/index.js.map +1 -1
  117. package/lib/module/installCheck.js +3 -3
  118. package/lib/module/installCheck.js.map +1 -1
  119. package/lib/module/lifecycle.js +2 -0
  120. package/lib/module/lifecycle.js.map +1 -1
  121. package/lib/module/pairing/PairingController.js.map +1 -1
  122. package/lib/module/runtime/BannerHost.js +3 -3
  123. package/lib/module/runtime/BannerHost.js.map +1 -1
  124. package/lib/module/runtime/UserflowOverlay.js +18 -14
  125. package/lib/module/runtime/UserflowOverlay.js.map +1 -1
  126. package/lib/module/runtime/WindowOverlayHost.js +76 -0
  127. package/lib/module/runtime/WindowOverlayHost.js.map +1 -0
  128. package/lib/module/runtime/pushBannerLayoutContext.js +11 -8
  129. package/lib/module/runtime/pushBannerLayoutContext.js.map +1 -1
  130. package/lib/module/runtime/userflowCore.js +9 -2
  131. package/lib/module/runtime/userflowCore.js.map +1 -1
  132. package/lib/module/surfaces/BannerSurface.js +2 -6
  133. package/lib/module/surfaces/BannerSurface.js.map +1 -1
  134. package/lib/module/surfaces/ProgressBar.js +2 -1
  135. package/lib/module/surfaces/ProgressBar.js.map +1 -1
  136. package/lib/module/surfaces/TooltipSurface.js +114 -51
  137. package/lib/module/surfaces/TooltipSurface.js.map +1 -1
  138. package/lib/module/surfaces/bannerWebView/BannerWebViewBar.js +6 -4
  139. package/lib/module/surfaces/bannerWebView/BannerWebViewBar.js.map +1 -1
  140. package/lib/module/surfaces/bannerWebView/bannerNeedsWebView.js +3 -31
  141. package/lib/module/surfaces/bannerWebView/bannerNeedsWebView.js.map +1 -1
  142. package/lib/module/surfaces/bannerWebView/bannerThemeStyles.js +2 -1
  143. package/lib/module/surfaces/bannerWebView/bannerThemeStyles.js.map +1 -1
  144. package/lib/module/surfaces/bannerWebView/bannerWebViewHeight.js +29 -0
  145. package/lib/module/surfaces/bannerWebView/bannerWebViewHeight.js.map +1 -0
  146. package/lib/module/surfaces/bannerWebView/buildCustomBannerHtml.js +45 -12
  147. package/lib/module/surfaces/bannerWebView/buildCustomBannerHtml.js.map +1 -1
  148. package/lib/module/surfaces/tooltip/TooltipHighlight.js +6 -6
  149. package/lib/module/surfaces/tooltip/TooltipHighlight.js.map +1 -1
  150. package/lib/module/surfaces/tooltip/targetOrigin.js +67 -0
  151. package/lib/module/surfaces/tooltip/targetOrigin.js.map +1 -0
  152. package/lib/module/version.js +1 -1
  153. package/lib/typescript/commonjs/src/anchors/AnchorRegistry.d.ts +7 -0
  154. package/lib/typescript/commonjs/src/anchors/AnchorRegistry.d.ts.map +1 -1
  155. package/lib/typescript/commonjs/src/anchors/ScrollContainerRegistry.d.ts +11 -2
  156. package/lib/typescript/commonjs/src/anchors/ScrollContainerRegistry.d.ts.map +1 -1
  157. package/lib/typescript/commonjs/src/anchors/fiber/FiberScanRootStore.d.ts +5 -0
  158. package/lib/typescript/commonjs/src/anchors/fiber/FiberScanRootStore.d.ts.map +1 -1
  159. package/lib/typescript/commonjs/src/anchors/fiber/detectAppFontFamily.d.ts +30 -0
  160. package/lib/typescript/commonjs/src/anchors/fiber/detectAppFontFamily.d.ts.map +1 -0
  161. package/lib/typescript/commonjs/src/anchors/fiber/presentedModal.d.ts +45 -0
  162. package/lib/typescript/commonjs/src/anchors/fiber/presentedModal.d.ts.map +1 -0
  163. package/lib/typescript/commonjs/src/anchors/fiber/visibleRect.d.ts +5 -2
  164. package/lib/typescript/commonjs/src/anchors/fiber/visibleRect.d.ts.map +1 -1
  165. package/lib/typescript/commonjs/src/anchors/fiber/visibleScreens.d.ts +2 -0
  166. package/lib/typescript/commonjs/src/anchors/fiber/visibleScreens.d.ts.map +1 -1
  167. package/lib/typescript/commonjs/src/anchors/useUserflowAnchor.d.ts +2 -2
  168. package/lib/typescript/commonjs/src/anchors/useUserflowAnchor.d.ts.map +1 -1
  169. package/lib/typescript/commonjs/src/anchors/useUserflowScrollContainer.d.ts +3 -2
  170. package/lib/typescript/commonjs/src/anchors/useUserflowScrollContainer.d.ts.map +1 -1
  171. package/lib/typescript/commonjs/src/authoring/ElementPickerOverlay.d.ts +4 -0
  172. package/lib/typescript/commonjs/src/authoring/ElementPickerOverlay.d.ts.map +1 -1
  173. package/lib/typescript/commonjs/src/authoring/hitTest.d.ts +25 -2
  174. package/lib/typescript/commonjs/src/authoring/hitTest.d.ts.map +1 -1
  175. package/lib/typescript/commonjs/src/authoring/hostAtPoint.d.ts +6 -1
  176. package/lib/typescript/commonjs/src/authoring/hostAtPoint.d.ts.map +1 -1
  177. package/lib/typescript/commonjs/src/content/BannerStepButton.d.ts.map +1 -1
  178. package/lib/typescript/commonjs/src/content/RichContentRenderer.d.ts.map +1 -1
  179. package/lib/typescript/commonjs/src/content/StepButton.d.ts.map +1 -1
  180. package/lib/typescript/commonjs/src/content/resolveContentFontFamily.d.ts +35 -0
  181. package/lib/typescript/commonjs/src/content/resolveContentFontFamily.d.ts.map +1 -0
  182. package/lib/typescript/commonjs/src/deepLinking.d.ts +1 -1
  183. package/lib/typescript/commonjs/src/deepLinking.d.ts.map +1 -1
  184. package/lib/typescript/commonjs/src/deviceContext.d.ts +14 -5
  185. package/lib/typescript/commonjs/src/deviceContext.d.ts.map +1 -1
  186. package/lib/typescript/commonjs/src/index.d.ts +11 -5
  187. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  188. package/lib/typescript/commonjs/src/installCheck.d.ts +2 -2
  189. package/lib/typescript/commonjs/src/installCheck.d.ts.map +1 -1
  190. package/lib/typescript/commonjs/src/lifecycle.d.ts +1 -0
  191. package/lib/typescript/commonjs/src/lifecycle.d.ts.map +1 -1
  192. package/lib/typescript/commonjs/src/pairing/PairingController.d.ts +1 -1
  193. package/lib/typescript/commonjs/src/pairing/PairingController.d.ts.map +1 -1
  194. package/lib/typescript/commonjs/src/runtime/UserflowOverlay.d.ts.map +1 -1
  195. package/lib/typescript/commonjs/src/runtime/WindowOverlayHost.d.ts +34 -0
  196. package/lib/typescript/commonjs/src/runtime/WindowOverlayHost.d.ts.map +1 -0
  197. package/lib/typescript/commonjs/src/runtime/pushBannerLayoutContext.d.ts +5 -0
  198. package/lib/typescript/commonjs/src/runtime/pushBannerLayoutContext.d.ts.map +1 -1
  199. package/lib/typescript/commonjs/src/runtime/userflowCore.d.ts.map +1 -1
  200. package/lib/typescript/commonjs/src/surfaces/BannerSurface.d.ts +1 -4
  201. package/lib/typescript/commonjs/src/surfaces/BannerSurface.d.ts.map +1 -1
  202. package/lib/typescript/commonjs/src/surfaces/ProgressBar.d.ts.map +1 -1
  203. package/lib/typescript/commonjs/src/surfaces/TooltipSurface.d.ts.map +1 -1
  204. package/lib/typescript/commonjs/src/surfaces/bannerWebView/BannerWebViewBar.d.ts.map +1 -1
  205. package/lib/typescript/commonjs/src/surfaces/bannerWebView/bannerNeedsWebView.d.ts +3 -12
  206. package/lib/typescript/commonjs/src/surfaces/bannerWebView/bannerNeedsWebView.d.ts.map +1 -1
  207. package/lib/typescript/commonjs/src/surfaces/bannerWebView/bannerThemeStyles.d.ts.map +1 -1
  208. package/lib/typescript/commonjs/src/surfaces/bannerWebView/bannerWebViewHeight.d.ts +13 -0
  209. package/lib/typescript/commonjs/src/surfaces/bannerWebView/bannerWebViewHeight.d.ts.map +1 -0
  210. package/lib/typescript/commonjs/src/surfaces/bannerWebView/buildCustomBannerHtml.d.ts.map +1 -1
  211. package/lib/typescript/commonjs/src/surfaces/tooltip/targetOrigin.d.ts +26 -0
  212. package/lib/typescript/commonjs/src/surfaces/tooltip/targetOrigin.d.ts.map +1 -0
  213. package/lib/typescript/commonjs/src/version.d.ts +1 -1
  214. package/lib/typescript/module/src/anchors/AnchorRegistry.d.ts +7 -0
  215. package/lib/typescript/module/src/anchors/AnchorRegistry.d.ts.map +1 -1
  216. package/lib/typescript/module/src/anchors/ScrollContainerRegistry.d.ts +11 -2
  217. package/lib/typescript/module/src/anchors/ScrollContainerRegistry.d.ts.map +1 -1
  218. package/lib/typescript/module/src/anchors/fiber/FiberScanRootStore.d.ts +5 -0
  219. package/lib/typescript/module/src/anchors/fiber/FiberScanRootStore.d.ts.map +1 -1
  220. package/lib/typescript/module/src/anchors/fiber/detectAppFontFamily.d.ts +30 -0
  221. package/lib/typescript/module/src/anchors/fiber/detectAppFontFamily.d.ts.map +1 -0
  222. package/lib/typescript/module/src/anchors/fiber/presentedModal.d.ts +45 -0
  223. package/lib/typescript/module/src/anchors/fiber/presentedModal.d.ts.map +1 -0
  224. package/lib/typescript/module/src/anchors/fiber/visibleRect.d.ts +5 -2
  225. package/lib/typescript/module/src/anchors/fiber/visibleRect.d.ts.map +1 -1
  226. package/lib/typescript/module/src/anchors/fiber/visibleScreens.d.ts +2 -0
  227. package/lib/typescript/module/src/anchors/fiber/visibleScreens.d.ts.map +1 -1
  228. package/lib/typescript/module/src/anchors/useUserflowAnchor.d.ts +2 -2
  229. package/lib/typescript/module/src/anchors/useUserflowAnchor.d.ts.map +1 -1
  230. package/lib/typescript/module/src/anchors/useUserflowScrollContainer.d.ts +3 -2
  231. package/lib/typescript/module/src/anchors/useUserflowScrollContainer.d.ts.map +1 -1
  232. package/lib/typescript/module/src/authoring/ElementPickerOverlay.d.ts +4 -0
  233. package/lib/typescript/module/src/authoring/ElementPickerOverlay.d.ts.map +1 -1
  234. package/lib/typescript/module/src/authoring/hitTest.d.ts +25 -2
  235. package/lib/typescript/module/src/authoring/hitTest.d.ts.map +1 -1
  236. package/lib/typescript/module/src/authoring/hostAtPoint.d.ts +6 -1
  237. package/lib/typescript/module/src/authoring/hostAtPoint.d.ts.map +1 -1
  238. package/lib/typescript/module/src/content/BannerStepButton.d.ts.map +1 -1
  239. package/lib/typescript/module/src/content/RichContentRenderer.d.ts.map +1 -1
  240. package/lib/typescript/module/src/content/StepButton.d.ts.map +1 -1
  241. package/lib/typescript/module/src/content/resolveContentFontFamily.d.ts +35 -0
  242. package/lib/typescript/module/src/content/resolveContentFontFamily.d.ts.map +1 -0
  243. package/lib/typescript/module/src/deepLinking.d.ts +1 -1
  244. package/lib/typescript/module/src/deepLinking.d.ts.map +1 -1
  245. package/lib/typescript/module/src/deviceContext.d.ts +14 -5
  246. package/lib/typescript/module/src/deviceContext.d.ts.map +1 -1
  247. package/lib/typescript/module/src/index.d.ts +11 -5
  248. package/lib/typescript/module/src/index.d.ts.map +1 -1
  249. package/lib/typescript/module/src/installCheck.d.ts +2 -2
  250. package/lib/typescript/module/src/installCheck.d.ts.map +1 -1
  251. package/lib/typescript/module/src/lifecycle.d.ts +1 -0
  252. package/lib/typescript/module/src/lifecycle.d.ts.map +1 -1
  253. package/lib/typescript/module/src/pairing/PairingController.d.ts +1 -1
  254. package/lib/typescript/module/src/pairing/PairingController.d.ts.map +1 -1
  255. package/lib/typescript/module/src/runtime/UserflowOverlay.d.ts.map +1 -1
  256. package/lib/typescript/module/src/runtime/WindowOverlayHost.d.ts +34 -0
  257. package/lib/typescript/module/src/runtime/WindowOverlayHost.d.ts.map +1 -0
  258. package/lib/typescript/module/src/runtime/pushBannerLayoutContext.d.ts +5 -0
  259. package/lib/typescript/module/src/runtime/pushBannerLayoutContext.d.ts.map +1 -1
  260. package/lib/typescript/module/src/runtime/userflowCore.d.ts.map +1 -1
  261. package/lib/typescript/module/src/surfaces/BannerSurface.d.ts +1 -4
  262. package/lib/typescript/module/src/surfaces/BannerSurface.d.ts.map +1 -1
  263. package/lib/typescript/module/src/surfaces/ProgressBar.d.ts.map +1 -1
  264. package/lib/typescript/module/src/surfaces/TooltipSurface.d.ts.map +1 -1
  265. package/lib/typescript/module/src/surfaces/bannerWebView/BannerWebViewBar.d.ts.map +1 -1
  266. package/lib/typescript/module/src/surfaces/bannerWebView/bannerNeedsWebView.d.ts +3 -12
  267. package/lib/typescript/module/src/surfaces/bannerWebView/bannerNeedsWebView.d.ts.map +1 -1
  268. package/lib/typescript/module/src/surfaces/bannerWebView/bannerThemeStyles.d.ts.map +1 -1
  269. package/lib/typescript/module/src/surfaces/bannerWebView/bannerWebViewHeight.d.ts +13 -0
  270. package/lib/typescript/module/src/surfaces/bannerWebView/bannerWebViewHeight.d.ts.map +1 -0
  271. package/lib/typescript/module/src/surfaces/bannerWebView/buildCustomBannerHtml.d.ts.map +1 -1
  272. package/lib/typescript/module/src/surfaces/tooltip/targetOrigin.d.ts +26 -0
  273. package/lib/typescript/module/src/surfaces/tooltip/targetOrigin.d.ts.map +1 -0
  274. package/lib/typescript/module/src/version.d.ts +1 -1
  275. package/package.json +5 -4
  276. package/src/anchors/AnchorRegistry.ts +8 -0
  277. package/src/anchors/ScrollContainerRegistry.ts +15 -3
  278. package/src/anchors/fiber/FiberScanRootStore.ts +8 -0
  279. package/src/anchors/fiber/detectAppFontFamily.ts +400 -0
  280. package/src/anchors/fiber/presentedModal.ts +203 -0
  281. package/src/anchors/fiber/touchTargetFiber.ts +2 -1
  282. package/src/anchors/fiber/visibleRect.ts +12 -3
  283. package/src/anchors/fiber/visibleScreens.ts +5 -0
  284. package/src/anchors/useUserflowAnchor.ts +4 -5
  285. package/src/anchors/useUserflowScrollContainer.ts +5 -4
  286. package/src/authoring/ElementPickerOverlay.tsx +242 -166
  287. package/src/authoring/hitTest.ts +88 -13
  288. package/src/authoring/hostAtPoint.ts +67 -21
  289. package/src/content/BannerStepButton.tsx +2 -1
  290. package/src/content/RichContentRenderer.tsx +16 -9
  291. package/src/content/StepButton.tsx +2 -1
  292. package/src/content/resolveContentFontFamily.ts +119 -0
  293. package/src/deepLinking.ts +2 -1
  294. package/src/deviceContext.ts +50 -14
  295. package/src/index.ts +13 -5
  296. package/src/installCheck.ts +3 -3
  297. package/src/lifecycle.ts +2 -1
  298. package/src/pairing/PairingController.ts +2 -1
  299. package/src/runtime/BannerHost.tsx +3 -3
  300. package/src/runtime/UserflowOverlay.tsx +29 -21
  301. package/src/runtime/WindowOverlayHost.tsx +95 -0
  302. package/src/runtime/pushBannerLayoutContext.tsx +14 -9
  303. package/src/runtime/userflowCore.ts +8 -2
  304. package/src/surfaces/BannerSurface.tsx +2 -6
  305. package/src/surfaces/ProgressBar.tsx +2 -1
  306. package/src/surfaces/TooltipSurface.tsx +118 -47
  307. package/src/surfaces/bannerWebView/BannerWebViewBar.tsx +6 -4
  308. package/src/surfaces/bannerWebView/bannerNeedsWebView.ts +4 -36
  309. package/src/surfaces/bannerWebView/bannerThemeStyles.ts +2 -1
  310. package/src/surfaces/bannerWebView/bannerWebViewHeight.ts +32 -0
  311. package/src/surfaces/bannerWebView/buildCustomBannerHtml.ts +48 -12
  312. package/src/surfaces/tooltip/TooltipHighlight.tsx +3 -5
  313. package/src/surfaces/tooltip/targetOrigin.ts +74 -0
  314. package/src/version.ts +1 -1
  315. package/vendor/core/dist/engine/UserflowCore.d.ts +7 -0
  316. package/vendor/core/dist/engine/UserflowCore.d.ts.map +1 -1
  317. package/vendor/core/dist/engine/UserflowCore.js +3 -2
  318. package/vendor/core/dist/engine/UserflowCore.js.map +1 -1
  319. package/vendor/core/dist/transport/phoenix.d.ts +12 -2
  320. package/vendor/core/dist/transport/phoenix.d.ts.map +1 -1
  321. package/vendor/core/dist/transport/phoenix.js +7 -6
  322. package/vendor/core/dist/transport/phoenix.js.map +1 -1
  323. package/vendor/core/dist/version.d.ts +1 -1
  324. package/vendor/core/dist/version.js +1 -1
  325. package/vendor/core/package.json +1 -1
  326. package/vendor/protocol/dist/flows.d.ts +2 -0
  327. package/vendor/protocol/dist/flows.d.ts.map +1 -1
  328. package/vendor/protocol/package.json +1 -1
@@ -1,16 +1,24 @@
1
1
  /**
2
- * Resolve mobile platform metadata for Userflow user attributes.
2
+ * Resolve mobile platform metadata and the running SDK version for Userflow
3
+ * user attributes.
3
4
  *
4
5
  * Cached once during {@link Userflow.init} and merged into identify attributes
5
6
  * (same lifecycle as {@link hostAppVersion.ts}).
6
7
  */
7
8
 
9
+ import { SDK_VERSION } from './version';
10
+
8
11
  export type SdkPlatform = 'react_native';
9
12
  export type DeviceOs = 'ios' | 'android';
10
13
  export type DeviceType = 'phone' | 'tablet';
11
14
 
12
15
  export interface DeviceContext {
13
16
  sdk: SdkPlatform;
17
+ /**
18
+ * Published `@userflow-tech/react-native` version, e.g. `0.4.6`. Always set by
19
+ * the SDK; optional so context objects built by host code (mocks) stay valid.
20
+ */
21
+ sdkVersion?: string;
14
22
  deviceOs?: DeviceOs;
15
23
  deviceType?: DeviceType;
16
24
  }
@@ -19,6 +27,7 @@ export interface DeviceContext {
19
27
  export const ANDROID_TABLET_SMALLEST_WIDTH_DP = 600;
20
28
 
21
29
  export const SDK_USER_ATTRIBUTE = 'sdk';
30
+ export const SDK_VERSION_USER_ATTRIBUTE = 'sdk_version';
22
31
  export const DEVICE_OS_USER_ATTRIBUTE = 'device_os';
23
32
  export const DEVICE_TYPE_USER_ATTRIBUTE = 'device_type';
24
33
 
@@ -70,6 +79,7 @@ export function resolveDeviceContextFromSources(sources: {
70
79
  const deviceType = resolveDeviceTypeFromSources(sources);
71
80
  return {
72
81
  sdk: 'react_native',
82
+ sdkVersion: SDK_VERSION,
73
83
  ...(deviceOs ? { deviceOs } : {}),
74
84
  ...(deviceType ? { deviceType } : {}),
75
85
  };
@@ -103,6 +113,7 @@ export function resolveDeviceContext(): DeviceContext {
103
113
 
104
114
  /** `undefined` until the first {@link cacheDeviceContextAtInit}; then resolved. */
105
115
  let cachedDeviceContext: DeviceContext | undefined;
116
+ let didWarnSdkVersionOverride = false;
106
117
 
107
118
  /**
108
119
  * Resolve and cache device metadata during {@link Userflow.init}.
@@ -118,33 +129,57 @@ export function getCachedDeviceContext(): DeviceContext | null {
118
129
  return cachedDeviceContext ?? null;
119
130
  }
120
131
 
121
- /** Returns cached device fields for UpsertUser, or `{}` before init. */
122
- export function deviceContextUserAttributes(): Record<string, string> {
123
- const cached = getCachedDeviceContext();
124
- if (!cached) return {};
132
+ /** Device fields for UpsertUser that identify attributes may override. */
133
+ function overridableDeviceAttributes(context: DeviceContext): Record<string, string> {
125
134
  return {
126
- [SDK_USER_ATTRIBUTE]: cached.sdk,
127
- ...(cached.deviceOs ? { [DEVICE_OS_USER_ATTRIBUTE]: cached.deviceOs } : {}),
128
- ...(cached.deviceType ? { [DEVICE_TYPE_USER_ATTRIBUTE]: cached.deviceType } : {}),
135
+ [SDK_USER_ATTRIBUTE]: context.sdk,
136
+ ...(context.deviceOs ? { [DEVICE_OS_USER_ATTRIBUTE]: context.deviceOs } : {}),
137
+ ...(context.deviceType ? { [DEVICE_TYPE_USER_ATTRIBUTE]: context.deviceType } : {}),
129
138
  };
130
139
  }
131
140
 
132
141
  /** Optional user-attribute keys added by {@link mergeDeviceContextUserAttributes}. */
133
142
  export type DeviceContextUserAttributeMap = Partial<{
134
143
  [SDK_USER_ATTRIBUTE]: SdkPlatform;
144
+ [SDK_VERSION_USER_ATTRIBUTE]: string;
135
145
  [DEVICE_OS_USER_ATTRIBUTE]: DeviceOs;
136
146
  [DEVICE_TYPE_USER_ATTRIBUTE]: DeviceType;
137
147
  }>;
138
148
 
139
- /** Merges cached device attrs into identify attributes; caller values win on key conflicts. */
149
+ /** One development warning when identify attributes try to set `sdk_version`. */
150
+ function warnIfSdkVersionOverridden(attributes: Record<string, unknown> | undefined): void {
151
+ if (!__DEV__ || didWarnSdkVersionOverride) return;
152
+ const passed = attributes?.[SDK_VERSION_USER_ATTRIBUTE];
153
+ // `{ set: value }` is the long form of a bare literal.
154
+ const value =
155
+ typeof passed === 'object' && passed !== null && 'set' in passed
156
+ ? (passed as { set: unknown }).set
157
+ : passed;
158
+ if (value === undefined || value === SDK_VERSION) return;
159
+ didWarnSdkVersionOverride = true;
160
+ // eslint-disable-next-line no-console -- intentional development diagnostic
161
+ console.warn(
162
+ `[Userflow] "${SDK_VERSION_USER_ATTRIBUTE}" is set by the SDK (${SDK_VERSION}); the value passed to identify / identifyAnonymous was ignored.`,
163
+ );
164
+ }
165
+
166
+ /**
167
+ * Merges cached device attrs into identify attributes. Caller values win on key
168
+ * conflicts, except `sdk_version`, which always reports the running SDK.
169
+ */
140
170
  export function mergeDeviceContextUserAttributes<T extends Record<string, unknown>>(
141
171
  attributes?: T,
142
172
  ): (T & DeviceContextUserAttributeMap) | undefined {
143
- const system = deviceContextUserAttributes();
144
- if (Object.keys(system).length === 0) {
173
+ const cached = getCachedDeviceContext();
174
+ if (!cached) {
145
175
  return attributes as (T & DeviceContextUserAttributeMap) | undefined;
146
176
  }
147
- return { ...system, ...(attributes ?? {}) } as T & DeviceContextUserAttributeMap;
177
+ warnIfSdkVersionOverridden(attributes);
178
+ return {
179
+ ...overridableDeviceAttributes(cached),
180
+ ...(attributes ?? {}),
181
+ [SDK_VERSION_USER_ATTRIBUTE]: SDK_VERSION,
182
+ } as T & DeviceContextUserAttributeMap;
148
183
  }
149
184
 
150
185
  export function formatDeviceContextLog(resolved: DeviceContext | null): string {
@@ -153,7 +188,7 @@ export function formatDeviceContextLog(resolved: DeviceContext | null): string {
153
188
  }
154
189
  const os = resolved.deviceOs ?? 'unknown';
155
190
  const type = resolved.deviceType ?? 'unknown';
156
- return `[Userflow] device context sdk=${resolved.sdk} device_os=${os} device_type=${type}`;
191
+ return `[Userflow] device context sdk=${resolved.sdk} sdk_version=${resolved.sdkVersion ?? 'unknown'} device_os=${os} device_type=${type}`;
157
192
  }
158
193
 
159
194
  /** Log cached user-attribute values. Requires {@link cacheDeviceContextAtInit}. */
@@ -162,7 +197,8 @@ export function logDeviceContext(): void {
162
197
  console.log(formatDeviceContextLog(getCachedDeviceContext()));
163
198
  }
164
199
 
165
- /** @internal Resets init cache between tests. */
200
+ /** @internal Resets init cache and the one-time override warning between tests. */
166
201
  export function resetCachedDeviceContextForTests(): void {
167
202
  cachedDeviceContext = undefined;
203
+ didWarnSdkVersionOverride = false;
168
204
  }
package/src/index.ts CHANGED
@@ -22,6 +22,7 @@ import type {
22
22
 
23
23
  import './anchors/autoAnchor';
24
24
  import { anchorChangeTicker } from './anchors/anchorChangeTicker';
25
+ import { resetDetectedAppFont } from './anchors/fiber/detectAppFontFamily';
25
26
  import { notifyAnchorScreenChange } from './anchors/resolveAnchorHost';
26
27
  import {
27
28
  setCustomScrollIntoView as setCustomScrollIntoViewConfig,
@@ -367,7 +368,10 @@ export const Userflow = {
367
368
  setOnNavigate(handler: FlowNavigateHandler | null | undefined): void {
368
369
  setHostOnNavigate(handler);
369
370
  },
370
- /** Identify the current user and upsert their attributes. */
371
+ /**
372
+ * Identify the current user and upsert their attributes. The SDK adds `sdk_version`
373
+ * itself; a value passed for it here is ignored.
374
+ */
371
375
  async identify(
372
376
  userId: string,
373
377
  attributes?: UserflowAttributes,
@@ -390,7 +394,10 @@ export const Userflow = {
390
394
  await core.identify(userId, mergeSystemUserAttributes(attributes), options);
391
395
  await afterIdentify();
392
396
  },
393
- /** Identify an anonymous user with a stable auto-generated id stored on device. */
397
+ /**
398
+ * Identify an anonymous user with a stable auto-generated id stored on device. Like
399
+ * {@link identify}, the SDK sets `sdk_version` itself.
400
+ */
394
401
  async identifyAnonymous(
395
402
  attributes?: UserflowAttributes,
396
403
  options?: UserflowIdentifyOptions,
@@ -477,8 +484,8 @@ export const Userflow = {
477
484
  return getCachedHostAppVersion();
478
485
  },
479
486
  /**
480
- * Platform metadata cached during {@link init} (`sdk`, `deviceOs`, `deviceType`),
481
- * or `null` before init.
487
+ * Platform metadata cached during {@link init} (`sdk`, `sdkVersion`, `deviceOs`,
488
+ * `deviceType`), or `null` before init.
482
489
  */
483
490
  getDeviceContext(): DeviceContext | null {
484
491
  return getCachedDeviceContext();
@@ -493,6 +500,7 @@ export const Userflow = {
493
500
  },
494
501
  /** Clears the current user identity and disconnects from Userflow. */
495
502
  async reset(): Promise<void> {
503
+ resetDetectedAppFont();
496
504
  resetClientConditionEngine();
497
505
  resetFlowSessionEngine();
498
506
  resetBannerSessionEngine();
@@ -574,7 +582,7 @@ export const Userflow = {
574
582
  logHostAppVersionToConsole();
575
583
  },
576
584
  /**
577
- * Log cached user-attribute values (`sdk`, `device_os`, `device_type`).
585
+ * Log cached user-attribute values (`sdk`, `sdk_version`, `device_os`, `device_type`).
578
586
  * Requires {@link init}; before init, logs that init is required.
579
587
  */
580
588
  logDeviceContext(): void {
@@ -10,7 +10,7 @@ export const INSTALL_ASYNC_STORAGE_LINE =
10
10
  '- @react-native-async-storage/async-storage is not linked. Anonymous users and Builder pairing will not persist. Add it to the app package.json (npx expo install @react-native-async-storage/async-storage), run pod install on iOS, and rebuild.';
11
11
 
12
12
  export const INSTALL_VIEW_SHOT_LINE =
13
- '- react-native-view-shot is not linked, so Builder element selection gets no screenshot. Install it and rebuild. On Expo SDK 56 and 57, run npx expo install react-native-view-shot unpinned, with no expo.install.exclude entry for it. Otherwise install react-native-view-shot@^5.0.0; on Expo SDK 55 and older, an unpinned npx expo install resolves 4.0.3.';
13
+ '- react-native-view-shot is not linked, so Builder element selection gets no screenshot. Install it and rebuild. On Expo SDK 56 to 58, run npx expo install react-native-view-shot unpinned, with no expo.install.exclude entry for it. Otherwise install react-native-view-shot@^5.0.0; on Expo SDK 55 and older, an unpinned npx expo install resolves 4.0.3.';
14
14
 
15
15
  export const INSTALL_WEBVIEW_LINE =
16
16
  '- react-native-webview is not linked. Evaluate JavaScript and WebView banners will not run. Install it (npx expo install react-native-webview) and rebuild.';
@@ -36,7 +36,7 @@ export const INSTALL_SAFE_AREA_WARNING =
36
36
  export function formatViewShotVersionWarning(version: string): string {
37
37
  return (
38
38
  `[Userflow] react-native-view-shot@${version} is older than 5.0.0, so Builder element selection may not get a screenshot. ` +
39
- 'On Expo SDK 56 and 57, run npx expo install react-native-view-shot unpinned, with no expo.install.exclude entry for it, and rebuild. ' +
39
+ 'On Expo SDK 56 to 58, run npx expo install react-native-view-shot unpinned, with no expo.install.exclude entry for it, and rebuild. ' +
40
40
  'Otherwise install react-native-view-shot@^5.0.0 in the same command as the SDK and rebuild; on Expo SDK 55 and older, also add "react-native-view-shot" to expo.install.exclude. ' +
41
41
  'Do not retry the install with --force or --legacy-peer-deps; that leaves this version in place.\n' +
42
42
  INSTALL_CHECK_FOOTER
@@ -89,7 +89,7 @@ function readViewShotVersion(): string | null {
89
89
  }
90
90
  }
91
91
 
92
- /** Dev warning when view-shot 4.x is installed. Null on 5.x or when it is absent. */
92
+ /** Dev warning when view-shot 4.x is installed. Null on 5.x and later, or when it is absent. */
93
93
  export function viewShotVersionWarning(): string | null {
94
94
  const version = readViewShotVersion();
95
95
  if (!version) return null;
package/src/lifecycle.ts CHANGED
@@ -94,7 +94,8 @@ export class LifecycleController {
94
94
  private readonly scheduler: LifecycleScheduler;
95
95
  private readonly now: () => number;
96
96
  private readonly suspendGraceMs: number;
97
- private readonly getCurrentAppState: () => AppStateStatus;
97
+ /** Wider than AppStateStatus: React Native 0.88 types currentState as `string | null | undefined`. */
98
+ private readonly getCurrentAppState: () => string | null | undefined;
98
99
  private readonly subscribeAppState: (handler: (status: AppStateStatus) => void) => () => void;
99
100
 
100
101
  private unsubscribeAppState: (() => void) | null = null;
@@ -59,7 +59,8 @@ export interface PairingControllerOptions {
59
59
  */
60
60
  cancelPendingDraftEnd?: () => void;
61
61
  LinkingModule?: {
62
- getInitialURL(): Promise<string | null>;
62
+ // React Native 0.88 adds undefined to the result.
63
+ getInitialURL(): Promise<string | null | undefined>;
63
64
  addEventListener(type: 'url', handler: (event: { url: string }) => void): { remove(): void };
64
65
  };
65
66
  AppStateModule?: {
@@ -49,15 +49,15 @@ export function BannerHost({
49
49
  if (edgeFilter && edge !== edgeFilter) return null;
50
50
 
51
51
  const floats = banner.overlay !== false;
52
- const usesWebView = bannerNeedsWebView(banner, session.version.theme);
53
- // Custom-css / eval WebViews paint in the overlay host (same as userflow.js). A second
52
+ const usesWebView = bannerNeedsWebView(banner);
53
+ // Custom banner WebViews paint in the overlay host (same as userflow.js). A second
54
54
  // WKWebView in the flow slot often fails to load after the first banner dismisses.
55
55
  const hostAsOverlay = floats || usesWebView;
56
56
  if ((placement === 'overlay') !== hostAsOverlay) return null;
57
57
 
58
58
  const pushLayoutEdge = placement === 'flow' && !hostAsOverlay ? edge : null;
59
59
  // Builder overlay:true floats below the status bar. Push-layout WebViews in the overlay
60
- // host still paint safe-area chrome (overlay:false + custom CSS).
60
+ // host still paint safe-area chrome (overlay:false + custom banner).
61
61
  const overlaySafeEdge = hostAsOverlay && !floats ? edge : null;
62
62
 
63
63
  const surface = (
@@ -12,6 +12,7 @@ import { stepTrapsHostAccessibility } from '../surfaces/hostAccessibilityTrap';
12
12
 
13
13
  import { BannerHost } from './BannerHost';
14
14
  import { FlowRenderer } from './FlowRenderer';
15
+ import { WindowOverlayHost } from './WindowOverlayHost';
15
16
  import { useFlowSessionState } from './useFlowSessionState';
16
17
  import { getUserflowCore } from './userflowCore';
17
18
 
@@ -86,30 +87,37 @@ export function UserflowOverlay({
86
87
  * destroy a running script. `suppressed` hides it for the pick.
87
88
  */}
88
89
  <EvalJsHost suppressed={pickerActive} />
89
- <PreviewModeBanner
90
- onConfirmingChange={setPreviewConfirming}
91
- onExit={onExitPreview}
92
- held={previewHeld}
93
- onRestart={onRestartPreview}
94
- state={pairingState}
95
- suppressed={pickerActive}
96
- />
97
90
  {/*
98
- * Unmount flow chrome for the whole pick. The session stays alive;
99
- * captureScreen would otherwise include the modal or tooltip.
100
- * Remounting reads the same session back.
91
+ * One host for all three, so they keep this paint order above native
92
+ * modal screens. The host app's trap does not reach a natively presented
93
+ * modal, so the host traps VoiceOver itself.
101
94
  */}
102
- {pickerActive ? null : (
103
- <FlowRenderer
104
- engine={engine}
105
- previewRestartGeneration={pairingState.previewRestartGeneration}
95
+ <WindowOverlayHost accessibilityModal={trapHostAccessibility}>
96
+ <PreviewModeBanner
97
+ onConfirmingChange={setPreviewConfirming}
98
+ onExit={onExitPreview}
99
+ held={previewHeld}
100
+ onRestart={onRestartPreview}
101
+ state={pairingState}
102
+ suppressed={pickerActive}
106
103
  />
107
- )}
108
- {/*
109
- * After flow chrome so BODY_FIRST / BODY_LAST overlay banners stay visible
110
- * while a tour step (modal, tooltip, condition wait) is still active.
111
- */}
112
- <BannerHost engine={bannerEngine} hidden={pickerActive} />
104
+ {/*
105
+ * Unmount flow chrome for the whole pick. The session stays alive;
106
+ * captureScreen would otherwise include the modal or tooltip.
107
+ * Remounting reads the same session back.
108
+ */}
109
+ {pickerActive ? null : (
110
+ <FlowRenderer
111
+ engine={engine}
112
+ previewRestartGeneration={pairingState.previewRestartGeneration}
113
+ />
114
+ )}
115
+ {/*
116
+ * After flow chrome so BODY_FIRST / BODY_LAST overlay banners stay visible
117
+ * while a tour step (modal, tooltip, condition wait) is still active.
118
+ */}
119
+ <BannerHost engine={bannerEngine} hidden={pickerActive} />
120
+ </WindowOverlayHost>
113
121
  <ElementPickerOverlay />
114
122
  </>
115
123
  );
@@ -0,0 +1,95 @@
1
+ import * as React from 'react';
2
+ import { Platform } from 'react-native';
3
+
4
+ import { isNativeModuleLinked } from '../nativeModules';
5
+
6
+ interface FullWindowOverlayProps {
7
+ children?: React.ReactNode;
8
+ /** react-native-screens 4.x. Defaults to true, which traps VoiceOver inside the overlay. */
9
+ unstable_accessibilityContainerViewIsModal?: boolean;
10
+ }
11
+
12
+ type FullWindowOverlayComponent = React.ComponentType<FullWindowOverlayProps>;
13
+
14
+ /**
15
+ * Native module in every react-native-screens 3.x and 4.x build. Rendering
16
+ * `FullWindowOverlay` without the native half would mount an unregistered
17
+ * component, so the package is not required until this is linked.
18
+ */
19
+ const SCREENS_NATIVE_MODULE = 'RNSModule';
20
+
21
+ let cached: FullWindowOverlayComponent | null | undefined;
22
+
23
+ /** react-native-screens' `FullWindowOverlay`, or null when it cannot host chrome here. */
24
+ function getFullWindowOverlay(): FullWindowOverlayComponent | null {
25
+ if (cached !== undefined) return cached;
26
+ cached = null;
27
+
28
+ // FullWindowOverlay is iOS-only; elsewhere it renders a plain View.
29
+ if (Platform.OS !== 'ios' || typeof require !== 'function') return cached;
30
+ if (!isNativeModuleLinked(SCREENS_NATIVE_MODULE)) return cached;
31
+
32
+ try {
33
+ // Not a peer: apps that present native modals already have it, through
34
+ // Expo Router or React Navigation's native stack.
35
+ // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires -- optional package probe
36
+ const mod = require('react-native-screens') as {
37
+ FullWindowOverlay?: FullWindowOverlayComponent;
38
+ };
39
+ cached = mod?.FullWindowOverlay ?? null;
40
+ } catch {
41
+ cached = null;
42
+ }
43
+ return cached;
44
+ }
45
+
46
+ export interface WindowOverlayHostProps {
47
+ children: React.ReactNode;
48
+ /**
49
+ * Hide everything outside the host from VoiceOver, natively presented
50
+ * modals included. Defaults to false.
51
+ */
52
+ accessibilityModal?: boolean;
53
+ }
54
+
55
+ /** True when {@link WindowOverlayHost} draws above natively presented modals. */
56
+ export function hasWindowOverlayHost(): boolean {
57
+ return getFullWindowOverlay() != null;
58
+ }
59
+
60
+ /**
61
+ * Hosts SDK chrome above everything else in the app window.
62
+ *
63
+ * On iOS, react-native-screens presents `modal`, `transparentModal`,
64
+ * `formSheet` and `fullScreenModal` screens, and React Native presents
65
+ * `<Modal>`, as view controllers above the React Native root view, so chrome
66
+ * rendered in `UserflowProvider`'s overlay is drawn beneath them and never
67
+ * receives touches there. `FullWindowOverlay` moves its children into a
68
+ * container on the window itself. Measured on iOS 17.4 and 26.5 with
69
+ * react-native-screens 4.16, that container stays above sheets whether they are
70
+ * presented before or after it mounts.
71
+ *
72
+ * Each host is its own container, stacked by when it was attached rather than
73
+ * by React order, so chrome that has to keep a paint order shares one host.
74
+ *
75
+ * Touches inside the host arrive in window coordinates, as they do in the root
76
+ * view. Children render in place when the overlay is unavailable: on Android,
77
+ * and in apps without react-native-screens.
78
+ */
79
+ export function WindowOverlayHost({
80
+ children,
81
+ accessibilityModal = false,
82
+ }: WindowOverlayHostProps): React.ReactElement {
83
+ const FullWindowOverlay = getFullWindowOverlay();
84
+ if (!FullWindowOverlay) return <>{children}</>;
85
+ return (
86
+ <FullWindowOverlay unstable_accessibilityContainerViewIsModal={accessibilityModal}>
87
+ {children}
88
+ </FullWindowOverlay>
89
+ );
90
+ }
91
+
92
+ /** @internal Clears the cached `FullWindowOverlay` lookup between tests. */
93
+ export function resetWindowOverlayHostForTests(): void {
94
+ cached = undefined;
95
+ }
@@ -92,6 +92,11 @@ export function usePushBannerLayoutRegistration(
92
92
  * Clears the host top/bottom safe-area override only after push-layout chrome
93
93
  * has laid out, so a session without visible chrome cannot leave a white strip.
94
94
  *
95
+ * Remembers which edge laid out instead of resetting a flag in an effect: on
96
+ * Fabric the chrome's first onLayout can run before the mount's passive effects
97
+ * flush, and a reset there would discard it until the banner happened to
98
+ * re-layout, leaving already-mounted host screens on the old inset.
99
+ *
95
100
  * @internal
96
101
  */
97
102
  export function usePushBannerHostInsetRegistration(
@@ -99,23 +104,23 @@ export function usePushBannerHostInsetRegistration(
99
104
  sessionId: string,
100
105
  enabled: boolean,
101
106
  ): (event: LayoutChangeEvent) => void {
102
- const [laidOut, setLaidOut] = React.useState(false);
103
-
104
- React.useEffect(() => {
105
- setLaidOut(false);
106
- }, [edge, enabled]);
107
+ const activeEdge = enabled && edge ? edge : null;
108
+ const [laidOutEdge, setLaidOutEdge] = React.useState<PushBannerLayoutEdge | null>(null);
107
109
 
108
- usePushBannerLayoutRegistration(enabled && laidOut && edge ? edge : null, sessionId);
110
+ usePushBannerLayoutRegistration(
111
+ activeEdge && laidOutEdge === activeEdge ? activeEdge : null,
112
+ sessionId,
113
+ );
109
114
 
110
115
  return React.useCallback(
111
116
  (event: LayoutChangeEvent) => {
112
- if (!enabled || !edge) {
117
+ if (!activeEdge) {
113
118
  return;
114
119
  }
115
120
  if (event.nativeEvent.layout.height > 0) {
116
- setLaidOut(true);
121
+ setLaidOutEdge(activeEdge);
117
122
  }
118
123
  },
119
- [edge, enabled],
124
+ [activeEdge],
120
125
  );
121
126
  }
@@ -1,7 +1,13 @@
1
1
  import { UserflowCore } from '@userflow-tech/core';
2
2
 
3
- /** Shared {@link UserflowCore} singleton for the RN package facade + provider. */
4
- const core = new UserflowCore();
3
+ import { SDK_VERSION } from '../version';
4
+
5
+ /**
6
+ * Shared {@link UserflowCore} singleton for the RN package facade + provider.
7
+ * Joins report the published SDK version (not the internal core version) as
8
+ * `userflowClientBuild`.
9
+ */
10
+ const core = new UserflowCore({ clientBuild: `react-native-${SDK_VERSION}` });
5
11
 
6
12
  export function getUserflowCore(): UserflowCore {
7
13
  return core;
@@ -25,10 +25,7 @@ export interface BannerSurfaceProps {
25
25
 
26
26
  let warnedMissingWebView = false;
27
27
 
28
- /**
29
- * Native banner bar, or a WebView when a button runs Evaluate JavaScript or the
30
- * theme has published custom CSS (same CDN stylesheet as userflow.js iframes).
31
- */
28
+ /** Native banner bar, or a WebView when `customBannerEnabled` is set on the banner. */
32
29
  export function BannerSurface({
33
30
  session,
34
31
  pushLayoutEdge = null,
@@ -37,8 +34,7 @@ export function BannerSurface({
37
34
  onDismiss,
38
35
  }: BannerSurfaceProps): React.ReactElement | null {
39
36
  const banner = session.version.banner;
40
- const theme = session.version.theme;
41
- const needsWebView = banner != null && bannerNeedsWebView(banner, theme);
37
+ const needsWebView = banner != null && bannerNeedsWebView(banner);
42
38
  const webView = needsWebView ? getEvalJsWebView() : null;
43
39
 
44
40
  React.useEffect(() => {
@@ -2,6 +2,7 @@ import type { ThemeFragment } from '@userflow-tech/protocol';
2
2
  import * as React from 'react';
3
3
  import { StyleSheet, Text, View } from 'react-native';
4
4
 
5
+ import { resolveContentFontFamily } from '../content/resolveContentFontFamily';
5
6
  import { foregroundAlpha } from '../content/themeColor';
6
7
 
7
8
  export type ProgressBarPlacement = 'TOP' | 'BOTTOM';
@@ -72,7 +73,7 @@ export function ProgressBar({
72
73
  styles.numberedLabel,
73
74
  {
74
75
  color: foregroundAlpha(theme.fontColor, 0.55),
75
- fontFamily: theme.fontFamily || undefined,
76
+ fontFamily: resolveContentFontFamily(theme),
76
77
  fontSize: Math.max(12, Math.round(theme.fontSize * 0.875)),
77
78
  },
78
79
  ]}