react-navigation-reanimated-top-tabs 0.7.0 → 0.9.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 (95) hide show
  1. package/lib/commonjs/components/ReanimatedTopTab/AnimationHelper.js +21 -26
  2. package/lib/commonjs/components/ReanimatedTopTab/AnimationHelper.js.map +1 -1
  3. package/lib/commonjs/components/ReanimatedTopTab/ReanimatedTabView.js +13 -12
  4. package/lib/commonjs/components/ReanimatedTopTab/ReanimatedTabView.js.map +1 -1
  5. package/lib/commonjs/components/elements/TabBarBaseComponent.js +42 -25
  6. package/lib/commonjs/components/elements/TabBarBaseComponent.js.map +1 -1
  7. package/lib/commonjs/components/elements/TabBarBaseItem.js +55 -0
  8. package/lib/commonjs/components/elements/TabBarBaseItem.js.map +1 -0
  9. package/lib/commonjs/components/elements/TabBarLabelBaseComponent.js +3 -3
  10. package/lib/commonjs/components/elements/TabBarLabelBaseComponent.js.map +1 -1
  11. package/lib/commonjs/components/wrappers/GestureWrapper.js +40 -11
  12. package/lib/commonjs/components/wrappers/GestureWrapper.js.map +1 -1
  13. package/lib/commonjs/components/wrappers/SectionList.js +72 -0
  14. package/lib/commonjs/components/wrappers/SectionList.js.map +1 -0
  15. package/lib/commonjs/context/Context.hooks.js +22 -17
  16. package/lib/commonjs/context/Context.hooks.js.map +1 -1
  17. package/lib/commonjs/context/Context.js +11 -8
  18. package/lib/commonjs/context/Context.js.map +1 -1
  19. package/lib/commonjs/hooks/useHeader.js +2 -10
  20. package/lib/commonjs/hooks/useHeader.js.map +1 -1
  21. package/lib/commonjs/hooks/useTabOffset.js +2 -2
  22. package/lib/commonjs/hooks/useTabOffset.js.map +1 -1
  23. package/lib/commonjs/index.js +2 -0
  24. package/lib/commonjs/index.js.map +1 -1
  25. package/lib/commonjs/navigator/createReanimatedTopTabNavigator.js +27 -23
  26. package/lib/commonjs/navigator/createReanimatedTopTabNavigator.js.map +1 -1
  27. package/lib/commonjs/types.js.map +1 -1
  28. package/lib/module/components/ReanimatedTopTab/AnimationHelper.js +23 -28
  29. package/lib/module/components/ReanimatedTopTab/AnimationHelper.js.map +1 -1
  30. package/lib/module/components/ReanimatedTopTab/ReanimatedTabView.js +14 -13
  31. package/lib/module/components/ReanimatedTopTab/ReanimatedTabView.js.map +1 -1
  32. package/lib/module/components/elements/TabBarBaseComponent.js +44 -27
  33. package/lib/module/components/elements/TabBarBaseComponent.js.map +1 -1
  34. package/lib/module/components/elements/TabBarBaseItem.js +48 -0
  35. package/lib/module/components/elements/TabBarBaseItem.js.map +1 -0
  36. package/lib/module/components/elements/TabBarLabelBaseComponent.js +3 -3
  37. package/lib/module/components/elements/TabBarLabelBaseComponent.js.map +1 -1
  38. package/lib/module/components/wrappers/GestureWrapper.js +41 -12
  39. package/lib/module/components/wrappers/GestureWrapper.js.map +1 -1
  40. package/lib/module/components/wrappers/SectionList.js +66 -0
  41. package/lib/module/components/wrappers/SectionList.js.map +1 -0
  42. package/lib/module/context/Context.hooks.js +22 -17
  43. package/lib/module/context/Context.hooks.js.map +1 -1
  44. package/lib/module/context/Context.js +11 -8
  45. package/lib/module/context/Context.js.map +1 -1
  46. package/lib/module/hooks/useHeader.js +3 -11
  47. package/lib/module/hooks/useHeader.js.map +1 -1
  48. package/lib/module/hooks/useTabOffset.js +2 -2
  49. package/lib/module/hooks/useTabOffset.js.map +1 -1
  50. package/lib/module/index.js +2 -0
  51. package/lib/module/index.js.map +1 -1
  52. package/lib/module/navigator/createReanimatedTopTabNavigator.js +28 -24
  53. package/lib/module/navigator/createReanimatedTopTabNavigator.js.map +1 -1
  54. package/lib/module/types.js.map +1 -1
  55. package/lib/typescript/src/components/ReanimatedTopTab/AnimationHelper.d.ts.map +1 -1
  56. package/lib/typescript/src/components/ReanimatedTopTab/ReanimatedTabView.d.ts +2 -1
  57. package/lib/typescript/src/components/ReanimatedTopTab/ReanimatedTabView.d.ts.map +1 -1
  58. package/lib/typescript/src/components/ReanimatedTopTab/types.d.ts +3 -7
  59. package/lib/typescript/src/components/ReanimatedTopTab/types.d.ts.map +1 -1
  60. package/lib/typescript/src/components/elements/TabBarBaseComponent.d.ts +1 -1
  61. package/lib/typescript/src/components/elements/TabBarBaseComponent.d.ts.map +1 -1
  62. package/lib/typescript/src/components/elements/TabBarBaseItem.d.ts +12 -0
  63. package/lib/typescript/src/components/elements/TabBarBaseItem.d.ts.map +1 -0
  64. package/lib/typescript/src/components/wrappers/GestureWrapper.d.ts +2 -1
  65. package/lib/typescript/src/components/wrappers/GestureWrapper.d.ts.map +1 -1
  66. package/lib/typescript/src/components/wrappers/SectionList.d.ts +3 -0
  67. package/lib/typescript/src/components/wrappers/SectionList.d.ts.map +1 -0
  68. package/lib/typescript/src/context/Context.d.ts.map +1 -1
  69. package/lib/typescript/src/context/Context.hooks.d.ts +4 -3
  70. package/lib/typescript/src/context/Context.hooks.d.ts.map +1 -1
  71. package/lib/typescript/src/hooks/useHeader.d.ts +0 -6
  72. package/lib/typescript/src/hooks/useHeader.d.ts.map +1 -1
  73. package/lib/typescript/src/hooks/useScreenProperties.d.ts +1 -1
  74. package/lib/typescript/src/index.d.ts +3 -8
  75. package/lib/typescript/src/index.d.ts.map +1 -1
  76. package/lib/typescript/src/navigator/createReanimatedTopTabNavigator.d.ts +1 -1
  77. package/lib/typescript/src/navigator/createReanimatedTopTabNavigator.d.ts.map +1 -1
  78. package/lib/typescript/src/types.d.ts +11 -5
  79. package/lib/typescript/src/types.d.ts.map +1 -1
  80. package/package.json +1 -1
  81. package/src/components/ReanimatedTopTab/AnimationHelper.ts +24 -32
  82. package/src/components/ReanimatedTopTab/ReanimatedTabView.tsx +19 -17
  83. package/src/components/ReanimatedTopTab/types.ts +3 -5
  84. package/src/components/elements/TabBarBaseComponent.tsx +47 -36
  85. package/src/components/elements/TabBarBaseItem.tsx +76 -0
  86. package/src/components/elements/TabBarLabelBaseComponent.tsx +3 -3
  87. package/src/components/wrappers/GestureWrapper.tsx +41 -14
  88. package/src/components/wrappers/SectionList.tsx +75 -0
  89. package/src/context/Context.hooks.ts +26 -16
  90. package/src/context/Context.tsx +8 -5
  91. package/src/hooks/useHeader.ts +4 -22
  92. package/src/hooks/useTabOffset.ts +2 -2
  93. package/src/index.tsx +2 -0
  94. package/src/navigator/createReanimatedTopTabNavigator.tsx +31 -26
  95. package/src/types.ts +21 -5
