@ceed/ads 1.30.0 → 1.30.1

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.
Files changed (62) hide show
  1. package/dist/Overview.md +5 -5
  2. package/dist/components/data-display/Avatar.md +85 -74
  3. package/dist/components/data-display/Badge.md +23 -5
  4. package/dist/components/data-display/Chip.md +49 -35
  5. package/dist/components/data-display/DataTable.md +93 -0
  6. package/dist/components/data-display/InfoSign.md +15 -5
  7. package/dist/components/data-display/Markdown.md +22 -26
  8. package/dist/components/data-display/Table.md +63 -53
  9. package/dist/components/data-display/Tooltip.md +70 -58
  10. package/dist/components/data-display/Typography.md +28 -11
  11. package/dist/components/feedback/Alert.md +86 -74
  12. package/dist/components/feedback/CircularProgress.md +20 -5
  13. package/dist/components/feedback/Dialog.md +8 -12
  14. package/dist/components/feedback/Modal.md +12 -16
  15. package/dist/components/feedback/Skeleton.md +20 -5
  16. package/dist/components/inputs/Autocomplete.md +8 -10
  17. package/dist/components/inputs/Button.md +107 -87
  18. package/dist/components/inputs/ButtonGroup.md +20 -5
  19. package/dist/components/inputs/Calendar.md +25 -5
  20. package/dist/components/inputs/Checkbox.md +171 -450
  21. package/dist/components/inputs/CurrencyInput.md +25 -5
  22. package/dist/components/inputs/DatePicker.md +39 -5
  23. package/dist/components/inputs/DateRangePicker.md +29 -5
  24. package/dist/components/inputs/FilterMenu.md +85 -9
  25. package/dist/components/inputs/FilterableCheckboxGroup.md +23 -8
  26. package/dist/components/inputs/FormControl.md +34 -6
  27. package/dist/components/inputs/IconButton.md +21 -5
  28. package/dist/components/inputs/Input.md +254 -68
  29. package/dist/components/inputs/MonthPicker.md +28 -5
  30. package/dist/components/inputs/MonthRangePicker.md +26 -5
  31. package/dist/components/inputs/PercentageInput.md +28 -5
  32. package/dist/components/inputs/RadioButton.md +26 -5
  33. package/dist/components/inputs/RadioList.md +23 -6
  34. package/dist/components/inputs/RadioTileGroup.md +40 -8
  35. package/dist/components/inputs/Select.md +59 -5
  36. package/dist/components/inputs/Slider.md +26 -5
  37. package/dist/components/inputs/Switch.md +23 -5
  38. package/dist/components/inputs/Textarea.md +27 -5
  39. package/dist/components/inputs/Uploader/Uploader.md +24 -5
  40. package/dist/components/layout/Box.md +66 -58
  41. package/dist/components/layout/Container.md +9 -13
  42. package/dist/components/layout/Grid.md +91 -75
  43. package/dist/components/layout/Stack.md +85 -70
  44. package/dist/components/navigation/Breadcrumbs.md +23 -14
  45. package/dist/components/navigation/Dropdown.md +29 -20
  46. package/dist/components/navigation/IconMenuButton.md +24 -11
  47. package/dist/components/navigation/InsetDrawer.md +16 -5
  48. package/dist/components/navigation/Link.md +30 -14
  49. package/dist/components/navigation/Menu.md +33 -20
  50. package/dist/components/navigation/MenuButton.md +26 -12
  51. package/dist/components/navigation/NavigationGroup.md +7 -11
  52. package/dist/components/navigation/NavigationItem.md +8 -12
  53. package/dist/components/navigation/Navigator.md +5 -9
  54. package/dist/components/navigation/Pagination.md +21 -12
  55. package/dist/components/navigation/ProfileMenu.md +17 -5
  56. package/dist/components/navigation/Stepper.md +18 -5
  57. package/dist/components/navigation/Tabs.md +37 -14
  58. package/dist/components/surfaces/Accordions.md +12 -16
  59. package/dist/components/surfaces/Card.md +59 -47
  60. package/dist/components/surfaces/Divider.md +70 -61
  61. package/dist/components/surfaces/Sheet.md +18 -5
  62. package/package.json +1 -1
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Introduction
4
4
 
