Skip to content

Commit 160ff01

Browse files
aharwood9e-younan
authored andcommitted
feat: add LargeHeaderSubtitleComponent
1 parent c2ee083 commit 160ff01

File tree

9 files changed

+149
-70
lines changed

9 files changed

+149
-70
lines changed

example/src/screens/usage/Simple.tsx

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ import { RefreshControl, StyleSheet, Text, TouchableOpacity, View } from 'react-
33
import { useSafeAreaInsets } from 'react-native-safe-area-context';
44
import { useNavigation } from '@react-navigation/native';
55
import { Header, LargeHeader, ScrollViewWithHeaders } from '@codeherence/react-native-header';
6-
import type { ScrollHeaderProps, ScrollLargeHeaderProps } from '@codeherence/react-native-header';
6+
import type {
7+
ScrollHeaderProps,
8+
ScrollLargeHeaderProps,
9+
ScrollLargeHeaderSubtitleProps,
10+
} from '@codeherence/react-native-header';
711
import { range } from '../../utils';
812
import { Avatar, BackButton } from '../../components';
913
import { RANDOM_IMAGE_NUM } from '../../constants';
@@ -24,7 +28,12 @@ const HeaderComponent: React.FC<ScrollHeaderProps> = ({ showNavBar }) => {
2428
}
2529
headerRight={
2630
<TouchableOpacity onPress={onPressProfile}>
27-
<Avatar size="sm" source={{ uri: `https://i.pravatar.cc/128?img=${RANDOM_IMAGE_NUM}` }} />
31+
<Avatar
32+
size="sm"
33+
source={{
34+
uri: `https://i.pravatar.cc/128?img=${RANDOM_IMAGE_NUM}`,
35+
}}
36+
/>
2837
</TouchableOpacity>
2938
}
3039
headerRightFadesIn
@@ -46,6 +55,10 @@ const LargeHeaderComponent: React.FC<ScrollLargeHeaderProps> = () => {
4655
);
4756
};
4857

