@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
|
@@ -23,14 +23,18 @@ import { getEvalJsWebView, type EvalJsWebViewHandle } from '../../evalJs/getWebV
|
|
|
23
23
|
import { injectEvalPendingIntoWebView } from '../../evalJs/injectEvalPending';
|
|
24
24
|
import type { EvalJsContext } from '../../evalJs/types';
|
|
25
25
|
import { useEvalJsWebViewInjection } from '../../evalJs/useEvalJsWebViewInjection';
|
|
26
|
+
import { usePushBannerHostInsetRegistration } from '../../runtime/pushBannerLayoutContext';
|
|
27
|
+
import { setBannerFlowSpacerHeight } from '../../runtime/bannerFlowSpacer';
|
|
28
|
+
import { warnBannerOnce } from '../../runtime/bannerPlacement';
|
|
26
29
|
import { getUserflowCore } from '../../runtime/userflowCore';
|
|
27
30
|
import { getCurrentScreenLocation, subscribeScreenLocation } from '../../screenTracker';
|
|
28
31
|
import {
|
|
29
32
|
bannerFrameStyle,
|
|
30
|
-
|
|
33
|
+
bannerPushLayoutChrome,
|
|
31
34
|
resolveBannerBarBorderRadius,
|
|
32
35
|
} from '../bannerBarLayout';
|
|
33
36
|
import { bannerOverlayShadowStyle } from '../bannerBarTokens';
|
|
37
|
+
import { resolveBannerBackgroundColor } from '../resolveBannerTheme';
|
|
34
38
|
import { useUserflowSafeAreaInsets } from '../safeArea';
|
|
35
39
|
|
|
36
40
|
import { collectBannerAutoRunEvalCodes } from './bannerAutoRunEvalJs';
|
|
@@ -39,6 +43,8 @@ import { buildCustomBannerBodyHtml } from './buildCustomBannerHtml';
|
|
|
39
43
|
|
|
40
44
|
export interface BannerWebViewBarProps {
|
|
41
45
|
session: BannerSessionFragment;
|
|
46
|
+
pushLayoutEdge?: 'top' | 'bottom' | null;
|
|
47
|
+
overlaySafeEdge?: 'top' | 'bottom' | null;
|
|
42
48
|
onActions: (actions: FlowActionFragment[]) => void | Promise<void>;
|
|
43
49
|
onDismiss: (endReason: EndFlowReasonInput) => void;
|
|
44
50
|
}
|
|
@@ -68,14 +74,27 @@ function useEvalJsScreen(): { name?: string; path?: string } {
|
|
|
68
74
|
|
|
69
75
|
export function BannerWebViewBar({
|
|
70
76
|
session,
|
|
77
|
+
pushLayoutEdge = null,
|
|
78
|
+
overlaySafeEdge = null,
|
|
71
79
|
onActions,
|
|
72
80
|
onDismiss,
|
|
73
81
|
}: BannerWebViewBarProps): React.ReactElement | null {
|
|
74
82
|
const banner = session.version.banner;
|
|
83
|
+
const overlay = banner?.overlay !== false;
|
|
84
|
+
const hostInsetEdge = banner && !overlay && pushLayoutEdge ? pushLayoutEdge : null;
|
|
85
|
+
const pushLayoutRegistrationEdge =
|
|
86
|
+
hostInsetEdge ?? (!overlay && overlaySafeEdge ? overlaySafeEdge : null);
|
|
87
|
+
const safeAreaEdge = hostInsetEdge ?? overlaySafeEdge ?? null;
|
|
88
|
+
const onPushChromeLayout = usePushBannerHostInsetRegistration(
|
|
89
|
+
pushLayoutRegistrationEdge,
|
|
90
|
+
session.id,
|
|
91
|
+
pushLayoutRegistrationEdge != null,
|
|
92
|
+
);
|
|
75
93
|
const WebView = getEvalJsWebView();
|
|
76
94
|
const webRef = React.useRef<EvalJsWebViewHandle>(null);
|
|
77
95
|
const [pageReady, setPageReady] = React.useState(false);
|
|
78
96
|
const [contentHeight, setContentHeight] = React.useState(56);
|
|
97
|
+
const [webLayoutHeight, setWebLayoutHeight] = React.useState<number | null>(null);
|
|
79
98
|
const colorScheme = useColorScheme();
|
|
80
99
|
const viewport = useWindowDimensions();
|
|
81
100
|
const insets = useUserflowSafeAreaInsets();
|
|
@@ -104,18 +123,18 @@ export function BannerWebViewBar({
|
|
|
104
123
|
const serverEndpoint = getUserflowCore().getServerEndpoint() ?? DEFAULT_SERVER_ENDPOINT;
|
|
105
124
|
|
|
106
125
|
const skipAutoRunEval = shouldSkipBannerAutoRunEval(session.id);
|
|
107
|
-
const initialContext = React.useRef(context);
|
|
108
126
|
const html = React.useMemo(() => {
|
|
109
127
|
const body = buildCustomBannerBodyHtml(session, lookupAttribute, serverEndpoint, {
|
|
110
128
|
skipAutoRunEval,
|
|
111
129
|
});
|
|
112
|
-
return buildBootstrapHtml(
|
|
113
|
-
}, [lookupAttribute, serverEndpoint, session, skipAutoRunEval]);
|
|
130
|
+
return buildBootstrapHtml(context, body);
|
|
131
|
+
}, [context, lookupAttribute, serverEndpoint, session, skipAutoRunEval]);
|
|
114
132
|
|
|
115
|
-
const
|
|
133
|
+
const fadeIn = banner?.animate === true && hostInsetEdge == null;
|
|
134
|
+
const opacity = React.useRef(new Animated.Value(fadeIn ? 0 : 1)).current;
|
|
116
135
|
|
|
117
136
|
React.useEffect(() => {
|
|
118
|
-
if (!
|
|
137
|
+
if (!fadeIn) {
|
|
119
138
|
opacity.setValue(1);
|
|
120
139
|
return;
|
|
121
140
|
}
|
|
@@ -129,13 +148,39 @@ export function BannerWebViewBar({
|
|
|
129
148
|
return () => {
|
|
130
149
|
animation.stop();
|
|
131
150
|
};
|
|
132
|
-
}, [
|
|
151
|
+
}, [fadeIn, opacity, session.id]);
|
|
133
152
|
|
|
134
153
|
React.useEffect(() => {
|
|
135
154
|
setPageReady(false);
|
|
136
155
|
setContentHeight(56);
|
|
156
|
+
setWebLayoutHeight(null);
|
|
137
157
|
}, [session.id, html]);
|
|
138
158
|
|
|
159
|
+
const reserveFlowSpace = !overlay && overlaySafeEdge != null;
|
|
160
|
+
React.useEffect(() => {
|
|
161
|
+
if (!reserveFlowSpace || !overlaySafeEdge) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
return () => {
|
|
165
|
+
setBannerFlowSpacerHeight(overlaySafeEdge, 0);
|
|
166
|
+
};
|
|
167
|
+
}, [overlaySafeEdge, reserveFlowSpace, session.id]);
|
|
168
|
+
|
|
169
|
+
React.useEffect(() => {
|
|
170
|
+
if (pushLayoutRegistrationEdge == null) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const timer = setTimeout(() => {
|
|
174
|
+
if (webLayoutHeight == null) {
|
|
175
|
+
warnBannerOnce(
|
|
176
|
+
`push-webview-layout:${session.id}`,
|
|
177
|
+
'Userflow: push-layout WebView banner did not report a layout height; check custom CSS / WebView logs',
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
}, 4000);
|
|
181
|
+
return () => clearTimeout(timer);
|
|
182
|
+
}, [pushLayoutRegistrationEdge, session.id, webLayoutHeight]);
|
|
183
|
+
|
|
139
184
|
React.useEffect(() => {
|
|
140
185
|
if (!pageReady || skipAutoRunEval || !banner) {
|
|
141
186
|
return;
|
|
@@ -177,17 +222,23 @@ export function BannerWebViewBar({
|
|
|
177
222
|
const maxHeight = Math.floor(viewport.height * 0.92);
|
|
178
223
|
const next = Math.min(Math.ceil(height), maxHeight);
|
|
179
224
|
setContentHeight((prev) => (Math.abs(next - prev) <= 1 ? prev : next));
|
|
225
|
+
setWebLayoutHeight(next);
|
|
180
226
|
}
|
|
181
227
|
return;
|
|
182
228
|
}
|
|
183
229
|
if (record.__userflow === 1 && record.type === 'bannerButton') {
|
|
184
230
|
const buttonId = record.buttonId;
|
|
185
231
|
if (typeof buttonId === 'string' && banner) {
|
|
186
|
-
const button =
|
|
232
|
+
const button =
|
|
233
|
+
banner.buttons.find((entry) => entry.id === buttonId) ??
|
|
234
|
+
banner.buttons.find((entry) => entry.cvid === buttonId);
|
|
187
235
|
if (button) {
|
|
188
236
|
void Promise.resolve(onActions(button.actions)).then(() => {
|
|
189
237
|
injectEvalPendingIntoWebView(webRef.current);
|
|
190
238
|
});
|
|
239
|
+
} else if (__DEV__) {
|
|
240
|
+
// eslint-disable-next-line no-console -- intentional development diagnostic
|
|
241
|
+
console.warn('[Userflow] banner button not found for id', buttonId);
|
|
191
242
|
}
|
|
192
243
|
}
|
|
193
244
|
return;
|
|
@@ -241,72 +292,113 @@ export function BannerWebViewBar({
|
|
|
241
292
|
return;
|
|
242
293
|
}
|
|
243
294
|
},
|
|
244
|
-
[
|
|
295
|
+
[
|
|
296
|
+
banner,
|
|
297
|
+
insets.bottom,
|
|
298
|
+
insets.top,
|
|
299
|
+
onActions,
|
|
300
|
+
onDismiss,
|
|
301
|
+
overlaySafeEdge,
|
|
302
|
+
reserveFlowSpace,
|
|
303
|
+
viewport.height,
|
|
304
|
+
],
|
|
245
305
|
);
|
|
246
306
|
|
|
247
307
|
if (!banner || !WebView) {
|
|
248
308
|
return null;
|
|
249
309
|
}
|
|
250
310
|
|
|
251
|
-
const overlay = banner.overlay !== false;
|
|
252
311
|
const frameStyle = bannerFrameStyle(banner);
|
|
253
|
-
const innerStyle = bannerInnerStyle(banner);
|
|
254
312
|
const overlayEdge = banner.embedMode === BannerEmbedMode.BODY_LAST ? 'bottom' : 'top';
|
|
255
313
|
const barRadius = resolveBannerBarBorderRadius(banner);
|
|
314
|
+
const backgroundColor = resolveBannerBackgroundColor(session.version.theme);
|
|
256
315
|
const webStyle: ViewStyle = {
|
|
257
316
|
width: '100%',
|
|
258
317
|
height: contentHeight,
|
|
259
|
-
backgroundColor
|
|
318
|
+
backgroundColor,
|
|
260
319
|
};
|
|
261
320
|
const debugging = typeof __DEV__ !== 'undefined' && __DEV__ ? true : undefined;
|
|
321
|
+
const insetChrome = safeAreaEdge
|
|
322
|
+
? bannerPushLayoutChrome(safeAreaEdge, insets, backgroundColor)
|
|
323
|
+
: null;
|
|
324
|
+
const insetChromeOutsideFade = insetChrome != null && fadeIn;
|
|
325
|
+
|
|
326
|
+
const webViewBar = (
|
|
327
|
+
<View
|
|
328
|
+
testID="userflow-banner-webview"
|
|
329
|
+
pointerEvents="auto"
|
|
330
|
+
style={[{ borderRadius: barRadius ?? 0, overflow: 'hidden' as const }]}
|
|
331
|
+
>
|
|
332
|
+
<WebView
|
|
333
|
+
key={session.id}
|
|
334
|
+
ref={webRef}
|
|
335
|
+
source={{ html, baseUrl: EVAL_JS_BASE_URL }}
|
|
336
|
+
style={webStyle}
|
|
337
|
+
javaScriptEnabled
|
|
338
|
+
domStorageEnabled
|
|
339
|
+
scrollEnabled={false}
|
|
340
|
+
bounces={false}
|
|
341
|
+
showsHorizontalScrollIndicator={false}
|
|
342
|
+
showsVerticalScrollIndicator={false}
|
|
343
|
+
originWhitelist={['*']}
|
|
344
|
+
setSupportMultipleWindows={false}
|
|
345
|
+
androidLayerType="hardware"
|
|
346
|
+
{...(debugging !== undefined ? { webviewDebuggingEnabled: debugging } : {})}
|
|
347
|
+
onMessage={onMessage}
|
|
348
|
+
onLoadEnd={() => {
|
|
349
|
+
setPageReady(true);
|
|
350
|
+
webRef.current?.injectJavaScript(
|
|
351
|
+
'window.__userflowBannerLayout&&window.__userflowBannerLayout();true;',
|
|
352
|
+
);
|
|
353
|
+
}}
|
|
354
|
+
onShouldStartLoadWithRequest={(request) => {
|
|
355
|
+
if (isBootstrapUrl(request.url)) {
|
|
356
|
+
return true;
|
|
357
|
+
}
|
|
358
|
+
openExternal(request.url);
|
|
359
|
+
return false;
|
|
360
|
+
}}
|
|
361
|
+
onOpenWindow={(event) => {
|
|
362
|
+
const url = event.nativeEvent.targetUrl;
|
|
363
|
+
if (url) {
|
|
364
|
+
openExternal(url);
|
|
365
|
+
}
|
|
366
|
+
}}
|
|
367
|
+
/>
|
|
368
|
+
</View>
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
const animatedBar = (
|
|
372
|
+
<Animated.View
|
|
373
|
+
style={[
|
|
374
|
+
{ opacity },
|
|
375
|
+
overlay ? bannerOverlayShadowStyle(overlayEdge) : null,
|
|
376
|
+
insetChromeOutsideFade ? null : insetChrome,
|
|
377
|
+
]}
|
|
378
|
+
>
|
|
379
|
+
{webViewBar}
|
|
380
|
+
</Animated.View>
|
|
381
|
+
);
|
|
262
382
|
|
|
263
383
|
return (
|
|
264
|
-
<View
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
ref={webRef}
|
|
275
|
-
source={{ html, baseUrl: EVAL_JS_BASE_URL }}
|
|
276
|
-
style={webStyle}
|
|
277
|
-
javaScriptEnabled
|
|
278
|
-
domStorageEnabled
|
|
279
|
-
scrollEnabled={false}
|
|
280
|
-
bounces={false}
|
|
281
|
-
showsHorizontalScrollIndicator={false}
|
|
282
|
-
showsVerticalScrollIndicator={false}
|
|
283
|
-
originWhitelist={['*']}
|
|
284
|
-
setSupportMultipleWindows={false}
|
|
285
|
-
androidLayerType="hardware"
|
|
286
|
-
{...(debugging !== undefined ? { webviewDebuggingEnabled: debugging } : {})}
|
|
287
|
-
onMessage={onMessage}
|
|
288
|
-
onLoadEnd={() => {
|
|
289
|
-
setPageReady(true);
|
|
290
|
-
webRef.current?.injectJavaScript(
|
|
291
|
-
'window.__userflowBannerLayout&&window.__userflowBannerLayout();true;',
|
|
292
|
-
);
|
|
293
|
-
}}
|
|
294
|
-
onShouldStartLoadWithRequest={(request) => {
|
|
295
|
-
if (isBootstrapUrl(request.url)) {
|
|
296
|
-
return true;
|
|
384
|
+
<View
|
|
385
|
+
testID="userflow-banner-frame"
|
|
386
|
+
style={frameStyle}
|
|
387
|
+
onLayout={
|
|
388
|
+
reserveFlowSpace && overlaySafeEdge
|
|
389
|
+
? (event) => {
|
|
390
|
+
onPushChromeLayout(event);
|
|
391
|
+
const h = event.nativeEvent.layout.height;
|
|
392
|
+
if (h > 0) {
|
|
393
|
+
setBannerFlowSpacerHeight(overlaySafeEdge, h);
|
|
297
394
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
}
|
|
306
|
-
}}
|
|
307
|
-
/>
|
|
308
|
-
</View>
|
|
309
|
-
</Animated.View>
|
|
395
|
+
}
|
|
396
|
+
: pushLayoutRegistrationEdge
|
|
397
|
+
? onPushChromeLayout
|
|
398
|
+
: undefined
|
|
399
|
+
}
|
|
400
|
+
>
|
|
401
|
+
{insetChromeOutsideFade ? <View style={insetChrome}>{animatedBar}</View> : animatedBar}
|
|
310
402
|
</View>
|
|
311
403
|
);
|
|
312
404
|
}
|
|
@@ -7,6 +7,8 @@ import type { EvalJsContext } from '../../evalJs/types';
|
|
|
7
7
|
|
|
8
8
|
import { collectBannerAutoRunEvalCodes } from './bannerAutoRunEvalJs';
|
|
9
9
|
import { bannerThemeStyleAttribute } from './bannerThemeStyles';
|
|
10
|
+
import { resolveBannerInnerMaxWidth } from '../bannerBarLayout';
|
|
11
|
+
|
|
10
12
|
import { BANNER_WEB_FRAME_CSS } from './bannerWebFrameCss';
|
|
11
13
|
import { buttonClassName } from './buttonClassName';
|
|
12
14
|
import { resolveCustomStylesheetUrl } from './resolveCdnHost';
|
|
@@ -58,30 +60,71 @@ function layoutMeasureScript(): string {
|
|
|
58
60
|
`;
|
|
59
61
|
}
|
|
60
62
|
|
|
61
|
-
function bannerInteractionScript(): string {
|
|
63
|
+
function bannerInteractionScript(buttonsJson: string): string {
|
|
62
64
|
return `
|
|
63
65
|
(function(){
|
|
66
|
+
var __userflowBannerButtons=${buttonsJson};
|
|
64
67
|
function post(msg){
|
|
65
68
|
if(window.ReactNativeWebView&&window.ReactNativeWebView.postMessage){
|
|
66
69
|
window.ReactNativeWebView.postMessage(JSON.stringify(Object.assign({__userflow:1},msg)));
|
|
67
70
|
}
|
|
68
71
|
}
|
|
69
|
-
|
|
72
|
+
function resolveButtonId(el){
|
|
73
|
+
if(!el||!el.closest)return null;
|
|
74
|
+
var tagged=el.closest('[data-userflow-banner-button]');
|
|
75
|
+
if(tagged){
|
|
76
|
+
return tagged.getAttribute('data-userflow-banner-button');
|
|
77
|
+
}
|
|
78
|
+
function hasClass(el,token){
|
|
79
|
+
if(!token)return false;
|
|
80
|
+
var cls=el.className||'';
|
|
81
|
+
var parts=cls.split(/\\s+/);
|
|
82
|
+
for(var p=0;p<parts.length;p++){
|
|
83
|
+
if(parts[p]===token)return true;
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
function appearanceClass(appearance){
|
|
88
|
+
if(!appearance)return '';
|
|
89
|
+
var value=appearance;
|
|
90
|
+
var known=value==='primary'||value==='PRIMARY'||value==='default'||value==='DEFAULT'||value==='banner-primary'||value==='banner-secondary';
|
|
91
|
+
return known?'userflowjs-bubble-button--'+value.toLowerCase():value;
|
|
92
|
+
}
|
|
93
|
+
var bubble=el.closest('.userflowjs-bubble-button,button.userflowjs-bubble-button');
|
|
94
|
+
if(bubble){
|
|
95
|
+
var id=bubble.getAttribute('data-userflow-banner-button');
|
|
96
|
+
if(id)return id;
|
|
97
|
+
for(var i=0;i<__userflowBannerButtons.length;i++){
|
|
98
|
+
var meta=__userflowBannerButtons[i];
|
|
99
|
+
if(meta.appearance&&hasClass(bubble,appearanceClass(meta.appearance)))return meta.id;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
var custom=el.closest('[class*="userflow-custom-button"]');
|
|
103
|
+
if(custom){
|
|
104
|
+
for(var j=0;j<__userflowBannerButtons.length;j++){
|
|
105
|
+
var entry=__userflowBannerButtons[j];
|
|
106
|
+
if(entry.appearance&&hasClass(custom,appearanceClass(entry.appearance)))return entry.id;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
function onActivate(ev){
|
|
70
112
|
var t=ev.target;
|
|
71
113
|
if(!t||!t.closest)return;
|
|
72
|
-
var btn=t.closest('[data-userflow-banner-button]');
|
|
73
|
-
if(btn){
|
|
74
|
-
ev.preventDefault();
|
|
75
|
-
post({type:'bannerButton',buttonId:btn.getAttribute('data-userflow-banner-button')});
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
114
|
var close=t.closest('[data-userflow-banner-dismiss]');
|
|
79
115
|
if(close){
|
|
80
116
|
ev.preventDefault();
|
|
81
117
|
window.__userflowBannerEvalDismissed=true;
|
|
82
118
|
post({type:'bannerDismiss'});
|
|
119
|
+
return;
|
|
83
120
|
}
|
|
84
|
-
|
|
121
|
+
var buttonId=resolveButtonId(t);
|
|
122
|
+
if(buttonId){
|
|
123
|
+
ev.preventDefault();
|
|
124
|
+
post({type:'bannerButton',buttonId:buttonId});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
document.addEventListener('click',onActivate,true);
|
|
85
128
|
})();
|
|
86
129
|
`;
|
|
87
130
|
}
|
|
@@ -129,8 +172,9 @@ export function buildCustomBannerBodyHtml(
|
|
|
129
172
|
const layoutClass = contentLayoutClass(banner.contentLayout);
|
|
130
173
|
const themeStyle = bannerThemeStyleAttribute(theme);
|
|
131
174
|
const customCssUrl = resolveCustomStylesheetUrl(serverEndpoint, theme);
|
|
175
|
+
const innerMaxWidth = resolveBannerInnerMaxWidth(banner);
|
|
132
176
|
const maxInner =
|
|
133
|
-
|
|
177
|
+
innerMaxWidth != null && innerMaxWidth > 0 ? ` style="max-width:${innerMaxWidth}px"` : '';
|
|
134
178
|
const contentHtml = richContentDocToHtml(banner.content, lookupAttribute);
|
|
135
179
|
const buttonsHtml = banner.buttons
|
|
136
180
|
.map((button) => {
|
|
@@ -143,6 +187,14 @@ export function buildCustomBannerBodyHtml(
|
|
|
143
187
|
? '<div class="userflowjs-banner-start-spacer"></div>'
|
|
144
188
|
: '<button type="button" class="userflowjs-banner-close userflowjs-button-reset" data-userflow-banner-dismiss="1" aria-label="Dismiss">×</button>';
|
|
145
189
|
|
|
190
|
+
const buttonMetaJson = JSON.stringify(
|
|
191
|
+
banner.buttons.map((button) => ({
|
|
192
|
+
id: button.id,
|
|
193
|
+
cvid: button.cvid,
|
|
194
|
+
appearance: button.appearance ?? '',
|
|
195
|
+
})),
|
|
196
|
+
).replace(/</g, '\\u003c');
|
|
197
|
+
|
|
146
198
|
const customLink = customCssUrl
|
|
147
199
|
? `<link rel="stylesheet" href="${escapeAttr(customCssUrl)}" />`
|
|
148
200
|
: '';
|
|
@@ -158,7 +210,7 @@ ${customLink}
|
|
|
158
210
|
</div>
|
|
159
211
|
${closeHtml}
|
|
160
212
|
</div>
|
|
161
|
-
<script>${layoutMeasureScript()}${bannerInteractionScript()}${options?.skipAutoRunEval ? '' : bannerAutoRunEvalScript(banner, lookupAttribute)}</script>
|
|
213
|
+
<script>${layoutMeasureScript()}${bannerInteractionScript(buttonMetaJson)}${options?.skipAutoRunEval ? '' : bannerAutoRunEvalScript(banner, lookupAttribute)}</script>
|
|
162
214
|
`;
|
|
163
215
|
}
|
|
164
216
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { FlowStepFragment } from '@userflow-tech/protocol';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Whether a step hides host app content from the accessibility tree.
|
|
5
|
+
*
|
|
6
|
+
* Modals always do. A tooltip does only when `tooltipTargetBlocked` seals its
|
|
7
|
+
* target too — otherwise the target is the control the step asks the user to
|
|
8
|
+
* press, so a screen reader has to be able to reach it.
|
|
9
|
+
*
|
|
10
|
+
* `UserflowOverlay` traps the host with this, and tooltip cards gate
|
|
11
|
+
* `accessibilityViewIsModal` on it: on iOS that flag alone drops the host app,
|
|
12
|
+
* target included, out of VoiceOver's reach.
|
|
13
|
+
*/
|
|
14
|
+
export function stepTrapsHostAccessibility(
|
|
15
|
+
step: Pick<FlowStepFragment, 'appearance' | 'tooltipTargetBlocked'>,
|
|
16
|
+
): boolean {
|
|
17
|
+
const appearance = String(step.appearance).toUpperCase();
|
|
18
|
+
if (appearance === 'HIDDEN') {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
if (appearance !== 'TOOLTIP') {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
return step.tooltipTargetBlocked;
|
|
25
|
+
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { ThemeFragment } from '@userflow-tech/protocol';
|
|
2
2
|
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Last-resort banner chrome when neither banner nor brand tokens are set on the
|
|
5
|
+
* wire (web `applyThemeDefaults` falls back to brand first).
|
|
6
|
+
*/
|
|
4
7
|
export const DEFAULT_BANNER_BACKGROUND_COLOR = '#0A1A24';
|
|
5
8
|
export const DEFAULT_BANNER_FOREGROUND_COLOR = '#FFFFFF';
|
|
6
9
|
|
|
@@ -10,9 +13,17 @@ function readThemeColor(theme: ThemeFragment, key: string): string | undefined {
|
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
export function resolveBannerBackgroundColor(theme: ThemeFragment): string {
|
|
13
|
-
return
|
|
16
|
+
return (
|
|
17
|
+
readThemeColor(theme, 'bannerBackgroundColor') ??
|
|
18
|
+
readThemeColor(theme, 'brandBackgroundColor') ??
|
|
19
|
+
DEFAULT_BANNER_BACKGROUND_COLOR
|
|
20
|
+
);
|
|
14
21
|
}
|
|
15
22
|
|
|
16
23
|
export function resolveBannerForegroundColor(theme: ThemeFragment): string {
|
|
17
|
-
return
|
|
24
|
+
return (
|
|
25
|
+
readThemeColor(theme, 'bannerForegroundColor') ??
|
|
26
|
+
readThemeColor(theme, 'brandForegroundColor') ??
|
|
27
|
+
DEFAULT_BANNER_FOREGROUND_COLOR
|
|
28
|
+
);
|
|
18
29
|
}
|
|
@@ -28,6 +28,12 @@ export interface TooltipBubbleProps {
|
|
|
28
28
|
* target. Defaults to true so isolated chrome tests keep the diamond.
|
|
29
29
|
*/
|
|
30
30
|
showNotch?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* iOS: confine VoiceOver to this card. VoiceOver then skips the host app,
|
|
33
|
+
* including the target, so set it only while the host is hidden from
|
|
34
|
+
* accessibility anyway. Defaults to false.
|
|
35
|
+
*/
|
|
36
|
+
accessibilityViewIsModal?: boolean;
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
/**
|
|
@@ -56,6 +62,7 @@ export function TooltipBubble({
|
|
|
56
62
|
children,
|
|
57
63
|
maxHeight,
|
|
58
64
|
showNotch: showNotchProp = true,
|
|
65
|
+
accessibilityViewIsModal = false,
|
|
59
66
|
}: TooltipBubbleProps): React.ReactElement {
|
|
60
67
|
const showNotch = showNotchProp && chrome.notchSize > 0;
|
|
61
68
|
const bordered = chrome.borderWidth > 0;
|
|
@@ -104,7 +111,7 @@ export function TooltipBubble({
|
|
|
104
111
|
return (
|
|
105
112
|
<CardFade
|
|
106
113
|
testID="userflow-tooltip-card"
|
|
107
|
-
accessibilityViewIsModal
|
|
114
|
+
accessibilityViewIsModal={accessibilityViewIsModal}
|
|
108
115
|
pointerEvents="auto"
|
|
109
116
|
onLayout={onLayout}
|
|
110
117
|
style={[styles.shell, style]}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* When TooltipSurface looks for its target.
|
|
3
|
+
*
|
|
4
|
+
* - Anchored: a steady poll, so a covered or remounted host is noticed quickly.
|
|
5
|
+
* Each search is a cache hit for the resolved host.
|
|
6
|
+
* - Missing: exponential backoff. A miss walks the tree and scores registered
|
|
7
|
+
* hosts, so a target on another screen must not cost a full search every
|
|
8
|
+
* second for as long as the flow stays open.
|
|
9
|
+
* - Registry churn (list rows mounting while the user scrolls) pulls the next
|
|
10
|
+
* missing search forward, never closer than {@link MISSING_TRIGGER_GAP_MS}
|
|
11
|
+
* to the previous one.
|
|
12
|
+
* - A screen change or a return to the foreground starts the backoff over.
|
|
13
|
+
* - Nothing runs while paused (app not active).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** Poll while the target is anchored. */
|
|
17
|
+
export const ANCHORED_POLL_MS = 250;
|
|
18
|
+
/** First retry after a miss; doubles per consecutive miss. */
|
|
19
|
+
export const MISSING_BACKOFF_BASE_MS = 250;
|
|
20
|
+
/** Ceiling for the missing-target backoff. */
|
|
21
|
+
export const MISSING_BACKOFF_MAX_MS = 4000;
|
|
22
|
+
/** Closest a registry change can pull a missing search to the previous one. */
|
|
23
|
+
export const MISSING_TRIGGER_GAP_MS = 500;
|
|
24
|
+
|
|
25
|
+
export type TargetSearchMode = 'anchored' | 'missing';
|
|
26
|
+
|
|
27
|
+
export interface TargetSearchClock {
|
|
28
|
+
now(): number;
|
|
29
|
+
setTimeout(handler: () => void, ms: number): ReturnType<typeof setTimeout>;
|
|
30
|
+
clearTimeout(handle: ReturnType<typeof setTimeout>): void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const defaultClock: TargetSearchClock = {
|
|
34
|
+
now: () => Date.now(),
|
|
35
|
+
setTimeout: (handler, ms) => setTimeout(handler, ms),
|
|
36
|
+
clearTimeout: (handle) => clearTimeout(handle),
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/** Delay before the next search after `misses` consecutive missing searches. */
|
|
40
|
+
export function missingBackoffDelay(misses: number): number {
|
|
41
|
+
const exponent = Math.max(0, misses - 1);
|
|
42
|
+
return Math.min(MISSING_BACKOFF_MAX_MS, MISSING_BACKOFF_BASE_MS * 2 ** exponent);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class TargetSearchSchedule {
|
|
46
|
+
private mode: TargetSearchMode = 'missing';
|
|
47
|
+
/** Searches run since the target was last anchored (or the backoff restarted). */
|
|
48
|
+
private misses = 0;
|
|
49
|
+
private lastRunAt = Number.NEGATIVE_INFINITY;
|
|
50
|
+
private handle: ReturnType<typeof setTimeout> | null = null;
|
|
51
|
+
private dueAt = Number.POSITIVE_INFINITY;
|
|
52
|
+
private paused = false;
|
|
53
|
+
private disposed = false;
|
|
54
|
+
|
|
55
|
+
constructor(
|
|
56
|
+
private readonly search: () => void,
|
|
57
|
+
private readonly clock: TargetSearchClock = defaultClock,
|
|
58
|
+
) {}
|
|
59
|
+
|
|
60
|
+
/** Search now and schedule the next one. No-op while paused. */
|
|
61
|
+
runNow(): void {
|
|
62
|
+
if (this.disposed || this.paused) return;
|
|
63
|
+
this.cancel();
|
|
64
|
+
this.lastRunAt = this.clock.now();
|
|
65
|
+
if (this.mode === 'missing') this.misses += 1;
|
|
66
|
+
try {
|
|
67
|
+
this.search();
|
|
68
|
+
} finally {
|
|
69
|
+
if (!this.disposed && !this.paused && this.handle == null) {
|
|
70
|
+
this.scheduleIn(this.nextDelay());
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** The target was found or lost. Starts the matching cadence from now. */
|
|
76
|
+
setMode(mode: TargetSearchMode): void {
|
|
77
|
+
if (this.disposed || mode === this.mode) return;
|
|
78
|
+
this.mode = mode;
|
|
79
|
+
this.misses = 0;
|
|
80
|
+
if (this.paused) return;
|
|
81
|
+
this.scheduleIn(mode === 'anchored' ? ANCHORED_POLL_MS : MISSING_BACKOFF_BASE_MS);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Something the target may depend on changed (a registry mount / unmount). */
|
|
85
|
+
trigger(): void {
|
|
86
|
+
if (this.disposed || this.paused || this.mode !== 'missing') return;
|
|
87
|
+
const now = this.clock.now();
|
|
88
|
+
const dueAt = Math.max(now, this.lastRunAt + MISSING_TRIGGER_GAP_MS);
|
|
89
|
+
if (dueAt >= this.dueAt) return;
|
|
90
|
+
this.scheduleIn(dueAt - now);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Restart the backoff and search now (screen change, foreground). */
|
|
94
|
+
rearm(): void {
|
|
95
|
+
if (this.disposed) return;
|
|
96
|
+
this.misses = 0;
|
|
97
|
+
this.runNow();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Stop searching until {@link resume}. */
|
|
101
|
+
pause(): void {
|
|
102
|
+
if (this.disposed || this.paused) return;
|
|
103
|
+
this.paused = true;
|
|
104
|
+
this.cancel();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Leave the paused state and search right away. */
|
|
108
|
+
resume(): void {
|
|
109
|
+
if (this.disposed || !this.paused) return;
|
|
110
|
+
this.paused = false;
|
|
111
|
+
this.rearm();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
dispose(): void {
|
|
115
|
+
this.cancel();
|
|
116
|
+
this.disposed = true;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private nextDelay(): number {
|
|
120
|
+
return this.mode === 'anchored' ? ANCHORED_POLL_MS : missingBackoffDelay(this.misses);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private scheduleIn(ms: number): void {
|
|
124
|
+
this.cancel();
|
|
125
|
+
this.dueAt = this.clock.now() + ms;
|
|
126
|
+
this.handle = this.clock.setTimeout(() => {
|
|
127
|
+
this.handle = null;
|
|
128
|
+
this.dueAt = Number.POSITIVE_INFINITY;
|
|
129
|
+
this.runNow();
|
|
130
|
+
}, ms);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private cancel(): void {
|
|
134
|
+
if (this.handle != null) {
|
|
135
|
+
this.clock.clearTimeout(this.handle);
|
|
136
|
+
this.handle = null;
|
|
137
|
+
}
|
|
138
|
+
this.dueAt = Number.POSITIVE_INFINITY;
|
|
139
|
+
}
|
|
140
|
+
}
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Generated by scripts/write-version.mjs — do not edit. */
|
|
2
|
-
export const SDK_VERSION = '0.
|
|
2
|
+
export const SDK_VERSION = '0.5.0';
|