5
- Checkbox 컴포넌트는 사용자가 여러 옵션 중에서 하나 또는 여러 개를 선택할 있는 입력 요소입니다. Joy UI Checkbox 기반으로 하며, Framer Motion 애니메이션 지원이 추가되었습니다. 설정 화면, 폼, 필터링, 다중 선택 목록 등에서 널리 사용됩니다.
5
+ Checkbox is an input element that allows users to select one or more options from a set. Built on Joy UI's Checkbox with Framer Motion animation support, it is used in settings screens, forms, filters, multi-select lists, and agreement flows. It supports indeterminate state for "select all" patterns, decorators for custom content, and overlay mode for clickable card patterns.
6
6
 
7
7
  ```tsx
8
8
  <Checkbox />
@@ -27,7 +27,7 @@ function MyComponent() {
27
27
 
28
28
  return (
29
29
  <Checkbox
30
- label="동의합니다"
30
+ label="I agree"
31
31
  checked={checked}
32
32
  onChange={(e) => setChecked(e.target.checked)}
33
33
  />
@@ -35,29 +35,92 @@ function MyComponent() {
35
35
  }
36
36
  ```
37
37
 
38
- ## Examples
38
+ ## Basic Usage
39
39
 
40
- ### Basic Usage
41
-
42
- 가장 기본적인 Checkbox 사용법입니다.
40
+ A simple checkbox with a label.
43
41
 
44
42
  ```tsx
45
43
  <Checkbox label="Label" />
46
44
  ```
47
45
 
48
- ### With Labels
46
+ ## Variants
49
47
 
50
- 체크박스에 라벨을 추가할 있습니다.
48
+ Four visual styles are available: `solid` (default when checked), `soft`, `outlined`, and `plain`.
51
49
 
52
50
  ```tsx
53
- <Checkbox />
51
+ <Stack spacing={2}>
52
+ <Checkbox label="Solid" variant="solid" defaultChecked />
53
+ <Checkbox label="Soft" variant="soft" defaultChecked />
54
+ <Checkbox label="Outlined" variant="outlined" defaultChecked />
55
+ <Checkbox label="Plain" variant="plain" defaultChecked />
56
+ </Stack>
57
+ ```
58
+
59
+ ## Sizes
60
+
61
+ Three sizes are available: `sm`, `md` (default), and `lg`.
62
+
63
+ ```tsx
64
+ <Stack direction="row" spacing={2} alignItems="center">
65
+ <Checkbox label="Small" size="sm" defaultChecked />
66
+ <Checkbox label="Medium" size="md" defaultChecked />
67
+ <Checkbox label="Large" size="lg" defaultChecked />
68
+ </Stack>
69
+ ```
70
+
71
+ ## Colors
72
+
73
+ Apply semantic colors to communicate meaning.
74
+
75
+ ```tsx
76
+ <Stack spacing={2}>
77
+ <Checkbox label="Primary" color="primary" defaultChecked />
78
+ <Checkbox label="Success" color="success" defaultChecked />
79
+ <Checkbox label="Warning" color="warning" defaultChecked />
80
+ <Checkbox label="Danger" color="danger" defaultChecked />
81
+ <Checkbox label="Neutral" color="neutral" defaultChecked />
82
+ </Stack>
83
+ ```
84
+
85
+ ## Checkbox Indeterminate State
86
+
87
+ Represents a partially selected state, commonly used in "select all" patterns where some but not all children are selected.
88
+
89
+ ```tsx
90
+ <Checkbox
91
+ label="Partially selected"
92
+ indeterminate
93
+ onChange={handleChange}
94
+ />
54
95
  ```
55
96
 
56
- ## Common Use Cases
97
+ ## Disabled Checkbox
57
98
 
58
- ### Terms and Conditions
99
+ A disabled checkbox cannot be interacted with.
59
100
 
60
- 이용약관 동의에 체크박스를 사용하는 예제입니다.
101
+ ```tsx
102
+ <Stack spacing={1}>
103
+ <Checkbox label="Disabled (unchecked)" disabled />
104
+ <Checkbox label="Disabled (checked)" disabled defaultChecked />
105
+ <Checkbox label="Disabled (indeterminate)" disabled indeterminate />
106
+ </Stack>
107
+ ```
108
+
109
+ ## Checkbox Validation Error
110
+
111
+ Use with `FormControl` to show validation errors.
112
+
113
+ ```tsx
114
+ <FormControl error>
115
+ <Checkbox label="Required agreement" required />
116
+ <FormHelperText>
117
+ <InfoOutlinedIcon />
118
+ This field is required.
119
+ </FormHelperText>
120
+ </FormControl>
121
+ ```
122
+
123
+ ## Checkbox for Terms and Conditions
61
124
 
