chore(sw): remove selected Storybook demos

This commit is contained in:
shkim4 committed 2026-10-19 10:42:32 +09:00
1 parent 92830fe11d
commit 50bf5bda8e
11 files changed
+2387 -265

No files matched your search

@@ -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"
}
]
@@ -0,0 +1,498 @@
[
{
"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--default",
"name": "Default",
"title": "SW/Header",
"importPath": "./src/sw/sw-header.stories.tsx",
"componentPath": "./packages/sw/dist/index.js",
"tags": [
"dev",
"test",
"manifest"
],
"exportName": "Default"
},
{
"type": "story",
"subtype": "story",
"id": "sw-header--controls",
"name": "Controls",
"title": "SW/Header",
"importPath": "./src/sw/sw-header.stories.tsx",
"componentPath": "./packages/sw/dist/index.js",
"tags": [
"dev",
"test",
"manifest"
],
"exportName": "Controls"
},
{
"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--responsive",
"name": "Responsive",
"title": "SW/Header",
"importPath": "./src/sw/sw-header.stories.tsx",
"componentPath": "./packages/sw/dist/index.js",
"tags": [
"dev",
"test",
"manifest"
],
"exportName": "Responsive"
},
{
"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--text-stroke",
"name": "Text Stroke",
"title": "SW/Header",
"importPath": "./src/sw/sw-header.stories.tsx",
"componentPath": "./packages/sw/dist/index.js",
"tags": [
"dev",
"test",
"manifest"
],
"exportName": "TextStroke"
},
{
"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--dynamic-data",
"name": "Dynamic Data",
"title": "SW/Header",
"importPath": "./src/sw/sw-header.stories.tsx",
"componentPath": "./packages/sw/dist/index.js",
"tags": [
"dev",
"test",
"manifest"
],
"exportName": "DynamicData"
},
{
"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"
}
]
@@ -0,0 +1,114 @@
{
"mode": "preservation",
"browser": "155.0.8059.80",
"checks": [
{
"name": "required responsive width 390",
"status": "PASS",
"data": {
"height": 49,
"overflow": 0,
"documentOverflow": 0
}
},
{
"name": "required responsive width 768",
"status": "PASS",
"data": {
"height": 49,
"overflow": 0,
"documentOverflow": 0
}
},
{
"name": "required responsive width 1280",
"status": "PASS",
"data": {
"height": 49,
"overflow": 0,
"documentOverflow": 0
}
},
{
"name": "required responsive width 1440",
"status": "PASS",
"data": {
"height": 49,
"overflow": 0,
"documentOverflow": 0
}
},
{
"name": "preserve property panel none",
"status": "PASS",
"data": {
"x": 360,
"y": 204.5,
"width": 314,
"height": 256
}
},
{
"name": "preserve property panel all",
"status": "PASS",
"data": {
"x": 360,
"y": 204.5,
"width": 314,
"height": 361
}
},
{
"name": "preserve property panel circle",
"status": "PASS",
"data": {
"x": 360,
"y": 204.5,
"width": 314,
"height": 658
}
},
{
"name": "preserve property panel expanded",
"status": "PASS",
"data": {
"x": 360,
"y": 204.5,
"width": 314,
"height": 754
}
},
{
"name": "preserve window motion 1400ms",
"status": "PASS"
},
{
"name": "window motion leave clears animations",
"status": "PASS"
},
{
"name": "preserve K guide animation",
"status": "PASS"
},
{
"name": "K guide leave closes",
"status": "PASS"
},
{
"name": "preserve Colorize size",
"status": "PASS"
},
{
"name": "preserve editable Input",
"status": "PASS"
},
{
"name": "no browser errors",
"status": "PASS",
"data": []
}
],
"errors": [],
"styles": {},
"status": "PASS"
}
@@ -0,0 +1,678 @@
{
"checks": [
{
"name": "33 -> 28; precisely the five requested IDs removed",
"status": "PASS",
"data": [
{
"name": "Default",
"id": "sw-header--default"
},
{
"name": "Controls",
"id": "sw-header--controls"
},
{
"name": "Responsive",
"id": "sw-header--responsive"
},
{
"name": "Text Stroke",
"id": "sw-header--text-stroke"
},
{
"name": "Dynamic Data",
"id": "sw-header--dynamic-data"
}
]
},
{
"name": "all retained names, IDs, ordering and tags unchanged",
"status": "PASS"
},
{
"name": "every retained declaration unchanged except WindowMoveMotion",
"status": "PASS",
"data": []
},
{
"name": "retained step section is byte-identical after newline normalization",
"status": "PASS"
},
{
"name": "production implementation, CSS, SVG/assets and Storybook configuration unchanged",
"status": "PASS"
},
{
"name": "render sw-header--detail-buttons",
"status": "PASS"
},
{
"name": "render sw-header--overview",
"status": "PASS"
},
{
"name": "render sw-header--interactive-states",
"status": "PASS"
},
{
"name": "render sw-header--window-move-motion",
"status": "PASS"
},
{
"name": "render sw-header--composed-controls",
"status": "PASS"
},
{
"name": "render sw-header--logo-slot",
"status": "PASS"
},
{
"name": "render sw-header--document-dropdown",
"status": "PASS"
},
{
"name": "render sw-header--layer-dropdown",
"status": "PASS"
},
{
"name": "render sw-header--color-dropdown",
"status": "PASS"
},
{
"name": "render sw-header--line-style-dropdown",
"status": "PASS"
},
{
"name": "render sw-header--text-dimension-style-dropdown",
"status": "PASS"
},
{
"name": "render sw-header--responsive-more",
"status": "PASS"
},
{
"name": "render sw-header--layer-detail-input",
"status": "PASS"
},
{
"name": "render sw-header--property-panel",
"status": "PASS"
},
{
"name": "render sw-header--property-panel-variants",
"status": "PASS"
},
{
"name": "render sw-header--k-guide",
"status": "PASS"
},
{
"name": "render sw-header--additional-hover",
"status": "PASS"
},
{
"name": "render sw-header--property-bar",
"status": "PASS"
},
{
"name": "render sw-header--dynamic-controls",
"status": "PASS"
},
{
"name": "render sw-header--colorize",
"status": "PASS"
},
{
"name": "render sw-header--composition",
"status": "PASS"
},
{
"name": "render sw-header--property-panel-none",
"status": "PASS"
},
{
"name": "render sw-header--property-panel-all",
"status": "PASS"
},
{
"name": "render sw-header--property-panel-circle",
"status": "PASS"
},
{
"name": "render sw-header--property-panel-expanded",
"status": "PASS"
},
{
"name": "render sw-header--property-panel-compare",
"status": "PASS"
},
{
"name": "render sw-header--property-shape-slot",
"status": "PASS"
},
{
"name": "render sw-header--property-fields",
"status": "PASS"
},
{
"name": "only the requested section remains",
"status": "PASS",
"data": [
"단계별 진행 (3배 확대)"
]
},
{
"name": "removed live demos, frame specimens and callback logs absent",
"status": "PASS"
},
{
"name": "nine original steps and 3x magnification preserved",
"status": "PASS",
"data": [
{
"time": "rest",
"zoom": "3",
"width": 456,
"height": 144,
"animations": []
},
{
"time": "0",
"zoom": "3",
"width": 456,
"height": 144,
"animations": [
{
"state": "paused",
"time": 0,
"duration": 1400
},
{
"state": "paused",
"time": 0,
"duration": 1400
},
{
"state": "paused",
"time": 0,
"duration": 1400
}
]
},
{
"time": "204.8780487804878",
"zoom": "3",
"width": 456,
"height": 144,
"animations": [
{
"state": "paused",
"time": 204.8780487804878,
"duration": 1400
},
{
"state": "paused",
"time": 204.8780487804878,
"duration": 1400
},
{
"state": "paused",
"time": 204.8780487804878,
"duration": 1400
}
]
},
{
"time": "409.7560975609756",
"zoom": "3",
"width": 456,
"height": 144,
"animations": [
{
"state": "paused",
"time": 409.7560975609756,
"duration": 1400
},
{
"state": "paused",
"time": 409.7560975609756,
"duration": 1400
},
{
"state": "paused",
"time": 409.7560975609756,
"duration": 1400
}
]
},
{
"time": "443.9024390243902",
"zoom": "3",
"width": 456,
"height": 144,
"animations": [
{
"state": "paused",
"time": 443.9024390243902,
"duration": 1400
},
{
"state": "paused",
"time": 443.9024390243902,
"duration": 1400
},
{
"state": "paused",
"time": 443.9024390243902,
"duration": 1400
}
]
},
{
"time": "682.9268292682926",
"zoom": "3",
"width": 456,
"height": 144,
"animations": [
{
"state": "paused",
"time": 682.9268292682926,
"duration": 1400
},
{
"state": "paused",
"time": 682.9268292682926,
"duration": 1400
},
{
"state": "paused",
"time": 682.9268292682926,
"duration": 1400
}
]
},
{
"time": "887.8048780487804",
"zoom": "3",
"width": 456,
"height": 144,
"animations": [
{
"state": "paused",
"time": 887.8048780487804,
"duration": 1400
},
{
"state": "paused",
"time": 887.8048780487804,
"duration": 1400
},
{
"state": "paused",
"time": 887.8048780487804,
"duration": 1400
}
]
},
{
"time": "1365.8536585365853",
"zoom": "3",
"width": 456,
"height": 144,
"animations": [
{
"state": "paused",
"time": 1365.8536585365853,
"duration": 1400
},
{
"state": "paused",
"time": 1365.8536585365853,
"duration": 1400
},
{
"state": "paused",
"time": 1365.8536585365853,
"duration": 1400
}
]
},
{
"time": "1400",
"zoom": "3",
"width": 456,
"height": 144,
"animations": [
{
"state": "paused",
"time": 1400,
"duration": 1400
},
{
"state": "paused",
"time": 1400,
"duration": 1400
},
{
"state": "paused",
"time": 1400,
"duration": 1400
}
]
}
]
},
{
"name": "rest is static; timed specimens pause three 1400ms animations at their original positions",
"status": "PASS"
},
{
"name": "live Hover motion advances with original 1400ms infinite cycle",
"status": "PASS",
"data": [
{
"before": 0,
"after": 199.92699997154995,
"state": "running",
"duration": 1400,
"iterations": "infinite"
},
{
"before": 0,
"after": 199.92699997154995,
"state": "running",
"duration": 1400,
"iterations": "infinite"
},
{
"before": 0,
"after": 199.92699997154995,
"state": "running",
"duration": 1400,
"iterations": "infinite"
}
]
},
{
"name": "pointer held pauses motion and hides tooltip",
"status": "PASS"
},
{
"name": "Hover leave resets live specimen",
"status": "PASS"
},
{
"name": "Responsive More still switches the representative field and opens its dropdown",
"status": "PASS"
},
{
"name": "Dynamic Controls removes a configured field",
"status": "PASS"
},
{
"name": "Dynamic Controls restores a configured field",
"status": "PASS"
},
{
"name": "host-owned document list can still grow dynamically",
"status": "PASS"
},
{
"name": "retained fluid header layout at 390px",
"status": "PASS",
"data": {
"height": 49,
"overflow": 0
}
},
{
"name": "retained fluid header layout at 768px",
"status": "PASS",
"data": {
"height": 49,
"overflow": 0
}
},
{
"name": "retained fluid header layout at 1280px",
"status": "PASS",
"data": {
"height": 49,
"overflow": 0
}
},
{
"name": "retained fluid header layout at 1440px",
"status": "PASS",
"data": {
"height": 49,
"overflow": 0
}
},
{
"name": "no browser errors",
"status": "PASS",
"data": []
}
],
"errors": [],
"baseCommit": "92830fe11db7f37eb6a45e8bbc6a5038ec579649",
"deleted": [
{
"name": "Default",
"id": "sw-header--default"
},
{
"name": "Controls",
"id": "sw-header--controls"
},
{
"name": "Responsive",
"id": "sw-header--responsive"
},
{
"name": "Text Stroke",
"id": "sw-header--text-stroke"
},
{
"name": "Dynamic Data",
"id": "sw-header--dynamic-data"
}
],
"browser": "155.0.8059.80",
"stages": [
{
"time": "rest",
"zoom": "3",
"width": 456,
"height": 144,
"animations": []
},
{
"time": "0",
"zoom": "3",
"width": 456,
"height": 144,
"animations": [
{
"state": "paused",
"time": 0,
"duration": 1400
},
{
"state": "paused",
"time": 0,
"duration": 1400
},
{
"state": "paused",
"time": 0,
"duration": 1400
}
]
},
{
"time": "204.8780487804878",
"zoom": "3",
"width": 456,
"height": 144,
"animations": [
{
"state": "paused",
"time": 204.8780487804878,
"duration": 1400
},
{
"state": "paused",
"time": 204.8780487804878,
"duration": 1400
},
{
"state": "paused",
"time": 204.8780487804878,
"duration": 1400
}
]
},
{
"time": "409.7560975609756",
"zoom": "3",
"width": 456,
"height": 144,
"animations": [
{
"state": "paused",
"time": 409.7560975609756,
"duration": 1400
},
{
"state": "paused",
"time": 409.7560975609756,
"duration": 1400
},
{
"state": "paused",
"time": 409.7560975609756,
"duration": 1400
}
]
},
{
"time": "443.9024390243902",
"zoom": "3",
"width": 456,
"height": 144,
"animations": [
{
"state": "paused",
"time": 443.9024390243902,
"duration": 1400
},
{
"state": "paused",
"time": 443.9024390243902,
"duration": 1400
},
{
"state": "paused",
"time": 443.9024390243902,
"duration": 1400
}
]
},
{
"time": "682.9268292682926",
"zoom": "3",
"width": 456,
"height": 144,
"animations": [
{
"state": "paused",
"time": 682.9268292682926,
"duration": 1400
},
{
"state": "paused",
"time": 682.9268292682926,
"duration": 1400
},
{
"state": "paused",
"time": 682.9268292682926,
"duration": 1400
}
]
},
{
"time": "887.8048780487804",
"zoom": "3",
"width": 456,
"height": 144,
"animations": [
{
"state": "paused",
"time": 887.8048780487804,
"duration": 1400
},
{
"state": "paused",
"time": 887.8048780487804,
"duration": 1400
},
{
"state": "paused",
"time": 887.8048780487804,
"duration": 1400
}
]
},
{
"time": "1365.8536585365853",
"zoom": "3",
"width": 456,
"height": 144,
"animations": [
{
"state": "paused",
"time": 1365.8536585365853,
"duration": 1400
},
{
"state": "paused",
"time": 1365.8536585365853,
"duration": 1400
},
{
"state": "paused",
"time": 1365.8536585365853,
"duration": 1400
}
]
},
{
"time": "1400",
"zoom": "3",
"width": 456,
"height": 144,
"animations": [
{
"state": "paused",
"time": 1400,
"duration": 1400
},
{
"state": "paused",
"time": 1400,
"duration": 1400
},
{
"state": "paused",
"time": 1400,
"duration": 1400
}
]
}
],
"status": "PASS"
}
@@ -0,0 +1,418 @@
> hm-design-system-poc@0.1.0 prebuild-storybook
> npm run check:theme-defaults && npm run build:packages
> hm-design-system-poc@0.1.0 check:theme-defaults
> node scripts/theme-defaults.mjs --check
Theme defaults: 92 JSON colors / 94 contract defaults; generated outputs match
> hm-design-system-poc@0.1.0 build:packages
> npm run build:org-chart && npm run build:ui && npm run build:center-graphic && npm run build:org-chart-react && npm run build:sw
> hm-design-system-poc@0.1.0 build:org-chart
> npm run build -w @hm-design/org-chart
> @hm-design/org-chart@0.1.0 build
> node build.mjs
vite v8.3.0 building client environment for production...
transforming...
✓ 70 modules transformed.
rendering chunks...
computing gzip size...
dist/index.js 2,450.52 kB │ gzip: 1,648.92 kB
✓ built in 95ms
vite v8.3.0 building client environment for production...
transforming...
✓ 70 modules transformed.
rendering chunks...
computing gzip size...
dist/orgchart.browser.js 2,456.85 kB │ gzip: 1,649.32 kB
✓ built in 81ms
> hm-design-system-poc@0.1.0 build:ui
> npm run build -w @hm-design/ui
> @hm-design/ui@0.1.0 build
> node ../../scripts/build-package.mjs ui
vite v8.3.0 building client environment for production...
transforming...
✓ 70 modules transformed.
rendering chunks...
computing gzip size...
dist/theme/index.js 25.18 kB │ gzip: 3.98 kB
dist/index.js 120.43 kB │ gzip: 21.30 kB
✓ built in 73ms
> hm-design-system-poc@0.1.0 build:center-graphic
> npm run build -w @hm-design/center-graphic
> @hm-design/center-graphic@0.1.0 build
> node ../../scripts/build-package.mjs center-graphic
vite v8.3.0 building client environment for production...
transforming...
✓ 145 modules transformed.
rendering chunks...
computing gzip size...
dist/style.css 88.68 kB │ gzip: 20.14 kB
dist/reference.js 0.65 kB │ gzip: 0.23 kB
dist/index.js 1.86 kB │ gzip: 0.84 kB
dist/FacilityBatch-PtW_fbvn.js 1,675.84 kB │ gzip: 276.13 kB
✓ built in 118ms
> hm-design-system-poc@0.1.0 build:org-chart-react
> npm run build -w @hm-design/org-chart-react
> @hm-design/org-chart-react@0.1.0 build
> node build.mjs
vite v8.3.0 building client environment for production...
transforming...
✓ 5 modules transformed.
rendering chunks...
computing gzip size...
dist/index.js 0.09 kB │ gzip: 0.09 kB
dist/hm-dialog.js 4.39 kB │ gzip: 1.80 kB
dist/OrgChart-DZlWXlj3.js 10.50 kB │ gzip: 2.63 kB
✓ built in 35ms
> 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 111ms
> hm-design-system-poc@0.1.0 build-storybook
> storybook build -o storybook-static --disable-telemetry
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
| Vite vite v8.3.0 building client environment for production...
transforming...
|
• Copying static files: themes at storybook-static\themes
Found 1 warning while optimizing generated CSS:
│ }
│ .bg-\[var\(\.\.\.\)\] {
│ background-color: var(...);
┆ ^-- Unexpected token Delim('.')
┆
│ }
│ .bg-background {
✓ 3101 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-C90CBOQd.css
| 71.39 kB │ gzip: 13.24 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-B2ZqwRQr.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-CrDPAp-u.js
| 0.41 kB │ gzip: 0.29 kB
| storybook-static/assets/layout-grid-Dec_L8Aj.js
| 0.48 kB │ gzip: 0.28 kB
| storybook-static/assets/italic-C62xCiKB.js
| 0.58 kB │ gzip: 0.35 kB
| storybook-static/assets/org-chart-full-composition.stories-CmXC5sW1.js
| 0.59 kB │ gzip: 0.39 kB
| storybook-static/assets/org-chart-p1.stories-BSRSHtxP.js
| 0.59 kB │ gzip: 0.40 kB
| storybook-static/assets/org-chart-department-colors.stories-BJ6NN2og.js
| 0.60 kB │ gzip: 0.39 kB
| storybook-static/assets/settings-IEEhIdXT.js
| 0.62 kB │ gzip: 0.34 kB
| storybook-static/assets/org-chart-summary.stories-DUf6hNdy.js
| 0.76 kB │ gzip: 0.39 kB
| storybook-static/assets/center-information.stories-CTlvamgN.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-Cq7GuYZv.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-BBmUr86Z.js
| 1.36 kB │ gzip: 0.88 kB
| storybook-static/assets/org-chart-overview-internal.stories-xfMk8xm3.js
| 1.43 kB │ gzip: 0.68 kB
| storybook-static/assets/org-chart-cards.stories-5sVa_xK1.js
| 1.60 kB │ gzip: 0.92 kB
| storybook-static/assets/color.stories-CRESndSc.js
| 1.80 kB │ gzip: 1.03 kB
| storybook-static/assets/center-facility.stories-MbEz9XLY.js
| 1.90 kB │ gzip: 1.07 kB
| storybook-static/assets/loading-screen.stories-c2mCZt7h.js
| 1.96 kB │ gzip: 1.03 kB
| storybook-static/assets/story-board-CMOyevtm.js
| 1.99 kB │ gzip: 0.89 kB
| storybook-static/assets/skeleton.stories-Bn6sImwM.js
| 2.10 kB │ gzip: 1.00 kB
| storybook-static/assets/story-page-InLs9Vcj.js
| 2.13 kB │ gzip: 0.69 kB
| storybook-static/assets/verification-state-CRE5GvFI.js
| 2.15 kB │ gzip: 1.05 kB
| storybook-static/assets/hover-card.stories-DK6TOk7K.js
| 2.34 kB │ gzip: 1.09 kB
| storybook-static/assets/alert-dialog.stories-C3y8_aeE.js
| 2.48 kB │ gzip: 1.08 kB
| storybook-static/assets/separator.stories-DD1Lnw5I.js
| 2.56 kB │ gzip: 1.16 kB
| storybook-static/assets/dropdown-menu.stories-Ct3gPj8c.js
| 2.58 kB │ gzip: 1.29 kB
| storybook-static/assets/badge.stories-B45ffhR3.js
| 2.61 kB │ gzip: 1.23 kB
| storybook-static/assets/tooltip.stories-CdfcrH9l.js
| 2.65 kB │ gzip: 1.23 kB
| storybook-static/assets/publisher-regression.stories-BUA6jhK3.js
| 2.70 kB │ gzip: 1.14 kB
| storybook-static/assets/calendar.stories-JsGZzMU6.js
| 2.79 kB │ gzip: 1.30 kB
| storybook-static/assets/switch.stories-BkiV1juR.js
| 2.86 kB │ gzip: 1.28 kB
| storybook-static/assets/reference-CNG9Q7Qf.js
| 2.88 kB │ gzip: 1.24 kB
| storybook-static/assets/context-menu.stories-DYgUrl_5.js
| 2.95 kB │ gzip: 1.47 kB
| storybook-static/assets/center-shared-C3dIvnsE.js
| 2.96 kB │ gzip: 1.36 kB
| storybook-static/assets/scroll-area.stories-BDJ-Spvu.js
| 3.02 kB │ gzip: 1.30 kB
| storybook-static/assets/popover.stories-DpV76T6Y.js
| 3.05 kB │ gzip: 1.30 kB
| storybook-static/assets/aspect-ratio.stories-DgNz1xSz.js
| 3.06 kB │ gzip: 1.51 kB
| storybook-static/assets/typography.stories-CGPtsrfA.js
| 3.07 kB │ gzip: 1.42 kB
| storybook-static/assets/pagination.stories-CWF8okYi.js
| 3.12 kB │ gzip: 1.50 kB
| storybook-static/assets/alert.stories-oDf5co-_.js
| 3.16 kB │ gzip: 1.29 kB
| storybook-static/assets/label.stories-2WonSZOr.js
| 3.19 kB │ gzip: 1.39 kB
| storybook-static/assets/collapsible.stories-CHcI8y1q.js
| 3.19 kB │ gzip: 1.50 kB
| storybook-static/assets/drawer.stories-TOTXcbXX.js
| 3.23 kB │ gzip: 1.47 kB
| storybook-static/assets/radio-group.stories-z8I630HS.js
| 3.24 kB │ gzip: 1.47 kB
| storybook-static/assets/avatar.stories-Bsma4jmS.js
| 3.30 kB │ gzip: 1.45 kB
| storybook-static/assets/page-header.stories-CgClekDL.js
| 3.32 kB │ gzip: 1.30 kB
| storybook-static/assets/menubar.stories-C2OkGMXB.js
| 3.33 kB │ gzip: 1.39 kB
| storybook-static/assets/command.stories-BGdtj-Vw.js
| 3.33 kB │ gzip: 1.58 kB
| storybook-static/assets/center-overview.stories-BUlg6ljN.js
| 3.36 kB │ gzip: 1.77 kB
| storybook-static/assets/filter-bar.stories-kxI3Llmp.js
| 3.43 kB │ gzip: 1.72 kB
| storybook-static/assets/sheet.stories-BDx_nhob.js
| 3.51 kB │ gzip: 1.44 kB
| storybook-static/assets/progress.stories-c7TrYqeB.js
| 3.52 kB │ gzip: 1.60 kB
| storybook-static/assets/breadcrumb.stories-DWOevXaH.js
| 3.55 kB │ gzip: 1.52 kB
| storybook-static/assets/card.stories-ZUo4F81H.js
| 3.74 kB │ gzip: 1.63 kB
| storybook-static/assets/navigation-menu.stories-BmS0c7qz.js
| 3.86 kB │ gzip: 1.62 kB
| storybook-static/assets/resizable.stories-DoJps_3U.js
| 3.96 kB │ gzip: 1.46 kB
| storybook-static/assets/specimens-C49VJeZT.js
| 4.13 kB │ gzip: 1.36 kB
| storybook-static/assets/sonner.stories-vuU_t7oM.js
| 4.22 kB │ gzip: 1.83 kB
| storybook-static/assets/checkbox.stories-CZ2w2Qab.js
| 4.39 kB │ gzip: 1.66 kB
| storybook-static/assets/date-picker.stories-COb2hSCU.js
| 4.45 kB │ gzip: 1.68 kB
| storybook-static/assets/slider.stories-CwDpW7mP.js
| 4.53 kB │ gzip: 1.85 kB
| storybook-static/assets/org-chart-page-previews-DkDa-PWK.js
| 4.70 kB │ gzip: 2.05 kB
| storybook-static/assets/carousel.stories-CA_mwrsr.js
| 4.75 kB │ gzip: 1.91 kB
| storybook-static/assets/layout.stories-CQ6ojhKi.js
| 4.79 kB │ gzip: 1.92 kB
| storybook-static/assets/table.stories-13OnP4or.js
| 4.86 kB │ gzip: 2.02 kB
| storybook-static/assets/combobox.stories-7-ze7vBq.js
| 5.03 kB │ gzip: 2.06 kB
| storybook-static/assets/accordion.stories-CE5xTSQ-.js
| 5.05 kB │ gzip: 1.81 kB
| storybook-static/assets/OrgChart-DZlWXlj3-DpBLtOar.js
| 5.35 kB │ gzip: 1.94 kB
| storybook-static/assets/dialog.stories-BtscPLmz.js
| 5.53 kB │ gzip: 2.13 kB
| storybook-static/assets/toggle.stories-DWnnq7g_.js
| 5.81 kB │ gzip: 2.12 kB
| storybook-static/assets/data-table.stories-CV4Eyfkw.js
| 5.92 kB │ gzip: 2.51 kB
| storybook-static/assets/textarea.stories-q50rAgK3.js
| 5.99 kB │ gzip: 2.43 kB
| storybook-static/assets/runtime-loader.stories-DuMZGCVT.js
| 6.18 kB │ gzip: 2.45 kB
| storybook-static/assets/toggle-group.stories-BTaGOcrf.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-Co1wru0X.js
| 8.32 kB │ gzip: 3.05 kB
| storybook-static/assets/button.stories-CW2ZQ7Bp.js
| 9.65 kB │ gzip: 3.62 kB
| storybook-static/assets/select.stories-CAX3tTcq.js
| 10.52 kB │ gzip: 3.39 kB
| storybook-static/assets/tabs.stories-DZ_x3GeH.js
| 11.57 kB │ gzip: 4.13 kB
| storybook-static/assets/org-chart.stories-D49__YqK.js
| 12.54 kB │ gzip: 4.15 kB
| storybook-static/assets/designer-theme.stories-D8Hrex2Y.js
| 14.62 kB │ gzip: 5.52 kB
| storybook-static/assets/gnb.stories-Bz0tX0qH.js
| 16.56 kB │ gzip: 5.83 kB
| storybook-static/assets/theme-CZw7CMzf.js
| 18.61 kB │ gzip: 3.18 kB
| storybook-static/assets/lnb.stories-DHeUgKcQ.js
| 23.06 kB │ gzip: 6.43 kB
| storybook-static/assets/dashboard-layout.stories-D3EPoHnA.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-o-w95Yhu.js
| 61.92 kB │ gzip: 11.60 kB
| storybook-static/assets/org-chart-expanded.stories-DwIuuCDG.js
| 79.03 kB │ gzip: 10.07 kB
| storybook-static/assets/react-18-DPql6C9x.js
| 207.62 kB │ gzip: 65.12 kB
| storybook-static/assets/core-component-preview-qVlFRdYj.js
| 258.40 kB │ gzip: 146.05 kB
| storybook-static/assets/sw-header.stories-rIXaAc8o.js
| 758.58 kB │ gzip: 357.47 kB
| storybook-static/assets/reference-CBHPHHCT.js
| 1,644.48 kB │ gzip: 270.35 kB
| storybook-static/assets/iframe-DVD1nTdY.js
| 1,754.05 kB │ gzip: 503.60 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.88s
|
! Vite [PLUGIN_TIMINGS] JavaScript callbacks ran for 3.4s of this 3.9s
| build (87%).
| 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.3s, 3101
| 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
@@ -0,0 +1,32 @@
{
"storybookBuild": {
"command": "npm.cmd run build-storybook",
"exitCode": 0,
"status": "PASS",
"log": "storybook-build.txt"
},
"swTypecheck": {
"command": "npm.cmd run typecheck:sw",
"exitCode": 0,
"status": "PASS"
},
"storyTypecheck": {
"command": "npm.cmd exec -- tsc -p tsconfig.app.json --noEmit",
"exitCode": 0,
"status": "PASS"
},
"browser": {
"status": "PASS",
"checks": 49
},
"preservation": {
"status": "PASS",
"checks": 15
},
"warnings": [
"CSS optimizer: background-color: var(...) generated utility",
"OrgChart :host-context minifier warnings",
"Vite chunk size warnings"
],
"scope": "STORYBOOK_ONLY; no new application screen; AI screen generation guard not applicable"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

@@ -0,0 +1,67 @@
# SW Storybook 2차 정리 1단계 — 지정 항목 삭제
- 판정: PASS. 범위는 `STORYBOOK_ONLY`이며 신규 업무 화면 생성이 아니므로 AI 화면 생성 Guard는 적용하지 않았습니다.
- 시작 상태: `D:\디자인시스템\HMDesign-SW`, `feature/sw-package`, `92830fe11db7f37eb6a45e8bbc6a5038ec579649`, Working Tree clean, upstream 대비 기존 로컬 Commit 2개.
- 사용자 요청에 따라 현재 브랜치에서 로컬 Commit만 수행합니다. Push·PR·다음 정리 단계는 수행하지 않습니다.
## 적용 내용
삭제한 독립 Story 5개:
- Responsive — `sw-header--responsive`
- Text Stroke — `sw-header--text-stroke`
- Dynamic Data — `sw-header--dynamic-data`
- Default — `sw-header--default`
- Controls — `sw-header--controls`
Window Move Motion(`sw-header--window-move-motion`)에는 **단계별 진행 (3배 확대)** 섹션만 남겼습니다. 페이지 제목은 유지했고 다른 시연에 대한 머리말 설명은 제거했습니다.
제거한 시연 섹션:
- GIF 주요 3상태 (정적, 3배 확대)
- 실제 Hover · 창 이동 · 클릭 (1920)
- 이동 완료 실제 배치 (1920, 고정)
- 헤더 1080 미만 (1079 고정 · 768 실제 Hover)
- Reduced Motion
해당 Story에서만 사용하는 `MotionDemo`, `RESPONSIVE_WIDTHS`, `DynamicDataDemo` 및 전용 타입·상수·목록 조작 함수도 제거했습니다. 공유 Fixture·Callback·함수는 유지했습니다.
## 보존 및 검증
- 수정 전 현재 소스에 Storybook index 명령을 실행해 33개를 확보했습니다. 기존 `storybook-static`은 최신 소스와 목록이 달라 기준으로 사용하지 않았습니다.
- 최종 Build index는 28개입니다. 삭제 차이는 위 5개와 정확히 일치하고 나머지 ID·이름·순서·태그는 동일합니다. verification 태그도 그대로입니다.
- `Responsive More`, `Dynamic Controls`를 포함한 남은 Story 28개가 실제 Chrome에서 렌더링됩니다.
- 시작 Commit과 AST 선언 텍스트를 비교해 `WindowMoveMotion` 외 모든 남은 선언이 동일함을 확인했습니다. 단계별 섹션 JSX·`MOTION_STAGES`·`motionTime`·`MotionAt`·`MotionSpecimen`도 그대로입니다.
- 단계 9개, `zoom: 3` 및 실제 456×144px 표본, 정지 표본 3개 애니메이션의 원래 시간 위치, 실제 Hover 재생·1400ms 무한 반복·Pointer 누름 중 정지·Tooltip 숨김·이탈 복귀를 확인했습니다.
- More의 대표 필드 전환·Dropdown 열림, Dynamic Controls 항목 제거·복원 및 문서 목록 추가를 확인했습니다.
- 기존 보존 검증에서 390/768/1280/1440px Header overflow·높이, 속성창 크기, K 가이드, Colorize 및 편집 Input도 통과했습니다.
- Header 구현·공개 API·패키지 CSS·Story CSS·SVG/이미지·Storybook 설정은 시작 Commit과 동일합니다. 실제 반응형·텍스트 외곽선·동적 데이터 기능과 Controls 관련 설정은 유지됩니다.
실행 결과:
- `npm.cmd run build-storybook`: PASS. 패키지 사전 빌드 포함.
- `npm.cmd run typecheck:sw`: PASS.
- `npm.cmd exec -- tsc -p tsconfig.app.json --noEmit`: PASS. Story 파일 포함.
- `node packages/sw/tests/storybook-cleanup-stage1.browser.mjs`: **49/49 PASS**, 브라우저 오류 0.
- `node packages/sw/tests/detail-buttons.browser.mjs preservation docs/sw/storybook-cleanup-stage1-qa/preservation`: **15/15 PASS**, 브라우저 오류 0.
- `git diff --check`: PASS.
Build에는 생성된 `var(...)` 유틸리티, OrgChart `:host-context`, chunk 크기 관련 경고가 있습니다. Build는 성공했으며 해당 코드·설정은 이번 변경 범위 밖입니다.
검증 범위는 Chrome의 변경 Story 및 관련 보존 동작입니다. 나머지 모든 Story의 모든 상호작용과 Firefox 전체 회귀 검사는 이번에 재실행하지 않았습니다(`NOT VERIFIED`).
## 테스트 참조와 증거
기존 `detail-buttons.browser.mjs`의 삭제된 Default/Controls 렌더링 참조를 Overview/Composition으로 옮겼고, Story 목록 비교에서 승인된 5개 삭제만 허용하도록 수정했습니다. 기존 baseline·검증 파일·증거는 삭제하거나 덮어쓰지 않았습니다. 전체 `verify` 모드의 Header 위치 비교는 대체 Story 기준 baseline이 필요하므로 필요 시 **새 증거 디렉터리**에 `baseline` 모드로 먼저 확보합니다. 이번에는 영향을 받는 `preservation` 모드와 범위 전용 검증을 실행했습니다.
새 증거:
- [수정 전 33개 목록](storybook-cleanup-stage1-qa/before-index.json)
- [수정 후 28개 목록](storybook-cleanup-stage1-qa/after-index.json)
- [범위 전용 검증 결과](storybook-cleanup-stage1-qa/result.json)
- [기존 보존 검증 결과](storybook-cleanup-stage1-qa/preservation/preservation-result.json)
- [통합 검증 요약](storybook-cleanup-stage1-qa/validation-summary.json)
- [Storybook Build 기록](storybook-cleanup-stage1-qa/storybook-build.txt)
- [정리 후 Window Move Motion 화면](storybook-cleanup-stage1-qa/window-move-motion.png)
이전 1차 정리 보고서와 과거 검증 기록은 당시 상태를 보여 주는 기록으로 보존했습니다.
+8 -5
View File
@@ -42,7 +42,7 @@ try {
await page.locator('[data-detail-row="문자스타일 상세"] [data-detail-case="hover"] button').hover()
await page.screenshot({path:path.join(output,'comparison-pointer-hover.png'),fullPage:true})
} else if (mode === 'preservation') {
await goto('controls')
await goto('composition')
for(const width of [390,768,1280,1440]){
await page.setViewportSize({width,height:1000})
const layout=await page.locator('header.hm-sw-header').first().evaluate(h=>({height:h.getBoundingClientRect().height,overflow:h.scrollWidth-h.clientWidth,documentOverflow:document.documentElement.scrollWidth-document.documentElement.clientWidth}))
@@ -54,7 +54,7 @@ try {
const box=await page.locator('.hm-sw-property').first().boundingBox()
check(`preserve property panel ${id}`,box.width===314&&box.height===height,box)
}
await goto('controls')
await goto('composition')
const motion=page.locator('[data-sw-window-move]').first();await motion.hover()
check('preserve window motion 1400ms',await motion.evaluate(e=>e.getAnimations({subtree:true}).length===3&&e.getAnimations({subtree:true}).every(a=>a.effect.getTiming().duration===1400)))
await page.mouse.move(1,900);check('window motion leave clears animations',await motion.evaluate(e=>e.getAnimations({subtree:true}).length===0))
@@ -70,7 +70,8 @@ try {
const ids = Object.values(index.entries).filter(e => e.title === 'SW/Header' && e.type === 'story').map(e => e.id)
report.storyIds = ids
if (mode === 'baseline') await writeFile(path.join(output, 'baseline-story-ids.json'), JSON.stringify(ids))
for (const story of ['default', 'controls']) {
// These retained examples cover fixed-width and fluid headers after the two Args demos were retired.
for (const story of ['overview', 'composition']) {
await goto(story)
for (const width of [1920,1800,1440,1180,1080,900,768,640,520,390]) {
await page.setViewportSize({ width, height:1000 })
@@ -94,9 +95,11 @@ try {
await writeFile(path.join(output,'baseline.json'),JSON.stringify(snapshots,null,2))
} else {
const before=JSON.parse(await readFile(path.join(output,'baseline.json'),'utf8'))
for(const key of Object.keys(before).filter(k=>!k.startsWith('text'))) check(`unchanged header ${key}`,JSON.stringify(before[key])===JSON.stringify(snapshots[key]))
for(const key of Object.keys(snapshots).filter(k=>!k.startsWith('text'))) check(`unchanged header ${key} (capture a current baseline for replacement fixtures)`,JSON.stringify(before[key])===JSON.stringify(snapshots[key]))
const oldIds=JSON.parse(await readFile(path.join(output,'baseline-story-ids.json'),'utf8'))
check('all previous 31 stories retained',oldIds.length===31&&oldIds.every(id=>ids.includes(id)),{before:oldIds.length,after:ids.length})
const retiredIds=['default','controls','responsive','text-stroke','dynamic-data'].map(id=>`sw-header--${id}`)
const retainedIds=oldIds.filter(id=>!retiredIds.includes(id))
check('retained stories remain; only the five approved demos are absent',ids.length===28&&retainedIds.every(id=>ids.includes(id))&&retiredIds.every(id=>!ids.includes(id)),{before:oldIds.length,after:ids.length})
for(const id of ids){await goto(id.replace('sw-header--',''));check(`render ${id}`,!(await page.locator('.sb-errordisplay').isVisible()))}
await goto('composition')
const presets=['기본 전체','구성 A','구성 B (레이어·선스타일)','구성 C (로고만)','파일 목록 제거','레이어 제거','색상 제거','스타일 그룹 제거','여러 메뉴 제거','순서 변경','숨김 + 순서 변경']
@@ -0,0 +1,148 @@
// Scoped verification for the five approved Story removals; serves the production build locally.
// Usage: node packages/sw/tests/storybook-cleanup-stage1.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-cleanup-stage1-qa')
await mkdir(out, { recursive: true })
const report = { checks: [], errors: [], baseCommit: '92830fe11db7f37eb6a45e8bbc6a5038ec579649' }
const check = (name, ok, data) => {
report.checks.push({ name, status: ok ? 'PASS' : 'FAIL', data })
console.log(ok ? 'PASS' : 'FAIL', name)
}
const retired = ['responsive', 'text-stroke', 'dynamic-data', 'default', 'controls'].map(id => `sw-header--${id}`)
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')
report.deleted = before.filter(e => !after.some(a => a.id === e.id)).map(e => ({ name: e.name, id: e.id }))
check('33 -> 28; precisely the five requested IDs removed', before.length === 33 && after.length === 28 &&
report.deleted.length === 5 && retired.every(id => report.deleted.some(e => e.id === id)), report.deleted)
check('all retained names, IDs, ordering and tags unchanged', JSON.stringify(before.filter(e => !retired.includes(e.id)).map(e => [e.id, e.name, e.tags])) ===
JSON.stringify(after.map(e => [e.id, e.name, e.tags])))
// Compare declaration text with the starting commit, including every retained fixture/helper.
const file = 'src/sw/sw-header.stories.tsx'
const original = execFileSync('git', ['show', `${report.baseCommit}:${file}`], { encoding: 'utf8' }).replaceAll('\r\n', '\n')
const current = (await readFile(file, 'utf8')).replaceAll('\r\n', '\n')
const declarations = text => {
return parse(text, { sourceType: 'module', plugins: ['typescript', 'jsx'] }).program.body.map(statement => {
const n = statement.type === 'ExportNamedDeclaration' ? statement.declaration : statement
return {
name: n.type === 'VariableDeclaration' ? n.declarations.map(d => d.id.name).join(',') :
n.type === 'ImportDeclaration' ? `import:${n.source.value}` : n.id?.name ?? n.type,
text: text.slice(statement.start, statement.end),
}
})
}
const oldDeclarations = new Map(declarations(original).map(d => [d.name, d.text]))
const changed = declarations(current).filter(d => d.name !== 'WindowMoveMotion' && oldDeclarations.get(d.name) !== d.text)
check('every retained declaration unchanged except WindowMoveMotion', changed.length === 0, changed.map(d => d.name))
const section = text => text.match(/<StorySection title="단계별 진행 \(3배 확대\)"[\s\S]*?<\/StorySection>/)?.[0]
check('retained step section is byte-identical after newline normalization', !!section(original) && section(original) === section(current))
const productionDiff = execFileSync('git', ['diff', report.baseCommit, '--', 'packages/sw/src', 'src/sw/sw-stories.css', 'src/sw/assets', '.storybook'], { encoding: 'utf8' })
check('production implementation, CSS, SVG/assets and Storybook configuration unchanged', productionDiff === '')
const root = path.resolve('storybook-static')
const 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 pathname = new URL(req.url, 'http://localhost').pathname
const file = path.resolve(root, '.' + decodeURIComponent(pathname === '/' ? '/index.html' : pathname))
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
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()
const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } })
page.on('pageerror', e => report.errors.push(e.message))
page.on('console', m => { if (m.type() === 'error') report.errors.push(m.text()) })
const goto = async id => {
await page.goto(`${base}/iframe.html?id=${id.startsWith('sw-header--') ? 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.mouse.move(1, 1)
}
for (const entry of after) {
await goto(entry.id)
check(`render ${entry.id}`, !(await page.locator('.sb-errordisplay').isVisible()))
}
await goto('window-move-motion')
const titles = await page.locator('section > header h2').allTextContents()
check('only the requested section remains', JSON.stringify(titles) === JSON.stringify(['단계별 진행 (3배 확대)']), titles)
check('removed live demos, frame specimens and callback logs absent', await page.locator('[data-frame-width], [data-callback-log]').count() === 0)
const stages = await page.locator('[data-motion-time]').evaluateAll(elements => elements.map(e => {
const zoom = e.querySelector('.sw-story-zoom'), motion = e.querySelector('[data-sw-window-move]')
const box = zoom.getBoundingClientRect()
return { time: e.dataset.motionTime, zoom: getComputedStyle(zoom).zoom, width: box.width, height: box.height,
animations: motion.getAnimations({ subtree: true }).map(a => ({ state: a.playState, time: a.currentTime, duration: a.effect.getTiming().duration })) }
}))
report.stages = stages
const expected = ['rest', ...[0, 240, 480, 520, 800, 1040, 1600, 1640].map(t => String(t * 1400 / 1640))]
check('nine original steps and 3x magnification preserved', stages.length === 9 && stages.every((s, i) => s.time === expected[i] && Number(s.zoom) === 3 && s.width === 456 && s.height === 144), stages)
check('rest is static; timed specimens pause three 1400ms animations at their original positions', stages[0].animations.length === 0 && stages.slice(1).every(s => s.animations.length === 3 && s.animations.every(a => a.state === 'paused' && a.duration === 1400 && Math.abs(a.time - Number(s.time)) < 0.01)))
await page.screenshot({ path: path.join(out, 'window-move-motion.png'), fullPage: true })
const motion = page.locator('[data-motion-time="rest"] [data-sw-window-move]')
await motion.hover()
const timing = await motion.evaluate(async e => {
const animations = e.getAnimations({ subtree: true })
const before = animations.map(a => a.currentTime)
const started = performance.now()
await new Promise(resolve => { const tick = () => performance.now() - started >= 180 ? resolve() : requestAnimationFrame(tick); requestAnimationFrame(tick) })
return animations.map((a, i) => ({ before: before[i], after: a.currentTime, state: a.playState, duration: a.effect.getTiming().duration, iterations: a.effect.getTiming().iterations === Infinity ? 'infinite' : a.effect.getTiming().iterations }))
})
check('live Hover motion advances with original 1400ms infinite cycle', timing.length === 3 && timing.every(a => a.state === 'running' && a.after > a.before && a.duration === 1400 && a.iterations === 'infinite'), timing)
await page.mouse.down()
check('pointer held pauses motion and hides tooltip', await motion.evaluate(e => e.getAnimations({ subtree: true }).every(a => a.playState === 'paused') && getComputedStyle(e.querySelector('[role="tooltip"]')).visibility === 'hidden'))
await page.mouse.up()
await page.mouse.move(1, 1)
check('Hover leave resets live specimen', await motion.evaluate(e => e.getAnimations({ subtree: true }).length === 0))
await goto('responsive-more')
const header = page.locator('[data-frame-width="1440"] header.hm-sw-header').first()
await header.getByRole('button', { name: '더보기', exact: true }).click()
await header.locator('[role="menuitem"][data-menu="line-style"]').click()
check('Responsive More still switches the representative field and opens its dropdown', await header.locator('.hm-sw-header__line-menu').count() > 0 && await header.locator('.hm-sw-header__line-menu').isVisible())
await page.keyboard.press('Escape')
await goto('dynamic-controls')
await page.getByRole('checkbox', { name: '구성 color', exact: true }).uncheck()
check('Dynamic Controls removes a configured field', await page.locator('header.hm-sw-header [data-control="color"], header.hm-sw-header [data-menu="color"]').count() === 0)
await page.getByRole('checkbox', { name: '구성 color', exact: true }).check()
check('Dynamic Controls restores a configured field', await page.locator('header.hm-sw-header [data-menu="color"]').count() > 0)
await page.getByRole('button', { name: '구성 초기화', exact: true }).click()
const documents = page.locator('header.hm-sw-header .hm-sw-header__document-button')
await documents.click()
await page.getByRole('button', { name: '+ New', exact: true }).click()
await documents.click()
check('host-owned document list can still grow dynamically', await page.getByText('새 문서 1', { exact: true }).count() > 0)
await goto('composition')
for (const width of [390, 768, 1280, 1440]) {
await page.setViewportSize({ width, height: 1000 })
const geometry = await page.locator('header.hm-sw-header').evaluate(e => ({ height: e.getBoundingClientRect().height, overflow: e.scrollWidth - e.clientWidth }))
check(`retained fluid header layout at ${width}px`, geometry.height === 49 && geometry.overflow === 0, geometry)
}
check('no browser errors', report.errors.length === 0, report.errors)
} catch (error) {
check('suite completes', false, error.stack)
} finally {
if (browser) 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, 'result.json'), JSON.stringify(report, null, 2) + '\n')
console.log(JSON.stringify({ status: report.status, checks: report.checks.length, errors: report.errors }))
process.exitCode = report.status === 'PASS' ? 0 : 1
}
+1 -260
View File
@@ -198,14 +198,6 @@ export const Overview: Story = {
),
}
export const Default: Story = {
render: args => <Frame width={1920}><SWHeader {...args} /></Frame>,
}
export const Controls: Story = {
render: args => <SWHeader {...args} />,
}
export const InteractiveStates: Story = {
name: "Interactive States",
parameters: { controls: { disable: true } },
@@ -260,26 +252,6 @@ export const InteractiveStates: Story = {
),
}
const RESPONSIVE_WIDTHS = [1920, 1800, 1799, 1770, 1600, 1440, 1280, 1180, 1179, 1080, 1079, 900, 899, 768, 640, 639, 560, 390]
export const Responsive: Story = {
parameters: { controls: { disable: true } },
render: () => (
<StoryPage>
<StoryPageHeader
kicker={KICKER}
title="Responsive"
description="필드는 모든 폭에서 Figma 폭을 유지하고, 공간이 부족하면 기능을 더보기로 옮깁니다. 헤더 폭 1800 미만: 선·문자·치수 스타일 / 1180 미만: 그리기모드 라벨 숨김 / 1080 미만: 속성Bar·속성창 / 900 미만: 색상 / 640 미만: 인쇄·팝업 가이드. 520 미만에서만 레이어명이 말줄임됩니다. 헤더 폭 기준이므로 각 프레임에서 그대로 확인할 수 있습니다."
/>
{RESPONSIVE_WIDTHS.map(width => (
<StorySection key={width} title={`${width}px`}>
<Frame width={width}><InteractiveHeader /></Frame>
</StorySection>
))}
</StoryPage>
),
}
/** Preserve GIF phase ratios/positions, with the user-requested 1640 -> 1400ms speed change. */
const motionTime = (gifTime: number) => gifTime * 1400 / 1640
const MOTION_STAGES = [
@@ -320,58 +292,12 @@ function MotionSpecimen({ time }: { time?: number }) {
)
}
/** Live header with a callback / animation log, to check drag and clicks under the motion. */
function MotionDemo({ width }: { width: number }) {
const [log, setLog] = useState<string[]>([])
const ref = useRef<HTMLDivElement>(null)
const add = (line: string) => setLog(lines => [...lines.slice(-9), line])
useEffect(() => {
const area = ref.current?.querySelector(".hm-sw-header__motion")
if (!area) return
// One tooltip animation per play stands for the whole motion.
const listen = (type: string, line: string) => {
const handler = (event: Event) => { if ((event as AnimationEvent).animationName.endsWith("-tooltip")) add(line) }
area.addEventListener(type, handler)
return () => area.removeEventListener(type, handler)
}
const cleanups = [listen("animationstart", "motion start"), listen("animationiteration", "motion cycle"), listen("animationend", "motion end"), listen("animationcancel", "motion reset")]
return () => cleanups.forEach(cleanup => cleanup())
}, [])
return (
<>
<p className="sw-story-log" aria-live="polite" data-callback-log="">기록: {log.length ? log.join(" → ") : "없음"}</p>
<div ref={ref}>
<Frame width={width}>
<SWHeader
{...figmaArgs}
{...callbacks}
onWindowMoveStart={() => { console.info("[SWHeader] windowMoveStart"); add("onWindowMoveStart") }}
onMinimize={() => { callbacks.onMinimize(); add("onMinimize") }}
onClose={() => { callbacks.onClose(); add("onClose") }}
/>
</Frame>
</div>
</>
)
}
export const WindowMoveMotion: Story = {
name: "Window Move Motion",
parameters: { controls: { disable: true } },
render: () => (
<StoryPage>
<StoryPageHeader
kicker={KICKER}
title="Window Move Motion"
description="ani_hover_move.gif의 이동 경로·구간 비율을 유지하고 사용자 요청으로 1640ms → 1400ms로 단축했습니다: 커서 상승 → 약 444ms 문구 등장 → 오른쪽 위로 이동 → 약 888ms부터 512ms 유지 → 1400ms 반복. 이탈 시 기본 SVG로 복귀하고 누르는 동안 모션 정지·문구 숨김을 유지합니다. 88 × 48 영역·줄무늬·SVG·Tooltip 규격은 그대로입니다."
/>
<StorySection title="GIF 주요 3상태 (정적, 3배 확대)" description="왼쪽부터 기존 Default · 문구 등장 약 444ms · 이동 완료 약 888ms. 창 제어 영역(창 이동 88 + 최소화·종료 64)만 공개 하위 컴포넌트로 표시합니다. Tooltip은 창 이동 영역 밖으로 나갈 수 있으며 포인터를 가로채지 않습니다.">
<div className="sw-story-row">
<MotionSpecimen />
<MotionSpecimen time={motionTime(520)} />
<MotionSpecimen time={motionTime(1040)} />
</div>
</StorySection>
<StoryPageHeader kicker={KICKER} title="Window Move Motion" />
<StorySection title="단계별 진행 (3배 확대)" description="CSS 애니메이션을 해당 시점에 멈춘 화면입니다(Storybook 전용 data-sb-hover + Web Animations API로 시간만 고정).">
<div className="sw-story-stages">
{MOTION_STAGES.map(stage => (
@@ -382,21 +308,6 @@ export const WindowMoveMotion: Story = {
))}
</div>
</StorySection>
<StorySection title="실제 Hover · 창 이동 · 클릭 (1920)" description="Hover 동안 1.4초마다 반복(motion cycle)하고 이탈하면 복귀합니다(motion reset). 누르는 동안 모션 일시정지·Tooltip 숨김으로 Drag를 방해하지 않습니다. onWindowMoveStart는 기존대로 한 번 호출되며 최소화·종료 클릭도 그대로 전달됩니다.">
<MotionDemo width={1920} />
</StorySection>
<StorySection title="이동 완료 실제 배치 (1920, 고정)" description="현재 이동 완료 약 888ms(GIF 1040ms와 같은 위치)를 고정합니다. Tooltip은 최소화·종료 일부에 겹치지만 헤더 안에 머물러 가로 스크롤을 만들지 않습니다.">
<Frame width={1920}><MotionAt time={motionTime(1040)}><SWHeader {...figmaArgs} {...callbacks} /></MotionAt></Frame>
</StorySection>
<StorySection title="헤더 1080 미만 (1079 고정 · 768 실제 Hover)" description="창 이동 영역이 24px로 줄어드는 단계에서는 아이콘 모션 공간이 없어 Tooltip만 표시합니다(영역 오른쪽, Figma hover2와 같은 관계 x = 영역 폭 + 1, y 11). 640 미만에서는 기존대로 창 이동 영역이 숨겨집니다.">
<div className="sw-story-stack">
<Frame width={1079}><MotionAt time={500}><SWHeader {...figmaArgs} {...callbacks} /></MotionAt></Frame>
<MotionDemo width={768} />
</div>
</StorySection>
<StorySection title="Reduced Motion" description="OS의 동작 줄이기(prefers-reduced-motion: reduce)가 켜져 있으면 기존 Default SVG를 유지하고, Hover 동안 정적 Tooltip만 표시됩니다. Drag 중에는 문구를 숨깁니다.">
<p className="sw-story-log">OS 설정을 켠 뒤 위 &apos;실제 Hover&apos; 예제에 마우스를 올려 확인합니다. Storybook은 이 미디어 조건을 강제로 켤 수 없습니다.</p>
</StorySection>
</StoryPage>
),
}
@@ -1093,47 +1004,6 @@ export const ResponsiveMore: Story = {
),
}
export const TextStroke: Story = {
name: "Text Stroke",
parameters: { controls: { disable: true } },
render: () => (
<StoryPage>
<StoryPageHeader
kicker={KICKER}
title="Text Stroke"
description="Figma 26:8944와 메뉴의 텍스트 Stroke(모두 OUTSIDE) 중 검정 외곽선을 text-shadow로 표시합니다: 14 · 16px 값 = 검정 1.3px, 12px 라벨 = 검정 1px. 자기 색 Stroke(0.3px · '… 상세' 0.4px)는 2026-10-16 추가 수정으로 제거했습니다. 글꼴·크기·굵기·자간·기준선·말줄임은 그대로이며 Hover/Selected는 채움색만 바뀝니다."
/>
<StorySection title="구현 (1920)">
<Frame width={1920}><SWHeader {...figmaArgs} {...callbacks} /></Frame>
</StorySection>
<StorySection title="3배 확대 — Default · Hover (고정) · Selected" description="12px 라벨 · 14px 값(한글·영문·숫자) · 16px 글꼴 미리보기 · 상세보기 토글.">
<div className="sw-story-zoom sw-story-stack">
<SWTheme className="sw-story-composed">
<SWHeaderLayerControl value={{ name: "레이어_Layer_0123" }} />
<SWHeaderColorControl value={figmaArgs.color!} />
<SWHeaderTextStyle value={figmaArgs.textStyle!} />
</SWTheme>
<PinHover selectors={[".hm-sw-header__field"]}>
<SWTheme className="sw-story-composed">
<SWHeaderLayerControl value={{ name: "레이어_Layer_0123" }} />
<SWHeaderColorControl value={figmaArgs.color!} />
<SWHeaderTextStyle value={figmaArgs.textStyle!} />
</SWTheme>
</PinHover>
<SWTheme className="sw-story-composed">
<SWHeaderLayerControl value={{ name: "레이어_Layer_0123" }} selected />
<SWHeaderColorControl value={figmaArgs.color!} selected />
<SWHeaderProperties barOpen panelOpen />
</SWTheme>
</div>
</StorySection>
<StorySection title="긴 텍스트 말줄임" description="말줄임 텍스트는 Stroke가 잘리지 않도록 2px 여유(overflow-clip-margin)를 둡니다.">
<Frame width={1440}><SWHeader {...figmaArgs} {...callbacks} documentTitle="C0020101-006-평면및종단면도(06)-수정본-최종-검토용-2026-10-16.dwg" layer={{ name: "Sample-매우-긴-레이어-이름-Ellipsis-확인용-Layer-Name" }} /></Frame>
</StorySection>
</StoryPage>
),
}
/** Host-owned detail values for the editable input (the detail popup itself is not designed yet). */
function InputDemo() {
const [value, setValue] = useState("4.0526")
@@ -1229,135 +1099,6 @@ export const LayerDetailInput: Story = {
),
}
/* Dynamic data: every list is host data. Adding, removing, renaming, revaluing and reordering items
needs no component change; ids keep each row's state; a removed current item leaves no selection. */
type DynamicLists = {
layers: SWHeaderLayer[]
colors: SWHeaderColorOption[]
userColors: SWHeaderColorOption[]
lineTypes: SWHeaderLineType[]
lineWeights: SWHeaderLineWeight[]
textStyles: SWHeaderTextStyleOption[]
dimensionStyles: SWHeaderDimensionStyleOption[]
documents: SWHeaderDocument[]
}
type DynamicKey = keyof DynamicLists
const DYNAMIC_INITIAL: DynamicLists = {
layers: SAMPLE_LAYERS.slice(0, 4),
colors: FIGMA_COLORS,
userColors: FIGMA_USER_COLORS,
lineTypes: FIGMA_LINE_TYPES,
lineWeights: FIGMA_LINE_WEIGHTS,
textStyles: FIGMA_TEXT_STYLES,
dimensionStyles: FIGMA_DIMENSION_STYLES,
documents: CURRENT_DOCUMENT,
}
const DYNAMIC_LABELS: Record<DynamicKey, string> = {
layers: "레이어", colors: "기본 색상", userColors: "사용자 색상", lineTypes: "선 종류", lineWeights: "가중치",
textStyles: "문자스타일", dimensionStyles: "치수스타일", documents: "문서",
}
/** New sample item of each list (`n` keeps ids unique). */
const DYNAMIC_FACTORY: { [K in DynamicKey]: (n: number) => DynamicLists[K][number] } = {
layers: n => ({ id: `new-layer-${n}`, name: `New-Layer-${n}`, color: "#ffa500" }),
colors: n => ({ id: `color-${n}`, color: `hsl(${(n * 67) % 360} 80% 55%)`, label: `추가 색상 ${n}` }),
userColors: n => ({ id: `user-color-${n}`, color: `hsl(${(n * 83) % 360} 70% 60%)`, label: `사용자 색상 추가 ${n}` }),
lineTypes: n => ({ id: `line-${n}`, name: `DASH-${n}`, pattern: [12, 4, 12, 4] }),
lineWeights: n => ({ id: `weight-${n}`, name: `${(0.05 * n).toFixed(2)} mm`, value: (0.05 * n).toFixed(2) }),
textStyles: n => ({ id: `text-${n}`, font: "굴림", name: `Text-${n}` }),
dimensionStyles: n => ({ id: `dim-${n}`, name: `DIM-${n}` }),
documents: n => ({ id: `doc-${n}`, name: `Sample-New-${n}.dwg` }),
}
const renameFirst = <T extends { name?: string; label?: string }>(list: T[]) =>
list.map((item, index) => (index !== 0 ? item : "name" in item ? { ...item, name: `${item.name}*` } : { ...item, label: `${item.label ?? ""}*` }))
function DynamicDataDemo() {
const [lists, setLists] = useState(DYNAMIC_INITIAL)
const [active, setActive] = useState({ layer: "layer-0", lineType: "continuous", lineWeight: "w-default", textStyle: "standard", dimensionStyle: "standard", document: "doc-current" })
const [lineStyle, setLineStyle] = useState<SWHeaderLineStyleValue>(figmaArgs.lineStyle!)
const [log, setLog] = useState<string[]>([])
const counter = useRef(0)
const add = (line: string) => setLog(lines => [...lines.slice(-9), line])
const update = <K extends DynamicKey>(key: K, next: (list: DynamicLists[K]) => DynamicLists[K], line: string) => {
setLists(current => ({ ...current, [key]: next(current[key]) }))
add(line)
}
const keys = Object.keys(lists) as DynamicKey[]
const currentDocument = lists.documents.find(item => item.id === active.document)
return (
<>
<div className="sw-story-dynamic">
{keys.map(key => (
<div key={key} className="sw-story-controls" data-dynamic-list={key}>
<strong>{DYNAMIC_LABELS[key]} ({lists[key].length})</strong>
<button type="button" onClick={() => update(key, list => [...list, DYNAMIC_FACTORY[key](++counter.current)] as typeof list, `${key}: 추가`)}>추가</button>
<button type="button" onClick={() => update(key, list => list.slice(1) as typeof list, `${key}: 첫 항목 삭제`)}>첫 항목 삭제</button>
<button type="button" onClick={() => update(key, list => renameFirst(list as { name?: string; label?: string }[]) as typeof list, `${key}: 첫 항목 이름 변경`)}>이름 변경</button>
<button type="button" onClick={() => update(key, list => [...list].reverse() as typeof list, `${key}: 순서 뒤집기`)}>순서 뒤집기</button>
</div>
))}
<div className="sw-story-controls">
<strong>값 · 상태 변경</strong>
<button type="button" onClick={() => update("lineWeights", list => list.map(item => (item.editable ? { ...item, value: "0.50" } : item)), "lineWeights: User = 0.50")}>User 가중치 0.50</button>
<button type="button" onClick={() => update("layers", list => list.map((item, index) => (index === 1 ? { ...item, visible: item.visible === false } : item)), "layers: 2번째 표시 반전")}>2번째 레이어 표시 반전</button>
<button type="button" onClick={() => update("lineTypes", list => list.map(item => (item.id === "continuous" ? { ...item, disabled: !item.disabled } : item)), "lineTypes: Continuous disabled 반전")}>Continuous Disabled</button>
</div>
</div>
<p className="sw-story-log" aria-live="polite" data-callback-log="">기록: {log.length ? log.join(" → ") : "없음"}</p>
<pre className="sw-story-layer-state" data-dynamic-state="">{`active: ${JSON.stringify(active)}`}</pre>
<MenuFrame width={1920}>
<SWHeader
{...figmaArgs}
{...callbacks}
documentTitle={currentDocument?.name ?? "열린 문서 없음"}
documents={lists.documents}
activeDocumentId={active.document}
onDocumentSelect={document => { add(`onDocumentSelect(${document.id})`); setActive(current => ({ ...current, document: document.id })) }}
onDocumentClose={document => update("documents", list => list.filter(item => item.id !== document.id), `onDocumentClose(${document.id})`)}
layers={lists.layers}
activeLayerId={active.layer}
onLayerSelect={layer => { add(`onLayerSelect(${layer.id})`); setActive(current => ({ ...current, layer: layer.id })) }}
onLayerVisibilityChange={(layer, next) => update("layers", list => list.map(item => (item.id === layer.id ? { ...item, visible: next } : item)), `onLayerVisibilityChange(${layer.id}, ${next})`)}
colors={lists.colors}
userColors={lists.userColors}
onColorSelect={option => add(`onColorSelect(${option.id})`)}
lineStyle={lineStyle}
lineTypes={lists.lineTypes}
lineWeights={lists.lineWeights}
activeLineTypeId={active.lineType}
activeLineWeightId={active.lineWeight}
onLineTypeSelect={type => { add(`onLineTypeSelect(${type.id})`); setActive(current => ({ ...current, lineType: type.id })); setLineStyle(current => ({ ...current, name: type.name })) }}
onLineWeightSelect={weight => { add(`onLineWeightSelect(${weight.id})`); setActive(current => ({ ...current, lineWeight: weight.id })); setLineStyle(current => ({ ...current, weight: weight.value ?? weight.name })) }}
onLineWeightValueChange={(weight, value) => update("lineWeights", list => list.map(item => (item.id === weight.id ? { ...item, value } : item)), `onLineWeightValueChange(${weight.id}, ${value})`)}
onLineScaleChange={value => { add(`onLineScaleChange(${value})`); setLineStyle(current => ({ ...current, scale: value })) }}
textStyles={lists.textStyles}
activeTextStyleId={active.textStyle}
onTextStyleSelect={style => { add(`onTextStyleSelect(${style.id})`); setActive(current => ({ ...current, textStyle: style.id })) }}
dimensionStyles={lists.dimensionStyles}
activeDimensionStyleId={active.dimensionStyle}
onDimensionStyleSelect={style => { add(`onDimensionStyleSelect(${style.id})`); setActive(current => ({ ...current, dimensionStyle: style.id })) }}
/>
</MenuFrame>
</>
)
}
export const DynamicData: Story = {
name: "Dynamic Data",
parameters: { controls: { disable: true } },
render: () => (
<StoryPage>
<StoryPageHeader
kicker={KICKER}
title="Dynamic Data"
description="모든 Dropdown 항목은 호스트 데이터(id · 이름 · 값 · 순서 · disabled / editable)로 렌더링합니다. 아래 버튼으로 항목을 추가·삭제·이름 변경·값 변경·순서 변경해도 컴포넌트 소스 수정이 필요 없고, id 기준으로 해당 항목만 갱신됩니다. 현재 항목을 삭제하면 선택 표시가 없어지고(다음 항목 결정은 호스트) 필드는 값 Props를 그대로 표시합니다. 목록이 길면 Dropdown 안에서만 스크롤합니다."
/>
<StorySection title="항목 추가 · 삭제 · 이름 · 값 · 순서 변경" description="Dropdown을 연 채로 버튼을 눌러도 됩니다(버튼은 Storybook 전용 조작 UI, 헤더 스타일과 무관). 열린 목록은 버튼 클릭(바깥 클릭)으로 닫히므로 다시 열어 확인합니다.">
<DynamicDataDemo />
</StorySection>
</StoryPage>
),
}
/* Additional review 2026-10-16: fixture values are host data, never package defaults. */
const PROPERTY_GROUPS: SWHeaderPropertyGroup[] = [
{ id: "common", collapsedCount: 6 },