framer-motion 10.2.2 → 10.2.4

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.
Files changed (36) hide show
  1. package/dist/cjs/dom-entry.js +1 -1
  2. package/dist/cjs/index.js +18 -20
  3. package/dist/cjs/{wrap-b7ab39cb.js → wrap-62da7859.js} +456 -438
  4. package/dist/dom-entry.d.ts +497 -49
  5. package/dist/es/animation/GroupPlaybackControls.mjs +25 -0
  6. package/dist/es/animation/animate.mjs +2 -4
  7. package/dist/es/animation/create-instant-animation.mjs +13 -3
  8. package/dist/es/animation/generators/inertia.mjs +87 -0
  9. package/dist/es/animation/{legacy-popmotion → generators}/keyframes.mjs +8 -15
  10. package/dist/es/animation/{legacy-popmotion/find-spring.mjs → generators/spring/find.mjs} +6 -5
  11. package/dist/es/animation/generators/spring/index.mjs +129 -0
  12. package/dist/es/animation/generators/utils/velocity.mjs +9 -0
  13. package/dist/es/animation/index.mjs +2 -10
  14. package/dist/es/animation/js/driver-frameloop.mjs +12 -0
  15. package/dist/es/animation/js/index.mjs +206 -0
  16. package/dist/es/animation/optimized-appear/handoff.mjs +3 -1
  17. package/dist/es/animation/waapi/create-accelerated-animation.mjs +16 -10
  18. package/dist/es/frameloop/index.mjs +3 -4
  19. package/dist/es/gestures/pan/PanSession.mjs +2 -2
  20. package/dist/es/index.mjs +2 -3
  21. package/dist/es/render/utils/motion-values.mjs +1 -1
  22. package/dist/es/utils/time-conversion.mjs +2 -1
  23. package/dist/es/value/index.mjs +3 -3
  24. package/dist/es/value/use-spring.mjs +1 -1
  25. package/dist/es/value/use-velocity.mjs +4 -6
  26. package/dist/framer-motion.dev.js +475 -459
  27. package/dist/framer-motion.js +1 -1
  28. package/dist/index.d.ts +70 -114
  29. package/dist/projection.dev.js +5849 -5831
  30. package/dist/three-entry.d.ts +11 -9
  31. package/package.json +7 -7
  32. package/dist/es/animation/legacy-popmotion/decay.mjs +0 -34
  33. package/dist/es/animation/legacy-popmotion/index.mjs +0 -163
  34. package/dist/es/animation/legacy-popmotion/inertia.mjs +0 -90
  35. package/dist/es/animation/legacy-popmotion/spring.mjs +0 -143
  36. package/dist/es/frameloop/on-next-frame.mjs +0 -12
@@ -852,6 +852,13 @@ interface CustomValueType {
852
852
  toValue: () => number | string;
853
853
  }
854
854
 
855
+ /**
856
+ * @public
857
+ */
858
+ interface AnimationPlaybackControls {
859
+ currentTime: number;
860
+ stop: () => void;
861
+ }
855
862
  /**
856
863
  * @public
857
864
  */
@@ -1233,14 +1240,6 @@ declare class NodeStack {
1233
1240
  removeLeadSnapshot(): void;
1234
1241
  }
1235
1242
 
1236
- /**
1237
- * @public
1238
- */
1239
- interface AnimationPlaybackControls {
1240
- stop: () => void;
1241
- isAnimating: () => boolean;
1242
- }
1243
-
1244
1243
  interface WithDepth {
1245
1244
  depth: number;
1246
1245
  }
@@ -1414,9 +1413,12 @@ declare function MeasureLayout(props: MotionProps & {
1414
1413
  visualElement: VisualElement;
1415
1414
  }): JSX.Element;
1416
1415
 
