test(sw): approve the SW Viewer Header API and Storybook cleanup baselines
Deploy Storybook / deploy (push) Successful in 1m10s

Test-only approval commit after the 34f02bf main merge (sw-test-regression-
baseline section 9); no protected path changes.
- public-api.approved.json from the clean 34f02bf build: 170 exports kept,
  only SWViewerHeader.d.ts changes (7 optional SWViewerHeaderProps).
- approvedMainCommit b4e0771 -> b320a8f; approvedHeaderDeclarations for the
  23d522c Story declarations; withApprovedOrder for the approved SW Header
  first position; storybook-simplification expects SW/Theme hidden.
- Verification report: docs/sw/sw-viewer-storybook-merge-verification-2026-10-21.md
This commit is contained in:
shkim4 committed 2026-10-21 15:21:30 +09:00
1 parent b320a8f1e0
commit a25d2b31c5
5 files changed
+72 -8

No files matched your search

@@ -0,0 +1,54 @@
# SW Viewer Header · Storybook 정리 main 병합 검증 (2026-10-21)
## 1. 병합
| 항목 | 값 |
|---|---|
| 작업 Commit | `23d522c` (SW Viewer Header Optional Props, SW Storybook 정리) |
| 선언 승인 기록 | `34f02bf` (`approvedHeaderSourceChanges`에 23d522c 선언 11개, 브랜치에서 병합 전 기록) |
| main 병합 | `46119ea` → `34f02bf` Fast-forward, 원격 main Push |
| 병합 후 수정 | `b320a8f` Settings Popup Story 높이·배치, `VIEWER.md` Story 이름 |
| 승인 기준 Commit | 이 보고서와 같은 테스트 전용 Commit |
## 2. 승인 기준 갱신
- `public-api.approved.json`: 깨끗한 `34f02bf` 빌드(`build-info.json` dirty false)에서 `--snapshot`. 170개 Export·42개 선언 파일 유지, 바뀐 값은 `approvedCommit`과 `components/sw-viewer/SWViewerHeader.d.ts` 해시뿐입니다. 이 차이는 `SWViewerHeaderProps`의 Optional Props 7개(`logoMenu`, `logoMenu.items[].icon`, `documents`, `activeDocumentId`, `onDocumentSelect`, `onDocumentOpen`, `documentOpenLabel`)입니다. `logoMenu`·`icon`은 현재 Story·Fixture에서 쓰지 않지만 사용자 지시로 유지합니다.
- `approvedMainCommit`: `b4e0771` → `b320a8f` (§9 절차의 테스트 전용 Commit, 보호 경로 변경 없음). Snapshot의 `34f02bf`는 `b320a8f`와 HEAD의 조상입니다.
- `approvedHeaderDeclarations`: `Overview`, `ResponsiveMore`, `PropertyPanelComparePage`, `InteractiveStates`, `DocumentDropdown` → `23d522c` (이전 170a5c2 / 2b0e1a2 승인 대체). `approvedHeaderSourceChanges`의 23d522c 항목(11개)과 같은 승인입니다.
- `withApprovedOrder`: 승인된 SW Header 최상단 정렬(`sw-header--overview`)을 미사용 검사의 순서 비교에 반영합니다. 이름·제목·태그 비교는 그대로입니다.
- `storybook-simplification`: 사용자 요청으로 SW/Theme가 사이드바에서 숨겨져 기대 순서를 Header → Footer → Popup → Viewer로 바꿨습니다. Theme Story ID와 직접 URL은 유지됩니다.
## 3. 검증 결과 (Node 22.23.2, `npm run build-storybook` 후, 증거는 저장소 밖 임시 폴더)
| 검사 | 결과 |
|---|---|
| Public API Guard | 7/7 PASS |
| Typecheck (`tsconfig.app.json`) | 오류 0 |
| `check:ai-docs`, `ai-docs.check.mjs` | PASS, 46/46 PASS |
| home-menu-integration | 23/23 PASS |
| overview / overview overlays | 54/54, 20/20 PASS |
| storybook-unused-removal (Source Guard) | 93/93 PASS |
| dropdown-consolidation (Source Guard, Dropdown 숨김·직접 URL) | 229/229 PASS |
| storybook-cleanup-stage1 | 41/41 PASS |
| property-panel-comparison | 71/71 PASS |
| storybook-simplification | 9/9 PASS |
| integrated-improvement (options, popup) | 90/90 PASS |
| footer-popup-viewer-refinement | 47/47 PASS |
| keyboard-dismiss | 22/22 PASS |
| text-weight | 50/50 PASS |
| viewer | 70/70 PASS |
| viewer-logo-document-menu | 47/47 PASS |
| theme-inheritance | 25/25 PASS (수정 전 24/25, 아래 §4) |
| detail-buttons verify | 103/123, 기존 실패 20 (아래 §5) |
## 4. 병합 후 발견·수정
- theme-inheritance 회귀 1건(`sw-viewer--content-variants@1440`): 통합한 Settings Popup Story의 프레임이 870px로 커져 1000px 창보다 페이지가 길어졌고, 전체 페이지 캡처가 Viewport를 바꾸면서 속성 팝업의 실시간 좌표 값 9개가 바뀌었습니다(대조 실행도 같은 9개, 픽셀 차이 0). 상속 구조 문제가 아니라 Story 배치 문제라 `b320a8f`에서 프레임 760px, 옵션 오른쪽, 축척 지정은 속성 아래로 옮겼습니다. 1200px 기본 열에서 네 팝업이 겹치지 않습니다.
- `packages/sw/ai/VIEWER.md`의 Story 이름 `Popup Content Variants` → `SW/Viewer › Settings Popup`.
## 5. 남은 항목
- detail-buttons의 Header DOM 기준(`docs/sw/detail-button-qa/baseline.json`, 2026-10-16 `fc26afd`)은 이후 승인된 Header Commit 18개(글꼴·Bold·More 등) 이전 값이라 `overview`·`k-guide` 20건이 이번 변경 전부터 실패합니다(K Guide는 이번에 바뀌지 않음). 기준 갱신은 사용자 승인 후 진행합니다.
- 시각 회귀(`integrated-visual`, `viewer-regression`)는 이전 빌드와 새 빌드를 비교하는 스크립트라 실행하지 않았습니다. 간소화한 SW Story(SW Header·Responsive More·Home Menu·Footer Responsive More·Popup·Viewer Settings Popup·Header + Dropdown)의 스크린샷 차이는 예상된 차이이며 기준 이미지 재승인이 필요합니다. 기준 이미지는 갱신하지 않았습니다.
- Firefox 계열(range-cross-browser, viewer-logo-document-menu-firefox, hover-stability-firefox)과 hover-stability는 이번에 다시 실행하지 않았습니다.
- `packages/sw/src/components/sw-viewer/types.ts`의 `collapseBelow` / `iconOnlyBelow` JSDoc은 숫자를 순서로만 쓰는 현재 동작보다 오래된 설명입니다. 수정하면 Public API 선언 해시가 바뀌므로 별도 승인 작업으로 남깁니다.
+2 -2
View File
@@ -1,6 +1,6 @@
{
"package": "@hm-design/sw",
"approvedCommit": "553e4df4a865aaf6514b1c2b86cb2e3e9a658e5f",
"approvedCommit": "34f02bf0f4e6bd846833d349dd239a4391eed851",
"manifest": {
"name": "@hm-design/sw",
"exports": {
@@ -228,7 +228,7 @@
"components/sw-tool/SWTool.d.ts": "23b1eb156578cd3f1dee325afbd81988d88c4a3f421f7350a0e8c47c652e804c",
"components/sw-viewer/index.d.ts": "381caef510e7a4c903c70a12e24b6f5c1908c2ee98c3816066639583b0f7d658",
"components/sw-viewer/SWViewerControls.d.ts": "ca32e8a2a7de2cfefec36273ffb473271ad438cfb663f44a25871ee6aed9222d",
"components/sw-viewer/SWViewerHeader.d.ts": "2ca96432c4a0d2e14f7033ebde1c5a25980bf50903e2789d3657d5c3edc96039",
"components/sw-viewer/SWViewerHeader.d.ts": "586d07e74f5c2673fbe1d4849ed72cdcf80e7f8a391393168f101dc613490d24",
"components/sw-viewer/SWViewerIcon.d.ts": "3c81582860e481b037b395b3584ff93af73500e4040d8423c9da15c2b4dd108e",
"components/sw-viewer/SWViewerMenu.d.ts": "15fa615c3472d84037780f3c93387acbc6b4d05f5fb56731b0a99262b3f7f109",
"components/sw-viewer/SWViewerPanel.d.ts": "49b040d3f3d00de30e3fc0493fd2ce78e309616ec97a7ce226dfef300b640f92",
+12 -3
View File
@@ -53,7 +53,10 @@ export const integratedChangedFiles = [
// reviewed test-only commit (docs/sw/sw-test-regression-baseline-2026-10-20.md §9).
// History: 553e4df (Merge feature/sw-package) -> b4e0771 (2026-10-21, Merge fix/test-home-menu-integration: approved
// shared roving focus / outside pointer helpers and the Firefox line-values grid; no Story change, public API unchanged).
export const approvedMainCommit = 'b4e0771dd02304b6bb2a95318bc5b8c1b10c2303'
// -> 34f02bf (2026-10-21, fast-forward of feature/sw-viewer-storybook-cleanup: user-approved SW Viewer Header optional
// props and SW Storybook cleanup, 23d522c; declaration approvals 34f02bf; public-api.approved.json from the 34f02bf build),
// then b320a8f (Settings Popup Story fit and VIEWER.md Story name, found in the post-merge verification).
export const approvedMainCommit = 'b320a8f1e0eb9c6bd5bd3bb0a7d16e5733b5749a'
// 170a5c2: the SW/Header sidebar page of the home menu (the moved verification Stories are movedHomeMenuIds).
export const homeMenuSidebarIds = ['sw-header--home-menu']
// 6cf8854 SW Footer (current IDs after retiredFooterIds), 7f42923 viewer mode, 41e963a theme inheritance.
@@ -75,6 +78,9 @@ export const renamedEntries = { 'sw-header--overview': 'SW Header', 'sw-footer--
// Every approved SW Story ID added after the unused-demo removal, as the current index lists them.
export const approvedAddedStoryIds = [...integratedStoryIds.filter(id => !retiredToolIds.includes(id)), ...homeMenuSidebarIds,
...Object.values(movedHomeMenuIds).filter(id => !retiredHomeMenuCompareIds.includes(id)), ...footerStoryIds, ...viewerStoryIds, ...themeStoryIds]
// 2026-10-21 (user request): SW Header (sw-header--overview) is sorted first under SW/Header (preview storySort
// includeNames). Other entries keep their order.
export const withApprovedOrder = entries => [...entries.filter(entry => entry.id === 'sw-header--overview'), ...entries.filter(entry => entry.id !== 'sw-header--overview')]
// An earlier index entry with the approved tag / Popup move applied (2b0e1a2; the moved Story has no component path).
export const withApprovedEntryChanges = entry => {
if (renamedEntries[entry.id]) entry = { ...entry, name: renamedEntries[entry.id] }
@@ -86,9 +92,12 @@ export const withApprovedEntryChanges = entry => {
// src/sw/sw-header.stories.tsx declarations changed or added by approved commits (compared with that commit's version)
// and the Popup move (compared in its new file).
export const approvedHeaderDeclarations = {
Overview: '170a5c23aed10f8fc65e5b20e9b94bd3c1ff1227', ResponsiveMore: '170a5c23aed10f8fc65e5b20e9b94bd3c1ff1227', // home menu, measured More
// 170a5c2 (home menu, measured More) and 2b0e1a2 (exported for the moved Popup Story) were superseded by 23d522c.
WindowMoveMotion: '2b0e1a2262002aedb01c29c5d18ffae1219bf3ef', KGuide: '2b0e1a2262002aedb01c29c5d18ffae1219bf3ef', // verification tag
PropertyPanelComparePage: '2b0e1a2262002aedb01c29c5d18ffae1219bf3ef', // exported for the moved Popup Story
// 23d522c (2026-10-21 SW Storybook cleanup, user-approved): Overview named "SW Header", Responsive More 1440 / 768 / 390,
// comparison captions removed, Interactive States / Document Dropdown tagged verification.
Overview: '23d522c13627ed26ac3e4cbeaaa8359b34c60aab', ResponsiveMore: '23d522c13627ed26ac3e4cbeaaa8359b34c60aab', PropertyPanelComparePage: '23d522c13627ed26ac3e4cbeaaa8359b34c60aab',
InteractiveStates: '23d522c13627ed26ac3e4cbeaaa8359b34c60aab', DocumentDropdown: '23d522c13627ed26ac3e4cbeaaa8359b34c60aab',
}
export const movedHeaderDeclarations = { PropertyPanelCompare: ['src/sw/sw-property-panel.stories.tsx', '2b0e1a2262002aedb01c29c5d18ffae1219bf3ef'] }
// 2026-10-20 (legacy suite alignment): dropdown-consolidation, storybook-cleanup-stage1, property-panel-comparison and
@@ -49,7 +49,8 @@ await m.waitForTimeout(500)
const rows = await m.locator('#storybook-explorer-tree [data-item-id^="sw-"]').evaluateAll(list => list.map(e => [e.dataset.itemId, e.dataset.nodetype, e.textContent.replace('Skip to content', '').trim()]))
await writeFile(path.join(out, 'sidebar.json'), JSON.stringify(rows, null, 1))
const comps = rows.filter(r => r[1] === 'component').map(r => r[2])
check('sidebar SW order Header → Footer → Popup → Viewer → Theme', JSON.stringify(comps) === JSON.stringify(['Header', 'Footer', 'Popup', 'Viewer', 'Theme']), comps)
// 2026-10-21 (user request): SW/Theme left the sidebar (verification tag); its Story keeps its ID and direct URL.
check('sidebar SW order Header → Footer → Popup → Viewer (Theme hidden)', JSON.stringify(comps) === JSON.stringify(['Header', 'Footer', 'Popup', 'Viewer']), comps)
const hidden = ['sw-header--window-move-motion', 'sw-header--k-guide', 'sw-footer--figma-variants', 'sw-header--detail-buttons', 'sw-header--home-menu-capture-default']
check('verification Stories not in sidebar', rows.every(r => !hidden.includes(r[0])), rows.filter(r => hidden.includes(r[0])))
const popupRows = await m.locator('#storybook-explorer-tree [data-item-id]').evaluateAll(list => list.map(e => e.dataset.itemId))
@@ -8,7 +8,7 @@ import { execFileSync } from 'node:child_process'
import path from 'node:path'
import http from 'node:http'
import { parse } from '@babel/parser'
import { swStoryEntries, retiredUnusedDemoIds, integratedChangedFiles, movedToPopupIds, approvedMainCommit, approvedAddedStoryIds, withApprovedEntryChanges, approvedHeaderDeclarations, movedHeaderDeclarations } from './storybook-inventory.mjs'
import { swStoryEntries, retiredUnusedDemoIds, integratedChangedFiles, movedToPopupIds, approvedMainCommit, approvedAddedStoryIds, withApprovedEntryChanges, withApprovedOrder, approvedHeaderDeclarations, movedHeaderDeclarations } from './storybook-inventory.mjs'
import { loadPlaywright } from './playwright-runtime.mjs'
import { sourceChanges, unapprovedChanges } from './source-changes.mjs'
@@ -35,7 +35,7 @@ const added = stories(afterIndex).filter(e => !beforeIndex.entries[e.id])
const retainedSW = Object.values(afterIndex.entries).filter(e => expected.some(entry => entry.id === e.id))
check('inventory: 19 -> 10 retained SW Stories, 338 -> 329 total plus only the approved added Stories', beforeSW.length === 19 && expected.length === 10 && retainedSW.length === 10 && stories(beforeIndex).length === 338 && stories(afterIndex).length === 329 + approvedAddedStoryIds.length && JSON.stringify(added.map(e => e.id).sort()) === JSON.stringify([...approvedAddedStoryIds].sort()), { ...report.data.inventory, added: added.map(e => e.id), unapproved: added.map(e => e.id).filter(id => !approvedAddedStoryIds.includes(id)), missing: approvedAddedStoryIds.filter(id => !afterIndex.entries[id]) })
check('inventory: the nine requested IDs existed before and are absent now', retiredUnusedDemoIds.length === 9 && retiredUnusedDemoIds.every(id => beforeIndex.entries[id] && !afterIndex.entries[id]))
check('inventory: retained SW IDs, names, titles, tags and order unchanged except the approved tags and Popup move', sig(expected.map(withApprovedEntryChanges)) === sig(retainedSW), retainedSW.map(e => [e.id, e.title, e.tags]))
check('inventory: retained SW IDs, names, titles, tags and order unchanged except the approved tags and Popup move', sig(withApprovedOrder(expected.map(withApprovedEntryChanges))) === sig(retainedSW), retainedSW.map(e => [e.id, e.title, e.tags]))
// Entries outside SW keep their values and order; retained SW entries keep their values (order checked above), and the SW
// block sits right after Center Graphic (2b0e1a2 storySort: SW > Header, Footer, Popup, Viewer, Theme).
const others = index => Object.values(index.entries).filter(e => !retiredUnusedDemoIds.includes(e.id) && !approvedAddedStoryIds.includes(e.id) && !/^sw-(tool|popup)--docs$/.test(e.id))