본문 바로가기
coding/react

버튼 애니메이션 1 with styled-component

by 코딩희송 2022. 5. 20.

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

댓글