1416
+ interface FeatureClass<Props = unknown> {
1417
+ new (props: Props): Feature<Props>;
1418
+ }
1417
1419
  declare type HydratedFeatureDefinition = {
1418
1420
  isEnabled: (props: MotionProps) => boolean;
1419
- Feature: typeof Feature<unknown>;
1421
+ Feature: FeatureClass<unknown>;
1420
1422
  ProjectionNode?: any;
1421
1423
  MeasureLayout?: typeof MeasureLayout;
1422
1424
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "framer-motion",
3
- "version": "10.2.2",
3
+ "version": "10.2.4",
4
4
  "description": "A simple and powerful React and JavaScript animation library",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/es/index.mjs",
@@ -85,7 +85,7 @@
85
85
  "bundlesize": [
86
86
  {
87
87
  "path": "./dist/size-rollup-motion.js",
88
- "maxSize": "29.96 kB"
88
+ "maxSize": "29.85 kB"
89
89
  },
90
90
  {
91
91
  "path": "./dist/size-rollup-m.js",
@@ -93,11 +93,11 @@
93
93
  },
94
94
  {
95
95
  "path": "./dist/size-rollup-dom-animation.js",
96
- "maxSize": "14.79 kB"
96
+ "maxSize": "14.56 kB"
97
97
  },
98
98
  {
99
99
  "path": "./dist/size-rollup-dom-max.js",
100
- "maxSize": "25.69 kB"
100
+ "maxSize": "25.6 kB"
101
101
  },
102
102
  {
103
103
  "path": "./dist/size-rollup-animate.js",
@@ -109,12 +109,12 @@
109
109
  },
110
110
  {
111
111
  "path": "./dist/size-webpack-dom-animation.js",
112
- "maxSize": "18.8 kB"
112
+ "maxSize": "18.56 kB"
113
113
  },
114
114
  {
115
115
  "path": "./dist/size-webpack-dom-max.js",
116
- "maxSize": "30.55 kB"
116
+ "maxSize": "30.42 kB"
117
117
  }
118
118
  ],
119
- "gitHead": "daeddff03d931dba8ca04611b66b64b4f40b4736"
119
+ "gitHead": "82eb0ba26cd103d524a27dc95415e437cce35822"
120
120
  }
