Files

131 lines
6.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Popover
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6, §7), Token 구조 원칙은 `테마-토큰-가이드.md`를 따른다. 이 문서는 Popover 고유의 API·Token·상태·결정만 기록한다.
## 1. 상태
| 항목 | 내용 |
|---|---|
| 구현 상태 | 구현 완료 (현재 HM 규격) |
| 기준일 | 2026-10-02 |
| 기반 | shadcn/ui Popover (Radix `Popover`) |
| 대표 Story | `Components/Overlay/Popover` → `All` (이름 "Popover") |
| 보류 | 아래 §11 |
## 2. 적용 근거
- **참고 근거**: 외부 ui_viz Reference (ZIP 미포함)의 기존 테스트 규격에는 Popover 규격이 없다(인벤토리 "상세 디자인·API 보류"). 같은 floating surface인 Dialog의 윤곽 의도만 참고했다.
- **현재 HM 규격**: 아래 §3~§4. 현재 HM Semantic 체계로 새로 정했다.
- **구현 방식**: shadcn / Radix Popover 구조를 유지하고 theme CSS로 HM 스타일을 연결. Popover는 일반 floating panel이며 modal이 아니다(overlay·focus trap 없음).
- **보류**: §11.
## 3. 기본 규격 (현재 HM 규격)
| 항목 | 값 |
|---|---|
| Surface | `--hm-sem-bg-surface` |
| 전경 | `--hm-sem-fg-primary` |
| Border | 1px `--hm-sem-floating-border-color` |
| Radius | `--hm-radius-container` (4px) |
| Shadow | `0 0 12px rgb(0 0 0 / .2)` |
| Padding | 16px |
| Width | 288px (viewport − 16px 이하로 제한) |
| Typography | 14 / 20 / 400 |
| Position | `sideOffset` 4, `align` center (기본) |
## 4. 상태 규격
| 상태 | 값 |
|---|---|
| Open / Closed | Radix `data-state`, shadcn open/close animation |
| Focus | 열릴 때 Radix가 content 안 첫 focus 가능 요소로 이동, 닫힐 때 trigger로 복귀(Escape/Close) |
| 바깥 클릭 | 닫힘. focus는 클릭한 곳에 둔다 |
## 5. API
Radix Popover props 그대로. export: `Popover`, `PopoverTrigger`, `PopoverContent`, `PopoverAnchor`, `PopoverClose`.
- `PopoverContent`: `align` 기본 `center`, `sideOffset` 기본 4.
- `PopoverClose`: `asChild`일 때 자식의 `data-slot`을 유지(DialogClose와 같은 규칙, Button HM 스타일 보존).
- 출력 속성: `data-slot="popover-*"`, Radix `data-state`·`data-side`·`data-align`.
### 접근성 이름
`PopoverContent`는 `role="dialog"`로 출력된다. 소비자는 패널의 목적을 나타내는 접근성 이름을 `aria-label` 또는 `aria-labelledby`로 지정한다. Trigger의 텍스트는 패널 이름으로 자동 연결되지 않는다.
```tsx
<PopoverContent aria-label="프로젝트 이름 변경">
{/* 입력 폼 */}
</PopoverContent>
```
보이는 제목이 있다면 해당 제목의 고유 ID를 연결한다. 같은 화면에서 반복되는 패널은 `React.useId()` 등으로 서로 다른 ID를 생성한다.
```tsx
const titleId = React.useId()
<PopoverContent aria-labelledby={titleId}>
<h2 id={titleId}>프로젝트 안내</h2>
<p>일정과 담당자 정보를 확인합니다.</p>
</PopoverContent>
```
대표 Story는 정보·폼·정렬 예제 각각에 `aria-label`을 제공한다. 이름 지정은 기존 레이아웃과 Radix의 focus 이동·Escape·닫힘 동작을 바꾸지 않는다.
## 6. Token
Component Mapping 위치: `packages/ui/src/theme/popover.css` (`--hm-popover-*`).
`background`, `text`, `border-width`, `border-color`, `radius`, `shadow`, `padding`, `width`, `font-size`, `line-height`, `font-weight`. 다른 컴포넌트의 Component Token을 참조하지 않는다. 신규 Primitive 없음.
## 7. shadcn / Radix에서 유지한 항목
Radix 구조·ARIA(`role=dialog`, `aria-expanded`, `aria-controls`)·Escape·바깥 클릭 닫힘·focus 이동/복귀, Portal·positioning·collision, `data-slot`, `cn(..., className)`, animation class, `z-50`.
## 8. HM에서 변경한 항목
- shadcn `w-72 rounded-md border p-4 shadow-md bg-popover text-popover-foreground` 등 시각 class 제거 → theme CSS.
- `PopoverClose` 추가 export (shadcn 기본 export에 없는 Radix `Close`).
## 9. Storybook
- 대표 Story `All`("Popover"): 정보 패널, 폼 패널(Input + 취소/저장 `PopoverClose`), `align` start/center/end 비교.
- verification: `Open`(열린 상태).
## 10. 사용자 확정 결정
- 2026-10-02: ui-viz는 참고 자료이며 최종 기준은 현재 HM 구현과 이 문서다(작업 지시). 개별 수치에 대한 별도 결정은 없다.
## 11. 미확정 / 보류
- 수치(288px, 16px padding, 그림자)는 현재 HM 규격이며 디자인 확정 시 재검토.
- arrow 없음(shadcn 기본에 없음).
- 크기 variant 없음. 폭은 `className`으로 확장.
- Motion 규칙은 정의되지 않아 shadcn 기본 animation 유지.
## 12. 관련 파일
```
packages/ui/src/components/ui/popover.tsx
packages/ui/src/theme/popover.css
packages/ui/src/theme.css (import)
packages/ui/src/index.ts (export)
src/components/popover.stories.tsx
```
## 13. 검증 상태
- 2026-10-08: 대표 Story의 정보·폼·정렬 3종, 총 5개 `role="dialog"` 접근성 이름을 확인했다. 키보드 Enter·Tab·Escape, 폼 자동 focus, 취소/저장 `PopoverClose`의 닫힘·trigger focus 복귀, 바깥 클릭 닫힘을 Browser에서 확인했다. 공개 API 타입 검사 통과, 최종 검증 Console 오류 없음.
- `npm run typecheck`, `npm run build`: 통과(2026-10-02).
- 실제 interaction(Browser pane): 클릭 열기(focus가 content 안 Input으로 이동), Escape 닫힘과 trigger focus 복귀, 바깥 클릭 닫힘.
- computed style: width 288px, white, border `rgb(222,219,210)` 1px, radius 4px, padding 16px, shadow `0 0 12px .2`.
- 미확인: 좁은 viewport collision 시각.
## 14. Floating 계열 공통 (Semantic 승격 완료)
Dropdown Menu·Popover·Hover Card는 surface(White, 1px pale border, 4px radius, `0 0 12px .2` 그림자)가 같다. 의미(떠 있는 패널의 면·윤곽·그림자)도 같아 공통 Semantic 후보는 아래이며, `default.css`의 `--hm-sem-floating-*`로 승격했고 각 컴포넌트의 `--hm-<component>-*`가 이를 참조한다(Component Token은 유지). Dialog(Dialog 전용 값), Tooltip(dark inverse face)은 같은 면이 아니다.
- Floating background / border / shadow / radius
Popover만 다르게 하려면 `--hm-popover-*`만 override한다. Date Picker·Combobox popup은 Popover를 그대로 쓰므로 이 값을 따른다.