New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Site Editor: Improve the frame animation #60363
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ | |
"react-native": "src/index", | ||
"dependencies": { | ||
"@babel/runtime": "^7.16.0", | ||
"@react-spring/web": "^9.4.5", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This adds a new dependency to the site editor but I think it's worth it. |
||
"@wordpress/a11y": "file:../a11y", | ||
"@wordpress/api-fetch": "file:../api-fetch", | ||
"@wordpress/blob": "file:../blob", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { Controller } from '@react-spring/web'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useLayoutEffect, useMemo, useRef } from '@wordpress/element'; | ||
|
||
function getAbsolutePosition( element ) { | ||
return { | ||
top: element.offsetTop, | ||
left: element.offsetLeft, | ||
}; | ||
} | ||
|
||
const ANIMATION_DURATION = 300; | ||
|
||
/** | ||
* Hook used to compute the styles required to move a div into a new position. | ||
* | ||
* The way this animation works is the following: | ||
* - It first renders the element as if there was no animation. | ||
* - It takes a snapshot of the position of the block to use it | ||
* as a destination point for the animation. | ||
* - It restores the element to the previous position using a CSS transform | ||
* - It uses the "resetAnimation" flag to reset the animation | ||
* from the beginning in order to animate to the new destination point. | ||
* | ||
* @param {Object} $1 Options | ||
* @param {*} $1.triggerAnimationOnChange Variable used to trigger the animation if it changes. | ||
*/ | ||
function useMovingAnimation( { triggerAnimationOnChange } ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potentially this can be a generic hook in the compose package but I think the recent perf optimization that we've made to the block animation made it less likely to be shared. Maybe it's fine for it to be duplicated. (cc @ellatrix ) The other difference with the block animation is that this one animates the "width" and "height" as well as the position. |
||
const ref = useRef(); | ||
|
||
// Whenever the trigger changes, we need to take a snapshot of the current | ||
// position of the block to use it as a destination point for the animation. | ||
const { previous, prevRect } = useMemo( | ||
() => ( { | ||
previous: ref.current && getAbsolutePosition( ref.current ), | ||
prevRect: ref.current && ref.current.getBoundingClientRect(), | ||
} ), | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
[ triggerAnimationOnChange ] | ||
); | ||
|
||
useLayoutEffect( () => { | ||
if ( ! previous || ! ref.current ) { | ||
return; | ||
} | ||
|
||
// We disable the animation if the user has a preference for reduced | ||
// motion. | ||
const disableAnimation = window.matchMedia( | ||
'(prefers-reduced-motion: reduce)' | ||
).matches; | ||
|
||
if ( disableAnimation ) { | ||
return; | ||
} | ||
|
||
const controller = new Controller( { | ||
x: 0, | ||
y: 0, | ||
width: prevRect.width, | ||
height: prevRect.height, | ||
config: { duration: ANIMATION_DURATION }, | ||
onChange( { value } ) { | ||
if ( ! ref.current ) { | ||
return; | ||
} | ||
let { x, y, width, height } = value; | ||
x = Math.round( x ); | ||
y = Math.round( y ); | ||
width = Math.round( width ); | ||
height = Math.round( height ); | ||
const finishedMoving = x === 0 && y === 0; | ||
ref.current.style.transformOrigin = 'center center'; | ||
ref.current.style.transform = finishedMoving | ||
? null // Set to `null` to explicitly remove the transform. | ||
: `translate3d(${ x }px,${ y }px,0)`; | ||
ref.current.style.width = finishedMoving | ||
? null | ||
: `${ width }px`; | ||
ref.current.style.height = finishedMoving | ||
? null | ||
: `${ height }px`; | ||
}, | ||
} ); | ||
|
||
ref.current.style.transform = undefined; | ||
const destination = ref.current.getBoundingClientRect(); | ||
|
||
const x = Math.round( prevRect.left - destination.left ); | ||
const y = Math.round( prevRect.top - destination.top ); | ||
const width = destination.width; | ||
const height = destination.height; | ||
|
||
controller.start( { | ||
x: 0, | ||
y: 0, | ||
width, | ||
height, | ||
from: { x, y, width: prevRect.width, height: prevRect.height }, | ||
} ); | ||
|
||
return () => { | ||
controller.stop(); | ||
controller.set( { | ||
x: 0, | ||
y: 0, | ||
width: prevRect.width, | ||
height: prevRect.height, | ||
} ); | ||
}; | ||
}, [ previous, prevRect ] ); | ||
|
||
return ref; | ||
} | ||
|
||
export default useMovingAnimation; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this temporary to check what's causing the failures?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is what was causing the failures actually. I guess these days it's
docker compose
and notdocker-compose
and Github probably updated docker or something so the PHP tests started failing, I expect that they'll fail elsewhere as well.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shall we merge this so we fix the tests in other PRs as well?