廓形仪rn版本-技术调研
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

134 lines
3.2 KiB

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<typeof View> &
VariantProps<typeof skeletonStyle> & {
isLoaded?: boolean;
startColor?: string;
};
type ISkeletonTextProps = React.ComponentProps<typeof View> &
VariantProps<typeof skeletonTextStyle> & {
_lines?: number;
isLoaded?: boolean;
startColor?: string;
};
const Skeleton = forwardRef<
React.ComponentRef<typeof Animated.View>,
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 (
<Animated.View
style={{ opacity: pulseAnim }}
className={`${startColor} ${skeletonStyle({
variant,
class: className,
})}`}
{...props}
ref={ref}
/>
);
} else {
Animated.loop(pulse).stop();
return children;
}
});
const SkeletonText = forwardRef<
React.ComponentRef<typeof View>,
ISkeletonTextProps
>(function SkeletonText(
{
className,
_lines,
isLoaded = false,
startColor = 'bg-background-200',
gap = 2,
children,
...props
},
ref
) {
if (!isLoaded) {
if (_lines) {
return (
<View
className={`${skeletonTextStyle({
gap,
})}`}
ref={ref}
>
{Array.from({ length: _lines }).map((_, index) => (
<Skeleton
key={index}
className={`${startColor} ${skeletonTextStyle({
class: className,
})}`}
{...props}
/>
))}
</View>
);
} else {
return (
<Skeleton
className={`${startColor} ${skeletonTextStyle({
class: className,
})}`}
{...props}
ref={ref}
/>
);
}
} else {
return children;
}
});
Skeleton.displayName = 'Skeleton';
SkeletonText.displayName = 'SkeletonText';
export { Skeleton, SkeletonText };