// Current SW inventory after the approved stage-1 and Dropdown consolidations. export const retiredStage1Ids = ['responsive', 'text-stroke', 'dynamic-data', 'default', 'controls'].map(id => `sw-header--${id}`) export const retiredDropdownIds = ['layer-dropdown', 'color-dropdown', 'line-style-dropdown', 'text-dimension-style-dropdown'].map(id => `sw-header--${id}`) // 2026-10-19: duplicate property panel demos; the four states live on sw-header--property-panel-compare. export const retiredPropertyPanelIds = ['property-panel-variants', 'property-panel-none', 'property-panel-all', 'property-panel-circle', 'property-panel-expanded'].map(id => `sw-header--${id}`) // 2026-10-19: unused SW Header demo pages; their features stay in the package and the retained Stories. export const retiredUnusedDemoIds = ['property-fields', 'property-shape-slot', 'composition', 'colorize', 'dynamic-controls', 'property-bar', 'additional-hover', 'property-panel', 'layer-detail-input'].map(id => `sw-header--${id}`) // Include the old title when reading historical evidence; live hierarchy is asserted separately. export const swStoryEntries = index => Object.values(index.entries).filter(entry => entry.type === 'story' && (entry.title === 'SW/Header' || entry.title === 'SW/Header/Dropdown')) export const retainedInventory = entries => entries.filter(entry => ![...retiredStage1Ids, ...retiredDropdownIds].includes(entry.id)) .map(entry => entry.id === 'sw-header--composed-controls' ? { ...entry, name: 'Dropdown', title: 'SW/Header' } : entry) export const inventorySignature = entries => entries.map(entry => [entry.id, entry.name, entry.tags]).sort((a, b) => a[0].localeCompare(b[0])) // 2026-10-19 SW integrated improvement (0.2.0): the only Stories added after the unused-demo removal (two under // SW/Header next to its 10 retained Stories, the rest under SW/Tool and SW/Popup), and the only package files it changed. // The two Header Stories sit directly under SW/Header (no separate Options menu), in src/sw/sw-header-open.stories.tsx. export const integratedStoryIds = ['sw-header--document-open', 'sw-header--hidden-sub-controls', 'sw-tool--tool-buttons', 'sw-popup--custom-content', 'sw-popup--multiple-popups'] // 2026-10-19 (viewer worktree, user request): the SW/Tool Story menu was removed; SW/Popup (the common SWPopup // examples) stays. SWToolButton / SWToolGroup stay public; integrated-improvement.browser.mjs opening this id is historical evidence only. export const retiredToolIds = ["sw-tool--tool-buttons"] // 2026-10-19 (Header home menu merge, user request): the SW/Home Menu sidebar menu was removed; its Stories moved under // SW/Header as sw-header--home-menu (sidebar) and sw-header--home-menu-* (verification tag, reachable by URL). export const movedHomeMenuIds = Object.fromEntries(["figma-home-on:figma", "capture-default", "capture-active", "capture-outline", "capture-recent", "header-composition", "variants", "dynamic-data", "standalone", "recent-files-panel:recent-files", "property-bar-check", "capture-property-bar", "integration", "capture-responsive"] .map(entry => entry.split(":")).map(([from, to = from]) => [`sw-home-menu--${from}`, `sw-header--home-menu-${to}`])) // 2026-10-20 (SW Storybook simplification, user request): Figma screenshot comparisons and duplicate Variant pages that // no test or document used were removed; the Figma originals stay in docs/sw/figma-additional/screenshots/. export const retiredHomeMenuCompareIds = ["figma", "capture-active", "capture-outline", "capture-recent", "variants", "recent-files"].map(id => `sw-header--home-menu-${id}`) // 2026-10-20: Property Panel · 4개 비교 moved to SW/Popup in the sidebar; its ID is unchanged (meta id "sw-header"). export const movedToPopupIds = ["sw-header--property-panel-compare"] // 2026-10-20 (Footer Story cleanup, user request): 기본 Footer and the States page were removed. Their screens are sections // of sw-footer--full-footer (Figma 기본 구성, 상태); the aux Figma comparison moved to sw-footer--figma-variants. export const retiredFooterIds = ["default", "states"].map(id => `sw-footer--${id}`) export const integratedChangedFiles = [ 'packages/sw/README.md', 'packages/sw/package.json', 'packages/sw/build.mjs', 'packages/sw/ai/AI_USAGE.md', 'packages/sw/ai/COMPONENT_CATALOG.md', 'packages/sw/ai/COMPOSITION_PATTERNS.md', 'packages/sw/ai/DESIGN_RULES.md', 'packages/sw/ai/examples/ExampleE-CustomPopup.tsx', 'packages/sw/ai/examples/ExampleF-ViewerToolbar.tsx', 'packages/sw/src/index.ts', 'packages/sw/src/theme/sw.css', 'packages/sw/src/components/sw-popup/SWPopup.tsx', 'packages/sw/src/components/sw-tool/SWTool.tsx', 'packages/sw/src/components/sw-header/SWHeader.tsx', 'packages/sw/src/components/sw-header/index.ts', 'packages/sw/src/components/sw-header/types.ts', ...['SWHeaderDocumentTitle', 'SWHeaderDropdown', 'SWHeaderFields', 'SWHeaderLayerMenu', 'SWHeaderLineStyleMenu', 'SWHeaderMore', 'SWHeaderPropertyFields', 'SWHeaderPropertyPanel'].map(name => `packages/sw/src/components/sw-header/components/${name}.tsx`), ] // 2026-10-20 (test alignment): approved SW Story changes after the unused-demo removal that the lists above do not name. // Each comes from a user-requested commit merged into main as 553e4df. Regressions accept exactly these changes. // approvedMainCommit is the reviewed main merge the regressions treat as the accepted source state. overview.browser.mjs // (both modes) and storybook-unused-removal.browser.mjs keep their old baselines (50bf5bd, c8e5fbe) for the Story // inventory and declarations, and accept only the changes named in this file. For the source paths they guard (overview: // packages/sw/src; unused-removal: also the SW ai/package files, the other packages, Overview, Dropdown CSF, assets and // .storybook) they require no difference from this commit (integratedChangedFiles excepted) and report the diff from the // old baseline as sinceBaseline only. // Update it only after a merge into main whose Story and product source changes were all approved, in the same change // that records that merge's approved Story additions, removals, moves and tag changes in the lists of this file. // Never move it to make a failing check pass, and never to a commit that carries unreviewed Story or source changes. // A new main HEAD alone is no reason to move it: no script or workflow updates it automatically; it changes only in a // 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). // -> 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) // -> c1a69a4 (2026-10-21, Merge fix/sw-design-review-2026-10-21: user-approved SW design review and header without More // from 760px, 2fc1b3e; declaration approvals e1e6fca; public-api.approved.json from the c1a69a4 build, comment-only // .d.ts changes for the approved Footer guide default, 3 recent files and the path + name caption) // -> c73f043 (2026-10-21, Merge fix/sw-design-review-2026-10-21: user-approved doc alignment 8127cc7 — AI docs and // comments only, no Story or logic change; public-api.approved.json from the c73f043 build, comment-only .d.ts changes in // SWRecentFiles / home-menu types / viewer types for the preview and collapseBelow / iconOnlyBelow JSDoc). // -> 21fe7a2 (2026-10-21, Merge fix/sw-property-counts-hover: user-approved property popup count Hover only on the // object list, 17170d2; no Story change, public .d.ts unchanged so public-api.approved.json is kept). // -> f26ec7c (2026-10-21, Merge docs/sw-viewer-layer-eye: user-approved viewer layer eye-icon rule, header hover, // trailing strip, file-name width and open icon outline, caf4c32; no Story change, public .d.ts unchanged so // public-api.approved.json is kept). // -> 6b6f17c (2026-10-21, Merge fix/sw-viewer-strip-round: user-approved rounded viewer menu surface end and solid // viewer background, 3671657; CSS and docs only, no Story change, public-api.approved.json kept). // -> f340a26 (2026-10-21, Merge fix/sw-viewer-open-icon-16: user-approved viewer open icon 16px area, open padding // and button-height token, 0840d76; CSS and docs only, no Story change, public-api.approved.json kept). export const approvedMainCommit = 'f340a264b88e8d7091dddea0bca961d45564c2d9' // 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. export const footerStoryIds = ['full-footer', 'tool-groups', 'figma-variants', 'custom-content', 'responsive', 'parts'].map(id => `sw-footer--${id}`) export const viewerStoryIds = ['viewer-header', 'menu-groups', 'states', 'dropdowns', 'settings-panel', 'content-variants', 'variable-size', 'responsive', 'compare-with-sw-header', 'logo'].map(id => `sw-viewer--${id}`) export const themeStoryIds = ['sw-theme--theme-inheritance'] // 2b0e1a2 sidebar simplification: ID and direct URL kept, hidden from the sidebar by the verification tag. // 2026-10-21 (SW Storybook menu cleanup, user request): Interactive States and Document Dropdown left the sidebar the // same way; Overview is named "SW Header" and sorted first (preview storySort). menuCleanupHiddenIds lists every Story the // cleanup hid (also the approved additions hidden-sub-controls / home-menu-standalone and three Footer pages). export const verificationTaggedIds = ['sw-header--window-move-motion', 'sw-header--k-guide', 'sw-header--interactive-states', 'sw-header--document-dropdown', 'sw-header--composed-controls'] export const menuCleanupHiddenIds = ['sw-header--interactive-states', 'sw-header--document-dropdown', 'sw-header--hidden-sub-controls', 'sw-header--home-menu-standalone', ...['tool-groups', 'custom-content', 'parts'].map(id => `sw-footer--${id}`), // Second pass (same day): SW/Theme hidden as a whole; Viewer settings-panel merged into content-variants. 'sw-header--document-open', 'sw-header--composed-controls', ...themeStoryIds, ...['menu-groups', 'states', 'dropdowns', 'variable-size', 'settings-panel'].map(id => `sw-viewer--${id}`)] export const renamedEntries = { 'sw-header--overview': 'SW Header', 'sw-footer--full-footer': 'SW Footer', 'sw-footer--responsive': 'Responsive More', 'sw-viewer--content-variants': 'Settings Popup', 'sw-viewer--responsive': 'Responsive More' } // 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] } if (verificationTaggedIds.includes(entry.id)) return { ...entry, tags: [...entry.tags, 'verification'] } if (!movedToPopupIds.includes(entry.id)) return entry const { componentPath, ...rest } = entry return { ...rest, title: 'SW/Popup', importPath: './src/sw/sw-property-panel.stories.tsx' } } // 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 = { // 170a5c2 (home menu, measured More) and 2b0e1a2 (exported for the moved Popup Story) were superseded by 23d522c. WindowMoveMotion: '2b0e1a2262002aedb01c29c5d18ffae1219bf3ef', KGuide: '2b0e1a2262002aedb01c29c5d18ffae1219bf3ef', // verification tag // 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', // 2fc1b3e (2026-10-21 SW design review, user-approved): Overview passes the Bar title 원; ComposedDemo shows the Bar // values read-only in the approved order. Responsive More widths 1920 … 760 (MORE_WIDTHS, a non-export). Overview: '2fc1b3e1084840277898061f04844dcb05b9349c', ComposedDemo: '2fc1b3e1084840277898061f04844dcb05b9349c', } 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 // detail-buttons compare an earlier SW/Header inventory or source with today's through the approved changes below. // Retired after the Dropdown consolidation and absent today (the Popup move keeps its ID: withApprovedEntryChanges). export const laterRetiredHeaderIds = [...retiredPropertyPanelIds, ...retiredUnusedDemoIds] // The approved additions that sit under SW/Header. export const approvedAddedHeaderIds = approvedAddedStoryIds.filter(id => id.startsWith('sw-header--')) // An earlier SW/Header entry list against today's index: `changed` (ID, name, title or tags differ from the earlier entry // with the approved changes applied), `unexpected` (SW/Header Stories neither retained nor approved), `missing` (approved // additions not under SW/Header) and `retiredPresent` (an approved retirement back in the index). export const headerInventoryIssues = (entries, index) => { const expected = retainedInventory(entries).filter(entry => !laterRetiredHeaderIds.includes(entry.id)).map(withApprovedEntryChanges) const signature = entry => entry && JSON.stringify([entry.id, entry.name, entry.title, entry.tags]) const current = swStoryEntries(index) const issues = { actual: current.length, expected: expected.filter(entry => entry.title === 'SW/Header').length + approvedAddedHeaderIds.length, changed: expected.filter(entry => signature(entry) !== signature(index.entries[entry.id])).map(entry => entry.id), unexpected: current.filter(entry => !expected.some(item => item.id === entry.id) && !approvedAddedHeaderIds.includes(entry.id)).map(entry => entry.id), missing: approvedAddedHeaderIds.filter(id => index.entries[id]?.title !== 'SW/Header'), retiredPresent: [...retiredStage1Ids, ...retiredDropdownIds, ...laterRetiredHeaderIds].filter(id => index.entries[id]), } return { ...issues, ok: issues.actual === issues.expected && ['changed', 'unexpected', 'missing', 'retiredPresent'].every(key => issues[key].length === 0) } } // src/sw/sw-header.stories.tsx top-level declarations (Story exports, helpers, fixtures, types; imports as // `import:`) that approved commits changed, added or removed after the stage-1 baseline 92830fe, under the last // commit that touched each. Each suite still excludes the declarations of its own change (Dropdown, motion, ComposedDemo, meta). export const approvedHeaderSourceChanges = { // chore(sw): improve interactive header story preview (Overview itself changed again in 170a5c2) 'bf16578226fe89e5d9a6ba904b7979bebb602661': ['import:./sw-header-overview'], // refactor(storybook): consolidate property panel comparison layout (retiredPropertyPanelIds) 'c8e5fbeebc26fba92998fc5ddcd28c6c110e452d': ['PropertyCompare', 'PropertyPanelVariants', 'PropertyStateStory', 'PropertyPanelNone', 'PropertyPanelAll', 'PropertyPanelCircle', 'PropertyPanelExpanded'], // refactor(storybook): remove unused SW header demo stories (retiredUnusedDemoIds and the demo code only they used) '5faa1f1ffe89eb7aeb4aaec81ac5bb2d0f4fced9': ['StyleHostProps', 'StyleHeader', 'FIGMA_LAYERS', 'noop', 'LayerHostProps', 'describeLayers', 'LayerHeader', 'LayerDemo', 'InputDemo', 'LayerDetailInput', 'PropertyPanelDemo', 'PropertyPanel', 'RequiredColorDemo', 'AdditionalHover', 'PropertyBarDemo', 'PropertyBar', 'CONTROL_FIXTURE', 'DynamicControlsDemo', 'DynamicControls', 'Colorize', 'HIDEABLE_PARTS', 'MENU_IDS', 'COMPOSITION_PRESETS', 'CompositionDemo', 'Composition', 'SampleShapeViewer', 'SHAPE_MODES', 'SHAPE_MODE_LABELS', 'ShapeSlotDemo', 'PropertyShapeSlot', 'FIELD_NODES', 'FIELD_FIXTURE', 'FIELD_HOVER', 'FieldPanel', 'PropertyFieldsDemo', 'PropertyFields', 'import:./assets/figma-reference/btn-detail-layer-26-10767.png', 'import:./assets/figma-reference/input-26-11656.png'], // feat(sw): integrate responsive home menu into header '170a5c23aed10f8fc65e5b20e9b94bd3c1ff1227': ['import:@hm-design/sw', 'import:./sw-home-menu-fixture', 'OVERVIEW_HOME_MENU', 'Overview', 'MeasuredMoreDemo', 'ResponsiveMore'], // refactor(sw): simplify storybook navigation and examples (verification tags, Popup move) '2b0e1a2262002aedb01c29c5d18ffae1219bf3ef': ['meta', 'WindowMoveMotion', 'KGuide', 'PropertyPanelCompare', 'PropertyPanelComparePage'], // feat(sw): viewer header logo menu and file list; simplify SW Storybook (2026-10-21 user-approved Storybook cleanup: // Overview renamed, two Stories tagged verification, Responsive More reduced to 1440 / 768 / 390 (StyleDemo and // MeasuredMoreDemo removed), property-panel comparison captions removed). Listed last so it wins for repeated names. '23d522c13627ed26ac3e4cbeaaa8359b34c60aab': ['import:@hm-design/sw', 'Overview', 'InteractiveStates', 'DocumentDropdown', 'MORE_WIDTHS', 'ResponsiveMore', 'PROPERTY_STATES', 'PropertyCompare', 'PropertyPanelComparePage', 'StyleDemo', 'MeasuredMoreDemo'], // fix(sw): 2026-10-21 SW design review (user-approved): Overview Bar title, Responsive More 1920 / 1440 / 1280 / 950 / // 860 / 760 (no More from 760px), property fixture (선꼴, editable 원주 / 면적, weight annotation), Bar fixture computed // in the order 반지름 / 지름 / 원주 / 면적 with BAR_TITLE 원, ComposedDemo Bar read-only. Listed last so it wins. '2fc1b3e1084840277898061f04844dcb05b9349c': ['Overview', 'ComposedDemo', 'MORE_WIDTHS', 'PROPERTY_FIXTURE', 'BAR_TITLE', 'BAR_FIXTURE'], } const approvedHeaderSourceCommit = Object.fromEntries(Object.entries(approvedHeaderSourceChanges).flatMap(([commit, names]) => names.map(name => [name, commit]))) // Declarations among `names` that differ between `base` and `current` without an approved change: none listed, or the // current text differs from the approving commit's, or that commit did not change it. `at(ref)` returns the declaration // map of the file at a Git ref, keyed like `base` and `current`. export const headerSourceIssues = (names, base, current, at) => { const cache = new Map(), version = ref => { if (!cache.has(ref)) cache.set(ref, at(ref)); return cache.get(ref) } return names.filter(name => base[name] !== current[name]).filter(name => { const commit = approvedHeaderSourceCommit[name] return !commit || current[name] !== version(commit)[name] || version(`${commit}^`)[name] === version(commit)[name] }) }