chore: add better documentation to a complicated hook (#6689)
* chore: add better documentation to a complicated hook * input from eddie * Update src/hooks/useUnmountingAnimation.ts Co-authored-by: Zach Pomerantz <zzmp@uniswap.org> * remove jsdoc types --------- Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>
This commit is contained in:
parent
f834af69fe
commit
1cdddd1321
@ -1,9 +1,29 @@
|
||||
import { RefObject, useEffect } from 'react'
|
||||
|
||||
function isAnimating(node?: Animatable | Document) {
|
||||
/**
|
||||
* Checks whether a given node is currently animating.
|
||||
*
|
||||
* @param node - The node to check for ongoing animations.
|
||||
* @returns - true if the node is animating; false otherwise.
|
||||
*/
|
||||
function isAnimating(node?: Animatable | Document): boolean {
|
||||
return (node?.getAnimations?.().length ?? 0) > 0
|
||||
}
|
||||
|
||||
/**
|
||||
* This hook runs an unmounting animation on a specified node.
|
||||
*
|
||||
* The hook will also run the animation on any additional elements specified in
|
||||
* the `animatedElements` parameter. If no additional elements are specified,
|
||||
* the animation will only run on the provided node.
|
||||
*
|
||||
* After any of the animated elements have completed their animation, `node` is removed from its parent.
|
||||
*
|
||||
* @param node - The node to animate and remove.
|
||||
* @param getAnimatingClass - A function that returns the CSS class to add to the animating elements.
|
||||
* @param animatedElements - Additional elements to animate.
|
||||
* @param skip - Whether to skip the animation and remove the node immediately.
|
||||
*/
|
||||
export function useUnmountingAnimation(
|
||||
node: RefObject<HTMLElement>,
|
||||
getAnimatingClass: () => string,
|
||||
@ -12,16 +32,26 @@ export function useUnmountingAnimation(
|
||||
) {
|
||||
useEffect(() => {
|
||||
const current = node.current
|
||||
|
||||
// Gather all elements to animate, defaulting to the current node if none are specified.
|
||||
const animated = animatedElements?.map((element) => element.current) ?? [current]
|
||||
const parent = current?.parentElement
|
||||
const removeChild = parent?.removeChild
|
||||
|
||||
// If we can't remove the child or skipping is requested, stop here.
|
||||
if (!(parent && removeChild) || skip) return
|
||||
|
||||
// Override the parent's removeChild function to add our animation logic
|
||||
parent.removeChild = function <T extends Node>(child: T) {
|
||||
// If the current child is the one being removed and it's supposed to animate
|
||||
if ((child as Node) === current && animated) {
|
||||
// Add animation class to all elements
|
||||
animated.forEach((element) => element?.classList.add(getAnimatingClass()))
|
||||
|
||||
// Check if any of the animated elements is animating
|
||||
const animating = animated.find((element) => isAnimating(element ?? undefined))
|
||||
if (animating) {
|
||||
// If an element is animating, we wait for the animation to end before removing the child
|
||||
animating?.addEventListener('animationend', (x) => {
|
||||
// This check is needed because the animationend event will fire for all animations on the
|
||||
// element or its children.
|
||||
@ -30,13 +60,18 @@ export function useUnmountingAnimation(
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// If no element is animating, we remove the child immediately
|
||||
removeChild.call(parent, child)
|
||||
}
|
||||
// We've handled the removal, so we return the child
|
||||
return child
|
||||
} else {
|
||||
// If the child isn't the one we're supposed to animate, remove it normally
|
||||
return removeChild.call(parent, child) as T
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the removeChild function to its original value when the component is unmounted
|
||||
return () => {
|
||||
parent.removeChild = removeChild
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user