Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/docs/01-getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Before using this package, please make sure that you install the correct version
| 0.6.x | >= 0.65 | >= 2.11.0 | >= 4.1.0 | N/A |
| 0.7.x | >= 0.65 | >= 2.0.0 | >= 4.1.0 | N/A |
| 0.8.x | >= 0.65 | >= 2.0.0 | >= 4.1.0 | N/A |
| 0.9.x | >= 0.65 | >= 2.0.0 | >= 4.1.0 | >= 3.2.0 |
| >= 0.9.x | >= 0.65 | >= 2.0.0 | >= 4.1.0 | >= 3.2.0 |

## Pre-requisites

Expand Down
20 changes: 20 additions & 0 deletions docs/docs/03-api-reference/01-scroll-view-with-headers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,28 @@ want to access the layout of the large header to calculate the height of the lar
This property controls whether or not the header component is absolutely positioned. This is useful
if you want to render a header component that allows for transparency.

**Note**: This is only available in version >= 0.9.0.

### initialAbsoluteHeaderHeight

This property is used when `absoluteHeader` is true. This is the initial height of the
absolute header. Since the header's height is computed on its layout event, this is used
to set the initial height of the header so that it doesn't jump when it is initially rendered.

**Note**: This is only available in version >= 0.9.0.

### headerFadeInThreshold

A number between 0 and 1 representing at what point the header should fade in,
based on the percentage of the LargeHeader's height. For example, if this is set to 0.5,
the header will fade in when the scroll position is at 50% of the LargeHeader's height.

Defaults to `1`.

**Note**: This is only available in version >= 0.10.0.

### disableLargeHeaderFadeAnim

Whether or not the LargeHeaderComponent should fade in and out. Defaults to `false`.

**Note**: This is only available in version >= 0.10.0.
20 changes: 20 additions & 0 deletions docs/docs/03-api-reference/02-flat-list-with-headers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,28 @@ want to access the layout of the large header to calculate the height of the lar
This property controls whether or not the header component is absolutely positioned. This is useful
if you want to render a header component that allows for transparency.

**Note**: This is only available in version >= 0.9.0.

### initialAbsoluteHeaderHeight

This property is used when `absoluteHeader` is true. This is the initial height of the
absolute header. Since the header's height is computed on its layout event, this is used
to set the initial height of the header so that it doesn't jump when it is initially rendered.

**Note**: This is only available in version >= 0.9.0.

### headerFadeInThreshold

A number between 0 and 1 representing at what point the header should fade in,
based on the percentage of the LargeHeader's height. For example, if this is set to 0.5,
the header will fade in when the scroll position is at 50% of the LargeHeader's height.

Defaults to `1`.

**Note**: This is only available in version >= 0.10.0.

### disableLargeHeaderFadeAnim

Whether or not the LargeHeaderComponent should fade in and out. Defaults to `false`.

**Note**: This is only available in version >= 0.10.0.
20 changes: 20 additions & 0 deletions docs/docs/03-api-reference/03-section-list-with-headers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,28 @@ want to access the layout of the large header to calculate the height of the lar
This property controls whether or not the header component is absolutely positioned. This is useful
if you want to render a header component that allows for transparency.

**Note**: This is only available in version >= 0.9.0.

### initialAbsoluteHeaderHeight

This property is used when `absoluteHeader` is true. This is the initial height of the
absolute header. Since the header's height is computed on its layout event, this is used
to set the initial height of the header so that it doesn't jump when it is initially rendered.

**Note**: This is only available in version >= 0.9.0.

### headerFadeInThreshold

A number between 0 and 1 representing at what point the header should fade in,
based on the percentage of the LargeHeader's height. For example, if this is set to 0.5,
the header will fade in when the scroll position is at 50% of the LargeHeader's height.

Defaults to `1`.

**Note**: This is only available in version >= 0.10.0.

### disableLargeHeaderFadeAnim

Whether or not the LargeHeaderComponent should fade in and out. Defaults to `false`.

**Note**: This is only available in version >= 0.10.0.
20 changes: 20 additions & 0 deletions docs/docs/03-api-reference/04-flash-list-with-headers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,28 @@ want to access the layout of the large header to calculate the height of the lar
This property controls whether or not the header component is absolutely positioned. This is useful
if you want to render a header component that allows for transparency.

