|
@@ -0,0 +1,135 @@
|
|
|
|
|
+import React, { memo, useMemo } from 'react';
|
|
|
|
|
+import { StyleSheet, View } from 'react-native';
|
|
|
|
|
+import Animated, {
|
|
|
|
|
+ useSharedValue,
|
|
|
|
|
+ withRepeat,
|
|
|
|
|
+ withTiming,
|
|
|
|
|
+ useAnimatedReaction,
|
|
|
|
|
+ useDerivedValue,
|
|
|
|
|
+ useAnimatedStyle,
|
|
|
|
|
+ Easing,
|
|
|
|
|
+} from 'react-native-reanimated';
|
|
|
|
|
+import { useLayout, useGetBones } from '../skeleton/hooks';
|
|
|
|
|
+import TextView from './TextView';
|
|
|
|
|
+
|
|
|
|
|
+export const ANIMATION_TYPE = {
|
|
|
|
|
+ NONE: "none",
|
|
|
|
|
+ SHIVER: "shiver",
|
|
|
|
|
+ PULSE: "pulse"
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export const ANIMATION_DIRECTION = {
|
|
|
|
|
+ HORIZONTAL_LEFT: "horizontalLeft",
|
|
|
|
|
+ HORIZONTAL_RIGHT: "horizontalRight",
|
|
|
|
|
+ VERTICAL_TOP: "verticalTop",
|
|
|
|
|
+ VERTICAL_DOWN: "verticalDown",
|
|
|
|
|
+ DIAGONAL_DOWN_LEFT: "diagonalDownLeft",
|
|
|
|
|
+ DIAGONAL_DOWN_RIGHT: "diagonalDownRight",
|
|
|
|
|
+ DIAGONAL_TOP_LEFT: "diagonalTopLeft",
|
|
|
|
|
+ DIAGONAL_TOP_RIGHT: "diagonalTopRight"
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const VbeSkeleton = ({
|
|
|
|
|
+ style=styles.container,
|
|
|
|
|
+ viewStyle=styles.viewStyle,
|
|
|
|
|
+ textStyle={},
|
|
|
|
|
+ text,
|
|
|
|
|
+ duration=1200,
|
|
|
|
|
+ layout=[],
|
|
|
|
|
+ numberOfLines,
|
|
|
|
|
+ animationType=ANIMATION_TYPE.SHIVER,
|
|
|
|
|
+ animationDirection=ANIMATION_DIRECTION.HORIZONTAL_LEFT,
|
|
|
|
|
+ easing=Easing.bezier(0.5, 0, 0.25, 1),
|
|
|
|
|
+ isLoading=true,
|
|
|
|
|
+ boneColor='#eeeeee',
|
|
|
|
|
+ highlightColor='#f6f6f6',
|
|
|
|
|
+ hasFadeIn=false,
|
|
|
|
|
+ children
|
|
|
|
|
+}) => {
|
|
|
|
|
+ const animationValue = useSharedValue(0);
|
|
|
|
|
+ const loadingValue = useSharedValue(0);
|
|
|
|
|
+ const shiverValue = useSharedValue(animationType === 'shiver' ? 1 : 0);
|
|
|
|
|
+ const [componentSize, onLayout] = useLayout();
|
|
|
|
|
+ const generalStyles = useMemo(
|
|
|
|
|
+ () => ({
|
|
|
|
|
+ animationDirection,
|
|
|
|
|
+ animationType,
|
|
|
|
|
+ boneColor,
|
|
|
|
|
+ animationValue,
|
|
|
|
|
+ highlightColor,
|
|
|
|
|
+ }),
|
|
|
|
|
+ [
|
|
|
|
|
+ animationDirection,
|
|
|
|
|
+ animationType,
|
|
|
|
|
+ animationValue,
|
|
|
|
|
+ boneColor,
|
|
|
|
|
+ highlightColor,
|
|
|
|
|
+ ],
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ const getBones = useGetBones(componentSize);
|
|
|
|
|
+
|
|
|
|
|
+ useAnimatedReaction(
|
|
|
|
|
+ () => ({ isLoading, loadingValue }),
|
|
|
|
|
+ () => {
|
|
|
|
|
+ if (isLoading && loadingValue.value !== 1) {
|
|
|
|
|
+ /* NOTE: Reset behaviour to ensure animation always starts from the beginning */
|
|
|
|
|
+ animationValue.value = 0;
|
|
|
|
|
+
|
|
|
|
|
+ animationValue.value =
|
|
|
|
|
+ shiverValue.value === 1
|
|
|
|
|
+ ? withRepeat(withTiming(1, { duration, easing }), -1, false)
|
|
|
|
|
+ : withRepeat(
|
|
|
|
|
+ withTiming(1, { duration: duration / 2, easing }),
|
|
|
|
|
+ -1,
|
|
|
|
|
+ true,
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ [isLoading, shiverValue],
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ const opacity = useDerivedValue(() => {
|
|
|
|
|
+ if (!isLoading) {
|
|
|
|
|
+ return withTiming(1, { duration: 250 });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ const animatedStyle = useAnimatedStyle(() => ({
|
|
|
|
|
+ opacity: opacity.value,
|
|
|
|
|
+ }));
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <View style={style} onLayout={onLayout}>
|
|
|
|
|
+ {isLoading ? (
|
|
|
|
|
+ getBones({
|
|
|
|
|
+ bonesLayout: layout,
|
|
|
|
|
+ children,
|
|
|
|
|
+ generalStyles,
|
|
|
|
|
+ })
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <Animated.View style={[viewStyle, hasFadeIn ? animatedStyle : {}]}>
|
|
|
|
|
+ { text
|
|
|
|
|
+ ? <TextView style={textStyle} numberOfLines={numberOfLines}>{text}</TextView>
|
|
|
|
|
+ : children
|
|
|
|
|
+ }
|
|
|
|
|
+ </Animated.View>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </View>
|
|
|
|
|
+ );
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+export default memo(VbeSkeleton);
|
|
|
|
|
+
|
|
|
|
|
+const styles = StyleSheet.create({
|
|
|
|
|
+ container: {
|
|
|
|
|
+ flex: 1,
|
|
|
|
|
+ alignItems: 'center',
|
|
|
|
|
+ justifyContent: 'center'
|
|
|
|
|
+ },
|
|
|
|
|
+ viewStyle: {
|
|
|
|
|
+ alignItems: 'center'
|
|
|
|
|
+ }
|
|
|
|
|
+});
|