react-native-screen-transitions 2.0.2 → 2.0.3

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.
Files changed (57) hide show
  1. package/package.json +5 -3
  2. package/src/__tests__ /geometry.test.ts +127 -0
  3. package/src/components/bounds-activator.tsx +29 -0
  4. package/src/components/controllers/screen-lifecycle.tsx +72 -0
  5. package/src/components/create-transition-aware-component.tsx +99 -0
  6. package/src/components/root-transition-aware.tsx +56 -0
  7. package/src/configs/index.ts +2 -0
  8. package/src/configs/presets.ts +227 -0
  9. package/src/configs/specs.ts +9 -0
  10. package/src/hooks/animation/use-associated-style.tsx +28 -0
  11. package/src/hooks/animation/use-screen-animation.tsx +142 -0
  12. package/src/hooks/bounds/use-bound-measurer.tsx +71 -0
  13. package/src/hooks/gestures/use-build-gestures.tsx +369 -0
  14. package/src/hooks/gestures/use-scroll-progress.tsx +60 -0
  15. package/src/hooks/use-stable-callback.tsx +15 -0
  16. package/src/index.ts +32 -0
  17. package/src/integrations/native-stack/navigators/createNativeStackNavigator.tsx +112 -0
  18. package/src/integrations/native-stack/utils/debounce.tsx +14 -0
  19. package/src/integrations/native-stack/utils/getModalRoutesKeys.ts +21 -0
  20. package/src/integrations/native-stack/utils/useAnimatedHeaderHeight.tsx +18 -0
  21. package/src/integrations/native-stack/utils/useDismissedRouteError.tsx +30 -0
  22. package/src/integrations/native-stack/utils/useInvalidPreventRemoveError.tsx +31 -0
  23. package/src/integrations/native-stack/views/FontProcessor.native.tsx +12 -0
  24. package/src/integrations/native-stack/views/FontProcessor.tsx +5 -0
  25. package/src/integrations/native-stack/views/FooterComponent.tsx +10 -0
  26. package/src/integrations/native-stack/views/NativeStackView.native.tsx +657 -0
  27. package/src/integrations/native-stack/views/NativeStackView.tsx +214 -0
  28. package/src/integrations/native-stack/views/useHeaderConfigProps.tsx +295 -0
  29. package/src/providers/gestures.tsx +89 -0
  30. package/src/providers/keys.tsx +38 -0
  31. package/src/stores/animations.ts +45 -0
  32. package/src/stores/bounds.ts +71 -0
  33. package/src/stores/gestures.ts +55 -0
  34. package/src/stores/navigator-dismiss-state.ts +17 -0
  35. package/src/stores/utils/reset-stores-for-screen.ts +14 -0
  36. package/src/types/animation.ts +76 -0
  37. package/src/types/bounds.ts +82 -0
  38. package/src/types/core.ts +50 -0
  39. package/src/types/gesture.ts +33 -0
  40. package/src/types/navigator.ts +744 -0
  41. package/src/types/utils.ts +3 -0
  42. package/src/utils/animation/animate.ts +28 -0
  43. package/src/utils/animation/run-transition.ts +49 -0
  44. package/src/utils/bounds/_types/builder.ts +35 -0
  45. package/src/utils/bounds/_types/geometry.ts +17 -0
  46. package/src/utils/bounds/_types/get-bounds.ts +10 -0
  47. package/src/utils/bounds/build-bound-styles.ts +184 -0
  48. package/src/utils/bounds/constants.ts +28 -0
  49. package/src/utils/bounds/flatten-styles.ts +21 -0
  50. package/src/utils/bounds/geometry.ts +113 -0
  51. package/src/utils/bounds/get-bounds.ts +56 -0
  52. package/src/utils/bounds/index.ts +46 -0
  53. package/src/utils/bounds/style-composers.ts +172 -0
  54. package/src/utils/gesture/apply-gesture-activation-criteria.ts +109 -0
  55. package/src/utils/gesture/map-gesture-to-progress.ts +11 -0
  56. package/src/utils/gesture/normalize-gesture-translation.ts +20 -0
  57. package/src/utils/index.ts +1 -0