62
125
  ```tsx
63
126
  function TermsForm() {
@@ -70,22 +133,19 @@ function TermsForm() {
70
133
  const handleChange = (key: keyof typeof agreements) => (
71
134
  event: React.ChangeEvent<HTMLInputElement>
72
135
  ) => {
73
- setAgreements(prev => ({
74
- ...prev,
75
- [key]: event.target.checked
76
- }));
136
+ setAgreements(prev => ({ ...prev, [key]: event.target.checked }));
77
137
  };
78
138
 
79
139
  return (
80
140
  <Stack spacing={2}>
81
- <Typography level="title-md">약관 동의</Typography>
141
+ <Typography level="title-md">Agreements</Typography>
82
142
 
83
143
  <Checkbox
84
144
  label={
85
145
  <Typography>
86
- <strong>(필수)</strong> 이용약관에 동의합니다.
146
+ <strong>(Required)</strong> I agree to the Terms of Service.
87
147
  <Link href="/terms" target="_blank" sx={{ ml: 1 }}>
88
- 약관 보기
148
+ View Terms
89
149
  </Link>
90
150
  </Typography>
91
151
  }
@@ -97,9 +157,9 @@ function TermsForm() {
97
157
  <Checkbox
98
158
  label={
99
159
  <Typography>
100
- <strong>(필수)</strong> 개인정보 처리방침에 동의합니다.
160
+ <strong>(Required)</strong> I agree to the Privacy Policy.
101
161
  <Link href="/privacy" target="_blank" sx={{ ml: 1 }}>
102
- 방침 보기
162
+ View Policy
103
163
  </Link>
104
164
  </Typography>
105
165
  }
@@ -109,140 +169,29 @@ function TermsForm() {
109
169
  />
110
170
 
111
171
  <Checkbox
112
- label="(선택) 마케팅 정보 수신에 동의합니다."
172
+ label="(Optional) I agree to receive marketing communications."
113
173
  checked={agreements.marketing}
114
174
  onChange={handleChange('marketing')}
115
175
  color="neutral"
116
176
  />
117
177
 
118
- <Button
119
- disabled={!agreements.terms || !agreements.privacy}
120
- sx={{ mt: 2 }}
121
- >
122
- 가입하기
178
+ <Button disabled={!agreements.terms || !agreements.privacy} sx={{ mt: 2 }}>
179
+ Sign Up
123
180
  </Button>
124
181
  </Stack>
125
182
  );
126
183
  }
127
184
  ```
128
185
 
