-
Notifications
You must be signed in to change notification settings - Fork 2.9k
/
index.tsx
107 lines (94 loc) · 4.22 KB
/
index.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import type {ParamListBase, RouteProp, StackActionHelpers, StackNavigationState} from '@react-navigation/native';
import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native';
import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack';
import {StackView} from '@react-navigation/stack';
import React, {useEffect, useMemo} from 'react';
import {View} from 'react-native';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute';
import navigationRef from '@libs/Navigation/navigationRef';
import type {RootStackParamList, State} from '@libs/Navigation/types';
import NAVIGATORS from '@src/NAVIGATORS';
import SCREENS from '@src/SCREENS';
import CustomRouter from './CustomRouter';
import type {ResponsiveStackNavigatorProps, ResponsiveStackNavigatorRouterOptions} from './types';
type Routes = StackNavigationState<ParamListBase>['routes'];
function reduceCentralPaneRoutes(routes: Routes): Routes {
const result: Routes = [];
let count = 0;
const reverseRoutes = [...routes].reverse();
reverseRoutes.forEach((route) => {
if (route.name === NAVIGATORS.CENTRAL_PANE_NAVIGATOR) {
// Remove all central pane routes except the last 3. This will improve performance.
if (count < 3) {
result.push(route);
count++;
}
} else {
result.push(route);
}
});
return result.reverse();
}
function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) {
const {isSmallScreenWidth} = useWindowDimensions();
const styles = useThemeStyles();
const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder<
StackNavigationState<ParamListBase>,
ResponsiveStackNavigatorRouterOptions,
StackActionHelpers<ParamListBase>,
StackNavigationOptions,
StackNavigationEventMap
>(CustomRouter, {
children: props.children,
screenOptions: props.screenOptions,
initialRouteName: props.initialRouteName,
});
useEffect(() => {
if (!navigationRef.isReady()) {
return;
}
navigationRef.resetRoot(navigationRef.getRootState());
}, [isSmallScreenWidth]);
const {stateToRender, searchRoute} = useMemo(() => {
const routes = reduceCentralPaneRoutes(state.routes);
// On narrow layout, if we are on /search route we want to hide the search central pane route.
if (isSmallScreenWidth) {
const isSearchCentralPane = (route: RouteProp<ParamListBase>) => getTopmostCentralPaneRoute({routes: [route]} as State<RootStackParamList>)?.name === SCREENS.SEARCH.CENTRAL_PANE;
const lastRoute = routes[routes.length - 1];
const lastSearchCentralPane = isSearchCentralPane(lastRoute) ? lastRoute : undefined;
const filteredRoutes = routes.filter((route) => !isSearchCentralPane(route));
return {
stateToRender: {
...state,
index: filteredRoutes.length - 1,
routes: filteredRoutes,
},
searchRoute: lastSearchCentralPane,
};
}
return {
stateToRender: {
...state,
index: routes.length - 1,
routes: [...routes],
},
searchRoute: undefined,
};
}, [state, isSmallScreenWidth]);
return (
<NavigationContent>
<StackView
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
state={stateToRender}
descriptors={descriptors}
navigation={navigation}
/>
{searchRoute && <View style={styles.dNone}>{descriptors[searchRoute.key].render()}</View>}
</NavigationContent>
);
}
ResponsiveStackNavigator.displayName = 'ResponsiveStackNavigator';
export default createNavigatorFactory<StackNavigationState<ParamListBase>, StackNavigationOptions, StackNavigationEventMap, typeof ResponsiveStackNavigator>(ResponsiveStackNavigator);