react-navigation-reanimated-top-tabs 0.7.0 → 0.8.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 (78) hide show
  1. package/lib/commonjs/components/ReanimatedTopTab/AnimationHelper.js +1 -1
  2. package/lib/commonjs/components/ReanimatedTopTab/AnimationHelper.js.map +1 -1
  3. package/lib/commonjs/components/ReanimatedTopTab/ReanimatedTabView.js +4 -2
  4. package/lib/commonjs/components/ReanimatedTopTab/ReanimatedTabView.js.map +1 -1
  5. package/lib/commonjs/components/ReanimatedTopTab/types.js.map +1 -1
  6. package/lib/commonjs/components/elements/TabBarBaseComponent.js +42 -17
  7. package/lib/commonjs/components/elements/TabBarBaseComponent.js.map +1 -1
  8. package/lib/commonjs/components/elements/TabBarBaseItem.js +52 -0
  9. package/lib/commonjs/components/elements/TabBarBaseItem.js.map +1 -0
  10. package/lib/commonjs/components/wrappers/GestureWrapper.js +13 -3
  11. package/lib/commonjs/components/wrappers/GestureWrapper.js.map +1 -1
  12. package/lib/commonjs/components/wrappers/SectionList.js +72 -0
  13. package/lib/commonjs/components/wrappers/SectionList.js.map +1 -0
  14. package/lib/commonjs/context/Context.hooks.js +10 -7
  15. package/lib/commonjs/context/Context.hooks.js.map +1 -1
  16. package/lib/commonjs/hooks/useHeader.js +2 -10
  17. package/lib/commonjs/hooks/useHeader.js.map +1 -1
  18. package/lib/commonjs/index.js +2 -0
  19. package/lib/commonjs/index.js.map +1 -1
  20. package/lib/commonjs/navigator/createReanimatedTopTabNavigator.js +24 -22
  21. package/lib/commonjs/navigator/createReanimatedTopTabNavigator.js.map +1 -1
  22. package/lib/commonjs/types.js.map +1 -1
  23. package/lib/module/components/ReanimatedTopTab/AnimationHelper.js +3 -3
  24. package/lib/module/components/ReanimatedTopTab/AnimationHelper.js.map +1 -1
  25. package/lib/module/components/ReanimatedTopTab/ReanimatedTabView.js +4 -2
  26. package/lib/module/components/ReanimatedTopTab/ReanimatedTabView.js.map +1 -1
  27. package/lib/module/components/ReanimatedTopTab/types.js.map +1 -1
  28. package/lib/module/components/elements/TabBarBaseComponent.js +44 -19
  29. package/lib/module/components/elements/TabBarBaseComponent.js.map +1 -1
  30. package/lib/module/components/elements/TabBarBaseItem.js +45 -0
  31. package/lib/module/components/elements/TabBarBaseItem.js.map +1 -0
  32. package/lib/module/components/wrappers/GestureWrapper.js +13 -3
  33. package/lib/module/components/wrappers/GestureWrapper.js.map +1 -1
  34. package/lib/module/components/wrappers/SectionList.js +66 -0
  35. package/lib/module/components/wrappers/SectionList.js.map +1 -0
  36. package/lib/module/context/Context.hooks.js +10 -7
  37. package/lib/module/context/Context.hooks.js.map +1 -1
  38. package/lib/module/hooks/useHeader.js +3 -11
  39. package/lib/module/hooks/useHeader.js.map +1 -1
  40. package/lib/module/index.js +2 -0
  41. package/lib/module/index.js.map +1 -1
  42. package/lib/module/navigator/createReanimatedTopTabNavigator.js +25 -23
  43. package/lib/module/navigator/createReanimatedTopTabNavigator.js.map +1 -1
  44. package/lib/module/types.js.map +1 -1
  45. package/lib/typescript/src/components/ReanimatedTopTab/ReanimatedTabView.d.ts +2 -0
  46. package/lib/typescript/src/components/ReanimatedTopTab/ReanimatedTabView.d.ts.map +1 -1
  47. package/lib/typescript/src/components/ReanimatedTopTab/types.d.ts +3 -1
  48. package/lib/typescript/src/components/ReanimatedTopTab/types.d.ts.map +1 -1
  49. package/lib/typescript/src/components/elements/TabBarBaseComponent.d.ts +1 -1
  50. package/lib/typescript/src/components/elements/TabBarBaseComponent.d.ts.map +1 -1
  51. package/lib/typescript/src/components/elements/TabBarBaseItem.d.ts +14 -0
  52. package/lib/typescript/src/components/elements/TabBarBaseItem.d.ts.map +1 -0
  53. package/lib/typescript/src/components/wrappers/GestureWrapper.d.ts.map +1 -1
  54. package/lib/typescript/src/components/wrappers/SectionList.d.ts +3 -0
  55. package/lib/typescript/src/components/wrappers/SectionList.d.ts.map +1 -0
  56. package/lib/typescript/src/context/Context.hooks.d.ts.map +1 -1
  57. package/lib/typescript/src/hooks/useHeader.d.ts +0 -6
  58. package/lib/typescript/src/hooks/useHeader.d.ts.map +1 -1
  59. package/lib/typescript/src/hooks/useScreenProperties.d.ts +1 -1
  60. package/lib/typescript/src/index.d.ts +3 -8
  61. package/lib/typescript/src/index.d.ts.map +1 -1
  62. package/lib/typescript/src/navigator/createReanimatedTopTabNavigator.d.ts +1 -1
  63. package/lib/typescript/src/navigator/createReanimatedTopTabNavigator.d.ts.map +1 -1
  64. package/lib/typescript/src/types.d.ts +8 -4
  65. package/lib/typescript/src/types.d.ts.map +1 -1
  66. package/package.json +1 -1
  67. package/src/components/ReanimatedTopTab/AnimationHelper.ts +3 -3
  68. package/src/components/ReanimatedTopTab/ReanimatedTabView.tsx +4 -0
  69. package/src/components/ReanimatedTopTab/types.ts +3 -1
  70. package/src/components/elements/TabBarBaseComponent.tsx +53 -19
  71. package/src/components/elements/TabBarBaseItem.tsx +76 -0
  72. package/src/components/wrappers/GestureWrapper.tsx +11 -1
  73. package/src/components/wrappers/SectionList.tsx +75 -0
  74. package/src/context/Context.hooks.ts +13 -5
  75. package/src/hooks/useHeader.ts +3 -21
  76. package/src/index.tsx +2 -0
  77. package/src/navigator/createReanimatedTopTabNavigator.tsx +30 -26
  78. package/src/types.ts +18 -4
