@react-navigation/stack 8.0.0-alpha.51 → 8.0.0-alpha.52

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 (61) hide show
  1. package/lib/module/TransitionConfigs/CardStyleInterpolators.js +241 -83
  2. package/lib/module/TransitionConfigs/CardStyleInterpolators.js.map +1 -1
  3. package/lib/module/TransitionConfigs/HeaderStyleInterpolators.js +11 -44
  4. package/lib/module/TransitionConfigs/HeaderStyleInterpolators.js.map +1 -1
  5. package/lib/module/TransitionConfigs/TransitionEasings.js +71 -0
  6. package/lib/module/TransitionConfigs/TransitionEasings.js.map +1 -0
  7. package/lib/module/TransitionConfigs/TransitionPresets.js +50 -10
  8. package/lib/module/TransitionConfigs/TransitionPresets.js.map +1 -1
  9. package/lib/module/TransitionConfigs/TransitionSpecs.js +69 -34
  10. package/lib/module/TransitionConfigs/TransitionSpecs.js.map +1 -1
  11. package/lib/module/navigators/createStackNavigator.js +25 -16
  12. package/lib/module/navigators/createStackNavigator.js.map +1 -1
  13. package/lib/module/views/Header/Header.js +2 -0
  14. package/lib/module/views/Header/Header.js.map +1 -1
  15. package/lib/module/views/Header/HeaderContainer.js +8 -3
  16. package/lib/module/views/Header/HeaderContainer.js.map +1 -1
  17. package/lib/module/views/Header/HeaderSegment.js +3 -6
  18. package/lib/module/views/Header/HeaderSegment.js.map +1 -1
  19. package/lib/module/views/Stack/Card.js +57 -32
  20. package/lib/module/views/Stack/Card.js.map +1 -1
  21. package/lib/module/views/Stack/CardContainer.js +17 -2
  22. package/lib/module/views/Stack/CardContainer.js.map +1 -1
  23. package/lib/module/views/Stack/CardStack.js +24 -13
  24. package/lib/module/views/Stack/CardStack.js.map +1 -1
  25. package/lib/typescript/src/TransitionConfigs/CardStyleInterpolators.d.ts +19 -11
  26. package/lib/typescript/src/TransitionConfigs/CardStyleInterpolators.d.ts.map +1 -1
  27. package/lib/typescript/src/TransitionConfigs/HeaderStyleInterpolators.d.ts +3 -3
  28. package/lib/typescript/src/TransitionConfigs/HeaderStyleInterpolators.d.ts.map +1 -1
  29. package/lib/typescript/src/TransitionConfigs/TransitionEasings.d.ts +38 -0
  30. package/lib/typescript/src/TransitionConfigs/TransitionEasings.d.ts.map +1 -0
  31. package/lib/typescript/src/TransitionConfigs/TransitionPresets.d.ts +14 -2
  32. package/lib/typescript/src/TransitionConfigs/TransitionPresets.d.ts.map +1 -1
  33. package/lib/typescript/src/TransitionConfigs/TransitionSpecs.d.ts +43 -14
  34. package/lib/typescript/src/TransitionConfigs/TransitionSpecs.d.ts.map +1 -1
  35. package/lib/typescript/src/navigators/createStackNavigator.d.ts.map +1 -1
  36. package/lib/typescript/src/types.d.ts +44 -28
  37. package/lib/typescript/src/types.d.ts.map +1 -1
  38. package/lib/typescript/src/views/Header/Header.d.ts +1 -1
  39. package/lib/typescript/src/views/Header/Header.d.ts.map +1 -1
  40. package/lib/typescript/src/views/Header/HeaderContainer.d.ts.map +1 -1
  41. package/lib/typescript/src/views/Header/HeaderSegment.d.ts +1 -0
  42. package/lib/typescript/src/views/Header/HeaderSegment.d.ts.map +1 -1
  43. package/lib/typescript/src/views/Stack/Card.d.ts +9 -3
  44. package/lib/typescript/src/views/Stack/Card.d.ts.map +1 -1
  45. package/lib/typescript/src/views/Stack/CardContainer.d.ts +3 -1
  46. package/lib/typescript/src/views/Stack/CardContainer.d.ts.map +1 -1
  47. package/lib/typescript/src/views/Stack/CardStack.d.ts.map +1 -1
  48. package/package.json +5 -5
  49. package/src/TransitionConfigs/CardStyleInterpolators.tsx +351 -100
  50. package/src/TransitionConfigs/HeaderStyleInterpolators.tsx +15 -46
  51. package/src/TransitionConfigs/TransitionEasings.tsx +90 -0
  52. package/src/TransitionConfigs/TransitionPresets.tsx +56 -10
  53. package/src/TransitionConfigs/TransitionSpecs.tsx +68 -34
  54. package/src/navigators/createStackNavigator.tsx +33 -24
  55. package/src/types.tsx +46 -29
  56. package/src/views/Header/Header.tsx +2 -0
  57. package/src/views/Header/HeaderContainer.tsx +10 -4
  58. package/src/views/Header/HeaderSegment.tsx +4 -4
  59. package/src/views/Stack/Card.tsx +82 -37
  60. package/src/views/Stack/CardContainer.tsx +17 -2
  61. package/src/views/Stack/CardStack.tsx +69 -14
