UNPKG

react-native-reanimated

Version:

More powerful alternative to Animated library for React Native.

121 lines (111 loc) 3.48 kB
'use strict'; import type { WorkletFunction } from '../commonTypes'; import { ReanimatedError } from '../errors'; import type { DependencyList } from './commonTypes'; // Builds one big hash from multiple worklets' hashes. export function buildWorkletsHash<Args extends unknown[], ReturnValue>( worklets: | Record<string, WorkletFunction<Args, ReturnValue>> | WorkletFunction<Args, ReturnValue>[] ) { // For arrays `Object.values` returns the array itself. return Object.values(worklets).reduce( (acc, worklet: WorkletFunction<Args, ReturnValue>) => acc + worklet.__workletHash.toString(), '' ); } // Builds dependencies array for useEvent handlers. export function buildDependencies( dependencies: DependencyList, handlers: Record<string, WorkletFunction | undefined> ) { type Handler = (typeof handlers)[keyof typeof handlers]; const handlersList = Object.values(handlers).filter( (handler) => handler !== undefined ) as NonNullable<Handler>[]; if (!dependencies) { dependencies = handlersList.map((handler) => { return { workletHash: handler.__workletHash, closure: handler.__closure, }; }); } else { dependencies.push(buildWorkletsHash(handlersList)); } return dependencies; } // This is supposed to work as useEffect comparison. export function areDependenciesEqual( nextDependencies: DependencyList, prevDependencies: DependencyList ) { function is(x: number, y: number) { return ( (x === y && (x !== 0 || 1 / x === 1 / y)) || (Number.isNaN(x) && Number.isNaN(y)) ); } const objectIs: (nextDeps: unknown, prevDeps: unknown) => boolean = typeof Object.is === 'function' ? Object.is : is; function areHookInputsEqual( nextDeps: DependencyList, prevDeps: DependencyList ) { if (!nextDeps || !prevDeps || prevDeps.length !== nextDeps.length) { return false; } for (let i = 0; i < prevDeps.length; ++i) { if (!objectIs(nextDeps[i], prevDeps[i])) { return false; } } return true; } return areHookInputsEqual(nextDependencies, prevDependencies); } export function isAnimated(prop: unknown) { 'worklet'; if (Array.isArray(prop)) { return prop.some(isAnimated); } else if (typeof prop === 'object' && prop !== null) { if ((prop as Record<string, unknown>).onFrame !== undefined) { return true; } else { return Object.values(prop).some(isAnimated); } } return false; } // This function works because `Object.keys` // return empty array of primitives and on arrays // it returns array of its indices. export function shallowEqual< T extends Record<string | number | symbol, unknown>, >(a: T, b: T) { 'worklet'; const aKeys = Object.keys(a); const bKeys = Object.keys(b); if (aKeys.length !== bKeys.length) { return false; } for (let i = 0; i < aKeys.length; i++) { if (a[aKeys[i]] !== b[aKeys[i]]) { return false; } } return true; } export function validateAnimatedStyles(styles: unknown[] | object) { 'worklet'; if (typeof styles !== 'object') { throw new ReanimatedError( `\`useAnimatedStyle\` has to return an object, found ${typeof styles} instead.` ); } else if (Array.isArray(styles)) { throw new ReanimatedError( '`useAnimatedStyle` has to return an object and cannot return static styles combined with dynamic ones. Please do merging where a component receives props.' ); } }