SW package 0.2.0 integrated improvement (Task A, steps 1-8). All new props are
optional; existing SW Stories are pixel-identical to the previous build (28/28).
- Build reproducibility: dist text normalized to LF, dist/build-info.json
(commit, dirty, tool versions, no timestamp), packages/sw/.gitattributes
(eol=lf). LF checkouts give identical dist and tarball.
- SWHeader: documentOpenPlacement ("menu" default | "header": Open right of
the logo in the existing document-button look, reusing onDocumentOpen and
documentOpenLabel, no duplicate Open in the dropdown), leading slot,
hiddenControls sub-items documentNew / documentOpen / layerFreeze /
layerLock. Open moves into More on measured overflow (with hysteresis).
- showNew / showOpen (SWHeaderDocumentTitle), showFreeze / showLock (layer
menu, field, property window list).
- SWToolButton (text / pill / document) and SWToolGroup (radio selection),
reusing the existing toggle, pill and file-name looks.
- SWPopup / SWPopupSection / SWPopupRow on the shared property window frame;
SWHeaderPropertyPanel gains children, title, autoFocus and optional
selection / properties / groups. Escape stack for several popups.
- Field dropdowns inside a popup use the shared fixed overlay
(useSWFixedDropdownPosition), so the scrolling body no longer clips them.
- AI guide, examples E/F, README, Storybook (SW/Header/Options, SW/Tool,
SW/Popup) and verification record docs/sw/sw-integrated-improvement-2026-10-19.md.
- Regression scripts rescoped for the intended changes (unused-removal 81/81,
overview 52/54 with the two pre-existing historical assertions).
Known limitation (unresolved): tools / leading content (incl. SWToolGroup)
does not move into More. With a wide tool bar the configured fields shrink
instead; in Example F the document name and layer field reach 0px at 390px.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
18 KiB
@hm-design/sw 컴포넌트 카탈로그
기준: @hm-design/sw 0.2.0, dist/index.d.ts 공개 Export(2026-10-19 통합 개선 반영). 출처 Commit·빌드 도구 버전은 dist/build-info.json에 있습니다. 모든 Import는 from "@hm-design/sw"이며 CSS는 @hm-design/sw/styles.css 한 개입니다. 이 표에 없는 이름은 공개 API가 아닙니다.
- 단독 사용:
SWHeader밖에서는<SWTheme>안에 둡니다(토큰·글꼴·버튼 초기화). - 상태 소유: 값은 Props, 사용자 행동은 Callback입니다. 컴포넌트는 CAD 데이터를 바꾸지 않습니다. 호스트가 Callback을 받아 Props를 갱신합니다.
- 열림 상태: Dropdown은
open/onOpenChange(Controlled)를 주지 않으면 내부 상태로 동작합니다. - 공통 키보드: Click·Enter·Space 열기/닫기(Hover로는 열리지 않음), ArrowDown 열고 첫(현재) 항목 Focus, Arrow 이동, Escape·바깥 클릭·Tab 이탈 닫기(Escape는 Trigger로 Focus 복귀).
- 검증 표시: ✅ = 2026-10-19 독립 소비 프로젝트(Tarball 설치)에서 브라우저 검증, ◻ = 소비 검증 범위 밖(Storybook 검증 기록만 있음).
- 무엇을 쓸까: Header 전체 →
SWHeader(1). Header 부품 조합 → 개별 컨트롤(2). 팝업·설정창·정보창 →SWPopup(3). 도구 막대·탭·토글 →SWToolButton/SWToolGroup(4). Slider·Switch·Badge·Progress·Dialog(모달)·Label·FilterBar는 SW에 없습니다 →@hm-design/ui를 그대로 씁니다(필요하면SWPopupchildren 안에).
1. 완성형 템플릿
SWHeader ✅
SW 공식 기준 Header(Figma 26:8944, 1920 × 49). 로고 · 파일 · 객체 수정 영역(그리기모드, 레이어/색상/선/문자/치수스타일, 상세보기) · 창 영역(인쇄·K, 창 이동, 최소화, 종료)과 반응형 More, 속성Bar, 속성창을 포함합니다.
| 구분 | Props / Callback |
|---|---|
| 필수 | documentTitle: string |
| 구성 | hiddenControls?: SWHeaderHideableControlId[](로고 외 부품 제거, home 제거 시 정적 로고. 하위 항목 documentNew·documentOpen·layerFreeze·layerLock도 제거 — 레이아웃 변화 없음), menuOrder?: SWHeaderMenuId[](5개 메뉴끼리 순서), controls?: SWHeaderControlConfig[](객체 영역 전체 allowlist·순서·label) |
| 로고 오른쪽 | documentOpenPlacement?: "menu" | "header"(기본 menu = 기존 Dropdown 하단. header = 로고 바로 오른쪽에 파일명과 같은 면의 Open 버튼, Dropdown의 Open은 숨김. 둘 다 onDocumentOpen·documentOpenLabel), leading?: ReactNode(Open 뒤·파일명 앞 추가 부품, 예: SWToolButton appearance="document") |
| 로고 | logo?: ReactNode, logoSrc?: string, logoAlt?: string, onHomeClick |
| 파일 | documents, activeDocumentId, documentMenuOpen, onDocumentMenuOpenChange, onDocumentSelect, onDocumentClose, onDocumentNew, onDocumentOpen, onDocumentClick, documentIcon, documentNewLabel, documentOpenLabel |
| 레이어 | layer, layers, activeLayerId, layerMenuOpen, onLayerMenuOpenChange, onLayerSelect, onLayerVisibilityChange, onLayerFreezeChange, onLayerLockChange, onLayerDetail, onLayerOpen |
| 색상 | color, colors, userColors, colorMode, colorMenuOpen, onColorMenuOpenChange, onColorSelect, onColorModeChange, onColorInput, onColorPick, onColorDetail, onColorOpen |
| 선스타일 | lineStyle, lineTypes, lineWeights, activeLineTypeId, activeLineWeightId, lineStyleMenuOpen, onLineStyleMenuOpenChange, onLineTypeSelect, onLineWeightSelect, onLineWeightValueChange, onLineScaleChange, onLineStyleDetail, onLineStyleOpen |
| 문자/치수 | textStyle, textStyles, activeTextStyleId, textStyleMenuOpen, onTextStyleMenuOpenChange, onTextStyleSelect, onTextStyleDetail, onTextStyleOpen / dimensionStyle, dimensionStyles, activeDimensionStyleId, dimensionStyleMenuOpen, onDimensionStyleMenuOpenChange, onDimensionStyleSelect, onDimensionStyleDetail, onDimensionStyleOpen |
| 상세 | propertyBar, propertyBarOpen, defaultPropertyBarOpen, onPropertyBarOpenChange, onPropertyBarToggle, propertyPanel, propertyPanelOpen, onPropertyPanelOpenChange, onPropertyPanelToggle |
| 창 | onPrint, onPopupGuide, onWindowMoveStart(PointerEvent), onMinimize, onClose |
| 기타 | activeMenu, disabled(창 버튼 제외), drawingModeLabel, tools?: ReactNode(객체 영역 메뉴 뒤), <header> HTML 속성·ref |
- 데이터 배열(
layers,colors,lineTypes/lineWeights,textStyles,dimensionStyles,documents)을 주지 않으면 해당 필드는 Dropdown 없는 버튼입니다. - 반응형(More·대표 필드 전환·창 영역 축소)은
SWHeader안에서만 동작합니다(CSS containerhm-sw-header). 조합형 구성이 반응형이어야 하면controls+documentOpenPlacement+leading+tools로SWHeader안에서 구성합니다(예제 F). - 로고 옆 Open은 실제 공간을 측정해 넘칠 때만 More로 이동하고, 그 시점보다 Open 폭만큼 넓어지면 돌아옵니다. Open이 보이는 동안 파일명이 먼저 줄고 레이어 필드는 Figma 폭을 유지합니다.
<SWHeader documentTitle={name} logoSrc={logo} logoAlt="제품명" layers={layers} activeLayerId={id} onLayerSelect={l => setId(l.id)} onClose={closeWindow} />
2. 개별 컨트롤 (조합용)
| 컴포넌트 | 용도 | 주요 Props / Callback | 크기(Figma) | 상태 | 검증 |
|---|---|---|---|---|---|
SWTheme |
단독 사용 범위(토큰·글꼴·초기화). 배치는 정하지 않음 | div HTML 속성, className, style(토큰 override) |
— | — | ✅ |
SWHeaderHome |
로고 슬롯 + 홈 버튼 | logo, logoSrc, logoAlt, onClick, interactive(false = 정적 로고) |
80 × 48, 로고 슬롯 32 × 17, 오른쪽 −17px로 다음 파일 면과 겹침 | Hover 배경 교체, Focus | ✅ |
SWHeaderDocumentTitle |
파일명 + 문서 Dropdown(+ New / Open) | title(필수), documents, activeDocumentId, menuOpen, onMenuOpenChange, onDocumentSelect, onDocumentClose, onNew, onOpen, onClick, documentIcon, newLabel, openLabel, label, showNew / showOpen(기본 true, 둘 다 false면 하단 없음) |
높이 48, 폭 190–310(반응형 clamp), 메뉴 310 | 텍스트만 Hover #FFC600, 열림 화살표 회전 | ✅ |
SWHeaderLayerMenu |
레이어 필드 + Dropdown | value(필수), layers(필수), activeLayerId, open, onOpenChange, onClick, selected, disabled, onLayerSelect, onVisibilityChange, onFreezeChange, onLockChange, onDetail, label, showFreeze / showLock(기본 true. false = 그 상태를 그리지 않고 20px 자리만 유지) |
필드 234 × 38, 메뉴 234 | Hover 링, Selected, Expanded, 행 Hover | ✅ |
SWHeaderColorMenu |
색상 필드 + Dropdown(ByLayer/ByBlock, 팔레트, 사용자 색, 추출, RGB 입력) | value, colors(필수), userColors, mode, open, onOpenChange, onClick, selected, disabled, onColorSelect, onModeChange, onColorInput, onPick, onDetail, label |
필드 192 × 38 | 칩 선택 시 열림 유지 | ✅ |
SWHeaderLineStyleMenu |
선스타일 필드 + 3열 Dropdown | value, lineTypes, lineWeights, activeLineTypeId, activeLineWeightId, open, onOpenChange, onClick, selected, disabled, onLineTypeSelect, onLineWeightSelect, onLineWeightValueChange, onScaleChange, onDetail, label |
필드 284 × 38, 열 182·142·142(필드 중앙 정렬) | 열별 선택, 열림 유지 | ✅ |
SWHeaderTextStyleMenu |
문자스타일 필드 + 목록 | value, textStyles(필수), activeTextStyleId, onTextStyleSelect, open, onOpenChange, onClick, selected, disabled, onDetail, label |
필드 164 × 38 | 선택 시 닫힘 | ✅ |
SWHeaderDimensionStyleMenu |
치수스타일 필드 + 목록 | value, dimensionStyles(필수), activeDimensionStyleId, onDimensionStyleSelect, 열림·onDetail·label 동일 |
필드 164 × 38 | 선택 시 닫힘 | ✅ |
SWHeaderLayerControl · SWHeaderColorControl · SWHeaderLineStyle · SWHeaderTextStyle · SWHeaderDimensionStyle |
Dropdown 없는 필드 버튼(호스트가 자체 팝업을 열 때) | value(필수), label, selected, disabled, onClick, expanded, controls, buttonRef / SWHeaderLayerControl은 state(표시·동결·잠금), showFreeze / showLock |
위 필드 크기와 같음 | Hover 링, Selected | ◻ |
SWHeaderActions |
인쇄·K 버튼 pill | onPrint, onPopupGuide, disabled, showPrint, showPopupGuide(하나만 남기면 pill이 축소) |
pill 85 × 42(버튼 40 × 38) | 아이콘 Hover, Hover 링, K 가이드 미리보기(반복 Motion, Reduced Motion 정적) | ✅ |
SWHeaderWindowControls |
창 이동·최소화·종료 | onWindowMoveStart, onMinimize, onClose, showWindowMove, showMinimize, showClose |
이동 88 × 48, 버튼 32 × 48 | 창 이동 Hover Motion 1.4s, 종료 Hover 자산 | ◻ |
SWHeaderProperties |
상세보기 / 속성Bar · 속성창 토글 | barOpen, panelOpen, panelId, disabled, onBarToggle, onPanelToggle, showCaption, showBar, showPanel |
157 × 38 | 텍스트 Hover #FFC600 | ◻ |
SWHeaderPropertyBar |
28px 속성 편집 띠 | selection, properties, onPropertyChange, readOnly, disabled, div 속성 |
높이 28, 콘텐츠 폭 | Input 상태 | ◻ |
SWHeaderPropertyPanel |
데이터 기반 속성창(필드 타입 6종 text·number·select·color·slider·computed + picker, 그룹 레이아웃 rows·circle·position, 형상 Slot) |
selection·properties·groups(0.2.0부터 선택), title, children(그룹 뒤 자유 콘텐츠), autoFocus, onPropertyChange, menus(showLayerFreeze/showLayerLock 포함), expandedGroupIds/defaultExpandedGroupIds/onExpandedGroupsChange, toolActive/onToolActiveChange, toolLabel, onOverviewClick, shapeContent, onClose, id, anchorRef, style |
314 폭, 높이는 콘텐츠(최대 화면, 본문 스크롤). anchorRef가 있으면 고정 위치 Overlay, 없으면 문서 흐름(위치는 style) |
4가지 선택 상태 | ✅ |
SWHeaderInput |
수정 가능한 SW Input | value(필수), onValueChange, onCommit(Enter·Blur, 유효 + 변경 시), onCancel(Escape 복원), valueType(text/number), parse, readOnly, disabled, commitOnUnmount, input 속성 |
58 × 20 기준, Hover/편집 24px | Default/Hover/편집/ReadOnly/Disabled, IME 조합 중 Enter 무시 | ✅ |
parseSWHeaderColor · parseSWHeaderNumber |
Input 검증 도우미 | r,g,b / #rrggbb, 숫자(min, max) |
— | — | ◻ |
SWHeaderLinePreview · swHeaderLinePatterns |
70 × 2 선 미리보기, CENTER/HIDDEN 패턴 | pattern?: number[] |
70 × 2 | — | ◻(패턴 상수만 예제 데이터에서 사용) |
3. Popup — 외형 고정, 콘텐츠 자유
속성창(Figma 26:11822)의 외형과 공통 동작을 그대로 쓰는 Popup입니다. Header 없이 <SWTheme> 안에서 씁니다. 내용은 children으로 자유롭게 구성합니다(SW 컨트롤, @hm-design/ui 컴포넌트, 소비 프로젝트 요소 모두 가능, 구조 제한 없음).
| 컴포넌트 | 용도 | 주요 Props | 크기·동작 | 검증 |
|---|---|---|---|---|
SWPopup |
설정·정보·사용자 정의 Popup 프레임 | title(필수), children, onClose(닫기 버튼·Escape), closeLabel(기본 닫기), autoFocus(열릴 때 Focus, 안에서 닫히면 원래 위치로 복귀), anchorRef(기준 요소 아래 고정 Overlay), style·className·div 속성 |
폭 314, 제목줄 30, 높이는 콘텐츠(최대 화면 − 8px, style.maxHeight로 더 줄일 수 있음) → 본문 스크롤. Non-modal(Dim·Portal·Focus trap 없음) |
✅ |
SWPopupSection |
속성창 그룹 면(제목 + 내용) | title, children, section 속성 |
그룹 제목 700·70% 검정, 내용 면 --hm-sw-property-content |
✅ |
SWPopupRow |
속성창 한 줄(라벨 + 값) | label(필수), htmlFor, children(값 컨트롤, SW 필드는 SWHeaderInput), unit, field(box 기본 · compact · none), numeric(숫자 편집 On), readOnly, disabled |
행 최소 32, 라벨 72, 값 상자 28(Default·Hover 테두리, 숫자 편집 시 #0F0D0A). compact = 41px hug 숫자 필드 |
✅ |
SWHeaderPropertyPanel |
데이터 기반 속성창(2절). 같은 프레임이며 children도 받음 |
2절 | 같은 DOM·class | ✅ |
- Escape·Focus: Popup 안의 Escape는 그 Popup만 닫습니다. 바깥의 Escape는 가장 최근에 열리거나 사용한(Focus·클릭) Popup 하나만 닫습니다. Dropdown·편집 중인 Input처럼 Escape를 이미 처리한 요소(
preventDefault/ 전파 중단)가 있으면 Popup은 닫히지 않습니다. - Popup 안 SW Dropdown: 레이어·색상·선·문자·치수 Dropdown은 Popup 안에서 고정 위치 Overlay로 열려 스크롤 본문에 잘리지 않습니다(아래에 자리가 없으면 위로 열림). 단, Header용 어두운 필드 모양 그대로이므로 밝은 Popup 면과 대비가 다릅니다. 속성창 행 모양의 선택 필드가 필요하면
SWHeaderPropertyPanel의picker속성(properties)을 씁니다. - Popup 하단 버튼(적용·취소)의 SW 전용 디자인은 아직 없습니다. 필요하면 소비 프로젝트 버튼이나
@hm-design/ui의Button을children에 둡니다. 어두운SWToolButton을 밝은 Popup에 강제로 쓰지 않습니다.
4. 도구 막대 — 기존 SW 버튼 3종
새 디자인 값 없이 기존 SW 버튼 모양을 공개 버튼으로 씁니다(뷰어의 Model/Layout, Fit, 2.5D, 파일 열기 등). SWHeader의 tools·leading 안이나 <SWTheme> 안에 둡니다.
| 컴포넌트 | 용도 | 주요 Props | 모양(기존 기준) | 검증 |
|---|---|---|---|---|
SWToolButton |
버튼·토글 | appearance(text 기본 / pill / document), pressed(토글·선택), children(글자. pill은 접근성 이름으로만 사용), icon·hoverIcon(pill), button 속성 |
text = 속성Bar·속성창 글자 토글(700, Hover·선택 #FFC600, 행 19px). pill = 인쇄·K 40 × 38(노란 Hover 링, 아이콘 24 × 23 영역). document = 파일명 면(48px, 글자만 Hover #FFC600). Home 바로 뒤에 두면 로고 사선 접점을 그대로 공유 |
✅ |
SWToolGroup |
버튼 묶음 | appearance(text 기본 = 상세보기 묶음, pill = 인쇄·K pill), label(text의 12px 캡션·접근성 이름), selection(single = radiogroup, 화살표·Home·End로 이동·선택), div 속성 |
버튼 사이 1px 구분선(text), 내용 폭 pill |
✅ |
- 탭(Model / Layout)은 별도 컴포넌트 없이
SWToolGroup selection="single"+SWToolButton pressed입니다. - 상태 표시(로드 상태 등) 전용 SW 디자인은 아직 없습니다(상태 표시 컴포넌트는 디자인 확정 후 검토).
5. 공개 타입
SWHeaderProps, 각 컴포넌트 *Props, SWThemeProps, SWPopupProps, SWPopupSectionProps, SWPopupRowProps, SWToolButtonProps, SWToolButtonAppearance, SWToolGroupProps, SWHeaderMenuId, SWHeaderControlId, SWHeaderControlConfig, SWHeaderFrameControlId, SWHeaderSubControlId, SWHeaderHideableControlId, SWHeaderDocument, SWHeaderLayer, SWHeaderLayerValue, SWHeaderColorValue, SWHeaderColorOption, SWHeaderColorMode, SWHeaderColorInputValue, SWHeaderLineStyleValue, SWHeaderLineType, SWHeaderLineWeight, SWHeaderTextStyleValue, SWHeaderTextStyleOption, SWHeaderDimensionStyleValue, SWHeaderDimensionStyleOption, SWHeaderInputValueType, SWHeaderProperty, SWHeaderPropertyType, SWHeaderPropertyPicker, SWHeaderPropertyMenus, SWHeaderPropertyGroup, SWHeaderPropertySelection, SWHeaderPropertyShapeContent, SWHeaderPropertyShapeContext.
6. 공개하지 않은 것 (사용 금지)
SWHeaderMore, SWHeaderField/SWHeaderFieldText, SWHeaderKGuide, useSWHeaderDropdown, SWHeaderMenuDetail, SWHeaderColorChip, SWHeaderLayerRows, SWHeaderColorPanelBody, SWHeaderLineStyleColumns, SWPopupFrame, useSWFixedDropdownPosition, 속성창 내부 Picker, useSWHeaderOverlay 등은 내부 구현입니다. 필요하면 공개 컴포넌트로 대체하거나, 부족한 API로 보고합니다.
7. 알려진 단독 사용 제약
| 항목 | 내용 | 대응 |
|---|---|---|
| 반응형 More | SWHeader 전용. SWTheme로 직접 배치한 조합 Header에는 More·필드 이동이 없음 |
반응형이 필요하면 SWHeader의 controls·documentOpenPlacement·leading·tools로 구성(예제 F). 직접 배치하면 폭은 소비 앱이 정함 |
SWHeaderDocumentTitle 왼쪽 테두리 |
앞의 로고와 겹치는 전제로 왼쪽 테두리가 없음 | 로고 없이 첫 칸이면 소비 레이아웃 wrapper에 1px 테두리(예제 C) |
SWHeaderDocumentTitle 폭 |
clamp(190px, 100cqw − 1610px, 310px); Header 밖에서는 cqw가 뷰포트 기준 |
flex 부모 안에 둔다. 1920 뷰포트에서 310px |
| 창 영역 배경 | 배경·테두리는 SWHeader의 창 영역에 있음 |
소비 레이아웃이 토큰으로 표면 작성(예제 B·C) |
| Dropdown 위치 | SWHeader 안이면 헤더, 밖이면 뷰포트 안으로 좌우 보정. SWPopup·속성창 안이면 고정 위치 Overlay |
Popup 밖에서는 부모에 overflow: hidden을 두지 않는다 |
| 파일 열기 뒤 파일명 여백 | SWToolButton appearance="document" 바로 뒤의 파일명은 왼쪽 여백 12px(로고 아래가 아니므로) |
패키지 CSS가 처리. 소비 코드에서 조정하지 않음 |