Răsfoiți Sursa

Add VbeSkeleton.js

vbea 1 an în urmă
părinte
comite
e33e64a401
1 a modificat fișierele cu 135 adăugiri și 0 ștergeri
  1. 135 0
      Strides-APP/app/components/VbeSkeleton.js

+ 135 - 0
Strides-APP/app/components/VbeSkeleton.js

@@ -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'
+  }
+});