@@ -0,0 +1,76 @@
1
+ import {
2
+ Pressable,
3
+ StyleSheet,
4
+ Text,
5
+ type StyleProp,
6
+ type ViewStyle,
7
+ } from 'react-native';
8
+ import Animated, {
9
+ type SharedValue,
10
+ useAnimatedStyle,
11
+ interpolate,
12
+ } from 'react-native-reanimated';
13
+ import { type ReanimatedTabViewTypes } from '../ReanimatedTopTab/types';
14
+
15
+ interface TabBarBaseItemProps {
16
+ position: SharedValue<number>;
17
+ index: number;
18
+ inputRange: Array<number>;
19
+ onPress: (index: number) => void;
20
+ route: ReanimatedTabViewTypes.Route;
21
+ style?: StyleProp<ViewStyle>;
22
+ }
23
+
24
+ export const TabBarBaseItem = ({
25
+ position,
26
+ index,
27
+ inputRange,
28
+ onPress,
29
+ route,
30
+ style,
31
+ }: TabBarBaseItemProps) => {
32
+ const activeStyle = useAnimatedStyle(() => ({
33
+ opacity: interpolate(
34
+ position.value,
35
+ inputRange,
36
+ inputRange.map((i) => (i === index ? 1 : 0))
37
+ ),
38
+ position: 'absolute',
39
+ }));
40
+
41
+ const inactiveStyle = useAnimatedStyle(() => ({
42
+ opacity: interpolate(
43
+ position.value,
44
+ inputRange,
45
+ inputRange.map((i) => (i === index ? 0 : 1))
46
+ ),
47
+ }));
48
+
49
+ return (
50
+ <Pressable onPress={() => onPress(index)} style={[styles.container, style]}>
51
+ <Animated.View style={activeStyle}>
52
+ {route.tabBarLabel ? (
53
+ route.tabBarLabel(true)
54
+ ) : (
55
+ <Text>{route.title}</Text>
56
+ )}
57
+ </Animated.View>
58
+ <Animated.View style={inactiveStyle}>
59
+ {route.tabBarLabel ? (
60
+ route.tabBarLabel(false)
61
+ ) : (
62
+ <Text>{route.title}</Text>
63
+ )}
64
+ </Animated.View>
65
+ </Pressable>
66
+ );
67
+ };
68
+
69
+ const styles = StyleSheet.create({
70
+ container: {
71
+ alignItems: 'center',
72
+ flex: 1,
73
+ justifyContent: 'center',
74
+ minHeight: 50,
75
+ },
76
+ });
@@ -12,6 +12,7 @@ import Reanimated, {
12
12
  } from 'react-native-reanimated';
