This repository has been archived on 2022-06-22. You can view files and clone it, but cannot push or open issues or pull requests.
usaco-guide/src/components/Transition.tsx
2020-07-06 23:15:08 -07:00

125 lines
3.1 KiB
TypeScript

import { CSSTransition as ReactCSSTransition } from 'react-transition-group';
import * as React from 'react';
import { useRef, useEffect, useContext } from 'react';
const TransitionContext = React.createContext({
parent: {},
});
function useIsInitialRender() {
const isInitialRender = useRef(true);
useEffect(() => {
isInitialRender.current = false;
}, []);
return isInitialRender.current;
}
function CSSTransition({
show,
enter = '',
enterFrom = '',
enterTo = '',
leave = '',
leaveFrom = '',
leaveTo = '',
appear,
children,
isParent,
timeout,
}) {
const enterClasses = enter.split(' ').filter(s => s.length);
const enterFromClasses = enterFrom.split(' ').filter(s => s.length);
const enterToClasses = enterTo.split(' ').filter(s => s.length);
const leaveClasses = leave.split(' ').filter(s => s.length);
const leaveFromClasses = leaveFrom.split(' ').filter(s => s.length);
const leaveToClasses = leaveTo.split(' ').filter(s => s.length);
function addClasses(node, classes) {
classes.length && node.classList.add(...classes);
}
function removeClasses(node, classes) {
classes.length && node.classList.remove(...classes);
}
return (
<ReactCSSTransition
appear={appear}
unmountOnExit
in={show}
addEndListener={
isParent && timeout
? undefined
: (node, done) => {
node.addEventListener(
'transitionend',
e => {
if (node === e.target) done();
},
false
);
}
}
timeout={isParent ? timeout : undefined}
onEnter={node => {
addClasses(node, [...enterClasses, ...enterFromClasses]);
}}
onEntering={node => {
removeClasses(node, enterFromClasses);
addClasses(node, enterToClasses);
}}
onEntered={node => {
removeClasses(node, [...enterToClasses, ...enterClasses]);
}}
onExit={node => {
addClasses(node, [...leaveClasses, ...leaveFromClasses]);
}}
onExiting={node => {
removeClasses(node, leaveFromClasses);
addClasses(node, leaveToClasses);
}}
onExited={node => {
removeClasses(node, [...leaveToClasses, ...leaveClasses]);
}}
>
{children}
</ReactCSSTransition>
);
}
function Transition({ show, appear, ...rest }: any) {
const { parent }: { parent: any } = useContext(TransitionContext);
const isInitialRender = useIsInitialRender();
const isChild = show === undefined;
if (isChild) {
return (
// @ts-ignore
<CSSTransition
appear={parent.appear || !parent.isInitialRender}
show={parent.show}
isParent={false}
{...rest}
/>
);
}
return (
<TransitionContext.Provider
value={{
parent: {
show,
isInitialRender,
appear,
},
}}
>
{/*
// @ts-ignore*/}
<CSSTransition appear={appear} show={show} isParent={true} {...rest} />
</TransitionContext.Provider>
);
}
export default Transition;