diff --git a/docs/sw/storybook-overview-qa/after-index.json b/docs/sw/storybook-overview-qa/after-index.json new file mode 100644 index 0000000..d3311f8 --- /dev/null +++ b/docs/sw/storybook-overview-qa/after-index.json @@ -0,0 +1,423 @@ +[ + { + "type": "story", + "subtype": "story", + "id": "sw-header--detail-buttons", + "name": "Detail Buttons (Shared States)", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest", + "verification" + ], + "exportName": "DetailButtons" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--overview", + "name": "Overview", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "Overview" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--interactive-states", + "name": "Interactive States", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "InteractiveStates" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--window-move-motion", + "name": "Window Move Motion", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "WindowMoveMotion" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--composed-controls", + "name": "Composed Controls", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "ComposedControls" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--logo-slot", + "name": "Logo Slot", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "LogoSlot" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--document-dropdown", + "name": "Document Dropdown", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "DocumentDropdown" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--layer-dropdown", + "name": "Layer Dropdown", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "LayerDropdown" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--color-dropdown", + "name": "Color Dropdown", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "ColorDropdown" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--line-style-dropdown", + "name": "Line Style Dropdown", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "LineStyleDropdown" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--text-dimension-style-dropdown", + "name": "Text · Dimension Style Dropdown", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "TextDimensionStyleDropdown" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--responsive-more", + "name": "Responsive More", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "ResponsiveMore" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--layer-detail-input", + "name": "Layer Detail · Input", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "LayerDetailInput" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-panel", + "name": "Property Panel", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyPanel" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-panel-variants", + "name": "Property Panel Variants", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyPanelVariants" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--k-guide", + "name": "K Guide", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "KGuide" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--additional-hover", + "name": "Additional Hover", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "AdditionalHover" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-bar", + "name": "Property Bar", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyBar" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--dynamic-controls", + "name": "Dynamic Controls", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "DynamicControls" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--colorize", + "name": "Colorize", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "Colorize" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--composition", + "name": "Composition (Visibility · Order)", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "Composition" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-panel-none", + "name": "Property Panel · 선택 없음", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyPanelNone" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-panel-all", + "name": "Property Panel · 전체 선택", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyPanelAll" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-panel-circle", + "name": "Property Panel · 원 1개", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyPanelCircle" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-panel-expanded", + "name": "Property Panel · 모두 펼침", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyPanelExpanded" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-panel-compare", + "name": "Property Panel · 4개 비교", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyPanelCompare" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-shape-slot", + "name": "Property Panel · 형상 Slot", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyShapeSlot" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-fields", + "name": "Property Panel · 필드 13개", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyFields" + } +] diff --git a/docs/sw/storybook-overview-qa/before-index.json b/docs/sw/storybook-overview-qa/before-index.json new file mode 100644 index 0000000..d3311f8 --- /dev/null +++ b/docs/sw/storybook-overview-qa/before-index.json @@ -0,0 +1,423 @@ +[ + { + "type": "story", + "subtype": "story", + "id": "sw-header--detail-buttons", + "name": "Detail Buttons (Shared States)", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest", + "verification" + ], + "exportName": "DetailButtons" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--overview", + "name": "Overview", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "Overview" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--interactive-states", + "name": "Interactive States", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "InteractiveStates" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--window-move-motion", + "name": "Window Move Motion", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "WindowMoveMotion" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--composed-controls", + "name": "Composed Controls", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "ComposedControls" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--logo-slot", + "name": "Logo Slot", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "LogoSlot" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--document-dropdown", + "name": "Document Dropdown", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "DocumentDropdown" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--layer-dropdown", + "name": "Layer Dropdown", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "LayerDropdown" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--color-dropdown", + "name": "Color Dropdown", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "ColorDropdown" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--line-style-dropdown", + "name": "Line Style Dropdown", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "LineStyleDropdown" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--text-dimension-style-dropdown", + "name": "Text · Dimension Style Dropdown", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "TextDimensionStyleDropdown" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--responsive-more", + "name": "Responsive More", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "ResponsiveMore" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--layer-detail-input", + "name": "Layer Detail · Input", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "LayerDetailInput" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-panel", + "name": "Property Panel", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyPanel" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-panel-variants", + "name": "Property Panel Variants", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyPanelVariants" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--k-guide", + "name": "K Guide", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "KGuide" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--additional-hover", + "name": "Additional Hover", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "AdditionalHover" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-bar", + "name": "Property Bar", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyBar" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--dynamic-controls", + "name": "Dynamic Controls", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "DynamicControls" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--colorize", + "name": "Colorize", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "Colorize" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--composition", + "name": "Composition (Visibility · Order)", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "Composition" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-panel-none", + "name": "Property Panel · 선택 없음", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyPanelNone" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-panel-all", + "name": "Property Panel · 전체 선택", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyPanelAll" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-panel-circle", + "name": "Property Panel · 원 1개", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyPanelCircle" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-panel-expanded", + "name": "Property Panel · 모두 펼침", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyPanelExpanded" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-panel-compare", + "name": "Property Panel · 4개 비교", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyPanelCompare" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-shape-slot", + "name": "Property Panel · 형상 Slot", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyShapeSlot" + }, + { + "type": "story", + "subtype": "story", + "id": "sw-header--property-fields", + "name": "Property Panel · 필드 13개", + "title": "SW/Header", + "importPath": "./src/sw/sw-header.stories.tsx", + "componentPath": "./packages/sw/dist/index.js", + "tags": [ + "dev", + "test", + "manifest" + ], + "exportName": "PropertyFields" + } +] diff --git a/docs/sw/storybook-overview-qa/changed-files.json b/docs/sw/storybook-overview-qa/changed-files.json new file mode 100644 index 0000000..c5945d8 --- /dev/null +++ b/docs/sw/storybook-overview-qa/changed-files.json @@ -0,0 +1,234 @@ +[ + { + "status": " M", + "path": "src/sw/sw-header.stories.tsx" + }, + { + "status": " M", + "path": "src/sw/sw-stories.css" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/after-index.json" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/before-index.json" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/chrome-overlays-result.json" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/chrome-result.json" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/firefox-initial-infrastructure-result.json" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/firefox-result.json" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/initial-verifier-failure.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/manager-story-order.json" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/overview-after-expanded.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/overview-after-scrolled.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/overview-after.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/overview-before.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/overview-firefox-1400.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/overview-firefox-500.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/overview-manager.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/overview-narrow-overlay.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/overview-narrow.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/review-candidates.json" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screen-survey.json" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--additional-hover.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--color-dropdown.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--colorize.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--composed-controls.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--composition.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--detail-buttons.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--document-dropdown.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--dynamic-controls.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--interactive-states.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--k-guide.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--layer-detail-input.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--layer-dropdown.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--line-style-dropdown.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--logo-slot.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--overview.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--property-bar.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--property-fields.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--property-panel-all.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--property-panel-circle.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--property-panel-compare.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--property-panel-expanded.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--property-panel-none.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--property-panel-variants.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--property-panel.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--property-shape-slot.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--responsive-more.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--text-dimension-style-dropdown.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/screens/sw-header--window-move-motion.png" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/storybook-build.txt" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/sw-build.txt" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/sw-typecheck.txt" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/validation-summary.json" + }, + { + "status": "??", + "path": "docs/sw/sw-storybook-screen-review-2026-10-19.md" + }, + { + "status": "??", + "path": "packages/sw/tests/overview-firefox.browser.mjs" + }, + { + "status": "??", + "path": "packages/sw/tests/overview.browser.mjs" + }, + { + "status": "??", + "path": "src/sw/sw-header-overview.tsx" + }, + { + "status": "??", + "path": "docs/sw/storybook-overview-qa/changed-files.json" + } +] diff --git a/docs/sw/storybook-overview-qa/chrome-overlays-result.json b/docs/sw/storybook-overview-qa/chrome-overlays-result.json new file mode 100644 index 0000000..cfc59d5 --- /dev/null +++ b/docs/sw/storybook-overview-qa/chrome-overlays-result.json @@ -0,0 +1,104 @@ +{ + "baseCommit": "50bf5bda8e956a4973b923d64131f2f2285bd38c", + "checks": [ + { + "name": "all 28 Story IDs, names, order and tags retained", + "status": "PASS" + }, + { + "name": "other 27 Story declarations byte-identical", + "status": "PASS" + }, + { + "name": "package production source untouched", + "status": "PASS" + }, + { + "name": "document first row is above the property Bar and clickable", + "status": "PASS" + }, + { + "name": "existing 레이어 상세 reports Callback", + "status": "PASS" + }, + { + "name": "existing 색상 상세 reports Callback", + "status": "PASS" + }, + { + "name": "existing 선스타일 상세 reports Callback", + "status": "PASS" + }, + { + "name": "existing 문자스타일 상세 reports Callback", + "status": "PASS" + }, + { + "name": "existing 치수스타일 상세 reports Callback", + "status": "PASS" + }, + { + "name": "ByBlock mode immediately appears in Header without changing numeric RGB property", + "status": "PASS" + }, + { + "name": "direct color selection clears Header mode label", + "status": "PASS" + }, + { + "name": "small Inner layer dropdown stays in browser width", + "status": "PASS", + "data": { + "x": 141, + "y": 345.0625, + "width": 234, + "height": 250 + } + }, + { + "name": "small Inner lower layer row hit-test is unobstructed", + "status": "PASS" + }, + { + "name": "small Inner layer selection or Escape closes only nested dropdown", + "status": "PASS" + }, + { + "name": "small Inner line dropdown stays in browser width", + "status": "PASS", + "data": { + "x": 186, + "y": 39.0625, + "width": 189.1875, + "height": 342 + } + }, + { + "name": "small Inner line selection or Escape closes only nested dropdown", + "status": "PASS" + }, + { + "name": "small Inner color dropdown stays in browser width", + "status": "PASS", + "data": { + "x": 175, + "y": 377.0625, + "width": 192, + "height": 182 + } + }, + { + "name": "small Inner color selection or Escape closes only nested dropdown", + "status": "PASS" + }, + { + "name": "no overlay browser errors", + "status": "PASS", + "data": [] + } + ], + "errors": [], + "sizes": [], + "browser": "155.0.8059.80", + "status": "PASS" +} diff --git a/docs/sw/storybook-overview-qa/chrome-result.json b/docs/sw/storybook-overview-qa/chrome-result.json new file mode 100644 index 0000000..68a0805 --- /dev/null +++ b/docs/sw/storybook-overview-qa/chrome-result.json @@ -0,0 +1,670 @@ +{ + "baseCommit": "50bf5bda8e956a4973b923d64131f2f2285bd38c", + "checks": [ + { + "name": "all 28 Story IDs, names, order and tags retained", + "status": "PASS" + }, + { + "name": "other 27 Story declarations byte-identical", + "status": "PASS" + }, + { + "name": "package production source untouched", + "status": "PASS" + }, + { + "name": "16:9 fitted to both Inner dimensions at 1920x1080", + "status": "PASS", + "data": { + "stage": { + "x": 360, + "y": 264.25, + "w": 1200, + "h": 675, + "right": 1560, + "bottom": 939.25 + }, + "slot": { + "x": 360, + "y": 169.5, + "w": 1200, + "h": 864.5, + "right": 1560, + "bottom": 1034 + }, + "header": { + "x": 360, + "y": 264.25, + "w": 1200, + "h": 49, + "right": 1560, + "bottom": 313.25 + }, + "viewport": { + "w": 1920, + "h": 1080 + }, + "overflow": 0 + } + }, + { + "name": "16:9 fitted to both Inner dimensions at 1440x900", + "status": "PASS", + "data": { + "stage": { + "x": 120, + "y": 174.25, + "w": 1200, + "h": 675, + "right": 1320, + "bottom": 849.25 + }, + "slot": { + "x": 120, + "y": 169.5, + "w": 1200, + "h": 684.5, + "right": 1320, + "bottom": 854 + }, + "header": { + "x": 120, + "y": 174.25, + "w": 1200, + "h": 49, + "right": 1320, + "bottom": 223.25 + }, + "viewport": { + "w": 1440, + "h": 900 + }, + "overflow": 0 + } + }, + { + "name": "16:9 fitted to both Inner dimensions at 1280x720", + "status": "PASS", + "data": { + "stage": { + "x": 191.5625, + "y": 169.5, + "w": 896.875, + "h": 504.5, + "right": 1088.4375, + "bottom": 674 + }, + "slot": { + "x": 38.40625, + "y": 169.5, + "w": 1203.1875, + "h": 504.5, + "right": 1241.59375, + "bottom": 674 + }, + "header": { + "x": 191.5625, + "y": 169.5, + "w": 896.875, + "h": 49, + "right": 1088.4375, + "bottom": 218.5 + }, + "viewport": { + "w": 1280, + "h": 720 + }, + "overflow": 0 + } + }, + { + "name": "16:9 fitted to both Inner dimensions at 768x600", + "status": "PASS", + "data": { + "stage": { + "x": 42.21875, + "y": 169.5, + "w": 683.546875, + "h": 384.5, + "right": 725.765625, + "bottom": 554 + }, + "slot": { + "x": 23.046875, + "y": 169.5, + "w": 721.90625, + "h": 384.5, + "right": 744.953125, + "bottom": 554 + }, + "header": { + "x": 42.21875, + "y": 169.5, + "w": 683.546875, + "h": 49, + "right": 725.765625, + "bottom": 218.5 + }, + "viewport": { + "w": 768, + "h": 600 + }, + "overflow": 0 + } + }, + { + "name": "16:9 fitted to both Inner dimensions at 390x844", + "status": "PASS", + "data": { + "stage": { + "x": 16, + "y": 383.0625, + "w": 358, + "h": 201.375, + "right": 374, + "bottom": 584.4375 + }, + "slot": { + "x": 16, + "y": 169.5, + "w": 358, + "h": 628.5, + "right": 374, + "bottom": 798 + }, + "header": { + "x": 16, + "y": 383.0625, + "w": 390, + "h": 49, + "right": 406, + "bottom": 432.0625 + }, + "viewport": { + "w": 390, + "h": 844 + }, + "overflow": 0 + } + }, + { + "name": "16:9 fitted to both Inner dimensions at 1000x500", + "status": "PASS", + "data": { + "stage": { + "x": 247.109375, + "y": 169.5, + "w": 505.765625, + "h": 284.5, + "right": 752.875, + "bottom": 454 + }, + "slot": { + "x": 30, + "y": 169.5, + "w": 940, + "h": 284.5, + "right": 970, + "bottom": 454 + }, + "header": { + "x": 247.109375, + "y": 169.5, + "w": 505.765625, + "h": 49, + "right": 752.875, + "bottom": 218.5 + }, + "viewport": { + "w": 1000, + "h": 500 + }, + "overflow": 0 + } + }, + { + "name": "one Header and no duplicate fixed Figma specimen", + "status": "PASS" + }, + { + "name": "document selection updates Header and Callback", + "status": "PASS", + "data": "onDocumentClick → documentOpen(true) → onDocumentSelect(doc-2) → documentOpen(false)" + }, + { + "name": "layer selection updates shared data", + "status": "PASS", + "data": "onDocumentClick → documentOpen(true) → onDocumentSelect(doc-2) → documentOpen(false) → onLayerOpen → onLayerSelect(layer, CC-D GNL)" + }, + { + "name": "existing layer Detail callback closes list", + "status": "PASS" + }, + { + "name": "color selection invokes host callback", + "status": "PASS", + "data": "onLayerOpen → onLayerSelect(layer, CC-D GNL) → onLayerOpen → onLayerDetail → onColorOpen → onColorSelect(color, 255,255,255)" + }, + { + "name": "line selection updates Header", + "status": "PASS", + "data": "onLayerOpen → onLayerDetail → onColorOpen → onColorSelect(color, 255,255,255) → onLineStyleOpen → onLineTypeSelect(line, CENTER)" + }, + { + "name": "ByLayer weight mode does not turn numeric property into a mode string", + "status": "PASS" + }, + { + "name": "text style selection updates Header", + "status": "PASS", + "data": "onColorSelect(color, 255,255,255) → onLineStyleOpen → onLineTypeSelect(line, CENTER) → onLineWeightSelect(w-bylayer) → onTextStyleOpen → onTextStyleSelect(dotum)" + }, + { + "name": "dimension style selection updates Header", + "status": "PASS", + "data": "onLineTypeSelect(line, CENTER) → onLineWeightSelect(w-bylayer) → onTextStyleOpen → onTextStyleSelect(dotum) → onDimensionStyleOpen → onDimensionStyleSelect(iso-25)" + }, + { + "name": "opening another dropdown closes the previous one", + "status": "PASS" + }, + { + "name": "Escape closes Header dropdown", + "status": "PASS" + }, + { + "name": "outside click closes Header dropdown", + "status": "PASS" + }, + { + "name": "Bar Enter commits state", + "status": "PASS" + }, + { + "name": "Bar validates min=0", + "status": "PASS" + }, + { + "name": "Bar Escape cancels edit", + "status": "PASS" + }, + { + "name": "Header opens panel with same Bar value", + "status": "PASS" + }, + { + "name": "numeric weight property remains numeric after ByLayer mode", + "status": "PASS" + }, + { + "name": "Header layer value shared with panel", + "status": "PASS" + }, + { + "name": "panel edit updates the Bar", + "status": "PASS" + }, + { + "name": "panel number validation rejects negative radius", + "status": "PASS" + }, + { + "name": "panel Layer dropdown updates Header shared value", + "status": "PASS" + }, + { + "name": "panel line dropdown updates Header shared value", + "status": "PASS" + }, + { + "name": "panel color dropdown updates Header shared value", + "status": "PASS" + }, + { + "name": "panel RGB validation rejects out-of-range value", + "status": "PASS" + }, + { + "name": "gauge keyboard editing commits host state", + "status": "PASS" + }, + { + "name": "first Escape cancels draft and retains panel", + "status": "PASS" + }, + { + "name": "next Escape closes panel and restores Header focus", + "status": "PASS" + }, + { + "name": "panel Close button restores focus", + "status": "PASS" + }, + { + "name": "external Props update Bar", + "status": "PASS" + }, + { + "name": "Bar ReadOnly", + "status": "PASS" + }, + { + "name": "Bar Disabled", + "status": "PASS" + }, + { + "name": "dynamic Bar field added", + "status": "PASS" + }, + { + "name": "dynamic field shared with panel", + "status": "PASS" + }, + { + "name": "dynamic field removed from both", + "status": "PASS" + }, + { + "name": "shape Slot can be empty without changing panel structure", + "status": "PASS" + }, + { + "name": "original panel size none:314x256", + "status": "PASS", + "data": { + "x": 1000, + "y": 301.25, + "width": 314, + "height": 256 + } + }, + { + "name": "original panel size all:314x361", + "status": "PASS", + "data": { + "x": 1000, + "y": 301.25, + "width": 314, + "height": 361 + } + }, + { + "name": "original panel size circle:314x658", + "status": "PASS", + "data": { + "x": 1000, + "y": 301.25, + "width": 314, + "height": 658 + } + }, + { + "name": "original panel size expanded:314x754", + "status": "PASS", + "data": { + "x": 1000, + "y": 301.25, + "width": 314, + "height": 754 + } + }, + { + "name": "expanded popup bottom accessible through internal scroll", + "status": "PASS" + }, + { + "name": "small Inner reaches full popup bottom with native Header and popup dimensions", + "status": "PASS", + "data": { + "top": 630, + "left": 16, + "height": 201, + "scrollHeight": 831, + "width": 358, + "scrollWidth": 390 + } + }, + { + "name": "narrow popup Escape restores More focus", + "status": "PASS" + }, + { + "name": "actual Storybook manager iframe fits its own Inner", + "status": "PASS", + "data": { + "width": 1071.59375, + "height": 602.765625, + "slotWidth": 1071.59375, + "slotHeight": 744.5, + "viewportWidth": 1140, + "viewportHeight": 960 + } + }, + { + "name": "no browser errors", + "status": "PASS", + "data": [] + } + ], + "errors": [], + "sizes": [ + { + "stage": { + "x": 360, + "y": 264.25, + "w": 1200, + "h": 675, + "right": 1560, + "bottom": 939.25 + }, + "slot": { + "x": 360, + "y": 169.5, + "w": 1200, + "h": 864.5, + "right": 1560, + "bottom": 1034 + }, + "header": { + "x": 360, + "y": 264.25, + "w": 1200, + "h": 49, + "right": 1560, + "bottom": 313.25 + }, + "viewport": { + "w": 1920, + "h": 1080 + }, + "overflow": 0 + }, + { + "stage": { + "x": 120, + "y": 174.25, + "w": 1200, + "h": 675, + "right": 1320, + "bottom": 849.25 + }, + "slot": { + "x": 120, + "y": 169.5, + "w": 1200, + "h": 684.5, + "right": 1320, + "bottom": 854 + }, + "header": { + "x": 120, + "y": 174.25, + "w": 1200, + "h": 49, + "right": 1320, + "bottom": 223.25 + }, + "viewport": { + "w": 1440, + "h": 900 + }, + "overflow": 0 + }, + { + "stage": { + "x": 191.5625, + "y": 169.5, + "w": 896.875, + "h": 504.5, + "right": 1088.4375, + "bottom": 674 + }, + "slot": { + "x": 38.40625, + "y": 169.5, + "w": 1203.1875, + "h": 504.5, + "right": 1241.59375, + "bottom": 674 + }, + "header": { + "x": 191.5625, + "y": 169.5, + "w": 896.875, + "h": 49, + "right": 1088.4375, + "bottom": 218.5 + }, + "viewport": { + "w": 1280, + "h": 720 + }, + "overflow": 0 + }, + { + "stage": { + "x": 42.21875, + "y": 169.5, + "w": 683.546875, + "h": 384.5, + "right": 725.765625, + "bottom": 554 + }, + "slot": { + "x": 23.046875, + "y": 169.5, + "w": 721.90625, + "h": 384.5, + "right": 744.953125, + "bottom": 554 + }, + "header": { + "x": 42.21875, + "y": 169.5, + "w": 683.546875, + "h": 49, + "right": 725.765625, + "bottom": 218.5 + }, + "viewport": { + "w": 768, + "h": 600 + }, + "overflow": 0 + }, + { + "stage": { + "x": 16, + "y": 383.0625, + "w": 358, + "h": 201.375, + "right": 374, + "bottom": 584.4375 + }, + "slot": { + "x": 16, + "y": 169.5, + "w": 358, + "h": 628.5, + "right": 374, + "bottom": 798 + }, + "header": { + "x": 16, + "y": 383.0625, + "w": 390, + "h": 49, + "right": 406, + "bottom": 432.0625 + }, + "viewport": { + "w": 390, + "h": 844 + }, + "overflow": 0 + }, + { + "stage": { + "x": 247.109375, + "y": 169.5, + "w": 505.765625, + "h": 284.5, + "right": 752.875, + "bottom": 454 + }, + "slot": { + "x": 30, + "y": 169.5, + "w": 940, + "h": 284.5, + "right": 970, + "bottom": 454 + }, + "header": { + "x": 247.109375, + "y": 169.5, + "w": 505.765625, + "h": 49, + "right": 752.875, + "bottom": 218.5 + }, + "viewport": { + "w": 1000, + "h": 500 + }, + "overflow": 0 + } + ], + "browser": "155.0.8059.80", + "managerOrder": [ + "sw-header--overview", + "sw-header--interactive-states", + "sw-header--window-move-motion", + "sw-header--composed-controls", + "sw-header--logo-slot", + "sw-header--document-dropdown", + "sw-header--layer-dropdown", + "sw-header--color-dropdown", + "sw-header--line-style-dropdown", + "sw-header--text-dimension-style-dropdown", + "sw-header--responsive-more", + "sw-header--layer-detail-input", + "sw-header--property-panel", + "sw-header--property-panel-variants", + "sw-header--k-guide", + "sw-header--additional-hover", + "sw-header--property-bar", + "sw-header--dynamic-controls", + "sw-header--colorize", + "sw-header--composition", + "sw-header--property-panel-none", + "sw-header--property-panel-all", + "sw-header--property-panel-circle", + "sw-header--property-panel-expanded", + "sw-header--property-panel-compare", + "sw-header--property-shape-slot", + "sw-header--property-fields" + ], + "status": "PASS" +} diff --git a/docs/sw/storybook-overview-qa/firefox-initial-infrastructure-result.json b/docs/sw/storybook-overview-qa/firefox-initial-infrastructure-result.json new file mode 100644 index 0000000..6fa7b70 --- /dev/null +++ b/docs/sw/storybook-overview-qa/firefox-initial-infrastructure-result.json @@ -0,0 +1,86 @@ +{ + "checks": [ + { + "name": "Firefox 1400: 16:9 in Inner and Header 49", + "status": "PASS", + "data": { + "width": 1200, + "height": 675, + "slotWidth": 1200, + "slotHeight": 702.5, + "headerHeight": 49, + "viewportWidth": 1400, + "viewportHeight": 915 + } + }, + { + "name": "Firefox 1400: full original popup 314x754", + "status": "PASS", + "data": { + "width": 314, + "height": 754, + "focus": false + } + }, + { + "name": "Firefox 1400: popup bottom reachable and focusable", + "status": "PASS", + "data": { + "top": 156, + "visible": true + } + }, + { + "name": "Firefox 1400: Escape closes popup and restores focus", + "status": "PASS" + }, + { + "name": "Firefox 500: 16:9 in Inner and Header 49", + "status": "PASS", + "data": { + "width": 468, + "height": 263.25, + "slotWidth": 468, + "slotHeight": 502.5, + "headerHeight": 49, + "viewportWidth": 500, + "viewportHeight": 715 + } + }, + { + "name": "Firefox 500: full original popup 314x754", + "status": "PASS", + "data": { + "width": 314, + "height": 754, + "focus": false + } + }, + { + "name": "Firefox 500: popup bottom reachable and focusable", + "status": "PASS", + "data": { + "top": 567.75, + "visible": true + } + }, + { + "name": "Firefox 500: Escape closes popup and restores focus", + "status": "PASS" + }, + { + "name": "Firefox browser errors absent", + "status": "FAIL", + "data": [ + "downloadable font: download failed (font-family: \"Nunito Sans\" style:normal weight:400 width:100 src index:0): status=2147746065 source: http://127.0.0.1:12495/sb-common-assets/nunito-sans-regular.woff2", + "downloadable font: download failed (font-family: \"Nunito Sans\" style:normal weight:400 width:100 src index:0): status=2147746065 source: http://127.0.0.1:12495/sb-common-assets/nunito-sans-regular.woff2" + ] + } + ], + "errors": [ + "downloadable font: download failed (font-family: \"Nunito Sans\" style:normal weight:400 width:100 src index:0): status=2147746065 source: http://127.0.0.1:12495/sb-common-assets/nunito-sans-regular.woff2", + "downloadable font: download failed (font-family: \"Nunito Sans\" style:normal weight:400 width:100 src index:0): status=2147746065 source: http://127.0.0.1:12495/sb-common-assets/nunito-sans-regular.woff2" + ], + "version": "158.0", + "status": "FAIL" +} diff --git a/docs/sw/storybook-overview-qa/firefox-result.json b/docs/sw/storybook-overview-qa/firefox-result.json new file mode 100644 index 0000000..ea9b253 --- /dev/null +++ b/docs/sw/storybook-overview-qa/firefox-result.json @@ -0,0 +1,90 @@ +{ + "checks": [ + { + "name": "Firefox 1400: 16:9 in Inner and Header 49", + "status": "PASS", + "data": { + "width": 1200, + "height": 675, + "slotWidth": 1200, + "slotHeight": 700.5, + "headerHeight": 49, + "viewportWidth": 1400, + "viewportHeight": 915 + } + }, + { + "name": "Firefox 1400: full original popup 314x754", + "status": "PASS", + "data": { + "width": 314, + "height": 754, + "focus": false + } + }, + { + "name": "Firefox 1400: popup bottom reachable and focusable", + "status": "PASS", + "data": { + "top": 156, + "visible": true + } + }, + { + "name": "Firefox 1400: Escape closes popup and restores focus", + "status": "PASS" + }, + { + "name": "Firefox 500: 16:9 in Inner and Header 49", + "status": "PASS", + "data": { + "width": 468, + "height": 263.25, + "slotWidth": 468, + "slotHeight": 502.5, + "headerHeight": 49, + "viewportWidth": 500, + "viewportHeight": 715 + } + }, + { + "name": "Firefox 500: full original popup 314x754", + "status": "PASS", + "data": { + "width": 314, + "height": 754, + "focus": false + } + }, + { + "name": "Firefox 500: popup bottom reachable and focusable", + "status": "PASS", + "data": { + "top": 567.75, + "visible": true + } + }, + { + "name": "Firefox 500: Escape closes popup and restores focus", + "status": "PASS" + }, + { + "name": "Firefox SW runtime errors absent; known Storybook font warnings recorded separately", + "status": "PASS", + "data": { + "errors": [], + "warnings": [ + "downloadable font: download failed (font-family: \"Nunito Sans\" style:normal weight:400 width:100 src index:0): status=2147746065 source: http://127.0.0.1:8191/sb-common-assets/nunito-sans-regular.woff2", + "downloadable font: download failed (font-family: \"Nunito Sans\" style:normal weight:400 width:100 src index:0): status=2147746065 source: http://127.0.0.1:8191/sb-common-assets/nunito-sans-regular.woff2" + ] + } + } + ], + "errors": [], + "infrastructureWarnings": [ + "downloadable font: download failed (font-family: \"Nunito Sans\" style:normal weight:400 width:100 src index:0): status=2147746065 source: http://127.0.0.1:8191/sb-common-assets/nunito-sans-regular.woff2", + "downloadable font: download failed (font-family: \"Nunito Sans\" style:normal weight:400 width:100 src index:0): status=2147746065 source: http://127.0.0.1:8191/sb-common-assets/nunito-sans-regular.woff2" + ], + "version": "158.0", + "status": "PASS" +} diff --git a/docs/sw/storybook-overview-qa/initial-verifier-failure.png b/docs/sw/storybook-overview-qa/initial-verifier-failure.png new file mode 100644 index 0000000..5a7c188 Binary files /dev/null and b/docs/sw/storybook-overview-qa/initial-verifier-failure.png differ diff --git a/docs/sw/storybook-overview-qa/manager-story-order.json b/docs/sw/storybook-overview-qa/manager-story-order.json new file mode 100644 index 0000000..8f3393c --- /dev/null +++ b/docs/sw/storybook-overview-qa/manager-story-order.json @@ -0,0 +1,29 @@ +[ + "sw-header--overview", + "sw-header--interactive-states", + "sw-header--window-move-motion", + "sw-header--composed-controls", + "sw-header--logo-slot", + "sw-header--document-dropdown", + "sw-header--layer-dropdown", + "sw-header--color-dropdown", + "sw-header--line-style-dropdown", + "sw-header--text-dimension-style-dropdown", + "sw-header--responsive-more", + "sw-header--layer-detail-input", + "sw-header--property-panel", + "sw-header--property-panel-variants", + "sw-header--k-guide", + "sw-header--additional-hover", + "sw-header--property-bar", + "sw-header--dynamic-controls", + "sw-header--colorize", + "sw-header--composition", + "sw-header--property-panel-none", + "sw-header--property-panel-all", + "sw-header--property-panel-circle", + "sw-header--property-panel-expanded", + "sw-header--property-panel-compare", + "sw-header--property-shape-slot", + "sw-header--property-fields" +] diff --git a/docs/sw/storybook-overview-qa/overview-after-expanded.png b/docs/sw/storybook-overview-qa/overview-after-expanded.png new file mode 100644 index 0000000..9afb4cf Binary files /dev/null and b/docs/sw/storybook-overview-qa/overview-after-expanded.png differ diff --git a/docs/sw/storybook-overview-qa/overview-after-scrolled.png b/docs/sw/storybook-overview-qa/overview-after-scrolled.png new file mode 100644 index 0000000..dc5d847 Binary files /dev/null and b/docs/sw/storybook-overview-qa/overview-after-scrolled.png differ diff --git a/docs/sw/storybook-overview-qa/overview-after.png b/docs/sw/storybook-overview-qa/overview-after.png new file mode 100644 index 0000000..8a64869 Binary files /dev/null and b/docs/sw/storybook-overview-qa/overview-after.png differ diff --git a/docs/sw/storybook-overview-qa/overview-before.png b/docs/sw/storybook-overview-qa/overview-before.png new file mode 100644 index 0000000..e6d87e3 Binary files /dev/null and b/docs/sw/storybook-overview-qa/overview-before.png differ diff --git a/docs/sw/storybook-overview-qa/overview-firefox-1400.png b/docs/sw/storybook-overview-qa/overview-firefox-1400.png new file mode 100644 index 0000000..6e52ab3 Binary files /dev/null and b/docs/sw/storybook-overview-qa/overview-firefox-1400.png differ diff --git a/docs/sw/storybook-overview-qa/overview-firefox-500.png b/docs/sw/storybook-overview-qa/overview-firefox-500.png new file mode 100644 index 0000000..bae769c Binary files /dev/null and b/docs/sw/storybook-overview-qa/overview-firefox-500.png differ diff --git a/docs/sw/storybook-overview-qa/overview-manager.png b/docs/sw/storybook-overview-qa/overview-manager.png new file mode 100644 index 0000000..f44c5ac Binary files /dev/null and b/docs/sw/storybook-overview-qa/overview-manager.png differ diff --git a/docs/sw/storybook-overview-qa/overview-narrow-overlay.png b/docs/sw/storybook-overview-qa/overview-narrow-overlay.png new file mode 100644 index 0000000..7aff1f1 Binary files /dev/null and b/docs/sw/storybook-overview-qa/overview-narrow-overlay.png differ diff --git a/docs/sw/storybook-overview-qa/overview-narrow.png b/docs/sw/storybook-overview-qa/overview-narrow.png new file mode 100644 index 0000000..134f239 Binary files /dev/null and b/docs/sw/storybook-overview-qa/overview-narrow.png differ diff --git a/docs/sw/storybook-overview-qa/review-candidates.json b/docs/sw/storybook-overview-qa/review-candidates.json new file mode 100644 index 0000000..6caf03a --- /dev/null +++ b/docs/sw/storybook-overview-qa/review-candidates.json @@ -0,0 +1,366 @@ +[ + { + "number": "V-01", + "name": "Overview", + "id": "sw-header--overview", + "status": "KEEP", + "audience": "통합 시연 / 사용자", + "content": "16:9 Stage에서 Header·전체 Dropdown·속성Bar·속성창·공유 속성을 조작.", + "proposal": "현재 메인으로 유지.", + "impact": "중간", + "loss": "대체 메인 없음. 이번에 실제 수정한 유일한 Story.", + "url": "http://localhost:6024/?path=/story/sw-header--overview", + "screenshot": "overview-after.png" + }, + { + "number": "V-02", + "name": "Interactive States", + "id": "sw-header--interactive-states", + "status": "SIMPLIFY", + "audience": "상태 비교 / 사용자·QA", + "content": "12개 섹션: Host state, Hover/Selected/Disabled, 토글, 창 버튼 Callback, 긴 파일명.", + "proposal": "반복 Header 표본과 설명을 상태별로 축소 검토.", + "impact": "낮음", + "loss": "삭제하면 Disabled+Hover·키보드·창 버튼 Callback 비교를 잃음. 메인은 상태 비교표를 대체하지 않음.", + "url": "http://localhost:6024/?path=/story/sw-header--interactive-states", + "screenshot": "screens/sw-header--interactive-states.png" + }, + { + "number": "V-03", + "name": "Window Move Motion", + "id": "sw-header--window-move-motion", + "status": "KEEP", + "audience": "단계별 실컴포넌트 정지 표본 / QA", + "content": "기존 9단계의 창 이동 모션을 3배 확대.", + "proposal": "이번에 확정한 단계별 섹션 그대로 유지.", + "impact": "낮음", + "loss": "타이밍·위치 비교의 유일한 상세 화면. 메인의 실시간 Hover와 목적이 다름.", + "url": "http://localhost:6024/?path=/story/sw-header--window-move-motion", + "screenshot": "screens/sw-header--window-move-motion.png" + }, + { + "number": "V-04", + "name": "Composed Controls", + "id": "sw-header--composed-controls", + "status": "KEEP", + "audience": "하위 컴포넌트 조합 / 사용자", + "content": "레이어·색상·상세보기, 선·문자·치수 공개 하위 컴포넌트와 그룹 Hover.", + "proposal": "독립 조합 API 사용 예제로 유지.", + "impact": "중간", + "loss": "전체 Header 통합 시연으로 하위 컴포넌트 단독 조합을 대체할 수 없음.", + "url": "http://localhost:6024/?path=/story/sw-header--composed-controls", + "screenshot": "screens/sw-header--composed-controls.png" + }, + { + "number": "V-05", + "name": "Logo Slot", + "id": "sw-header--logo-slot", + "status": "KEEP", + "audience": "설정 예제 / 사용자", + "content": "기본 임시 로고, 가로형 logoSrc, 세로형 React logo, 미전달 4개 표본.", + "proposal": "로고 슬롯 계약 예제로 유지.", + "impact": "낮음", + "loss": "삭제하면 이미지/ReactNode/미전달의 차이를 직접 확인할 수 없음.", + "url": "http://localhost:6024/?path=/story/sw-header--logo-slot", + "screenshot": "screens/sw-header--logo-slot.png" + }, + { + "number": "V-06", + "name": "Document Dropdown", + "id": "sw-header--document-dropdown", + "status": "SIMPLIFY", + "audience": "실제 조작+정적 상태 / 사용자·QA", + "content": "18개 섹션: 문서 선택·닫기·New/Open·현재 문서 위치·Hover·18개/빈 목록·긴 이름·390px.", + "proposal": "반복 현재 문서/Hover 표본을 한 비교 구역으로 줄이는 방안 검토.", + "impact": "중간", + "loss": "메인은 기본 선택·목록 변경을 대체하지만 빈 목록·긴 이름·행 위치·18개 스크롤 사례는 대체하지 않음.", + "url": "http://localhost:6024/?path=/story/sw-header--document-dropdown", + "screenshot": "screens/sw-header--document-dropdown.png" + }, + { + "number": "V-07", + "name": "Layer Dropdown", + "id": "sw-header--layer-dropdown", + "status": "SIMPLIFY", + "audience": "실제 조작+정적 상태 / 사용자·QA", + "content": "19개 섹션: 전구·눈꽃·잠금, 상태 혼합, 선택, 긴/빈/많은 레이어, 6개 좁은 폭.", + "proposal": "중복 Header 표본을 줄이고 아이콘 상태표·예외 사례 유지 검토.", + "impact": "중간", + "loss": "메인은 정상 선택·Toggle만 대체. On/Off/Hover 아이콘 매트릭스·20개 목록·Callback 없는 상태가 고유함.", + "url": "http://localhost:6024/?path=/story/sw-header--layer-dropdown", + "screenshot": "screens/sw-header--layer-dropdown.png" + }, + { + "number": "V-08", + "name": "Color Dropdown", + "id": "sw-header--color-dropdown", + "status": "SIMPLIFY", + "audience": "실제 조작+디자인 비교 / 사용자·QA", + "content": "9개 섹션: 팔레트·사용자 색상 40개·ByLayer·RGB 입력·Colorize·상세 Callback.", + "proposal": "반복 Default/Hover Header와 설명을 축소; Colorize 통합 목적지로 검토.", + "impact": "중간", + "loss": "메인의 색상 변경은 40개 색상·정적 Hover 비교를 대체하지 않음.", + "url": "http://localhost:6024/?path=/story/sw-header--color-dropdown", + "screenshot": "screens/sw-header--color-dropdown.png" + }, + { + "number": "V-09", + "name": "Line Style Dropdown", + "id": "sw-header--line-style-dropdown", + "status": "SIMPLIFY", + "audience": "실제 조작+디자인 비교 / 사용자·QA", + "content": "8개 섹션: 3열 선 종류·가중치·스케일, 현재 행/상세 Hover, 390px.", + "proposal": "중복 Default/Hover를 줄이고 3열 입력·좁은 화면 사례 보존 검토.", + "impact": "중간", + "loss": "메인은 정상 선택을 대체하지만 상세 상태·열 배치 기준은 남길 필요가 있음.", + "url": "http://localhost:6024/?path=/story/sw-header--line-style-dropdown", + "screenshot": "screens/sw-header--line-style-dropdown.png" + }, + { + "number": "V-10", + "name": "Text · Dimension Style Dropdown", + "id": "sw-header--text-dimension-style-dropdown", + "status": "KEEP", + "audience": "실제 조작+디자인 비교 / 사용자·QA", + "content": "문자·치수스타일 목록과 각 행·상세 Hover, 선택 Callback 등 6개 섹션.", + "proposal": "서로 다른 두 필드의 목록 계약을 함께 확인하는 현 구성 유지.", + "impact": "낮음", + "loss": "메인의 선택만으로 각 행 미리보기와 Figma Hover 비교를 대체하지 못함.", + "url": "http://localhost:6024/?path=/story/sw-header--text-dimension-style-dropdown", + "screenshot": "screens/sw-header--text-dimension-style-dropdown.png" + }, + { + "number": "V-11", + "name": "Responsive More", + "id": "sw-header--responsive-more", + "status": "SIMPLIFY", + "audience": "반응형 실제 조작+폭 표본 / 사용자·QA", + "content": "1440/768/390 조작 구역 3개 + 경계 폭 16개. More 대표 필드 전환과 Callback.", + "proposal": "경계 폭 표본을 접는 방식 등 화면 길이 축소 검토. 기능은 유지 권장.", + "impact": "중간", + "loss": "삭제한 Responsive와 다른 기능. 메인은 현재 폭만 보여 주므로 모든 경계값 비교를 대체하지 않음.", + "url": "http://localhost:6024/?path=/story/sw-header--responsive-more", + "screenshot": "screens/sw-header--responsive-more.png" + }, + { + "number": "V-12", + "name": "Layer Detail · Input", + "id": "sw-header--layer-detail-input", + "status": "MERGE REVIEW", + "audience": "상세 버튼+독립 Input / 사용자·QA", + "content": "6개 섹션: Figma PNG, 레이어 상세 3상태, Input Default/Hover/ReadOnly/Disabled/Focus 및 입력·IME·확정/취소.", + "proposal": "상세 버튼 비교는 Detail Buttons로 옮기는 방안 검토. 독립 Input 시연은 남겨야 함.", + "impact": "중간", + "loss": "독립 Input Story는 현재 없음. 페이지 전체를 지우면 텍스트/숫자·외부 Props·취소 예제를 잃음. detail-buttons 검증이 이 ID를 참조함.", + "url": "http://localhost:6024/?path=/story/sw-header--layer-detail-input", + "screenshot": "screens/sw-header--layer-detail-input.png" + }, + { + "number": "V-13", + "name": "Property Panel", + "id": "sw-header--property-panel", + "status": "KEEP", + "audience": "Header 연동과 데이터 변형 / 사용자·QA", + "content": "4가지 선택, Controlled/Uncontrolled, 외부 Open/값, 항목 추가·삭제·순서, 제한 상태·게이지.", + "proposal": "고급 데이터/API 검증 화면으로 유지.", + "impact": "중간", + "loss": "메인에 없는 Controlled 전환, 개별 제한·옵션 삭제·선택 객체 교체가 남음. Firefox·닫기·필드 테스트가 참조.", + "url": "http://localhost:6024/?path=/story/sw-header--property-panel", + "screenshot": "screens/sw-header--property-panel.png" + }, + { + "number": "V-14", + "name": "Property Panel Variants", + "id": "sw-header--property-panel-variants", + "status": "MERGE REVIEW", + "audience": "독립 패널과 데이터 변형 / QA", + "content": "같은 PropertyPanelDemo를 standalone으로 렌더링. 4상태·데이터 버튼이 Property Panel과 거의 동일.", + "proposal": "단독 패널 기준이 필요하면 4개 개별/4개 비교 화면과 통합 검토.", + "impact": "중간", + "loss": "Header Overlay·Focus 복귀와 다른 단독 맥락. standalone의 닫기는 기록만 하고 패널을 유지하며 너비/Open 버튼은 Header 연동 검증을 대신하지 못함.", + "url": "http://localhost:6024/?path=/story/sw-header--property-panel-variants", + "screenshot": "screens/sw-header--property-panel-variants.png" + }, + { + "number": "V-15", + "name": "K Guide", + "id": "sw-header--k-guide", + "status": "KEEP", + "audience": "실시간 모션 / 사용자", + "content": "K 버튼 Hover/Focus의 원본 이미지 Pan·Zoom, 이탈 정지, Reduced Motion 안내.", + "proposal": "고유한 가이드 모션 예제로 유지.", + "impact": "낮음", + "loss": "Header 실시간 모션과 창 이동 1400ms 모션은 별개. 메인에서는 일부만 볼 수 있음.", + "url": "http://localhost:6024/?path=/story/sw-header--k-guide", + "screenshot": "screens/sw-header--k-guide.png" + }, + { + "number": "V-16", + "name": "Additional Hover", + "id": "sw-header--additional-hover", + "status": "MERGE REVIEW", + "audience": "상세/Selected 회귀·외부 모드 / QA", + "content": "StyleDemo 1920과 RequiredColorDemo: 5개 상세 Hover, Selected, 외부 ByLayer/ByBlock/직접 색상.", + "proposal": "상세 상태는 Detail Buttons, 외부 색상 모드는 Color Dropdown으로 이전 검토.", + "impact": "중간", + "loss": "외부 colorMode 제어는 메인의 일반 색상 선택과 다름. followup-four가 이 ID를 참조하므로 먼저 대체 시나리오가 필요함.", + "url": "http://localhost:6024/?path=/story/sw-header--additional-hover", + "screenshot": "screens/sw-header--additional-hover.png" + }, + { + "number": "V-17", + "name": "Property Bar", + "id": "sw-header--property-bar", + "status": "KEEP", + "audience": "속성Bar 전체 API / 사용자·QA", + "content": "Controlled, 외부 Open/값, 추가·삭제·순서 반전·객체 교체·개별 Disabled/ReadOnly, 1222px 부모 폭.", + "proposal": "메인의 참조 구현이자 고급 API 예제로 유지.", + "impact": "중간", + "loss": "메인은 공유 값·기본 추가/제거·제한만 제공. 개별 제한·순서·객체 교체·Controlled를 대체하지 않음.", + "url": "http://localhost:6024/?path=/story/sw-header--property-bar", + "screenshot": "screens/sw-header--property-bar.png" + }, + { + "number": "V-18", + "name": "Dynamic Controls", + "id": "sw-header--dynamic-controls", + "status": "KEEP", + "audience": "controls allowlist / 사용자", + "content": "12개 구성의 제거·재추가·라벨·순서·visible, 동적 문서 데이터.", + "proposal": "Composition과 다른 API임을 설명하는 방향으로 유지.", + "impact": "중간", + "loss": "controls는 전체 allowlist이며 로고 외 16개 요소를 숨기는 hiddenControls와 다름. 이름이 비슷해도 동일 기능이 아님.", + "url": "http://localhost:6024/?path=/story/sw-header--dynamic-controls", + "screenshot": "screens/sw-header--dynamic-controls.png" + }, + { + "number": "V-19", + "name": "Colorize", + "id": "sw-header--colorize", + "status": "REMOVE REVIEW", + "audience": "색상 추출 버튼 접근 / QA", + "content": "별도 기본/확대 상태표 없이 StyleDemo(1920)를 다시 표시. 색상 Dropdown의 추출 버튼으로 연결.", + "proposal": "Color Dropdown에 버튼 접근·Hover·Callback 증거를 남긴 뒤 메뉴 삭제 검토 가능.", + "impact": "중간", + "loss": "실제 색상 추출 CAD 기능은 호스트 소유. 삭제 시 전용 접근 URL을 잃고 detail-buttons preservation의 colorize 참조를 이전해야 함. 지금은 삭제하지 않음.", + "url": "http://localhost:6024/?path=/story/sw-header--colorize", + "screenshot": "screens/sw-header--colorize.png" + }, + { + "number": "V-20", + "name": "Composition (Visibility · Order)", + "id": "sw-header--composition", + "status": "KEEP", + "audience": "hiddenControls/menuOrder / 사용자·QA", + "content": "16개 표시 항목, 프리셋·순서·중복/알 수 없는 ID, 실제 화면/고정 폭, Callback 보존.", + "proposal": "개별 제거와 순서 계약을 보여 주는 예제로 유지.", + "impact": "중간", + "loss": "Dynamic Controls와 다른 API. 홈·창 이동·최소화·종료까지 개별 제어하고 메뉴 순서 정규화를 검증함.", + "url": "http://localhost:6024/?path=/story/sw-header--composition", + "screenshot": "screens/sw-header--composition.png" + }, + { + "number": "V-21", + "name": "Property Panel · 선택 없음", + "id": "sw-header--property-panel-none", + "status": "QA", + "audience": "단독 실제 컴포넌트 / 디자인 QA", + "content": "선택 없음 314×256 고정 상태와 실제 필드.", + "proposal": "일반 사용자 목록보다는 QA 분류 검토.", + "impact": "중간", + "loss": "Variants/Compare와 겹치지만 테스트의 상태별 직접 URL·치수 기준임. 삭제/통합 시 ID 참조 이전 필요.", + "url": "http://localhost:6024/?path=/story/sw-header--property-panel-none", + "screenshot": "screens/sw-header--property-panel-none.png" + }, + { + "number": "V-22", + "name": "Property Panel · 전체 선택", + "id": "sw-header--property-panel-all", + "status": "QA", + "audience": "단독 실제 컴포넌트 / 디자인 QA", + "content": "전체 선택 314×361, 혼합 레이어 값과 선택 개수.", + "proposal": "개별 QA 기준으로 유지하거나 Compare 통합 검토.", + "impact": "중간", + "loss": "선택 없음/원 상태와 내용이 다름. 테스트 직접 URL·혼합 값·개수 레이아웃을 보존해야 함.", + "url": "http://localhost:6024/?path=/story/sw-header--property-panel-all", + "screenshot": "screens/sw-header--property-panel-all.png" + }, + { + "number": "V-23", + "name": "Property Panel · 원 1개", + "id": "sw-header--property-panel-circle", + "status": "QA", + "audience": "단독 실제 컴포넌트 / 디자인 QA", + "content": "원 1개 314×658, 기본 형상·치수·XYZ·전체 선택 복귀.", + "proposal": "개별 QA 기준으로 유지하거나 Compare 통합 검토.", + "impact": "중간", + "loss": "원형 Slot과 위치·푸터를 포함. 다른 상태와 같은 이름의 단순 중복이 아님.", + "url": "http://localhost:6024/?path=/story/sw-header--property-panel-circle", + "screenshot": "screens/sw-header--property-panel-circle.png" + }, + { + "number": "V-24", + "name": "Property Panel · 모두 펼침", + "id": "sw-header--property-panel-expanded", + "status": "QA", + "audience": "단독 실제 컴포넌트 / 디자인 QA", + "content": "전체 펼침 314×754, 추가 공통 속성·형상·위치·푸터.", + "proposal": "개별 QA 기준으로 유지하거나 Compare 통합 검토.", + "impact": "중간", + "loss": "754px 전체 높이와 하단 잘림 검증에 필요. 개별 ID가 기존 테스트에서 동적으로 참조됨.", + "url": "http://localhost:6024/?path=/story/sw-header--property-panel-expanded", + "screenshot": "screens/sw-header--property-panel-expanded.png" + }, + { + "number": "V-25", + "name": "Property Panel · 4개 비교", + "id": "sw-header--property-panel-compare", + "status": "QA", + "audience": "4개 실제 패널 병렬 비교 / 디자인 QA", + "content": "4개 선택 상태를 동시에 렌더링하고 실측 폭·높이를 표시.", + "proposal": "나란히 비교하는 QA 목적을 유지. 개별 메뉴 통합 목적지로 검토 가능.", + "impact": "중간", + "loss": "Variants는 상태 전환, Compare는 동시 비교라는 차이가 있음. property-fields의 4상태 치수 검증이 참조함.", + "url": "http://localhost:6024/?path=/story/sw-header--property-panel-compare", + "screenshot": "screens/sw-header--property-panel-compare.png" + }, + { + "number": "V-26", + "name": "Property Panel · 형상 Slot", + "id": "sw-header--property-shape-slot", + "status": "KEEP", + "audience": "형상 확장 API / 사용자", + "content": "기본/null/ReactNode/Render Prop, 원·사각형 교체, 치수/그룹 추가.", + "proposal": "외부 컴포넌트 확장 계약 예제로 유지.", + "impact": "중간", + "loss": "메인은 기본/null만 제공. ReactNode와 Render Prop·형상 교체를 대체할 수 없음.", + "url": "http://localhost:6024/?path=/story/sw-header--property-shape-slot", + "screenshot": "screens/sw-header--property-shape-slot.png" + }, + { + "number": "V-27", + "name": "Property Panel · 필드 13개", + "id": "sw-header--property-fields", + "status": "QA", + "audience": "필드 상태·실제 조작 / 디자인 QA", + "content": "Figma 13개 필드 Default/Hover 표본, 실제 패널, 혼합 레이어·외부 값·제한·단위.", + "proposal": "77개 필드 검증의 기준 화면으로 유지 권장.", + "impact": "중간", + "loss": "메인은 필드별 디자인 상태표를 대체하지 않음. property-fields.browser.mjs의 핵심 직접 ID.", + "url": "http://localhost:6024/?path=/story/sw-header--property-fields", + "screenshot": "screens/sw-header--property-fields.png" + }, + { + "number": "V-28", + "name": "Detail Buttons (Shared States)", + "id": "sw-header--detail-buttons", + "status": "QA", + "audience": "실제 Pointer/Callback 비교 / QA", + "content": "5개 상세 버튼 × Default/Hover/Disabled/Callback 없음, 클릭 횟수. verification 태그로 기본 숨김.", + "proposal": "이미 적용된 숨김과 검증 표본 유지.", + "impact": "중간", + "loss": "메인은 실제 Dropdown 접근용이며 이 비교 매트릭스를 대체하지 못함. detail-buttons 검증의 직접 ID.", + "url": "http://localhost:6024/?path=/story/sw-header--detail-buttons", + "screenshot": "screens/sw-header--detail-buttons.png" + } +] diff --git a/docs/sw/storybook-overview-qa/screen-survey.json b/docs/sw/storybook-overview-qa/screen-survey.json new file mode 100644 index 0000000..75c6e52 --- /dev/null +++ b/docs/sw/storybook-overview-qa/screen-survey.json @@ -0,0 +1,2395 @@ +[ + { + "id": "sw-header--detail-buttons", + "name": "Detail Buttons (Shared States)", + "tags": [ + "dev", + "test", + "manifest", + "verification" + ], + "render": true, + "errors": [], + "sections": [], + "headings": [], + "buttons": [ + "레이어 상세", + "레이어 상세", + "레이어 상세", + "레이어 상세", + "색상 상세", + "색상 상세", + "색상 상세", + "색상 상세", + "선스타일 상세", + "선스타일 상세", + "선스타일 상세", + "선스타일 상세", + "문자스타일 상세", + "문자스타일 상세", + "문자스타일 상세", + "문자스타일 상세", + "치수스타일 상세", + "치수스타일 상세", + "치수스타일 상세", + "치수스타일 상세" + ], + "inputs": 0 + }, + { + "id": "sw-header--overview", + "name": "Overview", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [ + { + "title": "Figma 기준 1920 × 49", + "description": "홈 / 파일명 / 객체 수정(그리기모드 · 레이어 · 색상 · 선스타일 · 문자스타일 · 치수스타일 · 상세보기) / 인쇄 · 팝업 가이드 · 창 이동 · 최소화 · 종료" + }, + { + "title": "선택 상태", + "description": "선택된 텍스트와 화살표는 #FFC600으로만 바뀝니다. 선택 전용 배경·테두리·그림자는 없습니다." + } + ], + "headings": [ + "Figma 기준 1920 × 49", + "선택 상태" + ], + "buttons": [ + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료" + ], + "inputs": 0 + }, + { + "id": "sw-header--interactive-states", + "name": "Interactive States", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [ + { + "title": "Host state 연결 · Keyboard Focus", + "description": "실제로 마우스를 올려 Hover를, 메뉴·속성 토글을 눌러 선택 상태를 확인합니다. Tab 키로 Focus 윤곽선(2px #F0F7F5)을 확인합니다. Focus 윤곽선은 Hover 테두리보다 위에 그려집니다." + }, + { + "title": "Default", + "description": "Hover 전. 각 버튼의 기존 테두리·배경·그림자." + }, + { + "title": "Hover (고정)", + "description": "홈 · 5개 속성 필드 · 인쇄 · 팝업 가이드는 크기·배경·그림자·위치 변화 없이 테두리만 노란 gradient로 바뀝니다. 인쇄 · 팝업 가이드는 아이콘의 #B6D0C9 부분만 #FFC600으로 함께 바뀝니다. 파일명과 속성Bar · 속성창은 테두리 없이 글자만 #FFC600으로 바뀝니다. 최소화는 검정 20% 배경 + 흰 아이콘, 종료는 #E40000 배경 + 흰 X입니다(Figma 26:12156 / 26:12161). 그리기모드(텍스트)·창 이동은 대상이 아닙니다." + }, + { + "title": "Selected", + "description": "레이어 메뉴·속성창 선택. 글자만 #FFC600이고 선택 전용 테두리는 없습니다." + }, + { + "title": "Selected + Hover (고정)", + "description": "레이어 메뉴는 선택 글자색(#FFC600)을 유지하고 Hover 테두리를 더합니다. 속성창은 선택·Hover 모두 글자색만이라 노란 테두리가 없습니다." + }, + { + "title": "속성Bar · 속성창 상태", + "description": "두 토글은 Hover 시 글자만 #FFC600이고 노란 테두리·배경·그림자가 없습니다. 선택(propertyBarOpen / propertyPanelOpen)도 글자 #FFC600이며, 선택된 토글에 Hover해도 테두리가 생기지 않습니다. '상세보기' 안내 글자는 바뀌지 않습니다. 키보드 Focus 윤곽선은 위 Host state 예제에서 Tab으로 확인합니다." + }, + { + "title": "Disabled + Hover (고정)", + "description": "비활성 버튼에는 Hover 테두리와 아이콘 색 변화를 표시하지 않습니다. 홈·파일명·최소화·종료는 disabled 대상이 아니므로 Hover가 표시됩니다." + }, + { + "title": "인쇄 · 팝업 가이드 · 최소화 · 종료", + "description": "Default(위)와 Hover 고정(아래). 인쇄 · 팝업 가이드: 기존 노란 Gradient 테두리 + 아이콘의 #B6D0C9 부분만 #FFC600(검정 외곽선·그림자·팝업 가이드 녹색 타일은 그대로). 최소화: 투명 → 검정 20% 배경, 아이콘 #ADB0AF → #FFFFFF. 종료: 투명 → #E40000 배경, X #ADB0AF → #FFFFFF. 최소화·종료는 32 × 48 그대로이며 테두리·그림자·노란 테두리가 없습니다." + }, + { + "title": "인쇄 · 팝업 가이드 · 최소화 · 종료 Callback 기록", + "description": "각 버튼은 자기 Callback만 한 번 호출합니다. 종료는 onClose만 호출하며 Storybook에서 실제 창을 닫지 않습니다(창 동작은 호스트 소유). Tab으로 Focus 윤곽선(2px #F0F7F5)을 확인합니다." + }, + { + "title": "더보기 버튼 Hover (고정, 헤더 1440px)", + "description": "더보기 버튼에도 같은 테두리를 적용합니다. 더보기 메뉴 안 항목은 목록 구조이므로 기존 배경 Hover를 유지합니다." + }, + { + "title": "Disabled", + "description": "메뉴·속성·인쇄/가이드가 비활성화됩니다. 창 제어(최소화·종료)는 유지됩니다." + }, + { + "title": "긴 파일명", + "description": "파일명은 말줄임으로 처리하고 글자 크기를 줄이지 않습니다." + } + ], + "headings": [ + "Host state 연결 · Keyboard Focus", + "Default", + "Hover (고정)", + "Selected", + "Selected + Hover (고정)", + "속성Bar · 속성창 상태", + "Disabled + Hover (고정)", + "인쇄 · 팝업 가이드 · 최소화 · 종료", + "인쇄 · 팝업 가이드 · 최소화 · 종료 Callback 기록", + "더보기 버튼 Hover (고정, 헤더 1440px)", + "Disabled", + "긴 파일명" + ], + "buttons": [ + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄" + ], + "inputs": 0 + }, + { + "id": "sw-header--window-move-motion", + "name": "Window Move Motion", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [ + { + "title": "단계별 진행 (3배 확대)", + "description": "CSS 애니메이션을 해당 시점에 멈춘 화면입니다(Storybook 전용 data-sb-hover + Web Animations API로 시간만 고정)." + } + ], + "headings": [ + "단계별 진행 (3배 확대)" + ], + "buttons": [ + "최소화", + "종료", + "최소화", + "종료", + "최소화", + "종료", + "최소화", + "종료", + "최소화", + "종료", + "최소화", + "종료", + "최소화", + "종료", + "최소화", + "종료", + "최소화", + "종료" + ], + "inputs": 0 + }, + { + "id": "sw-header--composed-controls", + "name": "Composed Controls", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [ + { + "title": "레이어 · 색상 · 상세보기" + }, + { + "title": "선스타일 · 문자스타일 · 치수스타일", + "description": "필드 전체 Hover 시 라벨·값·선/폰트/치수 미리보기가 #FFC600입니다. 선의 검정 border와 치수 SVG의 검정 외곽선은 유지합니다." + }, + { + "title": "그룹 필드 Hover (고정)", + "description": "기존 노란 Gradient Border에 텍스트·지정 미리보기 강조만 더합니다. 색상 견본과 레이어 상태는 원래 색을 유지하며, 상세보기는 기존 텍스트 전용 Hover 그대로입니다." + } + ], + "headings": [ + "레이어 · 색상 · 상세보기", + "선스타일 · 문자스타일 · 치수스타일", + "그룹 필드 Hover (고정)" + ], + "buttons": [ + "레이어", + "색상", + "속성Bar", + "속성창", + "선스타일", + "문자스타일", + "치수스타일", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일" + ], + "inputs": 0 + }, + { + "id": "sw-header--logo-slot", + "name": "Logo Slot", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [ + { + "title": "기본 임시 로고", + "description": "logoSrc에 임시 SVG, logoAlt에 「임시 로고」를 전달합니다." + }, + { + "title": "사용자 지정 로고 — 가로형 이미지(logoSrc)", + "description": "120 × 20 비율의 이미지도 로고 영역 안에 contain으로 맞춰지고 넘치지 않습니다." + }, + { + "title": "사용자 지정 로고 — 세로형 React 요소(logo)", + "description": "logo에 SVG 요소를 전달하면 logoSrc보다 우선합니다." + }, + { + "title": "로고 미전달", + "description": "logo·logoSrc가 없으면 로고를 그리지 않고 홈 버튼 배경과 전체 배치를 그대로 유지합니다. 접근성 이름은 「홈」입니다." + } + ], + "headings": [ + "기본 임시 로고", + "사용자 지정 로고 — 가로형 이미지(logoSrc)", + "사용자 지정 로고 — 세로형 React 요소(logo)", + "로고 미전달" + ], + "buttons": [ + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "샘플 SW 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "샘플 SW 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료" + ], + "inputs": 0 + }, + { + "id": "sw-header--document-dropdown", + "name": "Document Dropdown", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [ + { + "title": "현재 열린 문서 1개 (기본 예제)", + "description": "2026-10-16 추가 요구: 기본 예제는 빈 목록 대신 현재 열린 문서 1개를 전달합니다(documents = [현재 문서], activeDocumentId). 펼치면 그 문서명이 #FFC600(현재 문서)으로 보이고 X·+ New·Open은 기존 그대로입니다. 문서를 늘리면 실제 개수만큼 표시되며 배열을 1개로 고정하지 않습니다." + }, + { + "title": "현재 열린 문서 1개 · 선택 · X · New / Open Callback", + "description": "파일명을 눌러 열고 확인합니다. 문서 선택은 onDocumentSelect, X는 onDocumentClose(이 예제의 호스트는 목록에서 제거 → '열린 문서 없음'), + New / Open은 각 Callback만 한 번 호출합니다. 존재하지 않는 문서를 임의로 만들지 않습니다." + }, + { + "title": "Default", + "description": "documents를 전달하면 파일명이 문서 목록 버튼이 됩니다(aria-expanded). 화살표는 아래 방향입니다." + }, + { + "title": "Hover (고정)", + "description": "파일명 Hover는 노란 테두리 없이 글자만 #FFC600으로 바꿉니다. 녹색 테두리·배경·초록 화살표는 그대로이며 목록은 열리지 않습니다." + }, + { + "title": "Dropdown Open (Figma 4개 문서)", + "description": "열린 상태: 파일명과 화살표 #FFC600, 화살표 위쪽. 목록 310 × 168(항목 32 × 4 + 하단 40), 배경 #103127, 1px #041611, 하단 radius 4px." + }, + { + "title": "목록 항목 · + New · Open Hover (고정)", + "description": "Figma hover: 목록 항목은 검정 40% 배경(글자·아이콘 그대로, 26:10680), + New / Open은 배경 20% → 30%, 글자 검정 70% → 100%(26:10762 / 26:10805). 노란 테두리는 쓰지 않습니다. 위 Default와 비교합니다(두 번째 항목, + New, Open 고정)." + }, + { + "title": "문서 항목 선택 · New / Open", + "description": "클릭으로 열고 닫습니다. 항목을 고르면 onDocumentSelect가 호출되고(이 예제는 선택한 문서를 파일명·현재 문서로 표시), New / Open은 각각 onDocumentNew / onDocumentOpen을 호출합니다. 바깥 클릭·Escape로 닫힙니다. 키보드: Enter/Space 열기, ↓↑ 이동." + }, + { + "title": "현재 문서 — 첫 번째 문서 선택", + "description": "사용자 추가 요구(Figma 외): activeDocumentId 문서의 이름만 #FFC600으로 표시합니다. 목록은 documents 순서 그대로이고, 아이콘·높이·padding은 같으며 노란 테두리·배경은 없습니다. 모든 행 오른쪽에 Close Document(X) 자리가 있으며 평상시에는 숨겨져 있습니다." + }, + { + "title": "현재 문서 — 중간 문서(3번째) 선택", + "description": "선택한 문서는 제자리(3번째)에 있고 이름만 #FFC600입니다. 목록 순서 1 → 2 → 3 → 4는 바뀌지 않습니다." + }, + { + "title": "현재 문서 — 마지막 문서 선택" + }, + { + "title": "일반 문서 Hover (고정)", + "description": "Hover한 행에만 X가 나타납니다(선택 여부와 무관). 배경은 Figma 목록 Hover(검정 40%), 글자는 #F0F7F5 그대로입니다." + }, + { + "title": "현재 문서 Hover (고정)", + "description": "현재 문서는 노란 글자를 유지한 채 Hover 배경(검정 40%)과 X가 함께 표시됩니다. 선택은 글자색, Hover는 배경이라 서로 구분됩니다." + }, + { + "title": "X 버튼 Hover (고정)", + "description": "X 자체에 Hover하면 배경 rgba(182,208,201,.2)와 밝은 아이콘으로 바뀝니다(사용자 추가 요소, Figma 없음). 키보드 Focus는 아래 예제에서 Tab으로 확인합니다(행에 Focus가 오면 X가 보이고, X에는 2px #F0F7F5 윤곽선)." + }, + { + "title": "선택 변경 · 닫기 Callback 기록", + "description": "다른 문서를 고르면 onDocumentSelect만 호출되고, 목록 순서는 그대로 둔 채 노란 글자가 그 문서로 옮겨갑니다. 마우스를 옮기면 X도 Hover한 행으로 옮겨갑니다. 어느 행이든 X(또는 X에 Focus 후 Enter/Space)는 그 문서의 onDocumentClose만 한 번 호출합니다. 이 예제의 호스트는 닫은 문서를 목록에서 빼고, 현재 문서를 닫았을 때만 선택을 비웁니다(다음 문서 자동 선택은 호스트가 결정)." + }, + { + "title": "여러 문서 (18개)", + "description": "목록이 길면 Dropdown 안에서만 세로 스크롤합니다(최대 320px)." + }, + { + "title": "예외 — 문서 없음 (documents = [])", + "description": "호스트에 열린 문서가 없을 때만의 예외 상태입니다(기본 예제 아님). 목록 영역 없이 New / Open만 표시합니다. documents를 전달하지 않으면 Dropdown 없이 기존 버튼으로 동작합니다." + }, + { + "title": "긴 파일명", + "description": "파일명과 목록 항목 모두 말줄임을 유지합니다." + }, + { + "title": "좁은 화면 (헤더 390px)", + "description": "파일명이 좁아져도 목록은 파일명 왼쪽에 맞춰 열리고, 헤더 폭을 넘지 않도록 너비가 줄어듭니다." + } + ], + "headings": [ + "현재 열린 문서 1개 (기본 예제)", + "현재 열린 문서 1개 · 선택 · X · New / Open Callback", + "Default", + "Hover (고정)", + "Dropdown Open (Figma 4개 문서)", + "목록 항목 · + New · Open Hover (고정)", + "문서 항목 선택 · New / Open", + "현재 문서 — 첫 번째 문서 선택", + "현재 문서 — 중간 문서(3번째) 선택", + "현재 문서 — 마지막 문서 선택", + "일반 문서 Hover (고정)", + "현재 문서 Hover (고정)", + "X 버튼 Hover (고정)", + "선택 변경 · 닫기 Callback 기록", + "여러 문서 (18개)", + "예외 — 문서 없음 (documents = [])", + "긴 파일명", + "좁은 화면 (헤더 390px)" + ], + "buttons": [ + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "C0020101-006-평면및종단면도(06)", + "문서 닫기", + "+ New", + "Open", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "Sample-Drawing-01.dwg", + "문서 닫기", + "Sample-Drawing-02.dwg", + "문서 닫기", + "Sample-Plan-03.dxf", + "문서 닫기", + "Sample-Section-04.dxf", + "문서 닫기", + "+ New", + "Open", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "Sample-Drawing-01.dwg", + "문서 닫기", + "Sample-Drawing-02.dwg", + "문서 닫기", + "Sample-Plan-03.dxf", + "문서 닫기", + "Sample-Section-04.dxf", + "문서 닫기", + "+ New", + "Open", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: Sample-Drawing-01.dwg", + "Sample-Drawing-01.dwg", + "문서 닫기", + "Sample-Drawing-02.dwg", + "문서 닫기", + "Sample-Plan-03.dxf", + "문서 닫기", + "Sample-Section-04.dxf", + "문서 닫기", + "+ New", + "Open", + "레이어", + "색상", + "선스타일" + ], + "inputs": 0 + }, + { + "id": "sw-header--layer-dropdown", + "name": "Layer Dropdown", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [ + { + "title": "Layer Default", + "description": "layers를 전달한 기본 상태. 필드 234 × 38, 기존 테두리·그림자, 아이콘 3개 + 라벨/레이어명. layers를 전달하지 않으면 기존 필드 버튼(onLayerOpen) 그대로입니다." + }, + { + "title": "Layer Hover (고정)", + "description": "기존 노란 Gradient Border와 라벨·레이어명 #FFC600. 목록은 열리지 않습니다." + }, + { + "title": "Layer Dropdown Open (Figma 8개 행)", + "description": "Variant3: 라벨·레이어명 #FFC600, 필드 테두리 #081813·하단 각진 모서리, 필드+목록을 감싸는 노란 Gradient 1px 외곽선(236 × 320). 목록 234 × 280(행 30 × 8 + 하단 40), 배경 #27241D, 검정 1px, 하단 radius 3px, Shadow 0 4px 8px rgba(16,48,38,.25). 이 예제는 onLayerDetail이 없어 클릭은 무동작이며 상세 버튼의 공통 Hover는 유지합니다." + }, + { + "title": "Layer Row Default · Row Hover (고정)", + "description": "두 번째 행 Hover 고정: 배경 #62533D, 레이어명 #FF5C00(26:10695). 행 크기·아이콘 위치는 그대로입니다. 다른 필드·문서 목록의 Hover 색과 무관한 이 목록 전용 색입니다." + }, + { + "title": "전구 · 눈꽃 · 자물쇠 On / Hover / Off / Off Hover (3배 확대)", + "description": "1행 컬러(Default: visible=true · frozen=false · locked=false) · 2행 컬러 Hover(Variant2, 고정) · 3행 회색(Variant3: visible=false · frozen=true · locked=true) · 4행 회색 Hover(Variant4, 고정). 전구 Hover는 검정 25% 배경, 눈꽃·자물쇠 Hover는 Figma Hover SVG(같은 아이콘 + 검정 25% 타일)입니다. Off → Off Hover는 Figma Smart Animate에 맞춰 300ms ease-out으로 전환됩니다." + }, + { + "title": "레이어 선택 · 개별 아이콘 Toggle · Callback 기록", + "description": "필드 클릭으로 열고, 레이어명(색상 견본 포함)을 누르면 onLayerSelect만 호출되고 필드에 그 레이어가 표시되며 목록이 닫힙니다. 전구·눈꽃·자물쇠는 각각 onLayerVisibilityChange(layer, !visible) / onLayerFreezeChange(layer, !frozen) / onLayerLockChange(layer, !locked)만 한 번 호출하고 목록은 열린 채 유지됩니다(전구 컬러 = visible=true, 눈꽃 컬러 = frozen=false 동결 해제, 자물쇠 컬러 = locked=false 잠금 해제, 회색은 반대). 위 상태표로 해당 레이어만 바뀌는 것을 확인합니다. 키보드: Enter/Space 열기, ↓↑ 행 이동(같은 열 유지), ←→ 행 안 이동, Escape 닫기, Tab으로 벗어나면 닫힘." + }, + { + "title": "여러 레이어의 서로 다른 상태 · 현재 레이어", + "description": "현재 레이어(activeLayerId)는 Hover와 같은 갈색 배경·주황 글자이고 필드 아이콘도 그 레이어 상태를 따릅니다. Sample-Defpoints는 disabled 예시입니다." + }, + { + "title": "현재 레이어 Hover (고정)", + "description": "현재 레이어의 갈색 배경·주황 글자는 Hover 및 Mouse Leave 뒤에도 유지됩니다." + }, + { + "title": "긴 레이어명", + "description": "필드와 행 모두 말줄임으로 처리합니다. 전체 이름은 title로 확인합니다." + }, + { + "title": "많은 레이어 (20개)", + "description": "목록 부분만 세로 스크롤(최대 8행, 240px)하고 레이어 상세 영역은 고정입니다. 헤더에는 스크롤이 생기지 않습니다." + }, + { + "title": "레이어가 없는 상태", + "description": "layers=[]이면 목록 없이 레이어 상세 영역만 표시하고 필드는 layer.name을 표시합니다." + }, + { + "title": "레이어 상세 버튼", + "description": "onLayerDetail을 전달하면 Callback 호출 후 목록을 닫습니다(아래 기록). 전달하지 않아도 공통 Default/Hover(텍스트 35%)를 유지하며 클릭은 안전한 무동작입니다(위 Figma 8개 행 예제). Disabled는 명시적으로 지정합니다." + }, + { + "title": "상태 표시 전용(Toggle Callback 없음)", + "description": "onLayerVisibilityChange 등을 전달하지 않으면 해당 아이콘은 버튼이 아닌 상태 표시(role=img)이며 Hover·클릭 반응이 없습니다." + }, + { + "title": "좁은 화면 (헤더 1440px)", + "description": "필드 위치와 헤더 49px를 유지하고 목록은 필드 왼쪽에 맞춰 열립니다." + }, + { + "title": "좁은 화면 (헤더 1080px)", + "description": "필드 위치와 헤더 49px를 유지하고 목록은 필드 왼쪽에 맞춰 열립니다." + }, + { + "title": "좁은 화면 (헤더 900px)", + "description": "필드 위치와 헤더 49px를 유지하고 목록은 필드 왼쪽에 맞춰 열립니다." + }, + { + "title": "좁은 화면 (헤더 768px)", + "description": "필드 위치와 헤더 49px를 유지하고 목록은 필드 왼쪽에 맞춰 열립니다." + }, + { + "title": "좁은 화면 (헤더 640px)", + "description": "필드 위치와 헤더 49px를 유지하고 목록은 필드 왼쪽에 맞춰 열립니다." + }, + { + "title": "좁은 화면 (헤더 390px)", + "description": "520 미만에서는 필드의 상태 아이콘이 숨고 레이어명이 말줄임됩니다. 목록은 234px 그대로이며 헤더 밖으로 넘치지 않도록 왼쪽으로 이동합니다(이때 노란 외곽선은 목록만 감쌉니다). 필드를 눌러 열고 조작합니다." + } + ], + "headings": [ + "Layer Default", + "Layer Hover (고정)", + "Layer Dropdown Open (Figma 8개 행)", + "Layer Row Default · Row Hover (고정)", + "전구 · 눈꽃 · 자물쇠 On / Hover / Off / Off Hover (3배 확대)", + "레이어 선택 · 개별 아이콘 Toggle · Callback 기록", + "여러 레이어의 서로 다른 상태 · 현재 레이어", + "현재 레이어 Hover (고정)", + "긴 레이어명", + "많은 레이어 (20개)", + "레이어가 없는 상태", + "레이어 상세 버튼", + "상태 표시 전용(Toggle Callback 없음)", + "좁은 화면 (헤더 1440px)", + "좁은 화면 (헤더 1080px)", + "좁은 화면 (헤더 900px)", + "좁은 화면 (헤더 768px)", + "좁은 화면 (헤더 640px)", + "좁은 화면 (헤더 390px)" + ], + "buttons": [ + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "CC-D GNL 표시", + "CC-D GNL 동결", + "CC-D GNL 잠금", + "CC-D GNL", + "CC-D GNL 표시", + "CC-D GNL 동결", + "CC-D GNL 잠금", + "CC-D GNL", + "CC-D GNL 표시", + "CC-D GNL 동결", + "CC-D GNL 잠금", + "CC-D GNL", + "CC-D GNL 표시", + "CC-D GNL 동결", + "CC-D GNL 잠금", + "CC-D GNL", + "CC-D GNL 표시", + "CC-D GNL 동결", + "CC-D GNL 잠금", + "CC-D GNL", + "CC-D GNL 표시", + "CC-D GNL 동결", + "CC-D GNL 잠금", + "CC-D GNL", + "CC-D GNL 표시", + "CC-D GNL 동결", + "CC-D GNL 잠금", + "CC-D GNL", + "CC-D GNL 표시", + "CC-D GNL 동결", + "CC-D GNL 잠금", + "CC-D GNL", + "레이어 상세", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "CC-D GNL 표시", + "CC-D GNL 동결", + "CC-D GNL 잠금", + "CC-D GNL", + "CC-D GNL 표시", + "CC-D GNL 동결", + "CC-D GNL 잠금", + "CC-D GNL", + "CC-D GNL 표시", + "CC-D GNL 동결", + "CC-D GNL 잠금", + "CC-D GNL", + "CC-D GNL 표시", + "CC-D GNL 동결", + "CC-D GNL 잠금", + "CC-D GNL", + "CC-D GNL 표시", + "CC-D GNL 동결", + "CC-D GNL 잠금", + "CC-D GNL", + "CC-D GNL 표시", + "CC-D GNL 동결", + "CC-D GNL 잠금", + "CC-D GNL", + "CC-D GNL 표시", + "CC-D GNL 동결", + "CC-D GNL 잠금", + "CC-D GNL", + "CC-D GNL 표시", + "CC-D GNL 동결", + "CC-D GNL 잠금", + "CC-D GNL", + "레이어 상세", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "레이어", + "컬러 (Default) 표시", + "컬러 (Default) 동결", + "컬러 (Default) 잠금", + "컬러 (Default)", + "컬러 Hover (Variant2) 표시", + "컬러 Hover (Variant2) 동결", + "컬러 Hover (Variant2) 잠금", + "컬러 Hover (Variant2)", + "회색 (Variant3) 표시", + "회색 (Variant3) 동결", + "회색 (Variant3) 잠금", + "회색 (Variant3)", + "회색 Hover (Variant4) 표시", + "회색 Hover (Variant4) 동결" + ], + "inputs": 0 + }, + { + "id": "sw-header--color-dropdown", + "name": "Color Dropdown", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [ + { + "title": "Default", + "description": "colors를 전달하면 색상 필드가 Dropdown 버튼이 됩니다. 192 × 38, 견본은 현재 색상(color.swatch)." + }, + { + "title": "Hover (고정)", + "description": "기존 노란 Gradient Border + 라벨·값 #FFC600. 색상 견본은 실제 색 그대로입니다." + }, + { + "title": "Expanded (Figma 26:11005)", + "description": "192 × 158: ByLayer/ByBlock 167 × 30 · 팔레트 168 × 22(칩 22px 7개) · 색상 추출 24 + 입력 130 · 하단 40(색상 상세). 필드 테두리 #081813·아래 모서리 각짐, 필드+목록 노란 1px 외곽선(194 × 198)." + }, + { + "title": "사용자 추가 색상 (Figma 26:11036)", + "description": "userColors 2개: 24px 행이 추가되어 본문 182px. 개수는 가변이며 2px 간격으로 줄바꿈합니다." + }, + { + "title": "사용자 색상 40개", + "description": "팔레트 + 사용자 색상 4행(118px)을 넘으면 팔레트 영역만 세로 스크롤합니다. 헤더 높이·다른 필드 위치는 그대로입니다." + }, + { + "title": "ByLayer On (Figma on 26:12671)", + "description": "colorMode='byLayer': #62533D 배경 + 밝은 inner shadow. 텍스트 #D4CBBD + 검정 Stroke. ByBlock은 Default(rgba(98,83,61,.3) + 어두운 inner shadow)." + }, + { + "title": "내부 버튼 Hover (고정) — 2026-10-16 추가 수정 정책", + "description": "ByLayer / ByBlock 글자 #FF5C00. 선택 배경과 Inset Shadow는 유지합니다. 색상 상세는 배경 .25·radius 25·Hover 아이콘으로 변합니다. 색상 칩은 Hover가 없고, 색상 추출은 btn_colorize Hover(26:11305)입니다." + }, + { + "title": "RGB 입력 Hover (고정)", + "description": "입력은 수정 가능함을 알리는 Figma Hover를 유지합니다(header/menu/색상/input hover: 1px rgba(197,177,158,.2)). 편집 중(Focus)에는 값 영역이 검정이 되고 커서는 #E60403입니다 — 아래 실제 예제에서 클릭해 확인합니다." + }, + { + "title": "선택 · 입력 · Callback 기록", + "description": "칩 → onColorSelect, ByLayer/ByBlock → onColorModeChange(서로 배타: 이 호스트는 선택한 쪽만 On), 입력(255,0,0 · #00ff00 등, Enter 또는 Focus 이동) → 유효하면 onColorInput, 잘못된 값(256,0,0 · abc)은 복원. 색상 추출 → onColorPick 후 닫힘, 색상 상세 → onColorDetail 후 닫힘. 선택·입력 후에도 목록은 열려 있고 다른 속성(레이어·선스타일 등)은 그대로입니다. Escape·바깥 클릭·Tab으로 닫힘." + } + ], + "headings": [ + "Default", + "Hover (고정)", + "Expanded (Figma 26:11005)", + "사용자 추가 색상 (Figma 26:11036)", + "사용자 색상 40개", + "ByLayer On (Figma on 26:12671)", + "내부 버튼 Hover (고정) — 2026-10-16 추가 수정 정책", + "RGB 입력 Hover (고정)", + "선택 · 입력 · Callback 기록" + ], + "buttons": [ + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "ByLayer", + "ByBlock", + "흰색", + "빨강", + "초록", + "노랑", + "파랑", + "자홍", + "청록", + "색상 추출", + "색상 상세", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "ByLayer", + "ByBlock", + "흰색", + "빨강", + "초록", + "노랑", + "파랑", + "자홍", + "청록", + "사용자 색상 1", + "사용자 색상 2", + "색상 추출", + "색상 상세", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "ByLayer", + "ByBlock", + "흰색", + "빨강", + "초록", + "노랑", + "파랑", + "자홍", + "청록", + "사용자 색상 1", + "사용자 색상 2", + "사용자 색상 3", + "사용자 색상 4", + "사용자 색상 5", + "사용자 색상 6", + "사용자 색상 7", + "사용자 색상 8", + "사용자 색상 9", + "사용자 색상 10", + "사용자 색상 11", + "사용자 색상 12", + "사용자 색상 13", + "사용자 색상 14", + "사용자 색상 15", + "사용자 색상 16", + "사용자 색상 17", + "사용자 색상 18", + "사용자 색상 19", + "사용자 색상 20", + "사용자 색상 21", + "사용자 색상 22", + "사용자 색상 23", + "사용자 색상 24", + "사용자 색상 25", + "사용자 색상 26", + "사용자 색상 27", + "사용자 색상 28", + "사용자 색상 29", + "사용자 색상 30", + "사용자 색상 31", + "사용자 색상 32", + "사용자 색상 33", + "사용자 색상 34", + "사용자 색상 35", + "사용자 색상 36", + "사용자 색상 37", + "사용자 색상 38", + "사용자 색상 39", + "사용자 색상 40", + "색상 추출", + "색상 상세", + "선스타일", + "문자스타일" + ], + "inputs": 6 + }, + { + "id": "sw-header--line-style-dropdown", + "name": "Line Style Dropdown", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [ + { + "title": "Default", + "description": "284 × 38. 선 미리보기 10 × 4 × 5, 선스타일 / 가중치 / 스케일." + }, + { + "title": "Hover (고정)", + "description": "라벨·값 #FFC600, 선 미리보기 채움 #FFC600(검정 1px 유지), 노란 Gradient Border." + }, + { + "title": "Expanded (Figma 26:11143)", + "description": "필드 링(286 × 39) + 468 × 192 drop_wrap(1px 노란 링, x −92, y 37). 선 종류 5행 + 하단 40(선스타일 상세), 가중치 4행(ByDefault 0.25, User 입력), 스케일 입력. 현재 선 종류·가중치는 Hover와 같은 갈색 배경·주황 텍스트·선입니다." + }, + { + "title": "선 종류 행 Default · Hover (Figma 26:10703 / 26:10706, 고정)", + "description": "1·4번째 행 Hover 고정: 배경 #62533D, 선 미리보기·텍스트 #FF5C00, 검정 Stroke 유지, 크기 182 × 30·위치 그대로. CENTER·HIDDEN은 각자의 패턴(22·7 / 33·33)을 유지합니다. 가중치 2번째 행·스케일 행도 Figma 행 Hover를 고정했습니다." + }, + { + "title": "현재 행 Hover (고정)", + "description": "현재 선 종류(Continuous)는 Hover 및 Mouse Leave 뒤에도 갈색 배경·주황 선·이름을 유지합니다." + }, + { + "title": "상세 버튼 Hover (고정)", + "description": "2026-10-16 추가 수정 기준으로 선스타일 상세의 Figma 배경 .25·radius 25·Hover 아이콘을 적용합니다." + }, + { + "title": "선 종류 · 가중치 · 스케일 선택 Callback", + "description": "선 종류 → onLineTypeSelect(가중치·스케일 유지), 가중치 → onLineWeightSelect(선 종류·스케일 유지), User 입력 → onLineWeightValueChange(0 이상), 스케일 입력 → onLineScaleChange(0 초과). 입력은 Enter/Focus 이동으로 확정, Escape는 취소. ↓↑로 항목 이동." + }, + { + "title": "좁은 헤더 390px", + "description": "468px 목록이 헤더보다 넓으면 3열을 세로로 쌓아(필요 시 세로 스크롤) 화면 밖 이탈·가로 스크롤 없이 모든 항목에 접근합니다. 더보기 → 선스타일로 엽니다." + } + ], + "headings": [ + "Default", + "Hover (고정)", + "Expanded (Figma 26:11143)", + "선 종류 행 Default · Hover (Figma 26:10703 / 26:10706, 고정)", + "현재 행 Hover (고정)", + "상세 버튼 Hover (고정)", + "선 종류 · 가중치 · 스케일 선택 Callback", + "좁은 헤더 390px" + ], + "buttons": [ + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "ByBlock", + "ByLayer", + "Continuous", + "CENTER", + "HIDDEN", + "선스타일 상세", + "ByLayer", + "ByBlock", + "ByDefault0.25", + "User", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "ByBlock", + "ByLayer", + "Continuous", + "CENTER", + "HIDDEN", + "선스타일 상세", + "ByLayer", + "ByBlock", + "ByDefault0.25", + "User", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "ByBlock", + "ByLayer", + "Continuous", + "CENTER", + "HIDDEN", + "선스타일 상세", + "ByLayer", + "ByBlock", + "ByDefault0.25", + "User", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "ByBlock", + "ByLayer", + "Continuous", + "CENTER", + "HIDDEN", + "선스타일 상세", + "ByLayer", + "ByBlock", + "ByDefault0.25", + "User", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화" + ], + "inputs": 8 + }, + { + "id": "sw-header--text-dimension-style-dropdown", + "name": "Text · Dimension Style Dropdown", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [ + { + "title": "Default · Hover (고정)", + "description": "위: Default. 아래: Hover — 라벨·값·글꼴 미리보기 #FFC600, 치수 미리보기는 Figma Hover SVG, 검정 외곽선 유지." + }, + { + "title": "문자스타일 Expanded (Figma 26:11200)", + "description": "Arial / Standard, 돋움 / Dotum. 글꼴 16px + 이름 14px(모두 검정 Stroke). 하단 '문자스타일 상세'는 Figma처럼 왼쪽 정렬(테두리 .25)." + }, + { + "title": "문자스타일 행·상세 버튼 Hover (고정)", + "description": "두 번째 행과 현재 스타일 모두 #62533D / 글꼴·이름 #FF5C00입니다. 상세 버튼도 Figma Hover입니다." + }, + { + "title": "치수스타일 Expanded (Figma 26:11242)", + "description": "Standard, ISO - 25. 치수 미리보기 60 × 15(Figma 행 자산 #F6F4F2). 하단 '치수스타일 상세' 오른쪽 정렬." + }, + { + "title": "치수스타일 행·상세 버튼 Hover (고정)", + "description": "두 번째 행: #62533D, 이름·치수 미리보기 #FF5C00(Figma Hover 자산). 상세 버튼 Hover는 26:10799(기본 아이콘·텍스트 100%)이며 Variant3와 혼합하지 않습니다." + }, + { + "title": "선택 Callback", + "description": "행 → onTextStyleSelect / onDimensionStyleSelect 1회 후 닫힘, 상세 → on*Detail 1회 후 닫힘. 필드 값이 호스트 상태로 갱신됩니다." + } + ], + "headings": [ + "Default · Hover (고정)", + "문자스타일 Expanded (Figma 26:11200)", + "문자스타일 행·상세 버튼 Hover (고정)", + "치수스타일 Expanded (Figma 26:11242)", + "치수스타일 행·상세 버튼 Hover (고정)", + "선택 Callback" + ], + "buttons": [ + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "ArialStandard", + "돋움Dotum", + "문자스타일 상세", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "ArialStandard", + "돋움Dotum", + "문자스타일 상세", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "Standard", + "ISO - 25", + "치수스타일 상세", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "Standard", + "ISO - 25", + "치수스타일 상세", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료" + ], + "inputs": 0 + }, + { + "id": "sw-header--responsive-more", + "name": "Responsive More", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [ + { + "title": "전환 · Callback 기록 (1440)", + "description": "… → 선스타일: 대표 칸이 선스타일(미리보기·이름·가중치·스케일)로 바뀌고 선스타일 Dropdown이 열립니다. … → 문자스타일: 선스타일 Dropdown이 닫히고 대표 칸이 문자스타일로. … → 레이어: 원래 배치로 복귀. 값은 모두 유지됩니다." + }, + { + "title": "전환 · Callback 기록 (768)", + "description": "색상도 더보기에 있는 폭입니다. … → 색상: 색상 필드와 목록." + }, + { + "title": "전환 · Callback 기록 (390)", + "description": "대표 필드는 남는 폭에 맞춰 값이 말줄임되고, 목록은 헤더 안쪽으로 이동합니다." + }, + { + "title": "1920px" + }, + { + "title": "1800px" + }, + { + "title": "1799px" + }, + { + "title": "1440px" + }, + { + "title": "1180px" + }, + { + "title": "1179px" + }, + { + "title": "1080px" + }, + { + "title": "1079px" + }, + { + "title": "900px" + }, + { + "title": "899px" + }, + { + "title": "768px" + }, + { + "title": "640px" + }, + { + "title": "639px" + }, + { + "title": "520px" + }, + { + "title": "519px" + }, + { + "title": "390px" + } + ], + "headings": [ + "전환 · Callback 기록 (1440)", + "전환 · Callback 기록 (768)", + "전환 · Callback 기록 (390)", + "1920px", + "1800px", + "1799px", + "1440px", + "1180px", + "1179px", + "1080px", + "1079px", + "900px", + "899px", + "768px", + "640px", + "639px", + "520px", + "519px", + "390px" + ], + "buttons": [ + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄" + ], + "inputs": 0 + }, + { + "id": "sw-header--layer-detail-input", + "name": "Layer Detail · Input", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [ + { + "title": "Figma 원본 (비교용 이미지)", + "description": "왼쪽: 레이어 상세 Default / Hover(배경 .25 · radius 25 · 아이콘 35%). 오른쪽: Input Default 58 × 20 / Hover 58 × 24 / On 58 × 24. 최신 요청에 따라 아래 실제 버튼에도 Hover를 적용합니다. 이미지는 Storybook 비교용이며 패키지에 포함하지 않습니다." + }, + { + "title": "레이어 상세 — Default · Hover (고정) · Disabled (3배 확대)", + "description": "왼쪽: Callback 없이 사용 가능(Default). 가운데: Hover 배경 .25·radius 25·Hover 아이콘. 오른쪽: 호스트가 fieldset disabled를 명시한 상태. Figma와 같은 113 × 24, 아이콘 14 · 간격 4 · padding 5 / 10 · 배경 rgba(197,177,158,.15) · radius 24 · 글자 35%. CAD 상세 실행은 호스트 Callback이 있을 때만 가능합니다." + }, + { + "title": "레이어 상세 Click Callback", + "description": "필드를 열고 '레이어 상세'를 누르면 onLayerDetail 1회 후 목록이 닫힙니다(기존 동작). 레이어 선택·전구·눈꽃·자물쇠 매핑은 변경하지 않았습니다." + }, + { + "title": "Input — Default · Hover (고정) · ReadOnly · Disabled (3배 확대)", + "description": "Default: 배경·테두리 없음, #E60403 14px + 검정 1.3px Stroke. Hover: 1px rgba(212,203,189,.25), 24px(글자 위치 그대로). ReadOnly(onCommit 없음 또는 readOnly): Hover·편집 상태 없음. Disabled: 40%." + }, + { + "title": "Input — Editing (Focus)", + "description": "편집 중(26:11661): 배경 #0F0D0A, 1px rgba(212,203,189,.3), 글자 #E60403 유지, 네이티브 커서 #E60403(caret-color, 깜박임 = Figma cursor Default / Variant2). 이 예제는 입력에 자동 Focus합니다." + }, + { + "title": "Input — 입력 · Enter 확정 · Escape 취소 · 외부 값 갱신", + "description": "숫자 입력(valueType='number'): 유효한 소수만 onCommit, 잘못된 값은 복원. 텍스트 입력(한글 IME 포함): 조합 중 Enter는 확정하지 않습니다. Escape는 편집 취소(onCancel) — 확정값으로 복원. Focus 이동(Tab / 바깥 클릭)도 확정합니다. 위 버튼으로 호스트 값을 바꾸면 최신 값이 표시됩니다." + } + ], + "headings": [ + "Figma 원본 (비교용 이미지)", + "레이어 상세 — Default · Hover (고정) · Disabled (3배 확대)", + "레이어 상세 Click Callback", + "Input — Default · Hover (고정) · ReadOnly · Disabled (3배 확대)", + "Input — Editing (Focus)", + "Input — 입력 · Enter 확정 · Escape 취소 · 외부 값 갱신" + ], + "buttons": [ + "레이어", + "CC-D GNL", + "CC-D GNL", + "레이어 상세", + "레이어", + "CC-D GNL", + "CC-D GNL", + "레이어 상세", + "레이어", + "CC-D GNL", + "CC-D GNL", + "레이어 상세", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "외부 값 변경 (12.5)", + "외부 텍스트 변경" + ], + "inputs": 7 + }, + { + "id": "sw-header--property-panel", + "name": "Property Panel", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [], + "headings": [], + "buttons": [ + "선택 없음", + "전체 선택", + "원 1개", + "모두 펼침", + "1920px", + "1440px", + "1080px", + "900px", + "768px", + "640px", + "390px", + "Controlled: false", + "외부 Open 변경", + "속성 추가", + "형상 속성 추가", + "CENTER 옵션 삭제", + "레이어 속성 삭제", + "외부 값 변경", + "선택 객체 교체", + "속성 순서 뒤집기", + "가중치 Disabled", + "레이어 ReadOnly", + "투명도 외부 값 변경", + "투명도 Disabled", + "투명도 ReadOnly", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료" + ], + "inputs": 0 + }, + { + "id": "sw-header--property-panel-variants", + "name": "Property Panel Variants", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [], + "headings": [], + "buttons": [ + "선택 없음", + "전체 선택", + "원 1개", + "모두 펼침", + "1920px", + "1440px", + "1080px", + "900px", + "768px", + "640px", + "390px", + "Controlled: false", + "외부 Open 변경", + "속성 추가", + "형상 속성 추가", + "CENTER 옵션 삭제", + "레이어 속성 삭제", + "외부 값 변경", + "선택 객체 교체", + "속성 순서 뒤집기", + "가중치 Disabled", + "레이어 ReadOnly", + "투명도 외부 값 변경", + "투명도 Disabled", + "투명도 ReadOnly", + "객체 선택 도구", + "속성창 닫기", + "0", + "Continuous(ByL)", + "공통 속성 펼치기" + ], + "inputs": 5 + }, + { + "id": "sw-header--k-guide", + "name": "K Guide", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [], + "headings": [], + "buttons": [ + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료" + ], + "inputs": 0 + }, + { + "id": "sw-header--additional-hover", + "name": "Additional Hover", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [], + "headings": [], + "buttons": [ + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료", + "외부 ByLayer", + "외부 ByBlock", + "외부 직접 색상", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료" + ], + "inputs": 0 + }, + { + "id": "sw-header--property-bar", + "name": "Property Bar", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [ + { + "title": "콘텐츠 폭 기준 (부모 1222px, 높이 28)" + } + ], + "headings": [ + "콘텐츠 폭 기준 (부모 1222px, 높이 28)" + ], + "buttons": [ + "Controlled 전환", + "외부 열림 변경", + "Bar 필드 추가", + "Bar 반지름 삭제", + "Bar 순서 반전", + "Bar 외부 값 변경", + "Bar 객체 교체", + "Bar ReadOnly", + "Bar Disabled", + "Bar 개별 제한", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료" + ], + "inputs": 4 + }, + { + "id": "sw-header--dynamic-controls", + "name": "Dynamic Controls", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [], + "headings": [], + "buttons": [ + "구성 초기화", + "모두 제거", + "레이어·선스타일만", + "파일·색상 제거", + "구성 순서 반전", + "구성 라벨 변경", + "색상 숨김", + "숨김 복원", + "임시 로고 홈", + "문서: 현재 문서.dwg", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "더보기", + "최소화", + "종료" + ], + "inputs": 12 + }, + { + "id": "sw-header--colorize", + "name": "Colorize", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [], + "headings": [], + "buttons": [ + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료" + ], + "inputs": 0 + }, + { + "id": "sw-header--composition", + "name": "Composition (Visibility · Order)", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [], + "headings": [], + "buttons": [ + "기본 전체", + "구성 A", + "구성 B (레이어·선스타일)", + "구성 C (로고만)", + "파일 목록 제거", + "레이어 제거", + "색상 제거", + "스타일 그룹 제거", + "여러 메뉴 제거", + "순서 변경", + "숨김 + 순서 변경", + "기본 순서", + "순서 반전", + "첫 메뉴를 끝으로", + "중복·알 수 없는 ID", + "실제 화면", + "1920px", + "1440px", + "1080px", + "900px", + "768px", + "640px", + "390px", + "임시 로고 홈", + "문서: C0020101-006-평면및종단면도(06)", + "레이어", + "색상", + "선스타일", + "문자스타일", + "치수스타일", + "더보기", + "속성Bar", + "속성창", + "인쇄", + "팝업 가이드", + "최소화", + "종료" + ], + "inputs": 16 + }, + { + "id": "sw-header--property-panel-none", + "name": "Property Panel · 선택 없음", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [], + "headings": [], + "buttons": [ + "객체 선택 도구", + "속성창 닫기", + "0", + "Continuous(ByL)", + "공통 속성 펼치기" + ], + "inputs": 5 + }, + { + "id": "sw-header--property-panel-all", + "name": "Property Panel · 전체 선택", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [], + "headings": [], + "buttons": [ + "객체 선택 도구", + "속성창 닫기", + "다양함", + "Continuous(ByL)", + "공통 속성 펼치기" + ], + "inputs": 5 + }, + { + "id": "sw-header--property-panel-circle", + "name": "Property Panel · 원 1개", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [], + "headings": [ + "형상", + "위치" + ], + "buttons": [ + "속성창 닫기", + "0_Layer_Cludmark", + "Continuous(ByL)", + "공통 속성 펼치기", + "선택된 객체 - 전체 11" + ], + "inputs": 12 + }, + { + "id": "sw-header--property-panel-expanded", + "name": "Property Panel · 모두 펼침", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [], + "headings": [ + "형상", + "위치" + ], + "buttons": [ + "속성창 닫기", + "0_Layer_Cludmark", + "Continuous(ByL)", + "공통 속성 접기", + "선택된 객체 - 전체 11" + ], + "inputs": 15 + }, + { + "id": "sw-header--property-panel-compare", + "name": "Property Panel · 4개 비교", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [], + "headings": [ + "형상", + "위치", + "형상", + "위치" + ], + "buttons": [ + "객체 선택 도구", + "속성창 닫기", + "0", + "Continuous(ByL)", + "공통 속성 펼치기", + "객체 선택 도구", + "속성창 닫기", + "다양함", + "Continuous(ByL)", + "공통 속성 펼치기", + "속성창 닫기", + "0_Layer_Cludmark", + "Continuous(ByL)", + "공통 속성 펼치기", + "선택된 객체 - 전체 11", + "속성창 닫기", + "0_Layer_Cludmark", + "Continuous(ByL)", + "공통 속성 접기", + "선택된 객체 - 전체 11" + ], + "inputs": 37 + }, + { + "id": "sw-header--property-shape-slot", + "name": "Property Panel · 형상 Slot", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [], + "headings": [ + "형상", + "위치" + ], + "buttons": [ + "기본 Figma 형상", + "비움 (null)", + "외부 컴포넌트", + "Render Prop", + "형상 교체 (원 ↔ 사각형)", + "지름·반지름 외부 변경", + "형상 그룹 항목 추가", + "면적 삭제", + "속성창 닫기", + "0_Layer_Cludmark", + "Continuous(ByL)", + "공통 속성 펼치기", + "선택된 객체 - 전체 11" + ], + "inputs": 12 + }, + { + "id": "sw-header--property-fields", + "name": "Property Panel · 필드 13개", + "tags": [ + "dev", + "test", + "manifest" + ], + "render": true, + "errors": [], + "sections": [], + "headings": [], + "buttons": [ + "레이어 다양함 ↔ 단일", + "레이어 외부 값 변경", + "선축적 외부 값 변경", + "두께 단위 변경", + "선스타일 외부 CENTER", + "두께·레이어 ReadOnly", + "선축적·색상 Disabled", + "속성 추가", + "하이퍼링크 삭제", + "menus 없음(options 사용): false", + "객체 선택 도구", + "속성창 닫기", + "다양함", + "0_Layer_Cludmark", + "Continuous(ByL)", + "객체 선택 도구", + "속성창 닫기", + "다양함", + "0_Layer_Cludmark", + "Continuous(ByL)", + "객체 선택 도구", + "속성창 닫기", + "다양함", + "0_Layer_Cludmark", + "Continuous(ByL)" + ], + "inputs": 24 + } +] diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--additional-hover.png b/docs/sw/storybook-overview-qa/screens/sw-header--additional-hover.png new file mode 100644 index 0000000..0226cc5 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--additional-hover.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--color-dropdown.png b/docs/sw/storybook-overview-qa/screens/sw-header--color-dropdown.png new file mode 100644 index 0000000..94b4605 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--color-dropdown.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--colorize.png b/docs/sw/storybook-overview-qa/screens/sw-header--colorize.png new file mode 100644 index 0000000..470ca41 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--colorize.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--composed-controls.png b/docs/sw/storybook-overview-qa/screens/sw-header--composed-controls.png new file mode 100644 index 0000000..3c9dbb1 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--composed-controls.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--composition.png b/docs/sw/storybook-overview-qa/screens/sw-header--composition.png new file mode 100644 index 0000000..04269f9 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--composition.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--detail-buttons.png b/docs/sw/storybook-overview-qa/screens/sw-header--detail-buttons.png new file mode 100644 index 0000000..6114106 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--detail-buttons.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--document-dropdown.png b/docs/sw/storybook-overview-qa/screens/sw-header--document-dropdown.png new file mode 100644 index 0000000..586b910 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--document-dropdown.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--dynamic-controls.png b/docs/sw/storybook-overview-qa/screens/sw-header--dynamic-controls.png new file mode 100644 index 0000000..e8d7e33 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--dynamic-controls.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--interactive-states.png b/docs/sw/storybook-overview-qa/screens/sw-header--interactive-states.png new file mode 100644 index 0000000..cfc8f68 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--interactive-states.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--k-guide.png b/docs/sw/storybook-overview-qa/screens/sw-header--k-guide.png new file mode 100644 index 0000000..17444c9 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--k-guide.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--layer-detail-input.png b/docs/sw/storybook-overview-qa/screens/sw-header--layer-detail-input.png new file mode 100644 index 0000000..3476f02 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--layer-detail-input.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--layer-dropdown.png b/docs/sw/storybook-overview-qa/screens/sw-header--layer-dropdown.png new file mode 100644 index 0000000..396b4d8 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--layer-dropdown.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--line-style-dropdown.png b/docs/sw/storybook-overview-qa/screens/sw-header--line-style-dropdown.png new file mode 100644 index 0000000..c37fae1 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--line-style-dropdown.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--logo-slot.png b/docs/sw/storybook-overview-qa/screens/sw-header--logo-slot.png new file mode 100644 index 0000000..3af064b Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--logo-slot.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--overview.png b/docs/sw/storybook-overview-qa/screens/sw-header--overview.png new file mode 100644 index 0000000..e6d87e3 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--overview.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--property-bar.png b/docs/sw/storybook-overview-qa/screens/sw-header--property-bar.png new file mode 100644 index 0000000..5430403 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--property-bar.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--property-fields.png b/docs/sw/storybook-overview-qa/screens/sw-header--property-fields.png new file mode 100644 index 0000000..7271205 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--property-fields.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--property-panel-all.png b/docs/sw/storybook-overview-qa/screens/sw-header--property-panel-all.png new file mode 100644 index 0000000..a8e1a65 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--property-panel-all.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--property-panel-circle.png b/docs/sw/storybook-overview-qa/screens/sw-header--property-panel-circle.png new file mode 100644 index 0000000..3d7d73d Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--property-panel-circle.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--property-panel-compare.png b/docs/sw/storybook-overview-qa/screens/sw-header--property-panel-compare.png new file mode 100644 index 0000000..9656dfa Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--property-panel-compare.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--property-panel-expanded.png b/docs/sw/storybook-overview-qa/screens/sw-header--property-panel-expanded.png new file mode 100644 index 0000000..feb935e Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--property-panel-expanded.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--property-panel-none.png b/docs/sw/storybook-overview-qa/screens/sw-header--property-panel-none.png new file mode 100644 index 0000000..d9d9667 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--property-panel-none.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--property-panel-variants.png b/docs/sw/storybook-overview-qa/screens/sw-header--property-panel-variants.png new file mode 100644 index 0000000..97cf3d0 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--property-panel-variants.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--property-panel.png b/docs/sw/storybook-overview-qa/screens/sw-header--property-panel.png new file mode 100644 index 0000000..ed6697d Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--property-panel.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--property-shape-slot.png b/docs/sw/storybook-overview-qa/screens/sw-header--property-shape-slot.png new file mode 100644 index 0000000..1c90410 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--property-shape-slot.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--responsive-more.png b/docs/sw/storybook-overview-qa/screens/sw-header--responsive-more.png new file mode 100644 index 0000000..eb45b13 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--responsive-more.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--text-dimension-style-dropdown.png b/docs/sw/storybook-overview-qa/screens/sw-header--text-dimension-style-dropdown.png new file mode 100644 index 0000000..28ebb7e Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--text-dimension-style-dropdown.png differ diff --git a/docs/sw/storybook-overview-qa/screens/sw-header--window-move-motion.png b/docs/sw/storybook-overview-qa/screens/sw-header--window-move-motion.png new file mode 100644 index 0000000..3da7a58 Binary files /dev/null and b/docs/sw/storybook-overview-qa/screens/sw-header--window-move-motion.png differ diff --git a/docs/sw/storybook-overview-qa/storybook-build.txt b/docs/sw/storybook-overview-qa/storybook-build.txt new file mode 100644 index 0000000..a3fc2a2 --- /dev/null +++ b/docs/sw/storybook-overview-qa/storybook-build.txt @@ -0,0 +1,306 @@ + +T Building storybook v10.6.1 +| +o Cleaning outputDir: storybook-static +| +o Loading presets +| +o Building manager.. +| +• Building open services.. +| +• Building preview.. +| +• Copying static files: public\fonts at storybook-static\fonts +| +• Copying static files: themes at storybook-static\themes +| Vite vite v8.3.0 building client environment for production... +transforming... +Found 1 warning while optimizing generated CSS: + +│ } +│ .bg-\[var\(\.\.\.\)\] { +│ background-color: var(...); +┆ ^-- Unexpected token Delim('.') +┆ +│ } +│ .bg-background { + +✓ 3102 modules transformed. +| +! Vite [lightningcss minify] 'host-context' is not recognized as a valid +| pseudo-class. Did you mean '::host-context' (pseudo-element) or is +| this a typo? +| 1322 | background-color: var(--hm-orgchart-dialog-close-hover); +| 1323 | } +| 1324 | :host-context(.dark) .hm-orgchart-employee-dialog-close:hover, +| | ^ +| 1325 | .dark .hm-orgchart-employee-dialog-close:hover { +| 1326 | background-color: color-mix(in oklab, +| var(--hm-orgchart-dialog-close-hover) 50%, transparent); +rendering chunks... +computing gzip size... +| Vite storybook-static/assets/input-26-11656-BIXt51ww.png +| 5.09 kB +| storybook-static/iframe.html +| 19.07 kB │ gzip: 5.42 kB +| storybook-static/assets/NotoSansKR-variable-k7NQXPol.ttf +| 10,414.58 kB +| storybook-static/assets/data-table-x0avmA1M.css +| 0.89 kB │ gzip: 0.32 kB +| storybook-static/assets/department-colors-preview-C8o8mgn-.css +| 1.12 kB │ gzip: 0.39 kB +| storybook-static/assets/org-chart-stories-CVVpQeIs.css +| 1.15 kB │ gzip: 0.39 kB +| storybook-static/assets/org-chart-expanded-BQqXfdmZ.css +| 1.34 kB │ gzip: 0.43 kB +| storybook-static/assets/story-page-B9TObVPB.css +| 1.74 kB │ gzip: 0.49 kB +| storybook-static/assets/designer-theme-Bv3QXGf0.css +| 2.88 kB │ gzip: 0.85 kB +| storybook-static/assets/reference-CElszmAj.css +| 3.13 kB │ gzip: 0.87 kB +| storybook-static/assets/center-stories-MLQreMPw.css +| 6.77 kB │ gzip: 1.49 kB +| storybook-static/assets/dashboard-layout-cwHZMCdB.css +| 6.90 kB │ gzip: 1.21 kB +| storybook-static/assets/engine-DrWcIejL.css +| 15.64 kB │ gzip: 3.10 kB +| storybook-static/assets/center-shared-CBSMPY7X.css +| 55.67 kB │ gzip: 10.48 kB +| storybook-static/assets/sw-header-CUYjY3HM.css +| 73.13 kB │ gzip: 13.58 kB +| storybook-static/assets/style-BhhUui7W.css +| 93.80 kB │ gzip: 12.41 kB +| storybook-static/assets/iframe-BW1xNYqB.css +| 237.20 kB │ gzip: 36.15 kB +| storybook-static/assets/iframe-BN7HSSg4.js +| 0.04 kB │ gzip: 0.06 kB +| storybook-static/assets/center-stories-Cr38slYE.js +| 0.09 kB │ gzip: 0.11 kB +| storybook-static/assets/org-chart-stories-BU9b3y-N.js +| 0.09 kB │ gzip: 0.11 kB +| storybook-static/assets/chart-column-39yOKDYH.js +| 0.41 kB │ gzip: 0.29 kB +| storybook-static/assets/layout-grid-6y2ii6HT.js +| 0.48 kB │ gzip: 0.28 kB +| storybook-static/assets/italic-DkeWgR9v.js +| 0.58 kB │ gzip: 0.36 kB +| storybook-static/assets/org-chart-full-composition.stories-D1pErr-l.js +| 0.59 kB │ gzip: 0.39 kB +| storybook-static/assets/org-chart-p1.stories-CfXa_6Rp.js +| 0.59 kB │ gzip: 0.40 kB +| storybook-static/assets/org-chart-department-colors.stories-CtRK7aJI.js +| 0.60 kB │ gzip: 0.39 kB +| storybook-static/assets/settings-BS9DjRDa.js +| 0.62 kB │ gzip: 0.34 kB +| storybook-static/assets/org-chart-summary.stories-B900zJzh.js +| 0.76 kB │ gzip: 0.40 kB +| storybook-static/assets/center-information.stories-QS-Xk9cm.js +| 0.94 kB │ gzip: 0.63 kB +| storybook-static/assets/sample-users-CAqvNHXG.js +| 0.94 kB │ gzip: 0.67 kB +| storybook-static/assets/center-spatial.stories-BKywiGMs.js +| 0.97 kB │ gzip: 0.64 kB +| storybook-static/assets/rolldown-runtime-DkW27tQK.js +| 1.19 kB │ gzip: 0.67 kB +| storybook-static/assets/preload-helper-VEOc_cSF.js +| 1.33 kB │ gzip: 0.75 kB +| storybook-static/assets/center-title.stories-D4g3unBO.js +| 1.36 kB │ gzip: 0.88 kB +| storybook-static/assets/org-chart-overview-internal.stories-CZjDbHDQ.js +| 1.43 kB │ gzip: 0.68 kB +| storybook-static/assets/org-chart-cards.stories-BMF7xDR7.js +| 1.60 kB │ gzip: 0.92 kB +| storybook-static/assets/color.stories-DZb1MHtw.js +| 1.80 kB │ gzip: 1.03 kB +| storybook-static/assets/center-facility.stories-SWGtrHnb.js +| 1.90 kB │ gzip: 1.08 kB +| storybook-static/assets/loading-screen.stories-Dff8ndFU.js +| 1.96 kB │ gzip: 1.04 kB +| storybook-static/assets/story-board-BEJDReki.js +| 1.99 kB │ gzip: 0.89 kB +| storybook-static/assets/skeleton.stories-kNCVEaAs.js +| 2.10 kB │ gzip: 1.01 kB +| storybook-static/assets/story-page-BdQwBtvH.js +| 2.13 kB │ gzip: 0.69 kB +| storybook-static/assets/verification-state-BvmqrSTe.js +| 2.15 kB │ gzip: 1.05 kB +| storybook-static/assets/hover-card.stories-Crbf6ekx.js +| 2.34 kB │ gzip: 1.09 kB +| storybook-static/assets/alert-dialog.stories-YCXcnGTq.js +| 2.48 kB │ gzip: 1.08 kB +| storybook-static/assets/separator.stories-DCH35yh1.js +| 2.56 kB │ gzip: 1.16 kB +| storybook-static/assets/dropdown-menu.stories-GGuA7NCs.js +| 2.58 kB │ gzip: 1.29 kB +| storybook-static/assets/badge.stories-CHBpLyWb.js +| 2.61 kB │ gzip: 1.23 kB +| storybook-static/assets/tooltip.stories-CAhvJiqg.js +| 2.65 kB │ gzip: 1.23 kB +| storybook-static/assets/publisher-regression.stories-BSdjbYdq.js +| 2.70 kB │ gzip: 1.15 kB +| storybook-static/assets/calendar.stories-CEWYrdQ5.js +| 2.79 kB │ gzip: 1.31 kB +| storybook-static/assets/switch.stories-DHCVpaSE.js +| 2.86 kB │ gzip: 1.28 kB +| storybook-static/assets/reference-yKN_SnBk.js +| 2.88 kB │ gzip: 1.24 kB +| storybook-static/assets/context-menu.stories-ZITwa1kb.js +| 2.95 kB │ gzip: 1.47 kB +| storybook-static/assets/center-shared-CSGUuM9T.js +| 2.96 kB │ gzip: 1.36 kB +| storybook-static/assets/scroll-area.stories-DEvdgplg.js +| 3.02 kB │ gzip: 1.30 kB +| storybook-static/assets/popover.stories-DvMwP766.js +| 3.05 kB │ gzip: 1.30 kB +| storybook-static/assets/aspect-ratio.stories-7mL3laNq.js +| 3.06 kB │ gzip: 1.52 kB +| storybook-static/assets/typography.stories-CKjfpWpM.js +| 3.07 kB │ gzip: 1.42 kB +| storybook-static/assets/pagination.stories-Mbhc8AU9.js +| 3.12 kB │ gzip: 1.50 kB +| storybook-static/assets/alert.stories-CpyLpNi-.js +| 3.16 kB │ gzip: 1.30 kB +| storybook-static/assets/label.stories-CPEv7gzc.js +| 3.19 kB │ gzip: 1.39 kB +| storybook-static/assets/collapsible.stories-DO9N9ksi.js +| 3.19 kB │ gzip: 1.50 kB +| storybook-static/assets/drawer.stories-C9cifdBI.js +| 3.23 kB │ gzip: 1.47 kB +| storybook-static/assets/radio-group.stories-DwqwXVDe.js +| 3.24 kB │ gzip: 1.47 kB +| storybook-static/assets/avatar.stories-B6K5na20.js +| 3.30 kB │ gzip: 1.45 kB +| storybook-static/assets/page-header.stories-HeG_6w9V.js +| 3.32 kB │ gzip: 1.30 kB +| storybook-static/assets/menubar.stories-BhTzLN_a.js +| 3.33 kB │ gzip: 1.39 kB +| storybook-static/assets/command.stories-D-XMtuKM.js +| 3.33 kB │ gzip: 1.58 kB +| storybook-static/assets/center-overview.stories-E8zT3EyS.js +| 3.36 kB │ gzip: 1.77 kB +| storybook-static/assets/filter-bar.stories-DcTIJuSP.js +| 3.43 kB │ gzip: 1.72 kB +| storybook-static/assets/sheet.stories-DdnpVhWc.js +| 3.51 kB │ gzip: 1.44 kB +| storybook-static/assets/progress.stories-BDmSy5Qj.js +| 3.52 kB │ gzip: 1.61 kB +| storybook-static/assets/breadcrumb.stories-ChR_KDt-.js +| 3.55 kB │ gzip: 1.52 kB +| storybook-static/assets/card.stories-_z1r7XI2.js +| 3.74 kB │ gzip: 1.63 kB +| storybook-static/assets/navigation-menu.stories-H4SlN4bU.js +| 3.86 kB │ gzip: 1.62 kB +| storybook-static/assets/resizable.stories-uaf5IGxv.js +| 3.96 kB │ gzip: 1.46 kB +| storybook-static/assets/specimens-Ch5aVLS1.js +| 4.13 kB │ gzip: 1.36 kB +| storybook-static/assets/sonner.stories-gVdEDxUX.js +| 4.22 kB │ gzip: 1.83 kB +| storybook-static/assets/checkbox.stories-CgA-2wok.js +| 4.39 kB │ gzip: 1.66 kB +| storybook-static/assets/date-picker.stories-DHa1DjlV.js +| 4.45 kB │ gzip: 1.69 kB +| storybook-static/assets/slider.stories-BcPpzY38.js +| 4.53 kB │ gzip: 1.86 kB +| storybook-static/assets/org-chart-page-previews-Ctz_kKme.js +| 4.70 kB │ gzip: 2.05 kB +| storybook-static/assets/carousel.stories-BLEYsPtS.js +| 4.75 kB │ gzip: 1.91 kB +| storybook-static/assets/layout.stories-BQltBMcD.js +| 4.79 kB │ gzip: 1.92 kB +| storybook-static/assets/table.stories-B82HKFvC.js +| 4.86 kB │ gzip: 2.02 kB +| storybook-static/assets/combobox.stories-49EFqEgG.js +| 5.03 kB │ gzip: 2.07 kB +| storybook-static/assets/accordion.stories-Bzzb4Ud4.js +| 5.05 kB │ gzip: 1.81 kB +| storybook-static/assets/OrgChart-DZlWXlj3-Cg7VHAIW.js +| 5.35 kB │ gzip: 1.95 kB +| storybook-static/assets/dialog.stories-CHiRjmir.js +| 5.53 kB │ gzip: 2.13 kB +| storybook-static/assets/toggle.stories-DffHj9E4.js +| 5.81 kB │ gzip: 2.13 kB +| storybook-static/assets/data-table.stories-B40WrOK1.js +| 5.92 kB │ gzip: 2.52 kB +| storybook-static/assets/textarea.stories-t-9JtP6t.js +| 5.99 kB │ gzip: 2.43 kB +| storybook-static/assets/runtime-loader.stories-Cgs8Weu2.js +| 6.18 kB │ gzip: 2.45 kB +| storybook-static/assets/toggle-group.stories-BRmj8DKL.js +| 6.57 kB │ gzip: 2.23 kB +| storybook-static/assets/react-Q1GcV6wX.js +| 7.87 kB │ gzip: 3.01 kB +| storybook-static/assets/input.stories-BXqV7hCq.js +| 8.32 kB │ gzip: 3.05 kB +| storybook-static/assets/button.stories-CG1boIti.js +| 9.65 kB │ gzip: 3.62 kB +| storybook-static/assets/select.stories-CwcBCz1l.js +| 10.52 kB │ gzip: 3.39 kB +| storybook-static/assets/tabs.stories-G8gk_Flp.js +| 11.57 kB │ gzip: 4.13 kB +| storybook-static/assets/org-chart.stories-welHTajy.js +| 12.54 kB │ gzip: 4.16 kB +| storybook-static/assets/designer-theme.stories-BzNQsLun.js +| 14.62 kB │ gzip: 5.51 kB +| storybook-static/assets/gnb.stories-CIUtlAzi.js +| 16.56 kB │ gzip: 5.84 kB +| storybook-static/assets/theme-CZw7CMzf.js +| 18.61 kB │ gzip: 3.18 kB +| storybook-static/assets/lnb.stories-BFHV7Rpz.js +| 23.06 kB │ gzip: 6.43 kB +| storybook-static/assets/dashboard-layout.stories-Okv-SwFR.js +| 23.84 kB │ gzip: 6.25 kB +| storybook-static/vite-inject-mocker-entry.js +| 27.84 kB │ gzip: 9.66 kB +| storybook-static/assets/reference-data-Dp4dBiCx.js +| 40.42 kB │ gzip: 9.43 kB +| storybook-static/assets/runtime-theme.stories-WGYRELlW.js +| 61.92 kB │ gzip: 11.60 kB +| storybook-static/assets/org-chart-expanded.stories-DYDKWoe7.js +| 79.03 kB │ gzip: 10.07 kB +| storybook-static/assets/react-18-BukvVaPF.js +| 207.62 kB │ gzip: 65.12 kB +| storybook-static/assets/core-component-preview-CbmTQndg.js +| 258.40 kB │ gzip: 146.05 kB +| storybook-static/assets/sw-header.stories-edbdMdWE.js +| 768.59 kB │ gzip: 359.85 kB +| storybook-static/assets/reference-Bz-UmAfk.js +| 1,644.48 kB │ gzip: 270.35 kB +| storybook-static/assets/iframe-NxI5EhLm.js +| 1,754.05 kB │ gzip: 503.61 kB +| storybook-static/assets/style-CNeiB0x2.js +| 2,359.94 kB │ gzip: 1,631.23 kB + +| +! Vite [plugin builtin:vite-reporter] +| (!) Some chunks are larger than 500 kB after minification. Consider: +| - Using dynamic import() to code-split the application +| - Use build.rolldownOptions.output.codeSplitting to improve chunking: +| ]8;;https://rolldown.rs/reference/OutputOptions.codeSplittinghttps://rolldown.rs/reference/OutputOptions.codeSplitting]8;; +| - Adjust chunk size limit for this warning via +| build.chunkSizeWarningLimit. +| Vite ✓ built in 3.55s +| +! Vite [PLUGIN_TIMINGS] JavaScript callbacks ran for 3.0s of this 3.5s +| build (86%). +| The slowest callbacks, timed inside each callback (the wait before a +| callback starts is excluded, the time it awaits is included): +| - plugin storybook:react-docgen-plugin transform (60%, 2.1s, 3102 +| calls) +| Additional callback time came from the callbacks below and from +| callbacks under 1s. +| 3 callbacks are listed without a time. Their calls overlapped, so the +| time inside one call includes work from other calls. To find their +| cost, profile the build with `node --cpu-prof`: +| - plugin vite:asset load (31 calls) +| - plugin @tailwindcss/vite:generate:build transform (19 calls) +| - plugin vite:css transform (19 calls) +| See ]8;;https://rolldown.rs/reference/InputOptions.checks#bundlertimingshttps://rolldown.rs/reference/InputOptions.checks#bundlertimings]8;; +| for more details. + +| +o Output directory: D:/디자인시스템/HMDesign-SW/storybook-static +| +— Storybook build completed successfully diff --git a/docs/sw/storybook-overview-qa/sw-build.txt b/docs/sw/storybook-overview-qa/sw-build.txt new file mode 100644 index 0000000..c043564 --- /dev/null +++ b/docs/sw/storybook-overview-qa/sw-build.txt @@ -0,0 +1,17 @@ + +> hm-design-system-poc@0.1.0 build:sw +> npm run build -w @hm-design/sw + + +> @hm-design/sw@0.1.0 build +> node build.mjs + +vite v8.3.0 building client environment for production... +transforming... +✓ 69 modules transformed. +rendering chunks... +computing gzip size... +dist/styles.css 100.39 kB │ gzip: 23.57 kB +dist/index.js 712.25 kB │ gzip: 337.98 kB + +✓ built in 131ms diff --git a/docs/sw/storybook-overview-qa/sw-typecheck.txt b/docs/sw/storybook-overview-qa/sw-typecheck.txt new file mode 100644 index 0000000..628ebf5 --- /dev/null +++ b/docs/sw/storybook-overview-qa/sw-typecheck.txt @@ -0,0 +1,7 @@ + +> hm-design-system-poc@0.1.0 typecheck:sw +> npm run typecheck -w @hm-design/sw + + +> @hm-design/sw@0.1.0 typecheck +> tsc -p tsconfig.json diff --git a/docs/sw/storybook-overview-qa/validation-summary.json b/docs/sw/storybook-overview-qa/validation-summary.json new file mode 100644 index 0000000..ebb0839 --- /dev/null +++ b/docs/sw/storybook-overview-qa/validation-summary.json @@ -0,0 +1,58 @@ +{ + "baseCommit": "50bf5bda8e956a4973b923d64131f2f2285bd38c", + "scope": "STORYBOOK_ONLY", + "storybookCount": { + "before": 28, + "after": 28 + }, + "chrome": { + "checks": 53, + "status": "PASS" + }, + "overlays": { + "checks": 19, + "status": "PASS" + }, + "firefox": { + "checks": 9, + "status": "PASS", + "version": "158.0", + "infrastructureWarnings": [ + "downloadable font: download failed (font-family: \"Nunito Sans\" style:normal weight:400 width:100 src index:0): status=2147746065 source: http://127.0.0.1:8191/sb-common-assets/nunito-sans-regular.woff2", + "downloadable font: download failed (font-family: \"Nunito Sans\" style:normal weight:400 width:100 src index:0): status=2147746065 source: http://127.0.0.1:8191/sb-common-assets/nunito-sans-regular.woff2" + ] + }, + "commands": [ + { + "command": "npm.cmd run typecheck:sw", + "status": "PASS" + }, + { + "command": "npm.cmd exec -- tsc -p tsconfig.app.json --noEmit", + "status": "PASS" + }, + { + "command": "npm.cmd run build:sw", + "status": "PASS", + "distIndexUnchanged": true + }, + { + "command": "npm.cmd exec -- storybook build -o storybook-static --disable-telemetry", + "status": "PASS" + } + ], + "sourceSha256": { + "src/sw/sw-header.stories.tsx": "a2d81948871ed52821ab3fe821033c723c8e7ff38f562fa942bfd71d9a5d6e67", + "src/sw/sw-header-overview.tsx": "74a7c032fa11966147f6ab16837cc523f82012502a6de9fec59930477de721df", + "src/sw/sw-stories.css": "462e2314756a86e74e385f92fed1542e4a146f932617a9e7d860183041a28259" + }, + "unchangedStoryDeclarations": 27, + "originalStoryStylesPreserved": true, + "productionPackageSourceUnchanged": true, + "notVerified": [ + "Full interaction regression of the other 27 Stories", + "Full Firefox dropdown/bar/gauge integration", + "CAD, file and operating-system integrations", + "Full accessibility certification" + ] +} diff --git a/docs/sw/sw-storybook-screen-review-2026-10-19.md b/docs/sw/sw-storybook-screen-review-2026-10-19.md new file mode 100644 index 0000000..3c211c1 --- /dev/null +++ b/docs/sw/sw-storybook-screen-review-2026-10-19.md @@ -0,0 +1,308 @@ +# SW Header 메인 개선 및 Storybook 화면별 검토 — 2026-10-19 + +**최종 판정: PASS — 요청한 Overview 개선·28개 화면 조사 범위.** 다른 Story의 삭제·통합·이름 변경·재분류는 적용하지 않았습니다. + +- 시작: `D:\디자인시스템\HMDesign-SW`, `feature/sw-package`, HEAD `50bf5bda8e956a4973b923d64131f2f2285bd38c`, Working Tree clean, 기존 로컬 Commit 3개. +- 실제 수정 Story: **Overview — `sw-header--overview`**. 공개 `@hm-design/sw` 컴포넌트를 사용합니다. +- Story 수는 **28 → 28**이며 ID·이름·순서·태그가 그대로입니다. 다른 27개 Story 선언은 시작 Commit과 동일합니다. +- `packages/sw/src`, 공개 API, 패키지 CSS·자산, 기존 QA 기록과 디자인 명세는 수정하지 않았습니다. +- Git 정책: 현재 브랜치에 로컬 Commit만 생성. Push·PR·배포·새 브랜치 생성 없음. Commit Hash와 최종 Git 상태는 완료 메시지에 기록합니다. + +## 메인 화면의 변경 + +이전에는 `Figma 기준 1920 × 49`와 `선택 상태`라는 고정 1920px Header 표본 두 개를 표시했습니다. 이 두 시연 영역과 긴 설명을 제거하고, 하나의 실제 Header와 편집 가능한 미리보기로 바꿨습니다. `SW Header` 페이지 제목은 한 번만 표시합니다. + +- [수정 전](storybook-overview-qa/overview-before.png) +- [수정 후](storybook-overview-qa/overview-after.png) +- [Storybook 사이드바가 열린 실제 화면](storybook-overview-qa/overview-manager.png) +- [전체 펼침 팝업](storybook-overview-qa/overview-after-expanded.png) +- [팝업 하단 스크롤·편집](storybook-overview-qa/overview-after-scrolled.png) +- [작은 Inner에서 하단 접근](storybook-overview-qa/overview-narrow.png) + +### 16:9 Stage와 큰 팝업 처리 + +기존 StoryPage의 실제 `.sb-page-inner` 안에서 제목·시연 설정·상태 줄을 제외한 남은 영역을 `ResizeObserver`로 측정합니다. `width = min(사용 가능한 폭, 사용 가능한 높이 × 16 / 9)`, `height = width × 9 / 16`으로 두 방향 모두 맞추고 중앙 정렬합니다. iframe 자체 크기를 사용하므로 Storybook 사이드바·툴바·미리보기 크기 변경에도 다시 계산됩니다. + +실측 예: + +- iframe 1920×1080 / 1440×900: Stage **1200×675px**. 기존 Inner 최대 폭을 따릅니다. +- iframe 1280×720: **896.875×504.5px**. 높이가 크기 제한입니다. +- iframe 768×600: **683.547×384.5px**. +- iframe 390×844: **358×201.375px**. +- iframe 1000×500: **505.766×284.5px**. 낮은 화면에서도 폭만으로 계산하지 않습니다. +- 1440×1000 브라우저에서 실제 Storybook manager 표시: 미리보기 iframe 1140×960, Stage **1071.594×602.766px**. +- 모든 조건의 Header는 **49px**, 속성Bar는 기존 **28px**입니다. Header의 문자·아이콘·버튼·Dropdown을 확대/축소하지 않습니다. + +Stage는 내부 스크롤 영역이며 미리보기 내용의 최소 폭은 390px입니다. Stage가 그보다 좁으면 가로 스크롤을 제공합니다. 팝업의 **314×256 / 314×361 / 314×658 / 314×754px**는 그대로입니다. 전체 펼침 팝업이 Stage 높이보다 크면 세로 스크롤로 하단 XYZ·푸터에 접근합니다. 390px 화면에서도 실제 Z 입력·확정과 Escape 후 More Focus 복귀를 확인했습니다. + +Header의 공개 `propertyPanel` 타입은 위치 `style`을 받지 않으므로 Overview에만 한정한 Story CSS로 팝업을 Header 아래의 절대 배치로 바꿨습니다. `top/left/max-height`만 배치 목적에 맞게 조정하며 자연 폭·폰트·간격·색·모양은 유지합니다. 문서 목록이 열린 경우에만 문서 wrapper의 쌓임 순서를 올려 속성Bar에 가려지지 않게 했습니다. 중첩 속성 Dropdown은 기존 fixed 위치 계산과 z-index를 사용합니다. 이 예외는 다른 Story와 제품 CSS에 적용되지 않습니다. + +### 연결한 기능과 상태 + +- 문서 목록: 선택·닫기·New 목록 추가, Open Callback. Storybook 호스트 목록만 변경하며 실제 파일 열기/저장은 수행하지 않습니다. +- 레이어: 선택·전구·눈꽃·잠금과 상세 Callback. Header와 속성창은 같은 레이어 목록·현재 값을 사용합니다. +- 색상: 기본/사용자 팔레트·ByLayer/ByBlock·RGB 검증·Colorize·상세 Callback. Header와 속성창이 같은 RGB 상태를 사용합니다. +- 선스타일: 선 종류·가중치·User 값·스케일·상세 Callback. ByLayer/ByBlock 가중치 모드는 숫자 속성을 모드 문자열로 덮어쓰지 않습니다. +- 문자스타일·치수스타일: 각각의 선택 상태와 상세 Callback. 다른 속성 데이터에 억지로 동기화하지 않습니다. +- More: 기존 반응형 정책대로 감춰진 필드·속성Bar·속성창에 접근합니다. 모든 Dropdown을 동시에 펼치지 않습니다. +- 속성Bar: 기존 `BAR_FIXTURE`의 형상 필드와 공개 `SWHeaderPropertyBar` 편집 동작을 사용합니다. 형상 값은 속성창과 공유하며 Enter·Escape·min 검증·외부 값·Disabled/ReadOnly·필드 추가/제거를 연결했습니다. CAD 계산 관계를 새로 만들지 않았습니다. +- 속성창: Header 열기·닫기 버튼·Escape·Focus 복귀, 레이어/색상/선스타일 Dropdown, 숫자 편집·게이지·4개 선택 상태·그룹 펼침·기본/null 형상 Slot. +- 홈·인쇄·가이드·창 이동·최소화·종료는 기존 버튼과 Callback을 유지합니다. 실제 CAD/OS 동작은 호스트 소유이며 Storybook에서는 Callback을 기록합니다. + +선택 상태와 외부 값·추가 필드·제한 상태·형상 Slot 설정은 **Stage 밖의 Storybook 전용 시연 설정**입니다. 기존 Storybook 조작 방식에 맞춰 native label/select/checkbox/button을 사용했으며, 제품 Header에 추가 버튼을 넣지 않았습니다. 기존 Property Bar Story와 다른 Story의 상태 관리 코드는 변경하지 않았습니다. + +## 검증 결과와 재사용 근거 + +이번에 실행: + +- `npm.cmd run typecheck:sw`: PASS. +- `npm.cmd exec -- tsc -p tsconfig.app.json --noEmit`: PASS. 새 Overview와 Story 파일 포함. +- `npm.cmd run build:sw`: PASS. 재생성 전후 `packages/sw/dist/index.js` 해시도 동일했습니다. +- `npm.cmd run build-storybook`의 패키지 사전 빌드와 Storybook Build: PASS. 이후 Storybook 코드 수정분은 `npm.cmd exec -- storybook build -o storybook-static --disable-telemetry`로 최종 빌드했습니다. +- `overview.browser.mjs`: **53/53 PASS**. Chrome 155.0.8059.80, Inner 6개 크기, 실제 manager iframe, Dropdown 선택/전환/닫기, 공유 값, 입력 검증, 게이지, Focus, 4상태 크기, 내부 스크롤. +- `overview.browser.mjs docs/sw/storybook-overview-qa overlays`: **19/19 PASS**. 상세 Callback 5종, Header 색상 모드 표시/직접 색상 복귀, 문서 첫 행 가림, 작은 Inner 중첩 Dropdown의 폭·하단 행 클릭·Escape. +- `overview-firefox.browser.mjs`: **9/9 PASS**. 설치된 Firefox 158.0, 1400/500px 창에서 Stage·Header 높이·원래 754px 팝업·하단 접근·닫기/Focus. +- 수정 전 28개 모두 실제 Chrome 초기 렌더링·브라우저 오류 0을 확인했습니다. 수정 후 나머지 27개 Story 선언 동일, CSS의 기존 구간 동일, 패키지 소스 동일을 확인했습니다. +- Git Diff의 범위·공백 오류와 Commit 직전 Staged Diff를 검토했습니다. + +경고: + +- Storybook Build는 생성 유틸리티의 `var(...)`, OrgChart `:host-context`, chunk 크기 경고를 포함하지만 성공했습니다. 해당 코드·설정은 변경하지 않았습니다. +- Firefox는 기존에도 보고된 `/sb-common-assets/nunito-sans-regular.woff2` 글꼴 다운로드 경고가 있습니다. 정확히 이 글꼴 경고만 infrastructureWarnings로 구분하고 SW runtime 오류는 0인지 별도로 검사했습니다. [원래 인프라 경고 포함 결과](storybook-overview-qa/firefox-initial-infrastructure-result.json)와 [최종 Firefox 결과](storybook-overview-qa/firefox-result.json)를 함께 보존합니다. 이전 [Firefox 검증 기록](sw-header-firefox-range-close-verification-2026-10-19.md)에도 같은 경고가 있습니다. + +재사용한 과거 PASS — 이번 실행 결과와 구분: + +- [1단계 정리](sw-storybook-cleanup-stage1-2026-10-19.md): 33→28, 범위 검증 49/49, 기존 보존 15/15. 이번에는 현재 28개 ID·이름·태그 유지와 새 메인 동작을 별도로 검증했습니다. +- [속성 필드 검증](sw-property-fields-verification-2026-10-19.md): 필드 77/77, Header 회귀 257 checks 등은 패키지·기존 Story 구현이 동일하므로 관련 근거로 재사용합니다. +- [Firefox 게이지](sw-header-firefox-range-close-verification-2026-10-19.md): 기존 29/29의 게이지 디자인·엔진별 동작은 수정하지 않았습니다. 이번 메인의 게이지 상태 연결은 Chrome에서 새로 검증했습니다. +- 과거 baseline과 1단계 전용 검증 스크립트는 당시의 고정 화면·선언을 기준으로 한 기록입니다. Overview의 의도된 변경으로 무효화되는 화면/선언 동일성 검사를 현재 메인의 합격 기준으로 재사용하지 않았고, 기존 증거를 덮어쓰지 않았습니다. + +**NOT VERIFIED:** 다른 27개 Story의 모든 인터랙션에 대한 새 전체 회귀, Firefox의 메인 전체 Dropdown·속성Bar·게이지 연동, 새로운 전체 접근성 인증, CAD/파일/OS 실제 연동. 신규 업무 화면 생성이 아닌 기존 Storybook Reference 수정이므로 AI 화면 생성 Guard는 적용 대상이 아닙니다. + +증거: [Chrome](storybook-overview-qa/chrome-result.json), [중첩 Dropdown](storybook-overview-qa/chrome-overlays-result.json), [Firefox](storybook-overview-qa/firefox-result.json), [원본 화면 조사](storybook-overview-qa/screen-survey.json), [수정 전 ID](storybook-overview-qa/before-index.json), [수정 후 ID](storybook-overview-qa/after-index.json). + +변경 파일: + +- `src/sw/sw-header.stories.tsx` — Overview 연결만 교체. +- `src/sw/sw-header-overview.tsx` — Storybook 전용 호스트 상태와 Inner 크기 계산. +- `src/sw/sw-stories.css` — Overview에만 적용되는 레이아웃·스크롤·팝업 위치. +- `packages/sw/tests/overview.browser.mjs` — 메인·중첩 Overlay 검증. +- `packages/sw/tests/overview-firefox.browser.mjs` — 설치된 Firefox 검증. +- 이 보고서 및 `docs/sw/storybook-overview-qa/`의 새 목록·조사 데이터·화면·검증 기록. [전체 변경 파일 목록](storybook-overview-qa/changed-files.json), [통합 요약과 소스 해시](storybook-overview-qa/validation-summary.json). + +## 추가 정리 후보 — 이번에는 제안만 + +**KEEP 11 / SIMPLIFY 6 / MERGE REVIEW 3 / REMOVE REVIEW 1 / QA 7.** 사용자 승인 없이 적용한 항목은 없습니다. 삭제한 Default/Controls/Responsive/Text Stroke/Dynamic Data는 후보에서 제외했습니다. + +- 우선 통합 검토: Property Panel Variants, Additional Hover, Layer Detail · Input의 상세 버튼 부분. +- 삭제 검토: Colorize. Color Dropdown의 대응 시연 및 테스트 참조를 먼저 이전해야 합니다. +- 길이 축소 검토: Interactive States, Document/Layer/Color/Line Style Dropdown, Responsive More. +- 개별 속성창 4개는 상태별 고정 치수·직접 검증 URL을 가진 QA 표본입니다. Compare/Variants와 겹치는 부분이 있어도 즉시 삭제할 근거는 아닙니다. +- Dynamic Controls와 Composition은 각각 `controls`와 `hiddenControls/menuOrder`를 보여 줍니다. API 차이가 있어 유지 권장입니다. +- 별도의 Input Story는 없습니다. Layer Detail · Input 전체를 삭제하면 독립 Input 시연도 사라집니다. + +아래 V-01~V-27은 실제 manager 사이드바 표시 순서입니다. V-28 Detail Buttons는 `verification` 태그로 기본 숨김이며 직접 URL로 접근합니다(원본 index에는 첫 번째). [관측한 사이드바 순서](storybook-overview-qa/manager-story-order.json). + +Story 링크는 `npm.cmd run storybook` 실행 후 기본 포트 `http://localhost:6024` 기준입니다. 이번 자동 검증은 별도 임시 로컬 포트에서 수행했습니다. 스크린샷은 메인 외에는 수정 전 1440×1000 초기 화면이며, 긴 페이지 전체 내용은 원본 DOM 섹션 조사와 소스를 함께 확인했습니다. **28개 초기 렌더링은 PASS이며, 표의 기능 설명을 모든 인터랙션의 신규 PASS로 해석하면 안 됩니다.** + + +| 번호 | Story 이름 | Story ID | 현재 내용 | 정리 제안 | 영향도 | +|---|---|---|---|---|---| +| V-01 | [Overview](http://localhost:6024/?path=/story/sw-header--overview) | `sw-header--overview` | 통합 시연 / 사용자: 16:9 Stage에서 Header·전체 Dropdown·속성Bar·속성창·공유 속성을 조작. | **KEEP** — 현재 메인으로 유지. | 중간 | +| V-02 | [Interactive States](http://localhost:6024/?path=/story/sw-header--interactive-states) | `sw-header--interactive-states` | 상태 비교 / 사용자·QA: 12개 섹션: Host state, Hover/Selected/Disabled, 토글, 창 버튼 Callback, 긴 파일명. | **SIMPLIFY** — 반복 Header 표본과 설명을 상태별로 축소 검토. | 낮음 | +| V-03 | [Window Move Motion](http://localhost:6024/?path=/story/sw-header--window-move-motion) | `sw-header--window-move-motion` | 단계별 실컴포넌트 정지 표본 / QA: 기존 9단계의 창 이동 모션을 3배 확대. | **KEEP** — 이번에 확정한 단계별 섹션 그대로 유지. | 낮음 | +| V-04 | [Composed Controls](http://localhost:6024/?path=/story/sw-header--composed-controls) | `sw-header--composed-controls` | 하위 컴포넌트 조합 / 사용자: 레이어·색상·상세보기, 선·문자·치수 공개 하위 컴포넌트와 그룹 Hover. | **KEEP** — 독립 조합 API 사용 예제로 유지. | 중간 | +| V-05 | [Logo Slot](http://localhost:6024/?path=/story/sw-header--logo-slot) | `sw-header--logo-slot` | 설정 예제 / 사용자: 기본 임시 로고, 가로형 logoSrc, 세로형 React logo, 미전달 4개 표본. | **KEEP** — 로고 슬롯 계약 예제로 유지. | 낮음 | +| V-06 | [Document Dropdown](http://localhost:6024/?path=/story/sw-header--document-dropdown) | `sw-header--document-dropdown` | 실제 조작+정적 상태 / 사용자·QA: 18개 섹션: 문서 선택·닫기·New/Open·현재 문서 위치·Hover·18개/빈 목록·긴 이름·390px. | **SIMPLIFY** — 반복 현재 문서/Hover 표본을 한 비교 구역으로 줄이는 방안 검토. | 중간 | +| V-07 | [Layer Dropdown](http://localhost:6024/?path=/story/sw-header--layer-dropdown) | `sw-header--layer-dropdown` | 실제 조작+정적 상태 / 사용자·QA: 19개 섹션: 전구·눈꽃·잠금, 상태 혼합, 선택, 긴/빈/많은 레이어, 6개 좁은 폭. | **SIMPLIFY** — 중복 Header 표본을 줄이고 아이콘 상태표·예외 사례 유지 검토. | 중간 | +| V-08 | [Color Dropdown](http://localhost:6024/?path=/story/sw-header--color-dropdown) | `sw-header--color-dropdown` | 실제 조작+디자인 비교 / 사용자·QA: 9개 섹션: 팔레트·사용자 색상 40개·ByLayer·RGB 입력·Colorize·상세 Callback. | **SIMPLIFY** — 반복 Default/Hover Header와 설명을 축소; Colorize 통합 목적지로 검토. | 중간 | +| V-09 | [Line Style Dropdown](http://localhost:6024/?path=/story/sw-header--line-style-dropdown) | `sw-header--line-style-dropdown` | 실제 조작+디자인 비교 / 사용자·QA: 8개 섹션: 3열 선 종류·가중치·스케일, 현재 행/상세 Hover, 390px. | **SIMPLIFY** — 중복 Default/Hover를 줄이고 3열 입력·좁은 화면 사례 보존 검토. | 중간 | +| V-10 | [Text · Dimension Style Dropdown](http://localhost:6024/?path=/story/sw-header--text-dimension-style-dropdown) | `sw-header--text-dimension-style-dropdown` | 실제 조작+디자인 비교 / 사용자·QA: 문자·치수스타일 목록과 각 행·상세 Hover, 선택 Callback 등 6개 섹션. | **KEEP** — 서로 다른 두 필드의 목록 계약을 함께 확인하는 현 구성 유지. | 낮음 | +| V-11 | [Responsive More](http://localhost:6024/?path=/story/sw-header--responsive-more) | `sw-header--responsive-more` | 반응형 실제 조작+폭 표본 / 사용자·QA: 1440/768/390 조작 구역 3개 + 경계 폭 16개. More 대표 필드 전환과 Callback. | **SIMPLIFY** — 경계 폭 표본을 접는 방식 등 화면 길이 축소 검토. 기능은 유지 권장. | 중간 | +| V-12 | [Layer Detail · Input](http://localhost:6024/?path=/story/sw-header--layer-detail-input) | `sw-header--layer-detail-input` | 상세 버튼+독립 Input / 사용자·QA: 6개 섹션: Figma PNG, 레이어 상세 3상태, Input Default/Hover/ReadOnly/Disabled/Focus 및 입력·IME·확정/취소. | **MERGE REVIEW** — 상세 버튼 비교는 Detail Buttons로 옮기는 방안 검토. 독립 Input 시연은 남겨야 함. | 중간 | +| V-13 | [Property Panel](http://localhost:6024/?path=/story/sw-header--property-panel) | `sw-header--property-panel` | Header 연동과 데이터 변형 / 사용자·QA: 4가지 선택, Controlled/Uncontrolled, 외부 Open/값, 항목 추가·삭제·순서, 제한 상태·게이지. | **KEEP** — 고급 데이터/API 검증 화면으로 유지. | 중간 | +| V-14 | [Property Panel Variants](http://localhost:6024/?path=/story/sw-header--property-panel-variants) | `sw-header--property-panel-variants` | 독립 패널과 데이터 변형 / QA: 같은 PropertyPanelDemo를 standalone으로 렌더링. 4상태·데이터 버튼이 Property Panel과 거의 동일. | **MERGE REVIEW** — 단독 패널 기준이 필요하면 4개 개별/4개 비교 화면과 통합 검토. | 중간 | +| V-15 | [K Guide](http://localhost:6024/?path=/story/sw-header--k-guide) | `sw-header--k-guide` | 실시간 모션 / 사용자: K 버튼 Hover/Focus의 원본 이미지 Pan·Zoom, 이탈 정지, Reduced Motion 안내. | **KEEP** — 고유한 가이드 모션 예제로 유지. | 낮음 | +| V-16 | [Additional Hover](http://localhost:6024/?path=/story/sw-header--additional-hover) | `sw-header--additional-hover` | 상세/Selected 회귀·외부 모드 / QA: StyleDemo 1920과 RequiredColorDemo: 5개 상세 Hover, Selected, 외부 ByLayer/ByBlock/직접 색상. | **MERGE REVIEW** — 상세 상태는 Detail Buttons, 외부 색상 모드는 Color Dropdown으로 이전 검토. | 중간 | +| V-17 | [Property Bar](http://localhost:6024/?path=/story/sw-header--property-bar) | `sw-header--property-bar` | 속성Bar 전체 API / 사용자·QA: Controlled, 외부 Open/값, 추가·삭제·순서 반전·객체 교체·개별 Disabled/ReadOnly, 1222px 부모 폭. | **KEEP** — 메인의 참조 구현이자 고급 API 예제로 유지. | 중간 | +| V-18 | [Dynamic Controls](http://localhost:6024/?path=/story/sw-header--dynamic-controls) | `sw-header--dynamic-controls` | controls allowlist / 사용자: 12개 구성의 제거·재추가·라벨·순서·visible, 동적 문서 데이터. | **KEEP** — Composition과 다른 API임을 설명하는 방향으로 유지. | 중간 | +| V-19 | [Colorize](http://localhost:6024/?path=/story/sw-header--colorize) | `sw-header--colorize` | 색상 추출 버튼 접근 / QA: 별도 기본/확대 상태표 없이 StyleDemo(1920)를 다시 표시. 색상 Dropdown의 추출 버튼으로 연결. | **REMOVE REVIEW** — Color Dropdown에 버튼 접근·Hover·Callback 증거를 남긴 뒤 메뉴 삭제 검토 가능. | 중간 | +| V-20 | [Composition (Visibility · Order)](http://localhost:6024/?path=/story/sw-header--composition) | `sw-header--composition` | hiddenControls/menuOrder / 사용자·QA: 16개 표시 항목, 프리셋·순서·중복/알 수 없는 ID, 실제 화면/고정 폭, Callback 보존. | **KEEP** — 개별 제거와 순서 계약을 보여 주는 예제로 유지. | 중간 | +| V-21 | [Property Panel · 선택 없음](http://localhost:6024/?path=/story/sw-header--property-panel-none) | `sw-header--property-panel-none` | 단독 실제 컴포넌트 / 디자인 QA: 선택 없음 314×256 고정 상태와 실제 필드. | **QA** — 일반 사용자 목록보다는 QA 분류 검토. | 중간 | +| V-22 | [Property Panel · 전체 선택](http://localhost:6024/?path=/story/sw-header--property-panel-all) | `sw-header--property-panel-all` | 단독 실제 컴포넌트 / 디자인 QA: 전체 선택 314×361, 혼합 레이어 값과 선택 개수. | **QA** — 개별 QA 기준으로 유지하거나 Compare 통합 검토. | 중간 | +| V-23 | [Property Panel · 원 1개](http://localhost:6024/?path=/story/sw-header--property-panel-circle) | `sw-header--property-panel-circle` | 단독 실제 컴포넌트 / 디자인 QA: 원 1개 314×658, 기본 형상·치수·XYZ·전체 선택 복귀. | **QA** — 개별 QA 기준으로 유지하거나 Compare 통합 검토. | 중간 | +| V-24 | [Property Panel · 모두 펼침](http://localhost:6024/?path=/story/sw-header--property-panel-expanded) | `sw-header--property-panel-expanded` | 단독 실제 컴포넌트 / 디자인 QA: 전체 펼침 314×754, 추가 공통 속성·형상·위치·푸터. | **QA** — 개별 QA 기준으로 유지하거나 Compare 통합 검토. | 중간 | +| V-25 | [Property Panel · 4개 비교](http://localhost:6024/?path=/story/sw-header--property-panel-compare) | `sw-header--property-panel-compare` | 4개 실제 패널 병렬 비교 / 디자인 QA: 4개 선택 상태를 동시에 렌더링하고 실측 폭·높이를 표시. | **QA** — 나란히 비교하는 QA 목적을 유지. 개별 메뉴 통합 목적지로 검토 가능. | 중간 | +| V-26 | [Property Panel · 형상 Slot](http://localhost:6024/?path=/story/sw-header--property-shape-slot) | `sw-header--property-shape-slot` | 형상 확장 API / 사용자: 기본/null/ReactNode/Render Prop, 원·사각형 교체, 치수/그룹 추가. | **KEEP** — 외부 컴포넌트 확장 계약 예제로 유지. | 중간 | +| V-27 | [Property Panel · 필드 13개](http://localhost:6024/?path=/story/sw-header--property-fields) | `sw-header--property-fields` | 필드 상태·실제 조작 / 디자인 QA: Figma 13개 필드 Default/Hover 표본, 실제 패널, 혼합 레이어·외부 값·제한·단위. | **QA** — 77개 필드 검증의 기준 화면으로 유지 권장. | 중간 | +| V-28 | [Detail Buttons (Shared States)](http://localhost:6024/?path=/story/sw-header--detail-buttons) | `sw-header--detail-buttons` | 실제 Pointer/Callback 비교 / QA: 5개 상세 버튼 × Default/Hover/Disabled/Callback 없음, 클릭 횟수. verification 태그로 기본 숨김. | **QA** — 이미 적용된 숨김과 검증 표본 유지. | 중간 | + +## 화면별 삭제 영향과 대체 가능성 + +### V-01 · Overview + +대체 메인 없음. 이번에 실제 수정한 유일한 Story. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--overview) · [대표 스크린샷](storybook-overview-qa/overview-after.png) + +### V-02 · Interactive States + +삭제하면 Disabled+Hover·키보드·창 버튼 Callback 비교를 잃음. 메인은 상태 비교표를 대체하지 않음. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--interactive-states) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--interactive-states.png) + +### V-03 · Window Move Motion + +타이밍·위치 비교의 유일한 상세 화면. 메인의 실시간 Hover와 목적이 다름. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--window-move-motion) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--window-move-motion.png) + +### V-04 · Composed Controls + +전체 Header 통합 시연으로 하위 컴포넌트 단독 조합을 대체할 수 없음. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--composed-controls) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--composed-controls.png) + +### V-05 · Logo Slot + +삭제하면 이미지/ReactNode/미전달의 차이를 직접 확인할 수 없음. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--logo-slot) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--logo-slot.png) + +### V-06 · Document Dropdown + +메인은 기본 선택·목록 변경을 대체하지만 빈 목록·긴 이름·행 위치·18개 스크롤 사례는 대체하지 않음. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--document-dropdown) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--document-dropdown.png) + +### V-07 · Layer Dropdown + +메인은 정상 선택·Toggle만 대체. On/Off/Hover 아이콘 매트릭스·20개 목록·Callback 없는 상태가 고유함. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--layer-dropdown) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--layer-dropdown.png) + +### V-08 · Color Dropdown + +메인의 색상 변경은 40개 색상·정적 Hover 비교를 대체하지 않음. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--color-dropdown) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--color-dropdown.png) + +### V-09 · Line Style Dropdown + +메인은 정상 선택을 대체하지만 상세 상태·열 배치 기준은 남길 필요가 있음. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--line-style-dropdown) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--line-style-dropdown.png) + +### V-10 · Text · Dimension Style Dropdown + +메인의 선택만으로 각 행 미리보기와 Figma Hover 비교를 대체하지 못함. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--text-dimension-style-dropdown) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--text-dimension-style-dropdown.png) + +### V-11 · Responsive More + +삭제한 Responsive와 다른 기능. 메인은 현재 폭만 보여 주므로 모든 경계값 비교를 대체하지 않음. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--responsive-more) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--responsive-more.png) + +### V-12 · Layer Detail · Input + +독립 Input Story는 현재 없음. 페이지 전체를 지우면 텍스트/숫자·외부 Props·취소 예제를 잃음. detail-buttons 검증이 이 ID를 참조함. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--layer-detail-input) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--layer-detail-input.png) + +### V-13 · Property Panel + +메인에 없는 Controlled 전환, 개별 제한·옵션 삭제·선택 객체 교체가 남음. Firefox·닫기·필드 테스트가 참조. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--property-panel) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--property-panel.png) + +### V-14 · Property Panel Variants + +Header Overlay·Focus 복귀와 다른 단독 맥락. standalone의 닫기는 기록만 하고 패널을 유지하며 너비/Open 버튼은 Header 연동 검증을 대신하지 못함. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--property-panel-variants) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--property-panel-variants.png) + +### V-15 · K Guide + +Header 실시간 모션과 창 이동 1400ms 모션은 별개. 메인에서는 일부만 볼 수 있음. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--k-guide) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--k-guide.png) + +### V-16 · Additional Hover + +외부 colorMode 제어는 메인의 일반 색상 선택과 다름. followup-four가 이 ID를 참조하므로 먼저 대체 시나리오가 필요함. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--additional-hover) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--additional-hover.png) + +### V-17 · Property Bar + +메인은 공유 값·기본 추가/제거·제한만 제공. 개별 제한·순서·객체 교체·Controlled를 대체하지 않음. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--property-bar) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--property-bar.png) + +### V-18 · Dynamic Controls + +controls는 전체 allowlist이며 로고 외 16개 요소를 숨기는 hiddenControls와 다름. 이름이 비슷해도 동일 기능이 아님. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--dynamic-controls) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--dynamic-controls.png) + +### V-19 · Colorize + +실제 색상 추출 CAD 기능은 호스트 소유. 삭제 시 전용 접근 URL을 잃고 detail-buttons preservation의 colorize 참조를 이전해야 함. 지금은 삭제하지 않음. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--colorize) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--colorize.png) + +### V-20 · Composition (Visibility · Order) + +Dynamic Controls와 다른 API. 홈·창 이동·최소화·종료까지 개별 제어하고 메뉴 순서 정규화를 검증함. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--composition) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--composition.png) + +### V-21 · Property Panel · 선택 없음 + +Variants/Compare와 겹치지만 테스트의 상태별 직접 URL·치수 기준임. 삭제/통합 시 ID 참조 이전 필요. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--property-panel-none) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--property-panel-none.png) + +### V-22 · Property Panel · 전체 선택 + +선택 없음/원 상태와 내용이 다름. 테스트 직접 URL·혼합 값·개수 레이아웃을 보존해야 함. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--property-panel-all) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--property-panel-all.png) + +### V-23 · Property Panel · 원 1개 + +원형 Slot과 위치·푸터를 포함. 다른 상태와 같은 이름의 단순 중복이 아님. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--property-panel-circle) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--property-panel-circle.png) + +### V-24 · Property Panel · 모두 펼침 + +754px 전체 높이와 하단 잘림 검증에 필요. 개별 ID가 기존 테스트에서 동적으로 참조됨. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--property-panel-expanded) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--property-panel-expanded.png) + +### V-25 · Property Panel · 4개 비교 + +Variants는 상태 전환, Compare는 동시 비교라는 차이가 있음. property-fields의 4상태 치수 검증이 참조함. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--property-panel-compare) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--property-panel-compare.png) + +### V-26 · Property Panel · 형상 Slot + +메인은 기본/null만 제공. ReactNode와 Render Prop·형상 교체를 대체할 수 없음. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--property-shape-slot) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--property-shape-slot.png) + +### V-27 · Property Panel · 필드 13개 + +메인은 필드별 디자인 상태표를 대체하지 않음. property-fields.browser.mjs의 핵심 직접 ID. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--property-fields) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--property-fields.png) + +### V-28 · Detail Buttons (Shared States) + +메인은 실제 Dropdown 접근용이며 이 비교 매트릭스를 대체하지 못함. detail-buttons 검증의 직접 ID. + +[현재 화면](http://localhost:6024/?path=/story/sw-header--detail-buttons) · [대표 스크린샷](storybook-overview-qa/screens/sw-header--detail-buttons.png) diff --git a/packages/sw/tests/overview-firefox.browser.mjs b/packages/sw/tests/overview-firefox.browser.mjs new file mode 100644 index 0000000..bdf21f1 --- /dev/null +++ b/packages/sw/tests/overview-firefox.browser.mjs @@ -0,0 +1,68 @@ +// Installed Firefox via WebDriver BiDi, matching the existing SW cross-browser workflow. +import { readFile, writeFile, mkdir } from 'node:fs/promises' +import { spawn } from 'node:child_process' +import path from 'node:path' +import http from 'node:http' + +const out = path.resolve(process.argv[2] ?? 'docs/sw/storybook-overview-qa') +await mkdir(out,{recursive:true}) +const report = { checks:[], errors:[], infrastructureWarnings:[] } +const check = (name,ok,data) => {report.checks.push({name,status:ok?'PASS':'FAIL',data});console.log(ok?'PASS':'FAIL',name)} +const sleep = ms => new Promise(resolve=>setTimeout(resolve,ms)) +const root=path.resolve('storybook-static'),mime={'.html':'text/html','.js':'text/javascript','.css':'text/css','.json':'application/json','.svg':'image/svg+xml','.ttf':'font/ttf','.png':'image/png'} +const server=http.createServer(async(req,res)=>{try{const p=new URL(req.url,'http://localhost').pathname,file=path.resolve(root,'.'+decodeURIComponent(p==='/'?'/index.html':p));if(path.relative(root,file).startsWith('..'))return res.writeHead(403).end();res.setHeader('Content-Type',mime[path.extname(file)]??'application/octet-stream');res.end(await readFile(file))}catch{res.writeHead(404).end()}}) +await new Promise(resolve=>server.listen(0,'127.0.0.1',resolve)) +const url=`http://127.0.0.1:${server.address().port}/iframe.html?id=sw-header--overview&viewMode=story` +let processFirefox,ws +try { + for(const [width,height]of[[1400,1000],[500,800]]){ + const profile=path.resolve('_local',`overview-firefox-${process.pid}-${width}`) + await mkdir(profile,{recursive:true}) + const port=9500+process.pid%400 + processFirefox=spawn(process.env.SW_FIREFOX_PATH??'C:/Program Files/Mozilla Firefox/firefox.exe',['--headless','--no-remote','--profile',profile,`--remote-debugging-port=${port}`],{stdio:'ignore',env:{...process.env,MOZ_HEADLESS_WIDTH:String(width),MOZ_HEADLESS_HEIGHT:String(height)}}) + ws=undefined + for(let i=0;i<40&&!ws;i++){await sleep(250);try{ws=await new Promise((resolve,reject)=>{const s=new WebSocket(`ws://127.0.0.1:${port}/session`);s.onopen=()=>resolve(s);s.onerror=reject})}catch{ws=undefined}} + if(!ws)throw Error('Firefox BiDi unavailable') + let id=0;const pending=new Map() + ws.onmessage=event=>{const m=JSON.parse(event.data);if(m.id&&pending.has(m.id)){const {resolve,reject}=pending.get(m.id);pending.delete(m.id);m.type==='error'?reject(Error(m.message)):resolve(m.result)}else if(m.method==='log.entryAdded'&&m.params.level==='error'){ + const text=m.params.text + if(text.startsWith('downloadable font: download failed')&&text.includes('/sb-common-assets/nunito-sans-regular.woff2'))report.infrastructureWarnings.push(text) + else report.errors.push(text) + }} + const send=(method,params={})=>new Promise((resolve,reject)=>{const next=++id;pending.set(next,{resolve,reject});ws.send(JSON.stringify({id:next,method,params}))}) + const session=await send('session.new',{capabilities:{}});report.version=session.capabilities.browserVersion + await send('session.subscribe',{events:['log.entryAdded']}) + const context=(await send('browsingContext.getTree')).contexts[0].context + const evaluate=async expression=>{const r=await send('script.evaluate',{expression,target:{context},awaitPromise:true});if(r.type==='exception')throw Error(r.exceptionDetails.text);return r.result.value} + const data=async expression=>JSON.parse(await evaluate(`JSON.stringify(${expression})`)) + const settle=()=>evaluate('new Promise(resolve=>requestAnimationFrame(()=>requestAnimationFrame(()=>resolve(true))))') + const key=async value=>send('input.performActions',{context,actions:[{type:'key',id:'keyboard',actions:[{type:'keyDown',value},{type:'keyUp',value}]}]}) + await send('browsingContext.navigate',{context,url,wait:'complete'}) + let ready=false + for(let i=0;i<40&&!ready;i++){ready=await evaluate('!!document.querySelector("[data-preview-stage]")');if(!ready)await sleep(100)} + if(!ready)throw Error('Overview did not render') + await settle() + const fit=await data('(()=>{const s=document.querySelector("[data-preview-stage]").getBoundingClientRect(),b=document.querySelector("[data-preview-slot]").getBoundingClientRect();return {width:s.width,height:s.height,slotWidth:b.width,slotHeight:b.height,headerHeight:document.querySelector("header.hm-sw-header").getBoundingClientRect().height,viewportWidth:innerWidth,viewportHeight:innerHeight}})()') + check(`Firefox ${width}: 16:9 in Inner and Header 49`,Math.abs(fit.width/fit.height-16/9)<.005&&fit.width<=fit.slotWidth+.1&&fit.height<=fit.slotHeight+.1&&fit.headerHeight===49,fit) + await evaluate('(()=>{const s=document.querySelector("select");s.value="expanded";s.dispatchEvent(new Event("change",{bubbles:true}));return true})()');await settle() + await evaluate('(()=>{const b=document.querySelector("[data-property-panel-trigger]");if(b.getClientRects().length)b.click();else{document.querySelector(".hm-sw-header__more-trigger").click()}return true})()');await settle() + await evaluate('(()=>{const m=[...document.querySelectorAll("[role=menuitemcheckbox]")].find(e=>e.textContent.trim()==="속성창");if(m)m.click();return true})()');await settle() + const popup=await data('(()=>{const e=document.querySelector(".hm-sw-property"),r=e.getBoundingClientRect();return {width:r.width,height:r.height,focus:document.activeElement===e}})()') + check(`Firefox ${width}: full original popup 314x754`,popup.width===314&&popup.height===754,popup) + const bottom=await data('(()=>{const z=document.querySelector(".hm-sw-property [data-property-id=z] input"),s=document.querySelector("[data-preview-stage]");z.scrollIntoView({block:"nearest",inline:"nearest"});z.focus();const r=z.getBoundingClientRect();return {top:s.scrollTop,visible:document.elementFromPoint(r.x+r.width/2,r.y+r.height/2)===z}})()') + check(`Firefox ${width}: popup bottom reachable and focusable`,bottom.top>0&&bottom.visible,bottom) + await key('\uE00C');await settle() + check(`Firefox ${width}: Escape closes popup and restores focus`,await evaluate('!document.querySelector(".hm-sw-property")&&document.activeElement.matches("[data-property-panel-trigger],.hm-sw-header__more-trigger")')) + await writeFile(path.join(out,`overview-firefox-${width}.png`),Buffer.from((await send('browsingContext.captureScreenshot',{context})).data,'base64')) + await send('session.end');ws.close();ws=undefined;processFirefox.kill();processFirefox=undefined + await sleep(250) + } + check('Firefox SW runtime errors absent; known Storybook font warnings recorded separately',report.errors.length===0,{errors:report.errors,warnings:report.infrastructureWarnings}) +}catch(error){check('Firefox suite completes',false,error.stack)} +finally{ + ws?.close();processFirefox?.kill();await new Promise(resolve=>server.close(resolve)) + report.status=report.checks.every(c=>c.status==='PASS')?'PASS':'FAIL' + await writeFile(path.join(out,'firefox-result.json'),JSON.stringify(report,null,2)+'\n') + console.log(JSON.stringify({status:report.status,checks:report.checks.length,version:report.version})) + process.exitCode=report.status==='PASS'?0:1 +} diff --git a/packages/sw/tests/overview.browser.mjs b/packages/sw/tests/overview.browser.mjs new file mode 100644 index 0000000..3314424 --- /dev/null +++ b/packages/sw/tests/overview.browser.mjs @@ -0,0 +1,217 @@ +// Focused Overview integration checks. Build Storybook first; historical evidence stays untouched. +// Usage: node packages/sw/tests/overview.browser.mjs [evidence-dir] +import { createRequire } from 'node:module' +import { readFile, writeFile, mkdir } from 'node:fs/promises' +import { execFileSync } from 'node:child_process' +import path from 'node:path' +import http from 'node:http' +import { parse } from '@babel/parser' + +const out = path.resolve(process.argv[2] ?? 'docs/sw/storybook-overview-qa') +await mkdir(out, { recursive: true }) +const report = { baseCommit: '50bf5bda8e956a4973b923d64131f2f2285bd38c', checks: [], errors: [], sizes: [] } +const check = (name, ok, data) => { report.checks.push({ name, status: ok ? 'PASS' : 'FAIL', data }); console.log(ok ? 'PASS' : 'FAIL', name) } +const before = JSON.parse(await readFile(path.join(out, 'before-index.json'), 'utf8')) +const after = Object.values(JSON.parse(await readFile('storybook-static/index.json', 'utf8')).entries).filter(e => e.type === 'story' && e.title === 'SW/Header') +await writeFile(path.join(out, 'after-index.json'), JSON.stringify(after, null, 2) + '\n') +check('all 28 Story IDs, names, order and tags retained', after.length === 28 && JSON.stringify(before.map(e => [e.id,e.name,e.tags])) === JSON.stringify(after.map(e => [e.id,e.name,e.tags]))) +const source = await readFile('src/sw/sw-header.stories.tsx', 'utf8') +const baseline = execFileSync('git', ['show', `${report.baseCommit}:src/sw/sw-header.stories.tsx`], { encoding: 'utf8' }) +const stories = text => Object.fromEntries(parse(text, { sourceType:'module', plugins:['typescript','jsx'] }).program.body + .filter(n => n.type === 'ExportNamedDeclaration').map(n => [n.declaration.declarations[0].id.name, text.slice(n.start,n.end).replaceAll('\r\n','\n')])) +const oldStories = stories(baseline), newStories = stories(source) +check('other 27 Story declarations byte-identical', Object.keys(oldStories).filter(k => k !== 'Overview').every(k => oldStories[k] === newStories[k])) +check('package production source untouched', !execFileSync('git', ['diff', report.baseCommit, '--', 'packages/sw/src'], { encoding:'utf8' })) + +const root = path.resolve('storybook-static'), mime = { '.html':'text/html','.js':'text/javascript','.css':'text/css','.json':'application/json','.svg':'image/svg+xml','.ttf':'font/ttf','.png':'image/png' } +const server = http.createServer(async(req,res) => { + try { const p = new URL(req.url,'http://localhost').pathname, file = path.resolve(root,'.'+decodeURIComponent(p === '/' ? '/index.html' : p)) + if (path.relative(root,file).startsWith('..')) return res.writeHead(403).end() + res.setHeader('Content-Type',mime[path.extname(file)] ?? 'application/octet-stream'); res.end(await readFile(file)) + } catch { res.writeHead(404).end() } +}) +await new Promise(resolve => server.listen(0,'127.0.0.1',resolve)) +const base = `http://127.0.0.1:${server.address().port}` +const { chromium } = createRequire(import.meta.url)(process.env.SW_PLAYWRIGHT_PATH ?? 'C:/Users/user/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright') +let browser, page +try { + browser = await chromium.launch({ headless:true, executablePath:process.env.SW_CHROME_PATH ?? 'C:/Program Files/Google/Chrome/Application/chrome.exe' }) + report.browser = browser.version() + page = await browser.newPage({ viewport:{width:1440,height:1000} }); page.setDefaultTimeout(6000) + page.on('pageerror', e => report.errors.push(e.message)); page.on('console', m => { if(m.type() === 'error') report.errors.push(m.text()) }) + const go = async(id='overview') => { + await page.goto(`${base}/iframe.html?id=sw-header--${id}&viewMode=story`) + await page.locator('.hm-sw-header,.hm-sw-theme').first().waitFor(); await page.evaluate(() => document.fonts.ready) + await page.evaluate(()=>new Promise(resolve=>requestAnimationFrame(()=>requestAnimationFrame(resolve)))) + } + const geometry = () => page.evaluate(() => { + const box = e => { const r=e.getBoundingClientRect(); return {x:r.x,y:r.y,w:r.width,h:r.height,right:r.right,bottom:r.bottom} } + const stage=document.querySelector('[data-preview-stage]'),slot=document.querySelector('[data-preview-slot]') + return {stage:box(stage),slot:box(slot),header:box(document.querySelector('header.hm-sw-header')),viewport:{w:innerWidth,h:innerHeight},overflow:document.documentElement.scrollWidth-document.documentElement.clientWidth} + }) + if(process.argv[3]==='overlays'){ + await go() + const stage=page.locator('[data-preview-stage]'),header=page.locator('header.hm-sw-header') + const covered=locator=>locator.evaluate(e=>{const r=e.getBoundingClientRect();return e.contains(document.elementFromPoint(r.x+r.width/2,r.y+r.height/2))}) + await header.locator('.hm-sw-header__document-button').click() + const firstDocument=header.locator('.hm-sw-header__document-item').first() + check('document first row is above the property Bar and clickable',await covered(firstDocument));await firstDocument.click() + for(const [id,label,detail]of[['layer','레이어','레이어 상세'],['color','색상','색상 상세'],['line-style','선스타일','선스타일 상세'],['text-style','문자스타일','문자스타일 상세'],['dimension-style','치수스타일','치수스타일 상세']]){ + await stage.evaluate(e=>e.scrollTop=0) + const button=header.getByRole('button',{name:label,exact:true}) + if(await button.isVisible())await button.click();else{await header.getByRole('button',{name:'더보기',exact:true}).click();await header.locator(`[role=menuitem][data-menu="${id}"]`).click()} + await header.getByRole('button',{name:detail,exact:true}).click() + check(`existing ${detail} reports Callback`,(await page.locator('[data-preview-callback]').textContent()).includes(`on${{'layer':'Layer','color':'Color','line-style':'LineStyle','text-style':'TextStyle','dimension-style':'DimensionStyle'}[id]}Detail`)) + } + await header.getByRole('button',{name:'색상',exact:true}).click() + await header.getByRole('button',{name:'ByBlock',exact:true}).click() + check('ByBlock mode immediately appears in Header without changing numeric RGB property',(await header.locator('.hm-sw-header__field--color').textContent()).includes('ByBlock')) + await page.keyboard.press('Escape') + await header.getByRole('button',{name:'색상',exact:true}).click() + await header.locator('.hm-sw-header__color-option').first().click() + check('direct color selection clears Header mode label',!(await header.locator('.hm-sw-header__field--color').textContent()).includes('ByBlock')) + await page.setViewportSize({width:390,height:700});await go();await page.getByLabel('선택 상태',{exact:true}).selectOption('expanded') + await header.getByRole('button',{name:'더보기',exact:true}).click();await header.getByRole('menuitemcheckbox',{name:'속성창',exact:true}).click() + for(const id of ['layer','line','color']){ + const field=page.locator(`.hm-sw-property [data-property-id="${id}"]`),trigger=field.locator(id==='color'?'input':'button') + await trigger.scrollIntoViewIfNeeded();await trigger.click() + const drop=page.locator('.hm-sw-property__drop');await drop.waitFor() + const r=await drop.boundingBox() + check(`small Inner ${id} dropdown stays in browser width`,r.x>=0&&r.x+r.width<=390.5,r) + if(id==='layer'){const last=drop.getByRole('button',{name:'Sample-Text',exact:true});check('small Inner lower layer row hit-test is unobstructed',await covered(last));await last.click()} + else await page.keyboard.press('Escape') + check(`small Inner ${id} selection or Escape closes only nested dropdown`,await drop.count()===0&&await page.locator('.hm-sw-property').count()===1) + } + await page.screenshot({path:path.join(out,'overview-narrow-overlay.png')}) + check('no overlay browser errors',report.errors.length===0,report.errors) + }else{ + for(const [width,height] of [[1920,1080],[1440,900],[1280,720],[768,600],[390,844],[1000,500]]) { + await page.setViewportSize({width,height}); await go() + const g=await geometry(); report.sizes.push(g) + check(`16:9 fitted to both Inner dimensions at ${width}x${height}`,g.stage.w>0&&Math.abs(g.stage.w/g.stage.h-16/9)<.005&&g.stage.w<=g.slot.w+.1&&g.stage.h<=g.slot.h+.1&&g.header.h===49&&g.overflow===0,g) + } + await page.setViewportSize({width:1440,height:1000}); await go() + const header=page.locator('header.hm-sw-header'),stage=page.locator('[data-preview-stage]') + const callback=()=>page.locator('[data-preview-callback]').textContent() + const open=async(id,label) => { + await stage.evaluate(e=>{e.scrollTop=0;e.scrollLeft=0}) + const button=header.getByRole('button',{name:label,exact:true}) + if(await button.isVisible()) {if(await button.getAttribute('aria-expanded')!=='true')await button.click()} + else {await header.getByRole('button',{name:'더보기',exact:true}).click();await header.locator(`[role="menuitem"][data-menu="${id}"]`).click()} + } + const panelButton=async()=>{ + const b=header.locator('[data-property-panel-trigger]') + if(await b.isVisible())await b.click() + else{await header.getByRole('button',{name:'더보기',exact:true}).click();await header.getByRole('menuitemcheckbox',{name:'속성창',exact:true}).click()} + } + const barInput=id=>page.locator(`.hm-sw-property-bar [data-property-id="${id}"] input`) + const panelInput=id=>page.locator(`.hm-sw-property [data-property-id="${id}"] input`).first() + const waitValue=async(locator,value)=>page.waitForFunction(([element,value])=>element.value===value,[await locator.elementHandle(),value]) + check('one Header and no duplicate fixed Figma specimen',await header.count()===1&&await page.getByText('Figma 기준 1920 × 49',{exact:true}).count()===0) + await header.locator('.hm-sw-header__document-button').click() + const document=header.locator('.hm-sw-header__document-list .hm-sw-header__document-item').nth(1) + const documentName=await document.textContent();await document.click() + check('document selection updates Header and Callback',!!documentName&&(await header.locator('.hm-sw-header__document-button').textContent()).includes(documentName.trim())&&(await callback()).includes('onDocumentSelect'),await callback()) + await open('layer','레이어');await header.getByRole('button',{name:'CC-D GNL',exact:true}).click() + check('layer selection updates shared data', (await callback()).includes('onLayerSelect(layer, CC-D GNL)'),await callback()) + await open('layer','레이어');await header.getByRole('button',{name:'레이어 상세',exact:true}).click() + check('existing layer Detail callback closes list',await header.locator('.hm-sw-header__layer-panel').count()===0&&(await callback()).includes('onLayerDetail')) + await open('color','색상') + const chip=header.locator('.hm-sw-header__color-menu .hm-sw-header__color-option').first() + await chip.click();check('color selection invokes host callback',(await callback()).includes('onColorSelect'),await callback()) + await open('line-style','선스타일');await header.getByRole('button',{name:'CENTER',exact:true}).click() + check('line selection updates Header', (await callback()).includes('onLineTypeSelect(line, CENTER)'),await callback()) + await open('line-style','선스타일');await header.locator('ul[aria-label="가중치"]').getByRole('button',{name:'ByLayer',exact:true}).click() + check('ByLayer weight mode does not turn numeric property into a mode string',(await header.locator('.hm-sw-header__field--line-style').textContent()).includes('ByLayer')) + await page.keyboard.press('Escape') + await open('text-style','문자스타일');await header.locator('.hm-sw-header__list-menu--text-style').getByRole('button',{name:/Dotum/}).click() + check('text style selection updates Header',(await callback()).includes('onTextStyleSelect(dotum)'),await callback()) + await open('dimension-style','치수스타일');await header.locator('.hm-sw-header__list-menu--dimension-style').getByRole('button',{name:/ISO - 25/}).click() + check('dimension style selection updates Header',(await callback()).includes('onDimensionStyleSelect(iso-25)'),await callback()) + await open('color','색상');await open('layer','레이어') + check('opening another dropdown closes the previous one',await header.locator('.hm-sw-header__color-menu').count()===0&&await header.locator('.hm-sw-header__layer-panel').count()===1) + await page.keyboard.press('Escape');check('Escape closes Header dropdown',await header.locator('.hm-sw-header__layer-panel').count()===0) + await open('layer','레이어');await page.locator('.sb-page-title').click();check('outside click closes Header dropdown',await header.locator('.hm-sw-header__layer-panel').count()===0) + + await barInput('radius').fill('6.25');await barInput('radius').press('Enter') + check('Bar Enter commits state',await barInput('radius').inputValue()==='6.25'&&(await callback()).includes('onPropertyChange(radius, 6.25)')) + await barInput('radius').fill('-1');await barInput('radius').press('Enter');check('Bar validates min=0',await barInput('radius').inputValue()==='6.25') + await barInput('radius').fill('9');await barInput('radius').press('Escape');check('Bar Escape cancels edit',await barInput('radius').inputValue()==='6.25') + await panelButton();await page.locator('.hm-sw-property').waitFor() + check('Header opens panel with same Bar value',await panelInput('radius').inputValue()==='6.25') + check('numeric weight property remains numeric after ByLayer mode',await panelInput('weight').inputValue()==='0.25') + check('Header layer value shared with panel',(await page.locator('.hm-sw-property [data-property-id="layer"]').textContent()).includes('CC-D GNL')) + await panelInput('radius').fill('7.5');await panelInput('radius').press('Enter') + await waitValue(barInput('radius'),'7.5') + check('panel edit updates the Bar',await barInput('radius').inputValue()==='7.5') + await panelInput('radius').fill('-2');await panelInput('radius').press('Enter');check('panel number validation rejects negative radius',await panelInput('radius').inputValue()==='7.5') + await page.locator('.hm-sw-property [data-property-id="layer"] button').click() + const drop=page.locator('.hm-sw-property__drop') + await drop.getByRole('button',{name:'Sample-Wall',exact:true}).click() + check('panel Layer dropdown updates Header shared value',(await header.locator('.hm-sw-header__field--layer').textContent()).includes('Sample-Wall')) + await page.locator('.hm-sw-property [data-property-id="line"] button').click();await drop.getByRole('button',{name:'HIDDEN',exact:true}).click() + check('panel line dropdown updates Header shared value',(await header.locator('.hm-sw-header__field--line-style').textContent()).includes('HIDDEN')) + await panelInput('color').click() + const colorOption=drop.locator('.hm-sw-header__color-option').nth(1) + const expectedColor=await colorOption.evaluate(e=>getComputedStyle(e.querySelector('.hm-sw-header__color-chip > span')).backgroundColor.match(/\d+/g).slice(0,3).join(',')) + await colorOption.click();await waitValue(panelInput('color'),expectedColor) + const selectedColor=await panelInput('color').inputValue() + check('panel color dropdown updates Header shared value',(await header.locator('.hm-sw-header__field--color').textContent()).includes(selectedColor)) + await panelInput('color').fill('300,0,0');await panelInput('color').press('Enter');check('panel RGB validation rejects out-of-range value',await panelInput('color').inputValue()===selectedColor) + await page.keyboard.press('Escape') + const gauge=page.locator('.hm-sw-property input[type="range"]') + await gauge.press('End');await gauge.press('Enter');await waitValue(panelInput('opacity'),'1') + check('gauge keyboard editing commits host state',await panelInput('opacity').inputValue()==='1') + await panelInput('radius').fill('8.5');await panelInput('radius').press('Escape') + check('first Escape cancels draft and retains panel',await panelInput('radius').inputValue()==='7.5'&&await page.locator('.hm-sw-property').count()===1) + await panelInput('radius').press('Escape');check('next Escape closes panel and restores Header focus',await page.locator('.hm-sw-property').count()===0&&await header.locator('[data-property-panel-trigger]').evaluate(e=>document.activeElement===e)) + await panelButton();await page.getByRole('button',{name:'속성창 닫기',exact:true}).click();check('panel Close button restores focus',await header.locator('[data-property-panel-trigger]').evaluate(e=>document.activeElement===e)) + await page.getByText('시연 데이터',{exact:true}).click() + await page.getByRole('button',{name:'외부 값 12.5',exact:true}).click();await waitValue(barInput('radius'),'12.5');check('external Props update Bar',await barInput('radius').inputValue()==='12.5') + await page.getByRole('checkbox',{name:'속성 ReadOnly',exact:true}).check();check('Bar ReadOnly',await barInput('radius').evaluate(e=>e.readOnly)) + await page.getByRole('checkbox',{name:'속성 ReadOnly',exact:true}).uncheck() + await page.getByRole('checkbox',{name:'속성 Disabled',exact:true}).check();check('Bar Disabled',await barInput('radius').isDisabled()) + await page.getByRole('checkbox',{name:'속성 Disabled',exact:true}).uncheck() + await page.getByRole('button',{name:'필드 추가',exact:true}).click();check('dynamic Bar field added',await page.locator('.hm-sw-property-bar [data-property-id^="preview-extra-"]').count()===1) + await panelButton();check('dynamic field shared with panel',await page.locator('.hm-sw-property [data-property-id^="preview-extra-"]').count()===1) + await page.getByRole('button',{name:'추가 필드 제거',exact:true}).click();check('dynamic field removed from both',await page.locator('[data-property-id^="preview-extra-"]').count()===0) + await page.getByRole('checkbox',{name:'형상 Slot 비우기',exact:true}).check();check('shape Slot can be empty without changing panel structure',await page.locator('.hm-sw-property [data-shape-slot="empty"]').count()===1) + await page.getByRole('checkbox',{name:'형상 Slot 비우기',exact:true}).uncheck() + await page.getByText('시연 데이터',{exact:true}).click() + for(const [selection,height]of[['none',256],['all',361],['circle',658],['expanded',754]]){ + await page.getByLabel('선택 상태',{exact:true}).selectOption(selection) + if(await page.locator('.hm-sw-property').count()===0)await panelButton() + const box=await page.locator('.hm-sw-property').boundingBox() + check(`original panel size ${selection}:314x${height}`,box.width===314&&box.height===height,box) + } + await page.screenshot({path:path.join(out,'overview-after-expanded.png')}) + await stage.evaluate(e=>{e.scrollTop=e.scrollHeight}) + await panelInput('z').scrollIntoViewIfNeeded();await panelInput('z').fill('5');await panelInput('z').press('Enter') + check('expanded popup bottom accessible through internal scroll',await panelInput('z').inputValue()==='5') + await page.screenshot({path:path.join(out,'overview-after-scrolled.png')}) + await go();await page.screenshot({path:path.join(out,'overview-after.png')}) + // A small Inner keeps native component dimensions; the Stage, rather than the browser document, scrolls. + await page.setViewportSize({width:390,height:700});await go();await page.getByLabel('선택 상태',{exact:true}).selectOption('expanded');await panelButton() + await panelInput('z').scrollIntoViewIfNeeded();await panelInput('z').fill('3');await panelInput('z').press('Enter') + const narrow=await stage.evaluate(e=>({top:e.scrollTop,left:e.scrollLeft,height:e.clientHeight,scrollHeight:e.scrollHeight,width:e.clientWidth,scrollWidth:e.scrollWidth})) + check('small Inner reaches full popup bottom with native Header and popup dimensions',await panelInput('z').inputValue()==='3'&&narrow.scrollHeight>narrow.height&&narrow.scrollWidth>=390,narrow) + await page.screenshot({path:path.join(out,'overview-narrow.png')}) + await panelInput('z').press('Escape') + check('narrow popup Escape restores More focus',await header.getByRole('button',{name:'더보기',exact:true}).evaluate(e=>document.activeElement===e)) + await page.setViewportSize({width:1440,height:1000});await page.goto(`${base}/?path=/story/sw-header--overview`) + const preview=page.frameLocator('#storybook-preview-iframe');await preview.locator('[data-preview-stage]').waitFor() + report.managerOrder=await page.locator('[data-item-id^="sw-header--"]').evaluateAll(elements=>[...new Set(elements.map(e=>e.dataset.itemId))]) + await writeFile(path.join(out,'manager-story-order.json'),JSON.stringify(report.managerOrder,null,2)+'\n') + await page.screenshot({path:path.join(out,'overview-manager.png')}) + const managerFit=await preview.locator('[data-preview-stage]').evaluate(e=>{const b=e.getBoundingClientRect(),slot=e.parentElement.getBoundingClientRect();return {width:b.width,height:b.height,slotWidth:slot.width,slotHeight:slot.height,viewportWidth:innerWidth,viewportHeight:innerHeight}}) + check('actual Storybook manager iframe fits its own Inner',managerFit.width<=managerFit.slotWidth+.1&&managerFit.height<=managerFit.slotHeight+.1&&Math.abs(managerFit.width/managerFit.height-16/9)<.005,managerFit) + check('no browser errors',report.errors.length===0,report.errors) + } +}catch(error){check('suite completes',false,error.stack);await page?.screenshot({path:path.join(out,'failure.png')}).catch(()=>{})} +finally{ + await browser?.close();await new Promise(resolve=>server.close(resolve)) + report.status=report.checks.every(c=>c.status==='PASS')?'PASS':'FAIL' + await writeFile(path.join(out,process.argv[3]==='overlays'?'chrome-overlays-result.json':'chrome-result.json'),JSON.stringify(report,null,2)+'\n') + console.log(JSON.stringify({status:report.status,checks:report.checks.length,failures:report.checks.filter(c=>c.status==='FAIL')})) + process.exitCode=report.status==='PASS'?0:1 +} diff --git a/src/sw/sw-header-overview.tsx b/src/sw/sw-header-overview.tsx new file mode 100644 index 0000000..ad18451 --- /dev/null +++ b/src/sw/sw-header-overview.tsx @@ -0,0 +1,199 @@ +import { useId, useLayoutEffect, useRef, useState, type CSSProperties } from "react" +import { + SWHeader, parseSWHeaderColor, type SWHeaderProps, type SWHeaderProperty, type SWHeaderPropertyGroup, + type SWHeaderPropertySelection, type SWHeaderPropertyMenus, type SWHeaderColorMode, type SWHeaderLayer, type SWHeaderLineWeight, +} from "@hm-design/sw" +import { StoryPage, StoryPageHeader } from "@/components/story-page" + +type Selection = "none" | "all" | "circle" | "expanded" +interface OverviewProps { + initial: SWHeaderProps + fixtures: Required> + propertyGroups: SWHeaderPropertyGroup[] + propertyFixture: (selection: Selection) => SWHeaderProperty[] + propertySelection: (selection: Selection) => SWHeaderPropertySelection + barFixture: SWHeaderProperty[] +} + +/** Storybook host only; dropdowns, validation, editing and focus use the public SW components. */ +export function SWHeaderOverview({ initial, fixtures, propertyGroups, propertyFixture, propertySelection, barFixture }: OverviewProps) { + const controlId = useId() + const slotRef = useRef(null) + const headerRef = useRef(null) + const [size, setSize] = useState({ width: 0, height: 0 }) + const [panelLeft, setPanelLeft] = useState(4) + const [example, setExample] = useState("circle") + const getProperties = (selection: Selection) => propertyFixture(selection).map(property => ({ + ...property, value: barFixture.find(item => item.id === property.id)?.value ?? property.value, + })) + const [properties, setProperties] = useState(() => getProperties("circle")) + const [documents, setDocuments] = useState(fixtures.documents) + const [documentId, setDocumentId] = useState(fixtures.documents[0]?.id) + const [layers, setLayers] = useState(fixtures.layers) + const [weights, setWeights] = useState(fixtures.lineWeights) + const [weightId, setWeightId] = useState("w-default") + const [colorMode, setColorMode] = useState(null) + const [textStyle, setTextStyle] = useState(fixtures.textStyles[0]) + const [dimensionStyle, setDimensionStyle] = useState(fixtures.dimensionStyles[0]) + const [barOpen, setBarOpen] = useState(true) + const [panelOpen, setPanelOpen] = useState(false) + const [expanded, setExpanded] = useState([]) + const [readOnly, setReadOnly] = useState(false) + const [disabled, setDisabled] = useState(false) + const [emptyShape, setEmptyShape] = useState(false) + const [callbackLog, setCallbackLog] = useState([]) + const counter = useRef(0) + const record = (line: string) => { setCallbackLog(lines => [...lines.slice(-5), line]); console.info(`[SWHeader Overview] ${line}`) } + const value = (id: string) => properties.find(property => property.id === id)?.value ?? "" + const change = (id: string, next: string, event = "onPropertyChange") => { + setProperties(items => items.map(property => property.id === id ? { + ...property, value: next, mixed: false, ...(id === "color" ? { swatch: parseSWHeaderColor(next)?.hex } : {}), + } : property)) + if (id === "color") setColorMode(null) + record(`${event}(${id}, ${next})`) + } + const onPropertyChange = (property: SWHeaderProperty, next: string) => change(property.id, next) + const changeExample = (next: Selection) => { + setExample(next); setProperties(getProperties(next)); setExpanded(next === "expanded" ? ["common"] : []) + record(`selection(${next})`) + } + + useLayoutEffect(() => { + const slot = slotRef.current + if (!slot) return + const measure = () => { + const bounds = slot.getBoundingClientRect() + const width = Math.max(0, Math.min(bounds.width, bounds.height * 16 / 9)) + setSize(previous => previous.width === width ? previous : { width, height: width * 9 / 16 }) + } + measure() + const observer = new ResizeObserver(measure) + observer.observe(slot) + return () => observer.disconnect() + }, []) + + useLayoutEffect(() => { + const header = headerRef.current + if (!header) return + const measure = () => { + const bounds = header.getBoundingClientRect() + const trigger = header.querySelector("[data-property-panel-trigger]") + const anchor = trigger?.getClientRects().length ? trigger : header.querySelector(".hm-sw-header__more-trigger") + setPanelLeft(Math.max(4, Math.min((anchor?.getBoundingClientRect().left ?? bounds.left) - bounds.left, bounds.width - 318))) + } + measure() + const observer = new ResizeObserver(measure) + observer.observe(header) + return () => observer.disconnect() + }, []) + + const toggleLayer = (key: "visible" | "frozen" | "locked") => (layer: SWHeaderLayer, next: boolean) => { + setLayers(items => items.map(item => item.id === layer.id ? { ...item, [key]: next } : item)) + record(`layer.${key}(${layer.id}, ${next})`) + } + const chooseWeight = (weight: SWHeaderLineWeight) => { + setWeightId(weight.id) + // ByLayer/ByBlock select a mode, not a numeric property value (same policy as usePropertyMenus). + if (weight.value !== undefined) change("weight", weight.value, "onLineWeightSelect") + else record(`onLineWeightSelect(${weight.id})`) + } + const changeWeight = (weight: SWHeaderLineWeight, next: string) => { + setWeights(items => items.map(item => item.id === weight.id ? { ...item, value: next } : item)) + if (weightId === weight.id) change("weight", next, "onLineWeightValueChange") + else record(`onLineWeightValueChange(${weight.id}, ${next})`) + } + const changeMode = (mode: SWHeaderColorMode) => { setColorMode(mode); record(`onColorModeChange(${mode})`) } + const scale = value("scale") + const menus: SWHeaderPropertyMenus = { + layers, onLayerVisibilityChange: toggleLayer("visible"), onLayerFreezeChange: toggleLayer("frozen"), onLayerLockChange: toggleLayer("locked"), + onLayerDetail: () => record("onLayerDetail"), lineTypes: fixtures.lineTypes, lineWeights: weights, activeLineWeightId: weightId, lineScale: scale, + onLineWeightSelect: chooseWeight, onLineWeightValueChange: changeWeight, + onLineScaleChange: next => change("scale", Number(next).toFixed(4), "onLineScaleChange"), onLineStyleDetail: () => record("onLineStyleDetail"), + colors: fixtures.colors, userColors: fixtures.userColors, colorMode, onColorModeChange: changeMode, + onColorPick: () => record("onColorPick"), onColorDetail: () => record("onColorDetail"), + } + const guardedProperties = properties.map(property => ({ ...property, disabled: disabled || property.disabled, readOnly: readOnly || property.readOnly })) + const barProperties = guardedProperties.flatMap(property => { + const bar = barFixture.find(item => item.id === property.id) + return bar ? [{ ...bar, value: property.value, disabled: property.disabled, readOnly: property.readOnly }] + : property.id.startsWith("preview-extra-") ? [property] : [] + }) + const layer = layers.find(item => item.id === value("layer")) + const line = fixtures.lineTypes.find(item => item.id === value("line")) + const color = parseSWHeaderColor(value("color")) + const weight = weights.find(item => item.id === weightId) + + return + +
+ + +
시연 데이터
+ + + + + + +
+
+
+
+
+ document.id === documentId)?.name ?? "열린 문서 없음"} + onDocumentClick={() => record("onDocumentClick")} onDocumentMenuOpenChange={open => record(`documentOpen(${open})`)} + onDocumentSelect={document => { setDocumentId(document.id); record(`onDocumentSelect(${document.id})`) }} + onDocumentClose={document => { + const next = documents.filter(item => item.id !== document.id); setDocuments(next) + if (documentId === document.id) setDocumentId(next[0]?.id) + record(`onDocumentClose(${document.id})`) + }} + onDocumentNew={() => { + const id = `preview-document-${++counter.current}` + setDocuments(items => [...items, { id, name: `새 문서 ${counter.current}.dwg` }]); setDocumentId(id); record("onDocumentNew") + }} onDocumentOpen={() => record("onDocumentOpen")} + layers={layers} layer={{ name: layer?.name ?? value("layer") }} activeLayerId={layer?.id} + onLayerSelect={item => change("layer", item.id, "onLayerSelect")} + onLayerVisibilityChange={menus.onLayerVisibilityChange} onLayerFreezeChange={menus.onLayerFreezeChange} onLayerLockChange={menus.onLayerLockChange} + onLayerOpen={() => record("onLayerOpen")} onLayerDetail={menus.onLayerDetail} + colors={fixtures.colors} userColors={fixtures.userColors} + color={{ value: colorMode === "byLayer" ? "ByLayer" : colorMode === "byBlock" ? "ByBlock" : value("color"), swatch: color?.hex }} colorMode={colorMode} + onColorSelect={item => change("color", item.value ?? parseSWHeaderColor(item.color)?.value ?? item.color, "onColorSelect")} + onColorInput={next => change("color", next.value, "onColorInput")} onColorModeChange={changeMode} + onColorOpen={() => record("onColorOpen")} onColorDetail={menus.onColorDetail} onColorPick={() => record("onColorPick")} + lineTypes={fixtures.lineTypes} lineWeights={weights} activeLineTypeId={line?.id} activeLineWeightId={weightId} + lineStyle={{ name: line?.name ?? value("line"), weight: weight && weight.value === undefined ? weight.name : value("weight"), scale }} + onLineTypeSelect={item => change("line", item.id, "onLineTypeSelect")} onLineWeightSelect={chooseWeight} onLineWeightValueChange={changeWeight} + onLineScaleChange={menus.onLineScaleChange} onLineStyleOpen={() => record("onLineStyleOpen")} onLineStyleDetail={menus.onLineStyleDetail} + textStyles={fixtures.textStyles} activeTextStyleId={textStyle?.id} textStyle={textStyle} + onTextStyleSelect={item => { setTextStyle(item); record(`onTextStyleSelect(${item.id})`) }} + onTextStyleOpen={() => record("onTextStyleOpen")} onTextStyleDetail={() => record("onTextStyleDetail")} + dimensionStyles={fixtures.dimensionStyles} activeDimensionStyleId={dimensionStyle?.id} dimensionStyle={dimensionStyle} + onDimensionStyleSelect={item => { setDimensionStyle(item); record(`onDimensionStyleSelect(${item.id})`) }} + onDimensionStyleOpen={() => record("onDimensionStyleOpen")} onDimensionStyleDetail={() => record("onDimensionStyleDetail")} + propertyBarOpen={barOpen} onPropertyBarOpenChange={next => { setBarOpen(next); record(`propertyBarOpen(${next})`) }} + propertyPanelOpen={panelOpen} onPropertyPanelOpenChange={next => { setPanelOpen(next); record(`propertyPanelOpen(${next})`) }} + propertyBar={{ selection: propertySelection(example), properties: barProperties, onPropertyChange, readOnly, disabled }} + propertyPanel={{ selection: propertySelection(example), properties: guardedProperties, groups: propertyGroups, + expandedGroupIds: expanded, onExpandedGroupsChange: setExpanded, onPropertyChange, menus, + shapeContent: emptyShape ? null : undefined, onOverviewClick: () => changeExample("all"), + }} + onHomeClick={() => record("onHomeClick")} onPrint={() => record("onPrint")} onPopupGuide={() => record("onPopupGuide")} + onMinimize={() => record("onMinimize")} onClose={() => record("onClose")} onWindowMoveStart={() => record("onWindowMoveStart")} + /> +
+
+
+
+ {Math.round(size.width)} × {Math.round(size.height)} · 16:9 · 내부 스크롤 + {callbackLog.join(" → ") || "Callback 없음"} +
+
+} diff --git a/src/sw/sw-header.stories.tsx b/src/sw/sw-header.stories.tsx index 9b7521c..84c579a 100644 --- a/src/sw/sw-header.stories.tsx +++ b/src/sw/sw-header.stories.tsx @@ -11,6 +11,7 @@ import "@hm-design/sw/styles.css" import { SWHeaderMenuDetail } from "../../packages/sw/src/components/sw-header/components/SWHeaderDropdown" import { StoryPage, StoryPageHeader, StorySection } from "@/components/story-page" import "./sw-stories.css" +import { SWHeaderOverview } from "./sw-header-overview" import placeholderLogo from "./assets/sw-header-logo-placeholder.svg" import figmaLayerDetailReference from "./assets/figma-reference/btn-detail-layer-26-10767.png" import figmaInputReference from "./assets/figma-reference/input-26-11656.png" @@ -181,21 +182,10 @@ function InteractiveHeader(props: Partial) { export const Overview: Story = { parameters: { controls: { disable: true } }, - render: () => ( - - - - - - - - - - ), + render: () => , } export const InteractiveStates: Story = { diff --git a/src/sw/sw-stories.css b/src/sw/sw-stories.css index 66b9e71..7709e14 100644 --- a/src/sw/sw-stories.css +++ b/src/sw/sw-stories.css @@ -51,3 +51,26 @@ /* Property fields (2026-10-19): Figma node table under the specimens. */ .sw-story-node-table { margin-top: 16px; border-collapse: collapse; font-size: 12px; color: #3d4a45; } .sw-story-node-table :is(th, td) { padding: 4px 10px; border-bottom: 1px solid #d5ddd9; text-align: left; } + +/* Overview host layout only. Native controls below are Storybook data controls, outside the product. */ +.sw-story-overview.sb-page { height: 100dvh; min-height: 0; padding-block: 16px; } +.sw-story-overview > .sb-page-inner { height: 100%; display: flex; flex-direction: column; gap: 12px; } +.sw-story-overview .sb-page-header { flex: 0 0 auto; padding-bottom: 8px; } +.sw-story-overview .sb-page-header .sb-page-kicker { margin-bottom: 4px; } +.sw-story-overview .sb-page-header .sb-page-title { margin-block: 0 4px; } +.sw-overview-toolbar { display: flex; flex: 0 0 auto; flex-wrap: wrap; align-items: center; gap: 8px; font-size: 13px; } +.sw-overview-toolbar select, .sw-overview-data button { font: inherit; padding: 3px 8px; color: inherit; background: var(--hm-sem-bg-surface); border: 1px solid var(--hm-sem-stroke-input-default); border-radius: 4px; } +.sw-overview-toolbar details { flex-basis: 100%; } +.sw-overview-toolbar summary { width: max-content; cursor: pointer; } +.sw-overview-data { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding-block: 8px; } +.sw-overview-data label { display: inline-flex; align-items: center; gap: 4px; } +.sw-overview-slot { flex: 1 1 0; min-width: 0; min-height: 0; display: flex; align-items: center; justify-content: center; } +.sw-overview-stage { flex: 0 0 auto; overflow: auto; overscroll-behavior: contain; background: var(--hm-sem-bg-surface); outline: 1px solid var(--hm-sem-stroke-input-default); } +.sw-overview-world { min-width: 390px; min-height: 100%; position: relative; } +/* Placement-only Storybook exception: keep the original panel size/content in the Stage scroll area. + Header's public API deliberately excludes panel style; package CSS and other Stories stay untouched. */ +.sw-overview-stage .hm-sw-property { position: absolute !important; left: var(--sw-preview-panel-left) !important; top: var(--sw-preview-panel-top) !important; max-height: none !important; } +/* The document wrapper otherwise stacks below the independently positioned property Bar. */ +.sw-overview-stage .hm-sw-header__document:has(.hm-sw-header__document-menu) { z-index: 3; } +.sw-overview-status { flex: 0 0 auto; display: flex; flex-wrap: wrap; gap: 4px 16px; font-size: 12px; min-width: 0; } +.sw-overview-status output { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }