ContextMenu#
우클릭(데스크탑) 또는 길게 누르기(모바일 — Flutter)로 표시되는 상황별 메뉴 컴포넌트입니다. 자식 영역 안에서 우클릭하면 액션 목록이 포인터 위치에 떠 있는 패널로 나타납니다.
ContextMenu는 레거시 Flutter ContextMenu와 Web ContextMenu를 통일한
컴포넌트입니다. Flutter와 Web이 동일한 파라미터 이름·동작·시각을 갖습니다.
액션 항목은 통합 CoreMenuItem 모델을 씁니다 — 컨텍스트 메뉴와
드롭다운 메뉴는 동일한 액션 / 구분선 엔트리 의미를 공유합니다.
Live Preview#
class ContextMenuDefaultExample extends StatelessComponent {
const ContextMenuDefaultExample({super.key});
@override
Component build(BuildContext context) {
return ContextMenu(
items: [
CoreMenuItem.action('Copy', onPressed: () {}),
CoreMenuItem.action('Paste', onPressed: () {}),
const CoreMenuItem.divider(),
CoreMenuItem.action('Delete', onPressed: () {}),
],
child: div(
[Text('Right-click here').bodyMedium],
classes: 'border rounded-${CoreRadius.scale.radius8} '
'px-${CoreSpace.scale.space24} py-${CoreSpace.scale.space16}',
),
);
}
}
class ContextMenuDefaultExample extends StatelessWidget {
const ContextMenuDefaultExample({super.key});
@override
Widget build(BuildContext context) {
return ContextMenu(
items: [
CoreMenuItem.action('Copy', onPressed: () {}),
CoreMenuItem.action('Paste', onPressed: () {}),
const CoreMenuItem.divider(),
CoreMenuItem.action('Delete', onPressed: () {}),
],
child: DecoratedBox(
decoration: BoxDecoration(
border: Border.all(
color: context.theme.colorScheme.outline!.toValue(),
width: CoreStrokeWidth.stroke1,
),
borderRadius: BorderRadius.circular(CoreRadius.radius8),
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: CoreSpace.space24,
vertical: CoreSpace.space16,
),
child: Text('Right-click here').bodyMedium,
),
),
);
}
}
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- 우클릭으로 항목별 액션 메뉴를 제공할 때
- 파일 / 행 / 카드 등에 상황별 액션이 필요할 때
대신 다른 컴포넌트를 사용하세요:
DropdownMenu: 버튼 클릭으로 여는 드롭다운에Menubar: 데스크탑 앱 상단 가로 메뉴 바에
기본 사용법 (Basic Usage)#
ContextMenu(
items: [
CoreMenuItem.action('Copy', onPressed: () {}),
CoreMenuItem.action('Paste', onPressed: () {}),
const CoreMenuItem.divider(),
CoreMenuItem.action('Delete', onPressed: () {}),
],
child: const Text('Right-click here'),
)
ContextMenu(
items: [
CoreMenuItem.action('Copy', onPressed: () {}),
CoreMenuItem.action('Paste', onPressed: () {}),
const CoreMenuItem.divider(),
CoreMenuItem.action('Delete', onPressed: () {}),
],
child: div([text('Right-click here')]),
)
Props / Parameters#
ContextMenu#
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
child | W | 필수 | 우클릭 트리거 영역 |
items |
List<CoreMenuItem<W>> |
필수 |
컨텍스트 메뉴 패널의 행 —
Menu
/
DropdownMenu
/
Menubar
와 공유하는 통합 [CoreMenuItem] 모델
|
enabled |
bool |
true |
컨텍스트 메뉴 활성화 여부 |
popupStyle |
CorePopupStyle? |
null |
인스턴스별 패널 chrome 스타일 |
CoreMenuItem (컨텍스트 메뉴에서 쓰는 종류)#
컨텍스트 메뉴는 통합 CoreMenuItem 모델을 받는다. 주로 쓰는 두 종류:
| 생성자 | 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|---|
.action |
label (positional) |
String |
필수 | 액션 행 텍스트 |
.action |
shortcut |
String? |
null |
라벨 뒤에 표시되는 단축키 힌트 |
.action |
disabled |
bool |
false |
true 시 muted 처리 + onPressed 미호출 |
.action |
onPressed |
void Function()? |
null |
활성 액션 선택 시 호출 |
.divider | — | — | — | 그룹 사이 구분선 |
스타일 시스템 (Style System)#
ContextMenu의 메뉴 패널은 떠 있는 popup 표면이므로 CorePopupStyle
chrome 슬롯을 공유합니다 (Epic #1415 option D). 엔트리 행 chrome 은
CoreDropdownMenuStyle의 defaultEntryPadding / defaultEntryBorderRadius
/
defaultEntryHoverColor / defaultDividerColor /
defaultEntryDuration
디자인 시스템 기본값으로 고정됩니다.
Resolve chain#
CorePopupStyle.defaultX // 디자인 시스템 기본값
→ CorePopupTheme.style // 프로젝트 공통
→ widget.popupStyle // 인스턴스별
동작 스펙 (Behavior)#
인터랙션#
- 우클릭: 자식 영역 우클릭 시 포인터 위치에 메뉴 열림
- 길게 누르기: 모바일(Flutter) 에서 길게 누르면 메뉴 열림
- 항목 선택: 활성 항목 클릭 시
onPressed호출 후 닫힘 - 외부 클릭 / Escape: 메뉴 닫힘
애니메이션#
- 엔트리 hover 배경: 150ms 색상 전환 (
CoreDuration.ms150)
사용 가이드라인 (Usage Guidelines)#
✅ Do#
관련 액션을 구분선으로 그룹화
ContextMenu(
items: const [
CoreMenuItem.action('Cut'),
CoreMenuItem.action('Copy'),
CoreMenuItem.divider(),
CoreMenuItem.action('Delete'),
],
child: const Text('Item'),
)
❌ Don't#
유일한 진입점으로 컨텍스트 메뉴 사용
// ❌ 우클릭으로만 접근 가능한 핵심 액션
ContextMenu(
items: const [CoreMenuItem.action('Save')],
child: editor,
)
핵심 액션은 보이는 버튼으로도 제공해야 한다. 컨텍스트 메뉴는 보조 경로다.
접근성 (Accessibility)#
시맨틱 역할#
- 메뉴 패널:
role="menu" - 엔트리:
role="menuitem"(비활성 시aria-disabled) - 구분선:
role="separator"
키보드 인터랙션#
| 키 | 동작 |
|---|---|
Escape | 열린 메뉴 닫기 |
크로스 플랫폼 차이점 (Platform Differences)#
ContextMenu는 Flutter와 Web이 동일한 child / items / enabled
/
popupStyle API와 동작을 갖습니다. 메뉴 패널은 Flutter에서는
OverlayPortal, Web에서는 루트 OverlayHost의 menu 레이어로 portal되어
양쪽 모두 ancestor overflow에 잘리지 않습니다. Web은 우클릭
(contextmenu)으로, Flutter는 우클릭 + 모바일 길게 누르기로 메뉴를 엽니다.
관련 컴포넌트 (Related Components)#
- DropdownMenu: 버튼 클릭 드롭다운
- Menu: 사이드바 형태의 일반 메뉴
- Popup: 플로팅 패널 컨테이너