129
- ### Multi-Select List
130
-
131
- 목록에서 여러 항목을 선택할 때 사용합니다.
132
-
133
- ```tsx
134
- function TodoList() {
135
- const [todos, setTodos] = useState([
136
- { id: 1, text: '회의 준비하기', completed: false },
137
- { id: 2, text: '보고서 작성하기', completed: true },
138
- { id: 3, text: '이메일 답장하기', completed: false },
139
- ]);
140
-
141
- const handleToggle = (id: number) => {
142
- setTodos(prev => prev.map(todo =>
143
- todo.id === id ? { ...todo, completed: !todo.completed } : todo
144
- ));
145
- };
146
-
147
- return (
148
- <Stack spacing={1}>
149
- <Typography level="title-md">할 일 목록</Typography>
150
- {todos.map(todo => (
151
- <Checkbox
152
- key={todo.id}
153
- label={
154
- <Typography
155
- sx={{
156
- textDecoration: todo.completed ? 'line-through' : 'none',
157
- color: todo.completed ? 'neutral.500' : 'inherit',
158
- }}
159
- >
160
- {todo.text}
161
- </Typography>
162
- }
163
- checked={todo.completed}
164
- onChange={() => handleToggle(todo.id)}
165
- color={todo.completed ? 'success' : 'primary'}
166
- />
167
- ))}
168
- </Stack>
169
- );
170
- }
171
- ```
172
-
173
- ### Filter Options
174
-
175
- 필터링 옵션에서 체크박스를 사용하는 예제입니다.
176
-
177
- ```tsx
178
- function ProductFilter() {
179
- const [filters, setFilters] = useState({
180
- categories: [] as string[],
181
- priceRanges: [] as string[],
182
- brands: [] as string[],
183
- });
184
-
185
- const handleCategoryChange = (category: string) => (
186
- event: React.ChangeEvent<HTMLInputElement>
187
- ) => {
188
- setFilters(prev => ({
189
- ...prev,
190
- categories: event.target.checked
191
- ? [...prev.categories, category]
192
- : prev.categories.filter(c => c !== category)
193
- }));
194
- };
195
-
196
- return (
197
- <Stack spacing={3}>
198
- <Stack spacing={2}>
199
- <Typography level="title-sm">카테고리</Typography>
200
- <Stack spacing={1} sx={{ pl: 1 }}>
201
- <Checkbox
202
- label="전자제품"
203
- checked={filters.categories.includes('electronics')}
204
- onChange={handleCategoryChange('electronics')}
205
- size="sm"
206
- />
207
- <Checkbox
208
- label="의류"
209
- checked={filters.categories.includes('clothing')}
210
- onChange={handleCategoryChange('clothing')}
211
- size="sm"
212
- />
213
- <Checkbox
214
- label="도서"
215
- checked={filters.categories.includes('books')}
216
- onChange={handleCategoryChange('books')}
217
- size="sm"
218
- />
219
- </Stack>
220
- </Stack>
221
-
222
- <Stack spacing={2}>
223
- <Typography level="title-sm">가격대</Typography>
224
- <Stack spacing={1} sx={{ pl: 1 }}>
225
- <Checkbox label="10만원 이하" size="sm" />
226
- <Checkbox label="10-50만원" size="sm" />
227
- <Checkbox label="50만원 이상" size="sm" />
228
- </Stack>
229
- </Stack>
230
- </Stack>
231
- );
232
- }
233
- ```
234
-
235
- ### Select All Pattern
236
-
237
- 전체 선택/해제 패턴을 구현하는 예제입니다.
186
+ ## Select All Pattern with Checkbox
238
187
 
239
188
  ```tsx
240
189
  function SelectAllExample() {
241
190
  const [items, setItems] = useState([
242
- { id: 1, name: '항목 1', selected: false },
243
- { id: 2, name: '항목 2', selected: true },
244
- { id: 3, name: '항목 3', selected: false },
245
- { id: 4, name: '항목 4', selected: false },
191
+ { id: 1, name: 'Item 1', selected: false },
192
+ { id: 2, name: 'Item 2', selected: true },
193
+ { id: 3, name: 'Item 3', selected: false },
194
+ { id: 4, name: 'Item 4', selected: false },
246
195
  ]);
247
196
 
248
197
  const selectedCount = items.filter(item => item.selected).length;
@@ -250,10 +199,7 @@ function SelectAllExample() {
250
199
  const isIndeterminate = selectedCount > 0 && selectedCount < items.length;
251
200
 
252
201
  const handleSelectAll = (event: React.ChangeEvent<HTMLInputElement>) => {
253
- setItems(prev => prev.map(item => ({
254
- ...item,
255
- selected: event.target.checked
256
- })));
202
+ setItems(prev => prev.map(item => ({ ...item, selected: event.target.checked })));
257
203
  };
258
204
 
259
205
  const handleItemToggle = (id: number) => {
@@ -265,7 +211,7 @@ function SelectAllExample() {
265
211
  return (
266
212
  <Stack spacing={2}>
267
213
  <Checkbox
268
- label={`전체 선택 (${selectedCount}/${items.length})`}
214
+ label={`Select All (${selectedCount}/${items.length})`}
269
215
  checked={isAllSelected}
270
216
  indeterminate={isIndeterminate}
271
217
  onChange={handleSelectAll}
@@ -291,179 +237,48 @@ function SelectAllExample() {
291
237
  }
292
238
  ```
293
239
 
294
- ### Form with Validation
295
-
296
- 폼 검증과 함께 사용하는 체크박스 예제입니다.
240
+ ## Checkbox as Filter Option
297
241
 
