GT2/Ejectable/node_modules/react-native-reanimated/lib/reanimated2/react-native-reanimated-tes...

563 lines
18 KiB
JavaScript

/* eslint-disable @typescript-eslint/no-empty-function */
/* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useState, useCallback, forwardRef } from 'react';
import { StyleSheet, Button, View, Image, } from 'react-native';
import { PanGestureHandler, PinchGestureHandler, FlatList, } from 'react-native-gesture-handler';
import Animated, { useSharedValue, useDerivedValue, useAnimatedStyle, useAnimatedScrollHandler, useAnimatedGestureHandler, Easing, withTiming, withSpring, cancelAnimation, withDelay, withRepeat, withSequence, withDecay, useWorkletCallback, createWorklet, runOnUI, useAnimatedReaction, interpolateColor, makeMutable, interpolateNode, useValue, color, interpolateColors, createAnimatedPropAdapter, useAnimatedProps, useAnimatedRef, } from 'react-native-reanimated';
class Path extends React.Component {
render() {
return null;
}
}
const SomeFC = (props) => {
return <View {...props}/>;
};
const SomeFCWithRef = forwardRef((props) => {
return <View {...props}/>;
});
// Class Component -> Animated Class Component
const AnimatedPath = Animated.createAnimatedComponent(Path);
const AnimatedImage = Animated.createAnimatedComponent(Image);
const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
const AnimatedTypedFlatList = Animated.createAnimatedComponent(FlatList);
// Function Component -> Animated Function Component
const AnimatedFC = Animated.createAnimatedComponent(SomeFC);
const AnimatedFCWithRef = Animated.createAnimatedComponent(SomeFCWithRef);
function CreateAnimatedComponentTest1() {
const animatedProps = useAnimatedProps(() => ({ fill: 'blue' }));
return <AnimatedPath animatedProps={animatedProps}/>;
}
function CreateAnimatedComponentTest2() {
const animatedProps = useAnimatedProps(() => ({ fill2: 'blue' }));
return (
// @ts-expect-error
<AnimatedPath animatedProps={animatedProps}/>);
}
function CreateAnimatedComponentTest3() {
const animatedProps = useAnimatedProps(() => ({ pointerEvents: 'none' }));
return (<Animated.View animatedProps={animatedProps}>
<AnimatedPath />
</Animated.View>);
}
function CreateAnimatedFlatList() {
const renderItem = useCallback(({ item, index }) => {
if (Math.random()) {
return null;
}
return <View style={{ width: 100 }}></View>;
}, []);
return (<>
<AnimatedTypedFlatList style={{ flex: 1 }} data={[]} renderItem={renderItem}/>
<AnimatedFlatList
// @ts-expect-error
style={{ flex: 1, red: false }} data={[]} renderItem={() => null}/>
<AnimatedImage style={{ flex: 1 }} source={{ uri: '' }}/>
</>);
}
function TestClassComponentRef() {
const animatedRef = useAnimatedRef();
return <AnimatedImage ref={animatedRef} source={{}}/>;
}
function TestFunctionComponentRef() {
const animatedRef = useAnimatedRef();
return (<AnimatedFC
// @ts-expect-error ref is not available on plain function-components
ref={animatedRef}/>);
}
function TestFunctionComponentForwardRef() {
const animatedRef = useAnimatedRef();
return <AnimatedFCWithRef ref={animatedRef}/>;
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
box: {
height: 50,
backgroundColor: 'blue',
},
});
/**
* Reanimated 1
*/
// @TODO: add reanimated 1 tests here
/**
* Reanimated 2 Functions
*/
// makeMutable
function MakeMutableTest() {
const mut = makeMutable(0);
const mut2 = makeMutable(true);
return <Animated.View style={styles.container}/>;
}
/**
* Reanimated 2 Hooks
*/
// useSharedValue
function SharedValueTest() {
const translate = useSharedValue(0);
const translate2 = useSharedValue(0);
const translate3 = useSharedValue(0);
const sharedBool = useSharedValue(false);
if (sharedBool.value) {
sharedBool.value = false;
}
return <Animated.View style={styles.container}/>;
}
// useAnimatedStyle
function AnimatedStyleTest() {
const width = useSharedValue(50);
const animatedStyle = useAnimatedStyle(() => {
return {
width: width.value,
};
});
return <Animated.View style={[styles.box, animatedStyle]}/>;
}
// useAnimatedStyle with arrays (invalid return)
function AnimatedStyleArrayTest() {
const width = useSharedValue(50);
// @ts-expect-error since the animated style cannot be an array.
const animatedStyle = useAnimatedStyle(() => {
return [styles.box, { width: width.value }];
});
return <Animated.View style={[styles.box, animatedStyle]}/>;
}
// useAnimatedStyle with null (invalid return)
function AnimatedStyleNullTest() {
const width = useSharedValue(50);
// @ts-expect-error since the animated style cannot be "false".
const animatedStyle = useAnimatedStyle(() => false);
return <Animated.View style={[styles.box, animatedStyle]}/>;
}
// useAnimatedStyle with number (invalid return)
function AnimatedStyleNumberTest() {
const width = useSharedValue(50);
// @ts-expect-error since the animated style cannot be a number.
const animatedStyle = useAnimatedStyle(() => 5);
return <Animated.View style={[styles.box, animatedStyle]}/>;
}
// useDerivedValue
function DerivedValueTest() {
const progress = useSharedValue(0);
const width = useDerivedValue(() => {
return progress.value * 250;
});
// @ts-expect-error width is readonly
width.value = 100;
return (<Button title="Random" onPress={() => (progress.value = Math.random())}/>);
}
// useAnimatedScrollHandler
function AnimatedScrollHandlerTest() {
const translationY = useSharedValue(0);
const scrollHandler = useAnimatedScrollHandler((event) => {
translationY.value = event.contentOffset.y;
});
const stylez = useAnimatedStyle(() => {
return {
color: "red",
backgroundColor: 0x00ff00,
transform: [
{
translateY: translationY.value,
},
{
rotate: `${Math.PI}rad`
}
],
};
});
// @ts-expect-error
const style2 = useAnimatedStyle(() => {
return {
transform: [
{
rotate: Math.PI
}
],
};
});
// @ts-expect-error
const style3 = useAnimatedStyle(() => {
return {
color: {}
};
});
return (<View style={styles.container}>
<Animated.View style={[styles.box, stylez]}/>
<Animated.ScrollView onScroll={scrollHandler} scrollEventThrottle={16}/>
</View>);
}
// useAnimatedGestureHandler with context
function AnimatedGestureHandlerTest() {
const x = useSharedValue(0);
const gestureHandler = useAnimatedGestureHandler({
onStart: (_, ctx) => {
ctx.startX = x.value;
},
onActive: (event, ctx) => {
x.value = ctx.startX + event.translationX;
},
onEnd: (_) => {
x.value = 0;
},
});
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [
{
translateX: x.value,
},
],
};
});
return (<PanGestureHandler onGestureEvent={gestureHandler}>
<Animated.View style={[styles.box, animatedStyle]}/>
</PanGestureHandler>);
}
function AnimatedPinchGestureHandlerTest() {
const x = useSharedValue(0);
const gestureHandler = useAnimatedGestureHandler({
onActive: (event) => {
x.value = event.scale;
},
onEnd: () => {
x.value = withTiming(1);
},
});
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [
{
scale: x.value,
},
],
};
});
return (<PinchGestureHandler onGestureEvent={gestureHandler}>
<Animated.View style={[styles.box, animatedStyle]}/>
</PinchGestureHandler>);
}
/**
* Reanimated 2 Animations
*/
// withTiming
function WithTimingTest() {
const width = useSharedValue(50);
const style = useAnimatedStyle(() => {
return {
width: withTiming(width.value, {
duration: 500,
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
}, (finished) => { }),
};
});
return (<View>
<Animated.View style={[styles.box, style]}/>
<Button onPress={() => (width.value = Math.random() * 300)} title="Hey"/>
</View>);
}
function WithTimingToValueAsColorTest() {
const style = useAnimatedStyle(() => {
return {
width: withTiming('rgba(255,105,180,0)', {
duration: 500,
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
}, (_finished) => { }),
};
});
return (<View>
<Animated.View style={[styles.box, style]}/>
</View>);
}
// withSpring
function WithSpringTest() {
const x = useSharedValue(0);
const gestureHandler = useAnimatedGestureHandler({
onStart: (_, ctx) => {
ctx.startX = x.value;
},
onActive: (event, ctx) => {
x.value = ctx.startX + event.translationX;
},
onEnd: (_) => {
x.value = withSpring(0, {}, (finished) => { });
},
});
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [
{
translateX: x.value,
},
],
};
});
return (<PanGestureHandler onGestureEvent={gestureHandler}>
<Animated.View style={[styles.box, animatedStyle]}/>
</PanGestureHandler>);
}
function WithSpringToValueAsColorTest() {
const style = useAnimatedStyle(() => {
return {
width: withSpring('rgba(255,105,180,0)', {}, (_finished) => { }),
};
});
return (<View>
<Animated.View style={[styles.box, style]}/>
</View>);
}
// cancelAnimation
function CancelAnimationTest() {
const x = useSharedValue(0);
const gestureHandler = useAnimatedGestureHandler({
onStart: (_, ctx) => {
cancelAnimation(x);
},
onActive: (event, ctx) => {
x.value = ctx.startX + event.translationX;
},
onEnd: (_) => {
x.value = 0;
},
});
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [
{
translateX: x.value,
},
],
};
});
return (<PanGestureHandler onGestureEvent={gestureHandler}>
<Animated.View style={[styles.box, animatedStyle]}/>
</PanGestureHandler>);
}
// withDelay
function WithDelayTest() {
const x = useSharedValue(0);
const gestureHandler = useAnimatedGestureHandler({
onStart: (_, _ctx) => {
cancelAnimation(x);
},
onActive: (event, ctx) => {
x.value = ctx.startX + event.translationX;
},
onEnd: (_) => {
x.value = withDelay(1000, withTiming(70));
},
});
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [
{
translateX: x.value,
},
],
};
});
return (<PanGestureHandler onGestureEvent={gestureHandler}>
<Animated.View style={[styles.box, animatedStyle]}/>
</PanGestureHandler>);
}
// withRepeat
function WithRepeatTest() {
const x = useSharedValue(0);
const gestureHandler = useAnimatedGestureHandler({
onStart: (_, _ctx) => {
cancelAnimation(x);
},
onActive: (event, ctx) => {
x.value = ctx.startX + event.translationX;
},
onEnd: (_) => {
x.value = withRepeat(withTiming(70), 1, true, (finished) => { });
},
});
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [
{
translateX: x.value,
},
],
};
});
return (<PanGestureHandler onGestureEvent={gestureHandler}>
<Animated.View style={[styles.box, animatedStyle]}/>
</PanGestureHandler>);
}
// withSequence
function WithSequenceTest() {
const x = useSharedValue(0);
const gestureHandler = useAnimatedGestureHandler({
onStart: (_, _ctx) => {
cancelAnimation(x);
},
onActive: (event, ctx) => {
x.value = ctx.startX + event.translationX;
},
onEnd: (_) => {
x.value = withSequence(withTiming(70), withTiming(70));
},
});
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [
{
translateX: x.value,
},
],
};
});
return (<PanGestureHandler onGestureEvent={gestureHandler}>
<Animated.View style={[styles.box, animatedStyle]}/>
</PanGestureHandler>);
}
// withDecay
function WithDecayTest() {
const x = useSharedValue(0);
const gestureHandler = useAnimatedGestureHandler({
onStart: (_, ctx) => {
ctx.startX = x.value;
},
onActive: (event, ctx) => {
x.value = ctx.startX + event.translationX;
},
onEnd: (evt) => {
x.value = withDecay({
velocity: evt.velocityX,
clamp: [0, 200],
});
},
});
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [
{
translateX: x.value,
},
],
};
});
return (<PanGestureHandler onGestureEvent={gestureHandler}>
<Animated.View style={[styles.box, animatedStyle]}/>
</PanGestureHandler>);
}
// useWorkletCallback
function UseWorkletCallbackTest() {
const workletCallback = useWorkletCallback((a, b) => {
return a + b;
}, []);
runOnUI(() => {
const res = workletCallback(1, 1);
console.log(res);
})();
return <Animated.View style={styles.container}/>;
}
// createWorklet
function CreateWorkletTest() {
const workletCallback = createWorklet((a, b) => {
return a + b;
});
runOnUI(() => {
const res = workletCallback(1, 1);
console.log(res);
})();
return <Animated.View style={styles.container}/>;
}
// useWorkletCallback
function UseAnimatedReactionTest() {
const [state, setState] = useState();
const sv = useSharedValue(0);
useAnimatedReaction(() => {
return sv.value;
}, (value) => {
console.log(value);
});
useAnimatedReaction(() => {
return sv.value;
}, (value) => {
console.log(value);
}, []);
useAnimatedReaction(() => {
return sv.value;
}, (value) => {
console.log(value);
}, [state]);
useAnimatedReaction(() => {
return sv.value;
}, (value, previousResult) => {
console.log(value, previousResult);
});
return null;
}
// interpolateColor
function interpolateColorTest() {
const sv = useSharedValue(0);
interpolateColor(sv.value, [0, 1], [0x00ff00, 0x0000ff]);
interpolateColor(sv.value, [0, 1], ['red', 'blue']);
interpolateColor(sv.value, [0, 1], ['#00FF00', '#0000FF'], 'RGB');
interpolateColor(sv.value, [0, 1], ['#FF0000', '#00FF99'], 'HSV');
return null;
}
function interpolateNodeTest() {
const value = useValue(0);
interpolateNode(value, {
inputRange: [0, 1],
outputRange: ['0deg', '100deg'],
});
interpolateNode(value, {
inputRange: [0, 1],
outputRange: ['0rad', `${Math.PI}rad`],
});
}
function colorTest() {
const r = useValue(255);
const g = useValue(255);
const b = useValue(255);
const a = useValue(255);
return color(r, g, b, a);
}
function interpolateColorsTest() {
const animationValue = useValue(0);
const color = interpolateColors(animationValue, {
inputRange: [0, 1],
outputColorRange: ['red', 'blue'],
});
return color;
}
// update props
function updatePropsTest() {
const adapter1 = createAnimatedPropAdapter((props) => { }, []);
const adapter2 = createAnimatedPropAdapter((props) => { }, ['prop1', 'prop2']);
const adapter3 = createAnimatedPropAdapter(() => { });
// @ts-expect-error works only for useAnimatedProps
useAnimatedStyle(() => ({}), undefined, [adapter1, adapter2, adapter3]);
useAnimatedProps(() => ({}), null, adapter1);
useAnimatedProps(() => ({}), null, [adapter2, adapter3]);
}
// test partial animated props
function testPartialAnimatedProps() {
const ap = useAnimatedProps(() => ({
height: 100
}));
const aps = useAnimatedProps(() => ({
source: { uri: 'whatever' }
}));
// @ts-expect-error it should fail because `source` is a required prop
const test1 = <AnimatedImage />;
// TODO: Figure out a way to let this error pass, if `source` is set in `animatedProps` that should be okay even if it is not set in normal props!!
// @ts-expect-error it should fail because `source` is a required prop, even though animatedProps sets it
const test2 = <AnimatedImage animatedProps={aps}/>;
// should pass because source is set
const test3 = <AnimatedImage source={{ uri: 'whatever' }}/>;
// should pass because source is set and `animatedProps` doesn't change that
const test4 = <AnimatedImage source={{ uri: 'whatever' }} animatedProps={ap}/>;
// TODO: Should this test fail? Setting it twice might not be intentional...
// should pass because source is set normally and in `animatedProps`
const test5 = <AnimatedImage source={{ uri: 'whatever' }} animatedProps={aps}/>;
}