framer-motion 7.7.3 → 7.8.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/index.js +313 -237
- package/dist/es/animation/legacy-popmotion/index.mjs +3 -3
- package/dist/es/animation/legacy-popmotion/spring.mjs +20 -28
- package/dist/es/animation/optimized-appear/data-id.mjs +6 -0
- package/dist/es/animation/optimized-appear/handoff.mjs +34 -0
- package/dist/es/animation/optimized-appear/start.mjs +15 -0
- package/dist/es/animation/optimized-appear/store-id.mjs +3 -0
- package/dist/es/animation/utils/transitions.mjs +19 -24
- package/dist/es/animation/waapi/easing.mjs +3 -0
- package/dist/es/animation/waapi/index.mjs +16 -0
- package/dist/es/animation/waapi/supports.mjs +17 -0
- package/dist/es/index.mjs +3 -0
- package/dist/es/render/utils/animation.mjs +13 -1
- package/dist/es/render/utils/motion-values.mjs +1 -1
- package/dist/es/utils/delay.mjs +3 -0
- package/dist/es/value/index.mjs +1 -1
- package/dist/framer-motion.dev.js +313 -237
- package/dist/framer-motion.js +1 -1
- package/dist/index.d.ts +32 -2
- package/dist/projection.dev.js +59 -70
- package/dist/size-rollup-dom-animation-assets.js +1 -1
- package/dist/size-rollup-dom-animation.js +1 -1
- package/dist/size-rollup-dom-max-assets.js +1 -1
- package/dist/size-rollup-dom-max.js +1 -1
- package/dist/size-rollup-motion.js +1 -1
- package/dist/size-webpack-dom-animation.js +1 -1
- package/dist/size-webpack-dom-max.js +1 -1
- package/dist/three-entry.d.ts +3 -1
- package/package.json +11 -9
|
@@ -72,7 +72,7 @@ function animate({ from, autoplay = true, driver = framesync, elapsed = 0, repea
|
|
|
72
72
|
latest = interpolateFromNumber(latest);
|
|
73
73
|
isComplete = isForwardPlayback ? state.done : elapsed <= 0;
|
|
74
74
|
}
|
|
75
|
-
onUpdate
|
|
75
|
+
onUpdate && onUpdate(latest);
|
|
76
76
|
if (isComplete) {
|
|
77
77
|
if (repeatCount === 0) {
|
|
78
78
|
computedDuration =
|
|
@@ -87,14 +87,14 @@ function animate({ from, autoplay = true, driver = framesync, elapsed = 0, repea
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
function play() {
|
|
90
|
-
onPlay
|
|
90
|
+
onPlay && onPlay();
|
|
91
91
|
driverControls = driver(update);
|
|
92
92
|
driverControls.start();
|
|
93
93
|
}
|
|
94
94
|
autoplay && play();
|
|
95
95
|
return {
|
|
96
96
|
stop: () => {
|
|
97
|
-
onStop
|
|
97
|
+
onStop && onStop();
|
|
98
98
|
driverControls.stop();
|
|
99
99
|
},
|
|
100
100
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { findSpring, calcAngularFreq } from './find-spring.mjs';
|
|
2
|
+
import { velocityPerSecond } from '../../utils/velocity-per-second.mjs';
|
|
2
3
|
|
|
3
4
|
const durationKeys = ["duration", "bounce"];
|
|
4
5
|
const physicsKeys = ["stiffness", "damping", "mass"];
|
|
@@ -28,6 +29,7 @@ function getSpringOptions(options) {
|
|
|
28
29
|
}
|
|
29
30
|
return springOptions;
|
|
30
31
|
}
|
|
32
|
+
const velocitySampleDuration = 5;
|
|
31
33
|
/**
|
|
32
34
|
* This is based on the spring implementation of Wobble https://github.com/skevy/wobble
|
|
33
35
|
*/
|
|
@@ -39,11 +41,10 @@ function spring({ from = 0.0, to = 1.0, restSpeed = 2, restDelta = 0.01, ...opti
|
|
|
39
41
|
const state = { done: false, value: from };
|
|
40
42
|
let { stiffness, damping, mass, velocity, duration, isResolvedFromDuration, } = getSpringOptions(options);
|
|
41
43
|
let resolveSpring = zero;
|
|
42
|
-
let
|
|
44
|
+
let initialVelocity = velocity ? -(velocity / 1000) : 0.0;
|
|
45
|
+
const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass));
|
|
43
46
|
function createSpring() {
|
|
44
|
-
const initialVelocity = velocity ? -(velocity / 1000) : 0.0;
|
|
45
47
|
const initialDelta = to - from;
|
|
46
|
-
const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass));
|
|
47
48
|
const undampedAngularFreq = Math.sqrt(stiffness / mass) / 1000;
|
|
48
49
|
/**
|
|
49
50
|
* If we're working within what looks like a 0-1 range, change the default restDelta
|
|
@@ -65,29 +66,6 @@ function spring({ from = 0.0, to = 1.0, restSpeed = 2, restDelta = 0.01, ...opti
|
|
|
65
66
|
Math.sin(angularFreq * t) +
|
|
66
67
|
initialDelta * Math.cos(angularFreq * t)));
|
|
67
68
|
};
|
|
68
|
-
resolveVelocity = (t) => {
|
|
69
|
-
// TODO Resolve these calculations with the above
|
|
70
|
-
const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
|
|
71
|
-
return (dampingRatio *
|
|
72
|
-
undampedAngularFreq *
|
|
73
|
-
envelope *
|
|
74
|
-
((Math.sin(angularFreq * t) *
|
|
75
|
-
(initialVelocity +
|
|
76
|
-
dampingRatio *
|
|
77
|
-
undampedAngularFreq *
|
|
78
|
-
initialDelta)) /
|
|
79
|
-
angularFreq +
|
|
80
|
-
initialDelta * Math.cos(angularFreq * t)) -
|
|
81
|
-
envelope *
|
|
82
|
-
(Math.cos(angularFreq * t) *
|
|
83
|
-
(initialVelocity +
|
|
84
|
-
dampingRatio *
|
|
85
|
-
undampedAngularFreq *
|
|
86
|
-
initialDelta) -
|
|
87
|
-
angularFreq *
|
|
88
|
-
initialDelta *
|
|
89
|
-
Math.sin(angularFreq * t)));
|
|
90
|
-
};
|
|
91
69
|
}
|
|
92
70
|
else if (dampingRatio === 1) {
|
|
93
71
|
// Critically damped spring
|
|
@@ -121,7 +99,21 @@ function spring({ from = 0.0, to = 1.0, restSpeed = 2, restDelta = 0.01, ...opti
|
|
|
121
99
|
next: (t) => {
|
|
122
100
|
const current = resolveSpring(t);
|
|
123
101
|
if (!isResolvedFromDuration) {
|
|
124
|
-
|
|
102
|
+
let currentVelocity = initialVelocity;
|
|
103
|
+
if (t !== 0) {
|
|
104
|
+
/**
|
|
105
|
+
* We only need to calculate velocity for under-damped springs
|
|
106
|
+
* as over- and critically-damped springs can't overshoot, so
|
|
107
|
+
* checking only for displacement is enough.
|
|
108
|
+
*/
|
|
109
|
+
if (dampingRatio < 1) {
|
|
110
|
+
const prevT = Math.max(0, t - velocitySampleDuration);
|
|
111
|
+
currentVelocity = velocityPerSecond(current - resolveSpring(prevT), t - prevT);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
currentVelocity = 0;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
125
117
|
const isBelowVelocityThreshold = Math.abs(currentVelocity) <= restSpeed;
|
|
126
118
|
const isBelowDisplacementThreshold = Math.abs(to - current) <= restDelta;
|
|
127
119
|
state.done =
|
|
@@ -134,7 +126,7 @@ function spring({ from = 0.0, to = 1.0, restSpeed = 2, restDelta = 0.01, ...opti
|
|
|
134
126
|
return state;
|
|
135
127
|
},
|
|
136
128
|
flipTarget: () => {
|
|
137
|
-
|
|
129
|
+
initialVelocity = -initialVelocity;
|
|
138
130
|
[from, to] = [to, from];
|
|
139
131
|
createSpring();
|
|
140
132
|
},
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { camelToDash } from '../../render/dom/utils/camel-to-dash.mjs';
|
|
2
|
+
|
|
3
|
+
const optimizedAppearDataId = "framerAppearId";
|
|
4
|
+
const optimizedAppearDataAttribute = "data-" + camelToDash(optimizedAppearDataId);
|
|
5
|
+
|
|
6
|
+
export { optimizedAppearDataAttribute, optimizedAppearDataId };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { sync } from '../../frameloop/index.mjs';
|
|
2
|
+
import { transformProps } from '../../render/html/utils/transform.mjs';
|
|
3
|
+
import { appearStoreId } from './store-id.mjs';
|
|
4
|
+
|
|
5
|
+
function handoffOptimizedAppearAnimation(id, name) {
|
|
6
|
+
const { MotionAppearAnimations } = window;
|
|
7
|
+
const animationId = appearStoreId(id, transformProps.has(name) ? "transform" : name);
|
|
8
|
+
const animation = MotionAppearAnimations && MotionAppearAnimations.get(animationId);
|
|
9
|
+
if (animation) {
|
|
10
|
+
/**
|
|
11
|
+
* We allow the animation to persist until the next frame:
|
|
12
|
+
* 1. So it continues to play until Framer Motion is ready to render
|
|
13
|
+
* (avoiding a potential flash of the element's original state)
|
|
14
|
+
* 2. As all independent transforms share a single transform animation, stopping
|
|
15
|
+
* it synchronously would prevent subsequent transforms from handing off.
|
|
16
|
+
*/
|
|
17
|
+
sync.render(() => {
|
|
18
|
+
/**
|
|
19
|
+
* Animation.cancel() throws so it needs to be wrapped in a try/catch
|
|
20
|
+
*/
|
|
21
|
+
try {
|
|
22
|
+
animation.cancel();
|
|
23
|
+
MotionAppearAnimations.delete(animationId);
|
|
24
|
+
}
|
|
25
|
+
catch (e) { }
|
|
26
|
+
});
|
|
27
|
+
return animation.currentTime || 0;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export { handoffOptimizedAppearAnimation };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { appearStoreId } from './store-id.mjs';
|
|
2
|
+
import { animateStyle } from '../waapi/index.mjs';
|
|
3
|
+
import { optimizedAppearDataId } from './data-id.mjs';
|
|
4
|
+
|
|
5
|
+
function startOptimizedAppearAnimation(element, name, keyframes, options) {
|
|
6
|
+
window.MotionAppearAnimations || (window.MotionAppearAnimations = new Map());
|
|
7
|
+
const id = element.dataset[optimizedAppearDataId];
|
|
8
|
+
const animation = animateStyle(element, name, keyframes, options);
|
|
9
|
+
if (id && animation) {
|
|
10
|
+
window.MotionAppearAnimations.set(appearStoreId(id, name), animation);
|
|
11
|
+
}
|
|
12
|
+
return animation;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { startOptimizedAppearAnimation };
|
|
@@ -6,9 +6,9 @@ import { warning } from 'hey-listen';
|
|
|
6
6
|
import { getAnimatableNone } from '../../render/dom/value-types/animatable-none.mjs';
|
|
7
7
|
import { instantAnimationState } from '../../utils/use-instant-transition-state.mjs';
|
|
8
8
|
import { resolveFinalValueInKeyframes } from '../../utils/resolve-value.mjs';
|
|
9
|
-
import { delay } from '../../utils/delay.mjs';
|
|
10
9
|
import { inertia } from '../legacy-popmotion/inertia.mjs';
|
|
11
10
|
import { animate } from '../legacy-popmotion/index.mjs';
|
|
11
|
+
import { delay } from '../../utils/delay.mjs';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Decide whether a transition is defined on a given Transition.
|
|
@@ -96,6 +96,9 @@ function getPopmotionAnimationOptions(transition, options, key) {
|
|
|
96
96
|
*/
|
|
97
97
|
function getAnimation(key, value, target, transition, onComplete) {
|
|
98
98
|
const valueTransition = getValueTransition(transition, key) || {};
|
|
99
|
+
const { elapsed = 0 } = transition;
|
|
100
|
+
valueTransition.elapsed =
|
|
101
|
+
elapsed - secondsToMilliseconds(transition.delay || 0);
|
|
99
102
|
let origin = valueTransition.from !== undefined ? valueTransition.from : value.get();
|
|
100
103
|
const isTargetAnimatable = isAnimatable(key, target);
|
|
101
104
|
if (origin === "none" && isTargetAnimatable && typeof target === "string") {
|
|
@@ -123,20 +126,23 @@ function getAnimation(key, value, target, transition, onComplete) {
|
|
|
123
126
|
onComplete,
|
|
124
127
|
onUpdate: (v) => value.set(v),
|
|
125
128
|
};
|
|
126
|
-
|
|
129
|
+
const animation = valueTransition.type === "inertia" ||
|
|
127
130
|
valueTransition.type === "decay"
|
|
128
131
|
? inertia({ ...options, ...valueTransition })
|
|
129
132
|
: animate({
|
|
130
133
|
...getPopmotionAnimationOptions(valueTransition, options, key),
|
|
131
134
|
onUpdate: (v) => {
|
|
132
135
|
options.onUpdate(v);
|
|
133
|
-
valueTransition.onUpdate &&
|
|
136
|
+
valueTransition.onUpdate &&
|
|
137
|
+
valueTransition.onUpdate(v);
|
|
134
138
|
},
|
|
135
139
|
onComplete: () => {
|
|
136
140
|
options.onComplete();
|
|
137
|
-
valueTransition.onComplete &&
|
|
141
|
+
valueTransition.onComplete &&
|
|
142
|
+
valueTransition.onComplete();
|
|
138
143
|
},
|
|
139
144
|
});
|
|
145
|
+
return () => animation.stop();
|
|
140
146
|
}
|
|
141
147
|
function set() {
|
|
142
148
|
const finalTarget = resolveFinalValueInKeyframes(target);
|
|
@@ -144,13 +150,16 @@ function getAnimation(key, value, target, transition, onComplete) {
|
|
|
144
150
|
onComplete();
|
|
145
151
|
valueTransition.onUpdate && valueTransition.onUpdate(finalTarget);
|
|
146
152
|
valueTransition.onComplete && valueTransition.onComplete();
|
|
147
|
-
return
|
|
153
|
+
return () => { };
|
|
148
154
|
}
|
|
149
|
-
|
|
155
|
+
const useInstantAnimation = !isOriginAnimatable ||
|
|
150
156
|
!isTargetAnimatable ||
|
|
151
|
-
valueTransition.type === false
|
|
152
|
-
|
|
153
|
-
|
|
157
|
+
valueTransition.type === false;
|
|
158
|
+
return useInstantAnimation
|
|
159
|
+
? valueTransition.elapsed
|
|
160
|
+
? () => delay(set, -valueTransition.elapsed)
|
|
161
|
+
: set()
|
|
162
|
+
: start();
|
|
154
163
|
}
|
|
155
164
|
function isZero(value) {
|
|
156
165
|
return (value === 0 ||
|
|
@@ -175,21 +184,7 @@ function startAnimation(key, value, target, transition = {}) {
|
|
|
175
184
|
transition = { type: false };
|
|
176
185
|
}
|
|
177
186
|
return value.start((onComplete) => {
|
|
178
|
-
|
|
179
|
-
const animation = getAnimation(key, value, target, transition, onComplete);
|
|
180
|
-
const delayBy = getDelayFromTransition(transition, key);
|
|
181
|
-
const start = () => (controls = animation());
|
|
182
|
-
let cancelDelay;
|
|
183
|
-
if (delayBy) {
|
|
184
|
-
cancelDelay = delay(start, secondsToMilliseconds(delayBy));
|
|
185
|
-
}
|
|
186
|
-
else {
|
|
187
|
-
start();
|
|
188
|
-
}
|
|
189
|
-
return () => {
|
|
190
|
-
cancelDelay && cancelDelay();
|
|
191
|
-
controls && controls.stop();
|
|
192
|
-
};
|
|
187
|
+
return getAnimation(key, value, target, { ...transition, delay: getDelayFromTransition(transition, key) }, onComplete);
|
|
193
188
|
});
|
|
194
189
|
}
|
|
195
190
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { supports } from './supports.mjs';
|
|
2
|
+
import { cubicBezierAsString } from './easing.mjs';
|
|
3
|
+
|
|
4
|
+
function animateStyle(element, valueName, keyframes, { delay, duration, ease }) {
|
|
5
|
+
if (!supports.waapi())
|
|
6
|
+
return undefined;
|
|
7
|
+
const animation = element.animate({ [valueName]: keyframes }, {
|
|
8
|
+
delay,
|
|
9
|
+
duration,
|
|
10
|
+
easing: Array.isArray(ease) ? cubicBezierAsString(ease) : ease,
|
|
11
|
+
fill: "both",
|
|
12
|
+
});
|
|
13
|
+
return animation;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { animateStyle };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const featureTests = {
|
|
2
|
+
waapi: () => Object.hasOwnProperty.call(Element.prototype, "animate"),
|
|
3
|
+
};
|
|
4
|
+
const results = {};
|
|
5
|
+
const supports = {};
|
|
6
|
+
/**
|
|
7
|
+
* Generate features tests that cache their results.
|
|
8
|
+
*/
|
|
9
|
+
for (const key in featureTests) {
|
|
10
|
+
supports[key] = () => {
|
|
11
|
+
if (results[key] === undefined)
|
|
12
|
+
results[key] = featureTests[key]();
|
|
13
|
+
return results[key];
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { supports };
|
package/dist/es/index.mjs
CHANGED
|
@@ -49,6 +49,9 @@ export { distance, distance2D } from './utils/distance.mjs';
|
|
|
49
49
|
export { mix } from './utils/mix.mjs';
|
|
50
50
|
export { pipe } from './utils/pipe.mjs';
|
|
51
51
|
export { wrap } from './utils/wrap.mjs';
|
|
52
|
+
export { startOptimizedAppearAnimation } from './animation/optimized-appear/start.mjs';
|
|
53
|
+
export { optimizedAppearDataAttribute } from './animation/optimized-appear/data-id.mjs';
|
|
54
|
+
export { spring } from './animation/legacy-popmotion/spring.mjs';
|
|
52
55
|
export { MotionContext, useVisualElementContext } from './context/MotionContext/index.mjs';
|
|
53
56
|
export { MotionConfigContext } from './context/MotionConfigContext.mjs';
|
|
54
57
|
export { PresenceContext } from './context/PresenceContext.mjs';
|
|
@@ -3,6 +3,8 @@ import { setTarget } from './setters.mjs';
|
|
|
3
3
|
import { resolveVariant } from './resolve-dynamic-variants.mjs';
|
|
4
4
|
import { transformProps } from '../html/utils/transform.mjs';
|
|
5
5
|
import { isWillChangeMotionValue } from '../../value/use-will-change/is.mjs';
|
|
6
|
+
import { handoffOptimizedAppearAnimation } from '../../animation/optimized-appear/handoff.mjs';
|
|
7
|
+
import { optimizedAppearDataAttribute } from '../../animation/optimized-appear/data-id.mjs';
|
|
6
8
|
|
|
7
9
|
function animateVisualElement(visualElement, definition, options = {}) {
|
|
8
10
|
visualElement.notify("AnimationStart", definition);
|
|
@@ -81,7 +83,7 @@ function animateTarget(visualElement, definition, { delay = 0, transitionOverrid
|
|
|
81
83
|
shouldBlockAnimation(animationTypeState, key))) {
|
|
82
84
|
continue;
|
|
83
85
|
}
|
|
84
|
-
let valueTransition = { delay, ...transition };
|
|
86
|
+
let valueTransition = { delay, elapsed: 0, ...transition };
|
|
85
87
|
/**
|
|
86
88
|
* Make animation instant if this is a transform prop and we should reduce motion.
|
|
87
89
|
*/
|
|
@@ -92,6 +94,16 @@ function animateTarget(visualElement, definition, { delay = 0, transitionOverrid
|
|
|
92
94
|
delay: 0,
|
|
93
95
|
};
|
|
94
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* If this is the first time a value is being animated, check
|
|
99
|
+
* to see if we're handling off from an existing animation.
|
|
100
|
+
*/
|
|
101
|
+
if (!value.hasAnimated) {
|
|
102
|
+
const appearId = visualElement.getProps()[optimizedAppearDataAttribute];
|
|
103
|
+
if (appearId) {
|
|
104
|
+
valueTransition.elapsed = handoffOptimizedAppearAnimation(appearId, key);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
95
107
|
let animation = startAnimation(key, value, valueTarget, valueTransition);
|
|
96
108
|
if (isWillChangeMotionValue(willChange)) {
|
|
97
109
|
willChange.add(key);
|
|
@@ -22,7 +22,7 @@ function updateMotionValuesFromProps(element, next, prev) {
|
|
|
22
22
|
* and warn against mismatches.
|
|
23
23
|
*/
|
|
24
24
|
if (process.env.NODE_ENV === "development") {
|
|
25
|
-
warnOnce(nextValue.version === "7.
|
|
25
|
+
warnOnce(nextValue.version === "7.8.0", `Attempting to mix Framer Motion versions ${nextValue.version} with 7.8.0 may not work as expected.`);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
else if (isMotionValue(prevValue)) {
|
package/dist/es/utils/delay.mjs
CHANGED
package/dist/es/value/index.mjs
CHANGED
|
@@ -25,7 +25,7 @@ class MotionValue {
|
|
|
25
25
|
* This will be replaced by the build step with the latest version number.
|
|
26
26
|
* When MotionValues are provided to motion components, warn if versions are mixed.
|
|
27
27
|
*/
|
|
28
|
-
this.version = "7.
|
|
28
|
+
this.version = "7.8.0";
|
|
29
29
|
/**
|
|
30
30
|
* Duration, in milliseconds, since last updating frame.
|
|
31
31
|
*
|