UNPKG

react-native-gifted-chat

Version:
92 lines 4.98 kB
import React, { useCallback, useEffect, useMemo, useState } from 'react'; import Animated, { interpolate, useAnimatedStyle, useDerivedValue, useSharedValue, useAnimatedReaction, withTiming, runOnJS } from 'react-native-reanimated'; import { Day } from '../../../Day'; import stylesCommon from '../../../styles'; import { isSameDay } from '../../../utils'; import { useAbsoluteScrolledPositionToBottomOfDay, useRelativeScrolledPositionToBottomOfDay } from '../Item'; import styles from './styles'; export * from './types'; export const DayAnimated = ({ scrolledY, daysPositions, listHeight, renderDay, messages, isLoading, ...rest }) => { const opacity = useSharedValue(0); const fadeOutOpacityTimeoutId = useSharedValue(undefined); const containerHeight = useSharedValue(0); const isScrolledOnMount = useSharedValue(false); const isLoadingAnim = useSharedValue(isLoading); const daysPositionsArray = useDerivedValue(() => Object.values(daysPositions.value).sort((a, b) => { 'worklet'; return a.y - b.y; })); const [createdAt, setCreatedAt] = useState(); const dayTopOffset = useMemo(() => 10, []); const dayBottomMargin = useMemo(() => 10, []); const absoluteScrolledPositionToBottomOfDay = useAbsoluteScrolledPositionToBottomOfDay(listHeight, scrolledY, containerHeight, dayBottomMargin, dayTopOffset); const relativeScrolledPositionToBottomOfDay = useRelativeScrolledPositionToBottomOfDay(listHeight, scrolledY, daysPositions, containerHeight, dayBottomMargin, dayTopOffset); const messagesDates = useMemo(() => { const messagesDates = []; for (let i = 1; i < messages.length; i++) { const previousMessage = messages[i - 1]; const message = messages[i]; if (!isSameDay(previousMessage, message) || !messagesDates.includes(new Date(message.createdAt).getTime())) messagesDates.push(new Date(message.createdAt).getTime()); } return messagesDates; }, [messages]); const createdAtDate = useDerivedValue(() => { for (let i = 0; i < daysPositionsArray.value.length; i++) { const day = daysPositionsArray.value[i]; const dayPosition = day.y + day.height - containerHeight.value - dayBottomMargin; if (absoluteScrolledPositionToBottomOfDay.value < dayPosition) return day.createdAt; } return messagesDates[messagesDates.length - 1]; }, [daysPositionsArray, absoluteScrolledPositionToBottomOfDay, messagesDates, containerHeight, dayBottomMargin]); const style = useAnimatedStyle(() => ({ top: interpolate(relativeScrolledPositionToBottomOfDay.value, [-dayTopOffset, -0.0001, 0, isLoadingAnim.value ? 0 : containerHeight.value + dayTopOffset], [dayTopOffset, dayTopOffset, -containerHeight.value, isLoadingAnim.value ? -containerHeight.value : dayTopOffset], 'clamp'), }), [relativeScrolledPositionToBottomOfDay, containerHeight, dayTopOffset, isLoadingAnim]); const contentStyle = useAnimatedStyle(() => ({ opacity: opacity.value, }), [opacity]); const fadeOut = useCallback(() => { 'worklet'; opacity.value = withTiming(0, { duration: 500 }); }, [opacity]); const scheduleFadeOut = useCallback(() => { clearTimeout(fadeOutOpacityTimeoutId.value); fadeOutOpacityTimeoutId.value = setTimeout(fadeOut, 500); }, [fadeOut, fadeOutOpacityTimeoutId]); const handleLayout = useCallback(({ nativeEvent }) => { containerHeight.value = nativeEvent.layout.height; }, [containerHeight]); useAnimatedReaction(() => [scrolledY.value, daysPositionsArray], (value, prevValue) => { if (!isScrolledOnMount.value) { isScrolledOnMount.value = true; return; } if (value[0] === prevValue?.[0]) return; opacity.value = withTiming(1, { duration: 500 }); runOnJS(scheduleFadeOut)(); }, [scrolledY, scheduleFadeOut, daysPositionsArray]); useAnimatedReaction(() => createdAtDate.value, (value, prevValue) => { if (value && value !== prevValue) runOnJS(setCreatedAt)(value); }, [createdAtDate]); useEffect(() => { isLoadingAnim.value = isLoading; }, [isLoadingAnim, isLoading]); const dayContent = useMemo(() => { if (!createdAt) return null; return renderDay ? renderDay({ ...rest, createdAt }) : <Day {...rest} containerStyle={[styles.dayAnimatedDayContainerStyle, rest.containerStyle]} createdAt={createdAt}/>; }, [createdAt, renderDay, rest]); if (!createdAt) return null; return (<Animated.View style={[stylesCommon.centerItems, styles.dayAnimated, style]} onLayout={handleLayout} pointerEvents='none'> <Animated.View style={contentStyle} pointerEvents='none'> {dayContent} </Animated.View> </Animated.View>); }; //# sourceMappingURL=index.js.map