framer-motion 7.7.3 → 7.8.1

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 (43) hide show
  1. package/dist/cjs/index.js +1966 -1860
  2. package/dist/es/animation/animate.mjs +2 -2
  3. package/dist/es/animation/create-accelerated-animation.mjs +8 -0
  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 +121 -0
  9. package/dist/es/animation/legacy-popmotion/decay.mjs +11 -4
  10. package/dist/es/animation/legacy-popmotion/index.mjs +23 -15
  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 +33 -39
  14. package/dist/es/animation/optimized-appear/data-id.mjs +6 -0
  15. package/dist/es/animation/optimized-appear/handoff.mjs +34 -0
  16. package/dist/es/animation/optimized-appear/start.mjs +15 -0
  17. package/dist/es/animation/optimized-appear/store-id.mjs +3 -0
  18. package/dist/es/animation/utils/default-transitions.mjs +9 -14
  19. package/dist/es/animation/utils/keyframes.mjs +41 -0
  20. package/dist/es/animation/utils/transitions.mjs +1 -171
  21. package/dist/es/animation/waapi/easing.mjs +3 -0
  22. package/dist/es/animation/waapi/index.mjs +16 -0
  23. package/dist/es/animation/waapi/supports.mjs +17 -0
  24. package/dist/es/gestures/drag/VisualElementDragControls.mjs +2 -2
  25. package/dist/es/index.mjs +6 -3
  26. package/dist/es/render/utils/animation.mjs +15 -3
  27. package/dist/es/render/utils/motion-values.mjs +1 -1
  28. package/dist/es/utils/delay.mjs +3 -0
  29. package/dist/es/value/index.mjs +2 -2
  30. package/dist/es/value/use-spring.mjs +1 -2
  31. package/dist/framer-motion.dev.js +1971 -1865
  32. package/dist/framer-motion.js +1 -1
  33. package/dist/index.d.ts +424 -341
  34. package/dist/projection.dev.js +1655 -1623
  35. package/dist/size-rollup-dom-animation-assets.js +1 -1
  36. package/dist/size-rollup-dom-animation.js +1 -1
  37. package/dist/size-rollup-dom-max-assets.js +1 -1
  38. package/dist/size-rollup-dom-max.js +1 -1
  39. package/dist/size-rollup-motion.js +1 -1
  40. package/dist/size-webpack-dom-animation.js +1 -1
  41. package/dist/size-webpack-dom-max.js +1 -1
  42. package/dist/three-entry.d.ts +289 -282
  43. package/package.json +11 -9
@@ -1,15 +1,13 @@
1
- import { isKeyframesTarget } from './is-keyframes-target.mjs';
2
-
3
1
  const underDampedSpring = () => ({
4
2
  type: "spring",
5
3
  stiffness: 500,
6
4
  damping: 25,
7
5
  restSpeed: 10,
8
6
  });