**Note**: This is only available in version >= 0.9.0.

### initialAbsoluteHeaderHeight

This property is used when `absoluteHeader` is true. This is the initial height of the
absolute header. Since the header's height is computed on its layout event, this is used
to set the initial height of the header so that it doesn't jump when it is initially rendered.

**Note**: This is only available in version >= 0.9.0.

### headerFadeInThreshold

A number between 0 and 1 representing at what point the header should fade in,
based on the percentage of the LargeHeader's height. For example, if this is set to 0.5,
the header will fade in when the scroll position is at 50% of the LargeHeader's height.

Defaults to `1`.

**Note**: This is only available in version >= 0.10.0.

### disableLargeHeaderFadeAnim

Whether or not the LargeHeaderComponent should fade in and out. Defaults to `false`.

**Note**: This is only available in version >= 0.10.0.
4 changes: 3 additions & 1 deletion docs/docs/03-api-reference/05-header.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ An animated value between 0 and 1 that indicates whether the header's children s

An optional style object to apply to the header's root container.

NOTE: Do not apply an `absolute` position to this container. Instead, use the `absoluteHeader` prop
**Note**: Do not apply an `absolute` position to this container. Instead, use the `absoluteHeader` prop
on any of the scroll containers to absolutely position the header.

### headerLeft
Expand Down Expand Up @@ -85,6 +85,8 @@ An optional width to use for the header's bottom border. Defaults to [StyleSheet

An optional component that can act as the surface of the header. Please ensure that the styling applied to the component includes `StyleSheet.absoluteFill` or `StyleSheet.absoluteFillObject` to ensure that the surface component fills the header.

**Note**: If you want to use a [BlurView](https://github.com/Kureev/react-native-blur#blurview) as the surface and want the content below to be seen under the surface, make sure you set [absoluteHeader](/docs/components/scroll-view-with-headers#absoluteHeader) to `true` on the scroll container.

#### Example

The following example will make the header have a **cyan** background when the user scrolls the scroll container up:
Expand Down
9 changes: 7 additions & 2 deletions example/src/navigation/AppNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
SimpleUsageScreen,
SurfaceComponentUsageScreen,
TwitterProfileScreen,
AbsoluteHeaderBlurSurface,
AbsoluteHeaderBlurSurfaceUsageScreen,
ArbitraryYTransitionHeaderUsageScreen,
} from '../screens';

const Stack = createNativeStackNavigator<RootStackParamList>();
Expand All @@ -34,7 +35,11 @@ export default () => (
<Stack.Screen name="TwitterProfileScreen" component={TwitterProfileScreen} />
<Stack.Screen
name="AbsoluteHeaderBlurSurfaceUsageScreen"
component={AbsoluteHeaderBlurSurface}
component={AbsoluteHeaderBlurSurfaceUsageScreen}
/>
<Stack.Screen
name="ArbitraryYTransitionHeaderUsageScreen"
component={ArbitraryYTransitionHeaderUsageScreen}
/>
</Stack.Navigator>
);
6 changes: 6 additions & 0 deletions example/src/navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type RootStackParamList = {
TwitterProfileScreen: undefined;
HeaderSurfaceComponentUsageScreen: undefined;
AbsoluteHeaderBlurSurfaceUsageScreen: undefined;
ArbitraryYTransitionHeaderUsageScreen: undefined;
};

// Overrides the typing for useNavigation in @react-navigation/native to support the internal
Expand Down Expand Up @@ -59,3 +60,8 @@ export type AbsoluteHeaderBlurSurfaceUsageScreenNavigationProps = NativeStackScr
RootStackParamList,
'AbsoluteHeaderBlurSurfaceUsageScreen'
>;

export type ArbitraryYTransitionHeaderUsageScreenNavigationProps = NativeStackScreenProps<
RootStackParamList,
'ArbitraryYTransitionHeaderUsageScreen'
>;
6 changes: 6 additions & 0 deletions example/src/screens/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ const SCREEN_LIST_CONFIG: ScreenConfigItem[] = [
route: 'AbsoluteHeaderBlurSurfaceUsageScreen',
description: 'An example of an absolutely-positioned header with a BlurView surface.',
},
{
name: 'Arbitrary Y Transition Header',
route: 'ArbitraryYTransitionHeaderUsageScreen',
description:
'An example of a header that transitions based on the scroll position of the ScrollView, instead of passing the height of the large header before animating.',
},
];

