import React, { useEffect, useRef, useState } from "react"; import type { LayoutChangeEvent } from "react-native"; import { Animated, Easing, View } from "react-native"; import Svg, { Defs, LinearGradient, Rect, Stop } from "react-native-svg"; import { shineWidth, useStyles } from "./Glimmer.style"; import { useSizeStyles } from "./Glimmer.size.style"; import { useShapeStyles } from "./Glimmer.shape.style"; import { tokens } from "../utils/design"; import { useAtlantisTheme } from "../AtlantisThemeContext"; export type GlimmerShapes = keyof ReturnType; export type GlimmerSizes = keyof ReturnType; export type GlimmerTimings = "base" | "fast"; interface GlimmerProps { /** * Sets the size of the glimmer. */ readonly shape?: GlimmerShapes; /** * Sets the shape of the glimmer. * * If you need a specific width, use the `width` prop. */ readonly size?: GlimmerSizes; /** * Control how fast the shine moves from left to right. This is useful when * the glimmer is used on smaller spaces. */ readonly timing?: GlimmerTimings; /** * Adjust the width of the glimmer in px or % values. */ readonly width?: number | `${number}%`; } export const GLIMMER_TEST_ID = "ATL-Glimmer"; export const GLIMMER_BACKGROUND_TEST_ID = "ATL-Glimmer-Background"; export const GLIMMER_SHINE_TEST_ID = "ATL-Glimmer-Shine"; export function Glimmer({ width, shape = "rectangle", size = "base", timing = "base", }: GlimmerProps) { const leftPosition = useRef(new Animated.Value(-shineWidth)).current; const [parentWidth, setParentWidth] = useState(0); useEffect(() => { const shine = Animated.loop( Animated.timing(leftPosition, { toValue: parentWidth + shineWidth, duration: timing === "base" ? tokens["timing-loading--extended"] : tokens["timing-loading"], easing: Easing.ease, useNativeDriver: true, }), ); shine.start(); return shine.stop; }, [parentWidth]); const styles = useStyles(); const sizeStyles = useSizeStyles(); const shapeStyles = useShapeStyles(); const { effectiveTheme, tokens: themeTokens } = useAtlantisTheme(); const shineOpacity = effectiveTheme === "dark" ? 0.2 : 0.75; return ( ); function getWidth(event: LayoutChangeEvent) { setParentWidth(event.nativeEvent.layout.width); } }