@@ -0,0 +1,172 @@
1
+ import type { MeasuredDimensions, StyleProps } from "react-native-reanimated";
2
+ import type { BoundsBuilderOptions } from "./_types/builder";
3
+ import type {
4
+ ContentTransformGeometry,
5
+ RelativeGeometry,
6
+ } from "./_types/geometry";
7
+
8
+ /**
9
+ * Common interpolation helper signature used by composers.
10
+ * It maps from a -> b over the already-determined progress range.
11
+ */
12
+ export type Interp = (a: number, b: number) => number;
13
+
14
+ /**
15
+ * Element-level (relative) params shared by size/transform composers.
16
+ * - start/end: absolute window bounds of the element in previous/next phases
17
+ * - geometry: relative deltas and scales between start/end (dx, dy, scaleX, scaleY, ...)
18
+ * - interp: function to interpolate between numbers using the correct progress range
19
+ */
20
+ export type ElementComposeParams = {
21
+ start: MeasuredDimensions;
22
+ end: MeasuredDimensions;
23
+ geometry: RelativeGeometry;
24
+ interp: Interp;
25
+ computeOptions: BoundsBuilderOptions;
26
+ };
27
+
28
+ /**
29
+ * Screen-level content transform params (for aligning destination bound to source).
30
+ * - start/end: absolute window bounds for the shared id (source/destination)
31
+ * - geometry: precomputed screen-level tx/ty/sx/sy plus ranges/entering
32
+ * - interp: function to interpolate between numbers using the correct progress range
33
+ */
34
+ export type ContentComposeParams = {
35
+ start: MeasuredDimensions;
36
+ end: MeasuredDimensions;
37
+ geometry: ContentTransformGeometry;
38
+ interp: Interp;
39
+ computeOptions: BoundsBuilderOptions;
40
+ };
41
+
42
+ export function composeSizeAbsolute(params: ElementComposeParams): StyleProps {
43
+ "worklet";
44
+ const { start, end, geometry, interp } = params;
45
+
46
+ if (geometry.entering) {
47
+ return {
48
+ width: interp(start.width, end.width),
49
+ height: interp(start.height, end.height),
50
+ transform: [
51
+ { translateX: interp(start.pageX, end.pageX) },
52
+ { translateY: interp(start.pageY, end.pageY) },
53
+ ],
54
+ } satisfies StyleProps;
55
+ }
56
+
57
+ return {
58
+ width: interp(end.width, start.width),
59
+ height: interp(end.height, start.height),
60
+ transform: [
61
+ { translateX: interp(end.pageX, start.pageX) },
62
+ { translateY: interp(end.pageY, start.pageY) },
63
+ ],
64
+ };
65
+ }
66
+
67
+ export function composeSizeRelative(params: ElementComposeParams): StyleProps {
68
+ "worklet";
69
+ const { start, end, geometry, interp } = params;
70
+
71
+ if (geometry.entering) {
72
+ return {
73
+ transform: [
74
+ { translateX: interp(geometry.dx, 0) },
75
+ { translateY: interp(geometry.dy, 0) },
76
+ ],
77
+ width: interp(start.width, end.width),
78
+ height: interp(start.height, end.height),
79
+ };
80
+ }
81
+
82
+ return {
83
+ transform: [
84
+ { translateX: interp(0, -geometry.dx) },
85
+ { translateY: interp(0, -geometry.dy) },
86
+ ],
87
+ width: interp(end.width, start.width),
88
+ height: interp(end.height, start.height),
89
+ };
90
+ }
91
+
92
+ export function composeTransformAbsolute(
93
+ params: ElementComposeParams,
94
+ ): StyleProps {
95
+ "worklet";
96
+ const { start, end, geometry, interp } = params;
97
+
98
+ if (geometry.entering) {
99
+ return {
100
+ transform: [
101
+ { translateX: interp(start.pageX, end.pageX) },
102
+ { translateY: interp(start.pageY, end.pageY) },
103
+ { scaleX: interp(geometry.scaleX, 1) },
104
+ { scaleY: interp(geometry.scaleY, 1) },
105
+ ],
106
+ };
107
+ }
108
+
109
+ return {
110
+ transform: [
111
+ { translateX: interp(end.pageX, start.pageX) },
112
+ { translateY: interp(end.pageY, start.pageY) },
113
+ { scaleX: interp(1, 1 / geometry.scaleX) },
114
+ { scaleY: interp(1, 1 / geometry.scaleY) },
115
+ ],
116
+ };
117
+ }
118
+
119
+ export function composeTransformRelative(
120
+ params: ElementComposeParams,
121
+ ): StyleProps {
122
+ "worklet";
123
+ const { geometry, computeOptions, interp } = params;
124
+
125
+ if (geometry.entering) {
126
+ return {
127
+ transform: [
128
+ { translateX: computeOptions.gestures?.x ?? 0 },
129
+ { translateY: computeOptions.gestures?.y ?? 0 },
130
+ { translateX: interp(geometry.dx, 0) },
131
+ { translateY: interp(geometry.dy, 0) },
132
+ { scaleX: interp(geometry.scaleX, 1) },
133
+ { scaleY: interp(geometry.scaleY, 1) },
134
+ ],
135
+ };
136
+ }
137
+
138
+ return {
139
+ transform: [
140
+ { translateX: computeOptions.gestures?.x ?? 0 },
141
+ { translateY: computeOptions.gestures?.y ?? 0 },
142
+ { translateX: interp(0, -geometry.dx) },
143
+ { translateY: interp(0, -geometry.dy) },
144
+ { scaleX: interp(1, 1 / geometry.scaleX) },
145
+ { scaleY: interp(1, 1 / geometry.scaleY) },
146
+ ],
147
+ };
148
+ }
149
+
150
+ export function composeContentStyle(params: ContentComposeParams): StyleProps {
151
+ "worklet";
152
+ const { geometry, interp } = params;
153
+ const { s, tx, ty, entering } = geometry;
154
+
155
+ if (entering) {
156
+ return {
157
+ transform: [
158
+ { translateX: interp(tx, 0) },
159
+ { translateY: interp(ty, 0) },
160
+ { scale: interp(s, 1) },
161
+ ],
162
+ };
163
+ }
164
+
165
+ return {
166
+ transform: [
167
+ { translateX: interp(0, tx) },
168
+ { translateY: interp(0, ty) },
169
+ { scale: interp(1, s) },
170
+ ],
171
+ };
172
+ }
@@ -0,0 +1,109 @@
1
+ import type { PanGesture } from "react-native-gesture-handler";
2
+ import type { ScreenTransitionConfig } from "../../types/navigator";
3
+
4
+ interface GestureActivationOptions {
5
+ gestureDirection:
6
+ | ScreenTransitionConfig["gestureDirection"]
7
+ | Array<ScreenTransitionConfig["gestureDirection"]>;
8
+ gestureResponseDistance: number;
9
+ panGesture: PanGesture;
10
+ }
11
+
12
+ /**
13
+ * rngh requires this type instead a number[]. We're returning a num[] which is still correct, this is just to remove the type error.
14
+ */
15
+ type OffsetErrorTypeBugFix = [start: number, end: number];
16
+
17
+ export const applyGestureActivationCriteria = ({
18
+ gestureDirection,
19
+ gestureResponseDistance,
20
+ panGesture,
21
+ }: GestureActivationOptions) => {
22
+ const directions = Array.isArray(gestureDirection)
23
+ ? gestureDirection
24
+ : [gestureDirection];
25
+
26
+ if (directions.includes("bidirectional")) {
27
+ return {
28
+ activeOffsetX: [
29
+ -gestureResponseDistance,
30
+ gestureResponseDistance,
31
+ ] as OffsetErrorTypeBugFix,
32
+ activeOffsetY: [
33
+ -gestureResponseDistance,
34
+ gestureResponseDistance,
35
+ ] as OffsetErrorTypeBugFix,
36
+ };
37
+ }
38
+
39
+ const allowedDown = directions.includes("vertical");
40
+ const allowedUp = directions.includes("vertical-inverted");
41
+ const allowedRight = directions.includes("horizontal");
42
+ const allowedLeft = directions.includes("horizontal-inverted");
43
+
44
+ const toleranceX = 15;
45
+ const toleranceY = 20;
46
+ const dist = gestureResponseDistance;
47
+
48
+ const result: {
49
+ activeOffsetX?: number | [number, number];
50
+ failOffsetX?: number | OffsetErrorTypeBugFix;
51
+ activeOffsetY?: number | [number, number];
52
+ failOffsetY?: number | OffsetErrorTypeBugFix;
53
+ } = {};
54
+
55
+ const hasHorizontal = allowedLeft || allowedRight;
56
+ if (hasHorizontal) {
57
+ if (allowedLeft && allowedRight) {
58
+ result.activeOffsetX = [-dist, dist];
59
+ } else if (allowedLeft) {
60
+ result.activeOffsetX = -dist;
61
+ } else if (allowedRight) {
62
+ result.activeOffsetX = dist;
63
+ }
64
+
65
+ if (allowedRight && !allowedLeft) {
66
+ result.failOffsetX = -dist;
67
+ } else if (allowedLeft && !allowedRight) {
68
+ result.failOffsetX = dist;
69
+ }
70
+ } else {
71
+ result.failOffsetX = [-toleranceX, toleranceX] as OffsetErrorTypeBugFix;
72
+ }
73
+
74
+ const hasVertical = allowedUp || allowedDown;
75
+ if (hasVertical) {
76
+ if (allowedUp && allowedDown) {
77
+ result.activeOffsetY = [-dist, dist];
78
+ } else if (allowedUp) {
79
+ result.activeOffsetY = -dist;
80
+ } else if (allowedDown) {
81
+ result.activeOffsetY = dist;
82
+ }
83
+
84
+ if (allowedDown && !allowedUp) {
85
+ result.failOffsetY = -dist;
86
+ } else if (allowedUp && !allowedDown) {
87
+ result.failOffsetY = dist;
88
+ }
89
+ } else {
90
+ result.failOffsetY = [-toleranceY, toleranceY] as OffsetErrorTypeBugFix;
91
+ }
92
+
93
+ if (result?.activeOffsetX) {
94
+ panGesture.activeOffsetX(result.activeOffsetX);
95
+ }
96
+ if (result?.activeOffsetY) {
97
+ panGesture.activeOffsetY(result.activeOffsetY);
98
+ }
99
+ if (result?.failOffsetX) {
100
+ panGesture.failOffsetX(result.failOffsetX);
101
+ }
102
+ if (result?.failOffsetY) {
103
+ panGesture.failOffsetY(result.failOffsetY);
104
+ }
105
+
106
+ panGesture.enableTrackpadTwoFingerGesture(true);
107
+
108
+ return panGesture;
109
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Utility function to map raw gesture translation to a progress value.
3
+ */
4
+ export const mapGestureToProgress = (
5
+ translation: number,
6
+ dimension: number,
7
+ ) => {
8
+ "worklet";
9
+ const rawProgress = translation / dimension;
10
+ return Math.max(0, Math.min(1, rawProgress));
11
+ };
@@ -0,0 +1,20 @@
1
+ import type { GestureDirection } from "../../types/gesture";
2
+
3
+ /**
4
+ * Utility function to normalize gesture translation based on direction.
5
+ */
6
+ export const normalizeGestureTranslation = (
7
+ translation: number,
8
+ gestureDirection: GestureDirection,
9
+ ) => {
10
+ "worklet";
11
+ const isInverted = gestureDirection.includes("inverted");
12
+
13
+ const translated = Math.abs(translation) * (isInverted ? -1 : 1);
14
+
15
+ if (isInverted) {
16
+ return Math.min(0, translated);
17
+ }
18
+
19
+ return Math.max(0, translated);
20
+ };
@@ -0,0 +1 @@
1
+ export * from "./animation/animate";