Files
HMDesign/docs/components/drawer.md
T

7.2 KiB
Raw Blame History

Drawer

2026-10-10 추가 수정 요청 기준: 데스크톱 하단 우측 가로 취소 → 실행, 640px 이하 전체 폭 세로 실행 위 / 취소 아래. DOM은 취소 → 실행 순서이며 모바일 CSS column-reverse 적용. vaul 드래그 닫기 유지. 과거 검증 기록은 당시 결과이며 현재 검증은 추가 수정 보고서를 따릅니다.

현재 HM 구현의 기준 문서. 공통 원칙은 docs/guidelines/프로젝트-지침.md(§6, §7), Token 구조 원칙은 테마-토큰-가이드.md를 따른다. 이 문서는 Drawer 고유의 API·Token·상태·결정만 기록한다. Dialog·Sheet와 값을 공유하지 않는다.

1. 상태

항목 내용
구현 상태 구현 완료 (현재 HM 규격)
기준일 2026-10-02
기반 shadcn/ui Drawer = vaul (vaul@1.1.2, 이번에 @hm-design/ui dependency로 추가) + Radix Dialog
대표 Story Components/Overlay/Drawer → All (이름 "Drawer")
보류 아래 §11

2. 적용 근거

  • 참고 근거: 외부 ui_viz Reference (ZIP 미포함)의 기존 테스트 규격에는 Drawer가 없다. 참고할 수치가 없었다.
  • 현재 HM 규격: 아래 §3~§4. Dialog의 접근성 원칙과 asChild 처리 규칙은 재사용하고 수치는 현재 HM Semantic으로 새로 정했다.
  • 구현 방식: shadcn Drawer 구조(vaul)를 유지하고 theme CSS로 HM 스타일 연결. drag·snap·dismiss는 vaul 기본이며 재구현하지 않았다.
  • vaul 추가 이유: shadcn 공식 Drawer가 vaul 기반이다(Radix에 Drawer가 없음). 프로젝트에 없던 dependency라서 추가했다(npm install vaul --workspace @hm-design/ui).
  • Sheet와의 역할 구분: Drawer = 손가락/포인터로 끌어 닫는 하단 중심 임시 panel(handle 포함), Sheet = 버튼으로 닫는 edge panel.

3. 기본 규격 (현재 HM 규격)

항목 값
Surface / 전경 --hm-sem-bg-surface / --hm-sem-fg-primary
Border 1px --hm-sem-stroke-input-default, 화면을 향한 한 변
Radius 8px, 화면 안쪽 두 모서리(bottom이면 위 두 모서리)
Shadow 0 0 12px rgb(0 0 0 / .2)
bottom / top 폭 100%, 높이 내용 기준, 최대 85dvh
left / right 폭 min(400px, 100vw − 48px), 높이 100%
Handle(bottom만) 48 × 4px 알약, --hm-sem-stroke-default, 위 12px
Padding 24px
Header padding 24 24 16, gap 8px
Title 18 / 28 / 700
Description 14 / 20 / 400, --hm-sem-fg-secondary
Body 14 / 20 / 400, 좌우 padding 24px, 유일한 scroll 영역
Footer padding 16 24 24, gap 8px. 데스크톱 우측 가로 취소 → 실행, 640px 이하 전체 폭 세로 실행 → 취소
Close(X) 없음(handle drag, Overlay 클릭, Escape, DrawerClose)
Overlay shadcn 기본(bg-black/10 + blur)

4. 상태 규격

상태 값
Closed / Open vaul data-state, 열림 시 modal, 배경 aria-hidden, scroll lock
Drag handle 또는 panel을 아래로 끌어 닫음(vaul 기본). 내부 scroll 영역이 있으면 vaul이 scroll과 drag를 구분
Focus 열릴 때 첫 tabbable로 이동, Tab 순환, 닫힐 때 trigger로 복귀
Long Content Header·Footer 고정, Body만 scroll

5. API

