import React, { useCallback } from 'react'; import { FlatList, FlatListProps, ViewStyle, RefreshControl } from 'react-native'; import Animated, { useSharedValue, useAnimatedStyle, withTiming, withDelay, withSpring, FadeIn, SlideInRight, Layout, } from 'react-native-reanimated'; import { useTheme } from '../../theme/ThemeContext'; const AnimatedFlatList = Animated.createAnimatedComponent(FlatList); interface AnimatedListProps extends Omit, 'renderItem'> { renderItem: (info: { item: T; index: number }) => React.ReactElement; /** Delay base entre items en ms */ staggerDelay?: number; /** Tipo de animación de entrada */ animationType?: 'fade' | 'slide' | 'spring'; /** Mostrar animación al refrescar */ animateOnRefresh?: boolean; /** Callback de refresh */ onRefresh?: () => Promise | void; /** Está refrescando */ isRefreshing?: boolean; } /** * Item animado wrapper */ function AnimatedItem({ children, index, staggerDelay, animationType, }: { children: React.ReactNode; index: number; staggerDelay: number; animationType: 'fade' | 'slide' | 'spring'; }) { const delay = Math.min(index * staggerDelay, 500); // Cap máximo de delay const entering = (() => { switch (animationType) { case 'slide': return SlideInRight.delay(delay).duration(300); case 'spring': return FadeIn.delay(delay).springify(); case 'fade': default: return FadeIn.delay(delay).duration(300); } })(); return ( {children} ); } /** * FlatList con animaciones de entrada staggered */ export function AnimatedList({ data, renderItem, staggerDelay = 50, animationType = 'fade', animateOnRefresh = true, onRefresh, isRefreshing = false, ...props }: AnimatedListProps) { const { colors } = useTheme(); const [key, setKey] = React.useState(0); const handleRefresh = useCallback(async () => { if (onRefresh) { await onRefresh(); if (animateOnRefresh) { setKey((prev) => prev + 1); } } }, [onRefresh, animateOnRefresh]); const animatedRenderItem = useCallback( ({ item, index }: { item: T; index: number }) => ( {renderItem({ item, index })} ), [renderItem, staggerDelay, animationType] ); return ( ) : undefined } {...(props as any)} /> ); } /** * Hook para crear estilos animados de item de lista */ export function useListItemEntering(index: number, baseDelay = 50) { const delay = Math.min(index * baseDelay, 500); return FadeIn.delay(delay).duration(300); } /** * Componente para animar un item individual */ export function AnimatedListItem({ children, index, baseDelay = 50, style, }: { children: React.ReactNode; index: number; baseDelay?: number; style?: ViewStyle; }) { const entering = useListItemEntering(index, baseDelay); return ( {children} ); }