@ceed/ads 1.23.2 → 1.23.4
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/dist/components/data-display/Badge.md +71 -39
- package/dist/components/data-display/InfoSign.md +74 -98
- package/dist/components/data-display/Typography.md +310 -61
- package/dist/components/feedback/CircularProgress.md +257 -0
- package/dist/components/feedback/Dialog.md +8 -4
- package/dist/components/feedback/Modal.md +7 -3
- package/dist/components/feedback/Skeleton.md +280 -0
- package/dist/components/feedback/llms.txt +2 -0
- package/dist/components/inputs/ButtonGroup.md +115 -106
- package/dist/components/inputs/Calendar.md +98 -459
- package/dist/components/inputs/CurrencyInput.md +181 -8
- package/dist/components/inputs/DatePicker.md +108 -436
- package/dist/components/inputs/DateRangePicker.md +130 -496
- package/dist/components/inputs/FilterMenu.md +169 -19
- package/dist/components/inputs/FilterableCheckboxGroup.md +119 -24
- package/dist/components/inputs/FormControl.md +368 -0
- package/dist/components/inputs/IconButton.md +137 -88
- package/dist/components/inputs/MonthPicker.md +95 -427
- package/dist/components/inputs/MonthRangePicker.md +89 -471
- package/dist/components/inputs/PercentageInput.md +183 -19
- package/dist/components/inputs/RadioButton.md +163 -35
- package/dist/components/inputs/RadioList.md +241 -0
- package/dist/components/inputs/RadioTileGroup.md +146 -62
- package/dist/components/inputs/Select.md +219 -328
- package/dist/components/inputs/Slider.md +334 -0
- package/dist/components/inputs/Switch.md +136 -376
- package/dist/components/inputs/Textarea.md +209 -11
- package/dist/components/inputs/Uploader/Uploader.md +145 -66
- package/dist/components/inputs/llms.txt +3 -0
- package/dist/components/navigation/Breadcrumbs.md +80 -322
- package/dist/components/navigation/Dropdown.md +92 -221
- package/dist/components/navigation/IconMenuButton.md +40 -502
- package/dist/components/navigation/InsetDrawer.md +68 -738
- package/dist/components/navigation/Link.md +39 -298
- package/dist/components/navigation/Menu.md +92 -285
- package/dist/components/navigation/MenuButton.md +55 -448
- package/dist/components/navigation/Pagination.md +47 -338
- package/dist/components/navigation/ProfileMenu.md +45 -268
- package/dist/components/navigation/Stepper.md +160 -28
- package/dist/components/navigation/Tabs.md +57 -316
- package/dist/components/surfaces/Sheet.md +150 -333
- package/dist/guides/ThemeProvider.md +116 -0
- package/dist/guides/llms.txt +9 -0
- package/dist/llms.txt +8 -0
- package/package.json +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Dropdown
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Dropdown is the stateful container that orchestrates the open/close behavior of a menu system. It acts as the invisible glue between a trigger element (such as MenuButton or IconMenuButton) and the Menu that appears when activated. Dropdown itself renders no visible UI -- it provides context so that its children can coordinate with each other.
|
|
4
4
|
|
|
5
|
-
Dropdown
|
|
5
|
+
Dropdown is part of a **composition pattern** together with Menu, MenuItem, MenuButton, and IconMenuButton. While MenuButton and IconMenuButton are higher-level convenience components that bundle trigger + menu into a single prop-driven API, Dropdown gives you full control over the trigger element, menu content, and layout when you need custom compositions.
|
|
6
6
|
|
|
7
7
|
```tsx
|
|
8
8
|
<Dropdown>
|
|
@@ -24,27 +24,39 @@ Dropdown 컴포넌트는 메뉴나 옵션 목록을 표시하는 컨테이너
|
|
|
24
24
|
## Usage
|
|
25
25
|
|
|
26
26
|
```tsx
|
|
27
|
-
import { Dropdown,
|
|
27
|
+
import { Dropdown, Menu, MenuItem } from '@ceed/ads';
|
|
28
|
+
import { MenuButton } from '@ceed/ads';
|
|
28
29
|
|
|
29
30
|
function MyComponent() {
|
|
30
31
|
return (
|
|
31
32
|
<Dropdown>
|
|
32
|
-
<MenuButton
|
|
33
|
+
<MenuButton>Open Menu</MenuButton>
|
|
33
34
|
<Menu>
|
|
34
|
-
<MenuItem
|
|
35
|
-
<MenuItem
|
|
36
|
-
<MenuItem
|
|
35
|
+
<MenuItem>Option 1</MenuItem>
|
|
36
|
+
<MenuItem>Option 2</MenuItem>
|
|
37
|
+
<MenuItem>Option 3</MenuItem>
|
|
37
38
|
</Menu>
|
|
38
39
|
</Dropdown>
|
|
39
40
|
);
|
|
40
41
|
}
|
|
41
42
|
```
|
|
42
43
|
|
|
43
|
-
##
|
|
44
|
+
## Composition Pattern
|
|
45
|
+
|
|
46
|
+
Dropdown, Menu, MenuItem, MenuButton, and IconMenuButton form a **menu component family**. Choose the right level of abstraction for your use case:
|
|
47
|
+
|
|
48
|
+
| Approach | When to use |
|
|
49
|
+
| ------------------------------------ | ------------------------------------------------------- |
|
|
50
|
+
| `MenuButton` (standalone) | Simple text-triggered menus with a list of items |
|
|
51
|
+
| `IconMenuButton` (standalone) | Icon-only triggers in space-constrained areas |
|
|
52
|
+
| `Dropdown` + `MenuButton` + `Menu` | Custom menu content (headers, dividers, mixed elements) |
|
|
53
|
+
| `Dropdown` + custom trigger + `Menu` | Fully custom trigger elements |
|
|
54
|
+
|
|
55
|
+
## Features
|
|
44
56
|
|
|
45
57
|
### Basic Dropdown
|
|
46
58
|
|
|
47
|
-
|
|
59
|
+
The simplest Dropdown pairs a MenuButton trigger with a Menu of items.
|
|
48
60
|
|
|
49
61
|
```tsx
|
|
50
62
|
<Stack direction="row" spacing={2}>
|
|
@@ -72,7 +84,7 @@ function MyComponent() {
|
|
|
72
84
|
|
|
73
85
|
### Button Variants
|
|
74
86
|
|
|
75
|
-
MenuButton
|
|
87
|
+
MenuButton supports `plain`, `outlined`, `soft`, and `solid` variants to match your design context.
|
|
76
88
|
|
|
77
89
|
```tsx
|
|
78
90
|
<Stack direction="row" spacing={2} flexWrap="wrap">
|
|
@@ -112,7 +124,7 @@ MenuButton의 다양한 스타일 변형을 사용할 수 있습니다.
|
|
|
112
124
|
|
|
113
125
|
### Button Colors
|
|
114
126
|
|
|
115
|
-
|
|
127
|
+
Apply semantic colors to the trigger button for different emphasis levels.
|
|
116
128
|
|
|
117
129
|
```tsx
|
|
118
130
|
<Stack direction="row" spacing={2} flexWrap="wrap">
|
|
@@ -170,7 +182,7 @@ MenuButton에 다양한 색상을 적용할 수 있습니다.
|
|
|
170
182
|
|
|
171
183
|
### Menu Placements
|
|
172
184
|
|
|
173
|
-
|
|
185
|
+
Control where the menu appears relative to the trigger using the `placement` prop on Menu.
|
|
174
186
|
|
|
175
187
|
```tsx
|
|
176
188
|
<Stack direction="row" spacing={2} sx={{
|
|
@@ -216,7 +228,7 @@ MenuButton에 다양한 색상을 적용할 수 있습니다.
|
|
|
216
228
|
|
|
217
229
|
### With Icons
|
|
218
230
|
|
|
219
|
-
|
|
231
|
+
Add icons to menu items and decorators to the trigger button for richer visual communication.
|
|
220
232
|
|
|
221
233
|
```tsx
|
|
222
234
|
<Dropdown>
|
|
@@ -249,7 +261,7 @@ MenuButton에 다양한 색상을 적용할 수 있습니다.
|
|
|
249
261
|
|
|
250
262
|
### Actions Menu
|
|
251
263
|
|
|
252
|
-
|
|
264
|
+
Build action menus for edit, delete, and other operations. Use `color="danger"` on destructive items.
|
|
253
265
|
|
|
254
266
|
```tsx
|
|
255
267
|
<Dropdown>
|
|
@@ -280,7 +292,7 @@ MenuButton에 다양한 색상을 적용할 수 있습니다.
|
|
|
280
292
|
|
|
281
293
|
### Filter Menu
|
|
282
294
|
|
|
283
|
-
|
|
295
|
+
Use Dropdown as an interactive filter selector with state management.
|
|
284
296
|
|
|
285
297
|
```tsx
|
|
286
298
|
<Dropdown>
|
|
@@ -298,7 +310,7 @@ MenuButton에 다양한 색상을 적용할 수 있습니다.
|
|
|
298
310
|
|
|
299
311
|
### Profile Dropdown
|
|
300
312
|
|
|
301
|
-
|
|
313
|
+
Combine custom content (user info header) with standard menu items for profile menus.
|
|
302
314
|
|
|
303
315
|
```tsx
|
|
304
316
|
<Dropdown>
|
|
@@ -350,7 +362,7 @@ MenuButton에 다양한 색상을 적용할 수 있습니다.
|
|
|
350
362
|
|
|
351
363
|
### Nested Menus
|
|
352
364
|
|
|
353
|
-
|
|
365
|
+
Place multiple Dropdown instances side by side to create menu bar patterns.
|
|
354
366
|
|
|
355
367
|
```tsx
|
|
356
368
|
<Stack direction="row" spacing={3}>
|
|
@@ -391,7 +403,7 @@ MenuButton에 다양한 색상을 적용할 수 있습니다.
|
|
|
391
403
|
|
|
392
404
|
### Controlled Dropdown
|
|
393
405
|
|
|
394
|
-
|
|
406
|
+
Use the `open` and `onOpenChange` props to programmatically control the menu state.
|
|
395
407
|
|
|
396
408
|
```tsx
|
|
397
409
|
<Stack spacing={2}>
|
|
@@ -416,7 +428,7 @@ MenuButton에 다양한 색상을 적용할 수 있습니다.
|
|
|
416
428
|
|
|
417
429
|
### Disabled State
|
|
418
430
|
|
|
419
|
-
|
|
431
|
+
Disable the entire trigger button or individual menu items.
|
|
420
432
|
|
|
421
433
|
```tsx
|
|
422
434
|
<Stack direction="row" spacing={2}>
|
|
@@ -440,7 +452,7 @@ MenuButton에 다양한 색상을 적용할 수 있습니다.
|
|
|
440
452
|
|
|
441
453
|
### Long Menu
|
|
442
454
|
|
|
443
|
-
|
|
455
|
+
Apply `maxHeight` and `overflow: 'auto'` to Menu for scrollable lists with many items.
|
|
444
456
|
|
|
445
457
|
```tsx
|
|
446
458
|
<Dropdown>
|
|
@@ -460,7 +472,7 @@ MenuButton에 다양한 색상을 적용할 수 있습니다.
|
|
|
460
472
|
|
|
461
473
|
### Custom Styling
|
|
462
474
|
|
|
463
|
-
|
|
475
|
+
Customize borders, shadows, border-radius, and gradients through the `sx` prop.
|
|
464
476
|
|
|
465
477
|
```tsx
|
|
466
478
|
<Stack direction="row" spacing={2}>
|
|
@@ -515,89 +527,27 @@ CSS 스타일을 이용해 드롭다운을 커스터마이징할 수 있습니
|
|
|
515
527
|
</Stack>
|
|
516
528
|
```
|
|
517
529
|
|
|
518
|
-
## Component Structure
|
|
519
|
-
|
|
520
|
-
Dropdown은 다음 컴포넌트들과 함께 사용됩니다:
|
|
521
|
-
|
|
522
|
-
```tsx
|
|
523
|
-
<Dropdown>
|
|
524
|
-
<MenuButton>트리거 버튼</MenuButton>
|
|
525
|
-
<Menu>
|
|
526
|
-
<MenuItem>메뉴 아이템 1</MenuItem>
|
|
527
|
-
<MenuItem>메뉴 아이템 2</MenuItem>
|
|
528
|
-
<ListDivider /> {/* 구분선 */}
|
|
529
|
-
<MenuItem>메뉴 아이템 3</MenuItem>
|
|
530
|
-
</Menu>
|
|
531
|
-
</Dropdown>
|
|
532
|
-
```
|
|
533
|
-
|
|
534
|
-
### MenuButton Props
|
|
535
|
-
|
|
536
|
-
MenuButton 컴포넌트의 주요 props:
|
|
537
|
-
|
|
538
|
-
- `variant`: `'plain' | 'outlined' | 'soft' | 'solid'`
|
|
539
|
-
- `color`: `'primary' | 'neutral' | 'danger' | 'success' | 'warning'`
|
|
540
|
-
- `size`: `'sm' | 'md' | 'lg'`
|
|
541
|
-
- `startDecorator`: 앞쪽에 표시할 요소
|
|
542
|
-
- `endDecorator`: 뒤쪽에 표시할 요소
|
|
543
|
-
- `disabled`: 비활성 상태
|
|
544
|
-
|
|
545
|
-
### Menu Props
|
|
546
|
-
|
|
547
|
-
Menu 컴포넌트의 주요 props:
|
|
548
|
-
|
|
549
|
-
- `placement`: `'top-start' | 'top' | 'top-end' | 'bottom-start' | 'bottom' | 'bottom-end'`
|
|
550
|
-
- `size`: `'sm' | 'md' | 'lg'`
|
|
551
|
-
- `sx`: 스타일 커스터마이징
|
|
552
|
-
|
|
553
530
|
## Common Use Cases
|
|
554
531
|
|
|
555
532
|
### Navigation Menu
|
|
556
533
|
|
|
557
534
|
```tsx
|
|
558
535
|
<Dropdown>
|
|
559
|
-
<MenuButton variant="plain"
|
|
536
|
+
<MenuButton variant="plain">Menu</MenuButton>
|
|
560
537
|
<Menu>
|
|
561
|
-
<MenuItem component="a" href="/home"
|
|
562
|
-
<MenuItem component="a" href="/about"
|
|
563
|
-
<MenuItem component="a" href="/products"
|
|
538
|
+
<MenuItem component="a" href="/home">Home</MenuItem>
|
|
539
|
+
<MenuItem component="a" href="/about">About</MenuItem>
|
|
540
|
+
<MenuItem component="a" href="/products">Products</MenuItem>
|
|
564
541
|
<ListDivider />
|
|
565
|
-
<MenuItem component="a" href="/contact"
|
|
542
|
+
<MenuItem component="a" href="/contact">Contact</MenuItem>
|
|
566
543
|
</Menu>
|
|
567
544
|
</Dropdown>
|
|
568
545
|
```
|
|
569
546
|
|
|
570
|
-
###
|
|
547
|
+
### Filter Selector
|
|
571
548
|
|
|
572
549
|
```tsx
|
|
573
|
-
|
|
574
|
-
<MenuButton
|
|
575
|
-
variant="plain"
|
|
576
|
-
startDecorator={<Avatar size="sm" />}
|
|
577
|
-
endDecorator={<ExpandMoreIcon />}
|
|
578
|
-
>
|
|
579
|
-
사용자명
|
|
580
|
-
</MenuButton>
|
|
581
|
-
<Menu>
|
|
582
|
-
<Stack px={2} py={1}>
|
|
583
|
-
<Typography level="title-sm">사용자명</Typography>
|
|
584
|
-
<Typography level="body-xs" color="neutral">
|
|
585
|
-
user@example.com
|
|
586
|
-
</Typography>
|
|
587
|
-
</Stack>
|
|
588
|
-
<ListDivider />
|
|
589
|
-
<MenuItem>프로필</MenuItem>
|
|
590
|
-
<MenuItem>설정</MenuItem>
|
|
591
|
-
<ListDivider />
|
|
592
|
-
<MenuItem>로그아웃</MenuItem>
|
|
593
|
-
</Menu>
|
|
594
|
-
</Dropdown>
|
|
595
|
-
```
|
|
596
|
-
|
|
597
|
-
### Filter Dropdown
|
|
598
|
-
|
|
599
|
-
```tsx
|
|
600
|
-
const [filter, setFilter] = useState('전체');
|
|
550
|
+
const [filter, setFilter] = useState('All');
|
|
601
551
|
|
|
602
552
|
<Dropdown>
|
|
603
553
|
<MenuButton
|
|
@@ -605,164 +555,85 @@ const [filter, setFilter] = useState('전체');
|
|
|
605
555
|
startDecorator={<FilterListIcon />}
|
|
606
556
|
endDecorator={<ExpandMoreIcon />}
|
|
607
557
|
>
|
|
608
|
-
|
|
609
|
-
</MenuButton>
|
|
610
|
-
<Menu>
|
|
611
|
-
<MenuItem onClick={() => setFilter('전체')}>전체</MenuItem>
|
|
612
|
-
<MenuItem onClick={() => setFilter('활성')}>활성</MenuItem>
|
|
613
|
-
<MenuItem onClick={() => setFilter('비활성')}>비활성</MenuItem>
|
|
614
|
-
</Menu>
|
|
615
|
-
</Dropdown>
|
|
616
|
-
```
|
|
617
|
-
|
|
618
|
-
### Action Menu
|
|
619
|
-
|
|
620
|
-
```tsx
|
|
621
|
-
<Dropdown>
|
|
622
|
-
<MenuButton variant="plain" size="sm">
|
|
623
|
-
작업
|
|
558
|
+
Filter: {filter}
|
|
624
559
|
</MenuButton>
|
|
625
560
|
<Menu>
|
|
626
|
-
<MenuItem>
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
</MenuItem>
|
|
630
|
-
<MenuItem>
|
|
631
|
-
<CopyIcon sx={{ mr: 1 }} />
|
|
632
|
-
복사
|
|
633
|
-
</MenuItem>
|
|
634
|
-
<MenuItem color="danger">
|
|
635
|
-
<DeleteIcon sx={{ mr: 1 }} />
|
|
636
|
-
삭제
|
|
637
|
-
</MenuItem>
|
|
561
|
+
<MenuItem onClick={() => setFilter('All')}>All</MenuItem>
|
|
562
|
+
<MenuItem onClick={() => setFilter('Active')}>Active</MenuItem>
|
|
563
|
+
<MenuItem onClick={() => setFilter('Inactive')}>Inactive</MenuItem>
|
|
638
564
|
</Menu>
|
|
639
565
|
</Dropdown>
|
|
640
566
|
```
|
|
641
567
|
|
|
642
|
-
###
|
|
568
|
+
### Controlled State with External Toggle
|
|
643
569
|
|
|
644
570
|
```tsx
|
|
645
|
-
const [
|
|
571
|
+
const [open, setOpen] = useState(false);
|
|
646
572
|
|
|
647
|
-
<Dropdown>
|
|
648
|
-
<MenuButton
|
|
649
|
-
{language}
|
|
650
|
-
</MenuButton>
|
|
573
|
+
<Dropdown open={open} onOpenChange={(event, isOpen) => setOpen(isOpen)}>
|
|
574
|
+
<MenuButton>Controlled Menu</MenuButton>
|
|
651
575
|
<Menu>
|
|
652
|
-
<MenuItem onClick={() =>
|
|
653
|
-
|
|
654
|
-
</MenuItem>
|
|
655
|
-
<MenuItem onClick={() => setLanguage('English')}>
|
|
656
|
-
English
|
|
657
|
-
</MenuItem>
|
|
658
|
-
<MenuItem onClick={() => setLanguage('日本語')}>
|
|
659
|
-
日本語
|
|
660
|
-
</MenuItem>
|
|
576
|
+
<MenuItem onClick={() => setOpen(false)}>Option A</MenuItem>
|
|
577
|
+
<MenuItem onClick={() => setOpen(false)}>Option B</MenuItem>
|
|
661
578
|
</Menu>
|
|
662
579
|
</Dropdown>
|
|
663
|
-
```
|
|
664
|
-
|
|
665
|
-
### Sort Options
|
|
666
580
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
<Dropdown>
|
|
671
|
-
<MenuButton
|
|
672
|
-
variant="outlined"
|
|
673
|
-
startDecorator={<SortIcon />}
|
|
674
|
-
endDecorator={<ExpandMoreIcon />}
|
|
675
|
-
>
|
|
676
|
-
정렬: {sortBy}
|
|
677
|
-
</MenuButton>
|
|
678
|
-
<Menu>
|
|
679
|
-
<MenuItem onClick={() => setSortBy('이름순')}>이름순</MenuItem>
|
|
680
|
-
<MenuItem onClick={() => setSortBy('날짜순')}>날짜순</MenuItem>
|
|
681
|
-
<MenuItem onClick={() => setSortBy('크기순')}>크기순</MenuItem>
|
|
682
|
-
</Menu>
|
|
683
|
-
</Dropdown>
|
|
581
|
+
<Button onClick={() => setOpen(!open)}>
|
|
582
|
+
{open ? 'Close' : 'Open'} Menu
|
|
583
|
+
</Button>
|
|
684
584
|
```
|
|
685
585
|
|
|
686
586
|
## Best Practices
|
|
687
587
|
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
2. **적절한 아이콘 사용**: 드롭다운임을 나타내는 화살표 아이콘을 사용하세요.
|
|
691
|
-
```tsx
|
|
692
|
-
<MenuButton endDecorator={<ExpandMoreIcon />}>
|
|
693
|
-
```
|
|
694
|
-
|
|
695
|
-
3. **메뉴 아이템 그룹화**: 관련된 메뉴 아이템들은 ListDivider로 구분하세요.
|
|
696
|
-
|
|
697
|
-
4. **키보드 접근성**: 키보드 탐색이 가능하도록 적절한 props를 설정하세요.
|
|
698
|
-
|
|
699
|
-
5. **적절한 배치**: 화면 공간을 고려하여 메뉴의 placement를 설정하세요.
|
|
700
|
-
|
|
701
|
-
6. **로딩 상태**: 필요한 경우 MenuButton에 loading 상태를 표시하세요.
|
|
702
|
-
|
|
703
|
-
7. **일관된 스타일**: 애플리케이션 전반에서 일관된 드롭다운 스타일을 유지하세요.
|
|
704
|
-
|
|
705
|
-
8. **모바일 고려**: 모바일에서도 사용하기 쉽도록 충분한 터치 영역을 확보하세요.
|
|
588
|
+
- **Use the right abstraction level.** If you only need a simple list of text items, prefer `MenuButton` or `IconMenuButton` standalone components. Use `Dropdown` + `Menu` when you need dividers, custom headers, or mixed content inside the menu.
|
|
706
589
|
|
|
707
|
-
|
|
590
|
+
```tsx
|
|
591
|
+
{/* ✅ Good: Simple list -- use MenuButton directly */}
|
|
592
|
+
<MenuButton buttonText="Actions" items={[{ text: 'Edit' }, { text: 'Delete' }]} />
|
|
708
593
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
<
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
</
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
594
|
+
{/* ✅ Good: Complex content -- use Dropdown composition */}
|
|
595
|
+
<Dropdown>
|
|
596
|
+
<MenuButton>User</MenuButton>
|
|
597
|
+
<Menu>
|
|
598
|
+
<Box sx={{ px: 2, py: 1 }}>
|
|
599
|
+
<Typography level="title-sm">User Name</Typography>
|
|
600
|
+
</Box>
|
|
601
|
+
<ListDivider />
|
|
602
|
+
<MenuItem>Settings</MenuItem>
|
|
603
|
+
<MenuItem>Logout</MenuItem>
|
|
604
|
+
</Menu>
|
|
605
|
+
</Dropdown>
|
|
606
|
+
```
|
|
721
607
|
|
|
722
|
-
|
|
723
|
-
const [open, setOpen] = useState(false);
|
|
608
|
+
- **Group related items with ListDivider.** Visually separate logical groups of menu items so users can scan options quickly.
|
|
724
609
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
onOpenChange={(event, isOpen) => setOpen(isOpen)}
|
|
728
|
-
>
|
|
729
|
-
<MenuButton>메뉴</MenuButton>
|
|
610
|
+
```tsx
|
|
611
|
+
{/* ✅ Good: Grouped by function */}
|
|
730
612
|
<Menu>
|
|
731
|
-
<MenuItem
|
|
613
|
+
<MenuItem>Edit</MenuItem>
|
|
614
|
+
<MenuItem>Duplicate</MenuItem>
|
|
615
|
+
<ListDivider />
|
|
616
|
+
<MenuItem color="danger">Delete</MenuItem>
|
|
732
617
|
</Menu>
|
|
733
|
-
|
|
734
|
-
```
|
|
618
|
+
```
|
|
735
619
|
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
Dropdown은 접근성을 위한 기본적인 기능들을 제공합니다:
|
|
739
|
-
|
|
740
|
-
- **키보드 탐색**: Tab, Enter, Escape, 화살표 키 지원
|
|
741
|
-
- **ARIA 속성**: 적절한 ARIA 라벨과 역할 자동 설정
|
|
742
|
-
- **포커스 관리**: 메뉴가 열릴 때 첫 번째 아이템으로 포커스 이동
|
|
743
|
-
- **스크린 리더**: 메뉴의 상태와 옵션들을 적절히 읽어줌
|
|
620
|
+
- **Indicate dropdown affordance.** Use `endDecorator={<ExpandMoreIcon />}` on the trigger button so users understand it opens a menu.
|
|
744
621
|
|
|
745
|
-
|
|
622
|
+
```tsx
|
|
623
|
+
{/* ✅ Good: Clear dropdown indicator */}
|
|
624
|
+
<MenuButton endDecorator={<ExpandMoreIcon />}>Options</MenuButton>
|
|
746
625
|
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
626
|
+
{/* ❌ Avoid: No visual hint that a menu will appear */}
|
|
627
|
+
<MenuButton>Options</MenuButton>
|
|
628
|
+
```
|
|
750
629
|
|
|
751
|
-
|
|
630
|
+
- **Keep menu item count reasonable.** Aim for 3-7 items. For longer lists, apply `maxHeight` with scrolling or consider a different UI pattern like a dialog or searchable list.
|
|
752
631
|
|
|
753
|
-
|
|
632
|
+
- **Use controlled mode sparingly.** Uncontrolled mode (no `open` prop) handles most scenarios. Only use controlled mode when external events need to open or close the menu.
|
|
754
633
|
|
|
755
|
-
|
|
756
|
-
- **필터링**: 여러 옵션 중 하나를 선택하는 필터가 필요할 때
|
|
757
|
-
- **액션 목록**: 특정 항목에 대한 여러 작업이 있을 때
|
|
758
|
-
- **사용자 메뉴**: 프로필, 설정, 로그아웃 등의 사용자 관련 기능
|
|
759
|
-
- **공간 절약**: 화면 공간이 제한적일 때 여러 옵션을 숨기고 싶을 때
|
|
760
|
-
|
|
761
|
-
### ❌ 사용하지 않는 것이 좋은 경우
|
|
762
|
-
|
|
763
|
-
- **단일 액션**: 하나의 간단한 작업만 있을 때는 일반 Button 사용
|
|
764
|
-
- **긴 폼**: 폼에서는 Select 컴포넌트가 더 적절
|
|
765
|
-
- **항상 보여야 하는 옵션**: 중요한 옵션들은 항상 표시하는 것이 좋음
|
|
766
|
-
- **너무 많은 옵션**: 20개 이상의 옵션이 있다면 다른 UI 패턴 고려
|
|
634
|
+
## Accessibility
|
|
767
635
|
|
|
768
|
-
|
|
636
|
+
- **Keyboard navigation**: Tab focuses the trigger button. Enter or Space opens the menu. Arrow keys navigate between items. Escape closes the menu and returns focus to the trigger.
|
|
637
|
+
- **ARIA attributes**: Dropdown automatically sets `aria-haspopup`, `aria-expanded`, `role="menu"`, and `role="menuitem"` on the appropriate elements.
|
|
638
|
+
- **Focus management**: When the menu opens, focus moves to the first menu item. When the menu closes, focus returns to the trigger button.
|
|
639
|
+
- **Color is not the only indicator**: When using `color="danger"` on destructive items, pair it with a clear text label (e.g., "Delete") so the meaning is not conveyed by color alone.
|