[Refactoring] Add waitForTransitionEnd and waitForAnimationEnd helpers

This commit is contained in:
Alexander Zinchuk 2021-08-04 02:35:25 +03:00
parent f13b1950ef
commit a77b826710
3 changed files with 47 additions and 30 deletions

View File

@ -22,6 +22,7 @@ import {
import { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck';
import buildClassName from '../../util/buildClassName';
import { fastRaf } from '../../util/schedulers';
import { waitForTransitionEnd } from '../../util/cssAnimationEndListeners';
import useShowTransition from '../../hooks/useShowTransition';
import useBackgroundMode from '../../hooks/useBackgroundMode';
import useBeforeUnload from '../../hooks/useBeforeUnload';
@ -135,17 +136,8 @@ const Main: FC<StateProps & DispatchProps> = ({
}
const dispatchHeavyAnimationEnd = dispatchHeavyAnimationEvent();
const middleColumnEl = document.getElementById('MiddleColumn')!;
middleColumnEl.addEventListener('transitionend', function handleTransitionEnd(e: TransitionEvent) {
if (e.target !== e.currentTarget) {
return;
}
middleColumnEl.removeEventListener('transitionend', handleTransitionEnd);
dispatchHeavyAnimationEnd();
});
waitForTransitionEnd(document.getElementById('MiddleColumn')!, dispatchHeavyAnimationEnd);
}, [isLeftColumnShown]);
// Dispatch heavy transition event and add body class when opening right column
@ -154,20 +146,13 @@ const Main: FC<StateProps & DispatchProps> = ({
return;
}
const dispatchHeavyAnimationEnd = dispatchHeavyAnimationEvent();
const rightColumnEl = document.getElementById('RightColumn')!;
fastRaf(() => {
document.body.classList.add('animating-right-column');
});
rightColumnEl.addEventListener('transitionend', function handleTransitionEnd(e: TransitionEvent) {
if (e.target !== e.currentTarget) {
return;
}
rightColumnEl.removeEventListener('transitionend', handleTransitionEnd);
const dispatchHeavyAnimationEnd = dispatchHeavyAnimationEvent();
waitForTransitionEnd(document.getElementById('RightColumn')!, () => {
dispatchHeavyAnimationEnd();
fastRaf(() => {

View File

@ -8,6 +8,7 @@ import useForceUpdate from '../../hooks/useForceUpdate';
import usePrevious from '../../hooks/usePrevious';
import buildClassName from '../../util/buildClassName';
import { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck';
import { waitForAnimationEnd } from '../../util/cssAnimationEndListeners';
import './Transition.scss';
@ -139,8 +140,6 @@ const Transition: FC<OwnProps> = ({
requestAnimationFrame(() => {
container.classList.add('animating');
const toNode = childNodes[activeIndex];
function onAnimationEnd() {
requestAnimationFrame(() => {
container.classList.remove('animating', 'backwards');
@ -174,15 +173,8 @@ const Transition: FC<OwnProps> = ({
}
if (animationLevel > 0) {
toNode.addEventListener('animationend', function handleAnimationEnd(e: AnimationEvent) {
if (e.target !== e.currentTarget) {
return;
}
toNode.removeEventListener('animationend', handleAnimationEnd as EventListener);
onAnimationEnd();
} as EventListener);
const toNode = name === 'mv-slide' ? childNodes[activeIndex].firstChild! : childNodes[activeIndex];
waitForAnimationEnd(toNode, onAnimationEnd);
} else {
onAnimationEnd();
}

View File

@ -0,0 +1,40 @@
// Sometimes event is fired earlier than animation completes
const ANIMATION_END_DELAY = 50;
export function waitForTransitionEnd(node: Node, handler: NoneToVoidFunction, propertyName?: string) {
waitForEndEvent('transitionend', node, handler, propertyName);
}
export function waitForAnimationEnd(node: Node, handler: NoneToVoidFunction, animationName?: string) {
waitForEndEvent('animationend', node, handler, animationName);
}
function waitForEndEvent(
eventType: 'transitionend' | 'animationend',
node: Node,
handler: NoneToVoidFunction,
detailedName?: string,
) {
let isHandled = false;
node.addEventListener(eventType, function handleAnimationEnd(e: TransitionEvent | AnimationEvent) {
if (isHandled || e.target !== e.currentTarget) {
return;
}
if (detailedName && (
(e instanceof TransitionEvent && e.propertyName === detailedName)
|| (e instanceof AnimationEvent && e.animationName === detailedName)
)) {
return;
}
isHandled = true;
node.removeEventListener(eventType, handleAnimationEnd as EventListener);
setTimeout(() => {
handler();
}, ANIMATION_END_DELAY);
} as EventListener);
}