framer-motion 7.8.0 → 7.9.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.
Files changed (39) hide show
  1. package/README.md +6 -5
  2. package/dist/cjs/index.js +2030 -1920
  3. package/dist/es/animation/animate.mjs +2 -2
  4. package/dist/es/animation/create-instant-animation.mjs +12 -0
  5. package/dist/es/animation/{animation-controls.mjs → hooks/animation-controls.mjs} +2 -2
  6. package/dist/es/animation/{use-animated-state.mjs → hooks/use-animated-state.mjs} +6 -6
  7. package/dist/es/animation/{use-animation.mjs → hooks/use-animation.mjs} +1 -1
  8. package/dist/es/animation/index.mjs +124 -0
  9. package/dist/es/animation/legacy-popmotion/decay.mjs +11 -4
  10. package/dist/es/animation/legacy-popmotion/index.mjs +22 -11
  11. package/dist/es/animation/legacy-popmotion/inertia.mjs +14 -8
  12. package/dist/es/animation/legacy-popmotion/keyframes.mjs +21 -13
  13. package/dist/es/animation/legacy-popmotion/spring.mjs +13 -11
  14. package/dist/es/animation/utils/default-transitions.mjs +9 -14
  15. package/dist/es/animation/utils/keyframes.mjs +41 -0
  16. package/dist/es/animation/utils/transitions.mjs +1 -166
  17. package/dist/es/animation/waapi/create-accelerated-animation.mjs +82 -0
  18. package/dist/es/animation/waapi/index.mjs +4 -6
  19. package/dist/es/gestures/drag/VisualElementDragControls.mjs +2 -2
  20. package/dist/es/index.mjs +3 -3
  21. package/dist/es/render/VisualElement.mjs +1 -1
  22. package/dist/es/render/utils/animation.mjs +2 -2
  23. package/dist/es/render/utils/motion-values.mjs +2 -2
  24. package/dist/es/render/utils/setters.mjs +1 -1
  25. package/dist/es/value/index.mjs +11 -5
  26. package/dist/es/value/use-spring.mjs +1 -2
  27. package/dist/framer-motion.dev.js +2051 -1941
  28. package/dist/framer-motion.js +1 -1
  29. package/dist/index.d.ts +409 -348
  30. package/dist/projection.dev.js +1672 -1535
  31. package/dist/size-rollup-dom-animation-assets.js +1 -1
  32. package/dist/size-rollup-dom-animation.js +1 -1
  33. package/dist/size-rollup-dom-max-assets.js +1 -1
  34. package/dist/size-rollup-dom-max.js +1 -1
  35. package/dist/size-rollup-motion.js +1 -1
  36. package/dist/size-webpack-dom-animation.js +1 -1
  37. package/dist/size-webpack-dom-max.js +1 -1
  38. package/dist/three-entry.d.ts +287 -281
  39. package/package.json +8 -8
@@ -1,14 +1,4 @@
1
- import { secondsToMilliseconds } from '../../utils/time-conversion.mjs';
2
- import { isEasingArray, easingDefinitionToFunction } from './easing.mjs';
3
- import { isAnimatable } from './is-animatable.mjs';
4
- import { getDefaultTransition } from './default-transitions.mjs';
5
- import { warning } from 'hey-listen';
6
1
  import { getAnimatableNone } from '../../render/dom/value-types/animatable-none.mjs';
7
- import { instantAnimationState } from '../../utils/use-instant-transition-state.mjs';
8
- import { resolveFinalValueInKeyframes } from '../../utils/resolve-value.mjs';
9
- import { inertia } from '../legacy-popmotion/inertia.mjs';
10
- import { animate } from '../legacy-popmotion/index.mjs';
11
- import { delay } from '../../utils/delay.mjs';
12
2
 
