@bigtablet/design-system 1.14.0 → 1.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +455 -509
- package/dist/index.css +199 -199
- package/dist/index.d.ts +1 -6
- package/dist/index.js +106 -137
- package/dist/next.css +22 -22
- package/dist/next.js +23 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
<img width="1800" height="300" alt="Image" src="https://github.com/user-attachments/assets/420a15cc-5be3-447f-9c64-068e946cb118" /> <br>
|
|
4
4
|
|
|
5
|
-
</div>
|
|
6
|
-
|
|
7
5
|
# Bigtablet Design System
|
|
8
6
|
|
|
9
7
|
[](https://www.npmjs.com/package/@bigtablet/design-system)
|
|
@@ -11,9 +9,9 @@
|
|
|
11
9
|
|
|
12
10
|
Bigtablet의 공식 디자인 시스템으로, Foundation(디자인 토큰)과 Components(UI 컴포넌트)로 구성된 통합 UI 라이브러리입니다.
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
[GitHub](https://github.com/Bigtablet/bigtablet-design-system) · [NPM](https://www.npmjs.com/package/@bigtablet/design-system) · [Storybook](https://bigtablet.github.io/bigtablet-design-system)
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
</div>
|
|
17
15
|
|
|
18
16
|
---
|
|
19
17
|
|
|
@@ -22,93 +20,73 @@ Bigtablet의 공식 디자인 시스템으로, Foundation(디자인 토큰)과 C
|
|
|
22
20
|
- [주요 특징](#주요-특징)
|
|
23
21
|
- [설치](#설치)
|
|
24
22
|
- [빠른 시작](#빠른-시작)
|
|
25
|
-
- [
|
|
23
|
+
- [컴포넌트](#컴포넌트)
|
|
26
24
|
- [Foundation (디자인 토큰)](#foundation-디자인-토큰)
|
|
27
|
-
- [Components (UI 컴포넌트)](#components-ui-컴포넌트)
|
|
28
25
|
- [개발 가이드](#개발-가이드)
|
|
29
26
|
- [기여하기](#기여하기)
|
|
30
|
-
- [라이센스](#라이센스)
|
|
31
27
|
|
|
32
28
|
---
|
|
33
29
|
|
|
34
30
|
## 주요 특징
|
|
35
31
|
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
- Storybook 8 기반 인터랙티브 문서화
|
|
43
|
-
- Chromatic 시각적 회귀 테스트
|
|
44
|
-
- Pure React / Next.js 전용 번들 제공
|
|
45
|
-
|
|
46
|
-
**최신 기술 스택**
|
|
47
|
-
- React 19 지원
|
|
48
|
-
- pnpm 워크스페이스
|
|
49
|
-
- GitHub Actions 자동 배포
|
|
50
|
-
- Changesets 기반 버전 관리
|
|
51
|
-
|
|
52
|
-
**디자인 시스템**
|
|
53
|
-
- 일관된 디자인 토큰 (색상, 타이포그래피, 간격 등)
|
|
54
|
-
- 접근성(a11y) 기본 지원
|
|
55
|
-
- 다크모드 준비중
|
|
32
|
+
- **React 19 지원** - 최신 React 버전 완벽 지원
|
|
33
|
+
- **TypeScript** - 완전한 타입 안정성
|
|
34
|
+
- **Pure React / Next.js** - 프레임워크별 최적화된 번들 제공
|
|
35
|
+
- **디자인 토큰** - 일관된 색상, 타이포그래피, 간격 시스템
|
|
36
|
+
- **접근성(a11y)** - 키보드 네비게이션, 스크린 리더 호환
|
|
37
|
+
- **Storybook** - 인터랙티브 문서화
|
|
56
38
|
|
|
57
39
|
---
|
|
58
40
|
|
|
59
41
|
## 설치
|
|
60
42
|
|
|
61
|
-
### npm
|
|
62
43
|
```bash
|
|
44
|
+
# npm
|
|
63
45
|
npm install @bigtablet/design-system
|
|
64
|
-
```
|
|
65
46
|
|
|
66
|
-
|
|
67
|
-
```bash
|
|
47
|
+
# yarn
|
|
68
48
|
yarn add @bigtablet/design-system
|
|
49
|
+
|
|
50
|
+
# pnpm
|
|
51
|
+
pnpm add @bigtablet/design-system
|
|
69
52
|
```
|
|
70
53
|
|
|
71
|
-
###
|
|
54
|
+
### Peer Dependencies
|
|
55
|
+
|
|
72
56
|
```bash
|
|
73
|
-
|
|
57
|
+
npm install react react-dom lucide-react react-toastify
|
|
74
58
|
```
|
|
75
59
|
|
|
76
60
|
---
|
|
77
61
|
|
|
78
62
|
## 빠른 시작
|
|
79
63
|
|
|
80
|
-
### Pure React
|
|
64
|
+
### Pure React
|
|
81
65
|
|
|
82
66
|
```tsx
|
|
83
67
|
import { Button, TextField } from '@bigtablet/design-system';
|
|
84
|
-
import '@bigtablet/design-system/
|
|
68
|
+
import '@bigtablet/design-system/style.css';
|
|
85
69
|
|
|
86
70
|
function App() {
|
|
87
71
|
return (
|
|
88
72
|
<div>
|
|
89
|
-
<TextField
|
|
90
|
-
|
|
91
|
-
type="email"
|
|
92
|
-
placeholder="email@example.com"
|
|
93
|
-
/>
|
|
94
|
-
<Button variant="primary" size="md">
|
|
95
|
-
제출하기
|
|
96
|
-
</Button>
|
|
73
|
+
<TextField label="이메일" placeholder="email@example.com" />
|
|
74
|
+
<Button variant="primary">제출</Button>
|
|
97
75
|
</div>
|
|
98
76
|
);
|
|
99
77
|
}
|
|
100
78
|
```
|
|
101
79
|
|
|
102
|
-
### Next.js
|
|
80
|
+
### Next.js
|
|
103
81
|
|
|
104
82
|
```tsx
|
|
105
83
|
import { Sidebar, Button } from '@bigtablet/design-system/next';
|
|
106
|
-
import '@bigtablet/design-system/
|
|
84
|
+
import '@bigtablet/design-system/style.css';
|
|
107
85
|
|
|
108
86
|
export default function Layout({ children }) {
|
|
109
87
|
return (
|
|
110
88
|
<div>
|
|
111
|
-
<Sidebar
|
|
89
|
+
<Sidebar
|
|
112
90
|
items={[
|
|
113
91
|
{ label: '홈', href: '/' },
|
|
114
92
|
{ label: '대시보드', href: '/dashboard' }
|
|
@@ -120,502 +98,582 @@ export default function Layout({ children }) {
|
|
|
120
98
|
}
|
|
121
99
|
```
|
|
122
100
|
|
|
123
|
-
### Foundation 토큰 사용
|
|
124
|
-
|
|
125
|
-
```tsx
|
|
126
|
-
import { colors, spacing, typography } from '@bigtablet/design-system/foundation';
|
|
127
|
-
|
|
128
|
-
const StyledComponent = styled.div`
|
|
129
|
-
color: ${colors.brand.primary};
|
|
130
|
-
padding: ${spacing.md};
|
|
131
|
-
font-size: ${typography.body.fontSize};
|
|
132
|
-
`;
|
|
133
|
-
```
|
|
134
|
-
|
|
135
101
|
---
|
|
136
102
|
|
|
137
|
-
##
|
|
103
|
+
## 컴포넌트
|
|
138
104
|
|
|
139
|
-
|
|
140
|
-
bigtablet-design-system/
|
|
141
|
-
├── .changeset/ # 버전 관리 설정
|
|
142
|
-
├── .github/
|
|
143
|
-
│ └── workflows/ # CI/CD 파이프라인
|
|
144
|
-
├── .storybook/ # Storybook 설정
|
|
145
|
-
├── public/ # 정적 리소스
|
|
146
|
-
├── scripts/ # 빌드 및 배포 스크립트
|
|
147
|
-
├── src/
|
|
148
|
-
│ ├── styles/
|
|
149
|
-
│ │ ├── ts/ # TypeScript 디자인 토큰
|
|
150
|
-
│ │ │ ├── colors.ts
|
|
151
|
-
│ │ │ ├── spacing.ts
|
|
152
|
-
│ │ │ ├── typography.ts
|
|
153
|
-
│ │ │ ├── radius.ts
|
|
154
|
-
│ │ │ ├── shadows.ts
|
|
155
|
-
│ │ │ ├── motion.ts
|
|
156
|
-
│ │ │ ├── z-index.ts
|
|
157
|
-
│ │ │ ├── breakpoints.ts
|
|
158
|
-
│ │ │ └── a11y.ts
|
|
159
|
-
│ │ └── scss/ # SCSS 믹스인 및 변수
|
|
160
|
-
│ ├── ui/
|
|
161
|
-
│ │ ├── form/ # 입력 컴포넌트
|
|
162
|
-
│ │ │ ├── Button/
|
|
163
|
-
│ │ │ ├── TextField/
|
|
164
|
-
│ │ │ ├── Checkbox/
|
|
165
|
-
│ │ │ ├── Radio/
|
|
166
|
-
│ │ │ ├── Switch/
|
|
167
|
-
│ │ │ ├── Select/
|
|
168
|
-
│ │ │ └── FileInput/
|
|
169
|
-
│ │ ├── feedback/ # 피드백 컴포넌트
|
|
170
|
-
│ │ │ ├── Alert/
|
|
171
|
-
│ │ │ ├── Toast/
|
|
172
|
-
│ │ │ └── Loading/
|
|
173
|
-
│ │ ├── navigation/ # 네비게이션 컴포넌트
|
|
174
|
-
│ │ │ ├── Pagination/
|
|
175
|
-
│ │ │ └── Sidebar/
|
|
176
|
-
│ │ ├── overlay/ # 오버레이 컴포넌트
|
|
177
|
-
│ │ │ └── Modal/
|
|
178
|
-
│ │ ├── display/ # 표시 컴포넌트
|
|
179
|
-
│ │ │ └── Card/
|
|
180
|
-
│ │ └── skeleton/ # 스켈레톤 컴포넌트
|
|
181
|
-
│ │ ├── SkeletonCard/
|
|
182
|
-
│ │ └── SkeletonList/
|
|
183
|
-
│ ├── index.ts # Pure React 진입점
|
|
184
|
-
│ └── next.ts # Next.js 진입점
|
|
185
|
-
├── package.json
|
|
186
|
-
├── tsconfig.json
|
|
187
|
-
├── tsup.config.ts
|
|
188
|
-
└── README.md
|
|
189
|
-
```
|
|
105
|
+
### General
|
|
190
106
|
|
|
191
|
-
|
|
107
|
+
#### Button
|
|
192
108
|
|
|
193
|
-
|
|
109
|
+
```tsx
|
|
110
|
+
import { Button } from '@bigtablet/design-system';
|
|
194
111
|
|
|
195
|
-
|
|
112
|
+
// 기본 사용
|
|
113
|
+
<Button>클릭</Button>
|
|
196
114
|
|
|
197
|
-
|
|
115
|
+
// Variants
|
|
116
|
+
<Button variant="primary">Primary</Button>
|
|
117
|
+
<Button variant="secondary">Secondary</Button>
|
|
118
|
+
<Button variant="ghost">Ghost</Button>
|
|
119
|
+
<Button variant="danger">Danger</Button>
|
|
198
120
|
|
|
199
|
-
|
|
121
|
+
// Sizes
|
|
122
|
+
<Button size="sm">Small</Button>
|
|
123
|
+
<Button size="md">Medium</Button>
|
|
124
|
+
<Button size="lg">Large</Button>
|
|
200
125
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
brand: {
|
|
205
|
-
primary: '#0066FF',
|
|
206
|
-
secondary: '#00C896',
|
|
207
|
-
},
|
|
208
|
-
background: {
|
|
209
|
-
primary: '#FFFFFF',
|
|
210
|
-
secondary: '#F5F5F5',
|
|
211
|
-
},
|
|
212
|
-
text: {
|
|
213
|
-
primary: '#1A1A1A',
|
|
214
|
-
secondary: '#666666',
|
|
215
|
-
},
|
|
216
|
-
status: {
|
|
217
|
-
success: '#22C55E',
|
|
218
|
-
error: '#EF4444',
|
|
219
|
-
warning: '#F59E0B',
|
|
220
|
-
}
|
|
221
|
-
};
|
|
126
|
+
// 너비 조절
|
|
127
|
+
<Button width="200px">고정 너비</Button>
|
|
128
|
+
<Button width="100%">전체 너비</Button>
|
|
222
129
|
```
|
|
223
130
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
131
|
+
| Prop | Type | Default | Description |
|
|
132
|
+
|------|------|---------|-------------|
|
|
133
|
+
| `variant` | `'primary' \| 'secondary' \| 'ghost' \| 'danger'` | `'primary'` | 버튼 스타일 |
|
|
134
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | 버튼 크기 |
|
|
135
|
+
| `width` | `string` | `'100%'` | 버튼 너비 |
|
|
136
|
+
| `disabled` | `boolean` | `false` | 비활성화 |
|
|
230
137
|
|
|
231
|
-
|
|
138
|
+
#### Select
|
|
232
139
|
|
|
233
|
-
|
|
140
|
+
```tsx
|
|
141
|
+
import { Select } from '@bigtablet/design-system';
|
|
234
142
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
md: '16px',
|
|
241
|
-
lg: '24px',
|
|
242
|
-
xl: '32px',
|
|
243
|
-
xxl: '48px',
|
|
244
|
-
};
|
|
245
|
-
```
|
|
143
|
+
const options = [
|
|
144
|
+
{ value: 'apple', label: '사과' },
|
|
145
|
+
{ value: 'banana', label: '바나나' },
|
|
146
|
+
{ value: 'orange', label: '오렌지', disabled: true },
|
|
147
|
+
];
|
|
246
148
|
|
|
247
|
-
|
|
149
|
+
// 기본 사용
|
|
150
|
+
<Select
|
|
151
|
+
label="과일 선택"
|
|
152
|
+
options={options}
|
|
153
|
+
placeholder="선택하세요"
|
|
154
|
+
onChange={(value, option) => console.log(value, option)}
|
|
155
|
+
/>
|
|
248
156
|
|
|
249
|
-
|
|
157
|
+
// Controlled
|
|
158
|
+
const [fruit, setFruit] = useState<string | null>(null);
|
|
159
|
+
<Select
|
|
160
|
+
options={options}
|
|
161
|
+
value={fruit}
|
|
162
|
+
onChange={(value) => setFruit(value)}
|
|
163
|
+
/>
|
|
250
164
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
base: 'Pretendard, -apple-system, sans-serif',
|
|
256
|
-
mono: 'Fira Code, monospace',
|
|
257
|
-
},
|
|
258
|
-
heading: {
|
|
259
|
-
h1: { fontSize: '32px', lineHeight: '40px', fontWeight: 700 },
|
|
260
|
-
h2: { fontSize: '24px', lineHeight: '32px', fontWeight: 700 },
|
|
261
|
-
h3: { fontSize: '20px', lineHeight: '28px', fontWeight: 600 },
|
|
262
|
-
},
|
|
263
|
-
body: {
|
|
264
|
-
large: { fontSize: '16px', lineHeight: '24px', fontWeight: 400 },
|
|
265
|
-
medium: { fontSize: '14px', lineHeight: '20px', fontWeight: 400 },
|
|
266
|
-
small: { fontSize: '12px', lineHeight: '16px', fontWeight: 400 },
|
|
267
|
-
}
|
|
268
|
-
};
|
|
165
|
+
// Variants & Sizes
|
|
166
|
+
<Select options={options} variant="outline" size="md" />
|
|
167
|
+
<Select options={options} variant="filled" size="lg" />
|
|
168
|
+
<Select options={options} variant="ghost" size="sm" />
|
|
269
169
|
```
|
|
270
170
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
171
|
+
| Prop | Type | Default | Description |
|
|
172
|
+
|------|------|---------|-------------|
|
|
173
|
+
| `options` | `SelectOption[]` | required | 옵션 목록 |
|
|
174
|
+
| `value` | `string \| null` | - | 선택된 값 (controlled) |
|
|
175
|
+
| `defaultValue` | `string \| null` | `null` | 기본 선택값 |
|
|
176
|
+
| `onChange` | `(value, option) => void` | - | 변경 핸들러 |
|
|
177
|
+
| `placeholder` | `string` | `'Select…'` | 플레이스홀더 |
|
|
178
|
+
| `variant` | `'outline' \| 'filled' \| 'ghost'` | `'outline'` | 스타일 |
|
|
179
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | 크기 |
|
|
180
|
+
| `fullWidth` | `boolean` | `false` | 전체 너비 |
|
|
181
|
+
| `disabled` | `boolean` | `false` | 비활성화 |
|
|
274
182
|
|
|
275
|
-
|
|
276
|
-
// src/styles/ts/radius.ts
|
|
277
|
-
export const radius = {
|
|
278
|
-
none: '0',
|
|
279
|
-
sm: '4px',
|
|
280
|
-
md: '8px',
|
|
281
|
-
lg: '12px',
|
|
282
|
-
full: '9999px',
|
|
283
|
-
};
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
### 5. Shadows (그림자)
|
|
183
|
+
---
|
|
287
184
|
|
|
288
|
-
|
|
185
|
+
### Form
|
|
289
186
|
|
|
290
|
-
|
|
291
|
-
// src/styles/ts/shadows.ts
|
|
292
|
-
export const shadows = {
|
|
293
|
-
sm: '0 1px 2px rgba(0, 0, 0, 0.05)',
|
|
294
|
-
md: '0 4px 6px rgba(0, 0, 0, 0.1)',
|
|
295
|
-
lg: '0 10px 15px rgba(0, 0, 0, 0.1)',
|
|
296
|
-
xl: '0 20px 25px rgba(0, 0, 0, 0.15)',
|
|
297
|
-
};
|
|
298
|
-
```
|
|
187
|
+
#### TextField
|
|
299
188
|
|
|
300
|
-
|
|
189
|
+
```tsx
|
|
190
|
+
import { TextField } from '@bigtablet/design-system';
|
|
301
191
|
|
|
302
|
-
|
|
192
|
+
// 기본 사용
|
|
193
|
+
<TextField label="이름" placeholder="이름을 입력하세요" />
|
|
303
194
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
duration: {
|
|
308
|
-
fast: '150ms',
|
|
309
|
-
normal: '300ms',
|
|
310
|
-
slow: '500ms',
|
|
311
|
-
},
|
|
312
|
-
easing: {
|
|
313
|
-
ease: 'ease',
|
|
314
|
-
easeIn: 'ease-in',
|
|
315
|
-
easeOut: 'ease-out',
|
|
316
|
-
easeInOut: 'ease-in-out',
|
|
317
|
-
}
|
|
318
|
-
};
|
|
319
|
-
```
|
|
195
|
+
// 상태 표시
|
|
196
|
+
<TextField label="이메일" error helperText="유효하지 않은 이메일입니다" />
|
|
197
|
+
<TextField label="이메일" success helperText="사용 가능한 이메일입니다" />
|
|
320
198
|
|
|
321
|
-
|
|
199
|
+
// 아이콘
|
|
200
|
+
import { Search, Eye } from 'lucide-react';
|
|
201
|
+
<TextField leftIcon={<Search size={16} />} placeholder="검색..." />
|
|
202
|
+
<TextField rightIcon={<Eye size={16} />} type="password" />
|
|
322
203
|
|
|
323
|
-
|
|
204
|
+
// Variants
|
|
205
|
+
<TextField variant="outline" label="Outline" />
|
|
206
|
+
<TextField variant="filled" label="Filled" />
|
|
207
|
+
<TextField variant="ghost" label="Ghost" />
|
|
324
208
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
modal: 1300,
|
|
332
|
-
toast: 1400,
|
|
333
|
-
tooltip: 1500,
|
|
334
|
-
};
|
|
209
|
+
// 값 변환 (자동 포맷팅)
|
|
210
|
+
<TextField
|
|
211
|
+
label="전화번호"
|
|
212
|
+
transformValue={(v) => v.replace(/\D/g, '').slice(0, 11)}
|
|
213
|
+
onChangeAction={(value) => console.log(value)}
|
|
214
|
+
/>
|
|
335
215
|
```
|
|
336
216
|
|
|
337
|
-
|
|
217
|
+
| Prop | Type | Default | Description |
|
|
218
|
+
|------|------|---------|-------------|
|
|
219
|
+
| `label` | `string` | - | 라벨 |
|
|
220
|
+
| `helperText` | `string` | - | 도움말 텍스트 |
|
|
221
|
+
| `error` | `boolean` | `false` | 에러 상태 |
|
|
222
|
+
| `success` | `boolean` | `false` | 성공 상태 |
|
|
223
|
+
| `variant` | `'outline' \| 'filled' \| 'ghost'` | `'outline'` | 스타일 |
|
|
224
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | 크기 |
|
|
225
|
+
| `leftIcon` | `ReactNode` | - | 왼쪽 아이콘 |
|
|
226
|
+
| `rightIcon` | `ReactNode` | - | 오른쪽 아이콘 |
|
|
227
|
+
| `fullWidth` | `boolean` | `false` | 전체 너비 |
|
|
228
|
+
| `onChangeAction` | `(value: string) => void` | - | 값 변경 콜백 |
|
|
229
|
+
| `transformValue` | `(value: string) => string` | - | 값 변환 함수 |
|
|
338
230
|
|
|
339
|
-
|
|
231
|
+
#### DatePicker
|
|
340
232
|
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
}
|
|
349
|
-
|
|
233
|
+
```tsx
|
|
234
|
+
import { DatePicker } from '@bigtablet/design-system';
|
|
235
|
+
|
|
236
|
+
// 기본 사용 (연-월-일)
|
|
237
|
+
const [date, setDate] = useState('');
|
|
238
|
+
<DatePicker
|
|
239
|
+
label="생년월일"
|
|
240
|
+
value={date}
|
|
241
|
+
onChange={setDate}
|
|
242
|
+
/>
|
|
350
243
|
|
|
351
|
-
|
|
244
|
+
// 연-월 모드
|
|
245
|
+
<DatePicker
|
|
246
|
+
label="시작 월"
|
|
247
|
+
mode="year-month"
|
|
248
|
+
value={date}
|
|
249
|
+
onChange={setDate}
|
|
250
|
+
/>
|
|
352
251
|
|
|
353
|
-
|
|
252
|
+
// 범위 제한
|
|
253
|
+
<DatePicker
|
|
254
|
+
label="예약일"
|
|
255
|
+
startYear={2020}
|
|
256
|
+
endYear={2030}
|
|
257
|
+
selectableRange="until-today" // 오늘까지만 선택 가능
|
|
258
|
+
value={date}
|
|
259
|
+
onChange={setDate}
|
|
260
|
+
/>
|
|
354
261
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
focusRing: '0 0 0 3px rgba(0, 102, 255, 0.3)',
|
|
359
|
-
focusRingError: '0 0 0 3px rgba(239, 68, 68, 0.3)',
|
|
360
|
-
tapMinSize: '44px', // 최소 터치 영역
|
|
361
|
-
};
|
|
262
|
+
// 너비 조절
|
|
263
|
+
<DatePicker label="날짜" width={300} onChange={setDate} />
|
|
264
|
+
<DatePicker label="날짜" width="50%" onChange={setDate} />
|
|
362
265
|
```
|
|
363
266
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
267
|
+
| Prop | Type | Default | Description |
|
|
268
|
+
|------|------|---------|-------------|
|
|
269
|
+
| `label` | `string` | - | 라벨 |
|
|
270
|
+
| `value` | `string` | - | 선택된 날짜 (`'YYYY-MM-DD'` 또는 `'YYYY-MM'`) |
|
|
271
|
+
| `onChange` | `(value: string) => void` | required | 변경 핸들러 |
|
|
272
|
+
| `mode` | `'year-month' \| 'year-month-day'` | `'year-month-day'` | 날짜 선택 모드 |
|
|
273
|
+
| `startYear` | `number` | `1950` | 시작 연도 |
|
|
274
|
+
| `endYear` | `number` | `현재년도 + 10` | 종료 연도 |
|
|
275
|
+
| `selectableRange` | `'all' \| 'until-today'` | `'all'` | 선택 가능 범위 |
|
|
276
|
+
| `minDate` | `string` | - | 최소 날짜 |
|
|
277
|
+
| `width` | `number \| string` | `'100%'` | 너비 |
|
|
278
|
+
| `disabled` | `boolean` | `false` | 비활성화 |
|
|
367
279
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
### Form (입력 컴포넌트)
|
|
371
|
-
|
|
372
|
-
#### Button
|
|
280
|
+
#### Checkbox
|
|
373
281
|
|
|
374
282
|
```tsx
|
|
375
|
-
|
|
376
|
-
기본 버튼
|
|
377
|
-
</Button>
|
|
378
|
-
```
|
|
283
|
+
import { Checkbox } from '@bigtablet/design-system';
|
|
379
284
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
- `size`: `sm` | `md` | `lg`
|
|
383
|
-
- `disabled`: `boolean`
|
|
384
|
-
- `loading`: `boolean`
|
|
285
|
+
// 기본 사용
|
|
286
|
+
<Checkbox label="동의합니다" />
|
|
385
287
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
placeholder="email@example.com"
|
|
393
|
-
helperText="이메일을 입력해주세요"
|
|
394
|
-
error={false}
|
|
395
|
-
leftIcon={<EmailIcon />}
|
|
288
|
+
// Controlled
|
|
289
|
+
const [checked, setChecked] = useState(false);
|
|
290
|
+
<Checkbox
|
|
291
|
+
label="알림 받기"
|
|
292
|
+
checked={checked}
|
|
293
|
+
onChange={(e) => setChecked(e.target.checked)}
|
|
396
294
|
/>
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
**Props:**
|
|
400
|
-
- `label`: `string`
|
|
401
|
-
- `type`: `text` | `email` | `password` | `number`
|
|
402
|
-
- `error`: `boolean`
|
|
403
|
-
- `helperText`: `string`
|
|
404
|
-
- `leftIcon` / `rightIcon`: `ReactNode`
|
|
405
295
|
|
|
406
|
-
|
|
296
|
+
// Indeterminate (부분 선택)
|
|
297
|
+
<Checkbox label="전체 선택" indeterminate />
|
|
407
298
|
|
|
408
|
-
|
|
409
|
-
<Checkbox
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
label="동의합니다"
|
|
413
|
-
indeterminate={false}
|
|
414
|
-
/>
|
|
299
|
+
// Sizes
|
|
300
|
+
<Checkbox size="sm" label="Small" />
|
|
301
|
+
<Checkbox size="md" label="Medium" />
|
|
302
|
+
<Checkbox size="lg" label="Large" />
|
|
415
303
|
```
|
|
416
304
|
|
|
305
|
+
| Prop | Type | Default | Description |
|
|
306
|
+
|------|------|---------|-------------|
|
|
307
|
+
| `label` | `ReactNode` | - | 라벨 |
|
|
308
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | 크기 |
|
|
309
|
+
| `indeterminate` | `boolean` | `false` | 부분 선택 상태 |
|
|
310
|
+
| `checked` | `boolean` | - | 체크 상태 |
|
|
311
|
+
| `disabled` | `boolean` | `false` | 비활성화 |
|
|
312
|
+
|
|
417
313
|
#### Radio
|
|
418
314
|
|
|
419
315
|
```tsx
|
|
316
|
+
import { Radio } from '@bigtablet/design-system';
|
|
317
|
+
|
|
318
|
+
const [selected, setSelected] = useState('option1');
|
|
319
|
+
|
|
420
320
|
<Radio
|
|
421
|
-
name="
|
|
422
|
-
value="
|
|
423
|
-
checked={selected === '1'}
|
|
424
|
-
onChange={(e) => setSelected(e.target.value)}
|
|
321
|
+
name="options"
|
|
322
|
+
value="option1"
|
|
425
323
|
label="옵션 1"
|
|
324
|
+
checked={selected === 'option1'}
|
|
325
|
+
onChange={(e) => setSelected(e.target.value)}
|
|
326
|
+
/>
|
|
327
|
+
<Radio
|
|
328
|
+
name="options"
|
|
329
|
+
value="option2"
|
|
330
|
+
label="옵션 2"
|
|
331
|
+
checked={selected === 'option2'}
|
|
332
|
+
onChange={(e) => setSelected(e.target.value)}
|
|
426
333
|
/>
|
|
427
334
|
```
|
|
428
335
|
|
|
429
336
|
#### Switch
|
|
430
337
|
|
|
431
338
|
```tsx
|
|
432
|
-
|
|
433
|
-
checked={isOn}
|
|
434
|
-
onChange={(checked) => setIsOn(checked)}
|
|
435
|
-
label="알림 받기"
|
|
436
|
-
/>
|
|
437
|
-
```
|
|
339
|
+
import { Switch } from '@bigtablet/design-system';
|
|
438
340
|
|
|
439
|
-
|
|
341
|
+
// 기본 사용
|
|
342
|
+
<Switch onChange={(checked) => console.log(checked)} />
|
|
440
343
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
placeholder="선택하세요"
|
|
450
|
-
/>
|
|
344
|
+
// Controlled
|
|
345
|
+
const [isOn, setIsOn] = useState(false);
|
|
346
|
+
<Switch checked={isOn} onChange={setIsOn} />
|
|
347
|
+
|
|
348
|
+
// Sizes
|
|
349
|
+
<Switch size="sm" />
|
|
350
|
+
<Switch size="md" />
|
|
351
|
+
<Switch size="lg" />
|
|
451
352
|
```
|
|
452
353
|
|
|
354
|
+
| Prop | Type | Default | Description |
|
|
355
|
+
|------|------|---------|-------------|
|
|
356
|
+
| `checked` | `boolean` | - | 켜짐 상태 (controlled) |
|
|
357
|
+
| `defaultChecked` | `boolean` | `false` | 기본 상태 |
|
|
358
|
+
| `onChange` | `(checked: boolean) => void` | - | 변경 핸들러 |
|
|
359
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | 크기 |
|
|
360
|
+
| `disabled` | `boolean` | `false` | 비활성화 |
|
|
361
|
+
|
|
453
362
|
#### FileInput
|
|
454
363
|
|
|
455
364
|
```tsx
|
|
365
|
+
import { FileInput } from '@bigtablet/design-system';
|
|
366
|
+
|
|
456
367
|
<FileInput
|
|
457
|
-
accept="image/*"
|
|
458
|
-
onChange={(file) => console.log(file)}
|
|
459
368
|
label="파일 선택"
|
|
369
|
+
accept="image/*"
|
|
370
|
+
onFiles={(files) => console.log(files)}
|
|
371
|
+
/>
|
|
372
|
+
|
|
373
|
+
// 여러 파일
|
|
374
|
+
<FileInput
|
|
375
|
+
label="이미지 업로드"
|
|
376
|
+
accept="image/*"
|
|
377
|
+
multiple
|
|
378
|
+
onFiles={(files) => console.log(files)}
|
|
460
379
|
/>
|
|
461
380
|
```
|
|
462
381
|
|
|
382
|
+
| Prop | Type | Default | Description |
|
|
383
|
+
|------|------|---------|-------------|
|
|
384
|
+
| `label` | `string` | `'파일 선택'` | 버튼 라벨 |
|
|
385
|
+
| `accept` | `string` | - | 허용 파일 타입 |
|
|
386
|
+
| `onFiles` | `(files: FileList \| null) => void` | - | 파일 선택 핸들러 |
|
|
387
|
+
| `multiple` | `boolean` | `false` | 다중 선택 |
|
|
388
|
+
| `disabled` | `boolean` | `false` | 비활성화 |
|
|
389
|
+
|
|
463
390
|
---
|
|
464
391
|
|
|
465
|
-
### Feedback
|
|
392
|
+
### Feedback
|
|
466
393
|
|
|
467
394
|
#### Alert
|
|
468
395
|
|
|
469
396
|
```tsx
|
|
470
|
-
import { useAlert } from '@bigtablet/design-system';
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
397
|
+
import { AlertProvider, useAlert } from '@bigtablet/design-system';
|
|
398
|
+
|
|
399
|
+
// App에 Provider 추가
|
|
400
|
+
function App() {
|
|
401
|
+
return (
|
|
402
|
+
<AlertProvider>
|
|
403
|
+
<YourComponent />
|
|
404
|
+
</AlertProvider>
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// 사용
|
|
409
|
+
function YourComponent() {
|
|
410
|
+
const { showAlert } = useAlert();
|
|
411
|
+
|
|
412
|
+
const handleDelete = () => {
|
|
413
|
+
showAlert({
|
|
414
|
+
variant: 'warning',
|
|
415
|
+
title: '삭제 확인',
|
|
416
|
+
message: '정말 삭제하시겠습니까?',
|
|
417
|
+
showCancel: true,
|
|
418
|
+
confirmText: '삭제',
|
|
419
|
+
cancelText: '취소',
|
|
420
|
+
onConfirm: () => console.log('삭제됨'),
|
|
421
|
+
onCancel: () => console.log('취소됨'),
|
|
482
422
|
});
|
|
483
423
|
};
|
|
424
|
+
|
|
425
|
+
return <button onClick={handleDelete}>삭제</button>;
|
|
484
426
|
}
|
|
485
427
|
```
|
|
486
428
|
|
|
487
|
-
|
|
429
|
+
| Option | Type | Default | Description |
|
|
430
|
+
|--------|------|---------|-------------|
|
|
431
|
+
| `variant` | `'info' \| 'success' \| 'warning' \| 'error'` | `'info'` | 알림 타입 |
|
|
432
|
+
| `title` | `ReactNode` | - | 제목 |
|
|
433
|
+
| `message` | `ReactNode` | - | 메시지 |
|
|
434
|
+
| `confirmText` | `string` | `'확인'` | 확인 버튼 텍스트 |
|
|
435
|
+
| `cancelText` | `string` | `'취소'` | 취소 버튼 텍스트 |
|
|
436
|
+
| `showCancel` | `boolean` | `false` | 취소 버튼 표시 |
|
|
437
|
+
| `actionsAlign` | `'left' \| 'center' \| 'right'` | `'right'` | 버튼 정렬 |
|
|
438
|
+
| `onConfirm` | `() => void` | - | 확인 핸들러 |
|
|
439
|
+
| `onCancel` | `() => void` | - | 취소 핸들러 |
|
|
488
440
|
|
|
489
441
|
#### Toast
|
|
490
442
|
|
|
491
443
|
```tsx
|
|
492
444
|
import { ToastProvider, useToast } from '@bigtablet/design-system';
|
|
493
445
|
|
|
446
|
+
// App에 Provider 추가
|
|
494
447
|
function App() {
|
|
495
448
|
return (
|
|
496
|
-
|
|
449
|
+
<>
|
|
450
|
+
<ToastProvider />
|
|
497
451
|
<YourComponent />
|
|
498
|
-
|
|
452
|
+
</>
|
|
499
453
|
);
|
|
500
454
|
}
|
|
501
455
|
|
|
456
|
+
// 사용
|
|
502
457
|
function YourComponent() {
|
|
503
458
|
const toast = useToast();
|
|
504
|
-
|
|
459
|
+
|
|
505
460
|
return (
|
|
506
|
-
<
|
|
507
|
-
|
|
508
|
-
|
|
461
|
+
<div>
|
|
462
|
+
<button onClick={() => toast.success('저장되었습니다')}>성공</button>
|
|
463
|
+
<button onClick={() => toast.error('오류가 발생했습니다')}>에러</button>
|
|
464
|
+
<button onClick={() => toast.warning('주의가 필요합니다')}>경고</button>
|
|
465
|
+
<button onClick={() => toast.info('참고 정보입니다')}>정보</button>
|
|
466
|
+
<button onClick={() => toast.message('일반 메시지')}>메시지</button>
|
|
467
|
+
</div>
|
|
509
468
|
);
|
|
510
469
|
}
|
|
511
470
|
```
|
|
512
471
|
|
|
513
|
-
|
|
514
|
-
- `toast.success(message)`
|
|
515
|
-
- `toast.error(message)`
|
|
516
|
-
- `toast.warning(message)`
|
|
517
|
-
- `toast.info(message)`
|
|
518
|
-
- `toast.message(message)`
|
|
472
|
+
#### Spinner
|
|
519
473
|
|
|
520
|
-
|
|
474
|
+
```tsx
|
|
475
|
+
import { Spinner } from '@bigtablet/design-system';
|
|
476
|
+
|
|
477
|
+
<Spinner /> // 기본 (24px)
|
|
478
|
+
<Spinner size={16} /> // 작은 크기
|
|
479
|
+
<Spinner size={48} /> // 큰 크기
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
#### TopLoading
|
|
521
483
|
|
|
522
484
|
```tsx
|
|
523
|
-
|
|
485
|
+
import { TopLoading } from '@bigtablet/design-system';
|
|
486
|
+
|
|
487
|
+
// Indeterminate (무한 로딩)
|
|
488
|
+
<TopLoading isLoading />
|
|
489
|
+
|
|
490
|
+
// Progress (진행률 표시)
|
|
491
|
+
<TopLoading isLoading progress={65} />
|
|
492
|
+
|
|
493
|
+
// 커스텀 스타일
|
|
494
|
+
<TopLoading isLoading color="#ff0000" height={5} />
|
|
495
|
+
|
|
496
|
+
// 숨기기
|
|
497
|
+
<TopLoading isLoading={false} />
|
|
524
498
|
```
|
|
525
499
|
|
|
526
|
-
|
|
527
|
-
|
|
500
|
+
| Prop | Type | Default | Description |
|
|
501
|
+
|------|------|---------|-------------|
|
|
502
|
+
| `isLoading` | `boolean` | `true` | 표시 여부 |
|
|
503
|
+
| `progress` | `number` | - | 진행률 (0-100), 없으면 indeterminate |
|
|
504
|
+
| `color` | `string` | primary | 로딩바 색상 |
|
|
505
|
+
| `height` | `number` | `3` | 로딩바 높이 (px) |
|
|
528
506
|
|
|
529
507
|
---
|
|
530
508
|
|
|
531
|
-
### Navigation
|
|
509
|
+
### Navigation
|
|
532
510
|
|
|
533
511
|
#### Pagination
|
|
534
512
|
|
|
535
513
|
```tsx
|
|
514
|
+
import { Pagination } from '@bigtablet/design-system';
|
|
515
|
+
|
|
516
|
+
const [page, setPage] = useState(1);
|
|
517
|
+
|
|
536
518
|
<Pagination
|
|
537
|
-
|
|
538
|
-
totalPages={
|
|
539
|
-
|
|
519
|
+
page={page}
|
|
520
|
+
totalPages={20}
|
|
521
|
+
onChange={setPage}
|
|
540
522
|
/>
|
|
541
523
|
```
|
|
542
524
|
|
|
543
|
-
|
|
525
|
+
| Prop | Type | Default | Description |
|
|
526
|
+
|------|------|---------|-------------|
|
|
527
|
+
| `page` | `number` | required | 현재 페이지 |
|
|
528
|
+
| `totalPages` | `number` | required | 전체 페이지 수 |
|
|
529
|
+
| `onChange` | `(page: number) => void` | required | 페이지 변경 핸들러 |
|
|
530
|
+
|
|
531
|
+
#### Sidebar (Next.js)
|
|
544
532
|
|
|
545
533
|
```tsx
|
|
546
534
|
import { Sidebar } from '@bigtablet/design-system/next';
|
|
535
|
+
import { Home, Settings, Users } from 'lucide-react';
|
|
536
|
+
|
|
537
|
+
const items = [
|
|
538
|
+
{ href: '/', label: '홈', icon: Home },
|
|
539
|
+
{ href: '/users', label: '사용자', icon: Users },
|
|
540
|
+
{
|
|
541
|
+
type: 'group',
|
|
542
|
+
id: 'settings',
|
|
543
|
+
label: '설정',
|
|
544
|
+
icon: Settings,
|
|
545
|
+
children: [
|
|
546
|
+
{ href: '/settings/profile', label: '프로필' },
|
|
547
|
+
{ href: '/settings/security', label: '보안' },
|
|
548
|
+
],
|
|
549
|
+
},
|
|
550
|
+
];
|
|
547
551
|
|
|
548
552
|
<Sidebar
|
|
549
|
-
items={
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
matchMode="startsWith" // 'startsWith' | 'exact'
|
|
553
|
+
items={items}
|
|
554
|
+
activePath={pathname}
|
|
555
|
+
match="startsWith"
|
|
556
|
+
brandHref="/main"
|
|
554
557
|
/>
|
|
555
558
|
```
|
|
556
559
|
|
|
560
|
+
| Prop | Type | Default | Description |
|
|
561
|
+
|------|------|---------|-------------|
|
|
562
|
+
| `items` | `SidebarItem[]` | `[]` | 메뉴 아이템 |
|
|
563
|
+
| `activePath` | `string` | - | 현재 활성 경로 |
|
|
564
|
+
| `match` | `'startsWith' \| 'exact'` | `'startsWith'` | 경로 매칭 방식 |
|
|
565
|
+
| `brandHref` | `string` | `'/main'` | 로고 클릭 시 이동 경로 |
|
|
566
|
+
| `onItemSelect` | `(href: string) => void` | - | 아이템 선택 핸들러 |
|
|
567
|
+
|
|
557
568
|
---
|
|
558
569
|
|
|
559
|
-
### Overlay
|
|
570
|
+
### Overlay
|
|
560
571
|
|
|
561
572
|
#### Modal
|
|
562
573
|
|
|
563
574
|
```tsx
|
|
575
|
+
import { Modal } from '@bigtablet/design-system';
|
|
576
|
+
|
|
577
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
578
|
+
|
|
579
|
+
<button onClick={() => setIsOpen(true)}>모달 열기</button>
|
|
580
|
+
|
|
564
581
|
<Modal
|
|
565
|
-
|
|
582
|
+
open={isOpen}
|
|
566
583
|
onClose={() => setIsOpen(false)}
|
|
567
584
|
title="모달 제목"
|
|
585
|
+
width={600}
|
|
568
586
|
>
|
|
569
|
-
<p>모달
|
|
587
|
+
<p>모달 내용입니다.</p>
|
|
570
588
|
</Modal>
|
|
571
589
|
```
|
|
572
590
|
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
591
|
+
| Prop | Type | Default | Description |
|
|
592
|
+
|------|------|---------|-------------|
|
|
593
|
+
| `open` | `boolean` | required | 열림 상태 |
|
|
594
|
+
| `onClose` | `() => void` | - | 닫기 핸들러 |
|
|
595
|
+
| `title` | `ReactNode` | - | 제목 |
|
|
596
|
+
| `width` | `number \| string` | `520` | 모달 너비 |
|
|
597
|
+
| `closeOnOverlay` | `boolean` | `true` | 오버레이 클릭 시 닫기 |
|
|
579
598
|
|
|
580
599
|
---
|
|
581
600
|
|
|
582
|
-
### Display
|
|
601
|
+
### Display
|
|
583
602
|
|
|
584
603
|
#### Card
|
|
585
604
|
|
|
586
605
|
```tsx
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
606
|
+
import { Card } from '@bigtablet/design-system';
|
|
607
|
+
|
|
608
|
+
<Card heading="카드 제목">
|
|
609
|
+
<p>카드 내용입니다.</p>
|
|
610
|
+
</Card>
|
|
611
|
+
|
|
612
|
+
// 스타일 옵션
|
|
613
|
+
<Card heading="제목" shadow="lg" padding="lg" bordered>
|
|
614
|
+
내용
|
|
590
615
|
</Card>
|
|
591
616
|
```
|
|
592
617
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
618
|
+
| Prop | Type | Default | Description |
|
|
619
|
+
|------|------|---------|-------------|
|
|
620
|
+
| `heading` | `ReactNode` | - | 카드 제목 |
|
|
621
|
+
| `shadow` | `'none' \| 'sm' \| 'md' \| 'lg'` | `'sm'` | 그림자 |
|
|
622
|
+
| `padding` | `'none' \| 'sm' \| 'md' \| 'lg'` | `'md'` | 내부 여백 |
|
|
623
|
+
| `bordered` | `boolean` | `false` | 테두리 표시 |
|
|
596
624
|
|
|
597
625
|
---
|
|
598
626
|
|
|
599
|
-
|
|
627
|
+
## Foundation (디자인 토큰)
|
|
600
628
|
|
|
601
|
-
|
|
629
|
+
### SCSS 토큰 사용
|
|
602
630
|
|
|
603
|
-
```
|
|
604
|
-
|
|
631
|
+
```scss
|
|
632
|
+
@use "@bigtablet/design-system/scss/token" as token;
|
|
633
|
+
|
|
634
|
+
.my-component {
|
|
635
|
+
color: token.$color_primary;
|
|
636
|
+
padding: token.$spacing_md;
|
|
637
|
+
border-radius: token.$radius_sm;
|
|
638
|
+
font-size: token.$font_size_base;
|
|
639
|
+
}
|
|
605
640
|
```
|
|
606
641
|
|
|
607
|
-
|
|
642
|
+
### 주요 토큰
|
|
643
|
+
|
|
644
|
+
| Category | Examples |
|
|
645
|
+
|----------|----------|
|
|
646
|
+
| **Colors** | `$color_primary`, `$color_error`, `$color_text_primary` |
|
|
647
|
+
| **Spacing** | `$spacing_xs` (4px), `$spacing_sm` (8px), `$spacing_md` (16px) |
|
|
648
|
+
| **Typography** | `$font_size_sm`, `$font_size_base`, `$font_weight_medium` |
|
|
649
|
+
| **Radius** | `$radius_sm` (4px), `$radius_md` (8px), `$radius_lg` (12px) |
|
|
650
|
+
| **Shadows** | `$shadow_sm`, `$shadow_md`, `$shadow_lg` |
|
|
651
|
+
| **Z-Index** | `$z_dropdown`, `$z_modal`, `$z_toast` |
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
655
|
+
## 프로젝트 구조
|
|
608
656
|
|
|
609
|
-
```
|
|
610
|
-
|
|
657
|
+
```
|
|
658
|
+
src/
|
|
659
|
+
├── styles/
|
|
660
|
+
│ ├── ts/ # TypeScript 디자인 토큰
|
|
661
|
+
│ └── scss/ # SCSS 토큰 및 믹스인
|
|
662
|
+
├── ui/
|
|
663
|
+
│ ├── general/ # Button, Select
|
|
664
|
+
│ ├── form/ # TextField, Checkbox, Radio, Switch, DatePicker, FileInput
|
|
665
|
+
│ ├── feedback/ # Alert, Toast, Spinner, TopLoading
|
|
666
|
+
│ ├── navigation/ # Pagination, Sidebar
|
|
667
|
+
│ ├── overlay/ # Modal
|
|
668
|
+
│ └── display/ # Card
|
|
669
|
+
├── index.ts # Pure React 진입점
|
|
670
|
+
└── next.ts # Next.js 진입점
|
|
611
671
|
```
|
|
612
672
|
|
|
613
673
|
---
|
|
614
674
|
|
|
615
675
|
## 개발 가이드
|
|
616
676
|
|
|
617
|
-
### 로컬 개발 환경 설정
|
|
618
|
-
|
|
619
677
|
```bash
|
|
620
678
|
# 저장소 클론
|
|
621
679
|
git clone https://github.com/Bigtablet/bigtablet-design-system.git
|
|
@@ -629,151 +687,39 @@ pnpm storybook
|
|
|
629
687
|
|
|
630
688
|
# 빌드
|
|
631
689
|
pnpm build
|
|
632
|
-
|
|
633
|
-
# 테스트
|
|
634
|
-
pnpm test
|
|
635
690
|
```
|
|
636
691
|
|
|
637
|
-
### Storybook 가이드라인
|
|
638
|
-
|
|
639
|
-
1. **Title 규칙**
|
|
640
|
-
- Foundation: `foundation/Colors`, `foundation/Typography`
|
|
641
|
-
- Components: `components/Button`, `components/TextField`
|
|
642
|
-
|
|
643
|
-
2. **Story 작성 원칙**
|
|
644
|
-
- 기본 상태(Default) 필수 포함
|
|
645
|
-
- 모든 variant와 size 예시 제공
|
|
646
|
-
- 실제 사용 사례 중심으로 작성
|
|
647
|
-
- 명확한 설명과 문서화
|
|
648
|
-
|
|
649
|
-
3. **예시**
|
|
650
|
-
|
|
651
|
-
```tsx
|
|
652
|
-
// Button.stories.tsx
|
|
653
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
654
|
-
import { Button } from './Button';
|
|
655
|
-
|
|
656
|
-
const meta: Meta<typeof Button> = {
|
|
657
|
-
title: 'components/Button',
|
|
658
|
-
component: Button,
|
|
659
|
-
tags: ['autodocs'],
|
|
660
|
-
};
|
|
661
|
-
|
|
662
|
-
export default meta;
|
|
663
|
-
type Story = StoryObj<typeof Button>;
|
|
664
|
-
|
|
665
|
-
export const Default: Story = {
|
|
666
|
-
args: {
|
|
667
|
-
children: '기본 버튼',
|
|
668
|
-
variant: 'primary',
|
|
669
|
-
size: 'md',
|
|
670
|
-
},
|
|
671
|
-
};
|
|
672
|
-
|
|
673
|
-
export const Variants: Story = {
|
|
674
|
-
render: () => (
|
|
675
|
-
<>
|
|
676
|
-
<Button variant="primary">Primary</Button>
|
|
677
|
-
<Button variant="secondary">Secondary</Button>
|
|
678
|
-
<Button variant="ghost">Ghost</Button>
|
|
679
|
-
<Button variant="danger">Danger</Button>
|
|
680
|
-
</>
|
|
681
|
-
),
|
|
682
|
-
};
|
|
683
|
-
```
|
|
684
|
-
|
|
685
|
-
### 컴포넌트 개발 원칙
|
|
686
|
-
|
|
687
|
-
1. **Foundation 토큰 사용 필수**
|
|
688
|
-
- 직접적인 색상/크기 값 사용 금지
|
|
689
|
-
- 모든 스타일은 토큰을 통해 정의
|
|
690
|
-
|
|
691
|
-
2. **접근성(a11y) 고려**
|
|
692
|
-
- 키보드 네비게이션 지원
|
|
693
|
-
- 스크린 리더 호환
|
|
694
|
-
- 적절한 ARIA 속성 사용
|
|
695
|
-
|
|
696
|
-
3. **상태 관리**
|
|
697
|
-
- hover, active, disabled, error 등 명확히 정의
|
|
698
|
-
- loading 상태 제공
|
|
699
|
-
|
|
700
|
-
4. **TypeScript 타입**
|
|
701
|
-
- Props 타입 명확히 정의
|
|
702
|
-
- Generic 타입 적절히 활용
|
|
703
|
-
|
|
704
692
|
---
|
|
705
693
|
|
|
706
694
|
## 기여하기
|
|
707
695
|
|
|
708
|
-
기여는 언제나 환영합니다! 다음 절차를 따라주세요:
|
|
709
|
-
|
|
710
696
|
1. Fork the repository
|
|
711
|
-
2. Create your feature branch (`git checkout -b
|
|
712
|
-
3. Commit your changes (`git commit -m '
|
|
713
|
-
4. Push to the branch (`git push origin
|
|
714
|
-
5. Open a Pull Request
|
|
697
|
+
2. Create your feature branch (`git checkout -b feat/amazing-feature`)
|
|
698
|
+
3. Commit your changes (`git commit -m 'feat: add amazing feature'`)
|
|
699
|
+
4. Push to the branch (`git push origin feat/amazing-feature`)
|
|
700
|
+
5. Open a Pull Request to `develop` branch
|
|
715
701
|
|
|
716
702
|
### Commit Convention
|
|
717
703
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
chore: 빌드 업무, 패키지 매니저 설정 등
|
|
726
|
-
```
|
|
727
|
-
|
|
728
|
-
---
|
|
729
|
-
|
|
730
|
-
## 버전 관리
|
|
731
|
-
|
|
732
|
-
이 프로젝트는 [Changesets](https://github.com/changesets/changesets)를 사용하여 버전을 관리합니다.
|
|
733
|
-
|
|
734
|
-
### 변경사항 추가
|
|
735
|
-
|
|
736
|
-
```bash
|
|
737
|
-
pnpm changeset
|
|
738
|
-
```
|
|
739
|
-
|
|
740
|
-
---
|
|
741
|
-
|
|
742
|
-
## 기술 스택
|
|
743
|
-
|
|
744
|
-
| Category | Technology |
|
|
745
|
-
|----------|------------|
|
|
746
|
-
| **Framework** | React 19 |
|
|
747
|
-
| **Language** | TypeScript |
|
|
748
|
-
| **Styling** | SCSS |
|
|
749
|
-
| **Documentation** | Storybook 8 |
|
|
750
|
-
| **Visual Test** | Chromatic |
|
|
751
|
-
| **Build** | tsup |
|
|
752
|
-
| **Package Manager** | pnpm |
|
|
753
|
-
| **CI/CD** | GitHub Actions |
|
|
754
|
-
| **Version Management** | Changesets |
|
|
755
|
-
|
|
756
|
-
---
|
|
757
|
-
|
|
758
|
-
## 브라우저 지원
|
|
759
|
-
|
|
760
|
-
- Chrome (최신 2개 버전)
|
|
761
|
-
- Firefox (최신 2개 버전)
|
|
762
|
-
- Safari (최신 2개 버전)
|
|
763
|
-
- Edge (최신 2개 버전)
|
|
704
|
+
| Label | Description |
|
|
705
|
+
|-------|-------------|
|
|
706
|
+
| `feat` | 새로운 기능 |
|
|
707
|
+
| `fix` | 버그/코드 수정 |
|
|
708
|
+
| `docs` | 문서 수정 |
|
|
709
|
+
| `style` | 코드 스타일 변경 |
|
|
710
|
+
| `config` | 설정 파일 수정 |
|
|
764
711
|
|
|
765
712
|
---
|
|
766
713
|
|
|
767
714
|
## 라이센스
|
|
768
715
|
|
|
769
|
-
[Bigtablet License](https://github.com/Bigtablet/.github/blob/main/BIGTABLET_LICENSE.md)
|
|
716
|
+
[Bigtablet License](https://github.com/Bigtablet/.github/blob/main/BIGTABLET_LICENSE.md)
|
|
770
717
|
|
|
771
718
|
---
|
|
772
719
|
|
|
773
720
|
## 링크
|
|
774
721
|
|
|
775
|
-
- [
|
|
776
|
-
- [NPM
|
|
777
|
-
- [
|
|
778
|
-
- [
|
|
779
|
-
|
|
722
|
+
- [GitHub](https://github.com/Bigtablet/bigtablet-design-system)
|
|
723
|
+
- [NPM](https://www.npmjs.com/package/@bigtablet/design-system)
|
|
724
|
+
- [Storybook](https://bigtablet.github.io/bigtablet-design-system)
|
|
725
|
+
- [Issues](https://github.com/Bigtablet/bigtablet-design-system/issues)
|