framer-motion 8.4.4 → 8.4.6
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 +98 -45
- package/dist/es/animation/create-instant-animation.mjs +1 -2
- package/dist/es/animation/index.mjs +2 -4
- package/dist/es/animation/legacy-popmotion/index.mjs +19 -0
- package/dist/es/animation/optimized-appear/handoff.mjs +19 -2
- package/dist/es/animation/waapi/create-accelerated-animation.mjs +23 -15
- package/dist/es/gestures/use-hover-gesture.mjs +4 -4
- package/dist/es/gestures/use-tap-gesture.mjs +8 -4
- package/dist/es/motion/utils/use-visual-element.mjs +13 -5
- package/dist/es/render/utils/animation.mjs +1 -1
- package/dist/es/render/utils/motion-values.mjs +2 -2
- package/dist/es/value/index.mjs +7 -7
- package/dist/framer-motion.dev.js +98 -45
- package/dist/framer-motion.js +1 -1
- package/dist/index.d.ts +133 -133
- package/dist/projection.dev.js +54 -30
- package/dist/size-rollup-dom-animation-m.js +1 -1
- package/dist/size-rollup-dom-animation.js +1 -1
- package/dist/size-rollup-dom-max.js +1 -1
- package/dist/size-rollup-m.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/size-webpack-m.js +1 -1
- package/dist/three-entry.d.ts +62 -62
- package/package.json +9 -9
|
@@ -79,11 +79,19 @@
|
|
|
79
79
|
visualElement && visualElement.render();
|
|
80
80
|
});
|
|
81
81
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
82
|
+
* Ideally this function would always run in a useEffect.
|
|
83
|
+
*
|
|
84
|
+
* However, if we have optimised appear animations to handoff from,
|
|
85
|
+
* it needs to happen synchronously to ensure there's no flash of
|
|
86
|
+
* incorrect styles in the event of a hydration error.
|
|
87
|
+
*
|
|
88
|
+
* So if we detect a situtation where optimised appear animations
|
|
89
|
+
* are running, we use useLayoutEffect to trigger animations.
|
|
85
90
|
*/
|
|
86
|
-
|
|
91
|
+
const useAnimateChangesEffect = window.MotionAppearAnimations
|
|
92
|
+
? useIsomorphicLayoutEffect
|
|
93
|
+
: React.useEffect;
|
|
94
|
+
useAnimateChangesEffect(() => {
|
|
87
95
|
if (visualElement && visualElement.animationState) {
|
|
88
96
|
visualElement.animationState.animateChanges();
|
|
89
97
|
}
|
|
@@ -1463,14 +1471,14 @@
|
|
|
1463
1471
|
return false;
|
|
1464
1472
|
}
|
|
1465
1473
|
|
|
1466
|
-
function createHoverEvent(visualElement, isActive, callback) {
|
|
1474
|
+
function createHoverEvent(visualElement, isActive, applyVariants, callback) {
|
|
1467
1475
|
return (event, info) => {
|
|
1468
1476
|
if (event.type === "touch" || isDragActive())
|
|
1469
1477
|
return;
|
|
1470
1478
|
/**
|
|
1471
1479
|
* Ensure we trigger animations before firing event callback
|
|
1472
1480
|
*/
|
|
1473
|
-
if (visualElement.animationState) {
|
|
1481
|
+
if (applyVariants && visualElement.animationState) {
|
|
1474
1482
|
visualElement.animationState.setActive(exports.AnimationType.Hover, isActive);
|
|
1475
1483
|
}
|
|
1476
1484
|
callback && callback(event, info);
|
|
@@ -1479,12 +1487,12 @@
|
|
|
1479
1487
|
function useHoverGesture({ onHoverStart, onHoverEnd, whileHover, visualElement, }) {
|
|
1480
1488
|
usePointerEvent(visualElement, "pointerenter", React.useMemo(() => {
|
|
1481
1489
|
return onHoverStart || whileHover
|
|
1482
|
-
? createHoverEvent(visualElement, true, onHoverStart)
|
|
1490
|
+
? createHoverEvent(visualElement, true, Boolean(whileHover), onHoverStart)
|
|
1483
1491
|
: undefined;
|
|
1484
1492
|
}, [onHoverStart, Boolean(whileHover), visualElement]), { passive: !onHoverStart });
|
|
1485
1493
|
usePointerEvent(visualElement, "pointerleave", React.useMemo(() => {
|
|
1486
1494
|
return onHoverEnd || whileHover
|
|
1487
|
-
? createHoverEvent(visualElement, false, onHoverEnd)
|
|
1495
|
+
? createHoverEvent(visualElement, false, Boolean(whileHover), onHoverEnd)
|
|
1488
1496
|
: undefined;
|
|
1489
1497
|
}, [onHoverStart, Boolean(whileHover), visualElement]), { passive: !onHoverEnd });
|
|
1490
1498
|
}
|
|
@@ -1546,8 +1554,10 @@
|
|
|
1546
1554
|
function checkPointerEnd() {
|
|
1547
1555
|
removePointerEndListener();
|
|
1548
1556
|
isPressing.current = false;
|
|
1549
|
-
visualElement.
|
|
1557
|
+
const latestProps = visualElement.getProps();
|
|
1558
|
+
if (latestProps.whileTap && visualElement.animationState) {
|
|
1550
1559
|
visualElement.animationState.setActive(exports.AnimationType.Tap, false);
|
|
1560
|
+
}
|
|
1551
1561
|
return !isDragActive();
|
|
1552
1562
|
}
|
|
1553
1563
|
function onPointerUp(event, info) {
|
|
@@ -1569,18 +1579,20 @@
|
|
|
1569
1579
|
(_b = (_a = visualElement.getProps()).onTapCancel) === null || _b === void 0 ? void 0 : _b.call(_a, event, info);
|
|
1570
1580
|
}
|
|
1571
1581
|
const startPress = React.useCallback((event, info) => {
|
|
1572
|
-
var _a
|
|
1582
|
+
var _a;
|
|
1573
1583
|
removePointerEndListener();
|
|
1574
1584
|
if (isPressing.current)
|
|
1575
1585
|
return;
|
|
1576
1586
|
isPressing.current = true;
|
|
1577
1587
|
cancelPointerEndListeners.current = pipe(addPointerEvent(window, "pointerup", onPointerUp, eventOptions), addPointerEvent(window, "pointercancel", onPointerCancel, eventOptions));
|
|
1588
|
+
const latestProps = visualElement.getProps();
|
|
1578
1589
|
/**
|
|
1579
1590
|
* Ensure we trigger animations before firing event callback
|
|
1580
1591
|
*/
|
|
1581
|
-
visualElement.animationState
|
|
1592
|
+
if (latestProps.whileTap && visualElement.animationState) {
|
|
1582
1593
|
visualElement.animationState.setActive(exports.AnimationType.Tap, true);
|
|
1583
|
-
|
|
1594
|
+
}
|
|
1595
|
+
(_a = latestProps.onTapStart) === null || _a === void 0 ? void 0 : _a.call(latestProps, event, info);
|
|
1584
1596
|
}, [Boolean(onTapStart), visualElement]);
|
|
1585
1597
|
usePointerEvent(visualElement, "pointerdown", hasPressListeners ? startPress : undefined, eventOptions);
|
|
1586
1598
|
useUnmountEffect(removePointerEndListener);
|
|
@@ -2079,7 +2091,7 @@
|
|
|
2079
2091
|
* This will be replaced by the build step with the latest version number.
|
|
2080
2092
|
* When MotionValues are provided to motion components, warn if versions are mixed.
|
|
2081
2093
|
*/
|
|
2082
|
-
this.version = "8.4.
|
|
2094
|
+
this.version = "8.4.6";
|
|
2083
2095
|
/**
|
|
2084
2096
|
* Duration, in milliseconds, since last updating frame.
|
|
2085
2097
|
*
|
|
@@ -2318,11 +2330,11 @@
|
|
|
2318
2330
|
*
|
|
2319
2331
|
* @internal
|
|
2320
2332
|
*/
|
|
2321
|
-
start(
|
|
2333
|
+
start(startAnimation) {
|
|
2322
2334
|
this.stop();
|
|
2323
2335
|
return new Promise((resolve) => {
|
|
2324
2336
|
this.hasAnimated = true;
|
|
2325
|
-
this.
|
|
2337
|
+
this.animation = startAnimation(resolve) || null;
|
|
2326
2338
|
if (this.events.animationStart) {
|
|
2327
2339
|
this.events.animationStart.notify();
|
|
2328
2340
|
}
|
|
@@ -2339,8 +2351,8 @@
|
|
|
2339
2351
|
* @public
|
|
2340
2352
|
*/
|
|
2341
2353
|
stop() {
|
|
2342
|
-
if (this.
|
|
2343
|
-
this.
|
|
2354
|
+
if (this.animation) {
|
|
2355
|
+
this.animation.stop();
|
|
2344
2356
|
if (this.events.animationCancel) {
|
|
2345
2357
|
this.events.animationCancel.notify();
|
|
2346
2358
|
}
|
|
@@ -2353,10 +2365,10 @@
|
|
|
2353
2365
|
* @public
|
|
2354
2366
|
*/
|
|
2355
2367
|
isAnimating() {
|
|
2356
|
-
return !!this.
|
|
2368
|
+
return !!this.animation;
|
|
2357
2369
|
}
|
|
2358
2370
|
clearAnimation() {
|
|
2359
|
-
this.
|
|
2371
|
+
this.animation = null;
|
|
2360
2372
|
}
|
|
2361
2373
|
/**
|
|
2362
2374
|
* Destroy and clean up subscribers to this `MotionValue`.
|
|
@@ -2775,11 +2787,28 @@
|
|
|
2775
2787
|
|
|
2776
2788
|
const appearStoreId = (id, value) => `${id}: ${value}`;
|
|
2777
2789
|
|
|
2778
|
-
function handoffOptimizedAppearAnimation(id, name) {
|
|
2790
|
+
function handoffOptimizedAppearAnimation(id, name, value) {
|
|
2779
2791
|
const { MotionAppearAnimations } = window;
|
|
2780
2792
|
const animationId = appearStoreId(id, transformProps.has(name) ? "transform" : name);
|
|
2781
2793
|
const animation = MotionAppearAnimations && MotionAppearAnimations.get(animationId);
|
|
2782
2794
|
if (animation) {
|
|
2795
|
+
const sampledTime = performance.now();
|
|
2796
|
+
/**
|
|
2797
|
+
* Resync handoff animation with optimised animation.
|
|
2798
|
+
*
|
|
2799
|
+
* This step would be unnecessary if we triggered animateChanges() in useEffect,
|
|
2800
|
+
* but due to potential hydration errors we currently fire them in useLayoutEffect.
|
|
2801
|
+
*
|
|
2802
|
+
* By the time we're safely ready to cancel the optimised WAAPI animation,
|
|
2803
|
+
* the main thread might have been blocked and desynced the two animations.
|
|
2804
|
+
*
|
|
2805
|
+
* Here, we resync the two animations before the optimised WAAPI animation is cancelled.
|
|
2806
|
+
*/
|
|
2807
|
+
sync.update(() => {
|
|
2808
|
+
if (value.animation) {
|
|
2809
|
+
value.animation.currentTime = performance.now() - sampledTime;
|
|
2810
|
+
}
|
|
2811
|
+
});
|
|
2783
2812
|
/**
|
|
2784
2813
|
* We allow the animation to persist until the next frame:
|
|
2785
2814
|
* 1. So it continues to play until Framer Motion is ready to render
|
|
@@ -2788,12 +2817,12 @@
|
|
|
2788
2817
|
* it synchronously would prevent subsequent transforms from handing off.
|
|
2789
2818
|
*/
|
|
2790
2819
|
sync.render(() => {
|
|
2820
|
+
MotionAppearAnimations.delete(animationId);
|
|
2791
2821
|
/**
|
|
2792
2822
|
* Animation.cancel() throws so it needs to be wrapped in a try/catch
|
|
2793
2823
|
*/
|
|
2794
2824
|
try {
|
|
2795
2825
|
animation.cancel();
|
|
2796
|
-
MotionAppearAnimations.delete(animationId);
|
|
2797
2826
|
}
|
|
2798
2827
|
catch (e) { }
|
|
2799
2828
|
});
|
|
@@ -3594,6 +3623,25 @@
|
|
|
3594
3623
|
onStop && onStop();
|
|
3595
3624
|
driverControls && driverControls.stop();
|
|
3596
3625
|
},
|
|
3626
|
+
/**
|
|
3627
|
+
* Set the current time of the animation. This is purposefully
|
|
3628
|
+
* mirroring the WAAPI animation API to make them interchanagable.
|
|
3629
|
+
* Going forward this file should be ported more towards
|
|
3630
|
+
* https://github.com/motiondivision/motionone/blob/main/packages/animation/src/Animation.ts
|
|
3631
|
+
* Which behaviourally adheres to WAAPI as far as possible.
|
|
3632
|
+
*
|
|
3633
|
+
* WARNING: This is not safe to use for most animations. We currently
|
|
3634
|
+
* only use it for handoff from WAAPI within Framer.
|
|
3635
|
+
*
|
|
3636
|
+
* This animation function consumes time every frame rather than being sampled for time.
|
|
3637
|
+
* So the sample() method performs some headless frames to ensure
|
|
3638
|
+
* repeats are handled correctly. Ideally in the future we will replace
|
|
3639
|
+
* that method with this, once repeat calculations are pure.
|
|
3640
|
+
*/
|
|
3641
|
+
set currentTime(t) {
|
|
3642
|
+
elapsed = initialElapsed;
|
|
3643
|
+
update(t);
|
|
3644
|
+
},
|
|
3597
3645
|
/**
|
|
3598
3646
|
* animate() can't yet be sampled for time, instead it
|
|
3599
3647
|
* consumes time. So to sample it we have to run a low
|
|
@@ -3750,21 +3798,29 @@
|
|
|
3750
3798
|
/**
|
|
3751
3799
|
* Animation interrupt callback.
|
|
3752
3800
|
*/
|
|
3753
|
-
return
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3801
|
+
return {
|
|
3802
|
+
get currentTime() {
|
|
3803
|
+
return animation.currentTime || 0;
|
|
3804
|
+
},
|
|
3805
|
+
set currentTime(t) {
|
|
3806
|
+
animation.currentTime = t;
|
|
3807
|
+
},
|
|
3808
|
+
stop: () => {
|
|
3809
|
+
/**
|
|
3810
|
+
* WAAPI doesn't natively have any interruption capabilities.
|
|
3811
|
+
*
|
|
3812
|
+
* Rather than read commited styles back out of the DOM, we can
|
|
3813
|
+
* create a renderless JS animation and sample it twice to calculate
|
|
3814
|
+
* its current value, "previous" value, and therefore allow
|
|
3815
|
+
* Motion to calculate velocity for any subsequent animation.
|
|
3816
|
+
*/
|
|
3817
|
+
const { currentTime } = animation;
|
|
3818
|
+
if (currentTime) {
|
|
3819
|
+
const sampleAnimation = animate$1({ ...options, autoplay: false });
|
|
3820
|
+
value.setWithVelocity(sampleAnimation.sample(currentTime - sampleDelta).value, sampleAnimation.sample(currentTime).value, sampleDelta);
|
|
3821
|
+
}
|
|
3822
|
+
sync.update(() => animation.cancel());
|
|
3823
|
+
},
|
|
3768
3824
|
};
|
|
3769
3825
|
}
|
|
3770
3826
|
|
|
@@ -3788,9 +3844,8 @@
|
|
|
3788
3844
|
const setValue = () => {
|
|
3789
3845
|
onUpdate && onUpdate(keyframes[keyframes.length - 1]);
|
|
3790
3846
|
onComplete && onComplete();
|
|
3791
|
-
return () => { };
|
|
3792
3847
|
};
|
|
3793
|
-
return elapsed ? delay(setValue, -elapsed) : setValue();
|
|
3848
|
+
return elapsed ? { stop: delay(setValue, -elapsed) } : setValue();
|
|
3794
3849
|
}
|
|
3795
3850
|
|
|
3796
3851
|
function inertia({ keyframes, velocity = 0, min, max, power = 0.8, timeConstant = 750, bounceStiffness = 500, bounceDamping = 10, restDelta = 1, modifyTarget, driver, onUpdate, onComplete, onStop, }) {
|
|
@@ -4067,8 +4122,7 @@
|
|
|
4067
4122
|
* If this is an inertia animation, we currently don't support pre-generating
|
|
4068
4123
|
* keyframes for this as such it must always run on the main thread.
|
|
4069
4124
|
*/
|
|
4070
|
-
|
|
4071
|
-
return () => animation.stop();
|
|
4125
|
+
return inertia(options);
|
|
4072
4126
|
}
|
|
4073
4127
|
/**
|
|
4074
4128
|
* If there's no transition defined for this value, we can generate
|
|
@@ -4106,8 +4160,7 @@
|
|
|
4106
4160
|
/**
|
|
4107
4161
|
* If we didn't create an accelerated animation, create a JS animation
|
|
4108
4162
|
*/
|
|
4109
|
-
|
|
4110
|
-
return () => animation.stop();
|
|
4163
|
+
return animate$1(options);
|
|
4111
4164
|
};
|
|
4112
4165
|
};
|
|
4113
4166
|
|
|
@@ -4196,7 +4249,7 @@
|
|
|
4196
4249
|
if (!value.hasAnimated) {
|
|
4197
4250
|
const appearId = visualElement.getProps()[optimizedAppearDataAttribute];
|
|
4198
4251
|
if (appearId) {
|
|
4199
|
-
valueTransition.elapsed = handoffOptimizedAppearAnimation(appearId, key);
|
|
4252
|
+
valueTransition.elapsed = handoffOptimizedAppearAnimation(appearId, key, value);
|
|
4200
4253
|
}
|
|
4201
4254
|
}
|
|
4202
4255
|
let animation = value.start(createMotionValueAnimation(key, value, valueTarget, visualElement.shouldReduceMotion && transformProps.has(key)
|
|
@@ -5946,7 +5999,7 @@
|
|
|
5946
5999
|
* and warn against mismatches.
|
|
5947
6000
|
*/
|
|
5948
6001
|
{
|
|
5949
|
-
warnOnce(nextValue.version === "8.4.
|
|
6002
|
+
warnOnce(nextValue.version === "8.4.6", `Attempting to mix Framer Motion versions ${nextValue.version} with 8.4.6 may not work as expected.`);
|
|
5950
6003
|
}
|
|
5951
6004
|
}
|
|
5952
6005
|
else if (isMotionValue(prevValue)) {
|
|
@@ -5972,7 +6025,7 @@
|
|
|
5972
6025
|
}
|
|
5973
6026
|
else {
|
|
5974
6027
|
const latestValue = element.getStaticValue(key);
|
|
5975
|
-
element.addValue(key, motionValue(latestValue !== undefined ? latestValue : nextValue));
|
|
6028
|
+
element.addValue(key, motionValue(latestValue !== undefined ? latestValue : nextValue, { owner: element }));
|
|
5976
6029
|
}
|
|
5977
6030
|
}
|
|
5978
6031
|
}
|