See the Pen Submit button animation by Tom (@yeptony) on CodePen.
import React from 'react';
import { View, Display, Text } from '@pip/theme';
import DefaultLayout from '../../layouts/Default';
import styled, { css, keyframes } from 'styled-components';
const Payment = () => {
const [ani, setAni] = React.useState({ click: false, circle: false });
const handleClick = () => {
setAni({ ...ani, click: true, circle: true });
};
React.useEffect(() => {
if (ani.click) {
setTimeout(() => {
setAni({ click: false, circle: false });
}, 9000);
}
}, [ani]);
return (
<Button onClick={handleClick} className={ani.circle ? 'circle' : undefined}>
<span className={ani.click ? 'click' : undefined}>Pay</span>
</Button>
);
};
const HomePage: React.FC = () => {
const [success, setSuccess] = React.useState(false);
return (
<DefaultLayout>
<View direction="column" align="center" spacing={8} block>
<Display>Home</Display>
<Text>Welcome!!</Text>
<Payment />
</View>
</DefaultLayout>
);
};
export default HomePage;
const width = 150;
const height = 45;
const Button = styled.button<{ click?: boolean }>`
box-shadow: none;
outline: none;
border: solid 2px #1ecd97;
width: ${width}px;
height: ${height}px;
border-radius: 30px;
font-weight: bold;
font-size: 18px;
background-color: #fff;
color: #1ecd97;
transition: background-color 0.4s ease;
position: relative;
&::before {
content: '';
display: block;
position: absolute;
width: 0;
height: 0;
border-radius: 50%;
background-color: #1ecd97;
margin: auto;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
&::after {
content: '';
display: block;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
width: 16px;
height: 8px;
border-left: solid 5px white;
border-bottom: solid 5px white;
margin: auto;
opacity: 0;
transform: rotate(-45deg);
}
&.circle {
animation-delay: 500ms, 3000ms;
animation-duration: 300ms, 800ms;
animation-timing-function: ease-out, ease-in;
animation-fill-mode: forwards;
animation-name: ${(p) => circle}, ${(p) => button_grow};
&::before {
animation-delay: 800ms;
animation-duration: 2500ms;
animation-timing-function: ease-out;
animation-fill-mode: forwards;
animation-name: ${(p) => grow};
}
&::after {
animation-delay: 4500ms;
animation-duration: 400ms;
animation-timing-function: ease-out;
animation-fill-mode: forwards;
animation-name: ${(p) => check};
}
}
.click {
animation-delay: 0s 600ms;
animation-duration: 300ms, 100ms;
animation-timing-function: ease-in-out, linear;
animation-fill-mode: none, forwards;
animation-name: ${(p) => bounce}, ${(p) => disapear};
&:after {
animation-delay: 4500ms;
animation-duration: 400ms;
animation-timing-function: ease-out;
animation-fill-mode: forwards;
animation-name: ${(p) => check};
}
}
`;
const bounce = keyframes`
30%{
font-size: 20px;
}
`;
const circle = keyframes`
100% {
width: ${height}px;
border: solid 6px #ccc;
}
`;
const disapear = keyframes`
100% {
opacity: 0;
}
`;
const grow = keyframes`
99.9% {
width: ${height};
height: ${height};
opacity: 1;
}
100% {
opacity: 0;
}
`;
const button_grow = keyframes`
0%{
width: ${height}px;
border: solid 2px #1ecd97;
background-color: #1ecd97;
}
100% {
width: ${width}px;
border: solid 2px #1ecd97;
background-color: #1ecd97;
}
`;
const check = keyframes`
25% {
opacity: 1;
}
60% {
opacity: 1;
transform: scale(1.3) rotate(-45deg);
}
100% {
opacity: 1;
transform: scale(1) rotate(-45deg);
}
`;
'coding > react' 카테고리의 다른 글
리코일, Selectors (0) | 2023.03.30 |
---|---|
리코일, Atoms (0) | 2023.03.30 |
async-await function in useEffect (0) | 2022.02.22 |
Next.js에서 백그라운드 이미지 적용해서 애니메이션 주기 (0) | 2021.11.17 |
zustand 사용하기 🚀 (0) | 2021.11.09 |
댓글