import Svg, { Path } from 'react-native-svg'; import type { ResolvedBgConfig, Layout } from './types'; import { use, useLayoutEffect, useMemo } from 'react'; import { useAnimatedSectorPath, useCombinedAnimation } from './hooks'; import { CircleLayoutContext } from './CircleLayoutContext'; export const Bg = ({ index, radius, minComponentLayout, centerComponentLayout, isVisible = true, color = '#3d19e0', strokeColor, strokeWidth = 1, outerRadius, innerRadius = 0, }: { index: number; radius: number; minComponentLayout: Layout; centerComponentLayout: Layout; isVisible?: boolean; } & ResolvedBgConfig) => { const { sectorAngles, componentAngles, animationDriver: driver, } = use(CircleLayoutContext); /* eslint-disable react-hooks/static-components, @eslint-react/static-components -- AnimatedSvg/AnimatedPath are memoized on `driver` (a dynamic, pluggable prop), not module-level constants, so they're necessarily defined inside the component; their identity stays stable across renders as long as `driver` doesn't change. */ const AnimatedSvg = useMemo( () => driver.createAnimatedComponent(Svg), [driver] ); const AnimatedPath = useMemo( () => driver.createAnimatedComponent(Path), [driver] ); const { startAngleInRadians, endAngleInRadians } = useMemo(() => { const angle = componentAngles[index]!; const sector = sectorAngles[index]!; return { startAngleInRadians: angle, endAngleInRadians: angle + sector, }; }, [componentAngles, sectorAngles, index]); const { size, center } = useMemo(() => { const padding = 0; const diameter = (outerRadius ?? radius) * 2; const width = diameter + minComponentLayout.width - centerComponentLayout.width / 2 + padding; const height = diameter + minComponentLayout.height - centerComponentLayout.height / 2 + padding; const s = Math.max(width, height); return { size: s, center: { x: s / 2, y: s / 2 } }; }, [ outerRadius, radius, minComponentLayout.width, minComponentLayout.height, centerComponentLayout.width, centerComponentLayout.height, ]); const { hideComponent, opacityValue, radiansValue, radiusValue, showComponent, } = useCombinedAnimation({ index, radians: endAngleInRadians, startAngle: startAngleInRadians, radius: size / 2, useNativeDriver: false, }); useLayoutEffect(() => { if (isVisible) { showComponent(); } else { hideComponent(); } }, [hideComponent, isVisible, showComponent]); const path = useAnimatedSectorPath({ driver, radius: radiusValue, startAngle: startAngleInRadians, endAngle: radiansValue, center, innerRadius, }); return ( ); /* eslint-enable react-hooks/static-components, @eslint-react/static-components -- end of the driver-dependent animated component region (see disable comment above AnimatedSvg/AnimatedPath). */ };