@tamagui/animations-reanimated 2.0.0-rc.9 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/createAnimations.cjs +573 -323
- package/dist/cjs/createAnimations.native.js +680 -405
- package/dist/cjs/createAnimations.native.js.map +1 -1
- package/dist/cjs/index.cjs +7 -5
- package/dist/cjs/index.native.js +7 -5
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/esm/createAnimations.mjs +546 -298
- package/dist/esm/createAnimations.mjs.map +1 -1
- package/dist/esm/createAnimations.native.js +653 -380
- package/dist/esm/createAnimations.native.js.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -6
- package/package.json +9 -9
- package/src/createAnimations.tsx +493 -207
- package/types/createAnimations.d.ts.map +4 -4
- package/types/index.d.ts.map +2 -2
- package/dist/cjs/createAnimations.js +0 -376
- package/dist/cjs/createAnimations.js.map +0 -6
- package/dist/cjs/index.js +0 -15
- package/dist/cjs/index.js.map +0 -6
- package/dist/esm/createAnimations.js +0 -376
- package/dist/esm/createAnimations.js.map +0 -6
|
@@ -1,143 +1,263 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getSplitStyles, hooks, isWeb, Text, useComposedRefs, useIsomorphicLayoutEffect, useThemeWithState, View } from "@tamagui/core";
|
|
1
|
+
import { getEffectiveAnimation, normalizeTransition } from "@tamagui/animation-helpers";
|
|
2
|
+
import { getSplitStyles, hooks, isWeb, Text, useComposedRefs, useEvent, useIsomorphicLayoutEffect, useThemeWithState, View } from "@tamagui/core";
|
|
3
3
|
import { ResetPresence, usePresence } from "@tamagui/use-presence";
|
|
4
4
|
import React, { forwardRef, useMemo, useRef } from "react";
|
|
5
|
-
import Animated_, { cancelAnimation, runOnJS, useAnimatedReaction, useAnimatedStyle, useDerivedValue, useSharedValue, withDelay, withSpring, withTiming } from "react-native-reanimated";
|
|
5
|
+
import Animated_, { cancelAnimation, runOnJS, runOnUI, useAnimatedReaction, useAnimatedStyle, useDerivedValue, useSharedValue, withDelay, withSpring, withTiming } from "react-native-reanimated";
|
|
6
6
|
import { jsx } from "react/jsx-runtime";
|
|
7
7
|
const getDefaultExport = module => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
const mod = module;
|
|
9
|
+
if (mod.__esModule || mod[Symbol.toStringTag] === "Module") {
|
|
10
|
+
return mod.default || mod;
|
|
11
|
+
}
|
|
12
|
+
return mod;
|
|
13
|
+
};
|
|
14
|
+
const Animated = getDefaultExport(Animated_);
|
|
15
|
+
const silenceAnimatedComponentDevCheck = style => {
|
|
16
|
+
if (process.env.NODE_ENV !== "development" || isWeb || !style || typeof style !== "object") {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(style, "_requiresAnimatedComponent", {
|
|
20
|
+
configurable: true,
|
|
21
|
+
enumerable: false,
|
|
22
|
+
value: true
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
const resolveDynamicValue = (value, isDark) => {
|
|
26
|
+
if (value !== null && typeof value === "object" && "dynamic" in value && typeof value.dynamic === "object") {
|
|
27
|
+
const dynamic = value.dynamic;
|
|
28
|
+
return isDark ? dynamic.dark : dynamic.light;
|
|
29
|
+
}
|
|
30
|
+
return value;
|
|
31
|
+
};
|
|
32
|
+
const cloneAnimationValue = value => {
|
|
33
|
+
if (Array.isArray(value)) {
|
|
34
|
+
return value.map(cloneAnimationValue);
|
|
35
|
+
}
|
|
36
|
+
if (value && typeof value === "object") {
|
|
37
|
+
const next = {};
|
|
38
|
+
for (const key in value) {
|
|
39
|
+
next[key] = cloneAnimationValue(value[key]);
|
|
16
40
|
}
|
|
17
|
-
return
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
41
|
+
return next;
|
|
42
|
+
}
|
|
43
|
+
return value;
|
|
44
|
+
};
|
|
45
|
+
const cloneTransitionConfig = config => {
|
|
46
|
+
return cloneAnimationValue(config);
|
|
47
|
+
};
|
|
48
|
+
const createReanimatedConfig = config => {
|
|
49
|
+
"worklet";
|
|
21
50
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
51
|
+
const next = {};
|
|
52
|
+
const source = config;
|
|
53
|
+
for (const key in source) {
|
|
54
|
+
if (key === "type" || key === "delay") continue;
|
|
55
|
+
const value = source[key];
|
|
56
|
+
if (value !== void 0) {
|
|
57
|
+
next[key] = value;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return next;
|
|
61
|
+
};
|
|
62
|
+
const applyAnimation = (targetValue, config, callback) => {
|
|
63
|
+
"worklet";
|
|
64
|
+
|
|
65
|
+
const delay = config.delay;
|
|
66
|
+
const reanimatedConfig = createReanimatedConfig(config);
|
|
67
|
+
let animatedValue;
|
|
68
|
+
if (config.type === "timing") {
|
|
69
|
+
animatedValue = withTiming(targetValue, reanimatedConfig, callback);
|
|
70
|
+
} else {
|
|
71
|
+
animatedValue = withSpring(targetValue, reanimatedConfig, callback);
|
|
72
|
+
}
|
|
73
|
+
if (delay && delay > 0) {
|
|
74
|
+
animatedValue = withDelay(delay, animatedValue);
|
|
75
|
+
}
|
|
76
|
+
return animatedValue;
|
|
77
|
+
};
|
|
78
|
+
const ANIMATABLE_PROPERTIES = {
|
|
79
|
+
// Transform
|
|
80
|
+
transform: true,
|
|
81
|
+
// Opacity
|
|
82
|
+
opacity: true,
|
|
83
|
+
// Dimensions
|
|
84
|
+
height: true,
|
|
85
|
+
width: true,
|
|
86
|
+
minWidth: true,
|
|
87
|
+
minHeight: true,
|
|
88
|
+
maxWidth: true,
|
|
89
|
+
maxHeight: true,
|
|
90
|
+
// Background
|
|
91
|
+
backgroundColor: true,
|
|
92
|
+
// Border colors
|
|
93
|
+
borderColor: true,
|
|
94
|
+
borderLeftColor: true,
|
|
95
|
+
borderRightColor: true,
|
|
96
|
+
borderTopColor: true,
|
|
97
|
+
borderBottomColor: true,
|
|
98
|
+
// Border radius
|
|
99
|
+
borderRadius: true,
|
|
100
|
+
borderTopLeftRadius: true,
|
|
101
|
+
borderTopRightRadius: true,
|
|
102
|
+
borderBottomLeftRadius: true,
|
|
103
|
+
borderBottomRightRadius: true,
|
|
104
|
+
// Border width
|
|
105
|
+
borderWidth: true,
|
|
106
|
+
borderLeftWidth: true,
|
|
107
|
+
borderRightWidth: true,
|
|
108
|
+
borderTopWidth: true,
|
|
109
|
+
borderBottomWidth: true,
|
|
110
|
+
// Text
|
|
111
|
+
color: true,
|
|
112
|
+
fontSize: true,
|
|
113
|
+
fontWeight: true,
|
|
114
|
+
lineHeight: true,
|
|
115
|
+
letterSpacing: true,
|
|
116
|
+
// Position
|
|
117
|
+
left: true,
|
|
118
|
+
right: true,
|
|
119
|
+
top: true,
|
|
120
|
+
bottom: true,
|
|
121
|
+
// Margin
|
|
122
|
+
margin: true,
|
|
123
|
+
marginTop: true,
|
|
124
|
+
marginBottom: true,
|
|
125
|
+
marginLeft: true,
|
|
126
|
+
marginRight: true,
|
|
127
|
+
marginHorizontal: true,
|
|
128
|
+
marginVertical: true,
|
|
129
|
+
// Padding
|
|
130
|
+
padding: true,
|
|
131
|
+
paddingTop: true,
|
|
132
|
+
paddingBottom: true,
|
|
133
|
+
paddingLeft: true,
|
|
134
|
+
paddingRight: true,
|
|
135
|
+
paddingHorizontal: true,
|
|
136
|
+
paddingVertical: true,
|
|
137
|
+
// Flex/Gap
|
|
138
|
+
gap: true,
|
|
139
|
+
rowGap: true,
|
|
140
|
+
columnGap: true,
|
|
141
|
+
flex: true,
|
|
142
|
+
flexGrow: true,
|
|
143
|
+
flexShrink: true
|
|
144
|
+
};
|
|
145
|
+
const canAnimateProperty = (key, value, animateOnly) => {
|
|
146
|
+
if (!ANIMATABLE_PROPERTIES[key]) return false;
|
|
147
|
+
if (value === "auto") return false;
|
|
148
|
+
if (typeof value === "string" && value.startsWith("calc")) return false;
|
|
149
|
+
if (animateOnly && !animateOnly.includes(key)) return false;
|
|
150
|
+
return true;
|
|
151
|
+
};
|
|
94
152
|
function createWebAnimatedComponent(defaultTag) {
|
|
95
|
-
const isText = defaultTag === "span"
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
153
|
+
const isText = defaultTag === "span";
|
|
154
|
+
const Component = Animated.createAnimatedComponent(forwardRef((propsIn, ref) => {
|
|
155
|
+
const {
|
|
156
|
+
forwardedRef,
|
|
157
|
+
render = defaultTag,
|
|
158
|
+
...rest
|
|
159
|
+
} = propsIn;
|
|
160
|
+
const hostRef = useRef(null);
|
|
161
|
+
const composedRefs = useComposedRefs(forwardedRef, ref, hostRef);
|
|
162
|
+
const stateRef = useRef({
|
|
163
|
+
get host() {
|
|
164
|
+
return hostRef.current;
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
const [, themeState] = useThemeWithState({});
|
|
168
|
+
const result = getSplitStyles(rest, isText ? Text.staticConfig : View.staticConfig, themeState?.theme ?? {}, themeState?.name ?? "", {
|
|
169
|
+
unmounted: false
|
|
170
|
+
}, {
|
|
171
|
+
isAnimated: false,
|
|
172
|
+
noClass: true
|
|
173
|
+
});
|
|
174
|
+
const viewProps = result?.viewProps ?? {};
|
|
175
|
+
const Element = render;
|
|
176
|
+
const transformedProps = hooks.usePropsTransform?.(render, viewProps, stateRef, false);
|
|
177
|
+
return /* @__PURE__ */jsx(Element, {
|
|
178
|
+
...transformedProps,
|
|
179
|
+
ref: composedRefs
|
|
180
|
+
});
|
|
181
|
+
}));
|
|
182
|
+
Component.acceptRenderProp = true;
|
|
183
|
+
return Component;
|
|
184
|
+
}
|
|
185
|
+
const AnimatedView = createWebAnimatedComponent("div");
|
|
186
|
+
const AnimatedText = createWebAnimatedComponent("span");
|
|
187
|
+
function buildTransitionConfig(transition, animations, animationState, styleKeys) {
|
|
188
|
+
const normalized = normalizeTransition(transition);
|
|
189
|
+
const effectiveKey = getEffectiveAnimation(normalized, animationState);
|
|
190
|
+
let base = cloneTransitionConfig(effectiveKey ? animations[effectiveKey] ?? {
|
|
191
|
+
type: "spring"
|
|
192
|
+
} : {
|
|
193
|
+
type: "spring"
|
|
194
|
+
});
|
|
195
|
+
if (normalized.delay) {
|
|
196
|
+
base = cloneTransitionConfig({
|
|
197
|
+
...base,
|
|
198
|
+
delay: normalized.delay
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
if (normalized.config) {
|
|
202
|
+
base = cloneTransitionConfig({
|
|
203
|
+
...base,
|
|
204
|
+
...normalized.config
|
|
205
|
+
});
|
|
206
|
+
if (base.type !== "timing" && normalized.config.duration !== void 0 && normalized.config.damping === void 0 && normalized.config.stiffness === void 0 && normalized.config.mass === void 0) {
|
|
207
|
+
base = cloneTransitionConfig({
|
|
208
|
+
...base,
|
|
209
|
+
type: "timing"
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
const propertyConfigs = {};
|
|
214
|
+
for (const key of styleKeys) {
|
|
215
|
+
const propAnimation = normalized.properties[key];
|
|
216
|
+
if (typeof propAnimation === "string") {
|
|
217
|
+
propertyConfigs[key] = cloneTransitionConfig(animations[propAnimation] ?? base);
|
|
218
|
+
} else if (propAnimation && typeof propAnimation === "object") {
|
|
219
|
+
const configType = propAnimation.type;
|
|
220
|
+
const baseForProp = configType ? animations[configType] ?? base : base;
|
|
221
|
+
propertyConfigs[key] = cloneTransitionConfig({
|
|
222
|
+
...baseForProp,
|
|
223
|
+
...propAnimation
|
|
121
224
|
});
|
|
122
|
-
}
|
|
123
|
-
|
|
225
|
+
} else {
|
|
226
|
+
propertyConfigs[key] = cloneTransitionConfig(base);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
baseConfig: base,
|
|
231
|
+
propertyConfigs
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function getStyleKeys(style) {
|
|
235
|
+
const keys = new Set(Object.keys(style));
|
|
236
|
+
if (style.transform && Array.isArray(style.transform)) {
|
|
237
|
+
for (const t of style.transform) {
|
|
238
|
+
if (t && typeof t === "object") {
|
|
239
|
+
keys.add(Object.keys(t)[0]);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return keys;
|
|
124
244
|
}
|
|
125
|
-
const AnimatedView = createWebAnimatedComponent("div"),
|
|
126
|
-
AnimatedText = createWebAnimatedComponent("span");
|
|
127
245
|
function createAnimations(animationsConfig) {
|
|
128
246
|
const animations = {};
|
|
129
|
-
for (const key in animationsConfig)
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
247
|
+
for (const key in animationsConfig) {
|
|
248
|
+
animations[key] = cloneTransitionConfig({
|
|
249
|
+
type: "spring",
|
|
250
|
+
...animationsConfig[key]
|
|
251
|
+
});
|
|
252
|
+
}
|
|
133
253
|
return {
|
|
254
|
+
needsCustomComponent: true,
|
|
134
255
|
View: isWeb ? AnimatedView : Animated.View,
|
|
135
256
|
Text: isWeb ? AnimatedText : Animated.Text,
|
|
136
|
-
isReactNative:
|
|
137
|
-
supportsCSS: !1,
|
|
257
|
+
isReactNative: true,
|
|
138
258
|
inputStyle: "value",
|
|
139
259
|
outputStyle: "inline",
|
|
140
|
-
avoidReRenders:
|
|
260
|
+
avoidReRenders: true,
|
|
141
261
|
animations,
|
|
142
262
|
usePresence,
|
|
143
263
|
ResetPresence,
|
|
@@ -160,18 +280,28 @@ function createAnimations(animationsConfig) {
|
|
|
160
280
|
setValue(next, config = {
|
|
161
281
|
type: "spring"
|
|
162
282
|
}, onFinish) {
|
|
163
|
-
"
|
|
283
|
+
if (config.type === "direct") {
|
|
284
|
+
sharedValue.value = next;
|
|
285
|
+
onFinish?.();
|
|
286
|
+
} else {
|
|
287
|
+
const cb = onFinish ? () => {
|
|
288
|
+
"worklet";
|
|
164
289
|
|
|
165
|
-
|
|
166
|
-
|
|
290
|
+
runOnJS(onFinish)();
|
|
291
|
+
} : void 0;
|
|
292
|
+
const animationConfig = cloneTransitionConfig(config);
|
|
293
|
+
if (isWeb) {
|
|
294
|
+
sharedValue.value = applyAnimation(next, animationConfig, cb);
|
|
295
|
+
} else {
|
|
296
|
+
runOnUI((targetValue, animationConfig2) => {
|
|
297
|
+
"worklet";
|
|
167
298
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
299
|
+
sharedValue.value = applyAnimation(targetValue, animationConfig2, cb);
|
|
300
|
+
})(next, animationConfig);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
171
303
|
},
|
|
172
304
|
stop() {
|
|
173
|
-
"worklet";
|
|
174
|
-
|
|
175
305
|
cancelAnimation(sharedValue);
|
|
176
306
|
}
|
|
177
307
|
}), [sharedValue]);
|
|
@@ -184,193 +314,295 @@ function createAnimations(animationsConfig) {
|
|
|
184
314
|
}, onValue) {
|
|
185
315
|
const instance = value.getInstance();
|
|
186
316
|
return useAnimatedReaction(() => instance.value, (next, prev) => {
|
|
187
|
-
prev !== next
|
|
317
|
+
if (prev !== next) {
|
|
318
|
+
runOnJS(onValue)(next);
|
|
319
|
+
}
|
|
188
320
|
}, [onValue, instance]);
|
|
189
321
|
},
|
|
190
322
|
// =========================================================================
|
|
191
323
|
// useAnimatedNumberStyle - Create animated styles from values
|
|
192
324
|
// =========================================================================
|
|
193
325
|
useAnimatedNumberStyle(val, getStyle) {
|
|
194
|
-
const instance = val.getInstance()
|
|
195
|
-
|
|
196
|
-
|
|
326
|
+
const instance = val.getInstance();
|
|
327
|
+
if (isWeb) {
|
|
328
|
+
return useAnimatedStyle(() => {
|
|
329
|
+
"worklet";
|
|
330
|
+
|
|
331
|
+
return getStyle(instance.value);
|
|
332
|
+
}, [instance, getStyle]);
|
|
333
|
+
}
|
|
334
|
+
const styleVal = useDerivedValue(() => {
|
|
335
|
+
"worklet";
|
|
336
|
+
|
|
337
|
+
return getStyle(instance.value);
|
|
338
|
+
});
|
|
339
|
+
const animatedStyle = useAnimatedStyle(() => {
|
|
340
|
+
"worklet";
|
|
341
|
+
|
|
342
|
+
return styleVal.value;
|
|
343
|
+
});
|
|
344
|
+
silenceAnimatedComponentDevCheck(animatedStyle);
|
|
345
|
+
return animatedStyle;
|
|
346
|
+
},
|
|
347
|
+
useAnimatedNumbersStyle(vals, getStyle) {
|
|
348
|
+
const instances = vals.map(v => v.getInstance());
|
|
349
|
+
const animatedStyle = useAnimatedStyle(() => {
|
|
350
|
+
"worklet";
|
|
351
|
+
|
|
352
|
+
const currentValues = instances.map(inst => inst.value);
|
|
353
|
+
return getStyle(...currentValues);
|
|
354
|
+
}, isWeb ? [getStyle, ...instances] : void 0);
|
|
355
|
+
silenceAnimatedComponentDevCheck(animatedStyle);
|
|
356
|
+
return animatedStyle;
|
|
197
357
|
},
|
|
198
358
|
// =========================================================================
|
|
199
359
|
// useAnimations - Main animation hook for components
|
|
200
360
|
// =========================================================================
|
|
201
361
|
useAnimations(animationProps) {
|
|
202
362
|
const {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
363
|
+
props,
|
|
364
|
+
presence,
|
|
365
|
+
style,
|
|
366
|
+
componentState,
|
|
367
|
+
useStyleEmitter,
|
|
368
|
+
themeName,
|
|
369
|
+
stateRef,
|
|
370
|
+
styleState
|
|
371
|
+
} = animationProps;
|
|
372
|
+
const isHydrating = componentState.unmounted === true;
|
|
373
|
+
const isMounting = componentState.unmounted === "should-enter";
|
|
374
|
+
const isEntering = !!componentState.unmounted;
|
|
375
|
+
const isExiting = presence?.[0] === false;
|
|
376
|
+
const wasEnteringRef = useRef(isEntering);
|
|
377
|
+
const justFinishedEntering = wasEnteringRef.current && !isEntering;
|
|
216
378
|
React.useEffect(() => {
|
|
217
379
|
wasEnteringRef.current = isEntering;
|
|
218
380
|
});
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
381
|
+
const effectiveTransition = styleState?.effectiveTransition ?? props.transition;
|
|
382
|
+
const normalized = normalizeTransition(effectiveTransition);
|
|
383
|
+
const animationState = isExiting ? "exit" : isMounting || justFinishedEntering ? "enter" : "default";
|
|
384
|
+
const animationKey = getEffectiveAnimation(normalized, animationState);
|
|
385
|
+
const disableAnimation = isHydrating || !animationKey;
|
|
386
|
+
const isDark = themeName?.startsWith("dark") || false;
|
|
387
|
+
const sendExitComplete = presence?.[1];
|
|
388
|
+
const exitCycleIdRef = useRef(0);
|
|
389
|
+
const pendingExitKeysRef = useRef(/* @__PURE__ */new Set());
|
|
390
|
+
const exitCompletedRef = useRef(false);
|
|
391
|
+
const wasExitingRef = useRef(false);
|
|
392
|
+
const justStartedExiting = isExiting && !wasExitingRef.current;
|
|
393
|
+
const justStoppedExiting = !isExiting && wasExitingRef.current;
|
|
394
|
+
const markExitKeyDone = useEvent((key, cycleId, finished) => {
|
|
395
|
+
if (cycleId !== exitCycleIdRef.current) return;
|
|
396
|
+
if (exitCompletedRef.current) return;
|
|
397
|
+
pendingExitKeysRef.current.delete(key);
|
|
398
|
+
if (pendingExitKeysRef.current.size === 0) {
|
|
399
|
+
exitCompletedRef.current = true;
|
|
400
|
+
sendExitComplete?.();
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
const isExitingRef = useSharedValue(isExiting);
|
|
404
|
+
const exitCycleIdShared = useSharedValue(exitCycleIdRef.current);
|
|
405
|
+
if (justStartedExiting) {
|
|
406
|
+
exitCycleIdRef.current++;
|
|
407
|
+
exitCompletedRef.current = false;
|
|
408
|
+
pendingExitKeysRef.current.clear();
|
|
409
|
+
}
|
|
410
|
+
if (justStoppedExiting) {
|
|
411
|
+
exitCycleIdRef.current++;
|
|
412
|
+
pendingExitKeysRef.current.clear();
|
|
413
|
+
}
|
|
414
|
+
useIsomorphicLayoutEffect(() => {
|
|
415
|
+
isExitingRef.value = isExiting;
|
|
416
|
+
exitCycleIdShared.value = exitCycleIdRef.current;
|
|
417
|
+
}, [isExiting, exitCycleIdRef.current]);
|
|
418
|
+
React.useEffect(() => {
|
|
419
|
+
wasExitingRef.current = isExiting;
|
|
420
|
+
});
|
|
421
|
+
const animatedTargetsRef = useSharedValue(null);
|
|
422
|
+
const staticTargetsRef = useSharedValue(null);
|
|
423
|
+
const transformTargetsRef = useSharedValue(null);
|
|
424
|
+
const {
|
|
425
|
+
animatedStyles,
|
|
426
|
+
staticStyles
|
|
427
|
+
} = useMemo(() => {
|
|
428
|
+
const animated = {};
|
|
429
|
+
const staticStyles2 = {};
|
|
430
|
+
const animateOnly = props.animateOnly;
|
|
431
|
+
for (const key in style) {
|
|
432
|
+
const rawValue = style[key];
|
|
433
|
+
const value = resolveDynamicValue(rawValue, isDark);
|
|
434
|
+
if (value === void 0) continue;
|
|
435
|
+
if (disableAnimation) {
|
|
436
|
+
staticStyles2[key] = cloneAnimationValue(value);
|
|
437
|
+
continue;
|
|
246
438
|
}
|
|
247
|
-
if (
|
|
439
|
+
if (canAnimateProperty(key, value, animateOnly)) {
|
|
440
|
+
animated[key] = cloneAnimationValue(value);
|
|
441
|
+
} else {
|
|
442
|
+
staticStyles2[key] = cloneAnimationValue(value);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (isMounting) {
|
|
446
|
+
for (const key in animated) {
|
|
447
|
+
staticStyles2[key] = animated[key];
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return {
|
|
451
|
+
animatedStyles: animated,
|
|
452
|
+
staticStyles: staticStyles2
|
|
453
|
+
};
|
|
454
|
+
}, [disableAnimation, style, isDark, isMounting, props.animateOnly]);
|
|
455
|
+
const {
|
|
456
|
+
baseConfig,
|
|
457
|
+
propertyConfigs
|
|
458
|
+
} = useMemo(() => {
|
|
459
|
+
if (isHydrating) {
|
|
248
460
|
return {
|
|
249
|
-
animatedStyles: animated,
|
|
250
|
-
staticStyles: staticStyles2
|
|
251
|
-
};
|
|
252
|
-
}, [disableAnimation, style, isDark, isMounting, props.animateOnly]),
|
|
253
|
-
{
|
|
254
|
-
baseConfig,
|
|
255
|
-
propertyConfigs
|
|
256
|
-
} = useMemo(() => {
|
|
257
|
-
if (isHydrating) return {
|
|
258
461
|
baseConfig: {
|
|
259
462
|
type: "timing",
|
|
260
463
|
duration: 0
|
|
261
464
|
},
|
|
262
465
|
propertyConfigs: {}
|
|
263
466
|
};
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
delay: normalized2.delay
|
|
274
|
-
}), normalized2.config && (base = {
|
|
275
|
-
...base,
|
|
276
|
-
...normalized2.config
|
|
277
|
-
});
|
|
278
|
-
const overrides = {};
|
|
279
|
-
for (const key in normalized2.properties) {
|
|
280
|
-
const animationNameOrConfig = normalized2.properties[key];
|
|
281
|
-
if (typeof animationNameOrConfig == "string") overrides[key] = animations[animationNameOrConfig] ?? base;else if (animationNameOrConfig && typeof animationNameOrConfig == "object") {
|
|
282
|
-
const configType = animationNameOrConfig.type,
|
|
283
|
-
baseForProp = configType ? animations[configType] ?? base : base;
|
|
284
|
-
overrides[key] = {
|
|
285
|
-
...baseForProp,
|
|
286
|
-
...animationNameOrConfig
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
const configs = {},
|
|
291
|
-
allKeys = new Set(Object.keys(animatedStyles));
|
|
292
|
-
if (animatedStyles.transform && Array.isArray(animatedStyles.transform)) for (const t of animatedStyles.transform) allKeys.add(Object.keys(t)[0]);
|
|
293
|
-
for (const key of allKeys) configs[key] = overrides[key] ?? base;
|
|
294
|
-
return {
|
|
295
|
-
baseConfig: base,
|
|
296
|
-
propertyConfigs: configs
|
|
297
|
-
};
|
|
298
|
-
}, [isHydrating, props.transition, animatedStyles, animationState]),
|
|
299
|
-
configRef = useSharedValue({
|
|
300
|
-
baseConfig,
|
|
301
|
-
propertyConfigs,
|
|
302
|
-
disableAnimation,
|
|
303
|
-
isHydrating
|
|
304
|
-
});
|
|
467
|
+
}
|
|
468
|
+
return buildTransitionConfig(props.transition, animations, animationState, getStyleKeys(animatedStyles));
|
|
469
|
+
}, [isHydrating, props.transition, animatedStyles, animationState]);
|
|
470
|
+
const configRef = useSharedValue({
|
|
471
|
+
baseConfig,
|
|
472
|
+
propertyConfigs,
|
|
473
|
+
disableAnimation,
|
|
474
|
+
isHydrating
|
|
475
|
+
});
|
|
305
476
|
useIsomorphicLayoutEffect(() => {
|
|
306
|
-
configRef.
|
|
477
|
+
configRef.value = {
|
|
307
478
|
baseConfig,
|
|
308
479
|
propertyConfigs,
|
|
309
480
|
disableAnimation,
|
|
310
481
|
isHydrating
|
|
311
|
-
}
|
|
312
|
-
}, [baseConfig, propertyConfigs, disableAnimation, isHydrating])
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
482
|
+
};
|
|
483
|
+
}, [baseConfig, propertyConfigs, disableAnimation, isHydrating]);
|
|
484
|
+
useStyleEmitter?.((nextStyle, effectiveTransition2) => {
|
|
485
|
+
const animateOnly = props.animateOnly;
|
|
486
|
+
const animated = {};
|
|
487
|
+
const statics = {};
|
|
488
|
+
const transforms = [];
|
|
489
|
+
const transitionToUse = effectiveTransition2 ?? props.transition;
|
|
490
|
+
const {
|
|
491
|
+
baseConfig: newBase,
|
|
492
|
+
propertyConfigs: newPropertyConfigs
|
|
493
|
+
} = buildTransitionConfig(transitionToUse, animations, animationState, getStyleKeys(nextStyle));
|
|
494
|
+
configRef.value = {
|
|
495
|
+
baseConfig: newBase,
|
|
496
|
+
propertyConfigs: newPropertyConfigs,
|
|
497
|
+
disableAnimation: configRef.value.disableAnimation,
|
|
498
|
+
isHydrating: configRef.value.isHydrating
|
|
499
|
+
};
|
|
317
500
|
for (const key in nextStyle) {
|
|
318
|
-
const rawValue = nextStyle[key]
|
|
319
|
-
|
|
320
|
-
if (value
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
501
|
+
const rawValue = nextStyle[key];
|
|
502
|
+
const value = resolveDynamicValue(rawValue, isDark);
|
|
503
|
+
if (value == void 0) continue;
|
|
504
|
+
if (configRef.value.disableAnimation) {
|
|
505
|
+
statics[key] = cloneAnimationValue(value);
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
508
|
+
if (key === "transform" && Array.isArray(value)) {
|
|
509
|
+
for (const t of value) {
|
|
510
|
+
if (t && typeof t === "object") {
|
|
511
|
+
const tKey = Object.keys(t)[0];
|
|
512
|
+
const tVal = t[tKey];
|
|
513
|
+
if (typeof tVal === "number" || typeof tVal === "string") {
|
|
514
|
+
transforms.push(cloneAnimationValue(t));
|
|
515
|
+
}
|
|
516
|
+
}
|
|
324
517
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
if (canAnimateProperty(key, value, animateOnly)) {
|
|
521
|
+
animated[key] = cloneAnimationValue(value);
|
|
522
|
+
} else {
|
|
523
|
+
statics[key] = cloneAnimationValue(value);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
animatedTargetsRef.value = animated;
|
|
527
|
+
staticTargetsRef.value = statics;
|
|
528
|
+
transformTargetsRef.value = transforms;
|
|
529
|
+
if (process.env.NODE_ENV === "development" && props.debug && props.debug !== "profile") {
|
|
530
|
+
console.info("[animations-reanimated] useStyleEmitter update", {
|
|
531
|
+
animated,
|
|
532
|
+
statics,
|
|
533
|
+
transforms
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
});
|
|
537
|
+
const exitKeysRegistered = useRef(false);
|
|
538
|
+
if (justStartedExiting && sendExitComplete) {
|
|
539
|
+
const exitKeys = [];
|
|
540
|
+
const animateOnly = props.animateOnly;
|
|
541
|
+
for (const key in animatedStyles) {
|
|
542
|
+
if (key === "transform") continue;
|
|
543
|
+
if (canAnimateProperty(key, animatedStyles[key], animateOnly)) {
|
|
544
|
+
exitKeys.push(key);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
const transforms = animatedStyles.transform;
|
|
548
|
+
if (transforms && Array.isArray(transforms)) {
|
|
549
|
+
for (const t of transforms) {
|
|
550
|
+
if (!t) continue;
|
|
551
|
+
const tKey = Object.keys(t)[0];
|
|
552
|
+
if (tKey) {
|
|
553
|
+
if (animateOnly && !animateOnly.includes(tKey)) {
|
|
554
|
+
continue;
|
|
330
555
|
}
|
|
331
|
-
|
|
556
|
+
exitKeys.push(`transform:${tKey}`);
|
|
332
557
|
}
|
|
333
|
-
canAnimateProperty(key, value, animateOnly) ? animated[key] = value : statics[key] = value;
|
|
334
558
|
}
|
|
335
559
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
})) : exitProgress.set(withSpring(1, config, finished => {
|
|
349
|
-
"worklet";
|
|
350
|
-
|
|
351
|
-
finished && runOnJS(sendExitComplete)();
|
|
352
|
-
})), () => {
|
|
353
|
-
cancelAnimation(exitProgress);
|
|
354
|
-
};
|
|
355
|
-
}, [isExiting, sendExitComplete]);
|
|
560
|
+
pendingExitKeysRef.current = new Set(exitKeys);
|
|
561
|
+
exitKeysRegistered.current = exitKeys.length > 0;
|
|
562
|
+
}
|
|
563
|
+
React.useEffect(() => {
|
|
564
|
+
if (!justStartedExiting || !sendExitComplete) return;
|
|
565
|
+
if (!exitKeysRegistered.current && pendingExitKeysRef.current.size === 0) {
|
|
566
|
+
if (!exitCompletedRef.current) {
|
|
567
|
+
exitCompletedRef.current = true;
|
|
568
|
+
sendExitComplete();
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}, [justStartedExiting, sendExitComplete]);
|
|
356
572
|
const animatedStyle = useAnimatedStyle(() => {
|
|
357
573
|
"worklet";
|
|
358
574
|
|
|
359
|
-
if (disableAnimation || isHydrating)
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
575
|
+
if (disableAnimation || isHydrating) {
|
|
576
|
+
return {};
|
|
577
|
+
}
|
|
578
|
+
const result = {};
|
|
579
|
+
const config = configRef.value;
|
|
580
|
+
const emitterAnimated = animatedTargetsRef.value;
|
|
581
|
+
const emitterStatic = staticTargetsRef.value;
|
|
582
|
+
const emitterTransforms = transformTargetsRef.value;
|
|
583
|
+
const hasEmitterUpdates = emitterAnimated !== null;
|
|
584
|
+
const animatedValues = hasEmitterUpdates ? emitterAnimated : animatedStyles;
|
|
585
|
+
const staticValues = hasEmitterUpdates ? emitterStatic : {};
|
|
586
|
+
const currentlyExiting = isExitingRef.value;
|
|
587
|
+
const currentCycleId = exitCycleIdShared.value;
|
|
588
|
+
for (const key in staticValues) {
|
|
589
|
+
result[key] = staticValues[key];
|
|
590
|
+
}
|
|
369
591
|
for (const key in animatedValues) {
|
|
370
592
|
if (key === "transform") continue;
|
|
371
|
-
const targetValue = animatedValues[key]
|
|
372
|
-
|
|
373
|
-
|
|
593
|
+
const targetValue = animatedValues[key];
|
|
594
|
+
const propConfig = config.propertyConfigs[key] ?? config.baseConfig;
|
|
595
|
+
let callback;
|
|
596
|
+
if (currentlyExiting) {
|
|
597
|
+
const capturedKey = key;
|
|
598
|
+
const capturedCycleId = currentCycleId;
|
|
599
|
+
callback = finished => {
|
|
600
|
+
"worklet";
|
|
601
|
+
|
|
602
|
+
runOnJS(markExitKeyDone)(capturedKey, capturedCycleId, finished ?? false);
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
result[key] = applyAnimation(targetValue, propConfig, callback);
|
|
374
606
|
}
|
|
375
607
|
const transforms = hasEmitterUpdates ? emitterTransforms : animatedStyles.transform;
|
|
376
608
|
if (transforms && Array.isArray(transforms)) {
|
|
@@ -380,30 +612,46 @@ function createAnimations(animationsConfig) {
|
|
|
380
612
|
const keys = Object.keys(t);
|
|
381
613
|
if (keys.length === 0) continue;
|
|
382
614
|
const value = t[keys[0]];
|
|
383
|
-
if (typeof value
|
|
384
|
-
const transformKey = Object.keys(t)[0]
|
|
385
|
-
|
|
386
|
-
|
|
615
|
+
if (typeof value === "number" || typeof value === "string") {
|
|
616
|
+
const transformKey = Object.keys(t)[0];
|
|
617
|
+
const targetValue = t[transformKey];
|
|
618
|
+
const propConfig = config.propertyConfigs[transformKey] ?? config.baseConfig;
|
|
619
|
+
let callback;
|
|
620
|
+
if (currentlyExiting) {
|
|
621
|
+
const capturedKey = `transform:${transformKey}`;
|
|
622
|
+
const capturedCycleId = currentCycleId;
|
|
623
|
+
callback = finished => {
|
|
624
|
+
"worklet";
|
|
625
|
+
|
|
626
|
+
runOnJS(markExitKeyDone)(capturedKey, capturedCycleId, finished ?? false);
|
|
627
|
+
};
|
|
628
|
+
}
|
|
387
629
|
validTransforms.push({
|
|
388
|
-
[transformKey]: applyAnimation(targetValue, propConfig)
|
|
630
|
+
[transformKey]: applyAnimation(targetValue, propConfig, callback)
|
|
389
631
|
});
|
|
390
632
|
}
|
|
391
633
|
}
|
|
392
|
-
validTransforms.length > 0
|
|
634
|
+
if (validTransforms.length > 0) {
|
|
635
|
+
result.transform = validTransforms;
|
|
636
|
+
}
|
|
393
637
|
}
|
|
394
638
|
return result;
|
|
395
|
-
}, [animatedStyles, baseConfig, propertyConfigs, disableAnimation, isHydrating,
|
|
396
|
-
//
|
|
397
|
-
animatedTargetsRef, staticTargetsRef, transformTargetsRef]);
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
639
|
+
}, isWeb ? [animatedStyles, baseConfig, propertyConfigs, disableAnimation, isHydrating,
|
|
640
|
+
// pass SharedValues so the mapper watches them on web (no babel plugin)
|
|
641
|
+
animatedTargetsRef, staticTargetsRef, transformTargetsRef, isExitingRef, exitCycleIdShared, markExitKeyDone] : void 0);
|
|
642
|
+
silenceAnimatedComponentDevCheck(animatedStyle);
|
|
643
|
+
if (process.env.NODE_ENV === "development" && props.debug && props.debug !== "profile") {
|
|
644
|
+
console.info("[animations-reanimated] useAnimations", {
|
|
645
|
+
animationKey,
|
|
646
|
+
componentState,
|
|
647
|
+
isExiting,
|
|
648
|
+
animatedStyles,
|
|
649
|
+
staticStyles,
|
|
650
|
+
baseConfig,
|
|
651
|
+
propertyConfigs
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
return {
|
|
407
655
|
style: [staticStyles, animatedStyle]
|
|
408
656
|
};
|
|
409
657
|
}
|