vaul Drawer.Root props 그대로(direction, snapPoints, dismissible, shouldScaleBackground, modal, open/onOpenChange …). export: Drawer, DrawerTrigger, DrawerPortal, DrawerOverlay, DrawerClose, DrawerContent, DrawerHeader, DrawerBody, DrawerFooter, DrawerTitle, DrawerDescription.

  • Drawer: autoFocus 기본값을 true로 둔다(vaul 기본은 false). vaul 기본값은 Radix의 초기 focus를 취소해, 열린 뒤에도 focus가 aria-hidden 처리된 trigger에 남고 Tab이 Drawer 밖으로 나간다(실측). autoFocus={false}로 vaul 동작을 되돌릴 수 있다.
  • DrawerContent: 방향은 root의 direction(기본 bottom), data-vaul-drawer-direction으로 출력.
  • DrawerBody(신규): scroll owner.
  • DrawerClose: asChild일 때 자식의 data-slot을 유지(DialogClose와 같은 규칙).
  • 새 prop은 만들지 않았다.

6. Token

Component Mapping 위치: packages/ui/src/theme/drawer.css (--hm-drawer-*).

background, text, border-width, border-color, radius, shadow, max-height, width, edge-gap, padding, header-gap, footer-gap, handle-width|height|color|margin-top, title-*, description-*, body-*. Semantic과 Theme palette만 참조하며 --hm-sheet-*·--hm-dialog-*를 참조하지 않는다. 신규 Primitive 없음.

7. shadcn / vaul / Radix에서 유지한 항목

vaul의 drag·snap·dismiss·body 처리와 data-vaul-* 속성, Radix의 Portal·focus trap·Escape·ARIA·focus 복귀, 방향별 position class, data-slot, cn(..., className), handle 요소(bottom 방향에서만 표시), Overlay.

8. HM에서 변경한 항목

  • shadcn bg-background, 방향별 rounded-*/border-*/max-h-[80vh], handle h-2 w-[100px] bg-muted, Header/Footer p-4 제거 → theme CSS.
  • Drawer의 autoFocus 기본 true(위 §5).
  • DrawerBody 추가, DrawerClose asChild data-slot 처리.
  • Handle을 data-slot="drawer-handle" 요소로 구분해 token으로 스타일.

9. Storybook

  • 대표 Story All("Drawer"): 트리거 3개(기본, 폼, 긴 내용)가 각각 실제 Drawer를 연다. 핸들을 끌어 닫을 수 있다.
  • verification: Open, Form, Long Content(처음부터 열림).

10. 사용자 확정 결정

  • 2026-10-02: ui-viz는 참고 자료이며 최종 기준은 현재 HM 구현과 이 문서다(작업 지시). 개별 수치에 대한 별도 결정은 없다.

11. 미확정 / 보류

  • 수치(85dvh, 18px Title, handle 크기, 그림자)는 현재 HM 규격이며 디자인 확정 시 재검토.
  • Overlay, drag/transition Motion은 vaul·shadcn 기본 유지. shouldScaleBackground는 쓰지 않았다.
  • snap points 사용 예는 만들지 않았다(API는 vaul 그대로 사용 가능).
  • left/right/top 방향의 시각은 CSS에 두었으나 Story로는 검증하지 않았다(bottom만 사용 예).
  • Drawer와 Sheet의 사용 경계 가이드는 후속.

12. 관련 파일

packages/ui/src/components/ui/drawer.tsx
packages/ui/src/theme/drawer.css
packages/ui/package.json             (dependency: vaul)
packages/ui/src/theme.css            (import)
packages/ui/src/index.ts             (export)
src/components/drawer.stories.tsx

13. 검증 상태

  • npm run typecheck, npm run build: 통과(2026-10-02).
  • 실제 interaction(Browser pane): 클릭 열기, focus가 "확인"으로 이동(autoFocus 적용 전에는 trigger에 남음), Tab 3회 후에도 Drawer 안(focus trap), Escape 닫힘과 trigger 복귀, handle을 아래로 drag해 닫힘과 focus 복귀, 바깥(Overlay) 클릭 닫힘.
  • 390×844 긴 내용: Drawer 높이 717px(85dvh), Body만 scroll, Footer가 viewport 하단, 가로 overflow 없음, Footer 버튼 세로 쌓임.
  • computed style: radius 8px 8px 0 0, border-top rgb(222,219,210), handle 48×4 rgb(154,146,132).
  • 미확인: 실제 터치 drag(마우스 drag만 확인), snap points, scroll 영역 안에서 drag와 scroll 구분, 닫기 animation 시각, left/right/top 방향 시각.