fix(storybook): show Dropdown directly under Header

This commit is contained in:
shkim4 committed 2026-10-19 12:36:10 +09:00
1 parent 9482d45f34
commit c705a1fc59
36 files changed
+8837 -42

No files matched your search

@@ -0,0 +1,16 @@
import type { Meta, StoryObj } from "@storybook/react-vite"
import { ComposedDemo } from "./sw-header.stories"
import "./sw-composed-controls.css"
const meta = {
title: "SW/Header/Dropdown",
// Keep existing bookmarks while placing the single example under Dropdown.
id: "sw-header",
parameters: { layout: "fullscreen", controls: { disable: true } },
} satisfies Meta
export default meta
export const ComposedControls: StoryObj<typeof meta> = {
name: "Composed Controls",
render: () => <ComposedDemo />,
}
@@ -0,0 +1 @@
{"v":5,"entries":{"foundation-color--all":{"type":"story","subtype":"story","id":"foundation-color--all","name":"Color","title":"Foundation/Color","importPath":"./src/foundation/color.stories.tsx","tags":["dev","test","manifest"],"exportName":"All"},"foundation-typography--all":{"type":"story","subtype":"story","id":"foundation-typography--all","name":"Typography","title":"Foundation/Typography","importPath":"./src/foundation/typography.stories.tsx","tags":["dev","test","manifest"],"exportName":"All"},"foundation-layout--all":{"type":"story","subtype":"story","id":"foundation-layout--all","name":"Layout","title":"Foundation/Layout","importPath":"./src/foundation/layout.stories.tsx","tags":["dev","test","manifest"],"exportName":"All"},"components-form-button--all":{"type":"story","subtype":"story","id":"components-form-button--all","name":"Button","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest"],"exportName":"All"},"components-form-button--roles":{"type":"story","subtype":"story","id":"components-form-button--roles","name":"Roles","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"Roles"},"components-form-button--sizes":{"type":"story","subtype":"story","id":"components-form-button--sizes","name":"Sizes","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"Sizes"},"components-form-button--states":{"type":"story","subtype":"story","id":"components-form-button--states","name":"Brand States","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"States"},"components-form-button--standard-states":{"type":"story","subtype":"story","id":"components-form-button--standard-states","name":"Standard States","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"StandardStates"},"components-form-button--long-label":{"type":"story","subtype":"story","id":"components-form-button--long-label","name":"Long Label","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"LongLabel"},"components-form-button--korean-labels":{"type":"story","subtype":"story","id":"components-form-button--korean-labels","name":"Korean Labels","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"KoreanLabels"},"components-form-button--icon-text-narrow":{"type":"story","subtype":"story","id":"components-form-button--icon-text-narrow","name":"Icon Text Narrow","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"IconTextNarrow"},"components-form-button--destructive":{"type":"story","subtype":"story","id":"components-form-button--destructive","name":"Destructive","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"Destructive"},"components-form-button--playground":{"type":"story","subtype":"story","id":"components-form-button--playground","name":"Playground","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"Playground"},"components-form-button--compatibility":{"type":"story","subtype":"story","id":"components-form-button--compatibility","name":"Compatibility","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"Compatibility"},"components-form-input--all":{"type":"story","subtype":"story","id":"components-form-input--all","name":"Input","title":"Components/Form/Input","importPath":"./src/components/input.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","play-fn"],"exportName":"All"},"components-form-input--default":{"type":"story","subtype":"story","id":"components-form-input--default","name":"Default","title":"Components/Form/Input","importPath":"./src/components/input.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":Line truncated
@@ -0,0 +1,233 @@
PASS 28 -> 24 SW Stories, exactly four approved Dropdown retirements
PASS Dropdown is one Story directly under Header with original ID, no Dropdown folder
PASS menu correction keeps all 24 IDs; only composed Story name/title change
PASS all non-SW index entries identical
PASS all retained declarations identical outside imports, meta and ComposedDemo
PASS runtime, API, AI template, Overview, existing CSS/assets and Storybook configuration untouched
PASS render sw-header--composed-controls
PASS render sw-header--detail-buttons
PASS render sw-header--overview
PASS render sw-header--interactive-states
PASS render sw-header--window-move-motion
PASS render sw-header--logo-slot
PASS render sw-header--document-dropdown
PASS render sw-header--responsive-more
PASS render sw-header--layer-detail-input
PASS render sw-header--property-panel
PASS render sw-header--property-panel-variants
PASS render sw-header--k-guide
PASS render sw-header--additional-hover
PASS render sw-header--property-bar
PASS render sw-header--dynamic-controls
PASS render sw-header--colorize
PASS render sw-header--composition
PASS render sw-header--property-panel-none
PASS render sw-header--property-panel-all
PASS render sw-header--property-panel-circle
PASS render sw-header--property-panel-expanded
PASS render sw-header--property-panel-compare
PASS render sw-header--property-shape-slot
PASS render sw-header--property-fields
PASS Dropdown page contains the Composed Controls group
PASS one copy of five Dropdown fields and the details group
PASS composition wraps without page overflow or scaling at 390
PASS 레이어 Hover does not open at 390
PASS 레이어 overlay in viewport, not clipped or covered at 390
PASS 레이어 selected and expanded at 390
PASS 레이어 Escape closes and restores focus at 390
PASS 레이어 trigger toggles closed at 390
PASS 레이어 outside click closes at 390
PASS 색상 Hover does not open at 390
PASS 색상 overlay in viewport, not clipped or covered at 390
PASS 색상 selected and expanded at 390
PASS 색상 Escape closes and restores focus at 390
PASS 색상 trigger toggles closed at 390
PASS 색상 outside click closes at 390
PASS 선스타일 Hover does not open at 390
PASS 선스타일 overlay in viewport, not clipped or covered at 390
PASS 선스타일 selected and expanded at 390
PASS 선스타일 Escape closes and restores focus at 390
PASS 선스타일 trigger toggles closed at 390
PASS 선스타일 outside click closes at 390
PASS 문자스타일 Hover does not open at 390
PASS 문자스타일 overlay in viewport, not clipped or covered at 390
PASS 문자스타일 selected and expanded at 390
PASS 문자스타일 Escape closes and restores focus at 390
PASS 문자스타일 trigger toggles closed at 390
PASS 문자스타일 outside click closes at 390
PASS 치수스타일 Hover does not open at 390
PASS 치수스타일 overlay in viewport, not clipped or covered at 390
PASS 치수스타일 selected and expanded at 390
PASS 치수스타일 Escape closes and restores focus at 390
PASS 치수스타일 trigger toggles closed at 390
PASS 치수스타일 outside click closes at 390
PASS composition wraps without page overflow or scaling at 768
PASS 레이어 Hover does not open at 768
PASS 레이어 overlay in viewport, not clipped or covered at 768
PASS 레이어 selected and expanded at 768
PASS 레이어 Escape closes and restores focus at 768
PASS 레이어 trigger toggles closed at 768
PASS 레이어 outside click closes at 768
PASS 색상 Hover does not open at 768
PASS 색상 overlay in viewport, not clipped or covered at 768
PASS 색상 selected and expanded at 768
PASS 색상 Escape closes and restores focus at 768
PASS 색상 trigger toggles closed at 768
PASS 색상 outside click closes at 768
PASS 선스타일 Hover does not open at 768
PASS 선스타일 overlay in viewport, not clipped or covered at 768
PASS 선스타일 selected and expanded at 768
PASS 선스타일 Escape closes and restores focus at 768
PASS 선스타일 trigger toggles closed at 768
PASS 선스타일 outside click closes at 768
PASS 문자스타일 Hover does not open at 768
PASS 문자스타일 overlay in viewport, not clipped or covered at 768
PASS 문자스타일 selected and expanded at 768
PASS 문자스타일 Escape closes and restores focus at 768
PASS 문자스타일 trigger toggles closed at 768
PASS 문자스타일 outside click closes at 768
PASS 치수스타일 Hover does not open at 768
PASS 치수스타일 overlay in viewport, not clipped or covered at 768
PASS 치수스타일 selected and expanded at 768
PASS 치수스타일 Escape closes and restores focus at 768
PASS 치수스타일 trigger toggles closed at 768
PASS 치수스타일 outside click closes at 768
PASS composition wraps without page overflow or scaling at 1280
PASS 레이어 Hover does not open at 1280
PASS 레이어 overlay in viewport, not clipped or covered at 1280
PASS 레이어 selected and expanded at 1280
PASS 레이어 Escape closes and restores focus at 1280
PASS 레이어 trigger toggles closed at 1280
PASS 레이어 outside click closes at 1280
PASS 색상 Hover does not open at 1280
PASS 색상 overlay in viewport, not clipped or covered at 1280
PASS 색상 selected and expanded at 1280
PASS 색상 Escape closes and restores focus at 1280
PASS 색상 trigger toggles closed at 1280
PASS 색상 outside click closes at 1280
PASS 선스타일 Hover does not open at 1280
PASS 선스타일 overlay in viewport, not clipped or covered at 1280
PASS 선스타일 selected and expanded at 1280
PASS 선스타일 Escape closes and restores focus at 1280
PASS 선스타일 trigger toggles closed at 1280
PASS 선스타일 outside click closes at 1280
PASS 문자스타일 Hover does not open at 1280
PASS 문자스타일 overlay in viewport, not clipped or covered at 1280
PASS 문자스타일 selected and expanded at 1280
PASS 문자스타일 Escape closes and restores focus at 1280
PASS 문자스타일 trigger toggles closed at 1280
PASS 문자스타일 outside click closes at 1280
PASS 치수스타일 Hover does not open at 1280
PASS 치수스타일 overlay in viewport, not clipped or covered at 1280
PASS 치수스타일 selected and expanded at 1280
PASS 치수스타일 Escape closes and restores focus at 1280
PASS 치수스타일 trigger toggles closed at 1280
PASS 치수스타일 outside click closes at 1280
PASS composition wraps without page overflow or scaling at 1440
PASS 레이어 Hover does not open at 1440
PASS 레이어 overlay in viewport, not clipped or covered at 1440
PASS 레이어 selected and expanded at 1440
PASS 레이어 Escape closes and restores focus at 1440
PASS 레이어 trigger toggles closed at 1440
PASS 레이어 outside click closes at 1440
PASS 색상 Hover does not open at 1440
PASS 색상 overlay in viewport, not clipped or covered at 1440
PASS 색상 selected and expanded at 1440
PASS 색상 Escape closes and restores focus at 1440
PASS 색상 trigger toggles closed at 1440
PASS 색상 outside click closes at 1440
PASS 선스타일 Hover does not open at 1440
PASS 선스타일 overlay in viewport, not clipped or covered at 1440
PASS 선스타일 selected and expanded at 1440
PASS 선스타일 Escape closes and restores focus at 1440
PASS 선스타일 trigger toggles closed at 1440
PASS 선스타일 outside click closes at 1440
PASS 문자스타일 Hover does not open at 1440
PASS 문자스타일 overlay in viewport, not clipped or covered at 1440
PASS 문자스타일 selected and expanded at 1440
PASS 문자스타일 Escape closes and restores focus at 1440
PASS 문자스타일 trigger toggles closed at 1440
PASS 문자스타일 outside click closes at 1440
PASS 치수스타일 Hover does not open at 1440
PASS 치수스타일 overlay in viewport, not clipped or covered at 1440
PASS 치수스타일 selected and expanded at 1440
PASS 치수스타일 Escape closes and restores focus at 1440
PASS 치수스타일 trigger toggles closed at 1440
PASS 치수스타일 outside click closes at 1440
PASS keyboard opens layer menu and focuses current row
PASS keyboard moves to next layer row
PASS onLayerSelect callback exactly once
PASS layer selection appears, closes and restores focus
PASS selected layer retains original row Hover background
PASS onLayerVisibilityChange callback exactly once
PASS onLayerVisibilityChange toggles only its own state, menu remains open
PASS onLayerFreezeChange callback exactly once
PASS onLayerFreezeChange toggles only its own state, menu remains open
PASS onLayerLockChange callback exactly once
PASS onLayerLockChange toggles only its own state, menu remains open
PASS disabled layer selection and toggles blocked
PASS full color menu: seven palette chips, two user colors, modes, RGB and pick
PASS onColorSelect callback exactly once
PASS color palette updates displayed RGB and leaves menu open
PASS onColorModeChange callback exactly once
PASS ByBlock On and displayed mode
PASS onColorInput callback exactly once
PASS RGB commit clears mode and updates chip
PASS invalid RGB restores without callback
PASS onColorPick callback exactly once
PASS color pick closes and restores focus
PASS color changes leave layer, line, text and dimension values intact
PASS all original line rows and weights retained
PASS onLineTypeSelect callback exactly once
PASS selected line retains original row Hover and preview
PASS onLineWeightSelect callback exactly once
PASS onLineWeightValueChange callback exactly once
PASS onLineScaleChange callback exactly once
PASS line type, editable weight and scale update independently; menu stays open
PASS invalid scale restores, no callback
PASS 문자스타일 full two-item list retained
PASS onTextStyleSelect callback exactly once
PASS 문자스타일 selection displayed, closes, focus returns
PASS 치수스타일 full two-item list retained
PASS onDimensionStyleSelect callback exactly once
PASS 치수스타일 selection displayed, closes, focus returns
PASS 레이어 detail Hover uses existing text opacity
PASS onLayerDetail callback exactly once
PASS 레이어 detail closes, focus returns, no fabricated popup
PASS 색상 detail Hover uses existing text opacity
PASS onColorDetail callback exactly once
PASS 색상 detail closes, focus returns, no fabricated popup
PASS 선스타일 detail Hover uses existing text opacity
PASS onLineStyleDetail callback exactly once
PASS 선스타일 detail closes, focus returns, no fabricated popup
PASS 문자스타일 detail Hover uses existing text opacity
PASS onTextStyleDetail callback exactly once
PASS 문자스타일 detail closes, focus returns, no fabricated popup
PASS 치수스타일 detail Hover uses existing text opacity
PASS onDimensionStyleDetail callback exactly once
PASS 치수스타일 detail closes, focus returns, no fabricated popup
PASS opening another control leaves exactly one menu and preserves selection
PASS keyboard Tab enters the open color controls
PASS details opens existing 28px property Bar
PASS details opens existing 314px property panel with focus
PASS property Bar and panel share edited state
PASS property panel weight edit appears in composed line field
PASS property panel close returns focus
PASS property panel Escape returns focus
PASS narrow details panel keeps natural width and fits viewport
PASS all seven actionable controls Disabled
PASS Disabled controls block callbacks and overlays
PASS callback-free layer icons become readonly status images
PASS missing detail callback keeps safe no-op and menu open
PASS retained long layer scenario
PASS long layer name preserved with full title
PASS retained many layer scenario
PASS long layer list scrolls internally
PASS all 40 user colors accessible with palette scroll
PASS retained empty layer scenario
PASS Overview keeps one Header at 49px and 16:9 Stage
PASS Window Move Motion retains only nine 3x steps
PASS manager shows a single Dropdown link directly under Header, no Composed Controls submenu
PASS retired Dropdown links absent in manager
PASS no browser console or page errors
{"status":"PASS","checks":232,"errors":[]}
@@ -0,0 +1 @@
{"v":5,"entries":{"foundation-color--all":{"type":"story","subtype":"story","id":"foundation-color--all","name":"Color","title":"Foundation/Color","importPath":"./src/foundation/color.stories.tsx","tags":["dev","test","manifest"],"exportName":"All"},"foundation-typography--all":{"type":"story","subtype":"story","id":"foundation-typography--all","name":"Typography","title":"Foundation/Typography","importPath":"./src/foundation/typography.stories.tsx","tags":["dev","test","manifest"],"exportName":"All"},"foundation-layout--all":{"type":"story","subtype":"story","id":"foundation-layout--all","name":"Layout","title":"Foundation/Layout","importPath":"./src/foundation/layout.stories.tsx","tags":["dev","test","manifest"],"exportName":"All"},"components-form-button--all":{"type":"story","subtype":"story","id":"components-form-button--all","name":"Button","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest"],"exportName":"All"},"components-form-button--roles":{"type":"story","subtype":"story","id":"components-form-button--roles","name":"Roles","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"Roles"},"components-form-button--sizes":{"type":"story","subtype":"story","id":"components-form-button--sizes","name":"Sizes","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"Sizes"},"components-form-button--states":{"type":"story","subtype":"story","id":"components-form-button--states","name":"Brand States","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"States"},"components-form-button--standard-states":{"type":"story","subtype":"story","id":"components-form-button--standard-states","name":"Standard States","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"StandardStates"},"components-form-button--long-label":{"type":"story","subtype":"story","id":"components-form-button--long-label","name":"Long Label","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"LongLabel"},"components-form-button--korean-labels":{"type":"story","subtype":"story","id":"components-form-button--korean-labels","name":"Korean Labels","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"KoreanLabels"},"components-form-button--icon-text-narrow":{"type":"story","subtype":"story","id":"components-form-button--icon-text-narrow","name":"Icon Text Narrow","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"IconTextNarrow"},"components-form-button--destructive":{"type":"story","subtype":"story","id":"components-form-button--destructive","name":"Destructive","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"Destructive"},"components-form-button--playground":{"type":"story","subtype":"story","id":"components-form-button--playground","name":"Playground","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"Playground"},"components-form-button--compatibility":{"type":"story","subtype":"story","id":"components-form-button--compatibility","name":"Compatibility","title":"Components/Form/Button","importPath":"./src/components/button.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","verification"],"exportName":"Compatibility"},"components-form-input--all":{"type":"story","subtype":"story","id":"components-form-input--all","name":"Input","title":"Components/Form/Input","importPath":"./src/components/input.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":["dev","test","manifest","play-fn"],"exportName":"All"},"components-form-input--default":{"type":"story","subtype":"story","id":"components-form-input--default","name":"Default","title":"Components/Form/Input","importPath":"./src/components/input.stories.tsx","componentPath":"./packages/ui/dist/index.js","tags":Line truncated
File diff suppressed because it is too large. Load diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

File diff suppressed because it is too large. Load diff
@@ -0,0 +1,849 @@
{
"before": [
{
"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"
}
],
"after": [
{
"type": "story",
"subtype": "story",
"id": "sw-header--composed-controls",
"name": "Dropdown",
"title": "SW/Header",
"importPath": "./src/sw/sw-header-dropdown.stories.tsx",
"tags": [
"dev",
"test",
"manifest"
],
"exportName": "ComposedControls"
},
{
"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--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--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"
}
],
"removed": [
{
"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"
}
]
}
@@ -0,0 +1,5 @@
{
"hostStateAndCallbacksUnchanged": true,
"publicSWComponentNodesUnchanged": true,
"publicComponentNodes": 8
}
@@ -0,0 +1,422 @@
> 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 118ms
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 98ms
> 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 78ms
> 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 139ms
> 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 36ms
> 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 128ms
> 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
|
• 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 {
✓ 3104 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/sw-header-dropdown-BSCl7vok.css
| 0.54 kB │ gzip: 0.25 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-Olchztma.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-DzTQQROB.js
| 0.41 kB │ gzip: 0.29 kB
| storybook-static/assets/sw-header-dropdown.stories-BLWq_qUx.js
| 0.43 kB │ gzip: 0.31 kB
| storybook-static/assets/layout-grid-DQpkss7s.js
| 0.48 kB │ gzip: 0.28 kB
| storybook-static/assets/italic-DRHybvZF.js
| 0.58 kB │ gzip: 0.35 kB
| storybook-static/assets/org-chart-full-composition.stories-C9mxZF1K.js
| 0.59 kB │ gzip: 0.39 kB
| storybook-static/assets/org-chart-p1.stories-DkPE6w6D.js
| 0.59 kB │ gzip: 0.40 kB
| storybook-static/assets/org-chart-department-colors.stories-Ds9ysgvK.js
| 0.60 kB │ gzip: 0.39 kB
| storybook-static/assets/settings-DHMVC_pq.js
| 0.62 kB │ gzip: 0.34 kB
| storybook-static/assets/org-chart-summary.stories-D6G98X-G.js
| 0.76 kB │ gzip: 0.39 kB
| storybook-static/assets/center-information.stories-itj1KVcH.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-CUNMjSD5.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-DuVsqEkP.js
| 1.36 kB │ gzip: 0.88 kB
| storybook-static/assets/org-chart-overview-internal.stories-XQneG5-p.js
| 1.43 kB │ gzip: 0.68 kB
| storybook-static/assets/org-chart-cards.stories-F30e8loV.js
| 1.60 kB │ gzip: 0.92 kB
| storybook-static/assets/color.stories-D5eRfXN2.js
| 1.80 kB │ gzip: 1.03 kB
| storybook-static/assets/center-facility.stories-BVDL8QJu.js
| 1.90 kB │ gzip: 1.07 kB
| storybook-static/assets/loading-screen.stories-D_y2tsKX.js
| 1.96 kB │ gzip: 1.04 kB
| storybook-static/assets/story-board-GBWHbV_K.js
| 1.99 kB │ gzip: 0.89 kB
| storybook-static/assets/skeleton.stories-Dq2xvuJ_.js
| 2.10 kB │ gzip: 1.00 kB
| storybook-static/assets/story-page-Dw6AdeT9.js
| 2.13 kB │ gzip: 0.69 kB
| storybook-static/assets/verification-state-BC88p1ZF.js
| 2.15 kB │ gzip: 1.05 kB
| storybook-static/assets/hover-card.stories-Bh3l2dpe.js
| 2.34 kB │ gzip: 1.09 kB
| storybook-static/assets/alert-dialog.stories-CGb5RGim.js
| 2.48 kB │ gzip: 1.08 kB
| storybook-static/assets/separator.stories-BWtjCMgQ.js
| 2.56 kB │ gzip: 1.16 kB
| storybook-static/assets/dropdown-menu.stories-BGSwg2KO.js
| 2.58 kB │ gzip: 1.29 kB
| storybook-static/assets/badge.stories-C7oTwj2k.js
| 2.61 kB │ gzip: 1.23 kB
| storybook-static/assets/tooltip.stories-BPEd_H_I.js
| 2.65 kB │ gzip: 1.23 kB
| storybook-static/assets/publisher-regression.stories-CEknSZ4X.js
| 2.70 kB │ gzip: 1.15 kB
| storybook-static/assets/calendar.stories-CDN9mxN4.js
| 2.79 kB │ gzip: 1.30 kB
| storybook-static/assets/switch.stories-QO4IieTO.js
| 2.86 kB │ gzip: 1.28 kB
| storybook-static/assets/reference-CAnPEoPV.js
| 2.88 kB │ gzip: 1.24 kB
| storybook-static/assets/context-menu.stories-Oc31UkaS.js
| 2.95 kB │ gzip: 1.47 kB
| storybook-static/assets/center-shared-CAy6Ywyu.js
| 2.96 kB │ gzip: 1.36 kB
| storybook-static/assets/scroll-area.stories-CUTu_J3W.js
| 3.02 kB │ gzip: 1.30 kB
| storybook-static/assets/popover.stories-BUhDynt2.js
| 3.05 kB │ gzip: 1.30 kB
| storybook-static/assets/aspect-ratio.stories-BMMNpNOx.js
| 3.06 kB │ gzip: 1.51 kB
| storybook-static/assets/typography.stories-BQNl5UzS.js
| 3.07 kB │ gzip: 1.42 kB
| storybook-static/assets/pagination.stories-B3mMRcF9.js
| 3.12 kB │ gzip: 1.50 kB
| storybook-static/assets/alert.stories-Bpfea0DC.js
| 3.16 kB │ gzip: 1.30 kB
| storybook-static/assets/label.stories-yhROtKGf.js
| 3.19 kB │ gzip: 1.39 kB
| storybook-static/assets/collapsible.stories-C-tONiTQ.js
| 3.19 kB │ gzip: 1.50 kB
| storybook-static/assets/drawer.stories-UQ-fYs8P.js
| 3.23 kB │ gzip: 1.47 kB
| storybook-static/assets/radio-group.stories-CRxOEo0j.js
| 3.24 kB │ gzip: 1.47 kB
| storybook-static/assets/avatar.stories-C25lHWKC.js
| 3.30 kB │ gzip: 1.44 kB
| storybook-static/assets/page-header.stories-Cca60xSQ.js
| 3.32 kB │ gzip: 1.30 kB
| storybook-static/assets/menubar.stories-DpBcJw9T.js
| 3.33 kB │ gzip: 1.39 kB
| storybook-static/assets/command.stories-DzL402bG.js
| 3.33 kB │ gzip: 1.58 kB
| storybook-static/assets/center-overview.stories-CEWSyuc4.js
| 3.36 kB │ gzip: 1.77 kB
| storybook-static/assets/filter-bar.stories-CXLay5xk.js
| 3.43 kB │ gzip: 1.72 kB
| storybook-static/assets/sheet.stories-B6hlcis0.js
| 3.51 kB │ gzip: 1.44 kB
| storybook-static/assets/progress.stories-DUXjr1dD.js
| 3.52 kB │ gzip: 1.60 kB
| storybook-static/assets/breadcrumb.stories-BGljEtUL.js
| 3.55 kB │ gzip: 1.52 kB
| storybook-static/assets/card.stories-D9PU1M3e.js
| 3.74 kB │ gzip: 1.63 kB
| storybook-static/assets/navigation-menu.stories-aty95A-R.js
| 3.86 kB │ gzip: 1.62 kB
| storybook-static/assets/resizable.stories-RUyN8U34.js
| 3.96 kB │ gzip: 1.46 kB
| storybook-static/assets/specimens-DXXR0Cv1.js
| 4.13 kB │ gzip: 1.36 kB
| storybook-static/assets/sonner.stories-CJGIhpCk.js
| 4.22 kB │ gzip: 1.83 kB
| storybook-static/assets/checkbox.stories-BJELvagz.js
| 4.39 kB │ gzip: 1.66 kB
| storybook-static/assets/date-picker.stories-Mg8eAg-o.js
| 4.45 kB │ gzip: 1.68 kB
| storybook-static/assets/slider.stories-CCtXkumo.js
| 4.53 kB │ gzip: 1.86 kB
| storybook-static/assets/org-chart-page-previews-D8Bwno3s.js
| 4.70 kB │ gzip: 2.05 kB
| storybook-static/assets/carousel.stories-B9e7wXBD.js
| 4.75 kB │ gzip: 1.91 kB
| storybook-static/assets/layout.stories-Dn0rmVbC.js
| 4.79 kB │ gzip: 1.92 kB
| storybook-static/assets/table.stories-D0MAaypx.js
| 4.86 kB │ gzip: 2.02 kB
| storybook-static/assets/combobox.stories-Ciii4aa6.js
| 5.03 kB │ gzip: 2.07 kB
| storybook-static/assets/accordion.stories-dVthhhqA.js
| 5.05 kB │ gzip: 1.82 kB
| storybook-static/assets/OrgChart-DZlWXlj3-Cs1hDnbD.js
| 5.35 kB │ gzip: 1.95 kB
| storybook-static/assets/dialog.stories-CaHEQpaa.js
| 5.53 kB │ gzip: 2.13 kB
| storybook-static/assets/toggle.stories-gFZxA17G.js
| 5.81 kB │ gzip: 2.12 kB
| storybook-static/assets/data-table.stories-n73aBYUO.js
| 5.92 kB │ gzip: 2.52 kB
| storybook-static/assets/textarea.stories-rpRk5Jpl.js
| 5.99 kB │ gzip: 2.43 kB
| storybook-static/assets/runtime-loader.stories-BedrGYfx.js
| 6.18 kB │ gzip: 2.45 kB
| storybook-static/assets/toggle-group.stories-DtMpXk--.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-DBnPw4ZA.js
| 8.32 kB │ gzip: 3.05 kB
| storybook-static/assets/button.stories-BVQl4fat.js
| 9.65 kB │ gzip: 3.62 kB
| storybook-static/assets/select.stories-C43RzEnL.js
| 10.52 kB │ gzip: 3.39 kB
| storybook-static/assets/tabs.stories-D3ZKHlxd.js
| 11.57 kB │ gzip: 4.13 kB
| storybook-static/assets/org-chart.stories-gv5n3NPq.js
| 12.54 kB │ gzip: 4.15 kB
| storybook-static/assets/designer-theme.stories-1iYlo6i7.js
| 14.62 kB │ gzip: 5.52 kB
| storybook-static/assets/gnb.stories-Du_W3nke.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-S5renETM.js
| 23.06 kB │ gzip: 6.43 kB
| storybook-static/assets/dashboard-layout.stories-CQ13TQtR.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-C9ryFORc.js
| 61.92 kB │ gzip: 11.60 kB
| storybook-static/assets/org-chart-expanded.stories-ChqDNkXm.js
| 79.03 kB │ gzip: 10.07 kB
| storybook-static/assets/react-18-Dw6a0NoJ.js
| 207.62 kB │ gzip: 65.12 kB
| storybook-static/assets/core-component-preview-t5Y-0WSV.js
| 258.40 kB │ gzip: 146.05 kB
| storybook-static/assets/sw-header.stories-DbU2s6M2.js
| 755.29 kB │ gzip: 356.77 kB
| storybook-static/assets/reference-isdVcKCS.js
| 1,644.48 kB │ gzip: 270.35 kB
| storybook-static/assets/iframe-DaG6F32f.js
| 1,754.32 kB │ gzip: 503.65 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 4.65s
|
! Vite [PLUGIN_TIMINGS] JavaScript callbacks ran for 4.1s of this 4.6s
| build (89%).
| 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 (61%, 2.8s, 3104
| 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 (20 calls)
| - plugin vite:css transform (20 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
Whitespace-only changes.
@@ -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
@@ -0,0 +1,44 @@
{
"startCommit": "9482d45f340981c4b4ad6537cb678bf4afcdc681",
"branch": "feature/sw-package",
"swBefore": 24,
"swAfter": 24,
"repositoryBefore": 343,
"repositoryAfter": 343,
"originalRemovedIds": [
"sw-header--layer-dropdown",
"sw-header--color-dropdown",
"sw-header--line-style-dropdown",
"sw-header--text-dimension-style-dropdown"
],
"additionalRemovals": [],
"dropdownId": "sw-header--composed-controls",
"menu": "SW/Header > Dropdown",
"browser": {
"status": "PASS",
"checks": 232,
"errors": []
},
"swTypecheck": {
"exitCode": 0,
"log": "sw-typecheck.txt"
},
"swBuild": {
"exitCode": 0,
"via": "build-storybook prebuild",
"log": "storybook-build.txt"
},
"storybookTypecheck": {
"exitCode": 0,
"log": "storybook-typecheck.txt"
},
"storybookBuild": {
"exitCode": 0,
"log": "storybook-build.txt"
},
"missingReportLinks": [],
"sourceHashes": {
"src/sw/sw-header.stories.tsx": "8ed1f4fb79415ddce23537e9924da4c3c067d80f748f4117f9525a65e3897ce1",
"src/sw/sw-header-dropdown.stories.tsx": "d67275c1ed13890b2dd6046e71d42d0e340dc5f5bee4247ce25e8f5b36bf8d39"
}
}
@@ -1,5 +1,7 @@
# SW Storybook Dropdown 통합 — 2026-10-19
> 이 문서는 최초 통합 작업 당시의 기록입니다. 이후 확정된 메뉴는 **Header → Dropdown 단일 Story**이며 Composed Controls는 페이지 내부 그룹명입니다. 현재 기준과 검증은 [메뉴 계층 수정 보고서](sw-storybook-header-dropdown-page-2026-10-19.md)를 따릅니다. 아래 당시 결과와 증거는 보존합니다.
최종 판정: **PASS (PASS-A ~ PASS-J)**. 범위는 `STORYBOOK_ONLY`이며 제품 컴포넌트·공개 API·디자인·AI 템플릿은 변경하지 않았습니다. 신규 업무 화면 생성이 아니므로 Navigation/FilterBar 선택 및 AI 화면 생성 Guard는 적용 대상이 아닙니다.
- 작업 경로: `D:\디자인시스템\HMDesign-SW`
@@ -0,0 +1,90 @@
# SW Storybook Header → Dropdown 단일 페이지 — 2026-10-19
**판정: PASS.** 최종 메뉴는 `SW → Header → Dropdown`입니다. Dropdown은 Header 바로 아래의 Story이며 별도 폴더나 Composed Controls 하위 메뉴가 없습니다. 페이지 제목은 **Dropdown**, 내부 컨트롤 그룹의 제목과 접근성 이름은 **Composed Controls**입니다.
## 시작 상태와 범위
- 작업 경로: `D:\디자인시스템\HMDesign-SW`
- 브랜치: `feature/sw-package`
- 실제 시작 HEAD: `9482d45f340981c4b4ad6537cb678bf4afcdc681`, Working Tree clean.
- 요청에 기재된 `c165753bbe24de6581c66704bde4ba3246049ec2` 뒤에 직전 Dropdown 통합 로컬 Commit이 존재함을 확인했습니다. 기존 이력을 그대로 이어서 작업했습니다.
- 범위: `STORYBOOK_ONLY`. 신규 업무 화면 생성이 아니므로 AI 화면 생성 Guard·Navigation 선택은 적용하지 않았습니다.
- 이번 작업도 로컬 Commit만 생성하며 Push·PR·배포는 하지 않습니다. Commit SHA와 종료 상태는 완료 메시지에 기록합니다.
## 메뉴와 ID
`sw-header-dropdown.stories.tsx`의 CSF title을 `SW/Header`, 표시 이름을 `Dropdown`으로 변경했습니다. 기존 북마크와 테스트 경로를 유지하기 위해 export/ID는 그대로 유지합니다.
- 최종 Dropdown Story ID: **`sw-header--composed-controls`**
- 사용자에게 표시되는 메뉴: **Header → Dropdown**
- 페이지 내부 그룹: **Composed Controls**
- 변경된 Story ID: 없음.
- `SW/Header/Dropdown`에 속하는 현재 Story: 0개.
- 다른 Header Story의 ID·이름·태그·선언은 그대로입니다. 이전 메뉴 계층은 역사적 before index에서만 비교 대상으로 읽습니다.
6개 컨트롤은 기존 공개 `SWHeaderLayerMenu`, `SWHeaderColorMenu`, `SWHeaderLineStyleMenu`, `SWHeaderTextStyleMenu`, `SWHeaderDimensionStyleMenu`, `SWHeaderProperties`를 재사용합니다. 내부 그룹명은 기존 `StorySection`으로 표시하며 컨트롤의 Props·Callback·상태 로직은 변경하지 않았습니다. 상세보기는 기존 속성Bar·속성창 연결을 유지합니다.
## 삭제 전후 Story 목록
직전 통합 작업에서 삭제한 중복 Story 4개는 계속 미노출입니다. **이번 메뉴 계층 수정에서 추가로 삭제한 Story는 없습니다.**
- `sw-header--layer-dropdown`
- `sw-header--color-dropdown`
- `sw-header--line-style-dropdown`
- `sw-header--text-dimension-style-dropdown`
원래 기준 `c165753`에서는 SW Story **28 → 24**, 저장소 전체 **347 → 343**입니다. 이번 실제 시작 `9482d45` 기준으로는 SW **24 → 24**, 전체 **343 → 343**입니다.
이번 수정 전후의 유지 ID 24개는 동일합니다(접두사 `sw-header--`). `composed-controls`의 표시 이름·title만 변경했습니다.
- `overview`, `composed-controls`, `detail-buttons`, `interactive-states`, `window-move-motion`, `logo-slot`
- `document-dropdown`, `responsive-more`, `layer-detail-input`, `property-panel`, `property-panel-variants`, `k-guide`
- `additional-hover`, `property-bar`, `dynamic-controls`, `colorize`, `composition`
- `property-panel-none`, `property-panel-all`, `property-panel-circle`, `property-panel-expanded`, `property-panel-compare`, `property-shape-slot`, `property-fields`
Document Dropdown은 문서 관리, Detail Buttons는 공통 버튼 상태, Layer Detail · Input은 입력 편집, Responsive More는 반응형 전환 검증 목적이므로 보존했습니다. Property Bar/Panel, Window Move Motion 및 나머지 Header Story도 유지했습니다.
수정 전 목록은 직전 Commit에 대응하는 보존된 정적 빌드 index와 `git show HEAD`의 CSF 선언을 대조했습니다. 수정 과정에서 생성한 source index는 별도 `draft-source-index.json`으로 보존했고 최종 목록은 최종 Build index에서 확보했습니다.
## 검증 결과
- SW Typecheck: `npm.cmd run typecheck:sw` — PASS.
- SW Build: `npm.cmd run build-storybook`의 사전 `build:packages → build:sw` — PASS. 동일 SW Build를 별도로 중복 실행하지 않았습니다.
- Storybook Typecheck: `npm.cmd exec -- tsc -p tsconfig.app.json --noEmit` — PASS.
- Storybook Build: `npm.cmd run build-storybook` — PASS.
- 관련 Chrome 브라우저 Smoke: **232/232 PASS**, 콘솔/page 오류 0건.
- `git diff --check` 및 Commit 전 Staged Diff 검사 — PASS.
브라우저에서는 실제 manager의 Header 바로 아래 Dropdown 링크 1개, Composed Controls 링크 0개, 페이지 H1 Dropdown·그룹 H2/접근성 이름 Composed Controls를 확인했습니다. 6개 컨트롤과 기존 기본/사용자 색상·스타일 목록, 선택값 표시, Hover·Selected/On·Disabled, 각 Callback 1회, 다른 값 보존, Enter/방향키/Tab·Escape·외부 클릭 닫기·Focus 복귀를 검증했습니다.
390/768/1280/1440px에서 기존 필드 크기와 페이지 가로 overflow 0, 메뉴/상세 버튼의 실제 hit-test·Overlay 노출을 확인했습니다. 상세보기 속성Bar 28px·속성창 314px, 편집값 공유·닫기/Escape·Focus 복귀도 통과했습니다.
모든 유지 SW Story 24개의 실제 렌더링, Overview의 16:9 Stage와 Header 49px, Window Move Motion의 9개 3배 확대 단계를 확인했습니다. `packages/sw/src`, 공개 API·타입, CSS·SVG·이미지, `packages/sw/ai`, AI 템플릿 자료, Overview 구현과 기존 Story CSS·Storybook 설정은 변경하지 않았습니다.
추가 정적 비교에서는 조합 호스트의 상태·Callback 로직과 공개 SW 컴포넌트 JSX 8개가 직전 Commit과 동일함을 확인했습니다(배치 들여쓰기 제외). 기존 Overview 54개 전체 회귀는 직전 작업에서 통과했고 해당 소스/스타일이 동일하므로 반복하지 않았습니다. 이번에는 관련 렌더링·Stage/높이를 새로 확인했습니다.
Build의 기존 생성 CSS `var(...)`, chunk 크기·bundler timing 경고는 유지되며 Build 실패는 없습니다. 새 텍스트 로그는 끝 공백·EOF 빈줄만 정규화했고 원문은 새 QA 폴더의 로컬 `raw-logs/*.log`에 보존했습니다. 과거 QA 결과는 덮어쓰지 않았습니다.
## 변경 파일과 증거
- `src/sw/sw-header-dropdown.stories.tsx`: Header 바로 아래 Dropdown으로 메뉴 표시 수정, ID 보존.
- `src/sw/sw-header.stories.tsx`: 페이지 제목 Dropdown, 내부 Composed Controls 그룹 표시.
- `packages/sw/tests/dropdown-consolidation.browser.mjs`: 새 계층·내부 그룹·24개 보존 검증 및 실제 컨트롤 회귀 유지.
- `packages/sw/tests/storybook-inventory.mjs`: 승인된 표시 이름 변경을 historical baseline 비교에 반영.
- `packages/sw/tests/storybook-cleanup-stage1.browser.mjs`: 같은 이름 변경만 허용하도록 목록 비교 갱신.
- `docs/sw/sw-storybook-dropdown-consolidation-2026-10-19.md`: 이전 결과 상단에 현재 메뉴 기준 안내 추가, 당시 내용·증거 보존.
- 이 보고서와 `docs/sw/storybook-dropdown-page-qa/`의 신규 증거.
현재 ID가 유지되므로 다른 테스트의 URL을 변경할 필요는 없습니다. 과거 메뉴 계층은 역사적 문서·snapshot에 남기고 현재 기준을 새 보고서로 연결했습니다. 테스트를 제거하여 PASS로 처리하지 않았습니다.
- [수정 전 index](storybook-dropdown-page-qa/before-full-index.json)
- [수정 후 index](storybook-dropdown-page-qa/smoke/after-full-index.json)
- [Story 목록과 기존 삭제 4개](storybook-dropdown-page-qa/smoke/story-inventory.json)
- [브라우저 검증 232개](storybook-dropdown-page-qa/smoke/result.json)
- [상태·Callback·공개 컴포넌트 보존 비교](storybook-dropdown-page-qa/source-preservation.json)
- [실제 Header → Dropdown 메뉴 화면](storybook-dropdown-page-qa/smoke/composed-manager.png)
- [최종 Build 로그](storybook-dropdown-page-qa/storybook-build.txt)
## NOT VERIFIED
Firefox/Safari 전체 회귀, 모든 유지 Story의 모든 상호작용, 스크린리더 전수 검사 및 Figma 실시간 재대조는 이번에 실행하지 않았습니다. 제품 디자인과 기능은 기존 구현·CSS·자산 불변 및 관련 Chrome 동작으로 확인했습니다. 실제 CAD/OS/파일 작업은 기존 호스트 Callback 밖의 기능입니다.
@@ -6,20 +6,24 @@ import { execFileSync } from 'node:child_process'
import path from 'node:path'
import http from 'node:http'
import { parse } from '@babel/parser'
import { retiredDropdownIds, swStoryEntries, inventorySignature } from './storybook-inventory.mjs'
import { retiredDropdownIds, swStoryEntries, retainedInventory, inventorySignature } from './storybook-inventory.mjs'
const out = path.resolve(process.argv[2] ?? 'docs/sw/storybook-dropdown-consolidation-qa')
const out = path.resolve(process.argv[2] ?? 'docs/sw/storybook-dropdown-page-qa')
await mkdir(out, { recursive: true })
const report = { baseCommit: 'c165753bbe24de6581c66704bde4ba3246049ec2', checks: [], errors: [], callbacks: [], geometry: [] }
const check = (name, ok, data) => { report.checks.push({ name, status: ok ? 'PASS' : 'FAIL', data }); console.log(`${ok ? 'PASS' : 'FAIL'} ${name}${ok ? '' : ` ${JSON.stringify(data)}`}`) }
const before = JSON.parse(await readFile('docs/sw/storybook-dropdown-consolidation-qa/before-full-index.json', 'utf8'))
const after = JSON.parse(await readFile('storybook-static/index.json', 'utf8'))
const beforeSW = swStoryEntries(before), afterSW = swStoryEntries(after)
const previous = JSON.parse(await readFile('docs/sw/storybook-dropdown-page-qa/before-full-index.json', 'utf8'))
const previousSW = swStoryEntries(previous)
report.menuCorrectionBaseCommit = '9482d45f340981c4b4ad6537cb678bf4afcdc681'
await writeFile(path.join(out, 'after-full-index.json'), JSON.stringify(after, null, 2) + '\n')
await writeFile(path.join(out, 'story-inventory.json'), JSON.stringify({ before: beforeSW, after: afterSW, removed: beforeSW.filter(e => retiredDropdownIds.includes(e.id)) }, null, 2) + '\n')
check('28 -> 24 SW Stories, exactly four approved Dropdown retirements', beforeSW.length === 28 && afterSW.length === 24 &&
JSON.stringify(inventorySignature(beforeSW.filter(e => !retiredDropdownIds.includes(e.id)))) === JSON.stringify(inventorySignature(afterSW)))
check('Dropdown group has only Composed Controls with original ID', afterSW.filter(e => e.title === 'SW/Header/Dropdown').length === 1 && after.entries['sw-header--composed-controls']?.title === 'SW/Header/Dropdown')
JSON.stringify(inventorySignature(retainedInventory(beforeSW))) === JSON.stringify(inventorySignature(afterSW)))
check('Dropdown is one Story directly under Header with original ID, no Dropdown folder', afterSW.filter(e => e.name === 'Dropdown').length === 1 && after.entries['sw-header--composed-controls']?.title === 'SW/Header' && !afterSW.some(e => e.title.startsWith('SW/Header/')))
check('menu correction keeps all 24 IDs; only composed Story name/title change', previousSW.length === 24 && afterSW.length === 24 && JSON.stringify(inventorySignature(retainedInventory(previousSW))) === JSON.stringify(inventorySignature(afterSW)) && JSON.stringify(previousSW.filter(e => e.id !== 'sw-header--composed-controls')) === JSON.stringify(afterSW.filter(e => e.id !== 'sw-header--composed-controls')))
const nonSW = index => Object.values(index.entries).filter(e => !e.title.startsWith('SW/Header'))
check('all non-SW index entries identical', JSON.stringify(nonSW(before)) === JSON.stringify(nonSW(after)))
const sourcePath = 'src/sw/sw-header.stories.tsx'
@@ -72,6 +76,7 @@ try {
const events = name => report.callbacks.filter(line => line.startsWith(name)).length
const once = async (name, action) => { const previous = events(name); await action(); check(`${name} callback exactly once`, events(name) === previous + 1, report.callbacks.slice(-5)) }
const labels = ['레이어', '색상', '선스타일', '문자스타일', '치수스타일']
check('Dropdown page contains the Composed Controls group', await page.getByRole('heading', { name: 'Dropdown', level: 1, exact: true }).count() === 1 && await page.getByRole('heading', { name: 'Composed Controls', level: 2, exact: true }).count() === 1 && await page.getByRole('group', { name: 'Composed Controls', exact: true }).count() === 1)
if (process.argv[3] !== 'followup') {
check('one copy of five Dropdown fields and the details group', await host.locator('.hm-sw-header__field').count() === 5 && await host.getByRole('group', { name: '상세보기', exact: true }).count() === 1 && await field('속성Bar').count() === 1 && await field('속성창').count() === 1)
const hitTest = locator => locator.evaluate(e => {
@@ -98,7 +103,7 @@ try {
check(`${label} Escape closes and restores focus at ${width}`, await menu().count() === 0 && await trigger.evaluate(e => e === document.activeElement))
await trigger.click(); await trigger.click()
check(`${label} trigger toggles closed at ${width}`, await menu().count() === 0)
await trigger.click(); await page.getByRole('heading', { name: 'Composed Controls', exact: true }).click()
await trigger.click(); await page.getByRole('heading', { name: 'Dropdown', level: 1, exact: true }).click()
check(`${label} outside click closes at ${width}`, await menu().count() === 0)
}
await page.screenshot({ path: path.join(out, `composed-${width}.png`), fullPage: true })
@@ -248,8 +253,10 @@ try {
check('Window Move Motion retains only nine 3x steps', JSON.stringify(await page.locator('section > header h2').allTextContents()) === JSON.stringify(['단계별 진행 (3배 확대)']) && await page.locator('[data-motion-time]').count() === 9 && await page.locator('.sw-story-zoom').first().evaluate(e => getComputedStyle(e).zoom === '3'))
await page.goto(`${base}/?path=/story/sw-header--composed-controls`)
await page.locator('#storybook-preview-iframe').waitFor()
await page.getByRole('link', { name: 'Composed Controls', exact: true }).waitFor()
check('manager shows Dropdown group with the single Composed Controls page', await page.getByText('Dropdown', { exact: true }).isVisible() && await page.getByRole('link', { name: 'Composed Controls', exact: true }).count() === 1)
const dropdownLink = page.getByRole('link', { name: 'Dropdown', exact: true })
await dropdownLink.waitFor()
await dropdownLink.scrollIntoViewIfNeeded()
check('manager shows a single Dropdown link directly under Header, no Composed Controls submenu', await dropdownLink.count() === 1 && await dropdownLink.getAttribute('href') === '/?path=/story/sw-header--composed-controls' && await page.getByRole('link', { name: 'Composed Controls', exact: true }).count() === 0)
check('retired Dropdown links absent in manager', await page.locator(retiredDropdownIds.map(id => `a[href*="${id}"]`).join(',')).count() === 0)
await page.screenshot({ path: path.join(out, 'composed-manager.png'), fullPage: true })
check('no browser console or page errors', report.errors.length === 0, report.errors)
@@ -6,7 +6,7 @@ import { execFileSync } from 'node:child_process'
import path from 'node:path'
import http from 'node:http'
import { parse } from '@babel/parser'
import { swStoryEntries, retiredDropdownIds, inventorySignature } from './storybook-inventory.mjs'
import { swStoryEntries, retiredDropdownIds, retainedInventory, inventorySignature } from './storybook-inventory.mjs'
const out = path.resolve(process.argv[2] ?? 'docs/sw/storybook-cleanup-stage1-qa')
await mkdir(out, { recursive: true })
@@ -22,7 +22,7 @@ await writeFile(path.join(out, 'after-index.json'), JSON.stringify(after, null,
report.deleted = before.filter(e => !after.some(a => a.id === e.id)).map(e => ({ name: e.name, id: e.id }))
check('33 -> 24; precisely the approved stage-1 and Dropdown IDs removed', before.length === 33 && after.length === 24 &&
report.deleted.length === 9 && retired.every(id => report.deleted.some(e => e.id === id)), report.deleted)
check('all retained names, IDs and tags unchanged', JSON.stringify(inventorySignature(before.filter(e => !retired.includes(e.id)))) ===
check('retained names, IDs and tags preserved except approved Dropdown rename', JSON.stringify(inventorySignature(retainedInventory(before))) ===
JSON.stringify(inventorySignature(after)))
// Compare declaration text with the starting commit, including every retained fixture/helper.
@@ -1,6 +1,8 @@
// Current SW inventory after the approved stage-1 and Dropdown consolidations.
export const retiredStage1Ids = ['responsive', 'text-stroke', 'dynamic-data', 'default', 'controls'].map(id => `sw-header--${id}`)
export const retiredDropdownIds = ['layer-dropdown', 'color-dropdown', 'line-style-dropdown', 'text-dimension-style-dropdown'].map(id => `sw-header--${id}`)
// Include the old title when reading historical evidence; live hierarchy is asserted separately.
export const swStoryEntries = index => Object.values(index.entries).filter(entry => entry.type === 'story' && (entry.title === 'SW/Header' || entry.title === 'SW/Header/Dropdown'))
export const retainedInventory = entries => entries.filter(entry => ![...retiredStage1Ids, ...retiredDropdownIds].includes(entry.id))
.map(entry => entry.id === 'sw-header--composed-controls' ? { ...entry, name: 'Dropdown', title: 'SW/Header' } : entry)
export const inventorySignature = entries => entries.map(entry => [entry.id, entry.name, entry.tags]).sort((a, b) => a[0].localeCompare(b[0]))
+3 -3
View File
@@ -3,14 +3,14 @@ import { ComposedDemo } from "./sw-header.stories"
import "./sw-composed-controls.css"
const meta = {
title: "SW/Header/Dropdown",
// Keep existing bookmarks while placing the single example under Dropdown.
title: "SW/Header",
// Keep existing bookmarks; Dropdown is a Story directly under Header.
id: "sw-header",
parameters: { layout: "fullscreen", controls: { disable: true } },
} satisfies Meta
export default meta
export const ComposedControls: StoryObj<typeof meta> = {
name: "Composed Controls",
name: "Dropdown",
render: () => <ComposedDemo />,
}
+32 -30
View File
@@ -376,7 +376,7 @@ export function ComposedDemo() {
}
const panelProperties = properties.map(item => ({ ...item, disabled, ...(item.id === "layer" ? { options: availableLayers.map(layer => ({ ...layer, id: layer.name })) } : {}) }))
return <StoryPage className="sw-composed-controls">
<StoryPageHeader kicker={KICKER} title="Composed Controls" description="SW Header의 레이어·색상·선스타일·문자스타일·치수스타일과 상세보기를 직접 조작합니다. 메뉴의 상세 버튼은 기존 호스트 Callback을 호출하며 CAD 상세 화면은 생성하지 않습니다." />
<StoryPageHeader kicker={KICKER} title="Dropdown" description="SW Header의 레이어·색상·선스타일·문자스타일·치수스타일과 상세보기를 직접 조작합니다. 메뉴의 상세 버튼은 기존 호스트 Callback을 호출하며 CAD 상세 화면은 생성하지 않습니다." />
<details className="sw-composed-controls__settings">
<summary>시연 설정</summary>
<div className="sw-composed-controls__settings-content">
@@ -388,36 +388,38 @@ export function ComposedDemo() {
<label><input type="checkbox" checked={detailCallbacks} onChange={event => setDetailCallbacks(event.target.checked)} />메뉴 상세 Callback 연결</label>
</div>
</details>
<SWTheme>
<div className="sw-story-composed" role="group" aria-label="조합 컨트롤" data-composed-controls="">
<SWHeaderLayerMenu {...menuProps("layer")} value={{ name: value("layer") }} layers={availableLayers} activeLayerId={currentLayer?.id}
onLayerSelect={layer => change("layer", layer.name, "onLayerSelect")} onDetail={detail("Layer")}
onVisibilityChange={scenario === "normal" ? menus.onLayerVisibilityChange : undefined} onFreezeChange={scenario === "normal" ? menus.onLayerFreezeChange : undefined} onLockChange={scenario === "normal" ? menus.onLayerLockChange : undefined} />
<SWHeaderColorMenu {...menuProps("color")} value={{ value: colorMode === "byLayer" ? "ByLayer" : colorMode === "byBlock" ? "ByBlock" : value("color"), swatch: color?.hex }}
colors={FIGMA_COLORS} userColors={menus.userColors} mode={colorMode}
onColorSelect={item => change("color", item.value ?? parseSWHeaderColor(item.color)?.value ?? item.color, "onColorSelect")}
onColorInput={next => change("color", next.value, "onColorInput")} onModeChange={mode => { setColorMode(mode); record(`onColorModeChange(${mode})`) }}
onPick={() => record("onColorPick")} onDetail={detail("Color")} />
<SWHeaderLineStyleMenu {...menuProps("lineStyle")} value={{ name: value("line"), weight: currentWeight?.value === undefined ? currentWeight?.name ?? value("weight") : value("weight"), scale: value("scale") }}
lineTypes={FIGMA_LINE_TYPES} lineWeights={weights} activeLineWeightId={weightId}
onLineTypeSelect={item => change("line", item.name, "onLineTypeSelect")} onLineWeightSelect={chooseWeight} onLineWeightValueChange={changeWeight}
onScaleChange={next => change("scale", next, "onLineScaleChange")} onDetail={detail("LineStyle")} />
<SWHeaderTextStyleMenu {...menuProps("textStyle")} value={textStyle} textStyles={FIGMA_TEXT_STYLES}
onTextStyleSelect={item => { setTextStyle({ font: item.font, name: item.name }); record(`onTextStyleSelect(${item.id})`) }} onDetail={detail("TextStyle")} />
<SWHeaderDimensionStyleMenu {...menuProps("dimensionStyle")} value={dimensionStyle} dimensionStyles={FIGMA_DIMENSION_STYLES}
onDimensionStyleSelect={item => { setDimensionStyle({ name: item.name }); record(`onDimensionStyleSelect(${item.id})`) }} onDetail={detail("DimensionStyle")} />
<div ref={detailRef}>
<SWHeaderProperties disabled={disabled} barOpen={bar} panelOpen={panel} panelId={panelId}
onBarToggle={() => { setActiveMenu(null); setBar(next => !next); record(`onPropertyBarOpenChange(${!bar})`) }}
onPanelToggle={() => { setActiveMenu(null); setPanel(next => !next); record(`onPropertyPanelOpenChange(${!panel})`) }} />
<StorySection title="Composed Controls">
<SWTheme>
<div className="sw-story-composed" role="group" aria-label="Composed Controls" data-composed-controls="">
<SWHeaderLayerMenu {...menuProps("layer")} value={{ name: value("layer") }} layers={availableLayers} activeLayerId={currentLayer?.id}
onLayerSelect={layer => change("layer", layer.name, "onLayerSelect")} onDetail={detail("Layer")}
onVisibilityChange={scenario === "normal" ? menus.onLayerVisibilityChange : undefined} onFreezeChange={scenario === "normal" ? menus.onLayerFreezeChange : undefined} onLockChange={scenario === "normal" ? menus.onLayerLockChange : undefined} />
<SWHeaderColorMenu {...menuProps("color")} value={{ value: colorMode === "byLayer" ? "ByLayer" : colorMode === "byBlock" ? "ByBlock" : value("color"), swatch: color?.hex }}
colors={FIGMA_COLORS} userColors={menus.userColors} mode={colorMode}
onColorSelect={item => change("color", item.value ?? parseSWHeaderColor(item.color)?.value ?? item.color, "onColorSelect")}
onColorInput={next => change("color", next.value, "onColorInput")} onModeChange={mode => { setColorMode(mode); record(`onColorModeChange(${mode})`) }}
onPick={() => record("onColorPick")} onDetail={detail("Color")} />
<SWHeaderLineStyleMenu {...menuProps("lineStyle")} value={{ name: value("line"), weight: currentWeight?.value === undefined ? currentWeight?.name ?? value("weight") : value("weight"), scale: value("scale") }}
lineTypes={FIGMA_LINE_TYPES} lineWeights={weights} activeLineWeightId={weightId}
onLineTypeSelect={item => change("line", item.name, "onLineTypeSelect")} onLineWeightSelect={chooseWeight} onLineWeightValueChange={changeWeight}
onScaleChange={next => change("scale", next, "onLineScaleChange")} onDetail={detail("LineStyle")} />
<SWHeaderTextStyleMenu {...menuProps("textStyle")} value={textStyle} textStyles={FIGMA_TEXT_STYLES}
onTextStyleSelect={item => { setTextStyle({ font: item.font, name: item.name }); record(`onTextStyleSelect(${item.id})`) }} onDetail={detail("TextStyle")} />
<SWHeaderDimensionStyleMenu {...menuProps("dimensionStyle")} value={dimensionStyle} dimensionStyles={FIGMA_DIMENSION_STYLES}
onDimensionStyleSelect={item => { setDimensionStyle({ name: item.name }); record(`onDimensionStyleSelect(${item.id})`) }} onDetail={detail("DimensionStyle")} />
<div ref={detailRef}>
<SWHeaderProperties disabled={disabled} barOpen={bar} panelOpen={panel} panelId={panelId}
onBarToggle={() => { setActiveMenu(null); setBar(next => !next); record(`onPropertyBarOpenChange(${!bar})`) }}
onPanelToggle={() => { setActiveMenu(null); setPanel(next => !next); record(`onPropertyPanelOpenChange(${!panel})`) }} />
</div>
</div>
</div>
{bar && <SWHeaderPropertyBar selection={propertySelection("circle")} properties={panelProperties.filter(item => BAR_FIXTURE.some(barItem => barItem.id === item.id))}
onPropertyChange={(property, next) => change(property.id, next, "onPropertyChange")} />}
{panel && <SWHeaderPropertyPanel id={panelId} anchorRef={detailRef} selection={propertySelection("circle")} properties={panelProperties} groups={PROPERTY_GROUPS}
menus={{ ...menus, layers: availableLayers.map(layer => ({ ...layer, id: layer.name })) }}
onPropertyChange={(property, next) => change(property.id, next, "onPropertyChange")} onClose={closePanel} />}
</SWTheme>
{bar && <SWHeaderPropertyBar selection={propertySelection("circle")} properties={panelProperties.filter(item => BAR_FIXTURE.some(barItem => barItem.id === item.id))}
onPropertyChange={(property, next) => change(property.id, next, "onPropertyChange")} />}
{panel && <SWHeaderPropertyPanel id={panelId} anchorRef={detailRef} selection={propertySelection("circle")} properties={panelProperties} groups={PROPERTY_GROUPS}
menus={{ ...menus, layers: availableLayers.map(layer => ({ ...layer, id: layer.name })) }}
onPropertyChange={(property, next) => change(property.id, next, "onPropertyChange")} onClose={closePanel} />}
</SWTheme>
</StorySection>
<div className="sw-composed-controls__status">
<output data-style-state="">레이어: {value("layer")} · 색상: {colorMode ?? value("color")} · 선: {value("line")} / {value("weight")} / {value("scale")} · 문자: {textStyle.name} · 치수: {dimensionStyle.name}</output>
<output aria-live="polite" data-callback-log="">Callback: {log.length ? log.join(" → ") : "없음"}</output>