-
-
Notifications
You must be signed in to change notification settings - Fork 897
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2661 from framer/fix/optimized-appear
Fix jump if optimised appear animation is interrupted
- Loading branch information
Showing
6 changed files
with
216 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
<html> | ||
<head> | ||
<style> | ||
body { | ||
margin: 0; | ||
} | ||
|
||
#box { | ||
width: 100px; | ||
height: 100px; | ||
background-color: #0077ff; | ||
} | ||
|
||
[data-layout-correct="false"] { | ||
background: #dd1144 !important; | ||
opacity: 1 !important; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<div id="root"></div> | ||
<script src="../../node_modules/react/umd/react.development.js"></script> | ||
<script src="../../node_modules/react-dom/umd/react-dom.development.js"></script> | ||
<script src="../../node_modules/react-dom/umd/react-dom-server-legacy.browser.development.js"></script> | ||
<script src="../../packages/framer-motion/dist/framer-motion.dev.js"></script> | ||
<script src="../projection/script-assert.js"></script> | ||
|
||
<script> | ||
const { | ||
motion, | ||
animateStyle, | ||
animate, | ||
startOptimizedAppearAnimation, | ||
optimizedAppearDataAttribute, | ||
motionValue, | ||
frame, | ||
} = window.Motion | ||
const { matchViewportBox } = window.Assert | ||
const root = document.getElementById("root") | ||
|
||
const duration = 4 | ||
const x = motionValue(0) | ||
const xTarget = 500 | ||
|
||
let isFirstFrame = true | ||
|
||
// This is the tree to be rendered "server" and client-side. | ||
const Component = React.createElement(motion.div, { | ||
id: "box", | ||
initial: { x: 0, opacity: 0 }, | ||
animate: { x: xTarget, opacity: 1 }, | ||
transition: { duration, ease: "linear" }, | ||
style: { x }, | ||
/** | ||
* On animation start, check the values we expect to see here | ||
*/ | ||
onAnimationStart: () => { | ||
const box = document.getElementById("box") | ||
|
||
box.style.backgroundColor = "green" | ||
|
||
setTimeout(() => { | ||
frame.postRender(() => { | ||
/** | ||
* The frame visible after the infinite loop | ||
* and before motion renders again | ||
*/ | ||
frame.preRender(() => { | ||
const left = box.getBoundingClientRect().left | ||
|
||
if (left < 200) { | ||
showError( | ||
document.getElementById("box"), | ||
`Stutter detected` | ||
) | ||
} | ||
}) | ||
}) | ||
/** | ||
* By blocking the main thread here, we ensure that | ||
* the keyframes are resolved a good duration after the | ||
* animation was initialised. | ||
*/ | ||
frame.postRender(() => { | ||
console.log( | ||
"Blocking main thread before keyframe resolution" | ||
) | ||
|
||
const startTime = performance.now() | ||
while (performance.now() - startTime < 1000) {} | ||
}) | ||
|
||
/** | ||
* This animation interrupts the optimised animation. Notably, we are animating | ||
* x in the optimised transform animation and only scale here. This ensures | ||
* that any transform can force the cancellation of the optimised animation on transform, | ||
* not just those involved in the original animation. | ||
*/ | ||
const options = { duration: 0.5, ease: "linear" } | ||
let frameCounter = 0 | ||
|
||
box.style.backgroundColor = "red" | ||
|
||
animate( | ||
box, | ||
{ scale: [1, 1] }, | ||
{ | ||
...options, | ||
onUpdate: () => { | ||
frameCounter++ | ||
console.log( | ||
getComputedStyle(box).transform, | ||
box.style.transform, | ||
box.getBoundingClientRect().left | ||
) | ||
}, | ||
} | ||
) | ||
}, 100) | ||
}, | ||
[optimizedAppearDataAttribute]: "a", | ||
children: "Content", | ||
}) | ||
|
||
// Emulate server rendering of element | ||
root.innerHTML = ReactDOMServer.renderToString(Component) | ||
|
||
// Start optimised opacity animation | ||
startOptimizedAppearAnimation( | ||
document.getElementById("box"), | ||
"opacity", | ||
[0, 1], | ||
{ | ||
duration: duration * 1000, | ||
ease: "linear", | ||
} | ||
) | ||
|
||
// Start WAAPI animation | ||
const animation = startOptimizedAppearAnimation( | ||
document.getElementById("box"), | ||
"transform", | ||
["translateX(0px)", `translateX(${xTarget}px)`], | ||
{ | ||
duration: duration * 1000, | ||
ease: "linear", | ||
}, | ||
(animation) => { | ||
setTimeout(() => { | ||
ReactDOM.hydrateRoot(root, Component) | ||
}, (duration * 1000) / 4) | ||
} | ||
) | ||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
["defer-handoff-layout.html","defer-handoff.html","interrupt-delay-after.html","interrupt-delay-before-accelerated.html","interrupt-delay-before.html","interrupt-spring.html","interrupt-tween-opacity-waapi.html","interrupt-tween-opacity.html","interrupt-tween-transforms.html","interrupt-tween-x.html","persist-optimised-animation.html","persist.html","portal.html","resync-delay.html","resync.html","start-after-hydration.html"] | ||
["defer-handoff-block.html","defer-handoff-layout.html","defer-handoff.html","interrupt-delay-after.html","interrupt-delay-before-accelerated.html","interrupt-delay-before.html","interrupt-spring.html","interrupt-tween-opacity-waapi.html","interrupt-tween-opacity.html","interrupt-tween-transforms.html","interrupt-tween-x.html","persist-optimised-animation.html","persist.html","portal.html","resync-delay.html","resync.html","start-after-hydration.html"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters