@userflow-tech/react-native 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -33
- package/docs/troubleshooting.md +38 -38
- package/expo-plugin/hostDependencyWarnings.d.ts +5 -5
- package/expo-plugin/hostDependencyWarnings.js +7 -7
- package/expo-plugin/hostDependencyWarnings.js.map +1 -1
- package/lib/commonjs/anchors/AnchorRegistry.js +5 -0
- package/lib/commonjs/anchors/AnchorRegistry.js.map +1 -1
- package/lib/commonjs/anchors/ScrollContainerRegistry.js +8 -0
- package/lib/commonjs/anchors/ScrollContainerRegistry.js.map +1 -1
- package/lib/commonjs/anchors/fiber/presentedModal.js +215 -0
- package/lib/commonjs/anchors/fiber/presentedModal.js.map +1 -0
- package/lib/commonjs/anchors/fiber/touchTargetFiber.js +1 -0
- package/lib/commonjs/anchors/fiber/touchTargetFiber.js.map +1 -1
- package/lib/commonjs/anchors/fiber/visibleRect.js +12 -3
- package/lib/commonjs/anchors/fiber/visibleRect.js.map +1 -1
- package/lib/commonjs/anchors/useUserflowAnchor.js.map +1 -1
- package/lib/commonjs/anchors/useUserflowScrollContainer.js.map +1 -1
- package/lib/commonjs/authoring/ElementPickerOverlay.js +197 -138
- package/lib/commonjs/authoring/ElementPickerOverlay.js.map +1 -1
- package/lib/commonjs/authoring/hitTest.js +67 -10
- package/lib/commonjs/authoring/hitTest.js.map +1 -1
- package/lib/commonjs/authoring/hostAtPoint.js +45 -21
- package/lib/commonjs/authoring/hostAtPoint.js.map +1 -1
- package/lib/commonjs/content/RichContentRenderer.js +19 -7
- package/lib/commonjs/content/RichContentRenderer.js.map +1 -1
- package/lib/commonjs/deepLinking.js.map +1 -1
- package/lib/commonjs/deviceContext.js +39 -19
- package/lib/commonjs/deviceContext.js.map +1 -1
- package/lib/commonjs/index.js +11 -5
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/installCheck.js +3 -3
- package/lib/commonjs/installCheck.js.map +1 -1
- package/lib/commonjs/lifecycle.js +2 -0
- package/lib/commonjs/lifecycle.js.map +1 -1
- package/lib/commonjs/pairing/PairingController.js.map +1 -1
- package/lib/commonjs/runtime/UserflowOverlay.js +17 -13
- package/lib/commonjs/runtime/UserflowOverlay.js.map +1 -1
- package/lib/commonjs/runtime/WindowOverlayHost.js +83 -0
- package/lib/commonjs/runtime/WindowOverlayHost.js.map +1 -0
- package/lib/commonjs/runtime/userflowCore.js +9 -2
- package/lib/commonjs/runtime/userflowCore.js.map +1 -1
- package/lib/commonjs/surfaces/TooltipSurface.js +109 -51
- package/lib/commonjs/surfaces/TooltipSurface.js.map +1 -1
- package/lib/commonjs/surfaces/tooltip/TooltipHighlight.js +6 -6
- package/lib/commonjs/surfaces/tooltip/TooltipHighlight.js.map +1 -1
- package/lib/commonjs/surfaces/tooltip/targetOrigin.js +74 -0
- package/lib/commonjs/surfaces/tooltip/targetOrigin.js.map +1 -0
- package/lib/commonjs/version.js +1 -1
- package/lib/module/anchors/AnchorRegistry.js +5 -0
- package/lib/module/anchors/AnchorRegistry.js.map +1 -1
- package/lib/module/anchors/ScrollContainerRegistry.js +8 -0
- package/lib/module/anchors/ScrollContainerRegistry.js.map +1 -1
- package/lib/module/anchors/fiber/presentedModal.js +206 -0
- package/lib/module/anchors/fiber/presentedModal.js.map +1 -0
- package/lib/module/anchors/fiber/touchTargetFiber.js +1 -0
- package/lib/module/anchors/fiber/touchTargetFiber.js.map +1 -1
- package/lib/module/anchors/fiber/visibleRect.js +12 -3
- package/lib/module/anchors/fiber/visibleRect.js.map +1 -1
- package/lib/module/anchors/useUserflowAnchor.js.map +1 -1
- package/lib/module/anchors/useUserflowScrollContainer.js.map +1 -1
- package/lib/module/authoring/ElementPickerOverlay.js +199 -140
- package/lib/module/authoring/ElementPickerOverlay.js.map +1 -1
- package/lib/module/authoring/hitTest.js +67 -11
- package/lib/module/authoring/hitTest.js.map +1 -1
- package/lib/module/authoring/hostAtPoint.js +45 -21
- package/lib/module/authoring/hostAtPoint.js.map +1 -1
- package/lib/module/content/RichContentRenderer.js +19 -7
- package/lib/module/content/RichContentRenderer.js.map +1 -1
- package/lib/module/deepLinking.js.map +1 -1
- package/lib/module/deviceContext.js +38 -17
- package/lib/module/deviceContext.js.map +1 -1
- package/lib/module/index.js +11 -5
- package/lib/module/index.js.map +1 -1
- package/lib/module/installCheck.js +3 -3
- package/lib/module/installCheck.js.map +1 -1
- package/lib/module/lifecycle.js +2 -0
- package/lib/module/lifecycle.js.map +1 -1
- package/lib/module/pairing/PairingController.js.map +1 -1
- package/lib/module/runtime/UserflowOverlay.js +18 -14
- package/lib/module/runtime/UserflowOverlay.js.map +1 -1
- package/lib/module/runtime/WindowOverlayHost.js +76 -0
- package/lib/module/runtime/WindowOverlayHost.js.map +1 -0
- package/lib/module/runtime/userflowCore.js +9 -2
- package/lib/module/runtime/userflowCore.js.map +1 -1
- package/lib/module/surfaces/TooltipSurface.js +109 -51
- package/lib/module/surfaces/TooltipSurface.js.map +1 -1
- package/lib/module/surfaces/tooltip/TooltipHighlight.js +6 -6
- package/lib/module/surfaces/tooltip/TooltipHighlight.js.map +1 -1
- package/lib/module/surfaces/tooltip/targetOrigin.js +67 -0
- package/lib/module/surfaces/tooltip/targetOrigin.js.map +1 -0
- package/lib/module/version.js +1 -1
- package/lib/typescript/commonjs/src/anchors/AnchorRegistry.d.ts +7 -0
- package/lib/typescript/commonjs/src/anchors/AnchorRegistry.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/ScrollContainerRegistry.d.ts +11 -2
- package/lib/typescript/commonjs/src/anchors/ScrollContainerRegistry.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/fiber/presentedModal.d.ts +45 -0
- package/lib/typescript/commonjs/src/anchors/fiber/presentedModal.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/anchors/fiber/visibleRect.d.ts +5 -2
- package/lib/typescript/commonjs/src/anchors/fiber/visibleRect.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/useUserflowAnchor.d.ts +2 -2
- package/lib/typescript/commonjs/src/anchors/useUserflowAnchor.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/anchors/useUserflowScrollContainer.d.ts +3 -2
- package/lib/typescript/commonjs/src/anchors/useUserflowScrollContainer.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/authoring/ElementPickerOverlay.d.ts +4 -0
- package/lib/typescript/commonjs/src/authoring/ElementPickerOverlay.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/authoring/hitTest.d.ts +25 -2
- package/lib/typescript/commonjs/src/authoring/hitTest.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/authoring/hostAtPoint.d.ts +6 -1
- package/lib/typescript/commonjs/src/authoring/hostAtPoint.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/deepLinking.d.ts +1 -1
- package/lib/typescript/commonjs/src/deepLinking.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/deviceContext.d.ts +14 -5
- package/lib/typescript/commonjs/src/deviceContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +11 -5
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/installCheck.d.ts +2 -2
- package/lib/typescript/commonjs/src/installCheck.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/lifecycle.d.ts +1 -0
- package/lib/typescript/commonjs/src/lifecycle.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/pairing/PairingController.d.ts +1 -1
- package/lib/typescript/commonjs/src/pairing/PairingController.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/runtime/UserflowOverlay.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/runtime/WindowOverlayHost.d.ts +34 -0
- package/lib/typescript/commonjs/src/runtime/WindowOverlayHost.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/runtime/userflowCore.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/surfaces/TooltipSurface.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/surfaces/tooltip/targetOrigin.d.ts +26 -0
- package/lib/typescript/commonjs/src/surfaces/tooltip/targetOrigin.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/version.d.ts +1 -1
- package/lib/typescript/module/src/anchors/AnchorRegistry.d.ts +7 -0
- package/lib/typescript/module/src/anchors/AnchorRegistry.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/ScrollContainerRegistry.d.ts +11 -2
- package/lib/typescript/module/src/anchors/ScrollContainerRegistry.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/fiber/presentedModal.d.ts +45 -0
- package/lib/typescript/module/src/anchors/fiber/presentedModal.d.ts.map +1 -0
- package/lib/typescript/module/src/anchors/fiber/visibleRect.d.ts +5 -2
- package/lib/typescript/module/src/anchors/fiber/visibleRect.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/useUserflowAnchor.d.ts +2 -2
- package/lib/typescript/module/src/anchors/useUserflowAnchor.d.ts.map +1 -1
- package/lib/typescript/module/src/anchors/useUserflowScrollContainer.d.ts +3 -2
- package/lib/typescript/module/src/anchors/useUserflowScrollContainer.d.ts.map +1 -1
- package/lib/typescript/module/src/authoring/ElementPickerOverlay.d.ts +4 -0
- package/lib/typescript/module/src/authoring/ElementPickerOverlay.d.ts.map +1 -1
- package/lib/typescript/module/src/authoring/hitTest.d.ts +25 -2
- package/lib/typescript/module/src/authoring/hitTest.d.ts.map +1 -1
- package/lib/typescript/module/src/authoring/hostAtPoint.d.ts +6 -1
- package/lib/typescript/module/src/authoring/hostAtPoint.d.ts.map +1 -1
- package/lib/typescript/module/src/deepLinking.d.ts +1 -1
- package/lib/typescript/module/src/deepLinking.d.ts.map +1 -1
- package/lib/typescript/module/src/deviceContext.d.ts +14 -5
- package/lib/typescript/module/src/deviceContext.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +11 -5
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/installCheck.d.ts +2 -2
- package/lib/typescript/module/src/installCheck.d.ts.map +1 -1
- package/lib/typescript/module/src/lifecycle.d.ts +1 -0
- package/lib/typescript/module/src/lifecycle.d.ts.map +1 -1
- package/lib/typescript/module/src/pairing/PairingController.d.ts +1 -1
- package/lib/typescript/module/src/pairing/PairingController.d.ts.map +1 -1
- package/lib/typescript/module/src/runtime/UserflowOverlay.d.ts.map +1 -1
- package/lib/typescript/module/src/runtime/WindowOverlayHost.d.ts +34 -0
- package/lib/typescript/module/src/runtime/WindowOverlayHost.d.ts.map +1 -0
- package/lib/typescript/module/src/runtime/userflowCore.d.ts.map +1 -1
- package/lib/typescript/module/src/surfaces/TooltipSurface.d.ts.map +1 -1
- package/lib/typescript/module/src/surfaces/tooltip/targetOrigin.d.ts +26 -0
- package/lib/typescript/module/src/surfaces/tooltip/targetOrigin.d.ts.map +1 -0
- package/lib/typescript/module/src/version.d.ts +1 -1
- package/package.json +5 -4
- package/src/anchors/AnchorRegistry.ts +8 -0
- package/src/anchors/ScrollContainerRegistry.ts +15 -3
- package/src/anchors/fiber/presentedModal.ts +203 -0
- package/src/anchors/fiber/touchTargetFiber.ts +2 -1
- package/src/anchors/fiber/visibleRect.ts +12 -3
- package/src/anchors/useUserflowAnchor.ts +4 -5
- package/src/anchors/useUserflowScrollContainer.ts +5 -4
- package/src/authoring/ElementPickerOverlay.tsx +242 -166
- package/src/authoring/hitTest.ts +88 -13
- package/src/authoring/hostAtPoint.ts +67 -21
- package/src/content/RichContentRenderer.tsx +11 -9
- package/src/deepLinking.ts +2 -1
- package/src/deviceContext.ts +50 -14
- package/src/index.ts +11 -5
- package/src/installCheck.ts +3 -3
- package/src/lifecycle.ts +2 -1
- package/src/pairing/PairingController.ts +2 -1
- package/src/runtime/UserflowOverlay.tsx +29 -21
- package/src/runtime/WindowOverlayHost.tsx +95 -0
- package/src/runtime/userflowCore.ts +8 -2
- package/src/surfaces/TooltipSurface.tsx +103 -45
- package/src/surfaces/tooltip/TooltipHighlight.tsx +3 -5
- package/src/surfaces/tooltip/targetOrigin.ts +74 -0
- package/src/version.ts +1 -1
- package/vendor/core/dist/engine/UserflowCore.d.ts +7 -0
- package/vendor/core/dist/engine/UserflowCore.d.ts.map +1 -1
- package/vendor/core/dist/engine/UserflowCore.js +3 -2
- package/vendor/core/dist/engine/UserflowCore.js.map +1 -1
- package/vendor/core/dist/transport/phoenix.d.ts +12 -2
- package/vendor/core/dist/transport/phoenix.d.ts.map +1 -1
- package/vendor/core/dist/transport/phoenix.js +7 -6
- package/vendor/core/dist/transport/phoenix.js.map +1 -1
- package/vendor/core/dist/version.d.ts +1 -1
- package/vendor/core/dist/version.js +1 -1
- package/vendor/core/package.json +1 -1
- package/vendor/protocol/package.json +1 -1
|
@@ -12,6 +12,7 @@ import { stepTrapsHostAccessibility } from '../surfaces/hostAccessibilityTrap';
|
|
|
12
12
|
|
|
13
13
|
import { BannerHost } from './BannerHost';
|
|
14
14
|
import { FlowRenderer } from './FlowRenderer';
|
|
15
|
+
import { WindowOverlayHost } from './WindowOverlayHost';
|
|
15
16
|
import { useFlowSessionState } from './useFlowSessionState';
|
|
16
17
|
import { getUserflowCore } from './userflowCore';
|
|
17
18
|
|
|
@@ -86,30 +87,37 @@ export function UserflowOverlay({
|
|
|
86
87
|
* destroy a running script. `suppressed` hides it for the pick.
|
|
87
88
|
*/}
|
|
88
89
|
<EvalJsHost suppressed={pickerActive} />
|
|
89
|
-
<PreviewModeBanner
|
|
90
|
-
onConfirmingChange={setPreviewConfirming}
|
|
91
|
-
onExit={onExitPreview}
|
|
92
|
-
held={previewHeld}
|
|
93
|
-
onRestart={onRestartPreview}
|
|
94
|
-
state={pairingState}
|
|
95
|
-
suppressed={pickerActive}
|
|
96
|
-
/>
|
|
97
90
|
{/*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
91
|
+
* One host for all three, so they keep this paint order above native
|
|
92
|
+
* modal screens. The host app's trap does not reach a natively presented
|
|
93
|
+
* modal, so the host traps VoiceOver itself.
|
|
101
94
|
*/}
|
|
102
|
-
{
|
|
103
|
-
<
|
|
104
|
-
|
|
105
|
-
|
|
95
|
+
<WindowOverlayHost accessibilityModal={trapHostAccessibility}>
|
|
96
|
+
<PreviewModeBanner
|
|
97
|
+
onConfirmingChange={setPreviewConfirming}
|
|
98
|
+
onExit={onExitPreview}
|
|
99
|
+
held={previewHeld}
|
|
100
|
+
onRestart={onRestartPreview}
|
|
101
|
+
state={pairingState}
|
|
102
|
+
suppressed={pickerActive}
|
|
106
103
|
/>
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
104
|
+
{/*
|
|
105
|
+
* Unmount flow chrome for the whole pick. The session stays alive;
|
|
106
|
+
* captureScreen would otherwise include the modal or tooltip.
|
|
107
|
+
* Remounting reads the same session back.
|
|
108
|
+
*/}
|
|
109
|
+
{pickerActive ? null : (
|
|
110
|
+
<FlowRenderer
|
|
111
|
+
engine={engine}
|
|
112
|
+
previewRestartGeneration={pairingState.previewRestartGeneration}
|
|
113
|
+
/>
|
|
114
|
+
)}
|
|
115
|
+
{/*
|
|
116
|
+
* After flow chrome so BODY_FIRST / BODY_LAST overlay banners stay visible
|
|
117
|
+
* while a tour step (modal, tooltip, condition wait) is still active.
|
|
118
|
+
*/}
|
|
119
|
+
<BannerHost engine={bannerEngine} hidden={pickerActive} />
|
|
120
|
+
</WindowOverlayHost>
|
|
113
121
|
<ElementPickerOverlay />
|
|
114
122
|
</>
|
|
115
123
|
);
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Platform } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { isNativeModuleLinked } from '../nativeModules';
|
|
5
|
+
|
|
6
|
+
interface FullWindowOverlayProps {
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
/** react-native-screens 4.x. Defaults to true, which traps VoiceOver inside the overlay. */
|
|
9
|
+
unstable_accessibilityContainerViewIsModal?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type FullWindowOverlayComponent = React.ComponentType<FullWindowOverlayProps>;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Native module in every react-native-screens 3.x and 4.x build. Rendering
|
|
16
|
+
* `FullWindowOverlay` without the native half would mount an unregistered
|
|
17
|
+
* component, so the package is not required until this is linked.
|
|
18
|
+
*/
|
|
19
|
+
const SCREENS_NATIVE_MODULE = 'RNSModule';
|
|
20
|
+
|
|
21
|
+
let cached: FullWindowOverlayComponent | null | undefined;
|
|
22
|
+
|
|
23
|
+
/** react-native-screens' `FullWindowOverlay`, or null when it cannot host chrome here. */
|
|
24
|
+
function getFullWindowOverlay(): FullWindowOverlayComponent | null {
|
|
25
|
+
if (cached !== undefined) return cached;
|
|
26
|
+
cached = null;
|
|
27
|
+
|
|
28
|
+
// FullWindowOverlay is iOS-only; elsewhere it renders a plain View.
|
|
29
|
+
if (Platform.OS !== 'ios' || typeof require !== 'function') return cached;
|
|
30
|
+
if (!isNativeModuleLinked(SCREENS_NATIVE_MODULE)) return cached;
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
// Not a peer: apps that present native modals already have it, through
|
|
34
|
+
// Expo Router or React Navigation's native stack.
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires -- optional package probe
|
|
36
|
+
const mod = require('react-native-screens') as {
|
|
37
|
+
FullWindowOverlay?: FullWindowOverlayComponent;
|
|
38
|
+
};
|
|
39
|
+
cached = mod?.FullWindowOverlay ?? null;
|
|
40
|
+
} catch {
|
|
41
|
+
cached = null;
|
|
42
|
+
}
|
|
43
|
+
return cached;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface WindowOverlayHostProps {
|
|
47
|
+
children: React.ReactNode;
|
|
48
|
+
/**
|
|
49
|
+
* Hide everything outside the host from VoiceOver, natively presented
|
|
50
|
+
* modals included. Defaults to false.
|
|
51
|
+
*/
|
|
52
|
+
accessibilityModal?: boolean;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** True when {@link WindowOverlayHost} draws above natively presented modals. */
|
|
56
|
+
export function hasWindowOverlayHost(): boolean {
|
|
57
|
+
return getFullWindowOverlay() != null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Hosts SDK chrome above everything else in the app window.
|
|
62
|
+
*
|
|
63
|
+
* On iOS, react-native-screens presents `modal`, `transparentModal`,
|
|
64
|
+
* `formSheet` and `fullScreenModal` screens, and React Native presents
|
|
65
|
+
* `<Modal>`, as view controllers above the React Native root view, so chrome
|
|
66
|
+
* rendered in `UserflowProvider`'s overlay is drawn beneath them and never
|
|
67
|
+
* receives touches there. `FullWindowOverlay` moves its children into a
|
|
68
|
+
* container on the window itself. Measured on iOS 17.4 and 26.5 with
|
|
69
|
+
* react-native-screens 4.16, that container stays above sheets whether they are
|
|
70
|
+
* presented before or after it mounts.
|
|
71
|
+
*
|
|
72
|
+
* Each host is its own container, stacked by when it was attached rather than
|
|
73
|
+
* by React order, so chrome that has to keep a paint order shares one host.
|
|
74
|
+
*
|
|
75
|
+
* Touches inside the host arrive in window coordinates, as they do in the root
|
|
76
|
+
* view. Children render in place when the overlay is unavailable: on Android,
|
|
77
|
+
* and in apps without react-native-screens.
|
|
78
|
+
*/
|
|
79
|
+
export function WindowOverlayHost({
|
|
80
|
+
children,
|
|
81
|
+
accessibilityModal = false,
|
|
82
|
+
}: WindowOverlayHostProps): React.ReactElement {
|
|
83
|
+
const FullWindowOverlay = getFullWindowOverlay();
|
|
84
|
+
if (!FullWindowOverlay) return <>{children}</>;
|
|
85
|
+
return (
|
|
86
|
+
<FullWindowOverlay unstable_accessibilityContainerViewIsModal={accessibilityModal}>
|
|
87
|
+
{children}
|
|
88
|
+
</FullWindowOverlay>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** @internal Clears the cached `FullWindowOverlay` lookup between tests. */
|
|
93
|
+
export function resetWindowOverlayHostForTests(): void {
|
|
94
|
+
cached = undefined;
|
|
95
|
+
}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { UserflowCore } from '@userflow-tech/core';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import { SDK_VERSION } from '../version';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Shared {@link UserflowCore} singleton for the RN package facade + provider.
|
|
7
|
+
* Joins report the published SDK version (not the internal core version) as
|
|
8
|
+
* `userflowClientBuild`.
|
|
9
|
+
*/
|
|
10
|
+
const core = new UserflowCore({ clientBuild: `react-native-${SDK_VERSION}` });
|
|
5
11
|
|
|
6
12
|
export function getUserflowCore(): UserflowCore {
|
|
7
13
|
return core;
|
|
@@ -23,7 +23,8 @@ import { autoAnchorRegistry } from '../anchors/AutoAnchorRegistry';
|
|
|
23
23
|
import { addAnimationFrameCallback, removeAnimationFrameCallback } from '../anchors/animationFrame';
|
|
24
24
|
import { isAppActive, subscribeAppActive } from '../anchors/appActive';
|
|
25
25
|
import { fiberScanRoot } from '../anchors/fiber/FiberScanRoot';
|
|
26
|
-
import type
|
|
26
|
+
import { type AnyFiber, fiberFromPublicInstance } from '../anchors/fiber/fiberInternals';
|
|
27
|
+
import type { Point } from '../anchors/fiber/presentedModal';
|
|
27
28
|
import { clipToScrollViewports } from '../anchors/fiber/visibleRect';
|
|
28
29
|
import {
|
|
29
30
|
clearFiberAnchorCache,
|
|
@@ -82,6 +83,7 @@ import {
|
|
|
82
83
|
tooltipSideGap,
|
|
83
84
|
tooltipVerticalGap,
|
|
84
85
|
} from './tooltip/resolveSideCardWidth';
|
|
86
|
+
import { locateTargetOrigin, offsetRect } from './tooltip/targetOrigin';
|
|
85
87
|
import { TargetSearchSchedule } from './tooltip/targetSearchSchedule';
|
|
86
88
|
|
|
87
89
|
export interface TooltipSurfaceProps {
|
|
@@ -201,6 +203,12 @@ export function TooltipSurface({
|
|
|
201
203
|
const [missingMode, setMissingMode] = React.useState<MissingMode>('waiting');
|
|
202
204
|
/** True after at least one *failed* measure for the current step/anchor. */
|
|
203
205
|
const [measureAttempted, setMeasureAttempted] = React.useState(false);
|
|
206
|
+
/**
|
|
207
|
+
* True while a natively presented modal hides the target, or the target is
|
|
208
|
+
* in a sheet that cannot be placed. The step waits without counting the
|
|
209
|
+
* target as missing, and draws nothing over the modal.
|
|
210
|
+
*/
|
|
211
|
+
const [concealed, setConcealed] = React.useState(false);
|
|
204
212
|
/**
|
|
205
213
|
* False only after a same-step `resetNonce` bump (preview restart) until one
|
|
206
214
|
* frame has passed, so dialog teardown cannot 0-size FLAG.
|
|
@@ -238,7 +246,15 @@ export function TooltipSurface({
|
|
|
238
246
|
const resolveEpochRef = React.useRef(0);
|
|
239
247
|
/** Latest resolved host fiber (for scroll-ancestor walk + rAF remeasure). */
|
|
240
248
|
const hostFiberRef = React.useRef<AnyFiber | null>(null);
|
|
241
|
-
/**
|
|
249
|
+
/**
|
|
250
|
+
* Window position of the host's measure space, from the last resolve. Not
|
|
251
|
+
* zero only inside a native sheet, whose content measures and receives
|
|
252
|
+
* touches relative to the sheet.
|
|
253
|
+
*/
|
|
254
|
+
const measureOriginRef = React.useRef<Point>({ x: 0, y: 0 });
|
|
255
|
+
/** `targetRef` in the host's measure space. */
|
|
256
|
+
const measuredRef = React.useRef<Rect | null>(null);
|
|
257
|
+
/** Target rect clipped to scroll viewports, for tap detection only. In measure space, as touches are. */
|
|
242
258
|
const clippedPressRef = React.useRef<Rect | null>(null);
|
|
243
259
|
const clipGenRef = React.useRef(0);
|
|
244
260
|
const hostMeasureRef = React.useRef<
|
|
@@ -263,6 +279,8 @@ export function TooltipSurface({
|
|
|
263
279
|
insetsRef.current = layoutInsets;
|
|
264
280
|
const missingModeRef = React.useRef(missingMode);
|
|
265
281
|
missingModeRef.current = missingMode;
|
|
282
|
+
const concealedRef = React.useRef(concealed);
|
|
283
|
+
concealedRef.current = concealed;
|
|
266
284
|
const behaviorRef = React.useRef(behavior);
|
|
267
285
|
behaviorRef.current = behavior;
|
|
268
286
|
const draftModeRef = React.useRef(session.draftMode);
|
|
@@ -292,6 +310,7 @@ export function TooltipSurface({
|
|
|
292
310
|
warnedSidePlacementStepRef.current = null;
|
|
293
311
|
targetStepIdRef.current = null;
|
|
294
312
|
targetRef.current = null;
|
|
313
|
+
measuredRef.current = null;
|
|
295
314
|
// Drop the previous card's measured size and side so the next step does not
|
|
296
315
|
// inherit a wrapped 115×400 LEFT into `fits(currentPlacement)`.
|
|
297
316
|
const nextPlacement = desiredPlacementRef.current ?? 'BELOW';
|
|
@@ -300,6 +319,7 @@ export function TooltipSurface({
|
|
|
300
319
|
setBubbleSize({ width: 280, height: 160 });
|
|
301
320
|
setMissingMode('waiting');
|
|
302
321
|
setMeasureAttempted(false);
|
|
322
|
+
setConcealed(false);
|
|
303
323
|
setTarget(null);
|
|
304
324
|
const prev = targetingIdentityRef.current;
|
|
305
325
|
const sameIdentity = prev.stepId === currentStep.id && prev.targetKey === targetKey;
|
|
@@ -319,10 +339,13 @@ export function TooltipSurface({
|
|
|
319
339
|
return () => clearTimeout(handle);
|
|
320
340
|
}, [resolveArmed]);
|
|
321
341
|
|
|
322
|
-
|
|
342
|
+
/** `next` is in window coordinates; `measured` is the same rect in the host's measure space. */
|
|
343
|
+
const applyTarget = React.useCallback((next: Rect | null, measured: Rect | null = next) => {
|
|
323
344
|
if (!mountedRef.current) return;
|
|
345
|
+
if (next != null) setConcealed(false);
|
|
324
346
|
targetStepIdRef.current = next == null ? null : currentStepIdRef.current;
|
|
325
|
-
if (rectsEqual(targetRef.current, next)) return;
|
|
347
|
+
if (rectsEqual(targetRef.current, next) && rectsEqual(measuredRef.current, measured)) return;
|
|
348
|
+
measuredRef.current = measured;
|
|
326
349
|
if (next == null) {
|
|
327
350
|
// The anchor went away (unmount / navigation), so whatever scroll position
|
|
328
351
|
// the user had settled on no longer applies. Treat its next appearance as
|
|
@@ -332,15 +355,15 @@ export function TooltipSurface({
|
|
|
332
355
|
}
|
|
333
356
|
targetRef.current = next;
|
|
334
357
|
setTarget(next);
|
|
335
|
-
if (next == null) {
|
|
358
|
+
if (next == null || measured == null) {
|
|
336
359
|
clippedPressRef.current = null;
|
|
337
360
|
return;
|
|
338
361
|
}
|
|
339
|
-
clippedPressRef.current =
|
|
362
|
+
clippedPressRef.current = measured;
|
|
340
363
|
const fiber = hostFiberRef.current;
|
|
341
364
|
const gen = (clipGenRef.current += 1);
|
|
342
365
|
if (!fiber) return;
|
|
343
|
-
void clipToScrollViewports(fiber,
|
|
366
|
+
void clipToScrollViewports(fiber, measured).then((clipped) => {
|
|
344
367
|
if (clipGenRef.current !== gen) return;
|
|
345
368
|
clippedPressRef.current = clipped;
|
|
346
369
|
});
|
|
@@ -364,10 +387,28 @@ export function TooltipSurface({
|
|
|
364
387
|
hostMeasureRef.current = null;
|
|
365
388
|
hostScrollIntoViewRef.current = undefined;
|
|
366
389
|
fiberCacheIdRef.current = null;
|
|
390
|
+
setConcealed(false);
|
|
367
391
|
markMeasureAttempted();
|
|
368
392
|
applyTarget(null);
|
|
369
393
|
}, [applyTarget, markMeasureAttempted]);
|
|
370
394
|
|
|
395
|
+
/**
|
|
396
|
+
* Forget the resolved host while a natively presented modal hides it. Unlike
|
|
397
|
+
* {@link dropHost} the target is not gone: the missing-target timer does not
|
|
398
|
+
* run, so opening a sheet mid-step cannot flag or end the flow, and the
|
|
399
|
+
* tooltip comes back when the sheet closes.
|
|
400
|
+
*/
|
|
401
|
+
const concealHost = React.useCallback(() => {
|
|
402
|
+
resolveEpochRef.current += 1;
|
|
403
|
+
measureInFlightRef.current = false;
|
|
404
|
+
hostFiberRef.current = null;
|
|
405
|
+
hostMeasureRef.current = null;
|
|
406
|
+
hostScrollIntoViewRef.current = undefined;
|
|
407
|
+
fiberCacheIdRef.current = null;
|
|
408
|
+
setConcealed(true);
|
|
409
|
+
applyTarget(null);
|
|
410
|
+
}, [applyTarget]);
|
|
411
|
+
|
|
371
412
|
const effectiveViewport = React.useCallback(() => {
|
|
372
413
|
const windowSize = Dimensions.get('window');
|
|
373
414
|
const scrollPadding = getScrollPadding();
|
|
@@ -386,8 +427,9 @@ export function TooltipSurface({
|
|
|
386
427
|
);
|
|
387
428
|
}, []);
|
|
388
429
|
|
|
430
|
+
/** `rect` is in window coordinates; `measured` is the same rect in the host's measure space. */
|
|
389
431
|
const maybeScrollIntoView = React.useCallback(
|
|
390
|
-
(rect: Rect) => {
|
|
432
|
+
(rect: Rect, measured: Rect) => {
|
|
391
433
|
// Scrolling the app to reveal a target we are fading away from is visible.
|
|
392
434
|
if (exitingRef.current) return;
|
|
393
435
|
if (scrollSettledRef.current) return;
|
|
@@ -408,8 +450,9 @@ export function TooltipSurface({
|
|
|
408
450
|
? { scrollIntoView: hostScrollIntoViewRef.current }
|
|
409
451
|
: {}),
|
|
410
452
|
};
|
|
453
|
+
// Scroll containers are measured in the same space as the host.
|
|
411
454
|
scrollAnchorIntoView({
|
|
412
|
-
rect,
|
|
455
|
+
rect: measured,
|
|
413
456
|
host,
|
|
414
457
|
fiber: hostFiberRef.current,
|
|
415
458
|
});
|
|
@@ -420,6 +463,31 @@ export function TooltipSurface({
|
|
|
420
463
|
[effectiveViewport],
|
|
421
464
|
);
|
|
422
465
|
|
|
466
|
+
/** Measure callback for both the resolve and the rAF remeasure of `epoch`'s host. */
|
|
467
|
+
const onHostMeasured = React.useCallback(
|
|
468
|
+
(epoch: number, x: number, y: number, width: number, height: number) => {
|
|
469
|
+
if (resolveEpochRef.current !== epoch) {
|
|
470
|
+
measureInFlightRef.current = false;
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
measureInFlightRef.current = false;
|
|
474
|
+
if (!mountedRef.current) return;
|
|
475
|
+
|
|
476
|
+
if (width <= 0 || height <= 0) {
|
|
477
|
+
const cacheId = fiberCacheIdRef.current;
|
|
478
|
+
if (cacheId) invalidateFiberAnchor(cacheId);
|
|
479
|
+
dropHost();
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const measured: Rect = { x, y, width, height };
|
|
484
|
+
const rect = offsetRect(measured, measureOriginRef.current);
|
|
485
|
+
maybeScrollIntoView(rect, measured);
|
|
486
|
+
applyTarget(rect, measured);
|
|
487
|
+
},
|
|
488
|
+
[applyTarget, dropHost, maybeScrollIntoView],
|
|
489
|
+
);
|
|
490
|
+
|
|
423
491
|
/**
|
|
424
492
|
* Resolve the anchor host (registry / fiber scan). Driven by
|
|
425
493
|
* {@link TargetSearchSchedule} — intentionally NOT on every animation frame.
|
|
@@ -450,26 +518,25 @@ export function TooltipSurface({
|
|
|
450
518
|
if (measureInFlightRef.current) return;
|
|
451
519
|
const epoch = resolveEpochRef.current;
|
|
452
520
|
measureInFlightRef.current = true;
|
|
453
|
-
|
|
454
|
-
|
|
521
|
+
const { host } = resolution;
|
|
522
|
+
const placedFiber = resolution.fiber ?? fiberFromPublicInstance(host.node);
|
|
523
|
+
// Refreshed per resolve, not per frame: a sheet moves rarely, and the
|
|
524
|
+
// lookup walks the whole tree.
|
|
525
|
+
locateTargetOrigin(placedFiber, (origin) => {
|
|
526
|
+
if (resolveEpochRef.current !== epoch || !mountedRef.current) {
|
|
455
527
|
measureInFlightRef.current = false;
|
|
456
528
|
return;
|
|
457
529
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
if (width <= 0 || height <= 0) {
|
|
462
|
-
const cacheId = fiberCacheIdRef.current;
|
|
463
|
-
if (cacheId) invalidateFiberAnchor(cacheId);
|
|
464
|
-
dropHost();
|
|
530
|
+
if (!origin) {
|
|
531
|
+
concealHost();
|
|
465
532
|
return;
|
|
466
533
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
534
|
+
measureOriginRef.current = origin;
|
|
535
|
+
host.measureInWindow((x, y, width, height) => {
|
|
536
|
+
onHostMeasured(epoch, x, y, width, height);
|
|
537
|
+
});
|
|
471
538
|
});
|
|
472
|
-
}, [anchorId,
|
|
539
|
+
}, [anchorId, concealHost, decodedAutoData, dropHost, isAuto, onHostMeasured]);
|
|
473
540
|
|
|
474
541
|
/**
|
|
475
542
|
* Live re-measure of an already-resolved host. Driven by the shared rAF hub
|
|
@@ -484,25 +551,9 @@ export function TooltipSurface({
|
|
|
484
551
|
const epoch = resolveEpochRef.current;
|
|
485
552
|
measureInFlightRef.current = true;
|
|
486
553
|
measure((x, y, width, height) => {
|
|
487
|
-
|
|
488
|
-
measureInFlightRef.current = false;
|
|
489
|
-
return;
|
|
490
|
-
}
|
|
491
|
-
measureInFlightRef.current = false;
|
|
492
|
-
if (!mountedRef.current) return;
|
|
493
|
-
|
|
494
|
-
if (width <= 0 || height <= 0) {
|
|
495
|
-
const cacheId = fiberCacheIdRef.current;
|
|
496
|
-
if (cacheId) invalidateFiberAnchor(cacheId);
|
|
497
|
-
dropHost();
|
|
498
|
-
return;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
const rect: Rect = { x, y, width, height };
|
|
502
|
-
maybeScrollIntoView(rect);
|
|
503
|
-
applyTarget(rect);
|
|
554
|
+
onHostMeasured(epoch, x, y, width, height);
|
|
504
555
|
});
|
|
505
|
-
}, [
|
|
556
|
+
}, [onHostMeasured]);
|
|
506
557
|
|
|
507
558
|
const resolveTargetRef = React.useRef(resolveTarget);
|
|
508
559
|
resolveTargetRef.current = resolveTarget;
|
|
@@ -521,7 +572,8 @@ export function TooltipSurface({
|
|
|
521
572
|
}
|
|
522
573
|
const search = new TargetSearchSchedule(() => resolveTargetRef.current());
|
|
523
574
|
searchRef.current = search;
|
|
524
|
-
|
|
575
|
+
// A concealed target keeps the steady poll, so the tooltip is back soon after the modal closes.
|
|
576
|
+
search.setMode(targetRef.current || concealedRef.current ? 'anchored' : 'missing');
|
|
525
577
|
|
|
526
578
|
const trigger = () => search.trigger();
|
|
527
579
|
const unsubscribers = [
|
|
@@ -556,8 +608,8 @@ export function TooltipSurface({
|
|
|
556
608
|
}, [resolveArmed, searchStopped, currentStep.id, targetKey]);
|
|
557
609
|
|
|
558
610
|
React.useEffect(() => {
|
|
559
|
-
searchRef.current?.setMode(target ? 'anchored' : 'missing');
|
|
560
|
-
}, [target]);
|
|
611
|
+
searchRef.current?.setMode(target || concealed ? 'anchored' : 'missing');
|
|
612
|
+
}, [target, concealed]);
|
|
561
613
|
|
|
562
614
|
// rAF tracking while a host is resolved (and we are not paused after report).
|
|
563
615
|
React.useEffect(() => {
|
|
@@ -592,7 +644,7 @@ export function TooltipSurface({
|
|
|
592
644
|
return;
|
|
593
645
|
}
|
|
594
646
|
|
|
595
|
-
if (!measureAttempted) {
|
|
647
|
+
if (!measureAttempted || concealed) {
|
|
596
648
|
return;
|
|
597
649
|
}
|
|
598
650
|
|
|
@@ -608,6 +660,7 @@ export function TooltipSurface({
|
|
|
608
660
|
}, [
|
|
609
661
|
target,
|
|
610
662
|
measureAttempted,
|
|
663
|
+
concealed,
|
|
611
664
|
engine,
|
|
612
665
|
currentStep.id,
|
|
613
666
|
theme.tooltipMissingBehavior,
|
|
@@ -872,6 +925,11 @@ export function TooltipSurface({
|
|
|
872
925
|
return null;
|
|
873
926
|
}
|
|
874
927
|
|
|
928
|
+
// A native modal hides the target: nothing over it, not even the blocker.
|
|
929
|
+
if (isMissing && concealed) {
|
|
930
|
+
return null;
|
|
931
|
+
}
|
|
932
|
+
|
|
875
933
|
const showBranding = session.flow.company.flowBranding;
|
|
876
934
|
const contentPadding = chrome.contentPadding;
|
|
877
935
|
// Modal only while the host is trapped too. Otherwise VoiceOver would skip
|
|
@@ -90,16 +90,14 @@ export function buildHighlightRings(rect: HighlightRect, chrome: HighlightChrome
|
|
|
90
90
|
|
|
91
91
|
function strokeGlow(chrome: HighlightChrome): ViewStyle {
|
|
92
92
|
const blur = Math.max(chrome.radius, 6);
|
|
93
|
-
|
|
93
|
+
// Built in one literal: React Native 0.88 types ViewStyle as readonly.
|
|
94
|
+
return {
|
|
94
95
|
shadowColor: chrome.color,
|
|
95
96
|
shadowOffset: { width: 0, height: 0 },
|
|
96
97
|
shadowOpacity: Math.min(0.45, chrome.opacity),
|
|
97
98
|
shadowRadius: blur,
|
|
99
|
+
...(Platform?.OS !== 'ios' ? { boxShadow: `0px 0px ${blur}px 0px ${chrome.glowColor}` } : null),
|
|
98
100
|
};
|
|
99
|
-
if (Platform?.OS !== 'ios') {
|
|
100
|
-
glow.boxShadow = `0px 0px ${blur}px 0px ${chrome.glowColor}`;
|
|
101
|
-
}
|
|
102
|
-
return glow;
|
|
103
101
|
}
|
|
104
102
|
|
|
105
103
|
function ringFrame(
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { fiberScanRoot } from '../../anchors/fiber/FiberScanRootStore';
|
|
2
|
+
import type { AnyFiber } from '../../anchors/fiber/fiberInternals';
|
|
3
|
+
import {
|
|
4
|
+
locatePresentedModal,
|
|
5
|
+
measureOriginOf,
|
|
6
|
+
type Point,
|
|
7
|
+
} from '../../anchors/fiber/presentedModal';
|
|
8
|
+
import { getFiberAnchorScreenKey } from '../../anchors/fiberAnchorCache';
|
|
9
|
+
import { hasWindowOverlayHost } from '../../runtime/WindowOverlayHost';
|
|
10
|
+
|
|
11
|
+
import type { Rect } from './inferTooltipPlacement';
|
|
12
|
+
|
|
13
|
+
const ZERO: Point = { x: 0, y: 0 };
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* How long "nothing is presented" is trusted on the same screen. The lookup
|
|
17
|
+
* walks the whole fiber tree (1.4ms for 2,200 fibers in a debug build), and
|
|
18
|
+
* an anchored tooltip resolves four times a second. Expo Router and native
|
|
19
|
+
* stack modals change the screen, which skips this wait; a React Native
|
|
20
|
+
* `<Modal>` over the target is noticed within it.
|
|
21
|
+
*/
|
|
22
|
+
export const NO_MODAL_TRUST_MS = 1000;
|
|
23
|
+
|
|
24
|
+
let noModalSince: { at: number; screenKey: string | null } | null = null;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Where a tooltip target's measured rects sit in the window. `done` gets the
|
|
28
|
+
* window position of `(0, 0)` in the target's measure space, or null when the
|
|
29
|
+
* tooltip cannot point at it: a natively presented modal covers the target,
|
|
30
|
+
* or the target is inside a modal that cannot be placed (see
|
|
31
|
+
* `presentedModal.ts`). Also null when the target has no fiber to place.
|
|
32
|
+
*
|
|
33
|
+
* Without the window host, flow chrome is drawn in the root view under any
|
|
34
|
+
* native modal, as before, and `done` runs synchronously with zero.
|
|
35
|
+
*/
|
|
36
|
+
export function locateTargetOrigin(
|
|
37
|
+
fiber: AnyFiber | null,
|
|
38
|
+
done: (origin: Point | null) => void,
|
|
39
|
+
): void {
|
|
40
|
+
if (!hasWindowOverlayHost()) {
|
|
41
|
+
done(ZERO);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const screenKey = getFiberAnchorScreenKey();
|
|
45
|
+
const now = Date.now();
|
|
46
|
+
if (
|
|
47
|
+
noModalSince &&
|
|
48
|
+
noModalSince.screenKey === screenKey &&
|
|
49
|
+
now - noModalSince.at < NO_MODAL_TRUST_MS
|
|
50
|
+
) {
|
|
51
|
+
done(ZERO);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
locatePresentedModal(fiberScanRoot.getFiber()).then(
|
|
55
|
+
(modal) => {
|
|
56
|
+
noModalSince = modal == null ? { at: now, screenKey } : null;
|
|
57
|
+
done(modal == null ? ZERO : fiber ? measureOriginOf(fiber, modal) : null);
|
|
58
|
+
},
|
|
59
|
+
() => {
|
|
60
|
+
noModalSince = null;
|
|
61
|
+
done(null);
|
|
62
|
+
},
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function offsetRect(rect: Rect, origin: Point): Rect {
|
|
67
|
+
if (origin.x === 0 && origin.y === 0) return rect;
|
|
68
|
+
return { ...rect, x: rect.x + origin.x, y: rect.y + origin.y };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** @internal Forgets the cached "nothing is presented" between tests. */
|
|
72
|
+
export function resetTargetOriginForTests(): void {
|
|
73
|
+
noModalSince = null;
|
|
74
|
+
}
|
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.7.0';
|
|
@@ -5,6 +5,13 @@ import type { PublicAttributes, UserflowConfig, UserflowGroupOptions, UserflowId
|
|
|
5
5
|
export interface UserflowCoreDeps {
|
|
6
6
|
validate?: ValidateCredentialsFn;
|
|
7
7
|
createConnection?: CreateConnectionFn;
|
|
8
|
+
/**
|
|
9
|
+
* Reported as `userflowClientBuild` by the default Phoenix transport, on both
|
|
10
|
+
* the init credential probe and the end-user channel. Each default applies it
|
|
11
|
+
* on its own, so an injected `validate` or `createConnection` only drops it
|
|
12
|
+
* for that one.
|
|
13
|
+
*/
|
|
14
|
+
clientBuild?: string;
|
|
8
15
|
}
|
|
9
16
|
export interface UpsertGroupPayload {
|
|
10
17
|
groupExternalId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserflowCore.d.ts","sourceRoot":"","sources":["../../src/engine/UserflowCore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,0BAA0B,EAC1B,aAAa,EACb,kBAAkB,EACnB,MAAM,yBAAyB,CAAC;AAQjC,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"UserflowCore.d.ts","sourceRoot":"","sources":["../../src/engine/UserflowCore.ts"],"names":[],"mappings":"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"}
|
|
@@ -30,12 +30,13 @@ export class UserflowCore {
|
|
|
30
30
|
this.attributes = {};
|
|
31
31
|
this.clientContext = { ...DEFAULT_CLIENT_CONTEXT };
|
|
32
32
|
this.initPromise = null;
|
|
33
|
+
const transportOptions = deps.clientBuild !== undefined ? { clientBuild: deps.clientBuild } : {};
|
|
33
34
|
this.validate =
|
|
34
35
|
deps.validate ??
|
|
35
|
-
((clientToken, serverEndpoint) => validateCredentials(clientToken, serverEndpoint));
|
|
36
|
+
((clientToken, serverEndpoint) => validateCredentials(clientToken, serverEndpoint, undefined, transportOptions));
|
|
36
37
|
this.createConnection =
|
|
37
38
|
deps.createConnection ??
|
|
38
|
-
((clientToken, serverEndpoint) => new PhoenixConnection(clientToken, serverEndpoint));
|
|
39
|
+
((clientToken, serverEndpoint) => new PhoenixConnection(clientToken, serverEndpoint, undefined, transportOptions));
|
|
39
40
|
}
|
|
40
41
|
init(options) {
|
|
41
42
|
if (this.initPromise)
|