@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
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Dimensions,
|
|
4
|
+
Keyboard,
|
|
5
|
+
StyleSheet,
|
|
6
|
+
View,
|
|
7
|
+
type GestureResponderEvent,
|
|
8
|
+
type ViewStyle,
|
|
9
|
+
} from 'react-native';
|
|
3
10
|
|
|
4
11
|
import { pointInRect, TARGET_PRESS_TAP_SLOP } from '../anchors/targetPressMonitor';
|
|
12
|
+
import { WindowOverlayHost } from '../runtime/WindowOverlayHost';
|
|
5
13
|
import { ABSOLUTE_FILL } from '../surfaces/absoluteFill';
|
|
6
14
|
import {
|
|
7
15
|
useReportAuthoringBottomHeight,
|
|
@@ -25,8 +33,10 @@ import {
|
|
|
25
33
|
defaultCandidateIndex,
|
|
26
34
|
hitTestAt,
|
|
27
35
|
nextContainingIndex,
|
|
36
|
+
remeasureCandidates,
|
|
28
37
|
type HitCandidate,
|
|
29
38
|
type HitRect,
|
|
39
|
+
type ModalMiss,
|
|
30
40
|
type PickTarget,
|
|
31
41
|
} from './hitTest';
|
|
32
42
|
|
|
@@ -46,6 +56,10 @@ const WARNING_HELPER =
|
|
|
46
56
|
'Element may have an unreliable ID. This element may be selected but could break later on.';
|
|
47
57
|
const ERROR_LABEL = 'Can’t select this element';
|
|
48
58
|
const ERROR_HELPER = 'Element ID not found — select a different element';
|
|
59
|
+
const UNPLACEABLE_SHEET_HELPER =
|
|
60
|
+
'Can’t tell where this sheet is on screen — in Navigate screens, close the keyboard or expand the sheet';
|
|
61
|
+
const BEHIND_SHEET_HELPER =
|
|
62
|
+
'This part of the screen is behind the sheet — select inside the sheet, or close it in Navigate screens';
|
|
49
63
|
const ONBOARDING_COPY = 'Double tap anywhere to access the menu';
|
|
50
64
|
const RETURN_NUDGE_TITLE = 'Return to the Userflow app';
|
|
51
65
|
const RETURN_NUDGE_BODY =
|
|
@@ -71,6 +85,28 @@ function waitForCapturePaint(): Promise<void> {
|
|
|
71
85
|
});
|
|
72
86
|
}
|
|
73
87
|
|
|
88
|
+
interface TapHits {
|
|
89
|
+
hits: HitCandidate[];
|
|
90
|
+
/** Why a tap on a presented sheet found nothing, so the helper can say so. */
|
|
91
|
+
modalMiss: ModalMiss | null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function hitsAtTap(pageX: number, pageY: number): Promise<TapHits> {
|
|
95
|
+
let modalMiss: ModalMiss | null = null;
|
|
96
|
+
const hits = await hitTestAt(pageX, pageY, {
|
|
97
|
+
onModalMiss: (miss) => {
|
|
98
|
+
modalMiss = miss;
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
return { hits, modalMiss };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function modalMissHelper(miss: ModalMiss | null): string | null {
|
|
105
|
+
if (miss === 'unplaceable') return UNPLACEABLE_SHEET_HELPER;
|
|
106
|
+
if (miss === 'outside') return BEHIND_SHEET_HELPER;
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
|
|
74
110
|
function ringStyle(rect: HitRect, inset: number): ViewStyle {
|
|
75
111
|
return {
|
|
76
112
|
position: 'absolute',
|
|
@@ -86,6 +122,10 @@ function ringStyle(rect: HitRect, inset: number): ViewStyle {
|
|
|
86
122
|
* Overlay chrome for in-app element picking. Mounted by UserflowProvider;
|
|
87
123
|
* renders nothing until {@link elementPickerController.beginSelection}.
|
|
88
124
|
* Every pick shows the menu and onboarding tooltip.
|
|
125
|
+
*
|
|
126
|
+
* Drawn in {@link WindowOverlayHost} so native modal screens on iOS cannot
|
|
127
|
+
* cover it. It mounts only while there is something to show, so the window
|
|
128
|
+
* container exists only for the pick.
|
|
89
129
|
*/
|
|
90
130
|
export function ElementPickerOverlay(): React.ReactElement | null {
|
|
91
131
|
const [state, setState] = React.useState<ElementPickerState>(() =>
|
|
@@ -248,12 +288,12 @@ export function ElementPickerOverlay(): React.ReactElement | null {
|
|
|
248
288
|
}
|
|
249
289
|
}, [phase]);
|
|
250
290
|
|
|
251
|
-
const applySelection = React.useCallback((hits:
|
|
291
|
+
const applySelection = React.useCallback(({ hits, modalMiss }: TapHits) => {
|
|
252
292
|
if (hits.length === 0) {
|
|
253
293
|
setCandidates([]);
|
|
254
294
|
setIndex(0);
|
|
255
295
|
setSelection('error-no-element');
|
|
256
|
-
setStatus(
|
|
296
|
+
setStatus(modalMissHelper(modalMiss));
|
|
257
297
|
return;
|
|
258
298
|
}
|
|
259
299
|
const nextIndex = defaultCandidateIndex(hits);
|
|
@@ -264,11 +304,11 @@ export function ElementPickerOverlay(): React.ReactElement | null {
|
|
|
264
304
|
}, []);
|
|
265
305
|
|
|
266
306
|
const applyHits = React.useCallback(
|
|
267
|
-
(
|
|
307
|
+
(tapHits: TapHits) => {
|
|
268
308
|
if (modeRef.current !== 'select') return;
|
|
269
309
|
lastTapRef.current = null;
|
|
270
310
|
setChromeVisible(true);
|
|
271
|
-
applySelection(
|
|
311
|
+
applySelection(tapHits);
|
|
272
312
|
},
|
|
273
313
|
[applySelection],
|
|
274
314
|
);
|
|
@@ -279,7 +319,7 @@ export function ElementPickerOverlay(): React.ReactElement | null {
|
|
|
279
319
|
const gen = tapGenRef.current;
|
|
280
320
|
setBusy(true);
|
|
281
321
|
setStatus(null);
|
|
282
|
-
const hitsPromise =
|
|
322
|
+
const hitsPromise = hitsAtTap(pageX, pageY);
|
|
283
323
|
const wait = new Promise<void>((resolve) => {
|
|
284
324
|
applyResolveRef.current = resolve;
|
|
285
325
|
applyTimerRef.current = setTimeout(() => {
|
|
@@ -290,9 +330,9 @@ export function ElementPickerOverlay(): React.ReactElement | null {
|
|
|
290
330
|
});
|
|
291
331
|
void (async () => {
|
|
292
332
|
try {
|
|
293
|
-
const [
|
|
333
|
+
const [tapHits] = await Promise.all([hitsPromise, wait]);
|
|
294
334
|
if (tapGenRef.current !== gen) return;
|
|
295
|
-
applyHits(
|
|
335
|
+
applyHits(tapHits);
|
|
296
336
|
} finally {
|
|
297
337
|
if (tapGenRef.current === gen) setBusy(false);
|
|
298
338
|
}
|
|
@@ -316,8 +356,7 @@ export function ElementPickerOverlay(): React.ReactElement | null {
|
|
|
316
356
|
setBusy(true);
|
|
317
357
|
setStatus(null);
|
|
318
358
|
try {
|
|
319
|
-
|
|
320
|
-
applySelection(hits);
|
|
359
|
+
applySelection(await hitsAtTap(pageX, pageY));
|
|
321
360
|
} finally {
|
|
322
361
|
setBusy(false);
|
|
323
362
|
}
|
|
@@ -377,6 +416,41 @@ export function ElementPickerOverlay(): React.ReactElement | null {
|
|
|
377
416
|
[hideOrShowChrome, onTap, scheduleSelection, selected, selection],
|
|
378
417
|
);
|
|
379
418
|
|
|
419
|
+
// The keyboard opening or closing moves a sheet under the selection, and a
|
|
420
|
+
// rotation moves everything. Measure the selection again so the ring, re-tap
|
|
421
|
+
// cycling, the crop and the rect sent to the Builder follow it.
|
|
422
|
+
const candidatesRef = React.useRef(candidates);
|
|
423
|
+
candidatesRef.current = candidates;
|
|
424
|
+
const hasSelection = candidates.length > 0;
|
|
425
|
+
React.useEffect(() => {
|
|
426
|
+
if (!hasSelection) return;
|
|
427
|
+
let latest = 0;
|
|
428
|
+
const refresh = () => {
|
|
429
|
+
const run = (latest += 1);
|
|
430
|
+
const before = candidatesRef.current;
|
|
431
|
+
void remeasureCandidates(before).then((next) => {
|
|
432
|
+
if (run !== latest || candidatesRef.current !== before) return;
|
|
433
|
+
if (next) {
|
|
434
|
+
setCandidates(next);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
setCandidates([]);
|
|
438
|
+
setIndex(0);
|
|
439
|
+
setSelection('idle');
|
|
440
|
+
setStatus(null);
|
|
441
|
+
});
|
|
442
|
+
};
|
|
443
|
+
const subscriptions = [
|
|
444
|
+
Keyboard.addListener('keyboardDidShow', refresh),
|
|
445
|
+
Keyboard.addListener('keyboardDidHide', refresh),
|
|
446
|
+
Dimensions.addEventListener('change', refresh),
|
|
447
|
+
];
|
|
448
|
+
return () => {
|
|
449
|
+
latest += 1;
|
|
450
|
+
for (const subscription of subscriptions) subscription.remove();
|
|
451
|
+
};
|
|
452
|
+
}, [hasSelection]);
|
|
453
|
+
|
|
380
454
|
const deselect = React.useCallback(() => {
|
|
381
455
|
setCandidates([]);
|
|
382
456
|
setIndex(0);
|
|
@@ -459,172 +533,174 @@ export function ElementPickerOverlay(): React.ReactElement | null {
|
|
|
459
533
|
const tooltipVisible = state.active && showOnboarding && chromeVisible && phase === 'selecting';
|
|
460
534
|
|
|
461
535
|
return (
|
|
462
|
-
<
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
536
|
+
<WindowOverlayHost>
|
|
537
|
+
<View pointerEvents="box-none" style={styles.root} testID="userflow-element-picker">
|
|
538
|
+
{returnNudge && !state.active ? (
|
|
539
|
+
<ChromeDialog
|
|
540
|
+
body={RETURN_NUDGE_BODY}
|
|
541
|
+
onClose={dismissReturnNudge}
|
|
542
|
+
title={RETURN_NUDGE_TITLE}
|
|
543
|
+
>
|
|
544
|
+
<ChromeButton
|
|
545
|
+
accessibilityLabel="Okay"
|
|
546
|
+
flex
|
|
547
|
+
label="Okay"
|
|
548
|
+
onPress={dismissReturnNudge}
|
|
549
|
+
testID="userflow-element-picker-return-okay"
|
|
550
|
+
/>
|
|
551
|
+
</ChromeDialog>
|
|
552
|
+
) : null}
|
|
553
|
+
{state.active && (phase === 'selecting' || phase === 'blocked') ? (
|
|
554
|
+
<View pointerEvents="none" style={styles.dim} testID="userflow-element-picker-dim" />
|
|
555
|
+
) : null}
|
|
556
|
+
|
|
557
|
+
{state.active && selected ? (
|
|
558
|
+
<>
|
|
559
|
+
{/*
|
|
560
|
+
* Painter only. TooltipCutout's band pointerEvents follow the end-user
|
|
561
|
+
* surface-interaction setting; the capture layer above absorbs every
|
|
562
|
+
* touch first so that flag cannot leak into picking.
|
|
563
|
+
*/}
|
|
564
|
+
<TooltipCutout
|
|
565
|
+
backdropColor={chromeOverlay.color}
|
|
566
|
+
backdropOpacity={chromeOverlay.opacity}
|
|
567
|
+
targetBlocked={false}
|
|
568
|
+
targetRect={{
|
|
569
|
+
top: selected.rect.y,
|
|
570
|
+
left: selected.rect.x,
|
|
571
|
+
width: selected.rect.width,
|
|
572
|
+
height: selected.rect.height,
|
|
573
|
+
}}
|
|
574
|
+
/>
|
|
575
|
+
<View
|
|
576
|
+
pointerEvents="none"
|
|
577
|
+
style={[
|
|
578
|
+
ringStyle(selected.rect, 5),
|
|
579
|
+
{ borderWidth: 4, borderColor: chromeColors.focusRing },
|
|
580
|
+
]}
|
|
581
|
+
testID="userflow-element-picker-focus-ring"
|
|
582
|
+
/>
|
|
583
|
+
<View
|
|
584
|
+
pointerEvents="none"
|
|
585
|
+
style={[
|
|
586
|
+
ringStyle(selected.rect, 1),
|
|
587
|
+
{ borderWidth: 1, borderColor: chromeColors.white },
|
|
588
|
+
]}
|
|
589
|
+
testID="userflow-element-picker-focus-ring-inner"
|
|
590
|
+
/>
|
|
591
|
+
</>
|
|
592
|
+
) : null}
|
|
593
|
+
|
|
594
|
+
{state.active && mode === 'select' ? (
|
|
508
595
|
<View
|
|
509
|
-
|
|
510
|
-
style={
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
testID="userflow-element-picker-focus-ring-inner"
|
|
596
|
+
testID="userflow-element-picker-capture"
|
|
597
|
+
style={styles.capture}
|
|
598
|
+
onStartShouldSetResponder={() => true}
|
|
599
|
+
onResponderGrant={onGrant}
|
|
600
|
+
onResponderRelease={onRelease}
|
|
515
601
|
/>
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
onResponderGrant={onGrant}
|
|
525
|
-
onResponderRelease={onRelease}
|
|
526
|
-
/>
|
|
527
|
-
) : null}
|
|
528
|
-
|
|
529
|
-
{showChromeBars ? (
|
|
530
|
-
<ChromeBarTransition
|
|
531
|
-
edge="top"
|
|
532
|
-
pointerEvents="box-none"
|
|
533
|
-
style={styles.top}
|
|
534
|
-
visible={chromeBarsVisible}
|
|
535
|
-
>
|
|
536
|
-
<ChromeTopBar
|
|
537
|
-
label={barLabel}
|
|
538
|
-
onMeasureHeight={onMeasureHeight}
|
|
539
|
-
tone={isError ? 'error' : 'default'}
|
|
540
|
-
{...(toneIcon ? { icon: toneIcon } : {})}
|
|
541
|
-
/>
|
|
542
|
-
</ChromeBarTransition>
|
|
543
|
-
) : null}
|
|
544
|
-
|
|
545
|
-
{tooltipVisible ? (
|
|
546
|
-
<View pointerEvents="none" style={[styles.tooltip, { top: barHeight }]}>
|
|
547
|
-
<ChromeTooltip
|
|
548
|
-
onDismiss={() => {
|
|
549
|
-
setShowOnboarding(false);
|
|
550
|
-
setChromeVisible(false);
|
|
551
|
-
}}
|
|
602
|
+
) : null}
|
|
603
|
+
|
|
604
|
+
{showChromeBars ? (
|
|
605
|
+
<ChromeBarTransition
|
|
606
|
+
edge="top"
|
|
607
|
+
pointerEvents="box-none"
|
|
608
|
+
style={styles.top}
|
|
609
|
+
visible={chromeBarsVisible}
|
|
552
610
|
>
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
611
|
+
<ChromeTopBar
|
|
612
|
+
label={barLabel}
|
|
613
|
+
onMeasureHeight={onMeasureHeight}
|
|
614
|
+
tone={isError ? 'error' : 'default'}
|
|
615
|
+
{...(toneIcon ? { icon: toneIcon } : {})}
|
|
616
|
+
/>
|
|
617
|
+
</ChromeBarTransition>
|
|
618
|
+
) : null}
|
|
619
|
+
|
|
620
|
+
{tooltipVisible ? (
|
|
621
|
+
<View pointerEvents="none" style={[styles.tooltip, { top: barHeight }]}>
|
|
622
|
+
<ChromeTooltip
|
|
623
|
+
onDismiss={() => {
|
|
624
|
+
setShowOnboarding(false);
|
|
625
|
+
setChromeVisible(false);
|
|
626
|
+
}}
|
|
627
|
+
>
|
|
628
|
+
{ONBOARDING_COPY}
|
|
629
|
+
</ChromeTooltip>
|
|
630
|
+
</View>
|
|
631
|
+
) : null}
|
|
632
|
+
|
|
633
|
+
{showChromeBars ? (
|
|
634
|
+
<ChromeBarTransition
|
|
635
|
+
edge="bottom"
|
|
636
|
+
pointerEvents="box-none"
|
|
637
|
+
style={styles.bottom}
|
|
638
|
+
visible={chromeBarsVisible}
|
|
570
639
|
>
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
/>
|
|
580
|
-
<ChromeButton
|
|
581
|
-
accessibilityLabel="Confirm element"
|
|
582
|
-
disabled={busy || isError}
|
|
583
|
-
label="Confirm element"
|
|
584
|
-
onPress={() => {
|
|
585
|
-
void confirm();
|
|
586
|
-
}}
|
|
587
|
-
testID="userflow-element-picker-confirm"
|
|
588
|
-
/>
|
|
589
|
-
</>
|
|
590
|
-
) : (
|
|
591
|
-
<>
|
|
592
|
-
<ChromeButton
|
|
593
|
-
accessibilityLabel="Cancel element selection"
|
|
594
|
-
label="Cancel"
|
|
595
|
-
onPress={() => elementPickerController.cancel()}
|
|
596
|
-
testID="userflow-element-picker-cancel"
|
|
597
|
-
variant="secondary"
|
|
598
|
-
/>
|
|
599
|
-
{phase === 'selecting' ? (
|
|
640
|
+
<ChromeBottomSheet
|
|
641
|
+
helperText={helperText}
|
|
642
|
+
onMeasureHeight={onMeasureSheetHeight}
|
|
643
|
+
tone={isError ? 'error' : 'default'}
|
|
644
|
+
{...(helperIcon ? { helperIcon } : {})}
|
|
645
|
+
>
|
|
646
|
+
{phase === 'selected' || phase === 'blocked' ? (
|
|
647
|
+
<>
|
|
600
648
|
<ChromeButton
|
|
601
|
-
accessibilityLabel="
|
|
602
|
-
label="
|
|
603
|
-
onPress={
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
setStatus(null);
|
|
607
|
-
setMode('navigate');
|
|
608
|
-
}}
|
|
609
|
-
testID="userflow-element-picker-navigate"
|
|
649
|
+
accessibilityLabel="Deselect"
|
|
650
|
+
label="Deselect"
|
|
651
|
+
onPress={deselect}
|
|
652
|
+
testID="userflow-element-picker-deselect"
|
|
653
|
+
variant="secondary"
|
|
610
654
|
/>
|
|
611
|
-
) : (
|
|
612
655
|
<ChromeButton
|
|
613
|
-
accessibilityLabel="
|
|
614
|
-
|
|
656
|
+
accessibilityLabel="Confirm element"
|
|
657
|
+
disabled={busy || isError}
|
|
658
|
+
label="Confirm element"
|
|
615
659
|
onPress={() => {
|
|
616
|
-
|
|
617
|
-
setMode('select');
|
|
660
|
+
void confirm();
|
|
618
661
|
}}
|
|
619
|
-
testID="userflow-element-picker-
|
|
662
|
+
testID="userflow-element-picker-confirm"
|
|
663
|
+
/>
|
|
664
|
+
</>
|
|
665
|
+
) : (
|
|
666
|
+
<>
|
|
667
|
+
<ChromeButton
|
|
668
|
+
accessibilityLabel="Cancel element selection"
|
|
669
|
+
label="Cancel"
|
|
670
|
+
onPress={() => elementPickerController.cancel()}
|
|
671
|
+
testID="userflow-element-picker-cancel"
|
|
672
|
+
variant="secondary"
|
|
620
673
|
/>
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
674
|
+
{phase === 'selecting' ? (
|
|
675
|
+
<ChromeButton
|
|
676
|
+
accessibilityLabel="Navigate screens"
|
|
677
|
+
label="Navigate screens"
|
|
678
|
+
onPress={() => {
|
|
679
|
+
cancelPendingSelection();
|
|
680
|
+
lastTapRef.current = null;
|
|
681
|
+
setStatus(null);
|
|
682
|
+
setMode('navigate');
|
|
683
|
+
}}
|
|
684
|
+
testID="userflow-element-picker-navigate"
|
|
685
|
+
/>
|
|
686
|
+
) : (
|
|
687
|
+
<ChromeButton
|
|
688
|
+
accessibilityLabel="Select element here"
|
|
689
|
+
label="Select element here"
|
|
690
|
+
onPress={() => {
|
|
691
|
+
setStatus(null);
|
|
692
|
+
setMode('select');
|
|
693
|
+
}}
|
|
694
|
+
testID="userflow-element-picker-select-here"
|
|
695
|
+
/>
|
|
696
|
+
)}
|
|
697
|
+
</>
|
|
698
|
+
)}
|
|
699
|
+
</ChromeBottomSheet>
|
|
700
|
+
</ChromeBarTransition>
|
|
701
|
+
) : null}
|
|
702
|
+
</View>
|
|
703
|
+
</WindowOverlayHost>
|
|
628
704
|
);
|
|
629
705
|
}
|
|
630
706
|
|