@react-navigation/stack 8.0.0-alpha.2 → 8.0.0-alpha.21
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/module/utils/useCardAnimation.js +1 -1
- package/lib/module/utils/useCardAnimation.js.map +1 -1
- package/lib/module/utils/useGestureHandlerRef.js +1 -1
- package/lib/module/utils/useGestureHandlerRef.js.map +1 -1
- package/lib/module/utils/useKeyboardManager.js +50 -26
- package/lib/module/utils/useKeyboardManager.js.map +1 -1
- package/lib/module/views/Header/Header.js +2 -2
- package/lib/module/views/Header/Header.js.map +1 -1
- package/lib/module/views/Header/HeaderContainer.js +8 -4
- package/lib/module/views/Header/HeaderContainer.js.map +1 -1
- package/lib/module/views/Header/HeaderSegment.js +2 -2
- package/lib/module/views/Header/HeaderSegment.js.map +1 -1
- package/lib/module/views/Stack/Card.js +25 -20
- package/lib/module/views/Stack/Card.js.map +1 -1
- package/lib/module/views/Stack/CardA11yWrapper.js +1 -2
- package/lib/module/views/Stack/CardA11yWrapper.js.map +1 -1
- package/lib/module/views/Stack/CardContainer.js +17 -19
- package/lib/module/views/Stack/CardContainer.js.map +1 -1
- package/lib/module/views/Stack/CardStack.js +72 -117
- package/lib/module/views/Stack/CardStack.js.map +1 -1
- package/lib/module/views/Stack/StackView.js +59 -23
- package/lib/module/views/Stack/StackView.js.map +1 -1
- package/lib/typescript/src/types.d.ts +46 -47
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/utils/gestureActivationCriteria.d.ts +1 -1
- package/lib/typescript/src/utils/gestureActivationCriteria.d.ts.map +1 -1
- package/lib/typescript/src/utils/useKeyboardManager.d.ts +9 -2
- package/lib/typescript/src/utils/useKeyboardManager.d.ts.map +1 -1
- package/lib/typescript/src/views/Header/Header.d.ts +1 -1
- package/lib/typescript/src/views/Header/Header.d.ts.map +1 -1
- package/lib/typescript/src/views/Header/HeaderContainer.d.ts.map +1 -1
- package/lib/typescript/src/views/Header/HeaderSegment.d.ts +2 -2
- package/lib/typescript/src/views/Header/HeaderSegment.d.ts.map +1 -1
- package/lib/typescript/src/views/Stack/Card.d.ts +3 -3
- package/lib/typescript/src/views/Stack/Card.d.ts.map +1 -1
- package/lib/typescript/src/views/Stack/CardA11yWrapper.d.ts +0 -1
- package/lib/typescript/src/views/Stack/CardA11yWrapper.d.ts.map +1 -1
- package/lib/typescript/src/views/Stack/CardContainer.d.ts +2 -2
- package/lib/typescript/src/views/Stack/CardContainer.d.ts.map +1 -1
- package/lib/typescript/src/views/Stack/CardStack.d.ts +1 -1
- package/lib/typescript/src/views/Stack/CardStack.d.ts.map +1 -1
- package/lib/typescript/src/views/Stack/StackView.d.ts +6 -6
- package/lib/typescript/src/views/Stack/StackView.d.ts.map +1 -1
- package/package.json +16 -16
- package/src/types.tsx +73 -67
- package/src/utils/gestureActivationCriteria.tsx +1 -1
- package/src/utils/useCardAnimation.tsx +1 -1
- package/src/utils/useGestureHandlerRef.tsx +1 -1
- package/src/utils/useKeyboardManager.tsx +67 -33
- package/src/views/Header/Header.tsx +2 -2
- package/src/views/Header/HeaderContainer.tsx +8 -3
- package/src/views/Header/HeaderSegment.tsx +4 -4
- package/src/views/Stack/Card.tsx +32 -23
- package/src/views/Stack/CardA11yWrapper.tsx +2 -14
- package/src/views/Stack/CardContainer.tsx +9 -21
- package/src/views/Stack/CardStack.tsx +102 -155
- package/src/views/Stack/StackView.tsx +106 -34
package/src/types.tsx
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
HeaderBackButton,
|
|
3
2
|
HeaderBackButtonDisplayMode,
|
|
4
3
|
HeaderBackButtonProps,
|
|
5
4
|
HeaderOptions,
|
|
6
5
|
HeaderTitleProps,
|
|
6
|
+
Icon,
|
|
7
7
|
} from '@react-navigation/elements';
|
|
8
8
|
import type {
|
|
9
9
|
DefaultNavigatorOptions,
|
|
@@ -138,12 +138,12 @@ export type SceneProgress = {
|
|
|
138
138
|
* Progress value for the screen after this one in the stack.
|
|
139
139
|
* This can be `undefined` in case the screen animating is the last one.
|
|
140
140
|
*/
|
|
141
|
-
next?: Animated.AnimatedInterpolation<number
|
|
141
|
+
next?: Animated.AnimatedInterpolation<number> | undefined;
|
|
142
142
|
/**
|
|
143
143
|
* Progress value for the screen before this one in the stack.
|
|
144
144
|
* This can be `undefined` in case the screen animating is the first one.
|
|
145
145
|
*/
|
|
146
|
-
previous?: Animated.AnimatedInterpolation<number
|
|
146
|
+
previous?: Animated.AnimatedInterpolation<number> | undefined;
|
|
147
147
|
};
|
|
148
148
|
|
|
149
149
|
export type StackHeaderMode = 'float' | 'screen';
|
|
@@ -187,14 +187,14 @@ export type StackHeaderOptions = Omit<
|
|
|
187
187
|
* Defaults to the previous screen's title, or "Back" if there's not enough space.
|
|
188
188
|
* Use `headerBackButtonDisplayMode` to customize the behavior.
|
|
189
189
|
*/
|
|
190
|
-
headerBackTitle?: string;
|
|
190
|
+
headerBackTitle?: string | undefined;
|
|
191
191
|
/**
|
|
192
192
|
* Title string used by the back button when `headerBackTitle` doesn't fit on the screen.
|
|
193
193
|
* Use `headerBackButtonDisplayMode` to customize the behavior.
|
|
194
194
|
*
|
|
195
195
|
* Defaults to "Back".
|
|
196
196
|
*/
|
|
197
|
-
headerBackTruncatedTitle?: string;
|
|
197
|
+
headerBackTruncatedTitle?: string | undefined;
|
|
198
198
|
/**
|
|
199
199
|
* How the back button displays icon and title.
|
|
200
200
|
*
|
|
@@ -211,27 +211,47 @@ export type StackHeaderOptions = Omit<
|
|
|
211
211
|
*/
|
|
212
212
|
headerBackTitleStyle?: StyleProp<TextStyle>;
|
|
213
213
|
/**
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
|
|
218
|
-
|
|
214
|
+
* Icon to display in the header in the back button.
|
|
215
|
+
*
|
|
216
|
+
* Supported types:
|
|
217
|
+
* - image: custom image source
|
|
218
|
+
* - sfSymbol: SF Symbol icon (iOS only)
|
|
219
|
+
* - materialSymbol: material symbol icon (Android only)
|
|
220
|
+
* - React Node: function that returns a React Element
|
|
221
|
+
*
|
|
222
|
+
* Defaults to back icon image for the platform
|
|
223
|
+
* - A chevron on iOS
|
|
224
|
+
* - An arrow on Android
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```js
|
|
228
|
+
* headerBackIcon: {
|
|
229
|
+
* type: 'image',
|
|
230
|
+
* source: require('./back-icon.png'),
|
|
231
|
+
* }
|
|
232
|
+
* ```
|
|
233
|
+
*/
|
|
234
|
+
headerBackIcon?:
|
|
235
|
+
| Icon
|
|
236
|
+
| ((props: { tintColor: ColorValue | undefined }) => React.ReactNode);
|
|
219
237
|
};
|
|
220
238
|
|
|
221
239
|
export type StackHeaderProps = {
|
|
222
240
|
/**
|
|
223
241
|
* Options for the back button.
|
|
224
242
|
*/
|
|
225
|
-
back?:
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
243
|
+
back?:
|
|
244
|
+
| {
|
|
245
|
+
/**
|
|
246
|
+
* Title of the previous screen.
|
|
247
|
+
*/
|
|
248
|
+
title: string | undefined;
|
|
249
|
+
/**
|
|
250
|
+
* The `href` to use for the anchor tag on web
|
|
251
|
+
*/
|
|
252
|
+
href: string | undefined;
|
|
253
|
+
}
|
|
254
|
+
| undefined;
|
|
235
255
|
/**
|
|
236
256
|
* Animated nodes representing the progress of the animation.
|
|
237
257
|
*/
|
|
@@ -258,26 +278,26 @@ export type StackHeaderRightProps = {
|
|
|
258
278
|
/**
|
|
259
279
|
* Tint color for the header button.
|
|
260
280
|
*/
|
|
261
|
-
tintColor?: ColorValue;
|
|
281
|
+
tintColor?: ColorValue | undefined;
|
|
262
282
|
/**
|
|
263
283
|
* Color for material ripple (Android >= 5.0 only).
|
|
264
284
|
*/
|
|
265
|
-
pressColor?: ColorValue;
|
|
285
|
+
pressColor?: ColorValue | undefined;
|
|
266
286
|
/**
|
|
267
287
|
* Opacity when the button is pressed, used when ripple is not supported.
|
|
268
288
|
*/
|
|
269
|
-
pressOpacity?: number;
|
|
289
|
+
pressOpacity?: number | undefined;
|
|
270
290
|
/**
|
|
271
291
|
* Whether it's possible to navigate back in stack.
|
|
272
292
|
*/
|
|
273
|
-
canGoBack?: boolean;
|
|
293
|
+
canGoBack?: boolean | undefined;
|
|
274
294
|
};
|
|
275
295
|
|
|
276
296
|
export type StackHeaderLeftProps = HeaderBackButtonProps & {
|
|
277
297
|
/**
|
|
278
298
|
* Whether it's possible to navigate back in stack.
|
|
279
299
|
*/
|
|
280
|
-
canGoBack?: boolean;
|
|
300
|
+
canGoBack?: boolean | undefined;
|
|
281
301
|
};
|
|
282
302
|
|
|
283
303
|
export type StackDescriptor = Descriptor<
|
|
@@ -330,9 +350,6 @@ export type StackNavigationOptions = StackHeaderOptions &
|
|
|
330
350
|
* You can also specify `{ backgroundColor: 'transparent' }` to make the previous screen visible underneath.
|
|
331
351
|
* This is useful to implement things like modal dialogs.
|
|
332
352
|
*
|
|
333
|
-
* You should also specify `detachPreviousScreen: false` in options when using a transparent background
|
|
334
|
-
* so that the previous screen isn't detached and stays below the current screen.
|
|
335
|
-
*
|
|
336
353
|
* You might also need to change the animation of the screen using `cardStyleInterpolator`
|
|
337
354
|
* so that the previous screen isn't transformed or invisible.
|
|
338
355
|
*/
|
|
@@ -348,7 +365,6 @@ export type StackNavigationOptions = StackHeaderOptions &
|
|
|
348
365
|
* - `transparentModal`: Similar to `modal`. This changes following things:
|
|
349
366
|
* - Sets `headerMode` to `screen` for the screen unless specified otherwise.
|
|
350
367
|
* - Sets background color of the screen to transparent, so previous screen is visible
|
|
351
|
-
* - Adjusts the `detachPreviousScreen` option so that the previous screen stays rendered.
|
|
352
368
|
* - Prevents the previous screen from animating from its last position.
|
|
353
369
|
* - Changes the screen animation to a vertical slide animation.
|
|
354
370
|
*
|
|
@@ -390,43 +406,29 @@ export type StackNavigationOptions = StackHeaderOptions &
|
|
|
390
406
|
* Not supported on Web.
|
|
391
407
|
*/
|
|
392
408
|
gestureVelocityImpact?: number;
|
|
393
|
-
/**
|
|
394
|
-
* Whether to detach the previous screen from the view hierarchy to save memory.
|
|
395
|
-
* Set it to `false` if you need the previous screen to be seen through the active screen.
|
|
396
|
-
* Only applicable if `detachInactiveScreens` isn't set to `false`.
|
|
397
|
-
* Defaults to `false` for the last screen for modals, otherwise `true`.
|
|
398
|
-
*/
|
|
399
|
-
detachPreviousScreen?: boolean;
|
|
400
409
|
/**
|
|
401
410
|
* If `false`, the keyboard will NOT automatically dismiss when navigating to a new screen from this screen.
|
|
402
411
|
* Defaults to `true`.
|
|
403
412
|
*/
|
|
404
413
|
keyboardHandlingEnabled?: boolean;
|
|
414
|
+
|
|
405
415
|
/**
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
*
|
|
416
|
+
* What should happen when screens become inactive.
|
|
417
|
+
* - `pause`: Effects are cleaned up
|
|
418
|
+
* - `unmount`: Screen is unmounted
|
|
419
|
+
* - `none`: Screen renders normally
|
|
409
420
|
*
|
|
410
|
-
*
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
* Whether the home indicator should prefer to stay hidden on this screen. Defaults to `false`.
|
|
421
|
+
* Defaults to `pause`.
|
|
422
|
+
*
|
|
423
|
+
* Preloaded screens won't be paused until after navigated to.
|
|
424
|
+
* This makes sure that effects are run to initialize the screen.
|
|
415
425
|
*
|
|
416
|
-
*
|
|
426
|
+
* Screens with nested navigators and last 2 screens won't be unmounted.
|
|
417
427
|
*/
|
|
418
|
-
|
|
428
|
+
inactiveBehavior?: 'pause' | 'unmount' | 'none' | undefined;
|
|
419
429
|
};
|
|
420
430
|
|
|
421
|
-
export type StackNavigationConfig = {
|
|
422
|
-
/**
|
|
423
|
-
* Whether inactive screens should be detached from the view hierarchy to save memory.
|
|
424
|
-
* This will have no effect if you disable `react-native-screens`.
|
|
425
|
-
*
|
|
426
|
-
* Defaults to `true`.
|
|
427
|
-
*/
|
|
428
|
-
detachInactiveScreens?: boolean;
|
|
429
|
-
};
|
|
431
|
+
export type StackNavigationConfig = {};
|
|
430
432
|
|
|
431
433
|
export type TransitionSpec =
|
|
432
434
|
| {
|
|
@@ -458,12 +460,14 @@ export type StackCardInterpolationProps = {
|
|
|
458
460
|
* Values for the screen after this one in the stack.
|
|
459
461
|
* This can be `undefined` in case the screen animating is the last one.
|
|
460
462
|
*/
|
|
461
|
-
next?:
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
463
|
+
next?:
|
|
464
|
+
| {
|
|
465
|
+
/**
|
|
466
|
+
* Animated node representing the progress value of the next screen.
|
|
467
|
+
*/
|
|
468
|
+
progress: Animated.AnimatedInterpolation<number>;
|
|
469
|
+
}
|
|
470
|
+
| undefined;
|
|
467
471
|
/**
|
|
468
472
|
* The index of the card with this interpolation in the stack.
|
|
469
473
|
*/
|
|
@@ -537,12 +541,14 @@ export type StackHeaderInterpolationProps = {
|
|
|
537
541
|
* Values for the screen after this one in the stack.
|
|
538
542
|
* This can be `undefined` in case the screen animating is the last one.
|
|
539
543
|
*/
|
|
540
|
-
next?:
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
544
|
+
next?:
|
|
545
|
+
| {
|
|
546
|
+
/**
|
|
547
|
+
* Animated node representing the progress value of the next screen.
|
|
548
|
+
*/
|
|
549
|
+
progress: Animated.AnimatedInterpolation<number>;
|
|
550
|
+
}
|
|
551
|
+
| undefined;
|
|
546
552
|
/**
|
|
547
553
|
* Writing direction of the layout.
|
|
548
554
|
*/
|
|
@@ -17,7 +17,7 @@ export const gestureActivationCriteria = ({
|
|
|
17
17
|
}: {
|
|
18
18
|
direction: LocaleDirection;
|
|
19
19
|
gestureDirection: GestureDirection;
|
|
20
|
-
gestureResponseDistance?: number;
|
|
20
|
+
gestureResponseDistance?: number | undefined;
|
|
21
21
|
layout: Layout;
|
|
22
22
|
}) => {
|
|
23
23
|
const enableTrackpadTwoFingerGesture = true;
|
|
@@ -3,7 +3,7 @@ import * as React from 'react';
|
|
|
3
3
|
import { CardAnimationContext } from './CardAnimationContext';
|
|
4
4
|
|
|
5
5
|
export function useCardAnimation() {
|
|
6
|
-
const animation = React.
|
|
6
|
+
const animation = React.use(CardAnimationContext);
|
|
7
7
|
|
|
8
8
|
if (animation === undefined) {
|
|
9
9
|
throw new Error(
|
|
@@ -3,7 +3,7 @@ import * as React from 'react';
|
|
|
3
3
|
import { GestureHandlerRefContext } from './GestureHandlerRefContext';
|
|
4
4
|
|
|
5
5
|
export function useGestureHandlerRef() {
|
|
6
|
-
const ref = React.
|
|
6
|
+
const ref = React.use(GestureHandlerRefContext);
|
|
7
7
|
|
|
8
8
|
if (ref === undefined) {
|
|
9
9
|
throw new Error(
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { type HostInstance, Keyboard, TextInput } from 'react-native';
|
|
3
3
|
|
|
4
|
-
export function useKeyboardManager(
|
|
4
|
+
export function useKeyboardManager({
|
|
5
|
+
enabled,
|
|
6
|
+
focused,
|
|
7
|
+
}: {
|
|
8
|
+
enabled: boolean;
|
|
9
|
+
focused: boolean;
|
|
10
|
+
}) {
|
|
5
11
|
// Numeric id of the previously focused text input
|
|
6
12
|
// When a gesture didn't change the tab, we can restore the focused input with this
|
|
7
13
|
const previouslyFocusedTextInputRef = React.useRef<HostInstance>(undefined);
|
|
8
14
|
const startTimestampRef = React.useRef<number>(0);
|
|
9
|
-
const keyboardTimeoutRef =
|
|
15
|
+
const keyboardTimeoutRef =
|
|
16
|
+
React.useRef<ReturnType<typeof setTimeout>>(undefined);
|
|
17
|
+
const enabledRef = React.useRef(enabled);
|
|
10
18
|
|
|
11
19
|
const clearKeyboardTimeout = React.useCallback(() => {
|
|
12
20
|
if (keyboardTimeoutRef.current !== undefined) {
|
|
@@ -16,7 +24,7 @@ export function useKeyboardManager(isEnabled: () => boolean) {
|
|
|
16
24
|
}, []);
|
|
17
25
|
|
|
18
26
|
const onPageChangeStart = React.useCallback(() => {
|
|
19
|
-
if (!
|
|
27
|
+
if (!enabledRef.current) {
|
|
20
28
|
return;
|
|
21
29
|
}
|
|
22
30
|
|
|
@@ -32,37 +40,10 @@ export function useKeyboardManager(isEnabled: () => boolean) {
|
|
|
32
40
|
|
|
33
41
|
// Store timestamp for touch start
|
|
34
42
|
startTimestampRef.current = Date.now();
|
|
35
|
-
}, [clearKeyboardTimeout
|
|
36
|
-
|
|
37
|
-
const onPageChangeConfirm = React.useCallback(
|
|
38
|
-
(force: boolean) => {
|
|
39
|
-
if (!isEnabled()) {
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
clearKeyboardTimeout();
|
|
44
|
-
|
|
45
|
-
if (force) {
|
|
46
|
-
// Always dismiss input, even if we don't have a ref to it
|
|
47
|
-
// We might not have the ref if onPageChangeStart was never called
|
|
48
|
-
// This can happen if page change was not from a gesture
|
|
49
|
-
Keyboard.dismiss();
|
|
50
|
-
} else {
|
|
51
|
-
const input = previouslyFocusedTextInputRef.current;
|
|
52
|
-
|
|
53
|
-
// Dismiss the keyboard only if an input was a focused before
|
|
54
|
-
// This makes sure we don't dismiss input on going back and focusing an input
|
|
55
|
-
input?.blur();
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Cleanup the ID on successful page change
|
|
59
|
-
previouslyFocusedTextInputRef.current = undefined;
|
|
60
|
-
},
|
|
61
|
-
[clearKeyboardTimeout, isEnabled]
|
|
62
|
-
);
|
|
43
|
+
}, [clearKeyboardTimeout]);
|
|
63
44
|
|
|
64
45
|
const onPageChangeCancel = React.useCallback(() => {
|
|
65
|
-
if (!
|
|
46
|
+
if (!enabledRef.current) {
|
|
66
47
|
return;
|
|
67
48
|
}
|
|
68
49
|
|
|
@@ -89,7 +70,60 @@ export function useKeyboardManager(isEnabled: () => boolean) {
|
|
|
89
70
|
previouslyFocusedTextInputRef.current = undefined;
|
|
90
71
|
}
|
|
91
72
|
}
|
|
92
|
-
}, [clearKeyboardTimeout
|
|
73
|
+
}, [clearKeyboardTimeout]);
|
|
74
|
+
|
|
75
|
+
const onPageChangeConfirm = React.useCallback(
|
|
76
|
+
({
|
|
77
|
+
gesture,
|
|
78
|
+
active,
|
|
79
|
+
closing,
|
|
80
|
+
}: {
|
|
81
|
+
gesture: boolean;
|
|
82
|
+
active: boolean;
|
|
83
|
+
closing: boolean;
|
|
84
|
+
}) => {
|
|
85
|
+
if (!enabledRef.current) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!closing) {
|
|
90
|
+
onPageChangeCancel();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
clearKeyboardTimeout();
|
|
95
|
+
|
|
96
|
+
if (!gesture) {
|
|
97
|
+
// Always dismiss input, even if we don't have a ref to it
|
|
98
|
+
// We might not have the ref if onPageChangeStart was never called
|
|
99
|
+
// This can happen if page change was not from a gesture
|
|
100
|
+
Keyboard.dismiss();
|
|
101
|
+
} else if (active) {
|
|
102
|
+
const input = previouslyFocusedTextInputRef.current;
|
|
103
|
+
|
|
104
|
+
// Dismiss the keyboard only if an input was a focused before
|
|
105
|
+
// This makes sure we don't dismiss input on going back and focusing an input
|
|
106
|
+
input?.blur();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Cleanup the ID on successful page change
|
|
110
|
+
previouslyFocusedTextInputRef.current = undefined;
|
|
111
|
+
},
|
|
112
|
+
[clearKeyboardTimeout, onPageChangeCancel]
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
// Dismiss keyboard when screen loses focus (e.g. when pushing a new screen).
|
|
116
|
+
// This handles the "navigate forward" case so we don't dismiss the new screen's
|
|
117
|
+
// auto-focused input from handleTransition.
|
|
118
|
+
React.useLayoutEffect(() => {
|
|
119
|
+
if (enabledRef.current && !focused) {
|
|
120
|
+
Keyboard.dismiss();
|
|
121
|
+
}
|
|
122
|
+
}, [focused]);
|
|
123
|
+
|
|
124
|
+
React.useLayoutEffect(() => {
|
|
125
|
+
enabledRef.current = enabled;
|
|
126
|
+
});
|
|
93
127
|
|
|
94
128
|
React.useEffect(() => {
|
|
95
129
|
return () => clearKeyboardTimeout();
|
|
@@ -41,8 +41,8 @@ export const Header = React.memo(function Header({
|
|
|
41
41
|
[navigation, route.key]
|
|
42
42
|
);
|
|
43
43
|
|
|
44
|
-
const isModal = React.
|
|
45
|
-
const isParentHeaderShown = React.
|
|
44
|
+
const isModal = React.use(ModalPresentationContext);
|
|
45
|
+
const isParentHeaderShown = React.use(HeaderShownContext);
|
|
46
46
|
|
|
47
47
|
const statusBarHeight =
|
|
48
48
|
options.headerStatusBarHeight !== undefined
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getHeaderTitle, HeaderBackContext } from '@react-navigation/elements';
|
|
2
|
+
import { ActivityView } from '@react-navigation/elements/internal';
|
|
2
3
|
import {
|
|
3
4
|
NavigationProvider,
|
|
4
5
|
type ParamListBase,
|
|
@@ -43,7 +44,7 @@ export function HeaderContainer({
|
|
|
43
44
|
style,
|
|
44
45
|
}: Props) {
|
|
45
46
|
const focusedRoute = getFocusedRoute();
|
|
46
|
-
const parentHeaderBack = React.
|
|
47
|
+
const parentHeaderBack = React.use(HeaderBackContext);
|
|
47
48
|
const { buildHref } = useLinkBuilder();
|
|
48
49
|
|
|
49
50
|
return (
|
|
@@ -156,7 +157,6 @@ export function HeaderContainer({
|
|
|
156
157
|
}
|
|
157
158
|
: undefined
|
|
158
159
|
}
|
|
159
|
-
aria-hidden={!isFocused}
|
|
160
160
|
style={[
|
|
161
161
|
// Avoid positioning the focused header absolutely
|
|
162
162
|
// Otherwise accessibility tools don't seem to be able to find it
|
|
@@ -168,7 +168,12 @@ export function HeaderContainer({
|
|
|
168
168
|
},
|
|
169
169
|
]}
|
|
170
170
|
>
|
|
171
|
-
|
|
171
|
+
<ActivityView
|
|
172
|
+
mode={isFocused ? 'normal' : 'inert'}
|
|
173
|
+
visible={true}
|
|
174
|
+
>
|
|
175
|
+
{header !== undefined ? header(props) : <Header {...props} />}
|
|
176
|
+
</ActivityView>
|
|
172
177
|
</View>
|
|
173
178
|
</NavigationProvider>
|
|
174
179
|
);
|
|
@@ -20,8 +20,8 @@ type Props = Omit<StackHeaderOptions, 'headerStatusBarHeight'> & {
|
|
|
20
20
|
headerStatusBarHeight: number;
|
|
21
21
|
title: string;
|
|
22
22
|
modal: boolean;
|
|
23
|
-
onGoBack?: () => void;
|
|
24
|
-
backHref?: string;
|
|
23
|
+
onGoBack?: (() => void) | undefined;
|
|
24
|
+
backHref?: string | undefined;
|
|
25
25
|
progress: SceneProgress;
|
|
26
26
|
styleInterpolator: StackHeaderStyleInterpolator;
|
|
27
27
|
};
|
|
@@ -40,7 +40,7 @@ export function HeaderSegment(props: Props) {
|
|
|
40
40
|
? (props: HeaderBackButtonProps) => <HeaderBackButton {...props} />
|
|
41
41
|
: undefined,
|
|
42
42
|
headerRight: right,
|
|
43
|
-
|
|
43
|
+
headerBackIcon,
|
|
44
44
|
headerBackTitle,
|
|
45
45
|
headerBackButtonDisplayMode,
|
|
46
46
|
headerBackTruncatedTitle,
|
|
@@ -93,7 +93,7 @@ export function HeaderSegment(props: Props) {
|
|
|
93
93
|
left({
|
|
94
94
|
...props,
|
|
95
95
|
href: backHref,
|
|
96
|
-
|
|
96
|
+
icon: headerBackIcon,
|
|
97
97
|
accessibilityLabel: headerBackAccessibilityLabel,
|
|
98
98
|
testID: headerBackTestID,
|
|
99
99
|
allowFontScaling: headerBackAllowFontScaling,
|
package/src/views/Stack/Card.tsx
CHANGED
|
@@ -58,7 +58,7 @@ type Props = {
|
|
|
58
58
|
overlayEnabled: boolean;
|
|
59
59
|
shadowEnabled: boolean | undefined;
|
|
60
60
|
gestureEnabled: boolean;
|
|
61
|
-
gestureResponseDistance?: number;
|
|
61
|
+
gestureResponseDistance?: number | undefined;
|
|
62
62
|
gestureVelocityImpact: number | undefined;
|
|
63
63
|
transitionSpec: {
|
|
64
64
|
open: TransitionSpec;
|
|
@@ -66,8 +66,8 @@ type Props = {
|
|
|
66
66
|
};
|
|
67
67
|
preloaded: boolean;
|
|
68
68
|
styleInterpolator: StackCardStyleInterpolator;
|
|
69
|
-
containerStyle?: StyleProp<ViewStyle
|
|
70
|
-
contentStyle?: StyleProp<ViewStyle
|
|
69
|
+
containerStyle?: StyleProp<ViewStyle> | undefined;
|
|
70
|
+
contentStyle?: StyleProp<ViewStyle> | undefined;
|
|
71
71
|
};
|
|
72
72
|
|
|
73
73
|
const GESTURE_VELOCITY_IMPACT = 0.3;
|
|
@@ -151,14 +151,14 @@ function Card({
|
|
|
151
151
|
containerStyle: customContainerStyle,
|
|
152
152
|
contentStyle,
|
|
153
153
|
}: Props) {
|
|
154
|
-
const [, forceUpdate] = React.useReducer((x) => x + 1, 0);
|
|
155
|
-
|
|
156
154
|
const didInitiallyAnimate = React.useRef(false);
|
|
157
155
|
const lastToValueRef = React.useRef<number | undefined>(undefined);
|
|
158
156
|
|
|
159
157
|
const animationHandleRef = React.useRef<number | undefined>(undefined);
|
|
160
158
|
const pendingGestureCallbackRef =
|
|
161
159
|
React.useRef<ReturnType<typeof setTimeout>>(undefined);
|
|
160
|
+
const pendingOnCloseCallbackRef =
|
|
161
|
+
React.useRef<ReturnType<typeof setTimeout>>(undefined);
|
|
162
162
|
|
|
163
163
|
const [isClosing] = React.useState(() => new Animated.Value(FALSE));
|
|
164
164
|
|
|
@@ -218,10 +218,8 @@ function Card({
|
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
animationHandleRef.current = requestAnimationFrame(() => {
|
|
221
|
-
if
|
|
222
|
-
|
|
223
|
-
forceUpdate();
|
|
224
|
-
}
|
|
221
|
+
// Make sure to re-open screen if it wasn't removed
|
|
222
|
+
maybeAnimate();
|
|
225
223
|
});
|
|
226
224
|
};
|
|
227
225
|
|
|
@@ -249,6 +247,8 @@ function Card({
|
|
|
249
247
|
({ nativeEvent }: PanGestureHandlerGestureEvent) => {
|
|
250
248
|
switch (nativeEvent.state) {
|
|
251
249
|
case GestureState.ACTIVE:
|
|
250
|
+
clearTimeout(pendingGestureCallbackRef.current);
|
|
251
|
+
clearTimeout(pendingOnCloseCallbackRef.current);
|
|
252
252
|
isSwiping.setValue(TRUE);
|
|
253
253
|
onGestureBegin?.();
|
|
254
254
|
break;
|
|
@@ -305,10 +305,13 @@ function Card({
|
|
|
305
305
|
pendingGestureCallbackRef.current = setTimeout(() => {
|
|
306
306
|
onClose();
|
|
307
307
|
|
|
308
|
-
//
|
|
309
|
-
//
|
|
310
|
-
|
|
311
|
-
|
|
308
|
+
// Check if the screen is still closing with a delay
|
|
309
|
+
// So state update from onClose has a chance to go through
|
|
310
|
+
// If route wasn't removed after onClose, re-open it
|
|
311
|
+
pendingOnCloseCallbackRef.current = setTimeout(() => {
|
|
312
|
+
maybeAnimate();
|
|
313
|
+
}, 32);
|
|
314
|
+
}, 16);
|
|
312
315
|
}
|
|
313
316
|
|
|
314
317
|
onGestureEnd?.();
|
|
@@ -350,17 +353,15 @@ function Card({
|
|
|
350
353
|
}
|
|
351
354
|
|
|
352
355
|
clearTimeout(pendingGestureCallbackRef.current);
|
|
356
|
+
clearTimeout(pendingOnCloseCallbackRef.current);
|
|
353
357
|
};
|
|
354
|
-
|
|
355
|
-
// We only want to clean up the animation on unmount
|
|
356
358
|
}, []);
|
|
357
359
|
|
|
358
|
-
const timeoutRef = React.useRef<ReturnType<typeof setTimeout
|
|
360
|
+
const timeoutRef = React.useRef<ReturnType<typeof setTimeout>>(undefined);
|
|
359
361
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
}
|
|
362
|
+
const maybeAnimate = useLatestCallback(() => {
|
|
363
|
+
clearTimeout(pendingGestureCallbackRef.current);
|
|
364
|
+
clearTimeout(pendingOnCloseCallbackRef.current);
|
|
364
365
|
|
|
365
366
|
if (!didInitiallyAnimate.current) {
|
|
366
367
|
// Animate the card in on initial mount
|
|
@@ -368,9 +369,8 @@ function Card({
|
|
|
368
369
|
// rending of the screen is done. This is especially important
|
|
369
370
|
// in the new architecture
|
|
370
371
|
// cf., https://github.com/react-navigation/react-navigation/issues/12401
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
}
|
|
372
|
+
clearTimeout(timeoutRef.current);
|
|
373
|
+
|
|
374
374
|
timeoutRef.current = setTimeout(() => {
|
|
375
375
|
didInitiallyAnimate.current = true;
|
|
376
376
|
animate({ closing });
|
|
@@ -410,6 +410,14 @@ function Card({
|
|
|
410
410
|
animate({ closing });
|
|
411
411
|
}
|
|
412
412
|
}
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
React.useEffect(() => {
|
|
416
|
+
if (preloaded) {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
maybeAnimate();
|
|
413
421
|
|
|
414
422
|
previousPropsRef.current = {
|
|
415
423
|
opening,
|
|
@@ -428,6 +436,7 @@ function Card({
|
|
|
428
436
|
layout,
|
|
429
437
|
opening,
|
|
430
438
|
preloaded,
|
|
439
|
+
maybeAnimate,
|
|
431
440
|
]);
|
|
432
441
|
|
|
433
442
|
const interpolationProps = React.useMemo(
|
|
@@ -6,7 +6,6 @@ type Props = {
|
|
|
6
6
|
active: boolean;
|
|
7
7
|
animated: boolean;
|
|
8
8
|
isNextScreenTransparent: boolean;
|
|
9
|
-
detachCurrentScreen: boolean;
|
|
10
9
|
children: React.ReactNode;
|
|
11
10
|
};
|
|
12
11
|
|
|
@@ -14,14 +13,7 @@ export type CardA11yWrapperRef = { setInert: (value: boolean) => void };
|
|
|
14
13
|
|
|
15
14
|
export const CardA11yWrapper = React.forwardRef(
|
|
16
15
|
(
|
|
17
|
-
{
|
|
18
|
-
focused,
|
|
19
|
-
active,
|
|
20
|
-
animated,
|
|
21
|
-
isNextScreenTransparent,
|
|
22
|
-
detachCurrentScreen,
|
|
23
|
-
children,
|
|
24
|
-
}: Props,
|
|
16
|
+
{ focused, active, animated, isNextScreenTransparent, children }: Props,
|
|
25
17
|
ref: React.Ref<CardA11yWrapperRef>
|
|
26
18
|
) => {
|
|
27
19
|
// Manage this in separate component to avoid re-rendering card during gestures
|
|
@@ -30,11 +22,7 @@ export const CardA11yWrapper = React.forwardRef(
|
|
|
30
22
|
|
|
31
23
|
React.useImperativeHandle(ref, () => ({ setInert }), []);
|
|
32
24
|
|
|
33
|
-
const isHidden =
|
|
34
|
-
!animated &&
|
|
35
|
-
isNextScreenTransparent === false &&
|
|
36
|
-
detachCurrentScreen !== false &&
|
|
37
|
-
!focused;
|
|
25
|
+
const isHidden = !animated && isNextScreenTransparent === false && !focused;
|
|
38
26
|
|
|
39
27
|
return (
|
|
40
28
|
<View
|