[TypeScript] 타입스크립트에서 Styled-components 애니메이션 재활용하기

김방울·2023년 3월 25일
0

TypeScript

목록 보기
9/12
post-thumbnail

SCSS에서는 mixin 기능으로 파라미터를 넣어 애니메이션을 유연하게👻 만들 수 있습니다.

@mixin jump($name: default, $x: 1.1, $y: 0.9, $z: -2rem, $time: 2.4s, $bounce: 0.05) {
  @keyframes jump__#{$name} {
    0% {
      transform: scale(1, 1) translateY(0);
    }

    5% {
      transform: scale($x, $y) translateY(0);
    }

    25% {
      transform: scale($y, $x) translateY($z);
    }

    50% {
      transform: scale($x, $y) translateY(0);
    }

    60% {
      transform: scale(#{$x + $bounce}, $y) translateY(0);
    }

    70% {
      transform: scale(1, 1) translateY(0);
    }

    100% {
      transform: scale(1, 1) translateY(0);
    }
  }

  animation: jump__#{$name} $time ease infinite;
}

@mixin animate($animation, $duration, $method, $times) {
  animation: $animation $duration $method $times;
}

Styled-components로도 animation을 유동적으로 생성할 수 있는 방법이 있을까 고민하다,
리터럴 문법을 활용해 보기로 하였습니다.

// _app.tsx
import { ThemeProvider } from 'styled-components';

import DefaultStyle from '@/assets/style';
import theme from '@/assets/style/Theme';
import HeadInfo from '@/components/common/HeadInfo';
import ModalView from '@/components/common/modal/ModalView';
import type { AppProps } from 'next/app';
import { Provider } from 'react-redux';
import indexStore from '@/redux';

export default function App({ Component, pageProps }: AppProps) {
  return (
    <>
      <HeadInfo />
      <DefaultStyle />
      <Provider store={indexStore}>
        <ThemeProvider theme={theme}>
          <Component {...pageProps} />
          <ModalView />
        </ThemeProvider>
      </Provider>
    </>
  );
}

일단 애니메이션을 어떤 컴포넌트에서도 사용할 수 있도록,
theme을 정의한 theme.ts 파일을 만들고 루트 컴포넌트에서ThemeProvider 로 내려주었습니다.

//theme.ts
import { css } from 'styled-components';
import { fadeInParamType } from './animation';

export const color = {...};
export const layout = {...};
export const font = {...};

export const animation = {
  fadeIn: ({ name, duration, count = '1', direction = 'normal' }: FadeInParamType) => css`
    @keyframes fadeInAni${name} {
      0% {
        opacity: 0;
      }
      100% {
        opacity: 100%;
      }
    }
    animation: ${'fadeInAni' + name} ${duration} ${count} ${direction};
  `,
};

const theme = {
  color,
  layout,
  font,
  animation,
};

export default theme;

그 다음에는 theme.ts 파일에 animation을 함수 형식으로 정의해 줍니다.
styled-components 라이브러리에서 css 함수를 import 한 뒤
유동적으로 만들어 줄 부분을 파라미터로 만들고, css 리터럴을 반환해주는 함수를 만들어 주었습니다. 💨

// animation.d.ts
type DirectionType = 'normal' | 'reverse' | 'alternate' | 'alternate-reverse';

interface BaseAniParamType {
  name: string;
  duration: string;
}

interface FadeInParamType extends BaseAniParamType {
  direction?: directionType;
  count?: string;
}

추가적으로, 저는 typeScript를 사용했기 때문에 함수 파라미터의 타입을 정의해 주는 animation.d.ts 파일을 만들었습니다.

const Modal = {
  Section: styled.section`
    display: flex;
    justify-content: center;
    align-items: center;
    background: rgba(0, 0, 0, 0.63);
    position: fixed;
    top: 0;
    left: 0;
    z-index: 99;
    width: 100%;
    height: 100%;
    ${({ theme }) => theme.animation.fadeIn({ name: 'modalFadeIn', duration: '0.2s' })};

${({ theme }) => theme.animation.fadeIn({ name: 'modalFadeIn', duration: '0.2s' })};

만든 애니메이션은 스타일 컴포넌트의 props.theme 에서 꺼내 다음과 같이 사용이 가능합니다.🙇

profile
코딩하는 고양이🐱 / UI Developer, Front-end Developer

0개의 댓글