import { useEffect, useState } from "react";
import { View } from "react-native";
import Animated, {
cancelAnimation,
Easing,
useAnimatedStyle,
useSharedValue,
withRepeat,
withTiming,
} from "react-native-reanimated";
const INDICATOR_WIDTH_FRACTION = 0.3;
const MIN_INDICATOR_WIDTH = 48;
function LoadingStripFrame(props: {
readonly children: React.ReactNode;
readonly onLayout?: (width: number) => void;
}) {
return (
{
props.onLayout?.(event.nativeEvent.layout.width);
}
: undefined
}
>
{props.children}
);
}
function IndeterminateLoadingStrip() {
const [containerWidth, setContainerWidth] = useState(0);
const travelProgress = useSharedValue(0);
const indicatorWidth = Math.max(MIN_INDICATOR_WIDTH, containerWidth * INDICATOR_WIDTH_FRACTION);
useEffect(() => {
travelProgress.value = 0;
travelProgress.value = withRepeat(
withTiming(1, {
duration: 1100,
easing: Easing.inOut(Easing.quad),
}),
-1,
false,
);
return () => {
cancelAnimation(travelProgress);
};
}, [travelProgress]);
const indicatorStyle = useAnimatedStyle(
() => ({
transform: [
{
translateX: (containerWidth + indicatorWidth) * travelProgress.value - indicatorWidth,
},
],
width: indicatorWidth,
}),
[containerWidth, indicatorWidth],
);
return (
);
}
export function LoadingStrip(props: { readonly progress?: number }) {
if (props.progress === undefined) {
return ;
}
const clampedProgress = Math.min(1, Math.max(0, props.progress));
return (
);
}