import React, { useCallback, useEffect, useState, useMemo } from 'react'
import { View } from 'react-native'
import Animated, {
runOnJS,
useAnimatedStyle,
useSharedValue,
withDelay,
withRepeat,
withSequence,
withTiming,
} from 'react-native-reanimated'
import stylesCommon from '../styles'
import styles from './styles'
import { TypingIndicatorProps } from './types'
export * from './types'
const DotsAnimation = () => {
const dot1 = useSharedValue(0)
const dot2 = useSharedValue(0)
const dot3 = useSharedValue(0)
const topY = useMemo(() => -5, [])
const bottomY = useMemo(() => 5, [])
const duration = useMemo(() => 500, [])
const dot1Style = useAnimatedStyle(() => ({
transform: [{
translateY: dot1.value,
}],
}), [dot1])
const dot2Style = useAnimatedStyle(() => ({
transform: [{
translateY: dot2.value,
}],
}), [dot2])
const dot3Style = useAnimatedStyle(() => ({
transform: [{
translateY: dot3.value,
}],
}), [dot3])
useEffect(() => {
dot1.value = withRepeat(
withSequence(
withTiming(topY, { duration }),
withTiming(bottomY, { duration })
),
0,
true
)
}, [dot1, topY, bottomY, duration])
useEffect(() => {
dot2.value = withDelay(100,
withRepeat(
withSequence(
withTiming(topY, { duration }),
withTiming(bottomY, { duration })
),
0,
true
)
)
}, [dot2, topY, bottomY, duration])
useEffect(() => {
dot3.value = withDelay(200,
withRepeat(
withSequence(
withTiming(topY, { duration }),
withTiming(bottomY, { duration })
),
0,
true
)
)
}, [dot3, topY, bottomY, duration])
return (
)
}
export const TypingIndicator = ({ isTyping, style }: TypingIndicatorProps) => {
const yCoords = useSharedValue(200)
const heightScale = useSharedValue(0)
const marginScale = useSharedValue(0)
const [isVisible, setIsVisible] = useState(isTyping)
const containerStyle = useAnimatedStyle(() => ({
transform: [
{
translateY: yCoords.value,
},
],
height: heightScale.value,
marginBottom: marginScale.value,
}), [yCoords, heightScale, marginScale])
const slideIn = useCallback(() => {
const duration = 250
yCoords.value = withTiming(0, { duration })
heightScale.value = withTiming(35, { duration })
marginScale.value = withTiming(8, { duration })
}, [yCoords, heightScale, marginScale])
const slideOut = useCallback(() => {
const duration = 250
yCoords.value = withTiming(200, { duration }, isFinished => {
if (isFinished)
runOnJS(setIsVisible)(false)
})
heightScale.value = withTiming(0, { duration })
marginScale.value = withTiming(0, { duration })
}, [yCoords, heightScale, marginScale])
useEffect(() => {
if (isVisible)
if (isTyping)
slideIn()
else
slideOut()
}, [isVisible, isTyping, slideIn, slideOut])
useEffect(() => {
if (isTyping)
setIsVisible(true)
}, [isTyping])
if (!isVisible)
return null
return (
)
}