Storybook 폴더 구조
스토리북을 설치하면 stories 폴더가 새로 생겨있을 것이다. 이 sotries 폴더 하위에에 문서화할 컴포넌트 명을 넣어 다음과 같이 stories 파일을 새로 생성한다. [컴포넌트명].stories.ts파일
'이미 components 폴더에 만들어놓은 컴포넌트 중 문서화를 해줄 컴포넌트를 stories 파일에서 import해온다 -> 그에 대해 서술하는 내용을 코드로 적는다'가 바로 스토리 작성이다.
컴포넌트 설계하기
Storybook을 실행하면 들어있는 예제 중 Button 컴포넌트를 뜯어보며
재사용하기 좋은 컴포넌트, 그리고 Storybook으로 문서화하기 좋은 컴포넌트는 어떻게 설계하면 되는지 알아보자.
1. 해당 컴포넌트의 특성 파악하기
이 버튼이란 녀석은
- 버튼 안에 글자를 가진다. (label)
- Primary / Secondary 처럼 중요도에 따라 다른 색깔을 가지는 등 약간 차별점이 있다. (primary)
- large, medium, small 등 사이즈를 조절할 수 있다.
- 때에 따라 원하는 배경색을 주입할 수 있어야 한다.
- 클릭하면 특정 함수를 실행하는 경우도 있다. (onClick)
는 특성을 가져야 한다.
2. 컴포넌트 작성 및 조건별 스타일링
MyButton이라는 컴포넌트를 생성해 원래 있던 것과 똑같이 따라 만들어보자.
기본 예제에서 Button.tsx는 css와 class로 스타일링 되어 있는데 나는 emotion으로 스타일링을 해줘보겠다.
컴포넌트 작성
components/MyButton.tsx
import React from 'react';
import { css } from '@emotion/react';
interface MyButtonProps {
primary?: boolean;
backgroundColor?: string;
size?: 'small' | 'medium' | 'large';
label: string;
onClick?: () => void;
}
function MyButton({
primary = false,
size = 'medium',
backgroundColor,
label,
...props
}: MyButtonProps) {
return (
<button
type="button"
css={[
MyButtonStyle,
getVariantStyles({ primary }),
getSizeStyles({ size }),
backgroundColor && setBackgroundColor(backgroundColor),
]}
{...props}
>
{label}
</button>
);
}
스타일 정의
MyButton function 바깥 부분에 아래의 스타일 변수 및 함수를 정의한다.
기본 스타일과, primary 여부나 사이즈별 스타일을 반환하는 함수를 작성한다.
// 기본 스타일
const MyButtonStyle = css`
font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-weight: 700;
border: 0;
border-radius: 3em;
cursor: pointer;
display: inline-block;
line-height: 1;
`;
// primary, primary 아님 여부
const getVariantStyles = ({ primary = false }) =>
primary
? css`
color: white;
background-color: #1ea7fd;
`
: css`
color: #333;
background-color: transparent;
box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;
`;
// size별 스타일
const getSizeStyles = ({ size = 'medium' }) => {
switch (size) {
case 'small': {
return css`
font-size: 12px;
padding: 10px 16px;
`;
}
case 'large': {
return css`
font-size: 16px;
padding: 12px 24px;
`;
}
default: {
return css`
font-size: 14px;
padding: 11px 20px;
`;
}
}
};
const setBackgroundColor = (colorCode: string) => css`
background-color: ${colorCode};
`;
export default MyButton;
각 상황별 스타일을 emotion의 css prop에서 배열을 이용해 중첩하고 있다.
css={[MyButtonStyle, getVariantStyles({ primary }), getSizeStyles({ size }),
backgroundColor && setBackgroundColor(backgroundColor),]}
주의해야 할 점은 getVariantStyles(primary) 이런 식으로 작성하면 안된다는 것이다.
const getVariantStyles = ({ primary = false }) => {}
와 같이 함수가 정의되어 있기 때문에 인자도 {} 괄호 안에 담아 object 형식으로 줘야 한다.
const getVariantStyles = ({primary}) => { //... }
결과
조건별로 버튼이 잘 나오고 있다.
function App() {
return (
<div css={containerStyle}>
<div>
<MyButton label="hi" primary />
<MyButton label="hi" />
</div>
<br />
<div>
<MyButton label="hi" size={'large'} />
<MyButton label="hi" size={'medium'} />
<MyButton label="hi" size={'small'} />
</div>
</div>
);
}
3. Story 작성하기
src/stories 폴더에 MyButton.stories.ts를 만들어주자.
meta는 해당 story 문서가 어떤 계층구조를 가지는지, 어떤 컴포넌트에 대한 문서인지와 같은 메타정보를 갖고 있다.
// src/stories/MyButton.stories.ts
import type { Meta, StoryObj } from '@storybook/react';
import MyButton from '../components/MyButton';
// meta 정보 작성
const meta = {
title: 'Atoms/MyButton',
component: MyButton,
tags: ['autodocs'],
argTypes: {
backgroundColor: { control: 'color' },
},
} satisfies Meta<typeof MyButton>;
export default meta;
title을 'Atoms/MyButton'로 설정했기 때문에 Atoms라는 폴더 하위에 MyButton이라는 이름으로 문서가 생긴다.
이어서 아랫부분에 다음 코드를 계속 작성한다.
Primary, Secondary, Large, Medium, Small처럼 컴포넌트가 특정 조건을 가졌을 때의 순간을 보여주기 위한 코드이다.
type Story = StoryObj<typeof meta>;
// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
export const Primary: Story = {
args: {
primary: true,
label: 'Button',
},
};
export const Secondary: Story = {
args: {
label: 'Button',
},
};
export const Large: Story = {
args: {
size: 'large',
label: 'Button',
},
};
export const Medium: Story = {
args: {
size: 'medium',
label: 'Button',
},
};
export const Small: Story = {
args: {
size: 'small',
label: 'Button',
},
};
4. props의 Description을 작성하고 싶다면
Storybook의 description, default, control 등은 주석 또는 Typescript의 interface에 의해 문서화된다.
이렇게 MyButton 컴포넌트의 interface에 주석을 달면 그 prop이 boolean인지 등 타입 뿐만 아니라 설명도 추가되는 것을 볼 수 있다.
interface MyButtonProps {
/**
* 페이지에서 가장 중요성을 갖는 버튼 요소인가?
*/
primary?: boolean;
backgroundColor?: string;
size?: 'small' | 'medium' | 'large';
label: string;
onClick?: () => void;
}
Reference
'Front-end > 스타일링 라이브러리' 카테고리의 다른 글
Typescript + Emotion + Storybook 설치 및 환경설정 (0) | 2023.06.19 |
---|---|
[React] emotion 설치 및 typescript에서 사용하기 (pragma 제거방법) (0) | 2022.11.24 |