import React, { forwardRef } from 'react'; import type { VariantProps } from '@gluestack-ui/nativewind-utils'; import { Animated, Easing, Platform, View } from 'react-native'; import { skeletonStyle, skeletonTextStyle } from './styles'; type ISkeletonProps = React.ComponentProps & VariantProps & { isLoaded?: boolean; startColor?: string; }; type ISkeletonTextProps = React.ComponentProps & VariantProps & { _lines?: number; isLoaded?: boolean; startColor?: string; }; const Skeleton = forwardRef< React.ComponentRef, ISkeletonProps >(function Skeleton( { className, variant, children, startColor = 'bg-background-200', isLoaded = false, speed = 2, ...props }, ref ) { const pulseAnim = new Animated.Value(1); const customTimingFunction = Easing.bezier(0.4, 0, 0.6, 1); const fadeDuration = 0.6; const animationDuration = (fadeDuration * 10000) / speed; // Convert seconds to milliseconds const pulse = Animated.sequence([ Animated.timing(pulseAnim, { toValue: 1, // Start with opacity 1 duration: animationDuration / 2, // Third of the animation duration easing: customTimingFunction, useNativeDriver: Platform.OS !== 'web', }), Animated.timing(pulseAnim, { toValue: 0.75, duration: animationDuration / 2, // Third of the animation duration easing: customTimingFunction, useNativeDriver: Platform.OS !== 'web', }), Animated.timing(pulseAnim, { toValue: 1, duration: animationDuration / 2, // Third of the animation duration easing: customTimingFunction, useNativeDriver: Platform.OS !== 'web', }), ]); if (!isLoaded) { Animated.loop(pulse).start(); return ( ); } else { Animated.loop(pulse).stop(); return children; } }); const SkeletonText = forwardRef< React.ComponentRef, ISkeletonTextProps >(function SkeletonText( { className, _lines, isLoaded = false, startColor = 'bg-background-200', gap = 2, children, ...props }, ref ) { if (!isLoaded) { if (_lines) { return ( {Array.from({ length: _lines }).map((_, index) => ( ))} ); } else { return ( ); } } else { return children; } }); Skeleton.displayName = 'Skeleton'; SkeletonText.displayName = 'SkeletonText'; export { Skeleton, SkeletonText };