298
242
  ```tsx
299
- function RegistrationForm() {
300
- const [formData, setFormData] = useState({
301
- name: '',
302
- email: '',
303
- agreeToTerms: false,
304
- subscribeNewsletter: false,
243
+ function ProductFilter() {
244
+ const [filters, setFilters] = useState({
245
+ categories: [] as string[],
305
246
  });
306
247
 
307
- const [errors, setErrors] = useState<Record<string, string>>({});
308
-
309
- const handleSubmit = (event: React.FormEvent) => {
310
- event.preventDefault();
311
-
312
- const newErrors: Record<string, string> = {};
313
-
314
- if (!formData.name) {
315
- newErrors.name = '이름을 입력해주세요';
316
- }
317
-
318
- if (!formData.email) {
319
- newErrors.email = '이메일을 입력해주세요';
320
- }
321
-
322
- if (!formData.agreeToTerms) {
323
- newErrors.agreeToTerms = '이용약관에 동의해주세요';
324
- }
325
-
326
- setErrors(newErrors);
327
-
328
- if (Object.keys(newErrors).length === 0) {
329
- console.log('폼 제출:', formData);
330
- }
248
+ const handleCategoryChange = (category: string) => (
249
+ event: React.ChangeEvent<HTMLInputElement>
250
+ ) => {
251
+ setFilters(prev => ({
252
+ ...prev,
253
+ categories: event.target.checked
254
+ ? [...prev.categories, category]
255
+ : prev.categories.filter(c => c !== category)
256
+ }));
331
257
  };
332
258
 
333
259
  return (
334
- <form onSubmit={handleSubmit}>
335
- <Stack spacing={3}>
336
- <Input
337
- placeholder="이름"
338
- value={formData.name}
339
- onChange={(e) => setFormData(prev => ({ ...prev, name: e.target.value }))}
340
- error={!!errors.name}
260
+ <Stack spacing={2}>
261
+ <Typography level="title-sm">Categories</Typography>
262
+ <Stack spacing={1} sx={{ pl: 1 }}>
263
+ <Checkbox
264
+ label="Electronics"
265
+ checked={filters.categories.includes('electronics')}
266
+ onChange={handleCategoryChange('electronics')}
267
+ size="sm"
341
268
  />
342
- {errors.name && (
343
- <Typography level="body-xs" color="danger">
344
- {errors.name}
345
- </Typography>
346
- )}
347
-
348
- <Input
349
- placeholder="이메일"
350
- type="email"
351
- value={formData.email}
352
- onChange={(e) => setFormData(prev => ({ ...prev, email: e.target.value }))}
353
- error={!!errors.email}
269
+ <Checkbox
270
+ label="Clothing"
271
+ checked={filters.categories.includes('clothing')}
272
+ onChange={handleCategoryChange('clothing')}
273
+ size="sm"
354
274
  />
355
- {errors.email && (
356
- <Typography level="body-xs" color="danger">
357
- {errors.email}
358
- </Typography>
359
- )}
360
-
361
- <FormControl error={!!errors.agreeToTerms}>
362
- <Checkbox
363
- label="이용약관 및 개인정보처리방침에 동의합니다"
364
- checked={formData.agreeToTerms}
365
- onChange={(e) => setFormData(prev => ({ ...prev, agreeToTerms: e.target.checked }))}
366
- required
367
- />
368
- {errors.agreeToTerms && (
369
- <FormHelperText>
370
- <InfoOutlinedIcon />
371
- {errors.agreeToTerms}
372
- </FormHelperText>
373
- )}
374
- </FormControl>
375
-
376
275
  <Checkbox
377
- label="뉴스레터 구독하기"
378
- checked={formData.subscribeNewsletter}
379
- onChange={(e) => setFormData(prev => ({ ...prev, subscribeNewsletter: e.target.checked }))}
380
- color="success"
381
- variant="soft"
276
+ label="Books"
277
+ checked={filters.categories.includes('books')}
278
+ onChange={handleCategoryChange('books')}
279
+ size="sm"
382
280
  />
383
-
384
- <Button type="submit">가입하기</Button>
385
281
  </Stack>
386
- </form>
387
- );
388
- }
389
- ```
390
-
391
- ### Data Table Row Selection
392
-
393
- 데이터 테이블에서 행 선택에 사용하는 예제입니다.
394
-
395
- ```tsx
396
- function DataTableWithSelection() {
397
- const [selectedRows, setSelectedRows] = useState<Set<number>>(new Set());
398
-
399
- const users = [
400
- { id: 1, name: '김철수', email: 'kim@example.com', role: '관리자' },
401
- { id: 2, name: '이영희', email: 'lee@example.com', role: '사용자' },
402
- { id: 3, name: '박민수', email: 'park@example.com', role: '사용자' },
403
- ];
404
-
405
- const handleRowSelect = (id: number) => {
406
- const newSelected = new Set(selectedRows);
407
- if (newSelected.has(id)) {
408
- newSelected.delete(id);
409
- } else {
410
- newSelected.add(id);
411
- }
412
- setSelectedRows(newSelected);
413
- };
414
-
415
- const handleSelectAll = (event: React.ChangeEvent<HTMLInputElement>) => {
416
- if (event.target.checked) {
417
- setSelectedRows(new Set(users.map(user => user.id)));
418
- } else {
419
- setSelectedRows(new Set());
420
- }
421
- };
422
-
423
- return (
424
- <Stack spacing={2}>
425
- {selectedRows.size > 0 && (
426
- <Alert color="primary">
427
- {selectedRows.size}개 항목이 선택되었습니다.
428
- <Button size="sm" variant="soft" sx={{ ml: 2 }}>
429
- 선택 항목 삭제
430
- </Button>
431
- </Alert>
432
- )}
433
-
434
- <Table>
435
- <thead>
436
- <tr>
437
- <th style={{ width: 48 }}>
438
- <Checkbox
439
- size="sm"
440
- checked={selectedRows.size === users.length}
441
- indeterminate={selectedRows.size > 0 && selectedRows.size < users.length}
442
- onChange={handleSelectAll}
443
- />
444
- </th>
445
- <th>이름</th>
446
- <th>이메일</th>
447
- <th>역할</th>
448
- </tr>
449
- </thead>
450
- <tbody>
451
- {users.map(user => (
452
- <tr key={user.id}>
453
- <td>
454
- <Checkbox
455
- size="sm"
456
- checked={selectedRows.has(user.id)}
457
- onChange={() => handleRowSelect(user.id)}
458
- />
459
- </td>
460
- <td>{user.name}</td>
461
- <td>{user.email}</td>
462
- <td>{user.role}</td>
463
- </tr>
464
- ))}
465
- </tbody>
466
- </Table>
467
282
  </Stack>
468
283
  );
469
284
  }
@@ -471,179 +286,85 @@ function DataTableWithSelection() {
471
286
 
472
287
  ## Props and Customization
473
288
 
474
- ### Colors
475
-
476
- 다양한 색상을 적용할 있습니다.
477
-
478
- ```tsx
479
- <Stack spacing={2}>
480
- <Checkbox label="Primary" color="primary" checked />
481
- <Checkbox label="Success" color="success" checked />
482
- <Checkbox label="Warning" color="warning" checked />
483
- <Checkbox label="Danger" color="danger" checked />
484
- <Checkbox label="Neutral" color="neutral" checked />
485
- </Stack>
486
- ```
487
-
488
- ### Sizes
489
-
490
- 체크박스의 크기를 조절할 있습니다.
491
-
492
- ```tsx
493
- <Stack direction="row" spacing={2} alignItems="center">
494
- <Checkbox label="Small" size="sm" checked />
495
- <Checkbox label="Medium" size="md" checked />
496
- <Checkbox label="Large" size="lg" checked />
497
- </Stack>
498
- ```
499
-
500
- ### Variants
501
-
502
- 다양한 시각적 스타일을 적용할 수 있습니다.
503
-
504
- ```tsx
505
- <Stack spacing={2}>
506
- <Checkbox label="Solid" variant="solid" checked />
507
- <Checkbox label="Soft" variant="soft" checked />
508
- <Checkbox label="Outlined" variant="outlined" checked />
509
- <Checkbox label="Plain" variant="plain" checked />
510
- </Stack>
511
- ```
512
-
513
- ## States
514
-
515
- ### Indeterminate State
516
-
517
- 부분적으로 선택된 상태를 나타낼 때 사용합니다.
518
-
519
- ```tsx
520
- <Checkbox
521
- label="부분 선택됨"
522
- indeterminate={true}
523
- onChange={handleChange}
524
- />
525
- ```
526
-
527
- ### Disabled State
528
-
529
- 비활성 상태의 체크박스입니다.
530
-
531
- ```tsx
532
- <Stack spacing={1}>
533
- <Checkbox label="비활성 (선택 안됨)" disabled />
534
- <Checkbox label="비활성 (선택됨)" disabled checked />
535
- <Checkbox label="비활성 (부분 선택)" disabled indeterminate />
536
- </Stack>
537
- ```
538
-
539
- ### Error State
540
-
541
- 오류 상태를 표시할 때 사용합니다.
542
-
543
- ```tsx
544
- <FormControl error>
545
- <Checkbox
546
- label="필수 동의 항목"
547
- required
548
- onChange={handleChange}
549
- />
550
- <FormHelperText>
551
- <InfoOutlinedIcon />
552
- 이 항목은 필수로 선택해야 합니다.
553
- </FormHelperText>
554
- </FormControl>
555
- ```
289
+ ### Key Props
290
+
291
+ | Prop | Type | Default | Description |
292
+ | ------------------- | -------------------------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------- |
293
+ | `checked` | `boolean` | - | Whether the checkbox is checked (controlled) |
294
+ | `defaultChecked` | `boolean` | `false` | Initial checked state (uncontrolled) |
295
+ | `indeterminate` | `boolean` | `false` | Shows a partial selection state (dash icon instead of checkmark) |
296
+ | `label` | `ReactNode` | - | Label content displayed next to the checkbox |
297
+ | `onChange` | `(event: ChangeEvent<HTMLInputElement>) => void` | - | Callback when the checked state changes |
298
+ | `color` | `'primary' \| 'neutral' \| 'danger' \| 'success' \| 'warning'` | `'neutral'` | Color scheme |
299
+ | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Checkbox size |
300
+ | `variant` | `'solid' \| 'soft' \| 'outlined' \| 'plain'` | `'solid'` | Visual style when checked |
301
+ | `disabled` | `boolean` | `false` | Disables the checkbox |
302
+ | `readOnly` | `boolean` | `false` | Makes the checkbox read-only |
303
+ | `required` | `boolean` | `false` | Marks the field as required |
304
+ | `name` | `string` | - | HTML name attribute for form submission |
305
+ | `value` | `string \| number` | - | Value attribute for form submission |
306
+ | `overlay` | `boolean` | `false` | Extends the clickable area to cover the parent container (useful for card-click patterns) |
307
+ | `disableIcon` | `boolean` | `false` | Hides the checkbox icon |
308
+ | `checkedIcon` | `ReactNode` | - | Custom icon for the checked state |
309
+ | `uncheckedIcon` | `ReactNode` | - | Custom icon for the unchecked state |
310
+ | `indeterminateIcon` | `ReactNode` | - | Custom icon for the indeterminate state |
311
+ | `endDecorator` | `ReactNode` | - | Content rendered after the checkbox label |
312
+ | `sx` | `SxProps` | - | Custom styles using the MUI system |
313
+
314
+ > **Note**: Checkbox also accepts all Joy UI Checkbox props and Framer Motion props.
556
315
 
557
316
  ## Best Practices
558
317
 
559
- 1. **명확한 라벨**: 체크박스가 무엇을 의미하는지 명확하게 표시하세요.
318
+ 1. **Use clear, descriptive labels.** The label should make it obvious what the user is agreeing to or selecting.
560
319
 
561
320
  ```tsx
562
- // ✅ 명확한 라벨
563
- <Checkbox label="마케팅 정보 수신에 동의합니다" />
321
+ // ✅ Good
322
+ <Checkbox label="I agree to receive marketing emails" />
564
323
 
565
- // ❌ 모호한 라벨
566
- <Checkbox label="동의" />
324
+ // ❌ Bad
325
+ <Checkbox label="Agree" />
567
326
  ```
568
327
 
569
- 2. **적절한 그룹화**: 관련된 체크박스들은 논리적으로 그룹화하세요.
328
+ 2. **Group related checkboxes logically.** Use headings and indentation to create visual hierarchy.
570
329
 
571
330
  ```tsx
572
331
  <Stack spacing={3}>
573
- <Typography level="title-md">알림 설정</Typography>
332
+ <Typography level="title-md">Notification Settings</Typography>
574
333
  <Stack spacing={1} sx={{ pl: 1 }}>
575
- <Checkbox label="이메일 알림" />
576
- <Checkbox label="SMS 알림" />
577
- <Checkbox label="푸시 알림" />
334
+ <Checkbox label="Email notifications" />
335
+ <Checkbox label="SMS notifications" />
336
+ <Checkbox label="Push notifications" />
578
337
  </Stack>
579
338
  </Stack>
580
339
  ```
581
340
 
582
- 3. **필수/선택 구분**: 필수 선택 항목과 선택사항을 명확히 구분하세요.
341
+ 3. **Distinguish required from optional.** Make it clear which selections are mandatory.
583
342
 
584
343
  ```tsx
585
- <Checkbox
586
- label={<><strong>(필수)</strong> 이용약관에 동의</>}
587
- required
588
- />
589
- <Checkbox
590
- label="(선택) 뉴스레터 구독"
591
- color="neutral"
592
- />
344
+ <Checkbox label={<><strong>(Required)</strong> Accept Terms</>} required />
345
+ <Checkbox label="(Optional) Subscribe to newsletter" color="neutral" />
593
346
  ```
594
347
 
595
- 4. **상태 피드백**: 사용자가 선택한 내용을 명확히 보여주세요.
348
+ 4. **Use the indeterminate state correctly.** Only apply it to a parent checkbox that represents a group of child checkboxes with mixed selection.
596
349
 
597
- ```tsx
598
- {selectedCount > 0 && (
599
- <Typography level="body-sm" color="primary">
600
- {selectedCount}개 항목이 선택되었습니다.
601
- </Typography>
602
- )}
603
- ```
350
+ 5. **Prefer Checkbox over Switch** when the setting is a binary choice that is not applied immediately. Use Switch for instant toggle actions.
604
351
 
605
352
  ## Accessibility
606
353
 
607
- Checkbox 컴포넌트는 다음과 같은 접근성 기능을 제공합니다:
608
-
609
- ### 키보드 탐색
354
+ - **Keyboard navigation**: Tab to focus, Space to toggle checked state.
355
+ - **ARIA attributes**: `role="checkbox"`, `aria-checked` reflects the current state (including `mixed` for indeterminate).
356
+ - **Label association**: The `label` prop is automatically associated with the checkbox input.
357
+ - **Error state**: When used inside `FormControl` with `error`, `aria-invalid` is applied.
358
+ - **Screen reader**: Announces as "\[label], checkbox, checked/unchecked/mixed".
610
359
 
611
- - **Tab**: 체크박스로 포커스 이동
612
- - **Space**: 체크박스 선택/해제
613
- - **Enter**: 링크나 버튼 라벨이 있는 경우 활성화
360
+ ## Performance Tips
614
361
 
615
- ### ARIA 속성
616
-
617
- - `role="checkbox"`: 체크박스 역할 정의
618
- - `aria-checked`: 현재 선택 상태 표시
619
- - `aria-describedby`: 추가 설명과 연결
620
-
621
- ### 추가 접근성 고려사항
622
-
623
- ```tsx
624
- <Checkbox
625
- label="마케팅 정보 수신 동의"
626
- aria-describedby="marketing-description"
627
- />
628
- <FormHelperText id="marketing-description">
629
- 새로운 제품이나 할인 정보를 이메일로 받아보실 수 있습니다.
630
- </FormHelperText>
631
- ```
632
-
633
- ## Performance Considerations
634
-
635
- 1. **상태 최적화**: 큰 목록에서는 상태 관리를 효율적으로 하세요.
362
+ Use `Set` instead of arrays for managing selection state in large lists:
636
363
 
637
364
  ```tsx
638
- // ✅ Set을 사용한 효율적인 선택 관리
365
+ // ✅ Good: O(1) lookup with Set
639
366
  const [selected, setSelected] = useState(new Set<number>());
640
367
 
641
- // ❌ 배열로 관리하는 비효율적 방법
368
+ // ❌ Bad: O(n) lookup with Array
642
369
  const [selected, setSelected] = useState<number[]>([]);
643
370
  ```
644
-
645
- 2. **메모이제이션**: 복잡한 핸들러는 useCallback으로 메모이제이션하세요.
646
-
647
- 3. **가상화**: 매우 긴 목록에서는 가상화를 고려하세요.
648
-
649
- Checkbox는 사용자가 다중 선택을 할 수 있는 직관적인 인터페이스를 제공하는 핵심 입력 컴포넌트입니다. 적절한 라벨링과 그룹화를 통해 명확하고 사용하기 쉬운 선택 인터페이스를 만들 수 있습니다.