1 | 'use strict';
|
2 | import { defineAnimation, getReduceMotionForAnimation } from '../util';
|
3 | import type {
|
4 | AnimationCallback,
|
5 | Timestamp,
|
6 | Animation,
|
7 | } from '../../commonTypes';
|
8 | import { rubberBandDecay } from './rubberBandDecay';
|
9 | import { isValidRubberBandConfig } from './utils';
|
10 | import type {
|
11 | DecayAnimation,
|
12 | DecayConfig,
|
13 | DefaultDecayConfig,
|
14 | InnerDecayAnimation,
|
15 | } from './utils';
|
16 | import { rigidDecay } from './rigidDecay';
|
17 |
|
18 | export type WithDecayConfig = DecayConfig;
|
19 |
|
20 |
|
21 | type withDecayType = (
|
22 | userConfig: DecayConfig,
|
23 | callback?: AnimationCallback
|
24 | ) => number;
|
25 |
|
26 | function 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 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 | export 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 |