react-native-gifted-chat
Version:
The most complete chat UI for React Native
92 lines • 4.98 kB
JavaScript
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