728x90

Story 작성하기

Storybook은 Story를 모아놓은 집합체가 되고, 각각의 Story는 저마다의 Vision State를 가지고 있는 Component를 의미한다. ex) primary button, secondary button, large button, small button , ...

 

하나의 Story를 만들기 위해 필요한 파일은 다음과 같다. 

  • component가 정의되어 있는 파일. ex) button.js(x)
  • style가 정의되어 있는 파일. ex) button.css
  • story가 정의되어 있는 파일. ex) button.stories.js

위 파일들은 하나의 폴더에 모여있어야한다.

 

다음과 같이 Button component와 style이 정의되어 있다고 가정하자

import React from 'react'
import './Button.css'

function Button(props) {
  const {variant = 'primary', children, ...rest} = props;
  return (
    <button className={`button ${variant}} `} {...rest}>{children}</button>
  )
}

export default Button
.button{
  border: none;
  color: white;
  padding: 15px 32px;
  text-align: center;
  text-decoration: none;
  display: inline-block;
  font-size: 16px;
  border-radius: 4px;
  cursor: pointer;
}

.primary {background-color: #008CBA;}
.secondary {background-color: #e7e7e7; color: black};
.success { background-color: #4CAF50;}
.danger {background-color: #f44336;}

총 4개의 디자인의 Button Story가 생성될 수 있다.

import React from 'react';
import Button from './Button';

export default{
  title: 'Button',// 필수, 전체 프로젝트에서 Unique해야한다.
  component: Button,
}

export const Primary = () => <Button variant='primary'>Primary</Button>
export const Secondary = () => <Button variant='secondary'>Secondary</Button>
export const Success = () => <Button variant='success'>Success</Button>
export const Danger = () => <Button variant='danger'>Danger</Button>

//Primary.storyName = 'Primary Button' // story를 rename 할 수 있다.

(npm run storybook을 하면 .storybook/main.js의 stories경로를 보고 해당하는 story 파일들을 읽어 보여준다.)

이같이 독립적으로 component의 디자인이 어떻게 될지 알 수 있다.

협업에서 굉장히 유용하다.

Story 안에 Story 넣기

다음과 같이 Input component도 추가 되었다고 가정하자.

import React from 'react'
import './Input.css';

function Input(props) {
  const {size='medium',...rest} = props;
  return (
    <input className={`input ${size}`} {...rest} />
  )
}

export default Input
.input{
  display: block;
  width:400px;
  padding-left:1rem;
  padding-right:1rem;
  border-radius: 0.25rem;
  border: 1px solid;
  border-color: inherit;
  background-color: #fff;
}

.small{
  height:2rem;
  font-size:0.875rem;
}

.medium{
  height:2.5rem;
  font-size:1rem;
}

.large{
  height:3rem;
  font-size:1.25rem;
}

primary button과 large input을 조합한 component를 subscription이란 이름의 story로 만들고 싶다. 이 때 다음과 같이 Subscription.stories.js를 작성하면된다.

import React from 'react';
import {Primary} from '../Button/Button.stories';
import {Large } from '../Button/Input.stories';

export default{
  title:'Form/Subcription' // Form directory 안에 생성됨
}

export const PrimarySubscription = () =>{
  <>
    <Large/>
    <Primary/>
  </>
}

args를 이용하여 story 만들기

지금까지 우리는 story를 만들때 개별적으로 import 한 component에 props를 넣어주면서 만들었다. 하지만 이 방법보다 storybook의 args속성을 이용하여 props를 설정하는 것이 좀 더 좋은 방법이다.

그 이유는 다음과 같다.

  1. props를 object로 표현하여 넘겨주는 것이 jsx element형식보다 더 적절하다
  2. 복잡한 component가 만들어 지는 상황에서 써야할 코드의 양을 줄일 수 있다.
  3. args는 다른 story에 재사용이 가능하다.
import React from 'react';
import Button from './Button';

export default{
  title: 'Form/Button',
  component: Button,
  // args:{
  //   children:'Button' // default 설정 가능
  // }
}

// export const Primary = () => <Button variant='primary'>Primary</Button>
// export const Secondary = () => <Button variant='secondary'>Secondary</Button>
// export const Success = () => <Button variant='success'>Success</Button>
// export const Danger = () => <Button variant='danger'>Danger</Button>

const Template = args => <Button {...args}/>

export const Primary = Template.bind({})
Primary.args={
  variant:'primary',
  children:'Primary Args'
}

export const LongPrimary = Template.bind({})
LongPrimary.args={
  ...Primary.args,
  children:'Long Primary Args'
}

 

 

Decorator

storybook web에서 보여지는 일괄적인 style을 적용하고 싶을 수 있다. 이때 사용하는 것이 Decorator이다.

Button을 가운데 정열하는 Decorator 파일은 다음과 같이 작성할 수 있다.

// utility component -> decorator
import React from 'react'
import './Center.css';

function Center(props) {
  return (
    <div className="center">{
      props.children
    }</div>
  )
}

export default Center
.center{
  display:flex;
  justify-content: center;
}

이후 Button story에 일괄적인 Center style를 적용하면 된다. 이 때 사용하는 것이 decorator 설정이다

import React from 'react';
import Button from './Button';
import Center from '../Center/Center'
export default{
  title: 'Form/Button',
  component: Button,
  decorators:[story => <Center>{story()}</Center>]
}

const Template = args => <Button {...args}/>

export const Primary = Template.bind({})
Primary.args={
  variant:'primary',
  children:'Primary Args'
}

export const LongPrimary = Template.bind({})
LongPrimary.args={
  ...Primary.args,
  children:'Long Primary Args'
}

결과는 다음과 같이 가운데 정렬이 된다.

모든 storybook에 일괄적인 decorator을 적용하고 싶다면 global decorator을 사용한다. preview.js에서 설정할 수 있다.

import React from 'react';
import {addDecorator} from '@storybook/react';
import Center from '../src/components/Center/Center'

addDecorator(story=><Center>{story()}</Center>)

+ Recent posts