본문 바로가기

React/NextJS

Nextjs Boilerplate 만들기 - 4 [Storybook 설정]

스토리북 설정

스토리북을 설치합니다.

스토리북은 UI 컴포넌트 개발용 지원 도구 입니다.

톡립적인 환경에서 UI 컴포넌트의 형태나 작동을 확인할 수 있고 

디자이너도 함께 사용하며 협업에도 도움을 줍니다.

 

npx storybook@latest init

 

설치가 완료되고 실행을 해봅니다.

 

yarn storybook

 

예시 컴포넌트를 생성하여 스토리북을 테스트해봅니다 

components/StyledButton.tsx 생성

 

import { css, styled } from 'styled-components'

const variants = {
  primary: {
    color: '#ffffff',
    backgroundColor: '#1D3461',
    border: 'none',
  },
  success: {
    color: '#ffffff',
    backgroundColor: '#5AB203',
    border: 'none',
  },
  transparent: {
    color: '#111111',
    backgroundColor: 'transparent',
    border: '1px solid black',
  },
} as const

type StyledButtonProps = {
  variant: keyof typeof variants
}

export const StyledButton = styled.button<StyledButtonProps>`
  ${({ variant }) => {
    const style = variants[variant]

    return css`
      color: ${style.color};
      background-color: ${style.backgroundColor};
      border: ${style.border};
    `
  }}

  border-radius: 12px;
  font-size: 14px;
  height: 38px;
  line-height: 22px;
  letter-spacing: 0;
  cursor: pointer;
  &:focus {
    outline: none;
  }
`

 

 

스토리북에서 StyledButton.tsx를 표시하기 위해 stories/StyledButton.stories.tsx 를 작성해봅니다.

 

import { StyledButton, StyledButtonProps } from '@/components'
import { Meta, StoryObj } from '@storybook/react'

const meta: Meta<typeof StyledButton> = {
  title: 'Components/StyledButton',
  component: StyledButton,
  tags: ['autodocs'],
  argTypes: {
    variant: {
      control: {
        type: 'radio',
      },
      options: ['primary', 'success', 'error', 'transparent'],
    },
    size: {
      control: {
        type: 'radio',
      },
      options: ['small', 'medium', 'large'],
    }
  },
}

export default meta

type Story = StoryObj<typeof StyledButton>

export const Primary: Story = {
  args: {
    variant: 'primary',
    label: 'Primary',
    size: 'medium',
  },
  render: (props: StyledButtonProps) => (
    <StyledButton {...props} variant='primary'>
      {props.label}
    </StyledButton>
  ),
}
export const Success: Story = {
  args: {
    variant: 'success',
    label: 'Success',
    size: 'small',
  },
  render: (props: StyledButtonProps) => (
    <StyledButton {...props} variant='success'>
      {props.label}
    </StyledButton>
  ),
}
export const Error: Story = {
  args: {
    variant: 'error',
    label: 'Error',
  },
  render: (props: StyledButtonProps) => (
    <StyledButton {...props} variant='error'>
      {props.label}
    </StyledButton>
  ),
}
export const Transparent: Story = {
  args: {
    variant: 'transparent',
    label: 'Transparent',
  },
  render: (props: StyledButtonProps) => (
    <StyledButton {...props} variant='transparent'>
      {props.label}
    </StyledButton>
  ),
}

 

 

 

스토리북을 실행해보면 경로를 못찾는 오류가 발생합니다. 

 

 

 

이 오류를 해결하기 위해  .storybook/main.ts 파일에 절대경로 설정을 추가해줍니다. [참고]

 

import type { StorybookConfig } from '@storybook/nextjs'

const path = require('path') // +
const config: StorybookConfig = {
  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
  addons: [
    '@storybook/addon-links',
    '@storybook/addon-essentials',
    '@storybook/addon-interactions',
  ],
  framework: {
    name: '@storybook/nextjs',
    options: {},
  },
  docs: {
    autodocs: 'tag',
  },
  webpackFinal: async (config) => {
    config.resolve!!.alias!!['@'] = path.resolve(__dirname, '../src/') // +
    return config
  },
  staticDirs: ['../public'],
}
export default config

 

근데 또 다른 오류가 있습니다. 

스토리북을 init 하면서 생성되었던 Button 예시를 보면 

 

 

jsx property를 eslint가 오류를 뱉어냅니다. 

이 부분은 .eslintrc.json 파일에 rule 를 추가하여 오류를 제거해줍니다.

 

"react/no-unknown-property": [2, { "ignore": ["jsx"] }]

 

 

StoryBook 실행 결과

 

yarn storybook

 

 

Actions

 

컴포넌트를 클릭하는 이벤트가 발생할 때 콜백이 호출되는지 스토리북에서 확인할 수 있습니다.

StyledButton.stories.tsx 파일에 있는 메타데이터를 수정합니다. 

 

const meta: Meta<typeof StyledButton> = {
  title: 'Components/StyledButton',
  component: StyledButton,
  tags: ['autodocs'],
  argTypes: {
    variant: {
      control: {
        type: 'radio',
      },
      options: ['primary', 'success', 'error', 'transparent'],
    },
    size: {
      control: {
        type: 'radio',
      },
      options: ['small', 'medium', 'large'],
    },
    onClick: { action: 'clicked' }, // +
  },
}

 

그리고 storybook 에서 Actions 탭에 있는 버튼을 클릭해보면 이벤트가 표시됩니다.