'use strict'; import type { RefObject } from 'react'; import { useEffect, useRef } from 'react'; import type { WorkletFunction } from 'react-native-worklets'; import { isWorkletFunction, makeShareable } from 'react-native-worklets'; import { initialUpdaterRun } from '../animation'; import { IS_JEST } from '../common'; import type { AnimatedPropsAdapterFunction, AnimatedPropsAdapterWorklet, AnimatedStyle, SharedValue, Timestamp, ViewDescriptorsWrapper, } from '../commonTypes'; import { startMapper, stopMapper } from '../core'; import type { AnimatedProps } from '../createAnimatedComponent/commonTypes'; import { updateProps } from '../updateProps'; import { makeViewDescriptorsSet } from '../ViewDescriptorsSet'; import type { AnimatedStyleHandle, DefaultStyle, DependencyList, Descriptor, JestAnimatedStyleHandle, } from './commonTypes'; import type { AnimatedState, AnimatedUpdaterData, } from './useAnimatedStyleCommon'; import { buildWorkletsHash, checkSharedValueUsage, createAnimatedStyleHandle, prepareAnimation, runAnimations, styleUpdater, } from './useAnimatedStyleCommon'; import { useSharedValue } from './useSharedValue'; import { isAnimated, shallowEqual, validateAnimatedStyles } from './utils'; const updatePropsJestWrapper = IS_JEST ? ( viewDescriptors: ViewDescriptorsWrapper, // eslint-disable-next-line @typescript-eslint/no-explicit-any updates: AnimatedStyle, // eslint-disable-next-line @typescript-eslint/no-explicit-any animatedValues: RefObject>, // eslint-disable-next-line @typescript-eslint/no-explicit-any adapters: ((updates: AnimatedStyle) => void)[] ): void => { adapters.forEach((adapter) => { adapter(updates); }); animatedValues.current.value = { ...animatedValues.current.value, ...updates, }; updateProps(viewDescriptors, updates); } : undefined; function jestStyleUpdater( viewDescriptors: SharedValue, // eslint-disable-next-line @typescript-eslint/no-explicit-any updater: WorkletFunction<[], AnimatedStyle> | (() => AnimatedStyle), state: AnimatedState, animationsActive: SharedValue, // eslint-disable-next-line @typescript-eslint/no-explicit-any animatedValues: RefObject>, adapters: AnimatedPropsAdapterFunction[], forceUpdate?: boolean ): void { 'worklet'; // eslint-disable-next-line @typescript-eslint/no-explicit-any const animations: AnimatedStyle = state.animations ?? {}; const newValues = updater() ?? {}; const oldValues = state.last; // extract animated props let hasAnimations = false; let frameTimestamp: number | undefined; Object.keys(animations).forEach((key) => { const value = newValues[key]; if (!isAnimated(value)) { delete animations[key]; } }); Object.keys(newValues).forEach((key) => { const value = newValues[key]; if (isAnimated(value)) { frameTimestamp = global.__frameTimestamp || global._getAnimationTimestamp(); prepareAnimation(frameTimestamp, value, animations[key], oldValues[key]); animations[key] = value; hasAnimations = true; } }); function frame(timestamp: Timestamp) { // eslint-disable-next-line @typescript-eslint/no-shadow const { animations, last, isAnimationCancelled } = state; if (isAnimationCancelled) { state.isAnimationRunning = false; return; } // eslint-disable-next-line @typescript-eslint/no-explicit-any const updates: AnimatedStyle = {}; let allFinished = true; Object.keys(animations).forEach((propName) => { const finished = runAnimations( animations[propName], timestamp, propName, updates, animationsActive ); if (finished) { last[propName] = updates[propName]; delete animations[propName]; } else { allFinished = false; } }); if (Object.keys(updates).length) { updatePropsJestWrapper?.( viewDescriptors, updates, animatedValues, adapters ); } if (!allFinished) { requestAnimationFrame(frame); } else { state.isAnimationRunning = false; } } if (hasAnimations) { state.animations = animations; if (!state.isAnimationRunning) { state.isAnimationCancelled = false; state.isAnimationRunning = true; frame(frameTimestamp!); } } else { state.isAnimationCancelled = true; state.animations = []; } // calculate diff state.last = newValues; if (!shallowEqual(oldValues, newValues) || forceUpdate) { updatePropsJestWrapper?.( viewDescriptors, newValues, animatedValues, adapters ); } } function animatedStyleHandleToJSON(): string { return '{}'; } /** * Lets you create a styles object, similar to StyleSheet styles, which can be * animated using shared values. * * @param updater - A function returning an object with style properties you * want to animate. * @param dependencies - An optional array of dependencies. Only relevant when * using Reanimated without the Babel plugin on the Web. * @returns An animated style object which has to be passed to the `style` * property of an Animated component you want to animate. * @see https://docs.swmansion.com/react-native-reanimated/docs/core/useAnimatedStyle */ // @ts-expect-error Public type definition which strips internals. export function useAnimatedStyle