13
3
  /**
14
4
  * Decide whether a transition is defined on a given Transition.
@@ -18,149 +8,6 @@ import { delay } from '../../utils/delay.mjs';
18
8
  function isTransitionDefined({ when, delay: _delay, delayChildren, staggerChildren, staggerDirection, repeat, repeatType, repeatDelay, from, ...transition }) {
19
9
  return !!Object.keys(transition).length;
20
10
  }
21
- /**
22
- * Convert Framer Motion's Transition type into Popmotion-compatible options.
23
- */
24
- function convertTransitionToAnimationOptions({ ease, times, ...transition }) {
25
- const options = { ...transition };
26
- if (times)
27
- options["offset"] = times;
28
- /**
29
- * Convert any existing durations from seconds to milliseconds
30
- */
31
- if (transition.duration)
32
- options["duration"] = secondsToMilliseconds(transition.duration);
33
- if (transition.repeatDelay)
34
- options.repeatDelay = secondsToMilliseconds(transition.repeatDelay);
35
- /**
36
- * Map easing names to Popmotion's easing functions
37
- */
38
- if (ease) {
39
- options["ease"] = isEasingArray(ease)
40
- ? ease.map(easingDefinitionToFunction)
41
- : easingDefinitionToFunction(ease);
42
- }
43
- /**
44
- * Support legacy transition API
45
- */
46
- if (transition.type === "tween")
47
- options.type = "keyframes";
48
- /**
49
- * TODO: Popmotion 9 has the ability to automatically detect whether to use
50
- * a keyframes or spring animation, but does so by detecting velocity and other spring options.
51
- * It'd be good to introduce a similar thing here.
52
- */
53
- if (transition.type !== "spring")
54
- options.type = "keyframes";
55
- return options;
56
- }
57
- /**
58
- * Get the delay for a value by checking Transition with decreasing specificity.
59
- */
60
- function getDelayFromTransition(transition, key) {
61
- const valueTransition = getValueTransition(transition, key) || {};
62
- return valueTransition.delay !== undefined
63
- ? valueTransition.delay
64
- : transition.delay !== undefined
65
- ? transition.delay
66
- : 0;
67
- }
68
- function hydrateKeyframes(options) {
69
- if (Array.isArray(options.to) && options.to[0] === null) {
70
- options.to = [...options.to];
71
- options.to[0] = options.from;
72
- }
73
- return options;
74
- }
75
- function getPopmotionAnimationOptions(transition, options, key) {
76
- if (Array.isArray(options.to) && transition.duration === undefined) {
77
- transition.duration = 0.8;
78
- }
79
- hydrateKeyframes(options);
80
- /**
81
- * Get a default transition if none is determined to be defined.
82
- */
83
- if (!isTransitionDefined(transition)) {
84
- transition = {
85
- ...transition,
86
- ...getDefaultTransition(key, options.to),
87
- };
88
- }
89
- return {
90
- ...options,
91
- ...convertTransitionToAnimationOptions(transition),
92
- };
93
- }
94
- /**
95
- *
96
- */
97
- function getAnimation(key, value, target, transition, onComplete) {
98
- const valueTransition = getValueTransition(transition, key) || {};
99
- const { elapsed = 0 } = transition;
100
- valueTransition.elapsed =
101
- elapsed - secondsToMilliseconds(transition.delay || 0);
102
- let origin = valueTransition.from !== undefined ? valueTransition.from : value.get();
103
- const isTargetAnimatable = isAnimatable(key, target);
104
- if (origin === "none" && isTargetAnimatable && typeof target === "string") {
105
- /**
106
- * If we're trying to animate from "none", try and get an animatable version
107
- * of the target. This could be improved to work both ways.
108
- */
109
- origin = getAnimatableNone(key, target);
110
- }
111
- else if (isZero(origin) && typeof target === "string") {
112
- origin = getZeroUnit(target);
113
- }
114
- else if (!Array.isArray(target) &&
115
- isZero(target) &&
116
- typeof origin === "string") {
117
- target = getZeroUnit(origin);
118
- }
119
- const isOriginAnimatable = isAnimatable(key, origin);
120
- warning(isOriginAnimatable === isTargetAnimatable, `You are trying to animate ${key} from "${origin}" to "${target}". ${origin} is not an animatable value - to enable this animation set ${origin} to a value animatable to ${target} via the \`style\` property.`);
121
- function start() {
122
- const options = {
123
- from: origin,
124
- to: target,
125
- velocity: value.getVelocity(),
126
- onComplete,
127
- onUpdate: (v) => value.set(v),
128
- };
129
- const animation = valueTransition.type === "inertia" ||
130
- valueTransition.type === "decay"
131
- ? inertia({ ...options, ...valueTransition })
132
- : animate({
133
- ...getPopmotionAnimationOptions(valueTransition, options, key),
134
- onUpdate: (v) => {
135
- options.onUpdate(v);
136
- valueTransition.onUpdate &&
137
- valueTransition.onUpdate(v);
138
- },
139
- onComplete: () => {
140
- options.onComplete();
141
- valueTransition.onComplete &&
142
- valueTransition.onComplete();
143
- },
144
- });
145
- return () => animation.stop();
146
- }
147
- function set() {
148
- const finalTarget = resolveFinalValueInKeyframes(target);
149
- value.set(finalTarget);
150
- onComplete();
151
- valueTransition.onUpdate && valueTransition.onUpdate(finalTarget);
152
- valueTransition.onComplete && valueTransition.onComplete();
153
- return () => { };
154
- }
155
- const useInstantAnimation = !isOriginAnimatable ||
156
- !isTargetAnimatable ||
157
- valueTransition.type === false;
158
- return useInstantAnimation
159
- ? valueTransition.elapsed
160
- ? () => delay(set, -valueTransition.elapsed)
161
- : set()
162
- : start();
163
- }
164
11
  function isZero(value) {
165
12
  return (value === 0 ||
166
13
  (typeof value === "string" &&
@@ -175,17 +22,5 @@ function getZeroUnit(potentialUnitType) {
175
22
  function getValueTransition(transition, key) {
176
23
  return transition[key] || transition["default"] || transition;
177
24
  }
178
- /**
179
- * Start animation on a MotionValue. This function is an interface between
180
- * Framer Motion and Popmotion
181
- */
182
- function startAnimation(key, value, target, transition = {}) {
183
- if (instantAnimationState.current) {
184
- transition = { type: false };
185
- }
186
- return value.start((onComplete) => {
187
- return getAnimation(key, value, target, { ...transition, delay: getDelayFromTransition(transition, key) }, onComplete);
188
- });
189
- }
190
25
 
191
- export { convertTransitionToAnimationOptions, getDelayFromTransition, getPopmotionAnimationOptions, getValueTransition, getZeroUnit, hydrateKeyframes, isTransitionDefined, isZero, startAnimation };
26
+ export { getValueTransition, getZeroUnit, isTransitionDefined, isZero };
@@ -0,0 +1,82 @@
1
+ import { sync } from '../../frameloop/index.mjs';
2
+ import { animate } from '../legacy-popmotion/index.mjs';
3
+ import { spring } from '../legacy-popmotion/spring.mjs';
4
+ import { animateStyle } from './index.mjs';
5
+
6
+ /**
7
+ * 10ms is chosen here as it strikes a balance between smooth
8
+ * results (more than one keyframe per frame at 60fps) and
9
+ * keyframe quantity.
10
+ */
11
+ const sampleDelta = 10; //ms
12
+ function createAcceleratedAnimation(value, valueName, { onUpdate, onComplete, ...options }) {
13
+ let { keyframes, duration = 0.3, elapsed = 0, ease } = options;
14
+ /**
15
+ * If this is a spring animation, pre-generate keyframes and
16
+ * record duration.
17
+ *
18
+ * TODO: When introducing support for values beyond opacity it
19
+ * might be better to use `animate.sample()`
20
+ */
21
+ if (options.type === "spring") {
22
+ const springAnimation = spring(options);
23
+ let state = { done: false, value: keyframes[0] };
24
+ const springKeyframes = [];
25
+ let t = 0;
26
+ while (!state.done) {
27
+ state = springAnimation.next(t);
28
+ springKeyframes.push(state.value);
29
+ t += sampleDelta;
30
+ }
31
+ keyframes = springKeyframes;
32
+ duration = t - sampleDelta;
33
+ ease = "linear";
34
+ }
35
+ const animation = animateStyle(value.owner.current, valueName, keyframes, {
36
+ ...options,
37
+ delay: -elapsed,
38
+ duration,
39
+ /**
40
+ * This function is currently not called if ease is provided
41
+ * as a function so the cast is safe.
42
+ *
43
+ * However it would be possible for a future refinement to port
44
+ * in easing pregeneration from Motion One for browsers that
45
+ * support the upcoming `linear()` easing function.
46
+ */
47
+ ease: ease,
48
+ });
49
+ /**
50
+ * Prefer the `onfinish` prop as it's more widely supported than
51
+ * the `finished` promise.
52
+ *
53
+ * Here, we synchronously set the provided MotionValue to the end
54
+ * keyframe. If we didn't, when the WAAPI animation is finished it would
55
+ * be removed from the element which would then revert to its old styles.
56
+ */
57
+ animation.onfinish = () => {
58
+ value.set(keyframes[keyframes.length - 1]);
59
+ onComplete && onComplete();
60
+ };
61
+ /**
62
+ * Animation interrupt callback.
63
+ */
64
+ return () => {
65
+ /**
66
+ * WAAPI doesn't natively have any interruption capabilities.
67
+ *
68
+ * Rather than read commited styles back out of the DOM, we can
69
+ * create a renderless JS animation and sample it twice to calculate
70
+ * its current value, "previous" value, and therefore allow
71
+ * Motion to calculate velocity for any subsequent animation.
72
+ */
73
+ const { currentTime } = animation;
74
+ if (currentTime) {
75
+ const sampleAnimation = animate(options);
76
+ value.setWithVelocity(sampleAnimation.sample(currentTime - sampleDelta), sampleAnimation.sample(currentTime), sampleDelta);
77
+ }
78
+ sync.update(() => animation.cancel());
79
+ };
80
+ }
81
+
82
+ export { createAcceleratedAnimation };
@@ -1,16 +1,14 @@
1
- import { supports } from './supports.mjs';
2
1
  import { cubicBezierAsString } from './easing.mjs';
3
2
 
4
- function animateStyle(element, valueName, keyframes, { delay, duration, ease }) {
5
- if (!supports.waapi())
6
- return undefined;
7
- const animation = element.animate({ [valueName]: keyframes }, {
3
+ function animateStyle(element, valueName, keyframes, { delay = 0, duration, repeat = 0, repeatType = "loop", ease, times, } = {}) {
4
+ return element.animate({ [valueName]: keyframes, offset: times }, {
8
5
  delay,
9
6
  duration,
10
7
  easing: Array.isArray(ease) ? cubicBezierAsString(ease) : ease,
11
8
  fill: "both",
9
+ iterations: repeat + 1,
10
+ direction: repeatType === "reverse" ? "alternate" : "normal",
12
11
  });
13
- return animation;
14
12
  }
15
13
 
16
14
  export { animateStyle };
@@ -9,12 +9,12 @@ import { createBox } from '../../projection/geometry/models.mjs';
9
9
  import { eachAxis } from '../../projection/utils/each-axis.mjs';
10
10
  import { measurePageBox } from '../../projection/utils/measure.mjs';
11
11
  import { extractEventInfo } from '../../events/event-info.mjs';
12
- import { startAnimation } from '../../animation/utils/transitions.mjs';
13
12
  import { convertBoxToBoundingBox, convertBoundingBoxToBox } from '../../projection/geometry/conversion.mjs';
14
13
  import { addDomEvent } from '../../events/use-dom-event.mjs';
15
14
  import { calcLength } from '../../projection/geometry/delta-calc.mjs';
16
15
  import { mix } from '../../utils/mix.mjs';
17
16
  import { percent } from '../../value/types/numbers/units.mjs';
17
+ import { createMotionValueAnimation } from '../../animation/index.mjs';
18
18
 
19
19
  const elementDragControls = new WeakMap();
20
20
  /**
@@ -271,7 +271,7 @@ class VisualElementDragControls {
271
271
  }
272
272
  startAxisValueAnimation(axis, transition) {
273
273
  const axisValue = this.getAxisMotionValue(axis);
274
- return startAnimation(axis, axisValue, 0, transition);
274
+ return axisValue.start(createMotionValueAnimation(axis, axisValue, 0, transition));
275
275
  }
276
276
  stopAnimation() {
277
277
  eachAxis((axis) => this.getAxisMotionValue(axis).stop());
package/dist/es/index.mjs CHANGED
@@ -22,8 +22,8 @@ export { useTime } from './value/use-time.mjs';
22
22
  export { useWillChange } from './value/use-will-change/index.mjs';
23
23
  export { useReducedMotion } from './utils/reduced-motion/use-reduced-motion.mjs';
24
24
  export { useReducedMotionConfig } from './utils/reduced-motion/use-reduced-motion-config.mjs';
25
- export { animationControls } from './animation/animation-controls.mjs';
26
- export { useAnimation, useAnimationControls } from './animation/use-animation.mjs';
25
+ export { animationControls } from './animation/hooks/animation-controls.mjs';
26
+ export { useAnimation, useAnimationControls } from './animation/hooks/use-animation.mjs';
27
27
  export { useAnimationFrame } from './utils/use-animation-frame.mjs';
28
28
  export { animate } from './animation/animate.mjs';
29
29
  export { animateVisualElement } from './render/utils/animation.mjs';
@@ -59,7 +59,7 @@ export { LayoutGroupContext } from './context/LayoutGroupContext.mjs';
59
59
  export { DeprecatedLayoutGroupContext } from './context/DeprecatedLayoutGroupContext.mjs';
60
60
  export { SwitchLayoutGroupContext } from './context/SwitchLayoutGroupContext.mjs';
61
61
  export { FlatTree } from './render/utils/flat-tree.mjs';
62
- export { useAnimatedState as useDeprecatedAnimatedState } from './animation/use-animated-state.mjs';
62
+ export { useAnimatedState as useDeprecatedAnimatedState } from './animation/hooks/use-animated-state.mjs';
63
63
  export { useInvertedScale as useDeprecatedInvertedScale } from './value/use-inverted-scale.mjs';
64
64
  export { AnimationType } from './render/utils/types.mjs';
65
65
  export { animations } from './motion/features/animations.mjs';
@@ -403,7 +403,7 @@ class VisualElement {
403
403
  }
404
404
  let value = this.values.get(key);
405
405
  if (value === undefined && defaultValue !== undefined) {
406
- value = motionValue(defaultValue);
406
+ value = motionValue(defaultValue, { owner: this });
407
407
  this.addValue(key, value);
408
408
  }
409
409
  return value;
@@ -1,10 +1,10 @@
1
- import { startAnimation } from '../../animation/utils/transitions.mjs';
2
1
  import { setTarget } from './setters.mjs';
3
2
  import { resolveVariant } from './resolve-dynamic-variants.mjs';
4
3
  import { transformProps } from '../html/utils/transform.mjs';
5
4
  import { isWillChangeMotionValue } from '../../value/use-will-change/is.mjs';
6
5
  import { handoffOptimizedAppearAnimation } from '../../animation/optimized-appear/handoff.mjs';
7
6
  import { optimizedAppearDataAttribute } from '../../animation/optimized-appear/data-id.mjs';
7
+ import { createMotionValueAnimation } from '../../animation/index.mjs';
8
8
 
9
9
  function animateVisualElement(visualElement, definition, options = {}) {
10
10
  visualElement.notify("AnimationStart", definition);
@@ -104,7 +104,7 @@ function animateTarget(visualElement, definition, { delay = 0, transitionOverrid
104
104
  valueTransition.elapsed = handoffOptimizedAppearAnimation(appearId, key);
105
105
  }
106
106
  }
107
- let animation = startAnimation(key, value, valueTarget, valueTransition);
107
+ let animation = value.start(createMotionValueAnimation(key, value, valueTarget, valueTransition));
108
108
  if (isWillChangeMotionValue(willChange)) {
109
109
  willChange.add(key);
110
110
  animation = animation.then(() => willChange.remove(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.8.0", `Attempting to mix Framer Motion versions ${nextValue.version} with 7.8.0 may not work as expected.`);
25
+ warnOnce(nextValue.version === "7.9.0", `Attempting to mix Framer Motion versions ${nextValue.version} with 7.9.0 may not work as expected.`);
26
26
  }
27
27
  }
28
28
  else if (isMotionValue(prevValue)) {
@@ -30,7 +30,7 @@ function updateMotionValuesFromProps(element, next, prev) {
30
30
  * If we're swapping from a motion value to a static value,
31
31
  * create a new motion value from that
32
32
  */
33
- element.addValue(key, motionValue(nextValue));
33
+ element.addValue(key, motionValue(nextValue, { owner: element }));
34
34
  if (isWillChangeMotionValue(willChange)) {
35
35
  willChange.remove(key);
36
36
  }
@@ -89,7 +89,7 @@ function checkTargetForNewValues(visualElement, target, origin) {
89
89
  else if (!findValueType(value) && complex.test(targetValue)) {
90
90
  value = getAnimatableNone(key, targetValue);
91
91
  }
92
- visualElement.addValue(key, motionValue(value));
92
+ visualElement.addValue(key, motionValue(value, { owner: visualElement }));
93
93
  if (origin[key] === undefined) {
94
94
  origin[key] = value;
95
95
  }
@@ -1,5 +1,5 @@
1
- import { sync } from '../frameloop/index.mjs';
2
1
  import { frameData } from '../frameloop/data.mjs';
2
+ import { sync } from '../frameloop/index.mjs';
3
3
  import { SubscriptionManager } from '../utils/subscription-manager.mjs';
4
4
  import { velocityPerSecond } from '../utils/velocity-per-second.mjs';
5
5
 
@@ -20,12 +20,12 @@ class MotionValue {
20
20
  *
21
21
  * @internal
22
22
  */
23
- constructor(init) {
23
+ constructor(init, options = {}) {
24
24
  /**
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.8.0";
28
+ this.version = "7.9.0";
29
29
  /**
30
30
  * Duration, in milliseconds, since last updating frame.
31
31
  *
@@ -114,6 +114,7 @@ class MotionValue {
114
114
  this.hasAnimated = false;
115
115
  this.prev = this.current = init;
116
116
  this.canTrackVelocity = isFloat(this.current);
117
+ this.owner = options.owner;
117
118
  }
118
119
  /**
119
120
  * Adds a function that will be notified when the `MotionValue` is updated.
@@ -213,6 +214,11 @@ class MotionValue {
213
214
  this.passiveEffect(v, this.updateAndNotify);
214
215
  }
215
216
  }
217
+ setWithVelocity(prev, current, delta) {
218
+ this.set(current);
219
+ this.prev = prev;
220
+ this.timeDelta = delta;
221
+ }
216
222
  /**
217
223
  * Returns the latest state of `MotionValue`
218
224
  *
@@ -299,8 +305,8 @@ class MotionValue {
299
305
  this.stop();
300
306
  }
301
307
  }
302
- function motionValue(init) {
303
- return new MotionValue(init);
308
+ function motionValue(init, options) {
309
+ return new MotionValue(init, options);
304
310
  }
305
311
 
306
312
  export { MotionValue, motionValue };
@@ -40,8 +40,7 @@ function useSpring(source, config = {}) {
40
40
  activeSpringAnimation.current.stop();
41
41
  }
42
42
  activeSpringAnimation.current = animate({
43
- from: value.get(),
44
- to: v,
43
+ keyframes: [value.get(), v],
45
44
  velocity: value.getVelocity(),
46
45
  type: "spring",
47
46
  ...config,