7.0 KiB
Command
현재 HM 구현의 기준 문서. 공통 원칙은 docs/guidelines/프로젝트-지침.md(§6, §7), Token 구조 원칙은 테마-토큰-가이드.md를 따른다. 이 문서는 Command 고유의 API·Token·상태·결정만 기록한다.
1. 상태와 성격
| 항목 | 내용 |
|---|---|
| 성격 | Primitive component (검색 가능한 command/list). Combobox 자체가 아니다 |
| 구현 상태 | 구현 완료 (현재 HM 규격) |
| 기준일 | 2026-10-02 |
| 기반 | shadcn/ui Command = cmdk |
| 대표 Story | Components/Search & Date/Command → All (이름 "Command") |
| 보류 | 아래 §11 |
2. 적용 근거
- 참고 근거: 외부 ui_viz Reference (ZIP 미포함)의 기존 테스트 규격에는 Command가 없다(Search Field의 후보 목록은 다른 컴포넌트). 참고할 수치가 없었다.
- 현재 HM 규격: 아래 §3~§4. 현재 HM Semantic/Primitive로 새로 정했다. Input·Popover·Dropdown Menu Token은 참조하지 않는다(Command Input은 Command 전용 Token).
- 구현 방식: cmdk가 검색 필터링, 방향키/Home/End 이동, Enter 선택, disabled 건너뜀, 그룹, Empty, listbox/option ARIA를 소유한다. HM은 cmdk의 속성(
data-selected,data-disabled,[cmdk-group-heading])에 시각을 연결한다. - 범위: 전역 Command Palette(
CommandDialog)는 만들지 않았다(별도 고급 패턴). - 보류: §11.
3. 기본 규격 (현재 HM 규격)
| 항목 | 값 |
|---|---|
| Command | 흰 면(--hm-sem-bg-surface), 글자 --hm-sem-fg-primary, radius 4px. border·shadow 없음(Popover 등 컨테이너 안에서 쓰는 것을 전제) |
| Input | 높이 40px, padding-x 12px, 14 / 20, 아래 1px --hm-sem-stroke-input-default 구분선, 검색 아이콘 16px --hm-sem-fg-secondary, placeholder --hm-sem-fg-placeholder |
| List | 최대 높이 280px(넘치면 세로 scroll), padding 4px |
| Item | 최소 높이 36px, padding-x 12px, gap 8px, radius 2px, 14 / 20, 아이콘 16px |
| Group heading | 12 / 18 / 500, --hm-sem-fg-secondary, padding 6px 12px |
| Separator | 1px --hm-sem-stroke-input-default, List 폭 전체 |
| Shortcut | 12px, --hm-sem-fg-secondary, letter-spacing .05em |
| Empty | padding 24px 12px, 가운데, --hm-sem-fg-secondary |
4. 상태 규격
| 상태 | 값 |
|---|---|
Highlighted (data-selected="true") |
배경 Accent 45%(--hm-sem-surface-highlight), 글자 --accent-foreground. 포인터 hover와 키보드 이동이 공유 |
Disabled (data-disabled="true") |
opacity 0.6(이 컴포넌트 값, 전역 Disabled 규칙으로 승격 안 함), cursor not-allowed, 방향키 이동에서 제외 |
| Empty | 필터 결과가 없을 때 CommandEmpty 표시 |
| Focus | Input에 있음(outline-hidden). 이동은 Highlighted 면으로 표시 |
5. API
cmdk props 그대로. export: Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator, CommandShortcut.
Command:value/onValueChange(highlight),filter(사용자 정의 필터),shouldFilter,loop,label.CommandItem:value,keywords,disabled,onSelect.CommandInput: Input + 검색 아이콘 wrapper(data-slot="command-input-wrapper")를 포함한다.- 필터링은 cmdk 기본(fuzzy) 그대로이며 HM이 검색 알고리즘을 만들지 않았다.
- 접근성:
CommandInput은role="combobox",aria-expanded,aria-controls(listbox),aria-autocomplete="list";CommandList는role="listbox";CommandItem은role="option".
6. Dependency
cmdk^1.1.1 (packages/ui에 추가, shadcn Command의 기반). CENTER 패키지에는 추가하지 않았다.
7. Token
Component Mapping 위치: packages/ui/src/theme/command.css (--hm-command-*).
background, text, radius, input-*(height, padding-x, gap, font, placeholder, icon), divider-color, list-max-height|padding, item-*(height, padding-x, gap, radius, font), highlight-background|text, group-label-*, shortcut-*, empty-*, disabled-opacity. Semantic과 Primitive(--hm-warm-neutral-pale)만 참조한다. 신규 Primitive와 Semantic 없음. 이 CSS는 cmdk 내부 속성에 맞춘 일반 CSS이며 @layer를 쓰지 않는다(className으로 Command의 높이 등을 바꾸는 것은 TSX class 영역).
8. cmdk에서 유지한 항목
필터링과 정렬, 키보드(ArrowUp/Down, Home/End, Enter, disabled 건너뜀), 그룹 숨김(결과 없는 그룹), Empty, data-selected/data-disabled, listbox/option ARIA, 마우스 hover가 highlight를 옮기는 동작.
9. Storybook
- 대표 Story
All("Command"): Search + disabled item(선택 로그), Groups·icons·shortcut(CalendarIcon,UserIcon,SettingsIcon), Long list(30개, List가 scroll)를 한 페이지에 둔다. 테두리 박스는 Story 조합이다. - verification:
Search,Grouped.
10. 사용자 확정 결정
- 2026-10-02: ui-viz는 참고 자료이며 최종 기준은 현재 HM 구현과 이 문서다(작업 지시). 개별 수치에 대한 별도 결정은 없다.
11. 미확정 / 보류
- 수치(40px Input, 36px Item, 280px List 최대 높이)는 현재 HM 규격이며 디자인 확정 시 재검토.
- Command Palette(
CommandDialog, 전역 단축키 호출)는 별도 패턴으로 남겼다. - 로딩 상태(
Command.Loading), 중첩 페이지는 스타일링하지 않았다. - 선택됨(value) 표시는 Command에 없다(highlight와 다르다). Combobox가 check 아이콘으로 따로 표시한다.
- Command의 Escape는 Command 자체에서는 하는 일이 없다(Popover/Dialog 안에서는 컨테이너가 닫는다).
12. 관련 파일
packages/ui/src/components/ui/command.tsx
packages/ui/src/theme/command.css
packages/ui/package.json (dependency: cmdk)
packages/ui/src/theme.css (import)
packages/ui/src/index.ts (export)
src/components/command.stories.tsx
13. 검증 상태
npm run typecheck,npm run build: 통과(2026-10-02).- ARIA(Browser pane): Input
role=combobox·aria-expanded=true·aria-controls·aria-autocomplete=list, Listrole=listbox, Itemrole=option, disabled Item에data-disabled="true". - keyboard: 첫 항목이 처음부터 highlight, ArrowDown으로 이동(비활성 항목 건너뜀: 바나나 → 포도), Enter로 선택(
onSelect로그 갱신), 그룹 간 이동(ArrowUp 환경설정 → 프로필), End로 마지막 활성 항목(비활성결제는 제외). - 검색: 한글 "바나" 입력 시 바나나만 표시, 결과 없는 "zzz"는 Empty 문구, 입력을 지우면 전체 4개로 복귀하고 첫 항목이 highlight. Escape는 Input focus를 유지(Command 단독에서는 동작 없음).
- computed style: Input 래퍼 40px, List 최대 280px·padding 4px, Item 36px·padding
0 12px·14/20, Highlightedrgb(189,223,212), Group heading 12px/500rgb(110,103,89), Shortcut 12px. - 미확인: 긴 List의 키보드 scroll 시각, 모바일 폭(Combobox 안에서만 확인), pointer hover 시각,
CommandItem의keywords외 사용자 정의filter.