UNPKG

@wolf-tp/react-native-boilerplate

Version:

React Native Template

231 lines (210 loc) 5.36 kB
import React, { Component, useEffect } from 'react'; import { useWindowDimensions } from 'react-native'; import Animated, { AnimationCallback, Easing, interpolate, interpolateColor, measure, useAnimatedRef, useDerivedValue, useSharedValue, withDelay, withSpring, WithSpringConfig, withTiming, WithTimingConfig, } from 'react-native-reanimated'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { sharedClamp, sharedMax, sharedMin } from './math'; /** * Interpolate number */ export const useInterpolate = ( progress: Animated.SharedValue<number>, input: number[], output: number[], type?: Animated.Extrapolate, ) => useDerivedValue(() => interpolate(progress.value, input, output, type)); /** * Interpolate color */ export const useInterpolateColor = ( progress: Animated.SharedValue<number>, input: number[], output: (number | string)[], colorSpace?: 'RGB' | 'HSV' | undefined, ) => { 'worklet'; return useDerivedValue(() => interpolateColor(progress.value, input, output, colorSpace), ); }; /** * Linear interpolation between x and y using a to weight between them */ export const useMix = ( progress: Animated.SharedValue<number>, x: number, y: number, ) => { 'worklet'; return useDerivedValue(() => x + progress.value * (y - x)); }; /** * Convert number to radian */ export const useRadian = (value: Animated.SharedValue<number>) => useDerivedValue(() => { 'worklet'; return `${value.value}deg`; }); /** * Clamp value when out of range */ export const useShareClamp = ( value: Animated.SharedValue<number>, lowerValue: number, upperValue: number, ) => { 'worklet'; return useDerivedValue(() => sharedClamp(value.value, lowerValue, upperValue), ); }; /** * Return min number of args */ export const useMin = (...args: Animated.SharedValue<number>[]) => { 'worklet'; return useDerivedValue(() => sharedMin(...args.map(x => x.value))); }; /** * Return max number of args */ export const useMax = (...args: Animated.SharedValue<number>[]) => { 'worklet'; return useDerivedValue(() => sharedMax(...args.map(x => x.value))); }; /** * Return view inside screen or not */ export function useInsideView<T extends Component>( wrapHeight: number | undefined = undefined, ): [React.RefObject<T>, Animated.SharedValue<boolean>] { const { height } = useWindowDimensions(); const { top } = useSafeAreaInsets(); const ref = useAnimatedRef<T>(); const toggle = useSharedValue(0); const rectBottom = useSharedValue(0); const rectTop = useSharedValue(0); const visible = useDerivedValue(() => { return rectTop.value <= (wrapHeight || height) && rectBottom.value >= 0; }); useDerivedValue(() => { try { const measured = measure(ref); rectTop.value = measured.pageY - top; rectBottom.value = measured.pageY + measured.height - top; toggle.value = toggle.value === 1 ? 0 : 1; } catch { toggle.value = toggle.value === 1 ? 0 : 1; } }); return [ref, visible]; } type Vector = { x: number; y: number; }; /** * Create Animated Shared Value Vector */ export const useVector = ({ x, y }: Vector) => { const ox = useSharedValue(x); const oy = useSharedValue(y); return [ox, oy]; }; type UseTimingParams = { toValue?: number; from?: number; config?: WithTimingConfig; callback?: AnimationCallback; delay?: number; }; export const useTiming = ({ callback, config, from = 0, toValue = 1, delay = 0, }: UseTimingParams = {}) => { const progress = useSharedValue(from); // effect useEffect(() => { progress.value = withDelay( delay, withTiming( toValue, Object.assign( { duration: 500, easing: Easing.bezier(0.33, 0.01, 0, 1), }, config, ), callback, ), ); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // result return progress; }; type UseSpringParams = { toValue?: number; from?: number; config?: WithSpringConfig; callback?: AnimationCallback; delay?: number; }; export const useSpring = ({ callback, config, from = 0, toValue = 1, delay = 0, }: UseSpringParams = {}) => { const progress = useSharedValue(from); // effect useEffect(() => { progress.value = withDelay(delay, withSpring(toValue, config, callback)); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // result return progress; }; // const TransactionLayout = CurvedTransition.delay(100); // export const makeAnimationComponent = <T extends object>( // _Component: FunctionComponent<T>, // ): React.FunctionComponent< // Animated.AnimateProps<T> & { inDelay?: number; notInOut?: boolean } // > => { // const Component = Animated.createAnimatedComponent(_Component); // // eslint-disable-next-line @typescript-eslint/no-explicit-any // return ({ children, notInOut, inDelay, ...props }: any) => { // const inOutProps = { // entering: FadeInUp.delay(inDelay || 0), // exiting: FadeOutUp.duration(100), // }; // return React.createElement( // Component, // { // ...(!notInOut && inOutProps), // layout: TransactionLayout, // ...props, // }, // ...children, // ); // }; // };