Components
Popover
Non-modal 플로팅 패널. 짧은 맥락 설명, 간단한 설정, 보조 액션에 사용.
Mobile
모바일에서 Popover는 두 갈래로 분기된다:
- Inline Popover — 트리거 근처에 좁고 짧은 패널을 인라인으로 표시 (예: 색상 피커, 작은 메뉴,
FolderScreen상단+액션 메뉴). 트리거 기준으로 정렬, 화면을 가리지 않음. 데스크탑 Popover에 가장 가까운 형태. - BottomSheet 변환 — 패널 콘텐츠가 길거나(폼·리스트), 트리거 주변 공간이 부족하거나, 인터랙션이 모달성을 띠는 경우 BottomSheet로 승격. 컨테이너 anatomy(detents, grabber, swipe-to-dismiss, safe area)는 Dialog → Mobile Presentation 참조.
판단 기준: 화면 면적의 1/3 이상을 차지하거나 사용자 입력이 필요하면 BottomSheet로. 그렇지 않으면 Inline.
FolderScreen 상단 +처럼 trigger 주변에서 1–3개 짧은 액션을 선택하는 UI는 Dialog popup이 아니라 Inline Popover로 분류한다.
Preview
preview-mobile
preview-mobile
Inline Popover — FolderScreen create menu
Anatomy
Popover는 trigger 클릭으로 열리는 작은 floating 패널. Tooltip처럼 맥락 가까이에 붙지만, 텍스트 설명을 넘어 버튼·토글·짧은 입력 같은 인터랙션을 담을 수 있다. 순수 옵션 목록은 DropdownMenu/Select를 우선한다.
PopoverRoot
├─ PopoverTrigger (외부 element — Button·Chip 등)
└─ PopoverContent (floating 컨테이너)
├─ PopoverArrow (optional, trigger 방향 화살표)
├─ PopoverHeader (optional)
│ ├─ PopoverTitle (Text · label1Medium)
│ └─ PopoverClose (optional, Button ghost icon-only)
├─ PopoverBody (자유 콘텐츠)
└─ PopoverFooter (optional, Button 1~2개)슬롯 규칙
| Slot | Required | Primitive | 비고 |
|---|---|---|---|
| PopoverTrigger | always | (외부) | Trigger element는 popover 외부 — anatomy에는 reference만 |
| PopoverContent | always | — | bg-white, 1px solid stone-100/200, rounded-lg, shadow-md (Level 2) |
| PopoverArrow | optional | — | trigger 방향 8px 삼각, content와 동일 색·border |
| PopoverTitle | optional | Text | label1Medium, color stone-700 |
| PopoverClose | optional | Button (ghost icon-only, size='sm') | header 우측 끝, aria-label="닫기" |
| PopoverBody | always | (자유) | min-width 200px, max-width 360px. 설명, 컨트롤 그룹, 보조 액션 조합 가능 |
| PopoverFooter | optional | Button | 최대 2개, 가로 right-align |
Layout invariants
- max-width 360px — 콘텐츠 길어지면 Sheet 또는 Dialog로 승격
- PopoverArrow는 trigger 중심을 가리키도록 자동 위치 (Radix Popper 자동)
- Trigger 외 영역 클릭 시 close (
dismissOnOutsideClick=truedefault) - Esc로 close, focus는 trigger로 복귀
- Trigger가 disabled면 popover 열리지 않음
Token Mapping
| Token | Value (web) | Value (mobile) | Description |
|---|---|---|---|
| presentation | floating popover (트리거 근처) | Inline popover 또는 BottomSheet (콘텐츠 크기에 따라) | Popover Mobile 판단 기준 참조 |
| bg | #FFFFFF | #FFFFFF | |
| border | 1px solid stone-100/200 | inline: 동일 / BottomSheet: 없음 | |
| elevation | Level 2 (shadow-md) | inline: 동일 / BottomSheet: native sheet elevation | |
| radius | rounded-lg (8px) | inline: 동일 / BottomSheet: top corners r4 (16px) | |
| padding | 12–16px | 동일 (px-5 py-4 BottomSheet 본문) | |
| max-width | 320px | inline: 화면 폭에서 인셋 16pt / BottomSheet: 100vw | 모바일 inline은 트리거 폭 기준 정렬 |
| inner interactive row height | h-8 (32px) | ≥44pt (iOS HIG) — inline·BottomSheet 모두 | 옵션·메뉴 항목 높이 |
| title | label1Medium text-stone-700 | 동일 | |
| description | body2Regular text-stone-500 | 동일 | |
| control label | label1Medium text-stone-600 | 동일 | |
| section label | caption1Medium text-stone-400 | 동일 |
Inline Popover 실제 값 — FolderScreen create menu
| Token | Value |
|---|---|
| library | react-native-popup-menu |
| trigger | header right Plus icon button, 32×32 |
| popover width | 200 |
| popover radius | 10 |
| popover padding | 10 |
| popover border | 1px, stone-200 |
| popover background | DesignColors.semantic.surface |
| popover shadow | shadowOpacity: 0.08, shadowRadius: 8, elevation: 6 |
| popover offset | marginTop: 32 |
| item layout | flex-row items-center justify-between p-1 |
| item text | Typography.body1_16, stone-950 |
| item icon | FolderPlus size={20}, stone-950 |
Props
type PopoverProps = {
open?: boolean
onOpenChange?: (v: boolean) => void
side?: 'top' | 'right' | 'bottom' | 'left'
align?: 'start' | 'center' | 'end'
}Usage
<Popover>
<PopoverTrigger asChild>
<Button type="ghost" layout="icon-only" aria-label="보기 설정"><SettingsIcon /></Button>
</PopoverTrigger>
<PopoverContent>
<Text className="label1Medium text-stone-700">노트 보기 설정</Text>
<Text className="body2Regular text-stone-500">현재 노트에서만 표시 방식을 조정합니다.</Text>
</PopoverContent>
</Popover>A11y
- Non-modal — body 인터랙션 차단하지 않음
- Trigger의
aria-expanded자동 전달 - 키보드 탐색 가능
Do / Don't
- Do: 짧은 정보 표시, 간단한 컨트롤 그룹, 맥락 액션
- Do: 포털 렌더 — 부모 stacking context 탈출
- Don't: hover-only 설명에는
Tooltip사용 - Don't: 긴 폼 입력은
Dialog또는Sheet로 승격 - Don't: 옵션 목록만 있으면
DropdownMenu, 선택값이 남으면Select