const HeaderComponent: React.FC<ScrollHeaderProps> = ({ showNavBar }) => {
Expand Down
3 changes: 2 additions & 1 deletion example/src/screens/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export { default as FlashListUsageScreen } from './usage/FlashList';
export { default as SectionListUsageScreen } from './usage/SectionList';
export { default as SurfaceComponentUsageScreen } from './usage/SurfaceComponent';
export { default as TwitterProfileScreen } from './usage/TwitterProfile';
export { default as AbsoluteHeaderBlurSurface } from './usage/AbsoluteHeaderBlurSurface';
export { default as AbsoluteHeaderBlurSurfaceUsageScreen } from './usage/AbsoluteHeaderBlurSurface';
export { default as ArbitraryYTransitionHeaderUsageScreen } from './usage/ArbitraryYTransitionHeader';
102 changes: 102 additions & 0 deletions example/src/screens/usage/ArbitraryYTransitionHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React, { useMemo, useState } from 'react';
import { RefreshControl, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useNavigation } from '@react-navigation/native';
import {
Header,
LargeHeader,
ScalingView,
ScrollViewWithHeaders,
} from '@codeherence/react-native-header';
import type { ScrollHeaderProps, ScrollLargeHeaderProps } from '@codeherence/react-native-header';
import { range } from '../../utils';
import { Avatar, BackButton } from '../../components';
import { RANDOM_IMAGE_NUM } from '../../constants';
import type { ArbitraryYTransitionHeaderUsageScreenNavigationProps } from '../../navigation';

const HeaderComponent: React.FC<ScrollHeaderProps> = ({ showNavBar }) => {
const navigation = useNavigation();
const onPressProfile = () => navigation.navigate('Profile');

return (
<Header
showNavBar={showNavBar}
headerCenter={
<Text style={styles.navBarTitle} numberOfLines={1}>
Header
</Text>
}
headerRight={
<TouchableOpacity onPress={onPressProfile}>
<Avatar size="sm" source={{ uri: `https://i.pravatar.cc/128?img=${RANDOM_IMAGE_NUM}` }} />
</TouchableOpacity>
}
headerRightFadesIn
headerLeft={<BackButton />}
/>
);
};

const LargeHeaderComponent: React.FC<ScrollLargeHeaderProps> = ({ scrollY }) => {
return (
<LargeHeader headerStyle={styles.largeHeaderStyle}>
<ScalingView scrollY={scrollY} style={styles.leftHeader}>
<Text style={styles.title}>Large Header</Text>
<Text style={styles.subtext}>
We test a larger LargeHeader in order to test the arbitrary y-value.
</Text>
</ScalingView>

<View style={styles.redBox} />
</LargeHeader>
);
};

const ArbitraryYTransitionHeader: React.FC<
ArbitraryYTransitionHeaderUsageScreenNavigationProps
> = () => {
const { bottom } = useSafeAreaInsets();
const [refreshing, setRefreshing] = useState(false);

const data = useMemo(() => range({ end: 100 }), []);

const onRefresh = async () => {
if (refreshing) return;

setRefreshing(true);
// Mimic some asynchronous task
await new Promise((res) => setTimeout(res, 2500));
setRefreshing(false);
};

return (
<ScrollViewWithHeaders
HeaderComponent={HeaderComponent}
headerFadeInThreshold={0.5}
disableLargeHeaderFadeAnim
LargeHeaderComponent={LargeHeaderComponent}
contentContainerStyle={{ paddingBottom: bottom }}
refreshControl={
<RefreshControl refreshing={refreshing} colors={['#8E8E93']} onRefresh={onRefresh} />
}
>
<View style={styles.children}>
{data.map((i) => (
<Text key={`text-${i}`}>Scroll to see header animation</Text>
))}
</View>
</ScrollViewWithHeaders>
);
};

export default ArbitraryYTransitionHeader;

const styles = StyleSheet.create({
children: { marginTop: 16, paddingHorizontal: 16 },
navBarTitle: { fontSize: 16, fontWeight: 'bold' },
largeHeaderStyle: { flexDirection: 'column' },
title: { fontSize: 32, fontWeight: 'bold' },
leftHeader: { gap: 4 },
subtext: { color: '#8E8E93' },
redBox: { width: 100, height: 100, backgroundColor: 'red' },
});
2 changes: 2 additions & 0 deletions example/src/screens/usage/TwitterProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,8 @@ const TwitterProfile: React.FC<TwitterProfileScreenNavigationProps> = () => {
// other relevant components to respect the safe area.
ignoreLeftSafeArea
ignoreRightSafeArea
headerFadeInThreshold={0.2}
disableLargeHeaderFadeAnim
style={styles.container}
contentContainerStyle={[styles.contentContainer, { paddingBottom: bottom }]}
containerStyle={styles.rootContainer}
Expand Down
15 changes: 12 additions & 3 deletions src/components/containers/FlashList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ const FlashListWithHeadersInputComp = <ItemT extends any = any>(
initialAbsoluteHeaderHeight = 0,
contentContainerStyle = {},
automaticallyAdjustsScrollIndicatorInsets,
headerFadeInThreshold = 1,
disableLargeHeaderFadeAnim = false,
...rest
}: AnimatedFlashListType<ItemT>,
ref: React.Ref<FlashList<ItemT>>
Expand All @@ -63,6 +65,7 @@ const FlashListWithHeadersInputComp = <ItemT extends any = any>(
largeHeaderExists: !!LargeHeaderComponent,
absoluteHeader,
initialAbsoluteHeaderHeight,
headerFadeInThreshold,
});

return (
Expand Down Expand Up @@ -119,9 +122,15 @@ const FlashListWithHeadersInputComp = <ItemT extends any = any>(
if (onLargeHeaderLayout) onLargeHeaderLayout(e.nativeEvent.layout);
}}
>
<FadingView opacity={largeHeaderOpacity} style={largeHeaderContainerStyle}>
{LargeHeaderComponent({ scrollY, showNavBar })}
</FadingView>
{!disableLargeHeaderFadeAnim ? (
<FadingView opacity={largeHeaderOpacity} style={largeHeaderContainerStyle}>
{LargeHeaderComponent({ scrollY, showNavBar })}
</FadingView>
) : (
<View style={largeHeaderContainerStyle}>
{LargeHeaderComponent({ scrollY, showNavBar })}
</View>
)}
</View>
) : undefined
}
Expand Down
15 changes: 12 additions & 3 deletions src/components/containers/FlatList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ const FlatListWithHeadersInputComp = <ItemT extends unknown>(
initialAbsoluteHeaderHeight = 0,
contentContainerStyle,
automaticallyAdjustsScrollIndicatorInsets,
headerFadeInThreshold = 1,
disableLargeHeaderFadeAnim = false,
...rest
}: AnimatedFlatListProps<ItemT> & SharedScrollContainerProps,
ref: React.Ref<Animated.FlatList<ItemT> | null>
Expand All @@ -59,6 +61,7 @@ const FlatListWithHeadersInputComp = <ItemT extends unknown>(
largeHeaderExists: !!LargeHeaderComponent,
absoluteHeader,
initialAbsoluteHeaderHeight,
headerFadeInThreshold,
});

return (
Expand Down Expand Up @@ -114,9 +117,15 @@ const FlatListWithHeadersInputComp = <ItemT extends unknown>(
if (onLargeHeaderLayout) onLargeHeaderLayout(e.nativeEvent.layout);
}}
>
<FadingView opacity={largeHeaderOpacity} style={largeHeaderContainerStyle}>
{LargeHeaderComponent({ scrollY, showNavBar })}
</FadingView>
{!disableLargeHeaderFadeAnim ? (
<FadingView opacity={largeHeaderOpacity} style={largeHeaderContainerStyle}>
{LargeHeaderComponent({ scrollY, showNavBar })}
</FadingView>
) : (
<View style={largeHeaderContainerStyle}>
{LargeHeaderComponent({ scrollY, showNavBar })}
</View>
)}
</View>
) : undefined
}
Expand Down
Loading