๐ Storybook
Storybook์ UI ์ปดํฌ๋ํธ๋ฅผ ๊ฐ๋ฐ, ํ ์คํธ ๋ฐ ๋ฌธ์ํํ๊ธฐ ์ํ ์คํ ์์ค ๋๊ตฌ์ ๋๋ค.
๊ฐ๋ฐํ ๊ณตํต ์ปดํฌ๋ํธ ํน์ ๋์์ธ ์์คํ ์ ํ ์คํธํ๊ณ ์๊ฐ์ ์ผ๋ก ํ์ธํ ์ ์๋ ํ๊ฒฝ์ ์ ๊ณตํฉ๋๋ค.
์ด๋ฒ์ ์ ์ฌ ๊ณตํต ์ปดํฌ๋ํธ๋ฅผ ์ค๊ณํ๊ณ ์ฌ๋ฌ ๋ฌธ์ํ ํด์ ๊ณ ๋ฏผํ๋ค ๊ฒฐ๊ตญ ์คํ ๋ฆฌ๋ถ์ ์ ํํ๊ฒ ๋์์ต๋๋ค.
๋จ ํ ๋ฒ๋ง ์คํ ๋ฆฌ ํ์ผ๊ณผ mdx ๋ฌธ์ ์์ ๋ฅผ ์์ฑํด ๋๊ณ ๋ฐฐํฌ ์๋ํ๊น์ง ํด๋์ผ๋ ์๊ฐํ๋ ๊ฒ๋ณด๋ค ํฐ ์ด๋ ค์์ ์์๊ณ ๋ง์กฑ๋๋ ๊ต์ฅํ ๋์์ต๋๋ค.
๊ทธ๋ผ ์คํ ๋ฆฌ๋ถ์ ์ฅ์ ๊ณผ ์ฌ์ฉ๋ฐฉ๋ฒ์ ๋ํด ์๊ฐํฉ๋๋ค.
๐ Storybook ์ฅ์
๐ ์๊ฐ์ ํ ์คํธ
๋ฐฑ๋ฌธ์ด ๋ถ์ด์ผ๊ฒฌ.
๊ฐ๊ฐ์ ์คํ ๋ฆฌ๋ฅผ ํตํด ์ปดํฌ๋ํธ๋ค์ props๋ฅผ ์ง์ ์กฐ์ํ๋ฉฐ ์๊ฐ์ ์ผ๋ก ํ์ธํ ์ ์๋ ํ๊ฒฝ์ ์ ๊ณตํฉ๋๋ค.
๋ค์ํ ์ํ์์ ์ปดํฌ๋ํธ๊ฐ ์ด๋ป๊ฒ ๋ณด์ด๋์ง ๋ฏธ๋ฆฌ ํ์ธํ์ฌ ๋์์ธ์ ์ผ๊ด์ฑ์ ์ ์งํ ์ ์๋๋ก ๋์ต๋๋ค.
๋ํ ํ๋ก ํธ ๊ฐ๋ฐ์ด ์ ํํ๊ฒ ๋ฌด์์ธ์ง ๋ชจ๋ฅด๋ ์ธ์์๊ฒ ํน์ ์ปดํฌ๋ํธ๋ฅผ ๊ฐ๋ฐํ๋ค๊ณ ์ค๋ช ํ๋ ๊ฒ์ด ๋๊ฐํ ๋๊ฐ ํ๋ ๋ฒ์ด ์๋์๋๋ฐ, ๊ทธ๋ฅ ์ค๋ช ์์ด ๋ ๋์ผ๋ก ํ์ธ์์ผ ์ค ์ ์๋ค๋ ์ฅ์ ๋ ์์ต๋๋ค.
๐ ๋ ๋ฆฝ์ ์ธ ๋ถ๋ฆฌ
์ฌ๋ด์์ ๊ณตํต์ ์ผ๋ก ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ๋ค์ ์ ์ํด Storybook์ ๋ฑ๋กํ๋ ค ํ๋ค๋ฉด, ๋๋ฉ์ธ์ ์๊ด์์ด ์ด๋ ํ ํ๋ก์ ํธ์์๋ ์ฌ์ฉํ ์ ์์ด์ผ ํฉ๋๋ค.
๊ทธ๋ฌ๊ธฐ ์ํด์ ์ปดํฌ๋ํธ๋ ํน์ ๊ด์ฌ์ฌ์ ์์กด์ฑ๋ค์ ๋ชจ๋ ์ ๊ฑฐํด ๋ฒ์ฉ์ฑ์ด ๋๊ณ ๋ ๋ฆฝ์ ์ด์ด์ผ ํฉ๋๋ค.
์ด๋ ๊ฒ ์ปดํฌ๋ํธ๋ค์ ์ค๊ณํ๋ค ๋ณด๋ฉด ์์ฐ์ค๋ ์ฌ์ฌ์ฉ์ฑ์ด ๋์ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค ์ ์๋ ์ฌ๊ณ ๋ ฅ๊ณผ ์ค๋ ฅ์ด ์ ์ฐจ ํฅ์๋ฉ๋๋ค.
๐ ์ ์ง๋ณด์
์ปดํฌ๋ํธ๊ฐ ๋ ๋ฆฝ์ ์ด๋ผ๋ ๊ฒ์ ์ฝ๋๋ฅผ ์ง์คํํด, ํ ๊ณณ์์ ๊ด๋ฆฌํ ์ ์๋ค๋ ์์ฒญ๋ ์ฅ์ ์ด ์์ต๋๋ค.
์ด์ ์ง์คํ ๋ ์ฝ๋๋ฅผ ๋ฐฐํฌ ํ ์ฒ ์ ํ ๋ฒ์ ๊ด๋ฆฌ๋ฅผ ํจ์ผ๋ก์จ ์ผ๊ด์ฑ ์๋ ์ ์ง๋ณด์๊ฐ ๊ฐ๋ฅํด์ง๋๋ค.
๐ ๋ฌธ์ํ
์คํ ๋ฆฌ๋ถ์ ์ปดํฌ๋ํธ์ ๋ํ ๋ฌธ์๋ฅผ ์๋์ผ๋ก ์์ฑํ๋ฉฐ, ์ฌ์ฉ์์๊ฒ ์ปดํฌ๋ํธ์ Props์ ์ฌ์ฉ๋ฒ, ์์ ๋ฅผ ์ฝ๊ฒ ์ ๊ณตํ ์ ์์ต๋๋ค.
๋๋ถ์ ๋ด๊ฐ ๋ง๋ค๊ฑฐ๋ ๋ค๋ฅธ ์ฌ๋์ด ๋ง๋ ์ปดํฌ๋ํธ๋ค์ ๋ ์ฝ๊ฒ ํ์ธํ๊ณ ์ฌ์ฉํ ์ ์๊ฒ ๋ฉ๋๋ค.
๐ Storybook ์ค์น
$ npx storybook@latest init
์ ๋ช ๋ น์ด๋ก ํ๋ก์ ํธ ๋ฃจํธ์์ ์คํ ๋ฆฌ๋ถ์ ์ค์นํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ํด๋ ๊ตฌ์กฐ๊ฐ ์๋์ผ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค.
package.json ํ์ผ์๋ ์คํ ๋ฆฌ๋ถ์ ์คํํ๊ณ ๋น๋ํ ์ ์๋ ๋ช ๋ น์ด๋ค์ด ์ถ๊ฐ๋ฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ .storybook
ํด๋ ์๋์๋ ์คํ ๋ฆฌ๋ถ์ ๊ตฌ์ฑํ๋ ์ค์ ํ์ผ์ด ์์นํ๊ฒ ๋ฉ๋๋ค.
์ฌ๊ธฐ์ stories
์์ฑ์ ๋ฐฐ์ด ๊ฐ์๋ ์คํ ๋ฆฌ ํ์ผ์ ์ธ์ํ ๊ฒฝ๋ก๋ฅผ ์ ๊ณตํด ์ฃผ๋ฉด ๋ฉ๋๋ค.
๐ Story ์์ฑ ๋ฐฉ๋ฒ
์์์ src ๊ฒฝ๋ก์ ์๋ ์คํ ๋ฆฌ ํ์ผ๋ค์ ์ฝ์ด์ค๋๋ก ์ค์ ํด์ ํด๋น ์์น์ ์ปดํฌ๋ํธ์ ์คํ ๋ฆฌ ํ์ผ์ ์์ฑํด ์ฃผ์์ต๋๋ค.
๊ทธ ํ ๊ฐ๋จํ๊ฒ children๊ณผ backgroundColor๋ฅผ props๋ก ๋ฐ๋ ๋ฒํผ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด ์ฃผ์์ต๋๋ค.
// src/components/Mybutton.tsx
import React from 'react';
export const MyButton = (props: {
children: React.ReactNode;
backgroundColor?: string;
}) => {
return (
<button style={{ backgroundColor: props.backgroundColor }}>
{props.children}
</button>
);
};
๊ทธ๋ค์ ํด๋น ์ปดํฌ๋ํธ์ ์คํ ๋ฆฌ ํ์ผ์ ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ์ต๋๋ค.
import { MyButton } from './MyButton';
const meta = {
title: 'MyComponent/MyButton',
component: MyButton,
argTypes: {
backgroundColor: { control: 'color' },
},
};
export default meta;
export const Primary = {
args: {
children: 'Button',
backgroundColor: '#fff',
},
};
์์ฑ์ ๋ง์น ํ npm run storybook
๋ช
๋ น์ด๋ก ์คํ ๋ฆฌ๋ถ์ ์คํํ๋ฉด ์์ฑํ ์ปดํฌ๋ํธ ์คํ ๋ฆฌ ๋ฌธ์๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
์์์ ์์ฑํ ์คํ ๋ฆฌ ๋ฌธ์์ ์ฃผ์ํ ๊ฐ์ฒด์ ์์ฑ๋ค์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
๐ const meta = { ... };
meta
๊ฐ์ฒด๋ ์คํ ๋ฆฌ์ ๋ฉํ ์ ๋ณด๋ฅผ ์ ์ํฉ๋๋ค.title: 'MyComponent/MyButton'
: ํ์ฌ ์คํ ๋ฆฌ์ ์ ๋ชฉ์ ์ ์ํฉ๋๋ค.
์ด๋ Storybook์์ ์คํ ๋ฆฌ์ ์์น ๋ฐ ๊ตฌ์กฐ๋ฅผ ๊ฒฐ์ ํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค./
๋ก ์คํ ๋ฆฌ ๊ฐ ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ์ค์ ํ ์ ์์ต๋๋ค.component: MyButton
: ํ์ฌ ์คํ ๋ฆฌ์์ ์ฌ์ฉ๋๋ ์ปดํฌ๋ํธ๋ฅผ ์ง์ ํฉ๋๋ค.argTypes: { ... }
: ์ปดํฌ๋ํธ์ ์ธ์(Props)๋ฅผ ์ง์ ์กฐ์ํ ์ ์๋๋ก ์ค์ ํ ์ ์์ต๋๋ค.
๐ export const Primary = { ... };
Primary
๋ผ๋ ์คํ ๋ฆฌ๋ฅผ ์ ์ํฉ๋๋ค.args: { children: 'Button', backgroundColor: '#fff' }
:Primary
์คํ ๋ฆฌ์ ๊ธฐ๋ณธ ์ธ์๋ฅผ ์ ์ํฉ๋๋ค. ์ฆ,MyButton
์ปดํฌ๋ํธ์ ์ ๋ฌ๋๋ Props ๊ฐ์ ๋๋ค. ์ฌ๊ธฐ์๋children
์ 'Button' ๋ฌธ์์ด์,backgroundColor
์๋#fff
๋ฅผ ๊ธฐ๋ณธ ๊ฐ์ผ๋ก ์ค์ ํ๊ณ ์์ต๋๋ค.
๐ argTypes Control Types
๋ฒํผ ์ปดํฌ๋ํธ์์ argTypes์ control ์์ฑ์ color๋ฅผ ์ง์ ํด ์์ ๊ฐ์ด ์ปฌ๋ฌ ํผ์ปค๋ฅผ ์ฌ์ฉํด props๋ฅผ ์กฐ์ํ ์ ์์์ต๋๋ค.
์ด์ ๊ฐ์ด ์ปดํฌ๋ํธ๋ฅผ ์ง๊ด์ ์ผ๋ก ์กฐ์ํ ์ ์๋๋ก ๋๋ ์ฌ๋ฌ ๊ฐ์ง control ์์ฑ๋ค์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- Boolean
- ์ฌ์ฉ์์๊ฒ ์ฒดํฌ๋ฐ์ค๋ฅผ ์ ๊ณตํ์ฌ, true/false ๊ฐ์ ํ ๊ธ ํ ์ ์๊ฒ ํฉ๋๋ค.
- ์:
{ control: { type: 'boolean' } }
- Text
- ๋ฌธ์์ด์ ์ ๋ ฅํ ์ ์๋ ํ ์คํธ ํ๋๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ์:
{ control: { type: 'text' } }
- Number
- ์ซ์๋ฅผ ์ ๋ ฅํ ์ ์๋ ํ๋๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ต์๊ฐ, ์ต๋๊ฐ, ์คํ (์ฆ๊ฐ ๋จ์)์ ์ต์ ์ผ๋ก ์ค์ ํ ์ ์์ต๋๋ค.
- ์:
{ control: { type: 'number', min: 0, max: 100, step: 5 } }
- Color
- ์์ ์ ํ๊ธฐ๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ฌ์ฉ์๊ฐ ์ปดํฌ๋ํธ์ ์์์ ์ฝ๊ฒ ๋ณ๊ฒฝํ ์ ์๊ฒ ํด ์ค๋๋ค.
- ์:
{ control: { type: 'color' } }
- Object
- ๊ฐ์ฒด๋ฅผ JSON ํํ๋ก ์ ๋ ฅํ ์ ์๋ ํ ์คํธ ์์ญ์ ์ ๊ณตํฉ๋๋ค. ๋ณต์กํ ๊ฐ์ฒด ๊ตฌ์กฐ๋ฅผ props๋ก ์ ๋ฌํ ๋ ์ ์ฉํฉ๋๋ค.
- ์:
{ control: { type: 'object' } }
- Select
- ์ฌ์ฉ์๊ฐ ๋ชฉ๋ก์์ ์ฌ๋ฌ ์ต์ ์ค ํ๋๋ฅผ ์ ํํ ์ ์๊ฒ ํ๋ ๋๋กญ๋ค์ด ๋ฉ๋ด๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ์:
{ control: { type: 'select', options: ['Option 1', 'Option 2'] } }
- Radio
- ์ฌ๋ฌ ์ต์
์ค ํ๋๋ฅผ ์ ํํ ์ ์๋ ๋ผ๋์ค ๋ฒํผ์ ์ ๊ณตํฉ๋๋ค.
select
์ ์ ์ฌํ์ง๋ง UI๊ฐ ๋ค๋ฆ ๋๋ค. - ์:
{ control: { type: 'radio', options: ['Option 1', 'Option 2'] } }
- ์ฌ๋ฌ ์ต์
์ค ํ๋๋ฅผ ์ ํํ ์ ์๋ ๋ผ๋์ค ๋ฒํผ์ ์ ๊ณตํฉ๋๋ค.
- InlineRadio
- ๋ผ๋์ค ๋ฒํผ์ ์ธ๋ผ์ธ(์ํ)์ผ๋ก ํ์ํฉ๋๋ค. ์ ํ ์ต์ ์ ์์ผ๋ก ๋์ดํฉ๋๋ค.
- ์:
{ control: { type: 'inline-radio', options: ['Option 1', 'Option 2'] } }
- Check
- ์ฌ์ฉ์๊ฐ ์ฌ๋ฌ ์ต์ ์ ์ ํํ ์ ์๋ ์ฒดํฌ๋ฐ์ค ๊ทธ๋ฃน์ ์ ๊ณตํฉ๋๋ค.
- ์:
{ control: { type: 'check', options: ['Option 1', 'Option 2'] } }
- InlineCheck
- ์ฒดํฌ๋ฐ์ค๋ฅผ ์ธ๋ผ์ธ(์ํ)์ผ๋ก ํ์ํฉ๋๋ค. ์ฌ๋ฌ ์ต์ ์ ์์ผ๋ก ๋์ดํฉ๋๋ค.
- ์:
{ control: { type: 'inline-check', options: ['Option 1', 'Option 2'] } }
- Range
- ์ฌ๋ผ์ด๋๋ฅผ ํตํด ์ซ์ ๊ฐ์ ์ ํํ ์ ์๋ ์ปจํธ๋กค์ ์ ๊ณตํฉ๋๋ค. ์ต์๊ฐ, ์ต๋๊ฐ, ์คํ ์ ์ค์ ํ ์ ์์ต๋๋ค.
- ์:
{ control: { type: 'range', min: 0, max: 100, step: 5 } }
- Date
- ๋ ์ง๋ฅผ ์ ํํ ์ ์๋ ๋ฌ๋ ฅ UI๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ์:
{ control: { type: 'date' } }
- File
- ํ์ผ์ ์ ๋ก๋ํ ์ ์๋ ์ ๋ ฅ ํ๋๋ฅผ ์ ๊ณตํฉ๋๋ค. ํ์ฉํ๋ ํ์ผ ํ์ ์ ์ค์ ํ ์ ์์ต๋๋ค.
- ์:
{ control: { type: 'file', accept: '.png,.jpg' } }
๐ mdx๋ก ๋ฌธ์ ์์ฑ
.storybook/main.ts ํ์ผ์ mdx ํ์ผ๋ ์ธ์ํ ์ ์๋๋ก ํ์ต๋๋ค.
์คํ ๋ฆฌ๋ถ์ Story ํ์ผ๋ฟ ์๋๋ผ mdx ํ์ฅ์ ํ์ผ๋ก๋ ๋ฌธ์ํ๋ฅผ ํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
์ฐ์ ์์ํ ์ ์์ผ๋ mdx ํ์ผ์ ๋ํ ์ค๋ช ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
๐ mdx ํ์ผ์ด๋
MDX๋ Markdown ๊ธฐ๋ฐ์ ๋ฌธ์๋ฅผ ํ์ฅํ ๊ฒ์ผ๋ก, React ์ปดํฌ๋ํธ๋ฅผ ํฌํจํ ์ ์๋ ๋งํฌ๋ค์ด ๋ฌธ์ ํ์์ ๋๋ค.
MDX ํ์ผ์ JavaScript์ JSX ์ฝ๋๋ฅผ ํฌํจํ์ฌ ๋ ๋์ ์ด๊ณ ์ธํฐ๋ํฐ๋ธ ํ ์ฝํ ์ธ ๋ฅผ ์์ฑํ ์ ์๊ฒ ํด ์ค๋๋ค.
์ฃผ๋ก ๋ฌธ์, ๋ธ๋ก๊ทธ ํฌ์คํธ, ํ๋ก์ ํธ์ ์ฌ์ฉ ์ค๋ช ์ ๋ฑ์ ์์ฑํ ๋ ์ฌ์ฉ๋ฉ๋๋ค.
ํ๋ง๋๋ก ๋งํฌ๋ค์ด ํ์์ ์ฌ์ฉํ๋ฉด์ ๋ฆฌ์กํธ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋ง ํ ์ ์๋ ๋ฌธ์์ ๋๋ค.
์คํ ๋ฆฌ๋ถ ํ๊ฒฝ์ ์์ฒด์ ์ผ๋ก ์คํ๋๊ธฐ ๋๋ฌธ์ ํน์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ปดํฌ๋ํธ๋ฅผ ์คํ ๋ฆฌ๋ก ๋ง๋๋ ค ํ ๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
๊ทธ๋ด ๋ ๋ค๋ฅธ ๋ฌธ์ํ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ์ง ์๊ณ mdx ํ์์ ์ด์ฉํด ์คํ ๋ฆฌ๋ถ ํ๊ฒฝ ๋ด์์ ๋ฌธ์๋ฅผ ํ์ธํ ์ ์๋๋ก ํฉ๋๋ค.
์์ ๊ฐ์ด ์์ฑํ๊ณ Meta์ ์์ ๊ฐ์ด ๊ณ์ธต๊ตฌ์กฐ๋ฅผ ์ ํด title์ ์ ํด์ฃผ๋ฉด ๋ค์๊ณผ ๊ฐ์ด ํ์๋ฉ๋๋ค.
๋๊ธ