react-navigation-reanimated-top-tabs 0.2.0

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 (131) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +26 -0
  3. package/lib/commonjs/components/ReanimatedTopTab/AnimationHelper.js +76 -0
  4. package/lib/commonjs/components/ReanimatedTopTab/AnimationHelper.js.map +1 -0
  5. package/lib/commonjs/components/ReanimatedTopTab/ReanimatedTabView.js +125 -0
  6. package/lib/commonjs/components/ReanimatedTopTab/ReanimatedTabView.js.map +1 -0
  7. package/lib/commonjs/components/ReanimatedTopTab/types.js +8 -0
  8. package/lib/commonjs/components/ReanimatedTopTab/types.js.map +1 -0
  9. package/lib/commonjs/components/elements/TabBarBaseComponent.js +71 -0
  10. package/lib/commonjs/components/elements/TabBarBaseComponent.js.map +1 -0
  11. package/lib/commonjs/components/elements/TabBarLabelBaseComponent.js +48 -0
  12. package/lib/commonjs/components/elements/TabBarLabelBaseComponent.js.map +1 -0
  13. package/lib/commonjs/components/wrappers/GestureWrapper.js +100 -0
  14. package/lib/commonjs/components/wrappers/GestureWrapper.js.map +1 -0
  15. package/lib/commonjs/components/wrappers/ScreenWrapper.js +34 -0
  16. package/lib/commonjs/components/wrappers/ScreenWrapper.js.map +1 -0
  17. package/lib/commonjs/components/wrappers/ScrollView.js +58 -0
  18. package/lib/commonjs/components/wrappers/ScrollView.js.map +1 -0
  19. package/lib/commonjs/context/TopTabContext.hooks.js +48 -0
  20. package/lib/commonjs/context/TopTabContext.hooks.js.map +1 -0
  21. package/lib/commonjs/context/TopTabContext.js +86 -0
  22. package/lib/commonjs/context/TopTabContext.js.map +1 -0
  23. package/lib/commonjs/hooks/TopTab.hooks.js +120 -0
  24. package/lib/commonjs/hooks/TopTab.hooks.js.map +1 -0
  25. package/lib/commonjs/index.js +92 -0
  26. package/lib/commonjs/index.js.map +1 -0
  27. package/lib/commonjs/navigator/createReanimatedTopTabNavigator.js +141 -0
  28. package/lib/commonjs/navigator/createReanimatedTopTabNavigator.js.map +1 -0
  29. package/lib/commonjs/types.js +8 -0
  30. package/lib/commonjs/types.js.map +1 -0
  31. package/lib/module/components/ReanimatedTopTab/AnimationHelper.js +72 -0
  32. package/lib/module/components/ReanimatedTopTab/AnimationHelper.js.map +1 -0
  33. package/lib/module/components/ReanimatedTopTab/ReanimatedTabView.js +119 -0
  34. package/lib/module/components/ReanimatedTopTab/ReanimatedTabView.js.map +1 -0
  35. package/lib/module/components/ReanimatedTopTab/types.js +4 -0
  36. package/lib/module/components/ReanimatedTopTab/types.js.map +1 -0
  37. package/lib/module/components/elements/TabBarBaseComponent.js +64 -0
  38. package/lib/module/components/elements/TabBarBaseComponent.js.map +1 -0
  39. package/lib/module/components/elements/TabBarLabelBaseComponent.js +41 -0
  40. package/lib/module/components/elements/TabBarLabelBaseComponent.js.map +1 -0
  41. package/lib/module/components/wrappers/GestureWrapper.js +94 -0
  42. package/lib/module/components/wrappers/GestureWrapper.js.map +1 -0
  43. package/lib/module/components/wrappers/ScreenWrapper.js +28 -0
  44. package/lib/module/components/wrappers/ScreenWrapper.js.map +1 -0
  45. package/lib/module/components/wrappers/ScrollView.js +52 -0
  46. package/lib/module/components/wrappers/ScrollView.js.map +1 -0
  47. package/lib/module/context/TopTabContext.hooks.js +44 -0
  48. package/lib/module/context/TopTabContext.hooks.js.map +1 -0
  49. package/lib/module/context/TopTabContext.js +82 -0
  50. package/lib/module/context/TopTabContext.js.map +1 -0
  51. package/lib/module/hooks/TopTab.hooks.js +110 -0
  52. package/lib/module/hooks/TopTab.hooks.js.map +1 -0
  53. package/lib/module/index.js +11 -0
  54. package/lib/module/index.js.map +1 -0
  55. package/lib/module/navigator/createReanimatedTopTabNavigator.js +134 -0
  56. package/lib/module/navigator/createReanimatedTopTabNavigator.js.map +1 -0
  57. package/lib/module/types.js +4 -0
  58. package/lib/module/types.js.map +1 -0
  59. package/lib/typescript/commonjs/package.json +1 -0
  60. package/lib/typescript/commonjs/src/components/ReanimatedTopTab/AnimationHelper.d.ts +11 -0
  61. package/lib/typescript/commonjs/src/components/ReanimatedTopTab/AnimationHelper.d.ts.map +1 -0
  62. package/lib/typescript/commonjs/src/components/ReanimatedTopTab/ReanimatedTabView.d.ts +14 -0
  63. package/lib/typescript/commonjs/src/components/ReanimatedTopTab/ReanimatedTabView.d.ts.map +1 -0
  64. package/lib/typescript/commonjs/src/components/ReanimatedTopTab/types.d.ts +30 -0
  65. package/lib/typescript/commonjs/src/components/ReanimatedTopTab/types.d.ts.map +1 -0
  66. package/lib/typescript/commonjs/src/components/elements/TabBarBaseComponent.d.ts +24 -0
  67. package/lib/typescript/commonjs/src/components/elements/TabBarBaseComponent.d.ts.map +1 -0
  68. package/lib/typescript/commonjs/src/components/elements/TabBarLabelBaseComponent.d.ts +8 -0
  69. package/lib/typescript/commonjs/src/components/elements/TabBarLabelBaseComponent.d.ts.map +1 -0
  70. package/lib/typescript/commonjs/src/components/wrappers/GestureWrapper.d.ts +2 -0
  71. package/lib/typescript/commonjs/src/components/wrappers/GestureWrapper.d.ts.map +1 -0
  72. package/lib/typescript/commonjs/src/components/wrappers/ScreenWrapper.d.ts +6 -0
  73. package/lib/typescript/commonjs/src/components/wrappers/ScreenWrapper.d.ts.map +1 -0
  74. package/lib/typescript/commonjs/src/components/wrappers/ScrollView.d.ts +6 -0
  75. package/lib/typescript/commonjs/src/components/wrappers/ScrollView.d.ts.map +1 -0
  76. package/lib/typescript/commonjs/src/context/TopTabContext.d.ts +4 -0
  77. package/lib/typescript/commonjs/src/context/TopTabContext.d.ts.map +1 -0
  78. package/lib/typescript/commonjs/src/context/TopTabContext.hooks.d.ts +5 -0
  79. package/lib/typescript/commonjs/src/context/TopTabContext.hooks.d.ts.map +1 -0
  80. package/lib/typescript/commonjs/src/hooks/TopTab.hooks.d.ts +33 -0
  81. package/lib/typescript/commonjs/src/hooks/TopTab.hooks.d.ts.map +1 -0
  82. package/lib/typescript/commonjs/src/index.d.ts +10 -0
  83. package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
  84. package/lib/typescript/commonjs/src/navigator/createReanimatedTopTabNavigator.d.ts +4 -0
  85. package/lib/typescript/commonjs/src/navigator/createReanimatedTopTabNavigator.d.ts.map +1 -0
  86. package/lib/typescript/commonjs/src/types.d.ts +56 -0
  87. package/lib/typescript/commonjs/src/types.d.ts.map +1 -0
  88. package/lib/typescript/module/package.json +1 -0
  89. package/lib/typescript/module/src/components/ReanimatedTopTab/AnimationHelper.d.ts +11 -0
  90. package/lib/typescript/module/src/components/ReanimatedTopTab/AnimationHelper.d.ts.map +1 -0
  91. package/lib/typescript/module/src/components/ReanimatedTopTab/ReanimatedTabView.d.ts +14 -0
  92. package/lib/typescript/module/src/components/ReanimatedTopTab/ReanimatedTabView.d.ts.map +1 -0
  93. package/lib/typescript/module/src/components/ReanimatedTopTab/types.d.ts +30 -0
  94. package/lib/typescript/module/src/components/ReanimatedTopTab/types.d.ts.map +1 -0
  95. package/lib/typescript/module/src/components/elements/TabBarBaseComponent.d.ts +24 -0
  96. package/lib/typescript/module/src/components/elements/TabBarBaseComponent.d.ts.map +1 -0
  97. package/lib/typescript/module/src/components/elements/TabBarLabelBaseComponent.d.ts +8 -0
  98. package/lib/typescript/module/src/components/elements/TabBarLabelBaseComponent.d.ts.map +1 -0
  99. package/lib/typescript/module/src/components/wrappers/GestureWrapper.d.ts +2 -0
  100. package/lib/typescript/module/src/components/wrappers/GestureWrapper.d.ts.map +1 -0
  101. package/lib/typescript/module/src/components/wrappers/ScreenWrapper.d.ts +6 -0
  102. package/lib/typescript/module/src/components/wrappers/ScreenWrapper.d.ts.map +1 -0
  103. package/lib/typescript/module/src/components/wrappers/ScrollView.d.ts +6 -0
  104. package/lib/typescript/module/src/components/wrappers/ScrollView.d.ts.map +1 -0
  105. package/lib/typescript/module/src/context/TopTabContext.d.ts +4 -0
  106. package/lib/typescript/module/src/context/TopTabContext.d.ts.map +1 -0
  107. package/lib/typescript/module/src/context/TopTabContext.hooks.d.ts +5 -0
  108. package/lib/typescript/module/src/context/TopTabContext.hooks.d.ts.map +1 -0
  109. package/lib/typescript/module/src/hooks/TopTab.hooks.d.ts +33 -0
  110. package/lib/typescript/module/src/hooks/TopTab.hooks.d.ts.map +1 -0
  111. package/lib/typescript/module/src/index.d.ts +10 -0
  112. package/lib/typescript/module/src/index.d.ts.map +1 -0
  113. package/lib/typescript/module/src/navigator/createReanimatedTopTabNavigator.d.ts +4 -0
  114. package/lib/typescript/module/src/navigator/createReanimatedTopTabNavigator.d.ts.map +1 -0
  115. package/lib/typescript/module/src/types.d.ts +56 -0
  116. package/lib/typescript/module/src/types.d.ts.map +1 -0
  117. package/package.json +204 -0
  118. package/src/components/ReanimatedTopTab/AnimationHelper.ts +94 -0
  119. package/src/components/ReanimatedTopTab/ReanimatedTabView.tsx +200 -0
  120. package/src/components/ReanimatedTopTab/types.ts +29 -0
  121. package/src/components/elements/TabBarBaseComponent.tsx +99 -0
  122. package/src/components/elements/TabBarLabelBaseComponent.tsx +63 -0
  123. package/src/components/wrappers/GestureWrapper.tsx +135 -0
  124. package/src/components/wrappers/ScreenWrapper.tsx +27 -0
  125. package/src/components/wrappers/ScrollView.tsx +59 -0
  126. package/src/context/TopTabContext.hooks.ts +55 -0
  127. package/src/context/TopTabContext.tsx +115 -0
  128. package/src/hooks/TopTab.hooks.ts +112 -0
  129. package/src/index.tsx +15 -0
  130. package/src/navigator/createReanimatedTopTabNavigator.tsx +192 -0
  131. package/src/types.ts +63 -0
