import React, { useMemo } from "react"; import { Animated, StyleSheet, useWindowDimensions, View } from "react-native"; import { Palette } from "../../styles"; const ORIENTATION = { HORIZONTAL: "horizontal", VERTICAL: "vertical", }; const AnimatedPaginationDot = ({ data = [], scrollValue, itemDimension, containerStyle, dotStyle, orientation = ORIENTATION.HORIZONTAL, expandingDotSize = 20, inactiveDotOpacity = 0.4, inactiveDotColor = "rgba(255,255,255,0.4)", activeDotColor = Palette.white, baseDotSize = 10, }) => { const animatedValue = useMemo( () => scrollValue || new Animated.Value(0), [scrollValue] ); const { width, height } = useWindowDimensions(); const distance = useMemo(() => { if (typeof itemDimension === "number" && itemDimension > 0) { return itemDimension; } if (orientation === ORIENTATION.VERTICAL) { return Math.max(height, 1); } return Math.max(width, 1); }, [height, itemDimension, orientation, width]); const resolvedDotStyle = useMemo( () => StyleSheet.flatten(dotStyle) || {}, [dotStyle] ); const defaultSize = Math.max(baseDotSize, 1); const baseWidth = typeof resolvedDotStyle?.width === "number" ? resolvedDotStyle.width : defaultSize; const baseHeight = typeof resolvedDotStyle?.height === "number" ? resolvedDotStyle.height : defaultSize; const containerOrientationStyle = orientation === ORIENTATION.VERTICAL ? styles.containerVertical : styles.containerHorizontal; return ( {data.map((_, index) => { const inputRange = [ (index - 1) * distance, index * distance, (index + 1) * distance, ]; const staticSizeStyle = { width: baseWidth, height: baseHeight, }; const color = animatedValue.interpolate({ inputRange, outputRange: [inactiveDotColor, activeDotColor, inactiveDotColor], extrapolate: "clamp", }); const opacity = animatedValue.interpolate({ inputRange, outputRange: [inactiveDotOpacity, 1, inactiveDotOpacity], extrapolate: "clamp", }); const primarySize = animatedValue.interpolate({ inputRange, outputRange: [ orientation === ORIENTATION.VERTICAL ? baseHeight : baseWidth, expandingDotSize, orientation === ORIENTATION.VERTICAL ? baseHeight : baseWidth, ], extrapolate: "clamp", }); const animatedSizeStyle = orientation === ORIENTATION.VERTICAL ? { height: primarySize } : { width: primarySize }; return ( ); })} ); }; AnimatedPaginationDot.orientation = ORIENTATION; export default AnimatedPaginationDot; const styles = StyleSheet.create({ containerBase: { alignItems: "center", justifyContent: "center", }, containerHorizontal: { flexDirection: "row", }, containerVertical: { flexDirection: "column", }, dotBase: { borderRadius: 999, marginHorizontal: 4, marginVertical: 4, }, });