Skip to content

Instantly share code, notes, and snippets.

@tzynwang
Created October 2, 2022 23:54
Show Gist options
  • Save tzynwang/b1362b13181e7d18c50b44ecf684d6ce to your computer and use it in GitHub Desktop.
Save tzynwang/b1362b13181e7d18c50b44ecf684d6ce to your computer and use it in GitHub Desktop.
import React, { memo, useMemo } from 'react';
import cn from 'classnames';
import { css, keyframes } from '@emotion/css';
import Portal from '@Components/Layer/Portal';
import useDelayUnmount from '@Hooks/useDelayUnmount';
import type { TransitionEffectProps } from './types';
const fadeIn = keyframes`
from {
opacity: 0;
}
to {
opacity: 1;
}
`;
const fadeOut = keyframes`
from {
opacity: 1;
}
to {
opacity: 0;
}
`;
const scaleIn = keyframes`
from {
transform: scale(0);
}
to {
transform: scale(1);
}
`;
const scaleOut = keyframes`
from {
transform: scale(1);
}
to {
transform: scale(0);
}
`;
const collapseIn = keyframes`
from {
clip-path: polygon(0 0, 100% 0, 100% 0, 0 0);
}
to {
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
}
`;
const collapseOut = keyframes`
from {
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
}
to {
clip-path: polygon(0 0, 100% 0, 100% 0, 0 0);
}
`;
function TransitionEffect(props: TransitionEffectProps): React.ReactElement {
/* States */
const { mount, children, effect = 'scale', portal = null } = props;
const shouldMount = useDelayUnmount(mount, 300);
const animations = useMemo(
() => ({ fadeIn, fadeOut, scaleIn, scaleOut, collapseIn, collapseOut }),
[]
);
/* Views */
const finalChildren = useMemo(
() => (
<span
className={cn(
css({
'& :first-child': {
animation: `${
mount ? animations[`${effect}In`] : animations[`${effect}Out`]
} .3s ease`,
},
})
)}
>
{children}
</span>
),
[mount, animations, effect, children]
);
const finalRender = useMemo(
() =>
portal ? (
<Portal container={portal}>{finalChildren}</Portal>
) : (
finalChildren
),
[portal, finalChildren]
);
/* Main */
return shouldMount ? finalRender : <React.Fragment />;
}
export default memo(TransitionEffect);
import React from 'react';
export interface TransitionEffectProps {
mount: boolean;
children: React.ReactNode;
effect?: 'fade' | 'scale' | 'collapse';
portal?: Element;
}
import React, { memo, useState, useCallback } from 'react';
import cn from 'classnames';
import { css } from '@emotion/css';
import Stack from '@Components/Layout/Stack';
import SpaceWrapper from '@Components/Layout/SpaceWrapper';
import Button from '@Components/Common/Button';
import TransitionEffect from '@Components/Layer/TransitionEffect';
const cardStyle = css({
width: '72px',
height: '72px',
display: 'inline-flex',
borderRadius: '8px',
backgroundColor: '#eee',
boxShadow: '1px 1px 4px 1px rgba(0,0,0,0.2)',
});
const fixedCardStyle = css({ position: 'fixed', top: '24px', right: '24px' });
function TransitionEffectDemo(): React.ReactElement {
/* States */
const [fade, setFade] = useState<boolean>(false);
const [scale, setScale] = useState<boolean>(false);
const [collapse, setCollapse] = useState<boolean>(false);
/* Functions */
const fadeBox = useCallback((): void => {
setFade((prev) => !prev);
}, []);
const scaleBox = useCallback((): void => {
setScale((prev) => !prev);
}, []);
const collapseBox = useCallback((): void => {
setCollapse((prev) => !prev);
}, []);
/* Main */
return (
<SpaceWrapper padding={24}>
<Stack>
<SpaceWrapper>
<Button onClick={fadeBox}>fade</Button>
</SpaceWrapper>
<SpaceWrapper padding={24}>
<TransitionEffect mount={fade} effect="fade">
<div className={cn(cardStyle)} />
</TransitionEffect>
</SpaceWrapper>
<SpaceWrapper>
<Button onClick={scaleBox}>scale</Button>
</SpaceWrapper>
<SpaceWrapper padding={24}>
<TransitionEffect mount={scale} effect="scale" portal={document.body}>
<div className={cn(cardStyle, fixedCardStyle)} />
</TransitionEffect>
</SpaceWrapper>
<SpaceWrapper>
<Button onClick={collapseBox}>collapse</Button>
</SpaceWrapper>
<SpaceWrapper padding={24}>
<TransitionEffect mount={collapse} effect="collapse">
<div className={cn(cardStyle)} />
</TransitionEffect>
</SpaceWrapper>
</Stack>
</SpaceWrapper>
);
}
export default memo(TransitionEffectDemo);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment