fix(sw): refine process header empty title states and UI guidance

- AI_GUIDE stage 5 "Header 전용 스타일의 적용 범위": header-only styles stay
  in the header (SW SWHeader / SWProcessHeader / SWViewerHeader, Web GNB /
  LNBMobileHeader / DashboardHeader); no header CSS or tokens on body UI,
  no global overrides, layout-only joins, package-shared tokens unchanged,
  whole-screen use only on explicit request. Synced to the 4 package
  copies; referenced from stage 6, SW and Web AI_USAGE §3
- SWProcessHeader: with documentTitle "" the file name keeps #AEDBCC on
  hover and a default cursor (root data-document-untitled). The button,
  focus and onDocumentClick are kept; a real file name keeps the yellow
  hover and pointer. Visual vs. click difference recorded as a UX item
- Step enablement documented as implemented: only an explicit disabled
  (step, group, process, header) turns steps off; project / file state
  never does; selection is activeStepId + onStepSelect (also for host
  previous / next); no activeStepId and empty groups described
- Regression check tests/process-header-states.check.mjs (15/15);
  typecheck:sw, build:sw, check:ai-docs pass; public-api keeps its 3
  existing failures, none new
This commit is contained in:
shkim4 committed 2026-11-05 16:45:54 +09:00
1 parent 6c61edadc1
commit 0086d66a94
14 files changed
+177 -9

No files matched your search

