Files
HMDesign/docs/sw/sw-header-layer-dropdown-verification-2026-10-16.md
T

148 lines
11 KiB
Markdown
Raw 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.
# SW Header 레이어 Dropdown 검증 기록 (2026-10-16)
> 범위: `@hm-design/sw` 레이어 필드 Dropdown과 전구·눈꽃·자물쇠 On/Off. 기준: Figma `rj6wpsfk24lOWvWiVRAANP` 5개 Node. 규격은 [디자인 명세 §5.2](./sw-header-design-spec.md#52-레이어-dropdown-figma-headermenu레이어-2610940-2026-10-16), 사용법은 [사용 가이드](./sw-header-usage.md#레이어-dropdown-예)를 따릅니다.
## 1. 작업 환경
| 항목 | 값 |
|---|---|
| Worktree / Branch | `D:\디자인시스템\HMDesign-SW` / `feature/sw-package` |
| HEAD | `9407c85` (시작·종료 동일, Commit 없음) |
| 시작 상태 | `M package.json`, `M package-lock.json`, `?? docs/sw/`, `?? packages/sw/`, `?? src/sw/` — 기존 미커밋·Untracked 파일 보존(시작 시 스크래치 백업, Reset/Clean/Checkout 없음) |
| 검증 Storybook | `npx storybook dev -p 6047`(6024·6031·6032는 다른 세션 사용 중) |
## 2. Figma 5개 Node
| # | Node | 내용 | 확인 방법 |
|---|---|---|---|
| ① | `26:10940` `header/menu/레이어` (default 26:10941, hover 26:10952, Variant3 26:10963) | 필드·펼침 목록·레이어 상세 | `get_design_context` + screenshot |
| ② | `26:10810` `icon_전구` | 4 Variant: 컬러 / 컬러 Hover(검정 25%) / 회색(ellipse `#E6E6E6→#555`) / 회색 Hover | `get_design_context` + screenshot |
| ③ | `26:10855` `icon_눈꽃` | 4 Variant SVG(`#00CCFF` / `#949494`, Hover = 검정 25% 타일 추가) | 동일 |
| ④ | `26:10912` `icon_자물쇠` | 4 Variant SVG(`#E4BF4D·#D8A300` / `#BEBEBE·#A1A1A1`, Hover = 타일 추가) | 동일 |
| ⑤ | `26:10687` `header/dropdown/brown/row` (Default 26:10688, Hover 26:10695) | 행 234 × 30, Hover `#62533D` / `#FF5C00` | 동일 |
Prototype의 Smart Animate(Off → Off Hover, ease-out 300ms)는 사용자 요청서 기재값을 따랐습니다. Figma Prototype player 재생으로는 확인하지 않았습니다(NOT VERIFIED).
## 3. 자산
- 신규 8개(`layer-ellipse-off`, `layer-freeze-hover/off/off-hover`, `layer-lock-hover/off/off-hover`, `layer-detail`)를 Figma MCP에서 내려받아 `packages/sw/src/assets/`에 저장. 수정·재작성 없음.
- 기존 `layer-union/ellipse/state-a/state-b`는 Figma 원본과 mask id 외 동일 → 재사용.
- Hover SVG = Default SVG + `<rect 20×20 rx2 fill=black 25%>` 1줄 외 동일(정규화 diff).
- `packages/sw/src`, `src/sw`, `packages/sw/dist`, `storybook-static`에서 `figma.com/api` 검색 0건.
## 4. 디자인 측정 (Storybook `SW / Header / Layer Dropdown`, 1920 프레임, `getBoundingClientRect`·computed style)
| 항목 | 기대(Figma) | 측정 | 판정 |
|---|---|---|---|
| 필드 | 234 × 38, x 467 | 234 × 38, x 466.7(헤더 기준) | MATCH |
| 펼친 필드 | 테두리 `#081813`, radius 3 3 0 0, 라벨·값 `#FFC600` | `rgb(8,24,19)`, `3px 3px 0 0`, `rgb(255,198,0)` | MATCH |
| 펼침 외곽선 | 236 × 320 at −1/−1, radius 4 | `::before` inset −39 / −1 / −1 / −1, radius 4, 노란 gradient | MATCH |
| 목록 | 234 × 280, 필드 바로 아래 | 234 × 280, y = 필드 하단 | MATCH |
| 배경·그림자·radius | `#27241D`, `0 4px 8px rgba(16,48,38,.25)`, 0 0 3 3 | 동일 | MATCH |
| 행 | 234 × 30 × 8 | 234 × 30, 8개 | MATCH |
| 아이콘 | 20 × 20, x+12 / 32 / 52 | 동일 | MATCH |
| 견본 | 16 × 16 at x+80, 안쪽 14 × 14 | 동일 | MATCH |
| 이름 | x+104(+1), `#F6F4F2`, 700 | 동일 | MATCH |
| 하단 | 40, 버튼 오른쪽 12px | 40, 버튼 오른쪽 끝 = 목록 −12 | MATCH |
| 레이어 상세 | radius 24, 배경 `rgba(197,177,158,.15)`, 아이콘 14, 글자 opacity .35 | 동일, 버튼 107.3 × 24(글자 69.3) | MATCH(글자 폭은 글꼴 차이) |
| 행 Hover | `#62533D` / `#FF5C00` | `rgb(98,83,61)` / `rgb(255,92,0)`(고정·실제 Hover 모두) | MATCH |
| 아이콘 Hover | 전구 검정 25% 배경, 눈꽃·자물쇠 Hover SVG | 전구 `rgba(0,0,0,.25)`, Hover img opacity 1 | MATCH |
| Off Hover 전환 | 300ms ease-out | Off: `0.3s ease-out`, On: 0s | MATCH |
| 헤더 높이 | 49 | 49 | MATCH |
3배 확대 아이콘 표(12개 Variant)를 Figma screenshot과 육안 비교: 형태·색 일치. 픽셀 diff는 수행하지 않았습니다.
## 5. 동작 검증
JS 이벤트(`click`, `PointerEvent`, `KeyboardEvent`)와 실제 마우스·키보드 입력(브라우저 pane `left_click`, `hover`, `key`)으로 확인했습니다.
| 시나리오 | 결과 |
|---|---|
| 필드 클릭 → 열림, 다시 클릭 → 닫힘 | PASS (`aria-expanded` 동기화, `onLayerMenuOpenChange` true/false) |
| 전구 / 눈꽃 / 자물쇠 클릭(JS 4회, 실제 마우스 1회, 키보드 Space·Enter 2회) | PASS — 각 Callback 1회, `onLayerSelect` 0회, 목록 유지, 해당 레이어만 변경(상태표 확인) |
| 행 선택(JS, 실제 Enter) | PASS — `onLayerSelect` 1회, 목록 닫힘, Focus 필드 복귀, 필드에 레이어명·상태 아이콘 반영(회색 전구 확인) |
| 바깥 pointerdown, 다른 필드 pointerdown | PASS — 닫힘 |
| Escape(JS, 실제 키) | PASS — 닫힘, Focus 필드 |
| ↓(닫힘) | PASS — 열림, 현재 레이어 이름 버튼 Focus(2px `#F0F7F5` outline) |
| ↓↑ / ←→ | PASS — 같은 열 유지 행 이동, 행 안 이동 |
| Tab 진입 / Shift+Tab 두 번으로 이탈 | PASS — 목록 안에서는 유지, 밖으로 나가면 닫힘 |
| 레이어 상세(Callback 있음) | PASS — `onLayerDetail` 1회 후 닫힘 |
| 레이어 상세(Callback 없음) | PASS — `disabled`, opacity 1(Figma 외형), cursor default |
| Callback 없는 아이콘 | PASS — `role="img"` span 24개, 버튼 0개 |
| disabled 레이어 | PASS — 아이콘 3개·선택 버튼 모두 disabled |
| 20개 레이어 | PASS — 목록 240px 내부 스크롤(scrollHeight 600), 전체 280, 헤더 가로 스크롤 0 |
| 레이어 없음 | PASS — 하단만(40px), 필드는 `layer.name` |
| 긴 레이어명 | PASS — 행·필드 ellipsis, 오른쪽 padding 12 유지 |
| 콘솔 오류 | 0건 |
## 6. 반응형
`Layer Dropdown`의 Callback 예제 프레임 폭을 바꿔 측정하고, 같은 폭의 기존 `Responsive` Story(`layers` 없음) 필드 위치와 비교했습니다.
| 폭 | 필드 x / 폭 (기존과 동일) | 열린 뒤 필드 이동 | 헤더 가로 스크롤 | 목록 헤더 안 | 목록 이동 | 아이콘·텍스트 겹침 | 견본 |
|---|---|---|---|---|---|---|---|
| 1920 | 466.7 / 234 ✔ | 없음 | 0 | ✔ | 0 | 없음 | 16 × 16 |
| 1800 | 346.7 / 234 ✔ | 없음 | 0 | ✔ | 0 | 없음 | 16 × 16 |
| 1799 | 466.7 / 234 ✔ | 없음 | 0 | ✔ | 0 | 없음 | 16 × 16 |
| 1440 | 466.7 / 234 ✔ | 없음 | 0 | ✔ | 0 | 없음 | 16 × 16 |
| 1180 | 306.7 / 234 ✔ | 없음 | 0 | ✔ | 0 | 없음 | 16 × 16 |
| 1080 | 207.7 / 234 ✔ | 없음 | 0 | ✔ | 0 | 없음 | 16 × 16 |
| 900 | 246.7 / 234 ✔ | 없음 | 0 | ✔ | 0 | 없음 | 16 × 16 |
| 768 | 310.7 / 234 ✔ | 없음 | 0 | ✔ | 0 | 없음 | 16 × 16 |
| 640 | 182.7 / 234 ✔ | 없음 | 0 | ✔ | 0 | 없음 | 16 × 16 |
| 390 | 167.7 / 113.7 ✔ | 없음 | 0 | ✔ | 왼쪽 이동, 오른쪽 여백 1.3 | 없음 | 16 × 16 |
- 1차 측정에서 390px 열림 상태에 헤더 `scrollWidth`가 1px 늘어나는 문제(외곽선이 목록 밖 1px)를 발견해, 이동 계산에 1px 여백을 두도록 수정 후 320 / 360 / 390 / 500 / 519 / 640에서 0을 재확인했습니다.
- 390에서 실제 조작(열기 + 자물쇠 Toggle → Callback 1회, 목록 유지) 확인. 브라우저 Viewport 390 에뮬레이션은 Storybook 페이지 내부 폭이 766px로 잡혀 헤더 프레임 390 기준으로만 확인했습니다(실기기 NOT VERIFIED).
- 더보기 메뉴 정책·기존 Breakpoint 변경 없음(필드 위치가 기존 Story와 동일).
## 7. 회귀 확인
| 항목 | 결과 |
|---|---|
| `layers` 미전달 필드 | 기존 DOM(아이콘 4개 img 14×18 / 14×14 / 20×20 / 20×20, `aria-expanded=false`)과 동일 |
| Composed Controls 고정 Hover | 5개 필드 값 `#FFC600`, Gradient ring opacity 1, 선 미리보기 `#FFC600` 유지 |
| 문서 Dropdown·창 이동·인쇄·최소화·종료·속성 토글 CSS | 변경 없음(diff는 레이어 관련 규칙 추가뿐) |
## 8. Build
| 명령 | 결과 |
|---|---|
| `npm run typecheck -w @hm-design/sw` | PASS |
| `npm run build:sw` | PASS (`dist/styles.css` 45.35 kB, `dist/index.js` 202.28 kB) |
| `npm run typecheck`(root, packages build 포함) | PASS |
| `npm run build`(root) | PASS (기존 500 kB chunk 경고만) |
| `npm run build-storybook` | PASS, index에 `sw-header--layer-dropdown` |
## 9. 아이콘 색상 ↔ 상태 매핑 확정 검증 (사용자 확정, 2026-10-16)
확정 기준: 전구 컬러 `visible=true` / 회색 `false`, 눈꽃 컬러 `frozen=false`(동결 해제) / 회색 `true`(동결), 자물쇠 컬러 `locked=false`(잠금 해제) / 회색 `true`(잠금). 클릭 시 해당 boolean 반전값을 Callback으로 전달합니다. 기존 구현(`layerIconOn()`, `onChange(layer, !pressed)`)이 이 기준과 같아 동작 코드는 바꾸지 않았고, 타입 주석·Story 설명·문서의 잠정 표기만 확정으로 바꿨습니다. SVG·Default/Hover CSS 변경 없음.
검증: Storybook `Layer Dropdown`의 Callback 예제에서 각 아이콘을 두 번씩 클릭했습니다. 색은 렌더링된 SVG의 실제 fill(전구 `#FAB846`/`#9C9C9C`, 눈꽃 `#00CCFF`/`#949494`, 자물쇠 `#E4BF4D`/`#BEBEBE`)로 판정했습니다.
| 레이어 · 아이콘 | 클릭 전 | Callback | 클릭 후 |
|---|---|---|---|
| layer-0 전구 | `visible=true` 컬러 | `onLayerVisibilityChange(layer-0, false)` | `false` 회색 |
| layer-0 전구 | `false` 회색 | `(layer-0, true)` | `true` 컬러 |
| layer-0 눈꽃 | `frozen=false` 컬러 | `onLayerFreezeChange(layer-0, true)` | `true` 회색 |
| layer-0 눈꽃 | `true` 회색 | `(layer-0, false)` | `false` 컬러 |
| layer-0 자물쇠 | `locked=false` 컬러 | `onLayerLockChange(layer-0, true)` | `true` 회색 |
| layer-0 자물쇠 | `true` 회색 | `(layer-0, false)` | `false` 컬러 |
| layer-5 전구 | `visible=false` 회색 | `onLayerVisibilityChange(layer-5, true)` | `true` 컬러 |
| layer-5 전구 | `true` 컬러 | `(layer-5, false)` | `false` 회색 |
| layer-5 눈꽃 | `frozen=true` 회색 | `onLayerFreezeChange(layer-5, false)` | `false` 컬러 |
| layer-5 눈꽃 | `false` 컬러 | `(layer-5, true)` | `true` 회색 |
| layer-5 자물쇠 | `locked=true` 회색 | `onLayerLockChange(layer-5, false)` | `false` 컬러 |
| layer-5 자물쇠 | `false` 컬러 | `(layer-5, true)` | `true` 회색 |
- 모든 클릭에서 Callback 1회, `onLayerSelect` 0회, 목록 유지. `aria-pressed`는 표시됨 / 동결됨 / 잠김과 일치.
- 클릭하지 않은 다른 레이어 7개의 상태는 변하지 않음.
## 10. 남은 차이 · NOT VERIFIED
- 아이콘 색상 ↔ 상태 매핑은 위 §9로 확정·검증했습니다. 실제 SW 호스트에서 이 값으로 도면이 표시·동결·잠금되는지는 외부 연동이 필요합니다(NOT VERIFIED).
- 실제 SW 호스트에서의 레이어 표시·동결·잠금 반영과 레이어 상세 화면: 패키지 단독 검증 불가(NOT VERIFIED).
- 현재 레이어 이름 `#FFC600`, 목록 최대 높이 240px, 좁은 폭 왼쪽 이동은 Figma에 없는 구현값입니다.
- 레이어 상세 버튼 Hover는 Figma Variant가 없어 추가하지 않았습니다.
- Figma Smart Animate 곡선의 Prototype player 실재생 비교, 픽셀 diff, 실기기 390px, 스크린리더 실사용 검증은 수행하지 않았습니다.