@@ -1,7 +1,7 @@
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 { SectionList, type LayoutRectangle, type StyleProp, type ViewStyle } from 'react-native';
5
5
  import { type NativeGesture } from 'react-native-gesture-handler';
6
6
  import Reanimated, { type SharedValue } from 'react-native-reanimated';
7
7
  import { type StackNavigationOptions } from '@react-navigation/stack';
@@ -17,8 +17,9 @@ export declare namespace ReanimatedTopTabNavigation {
17
17
  navHeight: SharedValue<number>;
18
18
  topTabHeight: SharedValue<number>;
19
19
  topTabNativeGesture: NativeGesture;
20
- transformationX: SharedValue<number>;
20
+ positionX: SharedValue<number>;
21
21
  transformationY: SharedValue<number>;
22
+ scrollY: SharedValue<number>;
22
23
  context: {
23
24
  screen: {
24
25
  properties: Record<string, {
@@ -27,12 +28,12 @@ export declare namespace ReanimatedTopTabNavigation {
27
28
  outerLayout: SharedValue<LayoutRectangle>;
28
29
  scrollY: SharedValue<number>;
29
30
  scrollRef: {
30
- current: Reanimated.ScrollView | null;
31
+ current: Reanimated.ScrollView | SectionList | null;
31
32
  };
32
33
  }>;
33
- setRef(key: string, ref: Reanimated.ScrollView | null): void;
34
+ setRef(key: string, ref: Reanimated.ScrollView | SectionList | null): void;
34
35
  getRef(key: string): {
35
- current: Reanimated.ScrollView | null;
36
+ current: Reanimated.ScrollView | SectionList | null;
36
37
  };
37
38
  };
38
39
  route: {
@@ -43,11 +44,13 @@ export declare namespace ReanimatedTopTabNavigation {
43
44
  }
44
45
  interface TabViewNavigatorProps {
45
46
  HeaderComponent?: React.ComponentType<Pick<ContextType, 'transformationY' | 'headerHeight'>>;
47
+ TopComponent?: React.ComponentType<Pick<ContextType, 'transformationY'>>;
46
48
  TabBarComponent?: typeof TabBarBaseComponent;
47
49
  children: ReactNode;
48
50
  config?: string[];
49
51
  initialRouteName?: string;
50
52
  screenOptions?: StackNavigationOptions;
53
+ bounces?: boolean;
51
54
  }
52
55
  type TopTabContextProps = Pick<ContextType, 'config' | 'context'> & {
53
56
  children: (props: ContextType) => React.ReactNode;
@@ -59,6 +62,9 @@ export declare namespace ReanimatedTopTabNavigation {
59
62
  title: string;
60
63
  }) => React.ReactNode;
61
64
  title?: string;
65
+ tabBarIndicatorStyle?: StyleProp<ViewStyle>;
66
+ tabBarItemStyle?: StyleProp<ViewStyle>;
67
+ tabBarStyle?: StyleProp<ViewStyle>;
62
68
  }
63
69
  }
64
70
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-navigation-reanimated-top-tabs",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "react-navigation-reanimated-top-tabs",
5
5
  "source": "./src/index.tsx",
6
6
  "main": "./lib/commonjs/index.js",
@@ -4,7 +4,7 @@ import type {
4
4
  PanGestureChangeEventPayload,
5
5
  PanGestureHandlerEventPayload,
6
6
  } from 'react-native-gesture-handler';
7
- import { withTiming as reanimatedWithTiming } from 'react-native-reanimated';
7
+ import { withTiming } from 'react-native-reanimated';
8
8
 
9
9
  type NavigationState = { size: number; index: number };
10
10
 
@@ -32,14 +32,18 @@ const getIndex = (
32
32
  type: 'increment' | 'decrement'
33
33
  ) => {
34
34
  'worklet';
35
- if (type === 'increment') {
36
- return navigationState.index === navigationState.size - 1
37
- ? navigationState.index
38
- : navigationState.index + 1;
35
+ const max = navigationState.size - 1;
36
+ const current = navigationState.index;
37
+
38
+ if (type === 'increment' && current < max) {
39
+ return current + 1;
40
+ }
41
+
42
+ if (type === 'decrement' && current > 0) {
43
+ return current - 1;
39
44
  }
40
- return navigationState.index === 0
41
- ? navigationState.index
42
- : navigationState.index - 1;
45
+
46
+ return current;
43
47
  };
44
48
 
45
49
  const onEnd = (
@@ -49,43 +53,31 @@ const onEnd = (
49
53
  navigationState: NavigationState
50
54
  ) => {
51
55
  'worklet';
52
- if (event.velocityX < -200) {
56
+ const { velocityX, translationX } = event;
57
+
58
+ if (velocityX < -200 || translationX < -minimumValueToChangeView) {
59
+ const newIndex = getIndex(navigationState, 'increment');
53
60
  return {
54
- index: getIndex(navigationState, 'increment'),
55
- value: -width * (navigationState.index + 1),
61
+ index: newIndex,
62
+ value: -width * newIndex,
56
63
  };
57
64
  }
58
- if (event.velocityX > 200) {
65
+ if (velocityX > 200 || translationX > minimumValueToChangeView) {
66
+ const newIndex = getIndex(navigationState, 'decrement');
59
67
  return {
60
- index: getIndex(navigationState, 'decrement'),
61
- value: -width * (navigationState.index - 1),
68
+ index: newIndex,
69
+ value: -width * newIndex,
62
70
  };
63
71
  }
64
- if (event.translationX < 0) {
65
- if (event.translationX < -minimumValueToChangeView) {
66
- return {
67
- index: getIndex(navigationState, 'increment'),
68
- value: -width * (navigationState.index + 1),
69
- };
70
- }
71
- }
72
- if (event.translationX > 0) {
73
- if (event.translationX > minimumValueToChangeView) {
74
- return {
75
- index: getIndex(navigationState, 'decrement'),
76
- value: -width * (navigationState.index - 1),
77
- };
78
- }
79
- }
80
72
  return {
81
73
  index: navigationState.index,
82
74
  value: -width * navigationState.index,
83
75
  };
84
76
  };
85
77
 
86
- const animation = (newValue: number, duration = 200) => {
78
+ const animation = (newValue: number, duration = 350) => {
87
79
  'worklet';
88
- return reanimatedWithTiming(newValue, { duration });
80
+ return withTiming(newValue, { duration });
89
81
  };
90
82
 
91
83
  export const AnimationHelper = {
@@ -6,15 +6,16 @@ import {
6
6
  GestureHandlerRootView,
7
7
  } from 'react-native-gesture-handler';
8
8
  import Reanimated, {
9
- Extrapolation,
10
9
  interpolate,
11
10
  LinearTransition,
12
11
  runOnJS,
13
12
  runOnUI,
13
+ useAnimatedReaction,
14
14
  useAnimatedStyle,
15
- useDerivedValue,
16
15
  useSharedValue,
17
16
  } from 'react-native-reanimated';
17
+ import type { ReanimatedTopTabNavigation } from 'react-navigation-reanimated-top-tabs';
18
+ import { useTabContext } from '../../hooks/useTabContext';
18
19
  import { AnimationHelper } from './AnimationHelper';
19
20
  import type { ReanimatedTabViewTypes } from './types';
20
21
 
@@ -23,12 +24,12 @@ export interface ReanimatedTabViewProps {
23
24
  lazy?: boolean;
24
25
  navigationState: ReanimatedTabViewTypes.NavigationState;
25
26
  percentageTrigger?: number;
26
- positionInterpolation?: ReanimatedTabViewTypes.PositionInterpolation;
27
27
  renderScene: (params: ReanimatedTabViewTypes.SceneProps) => React.ReactNode;
28
28
  renderTabBar?: (
29
29
  params: ReanimatedTabViewTypes.RenderTabsParams
30
30
  ) => React.ReactNode;
31
31
  navigate(index: number): void;
32
+ screenOptions?: ReanimatedTopTabNavigation.NavigationOptions;
32
33
  }
33
34
 
34
35
  export const ReanimatedTabView = React.memo<ReanimatedTabViewProps>(
@@ -37,28 +38,29 @@ export const ReanimatedTabView = React.memo<ReanimatedTabViewProps>(
37
38
  lazy = false,
38
39
  navigationState,
39
40
  percentageTrigger = 0.4,
40
- positionInterpolation,
41
41
  renderScene,
42
42
  renderTabBar,
43
43
  navigate,
44
+ screenOptions,
44
45
  }) => {
45
46
  const { width } = useWindowDimensions();
46
47
  const loadedScreens = useRef([
47
48
  navigationState.routes[navigationState.index],
48
49
  ]);
49
50
  const scrollPosition = useSharedValue(navigationState.index);
51
+ const { positionX } = useTabContext();
50
52
 
51
- const position = useDerivedValue(() => {
52
- if (!positionInterpolation) {
53
- return -scrollPosition.value;
53
+ useAnimatedReaction(
54
+ () => scrollPosition.value,
55
+ (value) => {
56
+ positionX.value = interpolate(
57
+ value,
58
+ navigationState.routes.map((_, i) => i * -width),
59
+ navigationState.routes.map((_, i) => i),
60
+ 'clamp'
61
+ );
54
62
  }
55
- return interpolate(
56
- -scrollPosition.value,
57
- positionInterpolation.input,
58
- positionInterpolation.output,
59
- Extrapolation.CLAMP
60
- );
61
- }, [positionInterpolation]);
63
+ );
62
64
 
63
65
  const _navigate = (index: number) => {
64
66
  scrollPosition.value = AnimationHelper.animation(-index * width);
@@ -105,7 +107,7 @@ export const ReanimatedTabView = React.memo<ReanimatedTabViewProps>(
105
107
  _navigationState.value.index = state.index;
106
108
  runOnJS(navigate)(state.index);
107
109
  }),
108
- [minimumValueToChangeView, width, _navigationState]
110
+ [minimumValueToChangeView, width]
109
111
  );
110
112
 
111
113
  const scrollPositionStyle = useAnimatedStyle(() => ({
@@ -115,7 +117,7 @@ export const ReanimatedTabView = React.memo<ReanimatedTabViewProps>(
115
117
  scrollPosition.value,
116
118
  [-width * (navigationState.routes.length - 1), 0],
117
119
  [-width * (navigationState.routes.length - 1), 0],
118
- Extrapolation.CLAMP
120
+ 'clamp'
119
121
  ),
120
122
  },
121
123
  ],
@@ -176,8 +178,8 @@ export const ReanimatedTabView = React.memo<ReanimatedTabViewProps>(
176
178
  {renderTabBar
177
179
  ? renderTabBar({
178
180
  navigationState,
179
- position,
180
181
  navigate: _navigate,
182
+ screenOptions,
181
183
  })
182
184
  : null}
183
185
  <GestureDetector gesture={panGesture}>
@@ -1,11 +1,11 @@
1
1
  import React from 'react';
2
- import type { SharedValue } from 'react-native-reanimated';
2
+ import type { ReanimatedTopTabNavigation } from 'react-navigation-reanimated-top-tabs';
3
3
 
4
4
  export namespace ReanimatedTabViewTypes {
5
5
  export interface Route {
6
6
  key: string;
7
7
  name: string;
8
- tabBarLabel?: () => React.ReactNode;
8
+ tabBarLabel?: (focused: boolean) => React.ReactNode;
9
9
  title?: string;
10
10
  }
11
11
 
@@ -13,14 +13,12 @@ export namespace ReanimatedTabViewTypes {
13
13
 
14
14
  export interface RenderTabsParams {
15
15
  navigationState: NavigationState;
16
- position: SharedValue<number>;
17
16
  navigate(index: number): void;
17
+ screenOptions?: ReanimatedTopTabNavigation.NavigationOptions;
18
18
  }
19
19
 
20
20
  export interface SceneProps {
21
21
  jumpTo?: (key: string) => void;
22
22
  route: Route;
23
23
  }
24
-
25
- export type PositionInterpolation = { input: number[]; output: number[] };
26
24
  }
@@ -1,13 +1,15 @@
1
1
  import * as React from 'react';
2
- import { Pressable, StyleSheet, Text, useWindowDimensions } from 'react-native';
2
+ import { StyleSheet } from 'react-native';
3
3
  import Reanimated, {
4
- type AnimatedStyle,
5
4
  interpolate,
6
- useAnimatedReaction,
5
+ useAnimatedStyle,
6
+ useSharedValue,
7
+ type AnimatedStyle,
7
8
  } from 'react-native-reanimated';
8
9
 
9
10
  import { useTabContext } from '../../hooks/useTabContext';
10
11
  import { type ReanimatedTabViewTypes } from '../ReanimatedTopTab/types';
12
+ import { TabBarBaseItem } from './TabBarBaseItem';
11
13
 
12
14
  export interface TabBarProps extends ReanimatedTabViewTypes.RenderTabsParams {
13
15
  children?: React.ReactNode;
@@ -17,28 +19,32 @@ export interface TabBarProps extends ReanimatedTabViewTypes.RenderTabsParams {
17
19
  export const TabBarBaseComponent = ({
18
20
  children,
19
21
  navigationState,
20
- position,
21
22
  style,
22
23
  navigate,
24
+ screenOptions,
23
25
  }: TabBarProps) => {
24
- const layout = useWindowDimensions();
26
+ const { topTabHeight, positionX } = useTabContext();
27
+ const width = useSharedValue(0);
25
28
 
26
- const { topTabHeight, transformationX } = useTabContext();
29
+ const { tabBarIndicatorStyle, tabBarItemStyle, tabBarStyle } =
30
+ screenOptions ?? {};
27
31
 
28
- //Assign interpolated offsetX to transformationX
29
- useAnimatedReaction(
30
- () =>
31
- interpolate(
32
- position.value,
33
- navigationState.routes.map((_, i) => i * layout.width),
34
- navigationState.routes.map((_, i) => i),
35
- 'clamp'
36
- ),
37
- (value) => {
38
- transformationX.value = value;
39
- },
40
- [navigationState.routes]
41
- );
32
+ const inputRange = navigationState.routes.map((_, index) => index);
33
+
34
+ const indicatorStyle = useAnimatedStyle(() => {
35
+ const outputRange = navigationState.routes.map(
36
+ (_, index) => index * (width.value / navigationState.routes.length)
37
+ );
38
+
39
+ return {
40
+ transform: [
41
+ {
42
+ translateX: interpolate(positionX.value, inputRange, outputRange),
43
+ },
44
+ ],
45
+ width: width.value / navigationState.routes.length,
46
+ };
47
+ });
42
48
 
43
49
  return (
44
50
  <Reanimated.View
@@ -46,21 +52,26 @@ export const TabBarBaseComponent = ({
46
52
  topTabHeight.value = nativeEvent.layout.height;
47
53
  }}
48
54
  >
49
- <Reanimated.View style={[styles.wrapper, style]}>
55
+ <Reanimated.View
56
+ onLayout={({ nativeEvent }) => {
57
+ width.value = nativeEvent.layout.width;
58
+ }}
59
+ style={[styles.wrapper, tabBarStyle, style]}
60
+ >
61
+ <Reanimated.View
62
+ style={[styles.indicator, indicatorStyle, tabBarIndicatorStyle]}
63
+ />
50
64
  {navigationState.routes.map((route, index) => (
51
- <Pressable
52
- style={styles.labelWrapper}
65
+ <TabBarBaseItem
66
+ index={index}
67
+ inputRange={inputRange}
53
68
  key={route.key}
54
69
  onPress={() => {
55
70
  navigate(index);
56
71
  }}
57
- >
58
- {route.tabBarLabel ? (
59
- route.tabBarLabel()
60
- ) : (
61
- <Text style={styles.label}>{route.title}</Text>
62
- )}
63
- </Pressable>
72
+ route={route}
73
+ style={tabBarItemStyle}
74
+ />
64
75
  ))}
65
76
  </Reanimated.View>
66
77
  {children}
@@ -75,14 +86,14 @@ const styles = StyleSheet.create({
75
86
  alignItems: 'center',
76
87
  justifyContent: 'center',
77
88
  },
78
- label: {
79
- color: 'red',
80
- },
81
89
  wrapper: {
82
- width: '100%',
83
90
  flexDirection: 'row',
84
91
  backgroundColor: 'white',
85
- paddingVertical: 8,
86
- height: 50,
92
+ },
93
+ indicator: {
94
+ backgroundColor: 'black',
95
+ bottom: 0,
96
+ height: 2,
97
+ position: 'absolute',
87
98
  },
88
99
  });
@@ -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
+ interpolate,
10
+ useAnimatedStyle,
11
+ } from 'react-native-reanimated';
12
+ import { useTabContext } from '../../hooks/useTabContext';
13
+ import { type ReanimatedTabViewTypes } from '../ReanimatedTopTab/types';
14
+
15
+ interface TabBarBaseItemProps {
16
+ index: number;
17
+ inputRange: Array<number>;
18
+ onPress: (index: number) => void;
19
+ route: ReanimatedTabViewTypes.Route;
20
+ style?: StyleProp<ViewStyle>;
21
+ }
22
+
23
+ export const TabBarBaseItem = ({
24
+ index,
25
+ inputRange,
26
+ onPress,
27
+ route,
28
+ style,
29
+ }: TabBarBaseItemProps) => {
30
+ const { positionX } = useTabContext();
31
+
32
+ const activeStyle = useAnimatedStyle(() => ({
33
+ opacity: interpolate(
34
+ positionX.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
+ positionX.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
+ });
@@ -16,12 +16,12 @@ export const TabBarLabelBaseComponent = ({
16
16
  index,
17
17
  ...props
18
18
  }: TabBarLabelTypes) => {
19
- const transformationX = useTabOffset();
19
+ const positionX = useTabOffset();
20
20
 
21
21
  const style = useAnimatedStyle(
22
22
  () => ({
23
23
  backgroundColor: interpolateColor(
24
- transformationX.value,
24
+ positionX.value,
25
25
  [index - 1, index, index + 1],
26
26
  ['transparent', 'blue', 'transparent']
27
27
  ),
@@ -32,7 +32,7 @@ export const TabBarLabelBaseComponent = ({
32
32
  const textStyle = useAnimatedStyle(
33
33
  () => ({
34
34
  color: interpolateColor(
35
- transformationX.value,
35
+ positionX.value,
36
36
  [index - 1, index, index + 1],
37
37
  ['black', 'white', 'black']
38
38
  ),
@@ -2,7 +2,6 @@ import React, { useMemo, useRef, useState } from 'react';
2
2
  import { Gesture, GestureDetector } from 'react-native-gesture-handler';
3
3
  import Reanimated, {
4
4
  Easing,
5
- interpolate,
6
5
  runOnJS,
7
6
  useAnimatedReaction,
8
7
  useAnimatedStyle,
@@ -12,12 +11,19 @@ import Reanimated, {
12
11
  } from 'react-native-reanimated';
13
12
 
14
13
  import { useTabContext } from '../../hooks/useTabContext';
14
+ import { Platform, StyleSheet, View } from 'react-native';
15
15
 
16
16
  interface GestureWrapperProps {
17
17
  children: React.ReactNode;
18
+ bounces?: boolean;
18
19
  }
19
20
 
20
- export const GestureWrapper = ({ children }: GestureWrapperProps) => {
21
+ export const GestureWrapper = ({ children, bounces }: GestureWrapperProps) => {
22
+ const _bounces = Platform.select({
23
+ ios: bounces,
24
+ default: false,
25
+ });
26
+
21
27
  const {
22
28
  context,
23
29
  currentScreenIndex,
@@ -25,6 +31,7 @@ export const GestureWrapper = ({ children }: GestureWrapperProps) => {
25
31
  gestureEnabled,
26
32
  headerHeight,
27
33
  transformationY,
34
+ scrollY,
28
35
  } = useTabContext();
29
36
 
30
37
  const movedY = useSharedValue(0);
@@ -105,26 +112,46 @@ export const GestureWrapper = ({ children }: GestureWrapperProps) => {
105
112
  [_gestureEnabled]
106
113
  );
107
114
 
108
- const style = useAnimatedStyle(
109
- () => ({
115
+ useAnimatedReaction(
116
+ () => {
117
+ if (transformationY.value > 0) {
118
+ if (_bounces) return transformationY.value * -0.3;
119
+ else return 0;
120
+ }
121
+ if (transformationY.value < -headerHeight.value) {
122
+ return headerHeight.value;
123
+ }
124
+
125
+ return -transformationY.value;
126
+ },
127
+ (value) => {
128
+ scrollY.value = value;
129
+ }
130
+ );
131
+
132
+ const style = useAnimatedStyle(() => {
133
+ return {
110
134
  flex: 1,
111
135
  transform: [
112
136
  {
113
- translateY: interpolate(
114
- transformationY.value,
115
- [0, -headerHeight.value],
116
- [0, -headerHeight.value],
117
- 'clamp'
118
- ),
137
+ translateY: scrollY.value * -1,
119
138
  },
120
139
  ],
121
- }),
122
- []
123
- );
140
+ };
141
+ }, []);
124
142
 
125
143
  return (
126
144
  <GestureDetector gesture={gesture}>
127
- <Reanimated.View style={style}>{children}</Reanimated.View>
145
+ <View style={styles.container}>
146
+ <Reanimated.View style={style}>{children}</Reanimated.View>
147
+ </View>
128
148
  </GestureDetector>
129
149
  );
130
150
  };
151
+
152
+ const styles = StyleSheet.create({
153
+ container: {
154
+ overflow: 'hidden',
155
+ flex: 1,
156
+ },
157
+ });