@userflow-tech/react-native 0.4.4 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +124 -34
- package/docs/anchoring.md +6 -1
- package/docs/deep-linking.md +26 -0
- package/docs/troubleshooting.md +50 -23
- package/expo-plugin/hostDependencyWarnings.d.ts +6 -4
- package/expo-plugin/hostDependencyWarnings.d.ts.map +1 -1
- package/expo-plugin/hostDependencyWarnings.js +8 -6
- package/expo-plugin/hostDependencyWarnings.js.map +1 -1
- package/lib/commonjs/anchors/AutoAnchorRegistry.js +144 -34
- package/lib/commonjs/anchors/AutoAnchorRegistry.js.map +1 -1
- package/lib/commonjs/anchors/animationFrame.js +29 -1
- package/lib/commonjs/anchors/animationFrame.js.map +1 -1
- package/lib/commonjs/anchors/appActive.js +61 -0
- package/lib/commonjs/anchors/appActive.js.map +1 -0
- package/lib/commonjs/anchors/elementConditionEvaluator.js +25 -8
- package/lib/commonjs/anchors/elementConditionEvaluator.js.map +1 -1
- package/lib/commonjs/anchors/elementTapMonitor.js +67 -12
- package/lib/commonjs/anchors/elementTapMonitor.js.map +1 -1
- package/lib/commonjs/anchors/elementTargetMatch.js +33 -7
- package/lib/commonjs/anchors/elementTargetMatch.js.map +1 -1
- package/lib/commonjs/anchors/fiber/fiberInternals.js +66 -0
- package/lib/commonjs/anchors/fiber/fiberInternals.js.map +1 -1
- package/lib/commonjs/anchors/fiber/indexHostFibers.js +4 -3
- package/lib/commonjs/anchors/fiber/indexHostFibers.js.map +1 -1
- package/lib/commonjs/anchors/fiber/resolveFiberPath.js +30 -15
- package/lib/commonjs/anchors/fiber/resolveFiberPath.js.map +1 -1
- package/lib/commonjs/anchors/fiberAnchorCache.js +20 -0
- package/lib/commonjs/anchors/fiberAnchorCache.js.map +1 -1
- package/lib/commonjs/anchors/gestureHandlerHandoff.js +304 -0
- package/lib/commonjs/anchors/gestureHandlerHandoff.js.map +1 -0
- package/lib/commonjs/anchors/resolveAnchorHost.js +6 -0
- package/lib/commonjs/anchors/resolveAnchorHost.js.map +1 -1
- package/lib/commonjs/anchors/resolveAutoAnchorHost.js +11 -6
- package/lib/commonjs/anchors/resolveAutoAnchorHost.js.map +1 -1
- package/lib/commonjs/anchors/resolveElementTargets.js +63 -8
- package/lib/commonjs/anchors/resolveElementTargets.js.map +1 -1
- package/lib/commonjs/anchors/semanticMatcher.js +43 -21
- package/lib/commonjs/anchors/semanticMatcher.js.map +1 -1
- package/lib/commonjs/anchors/tapSlop.js +16 -0
- package/lib/commonjs/anchors/tapSlop.js.map +1 -0
- package/lib/commonjs/anchors/targetPressMonitor.js +66 -12
- package/lib/commonjs/anchors/targetPressMonitor.js.map +1 -1
- package/lib/commonjs/authoring/fingerprintFromInstance.js +5 -9
- package/lib/commonjs/authoring/fingerprintFromInstance.js.map +1 -1
- package/lib/commonjs/content/RichContentRenderer.js +3 -3
- package/lib/commonjs/content/RichContentRenderer.js.map +1 -1
- package/lib/commonjs/content/openSafeUrl.js +3 -1
- package/lib/commonjs/content/openSafeUrl.js.map +1 -1
- package/lib/commonjs/expo-router/useUserflowExpoRouter.js +6 -0
- package/lib/commonjs/expo-router/useUserflowExpoRouter.js.map +1 -1
- package/lib/commonjs/index.js +19 -5
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/installCheck.js +2 -2
- package/lib/commonjs/installCheck.js.map +1 -1
- package/lib/commonjs/navigation/navigateUrlUtils.js +105 -0
- package/lib/commonjs/navigation/navigateUrlUtils.js.map +1 -0
- package/lib/commonjs/navigation/openExternalNavigateUrl.js +14 -0
- package/lib/commonjs/navigation/openExternalNavigateUrl.js.map +1 -0
- package/lib/commonjs/navigation/openFlowNavigateUrl.js +47 -41
- package/lib/commonjs/navigation/openFlowNavigateUrl.js.map +1 -1
- package/lib/commonjs/pairing/PairingController.js +3 -1
- package/lib/commonjs/pairing/PairingController.js.map +1 -1
- package/lib/commonjs/runtime/BannerHost.js +38 -29
- package/lib/commonjs/runtime/BannerHost.js.map +1 -1
- package/lib/commonjs/runtime/TargetPressBridge.js +55 -7
- package/lib/commonjs/runtime/TargetPressBridge.js.map +1 -1
- package/lib/commonjs/runtime/UserflowOverlay.js +5 -11
- package/lib/commonjs/runtime/UserflowOverlay.js.map +1 -1
- package/lib/commonjs/runtime/UserflowProvider.js +66 -40
- package/lib/commonjs/runtime/UserflowProvider.js.map +1 -1
- package/lib/commonjs/runtime/bannerEngine.js +8 -2
- package/lib/commonjs/runtime/bannerEngine.js.map +1 -1
- package/lib/commonjs/runtime/bannerFlowSpacer.js +71 -0
- package/lib/commonjs/runtime/bannerFlowSpacer.js.map +1 -0
- package/lib/commonjs/runtime/flowEngine.js +11 -0
- package/lib/commonjs/runtime/flowEngine.js.map +1 -1
- package/lib/commonjs/runtime/previewStart.js +39 -0
- package/lib/commonjs/runtime/previewStart.js.map +1 -0
- package/lib/commonjs/runtime/pushBannerLayoutContext.js +98 -0
- package/lib/commonjs/runtime/pushBannerLayoutContext.js.map +1 -0
- package/lib/commonjs/screenTracker.js +12 -0
- package/lib/commonjs/screenTracker.js.map +1 -1
- package/lib/commonjs/surfaces/BannerBar.js +79 -61
- package/lib/commonjs/surfaces/BannerBar.js.map +1 -1
- package/lib/commonjs/surfaces/BannerSurface.js +26 -0
- package/lib/commonjs/surfaces/BannerSurface.js.map +1 -1
- package/lib/commonjs/surfaces/TooltipSurface.js +43 -41
- package/lib/commonjs/surfaces/TooltipSurface.js.map +1 -1
- package/lib/commonjs/surfaces/bannerBarLayout.js +77 -10
- package/lib/commonjs/surfaces/bannerBarLayout.js.map +1 -1
- package/lib/commonjs/surfaces/bannerWebView/BannerWebViewBar.js +112 -63
- package/lib/commonjs/surfaces/bannerWebView/BannerWebViewBar.js.map +1 -1
- package/lib/commonjs/surfaces/bannerWebView/buildCustomBannerHtml.js +59 -11
- package/lib/commonjs/surfaces/bannerWebView/buildCustomBannerHtml.js.map +1 -1
- package/lib/commonjs/surfaces/hostAccessibilityTrap.js +28 -0
- package/lib/commonjs/surfaces/hostAccessibilityTrap.js.map +1 -0
- package/lib/commonjs/surfaces/resolveBannerTheme.js +6 -3
- package/lib/commonjs/surfaces/resolveBannerTheme.js.map +1 -1
- package/lib/commonjs/surfaces/tooltip/TooltipBubble.js +3 -2
- package/lib/commonjs/surfaces/tooltip/TooltipBubble.js.map +1 -1
- package/lib/commonjs/surfaces/tooltip/targetSearchSchedule.js +134 -0
- package/lib/commonjs/surfaces/tooltip/targetSearchSchedule.js.map +1 -0
- package/lib/commonjs/version.js +1 -1
- package/lib/module/anchors/AutoAnchorRegistry.js +145 -35
- package/lib/module/anchors/AutoAnchorRegistry.js.map +1 -1
- package/lib/module/anchors/animationFrame.js +29 -2
- package/lib/module/anchors/animationFrame.js.map +1 -1
- package/lib/module/anchors/appActive.js +57 -0
- package/lib/module/anchors/appActive.js.map +1 -0
- package/lib/module/anchors/elementConditionEvaluator.js +26 -9
- package/lib/module/anchors/elementConditionEvaluator.js.map +1 -1
- package/lib/module/anchors/elementTapMonitor.js +67 -12
- package/lib/module/anchors/elementTapMonitor.js.map +1 -1
- package/lib/module/anchors/elementTargetMatch.js +32 -7
- package/lib/module/anchors/elementTargetMatch.js.map +1 -1
- package/lib/module/anchors/fiber/fiberInternals.js +65 -0
- package/lib/module/anchors/fiber/fiberInternals.js.map +1 -1
- package/lib/module/anchors/fiber/indexHostFibers.js +4 -3
- package/lib/module/anchors/fiber/indexHostFibers.js.map +1 -1
- package/lib/module/anchors/fiber/resolveFiberPath.js +30 -15
- package/lib/module/anchors/fiber/resolveFiberPath.js.map +1 -1
- package/lib/module/anchors/fiberAnchorCache.js +19 -0
- package/lib/module/anchors/fiberAnchorCache.js.map +1 -1
- package/lib/module/anchors/gestureHandlerHandoff.js +298 -0
- package/lib/module/anchors/gestureHandlerHandoff.js.map +1 -0
- package/lib/module/anchors/resolveAnchorHost.js +1 -0
- package/lib/module/anchors/resolveAnchorHost.js.map +1 -1
- package/lib/module/anchors/resolveAutoAnchorHost.js +11 -6
- package/lib/module/anchors/resolveAutoAnchorHost.js.map +1 -1
- package/lib/module/anchors/resolveElementTargets.js +63 -8
- package/lib/module/anchors/resolveElementTargets.js.map +1 -1
- package/lib/module/anchors/semanticMatcher.js +43 -21
- package/lib/module/anchors/semanticMatcher.js.map +1 -1
- package/lib/module/anchors/tapSlop.js +11 -0
- package/lib/module/anchors/tapSlop.js.map +1 -0
- package/lib/module/anchors/targetPressMonitor.js +53 -8
- package/lib/module/anchors/targetPressMonitor.js.map +1 -1
- package/lib/module/authoring/fingerprintFromInstance.js +6 -10
- package/lib/module/authoring/fingerprintFromInstance.js.map +1 -1
- package/lib/module/content/RichContentRenderer.js +3 -3
- package/lib/module/content/RichContentRenderer.js.map +1 -1
- package/lib/module/content/openSafeUrl.js +3 -1
- package/lib/module/content/openSafeUrl.js.map +1 -1
- package/lib/module/expo-router/useUserflowExpoRouter.js +7 -1
- package/lib/module/expo-router/useUserflowExpoRouter.js.map +1 -1
- package/lib/module/index.js +22 -7
- package/lib/module/index.js.map +1 -1
- package/lib/module/installCheck.js +2 -2
- package/lib/module/installCheck.js.map +1 -1
- package/lib/module/navigation/navigateUrlUtils.js +94 -0
- package/lib/module/navigation/navigateUrlUtils.js.map +1 -0
- package/lib/module/navigation/openExternalNavigateUrl.js +11 -0
- package/lib/module/navigation/openExternalNavigateUrl.js.map +1 -0
- package/lib/module/navigation/openFlowNavigateUrl.js +22 -36
- package/lib/module/navigation/openFlowNavigateUrl.js.map +1 -1
- package/lib/module/pairing/PairingController.js +3 -1
- package/lib/module/pairing/PairingController.js.map +1 -1
- package/lib/module/runtime/BannerHost.js +38 -29
- package/lib/module/runtime/BannerHost.js.map +1 -1
- package/lib/module/runtime/TargetPressBridge.js +56 -8
- package/lib/module/runtime/TargetPressBridge.js.map +1 -1
- package/lib/module/runtime/UserflowOverlay.js +5 -11
- package/lib/module/runtime/UserflowOverlay.js.map +1 -1
- package/lib/module/runtime/UserflowProvider.js +66 -40
- package/lib/module/runtime/UserflowProvider.js.map +1 -1
- package/lib/module/runtime/bannerEngine.js +7 -2
- package/lib/module/runtime/bannerEngine.js.map +1 -1
- package/lib/module/runtime/bannerFlowSpacer.js +65 -0
- package/lib/module/runtime/bannerFlowSpacer.js.map +1 -0
- package/lib/module/runtime/flowEngine.js +11 -0
- package/lib/module/runtime/flowEngine.js.map +1 -1
- package/lib/module/runtime/previewStart.js +35 -0
- package/lib/module/runtime/previewStart.js.map +1 -0
- package/lib/module/runtime/pushBannerLayoutContext.js +91 -0
- package/lib/module/runtime/pushBannerLayoutContext.js.map +1 -0
- package/lib/module/screenTracker.js +11 -0
- package/lib/module/screenTracker.js.map +1 -1
- package/lib/module/surfaces/BannerBar.js +80 -62
- package/lib/module/surfaces/BannerBar.js.map +1 -1
- package/lib/module/surfaces/BannerSurface.js +26 -0
- package/lib/module/surfaces/BannerSurface.js.map +1 -1
- package/lib/module/surfaces/TooltipSurface.js +44 -42
- package/lib/module/surfaces/TooltipSurface.js.map +1 -1
- package/lib/module/surfaces/bannerBarLayout.js +72 -11
- package/lib/module/surfaces/bannerBarLayout.js.map +1 -1
- package/lib/module/surfaces/bannerWebView/BannerWebViewBar.js +113 -64
- package/lib/module/surfaces/bannerWebView/BannerWebViewBar.js.map +1 -1
- package/lib/module/surfaces/bannerWebView/buildCustomBannerHtml.js +59 -11
- package/lib/module/surfaces/bannerWebView/buildCustomBannerHtml.js.map +1 -1
- package/lib/module/surfaces/hostAccessibilityTrap.js +24 -0
- package/lib/module/surfaces/hostAccessibilityTrap.js.map +1 -0
- package/lib/module/surfaces/resolveBannerTheme.js +6 -3
- package/lib/module/surfaces/resolveBannerTheme.js.map +1 -1
- package/lib/module/surfaces/tooltip/TooltipBubble.js +3 -2
- package/lib/module/surfaces/tooltip/TooltipBubble.js.map +1 -1
- package/lib/module/surfaces/tooltip/targetSearchSchedule.js +128 -0
- package/lib/module/surfaces/tooltip/targetSearchSchedule.js.map +1 -0
- package/lib/module/version.js +1 -1
- package/lib/typescript/commonjs/src/anchors/AutoAnchorRegistry.d.ts +36 -2
- package/lib/typescript/commonjs/src/anchors/AutoAnchorRegistry.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/animationFrame.d.ts +0 -4
- package/lib/typescript/commonjs/src/anchors/animationFrame.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/appActive.d.ts +8 -0
- package/lib/typescript/commonjs/src/anchors/appActive.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/anchors/elementTapMonitor.d.ts +17 -0
- package/lib/typescript/commonjs/src/anchors/elementTapMonitor.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/elementTargetMatch.d.ts +7 -0
- package/lib/typescript/commonjs/src/anchors/elementTargetMatch.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/fiber/fiberInternals.d.ts +7 -0
- package/lib/typescript/commonjs/src/anchors/fiber/fiberInternals.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/fiber/indexHostFibers.d.ts +3 -2
- package/lib/typescript/commonjs/src/anchors/fiber/indexHostFibers.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/fiber/resolveFiberPath.d.ts +3 -0
- package/lib/typescript/commonjs/src/anchors/fiber/resolveFiberPath.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/fiberAnchorCache.d.ts +5 -0
- package/lib/typescript/commonjs/src/anchors/fiberAnchorCache.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/gestureHandlerHandoff.d.ts +70 -0
- package/lib/typescript/commonjs/src/anchors/gestureHandlerHandoff.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/anchors/resolveAnchorHost.d.ts +1 -0
- package/lib/typescript/commonjs/src/anchors/resolveAnchorHost.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/resolveAutoAnchorHost.d.ts +11 -4
- package/lib/typescript/commonjs/src/anchors/resolveAutoAnchorHost.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/resolveElementTargets.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/semanticMatcher.d.ts +2 -0
- package/lib/typescript/commonjs/src/anchors/semanticMatcher.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/tapSlop.d.ts +9 -0
- package/lib/typescript/commonjs/src/anchors/tapSlop.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/anchors/targetPressMonitor.d.ts +13 -8
- package/lib/typescript/commonjs/src/anchors/targetPressMonitor.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/authoring/fingerprintFromInstance.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/content/RichContentRenderer.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/content/openSafeUrl.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/expo-router/useUserflowExpoRouter.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +6 -5
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/installCheck.d.ts +1 -1
- package/lib/typescript/commonjs/src/installCheck.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/navigation/navigateUrlUtils.d.ts +15 -0
- package/lib/typescript/commonjs/src/navigation/navigateUrlUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/navigation/openExternalNavigateUrl.d.ts +3 -0
- package/lib/typescript/commonjs/src/navigation/openExternalNavigateUrl.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/navigation/openFlowNavigateUrl.d.ts +2 -5
- package/lib/typescript/commonjs/src/navigation/openFlowNavigateUrl.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/pairing/PairingController.d.ts +6 -0
- package/lib/typescript/commonjs/src/pairing/PairingController.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/runtime/BannerHost.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/runtime/TargetPressBridge.d.ts +3 -0
- package/lib/typescript/commonjs/src/runtime/TargetPressBridge.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/runtime/UserflowOverlay.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/runtime/UserflowProvider.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/runtime/bannerEngine.d.ts +5 -1
- package/lib/typescript/commonjs/src/runtime/bannerEngine.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/runtime/bannerFlowSpacer.d.ts +15 -0
- package/lib/typescript/commonjs/src/runtime/bannerFlowSpacer.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/runtime/flowEngine.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/runtime/previewStart.d.ts +13 -0
- package/lib/typescript/commonjs/src/runtime/previewStart.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/runtime/pushBannerLayoutContext.d.ts +17 -0
- package/lib/typescript/commonjs/src/runtime/pushBannerLayoutContext.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/screenTracker.d.ts +6 -0
- package/lib/typescript/commonjs/src/screenTracker.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/surfaces/BannerBar.d.ts +3 -1
- package/lib/typescript/commonjs/src/surfaces/BannerBar.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/surfaces/BannerSurface.d.ts +5 -1
- package/lib/typescript/commonjs/src/surfaces/BannerSurface.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/surfaces/TooltipSurface.d.ts +1 -1
- package/lib/typescript/commonjs/src/surfaces/TooltipSurface.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/surfaces/bannerBarLayout.d.ts +17 -0
- package/lib/typescript/commonjs/src/surfaces/bannerBarLayout.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/surfaces/bannerWebView/BannerWebViewBar.d.ts +3 -1
- package/lib/typescript/commonjs/src/surfaces/bannerWebView/BannerWebViewBar.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/surfaces/bannerWebView/buildCustomBannerHtml.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/surfaces/hostAccessibilityTrap.d.ts +14 -0
- package/lib/typescript/commonjs/src/surfaces/hostAccessibilityTrap.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/surfaces/resolveBannerTheme.d.ts +4 -1
- package/lib/typescript/commonjs/src/surfaces/resolveBannerTheme.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/surfaces/tooltip/TooltipBubble.d.ts +7 -1
- package/lib/typescript/commonjs/src/surfaces/tooltip/TooltipBubble.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/surfaces/tooltip/targetSearchSchedule.d.ts +60 -0
- package/lib/typescript/commonjs/src/surfaces/tooltip/targetSearchSchedule.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/version.d.ts +1 -1
- package/lib/typescript/module/src/anchors/AutoAnchorRegistry.d.ts +36 -2
- package/lib/typescript/module/src/anchors/AutoAnchorRegistry.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/animationFrame.d.ts +0 -4
- package/lib/typescript/module/src/anchors/animationFrame.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/appActive.d.ts +8 -0
- package/lib/typescript/module/src/anchors/appActive.d.ts.map +1 -0
- package/lib/typescript/module/src/anchors/elementTapMonitor.d.ts +17 -0
- package/lib/typescript/module/src/anchors/elementTapMonitor.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/elementTargetMatch.d.ts +7 -0
- package/lib/typescript/module/src/anchors/elementTargetMatch.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/fiber/fiberInternals.d.ts +7 -0
- package/lib/typescript/module/src/anchors/fiber/fiberInternals.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/fiber/indexHostFibers.d.ts +3 -2
- package/lib/typescript/module/src/anchors/fiber/indexHostFibers.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/fiber/resolveFiberPath.d.ts +3 -0
- package/lib/typescript/module/src/anchors/fiber/resolveFiberPath.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/fiberAnchorCache.d.ts +5 -0
- package/lib/typescript/module/src/anchors/fiberAnchorCache.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/gestureHandlerHandoff.d.ts +70 -0
- package/lib/typescript/module/src/anchors/gestureHandlerHandoff.d.ts.map +1 -0
- package/lib/typescript/module/src/anchors/resolveAnchorHost.d.ts +1 -0
- package/lib/typescript/module/src/anchors/resolveAnchorHost.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/resolveAutoAnchorHost.d.ts +11 -4
- package/lib/typescript/module/src/anchors/resolveAutoAnchorHost.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/resolveElementTargets.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/semanticMatcher.d.ts +2 -0
- package/lib/typescript/module/src/anchors/semanticMatcher.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/tapSlop.d.ts +9 -0
- package/lib/typescript/module/src/anchors/tapSlop.d.ts.map +1 -0
- package/lib/typescript/module/src/anchors/targetPressMonitor.d.ts +13 -8
- package/lib/typescript/module/src/anchors/targetPressMonitor.d.ts.map +1 -1
- package/lib/typescript/module/src/authoring/fingerprintFromInstance.d.ts.map +1 -1
- package/lib/typescript/module/src/content/RichContentRenderer.d.ts.map +1 -1
- package/lib/typescript/module/src/content/openSafeUrl.d.ts.map +1 -1
- package/lib/typescript/module/src/expo-router/useUserflowExpoRouter.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +6 -5
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/installCheck.d.ts +1 -1
- package/lib/typescript/module/src/installCheck.d.ts.map +1 -1
- package/lib/typescript/module/src/navigation/navigateUrlUtils.d.ts +15 -0
- package/lib/typescript/module/src/navigation/navigateUrlUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/navigation/openExternalNavigateUrl.d.ts +3 -0
- package/lib/typescript/module/src/navigation/openExternalNavigateUrl.d.ts.map +1 -0
- package/lib/typescript/module/src/navigation/openFlowNavigateUrl.d.ts +2 -5
- package/lib/typescript/module/src/navigation/openFlowNavigateUrl.d.ts.map +1 -1
- package/lib/typescript/module/src/pairing/PairingController.d.ts +6 -0
- package/lib/typescript/module/src/pairing/PairingController.d.ts.map +1 -1
- package/lib/typescript/module/src/runtime/BannerHost.d.ts.map +1 -1
- package/lib/typescript/module/src/runtime/TargetPressBridge.d.ts +3 -0
- package/lib/typescript/module/src/runtime/TargetPressBridge.d.ts.map +1 -1
- package/lib/typescript/module/src/runtime/UserflowOverlay.d.ts.map +1 -1
- package/lib/typescript/module/src/runtime/UserflowProvider.d.ts.map +1 -1
- package/lib/typescript/module/src/runtime/bannerEngine.d.ts +5 -1
- package/lib/typescript/module/src/runtime/bannerEngine.d.ts.map +1 -1
- package/lib/typescript/module/src/runtime/bannerFlowSpacer.d.ts +15 -0
- package/lib/typescript/module/src/runtime/bannerFlowSpacer.d.ts.map +1 -0
- package/lib/typescript/module/src/runtime/flowEngine.d.ts.map +1 -1
- package/lib/typescript/module/src/runtime/previewStart.d.ts +13 -0
- package/lib/typescript/module/src/runtime/previewStart.d.ts.map +1 -0
- package/lib/typescript/module/src/runtime/pushBannerLayoutContext.d.ts +17 -0
- package/lib/typescript/module/src/runtime/pushBannerLayoutContext.d.ts.map +1 -0
- package/lib/typescript/module/src/screenTracker.d.ts +6 -0
- package/lib/typescript/module/src/screenTracker.d.ts.map +1 -1
- package/lib/typescript/module/src/surfaces/BannerBar.d.ts +3 -1
- package/lib/typescript/module/src/surfaces/BannerBar.d.ts.map +1 -1
- package/lib/typescript/module/src/surfaces/BannerSurface.d.ts +5 -1
- package/lib/typescript/module/src/surfaces/BannerSurface.d.ts.map +1 -1
- package/lib/typescript/module/src/surfaces/TooltipSurface.d.ts +1 -1
- package/lib/typescript/module/src/surfaces/TooltipSurface.d.ts.map +1 -1
- package/lib/typescript/module/src/surfaces/bannerBarLayout.d.ts +17 -0
- package/lib/typescript/module/src/surfaces/bannerBarLayout.d.ts.map +1 -1
- package/lib/typescript/module/src/surfaces/bannerWebView/BannerWebViewBar.d.ts +3 -1
- package/lib/typescript/module/src/surfaces/bannerWebView/BannerWebViewBar.d.ts.map +1 -1
- package/lib/typescript/module/src/surfaces/bannerWebView/buildCustomBannerHtml.d.ts.map +1 -1
- package/lib/typescript/module/src/surfaces/hostAccessibilityTrap.d.ts +14 -0
- package/lib/typescript/module/src/surfaces/hostAccessibilityTrap.d.ts.map +1 -0
- package/lib/typescript/module/src/surfaces/resolveBannerTheme.d.ts +4 -1
- package/lib/typescript/module/src/surfaces/resolveBannerTheme.d.ts.map +1 -1
- package/lib/typescript/module/src/surfaces/tooltip/TooltipBubble.d.ts +7 -1
- package/lib/typescript/module/src/surfaces/tooltip/TooltipBubble.d.ts.map +1 -1
- package/lib/typescript/module/src/surfaces/tooltip/targetSearchSchedule.d.ts +60 -0
- package/lib/typescript/module/src/surfaces/tooltip/targetSearchSchedule.d.ts.map +1 -0
- package/lib/typescript/module/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/anchors/AutoAnchorRegistry.ts +166 -35
- package/src/anchors/animationFrame.ts +31 -1
- package/src/anchors/appActive.ts +63 -0
- package/src/anchors/elementConditionEvaluator.ts +29 -12
- package/src/anchors/elementTapMonitor.ts +68 -10
- package/src/anchors/elementTargetMatch.ts +34 -7
- package/src/anchors/fiber/fiberInternals.ts +68 -0
- package/src/anchors/fiber/indexHostFibers.ts +8 -3
- package/src/anchors/fiber/resolveFiberPath.ts +25 -16
- package/src/anchors/fiberAnchorCache.ts +19 -0
- package/src/anchors/gestureHandlerHandoff.ts +356 -0
- package/src/anchors/resolveAnchorHost.ts +2 -0
- package/src/anchors/resolveAutoAnchorHost.ts +18 -8
- package/src/anchors/resolveElementTargets.ts +64 -7
- package/src/anchors/semanticMatcher.ts +48 -27
- package/src/anchors/tapSlop.ts +18 -0
- package/src/anchors/targetPressMonitor.ts +56 -19
- package/src/authoring/fingerprintFromInstance.ts +4 -5
- package/src/content/RichContentRenderer.tsx +4 -3
- package/src/content/openSafeUrl.ts +3 -1
- package/src/expo-router/useUserflowExpoRouter.ts +10 -1
- package/src/index.ts +20 -9
- package/src/installCheck.ts +4 -4
- package/src/navigation/navigateUrlUtils.ts +100 -0
- package/src/navigation/openExternalNavigateUrl.ts +9 -0
- package/src/navigation/openFlowNavigateUrl.ts +36 -36
- package/src/pairing/PairingController.ts +9 -1
- package/src/runtime/BannerHost.tsx +41 -23
- package/src/runtime/TargetPressBridge.tsx +66 -9
- package/src/runtime/UserflowOverlay.tsx +7 -9
- package/src/runtime/UserflowProvider.tsx +56 -32
- package/src/runtime/bannerEngine.ts +10 -2
- package/src/runtime/bannerFlowSpacer.tsx +70 -0
- package/src/runtime/flowEngine.ts +11 -0
- package/src/runtime/previewStart.ts +49 -0
- package/src/runtime/pushBannerLayoutContext.tsx +121 -0
- package/src/screenTracker.ts +11 -0
- package/src/surfaces/BannerBar.tsx +93 -55
- package/src/surfaces/BannerSurface.tsx +59 -3
- package/src/surfaces/TooltipSurface.tsx +63 -51
- package/src/surfaces/bannerBarLayout.ts +80 -7
- package/src/surfaces/bannerWebView/BannerWebViewBar.tsx +149 -57
- package/src/surfaces/bannerWebView/buildCustomBannerHtml.ts +63 -11
- package/src/surfaces/hostAccessibilityTrap.ts +25 -0
- package/src/surfaces/resolveBannerTheme.ts +14 -3
- package/src/surfaces/tooltip/TooltipBubble.tsx +8 -1
- package/src/surfaces/tooltip/targetSearchSchedule.ts +140 -0
- package/src/version.ts +1 -1
- package/vendor/core/dist/engine/BannerSessionEngine.d.ts +29 -2
- package/vendor/core/dist/engine/BannerSessionEngine.d.ts.map +1 -1
- package/vendor/core/dist/engine/BannerSessionEngine.js +87 -6
- package/vendor/core/dist/engine/BannerSessionEngine.js.map +1 -1
- package/vendor/core/dist/engine/ClientConditionEngine.d.ts.map +1 -1
- package/vendor/core/dist/engine/ClientConditionEngine.js +30 -7
- package/vendor/core/dist/engine/ClientConditionEngine.js.map +1 -1
- package/vendor/core/dist/engine/PairingEngine.d.ts +6 -1
- package/vendor/core/dist/engine/PairingEngine.d.ts.map +1 -1
- package/vendor/core/dist/engine/PairingEngine.js +23 -3
- package/vendor/core/dist/engine/PairingEngine.js.map +1 -1
- package/vendor/core/dist/engine/handleActions.d.ts.map +1 -1
- package/vendor/core/dist/engine/handleActions.js +67 -2
- package/vendor/core/dist/engine/handleActions.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/package.json +1 -1
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type { BannerSessionEngine } from '@userflow-tech/core';
|
|
2
|
-
import type { BannerSessionFragment } from '@userflow-tech/protocol';
|
|
3
2
|
import * as React from 'react';
|
|
4
3
|
import { StyleSheet, View } from 'react-native';
|
|
5
4
|
|
|
6
5
|
import { BannerSurface } from '../surfaces/BannerSurface';
|
|
7
6
|
import { bannerOverlayHostPadding } from '../surfaces/bannerBarLayout';
|
|
8
|
-
import {
|
|
7
|
+
import { bannerNeedsWebView } from '../surfaces/bannerWebView/bannerNeedsWebView';
|
|
9
8
|
import { useUserflowSafeAreaInsets } from '../surfaces/safeArea';
|
|
10
9
|
|
|
11
10
|
import { SdkErrorBoundary } from './SdkErrorBoundary';
|
|
@@ -50,53 +49,72 @@ export function BannerHost({
|
|
|
50
49
|
if (edgeFilter && edge !== edgeFilter) return null;
|
|
51
50
|
|
|
52
51
|
const floats = banner.overlay !== false;
|
|
53
|
-
|
|
52
|
+
const usesWebView = bannerNeedsWebView(banner, session.version.theme);
|
|
53
|
+
// Custom-css / eval WebViews paint in the overlay host (same as userflow.js). A second
|
|
54
|
+
// WKWebView in the flow slot often fails to load after the first banner dismisses.
|
|
55
|
+
const hostAsOverlay = floats || usesWebView;
|
|
56
|
+
if ((placement === 'overlay') !== hostAsOverlay) return null;
|
|
57
|
+
|
|
58
|
+
const pushLayoutEdge = placement === 'flow' && !hostAsOverlay ? edge : null;
|
|
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).
|
|
61
|
+
const overlaySafeEdge = hostAsOverlay && !floats ? edge : null;
|
|
62
|
+
|
|
63
|
+
const surface = (
|
|
64
|
+
<BannerSurface
|
|
65
|
+
session={session}
|
|
66
|
+
pushLayoutEdge={pushLayoutEdge}
|
|
67
|
+
overlaySafeEdge={overlaySafeEdge}
|
|
68
|
+
onActions={(actions) => engine.handleActions(actions)}
|
|
69
|
+
onDismiss={(endReason) => {
|
|
70
|
+
void engine.endBanner(endReason);
|
|
71
|
+
}}
|
|
72
|
+
/>
|
|
73
|
+
);
|
|
54
74
|
|
|
55
75
|
const bar = (
|
|
56
76
|
<SdkErrorBoundary scope="banner" resetKey={session.id}>
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
77
|
+
{placement === 'flow' ? (
|
|
78
|
+
<View testID="userflow-banner-flow" style={styles.flow}>
|
|
79
|
+
{surface}
|
|
80
|
+
</View>
|
|
81
|
+
) : (
|
|
82
|
+
surface
|
|
83
|
+
)}
|
|
64
84
|
</SdkErrorBoundary>
|
|
65
85
|
);
|
|
66
86
|
|
|
67
87
|
if (placement === 'flow') {
|
|
68
|
-
|
|
69
|
-
const safePad = edge === 'top' ? { paddingTop: insets.top } : { paddingBottom: insets.bottom };
|
|
70
|
-
return (
|
|
71
|
-
<View testID="userflow-banner-flow" style={[styles.flow, safePad, { backgroundColor }]}>
|
|
72
|
-
{bar}
|
|
73
|
-
</View>
|
|
74
|
-
);
|
|
88
|
+
return bar;
|
|
75
89
|
}
|
|
76
90
|
|
|
77
|
-
const edgeStyle =
|
|
91
|
+
const edgeStyle =
|
|
92
|
+
edge === 'top' ? { top: floats ? insets.top : 0 } : { bottom: floats ? insets.bottom : 0 };
|
|
78
93
|
|
|
79
94
|
return (
|
|
80
95
|
<View
|
|
81
96
|
pointerEvents="box-none"
|
|
82
97
|
style={[styles.pin, edgeStyle, bannerOverlayHostPadding(insets)]}
|
|
83
98
|
>
|
|
84
|
-
{
|
|
99
|
+
<View pointerEvents="auto" style={styles.pinInteractive}>
|
|
100
|
+
{bar}
|
|
101
|
+
</View>
|
|
85
102
|
</View>
|
|
86
103
|
);
|
|
87
104
|
}
|
|
88
105
|
|
|
89
|
-
function bannerBackground(session: BannerSessionFragment): string {
|
|
90
|
-
return resolveBannerBackgroundColor(session.version.theme);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
106
|
const styles = StyleSheet.create({
|
|
94
107
|
pin: {
|
|
95
108
|
position: 'absolute',
|
|
96
109
|
left: 0,
|
|
97
110
|
right: 0,
|
|
111
|
+
zIndex: 10,
|
|
112
|
+
elevation: 10,
|
|
98
113
|
},
|
|
99
114
|
flow: {
|
|
100
115
|
alignSelf: 'stretch',
|
|
101
116
|
},
|
|
117
|
+
pinInteractive: {
|
|
118
|
+
alignSelf: 'stretch',
|
|
119
|
+
},
|
|
102
120
|
});
|
|
@@ -2,10 +2,12 @@ import * as React from 'react';
|
|
|
2
2
|
import { StyleSheet, View, type GestureResponderEvent } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import { elementTapMonitor } from '../anchors/elementTapMonitor';
|
|
5
|
+
import type { AnyFiber } from '../anchors/fiber/fiberInternals';
|
|
5
6
|
import { touchBelongsToEvent, touchTargetFiber } from '../anchors/fiber/touchTargetFiber';
|
|
6
|
-
import {
|
|
7
|
+
import { collectGestureHandlerTags } from '../anchors/gestureHandlerHandoff';
|
|
8
|
+
import { targetPressMonitor, type TouchIdentifier } from '../anchors/targetPressMonitor';
|
|
7
9
|
|
|
8
|
-
import {
|
|
10
|
+
import { forEachChangedTouch } from './changedTouchPoints';
|
|
9
11
|
import { isolateSync } from './isolateCall';
|
|
10
12
|
|
|
11
13
|
export interface TargetPressBridgeProps {
|
|
@@ -25,6 +27,9 @@ export interface TargetPressBridgeProps {
|
|
|
25
27
|
* Preview-chrome double taps are observed by `DoubleTapBridge` around the
|
|
26
28
|
* whole provider tree — this bridge never sees overlay touches.
|
|
27
29
|
*
|
|
30
|
+
* A touch that gesture-handler cancels is not dropped. The start is kept and
|
|
31
|
+
* counts as a tap if that handler later ends from ACTIVE.
|
|
32
|
+
*
|
|
28
33
|
* Does not claim the gesture responder.
|
|
29
34
|
*/
|
|
30
35
|
export function TargetPressBridge({ children }: TargetPressBridgeProps): React.ReactElement {
|
|
@@ -57,15 +62,23 @@ export function TargetPressBridge({ children }: TargetPressBridgeProps): React.R
|
|
|
57
62
|
|
|
58
63
|
const onTouchCancel = React.useCallback((event: GestureResponderEvent) => {
|
|
59
64
|
isolateSync('target-press', () => {
|
|
60
|
-
const
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
|
|
65
|
+
const changed = event.nativeEvent.changedTouches;
|
|
66
|
+
if (!changed || changed.length === 0) {
|
|
67
|
+
const identifiers = inProgressIdentifiers();
|
|
68
|
+
if (identifiers.length === 0) {
|
|
69
|
+
targetPressMonitor.cancelTouch();
|
|
70
|
+
elementTapMonitor.cancelTouch();
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
// No per-finger target on this event; every finger shares its view.
|
|
74
|
+
const fallback = touchTargetFiber(event);
|
|
75
|
+
for (const identifier of identifiers) {
|
|
76
|
+
handOffCancelledTouch(event, identifier, fallback);
|
|
77
|
+
}
|
|
64
78
|
return;
|
|
65
79
|
}
|
|
66
|
-
for (const touch of
|
|
67
|
-
|
|
68
|
-
elementTapMonitor.cancelTouch(touch.identifier);
|
|
80
|
+
for (const touch of changed) {
|
|
81
|
+
handOffCancelledTouch(event, touch.identifier, null);
|
|
69
82
|
}
|
|
70
83
|
});
|
|
71
84
|
}, []);
|
|
@@ -84,6 +97,50 @@ export function TargetPressBridge({ children }: TargetPressBridgeProps): React.R
|
|
|
84
97
|
);
|
|
85
98
|
}
|
|
86
99
|
|
|
100
|
+
/**
|
|
101
|
+
* A finger gesture-handler cancelled. Keep it if the touched view belongs to a
|
|
102
|
+
* gesture-handler control. A scroll container, or a touch with no handler, is
|
|
103
|
+
* dropped the way a system cancel is.
|
|
104
|
+
* `fallbackFiber` is used when this event names no per-finger target.
|
|
105
|
+
*/
|
|
106
|
+
function handOffCancelledTouch(
|
|
107
|
+
event: GestureResponderEvent,
|
|
108
|
+
identifier: TouchIdentifier,
|
|
109
|
+
fallbackFiber: AnyFiber | null,
|
|
110
|
+
): void {
|
|
111
|
+
const elementHas = elementTapMonitor.hasTouch(identifier);
|
|
112
|
+
const tooltipHas = targetPressMonitor.hasTouch(identifier);
|
|
113
|
+
if (!elementHas && !tooltipHas) {
|
|
114
|
+
elementTapMonitor.cancelTouch(identifier);
|
|
115
|
+
targetPressMonitor.cancelTouch(identifier);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const stored = elementHas ? elementTapMonitor.startFiber(identifier) : null;
|
|
119
|
+
const fiber = stored ?? fallbackFiber ?? touchTargetFiber(event, identifier);
|
|
120
|
+
const tags = collectGestureHandlerTags(fiber);
|
|
121
|
+
if (tags.length === 0) {
|
|
122
|
+
elementTapMonitor.cancelTouch(identifier);
|
|
123
|
+
targetPressMonitor.cancelTouch(identifier);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (elementHas) elementTapMonitor.handOffTouch(identifier, tags);
|
|
127
|
+
if (tooltipHas) targetPressMonitor.handOffTouch(identifier, tags);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function inProgressIdentifiers(): TouchIdentifier[] {
|
|
131
|
+
const seen = new Set<TouchIdentifier>();
|
|
132
|
+
const identifiers: TouchIdentifier[] = [];
|
|
133
|
+
for (const identifier of [
|
|
134
|
+
...elementTapMonitor.inProgressIdentifiers(),
|
|
135
|
+
...targetPressMonitor.inProgressIdentifiers(),
|
|
136
|
+
]) {
|
|
137
|
+
if (seen.has(identifier)) continue;
|
|
138
|
+
seen.add(identifier);
|
|
139
|
+
identifiers.push(identifier);
|
|
140
|
+
}
|
|
141
|
+
return identifiers;
|
|
142
|
+
}
|
|
143
|
+
|
|
87
144
|
const styles = StyleSheet.create({
|
|
88
145
|
root: {
|
|
89
146
|
flex: 1,
|
|
@@ -8,6 +8,7 @@ import { PreviewModeBanner } from '../pairing/PreviewModeBanner';
|
|
|
8
8
|
import { getPairingController } from '../pairing/pairingRuntime';
|
|
9
9
|
import { usePairingState } from '../pairing/usePairingState';
|
|
10
10
|
import { usePreviewBarHold } from '../pairing/usePreviewBarHold';
|
|
11
|
+
import { stepTrapsHostAccessibility } from '../surfaces/hostAccessibilityTrap';
|
|
11
12
|
|
|
12
13
|
import { BannerHost } from './BannerHost';
|
|
13
14
|
import { FlowRenderer } from './FlowRenderer';
|
|
@@ -57,14 +58,7 @@ export function UserflowOverlay({
|
|
|
57
58
|
if (!session || !currentStep) {
|
|
58
59
|
return false;
|
|
59
60
|
}
|
|
60
|
-
|
|
61
|
-
if (appearance === 'HIDDEN') {
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
if (appearance !== 'TOOLTIP') {
|
|
65
|
-
return true;
|
|
66
|
-
}
|
|
67
|
-
return currentStep.tooltipTargetBlocked;
|
|
61
|
+
return stepTrapsHostAccessibility(currentStep);
|
|
68
62
|
}, [pickerActive, previewConfirming, session, currentStep]);
|
|
69
63
|
|
|
70
64
|
React.useLayoutEffect(() => {
|
|
@@ -105,13 +99,17 @@ export function UserflowOverlay({
|
|
|
105
99
|
* captureScreen would otherwise include the modal or tooltip.
|
|
106
100
|
* Remounting reads the same session back.
|
|
107
101
|
*/}
|
|
108
|
-
<BannerHost engine={bannerEngine} hidden={pickerActive} />
|
|
109
102
|
{pickerActive ? null : (
|
|
110
103
|
<FlowRenderer
|
|
111
104
|
engine={engine}
|
|
112
105
|
previewRestartGeneration={pairingState.previewRestartGeneration}
|
|
113
106
|
/>
|
|
114
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} />
|
|
115
113
|
<ElementPickerOverlay />
|
|
116
114
|
</>
|
|
117
115
|
);
|
|
@@ -15,15 +15,15 @@ import type { EdgeInsets } from '../surfaces/safeArea';
|
|
|
15
15
|
import { SurfaceLayoutInsetsProvider } from '../surfaces/surfaceLayoutInsets';
|
|
16
16
|
|
|
17
17
|
import { BannerHost } from './BannerHost';
|
|
18
|
+
import { BannerWebViewFlowSpacer } from './bannerFlowSpacer';
|
|
18
19
|
import { SdkErrorBoundary } from './SdkErrorBoundary';
|
|
19
20
|
import { TargetPressBridge } from './TargetPressBridge';
|
|
20
21
|
import { UserflowOverlay } from './UserflowOverlay';
|
|
21
22
|
import { getBannerSessionEngine } from './bannerEngine';
|
|
22
23
|
import { BannerEngineContext } from './bannerEngineContext';
|
|
23
|
-
import { bannerEdge } from './bannerPlacement';
|
|
24
24
|
import { getFlowSessionEngine } from './flowEngine';
|
|
25
|
+
import { PushBannerLayoutProvider, type PushBannerLayoutEdge } from './pushBannerLayoutContext';
|
|
25
26
|
import { isolateSync } from './isolateCall';
|
|
26
|
-
import { useBannerSession } from './useBannerSession';
|
|
27
27
|
import { getUserflowCore } from './userflowCore';
|
|
28
28
|
|
|
29
29
|
export interface UserflowContextValue {
|
|
@@ -122,8 +122,9 @@ export function UserflowProvider({
|
|
|
122
122
|
const onOverlayError = React.useCallback(() => {
|
|
123
123
|
setTrapHostAccessibility(false);
|
|
124
124
|
}, []);
|
|
125
|
-
const bannerSession = useBannerSession(bannerEngine);
|
|
126
125
|
const safeInsets = useUserflowSafeAreaInsets();
|
|
126
|
+
const [pushBannerLayoutEdge, setPushBannerLayoutEdge] =
|
|
127
|
+
React.useState<PushBannerLayoutEdge | null>(null);
|
|
127
128
|
const [pickerActive, setPickerActive] = React.useState(
|
|
128
129
|
() => elementPickerController.getState().active,
|
|
129
130
|
);
|
|
@@ -134,15 +135,12 @@ export function UserflowProvider({
|
|
|
134
135
|
});
|
|
135
136
|
}, []);
|
|
136
137
|
|
|
137
|
-
const banner = bannerSession?.version.banner ?? null;
|
|
138
|
-
const flowEdge =
|
|
139
|
-
banner && banner.overlay === false && !pickerActive ? bannerEdge(banner.embedMode) : null;
|
|
140
138
|
const hostInsets: EdgeInsets | null =
|
|
141
|
-
|
|
139
|
+
pushBannerLayoutEdge === 'top' || pushBannerLayoutEdge === 'bottom'
|
|
142
140
|
? {
|
|
143
141
|
...safeInsets,
|
|
144
|
-
top:
|
|
145
|
-
bottom:
|
|
142
|
+
top: pushBannerLayoutEdge === 'top' ? 0 : safeInsets.top,
|
|
143
|
+
bottom: pushBannerLayoutEdge === 'bottom' ? 0 : safeInsets.bottom,
|
|
146
144
|
}
|
|
147
145
|
: null;
|
|
148
146
|
|
|
@@ -163,31 +161,44 @@ export function UserflowProvider({
|
|
|
163
161
|
<BannerEngineContext.Provider value={bannerEngine}>
|
|
164
162
|
<UserflowContext.Provider value={contextValue}>
|
|
165
163
|
<SurfaceLayoutInsetsProvider>
|
|
166
|
-
<
|
|
167
|
-
<
|
|
168
|
-
<
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
/>
|
|
176
|
-
<View style={styles.overlay} pointerEvents="box-none">
|
|
177
|
-
<SdkErrorBoundary
|
|
178
|
-
scope="overlay"
|
|
179
|
-
resetKey={overlayResetKey}
|
|
180
|
-
onError={onOverlayError}
|
|
181
|
-
>
|
|
182
|
-
<UserflowOverlay
|
|
183
|
-
engine={engine}
|
|
184
|
-
bannerEngine={bannerEngine}
|
|
185
|
-
onTrapChange={onTrapChange}
|
|
164
|
+
<PushBannerLayoutProvider onActiveEdgeChange={setPushBannerLayoutEdge}>
|
|
165
|
+
<DoubleTapBridge>
|
|
166
|
+
<View style={styles.root} collapsable={false} testID="userflow-root">
|
|
167
|
+
<View style={styles.flowBannerTop}>
|
|
168
|
+
<BannerHost
|
|
169
|
+
engine={bannerEngine}
|
|
170
|
+
placement="flow"
|
|
171
|
+
edge="top"
|
|
172
|
+
hidden={pickerActive}
|
|
186
173
|
/>
|
|
187
|
-
|
|
174
|
+
<BannerWebViewFlowSpacer engine={bannerEngine} edge="top" />
|
|
175
|
+
</View>
|
|
176
|
+
<HostSafeArea insets={hostInsets}>{appContent}</HostSafeArea>
|
|
177
|
+
<View style={styles.flowBannerBottom}>
|
|
178
|
+
<BannerHost
|
|
179
|
+
engine={bannerEngine}
|
|
180
|
+
placement="flow"
|
|
181
|
+
edge="bottom"
|
|
182
|
+
hidden={pickerActive}
|
|
183
|
+
/>
|
|
184
|
+
<BannerWebViewFlowSpacer engine={bannerEngine} edge="bottom" />
|
|
185
|
+
</View>
|
|
186
|
+
<View style={styles.overlay} pointerEvents="box-none">
|
|
187
|
+
<SdkErrorBoundary
|
|
188
|
+
scope="overlay"
|
|
189
|
+
resetKey={overlayResetKey}
|
|
190
|
+
onError={onOverlayError}
|
|
191
|
+
>
|
|
192
|
+
<UserflowOverlay
|
|
193
|
+
engine={engine}
|
|
194
|
+
bannerEngine={bannerEngine}
|
|
195
|
+
onTrapChange={onTrapChange}
|
|
196
|
+
/>
|
|
197
|
+
</SdkErrorBoundary>
|
|
198
|
+
</View>
|
|
188
199
|
</View>
|
|
189
|
-
</
|
|
190
|
-
</
|
|
200
|
+
</DoubleTapBridge>
|
|
201
|
+
</PushBannerLayoutProvider>
|
|
191
202
|
</SurfaceLayoutInsetsProvider>
|
|
192
203
|
</UserflowContext.Provider>
|
|
193
204
|
</BannerEngineContext.Provider>
|
|
@@ -228,7 +239,20 @@ const styles = StyleSheet.create({
|
|
|
228
239
|
appContent: {
|
|
229
240
|
flex: 1,
|
|
230
241
|
},
|
|
242
|
+
flowBannerTop: {
|
|
243
|
+
zIndex: 1,
|
|
244
|
+
elevation: 1,
|
|
245
|
+
pointerEvents: 'box-none',
|
|
246
|
+
},
|
|
247
|
+
flowBannerBottom: {
|
|
248
|
+
zIndex: 1,
|
|
249
|
+
elevation: 1,
|
|
250
|
+
pointerEvents: 'box-none',
|
|
251
|
+
},
|
|
231
252
|
overlay: {
|
|
232
253
|
...ABSOLUTE_FILL,
|
|
254
|
+
// Above flow banner slots so WebView banners receive touches (spacers are layout-only).
|
|
255
|
+
zIndex: 2,
|
|
256
|
+
elevation: 2,
|
|
233
257
|
},
|
|
234
258
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BannerSessionEngine, type UserflowCore } from '@userflow-tech/core';
|
|
2
|
+
import type { EndFlowReasonInput } from '@userflow-tech/protocol';
|
|
2
3
|
|
|
3
4
|
import { evalJsController } from '../evalJs/evalJsController';
|
|
4
5
|
import { openFlowNavigateUrl } from '../navigation/openFlowNavigateUrl';
|
|
@@ -44,8 +45,15 @@ export function resetBannerSessionEngine(): void {
|
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
/** Drop the local banner without detaching (preview exit, user switch). */
|
|
47
|
-
export function clearBannerSessionEngineLocalSession(
|
|
48
|
-
|
|
48
|
+
export function clearBannerSessionEngineLocalSession(options?: {
|
|
49
|
+
rememberDraftForPreviewEnd?: boolean;
|
|
50
|
+
}): void {
|
|
51
|
+
bannerEngine?.clearLocalSession(options);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Best-effort end of a Builder preview banner draft (including after local clear). */
|
|
55
|
+
export async function endDraftBannerSession(): Promise<void> {
|
|
56
|
+
await bannerEngine?.endDraftBannerSession('USER_CLOSED' as EndFlowReasonInput);
|
|
49
57
|
}
|
|
50
58
|
|
|
51
59
|
/** Test helper: drop the singleton so the next get recreates it. */
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { BannerSessionEngine } from '@userflow-tech/core';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { View } from 'react-native';
|
|
4
|
+
|
|
5
|
+
import { bannerEdge } from './bannerPlacement';
|
|
6
|
+
import { useBannerSession } from './useBannerSession';
|
|
7
|
+
|
|
8
|
+
type SpacerEdge = 'top' | 'bottom';
|
|
9
|
+
|
|
10
|
+
const heights: Record<SpacerEdge, number> = { top: 0, bottom: 0 };
|
|
11
|
+
const listeners = new Set<() => void>();
|
|
12
|
+
|
|
13
|
+
function emit(): void {
|
|
14
|
+
for (const listener of listeners) {
|
|
15
|
+
listener();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** @internal */
|
|
20
|
+
export function setBannerFlowSpacerHeight(edge: SpacerEdge, height: number): void {
|
|
21
|
+
const next = Math.max(0, Math.ceil(height));
|
|
22
|
+
if (heights[edge] === next) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
heights[edge] = next;
|
|
26
|
+
emit();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function subscribe(listener: () => void): () => void {
|
|
30
|
+
listeners.add(listener);
|
|
31
|
+
return () => {
|
|
32
|
+
listeners.delete(listener);
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function getHeight(edge: SpacerEdge): number {
|
|
37
|
+
return heights[edge];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Reserves layout space when a custom-css WebView banner is painted in the
|
|
42
|
+
* overlay host but the builder marked it `overlay: false` (push layout).
|
|
43
|
+
*/
|
|
44
|
+
export function BannerWebViewFlowSpacer({
|
|
45
|
+
engine,
|
|
46
|
+
edge,
|
|
47
|
+
}: {
|
|
48
|
+
engine: BannerSessionEngine;
|
|
49
|
+
edge: SpacerEdge;
|
|
50
|
+
}): React.ReactElement | null {
|
|
51
|
+
const session = useBannerSession(engine);
|
|
52
|
+
const height = React.useSyncExternalStore(
|
|
53
|
+
subscribe,
|
|
54
|
+
() => getHeight(edge),
|
|
55
|
+
() => getHeight(edge),
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
if (!session?.version.banner || height <= 0) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const pinnedEdge = bannerEdge(session.version.banner.embedMode);
|
|
62
|
+
if (pinnedEdge !== edge) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Layout-only: the painted banner lives in the overlay host (lower z-index).
|
|
67
|
+
return (
|
|
68
|
+
<View pointerEvents="none" testID={`userflow-banner-flow-spacer-${edge}`} style={{ height }} />
|
|
69
|
+
);
|
|
70
|
+
}
|
|
@@ -31,6 +31,17 @@ export function getFlowSessionEngine(core: UserflowCore): FlowSessionEngine {
|
|
|
31
31
|
updateUser: (attributes) => core.updateUser(attributes),
|
|
32
32
|
updateGroup: (attributes, options) => core.updateGroup(attributes, options),
|
|
33
33
|
});
|
|
34
|
+
flowEngine.on((event) => {
|
|
35
|
+
if (event.type !== 'sessionChange' || event.session !== null) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// Drop a flow's eval page when the tour ends. A banner WebView reuses the
|
|
39
|
+
// same controller and must keep its page alive until the banner dismisses.
|
|
40
|
+
if (evalJsController.getSnapshot().bannerOwnsWebView) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
evalJsController.reset();
|
|
44
|
+
});
|
|
34
45
|
if (endDraftOnArrival) watchForRestoredDraft();
|
|
35
46
|
}
|
|
36
47
|
return flowEngine;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { UserflowCore } from '@userflow-tech/core';
|
|
2
|
+
import type { EndFlowReasonInput } from '@userflow-tech/protocol';
|
|
3
|
+
|
|
4
|
+
import { evalJsController } from '../evalJs/evalJsController';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
clearBannerSessionEngineLocalSession,
|
|
8
|
+
endDraftBannerSession,
|
|
9
|
+
getBannerSessionEngine,
|
|
10
|
+
} from './bannerEngine';
|
|
11
|
+
import {
|
|
12
|
+
cancelPendingDraftEnd,
|
|
13
|
+
clearFlowSessionEngineLocalSession,
|
|
14
|
+
endDraftFlowSession,
|
|
15
|
+
} from './flowEngine';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Drop local tour state and reset eval before a Builder `startFlowWithToken`.
|
|
19
|
+
*
|
|
20
|
+
* When a draft banner is still active, end it on the server first. The channel
|
|
21
|
+
* dedupes an unchanged `SetBannerSession`, so clearing the banner locally
|
|
22
|
+
* without ending the draft leaves nothing visible on a second preview of the
|
|
23
|
+
* same banner.
|
|
24
|
+
*/
|
|
25
|
+
export async function prepareForBuilderPreviewStart(core: UserflowCore): Promise<void> {
|
|
26
|
+
cancelPendingDraftEnd();
|
|
27
|
+
clearFlowSessionEngineLocalSession();
|
|
28
|
+
core.setFlowSessionId(null);
|
|
29
|
+
|
|
30
|
+
const bannerEngine = getBannerSessionEngine(core);
|
|
31
|
+
const hasDraftBanner =
|
|
32
|
+
bannerEngine.getBannerSession()?.draftMode === true ||
|
|
33
|
+
bannerEngine.getDeferredDraftBannerSessionId() !== null;
|
|
34
|
+
|
|
35
|
+
if (hasDraftBanner) {
|
|
36
|
+
await bannerEngine.endDraftBannerForPreview('USER_CLOSED' as EndFlowReasonInput);
|
|
37
|
+
} else {
|
|
38
|
+
clearBannerSessionEngineLocalSession();
|
|
39
|
+
core.setBannerSessionId(null);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
evalJsController.reset();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** End tour and banner Builder drafts on the server (preview exit). */
|
|
46
|
+
export async function endDraftPreviewSessions(): Promise<void> {
|
|
47
|
+
await endDraftFlowSession();
|
|
48
|
+
await endDraftBannerSession();
|
|
49
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { LayoutChangeEvent } from 'react-native';
|
|
3
|
+
|
|
4
|
+
export type PushBannerLayoutEdge = 'top' | 'bottom';
|
|
5
|
+
|
|
6
|
+
interface PushBannerLayoutContextValue {
|
|
7
|
+
/** Push-layout banner chrome mounted; host safe-area may follow this edge. */
|
|
8
|
+
register: (edge: PushBannerLayoutEdge, token: string) => void;
|
|
9
|
+
unregister: (token: string) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const PushBannerLayoutContext = React.createContext<PushBannerLayoutContextValue | null>(null);
|
|
13
|
+
|
|
14
|
+
function pickEdge(registrations: Map<string, PushBannerLayoutEdge>): PushBannerLayoutEdge | null {
|
|
15
|
+
let top = false;
|
|
16
|
+
let bottom = false;
|
|
17
|
+
for (const edge of registrations.values()) {
|
|
18
|
+
if (edge === 'top') {
|
|
19
|
+
top = true;
|
|
20
|
+
}
|
|
21
|
+
if (edge === 'bottom') {
|
|
22
|
+
bottom = true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (top) {
|
|
26
|
+
return 'top';
|
|
27
|
+
}
|
|
28
|
+
if (bottom) {
|
|
29
|
+
return 'bottom';
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function PushBannerLayoutProvider({
|
|
35
|
+
children,
|
|
36
|
+
onActiveEdgeChange,
|
|
37
|
+
}: {
|
|
38
|
+
children: React.ReactNode;
|
|
39
|
+
onActiveEdgeChange: (edge: PushBannerLayoutEdge | null) => void;
|
|
40
|
+
}): React.ReactElement {
|
|
41
|
+
const registrations = React.useRef(new Map<string, PushBannerLayoutEdge>());
|
|
42
|
+
const onActiveEdgeChangeRef = React.useRef(onActiveEdgeChange);
|
|
43
|
+
onActiveEdgeChangeRef.current = onActiveEdgeChange;
|
|
44
|
+
|
|
45
|
+
const sync = React.useCallback(() => {
|
|
46
|
+
onActiveEdgeChangeRef.current(pickEdge(registrations.current));
|
|
47
|
+
}, []);
|
|
48
|
+
|
|
49
|
+
const value = React.useMemo<PushBannerLayoutContextValue>(
|
|
50
|
+
() => ({
|
|
51
|
+
register: (edge, token) => {
|
|
52
|
+
registrations.current.set(token, edge);
|
|
53
|
+
sync();
|
|
54
|
+
},
|
|
55
|
+
unregister: (token) => {
|
|
56
|
+
if (registrations.current.delete(token)) {
|
|
57
|
+
sync();
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
}),
|
|
61
|
+
[sync],
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
React.useLayoutEffect(() => {
|
|
65
|
+
sync();
|
|
66
|
+
}, [sync]);
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<PushBannerLayoutContext.Provider value={value}>{children}</PushBannerLayoutContext.Provider>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** @internal */
|
|
74
|
+
export function usePushBannerLayoutRegistration(
|
|
75
|
+
edge: PushBannerLayoutEdge | null | undefined,
|
|
76
|
+
sessionId: string | undefined,
|
|
77
|
+
): void {
|
|
78
|
+
const ctx = React.useContext(PushBannerLayoutContext);
|
|
79
|
+
React.useLayoutEffect(() => {
|
|
80
|
+
if (!ctx || !edge || !sessionId) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const token = `${sessionId}:${edge}`;
|
|
84
|
+
ctx.register(edge, token);
|
|
85
|
+
return () => {
|
|
86
|
+
ctx.unregister(token);
|
|
87
|
+
};
|
|
88
|
+
}, [ctx, edge, sessionId]);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Clears the host top/bottom safe-area override only after push-layout chrome
|
|
93
|
+
* has laid out, so a session without visible chrome cannot leave a white strip.
|
|
94
|
+
*
|
|
95
|
+
* @internal
|
|
96
|
+
*/
|
|
97
|
+
export function usePushBannerHostInsetRegistration(
|
|
98
|
+
edge: PushBannerLayoutEdge | null | undefined,
|
|
99
|
+
sessionId: string,
|
|
100
|
+
enabled: boolean,
|
|
101
|
+
): (event: LayoutChangeEvent) => void {
|
|
102
|
+
const [laidOut, setLaidOut] = React.useState(false);
|
|
103
|
+
|
|
104
|
+
React.useEffect(() => {
|
|
105
|
+
setLaidOut(false);
|
|
106
|
+
}, [edge, enabled]);
|
|
107
|
+
|
|
108
|
+
usePushBannerLayoutRegistration(enabled && laidOut && edge ? edge : null, sessionId);
|
|
109
|
+
|
|
110
|
+
return React.useCallback(
|
|
111
|
+
(event: LayoutChangeEvent) => {
|
|
112
|
+
if (!enabled || !edge) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (event.nativeEvent.layout.height > 0) {
|
|
116
|
+
setLaidOut(true);
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
[edge, enabled],
|
|
120
|
+
);
|
|
121
|
+
}
|