@@ -0,0 +1,90 @@
1
+ import { Easing } from 'react-native';
2
+
3
+ /**
4
+ * Exact piecewise path for Android's fast-out-extra-slow-in easing.
5
+ * See https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-14.0.0_r51/core/res/res/interpolator/fast_out_extra_slow_in.xml
6
+ */
7
+ const FAST_OUT_EXTRA_SLOW_IN_INITIAL = Easing.bezier(0.3, 0, 0.8, 0.15);
8
+ const FAST_OUT_EXTRA_SLOW_IN_FINAL = Easing.bezier(0.05, 0.7, 0.1, 1);
9
+
10
+ export const FAST_OUT_EXTRA_SLOW_IN = (t: number) => {
11
+ const breakpoint = 1 / 6;
12
+
13
+ if (t < breakpoint) {
14
+ return 0.4 * FAST_OUT_EXTRA_SLOW_IN_INITIAL(t / breakpoint);
15
+ }
16
+
17
+ return (
18
+ 0.4 +
19
+ 0.6 * FAST_OUT_EXTRA_SLOW_IN_FINAL((t - breakpoint) / (1 - breakpoint))
20
+ );
21
+ };
22
+
23
+ /**
24
+ * See https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-17.0.0_r1/core/res/res/interpolator/fast_out_slow_in.xml
25
+ */
26
+ export const FAST_OUT_SLOW_IN = Easing.bezier(0.4, 0, 0.2, 1);
27
+
28
+ /**
29
+ * See https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-17.0.0_r1/core/res/res/interpolator/linear_out_slow_in.xml
30
+ */
31
+ export const LINEAR_OUT_SLOW_IN = Easing.bezier(0, 0, 0.2, 1);
32
+
33
+ /**
34
+ * See https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r47/core/res/res/interpolator/activity_close_dim.xml
35
+ */
36
+ export const ACTIVITY_CLOSE_DIM = Easing.bezier(0.33, 0, 1, 1);
37
+
38
+ export const decelerate = (power: number, t: number) => 1 - (1 - t) ** power;
39
+
40
+ export const accelerate = (power: number, t: number) => t ** power;
41
+
42
+ export const clamp = (value: number) => Math.min(1, Math.max(0, value));
43
+
44
+ /**
45
+ * Creates interpolation ranges for a property that follows its own timeline.
46
+ *
47
+ * @param options - Options for the property timeline.
48
+ * @param options.duration - Total transition duration in milliseconds.
49
+ * @param options.easing - Easing used by the transition.
50
+ * @param options.closing - Whether the transition is closing.
51
+ * @param options.stops - Times in milliseconds to include in the ranges.
52
+ * @param options.output - Returns the property value at a time in milliseconds.
53
+ */
54
+ export function timeline({
55
+ duration,
56
+ easing,
57
+ closing = false,
58
+ stops = [],
59
+ output,
60
+ }: {
61
+ duration: number;
62
+ easing: (value: number) => number;
63
+ closing?: boolean;
64
+ stops?: number[];
65
+ output: (time: number) => number;
66
+ }) {
67
+ const times = [
68
+ ...new Set([
69
+ ...Array.from(
70
+ { length: Math.floor(duration / 10) + 1 },
71
+ (_, index) => index * 10
72
+ ),
73
+ ...stops,
74
+ duration,
75
+ ]),
76
+ ].sort((a, b) => a - b);
77
+
78
+ const points = times
79
+ .map((time) => ({
80
+ input: closing ? 1 - easing(time / duration) : easing(time / duration),
81
+ output: output(time),
82
+ }))
83
+ .sort((a, b) => a.input - b.input);
84
+
85
+ return {
86
+ inputRange: points.map(({ input }) => input),
87
+ outputRange: points.map(({ output }) => output),
88
+ extrapolate: 'clamp' as const,
89
+ };
90
+ }
@@ -3,11 +3,13 @@ import { Platform } from 'react-native';
3
3
  import type { TransitionPreset } from '../types';
