UNPKG

@likashefqet/react-native-image-zoom

Version:

A performant zoomable image written in Reanimated v2+ 🚀

74 lines (66 loc) • 1.97 kB
import { useCallback } from 'react'; import { AnimatableValue, AnimationCallback, runOnJS, useSharedValue, } from 'react-native-reanimated'; import { ANIMATION_VALUE, type OnResetAnimationEndCallback } from '../types'; export type OnAnimationEndCallback = AnimationCallback extends ( ...a: infer I ) => infer O ? ( interactionId: string, value: ANIMATION_VALUE, lastValue: number, ...a: I ) => O : never; type EndValues = Record< ANIMATION_VALUE, { lastValue: number; finished?: boolean; current?: AnimatableValue; } >; type PartialEndValues = Partial<EndValues>; type InteractionEndValues = Record<string, PartialEndValues>; const ANIMATION_VALUES = [ ANIMATION_VALUE.SCALE, ANIMATION_VALUE.FOCAL_X, ANIMATION_VALUE.FOCAL_Y, ANIMATION_VALUE.TRANSLATE_X, ANIMATION_VALUE.TRANSLATE_Y, ]; const isAnimationComplete = ( endValues: PartialEndValues ): endValues is EndValues => { 'worklet'; return ANIMATION_VALUES.every((item) => !!endValues[item]); }; export const useAnimationEnd = ( onResetAnimationEnd?: OnResetAnimationEndCallback ) => { const endValues = useSharedValue<InteractionEndValues>({}); const onAnimationEnd: OnAnimationEndCallback = useCallback( (interactionId, value, lastValue, finished, current) => { 'worklet'; if (onResetAnimationEnd) { const currentEndValues = endValues.value[interactionId] || {}; currentEndValues[value] = { lastValue, finished, current }; if (isAnimationComplete(currentEndValues)) { const completed = !Object.values(currentEndValues).some( (item) => !item.finished ); runOnJS(onResetAnimationEnd)(completed, currentEndValues); delete endValues.value[interactionId]; } else { endValues.value[interactionId] = currentEndValues; } } }, [onResetAnimationEnd, endValues] ); return { onAnimationEnd }; };