11 KiB
11 KiB
Select
현재 HM 구현의 기준 문서. 공통 원칙은 docs/guidelines/프로젝트-지침.md(§6, §7), Token 구조 원칙은 테마-토큰-가이드.md를 따른다. 이 문서는 Select 고유의 API·Token·상태·결정만 기록한다.
1. 상태
| 항목 | 내용 |
|---|---|
| 구현 상태 | HM 스타일 적용 완료 (hm-select-trigger class 없음) |
| 기준일 | 2026-10-02 |
| 기반 | shadcn/ui Select, Radix Select |
| 대표 Story | Components/Form/Select → All (이름 "Select") |
| 보류 | Item Disabled, 일반 Focus 두께 등 (§11) |
2. 적용 근거
- ui_viz Confirmed: size/높이(select.md §1.1 D-004, §8), 색·border(§10, §1.3, D-005, M06), indicator glyph(§7, 사용자 제공 Source), Trigger/Content 연결 윤곽(§8).
- ui_viz BASELINE_VALUE: padding-x 12, gap 12, option 높이 42(§8, §17) — "현재 적용 계약"으로 표기된 값.
- HM 사용자 결정: Trigger Disabled opacity
0.6(2026-10-02, §10). - shadcn/Radix 유지: 구조·접근성·positioning(§7).
- HM 사용자 결정(2026-10-06): Error는 Destructive border, Keyboard Focus는 독립 Focus Semantic ring.
3. 기본 규격
| Size | 외곽 | Trigger 내부 높이 | Trigger 글자 |
|---|---|---|---|
medium |
34 | 32 | 14 / 20 / 400 |
large (기본) |
44 | 42 | 16 / 24 / 400 |
- 높이는
min-height = 내부 높이 + 1px border × 2. - Padding-x 12, gap 12, border 1px
--hm-sem-stroke-input-default, radius--hm-radius-input, face--hm-sem-bg-surface. - Placeholder(
[data-placeholder]):--hm-sem-fg-placeholder. - Trigger와 Value는
min-width: 0; 긴 placeholder/선택값은 한 줄 ellipsis로 줄고 18px indicator를 밀지 않는다. ui_viz 공개 Story에 없던 현재 HM 복원력 규칙이며 parity 판정 근거로 쓰지 않는다. - Icon: HM glyph, 18×18
viewBox,M5 7 L9 11 L13 7, stroke 1.50542, 색#2d2d2d(--hm-select-indicator-color). - Content: Trigger와 같은 폭(
--radix-select-trigger-width), border 1px focus 색,bottom일 때 아래쪽만 radius. - Option: Trigger의 size를 따른다. min-height 42(두 size 공통, ui_viz §8), padding-x 12, 글자 Medium 14/20/400(Medium Trigger와 동일) · Large 16/24/400, radius 0. ui_viz는 Medium Option 글자 Role을 TBD로 남겼고, 2026-10-06 Trigger 값에 맞추기로 했다(사용자 요청). 높이·폭은 size로 바꾸지 않는다(Content = Trigger 외곽 폭).
- size 전달:
SelectTrigger size가 유일한 지정처다.Select가 내부 context로 받아 Portal된SelectContent의data-size로 노출하고,select.css가[data-slot="select-content"][data-size]로 Option profile을 정한다.SelectContent·SelectItem에는 size prop이 없다.
4. 상태 규격
| 상태 | 값 | 근거 |
|---|---|---|
| Default | 위 기본 규격 | ui_viz Confirmed |
Focus (:focus) |
border 색 → --hm-sem-stroke-input-focus, 두께 1px 유지 |
ui_viz Confirmed (1.5px 두께는 ui_viz FOLLOW_UP으로 보류) |
Open ([data-state="open"]) |
border 색 → focus 색, 위쪽 모서리만 round(리스트와 이어짐) | ui_viz Confirmed |
Selected (Item [data-state="checked"]) |
Hover와 같은 배경 면(--hm-sem-surface-highlight, Accent 45%), border·check icon 없음 |
표현: ui_viz Confirmed / 색: shadcn Token(accent) |
Highlighted (Item focus:/data-highlighted) |
Accent 45%(--hm-sem-surface-highlight) |
위와 동일 |
Disabled (Trigger :disabled) |
Default paint 유지, opacity: 0.6, cursor: not-allowed |
opacity: 사용자 결정 |
Disabled (Item data-disabled) |
shadcn 기본 opacity-50, 포인터 차단 |
미검증(§11) |
Invalid (aria-invalid="true") |
border 1px --hm-sem-action-destructive, Error ring 없음 |
2026-10-06 사용자 결정 |
Invalid + Keyboard Focus (:focus-visible) |
Destructive border 유지 + Focus Semantic 3px / 50% outer ring | 위와 동일 |
| Invalid + Open | Trigger Destructive border, 연결 seam은 Neutral. Content의 기존 Surface / Focus outer border / Accent 45% Option 유지 | 위와 동일 |
| Disabled Invalid | Destructive border + 기존 opacity 0.6, focus 불가 | 위와 동일 |
5. API
SelectTrigger size:
"sm" | "default"
→
"medium" | "large" 기본 "large"
SelectContent sideOffset:
shadcn 기본 4
→
기본 -1 (Trigger와 1px border를 공유)
SelectItem:
children 앞의 ItemIndicator(check icon) 제거. children만 ItemText로 렌더.
Select,SelectValue,SelectGroup,SelectLabel,SelectSeparator, 스크롤 버튼은 shadcn API 그대로.- 출력 속성:
data-slot="select-trigger",data-size. HM 전용error/open/focusedprop은 없다. 상태는 Radix 속성(data-state,data-placeholder,data-highlighted,data-side)과:disabled로 적용한다.
6. Token
Component Mapping 위치: packages/ui/src/theme/select.css (--hm-select-*).
- 재사용한 공통 Semantic:
--hm-radius-input(radius),--hm-sem-bg-surface,--hm-sem-fg-primary,--hm-sem-fg-placeholder,--hm-sem-stroke-input-default,--hm-sem-stroke-input-focus. - Select 전용 값:
--hm-select-control-height-{md,lg}(32/42),--hm-select-padding-x,--hm-select-gap,--hm-select-option-height,--hm-select-font-size-*,--hm-select-disabled-opacity,--hm-select-indicator-color. - indicator는
--hm-select-indicator-color→--hm-sem-palette-indicator를 참조한다(Default#2d2d2d). 신규 Primitive 없음. - Input·Button과 값(42 등)이 겹쳐도 alias하지 않는다. 각 ui_viz 규격이 따로 확정한 값이다.
--hm-select-disabled-opacity: 0.6은 Select 전용 Component Token이며 Input의 Disabled와 공유하지 않는다.
7. shadcn / Radix에서 유지한 항목
Radix Root/Trigger/Portal/Content/Viewport/Item/ItemText 구조, 키보드 조작·typeahead·focus 관리, Portal, popper positioning(position="popper", align="start"), 스크롤 버튼, 열림/닫힘 animation class, data-slot, cn(..., className), Trigger의 native aria-invalid 전달, Item의 data-disabled 처리.
8. HM에서 변경한 항목
- Size API(
sm|default→medium|large), 기본large,data-size. sideOffset기본-1, Content 폭을 Trigger 폭에 맞춤, Trigger/Content 연결형 윤곽.- chevron 아이콘을 HM glyph(inline SVG)로 교체.
- Item check indicator 제거, Selected를 배경 면으로 표현.
- shadcn Trigger의 높이·padding·border·focus ring class 제거 → theme CSS가 담당.
hm-select-triggerclass 제거.- 변경하지 않음: 스크롤 버튼의 lucide chevron(ChevronUp/Down).
9. Storybook
- 대표 Story
All("Select"): 구역default(Large, size 생략),selected,disabled,open. - verification(
tags: ["verification"]):Default,Open,Selected,Disabled,Sizes("Compare Sizes"),Medium,Large,LongContent,Scroll,Playground(HM 전용). DisabledStory 구성: Trigger 비활성 상태들(placeholder 포함).InvalidFocusverification Story: 앞/뒤 버튼 사이의 Invalid Trigger와 Disabled Invalid Trigger. Tab / Shift+Tab, Enter / Space, Escape 및 focus return을 실제 키보드로 확인한다.LongContent와Scroll은 ui_viz 공개 Story parity가 아니라 좁은 폭·긴 값·Radix scroll 회귀를 확인하는 HM 전용 Story다.- sidebar는
All하나만 보이는 1뎁스. 운영 규칙은 지침 §6.3, §7 참조.
10. 사용자 확정 결정
2026-10-02
- Select Trigger Disabled opacity
0.6확정(select.css의--hm-select-disabled-opacity). - 같은 날 Input Disabled
0.6도 확정되었다(input.md 참조). 현재 적용 범위는 Input / Select이며 전체 디자인 시스템 Disabled opacity로 자동 확대하지 않는다. - Select Item의 Disabled opacity는 이 결정에 포함하지 않는다. Trigger와 같은 규격이라고 판단하지 않는다.
11. 미확정 / 보류
- Item Disabled: 현재 shadcn 기본
opacity-50. 사용자 결정·ui_viz 근거 없음. 미검증. - FOLLOW_UP(ui_viz): Focus/Open 상태의 border 1.5px 두께.
- ui_viz 미정의: Group/Label/Separator 규격, 스크롤 버튼 규격,
item-alignedposition. Error 표현은 2026-10-06 HM 사용자 결정이 우선한다. - BASELINE_VALUE: padding-x 12, gap 12, option 42는 "현재 적용 계약"이며 별도 Confirmed 결정은 아니다.
- Selected/Highlighted는 현재 공통 Accent 45% 정책을 쓴다. ui_viz Temporary 표기는 도입 당시 근거다.
12. 관련 파일
packages/ui/src/components/ui/select.tsx
packages/ui/src/theme/select.css
src/components/select.stories.tsx
src/components/story-board.tsx
13. 검증 상태
- 2026-10-05:
npm run typecheck,npm run build,npm run build-storybook통과. 기존 generated CSS의bg-[var(...)]경고와 500kB chunk warning은 유지된다. - Storybook computed style: Medium/Large Trigger 34/44px, padding-x 12px, radius 4px, border 1px, Option 42px·16/24/400, Disabled Trigger opacity
0.6확인. - Open: Trigger와 Content 폭 동일,
sideOffset=-1접점, Focus/Open#123328, Content border/radius/shadow와 Portal listbox 확인. - Interaction: click open, ArrowUp/Down, Home/End, typeahead, Enter select, Escape, focus return, Disabled open 차단, 32개 Option의 wheel/keyboard scroll 확인.
- Responsive: 1280/768/390px에서 popup clipping·문서 가로 overflow 없음. 390px의 280px Trigger에서 긴 placeholder/선택값 ellipsis와 indicator 비중첩 확인.
- Story:
All의 공개 구역 4개와 숨김LongContent/Scrollverification Story 확인. - 미확인/보류: Item Disabled 시각, collision으로
side="top"이 된 연결 윤곽의 별도 디자인(원 ui_viz도 viewport edge flip TBD), 브라우저별 렌더 차이.
Invalid + Focus 검증 (2026-10-07)
- Focus ring:
--ring→--hm-sem-stroke-input-focus→--hm-color-border-focus. Invalid border: 기존--hm-sem-action-destructive. 새 Runtime Role / Production Error prop / 메시지 컴포넌트 없음. - Chromium computed style: Invalid border
rgb(211, 47, 47), Invalid + Keyboard Focus box-shadowcolor(srgb 0.14902 0.4 0.317647 / 0.5) 0px 0px 0px 3px,outline-style: none. Invalid 단독은box-shadow: none. - Theme Designer UI에서 Focus
#c75b00, Destructive#d41466, Active#007f73, Accent#ffd36d로 분리. Invalid borderrgb(212, 20, 102)+ Focus shadowcolor(srgb 0.780392 0.356863 0 / 0.5) 0px 0px 0px 3px확인. npm run typecheck,npm run build,npm run build-storybook통과. 기존 문서 예시 CSS warning 및 Storybook chunk 크기 / plugin timing warning 유지.- 검증 범위: Chromium 환경. 다른 브라우저의 렌더링은 별도 확인이 필요하다.
- 숨김
InvalidFocus에서 Closed Invalid / Tab Focus / Invalid Open / 방향키 강조 / Disabled Invalid 확인. Invalid border computed 1px; Tab 전후 shadow none → 3px Focus ring. Tab은 Disabled를 건너뛰고, Shift+Tab으로 복귀. Enter / Space open, ArrowDown 이동, Escape close 및 Trigger focus return 확인. - Invalid + Open은 Trigger Destructive border와 Neutral seam
rgb(222, 219, 210)을 동시에 유지. Popup white Surface, 외곽rgb(199, 91, 0)(Focus), Selected / Highlightedcolor(srgb 1 0.827451 0.427451 / 0.45)(Accent) 확인. Popup에 Error 색 없음. 대표All회귀 확인.