diff --git a/docs/sw/sw-viewer-storybook-merge-verification-2026-10-21.md b/docs/sw/sw-viewer-storybook-merge-verification-2026-10-21.md new file mode 100644 index 0000000..00f5e6c --- /dev/null +++ b/docs/sw/sw-viewer-storybook-merge-verification-2026-10-21.md @@ -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 선언 해시가 바뀌므로 별도 승인 작업으로 남깁니다. diff --git a/packages/sw/tests/public-api.approved.json b/packages/sw/tests/public-api.approved.json index 61e4a30..4a48282 100644 --- a/packages/sw/tests/public-api.approved.json +++ b/packages/sw/tests/public-api.approved.json @@ -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", diff --git a/packages/sw/tests/storybook-inventory.mjs b/packages/sw/tests/storybook-inventory.mjs index 248a169..4ba27ea 100644 --- a/packages/sw/tests/storybook-inventory.mjs +++ b/packages/sw/tests/storybook-inventory.mjs @@ -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 diff --git a/packages/sw/tests/storybook-simplification.browser.mjs b/packages/sw/tests/storybook-simplification.browser.mjs index 2ae62bf..98c1eef 100644 --- a/packages/sw/tests/storybook-simplification.browser.mjs +++ b/packages/sw/tests/storybook-simplification.browser.mjs @@ -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)) diff --git a/packages/sw/tests/storybook-unused-removal.browser.mjs b/packages/sw/tests/storybook-unused-removal.browser.mjs index 9b41574..bcb9bae 100644 --- a/packages/sw/tests/storybook-unused-removal.browser.mjs +++ b/packages/sw/tests/storybook-unused-removal.browser.mjs @@ -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))