@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.
- package/README.md +65 -33
- package/docs/custom-fonts.md +36 -0
- package/docs/troubleshooting.md +45 -44
- package/expo-plugin/hostDependencyWarnings.d.ts +5 -5
- package/expo-plugin/hostDependencyWarnings.js +7 -7
- package/expo-plugin/hostDependencyWarnings.js.map +1 -1
- package/lib/commonjs/anchors/AnchorRegistry.js +5 -0
- package/lib/commonjs/anchors/AnchorRegistry.js.map +1 -1
- package/lib/commonjs/anchors/ScrollContainerRegistry.js +8 -0
- package/lib/commonjs/anchors/ScrollContainerRegistry.js.map +1 -1
- package/lib/commonjs/anchors/fiber/FiberScanRootStore.js +8 -0
- package/lib/commonjs/anchors/fiber/FiberScanRootStore.js.map +1 -1
- package/lib/commonjs/anchors/fiber/detectAppFontFamily.js +341 -0
- package/lib/commonjs/anchors/fiber/detectAppFontFamily.js.map +1 -0
- package/lib/commonjs/anchors/fiber/presentedModal.js +215 -0
- package/lib/commonjs/anchors/fiber/presentedModal.js.map +1 -0
- package/lib/commonjs/anchors/fiber/touchTargetFiber.js +1 -0
- package/lib/commonjs/anchors/fiber/touchTargetFiber.js.map +1 -1
- package/lib/commonjs/anchors/fiber/visibleRect.js +12 -3
- package/lib/commonjs/anchors/fiber/visibleRect.js.map +1 -1
- package/lib/commonjs/anchors/fiber/visibleScreens.js +6 -0
- package/lib/commonjs/anchors/fiber/visibleScreens.js.map +1 -1
- package/lib/commonjs/anchors/useUserflowAnchor.js.map +1 -1
- package/lib/commonjs/anchors/useUserflowScrollContainer.js.map +1 -1
- package/lib/commonjs/authoring/ElementPickerOverlay.js +197 -138
- package/lib/commonjs/authoring/ElementPickerOverlay.js.map +1 -1
- package/lib/commonjs/authoring/hitTest.js +67 -10
- package/lib/commonjs/authoring/hitTest.js.map +1 -1
- package/lib/commonjs/authoring/hostAtPoint.js +45 -21
- package/lib/commonjs/authoring/hostAtPoint.js.map +1 -1
- package/lib/commonjs/content/BannerStepButton.js +2 -1
- package/lib/commonjs/content/BannerStepButton.js.map +1 -1
- package/lib/commonjs/content/RichContentRenderer.js +27 -9
- package/lib/commonjs/content/RichContentRenderer.js.map +1 -1
- package/lib/commonjs/content/StepButton.js +2 -1
- package/lib/commonjs/content/StepButton.js.map +1 -1
- package/lib/commonjs/content/resolveContentFontFamily.js +96 -0
- package/lib/commonjs/content/resolveContentFontFamily.js.map +1 -0
- package/lib/commonjs/deepLinking.js.map +1 -1
- package/lib/commonjs/deviceContext.js +39 -19
- package/lib/commonjs/deviceContext.js.map +1 -1
- package/lib/commonjs/index.js +13 -5
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/installCheck.js +3 -3
- package/lib/commonjs/installCheck.js.map +1 -1
- package/lib/commonjs/lifecycle.js +2 -0
- package/lib/commonjs/lifecycle.js.map +1 -1
- package/lib/commonjs/pairing/PairingController.js.map +1 -1
- package/lib/commonjs/runtime/BannerHost.js +3 -3
- package/lib/commonjs/runtime/BannerHost.js.map +1 -1
- package/lib/commonjs/runtime/UserflowOverlay.js +17 -13
- package/lib/commonjs/runtime/UserflowOverlay.js.map +1 -1
- package/lib/commonjs/runtime/WindowOverlayHost.js +83 -0
- package/lib/commonjs/runtime/WindowOverlayHost.js.map +1 -0
- package/lib/commonjs/runtime/pushBannerLayoutContext.js +11 -8
- package/lib/commonjs/runtime/pushBannerLayoutContext.js.map +1 -1
- package/lib/commonjs/runtime/userflowCore.js +9 -2
- package/lib/commonjs/runtime/userflowCore.js.map +1 -1
- package/lib/commonjs/surfaces/BannerSurface.js +2 -6
- package/lib/commonjs/surfaces/BannerSurface.js.map +1 -1
- package/lib/commonjs/surfaces/ProgressBar.js +2 -1
- package/lib/commonjs/surfaces/ProgressBar.js.map +1 -1
- package/lib/commonjs/surfaces/TooltipSurface.js +114 -51
- package/lib/commonjs/surfaces/TooltipSurface.js.map +1 -1
- package/lib/commonjs/surfaces/bannerWebView/BannerWebViewBar.js +6 -4
- package/lib/commonjs/surfaces/bannerWebView/BannerWebViewBar.js.map +1 -1
- package/lib/commonjs/surfaces/bannerWebView/bannerNeedsWebView.js +3 -33
- package/lib/commonjs/surfaces/bannerWebView/bannerNeedsWebView.js.map +1 -1
- package/lib/commonjs/surfaces/bannerWebView/bannerThemeStyles.js +2 -1
- package/lib/commonjs/surfaces/bannerWebView/bannerThemeStyles.js.map +1 -1
- package/lib/commonjs/surfaces/bannerWebView/bannerWebViewHeight.js +33 -0
- package/lib/commonjs/surfaces/bannerWebView/bannerWebViewHeight.js.map +1 -0
- package/lib/commonjs/surfaces/bannerWebView/buildCustomBannerHtml.js +45 -12
- package/lib/commonjs/surfaces/bannerWebView/buildCustomBannerHtml.js.map +1 -1
- package/lib/commonjs/surfaces/tooltip/TooltipHighlight.js +6 -6
- package/lib/commonjs/surfaces/tooltip/TooltipHighlight.js.map +1 -1
- package/lib/commonjs/surfaces/tooltip/targetOrigin.js +74 -0
- package/lib/commonjs/surfaces/tooltip/targetOrigin.js.map +1 -0
- package/lib/commonjs/version.js +1 -1
- package/lib/module/anchors/AnchorRegistry.js +5 -0
- package/lib/module/anchors/AnchorRegistry.js.map +1 -1
- package/lib/module/anchors/ScrollContainerRegistry.js +8 -0
- package/lib/module/anchors/ScrollContainerRegistry.js.map +1 -1
- package/lib/module/anchors/fiber/FiberScanRootStore.js +8 -0
- package/lib/module/anchors/fiber/FiberScanRootStore.js.map +1 -1
- package/lib/module/anchors/fiber/detectAppFontFamily.js +330 -0
- package/lib/module/anchors/fiber/detectAppFontFamily.js.map +1 -0
- package/lib/module/anchors/fiber/presentedModal.js +206 -0
- package/lib/module/anchors/fiber/presentedModal.js.map +1 -0
- package/lib/module/anchors/fiber/touchTargetFiber.js +1 -0
- package/lib/module/anchors/fiber/touchTargetFiber.js.map +1 -1
- package/lib/module/anchors/fiber/visibleRect.js +12 -3
- package/lib/module/anchors/fiber/visibleRect.js.map +1 -1
- package/lib/module/anchors/fiber/visibleScreens.js +5 -0
- package/lib/module/anchors/fiber/visibleScreens.js.map +1 -1
- package/lib/module/anchors/useUserflowAnchor.js.map +1 -1
- package/lib/module/anchors/useUserflowScrollContainer.js.map +1 -1
- package/lib/module/authoring/ElementPickerOverlay.js +199 -140
- package/lib/module/authoring/ElementPickerOverlay.js.map +1 -1
- package/lib/module/authoring/hitTest.js +67 -11
- package/lib/module/authoring/hitTest.js.map +1 -1
- package/lib/module/authoring/hostAtPoint.js +45 -21
- package/lib/module/authoring/hostAtPoint.js.map +1 -1
- package/lib/module/content/BannerStepButton.js +2 -1
- package/lib/module/content/BannerStepButton.js.map +1 -1
- package/lib/module/content/RichContentRenderer.js +27 -9
- package/lib/module/content/RichContentRenderer.js.map +1 -1
- package/lib/module/content/StepButton.js +2 -1
- package/lib/module/content/StepButton.js.map +1 -1
- package/lib/module/content/resolveContentFontFamily.js +89 -0
- package/lib/module/content/resolveContentFontFamily.js.map +1 -0
- package/lib/module/deepLinking.js.map +1 -1
- package/lib/module/deviceContext.js +38 -17
- package/lib/module/deviceContext.js.map +1 -1
- package/lib/module/index.js +13 -5
- package/lib/module/index.js.map +1 -1
- package/lib/module/installCheck.js +3 -3
- package/lib/module/installCheck.js.map +1 -1
- package/lib/module/lifecycle.js +2 -0
- package/lib/module/lifecycle.js.map +1 -1
- package/lib/module/pairing/PairingController.js.map +1 -1
- package/lib/module/runtime/BannerHost.js +3 -3
- package/lib/module/runtime/BannerHost.js.map +1 -1
- package/lib/module/runtime/UserflowOverlay.js +18 -14
- package/lib/module/runtime/UserflowOverlay.js.map +1 -1
- package/lib/module/runtime/WindowOverlayHost.js +76 -0
- package/lib/module/runtime/WindowOverlayHost.js.map +1 -0
- package/lib/module/runtime/pushBannerLayoutContext.js +11 -8
- package/lib/module/runtime/pushBannerLayoutContext.js.map +1 -1
- package/lib/module/runtime/userflowCore.js +9 -2
- package/lib/module/runtime/userflowCore.js.map +1 -1
- package/lib/module/surfaces/BannerSurface.js +2 -6
- package/lib/module/surfaces/BannerSurface.js.map +1 -1
- package/lib/module/surfaces/ProgressBar.js +2 -1
- package/lib/module/surfaces/ProgressBar.js.map +1 -1
- package/lib/module/surfaces/TooltipSurface.js +114 -51
- package/lib/module/surfaces/TooltipSurface.js.map +1 -1
- package/lib/module/surfaces/bannerWebView/BannerWebViewBar.js +6 -4
- package/lib/module/surfaces/bannerWebView/BannerWebViewBar.js.map +1 -1
- package/lib/module/surfaces/bannerWebView/bannerNeedsWebView.js +3 -31
- package/lib/module/surfaces/bannerWebView/bannerNeedsWebView.js.map +1 -1
- package/lib/module/surfaces/bannerWebView/bannerThemeStyles.js +2 -1
- package/lib/module/surfaces/bannerWebView/bannerThemeStyles.js.map +1 -1
- package/lib/module/surfaces/bannerWebView/bannerWebViewHeight.js +29 -0
- package/lib/module/surfaces/bannerWebView/bannerWebViewHeight.js.map +1 -0
- package/lib/module/surfaces/bannerWebView/buildCustomBannerHtml.js +45 -12
- package/lib/module/surfaces/bannerWebView/buildCustomBannerHtml.js.map +1 -1
- package/lib/module/surfaces/tooltip/TooltipHighlight.js +6 -6
- package/lib/module/surfaces/tooltip/TooltipHighlight.js.map +1 -1
- package/lib/module/surfaces/tooltip/targetOrigin.js +67 -0
- package/lib/module/surfaces/tooltip/targetOrigin.js.map +1 -0
- package/lib/module/version.js +1 -1
- package/lib/typescript/commonjs/src/anchors/AnchorRegistry.d.ts +7 -0
- package/lib/typescript/commonjs/src/anchors/AnchorRegistry.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/ScrollContainerRegistry.d.ts +11 -2
- package/lib/typescript/commonjs/src/anchors/ScrollContainerRegistry.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/fiber/FiberScanRootStore.d.ts +5 -0
- package/lib/typescript/commonjs/src/anchors/fiber/FiberScanRootStore.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/fiber/detectAppFontFamily.d.ts +30 -0
- package/lib/typescript/commonjs/src/anchors/fiber/detectAppFontFamily.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/anchors/fiber/presentedModal.d.ts +45 -0
- package/lib/typescript/commonjs/src/anchors/fiber/presentedModal.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/anchors/fiber/visibleRect.d.ts +5 -2
- package/lib/typescript/commonjs/src/anchors/fiber/visibleRect.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/fiber/visibleScreens.d.ts +2 -0
- package/lib/typescript/commonjs/src/anchors/fiber/visibleScreens.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/useUserflowAnchor.d.ts +2 -2
- package/lib/typescript/commonjs/src/anchors/useUserflowAnchor.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/useUserflowScrollContainer.d.ts +3 -2
- package/lib/typescript/commonjs/src/anchors/useUserflowScrollContainer.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/authoring/ElementPickerOverlay.d.ts +4 -0
- package/lib/typescript/commonjs/src/authoring/ElementPickerOverlay.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/authoring/hitTest.d.ts +25 -2
- package/lib/typescript/commonjs/src/authoring/hitTest.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/authoring/hostAtPoint.d.ts +6 -1
- package/lib/typescript/commonjs/src/authoring/hostAtPoint.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/content/BannerStepButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/content/RichContentRenderer.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/content/StepButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/content/resolveContentFontFamily.d.ts +35 -0
- package/lib/typescript/commonjs/src/content/resolveContentFontFamily.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/deepLinking.d.ts +1 -1
- package/lib/typescript/commonjs/src/deepLinking.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/deviceContext.d.ts +14 -5
- package/lib/typescript/commonjs/src/deviceContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +11 -5
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/installCheck.d.ts +2 -2
- package/lib/typescript/commonjs/src/installCheck.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/lifecycle.d.ts +1 -0
- package/lib/typescript/commonjs/src/lifecycle.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/pairing/PairingController.d.ts +1 -1
- package/lib/typescript/commonjs/src/pairing/PairingController.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/runtime/UserflowOverlay.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/runtime/WindowOverlayHost.d.ts +34 -0
- package/lib/typescript/commonjs/src/runtime/WindowOverlayHost.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/runtime/pushBannerLayoutContext.d.ts +5 -0
- package/lib/typescript/commonjs/src/runtime/pushBannerLayoutContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/runtime/userflowCore.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/surfaces/BannerSurface.d.ts +1 -4
- package/lib/typescript/commonjs/src/surfaces/BannerSurface.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/surfaces/ProgressBar.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/surfaces/TooltipSurface.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/surfaces/bannerWebView/BannerWebViewBar.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/surfaces/bannerWebView/bannerNeedsWebView.d.ts +3 -12
- package/lib/typescript/commonjs/src/surfaces/bannerWebView/bannerNeedsWebView.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/surfaces/bannerWebView/bannerThemeStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/surfaces/bannerWebView/bannerWebViewHeight.d.ts +13 -0
- package/lib/typescript/commonjs/src/surfaces/bannerWebView/bannerWebViewHeight.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/surfaces/bannerWebView/buildCustomBannerHtml.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/surfaces/tooltip/targetOrigin.d.ts +26 -0
- package/lib/typescript/commonjs/src/surfaces/tooltip/targetOrigin.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/version.d.ts +1 -1
- package/lib/typescript/module/src/anchors/AnchorRegistry.d.ts +7 -0
- package/lib/typescript/module/src/anchors/AnchorRegistry.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/ScrollContainerRegistry.d.ts +11 -2
- package/lib/typescript/module/src/anchors/ScrollContainerRegistry.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/fiber/FiberScanRootStore.d.ts +5 -0
- package/lib/typescript/module/src/anchors/fiber/FiberScanRootStore.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/fiber/detectAppFontFamily.d.ts +30 -0
- package/lib/typescript/module/src/anchors/fiber/detectAppFontFamily.d.ts.map +1 -0
- package/lib/typescript/module/src/anchors/fiber/presentedModal.d.ts +45 -0
- package/lib/typescript/module/src/anchors/fiber/presentedModal.d.ts.map +1 -0
- package/lib/typescript/module/src/anchors/fiber/visibleRect.d.ts +5 -2
- package/lib/typescript/module/src/anchors/fiber/visibleRect.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/fiber/visibleScreens.d.ts +2 -0
- package/lib/typescript/module/src/anchors/fiber/visibleScreens.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/useUserflowAnchor.d.ts +2 -2
- package/lib/typescript/module/src/anchors/useUserflowAnchor.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/useUserflowScrollContainer.d.ts +3 -2
- package/lib/typescript/module/src/anchors/useUserflowScrollContainer.d.ts.map +1 -1
- package/lib/typescript/module/src/authoring/ElementPickerOverlay.d.ts +4 -0
- package/lib/typescript/module/src/authoring/ElementPickerOverlay.d.ts.map +1 -1
- package/lib/typescript/module/src/authoring/hitTest.d.ts +25 -2
- package/lib/typescript/module/src/authoring/hitTest.d.ts.map +1 -1
- package/lib/typescript/module/src/authoring/hostAtPoint.d.ts +6 -1
- package/lib/typescript/module/src/authoring/hostAtPoint.d.ts.map +1 -1
- package/lib/typescript/module/src/content/BannerStepButton.d.ts.map +1 -1
- package/lib/typescript/module/src/content/RichContentRenderer.d.ts.map +1 -1
- package/lib/typescript/module/src/content/StepButton.d.ts.map +1 -1
- package/lib/typescript/module/src/content/resolveContentFontFamily.d.ts +35 -0
- package/lib/typescript/module/src/content/resolveContentFontFamily.d.ts.map +1 -0
- package/lib/typescript/module/src/deepLinking.d.ts +1 -1
- package/lib/typescript/module/src/deepLinking.d.ts.map +1 -1
- package/lib/typescript/module/src/deviceContext.d.ts +14 -5
- package/lib/typescript/module/src/deviceContext.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +11 -5
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/installCheck.d.ts +2 -2
- package/lib/typescript/module/src/installCheck.d.ts.map +1 -1
- package/lib/typescript/module/src/lifecycle.d.ts +1 -0
- package/lib/typescript/module/src/lifecycle.d.ts.map +1 -1
- package/lib/typescript/module/src/pairing/PairingController.d.ts +1 -1
- package/lib/typescript/module/src/pairing/PairingController.d.ts.map +1 -1
- package/lib/typescript/module/src/runtime/UserflowOverlay.d.ts.map +1 -1
- package/lib/typescript/module/src/runtime/WindowOverlayHost.d.ts +34 -0
- package/lib/typescript/module/src/runtime/WindowOverlayHost.d.ts.map +1 -0
- package/lib/typescript/module/src/runtime/pushBannerLayoutContext.d.ts +5 -0
- package/lib/typescript/module/src/runtime/pushBannerLayoutContext.d.ts.map +1 -1
- package/lib/typescript/module/src/runtime/userflowCore.d.ts.map +1 -1
- package/lib/typescript/module/src/surfaces/BannerSurface.d.ts +1 -4
- package/lib/typescript/module/src/surfaces/BannerSurface.d.ts.map +1 -1
- package/lib/typescript/module/src/surfaces/ProgressBar.d.ts.map +1 -1
- package/lib/typescript/module/src/surfaces/TooltipSurface.d.ts.map +1 -1
- package/lib/typescript/module/src/surfaces/bannerWebView/BannerWebViewBar.d.ts.map +1 -1
- package/lib/typescript/module/src/surfaces/bannerWebView/bannerNeedsWebView.d.ts +3 -12
- package/lib/typescript/module/src/surfaces/bannerWebView/bannerNeedsWebView.d.ts.map +1 -1
- package/lib/typescript/module/src/surfaces/bannerWebView/bannerThemeStyles.d.ts.map +1 -1
- package/lib/typescript/module/src/surfaces/bannerWebView/bannerWebViewHeight.d.ts +13 -0
- package/lib/typescript/module/src/surfaces/bannerWebView/bannerWebViewHeight.d.ts.map +1 -0
- package/lib/typescript/module/src/surfaces/bannerWebView/buildCustomBannerHtml.d.ts.map +1 -1
- package/lib/typescript/module/src/surfaces/tooltip/targetOrigin.d.ts +26 -0
- package/lib/typescript/module/src/surfaces/tooltip/targetOrigin.d.ts.map +1 -0
- package/lib/typescript/module/src/version.d.ts +1 -1
- package/package.json +5 -4
- package/src/anchors/AnchorRegistry.ts +8 -0
- package/src/anchors/ScrollContainerRegistry.ts +15 -3
- package/src/anchors/fiber/FiberScanRootStore.ts +8 -0
- package/src/anchors/fiber/detectAppFontFamily.ts +400 -0
- package/src/anchors/fiber/presentedModal.ts +203 -0
- package/src/anchors/fiber/touchTargetFiber.ts +2 -1
- package/src/anchors/fiber/visibleRect.ts +12 -3
- package/src/anchors/fiber/visibleScreens.ts +5 -0
- package/src/anchors/useUserflowAnchor.ts +4 -5
- package/src/anchors/useUserflowScrollContainer.ts +5 -4
- package/src/authoring/ElementPickerOverlay.tsx +242 -166
- package/src/authoring/hitTest.ts +88 -13
- package/src/authoring/hostAtPoint.ts +67 -21
- package/src/content/BannerStepButton.tsx +2 -1
- package/src/content/RichContentRenderer.tsx +16 -9
- package/src/content/StepButton.tsx +2 -1
- package/src/content/resolveContentFontFamily.ts +119 -0
- package/src/deepLinking.ts +2 -1
- package/src/deviceContext.ts +50 -14
- package/src/index.ts +13 -5
- package/src/installCheck.ts +3 -3
- package/src/lifecycle.ts +2 -1
- package/src/pairing/PairingController.ts +2 -1
- package/src/runtime/BannerHost.tsx +3 -3
- package/src/runtime/UserflowOverlay.tsx +29 -21
- package/src/runtime/WindowOverlayHost.tsx +95 -0
- package/src/runtime/pushBannerLayoutContext.tsx +14 -9
- package/src/runtime/userflowCore.ts +8 -2
- package/src/surfaces/BannerSurface.tsx +2 -6
- package/src/surfaces/ProgressBar.tsx +2 -1
- package/src/surfaces/TooltipSurface.tsx +118 -47
- package/src/surfaces/bannerWebView/BannerWebViewBar.tsx +6 -4
- package/src/surfaces/bannerWebView/bannerNeedsWebView.ts +4 -36
- package/src/surfaces/bannerWebView/bannerThemeStyles.ts +2 -1
- package/src/surfaces/bannerWebView/bannerWebViewHeight.ts +32 -0
- package/src/surfaces/bannerWebView/buildCustomBannerHtml.ts +48 -12
- package/src/surfaces/tooltip/TooltipHighlight.tsx +3 -5
- package/src/surfaces/tooltip/targetOrigin.ts +74 -0
- package/src/version.ts +1 -1
- package/vendor/core/dist/engine/UserflowCore.d.ts +7 -0
- package/vendor/core/dist/engine/UserflowCore.d.ts.map +1 -1
- package/vendor/core/dist/engine/UserflowCore.js +3 -2
- package/vendor/core/dist/engine/UserflowCore.js.map +1 -1
- package/vendor/core/dist/transport/phoenix.d.ts +12 -2
- package/vendor/core/dist/transport/phoenix.d.ts.map +1 -1
- package/vendor/core/dist/transport/phoenix.js +7 -6
- package/vendor/core/dist/transport/phoenix.js.map +1 -1
- package/vendor/core/dist/version.d.ts +1 -1
- package/vendor/core/dist/version.js +1 -1
- package/vendor/core/package.json +1 -1
- package/vendor/protocol/dist/flows.d.ts +2 -0
- package/vendor/protocol/dist/flows.d.ts.map +1 -1
- package/vendor/protocol/package.json +1 -1
|
@@ -23,7 +23,8 @@ import { autoAnchorRegistry } from '../anchors/AutoAnchorRegistry';
|
|
|
23
23
|
import { addAnimationFrameCallback, removeAnimationFrameCallback } from '../anchors/animationFrame';
|
|
24
24
|
import { isAppActive, subscribeAppActive } from '../anchors/appActive';
|
|
25
25
|
import { fiberScanRoot } from '../anchors/fiber/FiberScanRoot';
|
|
26
|
-
import type
|
|
26
|
+
import { type AnyFiber, fiberFromPublicInstance } from '../anchors/fiber/fiberInternals';
|
|
27
|
+
import type { Point } from '../anchors/fiber/presentedModal';
|
|
27
28
|
import { clipToScrollViewports } from '../anchors/fiber/visibleRect';
|
|
28
29
|
import {
|
|
29
30
|
clearFiberAnchorCache,
|
|
@@ -37,6 +38,7 @@ import { scrollAnchorIntoView } from '../anchors/scrollAnchorIntoView';
|
|
|
37
38
|
import { getScrollPadding } from '../anchors/scrollConfig';
|
|
38
39
|
import { targetPressMonitor } from '../anchors/targetPressMonitor';
|
|
39
40
|
import { RichContentRenderer } from '../content/RichContentRenderer';
|
|
41
|
+
import { resolveContentFontFamily } from '../content/resolveContentFontFamily';
|
|
40
42
|
import type { LookupAttribute } from '../content/types';
|
|
41
43
|
|
|
42
44
|
import { CardFade } from './CardFade';
|
|
@@ -81,6 +83,7 @@ import {
|
|
|
81
83
|
tooltipSideGap,
|
|
82
84
|
tooltipVerticalGap,
|
|
83
85
|
} from './tooltip/resolveSideCardWidth';
|
|
86
|
+
import { locateTargetOrigin, offsetRect } from './tooltip/targetOrigin';
|
|
84
87
|
import { TargetSearchSchedule } from './tooltip/targetSearchSchedule';
|
|
85
88
|
|
|
86
89
|
export interface TooltipSurfaceProps {
|
|
@@ -156,6 +159,7 @@ export function TooltipSurface({
|
|
|
156
159
|
}: TooltipSurfaceProps): React.ReactElement | null {
|
|
157
160
|
const version = session.version;
|
|
158
161
|
const chrome = resolveBubbleChrome(theme, 'tooltip');
|
|
162
|
+
const contentFontFamily = resolveContentFontFamily(theme);
|
|
159
163
|
const progress = resolveStepProgress(version, currentStep.id);
|
|
160
164
|
const showClose = !version.closeDisabled;
|
|
161
165
|
const backdropOpacity = parseBackdropOpacity(theme.backdropOpacity);
|
|
@@ -199,6 +203,12 @@ export function TooltipSurface({
|
|
|
199
203
|
const [missingMode, setMissingMode] = React.useState<MissingMode>('waiting');
|
|
200
204
|
/** True after at least one *failed* measure for the current step/anchor. */
|
|
201
205
|
const [measureAttempted, setMeasureAttempted] = React.useState(false);
|
|
206
|
+
/**
|
|
207
|
+
* True while a natively presented modal hides the target, or the target is
|
|
208
|
+
* in a sheet that cannot be placed. The step waits without counting the
|
|
209
|
+
* target as missing, and draws nothing over the modal.
|
|
210
|
+
*/
|
|
211
|
+
const [concealed, setConcealed] = React.useState(false);
|
|
202
212
|
/**
|
|
203
213
|
* False only after a same-step `resetNonce` bump (preview restart) until one
|
|
204
214
|
* frame has passed, so dialog teardown cannot 0-size FLAG.
|
|
@@ -236,7 +246,15 @@ export function TooltipSurface({
|
|
|
236
246
|
const resolveEpochRef = React.useRef(0);
|
|
237
247
|
/** Latest resolved host fiber (for scroll-ancestor walk + rAF remeasure). */
|
|
238
248
|
const hostFiberRef = React.useRef<AnyFiber | null>(null);
|
|
239
|
-
/**
|
|
249
|
+
/**
|
|
250
|
+
* Window position of the host's measure space, from the last resolve. Not
|
|
251
|
+
* zero only inside a native sheet, whose content measures and receives
|
|
252
|
+
* touches relative to the sheet.
|
|
253
|
+
*/
|
|
254
|
+
const measureOriginRef = React.useRef<Point>({ x: 0, y: 0 });
|
|
255
|
+
/** `targetRef` in the host's measure space. */
|
|
256
|
+
const measuredRef = React.useRef<Rect | null>(null);
|
|
257
|
+
/** Target rect clipped to scroll viewports, for tap detection only. In measure space, as touches are. */
|
|
240
258
|
const clippedPressRef = React.useRef<Rect | null>(null);
|
|
241
259
|
const clipGenRef = React.useRef(0);
|
|
242
260
|
const hostMeasureRef = React.useRef<
|
|
@@ -261,6 +279,8 @@ export function TooltipSurface({
|
|
|
261
279
|
insetsRef.current = layoutInsets;
|
|
262
280
|
const missingModeRef = React.useRef(missingMode);
|
|
263
281
|
missingModeRef.current = missingMode;
|
|
282
|
+
const concealedRef = React.useRef(concealed);
|
|
283
|
+
concealedRef.current = concealed;
|
|
264
284
|
const behaviorRef = React.useRef(behavior);
|
|
265
285
|
behaviorRef.current = behavior;
|
|
266
286
|
const draftModeRef = React.useRef(session.draftMode);
|
|
@@ -290,6 +310,7 @@ export function TooltipSurface({
|
|
|
290
310
|
warnedSidePlacementStepRef.current = null;
|
|
291
311
|
targetStepIdRef.current = null;
|
|
292
312
|
targetRef.current = null;
|
|
313
|
+
measuredRef.current = null;
|
|
293
314
|
// Drop the previous card's measured size and side so the next step does not
|
|
294
315
|
// inherit a wrapped 115×400 LEFT into `fits(currentPlacement)`.
|
|
295
316
|
const nextPlacement = desiredPlacementRef.current ?? 'BELOW';
|
|
@@ -298,6 +319,7 @@ export function TooltipSurface({
|
|
|
298
319
|
setBubbleSize({ width: 280, height: 160 });
|
|
299
320
|
setMissingMode('waiting');
|
|
300
321
|
setMeasureAttempted(false);
|
|
322
|
+
setConcealed(false);
|
|
301
323
|
setTarget(null);
|
|
302
324
|
const prev = targetingIdentityRef.current;
|
|
303
325
|
const sameIdentity = prev.stepId === currentStep.id && prev.targetKey === targetKey;
|
|
@@ -317,10 +339,13 @@ export function TooltipSurface({
|
|
|
317
339
|
return () => clearTimeout(handle);
|
|
318
340
|
}, [resolveArmed]);
|
|
319
341
|
|
|
320
|
-
|
|
342
|
+
/** `next` is in window coordinates; `measured` is the same rect in the host's measure space. */
|
|
343
|
+
const applyTarget = React.useCallback((next: Rect | null, measured: Rect | null = next) => {
|
|
321
344
|
if (!mountedRef.current) return;
|
|
345
|
+
if (next != null) setConcealed(false);
|
|
322
346
|
targetStepIdRef.current = next == null ? null : currentStepIdRef.current;
|
|
323
|
-
if (rectsEqual(targetRef.current, next)) return;
|
|
347
|
+
if (rectsEqual(targetRef.current, next) && rectsEqual(measuredRef.current, measured)) return;
|
|
348
|
+
measuredRef.current = measured;
|
|
324
349
|
if (next == null) {
|
|
325
350
|
// The anchor went away (unmount / navigation), so whatever scroll position
|
|
326
351
|
// the user had settled on no longer applies. Treat its next appearance as
|
|
@@ -330,15 +355,15 @@ export function TooltipSurface({
|
|
|
330
355
|
}
|
|
331
356
|
targetRef.current = next;
|
|
332
357
|
setTarget(next);
|
|
333
|
-
if (next == null) {
|
|
358
|
+
if (next == null || measured == null) {
|
|
334
359
|
clippedPressRef.current = null;
|
|
335
360
|
return;
|
|
336
361
|
}
|
|
337
|
-
clippedPressRef.current =
|
|
362
|
+
clippedPressRef.current = measured;
|
|
338
363
|
const fiber = hostFiberRef.current;
|
|
339
364
|
const gen = (clipGenRef.current += 1);
|
|
340
365
|
if (!fiber) return;
|
|
341
|
-
void clipToScrollViewports(fiber,
|
|
366
|
+
void clipToScrollViewports(fiber, measured).then((clipped) => {
|
|
342
367
|
if (clipGenRef.current !== gen) return;
|
|
343
368
|
clippedPressRef.current = clipped;
|
|
344
369
|
});
|
|
@@ -362,10 +387,28 @@ export function TooltipSurface({
|
|
|
362
387
|
hostMeasureRef.current = null;
|
|
363
388
|
hostScrollIntoViewRef.current = undefined;
|
|
364
389
|
fiberCacheIdRef.current = null;
|
|
390
|
+
setConcealed(false);
|
|
365
391
|
markMeasureAttempted();
|
|
366
392
|
applyTarget(null);
|
|
367
393
|
}, [applyTarget, markMeasureAttempted]);
|
|
368
394
|
|
|
395
|
+
/**
|
|
396
|
+
* Forget the resolved host while a natively presented modal hides it. Unlike
|
|
397
|
+
* {@link dropHost} the target is not gone: the missing-target timer does not
|
|
398
|
+
* run, so opening a sheet mid-step cannot flag or end the flow, and the
|
|
399
|
+
* tooltip comes back when the sheet closes.
|
|
400
|
+
*/
|
|
401
|
+
const concealHost = React.useCallback(() => {
|
|
402
|
+
resolveEpochRef.current += 1;
|
|
403
|
+
measureInFlightRef.current = false;
|
|
404
|
+
hostFiberRef.current = null;
|
|
405
|
+
hostMeasureRef.current = null;
|
|
406
|
+
hostScrollIntoViewRef.current = undefined;
|
|
407
|
+
fiberCacheIdRef.current = null;
|
|
408
|
+
setConcealed(true);
|
|
409
|
+
applyTarget(null);
|
|
410
|
+
}, [applyTarget]);
|
|
411
|
+
|
|
369
412
|
const effectiveViewport = React.useCallback(() => {
|
|
370
413
|
const windowSize = Dimensions.get('window');
|
|
371
414
|
const scrollPadding = getScrollPadding();
|
|
@@ -384,8 +427,9 @@ export function TooltipSurface({
|
|
|
384
427
|
);
|
|
385
428
|
}, []);
|
|
386
429
|
|
|
430
|
+
/** `rect` is in window coordinates; `measured` is the same rect in the host's measure space. */
|
|
387
431
|
const maybeScrollIntoView = React.useCallback(
|
|
388
|
-
(rect: Rect) => {
|
|
432
|
+
(rect: Rect, measured: Rect) => {
|
|
389
433
|
// Scrolling the app to reveal a target we are fading away from is visible.
|
|
390
434
|
if (exitingRef.current) return;
|
|
391
435
|
if (scrollSettledRef.current) return;
|
|
@@ -406,8 +450,9 @@ export function TooltipSurface({
|
|
|
406
450
|
? { scrollIntoView: hostScrollIntoViewRef.current }
|
|
407
451
|
: {}),
|
|
408
452
|
};
|
|
453
|
+
// Scroll containers are measured in the same space as the host.
|
|
409
454
|
scrollAnchorIntoView({
|
|
410
|
-
rect,
|
|
455
|
+
rect: measured,
|
|
411
456
|
host,
|
|
412
457
|
fiber: hostFiberRef.current,
|
|
413
458
|
});
|
|
@@ -418,6 +463,31 @@ export function TooltipSurface({
|
|
|
418
463
|
[effectiveViewport],
|
|
419
464
|
);
|
|
420
465
|
|
|
466
|
+
/** Measure callback for both the resolve and the rAF remeasure of `epoch`'s host. */
|
|
467
|
+
const onHostMeasured = React.useCallback(
|
|
468
|
+
(epoch: number, x: number, y: number, width: number, height: number) => {
|
|
469
|
+
if (resolveEpochRef.current !== epoch) {
|
|
470
|
+
measureInFlightRef.current = false;
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
measureInFlightRef.current = false;
|
|
474
|
+
if (!mountedRef.current) return;
|
|
475
|
+
|
|
476
|
+
if (width <= 0 || height <= 0) {
|
|
477
|
+
const cacheId = fiberCacheIdRef.current;
|
|
478
|
+
if (cacheId) invalidateFiberAnchor(cacheId);
|
|
479
|
+
dropHost();
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const measured: Rect = { x, y, width, height };
|
|
484
|
+
const rect = offsetRect(measured, measureOriginRef.current);
|
|
485
|
+
maybeScrollIntoView(rect, measured);
|
|
486
|
+
applyTarget(rect, measured);
|
|
487
|
+
},
|
|
488
|
+
[applyTarget, dropHost, maybeScrollIntoView],
|
|
489
|
+
);
|
|
490
|
+
|
|
421
491
|
/**
|
|
422
492
|
* Resolve the anchor host (registry / fiber scan). Driven by
|
|
423
493
|
* {@link TargetSearchSchedule} — intentionally NOT on every animation frame.
|
|
@@ -448,26 +518,25 @@ export function TooltipSurface({
|
|
|
448
518
|
if (measureInFlightRef.current) return;
|
|
449
519
|
const epoch = resolveEpochRef.current;
|
|
450
520
|
measureInFlightRef.current = true;
|
|
451
|
-
|
|
452
|
-
|
|
521
|
+
const { host } = resolution;
|
|
522
|
+
const placedFiber = resolution.fiber ?? fiberFromPublicInstance(host.node);
|
|
523
|
+
// Refreshed per resolve, not per frame: a sheet moves rarely, and the
|
|
524
|
+
// lookup walks the whole tree.
|
|
525
|
+
locateTargetOrigin(placedFiber, (origin) => {
|
|
526
|
+
if (resolveEpochRef.current !== epoch || !mountedRef.current) {
|
|
453
527
|
measureInFlightRef.current = false;
|
|
454
528
|
return;
|
|
455
529
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
if (width <= 0 || height <= 0) {
|
|
460
|
-
const cacheId = fiberCacheIdRef.current;
|
|
461
|
-
if (cacheId) invalidateFiberAnchor(cacheId);
|
|
462
|
-
dropHost();
|
|
530
|
+
if (!origin) {
|
|
531
|
+
concealHost();
|
|
463
532
|
return;
|
|
464
533
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
534
|
+
measureOriginRef.current = origin;
|
|
535
|
+
host.measureInWindow((x, y, width, height) => {
|
|
536
|
+
onHostMeasured(epoch, x, y, width, height);
|
|
537
|
+
});
|
|
469
538
|
});
|
|
470
|
-
}, [anchorId,
|
|
539
|
+
}, [anchorId, concealHost, decodedAutoData, dropHost, isAuto, onHostMeasured]);
|
|
471
540
|
|
|
472
541
|
/**
|
|
473
542
|
* Live re-measure of an already-resolved host. Driven by the shared rAF hub
|
|
@@ -482,25 +551,9 @@ export function TooltipSurface({
|
|
|
482
551
|
const epoch = resolveEpochRef.current;
|
|
483
552
|
measureInFlightRef.current = true;
|
|
484
553
|
measure((x, y, width, height) => {
|
|
485
|
-
|
|
486
|
-
measureInFlightRef.current = false;
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
measureInFlightRef.current = false;
|
|
490
|
-
if (!mountedRef.current) return;
|
|
491
|
-
|
|
492
|
-
if (width <= 0 || height <= 0) {
|
|
493
|
-
const cacheId = fiberCacheIdRef.current;
|
|
494
|
-
if (cacheId) invalidateFiberAnchor(cacheId);
|
|
495
|
-
dropHost();
|
|
496
|
-
return;
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
const rect: Rect = { x, y, width, height };
|
|
500
|
-
maybeScrollIntoView(rect);
|
|
501
|
-
applyTarget(rect);
|
|
554
|
+
onHostMeasured(epoch, x, y, width, height);
|
|
502
555
|
});
|
|
503
|
-
}, [
|
|
556
|
+
}, [onHostMeasured]);
|
|
504
557
|
|
|
505
558
|
const resolveTargetRef = React.useRef(resolveTarget);
|
|
506
559
|
resolveTargetRef.current = resolveTarget;
|
|
@@ -519,7 +572,8 @@ export function TooltipSurface({
|
|
|
519
572
|
}
|
|
520
573
|
const search = new TargetSearchSchedule(() => resolveTargetRef.current());
|
|
521
574
|
searchRef.current = search;
|
|
522
|
-
|
|
575
|
+
// A concealed target keeps the steady poll, so the tooltip is back soon after the modal closes.
|
|
576
|
+
search.setMode(targetRef.current || concealedRef.current ? 'anchored' : 'missing');
|
|
523
577
|
|
|
524
578
|
const trigger = () => search.trigger();
|
|
525
579
|
const unsubscribers = [
|
|
@@ -554,8 +608,8 @@ export function TooltipSurface({
|
|
|
554
608
|
}, [resolveArmed, searchStopped, currentStep.id, targetKey]);
|
|
555
609
|
|
|
556
610
|
React.useEffect(() => {
|
|
557
|
-
searchRef.current?.setMode(target ? 'anchored' : 'missing');
|
|
558
|
-
}, [target]);
|
|
611
|
+
searchRef.current?.setMode(target || concealed ? 'anchored' : 'missing');
|
|
612
|
+
}, [target, concealed]);
|
|
559
613
|
|
|
560
614
|
// rAF tracking while a host is resolved (and we are not paused after report).
|
|
561
615
|
React.useEffect(() => {
|
|
@@ -590,7 +644,7 @@ export function TooltipSurface({
|
|
|
590
644
|
return;
|
|
591
645
|
}
|
|
592
646
|
|
|
593
|
-
if (!measureAttempted) {
|
|
647
|
+
if (!measureAttempted || concealed) {
|
|
594
648
|
return;
|
|
595
649
|
}
|
|
596
650
|
|
|
@@ -606,6 +660,7 @@ export function TooltipSurface({
|
|
|
606
660
|
}, [
|
|
607
661
|
target,
|
|
608
662
|
measureAttempted,
|
|
663
|
+
concealed,
|
|
609
664
|
engine,
|
|
610
665
|
currentStep.id,
|
|
611
666
|
theme.tooltipMissingBehavior,
|
|
@@ -870,6 +925,11 @@ export function TooltipSurface({
|
|
|
870
925
|
return null;
|
|
871
926
|
}
|
|
872
927
|
|
|
928
|
+
// A native modal hides the target: nothing over it, not even the blocker.
|
|
929
|
+
if (isMissing && concealed) {
|
|
930
|
+
return null;
|
|
931
|
+
}
|
|
932
|
+
|
|
873
933
|
const showBranding = session.flow.company.flowBranding;
|
|
874
934
|
const contentPadding = chrome.contentPadding;
|
|
875
935
|
// Modal only while the host is trapped too. Otherwise VoiceOver would skip
|
|
@@ -915,6 +975,7 @@ export function TooltipSurface({
|
|
|
915
975
|
<Text
|
|
916
976
|
style={{
|
|
917
977
|
color: theme.fontColor,
|
|
978
|
+
fontFamily: contentFontFamily,
|
|
918
979
|
fontSize: theme.fontSize,
|
|
919
980
|
marginTop: 12,
|
|
920
981
|
textAlign: 'center',
|
|
@@ -962,11 +1023,21 @@ export function TooltipSurface({
|
|
|
962
1023
|
{showMissingUi ? (
|
|
963
1024
|
<View testID="userflow-tooltip-missing">
|
|
964
1025
|
<Text
|
|
965
|
-
style={[
|
|
1026
|
+
style={[
|
|
1027
|
+
styles.missingTitle,
|
|
1028
|
+
{ color: theme.fontColor, fontFamily: contentFontFamily, fontSize: theme.fontSize },
|
|
1029
|
+
]}
|
|
966
1030
|
>
|
|
967
1031
|
Target not found
|
|
968
1032
|
</Text>
|
|
969
|
-
<Text
|
|
1033
|
+
<Text
|
|
1034
|
+
style={{
|
|
1035
|
+
color: theme.fontColor,
|
|
1036
|
+
fontFamily: contentFontFamily,
|
|
1037
|
+
fontSize: theme.fontSize,
|
|
1038
|
+
opacity: 0.8,
|
|
1039
|
+
}}
|
|
1040
|
+
>
|
|
970
1041
|
This step's anchor is missing. Close to continue, or wait if the screen is still
|
|
971
1042
|
loading.
|
|
972
1043
|
</Text>
|
|
@@ -34,7 +34,6 @@ import {
|
|
|
34
34
|
resolveBannerBarBorderRadius,
|
|
35
35
|
} from '../bannerBarLayout';
|
|
36
36
|
import { bannerOverlayShadowStyle } from '../bannerBarTokens';
|
|
37
|
-
import { resolveBannerBackgroundColor } from '../resolveBannerTheme';
|
|
38
37
|
import { useUserflowSafeAreaInsets } from '../safeArea';
|
|
39
38
|
|
|
40
39
|
import { collectBannerAutoRunEvalCodes } from './bannerAutoRunEvalJs';
|
|
@@ -311,15 +310,18 @@ export function BannerWebViewBar({
|
|
|
311
310
|
const frameStyle = bannerFrameStyle(banner);
|
|
312
311
|
const overlayEdge = banner.embedMode === BannerEmbedMode.BODY_LAST ? 'bottom' : 'top';
|
|
313
312
|
const barRadius = resolveBannerBarBorderRadius(banner);
|
|
314
|
-
|
|
313
|
+
// Custom CSS paints the card, often with its own radius. The theme color
|
|
314
|
+
// (brand blue when banner tokens are unset) would otherwise fill the
|
|
315
|
+
// status-bar pad and the corners outside that radius.
|
|
316
|
+
const shellBackground = 'transparent';
|
|
315
317
|
const webStyle: ViewStyle = {
|
|
316
318
|
width: '100%',
|
|
317
319
|
height: contentHeight,
|
|
318
|
-
backgroundColor,
|
|
320
|
+
backgroundColor: shellBackground,
|
|
319
321
|
};
|
|
320
322
|
const debugging = typeof __DEV__ !== 'undefined' && __DEV__ ? true : undefined;
|
|
321
323
|
const insetChrome = safeAreaEdge
|
|
322
|
-
? bannerPushLayoutChrome(safeAreaEdge, insets,
|
|
324
|
+
? bannerPushLayoutChrome(safeAreaEdge, insets, shellBackground)
|
|
323
325
|
: null;
|
|
324
326
|
const insetChromeOutsideFade = insetChrome != null && fadeIn;
|
|
325
327
|
|
|
@@ -1,38 +1,6 @@
|
|
|
1
|
-
import type { BannerFragment
|
|
2
|
-
import { FlowActionType } from '@userflow-tech/protocol';
|
|
1
|
+
import type { BannerFragment } from '@userflow-tech/protocol';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
/** POC / local testing when the builder flag is not on the wire yet. */
|
|
9
|
-
export function setDebugForceWebViewBanner(enabled: boolean): void {
|
|
10
|
-
debugForceWebViewBanner = enabled;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/** @internal */
|
|
14
|
-
export function resetDebugForceWebViewBannerForTests(): void {
|
|
15
|
-
debugForceWebViewBanner = false;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function bannerHasEvalJsAction(banner: BannerFragment): boolean {
|
|
19
|
-
return banner.buttons.some((button) =>
|
|
20
|
-
button.actions.some((action) => action.type === FlowActionType.EVAL_JS),
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Use the WebView banner renderer when any button runs Evaluate JavaScript
|
|
26
|
-
* (needs the shared eval page), when the theme has published custom CSS
|
|
27
|
-
* (`.userflow-custom-container-*` / `.userflow-custom-button-*` via CDN),
|
|
28
|
-
* or when {@link setDebugForceWebViewBanner} is true.
|
|
29
|
-
*/
|
|
30
|
-
export function bannerNeedsWebView(banner: BannerFragment, theme?: ThemeFragment | null): boolean {
|
|
31
|
-
if (debugForceWebViewBanner) {
|
|
32
|
-
return true;
|
|
33
|
-
}
|
|
34
|
-
if (theme != null && themeHasPublishedCustomCss(theme)) {
|
|
35
|
-
return true;
|
|
36
|
-
}
|
|
37
|
-
return bannerHasEvalJsAction(banner);
|
|
3
|
+
/** Use the WebView banner renderer when the builder enabled custom banners. */
|
|
4
|
+
export function bannerNeedsWebView(banner: BannerFragment): boolean {
|
|
5
|
+
return banner.customBannerEnabled === true;
|
|
38
6
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ThemeFragment } from '@userflow-tech/protocol';
|
|
2
2
|
|
|
3
|
+
import { contentFontFamilyCss } from '../../content/resolveContentFontFamily';
|
|
3
4
|
import { resolveBannerBackgroundColor, resolveBannerForegroundColor } from '../resolveBannerTheme';
|
|
4
5
|
|
|
5
6
|
function readString(theme: ThemeFragment, key: string, fallback: string): string {
|
|
@@ -68,7 +69,7 @@ export function bannerThemeInlineStyles(theme: ThemeFragment): Record<string, st
|
|
|
68
69
|
'bannerActiveForegroundColor',
|
|
69
70
|
bannerFg,
|
|
70
71
|
),
|
|
71
|
-
'--userflow-font-family':
|
|
72
|
+
'--userflow-font-family': contentFontFamilyCss(theme),
|
|
72
73
|
'--userflow-font-size': `${fontSize}px`,
|
|
73
74
|
'--userflow-line-height': `${lineHeight}px`,
|
|
74
75
|
'--userflow-button-height': readCssLength(theme, 'buttonHeight', 32),
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Height the native WebView should use for a custom banner.
|
|
3
|
+
*
|
|
4
|
+
* Custom CSS often sizes the card with `min-height` and takes the copy and
|
|
5
|
+
* buttons out of flow (`position: absolute`). The WebView is created shorter
|
|
6
|
+
* than that card, so a root that only looks as tall as the viewport because of
|
|
7
|
+
* `min-height` must not be replaced with the close button's box.
|
|
8
|
+
*
|
|
9
|
+
* When the root really is stretching to fill a taller viewport (`height: 100%`),
|
|
10
|
+
* fall back to in-flow content, and never below `min-height`.
|
|
11
|
+
*/
|
|
12
|
+
export function resolveBannerWebViewHeight(
|
|
13
|
+
rectHeight: number,
|
|
14
|
+
scrollHeight: number,
|
|
15
|
+
viewportHeight: number,
|
|
16
|
+
minHeight: number,
|
|
17
|
+
contentHeight: number,
|
|
18
|
+
): number {
|
|
19
|
+
const rect = rectHeight > 0 ? rectHeight : 0;
|
|
20
|
+
const scroll = scrollHeight > 0 ? scrollHeight : 0;
|
|
21
|
+
let height = Math.ceil(Math.max(rect, scroll));
|
|
22
|
+
const floor = minHeight > 0 ? Math.ceil(minHeight) : 0;
|
|
23
|
+
if (viewportHeight > 0 && height >= viewportHeight - 2 && height > floor + 1) {
|
|
24
|
+
if (contentHeight > 0 && contentHeight < height) {
|
|
25
|
+
height = Math.ceil(contentHeight > floor ? contentHeight : floor);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (floor > height) {
|
|
29
|
+
height = floor;
|
|
30
|
+
}
|
|
31
|
+
return height;
|
|
32
|
+
}
|
|
@@ -2,6 +2,10 @@ import { interpolateVariables } from '@userflow-tech/core';
|
|
|
2
2
|
import type { BannerFragment, BannerSessionFragment } from '@userflow-tech/protocol';
|
|
3
3
|
import { BannerContentLayout } from '@userflow-tech/protocol';
|
|
4
4
|
|
|
5
|
+
import {
|
|
6
|
+
bannerContentFontLockCss,
|
|
7
|
+
contentFontFaceCss,
|
|
8
|
+
} from '../../content/resolveContentFontFamily';
|
|
5
9
|
import { buildBootstrapHtml, wrapCode } from '../../evalJs/bootstrap';
|
|
6
10
|
import type { EvalJsContext } from '../../evalJs/types';
|
|
7
11
|
|
|
@@ -27,26 +31,45 @@ function contentLayoutClass(layout: BannerContentLayout): string {
|
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
function layoutMeasureScript(): string {
|
|
34
|
+
// Inlined on purpose. Hermes' Function#toString is not the source text, so
|
|
35
|
+
// interpolating resolveBannerWebViewHeight.toString() ships a dead function.
|
|
36
|
+
// Keep this body in sync with resolveBannerWebViewHeight.
|
|
30
37
|
return `
|
|
31
38
|
(function(){
|
|
39
|
+
function resolveBannerWebViewHeight(rectHeight,scrollHeight,viewportHeight,minHeight,contentHeight){
|
|
40
|
+
var rect=rectHeight>0?rectHeight:0;
|
|
41
|
+
var scroll=scrollHeight>0?scrollHeight:0;
|
|
42
|
+
var height=Math.ceil(Math.max(rect,scroll));
|
|
43
|
+
var floor=minHeight>0?Math.ceil(minHeight):0;
|
|
44
|
+
if(viewportHeight>0&&height>=viewportHeight-2&&height>floor+1){
|
|
45
|
+
if(contentHeight>0&&contentHeight<height){
|
|
46
|
+
height=Math.ceil(contentHeight>floor?contentHeight:floor);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if(floor>height) height=floor;
|
|
50
|
+
return height;
|
|
51
|
+
}
|
|
32
52
|
function postLayout(){
|
|
33
53
|
var root=document.querySelector('.userflowjs-banner-root');
|
|
34
54
|
if(!root||!window.ReactNativeWebView||!window.ReactNativeWebView.postMessage)return;
|
|
35
55
|
var rectH=root.getBoundingClientRect().height;
|
|
36
56
|
var scrollH=root.scrollHeight;
|
|
37
|
-
var
|
|
57
|
+
var minH=parseFloat(window.getComputedStyle(root).minHeight);
|
|
58
|
+
if(!(minH>0)) minH=0;
|
|
38
59
|
var vh=window.innerHeight||0;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
60
|
+
var inFlow=0;
|
|
61
|
+
var all=0;
|
|
62
|
+
for(var i=0;i<root.childNodes.length;i++){
|
|
63
|
+
var node=root.childNodes[i];
|
|
64
|
+
if(!node||node.nodeType!==1) continue;
|
|
65
|
+
var box=node.scrollHeight||node.offsetHeight||0;
|
|
66
|
+
all+=box;
|
|
67
|
+
var cs=window.getComputedStyle(node);
|
|
68
|
+
if(cs.display==='none'||cs.position==='absolute'||cs.position==='fixed') continue;
|
|
69
|
+
inFlow+=box;
|
|
49
70
|
}
|
|
71
|
+
var content=inFlow>0?inFlow:all;
|
|
72
|
+
var h=resolveBannerWebViewHeight(rectH,scrollH,vh,minH,content);
|
|
50
73
|
window.ReactNativeWebView.postMessage(JSON.stringify({__userflow:1,type:'bannerLayout',height:h}));
|
|
51
74
|
}
|
|
52
75
|
window.__userflowBannerLayout=postLayout;
|
|
@@ -54,8 +77,18 @@ function layoutMeasureScript(): string {
|
|
|
54
77
|
var root=document.querySelector('.userflowjs-banner-root');
|
|
55
78
|
if(root){new ResizeObserver(postLayout).observe(root);}
|
|
56
79
|
}
|
|
80
|
+
var links=document.querySelectorAll('link[rel="stylesheet"]');
|
|
81
|
+
for(var s=0;s<links.length;s++){
|
|
82
|
+
links[s].addEventListener('load',postLayout);
|
|
83
|
+
links[s].addEventListener('error',postLayout);
|
|
84
|
+
}
|
|
57
85
|
window.addEventListener('load',postLayout);
|
|
86
|
+
// Custom CSS is often still applying on the first pass. A short WebView
|
|
87
|
+
// then clamps used height, so min-height never changes the box and
|
|
88
|
+
// ResizeObserver does not fire. Measure again after the stylesheet can apply.
|
|
58
89
|
setTimeout(postLayout,0);
|
|
90
|
+
setTimeout(postLayout,60);
|
|
91
|
+
setTimeout(postLayout,250);
|
|
59
92
|
})();
|
|
60
93
|
`;
|
|
61
94
|
}
|
|
@@ -171,6 +204,8 @@ export function buildCustomBannerBodyHtml(
|
|
|
171
204
|
const theme = session.version.theme;
|
|
172
205
|
const layoutClass = contentLayoutClass(banner.contentLayout);
|
|
173
206
|
const themeStyle = bannerThemeStyleAttribute(theme);
|
|
207
|
+
const fontFaceCss = contentFontFaceCss(theme);
|
|
208
|
+
const fontLockCss = bannerContentFontLockCss(theme);
|
|
174
209
|
const customCssUrl = resolveCustomStylesheetUrl(serverEndpoint, theme);
|
|
175
210
|
const innerMaxWidth = resolveBannerInnerMaxWidth(banner);
|
|
176
211
|
const maxInner =
|
|
@@ -200,8 +235,9 @@ export function buildCustomBannerBodyHtml(
|
|
|
200
235
|
: '';
|
|
201
236
|
|
|
202
237
|
return `
|
|
203
|
-
<style>${BANNER_WEB_FRAME_CSS}</style>
|
|
238
|
+
<style>${fontFaceCss}${BANNER_WEB_FRAME_CSS}</style>
|
|
204
239
|
${customLink}
|
|
240
|
+
<style>${fontLockCss}</style>
|
|
205
241
|
<div class="userflowjs-banner-root userflowjs-theme-root ${layoutClass}" style="${themeStyle}">
|
|
206
242
|
<div class="userflowjs-banner-start-spacer"></div>
|
|
207
243
|
<div class="userflowjs-banner-inner"${maxInner}>
|
|
@@ -90,16 +90,14 @@ export function buildHighlightRings(rect: HighlightRect, chrome: HighlightChrome
|
|
|
90
90
|
|
|
91
91
|
function strokeGlow(chrome: HighlightChrome): ViewStyle {
|
|
92
92
|
const blur = Math.max(chrome.radius, 6);
|
|
93
|
-
|
|
93
|
+
// Built in one literal: React Native 0.88 types ViewStyle as readonly.
|
|
94
|
+
return {
|
|
94
95
|
shadowColor: chrome.color,
|
|
95
96
|
shadowOffset: { width: 0, height: 0 },
|
|
96
97
|
shadowOpacity: Math.min(0.45, chrome.opacity),
|
|
97
98
|
shadowRadius: blur,
|
|
99
|
+
...(Platform?.OS !== 'ios' ? { boxShadow: `0px 0px ${blur}px 0px ${chrome.glowColor}` } : null),
|
|
98
100
|
};
|
|
99
|
-
if (Platform?.OS !== 'ios') {
|
|
100
|
-
glow.boxShadow = `0px 0px ${blur}px 0px ${chrome.glowColor}`;
|
|
101
|
-
}
|
|
102
|
-
return glow;
|
|
103
101
|
}
|
|
104
102
|
|
|
105
103
|
function ringFrame(
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { fiberScanRoot } from '../../anchors/fiber/FiberScanRootStore';
|
|
2
|
+
import type { AnyFiber } from '../../anchors/fiber/fiberInternals';
|
|
3
|
+
import {
|
|
4
|
+
locatePresentedModal,
|
|
5
|
+
measureOriginOf,
|
|
6
|
+
type Point,
|
|
7
|
+
} from '../../anchors/fiber/presentedModal';
|
|
8
|
+
import { getFiberAnchorScreenKey } from '../../anchors/fiberAnchorCache';
|
|
9
|
+
import { hasWindowOverlayHost } from '../../runtime/WindowOverlayHost';
|
|
10
|
+
|
|
11
|
+
import type { Rect } from './inferTooltipPlacement';
|
|
12
|
+
|
|
13
|
+
const ZERO: Point = { x: 0, y: 0 };
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* How long "nothing is presented" is trusted on the same screen. The lookup
|
|
17
|
+
* walks the whole fiber tree (1.4ms for 2,200 fibers in a debug build), and
|
|
18
|
+
* an anchored tooltip resolves four times a second. Expo Router and native
|
|
19
|
+
* stack modals change the screen, which skips this wait; a React Native
|
|
20
|
+
* `<Modal>` over the target is noticed within it.
|
|
21
|
+
*/
|
|
22
|
+
export const NO_MODAL_TRUST_MS = 1000;
|
|
23
|
+
|
|
24
|
+
let noModalSince: { at: number; screenKey: string | null } | null = null;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Where a tooltip target's measured rects sit in the window. `done` gets the
|
|
28
|
+
* window position of `(0, 0)` in the target's measure space, or null when the
|
|
29
|
+
* tooltip cannot point at it: a natively presented modal covers the target,
|
|
30
|
+
* or the target is inside a modal that cannot be placed (see
|
|
31
|
+
* `presentedModal.ts`). Also null when the target has no fiber to place.
|
|
32
|
+
*
|
|
33
|
+
* Without the window host, flow chrome is drawn in the root view under any
|
|
34
|
+
* native modal, as before, and `done` runs synchronously with zero.
|
|
35
|
+
*/
|
|
36
|
+
export function locateTargetOrigin(
|
|
37
|
+
fiber: AnyFiber | null,
|
|
38
|
+
done: (origin: Point | null) => void,
|
|
39
|
+
): void {
|
|
40
|
+
if (!hasWindowOverlayHost()) {
|
|
41
|
+
done(ZERO);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const screenKey = getFiberAnchorScreenKey();
|
|
45
|
+
const now = Date.now();
|
|
46
|
+
if (
|
|
47
|
+
noModalSince &&
|
|
48
|
+
noModalSince.screenKey === screenKey &&
|
|
49
|
+
now - noModalSince.at < NO_MODAL_TRUST_MS
|
|
50
|
+
) {
|
|
51
|
+
done(ZERO);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
locatePresentedModal(fiberScanRoot.getFiber()).then(
|
|
55
|
+
(modal) => {
|
|
56
|
+
noModalSince = modal == null ? { at: now, screenKey } : null;
|
|
57
|
+
done(modal == null ? ZERO : fiber ? measureOriginOf(fiber, modal) : null);
|
|
58
|
+
},
|
|
59
|
+
() => {
|
|
60
|
+
noModalSince = null;
|
|
61
|
+
done(null);
|
|
62
|
+
},
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function offsetRect(rect: Rect, origin: Point): Rect {
|
|
67
|
+
if (origin.x === 0 && origin.y === 0) return rect;
|
|
68
|
+
return { ...rect, x: rect.x + origin.x, y: rect.y + origin.y };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** @internal Forgets the cached "nothing is presented" between tests. */
|
|
72
|
+
export function resetTargetOriginForTests(): void {
|
|
73
|
+
noModalSince = null;
|
|
74
|
+
}
|