react-native-screen-transitions 4.0.0-alpha.4 → 4.0.0-alpha.5
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/lib/commonjs/components/boundary/hooks/lifecycles/use-initial-destination-measurement.js +17 -9
- package/lib/commonjs/components/boundary/hooks/lifecycles/use-initial-destination-measurement.js.map +1 -1
- package/lib/commonjs/components/boundary/portal/components/boundary-portal/components/portal-boundary-host.js +4 -15
- package/lib/commonjs/components/boundary/portal/components/boundary-portal/components/portal-boundary-host.js.map +1 -1
- package/lib/commonjs/components/boundary/portal/components/boundary-portal/hooks/use-active-portal-boundary-host.js +22 -24
- package/lib/commonjs/components/boundary/portal/components/boundary-portal/hooks/use-active-portal-boundary-host.js.map +1 -1
- package/lib/commonjs/components/boundary/portal/components/boundary-portal/hooks/use-boundary-portal-attachment.js +3 -36
- package/lib/commonjs/components/boundary/portal/components/boundary-portal/hooks/use-boundary-portal-attachment.js.map +1 -1
- package/lib/commonjs/components/boundary/portal/components/boundary-portal/hooks/use-host-measurement.js +1 -1
- package/lib/commonjs/components/boundary/portal/components/boundary-portal/hooks/use-host-measurement.js.map +1 -1
- package/lib/commonjs/components/boundary/portal/components/boundary-portal/stores/portal-boundary-host.store.js +1 -1
- package/lib/commonjs/components/boundary/portal/components/boundary-portal/stores/portal-boundary-host.store.js.map +1 -1
- package/lib/commonjs/components/boundary/utils/destination-signals.js +7 -1
- package/lib/commonjs/components/boundary/utils/destination-signals.js.map +1 -1
- package/lib/commonjs/providers/screen/styles/helpers/resolve-interpolator-style-handoff.js +15 -14
- package/lib/commonjs/providers/screen/styles/helpers/resolve-interpolator-style-handoff.js.map +1 -1
- package/lib/commonjs/providers/screen/styles/hooks/use-interpolated-style-maps.js +17 -17
- package/lib/commonjs/providers/screen/styles/hooks/use-interpolated-style-maps.js.map +1 -1
- package/lib/commonjs/stores/bounds/internals/entries.js +13 -3
- package/lib/commonjs/stores/bounds/internals/entries.js.map +1 -1
- package/lib/module/components/boundary/hooks/lifecycles/use-initial-destination-measurement.js +18 -10
- package/lib/module/components/boundary/hooks/lifecycles/use-initial-destination-measurement.js.map +1 -1
- package/lib/module/components/boundary/portal/components/boundary-portal/components/portal-boundary-host.js +4 -15
- package/lib/module/components/boundary/portal/components/boundary-portal/components/portal-boundary-host.js.map +1 -1
- package/lib/module/components/boundary/portal/components/boundary-portal/hooks/use-active-portal-boundary-host.js +22 -24
- package/lib/module/components/boundary/portal/components/boundary-portal/hooks/use-active-portal-boundary-host.js.map +1 -1
- package/lib/module/components/boundary/portal/components/boundary-portal/hooks/use-boundary-portal-attachment.js +3 -36
- package/lib/module/components/boundary/portal/components/boundary-portal/hooks/use-boundary-portal-attachment.js.map +1 -1
- package/lib/module/components/boundary/portal/components/boundary-portal/hooks/use-host-measurement.js +2 -2
- package/lib/module/components/boundary/portal/components/boundary-portal/hooks/use-host-measurement.js.map +1 -1
- package/lib/module/components/boundary/portal/components/boundary-portal/stores/portal-boundary-host.store.js +1 -1
- package/lib/module/components/boundary/portal/components/boundary-portal/stores/portal-boundary-host.store.js.map +1 -1
- package/lib/module/components/boundary/utils/destination-signals.js +7 -1
- package/lib/module/components/boundary/utils/destination-signals.js.map +1 -1
- package/lib/module/providers/screen/styles/helpers/resolve-interpolator-style-handoff.js +15 -14
- package/lib/module/providers/screen/styles/helpers/resolve-interpolator-style-handoff.js.map +1 -1
- package/lib/module/providers/screen/styles/hooks/use-interpolated-style-maps.js +17 -17
- package/lib/module/providers/screen/styles/hooks/use-interpolated-style-maps.js.map +1 -1
- package/lib/module/stores/bounds/internals/entries.js +13 -3
- package/lib/module/stores/bounds/internals/entries.js.map +1 -1
- package/lib/typescript/components/boundary/hooks/lifecycles/use-initial-destination-measurement.d.ts.map +1 -1
- package/lib/typescript/components/boundary/portal/components/boundary-portal/components/portal-boundary-host.d.ts.map +1 -1
- package/lib/typescript/components/boundary/portal/components/boundary-portal/hooks/use-active-portal-boundary-host.d.ts +1 -5
- package/lib/typescript/components/boundary/portal/components/boundary-portal/hooks/use-active-portal-boundary-host.d.ts.map +1 -1
- package/lib/typescript/components/boundary/portal/components/boundary-portal/hooks/use-boundary-portal-attachment.d.ts.map +1 -1
- package/lib/typescript/components/boundary/portal/components/boundary-portal/hooks/use-host-measurement.d.ts.map +1 -1
- package/lib/typescript/components/boundary/portal/components/boundary-portal/stores/portal-boundary-host.store.d.ts +0 -2
- package/lib/typescript/components/boundary/portal/components/boundary-portal/stores/portal-boundary-host.store.d.ts.map +1 -1
- package/lib/typescript/components/boundary/utils/destination-signals.d.ts +1 -1
- package/lib/typescript/components/boundary/utils/destination-signals.d.ts.map +1 -1
- package/lib/typescript/providers/screen/styles/helpers/resolve-interpolator-style-handoff.d.ts +1 -3
- package/lib/typescript/providers/screen/styles/helpers/resolve-interpolator-style-handoff.d.ts.map +1 -1
- package/lib/typescript/providers/screen/styles/hooks/use-interpolated-style-maps.d.ts +4 -4
- package/lib/typescript/providers/screen/styles/hooks/use-interpolated-style-maps.d.ts.map +1 -1
- package/lib/typescript/stores/bounds/internals/entries.d.ts +1 -1
- package/lib/typescript/stores/bounds/internals/entries.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/boundary/hooks/lifecycles/use-initial-destination-measurement.ts +34 -13
- package/src/components/boundary/portal/components/boundary-portal/components/portal-boundary-host.tsx +4 -20
- package/src/components/boundary/portal/components/boundary-portal/hooks/use-active-portal-boundary-host.ts +27 -37
- package/src/components/boundary/portal/components/boundary-portal/hooks/use-boundary-portal-attachment.ts +10 -57
- package/src/components/boundary/portal/components/boundary-portal/hooks/use-host-measurement.ts +1 -8
- package/src/components/boundary/portal/components/boundary-portal/stores/portal-boundary-host.store.ts +0 -3
- package/src/components/boundary/utils/destination-signals.ts +6 -2
- package/src/providers/screen/styles/helpers/resolve-interpolator-style-handoff.ts +16 -16
- package/src/providers/screen/styles/hooks/use-interpolated-style-maps.tsx +21 -24
- package/src/stores/bounds/internals/entries.ts +12 -1
- package/lib/commonjs/components/boundary/portal/components/boundary-portal/helpers/has-local-slot.js +0 -18
- package/lib/commonjs/components/boundary/portal/components/boundary-portal/helpers/has-local-slot.js.map +0 -1
- package/lib/module/components/boundary/portal/components/boundary-portal/helpers/has-local-slot.js +0 -13
- package/lib/module/components/boundary/portal/components/boundary-portal/helpers/has-local-slot.js.map +0 -1
- package/lib/typescript/components/boundary/portal/components/boundary-portal/helpers/has-local-slot.d.ts +0 -3
- package/lib/typescript/components/boundary/portal/components/boundary-portal/helpers/has-local-slot.d.ts.map +0 -1
- package/src/components/boundary/portal/components/boundary-portal/helpers/has-local-slot.ts +0 -16
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback, useLayoutEffect } from "react";
|
|
1
|
+
import { useCallback, useLayoutEffect, useMemo } from "react";
|
|
2
2
|
import {
|
|
3
3
|
cancelAnimation,
|
|
4
4
|
useAnimatedReaction,
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
withTiming,
|
|
8
8
|
} from "react-native-reanimated";
|
|
9
9
|
import { scheduleOnUI } from "react-native-worklets";
|
|
10
|
+
import { useStack } from "../../../../hooks/navigation/use-stack";
|
|
10
11
|
import { useDescriptorsStore } from "../../../../providers/screen/descriptors";
|
|
11
12
|
import { AnimationStore } from "../../../../stores/animation.store";
|
|
12
13
|
import {
|
|
@@ -61,6 +62,16 @@ export const useInitialDestinationMeasurement = ({
|
|
|
61
62
|
const preferredSourceScreenKey = destinationPairKey
|
|
62
63
|
? getSourceScreenKeyFromPairKey(destinationPairKey)
|
|
63
64
|
: undefined;
|
|
65
|
+
const stackScenes = useStack((store) => store.scenes);
|
|
66
|
+
// A retained closing screen can still have registered boundaries, but it
|
|
67
|
+
// cannot own a new transition link.
|
|
68
|
+
const closingSourceScreenKeys = useMemo(
|
|
69
|
+
() =>
|
|
70
|
+
stackScenes
|
|
71
|
+
.filter((scene) => scene.activity === "closing")
|
|
72
|
+
.map((scene) => scene.route.key),
|
|
73
|
+
[stackScenes],
|
|
74
|
+
);
|
|
64
75
|
const progress = AnimationStore.getValue(
|
|
65
76
|
currentScreenKey,
|
|
66
77
|
"transitionProgress",
|
|
@@ -74,6 +85,7 @@ export const useInitialDestinationMeasurement = ({
|
|
|
74
85
|
const retryToken = useSharedValue(0);
|
|
75
86
|
const handshakeRetries = useSharedValue(0);
|
|
76
87
|
const hasGivenUp = useSharedValue(0);
|
|
88
|
+
const hasFinishedInitialMeasurement = useSharedValue(0);
|
|
77
89
|
|
|
78
90
|
const releaseLifecycleStartBlock = useCallback(() => {
|
|
79
91
|
"worklet";
|
|
@@ -83,19 +95,22 @@ export const useInitialDestinationMeasurement = ({
|
|
|
83
95
|
return;
|
|
84
96
|
}
|
|
85
97
|
|
|
98
|
+
hasFinishedInitialMeasurement.set(1);
|
|
86
99
|
isBlockingLifecycleStart.set(0);
|
|
87
100
|
unblockLifecycleStart();
|
|
88
|
-
}, [
|
|
101
|
+
}, [
|
|
102
|
+
hasFinishedInitialMeasurement,
|
|
103
|
+
isBlockingLifecycleStart,
|
|
104
|
+
retryToken,
|
|
105
|
+
unblockLifecycleStart,
|
|
106
|
+
]);
|
|
89
107
|
|
|
90
108
|
const claimLifecycleStartBlock = useCallback(() => {
|
|
91
109
|
"worklet";
|
|
92
110
|
if (
|
|
93
111
|
!canReceiveDestination ||
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
currentScreenKey,
|
|
97
|
-
preferredSourceScreenKey,
|
|
98
|
-
)
|
|
112
|
+
hasFinishedInitialMeasurement.get() ||
|
|
113
|
+
!getMatchingSourceScreenKey(tag, currentScreenKey)
|
|
99
114
|
) {
|
|
100
115
|
return;
|
|
101
116
|
}
|
|
@@ -113,9 +128,9 @@ export const useInitialDestinationMeasurement = ({
|
|
|
113
128
|
blockLifecycleStart,
|
|
114
129
|
canReceiveDestination,
|
|
115
130
|
currentScreenKey,
|
|
131
|
+
hasFinishedInitialMeasurement,
|
|
116
132
|
isBlockingLifecycleStart,
|
|
117
133
|
progress,
|
|
118
|
-
preferredSourceScreenKey,
|
|
119
134
|
tag,
|
|
120
135
|
]);
|
|
121
136
|
|
|
@@ -147,7 +162,11 @@ export const useInitialDestinationMeasurement = ({
|
|
|
147
162
|
() => {
|
|
148
163
|
"worklet";
|
|
149
164
|
|
|
150
|
-
if (
|
|
165
|
+
if (
|
|
166
|
+
!canReceiveDestination ||
|
|
167
|
+
hasFinishedInitialMeasurement.get() ||
|
|
168
|
+
isBlockingLifecycleStart.get() <= 0
|
|
169
|
+
) {
|
|
151
170
|
return null;
|
|
152
171
|
}
|
|
153
172
|
|
|
@@ -160,6 +179,7 @@ export const useInitialDestinationMeasurement = ({
|
|
|
160
179
|
tag,
|
|
161
180
|
currentScreenKey,
|
|
162
181
|
preferredSourceScreenKey,
|
|
182
|
+
closingSourceScreenKeys,
|
|
163
183
|
);
|
|
164
184
|
const pairKey = sourceScreenKey
|
|
165
185
|
? createScreenPairKey(sourceScreenKey, currentScreenKey)
|
|
@@ -182,12 +202,12 @@ export const useInitialDestinationMeasurement = ({
|
|
|
182
202
|
},
|
|
183
203
|
(next, previous) => {
|
|
184
204
|
"worklet";
|
|
185
|
-
if (!next) {
|
|
205
|
+
if (!next || hasFinishedInitialMeasurement.get()) {
|
|
186
206
|
return;
|
|
187
207
|
}
|
|
188
208
|
|
|
189
209
|
const [measurePairKey, action, retryTick] = next;
|
|
190
|
-
if (!
|
|
210
|
+
if (!action) {
|
|
191
211
|
return;
|
|
192
212
|
}
|
|
193
213
|
|
|
@@ -213,19 +233,20 @@ export const useInitialDestinationMeasurement = ({
|
|
|
213
233
|
return;
|
|
214
234
|
}
|
|
215
235
|
|
|
216
|
-
if (action === "measure") {
|
|
236
|
+
if (action === "measure" && measurePairKey) {
|
|
217
237
|
measureBoundary({
|
|
218
238
|
type: "destination",
|
|
219
239
|
pairKey: measurePairKey,
|
|
220
240
|
});
|
|
221
241
|
}
|
|
222
242
|
|
|
223
|
-
const link = getLink(measurePairKey, linkKey);
|
|
243
|
+
const link = measurePairKey ? getLink(measurePairKey, linkKey) : null;
|
|
224
244
|
const linkComplete = !!link?.source && !!link.destination;
|
|
225
245
|
|
|
226
246
|
if (linkComplete || action === "complete") {
|
|
227
247
|
cancelAnimation(retryToken);
|
|
228
248
|
handshakeRetries.set(0);
|
|
249
|
+
hasFinishedInitialMeasurement.set(1);
|
|
229
250
|
if (escapeClipping) {
|
|
230
251
|
// Screen-level escape has a second readiness phase after destination
|
|
231
252
|
// matching: the host must commit before the transition starts, or
|
|
@@ -16,7 +16,6 @@ import { getLink } from "../../../../../../stores/bounds/internals/links";
|
|
|
16
16
|
import { SystemStore } from "../../../../../../stores/system.store";
|
|
17
17
|
import type { ScrollMeasuredDimensions } from "../../../../utils/measured-bounds";
|
|
18
18
|
import { NativePortalHost, PORTAL_POINTER_EVENTS } from "../../../teleport";
|
|
19
|
-
import { hasLocalSlot } from "../helpers/has-local-slot";
|
|
20
19
|
import { resolvePortalOffsetStyle } from "../helpers/offset-style";
|
|
21
20
|
import { getPortalHostBounds } from "../stores/host-bounds.store";
|
|
22
21
|
import type { ActivePortalBoundaryHost } from "../stores/portal-boundary-host.store";
|
|
@@ -44,11 +43,10 @@ export const PortalBoundaryHost = memo(function PortalBoundaryHost({
|
|
|
44
43
|
}
|
|
45
44
|
|
|
46
45
|
const link = getLink(host.pairKey, host.boundaryId);
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
hasLocalSlot(host.localStylesMaps.get(), host.boundaryId);
|
|
46
|
+
const hasSource = !!link?.source;
|
|
47
|
+
const hasHostBounds = getPortalHostBounds(host.hostKey) !== null;
|
|
48
|
+
const hasSlot = host.slotsMap.get()[host.boundaryId] !== undefined;
|
|
49
|
+
const hasGeometry = hasSource && hasHostBounds && hasSlot;
|
|
52
50
|
|
|
53
51
|
if (!hasGeometry) {
|
|
54
52
|
geometryReadyFrames.set(0);
|
|
@@ -103,20 +101,6 @@ export const PortalBoundaryHost = memo(function PortalBoundaryHost({
|
|
|
103
101
|
});
|
|
104
102
|
const slotStyle = useAnimatedStyle(() => {
|
|
105
103
|
"worklet";
|
|
106
|
-
// `slotsMap` is the resolved map: it may contain real interpolator output,
|
|
107
|
-
// inherited styles, or resolver-created reset patches for slots that just
|
|
108
|
-
// disappeared. Normal components need those reset patches so stale styles
|
|
109
|
-
// clear correctly.
|
|
110
|
-
//
|
|
111
|
-
// A screen-level portal host is different. It is only the temporary visual
|
|
112
|
-
// receiver for teleported content, not the original component that needs a
|
|
113
|
-
// cleanup frame. If the current local interpolator layers did not emit this
|
|
114
|
-
// boundary id, any resolved style here is cleanup/stale residue and should
|
|
115
|
-
// not be drawn by the host.
|
|
116
|
-
if (!hasLocalSlot(host.localStylesMaps.get(), host.boundaryId)) {
|
|
117
|
-
return NO_STYLES;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
104
|
const slot = host.slotsMap.get()[host.boundaryId];
|
|
121
105
|
|
|
122
106
|
return composeSlotStyleWithLocalTransform(
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { useCallback, useLayoutEffect, useRef, useState } from "react";
|
|
2
2
|
import { type SharedValue, useAnimatedReaction } from "react-native-reanimated";
|
|
3
3
|
import { scheduleOnRN } from "react-native-worklets";
|
|
4
|
-
import
|
|
5
|
-
import { pairs } from "../../../../../../stores/bounds/internals/state";
|
|
4
|
+
import { getPairKeyForSource } from "../../../../../../stores/bounds/internals/links";
|
|
6
5
|
import type { ScreenPairKey } from "../../../../../../stores/bounds/types";
|
|
7
6
|
import type { NormalizedTransitionInterpolatedStyle } from "../../../../../../types/animation.types";
|
|
8
7
|
import { createBoundaryPortalHostName } from "../../../utils/naming";
|
|
9
|
-
import { hasActiveBoundaryPortalLink } from "../helpers/active-pair";
|
|
10
8
|
import {
|
|
11
9
|
mountPortalBoundaryHost,
|
|
12
10
|
unmountPortalBoundaryHostByName,
|
|
@@ -16,62 +14,57 @@ type UseActivePortalBoundaryHostParams = {
|
|
|
16
14
|
boundaryId: string;
|
|
17
15
|
currentScreenKey: string;
|
|
18
16
|
escapeHostKey?: string;
|
|
19
|
-
localStylesMaps: SharedValue<LocalStyleLayers>;
|
|
20
17
|
portalHostName: SharedValue<string | null>;
|
|
21
18
|
portalHostReady: SharedValue<boolean>;
|
|
22
19
|
slotsMap: SharedValue<NormalizedTransitionInterpolatedStyle>;
|
|
23
|
-
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type ActivePortal = {
|
|
23
|
+
pairKey: ScreenPairKey;
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
export const useActivePortalBoundaryHost = ({
|
|
27
27
|
boundaryId,
|
|
28
28
|
currentScreenKey,
|
|
29
29
|
escapeHostKey,
|
|
30
|
-
localStylesMaps,
|
|
31
30
|
portalHostName,
|
|
32
31
|
portalHostReady,
|
|
33
32
|
slotsMap,
|
|
34
|
-
sourcePairKey,
|
|
35
33
|
}: UseActivePortalBoundaryHostParams) => {
|
|
36
|
-
const [
|
|
37
|
-
const
|
|
38
|
-
sourcePairKeyRef.current = sourcePairKey;
|
|
34
|
+
const [activePortal, setActivePortal] = useState<ActivePortal | null>(null);
|
|
35
|
+
const activePairKeyRef = useRef<ScreenPairKey | null>(null);
|
|
39
36
|
|
|
40
|
-
const
|
|
41
|
-
(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
) => {
|
|
45
|
-
if (sourcePairKeyRef.current !== observedSourcePairKey) {
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
37
|
+
const updateActivePortal = useCallback((pairKey: ScreenPairKey | null) => {
|
|
38
|
+
if (activePairKeyRef.current === pairKey) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
48
41
|
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
);
|
|
42
|
+
activePairKeyRef.current = pairKey;
|
|
43
|
+
setActivePortal(pairKey ? { pairKey } : null);
|
|
44
|
+
}, []);
|
|
53
45
|
|
|
54
46
|
useAnimatedReaction(
|
|
55
47
|
() => {
|
|
56
48
|
"worklet";
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
49
|
+
const isBoundaryAnimating = slotsMap.get()[boundaryId] !== undefined;
|
|
50
|
+
if (!isBoundaryAnimating) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return getPairKeyForSource(boundaryId, currentScreenKey);
|
|
62
55
|
},
|
|
63
|
-
(
|
|
56
|
+
(pairKey, previousPairKey) => {
|
|
64
57
|
"worklet";
|
|
65
|
-
if (
|
|
58
|
+
if (pairKey === previousPairKey) {
|
|
66
59
|
return;
|
|
67
60
|
}
|
|
68
61
|
|
|
69
|
-
scheduleOnRN(
|
|
62
|
+
scheduleOnRN(updateActivePortal, pairKey);
|
|
70
63
|
},
|
|
71
64
|
);
|
|
72
65
|
|
|
73
66
|
useLayoutEffect(() => {
|
|
74
|
-
if (!
|
|
67
|
+
if (!activePortal || !escapeHostKey) {
|
|
75
68
|
portalHostName.set(null);
|
|
76
69
|
portalHostReady.set(false);
|
|
77
70
|
return;
|
|
@@ -80,14 +73,13 @@ export const useActivePortalBoundaryHost = ({
|
|
|
80
73
|
const nextPortalHostName = createBoundaryPortalHostName(
|
|
81
74
|
escapeHostKey,
|
|
82
75
|
boundaryId,
|
|
83
|
-
|
|
76
|
+
activePortal.pairKey,
|
|
84
77
|
);
|
|
85
78
|
|
|
86
79
|
mountPortalBoundaryHost({
|
|
87
80
|
boundaryId,
|
|
88
81
|
hostKey: escapeHostKey,
|
|
89
|
-
|
|
90
|
-
pairKey: sourcePairKey,
|
|
82
|
+
pairKey: activePortal.pairKey,
|
|
91
83
|
portalHostName: nextPortalHostName,
|
|
92
84
|
portalHostReady,
|
|
93
85
|
screenKey: currentScreenKey,
|
|
@@ -101,14 +93,12 @@ export const useActivePortalBoundaryHost = ({
|
|
|
101
93
|
unmountPortalBoundaryHostByName(nextPortalHostName);
|
|
102
94
|
};
|
|
103
95
|
}, [
|
|
96
|
+
activePortal,
|
|
104
97
|
boundaryId,
|
|
105
98
|
currentScreenKey,
|
|
106
99
|
escapeHostKey,
|
|
107
|
-
localStylesMaps,
|
|
108
100
|
portalHostName,
|
|
109
101
|
portalHostReady,
|
|
110
|
-
sourcePairKey,
|
|
111
102
|
slotsMap,
|
|
112
|
-
hasActiveLink,
|
|
113
103
|
]);
|
|
114
104
|
};
|
|
@@ -1,17 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type SharedValue,
|
|
3
|
-
useAnimatedProps,
|
|
4
|
-
useSharedValue,
|
|
5
|
-
} from "react-native-reanimated";
|
|
1
|
+
import { useAnimatedProps, useSharedValue } from "react-native-reanimated";
|
|
6
2
|
import { useDescriptorsStore } from "../../../../../../providers/screen/descriptors";
|
|
7
3
|
import { useScreenSlots } from "../../../../../../providers/screen/styles";
|
|
8
|
-
import { hasCloseTransitionFinished } from "../../../../../../providers/screen/styles/helpers/transition-visual-state";
|
|
9
|
-
import { AnimationStore } from "../../../../../../stores/animation.store";
|
|
10
|
-
import { pairs } from "../../../../../../stores/bounds/internals/state";
|
|
11
|
-
import { SystemStore } from "../../../../../../stores/system.store";
|
|
12
4
|
import { PORTAL_HOST_NAME_RESET_VALUE } from "../../../utils/naming";
|
|
13
5
|
import { isTeleportEnabled } from "../../../utils/teleport-control";
|
|
14
|
-
import { hasActiveBoundaryPortalLink } from "../helpers/active-pair";
|
|
15
6
|
import { useActiveHostKey } from "../stores/host-registry.store";
|
|
16
7
|
import { useActivePortalBoundaryHost } from "./use-active-portal-boundary-host";
|
|
17
8
|
|
|
@@ -19,42 +10,23 @@ interface UseBoundaryPortalAttachmentParams {
|
|
|
19
10
|
boundaryId: string;
|
|
20
11
|
}
|
|
21
12
|
|
|
22
|
-
type AttachedDestination = {
|
|
23
|
-
animationProgress: SharedValue<number>;
|
|
24
|
-
closing: SharedValue<number>;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
13
|
export const useBoundaryPortalAttachment = ({
|
|
28
14
|
boundaryId,
|
|
29
15
|
}: UseBoundaryPortalAttachmentParams) => {
|
|
30
|
-
const sourcePairKey = useDescriptorsStore((s) => s.derivations.sourcePairKey);
|
|
31
16
|
const currentScreenKey = useDescriptorsStore(
|
|
32
17
|
(s) => s.derivations.currentScreenKey,
|
|
33
18
|
);
|
|
34
|
-
const
|
|
35
|
-
const destinationScreenKey = nextScreenKey ?? currentScreenKey;
|
|
36
|
-
const destinationAnimationProgress = SystemStore.getValue(
|
|
37
|
-
destinationScreenKey,
|
|
38
|
-
"animationProgress",
|
|
39
|
-
);
|
|
40
|
-
const destinationClosing = AnimationStore.getValue(
|
|
41
|
-
destinationScreenKey,
|
|
42
|
-
"closing",
|
|
43
|
-
);
|
|
44
|
-
const { localStylesMaps, slotsMap } = useScreenSlots();
|
|
19
|
+
const { slotsMap } = useScreenSlots();
|
|
45
20
|
const portalHostName = useSharedValue<string | null>(null);
|
|
46
21
|
const portalHostReady = useSharedValue(false);
|
|
47
|
-
const attachedDestination = useSharedValue<AttachedDestination | null>(null);
|
|
48
22
|
const escapeHostKey = useActiveHostKey(currentScreenKey);
|
|
49
23
|
|
|
50
24
|
useActivePortalBoundaryHost({
|
|
51
25
|
boundaryId,
|
|
52
26
|
currentScreenKey,
|
|
53
27
|
escapeHostKey,
|
|
54
|
-
localStylesMaps,
|
|
55
28
|
portalHostName,
|
|
56
29
|
portalHostReady,
|
|
57
|
-
sourcePairKey,
|
|
58
30
|
slotsMap,
|
|
59
31
|
});
|
|
60
32
|
|
|
@@ -67,36 +39,17 @@ export const useBoundaryPortalAttachment = ({
|
|
|
67
39
|
teleport,
|
|
68
40
|
...slotProps
|
|
69
41
|
} = slot?.props ?? {};
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const hasAttachableHost =
|
|
78
|
-
shouldTeleport && hasActiveLink && portalHostReady.get() && hostName;
|
|
79
|
-
|
|
80
|
-
if (hasAttachableHost) {
|
|
81
|
-
attachedDestination.set({
|
|
82
|
-
animationProgress: destinationAnimationProgress,
|
|
83
|
-
closing: destinationClosing,
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const attached = attachedDestination.get();
|
|
88
|
-
const hasAttachedCloseFinished =
|
|
89
|
-
attached !== null &&
|
|
90
|
-
hasCloseTransitionFinished({
|
|
91
|
-
animationProgress: attached.animationProgress.get(),
|
|
92
|
-
closing: attached.closing.get(),
|
|
93
|
-
});
|
|
94
|
-
const canAttach = hasAttachableHost && !hasAttachedCloseFinished;
|
|
95
|
-
const targetHostName = canAttach ? hostName : PORTAL_HOST_NAME_RESET_VALUE;
|
|
42
|
+
const shouldAttach =
|
|
43
|
+
slot !== undefined &&
|
|
44
|
+
isTeleportEnabled(teleport) &&
|
|
45
|
+
portalHostReady.get();
|
|
46
|
+
const hostName = shouldAttach
|
|
47
|
+
? portalHostName.get()
|
|
48
|
+
: PORTAL_HOST_NAME_RESET_VALUE;
|
|
96
49
|
|
|
97
50
|
return {
|
|
98
51
|
...slotProps,
|
|
99
|
-
hostName
|
|
52
|
+
hostName,
|
|
100
53
|
};
|
|
101
54
|
});
|
|
102
55
|
|
package/src/components/boundary/portal/components/boundary-portal/hooks/use-host-measurement.ts
CHANGED
|
@@ -16,7 +16,6 @@ import { getVisibilityBlockOffset } from "../../../../../../utils/visibility-blo
|
|
|
16
16
|
import {
|
|
17
17
|
adjustedMeasuredBoundsForOverscrollDeltas,
|
|
18
18
|
correctMeasuredBoundsForVisibilityGate,
|
|
19
|
-
isMeasurementInViewport,
|
|
20
19
|
} from "../../../../utils/measured-bounds";
|
|
21
20
|
import {
|
|
22
21
|
clearPortalHostBounds,
|
|
@@ -102,13 +101,7 @@ export const useHostMeasurement = ({
|
|
|
102
101
|
viewportHeight,
|
|
103
102
|
});
|
|
104
103
|
|
|
105
|
-
if (
|
|
106
|
-
!isMeasurementInViewport(
|
|
107
|
-
correctedMeasured,
|
|
108
|
-
viewportWidth,
|
|
109
|
-
viewportHeight,
|
|
110
|
-
)
|
|
111
|
-
) {
|
|
104
|
+
if (correctedMeasured.width <= 0 || correctedMeasured.height <= 0) {
|
|
112
105
|
cancelAnimation(retryToken);
|
|
113
106
|
retryToken.set(
|
|
114
107
|
withDelay(
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { useSyncExternalStore } from "react";
|
|
2
2
|
import type { SharedValue } from "react-native-reanimated";
|
|
3
|
-
import type { LocalStyleLayers } from "../../../../../../providers/screen/styles/helpers/resolve-slot-styles";
|
|
4
3
|
import type { NormalizedTransitionInterpolatedStyle } from "../../../../../../types/animation.types";
|
|
5
4
|
|
|
6
5
|
export type ActivePortalBoundaryHost = {
|
|
7
6
|
boundaryId: string;
|
|
8
7
|
hostKey: string;
|
|
9
|
-
localStylesMaps: SharedValue<LocalStyleLayers>;
|
|
10
8
|
pairKey: string;
|
|
11
9
|
portalHostName: string;
|
|
12
10
|
portalHostReady: SharedValue<boolean>;
|
|
@@ -56,7 +54,6 @@ const isSameHost = (
|
|
|
56
54
|
return (
|
|
57
55
|
a.boundaryId === b.boundaryId &&
|
|
58
56
|
a.hostKey === b.hostKey &&
|
|
59
|
-
a.localStylesMaps === b.localStylesMaps &&
|
|
60
57
|
a.pairKey === b.pairKey &&
|
|
61
58
|
a.portalHostName === b.portalHostName &&
|
|
62
59
|
a.portalHostReady === b.portalHostReady &&
|
|
@@ -14,7 +14,7 @@ export type InitialDestinationMeasurementAction =
|
|
|
14
14
|
| "complete";
|
|
15
15
|
|
|
16
16
|
export type InitialDestinationMeasurementSignal = {
|
|
17
|
-
pairKey: ScreenPairKey;
|
|
17
|
+
pairKey: ScreenPairKey | null;
|
|
18
18
|
action: InitialDestinationMeasurementAction;
|
|
19
19
|
};
|
|
20
20
|
|
|
@@ -37,10 +37,14 @@ export const getInitialDestinationMeasurementSignal = (params: {
|
|
|
37
37
|
sourcePresent,
|
|
38
38
|
linkState,
|
|
39
39
|
} = params;
|
|
40
|
-
if (!enabled
|
|
40
|
+
if (!enabled) {
|
|
41
41
|
return null;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
if (!pairKey) {
|
|
45
|
+
return { pairKey: null, action: "wait" };
|
|
46
|
+
}
|
|
47
|
+
|
|
44
48
|
if (!destinationPresent) {
|
|
45
49
|
return { pairKey, action: "wait" };
|
|
46
50
|
}
|
|
@@ -81,18 +81,18 @@ const mergeSlots = (
|
|
|
81
81
|
return merged;
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
const composeCurrentAndNextStyles = (
|
|
85
|
+
current: NormalizedTransitionInterpolatedStyle,
|
|
86
|
+
next: NormalizedTransitionInterpolatedStyle,
|
|
87
87
|
) => {
|
|
88
88
|
"worklet";
|
|
89
|
-
const composed: NormalizedTransitionInterpolatedStyle = { ...
|
|
89
|
+
const composed: NormalizedTransitionInterpolatedStyle = { ...current };
|
|
90
90
|
|
|
91
|
-
for (const slotId in
|
|
92
|
-
const
|
|
91
|
+
for (const slotId in next) {
|
|
92
|
+
const nextSlot = next[slotId];
|
|
93
93
|
|
|
94
|
-
if (
|
|
95
|
-
composed[slotId] = mergeSlots(
|
|
94
|
+
if (nextSlot) {
|
|
95
|
+
composed[slotId] = mergeSlots(current[slotId], nextSlot);
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
|
|
@@ -103,36 +103,36 @@ export const resolveInterpolatorStyleHandoff = ({
|
|
|
103
103
|
currentOwnsInterpolator,
|
|
104
104
|
currentStylesMap,
|
|
105
105
|
nextStylesMap,
|
|
106
|
-
frozenCurrentStylesMap,
|
|
107
106
|
}: {
|
|
108
107
|
currentOwnsInterpolator: boolean;
|
|
109
108
|
currentStylesMap: NormalizedTransitionInterpolatedStyle | undefined;
|
|
110
109
|
nextStylesMap: NormalizedTransitionInterpolatedStyle | undefined;
|
|
111
|
-
frozenCurrentStylesMap: NormalizedTransitionInterpolatedStyle;
|
|
112
110
|
}): {
|
|
113
111
|
localStylesMaps: LocalStyleLayers;
|
|
114
|
-
nextFrozenCurrentStylesMap: NormalizedTransitionInterpolatedStyle;
|
|
115
112
|
} => {
|
|
116
113
|
"worklet";
|
|
117
114
|
|
|
118
115
|
if (currentOwnsInterpolator) {
|
|
119
116
|
return {
|
|
120
117
|
localStylesMaps: currentStylesMap ? [currentStylesMap] : [],
|
|
121
|
-
nextFrozenCurrentStylesMap: currentStylesMap ?? frozenCurrentStylesMap,
|
|
122
118
|
};
|
|
123
119
|
}
|
|
124
120
|
|
|
125
121
|
if (!nextStylesMap) {
|
|
126
122
|
return {
|
|
127
|
-
localStylesMaps:
|
|
128
|
-
|
|
123
|
+
localStylesMaps: currentStylesMap ? [currentStylesMap] : [],
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!currentStylesMap) {
|
|
128
|
+
return {
|
|
129
|
+
localStylesMaps: [nextStylesMap],
|
|
129
130
|
};
|
|
130
131
|
}
|
|
131
132
|
|
|
132
133
|
return {
|
|
133
134
|
localStylesMaps: [
|
|
134
|
-
|
|
135
|
+
composeCurrentAndNextStyles(currentStylesMap, nextStylesMap),
|
|
135
136
|
],
|
|
136
|
-
nextFrozenCurrentStylesMap: frozenCurrentStylesMap,
|
|
137
137
|
};
|
|
138
138
|
};
|
|
@@ -125,10 +125,10 @@ const runInterpolator = ({
|
|
|
125
125
|
* normal interpolator selection once the gesture-driven close is no longer in
|
|
126
126
|
* play.
|
|
127
127
|
*
|
|
128
|
-
* At an ownership handoff, the
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
128
|
+
* At an ownership handoff, the current interpolator remains live but is
|
|
129
|
+
* evaluated without the next-screen relationship. The next owner replaces
|
|
130
|
+
* matching scalar keys and composes its live transforms after the current
|
|
131
|
+
* screen's self-owned transforms.
|
|
132
132
|
*/
|
|
133
133
|
export const useInterpolatedStylesMap = ({
|
|
134
134
|
enabled,
|
|
@@ -177,8 +177,6 @@ export const useInterpolatedStylesMap = ({
|
|
|
177
177
|
|
|
178
178
|
const isGesturingDuringCloseAnimation = useSharedValue(false);
|
|
179
179
|
const initialDestinationStylesReady = useSharedValue(0);
|
|
180
|
-
const frozenCurrentStylesMap =
|
|
181
|
-
useSharedValue<NormalizedTransitionInterpolatedStyle>(NO_STYLES);
|
|
182
180
|
const shouldPrepareInitialDestinationStyles =
|
|
183
181
|
enabled && !!destinationPairKey && !nextScreenKey && !!currentInterpolator;
|
|
184
182
|
|
|
@@ -261,17 +259,21 @@ export const useInterpolatedStylesMap = ({
|
|
|
261
259
|
? "current"
|
|
262
260
|
: "next";
|
|
263
261
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
262
|
+
// Once the next interpolator owns the relationship, the current
|
|
263
|
+
// interpolator remains responsible only for its own live presentation.
|
|
264
|
+
// This preserves snap-point transforms without letting current-screen
|
|
265
|
+
// unfocus rules compete with the next screen's outgoing transition.
|
|
266
|
+
const currentSelectedFrame = selectInterpolatorFrame(
|
|
267
|
+
props,
|
|
268
|
+
isInGestureMode || !!nextInterpolator,
|
|
269
|
+
);
|
|
270
|
+
const currentResult = runInterpolator({
|
|
271
|
+
interpolator: currentInterpolator,
|
|
272
|
+
props,
|
|
273
|
+
selectedFrame: currentSelectedFrame,
|
|
274
|
+
bounds: boundsAccessor,
|
|
275
|
+
transition,
|
|
276
|
+
});
|
|
275
277
|
|
|
276
278
|
const initialDestinationStyleGate = resolveInitialDestinationStyleGate({
|
|
277
279
|
shouldPrepareStyles: shouldPrepareInitialDestinationStyles,
|
|
@@ -295,22 +297,18 @@ export const useInterpolatedStylesMap = ({
|
|
|
295
297
|
currentOwnsInterpolator: true,
|
|
296
298
|
currentStylesMap: currentResult?.stylesMap,
|
|
297
299
|
nextStylesMap: undefined,
|
|
298
|
-
frozenCurrentStylesMap: frozenCurrentStylesMap.get(),
|
|
299
300
|
});
|
|
300
301
|
|
|
301
|
-
if (handoff.nextFrozenCurrentStylesMap !== frozenCurrentStylesMap.get()) {
|
|
302
|
-
frozenCurrentStylesMap.set(handoff.nextFrozenCurrentStylesMap);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
302
|
return handoff.localStylesMaps.length
|
|
306
303
|
? handoff.localStylesMaps
|
|
307
304
|
: NO_STYLE_LAYERS;
|
|
308
305
|
}
|
|
309
306
|
|
|
307
|
+
const nextSelectedFrame = selectInterpolatorFrame(props, false);
|
|
310
308
|
const nextResult = runInterpolator({
|
|
311
309
|
interpolator: nextInterpolator,
|
|
312
310
|
props,
|
|
313
|
-
selectedFrame,
|
|
311
|
+
selectedFrame: nextSelectedFrame,
|
|
314
312
|
bounds: boundsAccessor,
|
|
315
313
|
transition,
|
|
316
314
|
});
|
|
@@ -326,7 +324,6 @@ export const useInterpolatedStylesMap = ({
|
|
|
326
324
|
currentOwnsInterpolator: false,
|
|
327
325
|
currentStylesMap: currentResult?.stylesMap,
|
|
328
326
|
nextStylesMap: nextResult?.stylesMap,
|
|
329
|
-
frozenCurrentStylesMap: frozenCurrentStylesMap.get(),
|
|
330
327
|
});
|
|
331
328
|
|
|
332
329
|
return handoff.localStylesMaps.length
|