58+
const LargeHeaderSubtitleComponent: React.FC<ScrollLargeHeaderSubtitleProps> = () => (
59+
<Text style={styles.largeHeaderSubtitleStyle}>Scroll to see header animation</Text>
60+
);
61+
4962
const Simple: React.FC<SimpleUsageScreenNavigationProps> = () => {
5063
const { bottom } = useSafeAreaInsets();
5164
const [refreshing, setRefreshing] = useState(false);
@@ -65,14 +78,15 @@ const Simple: React.FC<SimpleUsageScreenNavigationProps> = () => {
6578
<ScrollViewWithHeaders
6679
HeaderComponent={HeaderComponent}
6780
LargeHeaderComponent={LargeHeaderComponent}
81+
LargeHeaderSubtitleComponent={LargeHeaderSubtitleComponent}
6882
contentContainerStyle={{ paddingBottom: bottom }}
6983
refreshControl={
7084
<RefreshControl refreshing={refreshing} colors={['#8E8E93']} onRefresh={onRefresh} />
7185
}
7286
>
7387
<View style={styles.children}>
7488
{data.map((i) => (
75-
<Text key={`text-${i}`}>Scroll to see header animation</Text>
89+
<View key={`text-${i}`} style={styles.box} />
7690
))}
7791
</View>
7892
</ScrollViewWithHeaders>
@@ -83,6 +97,17 @@ export default Simple;
8397

8498
const styles = StyleSheet.create({
8599
children: { marginTop: 16, paddingHorizontal: 16 },
100+
box: {
101+
backgroundColor: 'lightgray',
102+
height: 50,
103+
marginVertical: 8,
104+
borderRadius: 8,
105+
},
86106
navBarTitle: { fontSize: 16, fontWeight: 'bold' },
87107
largeHeaderStyle: { flexDirection: 'row-reverse' },
108+
largeHeaderSubtitleStyle: {
109+
fontSize: 16,
110+
fontWeight: 'bold',
111+
paddingHorizontal: 16,
112+
},
88113
});

src/components/containers/FlashList.tsx

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const FlashListWithHeadersInputComp = <ItemT extends any = any>(
2424
{
2525
largeHeaderShown,
2626
containerStyle,
27+
LargeHeaderSubtitleComponent,
2728
LargeHeaderComponent,
2829
largeHeaderContainerStyle,
2930
HeaderComponent,
@@ -131,23 +132,27 @@ const FlashListWithHeadersInputComp = <ItemT extends any = any>(
131132
}}
132133
ListHeaderComponent={
133134
LargeHeaderComponent ? (
134-
<View
135-
onLayout={(e) => {
136-
largeHeaderHeight.value = e.nativeEvent.layout.height;
135+
<>
136+
<View
137+
onLayout={(e) => {
138+
largeHeaderHeight.value = e.nativeEvent.layout.height;
137139

138-
if (onLargeHeaderLayout) onLargeHeaderLayout(e.nativeEvent.layout);
139-
}}
140-
>
141-
{!disableLargeHeaderFadeAnim ? (
142-
<FadingView opacity={largeHeaderOpacity} style={largeHeaderContainerStyle}>
143-
{LargeHeaderComponent({ scrollY, showNavBar })}
144-
</FadingView>
145-
) : (
146-
<View style={largeHeaderContainerStyle}>
147-
{LargeHeaderComponent({ scrollY, showNavBar })}
148-
</View>
149-
)}
150-
</View>
140+
if (onLargeHeaderLayout) onLargeHeaderLayout(e.nativeEvent.layout);
141+
}}
142+
>
143+
{!disableLargeHeaderFadeAnim ? (
144+
<FadingView opacity={largeHeaderOpacity} style={largeHeaderContainerStyle}>
145+
{LargeHeaderComponent({ scrollY, showNavBar })}
146+
</FadingView>
147+
) : (
148+
<View style={largeHeaderContainerStyle}>
149+
{LargeHeaderComponent({ scrollY, showNavBar })}
150+
</View>
151+
)}
152+
</View>
153+
{LargeHeaderSubtitleComponent &&
154+
LargeHeaderSubtitleComponent({ showNavBar, scrollY })}
155+
</>
151156
) : undefined
152157
}
153158
inverted={inverted}
@@ -165,7 +170,9 @@ const FlashListWithHeadersInputComp = <ItemT extends any = any>(
165170

166171
// The typecast is needed to make the component generic.
167172
const FlashListWithHeaders = React.forwardRef(FlashListWithHeadersInputComp) as <ItemT = any>(
168-
props: FlashListWithHeadersProps<ItemT> & { ref?: React.RefObject<FlashList<ItemT>> }
173+
props: FlashListWithHeadersProps<ItemT> & {
174+
ref?: React.RefObject<FlashList<ItemT>>;
175+
}
169176
) => React.ReactElement;
170177

171178
export default FlashListWithHeaders;

src/components/containers/FlatList.tsx

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const FlatListWithHeadersInputComp = <ItemT extends unknown>(
2323
{
2424
largeHeaderShown,
2525
containerStyle,
26+
LargeHeaderSubtitleComponent,
2627
LargeHeaderComponent,
2728
largeHeaderContainerStyle,
2829
HeaderComponent,
@@ -130,23 +131,27 @@ const FlatListWithHeadersInputComp = <ItemT extends unknown>(
130131
}}
131132
ListHeaderComponent={
132133
LargeHeaderComponent ? (
133-
<View
134-
onLayout={(e) => {
135-
largeHeaderHeight.value = e.nativeEvent.layout.height;
134+
<>
135+
<View
136+
onLayout={(e) => {
137+
largeHeaderHeight.value = e.nativeEvent.layout.height;
136138

137-
if (onLargeHeaderLayout) onLargeHeaderLayout(e.nativeEvent.layout);
138-
}}
139-
>
140-
{!disableLargeHeaderFadeAnim ? (
141-
<FadingView opacity={largeHeaderOpacity} style={largeHeaderContainerStyle}>
142-
{LargeHeaderComponent({ scrollY, showNavBar })}
143-
</FadingView>
144-
) : (
145-
<View style={largeHeaderContainerStyle}>
146-
{LargeHeaderComponent({ scrollY, showNavBar })}
147-
</View>
148-
)}
149-
</View>
139+
if (onLargeHeaderLayout) onLargeHeaderLayout(e.nativeEvent.layout);
140+
}}
141+
>
142+
{!disableLargeHeaderFadeAnim ? (
143+
<FadingView opacity={largeHeaderOpacity} style={largeHeaderContainerStyle}>
144+
{LargeHeaderComponent({ scrollY, showNavBar })}
145+
</FadingView>
146+
) : (
147+
<View style={largeHeaderContainerStyle}>
148+
{LargeHeaderComponent({ scrollY, showNavBar })}
149+
</View>
150+
)}
151+
</View>
152+
{LargeHeaderSubtitleComponent &&
153+
LargeHeaderSubtitleComponent({ showNavBar, scrollY })}
154+
</>
150155
) : undefined
151156
}
152157
inverted={inverted}
@@ -164,7 +169,9 @@ const FlatListWithHeadersInputComp = <ItemT extends unknown>(
164169

165170
// The typecast is needed to make the component generic.
166171
const FlatListWithHeaders = React.forwardRef(FlatListWithHeadersInputComp) as <ItemT = any>(
167-
props: FlatListWithHeadersProps<ItemT> & { ref?: React.Ref<Animated.FlatList<ItemT>> }
172+
props: FlatListWithHeadersProps<ItemT> & {
173+
ref?: React.Ref<Animated.FlatList<ItemT>>;
174+
}
168175
) => React.ReactElement;
169176

170177
export default FlatListWithHeaders;

src/components/containers/ScrollView.tsx

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const ScrollViewWithHeadersInputComp = (
2222
{
2323
largeHeaderShown,
2424
containerStyle,
25+
LargeHeaderSubtitleComponent,
2526
LargeHeaderComponent,
2627
largeHeaderContainerStyle,
2728
HeaderComponent,
@@ -130,23 +131,26 @@ const ScrollViewWithHeadersInputComp = (
130131
{...rest}
131132
>
132133
{LargeHeaderComponent ? (
133-
<View
134-
onLayout={(e) => {
135-
largeHeaderHeight.value = e.nativeEvent.layout.height;
134+
<>
135+
<View
136+
onLayout={(e) => {
137+
largeHeaderHeight.value = e.nativeEvent.layout.height;
136138

137-
if (onLargeHeaderLayout) onLargeHeaderLayout(e.nativeEvent.layout);
138-
}}
139-
>
140-
{!disableLargeHeaderFadeAnim ? (
141-
<FadingView opacity={largeHeaderOpacity} style={largeHeaderContainerStyle}>
142-
{LargeHeaderComponent({ scrollY, showNavBar })}
143-
</FadingView>
144-
) : (
145-
<View style={largeHeaderContainerStyle}>
146-
{LargeHeaderComponent({ scrollY, showNavBar })}
147-
</View>
148-
)}
149-
</View>
139+
if (onLargeHeaderLayout) onLargeHeaderLayout(e.nativeEvent.layout);
140+
}}
141+
>
142+
{!disableLargeHeaderFadeAnim ? (
143+
<FadingView opacity={largeHeaderOpacity} style={largeHeaderContainerStyle}>
144+
{LargeHeaderComponent({ scrollY, showNavBar })}
145+
</FadingView>
146+
) : (
147+
<View style={largeHeaderContainerStyle}>
148+
{LargeHeaderComponent({ scrollY, showNavBar })}
149+
</View>
150+
)}
151+
</View>
152+
{LargeHeaderSubtitleComponent && LargeHeaderSubtitleComponent({ showNavBar, scrollY })}
153+
</>
150154
) : null}
151155
{children}
152156
</AnimatedScrollView>

src/components/containers/SectionList.tsx

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const SectionListWithHeadersInputComp = <ItemT extends any = any, SectionT = Def
2727
{
2828
largeHeaderShown,
2929
containerStyle,
30+
LargeHeaderSubtitleComponent,
3031
LargeHeaderComponent,
3132
largeHeaderContainerStyle,
3233
HeaderComponent,
@@ -134,23 +135,27 @@ const SectionListWithHeadersInputComp = <ItemT extends any = any, SectionT = Def
134135
}}
135136
ListHeaderComponent={
136137
LargeHeaderComponent ? (
137-
<View
138-
onLayout={(e) => {
139-
largeHeaderHeight.value = e.nativeEvent.layout.height;
138+
<>
139+
<View
140+
onLayout={(e) => {
141+
largeHeaderHeight.value = e.nativeEvent.layout.height;
140142

141-
if (onLargeHeaderLayout) onLargeHeaderLayout(e.nativeEvent.layout);
142-
}}
143-
>
144-
{!disableLargeHeaderFadeAnim ? (
145-
<FadingView opacity={largeHeaderOpacity} style={largeHeaderContainerStyle}>
146-
{LargeHeaderComponent({ scrollY, showNavBar })}
147-
</FadingView>
148-
) : (
149-
<View style={largeHeaderContainerStyle}>
150-
{LargeHeaderComponent({ scrollY, showNavBar })}
151-
</View>
152-
)}
153-
</View>
143+
if (onLargeHeaderLayout) onLargeHeaderLayout(e.nativeEvent.layout);
144+
}}
145+
>
146+
{!disableLargeHeaderFadeAnim ? (
147+
<FadingView opacity={largeHeaderOpacity} style={largeHeaderContainerStyle}>
148+
{LargeHeaderComponent({ scrollY, showNavBar })}
149+
</FadingView>
150+
) : (
151+
<View style={largeHeaderContainerStyle}>
152+
{LargeHeaderComponent({ scrollY, showNavBar })}
153+
</View>
154+
)}
155+
</View>
156+
{LargeHeaderSubtitleComponent &&
157+
LargeHeaderSubtitleComponent({ showNavBar, scrollY })}
158+
</>
154159
) : undefined
155160
}
156161
inverted={inverted}
@@ -171,7 +176,9 @@ const SectionListWithHeaders = React.forwardRef(SectionListWithHeadersInputComp)
171176
ItemT = any,
172177
SectionT = DefaultSectionT
173178
>(
174-
props: SectionListWithHeadersProps<ItemT, SectionT> & { ref?: React.Ref<Animated.ScrollView> }
179+
props: SectionListWithHeadersProps<ItemT, SectionT> & {
180+
ref?: React.Ref<Animated.ScrollView>;
181+
}
175182
) => React.ReactElement;
176183

177184
export default SectionListWithHeaders;

src/components/containers/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ export { default as FlashListWithHeaders } from './FlashList';
77
export type {
88
ScrollHeaderProps,
99
ScrollLargeHeaderProps,
10+
ScrollLargeHeaderSubtitleProps,
1011
SharedScrollContainerProps,
1112
} from './types';

src/components/containers/types.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,25 @@ export interface ScrollLargeHeaderProps {
2626
showNavBar: Animated.SharedValue<number>;
2727
}
2828

29+
/**
30+
* The props supplied to the large header subtitle component of this scroll container.
31+
*/
32+
export interface ScrollLargeHeaderSubtitleProps {
33+
/**
34+
* The scroll position of the scroll view.
35+
*
36+
* @type {Animated.SharedValue<number>}
37+
*/
38+
scrollY: Animated.SharedValue<number>;
39+
/**
40+
* Animated value between 0 and 1 that indicates whether the small header's content should be
41+
* visible. This is used to animate the header's content in and out.
42+
*
43+
* @type {Animated.SharedValue<number>}
44+
*/
45+
showNavBar: Animated.SharedValue<number>;
46+
}
47+
2948
export interface ScrollHeaderProps {
3049
/**
3150
* Animated value between 0 and 1 that indicates whether the small header's content should be
@@ -59,6 +78,13 @@ export type SharedScrollContainerProps = {
5978
* @returns {React.ReactNode}
6079
*/
6180
LargeHeaderComponent?: (props: ScrollLargeHeaderProps) => React.ReactNode;
81+
/**
82+
* The subtitle component for the large header component. This is the component that is rendered below the large header component.
83+
*
84+
* @param {ScrollLargeHeaderSubtitleProps} props The props given to the large header subtitle component.
85+
* @returns {React.ReactNode}
86+
*/
87+
LargeHeaderSubtitleComponent?: (props: ScrollLargeHeaderSubtitleProps) => React.ReactNode;
6288
/**
6389
* The small header component. This is the component that is rendered on top of the scroll view.
6490
*

src/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export {
99
export type {
1010
ScrollHeaderProps,
1111
ScrollLargeHeaderProps,
12+
ScrollLargeHeaderSubtitleProps,
1213
SharedScrollContainerProps,
1314
} from './containers';
1415
export { Header, LargeHeader } from './headers';

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export type {
1414
LargeHeaderProps,
1515
ScrollHeaderProps,
1616
ScrollLargeHeaderProps,
17+
ScrollLargeHeaderSubtitleProps,
1718
SharedScrollContainerProps,
1819
SurfaceComponentProps,
1920
} from './components';

0 commit comments

Comments
 (0)