UNPKG

3.63 kBPlain TextView Raw
1'use strict';
2import { defineAnimation, getReduceMotionForAnimation } from '../util';
3import type {
4 AnimationCallback,
5 Timestamp,
6 Animation,
7} from '../../commonTypes';
8import { rubberBandDecay } from './rubberBandDecay';
9import { isValidRubberBandConfig } from './utils';
10import type {
11 DecayAnimation,
12 DecayConfig,
13 DefaultDecayConfig,
14 InnerDecayAnimation,
15} from './utils';
16import { rigidDecay } from './rigidDecay';
17
18export type WithDecayConfig = DecayConfig;
19
20// TODO TYPESCRIPT This is a temporary type to get rid of .d.ts file.
21type withDecayType = (
22 userConfig: DecayConfig,
23 callback?: AnimationCallback
24) => number;
25
26function validateConfig(config: DefaultDecayConfig): void {
27 'worklet';
28 if (config.clamp) {
29 if (!Array.isArray(config.clamp)) {
30 throw new Error(
31 `[Reanimated] \`config.clamp\` must be an array but is ${typeof config.clamp}.`
32 );
33 }
34 if (config.clamp.length !== 2) {
35 throw new Error(
36 `[Reanimated] \`clamp array\` must contain 2 items but is given ${
37 config.clamp.length as number
38 }.`
39 );
40 }
41 }
42 if (config.velocityFactor <= 0) {
43 throw new Error(
44 `[Reanimated] \`config.velocityFactor\` must be greather then 0 but is ${config.velocityFactor}.`
45 );
46 }
47 if (config.rubberBandEffect && !config.clamp) {
48 throw new Error(
49 '[Reanimated] You need to set `clamp` property when using `rubberBandEffect`.'
50 );
51 }
52}
53
54/**
55 * Lets you create animations that mimic objects in motion with friction.
56 *
57 * @param config - The decay animation configuration - {@link DecayConfig}.
58 * @param callback - A function called upon animation completion - {@link AnimationCallback}.
59 * @returns An [animation object](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/glossary#animation-object) which holds the current state of the animation.
60 * @see https://docs.swmansion.com/react-native-reanimated/docs/animations/withDecay
61 */
62export const withDecay = function (
63 userConfig: DecayConfig,
64 callback?: AnimationCallback
65): Animation<DecayAnimation> {
66 'worklet';
67
68 return defineAnimation<DecayAnimation>(0, () => {
69 'worklet';
70 const config: DefaultDecayConfig = {
71 deceleration: 0.998,
72 velocityFactor: 1,
73 velocity: 0,
74 rubberBandFactor: 0.6,
75 };
76 if (userConfig) {
77 Object.keys(userConfig).forEach(
78 (key) =>
79 ((config as any)[key] = userConfig[key as keyof typeof userConfig])
80 );
81 }
82
83 const decay: (animation: InnerDecayAnimation, now: number) => boolean =
84 isValidRubberBandConfig(config)
85 ? (animation, now) => rubberBandDecay(animation, now, config)
86 : (animation, now) => rigidDecay(animation, now, config);
87
88 function onStart(
89 animation: DecayAnimation,
90 value: number,
91 now: Timestamp
92 ): void {
93 animation.current = value;
94 animation.lastTimestamp = now;
95 animation.startTimestamp = now;
96 animation.initialVelocity = config.velocity;
97 validateConfig(config);
98
99 if (animation.reduceMotion && config.clamp) {
100 if (value < config.clamp[0]) {
101 animation.current = config.clamp[0];
102 } else if (value > config.clamp[1]) {
103 animation.current = config.clamp[1];
104 }
105 }
106 }
107
108 return {
109 onFrame: decay,
110 onStart,
111 callback,
112 velocity: config.velocity ?? 0,
113 initialVelocity: 0,
114 current: 0,
115 lastTimestamp: 0,
116 startTimestamp: 0,
117 reduceMotion: getReduceMotionForAnimation(config.reduceMotion),
118 } as DecayAnimation;
119 });
120} as unknown as withDecayType;
121
\No newline at end of file