UNPKG

3.88 kBPlain TextView Raw
1'use strict';
2import { defineAnimation, getReduceMotionForAnimation } from './util';
3import type {
4 Animation,
5 Timestamp,
6 AnimatableValue,
7 AnimationObject,
8 ReduceMotion,
9} from '../commonTypes';
10import type { DelayAnimation } from './commonTypes';
11
12// TODO TYPESCRIPT This is a temporary type to get rid of .d.ts file.
13type withDelayType = <T extends AnimatableValue>(
14 delayMs: number,
15 delayedAnimation: T,
16 reduceMotion?: ReduceMotion
17) => T;
18
19/**
20 * An animation modifier that lets you start an animation with a delay.
21 *
22 * @param delayMs - Duration (in milliseconds) before the animation starts.
23 * @param nextAnimation - The animation to delay.
24 * @param reduceMotion - Determines how the animation responds to the device's reduced motion accessibility setting. Default to `ReduceMotion.System` - {@link ReduceMotion}.
25 * @returns An [animation object](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/glossary#animation-object) which holds the current state of the animation.
26 * @see https://docs.swmansion.com/react-native-reanimated/docs/animations/withDelay
27 */
28export const withDelay = function <T extends AnimationObject>(
29 delayMs: number,
30 _nextAnimation: T | (() => T),
31 reduceMotion?: ReduceMotion
32): Animation<DelayAnimation> {
33 'worklet';
34 return defineAnimation<DelayAnimation, T>(
35 _nextAnimation,
36 (): DelayAnimation => {
37 'worklet';
38 const nextAnimation =
39 typeof _nextAnimation === 'function'
40 ? _nextAnimation()
41 : _nextAnimation;
42
43 function delay(animation: DelayAnimation, now: Timestamp): boolean {
44 const { startTime, started, previousAnimation } = animation;
45 const current: AnimatableValue = animation.current;
46
47 if (now - startTime > delayMs || animation.reduceMotion) {
48 if (!started) {
49 nextAnimation.onStart(
50 nextAnimation,
51 current,
52 now,
53 previousAnimation!
54 );
55 animation.previousAnimation = null;
56 animation.started = true;
57 }
58 const finished = nextAnimation.onFrame(nextAnimation, now);
59 animation.current = nextAnimation.current!;
60 return finished;
61 } else if (previousAnimation) {
62 const finished =
63 previousAnimation.finished ||
64 previousAnimation.onFrame(previousAnimation, now);
65 animation.current = previousAnimation.current;
66 if (finished) {
67 animation.previousAnimation = null;
68 }
69 }
70 return false;
71 }
72
73 function onStart(
74 animation: Animation<any>,
75 value: AnimatableValue,
76 now: Timestamp,
77 previousAnimation: Animation<any> | null
78 ): void {
79 animation.startTime = now;
80 animation.started = false;
81 animation.current = value;
82 if (previousAnimation === animation) {
83 animation.previousAnimation = previousAnimation.previousAnimation;
84 } else {
85 animation.previousAnimation = previousAnimation;
86 }
87
88 // child animations inherit the setting, unless they already have it defined
89 // they will have it defined only if the user used the `reduceMotion` prop
90 if (nextAnimation.reduceMotion === undefined) {
91 nextAnimation.reduceMotion = animation.reduceMotion;
92 }
93 }
94
95 const callback = (finished?: boolean): void => {
96 if (nextAnimation.callback) {
97 nextAnimation.callback(finished);
98 }
99 };
100
101 return {
102 isHigherOrder: true,
103 onFrame: delay,
104 onStart,
105 current: nextAnimation.current!,
106 callback,
107 previousAnimation: null,
108 startTime: 0,
109 started: false,
110 reduceMotion: getReduceMotionForAnimation(reduceMotion),
111 };
112 }
113 );
114} as withDelayType;