61 lines
1.1 KiB
TypeScript
61 lines
1.1 KiB
TypeScript
import React, { useEffect, useRef } from "react";
|
|
import { Animated, StyleProp, ViewStyle } from "react-native";
|
|
|
|
type Dimension = number | `${number}%`;
|
|
|
|
export type SkeletonProps = {
|
|
width?: Dimension;
|
|
height?: Dimension;
|
|
radius?: number;
|
|
style?: StyleProp<ViewStyle>;
|
|
};
|
|
|
|
const Skeleton: React.FC<SkeletonProps> = ({
|
|
width = "100%",
|
|
height = 16,
|
|
radius = 8,
|
|
style,
|
|
}) => {
|
|
const opacity = useRef(new Animated.Value(0.6)).current;
|
|
|
|
useEffect(() => {
|
|
const animation = Animated.loop(
|
|
Animated.sequence([
|
|
Animated.timing(opacity, {
|
|
toValue: 0.4,
|
|
duration: 600,
|
|
useNativeDriver: true,
|
|
}),
|
|
Animated.timing(opacity, {
|
|
toValue: 1,
|
|
duration: 800,
|
|
useNativeDriver: true,
|
|
}),
|
|
])
|
|
);
|
|
|
|
animation.start();
|
|
|
|
return () => {
|
|
animation.stop();
|
|
};
|
|
}, [opacity]);
|
|
|
|
return (
|
|
<Animated.View
|
|
style={[
|
|
{
|
|
width,
|
|
height,
|
|
borderRadius: radius,
|
|
backgroundColor: "#E5E7EB",
|
|
opacity,
|
|
},
|
|
style,
|
|
]}
|
|
/>
|
|
);
|
|
};
|
|
|
|
export default Skeleton;
|