@@ -1,34 +0,0 @@
1
- function decay({
2
- /**
3
- * The decay animation dynamically calculates an end of the animation
4
- * based on the initial keyframe, so we only need to define a single keyframe
5
- * as default.
6
- */
7
- keyframes = [0], velocity = 0, power = 0.8, timeConstant = 350, restDelta = 0.5, modifyTarget, }) {
8
- const origin = keyframes[0];
9
- /**
10
- * This is the Iterator-spec return value. We ensure it's mutable rather than using a generator
11
- * to reduce GC during animation.
12
- */
13
- const state = { done: false, value: origin };
14
- let amplitude = power * velocity;
15
- const ideal = origin + amplitude;
16
- const target = modifyTarget === undefined ? ideal : modifyTarget(ideal);
17
- /**
18
- * If the target has changed we need to re-calculate the amplitude, otherwise
19
- * the animation will start from the wrong position.
20
- */
21
- if (target !== ideal)
22
- amplitude = target - origin;
23
- return {
24
- next: (t) => {
25
- const delta = -amplitude * Math.exp(-t / timeConstant);
26
- state.done = !(delta > restDelta || delta < -restDelta);
27
- state.value = state.done ? target : target + delta;
28
- return state;
29
- },
30
- flipTarget: () => { },
31
- };
32
- }
33
-
34
- export { decay };
@@ -1,163 +0,0 @@
1
- import { keyframes } from './keyframes.mjs';
2
- import { spring } from './spring.mjs';
3
- import { decay } from './decay.mjs';
4
- import { sync, cancelSync } from '../../frameloop/index.mjs';
5
- import { interpolate } from '../../utils/interpolate.mjs';
6
-
7
- const types = {
8
- decay,
9
- keyframes: keyframes,
10
- tween: keyframes,
11
- spring,
12
- };
13
- function loopElapsed(elapsed, duration, delay = 0) {
14
- return elapsed - duration - delay;
15
- }
16
- function reverseElapsed(elapsed, duration = 0, delay = 0, isForwardPlayback = true) {
17
- return isForwardPlayback
18
- ? loopElapsed(duration + -elapsed, duration, delay)
19
- : duration - (elapsed - duration) + delay;
20
- }
21
- function hasRepeatDelayElapsed(elapsed, duration, delay, isForwardPlayback) {
22
- return isForwardPlayback ? elapsed >= duration + delay : elapsed <= -delay;
23
- }
24
- const framesync = (update) => {
25
- const passTimestamp = ({ delta }) => update(delta);
26
- return {
27
- start: () => sync.update(passTimestamp, true),
28
- stop: () => cancelSync.update(passTimestamp),
29
- };
30
- };
31
- function animateValue({ duration, driver = framesync, elapsed = 0, repeat: repeatMax = 0, repeatType = "loop", repeatDelay = 0, keyframes: keyframes$1, autoplay = true, onPlay, onStop, onComplete, onRepeat, onUpdate, type = "keyframes", ...options }) {
32
- const initialElapsed = elapsed;
33
- let driverControls;
34
- let repeatCount = 0;
35
- let computedDuration = duration;
36
- let isComplete = false;
37
- let isForwardPlayback = true;
38
- let interpolateFromNumber;
39
- const animator = types[keyframes$1.length > 2 ? "keyframes" : type] || keyframes;
40
- const origin = keyframes$1[0];
41
- const target = keyframes$1[keyframes$1.length - 1];
42
- let state = { done: false, value: origin };
43
- /**
44
- * If this value needs interpolation (ie is non-numerical), set up an interpolator.
45
- * TODO: Keyframes animation also performs this step. This could be removed so it only happens here.
46
- */
47
- const { needsInterpolation } = animator;
48
- if (needsInterpolation && needsInterpolation(origin, target)) {
49
- interpolateFromNumber = interpolate([0, 100], [origin, target], {
50
- clamp: false,
51
- });
52
- keyframes$1 = [0, 100];
53
- }
54
- const animation = animator({
55
- ...options,
56
- duration,
57
- keyframes: keyframes$1,
58
- });
59
- function repeat() {
60
- repeatCount++;
61
- if (repeatType === "reverse") {
62
- isForwardPlayback = repeatCount % 2 === 0;
63
- elapsed = reverseElapsed(elapsed, computedDuration, repeatDelay, isForwardPlayback);
64
- }
65
- else {
66
- elapsed = loopElapsed(elapsed, computedDuration, repeatDelay);
67
- if (repeatType === "mirror")
68
- animation.flipTarget();
69
- }
70
- isComplete = false;
71
- onRepeat && onRepeat();
72
- }
73
- function complete() {
74
- driverControls && driverControls.stop();
75
- onComplete && onComplete();
76
- }
77
- function update(delta) {
78
- if (!isForwardPlayback)
79
- delta = -delta;
80
- elapsed += delta;
81
- if (!isComplete) {
82
- state = animation.next(Math.max(0, elapsed));
83
- if (interpolateFromNumber)
84
- state.value = interpolateFromNumber(state.value);
85
- isComplete = isForwardPlayback ? state.done : elapsed <= 0;
86
- }
87
- onUpdate && onUpdate(state.value);
88
- if (isComplete) {
89
- if (repeatCount === 0) {
90
- computedDuration =
91
- computedDuration !== undefined ? computedDuration : elapsed;
92
- }
93
- if (repeatCount < repeatMax) {
94
- hasRepeatDelayElapsed(elapsed, computedDuration, repeatDelay, isForwardPlayback) && repeat();
95
- }
96
- else {
97
- complete();
98
- }
99
- }
100
- }
101
- function play() {
102
- onPlay && onPlay();
103
- driverControls = driver(update);
104
- driverControls.start();
105
- }
106
- autoplay && play();
107
- return {
108
- stop: () => {
109
- onStop && onStop();
110
- driverControls && driverControls.stop();
111
- },
112
- /**
113
- * Set the current time of the animation. This is purposefully
114
- * mirroring the WAAPI animation API to make them interchanagable.
115
- * Going forward this file should be ported more towards
116
- * https://github.com/motiondivision/motionone/blob/main/packages/animation/src/Animation.ts
117
- * Which behaviourally adheres to WAAPI as far as possible.
118
- *
119
- * WARNING: This is not safe to use for most animations. We currently
120
- * only use it for handoff from WAAPI within Framer.
121
- *
122
- * This animation function consumes time every frame rather than being sampled for time.
123
- * So the sample() method performs some headless frames to ensure
124
- * repeats are handled correctly. Ideally in the future we will replace
125
- * that method with this, once repeat calculations are pure.
126
- */
127
- set currentTime(t) {
128
- elapsed = initialElapsed;
129
- update(t);
130
- },
131
- /**
132
- * animate() can't yet be sampled for time, instead it
133
- * consumes time. So to sample it we have to run a low
134
- * temporal-resolution version.
135
- *
136
- * isControlled should be set to true if sample is being run within
137
- * a loop. This indicates that we're not arbitrarily sampling
138
- * the animation but running it one step after another. Therefore
139
- * we don't need to run a low-res version here. This is a stop-gap
140
- * until a rewrite can sample for time.
141
- */
142
- sample: (t, isControlled = false) => {
143
- elapsed = initialElapsed;
144
- if (isControlled) {
145
- update(t);
146
- return state;
147
- }
148
- const sampleResolution = duration && typeof duration === "number"
149
- ? Math.max(duration * 0.5, 50)
150
- : 50;
151
- let sampleElapsed = 0;
152
- update(0);
153
- while (sampleElapsed <= t) {
154
- const remaining = t - sampleElapsed;
155
- update(Math.min(remaining, sampleResolution));
156
- sampleElapsed += sampleResolution;
157
- }
158
- return state;
159
- },
160
- };
161
- }
162
-
163
- export { animateValue, hasRepeatDelayElapsed, loopElapsed, reverseElapsed };
@@ -1,90 +0,0 @@
1
- import { animateValue } from './index.mjs';
2
- import { velocityPerSecond } from '../../utils/velocity-per-second.mjs';
3
- import { frameData } from '../../frameloop/data.mjs';
4
-
5
- function inertia({ keyframes, velocity = 0, min, max, power = 0.8, timeConstant = 750, bounceStiffness = 500, bounceDamping = 10, restDelta = 1, modifyTarget, driver, onUpdate, onComplete, onStop, }) {
6
- const origin = keyframes[0];
7
- let currentAnimation;
8
- function isOutOfBounds(v) {
9
- return (min !== undefined && v < min) || (max !== undefined && v > max);
10
- }
11
- function findNearestBoundary(v) {
12
- if (min === undefined)
13
- return max;
14
- if (max === undefined)
15
- return min;
16
- return Math.abs(min - v) < Math.abs(max - v) ? min : max;
17
- }
18
- function startAnimation(options) {
19
- currentAnimation && currentAnimation.stop();
20
- currentAnimation = animateValue({
21
- keyframes: [0, 1],
22
- velocity: 0,
23
- ...options,
24
- driver,
25
- onUpdate: (v) => {
26
- onUpdate && onUpdate(v);
27
- options.onUpdate && options.onUpdate(v);
28
- },
29
- onComplete,
30
- onStop,
31
- });
32
- }
33
- function startSpring(options) {
34
- startAnimation({
35
- type: "spring",
36
- stiffness: bounceStiffness,
37
- damping: bounceDamping,
38
- restDelta,
39
- ...options,
40
- });
41
- }
42
- if (isOutOfBounds(origin)) {
43
- // Start the animation with spring if outside the defined boundaries
44
- startSpring({
45
- velocity,
46
- keyframes: [origin, findNearestBoundary(origin)],
47
- });
48
- }
49
- else {
50
- /**
51
- * Or if the value is out of bounds, simulate the inertia movement
52
- * with the decay animation.
53
- *
54
- * Pre-calculate the target so we can detect if it's out-of-bounds.
55
- * If it is, we want to check per frame when to switch to a spring
56
- * animation
57
- */
58
- let target = power * velocity + origin;
59
- if (typeof modifyTarget !== "undefined")
60
- target = modifyTarget(target);
61
- const boundary = findNearestBoundary(target);
62
- const heading = boundary === min ? -1 : 1;
63
- let prev;
64
- let current;
65
- const checkBoundary = (v) => {
66
- prev = current;
67
- current = v;
68
- velocity = velocityPerSecond(v - prev, frameData.delta);
69
- if ((heading === 1 && v > boundary) ||
70
- (heading === -1 && v < boundary)) {
71
- startSpring({ keyframes: [v, boundary], velocity });
72
- }
73
- };
74
- startAnimation({
75
- type: "decay",
76
- keyframes: [origin, 0],
77
- velocity,
78
- timeConstant,
79
- power,
80
- restDelta,
81
- modifyTarget,
82
- onUpdate: isOutOfBounds(target) ? checkBoundary : undefined,
83
- });
84
- }
85
- return {
86
- stop: () => currentAnimation && currentAnimation.stop(),
87
- };
88
- }
89
-
90
- export { inertia };
@@ -1,143 +0,0 @@
1
- import { findSpring, calcAngularFreq } from './find-spring.mjs';
2
- import { velocityPerSecond } from '../../utils/velocity-per-second.mjs';
3
-
4
- const durationKeys = ["duration", "bounce"];
5
- const physicsKeys = ["stiffness", "damping", "mass"];
6
- function isSpringType(options, keys) {
7
- return keys.some((key) => options[key] !== undefined);
8
- }
9
- function getSpringOptions(options) {
10
- let springOptions = {
11
- velocity: 0.0,
12
- stiffness: 100,
13
- damping: 10,
14
- mass: 1.0,
15
- isResolvedFromDuration: false,
16
- ...options,
17
- };
18
- // stiffness/damping/mass overrides duration/bounce
19
- if (!isSpringType(options, physicsKeys) &&
20
- isSpringType(options, durationKeys)) {
21
- const derived = findSpring(options);
22
- springOptions = {
23
- ...springOptions,
24
- ...derived,
25
- velocity: 0.0,
26
- mass: 1.0,
27
- };
28
- springOptions.isResolvedFromDuration = true;
29
- }
30
- return springOptions;
31
- }
32
- const velocitySampleDuration = 5;
33
- /**
34
- * This is based on the spring implementation of Wobble https://github.com/skevy/wobble
35
- */
36
- function spring({ keyframes, restDelta, restSpeed, ...options }) {
37
- let origin = keyframes[0];
38
- let target = keyframes[keyframes.length - 1];
39
- /**
40
- * This is the Iterator-spec return value. We ensure it's mutable rather than using a generator
41
- * to reduce GC during animation.
42
- */
43
- const state = { done: false, value: origin };
44
- const { stiffness, damping, mass, velocity, duration, isResolvedFromDuration, } = getSpringOptions(options);
45
- let resolveSpring = zero;
46
- let initialVelocity = velocity ? -(velocity / 1000) : 0.0;
47
- const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass));
48
- function createSpring() {
49
- const initialDelta = target - origin;
50
- const undampedAngularFreq = Math.sqrt(stiffness / mass) / 1000;
51
- /**
52
- * If we're working on a granular scale, use smaller defaults for determining
53
- * when the spring is finished.
54
- *
55
- * These defaults have been selected emprically based on what strikes a good
56
- * ratio between feeling good and finishing as soon as changes are imperceptible.
57
- */
58
- const isGranularScale = Math.abs(initialDelta) < 5;
59
- restSpeed || (restSpeed = isGranularScale ? 0.01 : 2);
60
- restDelta || (restDelta = isGranularScale ? 0.005 : 0.5);
61
- if (dampingRatio < 1) {
62
- const angularFreq = calcAngularFreq(undampedAngularFreq, dampingRatio);
63
- // Underdamped spring
64
- resolveSpring = (t) => {
65
- const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
66
- return (target -
67
- envelope *
68
- (((initialVelocity +
69
- dampingRatio * undampedAngularFreq * initialDelta) /
70
- angularFreq) *
71
- Math.sin(angularFreq * t) +
72
- initialDelta * Math.cos(angularFreq * t)));
73
- };
74
- }
75
- else if (dampingRatio === 1) {
76
- // Critically damped spring
77
- resolveSpring = (t) => target -
78
- Math.exp(-undampedAngularFreq * t) *
79
- (initialDelta +
80
- (initialVelocity + undampedAngularFreq * initialDelta) *
81
- t);
82
- }
83
- else {
84
- // Overdamped spring
85
- const dampedAngularFreq = undampedAngularFreq * Math.sqrt(dampingRatio * dampingRatio - 1);
86
- resolveSpring = (t) => {
87
- const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t);
88
- // When performing sinh or cosh values can hit Infinity so we cap them here
89
- const freqForT = Math.min(dampedAngularFreq * t, 300);
90
- return (target -
91
- (envelope *
92
- ((initialVelocity +
93
- dampingRatio * undampedAngularFreq * initialDelta) *
94
- Math.sinh(freqForT) +
95
- dampedAngularFreq *
96
- initialDelta *
97
- Math.cosh(freqForT))) /
98
- dampedAngularFreq);
99
- };
100
- }
101
- }
102
- createSpring();
103
- return {
104
- next: (t) => {
105
- const current = resolveSpring(t);
106
- if (!isResolvedFromDuration) {
107
- let currentVelocity = initialVelocity;
108
- if (t !== 0) {
109
- /**
110
- * We only need to calculate velocity for under-damped springs
111
- * as over- and critically-damped springs can't overshoot, so
112
- * checking only for displacement is enough.
113
- */
114
- if (dampingRatio < 1) {
115
- const prevT = Math.max(0, t - velocitySampleDuration);
116
- currentVelocity = velocityPerSecond(current - resolveSpring(prevT), t - prevT);
117
- }
118
- else {
119
- currentVelocity = 0;
120
- }
121
- }
122
- const isBelowVelocityThreshold = Math.abs(currentVelocity) <= restSpeed;
123
- const isBelowDisplacementThreshold = Math.abs(target - current) <= restDelta;
124
- state.done =
125
- isBelowVelocityThreshold && isBelowDisplacementThreshold;
126
- }
127
- else {
128
- state.done = t >= duration;
129
- }
130
- state.value = state.done ? target : current;
131
- return state;
132
- },
133
- flipTarget: () => {
134
- initialVelocity = -initialVelocity;
135
- [origin, target] = [target, origin];
136
- createSpring();
137
- },
138
- };
139
- }
140
- spring.needsInterpolation = (a, b) => typeof a === "string" || typeof b === "string";
141
- const zero = (_t) => 0;
142
-
143
- export { spring };
@@ -1,12 +0,0 @@
1
- /*
2
- Detect and load appropriate clock setting for the execution environment
3
- */
4
- const defaultTimestep = (1 / 60) * 1000;
5
- const getCurrentTime = typeof performance !== "undefined"
6
- ? () => performance.now()
7
- : () => Date.now();
8
- const onNextFrame = typeof window !== "undefined"
9
- ? (callback) => window.requestAnimationFrame(callback)
10
- : (callback) => setTimeout(() => callback(getCurrentTime()), defaultTimestep);
11
-
12
- export { defaultTimestep, onNextFrame };