react-navigation-reanimated-top-tabs 0.2.0 → 0.4.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.
- package/README.md +5 -17
- package/lib/commonjs/components/ReanimatedTopTab/ReanimatedTabView.js +5 -3
- package/lib/commonjs/components/ReanimatedTopTab/ReanimatedTabView.js.map +1 -1
- package/lib/commonjs/components/elements/TabBarBaseComponent.js +6 -5
- package/lib/commonjs/components/elements/TabBarBaseComponent.js.map +1 -1
- package/lib/commonjs/components/elements/TabBarLabelBaseComponent.js +2 -4
- package/lib/commonjs/components/elements/TabBarLabelBaseComponent.js.map +1 -1
- package/lib/commonjs/components/wrappers/GestureWrapper.js +18 -26
- package/lib/commonjs/components/wrappers/GestureWrapper.js.map +1 -1
- package/lib/commonjs/components/wrappers/ScreenWrapper.js +4 -4
- package/lib/commonjs/components/wrappers/ScreenWrapper.js.map +1 -1
- package/lib/commonjs/components/wrappers/ScrollView.js +27 -16
- package/lib/commonjs/components/wrappers/ScrollView.js.map +1 -1
- package/lib/commonjs/context/Context.helpers.js +19 -0
- package/lib/commonjs/context/Context.helpers.js.map +1 -0
- package/lib/commonjs/context/Context.hooks.js +216 -0
- package/lib/commonjs/context/Context.hooks.js.map +1 -0
- package/lib/commonjs/context/Context.js +68 -0
- package/lib/commonjs/context/Context.js.map +1 -0
- package/lib/commonjs/hooks/useHeader.js +30 -0
- package/lib/commonjs/hooks/useHeader.js.map +1 -0
- package/lib/commonjs/hooks/useScreenGesture.js +21 -0
- package/lib/commonjs/hooks/useScreenGesture.js.map +1 -0
- package/lib/commonjs/hooks/useScreenProperties.js +21 -0
- package/lib/commonjs/hooks/useScreenProperties.js.map +1 -0
- package/lib/commonjs/hooks/useScreenScrollable.js +64 -0
- package/lib/commonjs/hooks/useScreenScrollable.js.map +1 -0
- package/lib/commonjs/hooks/useTabContext.js +11 -0
- package/lib/commonjs/hooks/useTabContext.js.map +1 -0
- package/lib/commonjs/hooks/useTabOffset.js +18 -0
- package/lib/commonjs/hooks/useTabOffset.js.map +1 -0
- package/lib/commonjs/index.js +34 -80
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/navigator/createReanimatedTopTabNavigator.js +14 -29
- package/lib/commonjs/navigator/createReanimatedTopTabNavigator.js.map +1 -1
- package/lib/commonjs/services/Warning.service.js +16 -0
- package/lib/commonjs/services/Warning.service.js.map +1 -0
- package/lib/module/components/ReanimatedTopTab/ReanimatedTabView.js +8 -6
- package/lib/module/components/ReanimatedTopTab/ReanimatedTabView.js.map +1 -1
- package/lib/module/components/elements/TabBarBaseComponent.js +5 -4
- package/lib/module/components/elements/TabBarBaseComponent.js.map +1 -1
- package/lib/module/components/elements/TabBarLabelBaseComponent.js +2 -4
- package/lib/module/components/elements/TabBarLabelBaseComponent.js.map +1 -1
- package/lib/module/components/wrappers/GestureWrapper.js +18 -27
- package/lib/module/components/wrappers/GestureWrapper.js.map +1 -1
- package/lib/module/components/wrappers/ScreenWrapper.js +3 -3
- package/lib/module/components/wrappers/ScreenWrapper.js.map +1 -1
- package/lib/module/components/wrappers/ScrollView.js +23 -12
- package/lib/module/components/wrappers/ScrollView.js.map +1 -1
- package/lib/module/context/Context.helpers.js +15 -0
- package/lib/module/context/Context.helpers.js.map +1 -0
- package/lib/module/context/Context.hooks.js +213 -0
- package/lib/module/context/Context.hooks.js.map +1 -0
- package/lib/module/context/Context.js +64 -0
- package/lib/module/context/Context.js.map +1 -0
- package/lib/module/hooks/useHeader.js +25 -0
- package/lib/module/hooks/useHeader.js.map +1 -0
- package/lib/module/hooks/useScreenGesture.js +16 -0
- package/lib/module/hooks/useScreenGesture.js.map +1 -0
- package/lib/module/hooks/useScreenProperties.js +16 -0
- package/lib/module/hooks/useScreenProperties.js.map +1 -0
- package/lib/module/hooks/useScreenScrollable.js +57 -0
- package/lib/module/hooks/useScreenScrollable.js.map +1 -0
- package/lib/module/hooks/useTabContext.js +6 -0
- package/lib/module/hooks/useTabContext.js.map +1 -0
- package/lib/module/hooks/useTabOffset.js +12 -0
- package/lib/module/hooks/useTabOffset.js.map +1 -0
- package/lib/module/index.js +33 -8
- package/lib/module/index.js.map +1 -1
- package/lib/module/navigator/createReanimatedTopTabNavigator.js +13 -27
- package/lib/module/navigator/createReanimatedTopTabNavigator.js.map +1 -1
- package/lib/module/services/Warning.service.js +12 -0
- package/lib/module/services/Warning.service.js.map +1 -0
- package/lib/typescript/src/components/ReanimatedTopTab/AnimationHelper.d.ts.map +1 -0
- package/lib/typescript/src/components/ReanimatedTopTab/ReanimatedTabView.d.ts.map +1 -0
- package/lib/typescript/src/components/ReanimatedTopTab/types.d.ts.map +1 -0
- package/lib/typescript/{module/src → src}/components/elements/TabBarBaseComponent.d.ts +1 -2
- package/lib/typescript/src/components/elements/TabBarBaseComponent.d.ts.map +1 -0
- package/lib/typescript/{commonjs/src → src}/components/elements/TabBarLabelBaseComponent.d.ts +1 -2
- package/lib/typescript/src/components/elements/TabBarLabelBaseComponent.d.ts.map +1 -0
- package/lib/typescript/src/components/wrappers/GestureWrapper.d.ts +7 -0
- package/lib/typescript/src/components/wrappers/GestureWrapper.d.ts.map +1 -0
- package/lib/typescript/src/components/wrappers/ScreenWrapper.d.ts.map +1 -0
- package/lib/typescript/src/components/wrappers/ScrollView.d.ts +5 -0
- package/lib/typescript/src/components/wrappers/ScrollView.d.ts.map +1 -0
- package/lib/typescript/{commonjs/src/context/TopTabContext.d.ts → src/context/Context.d.ts} +2 -2
- package/lib/typescript/src/context/Context.d.ts.map +1 -0
- package/lib/typescript/src/context/Context.helpers.d.ts +4 -0
- package/lib/typescript/src/context/Context.helpers.d.ts.map +1 -0
- package/lib/typescript/src/context/Context.hooks.d.ts +15 -0
- package/lib/typescript/src/context/Context.hooks.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useHeader.d.ts +10 -0
- package/lib/typescript/src/hooks/useHeader.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useScreenGesture.d.ts +2 -0
- package/lib/typescript/src/hooks/useScreenGesture.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useScreenProperties.d.ts +10 -0
- package/lib/typescript/src/hooks/useScreenProperties.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useScreenScrollable.d.ts +14 -0
- package/lib/typescript/src/hooks/useScreenScrollable.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useTabContext.d.ts +2 -0
- package/lib/typescript/src/hooks/useTabContext.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useTabOffset.d.ts +2 -0
- package/lib/typescript/src/hooks/useTabOffset.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +45 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/navigator/createReanimatedTopTabNavigator.d.ts.map +1 -0
- package/lib/typescript/src/services/Warning.service.d.ts +5 -0
- package/lib/typescript/src/services/Warning.service.d.ts.map +1 -0
- package/lib/typescript/{module/src → src}/types.d.ts +24 -17
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +24 -38
- package/src/components/ReanimatedTopTab/ReanimatedTabView.tsx +7 -6
- package/src/components/elements/TabBarBaseComponent.tsx +7 -3
- package/src/components/elements/TabBarLabelBaseComponent.tsx +4 -3
- package/src/components/wrappers/GestureWrapper.tsx +27 -29
- package/src/components/wrappers/ScreenWrapper.tsx +4 -3
- package/src/components/wrappers/ScrollView.tsx +33 -19
- package/src/context/Context.helpers.tsx +10 -0
- package/src/context/Context.hooks.ts +253 -0
- package/src/context/Context.tsx +69 -0
- package/src/hooks/useHeader.ts +30 -0
- package/src/hooks/useScreenGesture.ts +13 -0
- package/src/hooks/useScreenProperties.ts +11 -0
- package/src/hooks/useScreenScrollable.ts +69 -0
- package/src/hooks/useTabContext.ts +4 -0
- package/src/hooks/useTabOffset.ts +8 -0
- package/src/index.tsx +34 -10
- package/src/navigator/createReanimatedTopTabNavigator.tsx +8 -32
- package/src/services/Warning.service.ts +11 -0
- package/src/types.ts +23 -19
- package/lib/commonjs/context/TopTabContext.hooks.js +0 -48
- package/lib/commonjs/context/TopTabContext.hooks.js.map +0 -1
- package/lib/commonjs/context/TopTabContext.js +0 -86
- package/lib/commonjs/context/TopTabContext.js.map +0 -1
- package/lib/commonjs/hooks/TopTab.hooks.js +0 -120
- package/lib/commonjs/hooks/TopTab.hooks.js.map +0 -1
- package/lib/module/context/TopTabContext.hooks.js +0 -44
- package/lib/module/context/TopTabContext.hooks.js.map +0 -1
- package/lib/module/context/TopTabContext.js +0 -82
- package/lib/module/context/TopTabContext.js.map +0 -1
- package/lib/module/hooks/TopTab.hooks.js +0 -110
- package/lib/module/hooks/TopTab.hooks.js.map +0 -1
- package/lib/typescript/commonjs/src/components/ReanimatedTopTab/AnimationHelper.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/components/ReanimatedTopTab/ReanimatedTabView.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/components/ReanimatedTopTab/types.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/components/elements/TabBarBaseComponent.d.ts +0 -24
- package/lib/typescript/commonjs/src/components/elements/TabBarBaseComponent.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/components/elements/TabBarLabelBaseComponent.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/components/wrappers/GestureWrapper.d.ts +0 -2
- package/lib/typescript/commonjs/src/components/wrappers/GestureWrapper.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/components/wrappers/ScreenWrapper.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/components/wrappers/ScrollView.d.ts +0 -6
- package/lib/typescript/commonjs/src/components/wrappers/ScrollView.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/context/TopTabContext.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/context/TopTabContext.hooks.d.ts +0 -5
- package/lib/typescript/commonjs/src/context/TopTabContext.hooks.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/hooks/TopTab.hooks.d.ts +0 -33
- package/lib/typescript/commonjs/src/hooks/TopTab.hooks.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/index.d.ts +0 -10
- package/lib/typescript/commonjs/src/index.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/navigator/createReanimatedTopTabNavigator.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/types.d.ts +0 -56
- package/lib/typescript/commonjs/src/types.d.ts.map +0 -1
- package/lib/typescript/module/src/components/ReanimatedTopTab/AnimationHelper.d.ts +0 -11
- package/lib/typescript/module/src/components/ReanimatedTopTab/AnimationHelper.d.ts.map +0 -1
- package/lib/typescript/module/src/components/ReanimatedTopTab/ReanimatedTabView.d.ts +0 -14
- package/lib/typescript/module/src/components/ReanimatedTopTab/ReanimatedTabView.d.ts.map +0 -1
- package/lib/typescript/module/src/components/ReanimatedTopTab/types.d.ts +0 -30
- package/lib/typescript/module/src/components/ReanimatedTopTab/types.d.ts.map +0 -1
- package/lib/typescript/module/src/components/elements/TabBarBaseComponent.d.ts.map +0 -1
- package/lib/typescript/module/src/components/elements/TabBarLabelBaseComponent.d.ts +0 -8
- package/lib/typescript/module/src/components/elements/TabBarLabelBaseComponent.d.ts.map +0 -1
- package/lib/typescript/module/src/components/wrappers/GestureWrapper.d.ts +0 -2
- package/lib/typescript/module/src/components/wrappers/GestureWrapper.d.ts.map +0 -1
- package/lib/typescript/module/src/components/wrappers/ScreenWrapper.d.ts +0 -6
- package/lib/typescript/module/src/components/wrappers/ScreenWrapper.d.ts.map +0 -1
- package/lib/typescript/module/src/components/wrappers/ScrollView.d.ts +0 -6
- package/lib/typescript/module/src/components/wrappers/ScrollView.d.ts.map +0 -1
- package/lib/typescript/module/src/context/TopTabContext.d.ts +0 -4
- package/lib/typescript/module/src/context/TopTabContext.d.ts.map +0 -1
- package/lib/typescript/module/src/context/TopTabContext.hooks.d.ts +0 -5
- package/lib/typescript/module/src/context/TopTabContext.hooks.d.ts.map +0 -1
- package/lib/typescript/module/src/hooks/TopTab.hooks.d.ts +0 -33
- package/lib/typescript/module/src/hooks/TopTab.hooks.d.ts.map +0 -1
- package/lib/typescript/module/src/index.d.ts +0 -10
- package/lib/typescript/module/src/index.d.ts.map +0 -1
- package/lib/typescript/module/src/navigator/createReanimatedTopTabNavigator.d.ts +0 -4
- package/lib/typescript/module/src/navigator/createReanimatedTopTabNavigator.d.ts.map +0 -1
- package/lib/typescript/module/src/types.d.ts.map +0 -1
- package/src/context/TopTabContext.hooks.ts +0 -55
- package/src/context/TopTabContext.tsx +0 -115
- package/src/hooks/TopTab.hooks.ts +0 -112
- /package/lib/{typescript/commonjs → commonjs}/package.json +0 -0
- /package/lib/{typescript/module → module}/package.json +0 -0
- /package/lib/typescript/{commonjs/src → src}/components/ReanimatedTopTab/AnimationHelper.d.ts +0 -0
- /package/lib/typescript/{commonjs/src → src}/components/ReanimatedTopTab/ReanimatedTabView.d.ts +0 -0
- /package/lib/typescript/{commonjs/src → src}/components/ReanimatedTopTab/types.d.ts +0 -0
- /package/lib/typescript/{commonjs/src → src}/components/wrappers/ScreenWrapper.d.ts +0 -0
- /package/lib/typescript/{commonjs/src → src}/navigator/createReanimatedTopTabNavigator.d.ts +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useMemo, useRef, useState } from 'react';
|
|
1
|
+
import React, { useMemo, useRef, useState } from 'react';
|
|
2
2
|
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
|
|
3
3
|
import Reanimated, {
|
|
4
4
|
Easing,
|
|
@@ -6,27 +6,38 @@ import Reanimated, {
|
|
|
6
6
|
runOnJS,
|
|
7
7
|
useAnimatedReaction,
|
|
8
8
|
useAnimatedStyle,
|
|
9
|
+
useDerivedValue,
|
|
9
10
|
useSharedValue,
|
|
10
11
|
withTiming,
|
|
11
12
|
} from 'react-native-reanimated';
|
|
12
|
-
import { useTabContext } from '../../hooks/TopTab.hooks';
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
import { useTabContext } from '../../hooks/useTabContext';
|
|
15
|
+
|
|
16
|
+
interface GestureWrapperProps {
|
|
17
|
+
children: React.ReactNode;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const GestureWrapper = ({ children }: GestureWrapperProps) => {
|
|
16
21
|
const {
|
|
22
|
+
context,
|
|
17
23
|
currentScreenIndex,
|
|
18
24
|
currentYPosition,
|
|
19
25
|
gestureEnabled,
|
|
20
26
|
headerHeight,
|
|
21
|
-
screenProperties,
|
|
22
27
|
transformationY,
|
|
23
|
-
screenRefs,
|
|
24
28
|
} = useTabContext();
|
|
25
29
|
|
|
26
30
|
const movedY = useSharedValue(0);
|
|
27
31
|
|
|
28
32
|
const gestureRef = useRef(Gesture.Pan());
|
|
29
33
|
|
|
34
|
+
const currentScreenScrollOffset = useDerivedValue(
|
|
35
|
+
() =>
|
|
36
|
+
Object.values(context.screen.properties).map(({ scrollY }) => scrollY)[
|
|
37
|
+
currentScreenIndex.value
|
|
38
|
+
]?.value ?? 0
|
|
39
|
+
);
|
|
40
|
+
|
|
30
41
|
const withTimingConfig = {
|
|
31
42
|
duration: 300,
|
|
32
43
|
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
|
|
@@ -42,41 +53,27 @@ export const GestureWrapper = ({ children }: any) => {
|
|
|
42
53
|
[]
|
|
43
54
|
);
|
|
44
55
|
|
|
45
|
-
const _scrollTo = (index: number, value: number = 0) => {
|
|
46
|
-
const { scrollTo } = Object.values(screenRefs.refs.current)[index]
|
|
47
|
-
?.current ?? { scrollTo: () => null };
|
|
48
|
-
|
|
49
|
-
scrollTo({
|
|
50
|
-
y: value,
|
|
51
|
-
animated: false,
|
|
52
|
-
});
|
|
53
|
-
};
|
|
54
|
-
|
|
55
56
|
const gesture = useMemo(
|
|
56
57
|
() =>
|
|
57
58
|
Gesture.Pan()
|
|
58
59
|
.activeOffsetY([-10, 10])
|
|
59
60
|
.onTouchesMove(({ state }, stateManager) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
'worklet';
|
|
62
|
+
if (
|
|
63
|
+
currentScreenScrollOffset.value > 0 &&
|
|
64
|
+
state !== 4 &&
|
|
65
|
+
state !== 3
|
|
66
|
+
) {
|
|
65
67
|
stateManager.fail();
|
|
66
68
|
}
|
|
67
69
|
})
|
|
68
70
|
.onUpdate(({ translationY }) => {
|
|
69
|
-
|
|
70
|
-
runOnJS(_scrollTo)(
|
|
71
|
-
currentScreenIndex.value,
|
|
72
|
-
Math.abs(translationY + headerHeight.value)
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
|
|
71
|
+
'worklet';
|
|
76
72
|
transformationY.value =
|
|
77
73
|
currentYPosition.value + translationY - movedY.value;
|
|
78
74
|
})
|
|
79
75
|
.onEnd(({ translationY, velocityY }) => {
|
|
76
|
+
'worklet';
|
|
80
77
|
const gestureValue = translationY + velocityY * 0.2;
|
|
81
78
|
const changeOffset = 0.2 * headerHeight.value;
|
|
82
79
|
|
|
@@ -98,10 +95,11 @@ export const GestureWrapper = ({ children }: any) => {
|
|
|
98
95
|
}
|
|
99
96
|
})
|
|
100
97
|
.onFinalize(() => {
|
|
98
|
+
'worklet';
|
|
101
99
|
movedY.value = 0;
|
|
102
100
|
})
|
|
103
101
|
.simultaneousWithExternalGesture(
|
|
104
|
-
...Object.values(
|
|
102
|
+
...Object.values(context.screen.properties).map(
|
|
105
103
|
({ nativeGesture }) => nativeGesture
|
|
106
104
|
)
|
|
107
105
|
)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useRoute } from '@react-navigation/native';
|
|
2
2
|
import { type LayoutChangeEvent, type ViewProps } from 'react-native';
|
|
3
3
|
import Reanimated, { type AnimatedProps } from 'react-native-reanimated';
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
import { useTabContext } from '../../hooks/useTabContext';
|
|
5
6
|
|
|
6
7
|
export interface ScreenWrapperProps
|
|
7
8
|
extends AnimatedProps<Omit<ViewProps, 'onLayout'>> {}
|
|
@@ -11,10 +12,10 @@ export const ScreenWrapper = ({
|
|
|
11
12
|
...viewProps
|
|
12
13
|
}: ScreenWrapperProps) => {
|
|
13
14
|
const { key } = useRoute();
|
|
14
|
-
const {
|
|
15
|
+
const { context } = useTabContext();
|
|
15
16
|
|
|
16
17
|
const onLayout = (event: LayoutChangeEvent) => {
|
|
17
|
-
const screen =
|
|
18
|
+
const screen = context.screen.properties[key];
|
|
18
19
|
if (!screen) throw 'No screen property registered for this route';
|
|
19
20
|
screen.outerLayout.value = event.nativeEvent.layout;
|
|
20
21
|
};
|
|
@@ -5,46 +5,60 @@ import {
|
|
|
5
5
|
} from 'react-native';
|
|
6
6
|
import { GestureDetector } from 'react-native-gesture-handler';
|
|
7
7
|
import Reanimated, { type AnimatedProps } from 'react-native-reanimated';
|
|
8
|
-
import {
|
|
9
|
-
useScreenGesture,
|
|
10
|
-
useScreenProperties,
|
|
11
|
-
useScreenScrollable,
|
|
12
|
-
useTabContext,
|
|
13
|
-
} from '../../hooks/TopTab.hooks';
|
|
14
8
|
import { useRef } from 'react';
|
|
15
9
|
import { useRoute } from '@react-navigation/native';
|
|
10
|
+
import { useTabContext } from '../../hooks/useTabContext';
|
|
11
|
+
import { useScreenGesture } from '../../hooks/useScreenGesture';
|
|
12
|
+
import { useScreenScrollable } from '../../hooks/useScreenScrollable';
|
|
13
|
+
import { useScreenProperties } from '../../hooks/useScreenProperties';
|
|
16
14
|
|
|
17
|
-
export
|
|
18
|
-
|
|
15
|
+
export type ScreenWrapperProps = AnimatedProps<
|
|
16
|
+
Omit<ScrollViewProps, 'onScroll' | 'onLayout' | 'bounces'>
|
|
17
|
+
> &
|
|
18
|
+
Pick<ScrollViewProps, 'onLayout'> & {};
|
|
19
19
|
|
|
20
20
|
export const ScrollView = ({
|
|
21
21
|
children,
|
|
22
22
|
style,
|
|
23
|
+
contentContainerStyle,
|
|
24
|
+
onLayout,
|
|
23
25
|
...props
|
|
24
26
|
}: ScreenWrapperProps) => {
|
|
25
27
|
const gesture = useScreenGesture();
|
|
26
|
-
const {
|
|
28
|
+
const {
|
|
29
|
+
style: _style,
|
|
30
|
+
contentContainerStyle: _contentContainerStyle,
|
|
31
|
+
onScroll,
|
|
32
|
+
bounces,
|
|
33
|
+
animatedProps,
|
|
34
|
+
} = useScreenScrollable();
|
|
27
35
|
const { innerLayout } = useScreenProperties();
|
|
28
|
-
const {
|
|
36
|
+
const { context } = useTabContext();
|
|
29
37
|
|
|
30
38
|
const { key } = useRoute();
|
|
31
|
-
|
|
32
39
|
const _ref = useRef<Reanimated.ScrollView>(null);
|
|
33
40
|
|
|
34
|
-
const
|
|
41
|
+
const _onLayout = (event: LayoutChangeEvent) => {
|
|
42
|
+
onLayout?.(event);
|
|
35
43
|
innerLayout.value = event.nativeEvent.layout;
|
|
36
|
-
|
|
44
|
+
context.screen.setRef(key, _ref.current);
|
|
37
45
|
};
|
|
38
46
|
|
|
39
47
|
return (
|
|
40
48
|
<GestureDetector gesture={gesture}>
|
|
41
49
|
<Reanimated.ScrollView
|
|
42
|
-
{...scrollProps}
|
|
43
|
-
{...props}
|
|
44
50
|
ref={_ref}
|
|
45
|
-
contentContainerStyle={
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
contentContainerStyle={[
|
|
52
|
+
_contentContainerStyle,
|
|
53
|
+
styleSheet.contentContainerStyle,
|
|
54
|
+
contentContainerStyle,
|
|
55
|
+
]}
|
|
56
|
+
onLayout={_onLayout}
|
|
57
|
+
style={[_style, style]}
|
|
58
|
+
onScroll={onScroll}
|
|
59
|
+
bounces={bounces}
|
|
60
|
+
animatedProps={animatedProps}
|
|
61
|
+
{...props}
|
|
48
62
|
>
|
|
49
63
|
{children}
|
|
50
64
|
</Reanimated.ScrollView>
|
|
@@ -52,7 +66,7 @@ export const ScrollView = ({
|
|
|
52
66
|
);
|
|
53
67
|
};
|
|
54
68
|
|
|
55
|
-
const
|
|
69
|
+
const styleSheet = StyleSheet.create({
|
|
56
70
|
contentContainerStyle: {
|
|
57
71
|
flexGrow: 1,
|
|
58
72
|
},
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const getTargetIndex = (currentValue: number, previousValue: number | null) => {
|
|
2
|
+
'worklet';
|
|
3
|
+
if (currentValue > (previousValue ?? 0)) {
|
|
4
|
+
return Math.ceil(currentValue);
|
|
5
|
+
} else {
|
|
6
|
+
return Math.floor(currentValue);
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const ContextHelpers = { getTargetIndex };
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import Reanimated, {
|
|
2
|
+
interpolate,
|
|
3
|
+
makeMutable,
|
|
4
|
+
runOnJS,
|
|
5
|
+
useAnimatedReaction,
|
|
6
|
+
useDerivedValue,
|
|
7
|
+
useSharedValue,
|
|
8
|
+
} from 'react-native-reanimated';
|
|
9
|
+
import { type ReanimatedTopTabNavigation } from '../types';
|
|
10
|
+
import { useRef } from 'react';
|
|
11
|
+
import type {
|
|
12
|
+
ParamListBase,
|
|
13
|
+
TabNavigationState,
|
|
14
|
+
} from '@react-navigation/native';
|
|
15
|
+
import { Gesture } from 'react-native-gesture-handler';
|
|
16
|
+
import { assign } from 'lodash';
|
|
17
|
+
import { ContextHelpers } from './Context.helpers';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Hook to reset the scroll offset for the approaching screen in a tab navigation context.
|
|
21
|
+
*
|
|
22
|
+
* @param {Object} params - The parameters for configuring the scroll offset reset.
|
|
23
|
+
* @param {ReanimatedTopTabNavigation.ContextType["context"]} params.context - The context containing navigation and screen information.
|
|
24
|
+
* @param {ReanimatedTopTabNavigation.ContextType["transformationX"]} params.transformationX - The horizontal transformation value used in animations.
|
|
25
|
+
* @param {ReanimatedTopTabNavigation.ContextType["currentYPosition"]} params.currentYPosition - The current vertical scroll position.
|
|
26
|
+
*
|
|
27
|
+
* The hook is responsible for resetting the vertical scroll offset of the "approaching" screen within a tabbed navigation interface,
|
|
28
|
+
* ensuring a smooth user experience by resetting the scroll position to the top under certain conditions.
|
|
29
|
+
* When the user swipes across tabs, it checks if the approaching screen has a non-zero scroll offset and resets it
|
|
30
|
+
* if the current screen is at the top position.
|
|
31
|
+
*/
|
|
32
|
+
const useResetApproachingScreenScrollOffset = ({
|
|
33
|
+
context,
|
|
34
|
+
transformationX,
|
|
35
|
+
currentYPosition,
|
|
36
|
+
}: Pick<
|
|
37
|
+
ReanimatedTopTabNavigation.ContextType,
|
|
38
|
+
'context' | 'currentYPosition' | 'transformationX'
|
|
39
|
+
>) => {
|
|
40
|
+
const screenOffsets = useDerivedValue(() =>
|
|
41
|
+
Object.values(context.screen.properties).map(({ scrollY }) => scrollY.value)
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const resetApproachingScreenOffset = (
|
|
45
|
+
index: number,
|
|
46
|
+
shouldReset: boolean
|
|
47
|
+
) => {
|
|
48
|
+
if (shouldReset) {
|
|
49
|
+
const { scrollTo } = context.screen.getRef(
|
|
50
|
+
context.route.getKeyForIndex(index)
|
|
51
|
+
).current ?? { scrollTo: () => {} };
|
|
52
|
+
//NOTE: use reanimated scrollTo does not work
|
|
53
|
+
scrollTo({ y: 0, animated: false });
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
useAnimatedReaction(
|
|
58
|
+
() => transformationX.value,
|
|
59
|
+
(current, previous) => {
|
|
60
|
+
const approachingIndex = ContextHelpers.getTargetIndex(current, previous);
|
|
61
|
+
|
|
62
|
+
const approachingScreenOffset =
|
|
63
|
+
screenOffsets.value[approachingIndex] ?? -1;
|
|
64
|
+
|
|
65
|
+
runOnJS(resetApproachingScreenOffset)(
|
|
66
|
+
approachingIndex,
|
|
67
|
+
approachingScreenOffset > 0 && currentYPosition.value === 0
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Custom hook to prepare a key map for Tab Navigation.
|
|
75
|
+
*
|
|
76
|
+
* @param {Object} params - The parameters for the hook.
|
|
77
|
+
* @param {TabNavigationState<any>} params.state - The navigation state object containing route information.
|
|
78
|
+
* @returns {ReanimatedTopTabNavigation.TopTabContextProps['context']['route']} An object containing:
|
|
79
|
+
* - map: A mapping of tab indices to route keys.
|
|
80
|
+
* - getKeyForIndex: A function that takes an index and returns the corresponding route key.
|
|
81
|
+
* @throws Will throw an error if the key for the provided index does not exist.
|
|
82
|
+
*/
|
|
83
|
+
const usePrepareKeyMap = ({
|
|
84
|
+
state,
|
|
85
|
+
}: {
|
|
86
|
+
state: TabNavigationState<any>;
|
|
87
|
+
}): ReanimatedTopTabNavigation.TopTabContextProps['context']['route'] => {
|
|
88
|
+
const indexToKeyMap = useRef(
|
|
89
|
+
state.routes.reduce(
|
|
90
|
+
(previousValue, currentValue, currentIndex) => ({
|
|
91
|
+
...previousValue,
|
|
92
|
+
[currentIndex]: currentValue.key,
|
|
93
|
+
}),
|
|
94
|
+
{} as Record<number, string>
|
|
95
|
+
)
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const getKeyForIndex = (index: number) => {
|
|
99
|
+
const key = indexToKeyMap.current[index];
|
|
100
|
+
if (!key) throw '[getKeyForIndex]: Key does not exist';
|
|
101
|
+
return key;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
return { map: indexToKeyMap.current, getKeyForIndex };
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Prepares screen properties and manages scroll references for each route in the navigation state.
|
|
109
|
+
*
|
|
110
|
+
* @param {Object} params - The parameters for preparing the screen.
|
|
111
|
+
* @param {TabNavigationState<any>} params.state - The navigation state containing route information.
|
|
112
|
+
* @returns {Object} An object containing screen properties, and methods to set and get scroll references.
|
|
113
|
+
* @property {Object} properties - The current screen properties.
|
|
114
|
+
* @property {Function} setRef - Function to set the scroll reference for a specific route.
|
|
115
|
+
* @property {Function} getRef - Function to get the scroll reference of a specific route.
|
|
116
|
+
*/
|
|
117
|
+
const usePrepareScreen = ({
|
|
118
|
+
state,
|
|
119
|
+
}: {
|
|
120
|
+
state: TabNavigationState<ParamListBase>;
|
|
121
|
+
}) => {
|
|
122
|
+
const screenProperties = useRef(
|
|
123
|
+
state.routes.reduce(
|
|
124
|
+
(prev, route) => ({
|
|
125
|
+
...prev,
|
|
126
|
+
[route.key]: {
|
|
127
|
+
innerLayout: makeMutable({
|
|
128
|
+
height: 0,
|
|
129
|
+
width: 0,
|
|
130
|
+
x: 0,
|
|
131
|
+
y: 0,
|
|
132
|
+
}),
|
|
133
|
+
nativeGesture: Gesture.Native(),
|
|
134
|
+
outerLayout: makeMutable({
|
|
135
|
+
height: 0,
|
|
136
|
+
width: 0,
|
|
137
|
+
x: 0,
|
|
138
|
+
y: 0,
|
|
139
|
+
}),
|
|
140
|
+
scrollY: makeMutable(0),
|
|
141
|
+
scrollRef: { current: null },
|
|
142
|
+
},
|
|
143
|
+
}),
|
|
144
|
+
{} as ReanimatedTopTabNavigation.ContextType['context']['screen']['properties']
|
|
145
|
+
)
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const setRef = (key: string, ref: Reanimated.ScrollView) => {
|
|
149
|
+
const newProperties = assign({}, screenProperties.current[key], {
|
|
150
|
+
scrollRef: { current: ref },
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
screenProperties.current = assign({}, screenProperties.current, {
|
|
154
|
+
[key]: newProperties,
|
|
155
|
+
});
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const getRef = (key: string) => {
|
|
159
|
+
const _ref = screenProperties.current[key]?.scrollRef;
|
|
160
|
+
if (!_ref) throw '[getRef]: Ref does not exist';
|
|
161
|
+
return _ref;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
return { properties: screenProperties.current, setRef, getRef };
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Prepares the context required for top tab navigation.
|
|
169
|
+
*
|
|
170
|
+
* This function takes the current state of the navigation
|
|
171
|
+
* and prepares the necessary context properties such as `screen`
|
|
172
|
+
* and `route`, which are then used for navigation purposes.
|
|
173
|
+
*
|
|
174
|
+
* @param {Object} params - The parameters for preparing the context.
|
|
175
|
+
* @param {TabNavigationState<any>} params.state - The current state of the navigation.
|
|
176
|
+
*
|
|
177
|
+
* @returns {ReanimatedTopTabNavigation.TopTabContextProps['context']} The prepared context containing screen and route properties.
|
|
178
|
+
*/
|
|
179
|
+
const usePrepareContext = ({
|
|
180
|
+
state,
|
|
181
|
+
}: {
|
|
182
|
+
state: TabNavigationState<ParamListBase>;
|
|
183
|
+
}): ReanimatedTopTabNavigation.TopTabContextProps['context'] => {
|
|
184
|
+
const screen = usePrepareScreen({ state });
|
|
185
|
+
const route = usePrepareKeyMap({ state });
|
|
186
|
+
|
|
187
|
+
return { screen, route };
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Custom hook that handles the transformation of a header component based on tab changes, particularly
|
|
192
|
+
* for animations and configurations involving header behavior. Utilizes shared and derived values to
|
|
193
|
+
* manage the translation of the header on the Y-axis and maintain its position based on the specified
|
|
194
|
+
* configurations.
|
|
195
|
+
*
|
|
196
|
+
* @param {Object} params - The parameters object.
|
|
197
|
+
* @param {Array} params.config - An array of configuration settings to determine the header's transformation.
|
|
198
|
+
* @returns {Object} An object containing shared values for header transformations and positioning:
|
|
199
|
+
* - transformationY: The derived Y-axis transformation value for the header.
|
|
200
|
+
* - transformationX: The shared X-axis transformation value to be observed.
|
|
201
|
+
* - currentYPosition: The shared Y-axis position of the header.
|
|
202
|
+
* - headerHeight: The shared height value of the header.
|
|
203
|
+
*/
|
|
204
|
+
const useTransformHeaderOnTabChange = ({
|
|
205
|
+
config,
|
|
206
|
+
}: Pick<ReanimatedTopTabNavigation.ContextType, 'config'>) => {
|
|
207
|
+
const headerHeight = useSharedValue(0);
|
|
208
|
+
const transformationY = useSharedValue(0);
|
|
209
|
+
const transformationX = useSharedValue(0);
|
|
210
|
+
const currentYPosition = useSharedValue(0);
|
|
211
|
+
|
|
212
|
+
//Hide header base on config
|
|
213
|
+
const inputRange = useDerivedValue(
|
|
214
|
+
() => config.map((_, idx) => idx),
|
|
215
|
+
[config]
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
const outputRange = useDerivedValue(
|
|
219
|
+
() =>
|
|
220
|
+
config.map((type) => {
|
|
221
|
+
switch (type) {
|
|
222
|
+
case 'normal':
|
|
223
|
+
return 0;
|
|
224
|
+
case 'minimalized':
|
|
225
|
+
return -headerHeight.value;
|
|
226
|
+
default:
|
|
227
|
+
return 0;
|
|
228
|
+
}
|
|
229
|
+
}),
|
|
230
|
+
[config]
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
useAnimatedReaction(
|
|
234
|
+
() => transformationX.value,
|
|
235
|
+
(value) => {
|
|
236
|
+
if (currentYPosition.value === -headerHeight.value) return;
|
|
237
|
+
transformationY.value = interpolate(
|
|
238
|
+
value,
|
|
239
|
+
inputRange.value,
|
|
240
|
+
outputRange.value,
|
|
241
|
+
'clamp'
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
return { transformationY, transformationX, currentYPosition, headerHeight };
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
export const ContextHooks = {
|
|
250
|
+
useResetApproachingScreenScrollOffset,
|
|
251
|
+
usePrepareContext,
|
|
252
|
+
useTransformHeaderOnTabChange,
|
|
253
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type ReanimatedTopTabNavigation } from '../types';
|
|
2
|
+
import { createContext, memo, useRef } from 'react';
|
|
3
|
+
import { Gesture } from 'react-native-gesture-handler';
|
|
4
|
+
import { useSharedValue } from 'react-native-reanimated';
|
|
5
|
+
import { ContextHooks } from './Context.hooks';
|
|
6
|
+
|
|
7
|
+
export const Context = createContext<ReanimatedTopTabNavigation.ContextType>(
|
|
8
|
+
{} as ReanimatedTopTabNavigation.ContextType
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
export const Provider = memo(
|
|
12
|
+
({
|
|
13
|
+
children,
|
|
14
|
+
config,
|
|
15
|
+
context,
|
|
16
|
+
}: ReanimatedTopTabNavigation.TopTabContextProps) => {
|
|
17
|
+
const gestureEnabled = useSharedValue(true);
|
|
18
|
+
const currentScreenIndex = useSharedValue(0);
|
|
19
|
+
|
|
20
|
+
const navHeight = useSharedValue(0);
|
|
21
|
+
const closeOffset = useSharedValue(0);
|
|
22
|
+
const topTabHeight = useSharedValue(0);
|
|
23
|
+
|
|
24
|
+
const topTabNativeGesture = useRef(Gesture.Native()).current;
|
|
25
|
+
|
|
26
|
+
const { transformationX, transformationY, currentYPosition, headerHeight } =
|
|
27
|
+
ContextHooks.useTransformHeaderOnTabChange({ config });
|
|
28
|
+
|
|
29
|
+
ContextHooks.useResetApproachingScreenScrollOffset({
|
|
30
|
+
currentYPosition,
|
|
31
|
+
transformationX,
|
|
32
|
+
context,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Context.Provider
|
|
37
|
+
value={{
|
|
38
|
+
closeOffset,
|
|
39
|
+
config,
|
|
40
|
+
currentScreenIndex,
|
|
41
|
+
currentYPosition,
|
|
42
|
+
gestureEnabled,
|
|
43
|
+
headerHeight,
|
|
44
|
+
navHeight,
|
|
45
|
+
topTabHeight,
|
|
46
|
+
topTabNativeGesture,
|
|
47
|
+
transformationX,
|
|
48
|
+
transformationY,
|
|
49
|
+
context,
|
|
50
|
+
}}
|
|
51
|
+
>
|
|
52
|
+
{children({
|
|
53
|
+
closeOffset,
|
|
54
|
+
config,
|
|
55
|
+
currentScreenIndex,
|
|
56
|
+
currentYPosition,
|
|
57
|
+
gestureEnabled,
|
|
58
|
+
headerHeight,
|
|
59
|
+
navHeight,
|
|
60
|
+
topTabHeight,
|
|
61
|
+
topTabNativeGesture,
|
|
62
|
+
transformationX,
|
|
63
|
+
transformationY,
|
|
64
|
+
context,
|
|
65
|
+
})}
|
|
66
|
+
</Context.Provider>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useTabContext } from './useTabContext';
|
|
2
|
+
import {
|
|
3
|
+
interpolate,
|
|
4
|
+
useAnimatedStyle,
|
|
5
|
+
withTiming,
|
|
6
|
+
} from 'react-native-reanimated';
|
|
7
|
+
|
|
8
|
+
export const useHeader = () => {
|
|
9
|
+
const { headerHeight, transformationX, transformationY } = useTabContext();
|
|
10
|
+
|
|
11
|
+
const hideHeader = () => {
|
|
12
|
+
transformationX.value = withTiming(-headerHeight.value);
|
|
13
|
+
};
|
|
14
|
+
|
|
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 };
|
|
30
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useRoute } from '@react-navigation/native';
|
|
2
|
+
import { useTabContext } from './useTabContext';
|
|
3
|
+
|
|
4
|
+
export const useScreenGesture = () => {
|
|
5
|
+
const { key } = useRoute();
|
|
6
|
+
const { context } = useTabContext();
|
|
7
|
+
|
|
8
|
+
const nativeRef = context.screen.properties[key]?.nativeGesture;
|
|
9
|
+
|
|
10
|
+
if (!nativeRef) throw 'GestureRef does not exist for this route';
|
|
11
|
+
|
|
12
|
+
return nativeRef;
|
|
13
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { useRoute } from '@react-navigation/native';
|
|
2
|
+
import { useTabContext } from './useTabContext';
|
|
3
|
+
|
|
4
|
+
export const useScreenProperties = () => {
|
|
5
|
+
const { key } = useRoute();
|
|
6
|
+
const { context } = useTabContext();
|
|
7
|
+
const screen = context.screen.properties[key];
|
|
8
|
+
if (!screen) throw 'No screen properties registered for this route';
|
|
9
|
+
|
|
10
|
+
return screen;
|
|
11
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { useRoute } from '@react-navigation/native';
|
|
2
|
+
import { useWindowDimensions } from 'react-native';
|
|
3
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
4
|
+
import { useTabContext } from './useTabContext';
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import { HeaderHeightContext } from '@react-navigation/elements';
|
|
7
|
+
import {
|
|
8
|
+
useAnimatedProps,
|
|
9
|
+
useAnimatedScrollHandler,
|
|
10
|
+
useAnimatedStyle,
|
|
11
|
+
useDerivedValue,
|
|
12
|
+
} from 'react-native-reanimated';
|
|
13
|
+
|
|
14
|
+
import { useScreenProperties } from './useScreenProperties';
|
|
15
|
+
|
|
16
|
+
export const useScreenScrollable = () => {
|
|
17
|
+
const { key } = useRoute();
|
|
18
|
+
const { height } = useWindowDimensions();
|
|
19
|
+
const { bottom, top } = useSafeAreaInsets();
|
|
20
|
+
const {
|
|
21
|
+
currentYPosition,
|
|
22
|
+
gestureEnabled,
|
|
23
|
+
headerHeight,
|
|
24
|
+
context,
|
|
25
|
+
topTabHeight,
|
|
26
|
+
transformationY,
|
|
27
|
+
} = useTabContext();
|
|
28
|
+
|
|
29
|
+
const screen = useScreenProperties();
|
|
30
|
+
|
|
31
|
+
const navigationHeader = React.useContext(HeaderHeightContext) ?? top;
|
|
32
|
+
|
|
33
|
+
const animatedProps = useAnimatedProps(() => ({
|
|
34
|
+
scrollEnabled:
|
|
35
|
+
!gestureEnabled.value || currentYPosition.value === -headerHeight.value,
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
const onScroll = useAnimatedScrollHandler(({ contentOffset }) => {
|
|
39
|
+
const scrollPosition = context.screen.properties[key]?.scrollY;
|
|
40
|
+
if (!scrollPosition)
|
|
41
|
+
throw 'ScrollPosition property does not exist for this route';
|
|
42
|
+
scrollPosition.value = contentOffset.y;
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const oppositeHeaderState = useDerivedValue(() =>
|
|
46
|
+
transformationY.value >= 0 ? headerHeight.value : 0
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const difference = useDerivedValue(() =>
|
|
50
|
+
Math.abs(screen.outerLayout.value.height - screen.innerLayout.value.height)
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const style = useAnimatedStyle(() => ({
|
|
54
|
+
minHeight:
|
|
55
|
+
height -
|
|
56
|
+
topTabHeight.value -
|
|
57
|
+
oppositeHeaderState.value -
|
|
58
|
+
navigationHeader -
|
|
59
|
+
difference.value,
|
|
60
|
+
}));
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
animatedProps,
|
|
64
|
+
bounces: false,
|
|
65
|
+
contentContainerStyle: { paddingBottom: bottom },
|
|
66
|
+
onScroll,
|
|
67
|
+
style,
|
|
68
|
+
};
|
|
69
|
+
};
|