/* eslint-disable no-unsafe-optional-chaining */ import { useSharedValue, withTiming, useDerivedValue, } from 'react-native-reanimated'; import {useEffect} from 'react'; import { animationHook, endPointAnimationFunction, startAnimationFunction, } from 'src/animations/animations'; import { getPathXArrayFromPath, getPathYArrayFromPath, svgBezierPath, } from './utils'; const useTransitionAttach: animationHook = ({path, duration, enabled}) => { if (!enabled) { return { derivedPathString: undefined, startAnimation: undefined, endPointAnimation: undefined, }; } const DURATION = duration || 0; const pathYSV = useSharedValue([]); const pathXSV = useSharedValue([]); useEffect(() => { const newPathXArray = getPathXArrayFromPath(path?.d || ''); const newPathYArray = getPathYArrayFromPath(path?.d || ''); if (path?.data.length && pathXSV.value.length < path?.data.length) { const paddedXArray = new Array( path?.data.length - pathXSV.value.length, ) .fill(0) .concat(pathXSV.value); const paddedYArray = new Array( path?.data.length - pathYSV.value.length, ) .fill(0) .concat(pathYSV.value); // reanimated handles arrays with 16 elements as a matrix // so we double the latest elements in the padded arrays too if (paddedXArray.length === 16) { paddedXArray.push(paddedXArray[15]); paddedYArray.push(paddedYArray[15]); } pathXSV.value = paddedXArray; pathYSV.value = paddedYArray; const isInitial = pathXSV.value.length === 0; // reanimated handles arrays with 16 elements as a matrix // so we double the latest elements if (newPathXArray.length === 16) { newPathXArray.push(newPathXArray[15] as number); newPathYArray.push(newPathYArray[15] as number); } pathXSV.value = withTiming(newPathXArray, { duration: isInitial ? 0 : DURATION / 2, }); pathYSV.value = withTiming(newPathYArray, { duration: isInitial ? 0 : DURATION / 2, }); } else if ( path?.data.length && pathXSV.value.length > path?.data.length ) { const pathArrayXAfter = [ ...new Array(pathXSV.value.length - newPathXArray.length).fill( newPathXArray[0], ), ...newPathXArray, ]; // reanimated handles arrays with 16 elements as a matrix // so we double the latest elements if (pathArrayXAfter.length === 16) { pathArrayXAfter.push(pathArrayXAfter[15]); } pathXSV.value = withTiming(pathArrayXAfter, { duration: DURATION / 2, }); const pathArrayYAfter = [ ...new Array(pathXSV.value.length - newPathYArray.length).fill( newPathYArray[0], ), ...newPathYArray, ]; // reanimated handles arrays with 16 elements as a matrix // so we double the latest elements if (pathArrayYAfter.length === 16) { pathArrayYAfter.push(pathArrayYAfter[15]); } pathYSV.value = withTiming(pathArrayYAfter, { duration: DURATION / 2, }); } else { // reanimated handles arrays with 16 elements as a matrix // so we double the latest elements if (newPathXArray.length === 16) { newPathXArray.push(newPathXArray[15] as number); newPathYArray.push(newPathYArray[15] as number); } pathXSV.value = withTiming(newPathXArray, { duration: DURATION / 2, }); pathYSV.value = withTiming(newPathYArray, { duration: DURATION / 2, }); } }, [path?.d]); const startAnimation: startAnimationFunction = ({ action, }: { action: () => void; }) => { action(); }; const generatePointsFromXAndY = (x: number[], y: number[]) => { 'worklet'; const points = new Array(x.length).fill(0).map((_value, i) => { if (x !== undefined && y !== undefined) { return { x: x[i], y: y[i], }; } return { x: 0, y: 0, }; }); return points; }; const derivedPathString = useDerivedValue(() => { if (pathXSV.value !== undefined && pathYSV.value !== undefined) { const points = generatePointsFromXAndY( pathXSV.value, pathYSV.value, ); return svgBezierPath(points, 0.03, 'complex'); } return ''; }, [path?.d]); const endPointAnimation: endPointAnimationFunction = ({ currentYPosition, newYPosition, }) => { currentYPosition.value = withTiming(newYPosition, { duration: DURATION / 2, }); }; return { derivedPathString, startAnimation, endPointAnimation, }; }; export default useTransitionAttach;