4
4
  import {
5
5
  forBottomSheetAndroid,
6
+ forCrossDissolveIOS,
7
+ forDialogAndroid,
6
8
  forFadeFromBottomAndroid,
7
- forFadeFromCenter as forFadeCard,
9
+ forFadeFromCenter,
8
10
  forFadeFromRightAndroid,
11
+ forFlipIOS,
9
12
  forHorizontalIOS,
10
- forHorizontalIOSInverted,
11
13
  forModalPresentationIOS,
12
14
  forRevealFromBottomAndroid,
13
15
  forScaleFromCenterAndroid,
@@ -17,8 +19,12 @@ import { forFade, forUIKit } from './HeaderStyleInterpolators';
17
19
  import {
18
20
  BottomSheetSlideInSpec,
19
21
  BottomSheetSlideOutSpec,
22
+ DialogAndroidSpec,
20
23
  FadeInFromBottomAndroidSpec,
24
+ FadeInFromRightAndroidSpec,
21
25
  FadeOutToBottomAndroidSpec,
26
+ FadeOutToRightAndroidSpec,
27
+ FlipIOSSpec,
22
28
  RevealFromBottomAndroidSpec,
23
29
  ScaleFromCenterAndroidSpec,
24
30
  TransitionIOSSpec,
@@ -80,6 +86,19 @@ export const FadeFromBottomAndroid: TransitionPreset = {
80
86
  headerStyleInterpolator: forFade,
81
87
  };
82
88
 
89
+ /**
90
+ * Standard Android dialog transition.
91
+ */
92
+ export const DialogAndroid: TransitionPreset = {
93
+ gestureDirection: 'vertical',
94
+ transitionSpec: {
95
+ open: DialogAndroidSpec,
96
+ close: DialogAndroidSpec,
97
+ },
98
+ cardStyleInterpolator: forDialogAndroid,
99
+ headerStyleInterpolator: forFade,
100
+ };
101
+
83
102
  /**
84
103
  * Standard Android navigation transition when opening or closing an Activity on Android 9 (Pie).
85
104
  */
@@ -107,20 +126,20 @@ export const ScaleFromCenterAndroid: TransitionPreset = {
107
126
  };
108
127
 
109
128
  /**
110
- * Standard Android navigation transition when opening or closing an Activity on Android 14.
129
+ * Standard Android navigation transition when opening or closing an Activity on Android 14 and later.
111
130
  */
112
131
  export const FadeFromRightAndroid: TransitionPreset = {
113
132
  gestureDirection: 'horizontal',
114
133
  transitionSpec: {
115
- open: FadeInFromBottomAndroidSpec,
116
- close: FadeOutToBottomAndroidSpec,
134
+ open: FadeInFromRightAndroidSpec,
135
+ close: FadeOutToRightAndroidSpec,
117
136
  },
118
137
  cardStyleInterpolator: forFadeFromRightAndroid,
119
138
  headerStyleInterpolator: forFade,
120
139
  };
121
140
 
122
141
  /**
123
- * Standard bottom sheet slide transition for Android 10.
142
+ * Standard Material 3 bottom sheet transition.
124
143
  */
125
144
  export const BottomSheetAndroid: TransitionPreset = {
126
145
  gestureDirection: 'vertical',
@@ -138,10 +157,36 @@ export const BottomSheetAndroid: TransitionPreset = {
138
157
  export const ModalFadeTransition: TransitionPreset = {
139
158
  gestureDirection: 'vertical',
140
159
  transitionSpec: {
141
- open: BottomSheetSlideInSpec,
142
- close: BottomSheetSlideOutSpec,
160
+ open: TransitionIOSSpec,
161
+ close: TransitionIOSSpec,
143
162
  },
144
- cardStyleInterpolator: forFadeCard,
163
+ cardStyleInterpolator: forFadeFromCenter,
164
+ headerStyleInterpolator: forFade,
165
+ };
166
+
167
+ /**
168
+ * Standard iOS horizontal flip transition.
169
+ */
170
+ export const ModalFlipIOS: TransitionPreset = {
171
+ gestureDirection: 'horizontal',
172
+ transitionSpec: {
173
+ open: FlipIOSSpec,
174
+ close: FlipIOSSpec,
175
+ },
176
+ cardStyleInterpolator: forFlipIOS,
177
+ headerStyleInterpolator: forFade,
178
+ };
179
+
180
+ /**
181
+ * Standard iOS cross-dissolve transition.
182
+ */
183
+ export const CrossDissolveIOS: TransitionPreset = {
184
+ gestureDirection: 'horizontal',
185
+ transitionSpec: {
186
+ open: TransitionIOSSpec,
187
+ close: TransitionIOSSpec,
188
+ },
189
+ cardStyleInterpolator: forCrossDissolveIOS,
145
190
  headerStyleInterpolator: forFade,
146
191
  };
147
192
 
@@ -174,5 +219,6 @@ export const ModalTransition = Platform.select({
174
219
  */
175
220
  export const SlideFromLeftIOS: TransitionPreset = {
176
221
  ...SlideFromRightIOS,
177
- cardStyleInterpolator: forHorizontalIOSInverted,
222
+ gestureDirection: 'horizontal-inverted',
223
+ cardStyleInterpolator: forHorizontalIOS,
178
224
  };
@@ -1,9 +1,10 @@
1
1
  import { Easing } from 'react-native';
2
2
 
3
3
  import type { TransitionSpec } from '../types';
4
+ import { FAST_OUT_EXTRA_SLOW_IN } from './TransitionEasings';
4
5
 
5
6
  /**
6
- * Exact values from UINavigationController's animation configuration.
7
+ * Approximation of the standard iOS navigation transition.
7
8
  */
8
9
  export const TransitionIOSSpec: TransitionSpec = {
9
10
  animation: 'spring',
@@ -17,9 +18,21 @@ export const TransitionIOSSpec: TransitionSpec = {
17
18
  },
18
19
  };
19
20
 
21
+ /**
22
+ * Configuration for the standard iOS horizontal flip transition.
23
+ */
24
+ export const FlipIOSSpec: TransitionSpec = {
25
+ animation: 'timing',
26
+ config: {
27
+ duration: 700,
28
+ easing: Easing.inOut(Easing.ease),
29
+ },
30
+ };
31
+
20
32
  /**
21
33
  * Configuration for activity open animation from Android Nougat.
22
- * See http://aosp.opersys.com/xref/android-7.1.2_r37/xref/frameworks/base/core/res/res/anim/activity_open_enter.xml
34
+ * See https://android.googlesource.com/platform/frameworks/base/+/android-7.1.2_r37/core/res/res/anim/activity_open_enter.xml
35
+ * See https://android.googlesource.com/platform/frameworks/base/+/android-7.1.2_r37/core/res/res/anim/activity_open_exit.xml
23
36
  */
24
37
  export const FadeInFromBottomAndroidSpec: TransitionSpec = {
25
38
  animation: 'timing',
@@ -31,94 +44,115 @@ export const FadeInFromBottomAndroidSpec: TransitionSpec = {
31
44
 
32
45
  /**
33
46
  * Configuration for activity close animation from Android Nougat.
34
- * See http://aosp.opersys.com/xref/android-7.1.2_r37/xref/frameworks/base/core/res/res/anim/activity_close_exit.xml
47
+ * See https://android.googlesource.com/platform/frameworks/base/+/android-7.1.2_r37/core/res/res/anim/activity_close_enter.xml
48
+ * See https://android.googlesource.com/platform/frameworks/base/+/android-7.1.2_r37/core/res/res/anim/activity_close_exit.xml
35
49
  */
36
50
  export const FadeOutToBottomAndroidSpec: TransitionSpec = {
37
51
  animation: 'timing',
38
52
  config: {
39
- duration: 150,
40
- easing: Easing.in(Easing.linear),
53
+ duration: 250,
54
+ easing: Easing.in(Easing.poly(4)),
41
55
  },
42
56
  };
43
57
 
44
58
  /**
45
- * Approximate configuration for activity open animation from Android Pie.
46
- * See http://aosp.opersys.com/xref/android-9.0.0_r47/xref/frameworks/base/core/res/res/anim/activity_open_enter.xml
59
+ * Configuration for the standard Android dialog transition.
60
+ * See https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-17.0.0_r1/core/res/res/anim/dialog_enter.xml
61
+ * See https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-17.0.0_r1/core/res/res/anim/dialog_exit.xml
62
+ * See https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-17.0.0_r1/core/res/res/values/config.xml
63
+ * See https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-17.0.0_r1/core/res/res/values/themes_material.xml
64
+ * See https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-17.0.0_r1/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
65
+ */
66
+ export const DialogAndroidSpec: TransitionSpec = {
67
+ animation: 'timing',
68
+ config: {
69
+ duration: 220,
70
+ easing: Easing.out(Easing.poly(5)),
71
+ },
72
+ };
73
+
74
+ /**
75
+ * Configuration for activity open animation from Android Pie.
76
+ * See https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r47/core/res/res/anim/activity_open_enter.xml
77
+ * See https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r47/core/res/res/anim/activity_open_exit.xml
78
+ * See https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r47/core/res/res/anim/activity_close_enter.xml
79
+ * See https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r47/core/res/res/anim/activity_close_exit.xml
47
80
  */
48
81
  export const RevealFromBottomAndroidSpec: TransitionSpec = {
49
82
  animation: 'timing',
50
83
  config: {
51
84
  duration: 425,
52
- // This is super rough approximation of the path used for the curve by android
53
- // See http://aosp.opersys.com/xref/android-9.0.0_r47/xref/frameworks/base/core/res/res/interpolator/fast_out_extra_slow_in.xml
54
- easing: Easing.bezier(0.20833, 0.82, 0.25, 1),
85
+ easing: FAST_OUT_EXTRA_SLOW_IN,
55
86
  },
56
87
  };
57
88
 
58
89
  /**
59
- * Approximate configuration for activity open animation from Android Q.
60
- * See http://aosp.opersys.com/xref/android-10.0.0_r2/xref/frameworks/base/core/res/res/anim/activity_open_enter.xml
90
+ * Configuration for activity open animation from Android Q.
91
+ * See https://android.googlesource.com/platform/frameworks/base/+/android-10.0.0_r2/core/res/res/anim/activity_open_enter.xml
92
+ * See https://android.googlesource.com/platform/frameworks/base/+/android-10.0.0_r2/core/res/res/anim/activity_open_exit.xml
93
+ * See https://android.googlesource.com/platform/frameworks/base/+/android-10.0.0_r2/core/res/res/anim/activity_close_enter.xml
94
+ * See https://android.googlesource.com/platform/frameworks/base/+/android-10.0.0_r2/core/res/res/anim/activity_close_exit.xml
61
95
  */
62
96
  export const ScaleFromCenterAndroidSpec: TransitionSpec = {
63
97
  animation: 'timing',
64
98
  config: {
65
99
  duration: 400,
66
- // This is super rough approximation of the path used for the curve by android
67
- // See http://aosp.opersys.com/xref/android-10.0.0_r2/xref/frameworks/base/core/res/res/interpolator/fast_out_extra_slow_in.xml
68
- easing: Easing.bezier(0.20833, 0.82, 0.25, 1),
100
+ easing: FAST_OUT_EXTRA_SLOW_IN,
69
101
  },
70
102
  };
71
103
 
72
104
  /**
73
- * Approximate configuration for activity open animation from Android 14.
105
+ * Configuration for activity open animation from Android 14 and later.
74
106
  * See https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-14.0.0_r51/core/res/res/anim/activity_open_enter.xml
107
+ * See https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-14.0.0_r51/core/res/res/anim/activity_open_exit.xml
75
108
  */
76
109
  export const FadeInFromRightAndroidSpec: TransitionSpec = {
77
110
  animation: 'timing',
78
111
  config: {
79
112
  duration: 450,
80
- // This is super rough approximation of the path used for the curve by android
81
- // See https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-14.0.0_r51/core/res/res/interpolator/fast_out_extra_slow_in.xml
82
- easing: Easing.bezier(0.20833, 0.82, 0.25, 1),
113
+ easing: FAST_OUT_EXTRA_SLOW_IN,
83
114
  },
84
115
  };
85
116
 
86
117
  /**
87
- * Approximate configuration for activity close animation from Android 14.
118
+ * Configuration for activity close animation from Android 14 and later.
119
+ * See https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-14.0.0_r51/core/res/res/anim/activity_close_enter.xml
88
120
  * See https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-14.0.0_r51/core/res/res/anim/activity_close_exit.xml
89
121
  */
90
- export const FadeOutToLeftAndroidSpec: TransitionSpec = {
122
+ export const FadeOutToRightAndroidSpec: TransitionSpec = {
91
123
  animation: 'timing',
92
124
  config: {
93
125
  duration: 450,
94
- // This is super rough approximation of the path used for the curve by android
95
- // See https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-14.0.0_r51/core/res/res/interpolator/fast_out_extra_slow_in.xml
96
- easing: Easing.bezier(0.20833, 0.82, 0.25, 1),
126
+ easing: FAST_OUT_EXTRA_SLOW_IN,
97
127
  },
98
128
  };
99
129
 
100
130
  /**
101
- * Configuration for bottom sheet slide in animation from Material Design.
102
- * See https://github.com/material-components/material-components-android/blob/fd3639092e1ffef9dc11bcedf79f32801d85e898/lib/java/com/google/android/material/bottomsheet/res/anim/mtrl_bottom_sheet_slide_in.xml
131
+ * Configuration for bottom sheet slide in animation from Material 3.
132
+ * See https://github.com/material-components/material-components-android/blob/1.14.0/lib/java/com/google/android/material/bottomsheet/res/anim/m3_bottom_sheet_slide_in.xml
133
+ * See https://github.com/material-components/material-components-android/blob/1.14.0/lib/java/com/google/android/material/motion/res/values/tokens.xml
134
+ * See https://github.com/material-components/material-components-android/blob/1.14.0/lib/java/com/google/android/material/dialog/res/values/tokens.xml
135
+ * See https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-17.0.0_r1/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
103
136
  */
104
137
  export const BottomSheetSlideInSpec: TransitionSpec = {
105
138
  animation: 'timing',
106
139
  config: {
107
- duration: 250,
108
- // See https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/animation/AccelerateDecelerateInterpolator.java
109
- easing: (t) => Math.cos((t + 1) * Math.PI) / 2.0 + 0.5,
140
+ duration: 400,
141
+ easing: FAST_OUT_EXTRA_SLOW_IN,
110
142
  },
111
143
  };
112
144
 
113
145
  /**
114
- * Configuration for bottom sheet slide out animation from Material Design.
115
- * See https://github.com/material-components/material-components-android/blob/fd3639092e1ffef9dc11bcedf79f32801d85e898/lib/java/com/google/android/material/bottomsheet/res/anim/mtrl_bottom_sheet_slide_in.xml
146
+ * Configuration for bottom sheet slide out animation from Material 3.
147
+ * See https://github.com/material-components/material-components-android/blob/1.14.0/lib/java/com/google/android/material/bottomsheet/res/anim/m3_bottom_sheet_slide_out.xml
148
+ * See https://github.com/material-components/material-components-android/blob/1.14.0/lib/java/com/google/android/material/motion/res/values/tokens.xml
149
+ * See https://github.com/material-components/material-components-android/blob/1.14.0/lib/java/com/google/android/material/dialog/res/values/tokens.xml
150
+ * See https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-17.0.0_r1/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
116
151
  */
117
152
  export const BottomSheetSlideOutSpec: TransitionSpec = {
118
153
  animation: 'timing',
119
154
  config: {
120
- duration: 200,
121
- // See https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/animation/AccelerateInterpolator.java
122
- easing: (t) => (t === 1.0 ? 1 : Math.pow(t, 2)),
155
+ duration: 350,
156
+ easing: FAST_OUT_EXTRA_SLOW_IN,
123
157
  },
124
158
  };
@@ -52,31 +52,40 @@ function StackNavigator({
52
52
  router,
53
53
  });
54
54
 
55
- React.useEffect(
56
- () =>
57
- // @ts-expect-error: there may not be a tab navigator in parent
58
- navigation.addListener?.('tabPress', (e) => {
59
- const isFocused = navigation.isFocused();
55
+ React.useEffect(() => {
56
+ let handle: ReturnType<typeof requestAnimationFrame> | undefined;
60
57
 
61
- // Run the operation in the next frame so we're sure all listeners have been run
62
- // This is necessary to know if preventDefault() has been called
63
- requestAnimationFrame(() => {
64
- if (
65
- state.index > 0 &&
66
- isFocused &&
67
- !(e as unknown as EventArg<'tabPress', true>).defaultPrevented
68
- ) {
69
- // When user taps on already focused tab and we're inside the tab,
70
- // reset the stack to replicate native behaviour
71
- navigation.dispatch({
72
- ...StackActions.popToTop(),
73
- target: state.key,
74
- });
75
- }
76
- });
77
- }),
78
- [navigation, state.index, state.key]
79
- );
58
+ // @ts-expect-error: there may not be a tab navigator in parent
59
+ const unsubscribe = navigation.addListener?.('tabPress', (e) => {
60
+ const isFocused = navigation.isFocused();
61
+
62
+ cancelAnimationFrame(handle);
63
+
64
+ // Run the operation in the next frame so we're sure all listeners have been run
65
+ // This is necessary to know if preventDefault() has been called
66
+ handle = requestAnimationFrame(() => {
67
+ const currentState = navigation.getState();
68
+
69
+ if (
70
+ isFocused &&
71
+ (currentState.index > 0 || currentState.routes[0]?.history?.length) &&
72
+ !(e as EventArg<'tabPress', true>).defaultPrevented
73
+ ) {
74
+ // When user taps on already focused tab and we're inside the tab,
75
+ // reset the stack to replicate native behaviour
76
+ navigation.dispatch({
77
+ ...StackActions.popToTop(),
78
+ target: currentState.key,
79
+ });
80
+ }
81
+ });
82
+ });
83
+
84
+ return () => {
85
+ cancelAnimationFrame(handle);
86
+ unsubscribe?.();
87
+ };
88
+ }, [navigation]);
80
89
 
81
90
  return (
82
91
  <NavigationContent>
package/src/types.tsx CHANGED
@@ -8,7 +8,6 @@ import type {
8
8
  import type {
9
9
  DefaultNavigatorOptions,
10
10
  Descriptor,
11
- LocaleDirection,
12
11
  NavigationHelpers,
13
12
  NavigationProp,
14
13
  ParamListBase,
@@ -97,6 +96,9 @@ export type StackAnimationName =
97
96
  | 'fade'
98
97
  | 'fade_from_bottom'
99
98
  | 'fade_from_right'
99
+ | 'flip'
100
+ | 'ios_from_left'
101
+ | 'ios_from_right'
100
102
  | 'none'
101
103
  | 'reveal_from_bottom'
102
104
  | 'scale_from_center'
@@ -107,7 +109,8 @@ export type StackAnimationName =
107
109
  type SceneOptionsDefaults = TransitionPreset & {
108
110
  animation: StackAnimationName;
109
111
  gestureEnabled: boolean;
110
- cardOverlayEnabled: boolean;
112
+ cardOverlayEnabled: boolean | undefined;
113
+ cardShadowEnabled: boolean | undefined;
111
114
  headerMode: StackHeaderMode;
112
115
  };
113
116
 
@@ -127,6 +130,10 @@ export type Scene = {
127
130
  * Animated nodes representing the progress of the animation.
128
131
  */
129
132
  progress: SceneProgress;
133
+ /**
134
+ * Animated node representing whether the screen is closing.
135
+ */
136
+ closing: Animated.Value;
130
137
  };
131
138
 
132
139
  export type SceneProgress = {
@@ -256,6 +263,10 @@ export type StackHeaderProps = {
256
263
  * Animated nodes representing the progress of the animation.
257
264
  */
258
265
  progress: SceneProgress;
266
+ /**
267
+ * Direction multiplier for the transition.
268
+ */
269
+ inverted: 1 | -1;
259
270
  /**
260
271
  * Options for the current screen.
261
272
  */
@@ -320,7 +331,8 @@ export type StackNavigationOptions = StackHeaderOptions &
320
331
  header?: (props: StackHeaderProps) => React.ReactNode;
321
332
  /**
322
333
  * Whether the header floats above the screen or part of the screen.
323
- * Defaults to `float` on iOS for non-modals, and `screen` for the rest.
334
+ * Defaults to `float` on iOS for animations where the header transitions
335
+ * separately, and `screen` otherwise.
324
336
  */
325
337
  headerMode?: StackHeaderMode;
326
338
  /**
@@ -329,14 +341,17 @@ export type StackNavigationOptions = StackHeaderOptions &
329
341
  */
330
342
  headerShown?: boolean;
331
343
  /**
332
- * Whether a shadow is visible for the card during transitions. Defaults to `true`.
344
+ * Whether a shadow is visible for the card during transitions.
345
+ * Defaults to whether `cardStyleInterpolator` returns a `shadowStyle`.
346
+ * Setting this overrides the default behavior.
333
347
  */
334
- cardShadowEnabled?: boolean;
348
+ cardShadowEnabled?: boolean | undefined;
335
349
  /**
336
350
  * Whether to have a semi-transparent dark overlay visible under the card during transitions.
337
- * Defaults to `true` on Android and `false` on iOS.
351
+ * Defaults to whether `cardStyleInterpolator` returns an `overlayStyle`.
352
+ * Setting this overrides the default behavior.
338
353
  */
339
- cardOverlayEnabled?: boolean;
354
+ cardOverlayEnabled?: boolean | undefined;
340
355
  /**
341
356
  * Function that returns a React Element to display as a overlay for the card.
342
357
  */
@@ -371,8 +386,12 @@ export type StackNavigationOptions = StackHeaderOptions &
371
386
  * Supported values:
372
387
  * - 'none': don't animate the screen
373
388
  * - 'default': use the platform default animation
374
- * - 'fade': fade screen in or out
389
+ * - 'fade': fade between screens
375
390
  * - 'fade_from_bottom': fade screen in or out from bottom
391
+ * - 'fade_from_right': fade screen in from the right
392
+ * - 'flip': flip the screen horizontally
393
+ * - 'ios_from_left': use the iOS-style slide from left
394
+ * - 'ios_from_right': use the iOS-style slide from right
376
395
  * - 'slide_from_bottom': slide in the new screen from bottom
377
396
  * - 'slide_from_right': slide in the new screen from right
378
397
  * - 'slide_from_left': slide in the new screen from left
@@ -386,7 +405,9 @@ export type StackNavigationOptions = StackHeaderOptions &
386
405
  */
387
406
  animationTypeForReplace?: 'push' | 'pop';
388
407
  /**
389
- * Whether you can use gestures to dismiss this screen. Defaults to `true` on iOS, `false` on Android.
408
+ * Whether you can use gestures to dismiss this screen. Defaults to `true`
409
+ * on iOS for navigation-style transitions with an interactive dismissal,
410
+ * and `false` otherwise.
390
411
  * Not supported on Web.
391
412
  */
392
413
  gestureEnabled?: boolean;
@@ -440,36 +461,32 @@ export type TransitionSpec =
440
461
  >;
441
462
  };
442
463
 
464
+ type StackCardInterpolationState = {
465
+ /**
466
+ * Animated node representing the progress value of the screen.
467
+ */
468
+ progress: Animated.AnimatedInterpolation<number>;
469
+ /**
470
+ * Animated node representing whether the screen is using the closing or
471
+ * opening animation (1 - closing, 0 - opening).
472
+ */
473
+ closing: Animated.AnimatedInterpolation<0 | 1>;
474
+ };
475
+
443
476
  export type StackCardInterpolationProps = {
444
477
  /**
445
478
  * Values for the current screen.
446
479
  */
447
- current: {
448
- /**
449
- * Animated node representing the progress value of the current screen.
450
- */
451
- progress: Animated.AnimatedInterpolation<number>;
452
- };
480
+ current: StackCardInterpolationState;
453
481
  /**
454
482
  * Values for the screen after this one in the stack.
455
483
  * This can be `undefined` in case the screen animating is the last one.
456
484
  */
457
- next?:
458
- | {
459
- /**
460
- * Animated node representing the progress value of the next screen.
461
- */
462
- progress: Animated.AnimatedInterpolation<number>;
463
- }
464
- | undefined;
485
+ next?: StackCardInterpolationState | undefined;
465
486
  /**
466
487
  * The index of the card with this interpolation in the stack.
467
488
  */
468
489
  index: number;
469
- /**
470
- * Animated node representing whether the card is closing (1 - closing, 0 - not closing).
471
- */
472
- closing: Animated.AnimatedInterpolation<0 | 1>;
473
490
  /**
474
491
  * Animated node representing whether the card is being swiped (1 - swiping, 0 - not swiping).
475
492
  */
@@ -548,9 +565,9 @@ export type StackHeaderInterpolationProps = {
548
565
  }
549
566
  | undefined;
550
567
  /**
551
- * Writing direction of the layout.
568
+ * Direction multiplier for the transition.
552
569
  */
553
- direction: LocaleDirection;
570
+ inverted: 1 | -1;
554
571
  /**
555
572
  * Layout measurements for various items we use for animation.
556
573
  */
@@ -11,6 +11,7 @@ import { HeaderSegment } from './HeaderSegment';
11
11
  export const Header = React.memo(function Header({
12
12
  back,
13
13
  progress,
14
+ inverted,
14
15
  options,
15
16
  route,
16
17
  navigation,
@@ -54,6 +55,7 @@ export const Header = React.memo(function Header({
54
55
  return (
55
56
  <HeaderSegment
56
57
  {...options}
58
+ inverted={inverted}
57
59
  title={getHeaderTitle(options, route.name)}
58
60
  progress={progress}
59
61
  modal={isModal}