@userflow-tech/react-native 0.4.5 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -2
- package/docs/anchoring.md +6 -1
- package/docs/troubleshooting.md +26 -0
- 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/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/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/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/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/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,7 +1,11 @@
|
|
|
1
1
|
import type { SemanticRole, SemanticSegment, SiblingDescriptor } from '@userflow-tech/protocol';
|
|
2
2
|
import type { MutableRefObject, RefObject } from 'react';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
createCurrentFiberResolver,
|
|
6
|
+
getLiveHostProps,
|
|
7
|
+
type AnyFiber,
|
|
8
|
+
} from './fiber/fiberInternals';
|
|
5
9
|
import {
|
|
6
10
|
createLazyHostFiberIndex,
|
|
7
11
|
lookupHostFiber,
|
|
@@ -134,10 +138,20 @@ function contentSignature(inst: AutoAnchorInstance): string | undefined {
|
|
|
134
138
|
}
|
|
135
139
|
|
|
136
140
|
interface LiveContentCache {
|
|
141
|
+
/** The fiber of the pair that was committed when read. */
|
|
137
142
|
fiber: AnyFiber;
|
|
138
|
-
/**
|
|
143
|
+
/** That fiber's props object. */
|
|
139
144
|
props: Record<string, unknown> | undefined;
|
|
140
|
-
|
|
145
|
+
/** Undefined when the host shows no readable text (the hint stays). */
|
|
146
|
+
childText: string | undefined;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Twin evidence for one registry group, computed once per settle. */
|
|
150
|
+
interface TwinGroup {
|
|
151
|
+
/** More than one member and none carries a manual id. */
|
|
152
|
+
unlabelled: boolean;
|
|
153
|
+
/** How many members show each content signature. */
|
|
154
|
+
signatures: Map<string, number>;
|
|
141
155
|
}
|
|
142
156
|
|
|
143
157
|
export class AutoAnchorRegistry {
|
|
@@ -148,6 +162,22 @@ export class AutoAnchorRegistry {
|
|
|
148
162
|
private readonly liveContent = new Map<string, LiveContentCache>();
|
|
149
163
|
private readonly listeners = new Set<AutoAnchorListener>();
|
|
150
164
|
private notifyScheduled = false;
|
|
165
|
+
/** Settled {@link AutoAnchorInstance.ambiguous} verdicts by instance id. */
|
|
166
|
+
private readonly ambiguity = new Map<string, boolean>();
|
|
167
|
+
/**
|
|
168
|
+
* Groups whose verdicts are out of date: `r:` registry key, `t:` template
|
|
169
|
+
* path, `m:` manual id. Mounting a list or reading changed row labels marks
|
|
170
|
+
* a group once; it is settled once, on the next read of a verdict, instead
|
|
171
|
+
* of being recomputed for every member that changed.
|
|
172
|
+
*/
|
|
173
|
+
private readonly staleGroups = new Set<string>();
|
|
174
|
+
/**
|
|
175
|
+
* Set instead of {@link staleGroups} once that outgrows the registry: with
|
|
176
|
+
* no flow or element condition reading verdicts, marks from list mounts
|
|
177
|
+
* would otherwise pile up for the whole session.
|
|
178
|
+
*/
|
|
179
|
+
private allStale = false;
|
|
180
|
+
private settling = false;
|
|
151
181
|
|
|
152
182
|
registerInstance(input: RegisterInstanceInput): { instanceId: string; dispose: () => void } {
|
|
153
183
|
const instanceId = mintInstanceId();
|
|
@@ -200,6 +230,7 @@ export class AutoAnchorRegistry {
|
|
|
200
230
|
childInstanceIds: [],
|
|
201
231
|
ambiguous: false,
|
|
202
232
|
};
|
|
233
|
+
this.defineAmbiguity(instance);
|
|
203
234
|
|
|
204
235
|
this.instances.set(instanceId, instance);
|
|
205
236
|
this.addIndex(this.byRegistryKey, input.registryKey, instanceId);
|
|
@@ -213,7 +244,7 @@ export class AutoAnchorRegistry {
|
|
|
213
244
|
if (parent) parent.childInstanceIds.push(instanceId);
|
|
214
245
|
}
|
|
215
246
|
|
|
216
|
-
this.
|
|
247
|
+
this.markStale(instance);
|
|
217
248
|
this.notify();
|
|
218
249
|
|
|
219
250
|
return {
|
|
@@ -272,7 +303,7 @@ export class AutoAnchorRegistry {
|
|
|
272
303
|
else delete inst.manualId;
|
|
273
304
|
}
|
|
274
305
|
this.refreshManualIndexes(inst, prevIds);
|
|
275
|
-
this.
|
|
306
|
+
this.markStale(inst, prevIds.manualId, prevIds.userflowId, prevIds.testID);
|
|
276
307
|
this.notify();
|
|
277
308
|
}
|
|
278
309
|
|
|
@@ -339,25 +370,32 @@ export class AutoAnchorRegistry {
|
|
|
339
370
|
*
|
|
340
371
|
* Direct fiber pointers are preferred; the scan-root index is built lazily
|
|
341
372
|
* and only if some instance cannot reach its fiber that way (Paper release
|
|
342
|
-
* builds, mainly), then reused for the rest of the pass.
|
|
373
|
+
* builds, mainly), then reused for the rest of the pass. Finding which fiber
|
|
374
|
+
* of each pair is committed walks to the root; the pass shares one walk per
|
|
375
|
+
* ancestor across every instance.
|
|
343
376
|
*
|
|
344
377
|
* Silent — does not notify listeners.
|
|
345
378
|
*/
|
|
346
379
|
refreshLiveContent(instances?: AutoAnchorInstance[]): void {
|
|
347
380
|
const list = instances ?? this.allInstances();
|
|
348
381
|
const getIndex = createLazyHostFiberIndex();
|
|
382
|
+
const resolveCurrent = createCurrentFiberResolver();
|
|
349
383
|
const seen = new Set<string>();
|
|
350
384
|
for (const inst of list) {
|
|
351
385
|
if (seen.has(inst.instanceId)) continue;
|
|
352
386
|
seen.add(inst.instanceId);
|
|
353
|
-
this.refreshOneLiveContent(inst, getIndex);
|
|
387
|
+
this.refreshOneLiveContent(inst, getIndex, resolveCurrent);
|
|
354
388
|
}
|
|
355
389
|
}
|
|
356
390
|
|
|
357
|
-
private refreshOneLiveContent(
|
|
391
|
+
private refreshOneLiveContent(
|
|
392
|
+
inst: AutoAnchorInstance,
|
|
393
|
+
getIndex: () => HostFiberIndex,
|
|
394
|
+
resolveCurrent: (fiber: AnyFiber) => AnyFiber,
|
|
395
|
+
): void {
|
|
358
396
|
let fiber: AnyFiber | null = null;
|
|
359
397
|
try {
|
|
360
|
-
fiber = lookupHostFiber(getIndex, inst.ref.current);
|
|
398
|
+
fiber = lookupHostFiber(getIndex, inst.ref.current, resolveCurrent);
|
|
361
399
|
} catch {
|
|
362
400
|
fiber = null;
|
|
363
401
|
}
|
|
@@ -370,12 +408,17 @@ export class AutoAnchorRegistry {
|
|
|
370
408
|
props = undefined;
|
|
371
409
|
}
|
|
372
410
|
|
|
411
|
+
// Same committed fiber and same props object means nothing was committed
|
|
412
|
+
// here since the last read, so the subtree walk would return what we
|
|
413
|
+
// already have. A commit that re-renders this host or anything inside it
|
|
414
|
+
// makes the other fiber of the pair current, even when the host keeps its
|
|
415
|
+
// props object. Both only change at commit, unlike Fabric's
|
|
416
|
+
// `canonical.currentProps`, which is written during render and stays the
|
|
417
|
+
// same object when only a child changed. Matters because resolution polls
|
|
418
|
+
// this for every registered instance.
|
|
373
419
|
const cached = this.liveContent.get(inst.instanceId);
|
|
374
|
-
// Same fiber and same props object means no re-render since the last read,
|
|
375
|
-
// so the subtree walk would return what we already have. Matters because
|
|
376
|
-
// resolution polls this for every registered instance.
|
|
377
420
|
if (cached && cached.fiber === fiber && props !== undefined && cached.props === props) {
|
|
378
|
-
inst.childText = cached.childText;
|
|
421
|
+
if (cached.childText !== undefined) inst.childText = cached.childText;
|
|
379
422
|
return;
|
|
380
423
|
}
|
|
381
424
|
|
|
@@ -391,17 +434,14 @@ export class AutoAnchorRegistry {
|
|
|
391
434
|
live = undefined;
|
|
392
435
|
}
|
|
393
436
|
|
|
394
|
-
|
|
395
|
-
|
|
437
|
+
// A host with no readable text is cached too, so it is not walked again
|
|
438
|
+
// until it re-renders; its build-time hint stays.
|
|
439
|
+
this.liveContent.set(inst.instanceId, { fiber, props, childText: live });
|
|
440
|
+
if (live && inst.childText !== live) {
|
|
396
441
|
inst.childText = live;
|
|
397
|
-
this.liveContent.set(inst.instanceId, { fiber, props, childText: live });
|
|
398
442
|
// Text is what separates helper-rendered twins, so the group's ambiguity
|
|
399
443
|
// verdict is only trustworthy once it has been read.
|
|
400
|
-
|
|
401
|
-
return;
|
|
402
|
-
}
|
|
403
|
-
if (cached && cached.fiber !== fiber) {
|
|
404
|
-
this.liveContent.delete(inst.instanceId);
|
|
444
|
+
this.markStale(inst);
|
|
405
445
|
}
|
|
406
446
|
}
|
|
407
447
|
|
|
@@ -421,7 +461,7 @@ export class AutoAnchorRegistry {
|
|
|
421
461
|
inst.manualId = liveTestID;
|
|
422
462
|
}
|
|
423
463
|
this.refreshManualIndexes(inst, prev);
|
|
424
|
-
this.
|
|
464
|
+
this.markStale(inst, prev.manualId, prev.userflowId, prev.testID);
|
|
425
465
|
}
|
|
426
466
|
|
|
427
467
|
subscribe(listener: AutoAnchorListener): () => void {
|
|
@@ -462,6 +502,9 @@ export class AutoAnchorRegistry {
|
|
|
462
502
|
this.byManualId.clear();
|
|
463
503
|
this.byTemplatePath.clear();
|
|
464
504
|
this.liveContent.clear();
|
|
505
|
+
this.ambiguity.clear();
|
|
506
|
+
this.staleGroups.clear();
|
|
507
|
+
this.allStale = false;
|
|
465
508
|
this.notifyScheduled = false;
|
|
466
509
|
nextInstanceSeq = 1;
|
|
467
510
|
}
|
|
@@ -483,13 +526,14 @@ export class AutoAnchorRegistry {
|
|
|
483
526
|
|
|
484
527
|
this.instances.delete(instanceId);
|
|
485
528
|
this.liveContent.delete(instanceId);
|
|
529
|
+
this.ambiguity.delete(instanceId);
|
|
486
530
|
this.removeIndex(this.byRegistryKey, inst.registryKey, instanceId);
|
|
487
531
|
this.removeIndex(this.byTemplatePath, inst.templatePath, instanceId);
|
|
488
532
|
if (inst.manualId) this.removeIndex(this.byManualId, inst.manualId, instanceId);
|
|
489
533
|
if (inst.userflowId) this.removeIndex(this.byManualId, inst.userflowId, instanceId);
|
|
490
534
|
if (inst.testID) this.removeIndex(this.byManualId, inst.testID, instanceId);
|
|
491
535
|
|
|
492
|
-
this.
|
|
536
|
+
this.markStale(inst);
|
|
493
537
|
this.notify();
|
|
494
538
|
}
|
|
495
539
|
|
|
@@ -533,29 +577,116 @@ export class AutoAnchorRegistry {
|
|
|
533
577
|
return false;
|
|
534
578
|
}
|
|
535
579
|
|
|
580
|
+
/**
|
|
581
|
+
* Back {@link AutoAnchorInstance.ambiguous} with a verdict that is settled on
|
|
582
|
+
* read, so callers holding an instance always see the current value.
|
|
583
|
+
*/
|
|
584
|
+
private defineAmbiguity(inst: AutoAnchorInstance): void {
|
|
585
|
+
const id = inst.instanceId;
|
|
586
|
+
Object.defineProperty(inst, 'ambiguous', {
|
|
587
|
+
configurable: true,
|
|
588
|
+
enumerable: true,
|
|
589
|
+
get: () => {
|
|
590
|
+
this.settleAmbiguity();
|
|
591
|
+
return this.ambiguity.get(id) ?? false;
|
|
592
|
+
},
|
|
593
|
+
set: (value: boolean) => {
|
|
594
|
+
this.ambiguity.set(id, value);
|
|
595
|
+
},
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/** Every group `inst` belongs to, plus ids it was indexed under before a change. */
|
|
600
|
+
private markStale(inst: AutoAnchorInstance, ...previousIds: Array<string | undefined>): void {
|
|
601
|
+
if (this.allStale) return;
|
|
602
|
+
this.staleGroups.add(`r:${inst.registryKey}`);
|
|
603
|
+
this.staleGroups.add(`t:${inst.templatePath}`);
|
|
604
|
+
for (const id of [inst.manualId, inst.userflowId, inst.testID, ...previousIds]) {
|
|
605
|
+
if (id) this.staleGroups.add(`m:${id}`);
|
|
606
|
+
}
|
|
607
|
+
// Settling every instance is linear in the registry, so past this size
|
|
608
|
+
// tracking groups no longer saves work.
|
|
609
|
+
if (this.staleGroups.size > this.instances.size) {
|
|
610
|
+
this.allStale = true;
|
|
611
|
+
this.staleGroups.clear();
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
private groupIds(groupKey: string): Set<string> | undefined {
|
|
616
|
+
const value = groupKey.slice(2);
|
|
617
|
+
if (groupKey.startsWith('r:')) return this.byRegistryKey.get(value);
|
|
618
|
+
if (groupKey.startsWith('t:')) return this.byTemplatePath.get(value);
|
|
619
|
+
return this.byManualId.get(value);
|
|
620
|
+
}
|
|
621
|
+
|
|
536
622
|
/**
|
|
537
623
|
* Instances sharing a template path are only twins while they look alike.
|
|
538
624
|
* Four rows from one `field()` helper are indistinguishable at register time
|
|
539
625
|
* and separate once their labels are read, so ambiguity is decided on
|
|
540
626
|
* content, not on the shared path alone. An instance stays ambiguous when it
|
|
541
627
|
* carries no content of its own, or when a peer carries the same content.
|
|
628
|
+
* An instance with a manual id is ambiguous only when another shares the id.
|
|
629
|
+
*
|
|
630
|
+
* Each stale group is settled once, in time linear in its size: recomputing
|
|
631
|
+
* a whole group for every member that changed made a list whose labels all
|
|
632
|
+
* changed cost the cube of its length.
|
|
542
633
|
*/
|
|
543
|
-
private
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
634
|
+
private settleAmbiguity(): void {
|
|
635
|
+
if ((this.staleGroups.size === 0 && !this.allStale) || this.settling) return;
|
|
636
|
+
this.settling = true;
|
|
637
|
+
try {
|
|
638
|
+
const affected = new Set<string>(this.allStale ? this.instances.keys() : []);
|
|
639
|
+
for (const groupKey of this.staleGroups) {
|
|
640
|
+
const ids = this.groupIds(groupKey);
|
|
641
|
+
if (ids) for (const id of ids) affected.add(id);
|
|
549
642
|
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
const
|
|
555
|
-
|
|
643
|
+
this.staleGroups.clear();
|
|
644
|
+
this.allStale = false;
|
|
645
|
+
|
|
646
|
+
const twinGroups = new Map<string, TwinGroup>();
|
|
647
|
+
for (const id of affected) {
|
|
648
|
+
const inst = this.instances.get(id);
|
|
649
|
+
if (!inst) continue;
|
|
650
|
+
this.ambiguity.set(id, this.computeAmbiguous(inst, twinGroups));
|
|
651
|
+
}
|
|
652
|
+
} finally {
|
|
653
|
+
this.settling = false;
|
|
556
654
|
}
|
|
557
655
|
}
|
|
558
656
|
|
|
657
|
+
private computeAmbiguous(inst: AutoAnchorInstance, twinGroups: Map<string, TwinGroup>): boolean {
|
|
658
|
+
if (inst.manualId) return (this.byManualId.get(inst.manualId)?.size ?? 0) > 1;
|
|
659
|
+
return (
|
|
660
|
+
this.isTwinInGroup(inst, `r:${inst.registryKey}`, twinGroups) ||
|
|
661
|
+
this.isTwinInGroup(inst, `t:${inst.templatePath}`, twinGroups)
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/** {@link isTwinWithin} against a whole registry group, with the group's evidence memoized. */
|
|
666
|
+
private isTwinInGroup(
|
|
667
|
+
inst: AutoAnchorInstance,
|
|
668
|
+
groupKey: string,
|
|
669
|
+
twinGroups: Map<string, TwinGroup>,
|
|
670
|
+
): boolean {
|
|
671
|
+
let group = twinGroups.get(groupKey);
|
|
672
|
+
if (!group) {
|
|
673
|
+
const members = this.idsToInstances(this.groupIds(groupKey));
|
|
674
|
+
const signatures = new Map<string, number>();
|
|
675
|
+
for (const member of members) {
|
|
676
|
+
const sig = contentSignature(member);
|
|
677
|
+
if (sig) signatures.set(sig, (signatures.get(sig) ?? 0) + 1);
|
|
678
|
+
}
|
|
679
|
+
group = {
|
|
680
|
+
unlabelled: members.length > 1 && members.every((member) => !member.manualId),
|
|
681
|
+
signatures,
|
|
682
|
+
};
|
|
683
|
+
twinGroups.set(groupKey, group);
|
|
684
|
+
}
|
|
685
|
+
if (!group.unlabelled) return false;
|
|
686
|
+
const sig = contentSignature(inst);
|
|
687
|
+
return !sig || (group.signatures.get(sig) ?? 0) > 1;
|
|
688
|
+
}
|
|
689
|
+
|
|
559
690
|
private addIndex(map: Map<string, Set<string>>, key: string, instanceId: string): void {
|
|
560
691
|
let set = map.get(key);
|
|
561
692
|
if (!set) {
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared requestAnimationFrame hub so multiple surfaces never stack loops.
|
|
3
3
|
* Mirrors web userflowjs `util/animation-frame.tsx`.
|
|
4
|
+
*
|
|
5
|
+
* Paused while the app is not active. In bridgeless React Native,
|
|
6
|
+
* `requestAnimationFrame` is a 0 ms timer, and once the app is backgrounded
|
|
7
|
+
* iOS fires timers from an NSTimer instead of the display link, so a loop that
|
|
8
|
+
* kept going would spin as fast as the JS thread allows.
|
|
4
9
|
*/
|
|
10
|
+
import { isAppActive, subscribeAppActive } from './appActive';
|
|
5
11
|
|
|
6
12
|
type Callback = () => void;
|
|
7
13
|
|
|
8
14
|
const callbacks: Callback[] = [];
|
|
9
15
|
let rafHandle: number | ReturnType<typeof setTimeout> | null = null;
|
|
10
16
|
let active = false;
|
|
17
|
+
let appActive = true;
|
|
18
|
+
let unsubscribeAppActive: (() => void) | null = null;
|
|
11
19
|
|
|
12
20
|
/**
|
|
13
21
|
* `callback` runs on every animation frame. Starts the shared loop when the
|
|
@@ -18,6 +26,7 @@ export function addAnimationFrameCallback(callback: Callback): void {
|
|
|
18
26
|
callbacks.push(callback);
|
|
19
27
|
if (callbacks.length === 1) {
|
|
20
28
|
active = true;
|
|
29
|
+
watchAppState();
|
|
21
30
|
requestNext();
|
|
22
31
|
}
|
|
23
32
|
}
|
|
@@ -33,6 +42,7 @@ export function removeAnimationFrameCallback(callback: Callback): void {
|
|
|
33
42
|
if (callbacks.length === 0) {
|
|
34
43
|
active = false;
|
|
35
44
|
cancelPending();
|
|
45
|
+
unwatchAppState();
|
|
36
46
|
}
|
|
37
47
|
}
|
|
38
48
|
|
|
@@ -41,6 +51,7 @@ export function resetAnimationFrameForTests(): void {
|
|
|
41
51
|
callbacks.length = 0;
|
|
42
52
|
active = false;
|
|
43
53
|
cancelPending();
|
|
54
|
+
unwatchAppState();
|
|
44
55
|
}
|
|
45
56
|
|
|
46
57
|
/** Test helper — number of active subscribers. */
|
|
@@ -62,8 +73,27 @@ function onAnimationFrame(): void {
|
|
|
62
73
|
requestNext();
|
|
63
74
|
}
|
|
64
75
|
|
|
76
|
+
function watchAppState(): void {
|
|
77
|
+
if (unsubscribeAppActive) return;
|
|
78
|
+
appActive = isAppActive();
|
|
79
|
+
unsubscribeAppActive = subscribeAppActive((next) => {
|
|
80
|
+
appActive = next;
|
|
81
|
+
if (!next) {
|
|
82
|
+
cancelPending();
|
|
83
|
+
} else if (rafHandle == null) {
|
|
84
|
+
requestNext();
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function unwatchAppState(): void {
|
|
90
|
+
unsubscribeAppActive?.();
|
|
91
|
+
unsubscribeAppActive = null;
|
|
92
|
+
appActive = true;
|
|
93
|
+
}
|
|
94
|
+
|
|
65
95
|
function requestNext(): void {
|
|
66
|
-
if (!active) return;
|
|
96
|
+
if (!active || !appActive) return;
|
|
67
97
|
const raf =
|
|
68
98
|
typeof globalThis.requestAnimationFrame === 'function'
|
|
69
99
|
? globalThis.requestAnimationFrame.bind(globalThis)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { AppState } from 'react-native';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Foreground signal for the anchoring loops (animation-frame tracking and the
|
|
5
|
+
* tooltip target search).
|
|
6
|
+
*
|
|
7
|
+
* Anything other than `background` / `inactive` counts as active, including
|
|
8
|
+
* `unknown` before the first native report. Hosts or test doubles without
|
|
9
|
+
* `AppState` always read as active and never notify.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
type AppStateLike = {
|
|
13
|
+
currentState?: unknown;
|
|
14
|
+
addEventListener?: (
|
|
15
|
+
type: 'change',
|
|
16
|
+
handler: (state: unknown) => void,
|
|
17
|
+
) => { remove: () => void } | undefined;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function appState(): AppStateLike | null {
|
|
21
|
+
const candidate = AppState as AppStateLike | undefined;
|
|
22
|
+
return candidate && typeof candidate === 'object' ? candidate : null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function isActiveState(state: unknown): boolean {
|
|
26
|
+
return state !== 'background' && state !== 'inactive';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Whether the app is in the foreground right now. */
|
|
30
|
+
export function isAppActive(): boolean {
|
|
31
|
+
try {
|
|
32
|
+
return isActiveState(appState()?.currentState);
|
|
33
|
+
} catch {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* `listener(active)` runs when the app moves between foreground and anything
|
|
40
|
+
* else. Repeated reports of the same side are dropped. Returns an unsubscribe.
|
|
41
|
+
*/
|
|
42
|
+
export function subscribeAppActive(listener: (active: boolean) => void): () => void {
|
|
43
|
+
const state = appState();
|
|
44
|
+
if (!state || typeof state.addEventListener !== 'function') return () => {};
|
|
45
|
+
let active = isAppActive();
|
|
46
|
+
try {
|
|
47
|
+
const subscription = state.addEventListener('change', (next) => {
|
|
48
|
+
const nextActive = isActiveState(next);
|
|
49
|
+
if (nextActive === active) return;
|
|
50
|
+
active = nextActive;
|
|
51
|
+
listener(nextActive);
|
|
52
|
+
});
|
|
53
|
+
return () => {
|
|
54
|
+
try {
|
|
55
|
+
subscription?.remove();
|
|
56
|
+
} catch {
|
|
57
|
+
// Teardown is best-effort.
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
} catch {
|
|
61
|
+
return () => {};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -7,7 +7,7 @@ import { decodeMobileAutoData, type FlowConditionFragment } from '@userflow-tech
|
|
|
7
7
|
|
|
8
8
|
import { anchorChangeTicker } from './anchorChangeTicker';
|
|
9
9
|
import { elementTapMonitor } from './elementTapMonitor';
|
|
10
|
-
import { fiberIsUnder, tapPathDisabled } from './elementTargetMatch';
|
|
10
|
+
import { fiberBearingAnchorId, fiberIsUnder, tapPathDisabled } from './elementTargetMatch';
|
|
11
11
|
import {
|
|
12
12
|
resolveElementTargets,
|
|
13
13
|
tapMayHitSelector,
|
|
@@ -188,22 +188,39 @@ function trackClick(
|
|
|
188
188
|
const subscription = {
|
|
189
189
|
unsubscribe: (): void => {},
|
|
190
190
|
};
|
|
191
|
+
const latch = (): void => {
|
|
192
|
+
latched = true;
|
|
193
|
+
report(valueWhenOccurred, { immediate: true });
|
|
194
|
+
subscription.unsubscribe();
|
|
195
|
+
stopWatchingResolution();
|
|
196
|
+
};
|
|
197
|
+
|
|
191
198
|
subscription.unsubscribe = elementTapMonitor.subscribe((tap) => {
|
|
192
199
|
if (latched) return;
|
|
193
200
|
if (!tapMayHitSelector(condition.selector, tap)) return;
|
|
194
|
-
const resolution = resolveElementTargets(condition.selector);
|
|
195
|
-
if (resolution.status !== 'found') return;
|
|
196
201
|
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
+
const resolution = resolveElementTargets(condition.selector);
|
|
203
|
+
if (resolution.status === 'found') {
|
|
204
|
+
const matched = resolution.targets.find(
|
|
205
|
+
(target) => target.fiber != null && fiberIsUnder(tap.targetFiber, target.fiber),
|
|
206
|
+
);
|
|
207
|
+
if (!matched?.fiber) return;
|
|
208
|
+
if (tapPathDisabled(tap.targetFiber, matched.fiber)) return;
|
|
209
|
+
latch();
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
202
212
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
213
|
+
// The press may already have navigated away, so the live scan is absent.
|
|
214
|
+
// The fiber captured at touch start still carries the manual id. This is
|
|
215
|
+
// only the fallback: a target that is still on screen keeps the registry
|
|
216
|
+
// and prop-tier precedence of the live scan.
|
|
217
|
+
if (resolution.status !== 'absent') return;
|
|
218
|
+
if ((condition.selector?.type as string | null) === 'AUTO') return;
|
|
219
|
+
const anchorId = resolveManualAnchorId(condition.selector?.css);
|
|
220
|
+
const capturedHost = anchorId ? fiberBearingAnchorId(tap.targetFiber, anchorId) : null;
|
|
221
|
+
if (!capturedHost) return;
|
|
222
|
+
if (tapPathDisabled(tap.targetFiber, capturedHost)) return;
|
|
223
|
+
latch();
|
|
207
224
|
});
|
|
208
225
|
|
|
209
226
|
return () => {
|
|
@@ -6,10 +6,14 @@
|
|
|
6
6
|
* tooltip target-press monitor uses. The host fiber is the one captured at
|
|
7
7
|
* touch start, before the press's setState commits a new tree.
|
|
8
8
|
*
|
|
9
|
+
* A touch that gesture-handler cancels is handed off instead of dropped: the
|
|
10
|
+
* same fiber is emitted if that handler later ends as a tap.
|
|
11
|
+
*
|
|
9
12
|
* With no subscribers the monitor stores nothing, so the bridge can skip the
|
|
10
13
|
* fiber lookup entirely.
|
|
11
14
|
*/
|
|
12
15
|
import type { AnyFiber } from './fiber/fiberInternals';
|
|
16
|
+
import { gestureHandlerHandoff } from './gestureHandlerHandoff';
|
|
13
17
|
import { type TouchIdentifier, type TouchPoint, withinTapSlop } from './targetPressMonitor';
|
|
14
18
|
|
|
15
19
|
export interface ElementTap {
|
|
@@ -25,6 +29,7 @@ interface TouchStart extends TouchPoint {
|
|
|
25
29
|
export class ElementTapMonitor {
|
|
26
30
|
private readonly listeners = new Set<ElementTapListener>();
|
|
27
31
|
private readonly touchStarts = new Map<TouchIdentifier, TouchStart>();
|
|
32
|
+
private readonly handoffStops = new Map<TouchIdentifier, () => void>();
|
|
28
33
|
|
|
29
34
|
get subscriberCount(): number {
|
|
30
35
|
return this.listeners.size;
|
|
@@ -36,10 +41,25 @@ export class ElementTapMonitor {
|
|
|
36
41
|
this.listeners.delete(listener);
|
|
37
42
|
if (this.listeners.size === 0) {
|
|
38
43
|
this.touchStarts.clear();
|
|
44
|
+
this.dropHandoffs();
|
|
39
45
|
}
|
|
40
46
|
};
|
|
41
47
|
}
|
|
42
48
|
|
|
49
|
+
/** Fingers with a recorded start that have not ended, cancelled, or been handed off. */
|
|
50
|
+
inProgressIdentifiers(): TouchIdentifier[] {
|
|
51
|
+
return [...this.touchStarts.keys()];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
hasTouch(identifier: TouchIdentifier): boolean {
|
|
55
|
+
return this.touchStarts.has(identifier);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Fiber captured at touch start, or null when this finger is not in progress. */
|
|
59
|
+
startFiber(identifier: TouchIdentifier): AnyFiber | null {
|
|
60
|
+
return this.touchStarts.get(identifier)?.targetFiber ?? null;
|
|
61
|
+
}
|
|
62
|
+
|
|
43
63
|
handleTouchStart(
|
|
44
64
|
identifier: TouchIdentifier,
|
|
45
65
|
pageX: number,
|
|
@@ -63,31 +83,69 @@ export class ElementTapMonitor {
|
|
|
63
83
|
if (!start || this.listeners.size === 0 || !start.targetFiber) return;
|
|
64
84
|
if (!withinTapSlop(start, { pageX, pageY })) return;
|
|
65
85
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
86
|
+
this.emit(start.targetFiber);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Gesture-handler cancelled this finger. Forget the RN touch and emit the
|
|
91
|
+
* start fiber if that handler later ends as a tap. A start with no fiber
|
|
92
|
+
* cannot latch, so it is dropped.
|
|
93
|
+
*/
|
|
94
|
+
handOffTouch(identifier: TouchIdentifier, handlerTags: readonly number[]): void {
|
|
95
|
+
const start = this.touchStarts.get(identifier);
|
|
96
|
+
if (!start) return;
|
|
97
|
+
this.touchStarts.delete(identifier);
|
|
98
|
+
this.handoffStops.get(identifier)?.();
|
|
99
|
+
if (!start.targetFiber || handlerTags.length === 0 || this.listeners.size === 0) return;
|
|
100
|
+
const fiber = start.targetFiber;
|
|
101
|
+
const stop = gestureHandlerHandoff.track({
|
|
102
|
+
identifier,
|
|
103
|
+
pageX: start.pageX,
|
|
104
|
+
pageY: start.pageY,
|
|
105
|
+
handlerTags,
|
|
106
|
+
onResolve: () => this.emit(fiber),
|
|
107
|
+
});
|
|
108
|
+
this.handoffStops.set(identifier, () => {
|
|
109
|
+
stop();
|
|
110
|
+
this.handoffStops.delete(identifier);
|
|
111
|
+
});
|
|
76
112
|
}
|
|
77
113
|
|
|
78
114
|
/** Drop in-progress gesture(s). Omit `identifier` to clear every finger. */
|
|
79
115
|
cancelTouch(identifier?: TouchIdentifier): void {
|
|
80
116
|
if (identifier == null) {
|
|
81
117
|
this.touchStarts.clear();
|
|
118
|
+
this.dropHandoffs();
|
|
82
119
|
return;
|
|
83
120
|
}
|
|
84
121
|
this.touchStarts.delete(identifier);
|
|
122
|
+
this.handoffStops.get(identifier)?.();
|
|
85
123
|
}
|
|
86
124
|
|
|
87
125
|
/** Test helper. */
|
|
88
126
|
resetForTests(): void {
|
|
89
127
|
this.listeners.clear();
|
|
90
128
|
this.touchStarts.clear();
|
|
129
|
+
this.dropHandoffs();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private emit(targetFiber: AnyFiber): void {
|
|
133
|
+
if (this.listeners.size === 0) return;
|
|
134
|
+
const tap: ElementTap = { targetFiber };
|
|
135
|
+
for (const listener of this.listeners) {
|
|
136
|
+
// One condition's failure must not cost the others this tap, or abort
|
|
137
|
+
// the bridge's handling of the event's remaining touches.
|
|
138
|
+
try {
|
|
139
|
+
listener(tap);
|
|
140
|
+
} catch {
|
|
141
|
+
// The condition stays at its current value.
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private dropHandoffs(): void {
|
|
147
|
+
for (const stop of this.handoffStops.values()) stop();
|
|
148
|
+
this.handoffStops.clear();
|
|
91
149
|
}
|
|
92
150
|
}
|
|
93
151
|
|