UNPKG

3.6 kBPlain TextView Raw
1'use strict';
2import { withStyleAnimation } from '../animation/styleAnimation';
3import type { SharedValue } from '../commonTypes';
4import { makeUIMutable } from '../mutables';
5import { LayoutAnimationType } from './animationBuilder';
6import { runOnUIImmediately } from '../threads';
7import type {
8 SharedTransitionAnimationsValues,
9 LayoutAnimation,
10} from './animationBuilder/commonTypes';
11
12const TAG_OFFSET = 1e9;
13
14function startObservingProgress(
15 tag: number,
16 sharedValue: SharedValue<Record<string, unknown>>,
17 animationType: LayoutAnimationType
18): void {
19 'worklet';
20 const isSharedTransition =
21 animationType === LayoutAnimationType.SHARED_ELEMENT_TRANSITION;
22 sharedValue.addListener(tag + TAG_OFFSET, () => {
23 global._notifyAboutProgress(tag, sharedValue.value, isSharedTransition);
24 });
25}
26
27function stopObservingProgress(
28 tag: number,
29 sharedValue: SharedValue<number>,
30 removeView = false
31): void {
32 'worklet';
33 sharedValue.removeListener(tag + TAG_OFFSET);
34 global._notifyAboutEnd(tag, removeView);
35}
36
37function createLayoutAnimationManager() {
38 'worklet';
39 const currentAnimationForTag = new Map();
40 const mutableValuesForTag = new Map();
41
42 return {
43 start(
44 tag: number,
45 type: LayoutAnimationType,
46 /**
47 * createLayoutAnimationManager creates an animation manager for both Layout animations and Shared Transition Elements animations.
48 */
49 yogaValues: Partial<SharedTransitionAnimationsValues>,
50 config: (
51 arg: Partial<SharedTransitionAnimationsValues>
52 ) => LayoutAnimation
53 ) {
54 if (type === LayoutAnimationType.SHARED_ELEMENT_TRANSITION_PROGRESS) {
55 global.ProgressTransitionRegister.onTransitionStart(tag, yogaValues);
56 return;
57 }
58
59 const style = config(yogaValues);
60 let currentAnimation = style.animations;
61
62 // When layout animation is requested, but a previous one is still running, we merge
63 // new layout animation targets into the ongoing animation
64 const previousAnimation = currentAnimationForTag.get(tag);
65 if (previousAnimation) {
66 currentAnimation = { ...previousAnimation, ...style.animations };
67 }
68 currentAnimationForTag.set(tag, currentAnimation);
69
70 let value = mutableValuesForTag.get(tag);
71 if (value === undefined) {
72 value = makeUIMutable(style.initialValues);
73 mutableValuesForTag.set(tag, value);
74 } else {
75 stopObservingProgress(tag, value);
76 value._value = style.initialValues;
77 }
78
79 // @ts-ignore The line below started failing because I added types to the method – don't have time to fix it right now
80 const animation = withStyleAnimation(currentAnimation);
81
82 animation.callback = (finished?: boolean) => {
83 if (finished) {
84 currentAnimationForTag.delete(tag);
85 mutableValuesForTag.delete(tag);
86 const shouldRemoveView = type === LayoutAnimationType.EXITING;
87 stopObservingProgress(tag, value, shouldRemoveView);
88 }
89 style.callback &&
90 style.callback(finished === undefined ? false : finished);
91 };
92
93 startObservingProgress(tag, value, type);
94 value.value = animation;
95 },
96 stop(tag: number) {
97 const value = mutableValuesForTag.get(tag);
98 if (!value) {
99 return;
100 }
101 stopObservingProgress(tag, value);
102 },
103 };
104}
105
106runOnUIImmediately(() => {
107 'worklet';
108 global.LayoutAnimationsManager = createLayoutAnimationManager();
109})();
110
111export type LayoutAnimationsManager = ReturnType<
112 typeof createLayoutAnimationManager
113>;