import type { ViewProps, ViewStyle } from 'react-native'; import { EntryAnimationsValues, EntryExitAnimationFunction, ExitAnimationsValues, StyleProps, withTiming, } from 'react-native-reanimated'; import { MOTION_ANIMATIONS } from '../internal/constants'; import { useAMAContext } from '../providers/AMAProvider'; export type ToAnimation = ViewProps['style']; type UseReanimatedAnimationBuilder = { from: AnimatedEntryViewStyle; to: ToAnimation; exitFrom?: AnimatedExitViewStyle; exitTo?: ToAnimation; duration: number; }; export const useReanimatedAnimationBuilder = ({ from, to, exitFrom, exitTo, duration, }: UseReanimatedAnimationBuilder) => { const { isReduceMotionEnabled } = useAMAContext(); const animationBuilder = ( initial: InitialValues, final: FinalValues, ): EntryExitAnimationFunction => { return (values: EntryAnimationsValues | ExitAnimationsValues) => { 'worklet'; const animations = (function generateAnimations(startValues, endValues) { return Object.keys(startValues as object).reduce( (outputAnimation, key) => { const k: keyof InitialValues = key as keyof InitialValues; const toValue = endValues[key as keyof FinalValues]; const value = startValues[k]; const mappedToValue = // @ts-ignore typeof toValue === 'string' ? values[toValue] || 0 : toValue; const realDuration = isReduceMotionEnabled && MOTION_ANIMATIONS.includes(key as keyof ViewStyle) ? 0 : duration; const newValue = Array.isArray(value) ? value.map((item, index) => generateAnimations( item as InitialValues, // @ts-ignore endValues?.[k]?.[index], ), ) : withTiming(mappedToValue, { duration: realDuration, }); outputAnimation[k] = newValue; return outputAnimation; }, {} as InitialValues, ); })(initial, final); const initialValues = (function generateInitialValues( startValues, ): StyleProps { return Object.entries(startValues as object).reduce( (newList, [key, value]) => { const mappedValue = // @ts-ignore typeof value === 'string' ? values[value] : value; const newValue = Array.isArray(value) ? value.map(item => generateInitialValues(item as InitialValues)) : mappedValue; newList[key as keyof StyleProps] = newValue; return newList; }, {} as StyleProps, ); })(initial); return { initialValues, animations, }; }; }; return { entering: animationBuilder(from, to), exiting: animationBuilder< ToAnimation, AnimatedExitViewStyle | AnimatedEntryViewStyle >(exitTo || to, exitFrom || from), }; }; export type AnimatedEntryViewStyle = ReanimatedStyle; export type AnimatedExitViewStyle = ReanimatedStyle; type ReanimatedStyle = { [key in keyof Omit]: ViewStyle[key] | K; } & { transform?: | ( | PerpectiveTransform | RotateTransform | RotateXTransform | RotateYTransform | RotateZTransform | ScaleTransform | ScaleXTransform | ScaleYTransform | TranslateXTransform | TranslateYTransform | SkewXTransform | SkewYTransform | MatrixTransform )[] | undefined; }; type PerpectiveTransform = { c: string | K; }; type RotateTransform = { rotate: string | K; }; type RotateXTransform = { rotateX: string | K; }; type RotateYTransform = { rotateY: string | K; }; type RotateZTransform = { rotateZ: string | K; }; type ScaleTransform = { scale: number | K; }; type ScaleXTransform = { scaleX: number | K; }; type ScaleYTransform = { scaleY: number | K; }; type TranslateXTransform = { translateX: number | K; }; type TranslateYTransform = { translateY: number | K; }; type SkewXTransform = { skewX: string | K; }; type SkewYTransform = { skewY: string | K; }; type MatrixTransform = { matrix: number[] | K; }; type ReanimatedEntryValues = keyof EntryAnimationsValues; type ReanimatedExitValues = keyof ExitAnimationsValues;