UNPKG

react-native-animated-header-flat-list

Version:

A React Native FlatList component with an animated collapsible header, featuring parallax effects, smooth title transitions, sticky component support, and customizable styles. Built with TypeScript and separate background/content layers in header.

197 lines (196 loc) 6.78 kB
"use strict"; import { forwardRef } from 'react'; import { StatusBar, StyleSheet, View } from 'react-native'; import { useLayoutEffect, useCallback, useMemo } from 'react'; import Animated from 'react-native-reanimated'; import { useAnimatedHeaderFlatListAnimatedStyles } from "../hooks/useAnimatedHeaderFlatListAnimatedStyles.js"; import { getFontSizeFromStyle } from "../utils/styleUtils.js"; import { useNavigation } from '@react-navigation/native'; import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; const HEADER_ITEM = 'REACT_NATIVE_ANIMATED_HEADER_FLAT_LIST_HEADER'; function AnimatedHeaderFlatListInner({ title, navigationBarColor, headerTitleStyle, navigationTitleStyle, HeaderBackground, HeaderContent, StickyComponent, parallax = true, navigationTitleTranslateX = 0, navigationTitleTranslateY = 0, ...flatListProps }, ref) { const navigation = useNavigation(); const { scrollHandler, navigationBarHeight, headerLayout, setHeaderLayout, setHeaderTitleLayout, stickyComponentLayout, setStickyComponentLayout, stickyComponentAnimatedStyle, navigationBarAnimatedStyle, navigationTitleAnimatedStyle, headerTitleAnimatedStyle, stickyHeaderAnimatedStyle, headerContentAnimatedStyle, headerBackgroundAnimatedStyle } = useAnimatedHeaderFlatListAnimatedStyles({ headerTitleFontSize: getFontSizeFromStyle(headerTitleStyle), navigationTitleFontSize: getFontSizeFromStyle(navigationTitleStyle), navigationTitleTranslateX, navigationTitleTranslateY }); const navigationTitle = useCallback(() => /*#__PURE__*/_jsx(Animated.Text, { style: [navigationTitleAnimatedStyle, navigationTitleStyle], numberOfLines: 1, children: title }), [navigationTitleAnimatedStyle, navigationTitleStyle, title]); useLayoutEffect(() => { navigation.setOptions({ headerShown: true, headerStyle: styles.navigationBar, headerShadowVisible: false, headerTransparent: true, headerTitle: navigationTitle, headerTitleAlign: 'center' }); }, [navigationTitle, navigation]); const ListHeaderComponent = useMemo(() => { return /*#__PURE__*/_jsx(View, { style: styles.headerWrapper, children: /*#__PURE__*/_jsxs(View, { style: [styles.headerContainer, { top: -navigationBarHeight }], onLayout: event => { setHeaderLayout({ ...event.nativeEvent.layout, height: event.nativeEvent.layout.height + navigationBarHeight }); }, children: [/*#__PURE__*/_jsx(Animated.View, { style: parallax ? headerBackgroundAnimatedStyle : undefined, children: /*#__PURE__*/_jsx(HeaderBackground, {}) }), HeaderContent && /*#__PURE__*/_jsx(Animated.View, { style: [headerContentAnimatedStyle, styles.headerContentContainer], children: /*#__PURE__*/_jsx(HeaderContent, {}) }), navigationBarColor && /*#__PURE__*/_jsx(Animated.View, { style: [navigationBarAnimatedStyle, styles.animatedNavigationBar, { backgroundColor: navigationBarColor }] }), /*#__PURE__*/_jsx(Animated.Text, { onLayout: event => { setHeaderTitleLayout(event.nativeEvent.layout); }, numberOfLines: 1, style: [headerTitleAnimatedStyle, styles.headerTitle, headerTitleStyle], children: title })] }) }); }, [navigationBarHeight, parallax, headerBackgroundAnimatedStyle, HeaderBackground, HeaderContent, headerContentAnimatedStyle, headerTitleAnimatedStyle, headerTitleStyle, title, setHeaderLayout, setHeaderTitleLayout, navigationBarAnimatedStyle, navigationBarColor]); const renderItem = useCallback(({ item }) => { if (item === HEADER_ITEM) { return /*#__PURE__*/_jsxs(View, { style: [styles.stickyHeaderContainer, { height: navigationBarHeight + stickyComponentLayout.height }], children: [/*#__PURE__*/_jsx(Animated.View, { style: [stickyHeaderAnimatedStyle, styles.stickyHeader, { bottom: headerLayout.height - navigationBarHeight * 2 + stickyComponentLayout.height }], children: ListHeaderComponent }), StickyComponent && /*#__PURE__*/_jsx(Animated.View, { style: [styles.stickyComponentContainer, stickyComponentAnimatedStyle], onLayout: event => { setStickyComponentLayout(event.nativeEvent.layout); }, children: /*#__PURE__*/_jsx(StickyComponent, {}) })] }); } return flatListProps.renderItem && typeof flatListProps.renderItem === 'function' ? flatListProps.renderItem({ item }) : null; }, [flatListProps, navigationBarHeight, stickyComponentLayout.height, stickyComponentAnimatedStyle, stickyHeaderAnimatedStyle, headerLayout.height, ListHeaderComponent, StickyComponent, setStickyComponentLayout]); const data = useMemo(() => { const listData = Array.isArray(flatListProps.data) ? flatListProps.data : []; return [HEADER_ITEM, ...listData]; }, [flatListProps.data]); return /*#__PURE__*/_jsxs(_Fragment, { children: [/*#__PURE__*/_jsx(StatusBar, { backgroundColor: "transparent", translucent: true }), /*#__PURE__*/_jsx(Animated.FlatList, { ...flatListProps, ref: ref, stickyHeaderIndices: [1], ListHeaderComponent: /*#__PURE__*/_jsx(Animated.View, { style: [styles.mainHeaderContainer, { height: headerLayout.height - navigationBarHeight * 2, transform: [{ translateY: navigationBarHeight }] }], children: ListHeaderComponent }), onScroll: scrollHandler, data: data, renderItem: renderItem })] }); } const styles = StyleSheet.create({ navigationBar: { backgroundColor: 'transparent' }, headerWrapper: { overflow: 'visible' }, headerContainer: { position: 'absolute', left: 0, right: 0, overflow: 'visible' }, stickyHeaderContainer: { width: '100%' }, stickyHeader: { position: 'absolute', left: 0, right: 0 }, mainHeaderContainer: { overflow: 'visible' }, animatedNavigationBar: { position: 'absolute', bottom: 0, left: 0, right: 0 }, headerTitle: { position: 'absolute' }, stickyComponentContainer: { position: 'absolute', bottom: 0, left: 0, right: 0 }, headerContentContainer: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 } }); export const AnimatedHeaderFlatList = /*#__PURE__*/forwardRef(AnimatedHeaderFlatListInner); //# sourceMappingURL=AnimatedHeaderFlatList.js.map