react-native-screen-transitions 2.3.0 → 2.3.2
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/__configs__/index.js.map +1 -0
- package/lib/commonjs/__configs__/presets.js.map +1 -0
- package/lib/commonjs/__configs__/specs.js.map +1 -0
- package/lib/commonjs/components/controllers/screen-lifecycle.js +5 -5
- package/lib/commonjs/components/controllers/screen-lifecycle.js.map +1 -1
- package/lib/commonjs/components/create-transition-aware-component.js +13 -32
- package/lib/commonjs/components/create-transition-aware-component.js.map +1 -1
- package/lib/commonjs/components/integrations/masked-view.js +3 -4
- package/lib/commonjs/components/integrations/masked-view.js.map +1 -1
- package/lib/commonjs/components/root-transition-aware.js +3 -3
- package/lib/commonjs/components/root-transition-aware.js.map +1 -1
- package/lib/commonjs/constants.js +103 -0
- package/lib/commonjs/constants.js.map +1 -0
- package/lib/commonjs/hooks/animation/use-associated-style.js +10 -9
- package/lib/commonjs/hooks/animation/use-associated-style.js.map +1 -1
- package/lib/commonjs/hooks/animation/use-screen-animation.js +7 -20
- package/lib/commonjs/hooks/animation/use-screen-animation.js.map +1 -1
- package/lib/commonjs/hooks/bounds/use-bound-registry.js +93 -31
- package/lib/commonjs/hooks/bounds/use-bound-registry.js.map +1 -1
- package/lib/commonjs/hooks/gestures/use-build-gestures.js +9 -13
- package/lib/commonjs/hooks/gestures/use-build-gestures.js.map +1 -1
- package/lib/commonjs/index.js +3 -3
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/integrations/native-stack/utils/debounce.js.map +1 -1
- package/lib/commonjs/integrations/native-stack/utils/useAnimatedHeaderHeight.js.map +1 -1
- package/lib/commonjs/integrations/native-stack/utils/useDismissedRouteError.js.map +1 -1
- package/lib/commonjs/integrations/native-stack/views/FontProcessor.js +1 -1
- package/lib/commonjs/integrations/native-stack/views/FontProcessor.js.map +1 -1
- package/lib/commonjs/integrations/native-stack/views/FontProcessor.native.js +1 -1
- package/lib/commonjs/integrations/native-stack/views/FontProcessor.native.js.map +1 -1
- package/lib/commonjs/integrations/native-stack/views/NativeStackView.native.js +3 -15
- package/lib/commonjs/integrations/native-stack/views/NativeStackView.native.js.map +1 -1
- package/lib/commonjs/providers/gestures.js +1 -9
- package/lib/commonjs/providers/gestures.js.map +1 -1
- package/lib/commonjs/providers/screen-transition-provider.js +34 -0
- package/lib/commonjs/providers/screen-transition-provider.js.map +1 -0
- package/lib/commonjs/providers/transition-styles.js +4 -4
- package/lib/commonjs/providers/transition-styles.js.map +1 -1
- package/lib/commonjs/utils/animation/{run-transition.js → start-screen-transition.js} +9 -9
- package/lib/commonjs/utils/animation/start-screen-transition.js.map +1 -0
- package/lib/commonjs/utils/bounds/index.js +6 -18
- package/lib/commonjs/utils/bounds/index.js.map +1 -1
- package/lib/commonjs/utils/gesture/apply-offset-rules.js +12 -21
- package/lib/commonjs/utils/gesture/apply-offset-rules.js.map +1 -1
- package/lib/module/__configs__/index.js.map +1 -0
- package/lib/module/__configs__/presets.js.map +1 -0
- package/lib/module/__configs__/specs.js.map +1 -0
- package/lib/module/components/controllers/screen-lifecycle.js +5 -5
- package/lib/module/components/controllers/screen-lifecycle.js.map +1 -1
- package/lib/module/components/create-transition-aware-component.js +13 -32
- package/lib/module/components/create-transition-aware-component.js.map +1 -1
- package/lib/module/components/integrations/masked-view.js +1 -2
- package/lib/module/components/integrations/masked-view.js.map +1 -1
- package/lib/module/components/root-transition-aware.js +3 -3
- package/lib/module/components/root-transition-aware.js.map +1 -1
- package/lib/module/constants.js +98 -0
- package/lib/module/constants.js.map +1 -0
- package/lib/module/hooks/animation/use-associated-style.js +10 -9
- package/lib/module/hooks/animation/use-associated-style.js.map +1 -1
- package/lib/module/hooks/animation/use-screen-animation.js +7 -20
- package/lib/module/hooks/animation/use-screen-animation.js.map +1 -1
- package/lib/module/hooks/bounds/use-bound-registry.js +94 -33
- package/lib/module/hooks/bounds/use-bound-registry.js.map +1 -1
- package/lib/module/hooks/gestures/use-build-gestures.js +4 -8
- package/lib/module/hooks/gestures/use-build-gestures.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/integrations/native-stack/utils/debounce.js.map +1 -1
- package/lib/module/integrations/native-stack/utils/useAnimatedHeaderHeight.js +1 -1
- package/lib/module/integrations/native-stack/utils/useAnimatedHeaderHeight.js.map +1 -1
- package/lib/module/integrations/native-stack/utils/useDismissedRouteError.js +1 -1
- package/lib/module/integrations/native-stack/utils/useDismissedRouteError.js.map +1 -1
- package/lib/module/integrations/native-stack/views/FontProcessor.js +1 -1
- package/lib/module/integrations/native-stack/views/FontProcessor.js.map +1 -1
- package/lib/module/integrations/native-stack/views/FontProcessor.native.js +2 -2
- package/lib/module/integrations/native-stack/views/FontProcessor.native.js.map +1 -1
- package/lib/module/integrations/native-stack/views/NativeStackView.native.js +3 -15
- package/lib/module/integrations/native-stack/views/NativeStackView.native.js.map +1 -1
- package/lib/module/providers/gestures.js +0 -8
- package/lib/module/providers/gestures.js.map +1 -1
- package/lib/module/providers/screen-transition-provider.js +30 -0
- package/lib/module/providers/screen-transition-provider.js.map +1 -0
- package/lib/module/providers/transition-styles.js +4 -4
- package/lib/module/providers/transition-styles.js.map +1 -1
- package/lib/module/utils/animation/{run-transition.js → start-screen-transition.js} +7 -7
- package/lib/module/utils/animation/start-screen-transition.js.map +1 -0
- package/lib/module/utils/bounds/index.js +5 -17
- package/lib/module/utils/bounds/index.js.map +1 -1
- package/lib/module/utils/gesture/apply-offset-rules.js +1 -10
- package/lib/module/utils/gesture/apply-offset-rules.js.map +1 -1
- package/lib/typescript/__configs__/index.d.ts.map +1 -0
- package/lib/typescript/__configs__/presets.d.ts.map +1 -0
- package/lib/typescript/__configs__/specs.d.ts.map +1 -0
- package/lib/typescript/components/create-transition-aware-component.d.ts +20 -2
- package/lib/typescript/components/create-transition-aware-component.d.ts.map +1 -1
- package/lib/typescript/components/integrations/masked-view.d.ts.map +1 -1
- package/lib/typescript/components/root-transition-aware.d.ts.map +1 -1
- package/lib/typescript/constants.d.ts +57 -0
- package/lib/typescript/constants.d.ts.map +1 -0
- package/lib/typescript/hooks/animation/use-associated-style.d.ts +1 -1
- package/lib/typescript/hooks/animation/use-associated-style.d.ts.map +1 -1
- package/lib/typescript/hooks/animation/use-screen-animation.d.ts.map +1 -1
- package/lib/typescript/hooks/bounds/use-bound-registry.d.ts +12 -9
- package/lib/typescript/hooks/bounds/use-bound-registry.d.ts.map +1 -1
- package/lib/typescript/hooks/gestures/use-build-gestures.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +2 -6
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/integrations/native-stack/utils/debounce.d.ts.map +1 -1
- package/lib/typescript/integrations/native-stack/utils/useAnimatedHeaderHeight.d.ts +2 -2
- package/lib/typescript/integrations/native-stack/utils/useDismissedRouteError.d.ts +2 -2
- package/lib/typescript/integrations/native-stack/utils/useDismissedRouteError.d.ts.map +1 -1
- package/lib/typescript/integrations/native-stack/views/FontProcessor.d.ts.map +1 -1
- package/lib/typescript/integrations/native-stack/views/FontProcessor.native.d.ts.map +1 -1
- package/lib/typescript/integrations/native-stack/views/NativeStackView.native.d.ts.map +1 -1
- package/lib/typescript/providers/gestures.d.ts +0 -1
- package/lib/typescript/providers/gestures.d.ts.map +1 -1
- package/lib/typescript/providers/screen-transition-provider.d.ts +11 -0
- package/lib/typescript/providers/screen-transition-provider.d.ts.map +1 -0
- package/lib/typescript/providers/transition-styles.d.ts.map +1 -1
- package/lib/typescript/types/core.d.ts +0 -8
- package/lib/typescript/types/core.d.ts.map +1 -1
- package/lib/typescript/utils/animation/start-screen-transition.d.ts +12 -0
- package/lib/typescript/utils/animation/start-screen-transition.d.ts.map +1 -0
- package/lib/typescript/utils/bounds/_types/get-bounds.d.ts +2 -2
- package/lib/typescript/utils/bounds/_types/get-bounds.d.ts.map +1 -1
- package/lib/typescript/utils/bounds/index.d.ts.map +1 -1
- package/lib/typescript/utils/gesture/apply-offset-rules.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/controllers/screen-lifecycle.tsx +5 -5
- package/src/components/create-transition-aware-component.tsx +23 -38
- package/src/components/integrations/masked-view.tsx +1 -3
- package/src/components/root-transition-aware.tsx +4 -8
- package/src/constants.ts +106 -0
- package/src/hooks/animation/use-associated-style.tsx +14 -10
- package/src/hooks/animation/use-screen-animation.tsx +17 -24
- package/src/hooks/bounds/use-bound-registry.tsx +113 -25
- package/src/hooks/gestures/use-build-gestures.tsx +11 -10
- package/src/index.ts +1 -1
- package/src/integrations/native-stack/utils/debounce.tsx +9 -9
- package/src/integrations/native-stack/utils/useAnimatedHeaderHeight.tsx +10 -10
- package/src/integrations/native-stack/utils/useDismissedRouteError.tsx +21 -21
- package/src/integrations/native-stack/views/FontProcessor.native.tsx +7 -7
- package/src/integrations/native-stack/views/FontProcessor.tsx +2 -2
- package/src/integrations/native-stack/views/NativeStackView.native.tsx +4 -14
- package/src/providers/gestures.tsx +0 -9
- package/src/providers/screen-transition-provider.tsx +33 -0
- package/src/providers/transition-styles.tsx +6 -5
- package/src/types/core.ts +0 -9
- package/src/utils/animation/{run-transition.ts → start-screen-transition.ts} +9 -9
- package/src/utils/bounds/_types/get-bounds.ts +7 -7
- package/src/utils/bounds/index.ts +12 -19
- package/src/utils/gesture/apply-offset-rules.ts +9 -11
- package/lib/commonjs/components/bound-capture.js +0 -38
- package/lib/commonjs/components/bound-capture.js.map +0 -1
- package/lib/commonjs/configs/index.js.map +0 -1
- package/lib/commonjs/configs/presets.js.map +0 -1
- package/lib/commonjs/configs/specs.js.map +0 -1
- package/lib/commonjs/utils/animation/run-transition.js.map +0 -1
- package/lib/module/components/bound-capture.js +0 -33
- package/lib/module/components/bound-capture.js.map +0 -1
- package/lib/module/configs/index.js.map +0 -1
- package/lib/module/configs/presets.js.map +0 -1
- package/lib/module/configs/specs.js.map +0 -1
- package/lib/module/utils/animation/run-transition.js.map +0 -1
- package/lib/typescript/components/bound-capture.d.ts +0 -8
- package/lib/typescript/components/bound-capture.d.ts.map +0 -1
- package/lib/typescript/configs/index.d.ts.map +0 -1
- package/lib/typescript/configs/presets.d.ts.map +0 -1
- package/lib/typescript/configs/specs.d.ts.map +0 -1
- package/lib/typescript/utils/animation/run-transition.d.ts +0 -12
- package/lib/typescript/utils/animation/run-transition.d.ts.map +0 -1
- package/src/components/bound-capture.tsx +0 -32
- /package/lib/commonjs/{configs → __configs__}/index.js +0 -0
- /package/lib/commonjs/{configs → __configs__}/presets.js +0 -0
- /package/lib/commonjs/{configs → __configs__}/specs.js +0 -0
- /package/lib/module/{configs → __configs__}/index.js +0 -0
- /package/lib/module/{configs → __configs__}/presets.js +0 -0
- /package/lib/module/{configs → __configs__}/specs.js +0 -0
- /package/lib/typescript/{configs → __configs__}/index.d.ts +0 -0
- /package/lib/typescript/{configs → __configs__}/presets.d.ts +0 -0
- /package/lib/typescript/{configs → __configs__}/specs.d.ts +0 -0
- /package/src/{configs → __configs__}/index.ts +0 -0
- /package/src/{configs → __configs__}/presets.ts +0 -0
- /package/src/{configs → __configs__}/specs.ts +0 -0
|
@@ -3,6 +3,10 @@ import { useMemo } from "react";
|
|
|
3
3
|
import { useWindowDimensions } from "react-native";
|
|
4
4
|
import { type SharedValue, useDerivedValue } from "react-native-reanimated";
|
|
5
5
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
6
|
+
import {
|
|
7
|
+
DEFAULT_SCREEN_TRANSITION_STATE,
|
|
8
|
+
NO_BOUNDS_MAP,
|
|
9
|
+
} from "../../constants";
|
|
6
10
|
import { useKeys } from "../../providers/keys";
|
|
7
11
|
import { Animations } from "../../stores/animations";
|
|
8
12
|
import { Bounds } from "../../stores/bounds";
|
|
@@ -11,7 +15,7 @@ import type {
|
|
|
11
15
|
ScreenInterpolationProps,
|
|
12
16
|
ScreenTransitionState,
|
|
13
17
|
} from "../../types/animation";
|
|
14
|
-
|
|
18
|
+
|
|
15
19
|
import type { NativeStackDescriptor } from "../../types/navigator";
|
|
16
20
|
import { derivations } from "../../utils/animation/derivations";
|
|
17
21
|
|
|
@@ -23,24 +27,6 @@ type BuiltState = {
|
|
|
23
27
|
route: RouteProp<ParamListBase>;
|
|
24
28
|
};
|
|
25
29
|
|
|
26
|
-
const EMPTY_BOUNDS = Object.freeze({}) as Record<string, BoundEntry>;
|
|
27
|
-
|
|
28
|
-
const FALLBACK: ScreenTransitionState = Object.freeze({
|
|
29
|
-
progress: 0,
|
|
30
|
-
closing: 0,
|
|
31
|
-
animating: 0,
|
|
32
|
-
gesture: {
|
|
33
|
-
x: 0,
|
|
34
|
-
y: 0,
|
|
35
|
-
normalizedX: 0,
|
|
36
|
-
normalizedY: 0,
|
|
37
|
-
isDismissing: 0,
|
|
38
|
-
isDragging: 0,
|
|
39
|
-
},
|
|
40
|
-
bounds: {} as Record<string, BoundEntry>,
|
|
41
|
-
route: {} as RouteProp<ParamListBase>,
|
|
42
|
-
});
|
|
43
|
-
|
|
44
30
|
const unwrap = (
|
|
45
31
|
s: BuiltState | undefined,
|
|
46
32
|
key: string | undefined,
|
|
@@ -60,7 +46,7 @@ const unwrap = (
|
|
|
60
46
|
isDismissing: s.gesture.isDismissing.value,
|
|
61
47
|
isDragging: s.gesture.isDragging.value,
|
|
62
48
|
},
|
|
63
|
-
bounds: Bounds.getBounds(key) ||
|
|
49
|
+
bounds: Bounds.getBounds(key) || NO_BOUNDS_MAP,
|
|
64
50
|
route: s.route,
|
|
65
51
|
};
|
|
66
52
|
};
|
|
@@ -102,9 +88,14 @@ export function _useScreenAnimation() {
|
|
|
102
88
|
"worklet";
|
|
103
89
|
|
|
104
90
|
const previous = unwrap(prevAnimation, previousDescriptor?.route.key);
|
|
105
|
-
|
|
91
|
+
|
|
92
|
+
const next = nextDescriptor?.options?.enableTransitions
|
|
93
|
+
? unwrap(nextAnimation, nextDescriptor?.route.key)
|
|
94
|
+
: undefined;
|
|
95
|
+
|
|
106
96
|
const current =
|
|
107
|
-
unwrap(currentAnimation, currentDescriptor?.route.key) ??
|
|
97
|
+
unwrap(currentAnimation, currentDescriptor?.route.key) ??
|
|
98
|
+
DEFAULT_SCREEN_TRANSITION_STATE;
|
|
108
99
|
|
|
109
100
|
const {
|
|
110
101
|
progress,
|
|
@@ -138,10 +129,12 @@ export function _useScreenAnimation() {
|
|
|
138
129
|
},
|
|
139
130
|
);
|
|
140
131
|
|
|
141
|
-
const
|
|
142
|
-
|
|
132
|
+
const nextInterpolator = nextDescriptor?.options.screenStyleInterpolator;
|
|
133
|
+
const currentInterpolator =
|
|
143
134
|
currentDescriptor?.options.screenStyleInterpolator;
|
|
144
135
|
|
|
136
|
+
const screenStyleInterpolator = nextInterpolator ?? currentInterpolator;
|
|
137
|
+
|
|
145
138
|
return { screenInterpolatorProps, screenStyleInterpolator };
|
|
146
139
|
}
|
|
147
140
|
|
|
@@ -1,72 +1,160 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
Fragment,
|
|
4
|
+
useCallback,
|
|
5
|
+
useContext,
|
|
6
|
+
useMemo,
|
|
7
|
+
} from "react";
|
|
2
8
|
import type { View } from "react-native";
|
|
3
9
|
import {
|
|
4
10
|
type AnimatedRef,
|
|
5
11
|
measure,
|
|
12
|
+
runOnJS,
|
|
13
|
+
runOnUI,
|
|
6
14
|
type StyleProps,
|
|
15
|
+
useAnimatedReaction,
|
|
7
16
|
useSharedValue,
|
|
8
17
|
} from "react-native-reanimated";
|
|
18
|
+
import type { SharedValue } from "react-native-reanimated/lib/typescript/commonTypes";
|
|
9
19
|
import { useKeys } from "../../providers/keys";
|
|
10
20
|
import { Bounds } from "../../stores/bounds";
|
|
11
21
|
import { flattenStyle } from "../../utils/bounds/_utils/flatten-styles";
|
|
12
22
|
import { isBoundsEqual } from "../../utils/bounds/_utils/is-bounds-equal";
|
|
23
|
+
import useStableCallback from "../use-stable-callback";
|
|
13
24
|
|
|
14
25
|
interface BoundMeasurerHookProps {
|
|
15
|
-
sharedBoundTag
|
|
26
|
+
sharedBoundTag?: string;
|
|
16
27
|
animatedRef: AnimatedRef<View>;
|
|
17
|
-
|
|
28
|
+
|
|
18
29
|
style: StyleProps;
|
|
30
|
+
onPress?: ((...args: unknown[]) => void) | undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface MeasurementUpdateContextType {
|
|
34
|
+
updateSignal: SharedValue<number>;
|
|
19
35
|
}
|
|
20
36
|
|
|
37
|
+
const MeasurementUpdateContext =
|
|
38
|
+
createContext<MeasurementUpdateContextType | null>(null);
|
|
39
|
+
|
|
21
40
|
export const useBoundsRegistry = ({
|
|
22
41
|
sharedBoundTag,
|
|
23
42
|
animatedRef,
|
|
24
|
-
current,
|
|
25
43
|
style,
|
|
44
|
+
onPress,
|
|
26
45
|
}: BoundMeasurerHookProps) => {
|
|
27
|
-
const { previous } = useKeys();
|
|
46
|
+
const { previous, current } = useKeys();
|
|
28
47
|
|
|
29
|
-
const
|
|
48
|
+
const ROOT_MEASUREMENT_SIGNAL = useContext(MeasurementUpdateContext);
|
|
49
|
+
const ROOT_SIGNAL = useSharedValue(0);
|
|
50
|
+
const IS_ROOT = !ROOT_MEASUREMENT_SIGNAL;
|
|
51
|
+
const hasMeasured = useSharedValue(false);
|
|
30
52
|
|
|
31
|
-
const
|
|
53
|
+
const emitUpdate = useCallback(() => {
|
|
32
54
|
"worklet";
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
|
|
55
|
+
if (IS_ROOT) ROOT_SIGNAL.value = ROOT_SIGNAL.value + 1;
|
|
56
|
+
}, [IS_ROOT, ROOT_SIGNAL]);
|
|
57
|
+
|
|
58
|
+
const maybeMeasureAndStore = useCallback(
|
|
59
|
+
({
|
|
60
|
+
onPress,
|
|
61
|
+
skipMarkingActive,
|
|
62
|
+
}: {
|
|
63
|
+
onPress?: () => void;
|
|
64
|
+
skipMarkingActive?: boolean;
|
|
65
|
+
}) => {
|
|
66
|
+
"worklet";
|
|
67
|
+
if (!sharedBoundTag) return;
|
|
68
|
+
|
|
69
|
+
const measured = measure(animatedRef);
|
|
70
|
+
|
|
71
|
+
if (!measured) {
|
|
72
|
+
console.warn(
|
|
73
|
+
`[react-native-screen-transitions] measure() returned null for sharedBoundTag="${sharedBoundTag}"`,
|
|
74
|
+
);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
36
78
|
const key = current.route.key;
|
|
79
|
+
|
|
37
80
|
if (isBoundsEqual({ measured, key, sharedBoundTag })) {
|
|
38
|
-
|
|
81
|
+
emitUpdate();
|
|
82
|
+
if (!skipMarkingActive) {
|
|
39
83
|
Bounds.setRouteActive(key, sharedBoundTag);
|
|
40
84
|
}
|
|
85
|
+
if (onPress) runOnJS(onPress)();
|
|
41
86
|
return;
|
|
42
87
|
}
|
|
43
88
|
|
|
89
|
+
emitUpdate();
|
|
90
|
+
|
|
44
91
|
Bounds.setBounds(key, sharedBoundTag, measured, flattenStyle(style));
|
|
45
|
-
if (
|
|
92
|
+
if (!skipMarkingActive) {
|
|
46
93
|
Bounds.setRouteActive(key, sharedBoundTag);
|
|
47
94
|
}
|
|
48
|
-
}
|
|
49
|
-
}, [sharedBoundTag, animatedRef, current.route.key, style]);
|
|
50
95
|
|
|
51
|
-
|
|
96
|
+
if (onPress) runOnJS(onPress)();
|
|
97
|
+
},
|
|
98
|
+
[sharedBoundTag, animatedRef, current.route.key, style, emitUpdate],
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const handleTransitionLayout = useCallback(() => {
|
|
52
102
|
"worklet";
|
|
53
|
-
const previousRouteKey = previous?.route.key;
|
|
54
103
|
|
|
55
|
-
|
|
104
|
+
const prevKey = previous?.route.key;
|
|
105
|
+
if (!sharedBoundTag || hasMeasured.value || !prevKey) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const prevBounds = Bounds.getBounds(prevKey)?.[sharedBoundTag];
|
|
110
|
+
|
|
111
|
+
if (prevBounds) {
|
|
112
|
+
// Should skip mark active if we are in a transition
|
|
113
|
+
maybeMeasureAndStore({ skipMarkingActive: true });
|
|
114
|
+
// Should not measure again while in transition
|
|
115
|
+
hasMeasured.value = true;
|
|
116
|
+
}
|
|
117
|
+
}, [maybeMeasureAndStore, sharedBoundTag, previous?.route.key, hasMeasured]);
|
|
118
|
+
|
|
119
|
+
const captureActiveOnPress = useStableCallback(() => {
|
|
120
|
+
if (!sharedBoundTag) {
|
|
121
|
+
if (onPress) onPress();
|
|
56
122
|
return;
|
|
57
123
|
}
|
|
58
124
|
|
|
59
|
-
|
|
60
|
-
|
|
125
|
+
// In this case, we DO want to mark active
|
|
126
|
+
runOnUI(maybeMeasureAndStore)({ onPress });
|
|
127
|
+
});
|
|
61
128
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
129
|
+
const MeasurementSyncProvider = useMemo(() => {
|
|
130
|
+
if (!IS_ROOT || !sharedBoundTag) {
|
|
131
|
+
return Fragment;
|
|
65
132
|
}
|
|
66
|
-
|
|
133
|
+
|
|
134
|
+
return ({ children }: { children: React.ReactNode }) => (
|
|
135
|
+
<MeasurementUpdateContext.Provider value={{ updateSignal: ROOT_SIGNAL }}>
|
|
136
|
+
{children}
|
|
137
|
+
</MeasurementUpdateContext.Provider>
|
|
138
|
+
);
|
|
139
|
+
}, [IS_ROOT, sharedBoundTag, ROOT_SIGNAL]);
|
|
140
|
+
|
|
141
|
+
useAnimatedReaction(
|
|
142
|
+
() => ROOT_MEASUREMENT_SIGNAL?.updateSignal.value,
|
|
143
|
+
(current) => {
|
|
144
|
+
"worklet";
|
|
145
|
+
|
|
146
|
+
// We don't want to run on the initial amount)
|
|
147
|
+
if (current === 0 || current === undefined) return;
|
|
148
|
+
|
|
149
|
+
// Children should not have the ability to mark active
|
|
150
|
+
maybeMeasureAndStore({ skipMarkingActive: true });
|
|
151
|
+
},
|
|
152
|
+
);
|
|
67
153
|
|
|
68
154
|
return {
|
|
69
|
-
|
|
70
|
-
|
|
155
|
+
maybeMeasureAndStore,
|
|
156
|
+
handleTransitionLayout,
|
|
157
|
+
captureActiveOnPress,
|
|
158
|
+
MeasurementSyncProvider,
|
|
71
159
|
};
|
|
72
160
|
};
|
|
@@ -14,25 +14,26 @@ import {
|
|
|
14
14
|
type SharedValue,
|
|
15
15
|
useSharedValue,
|
|
16
16
|
} from "react-native-reanimated";
|
|
17
|
+
import {
|
|
18
|
+
DEFAULT_GESTURE_ACTIVATION_AREA,
|
|
19
|
+
DEFAULT_GESTURE_DIRECTION,
|
|
20
|
+
DEFAULT_GESTURE_DRIVES_PROGRESS,
|
|
21
|
+
DEFAULT_GESTURE_ENABLED,
|
|
22
|
+
GESTURE_VELOCITY_IMPACT,
|
|
23
|
+
} from "../../constants";
|
|
17
24
|
import type { ScrollConfig } from "../../providers/gestures";
|
|
18
25
|
import { useKeys } from "../../providers/keys";
|
|
19
26
|
import { Animations } from "../../stores/animations";
|
|
20
27
|
import { Gestures } from "../../stores/gestures";
|
|
21
28
|
import { NavigatorDismissState } from "../../stores/navigator-dismiss-state";
|
|
22
|
-
import {
|
|
29
|
+
import { GestureOffsetState } from "../../types/gesture";
|
|
23
30
|
import { animate } from "../../utils/animation/animate";
|
|
24
|
-
import {
|
|
31
|
+
import { startScreenTransition } from "../../utils/animation/start-screen-transition";
|
|
25
32
|
import { applyOffsetRules } from "../../utils/gesture/check-gesture-activation";
|
|
26
33
|
import { determineDismissal } from "../../utils/gesture/determine-dismissal";
|
|
27
34
|
import { mapGestureToProgress } from "../../utils/gesture/map-gesture-to-progress";
|
|
28
35
|
import useStableCallback from "../use-stable-callback";
|
|
29
36
|
|
|
30
|
-
const GESTURE_VELOCITY_IMPACT = 0.3;
|
|
31
|
-
const DEFAULT_GESTURE_DIRECTION = "horizontal";
|
|
32
|
-
const DEFAULT_GESTURE_ENABLED = false;
|
|
33
|
-
const DEFAULT_GESTURE_DRIVES_PROGRESS = true;
|
|
34
|
-
const DEFAULT_GESTURE_ACTIVATION_AREA: ActivationArea = "screen";
|
|
35
|
-
|
|
36
37
|
interface BuildGesturesHookProps {
|
|
37
38
|
scrollConfig: SharedValue<ScrollConfig | null>;
|
|
38
39
|
}
|
|
@@ -293,9 +294,9 @@ export const useBuildGestures = ({
|
|
|
293
294
|
runOnJS(setNavigatorDismissal)();
|
|
294
295
|
}
|
|
295
296
|
|
|
296
|
-
|
|
297
|
+
startScreenTransition({
|
|
297
298
|
target: shouldDismiss ? "close" : "open",
|
|
298
|
-
|
|
299
|
+
onAnimationFinish: shouldDismiss ? handleDismiss : undefined,
|
|
299
300
|
spec: transitionSpec,
|
|
300
301
|
velocity,
|
|
301
302
|
animations,
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FlatList, Pressable, ScrollView, View } from "react-native";
|
|
2
|
+
import { presets, specs } from "./__configs__";
|
|
2
3
|
import { createTransitionAwareComponent } from "./components/create-transition-aware-component";
|
|
3
4
|
import MaskedView from "./components/integrations/masked-view";
|
|
4
|
-
import { presets, specs } from "./configs";
|
|
5
5
|
|
|
6
6
|
export default {
|
|
7
7
|
View: createTransitionAwareComponent(View),
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export function debounce<T extends (...args: any[]) => void>(
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
func: T,
|
|
3
|
+
duration: number,
|
|
4
4
|
): T {
|
|
5
|
-
|
|
5
|
+
let timeout: ReturnType<typeof setTimeout>;
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
return function (this: unknown, ...args) {
|
|
8
|
+
clearTimeout(timeout);
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
timeout = setTimeout(() => {
|
|
11
|
+
func.apply(this, args);
|
|
12
|
+
}, duration);
|
|
13
|
+
} as T;
|
|
14
14
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import * as React from
|
|
2
|
-
import type { Animated } from
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { Animated } from "react-native";
|
|
3
3
|
|
|
4
4
|
export const AnimatedHeaderHeightContext = React.createContext<
|
|
5
|
-
|
|
5
|
+
Animated.AnimatedInterpolation<number> | undefined
|
|
6
6
|
>(undefined);
|
|
7
7
|
|
|
8
8
|
export function useAnimatedHeaderHeight() {
|
|
9
|
-
|
|
9
|
+
const animatedValue = React.useContext(AnimatedHeaderHeightContext);
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
if (animatedValue === undefined) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
"Couldn't find the header height. Are you inside a screen in a native stack navigator?",
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
return animatedValue;
|
|
18
18
|
}
|
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
} from
|
|
5
|
-
import * as React from
|
|
2
|
+
ParamListBase,
|
|
3
|
+
StackNavigationState,
|
|
4
|
+
} from "@react-navigation/native";
|
|
5
|
+
import * as React from "react";
|
|
6
6
|
|
|
7
7
|
export function useDismissedRouteError(
|
|
8
|
-
|
|
8
|
+
state: StackNavigationState<ParamListBase>,
|
|
9
9
|
) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
const [nextDismissedKey, setNextDismissedKey] = React.useState<string | null>(
|
|
11
|
+
null,
|
|
12
|
+
);
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
const dismissedRouteName = nextDismissedKey
|
|
15
|
+
? state.routes.find((route) => route.key === nextDismissedKey)?.name
|
|
16
|
+
: null;
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
React.useEffect(() => {
|
|
19
|
+
if (dismissedRouteName) {
|
|
20
|
+
const message =
|
|
21
|
+
`The screen '${dismissedRouteName}' was removed natively but didn't get removed from JS state. ` +
|
|
22
|
+
`This can happen if the action was prevented in a 'beforeRemove' listener, which is not fully supported in native-stack.\n\n` +
|
|
23
|
+
`Consider using a 'usePreventRemove' hook with 'headerBackButtonMenuEnabled: false' to prevent users from natively going back multiple screens.`;
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
console.error(message);
|
|
26
|
+
}
|
|
27
|
+
}, [dismissedRouteName]);
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
return { setNextDismissedKey };
|
|
30
30
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// @ts-expect-error importing private module
|
|
2
|
-
import ReactNativeStyleAttributes from
|
|
2
|
+
import ReactNativeStyleAttributes from "react-native/Libraries/Components/View/ReactNativeStyleAttributes";
|
|
3
3
|
|
|
4
4
|
export function processFonts(
|
|
5
|
-
|
|
5
|
+
fontFamilies: (string | undefined)[],
|
|
6
6
|
): (string | undefined)[] {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
const fontFamilyProcessor = ReactNativeStyleAttributes.fontFamily?.process;
|
|
8
|
+
if (typeof fontFamilyProcessor === "function") {
|
|
9
|
+
return fontFamilies.map(fontFamilyProcessor);
|
|
10
|
+
}
|
|
11
|
+
return fontFamilies;
|
|
12
12
|
}
|
|
@@ -32,11 +32,7 @@ import {
|
|
|
32
32
|
ScreenStack,
|
|
33
33
|
ScreenStackItem,
|
|
34
34
|
} from "react-native-screens";
|
|
35
|
-
import {
|
|
36
|
-
import { RootTransitionAware } from "../../../components/root-transition-aware";
|
|
37
|
-
import { ScreenGestureProvider } from "../../../providers/gestures";
|
|
38
|
-
import { KeysProvider } from "../../../providers/keys";
|
|
39
|
-
import { TransitionStylesProvider } from "../../../providers/transition-styles";
|
|
35
|
+
import { ScreenTransitionProvider } from "../../../providers/screen-transition-provider";
|
|
40
36
|
import type {
|
|
41
37
|
NativeStackDescriptor,
|
|
42
38
|
NativeStackDescriptorMap,
|
|
@@ -469,19 +465,13 @@ const SceneView = ({
|
|
|
469
465
|
value={isParentHeaderShown || headerShown !== false}
|
|
470
466
|
>
|
|
471
467
|
<HeaderBackContext.Provider value={headerBack}>
|
|
472
|
-
<
|
|
468
|
+
<ScreenTransitionProvider
|
|
473
469
|
previous={previousDescriptor}
|
|
474
470
|
current={descriptor}
|
|
475
471
|
next={nextDescriptor}
|
|
476
472
|
>
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
<TransitionStylesProvider>
|
|
480
|
-
<RootTransitionAware>{render()}</RootTransitionAware>
|
|
481
|
-
</TransitionStylesProvider>
|
|
482
|
-
</ScreenLifecycleController>
|
|
483
|
-
</ScreenGestureProvider>
|
|
484
|
-
</KeysProvider>
|
|
473
|
+
{render()}
|
|
474
|
+
</ScreenTransitionProvider>
|
|
485
475
|
</HeaderBackContext.Provider>
|
|
486
476
|
</HeaderShownContext.Provider>
|
|
487
477
|
</HeaderHeightContext.Provider>
|
|
@@ -26,15 +26,6 @@ type ScreenGestureProviderProps = {
|
|
|
26
26
|
children: React.ReactNode;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
export const DEFAULT_SCROLL_CONFIG: ScrollConfig = {
|
|
30
|
-
x: 0,
|
|
31
|
-
y: 0,
|
|
32
|
-
contentHeight: 0,
|
|
33
|
-
contentWidth: 0,
|
|
34
|
-
layoutHeight: 0,
|
|
35
|
-
layoutWidth: 0,
|
|
36
|
-
};
|
|
37
|
-
|
|
38
29
|
const GestureContext = createContext<GestureContextType | undefined>(undefined);
|
|
39
30
|
|
|
40
31
|
export const ScreenGestureProvider = ({
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
import { ScreenLifecycleController } from "../components/controllers/screen-lifecycle";
|
|
3
|
+
import { RootTransitionAware } from "../components/root-transition-aware";
|
|
4
|
+
import { ScreenGestureProvider } from "../providers/gestures";
|
|
5
|
+
import { KeysProvider } from "../providers/keys";
|
|
6
|
+
import { TransitionStylesProvider } from "../providers/transition-styles";
|
|
7
|
+
import type { NativeStackDescriptor } from "../types/navigator";
|
|
8
|
+
|
|
9
|
+
type Props = {
|
|
10
|
+
previous?: NativeStackDescriptor;
|
|
11
|
+
current: NativeStackDescriptor;
|
|
12
|
+
next?: NativeStackDescriptor;
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export function ScreenTransitionProvider({
|
|
17
|
+
previous,
|
|
18
|
+
current,
|
|
19
|
+
next,
|
|
20
|
+
children,
|
|
21
|
+
}: Props) {
|
|
22
|
+
return (
|
|
23
|
+
<KeysProvider previous={previous} current={current} next={next}>
|
|
24
|
+
<ScreenGestureProvider>
|
|
25
|
+
<ScreenLifecycleController>
|
|
26
|
+
<TransitionStylesProvider>
|
|
27
|
+
<RootTransitionAware>{children}</RootTransitionAware>
|
|
28
|
+
</TransitionStylesProvider>
|
|
29
|
+
</ScreenLifecycleController>
|
|
30
|
+
</ScreenGestureProvider>
|
|
31
|
+
</KeysProvider>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createContext, useContext, useMemo } from "react";
|
|
2
2
|
import { isWorkletFunction, useDerivedValue } from "react-native-reanimated";
|
|
3
|
+
import { NO_STYLES } from "../constants";
|
|
3
4
|
import { _useScreenAnimation } from "../hooks/animation/use-screen-animation";
|
|
4
5
|
import type { TransitionInterpolatedStyle } from "../types/animation";
|
|
5
6
|
|
|
@@ -7,8 +8,6 @@ type Props = {
|
|
|
7
8
|
children: React.ReactNode;
|
|
8
9
|
};
|
|
9
10
|
|
|
10
|
-
const EMPTY_MAP = Object.freeze({});
|
|
11
|
-
|
|
12
11
|
const TransitionStylesContext = createContext<ReturnType<
|
|
13
12
|
typeof useMemo<{
|
|
14
13
|
stylesMap: ReturnType<typeof useDerivedValue<TransitionInterpolatedStyle>>;
|
|
@@ -25,13 +24,15 @@ export function TransitionStylesProvider({ children }: Props) {
|
|
|
25
24
|
"worklet";
|
|
26
25
|
|
|
27
26
|
if (screenStyleInterpolator && !isFunctionWorklet && __DEV__) {
|
|
28
|
-
console.warn(
|
|
29
|
-
|
|
27
|
+
console.warn(
|
|
28
|
+
`[react-native-screen-transitions] screenStyleInterpolator is not a worklet function`,
|
|
29
|
+
);
|
|
30
|
+
return NO_STYLES;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
return screenStyleInterpolator
|
|
33
34
|
? screenStyleInterpolator(screenInterpolatorProps.value)
|
|
34
|
-
:
|
|
35
|
+
: NO_STYLES;
|
|
35
36
|
});
|
|
36
37
|
|
|
37
38
|
const value = useMemo(() => {
|
package/src/types/core.ts
CHANGED
|
@@ -42,15 +42,6 @@ export type TransitionAwareProps<T extends object> = AnimatedProps<T> & {
|
|
|
42
42
|
* </Transition.View>
|
|
43
43
|
*/
|
|
44
44
|
sharedBoundTag?: string;
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Eagerly measure this component on layout and store the result in the
|
|
48
|
-
* Bounds registry. Useful for nested shared elements that may not receive
|
|
49
|
-
* the press event but still need up-to-date measurements at navigation time.
|
|
50
|
-
*
|
|
51
|
-
* Only has an effect when used together with `sharedBoundTag`.
|
|
52
|
-
*/
|
|
53
|
-
measureOnLayout?: boolean;
|
|
54
45
|
};
|
|
55
46
|
|
|
56
47
|
export type TransitionConfig = {
|
|
@@ -3,21 +3,21 @@ import type { AnimationMap } from "../../stores/animations";
|
|
|
3
3
|
import type { TransitionSpec } from "../../types/animation";
|
|
4
4
|
import { animate } from "./animate";
|
|
5
5
|
|
|
6
|
-
interface
|
|
6
|
+
interface StartScreenTransitionProps {
|
|
7
7
|
target: "open" | "close";
|
|
8
8
|
spec?: TransitionSpec;
|
|
9
|
-
|
|
9
|
+
onAnimationFinish?: (finished: boolean) => void;
|
|
10
10
|
animations: AnimationMap;
|
|
11
11
|
velocity?: number;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export const
|
|
14
|
+
export const startScreenTransition = ({
|
|
15
15
|
target,
|
|
16
16
|
spec,
|
|
17
|
-
|
|
17
|
+
onAnimationFinish,
|
|
18
18
|
animations,
|
|
19
19
|
velocity,
|
|
20
|
-
}:
|
|
20
|
+
}: StartScreenTransitionProps) => {
|
|
21
21
|
"worklet";
|
|
22
22
|
const value = target === "open" ? 1 : 0;
|
|
23
23
|
const config = target === "open" ? spec?.open : spec?.close;
|
|
@@ -32,8 +32,8 @@ export const runTransition = ({
|
|
|
32
32
|
animating.value = 0;
|
|
33
33
|
progress.value = value;
|
|
34
34
|
|
|
35
|
-
if (
|
|
36
|
-
runOnJS(
|
|
35
|
+
if (onAnimationFinish) {
|
|
36
|
+
runOnJS(onAnimationFinish)(true);
|
|
37
37
|
}
|
|
38
38
|
return;
|
|
39
39
|
}
|
|
@@ -44,8 +44,8 @@ export const runTransition = ({
|
|
|
44
44
|
"worklet";
|
|
45
45
|
if (finished) {
|
|
46
46
|
animating.value = 0;
|
|
47
|
-
if (
|
|
48
|
-
runOnJS(
|
|
47
|
+
if (onAnimationFinish) {
|
|
48
|
+
runOnJS(onAnimationFinish)(finished);
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
1
|
+
import type { ScreenTransitionState } from "../../../types/animation";
|
|
2
|
+
import type { ScreenPhase } from "../../../types/core";
|
|
3
3
|
|
|
4
4
|
export type GetBoundsParams = {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
id: string | null;
|
|
6
|
+
phase?: ScreenPhase;
|
|
7
|
+
previous?: ScreenTransitionState;
|
|
8
|
+
current: ScreenTransitionState;
|
|
9
|
+
next?: ScreenTransitionState;
|
|
10
10
|
};
|