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