- AI_USAGE §5: single rule for design-based header tools (icon priority 1-3, Storybook fixtures vs public API, pill icon states, window control omission via hiddenControls, existing-screen preservation, web/desktop) - Reference §5 from AI_GUIDE (+4 synced copies), COMPOSITION_PATTERNS, COMPONENT_CATALOG, DESIGN_RULES §9 - Process header spec §13: Figma tool icon export on hold, proposed swProcessToolIcons and preconditions (no source/API change)
39 KiB
@hm-design/sw — AI 코딩 도구 사용 안내
이 폴더(node_modules/@hm-design/sw/ai/)는 다른 React 프로젝트에서 AI 코딩 도구가 SW 패키지를 재사용·조합·확장할 때 먼저 읽는 안내서입니다. 패키지 자체에는 AI 기능이 없습니다. 아래 문서는 실제 공개 API와 CSS에서 확인한 값만 적습니다.
먼저 AI_GUIDE.md(HMDesign 공통: 사용 유형 Web / SW 일반·뷰어 / OrgChart / 혼합 확인, 작업 1~7단계, 패키지 분리, 결과 보고)를 읽고 사용 유형이 SW 또는 SW가 포함된 혼합일 때 이 폴더를 씁니다.
| 문서 | 내용 |
|---|---|
| AI_GUIDE.md | HMDesign 공통 진입점(모든 HMDesign 패키지에 같은 사본) |
| COMPONENT_CATALOG.md | 공식 공개 컴포넌트(일반 모드: Header·개별 컨트롤·Popup·도구 막대·로고 클릭 메뉴 / 뷰어 모드 §9: SWViewer* 전체 Export)·Props·Callback·크기·CSS 의존성 |
| DESIGN_RULES.md | SW 전용 토큰·Typography·간격·Hover/Focus/Selected·Overlay·Motion·반응형·Popup 외형·도구 버튼·로고 클릭 메뉴(일반 모드 §1~10·§12), 뷰어 토큰·상태값 요약(§11) |
| COMPOSITION_PATTERNS.md | 완성형·간소화·기능 중심·확장 Header, Popup(자유 콘텐츠), 일반 모드 Header + 도구 막대(1~6), 뷰어 모드 기본 조합(7) |
| examples/ | 공개 API만 쓰는 예제 AExampleA-DefaultHeader.tsx), B 간소화 Header(ExampleB-ViewerHeader.tsx), C 기능 중심 Header(ExampleC-FeatureHeader.tsx), D 신규 컨트롤 확장(ExampleD-SearchExtension.tsx), E 사용자 정의 Popup(ExampleE-CustomPopup.tsx), F 파일 열기 + 도구 막대(ExampleF-ViewerToolbar.tsx), G 로고 클릭 메뉴(ExampleG-HomeMenu.tsx), I Footer(ExampleI-Footer.tsx). A~F는 독립 소비 프로젝트에서 Typecheck·Build·브라우저 검증. B·F 파일명의 "Viewer"는 과거 이름이며 일반 모드 SWHeader 구성. 뷰어 모드 H(ExampleH-ViewerMode.tsx, SWViewer*). 두 모드 공통 J 테마 토큰 설정(ExampleJ-Theme.tsx, §3.1) |
| FOOTER.md | 일반 모드 하단 막대: SWFooter(보조기능·바 안 명령창·명령 칸·분류 탭·명령어 전체보기), SWFooterLayoutTabs(Model/Layout 탭), SWFooterCommandLine(명령창). AI 작업 순서 1~6 |
| VIEWER.md | 뷰어 모드 전용: SWViewerHeader(데이터 메뉴·More·외곽선·로고 규칙), SWViewerMenu(Dropdown·서브메뉴·우클릭), SWViewerPanel(팝업 프레임 + 자유 콘텐츠). 일반 SW 모드는 SWHeader·SWPopup을 그대로 씁니다 |
0. SW 모드 선택 — SW 일반 모드 / SW 뷰어 모드 (코드 작성 전에 결정)
SW 패키지에는 Header·Popup 계열이 두 벌 있습니다. 화면마다 하나의 모드를 고르고 그 모드의 컴포넌트만 씁니다. 공통 사용 유형 확인(Web / SW / OrgChart / 혼합)은 AI_GUIDE.md를 따르고, 사용 유형이 SW로 정해진 뒤 이 절로 모드를 정합니다.
0.1 판단 순서
-
소비 프로젝트 설정:
AGENTS.md·CLAUDE.md등에HMDesign 사용 유형: SW 일반또는HMDesign 사용 유형: SW 뷰어가 있으면 그 모드를 씁니다. 혼합(영역별)이면 SW 영역에 적힌 모드를 씁니다. -
요청 문구: 설정이 없거나
SW만 적혀 있으면 요청을 봅니다.- 뷰어 모드 근거: "뷰어", "DWG/DXF 보기", "도면 뷰어", "도면 보기·열람", "읽기 전용", 도면 공간(Model/Layout) 탭·전체 보기·레이어/설정 패널 토글·불러오기 상태가 중심.
- 일반 모드 근거: "편집", "그리기"(그리기모드), "객체 수정", 레이어·색상·선스타일·문자/치수스타일 값 편집, 속성Bar·"속성창" 편집이 중심.
- 근거가 한쪽에만 있고 분명할 때만 그 모드로 정합니다. 양쪽 근거가 섞여 있거나 하나라도 애매하면(예: "도면 화면", "CAD 화면 상단", "레이어 보기") 추측하지 않습니다.
-
그래도 모르면 코드 작성 전에 그대로 묻습니다.
SW 화면을 어떤 모드로 만들까요?
- SW 일반 모드(편집용
SWHeader·SWPopup) - SW 뷰어 모드(
SWViewerHeader·SWViewerMenu·SWViewerPanel)
- SW 일반 모드(편집용
-
설정·요청·이전 답변으로 모드가 이미 명확하면 다시 묻지 않습니다. 결과 보고에 정한 모드와 근거(설정 값 / 요청 문구 / 사용자 답변)를 적습니다(§4).
0.2 모드별 컴포넌트와 읽을 문서
| 구분 | SW 일반 모드 | SW 뷰어 모드 |
|---|---|---|
| 용도 | 설치형·도면 편집 SW 상단: 그리기모드, 레이어·색상·선/문자/치수스타일 선택, 속성Bar·속성창 | 도면 보기 화면 상단: 파일 열기·샘플, 도면 공간(Model/Layout) 탭, 전체 보기, 2.5D·배경 스위치, 레이어·설정·속성 패널 토글, 불러오기 상태 |
| 기준 | Figma 이지빔 SW 26:8944, 49px |
참고 DWG/DXF 뷰어 실측(1440px), 52px |
| Header | SWHeader, 또는 <SWTheme> 안의 개별 컨트롤(SWHeaderHome, SWHeaderDocumentTitle, SWHeaderLayerMenu, SWHeaderColorMenu, SWHeaderLineStyleMenu, SWHeaderTextStyleMenu, SWHeaderDimensionStyleMenu, SWHeaderActions, SWHeaderWindowControls, SWHeaderProperties …) |
SWViewerHeader(groups 데이터 + trailing), 오른쪽 끝·custom 버튼 SWViewerHeaderButton, 상태 SWViewerStatus |
| Dropdown | 각 필드 Dropdown(SWHeaderLayerMenu …) |
type: "menu" 항목, 단독·우클릭은 SWViewerMenu |
| 팝업·설정창 | SWPopup(titleActions, footer) + SWPopupSection / SWPopupRow + SWHeaderInput, 레이어·색상 행 SWPopupPropertyRow(Header 필드 Dropdown은 Header 전용), 게이지바 SWSlider(appearance), 선택 목록 SWSelect, 속성창 SWHeaderPropertyPanel, 속성Bar SWHeaderPropertyBar |
SWViewerPanel(이동·크기 조절·접기·modal, headerActions, footer) + SWViewerSection / SWViewerField / SWViewerSwitch / SWViewerInput / SWViewerButton / SWViewerBadge / SWViewerHint, 옵션 패널 게이지는 SWSlider appearance="property"(스타일 B, SWViewerSlider 아님), 선택 목록 SWSelect(뷰어 패널 토큰으로 표시) |
| 로고(홈) 버튼 메뉴 | SWHeader의 homeMenu(SWHomeMenu 데이터, 최근파일 SWRecentFiles, Figma 26:10591). 기본 숨김 → 로고 클릭 열기 → 다시 클릭 닫기 |
사용하지 않음. SWViewerHeader에는 홈 메뉴 Props가 없고 로고 클릭은 onHomeClick만 호출합니다. 파일 열기는 로고 오른쪽 버튼(onDocumentOpen·documentOpenLabel), 샘플 목록은 파일명 클릭 목록(documents·activeDocumentId·onDocumentSelect)이며 groups 항목으로 만들지 않습니다(VIEWER.md §2) |
| 하단 Footer | SWFooter(+ 바 안 명령창 command={<SWFooterCommandLine />}, 좌표 status, SWFooterLayoutTabs, 부품 SWFooter*), FOOTER.md |
사용하지 않음. 뷰어 화면에는 하단 명령 막대가 없습니다. 도면 공간 탭은 SWViewerHeader의 tabs 항목 |
| 버튼·탭·토글 | SWToolButton / SWToolGroup |
Header 항목 type: "button" | "toggle" | "tabs" | "switch", 패널 안 SWViewerButton |
| 아이콘 | 패키지 자산(필드 안 아이콘). 시안의 도구 아이콘 선택은 §5.2 | 프로그램 아이콘 16px, 직접 그린 아이콘은 SWViewerIcon으로 감쌈. 시안의 도구 아이콘 선택은 §5.2 |
| 범위 | Header 밖 부품은 <SWTheme> 안 |
SWViewerHeader·SWViewerMenu·SWViewerPanel은 루트에 hm-sw-theme이 있어 <SWTheme> 불필요. 패널 컨트롤은 SWViewerPanel 안 |
| 토큰 | --hm-sw-header-*, Popup 콘텐츠 --hm-sw-property-* |
--hm-sw-viewer-* + 공유 --hm-sw-header-*(아래 0.3) |
| 읽을 문서 | COMPONENT_CATALOG.md §1 |
VIEWER.md, COMPONENT_CATALOG.md §9, DESIGN_RULES.md §11, COMPOSITION_PATTERNS.md 7, 예제 H |
- 프로세스 단계 Header(로고 · 파일명 · 01 Modeling → 02 Analysis Result 같은 단계 탭 · Layer 필드 · 도구 pill · 최소화 · 최대화/복원 · 종료, Strana Main Header) 요청은 일반 모드의 독립 Header
SWProcessHeader입니다(카탈로그 §11, DESIGN_RULES §14, PATTERNS 12). 그룹·단계가 많은 다중 Step 화면(StrAna-SW)은 같은 컴포넌트의appearance="multi"입니다(별도 컴포넌트를 만들지 않음).SWHeader대신 쓰며 같은 화면에 함께 두지 않습니다. - 하단 명령 막대(Footer) 요청은 일반 모드입니다: FOOTER.md §1 순서로
SWFooter가 있는지 확인하고, 명령·분류·보조기능·문구·아이콘만 Props로 바꿉니다. Footer 외형을 새로 그리지 않습니다. - 일반 모드 Header에 도구 막대를 더한 구성(로고 옆 파일 열기 + Model/Layout·Fit·2.5D 버튼을
SWHeader에 추가)은 일반 모드입니다:SWHeader의documentOpenPlacement·leading·tools+SWToolButton/SWToolGroup(PATTERNS 6, 예제 F). "뷰어"·"도면 보기" 화면을 요청받았다면 이 구성이 아니라 뷰어 모드(SWViewer*)를 씁니다. - 모드 진입·종료, 파일 처리, 도면 렌더링, 메뉴 명령 실행은 어느 모드든 프로그램 담당입니다.
0.3 모드 혼합 금지
- 한 화면에 Header 하나.
SWHeader·SWProcessHeader·SWViewerHeader중 둘 이상을 같은 화면에 함께 두지 않습니다. 두 모드를 오가는 프로그램은 상태를 유지한 채 Header 컴포넌트만 바꿉니다(VIEWER.md §1). - 뷰어 화면:
SWHeader에 뷰어 메뉴를 넣거나SWHeader·SWPopup을 뷰어처럼 재스타일하지 않습니다. 뷰어 팝업은SWViewerPanel입니다. 예외: 창 최소화·닫기 버전은SWViewerHeader의trailing맨 끝에SWHeaderWindowControls(showWindowMove={false})를 그대로 둡니다(VIEWER.md §2.1, 2026-10-21). - 일반 화면:
SWViewerHeader·SWViewerMenu·SWViewerPanel과 패널 컨트롤(SWViewerSection…)을 쓰지 않습니다. - 로고(홈) 메뉴는 SW 일반 모드 전용:
SWHomeMenu·SWHomeMenuSection·SWHomeMenuItem·SWRecentFiles·useSWHomeMenuClose와SWHeader의homeMenu·homeMenuOpen·defaultHomeMenuOpen·onHomeMenuOpenChange는 일반 모드SWHeader화면에서만 씁니다. 뷰어 화면에는 홈 메뉴를 만들지 않고(SWViewerHeader옆·custom항목·SWViewerPanel안에 넣거나 비슷하게 다시 만들지 않음), 뷰어 Header와 기능은 그대로 둡니다. - 토큰:
--hm-sw-viewer-*토큰을 일반 모드 신규 UI에 쓰지 않고, 일반 모드 전용 모양(속성창 행SWPopupRow,SWToolButton의pill·text모양, 일반 필드 Dropdown)을 뷰어 신규 UI에 가져오지 않습니다. 두 토큰은 같은 범위(.hm-sw-header,.hm-sw-theme)에 함께 선언되어 있어 기술적으로 읽히지만, 읽힌다는 것이 허용을 뜻하지 않습니다. - 공유 — 모드 혼합 아님(실제 코드가 공유하는 부분):
SWViewerPanel은 내부에서SWPopup프레임(제목 막대·제목·닫기·테두리·면)을 렌더링합니다. 뷰어에서SWViewerPanel을 쓰는 것은 일반 모드 혼합이 아닙니다. 단, 뷰어 화면에서SWPopup을 직접 쓰지는 않습니다.- 두 Header는 사용자 확정 면 토큰
--hm-sw-header-document-*·--hm-sw-header-object-*·--hm-sw-header-property-*와 외곽선 토큰--hm-sw-header-text-outline*·--hm-sw-header-label-outline을 공유합니다(바꾸면 두 Header가 함께 바뀜). - 뷰어 패널 콘텐츠 토큰 일부(
--hm-sw-viewer-panel-background·-field-background·-inner-border·-text·-badge-background,--hm-sw-viewer-panel-switch-off)는--hm-sw-property-*값을 참조합니다. 뷰어 신규 UI는--hm-sw-viewer-panel-*이름으로 읽습니다.
0.4 없는 컴포넌트 처리 (모드별 3단계)
공통 원칙은 AI_GUIDE.md를 따르고, SW에서는 아래 값을 씁니다.
| 단계 | SW 일반 모드 | SW 뷰어 모드 |
|---|---|---|
| ① 기존 재사용 | SWHeader Props(hiddenControls·menuOrder·controls·documentOpenPlacement·leading·tools) → 개별 컨트롤 조합 → SWPopup children → SWToolButton / SWToolGroup |
SWViewerHeader의 groups 항목(button·toggle·menu·tabs·switch·custom)과 trailing → SWViewerMenu → SWViewerPanel children·footer·headerActions + 패널 컨트롤 |
| ② 소비 프로젝트에 신규 | 토큰 --hm-sw-header-*, Popup 안은 --hm-sw-property-*. 상태 표현은 DESIGN_RULES.md §4(테두리형 gradient 링, 텍스트형 글자만 #FFC600). 안쪽 입력은 SWHeaderInput 재사용(예제 D) |
토큰 --hm-sw-viewer-* + 공유 --hm-sw-header-*(면·외곽선). 상태 표현은 DESIGN_RULES.md §11 / VIEWER.md §2(Hover·Active·Pressed = 배경 변경 없이 글자·아이콘만 #FFC600, Focus 2px #FFC600). 안쪽은 뷰어 공개 컴포넌트 재사용(예: 새 패널 콘텐츠 = SWViewerField + SWViewerInput, 새 Header 도구 = custom 항목 안 SWViewerHeaderButton, 아이콘 = SWViewerIcon) |
| ③ 참고 값 없음 | 기존 HMDesign SW 규칙과 조화: Font Weight 400/500/700만, Light/Dark 없음, 전역 CSS(html·body·*) 금지, SW 공통 토큰 우선. 토큰에 없는 값은 결과 보고에 **"AI 구성 값 — 디자인 확인 필요"**로 표시 |
같음 |
- 뷰어 패널 안에
@hm-design/ui컨트롤을 넣는 것은SWViewerPanelchildren이ReactNode라 가능하지만,SWViewer*컨트롤로 안 될 때만 씁니다(별도 설치·외형 확인 필요, VIEWER.mdSWViewerPanel절). - 어느 단계에서도 패키지 원본(
node_modules/@hm-design/sw) 수정,hm-sw-*class 재사용·재정의,dist코드·CSS 복사를 하지 않습니다. 새 class는 소비 프로젝트 접두사(예:app-)를 씁니다.
1. 작업 순서 (필수)
- 먼저 검색한다. §0에서 모드를 정하고, 요청 기능을 COMPONENT_CATALOG.md의 공개 컴포넌트(뷰어 모드는 §9와 VIEWER.md)에서 찾는다.
- 있으면 재사용한다(1순위). 뷰어 모드는
SWViewerHeader·SWViewerMenu·SWViewerPanel이다(VIEWER.md). 일반 모드에서 완성형 Header가 필요하면SWHeader하나만 쓴다. 기존 Props(hiddenControls,menuOrder,controls,documentOpenPlacement,leading,tools, 각 데이터 배열·Callback)로 해결되는지 먼저 본다. 팝업·설정창은SWPopup, 버튼·탭·토글은SWToolButton/SWToolGroup, 일반 모드 로고 클릭 2단 메뉴는SWHeader의homeMenu(SWHomeMenu데이터, 최근파일은SWRecentFiles)이다.SWToolButton과SWHomeMenuItem은 역할이 다르다(도구 막대 버튼 / 메뉴 타일). 서로 대신 쓰지 않는다.- Popup 요청은 이렇게 판단한다: ①
SWPopup이 프레임(외형·닫기·Escape·스크롤)을 제공한다 → ② 내용은children으로 자유 구성(구조 제한 없음) → ③ 행 모양은SWPopupSection/SWPopupRow+SWHeaderInput, 레이어·색상·선스타일 선택 행은SWPopupPropertyRow(SWHeader 필드 Dropdown은 Header 전용), 게이지바는SWSlider, 선택 목록은SWSelect→ ④ 그래도 SW에 없는 컨트롤(Switch, 하단 Button 등)만@hm-design/ui를 children에 → ⑤ 프레임을 다시 만들거나 없는 Props(content,renderContent등)를 추측하지 않는다.
- Popup 요청은 이렇게 판단한다: ①
- 없으면 조합한다(2순위). 개별 공개 컴포넌트(
SWHeaderHome,SWHeaderDocumentTitle,SWHeaderLayerMenu…)를<SWTheme>안에 배치한다. 배치용 CSS만 소비 프로젝트에 작성한다(COMPOSITION_PATTERNS.md). - 조합으로도 안 될 때만 새로 만든다(3순위). 새 컴포넌트는 소비 프로젝트에 작성하고, 공개 컴포넌트(예:
SWHeaderInput)를 내부에 재사용하며, 외형은 공개 토큰--hm-sw-header-*만 읽는다(DESIGN_RULES.md, 예제 D). 뷰어 모드의 새 UI는--hm-sw-viewer-*(+ 공유--hm-sw-header-*면·외곽선, DESIGN_RULES.md §11)를 읽고 Header 버튼·패널 버튼·입력은SWViewerHeaderButton·SWViewerButton·SWViewerField+SWViewerInput을 재사용한다. 모드별 상세는 §0.4. 뷰어 화면에 일반 모드 컨트롤 모양을 섞지 않는다. - 토큰이 있는 값을 새로 만들지 않는다. 크기·색·간격은 선택 모드의 토큰과 DESIGN_RULES(뷰어는 VIEWER.md도)의 확인값을 쓴다. 참고 값이 없을 때만 §0.4 ③으로 구성하고 "AI 구성 값 — 디자인 확인 필요"로 보고한다(화면 인상을 크게 바꾸는 값은 구현 전에 사용자에게 확인).
- 존재하지 않는 API를 추측하지 않는다. 카탈로그와
dist/index.d.ts에 없는 Export·Props는 없는 것이다. - 패키지 코드를 복사하지 않는다.
node_modules/@hm-design/sw/dist의 구현이나hm-sw-*CSS 블록을 복사해 같은 컴포넌트를 다시 만들지 않는다. - 실제로 검증한다. 소비 프로젝트에서
tsc, Production Build, 브라우저 렌더링(Dropdown 열기·Callback·Focus)을 확인한 뒤 완료로 보고한다. 실행하지 않은 검증은 PASS로 적지 않는다.
2. 설치·Import 규칙
import { SWHeader, SWTheme, SWHeaderLayerMenu } from "@hm-design/sw"
import "@hm-design/sw/styles.css" // 앱 진입점에서 한 번
- 공식 진입점은
@hm-design/sw(JS·타입)와@hm-design/sw/styles.css두 개뿐이다.package.json의exports가 다른 경로를 막는다. - 금지:
@hm-design/sw/src/...,@hm-design/sw/dist/components/...같은 내부 경로 Import.dist에 내부 모듈의.d.ts가 보여도 공개 API가 아니다. - Peer:
react,react-dom^19.0.0. 런타임 dependency 없음.@hm-design/ui·조직도 패키지와 무관하다. - SVG·PNG 자산은 JS에 data URI로 포함되어 별도 설정이 없다.
- SW 기본 글꼴은 Noto Sans KR이다(
--hm-sw-header-font-family: "Noto Sans KR", "Malgun Gothic", "Apple SD Gothic Neo", sans-serif, 2026-10-20 확정 — 같은 날의 Dotum 기본값은 철회, Figma의 Dotum은 의도적으로 대체). 패키지는 글꼴 파일을 포함하지 않으며 앱이 Noto Sans KR(400/500/700)을 로드한다. 없으면 Malgun Gothic → Apple SD Gothic Neo로 대체된다. Dotum을 기본값으로 다시 넣지 않는다. - SW 화면은
SWTheme(또는 SW 컴포넌트 루트)와 SW 토큰의 글꼴을 그대로 쓴다. Web UI도 Noto Sans KR이지만 Web 토큰(--hm-font-family-base)이나 Webtheme.css의 글꼴 설정을 SW 화면에 복사하지 않고, SW 컴포넌트에font-family를 개별 지정하지 않는다. 프로그램(사용자)이 다른 글꼴을 정한 경우에만 §3.1 방법으로--hm-sw-header-font-family를 바꾸고 결과 보고에 "글꼴 변경"으로 적는다. - Weight 범위(2026-10-20 사용자 확정): SWHeader 안의 필드 값은 400, Composed Controls(SWHeader 밖에 단독 배치한
SWHeaderLayerMenu등)의 필드 값은 700. 파일명·Footer 보조기능/명령어 제목·Footer 분류 탭·Viewer Header 파일명/버튼 라벨/Model·Layout·최근파일 이름/경로/미리보기 제목, Footer Model/Layout 탭 라벨(모든 상태, 2026-10-22 사용자 확정, 이름 편집 입력은 400)은 700, Footer전체보기·명령·보조기능 라벨은 400. 임의로 일괄 변경하지 않는다. Figma 고정 폭 칸(예: 가중치·스케일 38px)에 그보다 긴 값(예:ByLayer)이 들어가면 말줄임 +title이 된다. Figma 레이어 이름의Dotum/bold/14를 보고 700으로 바꾸거나 겹침·외곽선을 따로 만들지 않는다. - CSS는 전역(
html,body,*)을 건드리지 않는다.bodymargin 등 페이지 기본값은 소비 앱이 정한다. - 스크롤바: SW 전용 스크롤바 디자인은 없다. 기존 SW 컴포넌트는 브라우저 기본 스크롤바를 쓰며(속성Bar만
scrollbar-width: thin), Popup 본문 스크롤은SWPopup이 처리한다. 새 스크롤 영역에 임의 스크롤바 색·두께를 만들지 않는다. - TypeScript에서 CSS side-effect import 오류가 나면 Vite의
vite/client타입을 포함한다.
3. 스타일 규칙
SWHeader밖에서 하위 컴포넌트를 쓰면 반드시<SWTheme>로 감싼다. 토큰·글꼴·버튼 초기화가 이 범위에서만 적용된다.- 소비 코드는
hm-sw-*class를 붙이거나 재정의하지 않는다. 배치는 자기 class(className)와style로 한다. - 뷰어 모드 컴포넌트(
SWViewerHeader·SWViewerMenu·SWViewerPanel)는 자체hm-sw-theme범위를 가지므로<SWTheme>로 감싸지 않아도 된다. 소비 코드는hm-sw-viewer-*class도 붙이거나 재정의하지 않는다. - 외형 변경은 §3.1의 방법만 쓴다. 사용자 확정 면(파일명·객체 수정·속성 입력)은 기본값 유지를 권장한다.
- Light/Dark 분기는 없다. SW 디자인은 하나다.
3.1 테마(토큰) 설정 — 공식 방법 (2026-10-20)
SW 토큰(--hm-sw-header-*, --hm-sw-property-*, --hm-sw-viewer-*, --hm-sw-footer-*)의 기본값은 가장 바깥 SW 범위(<SWTheme>, 또는 단독으로 쓴 SWHeader·SWViewerHeader·SWViewerPanel·SWViewerMenu·SWFooter의 루트)에서 한 번만 선언됩니다. 그 안의 SW 요소 — Header의 Dropdown·More, SWViewerMenu, SWViewerPanel과 안쪽 컨트롤, SWFooterCommandLine, Tooltip·안내 — 는 자기 루트에 hm-sw-theme이 있어도 값을 다시 정하지 않고 상속합니다.
- 화면 전체(Header·Panel·Menu가 같은 값)를 바꾸려면 화면을
<SWTheme style={theme}>하나로 감싸고 거기서만 토큰을 정합니다. 프로그램 class(<SWTheme className="app-sw-theme">+.app-sw-theme { --hm-sw-header-font-family: … })도 됩니다.const appSWTheme = { "--hm-sw-header-font-family": '"Malgun Gothic", sans-serif' } as CSSProperties // 프로그램이 정한 값만 <SWTheme style={appSWTheme}> <SWViewerHeader … /> {/* Dropdown·More 포함 */} <SWViewerPanel …>…</SWViewerPanel> </SWTheme> - 컴포넌트 하나만 쓰면 그 컴포넌트의
style로 정해도 됩니다(그 루트가 가장 바깥 범위). 안쪽 Dropdown·More·명령창에도 적용됩니다. - Portal: 상속은 DOM 위치를 따릅니다. 프로그램이
createPortal로 SW 요소를 범위 밖(document.body등)에 렌더링하면 값이 전달되지 않으므로, Portal 내용을 같은 theme 객체의<SWTheme style={appSWTheme}>으로 감쌉니다(예제 ExampleJ-Theme.tsx). SW 패키지 컴포넌트 자체는 Portal을 쓰지 않습니다(Dropdown·More·Panel 모두 범위 안에 렌더링). - 영역마다 다른 값이 필요하면 영역별
<SWTheme>을 둡니다. 옆 영역끼리 섞이지 않고, 안쪽<SWTheme style>은 그 안에서만 적용됩니다. - 하지 않음:
hm-sw-*class를 선택자로 쓴 CSS(.hm-sw-header, .hm-sw-theme { --… }등),!important, 안쪽 컴포넌트마다 같은 값을 반복 지정, SW 범위가 아닌 조상(body, 앱 루트div)에만 토큰 지정(SW 범위가 기본값을 다시 선언하므로 적용되지 않음).
- 다른 토큰을 참조하는 토큰(예:
--hm-sw-viewer-panel-background=var(--hm-sw-property-surface))은 가장 바깥 범위에서 계산됩니다. 참조되는 토큰을 바꿀 때도 가장 바깥 범위에서 바꿉니다.
4. 판단 기록 남기기
새 UI를 만들 때 결과 보고에 다음을 남긴다.
| 요청 항목 | 판단 | 근거 |
|---|---|---|
| 예: SW 모드 | 뷰어 모드 | 설정 HMDesign 사용 유형: SW 뷰어 / 요청 "DWG 뷰어" / 사용자 답변 중 실제 근거 |
| 예: 레이어 | 재사용 | SWHeaderLayerMenu |
| 예: 검색 | 신규(소비 프로젝트) | 카탈로그 MISSING. SWHeaderInput 재사용 + 토큰 기반 표면 |
| 예: 뷰어 측정 패널 | 신규 콘텐츠(소비 프로젝트) | SWViewerPanel children에 SWViewerField + SWViewerInput. 토큰에 없는 값은 "AI 구성 값 — 디자인 확인 필요" |
새 컴포넌트를 SW 패키지 공식 컴포넌트로 승격할지는 별도 검토 대상이다. 임의로 패키지에 추가하지 않는다.
5. 디자인 시안 기반 Header 구현 — 도구 아이콘·창 제어 버튼 판단 (2026-11-05)
화면 이미지·Figma·캡처 같은 디자인 시안을 보고 SW Header(SWHeader·SWProcessHeader·SWViewerHeader)의 도구 버튼과 창 제어 버튼을 구현할 때 따르는 단일 기준입니다. 다른 문서는 이 절을 요약·참조만 합니다. 크기·색·상태 값은 DESIGN_RULES.md(§9·§14, 뷰어는 VIEWER.md)를 따르며 이 절에서 다시 정하지 않습니다.
5.1 컴포넌트 기본 구성과 시안 재현은 다릅니다
| 구분 | 뜻 | 바꾸는 방법 |
|---|---|---|
| 컴포넌트 기본 구성 | Props를 생략했을 때 컴포넌트가 그리는 구성(예: SWProcessHeader는 hiddenControls가 없으면 창 이동·최소화·최대화/복원·종료를 모두 그림). 기존 소비 프로젝트가 의존하는 패키지 기본값 |
바꾸지 않습니다. 패키지 기본값·CSS를 고치거나 hm-sw-* class로 숨기지 않습니다 |
| 시안 재현 | 시안에 보이는 구성만 화면에 두는 것 | 공개 Props(hiddenControls·tools·trailing 등)로만 맞춥니다 |
- 카탈로그 예시·예제 파일·Storybook에 어떤 버튼이나 아이콘이 있다는 사실은 시안에 그것을 만들 근거가 아닙니다.
- 기존 화면 작업(기존 화면을 HMDesign으로 옮기기, 이미 HMDesign을 쓰는 화면에 새 시안 적용)에는 AI_GUIDE.md 4단계 "기존 화면 전환 시 원본 보존"·"디자인 적용 시 변경 범위 제한"이 우선합니다. 원본에 있는 버튼·아이콘·창 제어 기능을 "시안에 없다"는 이유만으로 지우거나
hiddenControls를 더해 숨기지 않고, 원본에 없는 창 제어 버튼을 시안만 근거로 더하지 않습니다. 시안과 원본이 다르면 결과 보고의 "원본 대비 변경"에 확인 대상으로 적습니다. §5.5의 생략·추가 규칙은 신규 화면 기준입니다. - 사용자가 창 제어·도구 버튼 구성 변경을 명시적으로 요청했으면 요청한 버튼에 한해 공개 Props로 바꾸고, "원본 대비 변경"의 근거를 "사용자 승인"으로 적습니다. 요청 범위 밖의 버튼은 그대로 둡니다.
5.2 도구 아이콘 선택 우선순위
| 순위 | 조건 | 할 일 |
|---|---|---|
| 1 | 사용자가 이번 작업에 제공했거나 사용을 승인한 이미지·SVG, 또는 소비 프로젝트에 이미 등록된 공식 아이콘이 있음 | 그 에셋을 씁니다. 상태별 그림이 있으면 기본은 icon, Hover 그림은 hoverIcon에 넣습니다(§5.4) |
| 2 | 제공된 에셋이 없고, @hm-design/sw가 공개 Export하는 아이콘·부품 중 기능과 의미가 같은 것이 있음 |
그것을 재사용합니다. 시안과 모양이 조금 달라도 기능이 같고 그 아이콘의 사용 위치·크기·상태 규칙 안이면 HMDesign 것을 우선합니다 |
| 3 | 1·2 모두 없음 | 대체하지 않고 미지원으로 보고합니다(아래) |
- 시안 속 아이콘의 사용 권한: Figma 등 시안에 그려져 있다는 사실만으로 사용 권한이 있다고 보지 않습니다. 시안에서 아이콘을 추출해 쓰려면 사용자가 그 에셋을 제공했거나 사용을 명시적으로 승인했는지 먼저 확인하고, 확인 전에는 1순위로 쓰지 않습니다(2·3순위로 판단). 이 승인은 해당 소비 프로젝트에서의 사용에만 해당하며, HMDesign 패키지 공식 등록·공개 배포 권한은 별도로 확인합니다(§5.3).
2순위 — 현재 공개된 아이콘·아이콘 포함 부품(목록 밖 이름은 COMPONENT_CATALOG.md와 dist/index.d.ts에서 확인):
| 공개 Export | 기능 | 사용 위치 |
|---|---|---|
SWHeader 기본 부품(인쇄 print, K 가이드 popupGuide, 창 이동·최소화·종료) |
인쇄, 단축키 안내, 창 제어 | SWHeader 안(hiddenControls로 개별 제거). 아이콘만 꺼내 쓰는 API는 없습니다 |
SWHeaderActions |
인쇄·K 가이드 버튼 pill(onPrint·onPopupGuide·showPrint·showPopupGuide·disabled) |
<SWTheme> 안 SW 일반 모드 조합 Header(COMPOSITION_PATTERNS.md 2). 컴포넌트 단위로만 재사용합니다 — 인쇄·K 아이콘 단독 Export는 없어 SWToolButton의 icon에 넣을 수 없습니다. SWHeader(이미 내장)·SWProcessHeader tools·뷰어 화면(VIEWER.md §2.1)에는 넣지 않습니다(검증된 조합 아님) |
SWHeaderWindowControls |
창 이동·최소화·종료 | SW 일반 모드 조합 Header, 뷰어 trailing 끝(최소화·닫기만, showWindowMove={false}, VIEWER.md §2.1) |
SWProcessSplitButton |
화면 분할 | SWProcessHeader의 tools |
SWLayerVisibilityIcon |
레이어 표시·숨김 전구 | 뷰어 레이어 Popup(VIEWER.md §4.1) |
swFooterToolIcons · swFooterAuxIcons |
Footer 명령(Line·Circle …)·보조기능(객체스냅 …) | SWFooter 칸(FOOTER.md). 크기·상태 색이 Header 도구 버튼과 달라 Header pill에는 쓰지 않습니다 |
- 모양이 비슷하다는 이유만으로 기능이 다른 아이콘을 쓰지 않습니다(예:
swFooterToolIcons.rect를 최대화 아이콘으로 쓰기 금지). SWViewerIcon은 외곽선만 더하는 감싸기 부품이며 그림을 제공하지 않습니다.- Header 도구 버튼용 범용 아이콘(도움말·3D 보기·설정·메뉴·나가기 등)은 현재 공개 Export가 없습니다. 이런 아이콘이 시안에 있고 1순위 에셋도 없으면 3순위입니다.
3순위 — 공식 아이콘이 없을 때:
- 외부 아이콘 라이브러리(
lucide-react등 — Web 패키지 의존성이지만 SW 화면에 쓰지 않음), AI가 그린 SVG, Storybook 파일 복사로 대신하지 않습니다. - 코드를 쓰기 전에 필요한 아이콘·기능·필요한 상태(기본·Hover 등)를 사용자에게 알리고 에셋 제공 또는 HMDesign 공식 아이콘 등록이 필요하다고 요청합니다.
- 답을 기다리지 않고 진행해야 하면 그 도구 버튼을 넣지 않거나, 사용자가 승인한 임시 표시만 쓰고 결과 보고에 "미지원 아이콘 — 에셋 필요"로 적습니다. 승인 없이 임시 아이콘을 최종 디자인으로 확정하지 않습니다.
5.3 Storybook 전용 에셋과 공개 에셋의 차이
| 구분 | 공개 에셋·API | Storybook 전용 에셋(Fixture) |
|---|---|---|
| 위치 | @hm-design/sw 진입점 Export(카탈로그에 이름이 있음). SVG는 JS에 data URI로 포함 |
HMDesign 저장소의 Story 데모 파일. 설치 패키지(dist·ai)에 포함되지 않음 |
| 보장 | 버전 호환·사용 규칙 문서화 대상 | 데모용. 출처·사용 권한·유지를 보장하지 않음 |
| 소비 프로젝트 | Import해서 사용 | Import·복사·경로 참조 금지(Git Submodule로 저장소 파일이 보여도 같음) |
- Storybook 화면에 보인다는 것은 공개 API라는 뜻이 아닙니다. Storybook은 조합·외형 참고용입니다(AI_GUIDE.md 4단계 "Git Submodule 사용 규칙").
- 2026-11-05 현재 Storybook 전용(공개 API 아님):
SW / Step HeaderStory의 도구 아이콘 — Multi Step의 도움말·3D 보기·설정·메뉴·나가기, Default의 View Property·Sub 창. 출처·사용 권한 확인 전이라 패키지에 등록하지 않았습니다. 시안에 이 아이콘이 있으면 1순위(사용자·프로젝트 제공)로 받거나 3순위로 보고합니다.
5.4 아이콘 상태 처리 — 기존 공개 API 방식 그대로
SWToolButton appearance="pill"의icon(기본 그림)과hoverIcon(상태 그림)만 씁니다. Disabled 전용 아이콘 Prop은 없습니다. 상태별 현재 동작(패키지 CSS 기준)은 버튼이 놓인 곳에 따라 다릅니다.
| 상태 | SWProcessHeader의 tools 안 |
그 밖의 pill(SWHeader의 tools, <SWTheme> 조합) |
|---|---|---|
| Default | icon. currentColor = #B6D0C9(--hm-sw-process-tool-icon-color) |
icon. currentColor = 상속 글자색 --hm-sw-header-text-color(#F6F4F2), #B6D0C9 아님 |
| Hover | 노란 링 + currentColor #FFC600 + hoverIcon이 있으면 그 그림 |
노란 링 + hoverIcon이 있으면 그 그림. currentColor 색은 바뀌지 않음 |
Pressed(pressed Prop, aria-pressed) |
Hover와 같은 모양(노란 링 + #FFC600 + hoverIcon) |
currentColor만 #FFC600. 노란 링·hoverIcon 전환 없음 |
| Disabled | Hover 반응 없음, 기본 그림 유지, 투명도 0.4 | 같음 |
- 누르는 순간(
:active)의 별도 모양은 없습니다. 위 Pressed는pressedProp 상태입니다. - 색이 고정된 이미지는 기본·Hover 두 장을 줍니다. Hover 그림이 제공되지 않으면
hoverIcon을 생략하며(Hover에도 기본 그림 유지), 제공된 그림의 색을 바꿔 Hover 그림을 만들지 않습니다.currentColor한 장으로 상태 색을 따르는 방식은SWProcessHeader의tools에서만#B6D0C9→#FFC600이 됩니다. 그 밖의pill에서 시안 색이 인쇄 버튼처럼#B6D0C9→#FFC600이면 기본·Hover 두 장 이미지를 씁니다(값은 DESIGN_RULES.md §9·§14). - 위 표와 다른 상태 모양이 시안에 있으면 CSS로 맞추지 않고 지원 범위 밖으로 보고합니다.
- 그림은 장식이므로
<img alt="" />로 두고 버튼 이름은children으로 줍니다. - 상태를 맞추려고
hm-sw-*class나 패키지 CSS를 덮지 않습니다.
5.5 창 제어 버튼(창 이동·최소화·최대화·닫기)
- 시안에 명확히 보이는 창 제어 버튼만 구현합니다(웹 화면은 4번, 기존 화면은 §5.1이 우선).
- 시안에 없고 별도 요구도 없으면 만들지 않는 것이 기본입니다. 컴포넌트 기본 구성(§5.1)에 있어도 공개 숨김 API로 뺍니다(신규 화면 기준, 기존 화면은 §5.1).
- 시안의 오른쪽이 잘렸거나 일부가 보이지 않으면 보이지 않는 버튼의 존재를 확정하지 않습니다. 코드를 쓰기 전에 묻고, 답 없이 진행해야 하면 보이는 범위만 구현한 뒤 결과 보고에 "확인 필요(시안 잘림)"로 적습니다.
- 브라우저에서 쓰는 웹 화면에서는 운영체제 창 제어 버튼을 새로 만들지 않는 것이 기본입니다. 시안에 창 제어 버튼이 보여도 실제로 연결할 창 동작(최소화·최대화·닫기를 처리하는 셸·Callback 요구)이 확인되지 않으면 임의로 구현하지 않습니다. 코드를 쓰기 전에 묻고, 답 없이 진행해야 하면 신규 창 제어 버튼 생성을 보류하고(아래 공개 숨김 API로 생략) 결과 보고에 "보류 — 창 동작 요구 확인 필요"로 적습니다. 빈 Callback·임의
window.close()연결 같은 가짜 동작을 만들지 않습니다. 기존 화면에 이미 있는 창 제어 기능은 이 규칙을 이유로 별도 승인 없이 제거하지 않습니다(§5.1). - 데스크톱 프로그램(설치형·WebView 셸 등)처럼 창 제어가 필수인 환경은 플랫폼 요구와 사용자 명세를 우선합니다. 시안에 없는데 플랫폼상 필요해 보이면 임의로 더하지 않고 확인합니다. 실제 창 이동·최소화·최대화·종료는 프로그램 담당입니다(Callback 연결).
- 숨김·생략은 아래 공개 API로만 합니다. 적절한 공개 API가 없으면 CSS로 감추는 우회 대신 지원 여부와 제약을 보고합니다.
| Header | 기본 구성 | 시안에 없을 때(공개 API) |
|---|---|---|
SWProcessHeader |
창 이동·최소화·최대화/복원·종료 표시 | hiddenControls에 "windowMove"·"minimize"·"maximize"·"close" 중 없는 것. 넷 다 숨기고 tools도 없으면 창 영역 자체가 렌더링되지 않음 |
SWHeader |
창 이동·최소화·종료 표시 | hiddenControls에 "windowMove"·"minimize"·"close" 중 없는 것 |
SWViewerHeader |
창 제어 없음 | trailing에 SWHeaderWindowControls를 넣지 않음. 시안에 최소화·닫기가 있으면 trailing 맨 끝에 showWindowMove={false}로만 둠(VIEWER.md §2.1 승인 구성). 창 이동은 뷰어에서 지원하지 않으므로 시안에 있어도 넣지 않고 미지원으로 보고 |
<SWTheme> 안 조합 Header |
— | SWHeaderWindowControls를 두지 않거나 showWindowMove·showMinimize·showClose로 일부만 표시 |
5.6 공식 구현 예시 (공개 API만)
import { SWHeader, SWProcessHeader, SWToolButton } from "@hm-design/sw"
// 1순위 에셋: 사용자·소비 프로젝트가 제공한 파일(HMDesign 패키지·Storybook 파일이 아님)
import helpIcon from "./assets/help.svg"
import helpIconHover from "./assets/help-hover.svg"
// 시안: 창 제어 버튼 없음, 도구는 도움말 하나
<SWProcessHeader appearance="multi" documentTitle={projectName} logoText="StrAna" onHomeClick={toggleFileMenu}
process={{ groups, activeStepId: step, onStepSelect: s => setStep(s.id) }}
tools={<SWToolButton appearance="pill" icon={<img src={helpIcon} alt="" />} hoverIcon={<img src={helpIconHover} alt="" />} onClick={openHelp}>도움말</SWToolButton>}
hiddenControls={["windowMove", "minimize", "maximize", "close"]} />
// 시안: 최소화·닫기만 있음(창 이동·최대화 없음)
<SWProcessHeader documentTitle={fileName} process={processProps}
hiddenControls={["windowMove", "maximize"]} onMinimize={minimize} onClose={closeWindow} />
// 시안: 완성형 SWHeader에 창 제어 버튼 없음
<SWHeader documentTitle={fileName} {...headerProps} hiddenControls={["windowMove", "minimize", "close"]} />
5.7 결과 보고에 남길 것
§4 표에 다음 판단을 함께 적습니다.
| 요청 항목 | 판단 | 근거 |
|---|---|---|
| 예: 도움말 아이콘 | 1순위 사용 / 2순위 재사용 / 3순위 미지원 | 사용자 제공 파일명 / 재사용한 공개 Export 이름 / "공개 아이콘 없음 — 에셋 제공 또는 공식 등록 필요(기능·필요 상태)" |
| 예: 창 제어 버튼 | 구현 / 생략 / 보류 / 원본 유지 / 확인 필요 | 시안에 보인 버튼 목록, 사용한 hiddenControls 값, 시안 잘림·웹/데스크톱·플랫폼 요구 여부, 기존 화면이면 원본 구성과 사용자 승인 여부 |