@pylerai/design-system 1.1.0
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 +515 -0
- package/dist/components/ui/badge.d.ts +9 -0
- package/dist/components/ui/body.d.ts +13 -0
- package/dist/components/ui/button.d.ts +26 -0
- package/dist/components/ui/checkbox.d.ts +9 -0
- package/dist/components/ui/chip.d.ts +16 -0
- package/dist/components/ui/dropdown.d.ts +42 -0
- package/dist/components/ui/headline.d.ts +13 -0
- package/dist/components/ui/input.d.ts +32 -0
- package/dist/components/ui/label.d.ts +15 -0
- package/dist/components/ui/loading-bar.d.ts +8 -0
- package/dist/components/ui/modal.d.ts +45 -0
- package/dist/components/ui/pagination.d.ts +16 -0
- package/dist/components/ui/radio.d.ts +7 -0
- package/dist/components/ui/search-field.d.ts +21 -0
- package/dist/components/ui/table.d.ts +67 -0
- package/dist/components/ui/tabs.d.ts +21 -0
- package/dist/components/ui/tag.d.ts +7 -0
- package/dist/components/ui/tips.d.ts +9 -0
- package/dist/components/ui/toast.d.ts +23 -0
- package/dist/components/ui/toggle.d.ts +10 -0
- package/dist/components/ui/use-modal.d.ts +36 -0
- package/dist/index.css.d.ts +0 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +5834 -0
- package/dist/lib/icons.d.ts +32 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/style.css +1 -0
- package/dist/tokens/pyler-light.d.ts +166 -0
- package/dist/tokens/typography.d.ts +90 -0
- package/package.json +86 -0
- package/pyler-tailwind-colors.cjs +65 -0
- package/pyler-typography.cjs +116 -0
- package/tailwind-preset.cjs +15 -0
package/README.md
ADDED
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
# @pylerai/design-system
|
|
2
|
+
|
|
3
|
+
Pyler Frontend를 위한 디자인 시스템 패키지 (Tailwind CSS + shadcn/ui 기반)
|
|
4
|
+
|
|
5
|
+
## 📦 패키지 정보
|
|
6
|
+
|
|
7
|
+
- **패키지명**: `@pylerai/design-system`
|
|
8
|
+
- **버전**: 1.0.1
|
|
9
|
+
- **라이선스**: ISC
|
|
10
|
+
- **레지스트리**: GitHub Packages
|
|
11
|
+
- **기술 스택**: React + TypeScript + Tailwind CSS + shadcn/ui + Storybook + Vitest
|
|
12
|
+
|
|
13
|
+
## 🚀 설치 및 사용
|
|
14
|
+
|
|
15
|
+
### 다른 프로젝트에서 사용하기
|
|
16
|
+
|
|
17
|
+
다른 레포지토리에서 이 디자인 시스템을 사용하려면 다음 단계를 따라하세요:
|
|
18
|
+
|
|
19
|
+
#### 1. GitHub Personal Access Token 생성
|
|
20
|
+
|
|
21
|
+
1. GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic)
|
|
22
|
+
2. "Generate new token (classic)" 클릭
|
|
23
|
+
3. `read:packages` 권한 체크
|
|
24
|
+
4. 토큰 생성 및 복사 (한 번만 표시되므로 안전하게 보관!)
|
|
25
|
+
|
|
26
|
+
#### 2. 프로젝트에 `.npmrc` 파일 생성
|
|
27
|
+
|
|
28
|
+
프로젝트 루트에 `.npmrc` 파일을 생성하고 다음 내용을 추가하세요:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
@pylerai:registry=https://npm.pkg.github.com
|
|
32
|
+
//npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`YOUR_GITHUB_TOKEN` 부분을 1단계에서 생성한 토큰으로 교체하세요.
|
|
36
|
+
|
|
37
|
+
> ⚠️ 주의: `.npmrc` 파일은 절대 git에 커밋하지 마세요! `.gitignore`에 추가되어 있는지 확인하세요.
|
|
38
|
+
|
|
39
|
+
#### 3. 패키지 설치
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install @pylerai/design-system
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
#### 4. Tailwind CSS 설정
|
|
46
|
+
|
|
47
|
+
사용할 프로젝트의 `tailwind.config.js` / `tailwind.config.cjs` 파일에 다음을 추가하세요:
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
module.exports = {
|
|
51
|
+
content: [
|
|
52
|
+
"./src/**/*.{js,jsx,ts,tsx}",
|
|
53
|
+
"./node_modules/@pylerai/design-system/**/*.{js,ts,jsx,tsx}", // 추가
|
|
54
|
+
],
|
|
55
|
+
// ...
|
|
56
|
+
};
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
그리고 CSS 파일에 다음을 추가하세요:
|
|
60
|
+
|
|
61
|
+
```css
|
|
62
|
+
@tailwind base;
|
|
63
|
+
@tailwind components;
|
|
64
|
+
@tailwind utilities;
|
|
65
|
+
|
|
66
|
+
/* 디자인 시스템 스타일 (컴포넌트 + Pyler 컬러 변수 등) */
|
|
67
|
+
@import "@pylerai/design-system/style.css";
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
앱 진입 TS/JS에서 한 번 로드하는 방식도 동일합니다.
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import "@pylerai/design-system/style.css";
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
> 구버전 번들러에서 서브패스가 동작하지 않으면 `@import "@pylerai/design-system/dist/style.css";` 또는 `import "@pylerai/design-system/dist/style.css";` 를 사용하세요.
|
|
77
|
+
|
|
78
|
+
#### 5. 사용하기
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { Button } from "@pylerai/design-system";
|
|
82
|
+
|
|
83
|
+
function App() {
|
|
84
|
+
return (
|
|
85
|
+
<div className="p-4">
|
|
86
|
+
<Button>클릭하세요</Button>
|
|
87
|
+
<Button variant="outline">외곽선</Button>
|
|
88
|
+
<Button variant="destructive">삭제</Button>
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 컬러 토큰 (Pyler Light)
|
|
95
|
+
|
|
96
|
+
Figma Light 모드와 동일한 HEX를 **TypeScript 상수**, **CSS 변수 (`--ds-*`)**, **Tailwind `ds` 팔레트**로 제공합니다. 앱 코드에 HEX를 직접 쓰지 말고 패키지 토큰을 참조하세요.
|
|
97
|
+
|
|
98
|
+
#### TypeScript에서 HEX·경로 사용
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import {
|
|
102
|
+
PYLER_LIGHT_COLOR_TOKENS,
|
|
103
|
+
flatPylerLightTokens,
|
|
104
|
+
getDsCssVar,
|
|
105
|
+
} from "@pylerai/design-system";
|
|
106
|
+
|
|
107
|
+
// 중첩 객체
|
|
108
|
+
const strong = PYLER_LIGHT_COLOR_TOKENS.text.strong.hex; // "#333333"
|
|
109
|
+
|
|
110
|
+
// 순회·문서화용 플랫 리스트
|
|
111
|
+
flatPylerLightTokens.forEach(({ path, hex, cssVar }) => {
|
|
112
|
+
console.log(path, hex, cssVar);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// CSS 변수 이름
|
|
116
|
+
getDsCssVar("text.strong"); // => "--ds-text-strong"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### CSS 변수
|
|
120
|
+
|
|
121
|
+
`style.css`를 로드한 뒤 임의 요소에 적용합니다.
|
|
122
|
+
|
|
123
|
+
```css
|
|
124
|
+
.my-title {
|
|
125
|
+
color: var(--ds-text-strong);
|
|
126
|
+
border-color: var(--ds-line-strong);
|
|
127
|
+
background-color: var(--ds-surface-normal);
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
#### Tailwind에서 `ds` 색상
|
|
132
|
+
|
|
133
|
+
1. **프리셋 사용 (권장)** — `theme.extend.colors.ds`가 자동으로 합쳐집니다.
|
|
134
|
+
|
|
135
|
+
```javascript
|
|
136
|
+
// tailwind.config.cjs
|
|
137
|
+
module.exports = {
|
|
138
|
+
presets: [require("@pylerai/design-system/tailwind-preset")],
|
|
139
|
+
content: [
|
|
140
|
+
"./src/**/*.{js,jsx,ts,tsx}",
|
|
141
|
+
"./node_modules/@pylerai/design-system/dist/**/*.{js,ts,jsx,tsx}",
|
|
142
|
+
],
|
|
143
|
+
theme: {
|
|
144
|
+
extend: {
|
|
145
|
+
/* 기존 앱 전용 확장 */
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
2. **색상 맵만 병합** — 이미 `extend.colors`를 쓰는 경우:
|
|
152
|
+
|
|
153
|
+
```javascript
|
|
154
|
+
const { dsColors } = require("@pylerai/design-system/pyler-tailwind-colors");
|
|
155
|
+
|
|
156
|
+
module.exports = {
|
|
157
|
+
theme: {
|
|
158
|
+
extend: {
|
|
159
|
+
colors: {
|
|
160
|
+
ds: dsColors,
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
유틸 클래스 예: `bg-ds-primary-blue-normal`, `text-ds-text-strong`, `border-ds-line-normal`.
|
|
168
|
+
|
|
169
|
+
동적으로 `bg-ds-*`만 조합하는 경우 Tailwind가 클래스를 빼버릴 수 있으므로, 소비 앱 `tailwind.config`에 `safelist: [{ pattern: /^bg-ds-/ }]`를 두는 것을 권장합니다.
|
|
170
|
+
|
|
171
|
+
스토리북 **Design Tokens → Color Tokens**에서 전체 스와치와 HEX를 확인할 수 있습니다.
|
|
172
|
+
|
|
173
|
+
#### 환경별 설정 예시
|
|
174
|
+
|
|
175
|
+
**`.env` 파일을 사용하는 경우** (추천):
|
|
176
|
+
|
|
177
|
+
프로젝트 루트에 `.env` 파일 생성:
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
GITHUB_TOKEN=your_token_here
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
`.npmrc` 파일:
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
@pylerai:registry=https://npm.pkg.github.com
|
|
187
|
+
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**CI/CD 환경** (GitHub Actions):
|
|
191
|
+
|
|
192
|
+
워크플로우 파일에 다음 추가:
|
|
193
|
+
|
|
194
|
+
```yaml
|
|
195
|
+
- uses: actions/checkout@v5
|
|
196
|
+
- uses: actions/setup-node@v4
|
|
197
|
+
with:
|
|
198
|
+
node-version: 20
|
|
199
|
+
registry-url: https://npm.pkg.github.com/
|
|
200
|
+
scope: "@pylerai"
|
|
201
|
+
- run: npm install @pylerai/design-system
|
|
202
|
+
env:
|
|
203
|
+
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## 🎨 컴포넌트
|
|
207
|
+
|
|
208
|
+
### Typography
|
|
209
|
+
|
|
210
|
+
일관된 타이포그래피를 위한 컴포넌트들입니다.
|
|
211
|
+
|
|
212
|
+
#### Headline
|
|
213
|
+
|
|
214
|
+
페이지와 섹션의 제목을 위한 컴포넌트입니다.
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
import { Headline } from '@pylerai/design-system';
|
|
218
|
+
|
|
219
|
+
// 기본 사용
|
|
220
|
+
<Headline>페이지 제목</Headline>
|
|
221
|
+
|
|
222
|
+
// Variant
|
|
223
|
+
<Headline variant="h1-20">페이지/섹션 최상위 제목</Headline>
|
|
224
|
+
<Headline variant="h1-20-m">보조 헤드라인</Headline>
|
|
225
|
+
<Headline variant="h1-20-r">큰 본문/설명</Headline>
|
|
226
|
+
<Headline variant="h2-18">섹션 제목</Headline>
|
|
227
|
+
<Headline variant="h2-18-sb">섹션 보조 제목</Headline>
|
|
228
|
+
<Headline variant="h2-18-r">크고 차분한 본문</Headline>
|
|
229
|
+
|
|
230
|
+
// HTML 태그 지정
|
|
231
|
+
<Headline as="h1">H1 태그로 렌더링</Headline>
|
|
232
|
+
<Headline as="h2">H2 태그로 렌더링</Headline>
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
#### Body
|
|
236
|
+
|
|
237
|
+
본문 텍스트를 위한 컴포넌트입니다.
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
import { Body } from '@pylerai/design-system';
|
|
241
|
+
|
|
242
|
+
// 기본 사용
|
|
243
|
+
<Body>본문 텍스트입니다.</Body>
|
|
244
|
+
|
|
245
|
+
// Variant
|
|
246
|
+
<Body variant="b1-16">강조 본문</Body>
|
|
247
|
+
<Body variant="b1-16-m">일반 본문(기본)</Body>
|
|
248
|
+
<Body variant="b1-16-r">일반 본문(라이트)</Body>
|
|
249
|
+
<Body variant="b2-14">작은 강조 본문</Body>
|
|
250
|
+
<Body variant="b2-14-m">작은 본문/캡션</Body>
|
|
251
|
+
<Body variant="b2-14-r">캡션/헬퍼텍스트</Body>
|
|
252
|
+
<Body variant="b3-13-m">세부설명/테이블 셀</Body>
|
|
253
|
+
<Body variant="b3-13-r">보조설명</Body>
|
|
254
|
+
<Body variant="b4-12-m">메타/상태</Body>
|
|
255
|
+
<Body variant="b4-12-r">아주 작은 본문</Body>
|
|
256
|
+
|
|
257
|
+
// HTML 태그 지정
|
|
258
|
+
<Body as="p">P 태그로 렌더링</Body>
|
|
259
|
+
<Body as="div">DIV 태그로 렌더링</Body>
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
#### Label
|
|
263
|
+
|
|
264
|
+
폼 요소나 작은 텍스트 라벨을 위한 컴포넌트입니다.
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
import { Label } from '@pylerai/design-system';
|
|
268
|
+
|
|
269
|
+
// 기본 사용
|
|
270
|
+
<Label>라벨 텍스트</Label>
|
|
271
|
+
|
|
272
|
+
// Variant
|
|
273
|
+
<Label variant="l1-10-sb">라벨/태그</Label>
|
|
274
|
+
<Label variant="l1-10-r">라벨(비강조)</Label>
|
|
275
|
+
|
|
276
|
+
// 폼과 함께 사용
|
|
277
|
+
<Label htmlFor="email">이메일 주소</Label>
|
|
278
|
+
<input id="email" type="email" />
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Button
|
|
282
|
+
|
|
283
|
+
다양한 variant와 size를 지원하는 버튼 컴포넌트입니다.
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
import { Button } from '@pylerai/design-system';
|
|
287
|
+
|
|
288
|
+
// 기본 사용
|
|
289
|
+
<Button>클릭하세요</Button>
|
|
290
|
+
|
|
291
|
+
// Variant
|
|
292
|
+
<Button variant="default">기본</Button>
|
|
293
|
+
<Button variant="destructive">삭제</Button>
|
|
294
|
+
<Button variant="outline">외곽선</Button>
|
|
295
|
+
<Button variant="secondary">두 번째</Button>
|
|
296
|
+
<Button variant="ghost">고스트</Button>
|
|
297
|
+
<Button variant="link">링크</Button>
|
|
298
|
+
|
|
299
|
+
// Size
|
|
300
|
+
<Button size="sm">작은 버튼</Button>
|
|
301
|
+
<Button size="default">기본</Button>
|
|
302
|
+
<Button size="lg">큰 버튼</Button>
|
|
303
|
+
<Button size="icon">🔍</Button>
|
|
304
|
+
|
|
305
|
+
// 조합
|
|
306
|
+
<Button variant="outline" size="lg">외곽선 큰 버튼</Button>
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## 📏 타이포그래피 스케일
|
|
310
|
+
|
|
311
|
+
### 디자인 토큰
|
|
312
|
+
|
|
313
|
+
| Token | Size(px) | Weight | Tailwind class | 용도 |
|
|
314
|
+
|-------|----------|--------|----------------|------|
|
|
315
|
+
| H1-20B | 20 | 700 | text-h1-20 | 페이지/섹션 최상위 제목 |
|
|
316
|
+
| H1-20M | 20 | 500 | text-h1-20-m | 보조 헤드라인 |
|
|
317
|
+
| H1-20R | 20 | 400 | text-h1-20-r | 큰 본문/설명 |
|
|
318
|
+
| H2-18B | 18 | 700 | text-h2-18 | 섹션 제목 |
|
|
319
|
+
| H2-18SB | 18 | 600 | text-h2-18-sb | 섹션 보조 제목 |
|
|
320
|
+
| H2-18R | 18 | 400 | text-h2-18-r | 크고 차분한 본문 |
|
|
321
|
+
| B1-16B | 16 | 700 | text-b1-16 | 강조 본문 |
|
|
322
|
+
| B1-16M | 16 | 500 | text-b1-16-m | 일반 본문(기본) |
|
|
323
|
+
| B1-16R | 16 | 400 | text-b1-16-r | 일반 본문(라이트) |
|
|
324
|
+
| B2-14B | 14 | 700 | text-b2-14 | 작은 강조 본문 |
|
|
325
|
+
| B2-14M | 14 | 500 | text-b2-14-m | 작은 본문/캡션 |
|
|
326
|
+
| B2-14R | 14 | 400 | text-b2-14-r | 캡션/헬퍼텍스트 |
|
|
327
|
+
| B3-13M | 13 | 500 | text-b3-13-m | 세부설명/테이블 셀 |
|
|
328
|
+
| B3-13R | 13 | 400 | text-b3-13-r | 보조설명 |
|
|
329
|
+
| B4-12M | 12 | 500 | text-b4-12-m | 메타/상태 |
|
|
330
|
+
| B4-12R | 12 | 400 | text-b4-12-r | 아주 작은 본문 |
|
|
331
|
+
| L1-10SB | 10 | 600 | text-l1-10-sb | 라벨/태그 |
|
|
332
|
+
| L1-10R | 10 | 400 | text-l1-10-r | 라벨(비강조) |
|
|
333
|
+
|
|
334
|
+
### 사용 가이드라인
|
|
335
|
+
|
|
336
|
+
#### ✅ 권장사항
|
|
337
|
+
|
|
338
|
+
- **계층 구조 유지**: H1 → H2 → H3 순서로 헤딩을 사용하고, 각 레벨의 용도를 일관되게 유지하세요.
|
|
339
|
+
- **충분한 대비**: 텍스트와 배경 간 충분한 색상 대비를 확보하여 가독성을 보장하세요.
|
|
340
|
+
- **적절한 라인 높이**: 본문 텍스트는 1.4~1.6의 라인 높이를 사용하여 가독성을 높이세요.
|
|
341
|
+
|
|
342
|
+
#### ❌ 주의사항
|
|
343
|
+
|
|
344
|
+
- **과도한 변형 사용**: 너무 많은 폰트 크기와 굵기를 혼용하면 일관성이 떨어집니다.
|
|
345
|
+
- **너무 작은 텍스트**: 10px 이하의 텍스트는 가독성과 접근성 문제를 일으킬 수 있습니다.
|
|
346
|
+
- **의미 없는 굵기 변경**: 단순히 강조를 위해 굵기를 변경하지 말고, 의미 있는 계층 구조를 사용하세요.
|
|
347
|
+
|
|
348
|
+
### 접근성
|
|
349
|
+
|
|
350
|
+
모든 타이포그래피 컴포넌트는 WCAG 2.1 AA 기준을 준수합니다:
|
|
351
|
+
|
|
352
|
+
- **색상 대비**: 최소 4.5:1의 대비율 유지
|
|
353
|
+
- **헤딩 계층**: 올바른 HTML 헤딩 태그 사용
|
|
354
|
+
- **스크린 리더**: 의미 있는 텍스트와 라벨 제공
|
|
355
|
+
- **키보드 네비게이션**: 포커스 표시 및 키보드 접근성 지원
|
|
356
|
+
|
|
357
|
+
## 📁 프로젝트 구조
|
|
358
|
+
|
|
359
|
+
```
|
|
360
|
+
design-system/
|
|
361
|
+
├── .storybook/
|
|
362
|
+
│ ├── main.cjs # Storybook 메인 설정 (CJS — Vite/Storybook 호환)
|
|
363
|
+
│ ├── preview.ts # Storybook 미리보기 설정
|
|
364
|
+
│ └── vitest.setup.ts # Vitest 테스트 설정
|
|
365
|
+
├── .github/
|
|
366
|
+
│ └── workflows/
|
|
367
|
+
│ └── release-package.yml # GitHub Actions 릴리스 워크플로우
|
|
368
|
+
├── src/
|
|
369
|
+
│ ├── components/
|
|
370
|
+
│ │ ├── ui/
|
|
371
|
+
│ │ │ ├── button.tsx # Button 컴포넌트 구현
|
|
372
|
+
│ │ │ └── button.stories.tsx # Button Storybook 스토리
|
|
373
|
+
│ │ └── Button.tsx # Button export
|
|
374
|
+
│ ├── stories/ # Storybook 데모 컴포넌트
|
|
375
|
+
│ │ ├── assets/ # 데모용 이미지/아이콘
|
|
376
|
+
│ │ ├── Button.tsx # 데모 Button
|
|
377
|
+
│ │ ├── Button.stories.ts # Button 스토리
|
|
378
|
+
│ │ ├── Header.tsx # 데모 Header
|
|
379
|
+
│ │ ├── Header.stories.ts # Header 스토리
|
|
380
|
+
│ │ ├── Page.tsx # 데모 Page
|
|
381
|
+
│ │ ├── Page.stories.ts # Page 스토리
|
|
382
|
+
│ │ └── *.css # 데모 스타일
|
|
383
|
+
│ ├── lib/
|
|
384
|
+
│ │ └── utils.ts # 유틸리티 함수 (cn, clsx)
|
|
385
|
+
│ ├── index.css # Tailwind CSS 스타일
|
|
386
|
+
│ ├── index.css.ts # CSS 타입 정의
|
|
387
|
+
│ └── index.tsx # 패키지 진입점
|
|
388
|
+
├── components.json # shadcn/ui 설정
|
|
389
|
+
├── tailwind.config.cjs # Tailwind CSS 설정
|
|
390
|
+
├── postcss.config.js # PostCSS 설정
|
|
391
|
+
├── tsconfig.json # TypeScript 설정
|
|
392
|
+
├── tsconfig.node.json # TypeScript Node 설정
|
|
393
|
+
├── vite.config.ts # Vite 설정
|
|
394
|
+
├── vitest.shims.d.ts # Vitest 타입 정의
|
|
395
|
+
└── package.json # 패키지 정보
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### 주요 디렉토리 설명
|
|
399
|
+
|
|
400
|
+
- **`src/components/`**: 실제 디자인 시스템 컴포넌트들이 위치
|
|
401
|
+
|
|
402
|
+
- `ui/`: shadcn/ui 기반 컴포넌트 구현
|
|
403
|
+
- 컴포넌트 export 파일들
|
|
404
|
+
|
|
405
|
+
- **`src/stories/`**: Storybook 데모 및 예제 컴포넌트들
|
|
406
|
+
|
|
407
|
+
- 실제 패키지에는 포함되지 않으며 개발/테스트 용도
|
|
408
|
+
- Button, Header, Page 등의 데모 컴포넌트
|
|
409
|
+
|
|
410
|
+
- **`src/lib/`**: 공통 유틸리티 함수
|
|
411
|
+
|
|
412
|
+
- `utils.ts`: class-variance-authority, clsx, tailwind-merge를 사용한 `cn` 함수
|
|
413
|
+
|
|
414
|
+
- **`.storybook/`**: Storybook 설정 파일
|
|
415
|
+
- Vitest 통합
|
|
416
|
+
- addons: a11y, docs, onboarding, vitest
|
|
417
|
+
|
|
418
|
+
## 🔧 개발
|
|
419
|
+
|
|
420
|
+
### 로컬 개발
|
|
421
|
+
|
|
422
|
+
```bash
|
|
423
|
+
# 의존성 설치
|
|
424
|
+
npm install
|
|
425
|
+
|
|
426
|
+
# 개발 서버 실행 (테스트용)
|
|
427
|
+
npm run dev
|
|
428
|
+
|
|
429
|
+
# 빌드
|
|
430
|
+
npm run build
|
|
431
|
+
|
|
432
|
+
# 테스트 실행
|
|
433
|
+
npm test
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Storybook 개발
|
|
437
|
+
|
|
438
|
+
컴포넌트를 개발하고 테스트하기 위해 Storybook을 사용할 수 있습니다.
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
# Storybook 개발 서버 실행
|
|
442
|
+
npm run storybook
|
|
443
|
+
|
|
444
|
+
# Storybook 빌드
|
|
445
|
+
npm run build-storybook
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
Storybook은 `http://localhost:6006`에서 실행됩니다.
|
|
449
|
+
|
|
450
|
+
컴포넌트 스토리는 `src/components/**/*.stories.tsx` 경로에 생성됩니다.
|
|
451
|
+
|
|
452
|
+
## 📤 배포
|
|
453
|
+
|
|
454
|
+
이 프로젝트는 GitHub Actions를 통해 자동 배포됩니다.
|
|
455
|
+
|
|
456
|
+
### 배포 프로세스
|
|
457
|
+
|
|
458
|
+
1. **릴리스 생성**: GitHub에서 새로운 릴리스를 생성하면 자동으로 워크플로우가 트리거됩니다.
|
|
459
|
+
2. **빌드 단계**:
|
|
460
|
+
- Node.js 20 환경에서 실행
|
|
461
|
+
- `npm ci`로 의존성 설치
|
|
462
|
+
- `npm test`로 테스트 실행
|
|
463
|
+
3. **퍼블리시 단계**:
|
|
464
|
+
- GitHub Packages에 패키지 퍼블리시
|
|
465
|
+
- 패키지 스코프: `@pylerai`
|
|
466
|
+
- 레지스트리: `https://npm.pkg.github.com`
|
|
467
|
+
|
|
468
|
+
### 워크플로우 파일
|
|
469
|
+
|
|
470
|
+
```yaml:.github/workflows/release-package.yml
|
|
471
|
+
name: Node.js Package
|
|
472
|
+
|
|
473
|
+
on:
|
|
474
|
+
release:
|
|
475
|
+
types: [created]
|
|
476
|
+
|
|
477
|
+
jobs:
|
|
478
|
+
build:
|
|
479
|
+
runs-on: ubuntu-latest
|
|
480
|
+
steps:
|
|
481
|
+
- uses: actions/checkout@v5
|
|
482
|
+
- uses: actions/setup-node@v4
|
|
483
|
+
with:
|
|
484
|
+
node-version: 20
|
|
485
|
+
- run: npm ci
|
|
486
|
+
- run: npm test
|
|
487
|
+
|
|
488
|
+
publish-gpr:
|
|
489
|
+
needs: build
|
|
490
|
+
runs-on: ubuntu-latest
|
|
491
|
+
permissions:
|
|
492
|
+
packages: write
|
|
493
|
+
contents: read
|
|
494
|
+
steps:
|
|
495
|
+
- uses: actions/checkout@v5
|
|
496
|
+
- uses: actions/setup-node@v4
|
|
497
|
+
with:
|
|
498
|
+
node-version: 20
|
|
499
|
+
registry-url: https://npm.pkg.github.com/
|
|
500
|
+
scope: "@pylerai"
|
|
501
|
+
- run: npm ci
|
|
502
|
+
- run: npm publish
|
|
503
|
+
env:
|
|
504
|
+
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
## 🔗 링크
|
|
508
|
+
|
|
509
|
+
- **Repository**: https://github.com/pylerAI/design-system
|
|
510
|
+
- **Issues**: https://github.com/pylerAI/design-system/issues
|
|
511
|
+
- **Homepage**: https://github.com/pylerAI/design-system#readme
|
|
512
|
+
|
|
513
|
+
## 📄 라이선스
|
|
514
|
+
|
|
515
|
+
ISC
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type BadgeColor = "normal" | "neutral" | "negative" | "positive";
|
|
3
|
+
export type BadgeSize = "medium" | "small";
|
|
4
|
+
export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
5
|
+
color?: BadgeColor;
|
|
6
|
+
size?: BadgeSize;
|
|
7
|
+
}
|
|
8
|
+
declare const Badge: React.ForwardRefExoticComponent<BadgeProps & React.RefAttributes<HTMLSpanElement>>;
|
|
9
|
+
export { Badge };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { VariantProps } from 'class-variance-authority';
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
declare const bodyVariants: (props?: ({
|
|
4
|
+
variant?: "body-1-m" | "body-1-r" | "body-2-sb" | "body-2-m" | "body-2-r" | "body-3-m" | "body-3-r" | "body-4-m" | "body-4-r" | null | undefined;
|
|
5
|
+
as?: "p" | "article" | "span" | "div" | "section" | null | undefined;
|
|
6
|
+
} & import('class-variance-authority/types').ClassProp) | undefined) => string;
|
|
7
|
+
export interface BodyProps extends React.HTMLAttributes<HTMLElement>, VariantProps<typeof bodyVariants> {
|
|
8
|
+
/** 렌더링할 HTML 태그. 기본값: "p" */
|
|
9
|
+
as?: "p" | "div" | "span" | "article" | "section";
|
|
10
|
+
asChild?: boolean;
|
|
11
|
+
}
|
|
12
|
+
declare const Body: React.ForwardRefExoticComponent<BodyProps & React.RefAttributes<HTMLElement>>;
|
|
13
|
+
export { Body, bodyVariants };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { VariantProps } from 'class-variance-authority';
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
declare const buttonVariants: (props?: ({
|
|
4
|
+
variant?: "text" | "icon" | "filled" | "outlined" | "indicator" | null | undefined;
|
|
5
|
+
color?: "blue" | "red" | "green" | null | undefined;
|
|
6
|
+
size?: "sm" | "md" | "lg" | "xl" | null | undefined;
|
|
7
|
+
} & import('class-variance-authority/types').ClassProp) | undefined) => string;
|
|
8
|
+
export interface ButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "color">, VariantProps<typeof buttonVariants> {
|
|
9
|
+
asChild?: boolean;
|
|
10
|
+
/** variant="icon"일 때만 유효. 기본값: "square" */
|
|
11
|
+
shape?: "square" | "round";
|
|
12
|
+
/** variant="icon"일 때 outlined 스타일로 전환. 기본값: "filled" */
|
|
13
|
+
iconStyle?: "filled" | "outlined";
|
|
14
|
+
/** 텍스트 왼쪽에 표시할 아이콘 */
|
|
15
|
+
leftIcon?: React.ReactNode;
|
|
16
|
+
/** 텍스트 오른쪽에 표시할 아이콘 */
|
|
17
|
+
rightIcon?: React.ReactNode;
|
|
18
|
+
}
|
|
19
|
+
declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
20
|
+
export interface ButtonIndicatorProps {
|
|
21
|
+
color?: "blue" | "red" | "green";
|
|
22
|
+
size?: "sm" | "md" | "lg" | "xl";
|
|
23
|
+
className?: string;
|
|
24
|
+
}
|
|
25
|
+
declare const ButtonIndicator: React.ForwardRefExoticComponent<ButtonIndicatorProps & React.RefAttributes<HTMLSpanElement>>;
|
|
26
|
+
export { Button, ButtonIndicator, buttonVariants };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "type" | "onChange"> {
|
|
3
|
+
/** 부분 선택(미결정) 상태 */
|
|
4
|
+
indeterminate?: boolean;
|
|
5
|
+
/** 체크 상태 변경 핸들러 */
|
|
6
|
+
onChange?: (checked: boolean) => void;
|
|
7
|
+
}
|
|
8
|
+
declare const Checkbox: React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLInputElement>>;
|
|
9
|
+
export { Checkbox };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type ChipSize = "medium" | "small";
|
|
3
|
+
export interface ChipProps {
|
|
4
|
+
/** 크기. 기본값: "medium" */
|
|
5
|
+
size?: ChipSize;
|
|
6
|
+
/** 선택 상태 */
|
|
7
|
+
selected?: boolean;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
/** 제거 버튼 클릭 핸들러. 정의 시 제거 버튼 표시 */
|
|
10
|
+
onRemove?: () => void;
|
|
11
|
+
onClick?: React.MouseEventHandler<HTMLDivElement>;
|
|
12
|
+
children?: React.ReactNode;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
declare const Chip: React.ForwardRefExoticComponent<ChipProps & React.RefAttributes<HTMLDivElement>>;
|
|
16
|
+
export { Chip };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type DropdownOption = {
|
|
3
|
+
label: string;
|
|
4
|
+
value: string;
|
|
5
|
+
};
|
|
6
|
+
export interface DropdownProps {
|
|
7
|
+
/** 드롭다운 타입. 기본값: "default" */
|
|
8
|
+
type?: "default" | "checkbox" | "radio";
|
|
9
|
+
/** 옵션 목록 */
|
|
10
|
+
options: DropdownOption[];
|
|
11
|
+
/** 단일 선택 값 (type="default" | "radio") */
|
|
12
|
+
value?: string;
|
|
13
|
+
/** 단일 선택 변경 핸들러 */
|
|
14
|
+
onValueChange?: (value: string) => void;
|
|
15
|
+
/** 복수 선택 값 (type="checkbox") */
|
|
16
|
+
values?: string[];
|
|
17
|
+
/** 복수 선택 변경 핸들러 */
|
|
18
|
+
onValuesChange?: (values: string[]) => void;
|
|
19
|
+
/** 미선택 시 표시 텍스트. 기본값: "선택해주세요" */
|
|
20
|
+
placeholder?: string;
|
|
21
|
+
/** 라벨 텍스트 */
|
|
22
|
+
label?: string;
|
|
23
|
+
/** 라벨 표시 여부. 기본값: true */
|
|
24
|
+
showLabel?: boolean;
|
|
25
|
+
/** 필수 입력 표시(*) */
|
|
26
|
+
require?: boolean;
|
|
27
|
+
/** 크기. 기본값: "large" */
|
|
28
|
+
size?: "large" | "medium" | "small";
|
|
29
|
+
disabled?: boolean;
|
|
30
|
+
readOnly?: boolean;
|
|
31
|
+
/** 에러 메시지. 표시 시 필드에 빨간 테두리 적용 */
|
|
32
|
+
error?: string;
|
|
33
|
+
/** 필드 하단 힌트 텍스트 */
|
|
34
|
+
hint?: string;
|
|
35
|
+
/** 트리거 좌측 아이콘 */
|
|
36
|
+
leftIcon?: React.ReactNode;
|
|
37
|
+
/** 외부 컨테이너 className */
|
|
38
|
+
wrapperClassName?: string;
|
|
39
|
+
className?: string;
|
|
40
|
+
}
|
|
41
|
+
declare const Dropdown: React.ForwardRefExoticComponent<DropdownProps & React.RefAttributes<HTMLDivElement>>;
|
|
42
|
+
export { Dropdown };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { VariantProps } from 'class-variance-authority';
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
declare const headlineVariants: (props?: ({
|
|
4
|
+
variant?: "title-1-sb" | "title-1-m" | "title-2-sb" | null | undefined;
|
|
5
|
+
as?: "p" | "span" | "div" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | null | undefined;
|
|
6
|
+
} & import('class-variance-authority/types').ClassProp) | undefined) => string;
|
|
7
|
+
export interface HeadlineProps extends React.HTMLAttributes<HTMLElement>, VariantProps<typeof headlineVariants> {
|
|
8
|
+
/** 렌더링할 HTML 태그. 기본값: "h1" */
|
|
9
|
+
as?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "div" | "span" | "p";
|
|
10
|
+
asChild?: boolean;
|
|
11
|
+
}
|
|
12
|
+
declare const Headline: React.ForwardRefExoticComponent<HeadlineProps & React.RefAttributes<HTMLElement>>;
|
|
13
|
+
export { Headline, headlineVariants };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface InputFieldProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> {
|
|
3
|
+
/** 라벨 텍스트 */
|
|
4
|
+
label?: string;
|
|
5
|
+
/** 라벨 표시 여부. 기본값: true */
|
|
6
|
+
showLabel?: boolean;
|
|
7
|
+
/** 필수 입력 표시(*) */
|
|
8
|
+
require?: boolean;
|
|
9
|
+
/** 라벨 아래 추가 메시지 */
|
|
10
|
+
message?: string;
|
|
11
|
+
/** 필드 하단 힌트 텍스트 */
|
|
12
|
+
hint?: string;
|
|
13
|
+
/** 에러 메시지. 표시 시 필드에 빨간 테두리 적용 */
|
|
14
|
+
error?: string;
|
|
15
|
+
/** 우측 아이콘. type="password"이면 기본 비밀번호 토글 아이콘 */
|
|
16
|
+
rightIcon?: React.ReactNode;
|
|
17
|
+
/** 크기. 기본값: "large" */
|
|
18
|
+
size?: "large" | "medium" | "small";
|
|
19
|
+
/** 외부 컨테이너 className */
|
|
20
|
+
wrapperClassName?: string;
|
|
21
|
+
}
|
|
22
|
+
declare const InputField: React.ForwardRefExoticComponent<InputFieldProps & React.RefAttributes<HTMLInputElement>>;
|
|
23
|
+
export interface TextFieldProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
24
|
+
/** 라벨 텍스트 */
|
|
25
|
+
label?: string;
|
|
26
|
+
/** 라벨 표시 여부. 기본값: true */
|
|
27
|
+
showLabel?: boolean;
|
|
28
|
+
/** 외부 컨테이너 className */
|
|
29
|
+
wrapperClassName?: string;
|
|
30
|
+
}
|
|
31
|
+
declare const TextField: React.ForwardRefExoticComponent<TextFieldProps & React.RefAttributes<HTMLTextAreaElement>>;
|
|
32
|
+
export { InputField, TextField };
|