+2 -1
View File
@@ -191,7 +191,7 @@ SW **뷰어 모드** 전용 Export입니다(2026-10-19 추가, 참고 DWG/DXF
| 컴포넌트 | 용도 | 주요 Props | 크기 | 검증 |
|---|---|---|---|---|
| `SWProcessHeader` | 49px Header: 로고 → 파일명 → 프로세스 영역 · Layer 면 → 창 영역(도구 pill · 창 이동 · 최소화 · 최대화/복원 · 종료) | `appearance`(`"default"` Strana · `"multi"` StrAna-SW 다중 Step, 기본 `default`, `process.appearance`가 없으면 프로세스 영역에도 적용), `documentTitle`(필수, 문서가 없으면 `""`), `documentEmptyLabel`(제목이 비었을 때 파일명 면 오른쪽 위 10px 표시, 예: `프로젝트 생성 전`), `onDocumentClick`, `logo`(커스텀 요소) / `logoText`(글자 로고) / `logoSrc`(SWHeader 로고 칸: 높이 17·로고 비율 폭, 32 × 17 → 홈 80, 두 타입 공통. 우선순위 `logo` > `logoText` > `logoSrc`, 셋 다 같은 로고 칸에 들어가 홈 = 12 + 로고 폭 + 36. 글자 로고는 최소 58px 칸 → 홈 최소 106, 더 긴 글자는 글자 폭만큼 넓어짐·잘림 없음), `logoAlt`(기본 `logoText`), `onHomeClick`, `homeMenuOpen`(로고 메뉴는 호스트 소유), `process: SWProcessBarProps`(필수), `layer?: SWProcessHeaderLayer`(`label` 기본 `레이어`, `value`, `visible`, `open`, `disabled`), `onLayerClick`, `onLayerVisibilityChange(next)`, `tools?: ReactNode`(`SWToolButton appearance="pill"`, Header가 pill로 감쌈), `toolsLabel`(기본 `도구`), `onWindowMoveStart`, `maximized`(기본 false = 최대화 글리프, true = 복원 글리프), `onMinimize`, `onMaximizeToggle`, `onClose`, `hiddenControls?: SWProcessHeaderHideableControlId[]`(`layer`·`tools`·`windowMove`·`minimize`·`maximize`·`close`), `disabled`(프로세스·Layer만, 로고·파일명·도구·창 버튼 제외), `<header>` HTML 속성·`ref` | 높이 49. `default`: 면 48, 파일명 286 : 가운데 1260(프로세스 1003 : Layer 257) 비율, 파일명 100~286, Layer 칸 152~257, 창 영역 약 312(도구 3개). `multi`: 면 49, 파일명 189 : 프로세스 1278, 파일명 100~189, SW pill(버튼 40 × 37), 창 영역 367(도구 5개, 최대화 숨김) | ◻ |
| `SWProcessHeader` | 49px Header: 로고 → 파일명 → 프로세스 영역 · Layer 면 → 창 영역(도구 pill · 창 이동 · 최소화 · 최대화/복원 · 종료) | `appearance`(`"default"` Strana · `"multi"` StrAna-SW 다중 Step, 기본 `default`, `process.appearance`가 없으면 프로세스 영역에도 적용), `documentTitle`(필수, 문서가 없으면 `""`), `documentEmptyLabel`(제목이 비었을 때 파일명 면 오른쪽 위 10px 표시, 예: `프로젝트 생성 전`. `documentTitle=""`이면 파일명 면에 Hover 색 변화·손가락 커서가 없음 — 크기·위치·색과 `onDocumentClick` 호출은 그대로, 2026-11-05), `onDocumentClick`, `logo`(커스텀 요소) / `logoText`(글자 로고) / `logoSrc`(SWHeader 로고 칸: 높이 17·로고 비율 폭, 32 × 17 → 홈 80, 두 타입 공통. 우선순위 `logo` > `logoText` > `logoSrc`, 셋 다 같은 로고 칸에 들어가 홈 = 12 + 로고 폭 + 36. 글자 로고는 최소 58px 칸 → 홈 최소 106, 더 긴 글자는 글자 폭만큼 넓어짐·잘림 없음), `logoAlt`(기본 `logoText`), `onHomeClick`, `homeMenuOpen`(로고 메뉴는 호스트 소유), `process: SWProcessBarProps`(필수), `layer?: SWProcessHeaderLayer`(`label` 기본 `레이어`, `value`, `visible`, `open`, `disabled`), `onLayerClick`, `onLayerVisibilityChange(next)`, `tools?: ReactNode`(`SWToolButton appearance="pill"`, Header가 pill로 감쌈), `toolsLabel`(기본 `도구`), `onWindowMoveStart`, `maximized`(기본 false = 최대화 글리프, true = 복원 글리프), `onMinimize`, `onMaximizeToggle`, `onClose`, `hiddenControls?: SWProcessHeaderHideableControlId[]`(`layer`·`tools`·`windowMove`·`minimize`·`maximize`·`close`), `disabled`(프로세스·Layer만, 로고·파일명·도구·창 버튼 제외), `<header>` HTML 속성·`ref` | 높이 49. `default`: 면 48, 파일명 286 : 가운데 1260(프로세스 1003 : Layer 257) 비율, 파일명 100~286, Layer 칸 152~257, 창 영역 약 312(도구 3개). `multi`: 면 49, 파일명 189 : 프로세스 1278, 파일명 100~189, SW pill(버튼 40 × 37), 창 영역 367(도구 5개, 최대화 숨김) | ◻ |
| `SWProcessSplitButton` | 화면 분할 도구(Strana 화면 분할, StrAna-SW 6758:12510): `tools` pill 안 버튼 + 233 × 36 선택 패널(칸 6개). 열리면 버튼이 어두운 면 + 금색 위·양옆으로 바뀌고 Header 끝까지 이어진 뒤 패널이 Header 바로 아래에 붙음 | `value: SWProcessSplitType`(필수, 버튼 아이콘·선택 칸), `onValueChange(value)`(다른 칸 선택, 패널은 열린 채), `open` / `defaultOpen` / `onOpenChange(open)`, `label`(기본 `화면 분할`, 버튼 접근성 이름·`title`·패널 이름), `typeLabels`, `disabled`. 키보드: Enter·Space 열기/닫기, ArrowDown 열고 선택 칸으로, 방향키·Home·End 선택, Escape 닫고 버튼으로, Tab 이탈·바깥 클릭 닫기. 실제 창 분할은 호스트 | 버튼 40 × 38(`multi` 37), 패널 233 × 36, 칸 38.5 × 34 | ◻ |
| `SWProcessBar` | 프로세스 영역: 그룹(번호·이름·단계 탭) + 그룹 사이 화살표, 활성 그룹 발광 면, 비활성 덮개. 단계 하나만 선택(radiogroup) | `appearance`(`"default"` · `"multi"`, 기본 `default`), `groups: SWProcessGroup[]`(필수, `id`·`number`·`label`·`labelHidden`(이름을 보조기술용으로만 둠, `multi`는 제목 줄 높이 유지)·`steps: SWProcessStep[]`(`id`·`label`·`disabled`)·`disabled`), `activeStepId`, `activeGroupId`(기본 = `activeStepId`가 속한 그룹), `onStepSelect(step, group)`(이미 선택된 단계를 다시 누르면 호출 안 함), `disabled`, `aria-label`(기본 `프로세스`), `div` 속성 | `default`: 높이 48, 탭 32(넓을 때 127). `multi`: 높이 49, 제목 12px 위 + 탭 25(글자 폭 + 25, 간격 0). 그룹은 자연 폭까지·좁으면 비례 축소 | ◻ |
@@ -199,6 +199,7 @@ SW **뷰어 모드** 전용 Export입니다(2026-10-19 추가, 참고 DWG/DXF
- **사다리꼴(그룹 면) 배치 확정(2026-11-03):** 시작(첫 그룹)과 끝(마지막 그룹)에만 둡니다(켜졌으면 발광 면, 아니면 비활성 면). 가운데 그룹은 켜져 있어도 도형 없이 밝은 바탕만 보입니다. 그룹 수와 관계없이, `default`·`multi` 공통입니다. 그룹 사이 화살표·비활성 덮개·선택 상태는 그대로입니다.
- **`multi`**(Figma StrAna-SW 873:16481 · 873:16254 · 873:17421): 그룹 수·단계 수는 데이터대로이며, 켜진 그룹보다 앞 그룹은 진행 완료(제목 700 흰색·밝은 탭), 뒤 그룹은 미진행(제목 500 `#C3EBDF`·70% 탭)으로 표시합니다. 바탕·덮개·발광·화살표·선택·키보드는 `default`와 같은 구현입니다.
- **키보드:** 탭 사이 Arrow(좌우·상하)·Home·End 이동 + 선택(비활성 단계 건너뜀), Tab은 선택된 단계 하나로만 들어갑니다.
- **단계 활성화(현재 구현, 2026-11-05 명시):** 단계는 기본으로 모두 선택할 수 있습니다. `step.disabled: true`, `group.disabled: true`, `process.disabled` 또는 Header `disabled`를 명시했을 때만 비활성입니다(생략·`false`는 활성). 프로젝트 생성 여부·파일명 유무(`documentTitle`, `documentEmptyLabel`)는 활성화에 영향을 주지 않으므로, 새 프로젝트라는 이유로 `disabled`를 넣지 않습니다. 단계 선택은 호스트가 `activeStepId`를 바꾸는 방식이며(`onStepSelect`에서 갱신, 이전·다음 버튼도 같은 값을 바꿈), 그룹의 켜짐·진행 완료 모양은 `activeStepId`로 정해집니다. `activeStepId`가 없으면 선택된 단계와 켜진 그룹 없이 모든 그룹이 켜지지 않은 모양이지만 단계는 그대로 선택할 수 있고, `groups`가 비면 단계 없이 프로세스 바탕만 그립니다. 컴포넌트는 단계를 만들거나 자동 선택하지 않습니다.
- **반응형:** 숨김·More·스크롤 없음. 보장 폭 1100px 이상이며 더 좁으면 Header 안에서 잘립니다. 탭 글자·파일명·Layer 이름은 `…` 말줄임. 공간이 부족하면 선택된 탭도 다른 탭과 같은 비율로 줄어듭니다(2026-11-03 개정): `default`는 모든 탭이 같은 폭, `multi`는 글자 폭에 비례하며 이름이 들어가지 않으면 `…`. 선택이 바뀌어도 탭 폭은 그대로입니다. 그룹은 이름 + 모든 탭 여백보다 좁아지지 않아 겹치지 않습니다. 그룹 사이 화살표·간격은 고정입니다. **넘침 정책 확정(2026-11-03): 그룹 접기·좌우 스크롤·More 메뉴를 추가하지 않습니다.**
- **원문 확인(현재 구현):** 파일명·Layer 값은 `title`로 전체 이름을 보여 줍니다. 단계 탭 이름과 `multi` 그룹 제목은 말줄임되어도 `title`이 없고 접근성 이름(탭 `aria-label`, 그룹 이름 `aria-describedby`)만 전체 이름입니다. 개선은 별도 과제입니다([DESIGN_RULES.md](./DESIGN_RULES.md) §15.1). 호스트 `tools`의 `SWToolButton pill`은 문자열 `children`이 기본 툴팁이 되며, 숫자·JSX `children`이면 호스트가 `title`을 전달합니다(§4).
- **범위 밖(호스트 소유):** 로고 메뉴 본체, Layer Popup, 실제 화면 분할 실행, 도구 아이콘(소비 측이 `tools`에 넣는 요소). 도움말·3D 보기·설정·메뉴·나가기 같은 Header 도구 아이콘은 공개 Export가 없고, Storybook `SW / Step Header`의 아이콘은 공개 API가 아닙니다. 시안의 아이콘 선택과 창 제어 버튼 생략(`hiddenControls`)은 [AI_USAGE.md](./AI_USAGE.md) §5를 따르며, 창 버튼 기본 구성(모두 표시)은 바뀌지 않습니다. 화면 분할 선택 UI는 `SWProcessSplitButton`(2026-11-03 추가). `SWHomeMenu`는 이 Header에 쓰지 않습니다(2단 타일 디자인이 다름).