@tamagui/animations-react-native 2.0.0-rc.4 → 2.0.0-rc.40

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.
@@ -1,56 +1,66 @@
1
- import { normalizeTransition, getEffectiveAnimation } from "@tamagui/animation-helpers";
1
+ import { getEffectiveAnimation, normalizeTransition } from "@tamagui/animation-helpers";
2
2
  import { isWeb, useIsomorphicLayoutEffect } from "@tamagui/constants";
3
3
  import { ResetPresence, usePresence } from "@tamagui/use-presence";
4
4
  import { useEvent, useThemeWithState } from "@tamagui/web";
5
5
  import React from "react";
6
6
  import { Animated } from "react-native-web";
7
- const resolveDynamicValue = (value, isDark) => value && typeof value == "object" && "dynamic" in value ? isDark ? value.dynamic.dark : value.dynamic.light : value,
8
- animatedStyleKey = {
9
- transform: !0,
10
- opacity: !0
11
- },
12
- colorStyleKey = {
13
- backgroundColor: !0,
14
- color: !0,
15
- borderColor: !0,
16
- borderLeftColor: !0,
17
- borderRightColor: !0,
18
- borderTopColor: !0,
19
- borderBottomColor: !0
20
- },
21
- costlyToAnimateStyleKey = {
22
- borderRadius: !0,
23
- borderTopLeftRadius: !0,
24
- borderTopRightRadius: !0,
25
- borderBottomLeftRadius: !0,
26
- borderBottomRightRadius: !0,
27
- borderWidth: !0,
28
- borderLeftWidth: !0,
29
- borderRightWidth: !0,
30
- borderTopWidth: !0,
31
- borderBottomWidth: !0,
32
- ...colorStyleKey
33
- // TODO for other keys like height or width, it's better to not add them here till layout animations are ready
34
- },
35
- AnimatedView = Animated.View,
36
- AnimatedText = Animated.Text;
7
+ const isFabric = !isWeb && typeof global !== "undefined" && !!global.__nativeFabricUIManager;
8
+ const resolveDynamicValue = (value, isDark) => {
9
+ if (value && typeof value === "object" && "dynamic" in value) {
10
+ const dynamicValue = isDark ? value.dynamic.dark : value.dynamic.light;
11
+ return dynamicValue;
12
+ }
13
+ return value;
14
+ };
15
+ const animatedStyleKey = {
16
+ transform: true,
17
+ opacity: true
18
+ };
19
+ const colorStyleKey = {
20
+ backgroundColor: true,
21
+ color: true,
22
+ borderColor: true,
23
+ borderLeftColor: true,
24
+ borderRightColor: true,
25
+ borderTopColor: true,
26
+ borderBottomColor: true
27
+ };
28
+ const costlyToAnimateStyleKey = {
29
+ borderRadius: true,
30
+ borderTopLeftRadius: true,
31
+ borderTopRightRadius: true,
32
+ borderBottomLeftRadius: true,
33
+ borderBottomRightRadius: true,
34
+ borderWidth: true,
35
+ borderLeftWidth: true,
36
+ borderRightWidth: true,
37
+ borderTopWidth: true,
38
+ borderBottomWidth: true,
39
+ ...colorStyleKey
40
+ };
41
+ const AnimatedView = Animated.View;
42
+ const AnimatedText = Animated.Text;
37
43
  function useAnimatedNumber(initial) {
38
44
  const state = React.useRef(null);
39
- return state.current || (state.current = {
40
- composite: null,
41
- val: new Animated.Value(initial),
42
- strategy: {
43
- type: "spring"
44
- }
45
- }), {
45
+ if (!state.current) {
46
+ state.current = {
47
+ composite: null,
48
+ val: new Animated.Value(initial),
49
+ strategy: {
50
+ type: "spring"
51
+ }
52
+ };
53
+ }
54
+ return {
46
55
  getInstance() {
47
56
  return state.current.val;
48
57
  },
49
58
  getValue() {
50
- return state.current.val._value;
59
+ return state.current.val["_value"];
51
60
  },
52
61
  stop() {
53
- state.current.composite?.stop(), state.current.composite = null;
62
+ state.current.composite?.stop();
63
+ state.current.composite = null;
54
64
  },
55
65
  setValue(next, {
56
66
  type,
@@ -58,55 +68,68 @@ function useAnimatedNumber(initial) {
58
68
  } = {
59
69
  type: "spring"
60
70
  }, onFinish) {
61
- const val = state.current.val,
62
- handleFinish = onFinish ? ({
63
- finished
64
- }) => finished ? onFinish() : null : void 0;
65
- if (type === "direct") val.setValue(next);else if (type === "spring") {
71
+ const val = state.current.val;
72
+ const handleFinish = onFinish ? ({
73
+ finished
74
+ }) => finished ? onFinish() : null : void 0;
75
+ if (type === "direct") {
76
+ val.setValue(next);
77
+ } else if (type === "spring") {
66
78
  state.current.composite?.stop();
67
79
  const composite = Animated.spring(val, {
68
80
  ...config,
69
81
  toValue: next,
70
- useNativeDriver: !isWeb
82
+ useNativeDriver: isFabric
71
83
  });
72
- composite.start(handleFinish), state.current.composite = composite;
84
+ composite.start(handleFinish);
85
+ state.current.composite = composite;
73
86
  } else {
74
87
  state.current.composite?.stop();
75
88
  const composite = Animated.timing(val, {
76
89
  ...config,
77
90
  toValue: next,
78
- useNativeDriver: !isWeb
91
+ useNativeDriver: isFabric
79
92
  });
80
- composite.start(handleFinish), state.current.composite = composite;
93
+ composite.start(handleFinish);
94
+ state.current.composite = composite;
81
95
  }
82
96
  }
83
97
  };
84
98
  }
85
99
  const useAnimatedNumberReaction = ({
86
- value
87
- }, onValue) => {
88
- const onChange = useEvent(current => {
89
- onValue(current.value);
90
- });
91
- React.useEffect(() => {
92
- const id = value.getInstance().addListener(onChange);
93
- return () => {
94
- value.getInstance().removeListener(id);
95
- };
96
- }, [value, onChange]);
97
- },
98
- useAnimatedNumberStyle = (value, getStyle) => getStyle(value.getInstance());
99
- function createAnimations(animations) {
100
+ value
101
+ }, onValue) => {
102
+ const onChange = useEvent(current => {
103
+ onValue(current.value);
104
+ });
105
+ React.useEffect(() => {
106
+ const id = value.getInstance().addListener(onChange);
107
+ return () => {
108
+ value.getInstance().removeListener(id);
109
+ };
110
+ }, [value, onChange]);
111
+ };
112
+ const useAnimatedNumberStyle = (value, getStyle) => {
113
+ return getStyle(value.getInstance());
114
+ };
115
+ const useAnimatedNumbersStyle = (vals, getStyle) => {
116
+ return getStyle(...vals.map(v => v.getInstance()));
117
+ };
118
+ function createAnimations(animations, options) {
119
+ const nativeDriver = options?.useNativeDriver ?? isFabric;
100
120
  return {
101
- isReactNative: !0,
121
+ isReactNative: true,
102
122
  inputStyle: "value",
103
123
  outputStyle: "inline",
124
+ avoidReRenders: true,
104
125
  animations,
126
+ needsCustomComponent: true,
105
127
  View: AnimatedView,
106
128
  Text: AnimatedText,
107
129
  useAnimatedNumber,
108
130
  useAnimatedNumberReaction,
109
131
  useAnimatedNumberStyle,
132
+ useAnimatedNumbersStyle,
110
133
  usePresence,
111
134
  ResetPresence,
112
135
  useAnimations: ({
@@ -114,163 +137,300 @@ function createAnimations(animations) {
114
137
  onDidAnimate,
115
138
  style,
116
139
  componentState,
117
- presence
140
+ presence,
141
+ useStyleEmitter
118
142
  }) => {
119
- const isDisabled = isWeb && componentState.unmounted === !0,
120
- isExiting = presence?.[0] === !1,
121
- sendExitComplete = presence?.[1],
122
- [, themeState] = useThemeWithState({}),
123
- isDark = themeState?.scheme === "dark" || themeState?.name?.startsWith("dark"),
124
- animateStyles = React.useRef({}),
125
- animatedTranforms = React.useRef([]),
126
- animationsState = React.useRef(/* @__PURE__ */new WeakMap()),
127
- animateOnly = props.animateOnly || [],
128
- hasTransitionOnly = !!props.animateOnly,
129
- isEntering = !!componentState.unmounted,
130
- wasEnteringRef = React.useRef(isEntering),
131
- justFinishedEntering = wasEnteringRef.current && !isEntering;
143
+ const isDisabled = isWeb && componentState.unmounted === true;
144
+ const isExiting = presence?.[0] === false;
145
+ const sendExitComplete = presence?.[1];
146
+ const [, themeState] = useThemeWithState({});
147
+ const isDark = themeState?.scheme === "dark" || themeState?.name?.startsWith("dark");
148
+ const animateStyles = React.useRef({});
149
+ const animatedTranforms = React.useRef([]);
150
+ const animationsState = React.useRef(/* @__PURE__ */new WeakMap());
151
+ const exitCycleIdRef = React.useRef(0);
152
+ const exitCompletedRef = React.useRef(false);
153
+ const wasExitingRef = React.useRef(false);
154
+ const justStartedExiting = isExiting && !wasExitingRef.current;
155
+ const justStoppedExiting = !isExiting && wasExitingRef.current;
156
+ if (justStartedExiting) {
157
+ exitCycleIdRef.current++;
158
+ exitCompletedRef.current = false;
159
+ }
160
+ if (justStoppedExiting) {
161
+ exitCycleIdRef.current++;
162
+ }
163
+ const animateOnly = props.animateOnly || [];
164
+ const hasTransitionOnly = !!props.animateOnly;
165
+ const isEntering = !!componentState.unmounted;
166
+ const wasEnteringRef = React.useRef(isEntering);
167
+ const justFinishedEntering = wasEnteringRef.current && !isEntering;
132
168
  React.useEffect(() => {
133
169
  wasEnteringRef.current = isEntering;
134
170
  });
135
- const args = [JSON.stringify(style), componentState, isExiting, !!onDidAnimate, isDark, justFinishedEntering],
136
- isThereNoNativeStyleKeys = React.useMemo(() => isWeb ? !0 : Object.keys(style).some(key => animateOnly ? !animatedStyleKey[key] && animateOnly.indexOf(key) === -1 : !animatedStyleKey[key]), args),
137
- res = React.useMemo(() => {
138
- const runners = [],
139
- completions = [],
140
- animationState = isExiting ? "exit" : isEntering || justFinishedEntering ? "enter" : "default",
141
- nonAnimatedStyle = {};
142
- for (const key in style) {
143
- const rawVal = style[key],
144
- val = resolveDynamicValue(rawVal, isDark);
145
- if (val !== void 0 && !isDisabled) {
146
- if (animatedStyleKey[key] == null && !costlyToAnimateStyleKey[key]) {
147
- nonAnimatedStyle[key] = val;
148
- continue;
149
- }
150
- if (hasTransitionOnly && !animateOnly.includes(key)) {
151
- nonAnimatedStyle[key] = val;
152
- continue;
153
- }
154
- if (key !== "transform") {
155
- animateStyles.current[key] = update(key, animateStyles.current[key], val);
156
- continue;
157
- }
158
- if (val) {
159
- if (typeof val == "string") {
160
- console.warn("Warning: Tamagui can't animate string transforms yet!");
161
- continue;
162
- }
163
- for (const [index, transform] of val.entries()) {
164
- if (!transform) continue;
165
- const tkey = Object.keys(transform)[0],
166
- currentTransform = animatedTranforms.current[index]?.[tkey];
167
- animatedTranforms.current[index] = {
168
- [tkey]: update(tkey, currentTransform, transform[tkey])
169
- }, animatedTranforms.current = [...animatedTranforms.current];
170
- }
171
- }
172
- }
171
+ const args = [JSON.stringify(style), componentState, isExiting, !!onDidAnimate, isDark, justFinishedEntering, hasTransitionOnly];
172
+ const res = React.useMemo(() => {
173
+ const runners = [];
174
+ const completions = [];
175
+ const animationState = isExiting ? "exit" : isEntering || justFinishedEntering ? "enter" : "default";
176
+ const nonAnimatedStyle = {};
177
+ for (const key in style) {
178
+ const rawVal = style[key];
179
+ const val = resolveDynamicValue(rawVal, isDark);
180
+ if (val === void 0) continue;
181
+ if (isDisabled) {
182
+ continue;
173
183
  }
174
- const animatedStyle = {
175
- ...Object.fromEntries(Object.entries(animateStyles.current).map(([k, v]) => [k, animationsState.current.get(v)?.interpolation || v])),
176
- transform: animatedTranforms.current.map(r => {
177
- const key = Object.keys(r)[0],
178
- val = animationsState.current.get(r[key])?.interpolation || r[key];
179
- return {
180
- [key]: val
181
- };
182
- })
183
- };
184
- return {
185
- runners,
186
- completions,
187
- style: [nonAnimatedStyle, animatedStyle]
188
- };
189
- function update(key, animated, valIn) {
190
- const isColorStyleKey = colorStyleKey[key],
191
- [val, type] = isColorStyleKey ? [0, void 0] : getValue(valIn);
192
- let animateToValue = val;
193
- const value = animated || new Animated.Value(val),
194
- curInterpolation = animationsState.current.get(value);
195
- let interpolateArgs;
196
- if (type && (interpolateArgs = getInterpolated(curInterpolation?.current ?? value._value, val, type), animationsState.current.set(value, {
184
+ if (animatedStyleKey[key] == null && !costlyToAnimateStyleKey[key]) {
185
+ nonAnimatedStyle[key] = val;
186
+ continue;
187
+ }
188
+ if (hasTransitionOnly && !animateOnly.includes(key)) {
189
+ nonAnimatedStyle[key] = val;
190
+ continue;
191
+ }
192
+ if (key !== "transform") {
193
+ animateStyles.current[key] = update(key, animateStyles.current[key], val);
194
+ continue;
195
+ }
196
+ if (!val) continue;
197
+ if (typeof val === "string") {
198
+ console.warn(`Warning: Tamagui can't animate string transforms yet!`);
199
+ continue;
200
+ }
201
+ for (const [index, transform] of val.entries()) {
202
+ if (!transform) continue;
203
+ const tkey = Object.keys(transform)[0];
204
+ const currentTransform = animatedTranforms.current[index]?.[tkey];
205
+ animatedTranforms.current[index] = {
206
+ [tkey]: update(tkey, currentTransform, transform[tkey])
207
+ };
208
+ animatedTranforms.current = [...animatedTranforms.current];
209
+ }
210
+ }
211
+ const animatedTransformStyle = animatedTranforms.current.length > 0 ? {
212
+ transform: animatedTranforms.current.map(r => {
213
+ const key = Object.keys(r)[0];
214
+ const val = animationsState.current.get(r[key])?.interpolation || r[key];
215
+ return {
216
+ [key]: val
217
+ };
218
+ })
219
+ } : {};
220
+ const animatedStyle = {
221
+ ...Object.fromEntries(Object.entries(animateStyles.current).map(([k, v]) => [k, animationsState.current.get(v)?.interpolation || v])),
222
+ ...animatedTransformStyle
223
+ };
224
+ return {
225
+ runners,
226
+ completions,
227
+ style: [nonAnimatedStyle, animatedStyle]
228
+ };
229
+ function update(key, animated, valIn) {
230
+ const isColorStyleKey = colorStyleKey[key];
231
+ const [val, type] = isColorStyleKey ? [0, void 0] : getValue(valIn);
232
+ let animateToValue = val;
233
+ const value = animated || new Animated.Value(val);
234
+ const curInterpolation = animationsState.current.get(value);
235
+ let interpolateArgs;
236
+ if (type) {
237
+ interpolateArgs = getInterpolated(curInterpolation?.current ?? value["_value"], val, type);
238
+ animationsState.current.set(value, {
197
239
  interpolation: value.interpolate(interpolateArgs),
198
240
  current: val
199
- })), isColorStyleKey && (animateToValue = curInterpolation?.animateToValue ? 0 : 1, interpolateArgs = getColorInterpolated(curInterpolation?.current,
241
+ });
242
+ }
243
+ if (isColorStyleKey) {
244
+ animateToValue = curInterpolation?.animateToValue ? 0 : 1;
245
+ interpolateArgs = getColorInterpolated(curInterpolation?.current,
200
246
  // valIn is the next color
201
- valIn, animateToValue), animationsState.current.set(value, {
247
+ valIn, animateToValue);
248
+ animationsState.current.set(value, {
202
249
  current: valIn,
203
250
  interpolation: value.interpolate(interpolateArgs),
204
251
  animateToValue: curInterpolation?.animateToValue ? 0 : 1
205
- })), value) {
206
- const animationConfig = getAnimationConfig(key, animations, props.transition, animationState);
207
- let resolve;
208
- const promise = new Promise(res2 => {
209
- resolve = res2;
210
- });
211
- completions.push(promise), runners.push(() => {
212
- value.stopAnimation();
213
- function getAnimation() {
214
- return Animated[animationConfig.type || "spring"](value, {
215
- toValue: animateToValue,
216
- useNativeDriver: !isWeb && !isThereNoNativeStyleKeys,
217
- ...animationConfig
218
- });
219
- }
220
- (animationConfig.delay ? Animated.sequence([Animated.delay(animationConfig.delay), getAnimation()]) : getAnimation()).start(({
221
- finished
222
- }) => {
223
- finished && resolve();
252
+ });
253
+ }
254
+ if (value) {
255
+ const animationConfig = getAnimationConfig(key, animations, props.transition, animationState);
256
+ let resolve;
257
+ const promise = new Promise(res2 => {
258
+ resolve = res2;
259
+ });
260
+ completions.push(promise);
261
+ runners.push(() => {
262
+ value.stopAnimation();
263
+ function getAnimation() {
264
+ return Animated[animationConfig.type || "spring"](value, {
265
+ toValue: animateToValue,
266
+ useNativeDriver: nativeDriver,
267
+ ...animationConfig
224
268
  });
269
+ }
270
+ const animation = animationConfig.delay ? Animated.sequence([Animated.delay(animationConfig.delay), getAnimation()]) : getAnimation();
271
+ animation.start(({
272
+ finished
273
+ }) => {
274
+ if (finished || isExiting) {
275
+ resolve();
276
+ }
225
277
  });
278
+ });
279
+ }
280
+ if (process.env.NODE_ENV === "development") {
281
+ if (props["debug"] === "verbose") {
282
+ console.info(" \u{1F4A0} animate", key, `from (${value["_value"]}) to`, valIn, `(${val})`, "type", type, "interpolate", interpolateArgs);
226
283
  }
227
- return process.env.NODE_ENV === "development" && props.debug === "verbose" && console.info(" \u{1F4A0} animate", key, `from (${value._value}) to`, valIn, `(${val})`, "type", type, "interpolate", interpolateArgs), value;
228
284
  }
229
- }, args);
230
- return useIsomorphicLayoutEffect(() => {
285
+ return value;
286
+ }
287
+ }, args);
288
+ React.useEffect(() => {
289
+ wasExitingRef.current = isExiting;
290
+ });
291
+ useIsomorphicLayoutEffect(() => {
231
292
  res.runners.forEach(r => r());
232
- let cancel = !1;
233
- return Promise.all(res.completions).then(() => {
234
- cancel || (onDidAnimate?.(), isExiting && sendExitComplete?.());
235
- }), () => {
236
- cancel = !0;
293
+ const cycleId = exitCycleIdRef.current;
294
+ if (res.completions.length === 0) {
295
+ onDidAnimate?.();
296
+ if (isExiting && !exitCompletedRef.current) {
297
+ exitCompletedRef.current = true;
298
+ sendExitComplete?.();
299
+ }
300
+ return;
301
+ }
302
+ let cancel = false;
303
+ Promise.all(res.completions).then(() => {
304
+ if (cancel) return;
305
+ if (isExiting && cycleId !== exitCycleIdRef.current) return;
306
+ if (isExiting && exitCompletedRef.current) return;
307
+ onDidAnimate?.();
308
+ if (isExiting) {
309
+ exitCompletedRef.current = true;
310
+ sendExitComplete?.();
311
+ }
312
+ });
313
+ return () => {
314
+ cancel = true;
237
315
  };
238
- }, args), process.env.NODE_ENV === "development" && props.debug === "verbose" && console.info("Animated", {
239
- response: res,
240
- inputStyle: style,
241
- isExiting
242
- }), res;
316
+ }, args);
317
+ useStyleEmitter?.(nextStyle => {
318
+ for (const key in nextStyle) {
319
+ const rawVal = nextStyle[key];
320
+ const val = resolveDynamicValue(rawVal, isDark);
321
+ if (val === void 0) continue;
322
+ if (key === "transform" && Array.isArray(val)) {
323
+ for (const [index, transform] of val.entries()) {
324
+ if (!transform) continue;
325
+ const tkey = Object.keys(transform)[0];
326
+ const currentTransform = animatedTranforms.current[index]?.[tkey];
327
+ animatedTranforms.current[index] = {
328
+ [tkey]: update(tkey, currentTransform, transform[tkey])
329
+ };
330
+ }
331
+ } else if (animatedStyleKey[key] != null || costlyToAnimateStyleKey[key]) {
332
+ animateStyles.current[key] = update(key, animateStyles.current[key], val);
333
+ }
334
+ }
335
+ res.runners.forEach(r => r());
336
+ function update(key, animated, valIn) {
337
+ const isColor = colorStyleKey[key];
338
+ const [numVal, type] = isColor ? [0, void 0] : getValue(valIn);
339
+ let animateToValue = numVal;
340
+ const value = animated || new Animated.Value(numVal);
341
+ const curInterpolation = animationsState.current.get(value);
342
+ if (type) {
343
+ animationsState.current.set(value, {
344
+ interpolation: value.interpolate(getInterpolated(curInterpolation?.current ?? value["_value"], numVal, type)),
345
+ current: numVal
346
+ });
347
+ }
348
+ if (isColor) {
349
+ animateToValue = curInterpolation?.animateToValue ? 0 : 1;
350
+ animationsState.current.set(value, {
351
+ current: valIn,
352
+ interpolation: value.interpolate(getColorInterpolated(curInterpolation?.current, valIn, animateToValue)),
353
+ animateToValue: curInterpolation?.animateToValue ? 0 : 1
354
+ });
355
+ }
356
+ const animationConfig = getAnimationConfig(key, animations, props.transition, "default");
357
+ res.runners.push(() => {
358
+ value.stopAnimation();
359
+ const anim = Animated[animationConfig.type || "spring"](value, {
360
+ toValue: animateToValue,
361
+ useNativeDriver: nativeDriver,
362
+ ...animationConfig
363
+ });
364
+ (animationConfig.delay ? Animated.sequence([Animated.delay(animationConfig.delay), anim]) : anim).start();
365
+ });
366
+ return value;
367
+ }
368
+ });
369
+ if (process.env.NODE_ENV === "development") {
370
+ if (props["debug"] === "verbose") {
371
+ console.info(`Animated`, {
372
+ response: res,
373
+ inputStyle: style,
374
+ isExiting
375
+ });
376
+ }
377
+ }
378
+ return res;
243
379
  }
244
380
  };
245
381
  }
246
382
  function getColorInterpolated(currentColor, nextColor, animateToValue) {
247
- const inputRange = [0, 1],
248
- outputRange = [currentColor || nextColor, nextColor];
249
- return animateToValue === 0 && outputRange.reverse(), {
383
+ const inputRange = [0, 1];
384
+ const outputRange = [currentColor ? currentColor : nextColor, nextColor];
385
+ if (animateToValue === 0) {
386
+ outputRange.reverse();
387
+ }
388
+ return {
250
389
  inputRange,
251
390
  outputRange
252
391
  };
253
392
  }
254
393
  function getInterpolated(current, next, postfix = "deg") {
255
- next === current && (current = next - 1e-9);
256
- const inputRange = [current, next],
257
- outputRange = [`${current}${postfix}`, `${next}${postfix}`];
258
- return next < current && (inputRange.reverse(), outputRange.reverse()), {
394
+ if (next === current) {
395
+ current = next - 1e-9;
396
+ }
397
+ const inputRange = [current, next];
398
+ const outputRange = [`${current}${postfix}`, `${next}${postfix}`];
399
+ if (next < current) {
400
+ inputRange.reverse();
401
+ outputRange.reverse();
402
+ }
403
+ return {
259
404
  inputRange,
260
405
  outputRange
261
406
  };
262
407
  }
263
408
  function getAnimationConfig(key, animations, transition, animationState = "default") {
264
- const normalized = normalizeTransition(transition),
265
- shortKey = transformShorthands[key],
266
- propAnimation = normalized.properties[key] ?? normalized.properties[shortKey];
267
- let animationType = null,
268
- extraConf = {};
269
- return typeof propAnimation == "string" ? animationType = propAnimation : propAnimation && typeof propAnimation == "object" ? (animationType = propAnimation.type || getEffectiveAnimation(normalized, animationState), extraConf = propAnimation) : animationType = getEffectiveAnimation(normalized, animationState), normalized.delay && !extraConf.delay && (extraConf = {
270
- ...extraConf,
271
- delay: normalized.delay
272
- }), {
273
- ...(animationType ? animations[animationType] : {}),
409
+ const normalized = normalizeTransition(transition);
410
+ const shortKey = transformShorthands[key];
411
+ const propAnimation = normalized.properties[key] ?? normalized.properties[shortKey];
412
+ let animationType = null;
413
+ let extraConf = {};
414
+ if (typeof propAnimation === "string") {
415
+ animationType = propAnimation;
416
+ } else if (propAnimation && typeof propAnimation === "object") {
417
+ animationType = propAnimation.type || getEffectiveAnimation(normalized, animationState);
418
+ extraConf = propAnimation;
419
+ } else {
420
+ animationType = getEffectiveAnimation(normalized, animationState);
421
+ }
422
+ if (normalized.delay && !extraConf.delay) {
423
+ extraConf = {
424
+ ...extraConf,
425
+ delay: normalized.delay
426
+ };
427
+ }
428
+ const found = animationType ? animations[animationType] : {};
429
+ return {
430
+ ...found,
431
+ // Apply global spring config overrides (from transition={['bouncy', { stiffness: 1000 }]})
432
+ ...normalized.config,
433
+ // Property-specific config takes highest precedence
274
434
  ...extraConf
275
435
  };
276
436
  }
@@ -280,10 +440,12 @@ const transformShorthands = {
280
440
  translateX: "x",
281
441
  translateY: "y"
282
442
  };
283
- function getValue(input, isColor = !1) {
284
- if (typeof input != "string") return [input];
443
+ function getValue(input, isColor = false) {
444
+ if (typeof input !== "string") {
445
+ return [input];
446
+ }
285
447
  const [_, number, after] = input.match(/([-0-9]+)(deg|%|px)/) ?? [];
286
448
  return [+number, after];
287
449
  }
288
- export { AnimatedText, AnimatedView, createAnimations, useAnimatedNumber, useAnimatedNumberReaction, useAnimatedNumberStyle };
450
+ export { AnimatedText, AnimatedView, createAnimations, useAnimatedNumber, useAnimatedNumberReaction, useAnimatedNumberStyle, useAnimatedNumbersStyle };
289
451
  //# sourceMappingURL=createAnimations.mjs.map