import { LinearGradient } from "expo-linear-gradient"; import React, { useEffect } from "react"; import { DimensionValue, I18nManager, LayoutChangeEvent, StyleProp, StyleSheet, View, ViewStyle, } from "react-native"; import Animated, { Easing, interpolate, useAnimatedStyle, useSharedValue, withRepeat, withTiming, } from "react-native-reanimated"; import { useTheme } from "../../theme"; interface ShimmerProps { children?: React.ReactNode; width?: DimensionValue; height: DimensionValue; style?: StyleProp; duration?: number; shimmerWidth?: number; shimmerColor?: string; } const Shimmer: React.FC = ({ children, width = "100%", height, style, shimmerColor, duration = 1500, shimmerWidth = 150, }) => { const { theme } = useTheme(); const layoutWidth = useSharedValue(0); const progress = useSharedValue(0); useEffect(() => { progress.value = withRepeat( withTiming(1, { duration: duration, easing: Easing.linear, }), -1, false ); }, [duration, progress]); // 3. Update width via shared value (no re-render) const handleLayout = (event: LayoutChangeEvent) => { layoutWidth.value = event.nativeEvent.layout.width; }; // 4. Calculate translation on the UI thread const rStyle = useAnimatedStyle(() => { if (layoutWidth.value === 0) { return { opacity: 0 }; } const start = -layoutWidth.value; const end = layoutWidth.value; const outputRange = I18nManager.isRTL ? [end, start] : [start, end]; const translateX = interpolate(progress.value, [0, 1], outputRange); return { opacity: 1, transform: [{ translateX }], }; }); const gradientColors = [ "rgba(255, 255, 255, 0)", shimmerColor || theme.skeletonShimmer || "rgba(255, 255, 255, 0.3)", "rgba(255, 255, 255, 0)", ]; return ( {children} ); }; const styles = StyleSheet.create({ container: { overflow: "hidden", }, }); export default Shimmer;