9
- const criticallyDampedSpring = (to) => ({
7
+ const criticallyDampedSpring = (target) => ({
10
8
  type: "spring",
11
9
  stiffness: 550,
12
- damping: to === 0 ? 2 * Math.sqrt(550) : 30,
10
+ damping: target === 0 ? 2 * Math.sqrt(550) : 30,
13
11
  restSpeed: 10,
14
12
  });
15
13
  const linearTween = () => ({
@@ -17,11 +15,10 @@ const linearTween = () => ({
17
15
  ease: "linear",
18
16
  duration: 0.3,
19
17
  });
20
- const keyframes = (values) => ({
18
+ const keyframesTransition = {
21
19
  type: "keyframes",
22
20
  duration: 0.8,
23
- values,
24
- });
21
+ };
25
22
  const defaultTransitions = {
26
23
  x: underDampedSpring,
27
24
  y: underDampedSpring,
@@ -38,16 +35,14 @@ const defaultTransitions = {
38
35
  color: linearTween,
39
36
  default: criticallyDampedSpring,
40
37
  };
41
- const getDefaultTransition = (valueKey, to) => {
42
- let transitionFactory;
43
- if (isKeyframesTarget(to)) {
44
- transitionFactory = keyframes;
38
+ const getDefaultTransition = (valueKey, { keyframes }) => {
39
+ if (keyframes.length > 2) {
40
+ return keyframesTransition;
45
41
  }
46
42
  else {
47
- transitionFactory =
48
- defaultTransitions[valueKey] || defaultTransitions.default;
43
+ const factory = defaultTransitions[valueKey] || defaultTransitions.default;
44
+ return factory(keyframes[1]);
49
45
  }
50
- return { to, ...transitionFactory(to) };
51
46
  };
52
47
 
53
48
  export { criticallyDampedSpring, getDefaultTransition, linearTween, underDampedSpring };
@@ -0,0 +1,41 @@
1
+ import { getAnimatableNone } from '../../render/dom/value-types/animatable-none.mjs';
2
+ import { isAnimatable } from './is-animatable.mjs';
3
+ import { isZero, getZeroUnit } from './transitions.mjs';
4
+
5
+ function getKeyframes(value, valueName, target, transition) {
6
+ const isTargetAnimatable = isAnimatable(valueName, target);
7
+ let origin = transition.from !== undefined ? transition.from : value.get();
8
+ if (origin === "none" && isTargetAnimatable && typeof target === "string") {
9
+ /**
10
+ * If we're trying to animate from "none", try and get an animatable version
11
+ * of the target. This could be improved to work both ways.
12
+ */
13
+ origin = getAnimatableNone(valueName, target);
14
+ }
15
+ else if (isZero(origin) && typeof target === "string") {
16
+ origin = getZeroUnit(target);
17
+ }
18
+ else if (!Array.isArray(target) &&
19
+ isZero(target) &&
20
+ typeof origin === "string") {
21
+ target = getZeroUnit(origin);
22
+ }
23
+ /**
24
+ * If the target has been defined as a series of keyframes
25
+ */
26
+ if (Array.isArray(target)) {
27
+ /**
28
+ * Ensure an initial wildcard keyframe is hydrated by the origin.
29
+ * TODO: Support extra wildcard keyframes i.e [1, null, 0]
30
+ */
31
+ if (target[0] === null) {
32
+ target[0] = origin;
33
+ }
34
+ return target;
35
+ }
36
+ else {
37
+ return [origin, target];
38
+ }
39
+ }
40
+
41
+ export { getKeyframes };
@@ -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 { delay } from '../../utils/delay.mjs';
10
- import { inertia } from '../legacy-popmotion/inertia.mjs';
11
- import { animate } from '../legacy-popmotion/index.mjs';
12
2
 
13
3
  /**
14
4
  * Decide whether a transition is defined on a given Transition.
@@ -18,140 +8,6 @@ import { animate } from '../legacy-popmotion/index.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
- let origin = valueTransition.from !== undefined ? valueTransition.from : value.get();
100
- const isTargetAnimatable = isAnimatable(key, target);
101
- if (origin === "none" && isTargetAnimatable && typeof target === "string") {
102
- /**
103
- * If we're trying to animate from "none", try and get an animatable version
104
- * of the target. This could be improved to work both ways.
105
- */
106
- origin = getAnimatableNone(key, target);
107
- }
108
- else if (isZero(origin) && typeof target === "string") {
109
- origin = getZeroUnit(target);
110
- }
111
- else if (!Array.isArray(target) &&
112
- isZero(target) &&
113
- typeof origin === "string") {
114
- target = getZeroUnit(origin);
115
- }
116
- const isOriginAnimatable = isAnimatable(key, origin);
117
- 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.`);
118
- function start() {
119
- const options = {
120
- from: origin,
121
- to: target,
122
- velocity: value.getVelocity(),
123
- onComplete,
124
- onUpdate: (v) => value.set(v),
125
- };
126
- return valueTransition.type === "inertia" ||
127
- valueTransition.type === "decay"
128
- ? inertia({ ...options, ...valueTransition })
129
- : animate({
130
- ...getPopmotionAnimationOptions(valueTransition, options, key),
131
- onUpdate: (v) => {
132
- options.onUpdate(v);
133
- valueTransition.onUpdate && valueTransition.onUpdate(v);
134
- },
135
- onComplete: () => {
136
- options.onComplete();
137
- valueTransition.onComplete && valueTransition.onComplete();
138
- },
139
- });
140
- }
141
- function set() {
142
- const finalTarget = resolveFinalValueInKeyframes(target);
143
- value.set(finalTarget);
144
- onComplete();
145
- valueTransition.onUpdate && valueTransition.onUpdate(finalTarget);
146
- valueTransition.onComplete && valueTransition.onComplete();
147
- return { stop: () => { } };
148
- }
149
- return !isOriginAnimatable ||
150
- !isTargetAnimatable ||
151
- valueTransition.type === false
152
- ? set
153
- : start;
154
- }
155
11
  function isZero(value) {
156
12
  return (value === 0 ||
157
13
  (typeof value === "string" &&
@@ -166,31 +22,5 @@ function getZeroUnit(potentialUnitType) {
166
22
  function getValueTransition(transition, key) {
167
23
  return transition[key] || transition["default"] || transition;
168
24
  }
169
- /**
170
- * Start animation on a MotionValue. This function is an interface between
171
- * Framer Motion and Popmotion
172
- */
173
- function startAnimation(key, value, target, transition = {}) {
174
- if (instantAnimationState.current) {
175
- transition = { type: false };
176
- }
177
- return value.start((onComplete) => {
178
- let controls;
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
- };
193
- });
194
- }
195
25
 
196
- export { convertTransitionToAnimationOptions, getDelayFromTransition, getPopmotionAnimationOptions, getValueTransition, getZeroUnit, hydrateKeyframes, isTransitionDefined, isZero, startAnimation };
26
+ export { getValueTransition, getZeroUnit, isTransitionDefined, isZero };
@@ -0,0 +1,3 @@
1
+ const cubicBezierAsString = ([a, b, c, d]) => `cubic-bezier(${a}, ${b}, ${c}, ${d})`;
2
+
3
+ export { cubicBezierAsString };
@@ -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 };
@@ -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';
@@ -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';
@@ -56,7 +59,7 @@ export { LayoutGroupContext } from './context/LayoutGroupContext.mjs';
56
59
  export { DeprecatedLayoutGroupContext } from './context/DeprecatedLayoutGroupContext.mjs';
57
60
  export { SwitchLayoutGroupContext } from './context/SwitchLayoutGroupContext.mjs';
58
61
  export { FlatTree } from './render/utils/flat-tree.mjs';
59
- export { useAnimatedState as useDeprecatedAnimatedState } from './animation/use-animated-state.mjs';
62
+ export { useAnimatedState as useDeprecatedAnimatedState } from './animation/hooks/use-animated-state.mjs';
60
63
  export { useInvertedScale as useDeprecatedInvertedScale } from './value/use-inverted-scale.mjs';
61
64
  export { AnimationType } from './render/utils/types.mjs';
62
65
  export { animations } from './motion/features/animations.mjs';
@@ -1,8 +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';
5
+ import { handoffOptimizedAppearAnimation } from '../../animation/optimized-appear/handoff.mjs';
6
+ import { optimizedAppearDataAttribute } from '../../animation/optimized-appear/data-id.mjs';
7
+ import { createMotionValueAnimation } from '../../animation/index.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,7 +94,17 @@ function animateTarget(visualElement, definition, { delay = 0, transitionOverrid
92
94
  delay: 0,
93
95
  };
94
96
  }
95
- let animation = startAnimation(key, value, valueTarget, valueTransition);
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
+ }
107
+ let animation = value.start(createMotionValueAnimation(key, value, valueTarget, valueTransition));
96
108
  if (isWillChangeMotionValue(willChange)) {
97
109
  willChange.add(key);
98
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.7.3", `Attempting to mix Framer Motion versions ${nextValue.version} with 7.7.3 may not work as expected.`);
25
+ warnOnce(nextValue.version === "7.8.1", `Attempting to mix Framer Motion versions ${nextValue.version} with 7.8.1 may not work as expected.`);
26
26
  }
27
27
  }
28
28
  else if (isMotionValue(prevValue)) {
@@ -1,5 +1,8 @@
1
1
  import { sync, cancelSync } from '../frameloop/index.mjs';
2
2
 
3
+ /**
4
+ * Timeout defined in ms
5
+ */
3
6
  function delay(callback, timeout) {
4
7
  const start = performance.now();
5
8
  const checkElapsed = ({ timestamp }) => {
@@ -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
 
@@ -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.7.3";
28
+ this.version = "7.8.1";
29
29
  /**
30
30
  * Duration, in milliseconds, since last updating frame.
31
31
  *
@@ -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,