13
13
 
14
14
  import { useTabContext } from '../../hooks/useTabContext';
15
+ import { StyleSheet, View } from 'react-native';
15
16
 
16
17
  interface GestureWrapperProps {
17
18
  children: React.ReactNode;
@@ -124,7 +125,16 @@ export const GestureWrapper = ({ children }: GestureWrapperProps) => {
124
125
 
125
126
  return (
126
127
  <GestureDetector gesture={gesture}>
127
- <Reanimated.View style={style}>{children}</Reanimated.View>
128
+ <View style={styles.container}>
129
+ <Reanimated.View style={style}>{children}</Reanimated.View>
130
+ </View>
128
131
  </GestureDetector>
129
132
  );
130
133
  };
134
+
135
+ const styles = StyleSheet.create({
136
+ container: {
137
+ overflow: 'hidden',
138
+ flex: 1,
139
+ },
140
+ });
@@ -0,0 +1,75 @@
1
+ import {
2
+ type DefaultSectionT,
3
+ type LayoutChangeEvent,
4
+ type SectionListProps,
5
+ SectionList as RNSectionList,
6
+ StyleSheet,
7
+ } from 'react-native';
8
+ import { GestureDetector } from 'react-native-gesture-handler';
9
+ import Reanimated from 'react-native-reanimated';
10
+ import { useRef } from 'react';
11
+ import { useRoute } from '@react-navigation/native';
12
+ import { useTabContext } from '../../hooks/useTabContext';
13
+ import { useScreenGesture } from '../../hooks/useScreenGesture';
14
+ import { useScreenScrollable } from '../../hooks/useScreenScrollable';
15
+ import { useScreenProperties } from '../../hooks/useScreenProperties';
16
+
17
+ export const SectionList = <ItemT, SectionT = DefaultSectionT>({
18
+ children,
19
+ style,
20
+ contentContainerStyle,
21
+ onLayout,
22
+ ...props
23
+ }: SectionListProps<ItemT, SectionT>) => {
24
+ const gesture = useScreenGesture();
25
+ const {
26
+ style: _style,
27
+ contentContainerStyle: _contentContainerStyle,
28
+ onScroll,
29
+ bounces,
30
+ animatedProps,
31
+ overScrollMode,
32
+ } = useScreenScrollable();
33
+ const { innerLayout } = useScreenProperties();
34
+ const { context } = useTabContext();
35
+
36
+ const { key } = useRoute();
37
+ const _ref = useRef<RNSectionList<any>>(null);
38
+
39
+ const _onLayout = (event: LayoutChangeEvent) => {
40
+ onLayout?.(event);
41
+ innerLayout.value = event.nativeEvent.layout;
42
+ context.screen.setRef(key, _ref.current);
43
+ };
44
+
45
+ return (
46
+ <GestureDetector gesture={gesture}>
47
+ <AnimatedSectionList
48
+ ref={_ref}
49
+ contentContainerStyle={[
50
+ _contentContainerStyle,
51
+ styleSheet.contentContainerStyle,
52
+ contentContainerStyle,
53
+ ]}
54
+ onLayout={_onLayout}
55
+ style={[_style, style]}
56
+ onScroll={onScroll}
57
+ bounces={bounces}
58
+ animatedProps={animatedProps}
59
+ overScrollMode={overScrollMode}
60
+ {...props}
61
+ >
62
+ {children}
63
+ </AnimatedSectionList>
64
+ </GestureDetector>
65
+ );
66
+ };
67
+
68
+ const styleSheet = StyleSheet.create({
69
+ contentContainerStyle: {
70
+ flexGrow: 1,
71
+ },
72
+ });
73
+
74
+ const AnimatedSectionList =
75
+ Reanimated.createAnimatedComponent<SectionListProps<any, any>>(RNSectionList);
@@ -15,6 +15,7 @@ import type {
15
15
  import { Gesture } from 'react-native-gesture-handler';
16
16
  import { assign, throttle } from 'lodash';
17
17
  import { ContextHelpers } from './Context.helpers';
18
+ import { SectionList } from 'react-native';
18
19
 
19
20
  /**
20
21
  * Hook to reset the scroll offset for the approaching screen in a tab navigation context.
@@ -46,11 +47,18 @@ const useResetApproachingScreenScrollOffset = ({
46
47
  shouldReset: boolean
47
48
  ) => {
48
49
  if (shouldReset) {
49
- const { scrollTo } = context.screen.getRef(
50
+ const ref = context.screen.getRef(
50
51
  context.route.getKeyForIndex(index)
51
- ).current ?? { scrollTo: () => {} };
52
- //NOTE: use reanimated scrollTo does not work
53
- scrollTo({ y: 0, animated: false });
52
+ ).current;
53
+
54
+ if (ref instanceof SectionList) {
55
+ ref.scrollToLocation({
56
+ animated: false,
57
+ sectionIndex: 0,
58
+ itemIndex: 0,
59
+ viewOffset: 0,
60
+ });
61
+ } else ref?.scrollTo({ y: 0, animated: false });
54
62
  }
55
63
  };
56
64
 
@@ -145,7 +153,7 @@ const usePrepareScreen = ({
145
153
  )
146
154
  );
147
155
 
148
- const setRef = (key: string, ref: Reanimated.ScrollView) => {
156
+ const setRef = (key: string, ref: Reanimated.ScrollView | SectionList) => {
149
157
  const newProperties = assign({}, screenProperties.current[key], {
150
158
  scrollRef: { current: ref },
151
159
  });
@@ -1,30 +1,12 @@
1
1
  import { useTabContext } from './useTabContext';
2
- import {
3
- interpolate,
4
- useAnimatedStyle,
5
- withTiming,
6
- } from 'react-native-reanimated';
2
+ import { withTiming } from 'react-native-reanimated';
7
3
 
8
4
  export const useHeader = () => {
9
- const { headerHeight, transformationX, transformationY } = useTabContext();
5
+ const { headerHeight, transformationX } = useTabContext();
10
6
 
11
7
  const hideHeader = () => {
12
8
  transformationX.value = withTiming(-headerHeight.value);
13
9
  };
14
10
 
15
- const defaultStyle = useAnimatedStyle(() => ({
16
- transform: [
17
- {
18
- translateY: interpolate(
19
- transformationY.value,
20
- [0, -headerHeight.value],
21
- [0, -headerHeight.value],
22
- 'clamp'
23
- ),
24
- },
25
- ],
26
- zIndex: -1,
27
- }));
28
-
29
- return { hideHeader, defaultStyle };
11
+ return { hideHeader };
30
12
  };
package/src/index.tsx CHANGED
@@ -1,4 +1,5 @@
1
1
  import { ScrollView } from './components/wrappers/ScrollView';
2
+ import { SectionList } from './components/wrappers/SectionList';
2
3
  import { ScreenWrapper } from './components/wrappers/ScreenWrapper';
3
4
  import { TabBarBaseComponent } from './components/elements/TabBarBaseComponent';
4
5
  import { TabBarLabelBaseComponent } from './components/elements/TabBarLabelBaseComponent';
@@ -33,6 +34,7 @@ export const TabHooks = {
33
34
 
34
35
  export const Tab = {
35
36
  ScrollView,
37
+ SectionList,
36
38
  ScreenWrapper,
37
39
  TabBarBaseComponent,
38
40
  TabBarLabelBaseComponent,
@@ -20,6 +20,7 @@ import { ContextHooks } from '../context/Context.hooks';
20
20
 
21
21
  const TabViewNavigator = ({
22
22
  HeaderComponent,
23
+ TopComponent,
23
24
  TabBarComponent = TabBarBaseComponent,
24
25
  children,
25
26
  config,
@@ -62,10 +63,11 @@ const TabViewNavigator = ({
62
63
  descriptors[route.key]?.options,
63
64
  'tabBarLabel'
64
65
  );
66
+
65
67
  const tabBarLabel = descriptors[route.key]?.options.tabBarLabel
66
- ? () =>
68
+ ? (focused: boolean) =>
67
69
  descriptors[route.key]?.options.tabBarLabel?.({
68
- focused: state.index === index,
70
+ focused,
69
71
  title: descriptors[route.key]?.options.title || route.name,
70
72
  index,
71
73
  })
@@ -88,30 +90,32 @@ const TabViewNavigator = ({
88
90
  return (
89
91
  <Provider config={_config} context={context}>
90
92
  {({ headerHeight, transformationY }) => (
91
- <>
92
- <Reanimated.View
93
- onLayout={({ nativeEvent }) => {
94
- headerHeight.value = nativeEvent.layout.height;
95
- }}
96
- >
97
- {HeaderComponent ? (
98
- <HeaderComponent
99
- headerHeight={headerHeight}
100
- transformationY={transformationY}
101
- />
102
- ) : null}
103
- </Reanimated.View>
104
- <NavigationContent>
105
- <GestureWrapper>
106
- <ReanimatedTabView
107
- navigationState={navigationState}
108
- navigate={navigate}
109
- renderScene={renderScene}
110
- renderTabBar={TabBarComponent}
111
- />
112
- </GestureWrapper>
113
- </NavigationContent>
114
- </>
93
+ <NavigationContent>
94
+ {TopComponent ? (
95
+ <TopComponent transformationY={transformationY} />
96
+ ) : null}
97
+ <GestureWrapper>
98
+ <Reanimated.View
99
+ onLayout={({ nativeEvent }) => {
100
+ headerHeight.value = nativeEvent.layout.height;
101
+ }}
102
+ >
103
+ {HeaderComponent ? (
104
+ <HeaderComponent
105
+ headerHeight={headerHeight}
106
+ transformationY={transformationY}
107
+ />
108
+ ) : null}
109
+ </Reanimated.View>
110
+ <ReanimatedTabView
111
+ navigationState={navigationState}
112
+ navigate={navigate}
113
+ renderScene={renderScene}
114
+ renderTabBar={TabBarComponent}
115
+ screenOptions={screenOptions}
116
+ />
117
+ </GestureWrapper>
118
+ </NavigationContent>
115
119
  )}
116
120
  </Provider>
117
121
  );
package/src/types.ts CHANGED
@@ -1,7 +1,12 @@
1
1
  import { TabBarBaseComponent } from './components/elements/TabBarBaseComponent';
2
2
  import * as React from 'react';
3
3
  import { type ReactNode } from 'react';
4
- import { type LayoutRectangle } from 'react-native';
4
+ import {
5
+ SectionList,
6
+ type LayoutRectangle,
7
+ type StyleProp,
8
+ type ViewStyle,
9
+ } from 'react-native';
5
10
  import { type NativeGesture } from 'react-native-gesture-handler';
6
11
  import Reanimated, { type SharedValue } from 'react-native-reanimated';
7
12
  import { type StackNavigationOptions } from '@react-navigation/stack';
@@ -29,11 +34,16 @@ export namespace ReanimatedTopTabNavigation {
29
34
  nativeGesture: NativeGesture;
30
35
  outerLayout: SharedValue<LayoutRectangle>;
31
36
  scrollY: SharedValue<number>;
32
- scrollRef: { current: Reanimated.ScrollView | null };
37
+ scrollRef: { current: Reanimated.ScrollView | SectionList | null };
33
38
  }
34
39
  >;
35
- setRef(key: string, ref: Reanimated.ScrollView | null): void;
36
- getRef(key: string): { current: Reanimated.ScrollView | null };
40
+ setRef(
41
+ key: string,
42
+ ref: Reanimated.ScrollView | SectionList | null
43
+ ): void;
44
+ getRef(key: string): {
45
+ current: Reanimated.ScrollView | SectionList | null;
46
+ };
37
47
  };
38
48
  route: {
39
49
  map: Record<number, string>;
@@ -46,6 +56,7 @@ export namespace ReanimatedTopTabNavigation {
46
56
  HeaderComponent?: React.ComponentType<
47
57
  Pick<ContextType, 'transformationY' | 'headerHeight'>
48
58
  >;
59
+ TopComponent?: React.ComponentType<Pick<ContextType, 'transformationY'>>;
49
60
  TabBarComponent?: typeof TabBarBaseComponent;
50
61
  children: ReactNode;
51
62
  config?: string[];
@@ -64,5 +75,8 @@ export namespace ReanimatedTopTabNavigation {
64
75
  title: string;
65
76
  }) => React.ReactNode;
66
77
  title?: string;
78
+ tabBarIndicatorStyle?: StyleProp<ViewStyle>;
79
+ tabBarItemStyle?: StyleProp<ViewStyle>;
80
+ tabBarStyle?: StyleProp<ViewStyle>;
67
81
  }
68
82
  }