terriajs
Version:
Geospatial data visualization platform.
57 lines (51 loc) • 1.74 kB
text/typescript
/**
* The purpose of this module is to provide a standard way to perform actions after an animations ends.
* The advantage is that the code is more tightly coupled together and we don't have to guess when the animation ends.
* There is also a timeout fallback that will reject the Promise if the animation end event is not fired in time.
*
* Old code:
*
triggerSomeAnimation();
setTimeout(function() {
somePostAction();
}, 200);
*
* New code:
animateEnd(this.elementRef.current).finally(somePostAction);
triggerAnimation();
*
*
*/
const ANIMATION_TIMEOUT = 500;
const transitionEnd = (element: Element | null) =>
new Promise<void>((resolve, reject) => {
if (!element) {
reject("Animation: Element is null");
} else {
const onEnd = () => {
element.removeEventListener("transitionend", onEnd);
resolve();
};
element.addEventListener("transitionend", onEnd);
}
});
const animationTimeout = (
_timeoutID: ReturnType<typeof setTimeout> | undefined
) =>
new Promise<void>((_, reject) => {
_timeoutID = setTimeout(() => {
reject("Animation timed out. Did you forget to animate the element?");
}, ANIMATION_TIMEOUT);
});
/**
*
* @param element - HTML element that will fire the transitionend event due to a CSS animation
* @returns Promise that will resolve when the element finishes its animation or reject if it is not detected within ANIMATION_DURATION ms
*/
export const animateEnd = (element: Element | null) => {
const timeoutID: ReturnType<typeof setTimeout> | undefined = undefined;
return Promise.race([
transitionEnd(element),
animationTimeout(timeoutID)
]).finally(() => timeoutID && clearTimeout(timeoutID));
};