@@ -0,0 +1,115 @@
1
+ import { type ReanimatedTopTabNavigation } from '../types';
2
+ import { createContext, memo, useRef } from 'react';
3
+ import { Gesture } from 'react-native-gesture-handler';
4
+ import {
5
+ interpolate,
6
+ useAnimatedReaction,
7
+ useDerivedValue,
8
+ useSharedValue,
9
+ } from 'react-native-reanimated';
10
+ import { useScreenRefs } from '../hooks/TopTab.hooks';
11
+ import { TopTabContextHooks } from './TopTabContext.hooks';
12
+
13
+ export const Context = createContext<ReanimatedTopTabNavigation.ContextType>(
14
+ {} as ReanimatedTopTabNavigation.ContextType
15
+ );
16
+
17
+ export const Provider = memo(
18
+ ({
19
+ children,
20
+ config,
21
+ screenProperties,
22
+ }: ReanimatedTopTabNavigation.TopTabContextProps) => {
23
+ const transformationY = useSharedValue(0);
24
+ const transformationX = useSharedValue(0);
25
+ const currentYPosition = useSharedValue(0);
26
+
27
+ const gestureEnabled = useSharedValue(true);
28
+ const currentScreenIndex = useSharedValue(0);
29
+
30
+ const navHeight = useSharedValue(0);
31
+ const headerHeight = useSharedValue(0);
32
+ const closeOffset = useSharedValue(0);
33
+ const topTabHeight = useSharedValue(0);
34
+
35
+ const topTapNativeRef = useRef(Gesture.Native()).current;
36
+ const screenRefs = useScreenRefs(Object.keys(screenProperties));
37
+
38
+ //Hide header base on config
39
+ const inputRange = useDerivedValue(
40
+ () => config.map((_, idx) => idx),
41
+ [config]
42
+ );
43
+
44
+ const outputRange = useDerivedValue(
45
+ () =>
46
+ config.map((type) => {
47
+ switch (type) {
48
+ case 'normal':
49
+ return 0;
50
+ case 'minimalized':
51
+ return -headerHeight.value;
52
+ default:
53
+ return 0;
54
+ }
55
+ }),
56
+ [config]
57
+ );
58
+
59
+ useAnimatedReaction(
60
+ () => transformationX.value,
61
+ (value) => {
62
+ if (currentYPosition.value === -headerHeight.value) return;
63
+ transformationY.value = interpolate(
64
+ value,
65
+ inputRange.value,
66
+ outputRange.value,
67
+ 'clamp'
68
+ );
69
+ }
70
+ );
71
+
72
+ TopTabContextHooks.useResetApproachingScreenScrollOffset({
73
+ screenRefs,
74
+ currentYPosition,
75
+ screenProperties,
76
+ transformationX,
77
+ });
78
+
79
+ return (
80
+ <Context.Provider
81
+ value={{
82
+ closeOffset,
83
+ config,
84
+ currentScreenIndex,
85
+ currentYPosition,
86
+ gestureEnabled,
87
+ headerHeight,
88
+ navHeight,
89
+ screenProperties,
90
+ topTabHeight,
91
+ topTapNativeRef,
92
+ transformationX,
93
+ transformationY,
94
+ screenRefs,
95
+ }}
96
+ >
97
+ {children({
98
+ screenRefs,
99
+ closeOffset,
100
+ config,
101
+ currentScreenIndex,
102
+ currentYPosition,
103
+ gestureEnabled,
104
+ headerHeight,
105
+ navHeight,
106
+ screenProperties,
107
+ topTabHeight,
108
+ topTapNativeRef,
109
+ transformationX,
110
+ transformationY,
111
+ })}
112
+ </Context.Provider>
113
+ );
114
+ }
115
+ );
@@ -0,0 +1,112 @@
1
+ import { useRoute } from '@react-navigation/native';
2
+ import { Context } from '../context/TopTabContext';
3
+ import { useContext } from 'react';
4
+ import {
5
+ useAnimatedProps,
6
+ useAnimatedScrollHandler,
7
+ useAnimatedStyle,
8
+ useDerivedValue,
9
+ withTiming,
10
+ } from 'react-native-reanimated';
11
+ import { useSafeAreaInsets } from 'react-native-safe-area-context';
12
+ import { useWindowDimensions } from 'react-native';
13
+
14
+ export const useTabContext = () => useContext(Context);
15
+
16
+ export const useScreenGesture = () => {
17
+ const { key } = useRoute();
18
+ const { screenProperties } = useTabContext();
19
+
20
+ const nativeRef = screenProperties[key]?.nativeGesture;
21
+
22
+ if (!nativeRef) throw 'GestureRef does not exist for this route';
23
+
24
+ return nativeRef;
25
+ };
26
+
27
+ export const useScreenScrollable = () => {
28
+ const { key } = useRoute();
29
+ const { height } = useWindowDimensions();
30
+ const { bottom } = useSafeAreaInsets();
31
+ const {
32
+ currentYPosition,
33
+ gestureEnabled,
34
+ headerHeight,
35
+ screenProperties,
36
+ topTabHeight,
37
+ transformationY,
38
+ } = useTabContext();
39
+
40
+ //TODO: Navigation header hook is available if Tabs are rendered inside the Stack (createNavigationStack())
41
+ //useHeaderHeight();
42
+ const navigationHeader = 50;
43
+
44
+ const animatedProps = useAnimatedProps(() => ({
45
+ scrollEnabled:
46
+ !gestureEnabled.value || currentYPosition.value === -headerHeight.value,
47
+ }));
48
+
49
+ const onScroll = useAnimatedScrollHandler(({ contentOffset }) => {
50
+ const scrollPosition = screenProperties[key]?.scrollY;
51
+ if (!scrollPosition)
52
+ throw 'ScrollPosition property does not exist for this route';
53
+ scrollPosition.value = contentOffset.y;
54
+ });
55
+
56
+ const oppositeHeaderState = useDerivedValue(() =>
57
+ transformationY.value >= 0 ? headerHeight.value : 0
58
+ );
59
+
60
+ const style = useAnimatedStyle(() => ({
61
+ minHeight:
62
+ height -
63
+ topTabHeight.value -
64
+ oppositeHeaderState.value -
65
+ navigationHeader,
66
+ }));
67
+
68
+ return {
69
+ animatedProps,
70
+ bounces: false,
71
+ contentContainerStyle: { paddingBottom: bottom },
72
+ onScroll,
73
+ style,
74
+ };
75
+ };
76
+
77
+ export const useScreenProperties = () => {
78
+ const { key } = useRoute();
79
+ const { screenProperties } = useTabContext();
80
+ const screen = screenProperties[key];
81
+ if (!screen) throw 'No screen properties registered for this route';
82
+
83
+ return screen;
84
+ };
85
+
86
+ export const useHeader = () => {
87
+ const { headerHeight, transformationX } = useTabContext();
88
+
89
+ const hideHeader = () => {
90
+ transformationX.value = withTiming(-headerHeight.value);
91
+ };
92
+
93
+ return { hideHeader };
94
+ };
95
+
96
+ export const useScreenRefs = (keys: string[]) => {
97
+ const refs = {
98
+ current: keys.reduce(
99
+ (prev, key) => ({
100
+ ...prev,
101
+ [key]: { current: null },
102
+ }),
103
+ {} as Record<string, { current: any }>
104
+ ),
105
+ };
106
+
107
+ const setRef = (key: string, ref: any) => {
108
+ refs.current = { ...refs.current, [key]: ref };
109
+ };
110
+
111
+ return { setRef, refs };
112
+ };
package/src/index.tsx ADDED
@@ -0,0 +1,15 @@
1
+ export { Provider, Context } from './context/TopTabContext';
2
+ export { createReanimatedTopTabNavigator } from './navigator/createReanimatedTopTabNavigator';
3
+ export { ScrollView } from './components/wrappers/ScrollView';
4
+ export { ScreenWrapper } from './components/wrappers/ScreenWrapper';
5
+ export { GestureWrapper } from './components/wrappers/GestureWrapper';
6
+ export { TabBarBaseComponent } from './components/elements/TabBarBaseComponent';
7
+ export { TabBarLabelBaseComponent } from './components/elements/TabBarLabelBaseComponent';
8
+ export {
9
+ useTabContext,
10
+ useHeader,
11
+ useScreenProperties,
12
+ useScreenScrollable,
13
+ useScreenGesture,
14
+ } from './hooks/TopTab.hooks';
15
+ export { type ReanimatedTopTabNavigation } from './types';
@@ -0,0 +1,192 @@
1
+ import {
2
+ createNavigatorFactory,
3
+ type ParamListBase,
4
+ TabActions,
5
+ type TabNavigationState,
6
+ TabRouter,
7
+ useNavigationBuilder,
8
+ } from '@react-navigation/native';
9
+ import type { DefaultRouterOptions } from '@react-navigation/routers';
10
+ import { GestureWrapper } from '../components/wrappers/GestureWrapper';
11
+ import {
12
+ type RenderTabsParams,
13
+ TabBarBaseComponent,
14
+ } from '../components/elements/TabBarBaseComponent';
15
+ import { Provider } from '../context/TopTabContext';
16
+ import { type ReanimatedTopTabNavigation } from '../types';
17
+ import { omit } from 'lodash';
18
+ import { useCallback, useMemo, useRef } from 'react';
19
+ import { Gesture } from 'react-native-gesture-handler';
20
+ import Reanimated, {
21
+ makeMutable,
22
+ type SharedValue,
23
+ } from 'react-native-reanimated';
24
+ import type { ReanimatedTabViewTypes } from '../components/ReanimatedTopTab/types';
25
+ import { ReanimatedTabView } from '../components/ReanimatedTopTab/ReanimatedTabView';
26
+
27
+ const TabViewNavigator = ({
28
+ HeaderComponent,
29
+ TabBarComponent = TabBarBaseComponent,
30
+ children,
31
+ config,
32
+ initialRouteName,
33
+ screenOptions = {},
34
+ }: ReanimatedTopTabNavigation.TabViewNavigatorProps) => {
35
+ const { NavigationContent, descriptors, navigation, state } =
36
+ useNavigationBuilder<
37
+ TabNavigationState<ParamListBase>,
38
+ DefaultRouterOptions,
39
+ {},
40
+ ReanimatedTopTabNavigation.NavigationOptions,
41
+ {}
42
+ >(TabRouter, {
43
+ children,
44
+ defaultScreenOptions: screenOptions,
45
+ initialRouteName,
46
+ screenOptions,
47
+ });
48
+
49
+ let _config: string[] = config!;
50
+
51
+ if (!config) {
52
+ _config = state.routes.map(() => 'normal');
53
+ }
54
+ const screenProperties = useRef(
55
+ state.routes.reduce(
56
+ (prev, route) => ({
57
+ ...prev,
58
+ [route.key]: {
59
+ innerLayout: makeMutable({
60
+ height: 0,
61
+ width: 0,
62
+ x: 0,
63
+ y: 0,
64
+ }),
65
+ nativeGesture: Gesture.Native(),
66
+ outerLayout: makeMutable({
67
+ height: 0,
68
+ width: 0,
69
+ x: 0,
70
+ y: 0,
71
+ }),
72
+ scrollY: makeMutable(0),
73
+ },
74
+ }),
75
+ {} as ReanimatedTopTabNavigation.ContextType['screenProperties']
76
+ )
77
+ ).current;
78
+
79
+ const onIndexChange =
80
+ (
81
+ currentScreenIndex: SharedValue<number>,
82
+ gestureEnabled: SharedValue<boolean>
83
+ ) =>
84
+ (index: number) => {
85
+ navigation.navigate(state.routes[index]?.name ?? '');
86
+ currentScreenIndex.value = index;
87
+ switch (_config[index]) {
88
+ case 'normal': {
89
+ gestureEnabled.value = true;
90
+ break;
91
+ }
92
+ case 'minimalized': {
93
+ gestureEnabled.value = false;
94
+ break;
95
+ }
96
+ }
97
+ };
98
+
99
+ const navigationState = useMemo(
100
+ () => ({
101
+ index: state.index,
102
+ routes: state.routes.map((route, index) => {
103
+ const restOptions = omit(
104
+ descriptors[route.key]?.options,
105
+ 'tabBarLabel'
106
+ );
107
+ const tabBarLabel = descriptors[route.key]?.options.tabBarLabel
108
+ ? () =>
109
+ descriptors[route.key]?.options.tabBarLabel?.({
110
+ focused: state.index === index,
111
+ title: descriptors[route.key]?.options.title || route.name,
112
+ index,
113
+ })
114
+ : undefined;
115
+
116
+ return {
117
+ ...route,
118
+ ...restOptions,
119
+ tabBarLabel,
120
+ title: descriptors[route.key]?.options.title || route.name,
121
+ };
122
+ }),
123
+ }),
124
+ [state]
125
+ );
126
+
127
+ const navigate = (route: any) => {
128
+ navigation.dispatch({
129
+ ...TabActions.jumpTo(route.name, route.params),
130
+ target: state.key,
131
+ });
132
+ };
133
+
134
+ const renderTabBar = useCallback(
135
+ (props: RenderTabsParams) => (
136
+ <TabBarComponent {...props} navigate={navigate} />
137
+ ),
138
+ []
139
+ );
140
+
141
+ const renderScene = ({ route }: ReanimatedTabViewTypes.SceneProps) =>
142
+ descriptors[route.key]?.render();
143
+
144
+ return (
145
+ <Provider config={_config} screenProperties={screenProperties}>
146
+ {({
147
+ currentScreenIndex,
148
+ gestureEnabled,
149
+ headerHeight,
150
+ transformationY,
151
+ }) => (
152
+ <>
153
+ <Reanimated.View
154
+ onLayout={({ nativeEvent }) => {
155
+ headerHeight.value = nativeEvent.layout.height;
156
+ }}
157
+ >
158
+ {HeaderComponent ? (
159
+ <HeaderComponent
160
+ headerHeight={headerHeight}
161
+ transformationY={transformationY}
162
+ />
163
+ ) : null}
164
+ </Reanimated.View>
165
+ <NavigationContent>
166
+ <GestureWrapper>
167
+ <ReanimatedTabView
168
+ navigationState={navigationState}
169
+ onIndexChange={onIndexChange(
170
+ currentScreenIndex,
171
+ gestureEnabled
172
+ )}
173
+ renderScene={renderScene}
174
+ renderTabBar={renderTabBar}
175
+ />
176
+ </GestureWrapper>
177
+ </NavigationContent>
178
+ </>
179
+ )}
180
+ </Provider>
181
+ );
182
+ };
183
+
184
+ export const createReanimatedTopTabNavigator = <
185
+ Params extends ParamListBase,
186
+ >() =>
187
+ createNavigatorFactory<
188
+ TabNavigationState<Params>,
189
+ ReanimatedTopTabNavigation.NavigationOptions,
190
+ {},
191
+ typeof TabViewNavigator
192
+ >(TabViewNavigator)();
package/src/types.ts ADDED
@@ -0,0 +1,63 @@
1
+ import { TabBarBaseComponent } from './components/elements/TabBarBaseComponent';
2
+ import * as React from 'react';
3
+ import { type ReactNode } from 'react';
4
+ import { type LayoutRectangle } from 'react-native';
5
+ import { type NativeGesture } from 'react-native-gesture-handler';
6
+ import { type SharedValue } from 'react-native-reanimated';
7
+ import { type StackNavigationOptions } from '@react-navigation/stack';
8
+
9
+ export namespace ReanimatedTopTabNavigation {
10
+ export interface ContextType {
11
+ screenRefs: {
12
+ refs: { current: Record<string, { current: any }> };
13
+ setRef(key: string, ref: any): void;
14
+ };
15
+ closeOffset: SharedValue<number>;
16
+ config: string[];
17
+ currentScreenIndex: SharedValue<number>;
18
+ currentYPosition: SharedValue<number>;
19
+ gestureEnabled: SharedValue<boolean>;
20
+ headerHeight: SharedValue<number>;
21
+ navHeight: SharedValue<number>;
22
+ screenProperties: Record<
23
+ string,
24
+ {
25
+ innerLayout: SharedValue<LayoutRectangle>;
26
+ nativeGesture: NativeGesture;
27
+ outerLayout: SharedValue<LayoutRectangle>;
28
+ scrollY: SharedValue<number>;
29
+ }
30
+ >;
31
+ topTabHeight: SharedValue<number>;
32
+ topTapNativeRef: NativeGesture;
33
+ transformationX: SharedValue<number>;
34
+ transformationY: SharedValue<number>;
35
+ }
36
+
37
+ export interface TabViewNavigatorProps {
38
+ HeaderComponent?: React.ComponentType<
39
+ Pick<ContextType, 'transformationY' | 'headerHeight'>
40
+ >;
41
+ TabBarComponent?: typeof TabBarBaseComponent;
42
+ children: ReactNode;
43
+ config?: string[];
44
+ initialRouteName?: string;
45
+ screenOptions?: StackNavigationOptions;
46
+ }
47
+
48
+ export type TopTabContextProps = Pick<
49
+ ContextType,
50
+ 'screenProperties' | 'config'
51
+ > & {
52
+ children: (props: ContextType) => React.ReactNode;
53
+ };
54
+
55
+ export interface NavigationOptions {
56
+ tabBarLabel?: (props: {
57
+ focused: boolean;
58
+ index: number;
59
+ title: string;
60
+ }) => React.ReactNode;
61
+ title?: string;
62
+ }
63
+ }