insystem-atoms 0.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 ADDED
@@ -0,0 +1,366 @@
1
+ # insystem-atoms
2
+
3
+ 사내 React 아토믹 디자인 컴포넌트 라이브러리.
4
+ SI 프로젝트 간 UI 일관성과 유지보수성 향상을 위해 설계되었습니다.
5
+
6
+ [![npm version](https://img.shields.io/npm/v/insystem-atoms)](https://www.npmjs.com/package/insystem-atoms)
7
+ [![license](https://img.shields.io/npm/l/insystem-atoms)](LICENSE)
8
+
9
+ ---
10
+
11
+ ## 설치
12
+
13
+ ```bash
14
+ npm install insystem-atoms styled-components
15
+ ```
16
+
17
+ > **peerDependencies**: `react >= 18`, `react-dom >= 18`, `styled-components >= 6`
18
+
19
+ ---
20
+
21
+ ## 빠른 시작
22
+
23
+ ```tsx
24
+ import { Button, Input, Checkbox } from 'insystem-atoms';
25
+
26
+ function App() {
27
+ return (
28
+ <>
29
+ <Button variant="primary" onClick={handleSave}>저장</Button>
30
+ <Input label="이름" required placeholder="홍길동" />
31
+ <Checkbox label="동의합니다" checked={agreed} onChange={setAgreed} />
32
+ </>
33
+ );
34
+ }
35
+ ```
36
+
37
+ ---
38
+
39
+ ## 브랜드 색상 / 폰트 오버라이드
40
+
41
+ 앱 진입점(`main.tsx`) 최상단에서 **렌더링 전** 한 번만 호출합니다.
42
+
43
+ ```ts
44
+ import { configureTokens } from 'insystem-atoms';
45
+
46
+ configureTokens({
47
+ color: {
48
+ primary: '#a44945',
49
+ primaryHover: '#8a3d3a',
50
+ primaryLight: '#fff0ef',
51
+ },
52
+ font: {
53
+ family: "'NanumSquareNeo', 'Apple SD Gothic Neo', sans-serif",
54
+ },
55
+ radius: {
56
+ md: '10px',
57
+ },
58
+ });
59
+ ```
60
+
61
+ ---
62
+
63
+ ## 컴포넌트
64
+
65
+ ### Button
66
+
67
+ ```tsx
68
+ import { Button } from 'insystem-atoms';
69
+
70
+ <Button variant="primary">저장</Button>
71
+ <Button variant="secondary" size="sm">취소</Button>
72
+ <Button variant="danger" loading>삭제 중...</Button>
73
+ <Button variant="primary" fullWidth>전체 너비</Button>
74
+ <Button leftIcon={<PlusIcon />}>추가</Button>
75
+ ```
76
+
77
+ | Prop | 타입 | 기본값 | 설명 |
78
+ |------|------|--------|------|
79
+ | `variant` | `primary` \| `secondary` \| `success` \| `warning` \| `danger` \| `ghost` \| `admin` \| `neutral` \| `conversion` \| `icon` | `primary` | 버튼 스타일 |
80
+ | `size` | `xs` \| `sm` \| `md` \| `lg` | `md` | 크기 |
81
+ | `loading` | `boolean` | `false` | 로딩 스피너 표시 |
82
+ | `fullWidth` | `boolean` | `false` | 컨테이너 전체 너비 |
83
+ | `width` | `string \| number` | — | 고정 너비 |
84
+ | `leftIcon` | `ReactNode` | — | 좌측 아이콘 슬롯 |
85
+ | `rightIcon` | `ReactNode` | — | 우측 아이콘 슬롯 |
86
+ | `iconOnly` | `boolean` | `false` | 아이콘 전용 (텍스트 숨김) |
87
+
88
+ ---
89
+
90
+ ### Input
91
+
92
+ ```tsx
93
+ import { Input } from 'insystem-atoms';
94
+
95
+ <Input label="이메일" required placeholder="example@email.com" />
96
+ <Input label="검색" prefix={<SearchIcon />} clearable />
97
+ <Input error="필수 입력값입니다" />
98
+ <Input hint="8자 이상 입력해주세요" />
99
+ ```
100
+
101
+ | Prop | 타입 | 기본값 | 설명 |
102
+ |------|------|--------|------|
103
+ | `label` | `string` | — | 레이블 |
104
+ | `required` | `boolean` | — | 필수 표시(`*`) |
105
+ | `error` | `string` | — | 에러 메시지 (빨간 테두리) |
106
+ | `hint` | `string` | — | 힌트 텍스트 |
107
+ | `size` | `sm` \| `md` \| `lg` | `md` | 크기 |
108
+ | `prefix` | `ReactNode` | — | 좌측 장식 슬롯 |
109
+ | `suffix` | `ReactNode` | — | 우측 장식 슬롯 |
110
+ | `clearable` | `boolean` | `false` | X 버튼으로 초기화 |
111
+ | `fullWidth` | `boolean` | `true` | 전체 너비 |
112
+ | `width` | `string \| number` | — | 고정 너비 |
113
+
114
+ ---
115
+
116
+ ### Checkbox
117
+
118
+ ```tsx
119
+ import { Checkbox } from 'insystem-atoms';
120
+
121
+ <Checkbox label="전체 동의" checked={all} onChange={handleAll} />
122
+ <Checkbox label="항목 1" indeterminate />
123
+ <Checkbox label="비활성" disabled />
124
+ ```
125
+
126
+ | Prop | 타입 | 설명 |
127
+ |------|------|------|
128
+ | `label` | `ReactNode` | 레이블 |
129
+ | `size` | `sm` \| `md` \| `lg` | 크기 |
130
+ | `indeterminate` | `boolean` | 중간 선택 상태 |
131
+ | `error` | `boolean` | 에러 테두리 |
132
+ | `checkColor` | `string` | 체크 활성 색상 오버라이드 |
133
+
134
+ ---
135
+
136
+ ### Radio / RadioGroup
137
+
138
+ ```tsx
139
+ import { RadioGroup } from 'insystem-atoms';
140
+
141
+ <RadioGroup
142
+ name="gender"
143
+ options={[
144
+ { value: 'male', label: '남성' },
145
+ { value: 'female', label: '여성' },
146
+ ]}
147
+ value={value}
148
+ onChange={setValue}
149
+ />
150
+
151
+ // 격자 배치
152
+ <RadioGroup
153
+ name="plan"
154
+ options={plans}
155
+ direction="grid"
156
+ gridColumns={3}
157
+ value={value}
158
+ onChange={setValue}
159
+ />
160
+ ```
161
+
162
+ | Prop | 타입 | 기본값 | 설명 |
163
+ |------|------|--------|------|
164
+ | `options` | `{ value, label, disabled? }[]` | — | 선택 항목 |
165
+ | `value` | `string` | — | 선택된 값 |
166
+ | `onChange` | `(value: string) => void` | — | 변경 콜백 |
167
+ | `direction` | `row` \| `column` \| `grid` | `row` | 배치 방향 |
168
+ | `gridColumns` | `number` | `3` | grid 열 수 |
169
+
170
+ ---
171
+
172
+ ### Select
173
+
174
+ ```tsx
175
+ import { Select } from 'insystem-atoms';
176
+
177
+ <Select
178
+ label="지역"
179
+ options={[
180
+ { value: 'seoul', label: '서울' },
181
+ { value: 'busan', label: '부산' },
182
+ ]}
183
+ placeholder="선택해주세요"
184
+ />
185
+ <Select variant="filled" options={options} />
186
+ ```
187
+
188
+ | Prop | 타입 | 기본값 | 설명 |
189
+ |------|------|--------|------|
190
+ | `options` | `{ value, label, disabled? }[]` | — | 선택 항목 |
191
+ | `placeholder` | `string` | — | 플레이스홀더 |
192
+ | `variant` | `default` \| `outlined` \| `filled` | `default` | 배경 스타일 |
193
+ | `label` | `string` | — | 레이블 |
194
+ | `error` | `string` | — | 에러 메시지 |
195
+
196
+ ---
197
+
198
+ ### TextArea
199
+
200
+ ```tsx
201
+ import { TextArea } from 'insystem-atoms';
202
+
203
+ <TextArea label="내용" required maxLength={500} />
204
+ <TextArea resize="none" rows={6} />
205
+ ```
206
+
207
+ ---
208
+
209
+ ### Label
210
+
211
+ ```tsx
212
+ import { Label } from 'insystem-atoms';
213
+
214
+ <Label required htmlFor="name">이름</Label>
215
+ <Label optional>설명</Label>
216
+ <Label disabled>비활성</Label>
217
+ ```
218
+
219
+ ---
220
+
221
+ ### Badge
222
+
223
+ ```tsx
224
+ import { Badge } from 'insystem-atoms';
225
+
226
+ <Badge variant="success">활성</Badge>
227
+ <Badge variant="danger" outline>오류</Badge>
228
+ <Badge variant="primary" dot /> {/* 점 뱃지 */}
229
+ ```
230
+
231
+ ---
232
+
233
+ ### Chip
234
+
235
+ ```tsx
236
+ import { Chip } from 'insystem-atoms';
237
+
238
+ // 필터 그룹 예시
239
+ const [selected, setSelected] = useState('all');
240
+
241
+ <Chip label="전체" active={selected === 'all'} count={24} onClick={() => setSelected('all')} />
242
+ <Chip label="진행중" active={selected === 'active'} count={8} onClick={() => setSelected('active')} />
243
+ ```
244
+
245
+ ---
246
+
247
+ ### Loading
248
+
249
+ ```tsx
250
+ import { Loading } from 'insystem-atoms';
251
+
252
+ <Loading size="md" />
253
+ <Loading size="lg" text="데이터를 불러오는 중..." />
254
+ <Loading fullscreen text="처리 중..." /> {/* 전체 화면 오버레이 */}
255
+ ```
256
+
257
+ ---
258
+
259
+ ### Pagination
260
+
261
+ ```tsx
262
+ import { Pagination } from 'insystem-atoms';
263
+
264
+ const [page, setPage] = useState(1);
265
+
266
+ <Pagination
267
+ currentPage={page}
268
+ totalPages={20}
269
+ onPageChange={setPage}
270
+ />
271
+ ```
272
+
273
+ ---
274
+
275
+ ### Toast
276
+
277
+ ```tsx
278
+ import { Toast } from 'insystem-atoms';
279
+
280
+ const [visible, setVisible] = useState(false);
281
+
282
+ {visible && (
283
+ <Toast
284
+ type="success"
285
+ message="저장되었습니다."
286
+ onClose={() => setVisible(false)}
287
+ />
288
+ )}
289
+ ```
290
+
291
+ | Prop | 타입 | 기본값 | 설명 |
292
+ |------|------|--------|------|
293
+ | `message` | `string` | — | 표시할 메시지 |
294
+ | `type` | `info` \| `success` \| `error` \| `warning` | `info` | 타입 |
295
+ | `duration` | `number` | `3000` | 자동 닫힘 ms (0 = 수동) |
296
+ | `position` | `top-center` \| `top-right` \| `bottom-center` \| `bottom-right` | `bottom-center` | 위치 |
297
+ | `onClose` | `() => void` | — | 닫기 콜백 |
298
+
299
+ ---
300
+
301
+ ## 스타일 오버라이드 Props
302
+
303
+ 모든 컴포넌트에 아래 props를 사용해 인라인으로 스타일을 변경할 수 있습니다.
304
+
305
+ ```tsx
306
+ <Button borderRadius="20px">둥근 버튼</Button>
307
+ <Button backgroundColor="#7C3AED" textColor="#fff">보라 버튼</Button>
308
+ <Input borderColor="#7C3AED" borderRadius="8px" />
309
+ <Badge backgroundColor="#f0fdf4" textColor="#166534">커스텀</Badge>
310
+ ```
311
+
312
+ | Prop | 컴포넌트 | 설명 |
313
+ |------|----------|------|
314
+ | `borderRadius` | 전체 | 모서리 반경 |
315
+ | `borderColor` | 전체 | 테두리 색상 |
316
+ | `textColor` | 전체 | 텍스트/전경 색상 |
317
+ | `backgroundColor` | 전체 | 배경색 |
318
+ | `padding` | Button, Input, TextArea | 내부 여백 |
319
+ | `checkColor` | Checkbox, Radio | 체크/선택 활성 색상 |
320
+ | `activeColor` | Chip, Pagination | 활성 상태 색상 |
321
+
322
+ ---
323
+
324
+ ## 디자인 토큰 전체 오버라이드
325
+
326
+ ```ts
327
+ import { configureTokens, resetTokens } from 'insystem-atoms';
328
+ import type { Tokens } from 'insystem-atoms';
329
+
330
+ // 오버라이드 (부분 적용 가능)
331
+ configureTokens({
332
+ color: {
333
+ primary: '#0f766e',
334
+ primaryHover: '#0d6b63',
335
+ primaryLight: '#f0fdfa',
336
+ danger: '#dc2626',
337
+ },
338
+ font: {
339
+ family: "'Noto Sans KR', sans-serif",
340
+ size: { md: '15px' },
341
+ },
342
+ radius: {
343
+ md: '8px',
344
+ full: '50px',
345
+ },
346
+ });
347
+
348
+ // 기본값 복원
349
+ resetTokens();
350
+ ```
351
+
352
+ ---
353
+
354
+ ## TypeScript
355
+
356
+ 모든 컴포넌트는 완전한 타입을 지원합니다.
357
+
358
+ ```ts
359
+ import type { ButtonProps, InputProps, Size, Variant } from 'insystem-atoms';
360
+ ```
361
+
362
+ ---
363
+
364
+ ## 라이선스
365
+
366
+ MIT