feat(sw): integrated improvement 0.2.0 (popup content, header open, tool buttons)
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>
This commit is contained in:
1 parent
5faa1f1ffe
commit
55179b4577
138 files changed
+17194
-162
No files matched your search
@@ -0,0 +1,91 @@
|
||||
import { useState, type ReactNode } from "react"
|
||||
import type { Meta, StoryObj } from "@storybook/react-vite"
|
||||
import { SWHeader, SWHeaderHome, SWTheme, SWToolButton, SWToolGroup } from "@hm-design/sw"
|
||||
import "@hm-design/sw/styles.css"
|
||||
import { StoryPage, StoryPageHeader, StorySection } from "@/components/story-page"
|
||||
import "./sw-stories.css"
|
||||
import "./sw-integrated-stories.css"
|
||||
import placeholderLogo from "./assets/sw-header-logo-placeholder.svg"
|
||||
|
||||
// SWToolButton / SWToolGroup (2026-10-19): the existing SW toggle, pill and file-name looks as public buttons
|
||||
// for viewer tool bars (Model / Layout, Fit, 2.5D, ...). Public API only, like a consuming project.
|
||||
const KICKER = "HM DESIGN SYSTEM / SW"
|
||||
|
||||
// Sample host icon (the program supplies its own): 24 x 23 box like the print icon, default #B6D0C9 / hover #FFC600.
|
||||
const FitIcon = ({ color }: { color: string }) => (
|
||||
<svg viewBox="0 0 24 23" width="24" height="23" aria-hidden="true">
|
||||
<path d="M2 8V2h6M16 2h6v6M22 15v6h-6M8 21H2v-6" fill="none" stroke={color} strokeWidth="2" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
const meta = {
|
||||
title: "SW/Tool",
|
||||
parameters: { layout: "fullscreen", controls: { disable: true } },
|
||||
} satisfies Meta
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
function Bar({ children }: { children: ReactNode }) {
|
||||
return <div className="sw-story-scroller"><div className="sw-story-frame" style={{ width: 1440 }}>{children}</div></div>
|
||||
}
|
||||
|
||||
function ToolPage() {
|
||||
const [view, setView] = useState<"model" | "layout">("model")
|
||||
const [depth, setDepth] = useState(false)
|
||||
const [log, setLog] = useState<string[]>([])
|
||||
const record = (line: string) => setLog(lines => [...lines.slice(-7), line])
|
||||
const viewGroup = (
|
||||
<SWToolGroup label="보기" selection="single" data-view-group="">
|
||||
<SWToolButton pressed={view === "model"} onClick={() => { setView("model"); record("view(model)") }}>Model</SWToolButton>
|
||||
<SWToolButton pressed={view === "layout"} onClick={() => { setView("layout"); record("view(layout)") }}>Layout</SWToolButton>
|
||||
</SWToolGroup>
|
||||
)
|
||||
const displayGroup = (
|
||||
<SWToolGroup label="표시" data-display-group="">
|
||||
<SWToolButton pressed={depth} onClick={() => { setDepth(!depth); record(`2.5D(${!depth})`) }}>2.5D</SWToolButton>
|
||||
</SWToolGroup>
|
||||
)
|
||||
const fit = (
|
||||
<SWToolGroup appearance="pill" aria-label="화면" data-fit-group="">
|
||||
<SWToolButton appearance="pill" icon={<FitIcon color="#B6D0C9" />} hoverIcon={<FitIcon color="var(--hm-sw-header-selected-color)" />} onClick={() => record("fit")}>화면 맞춤</SWToolButton>
|
||||
</SWToolGroup>
|
||||
)
|
||||
return (
|
||||
<StoryPage>
|
||||
<StoryPageHeader kicker={KICKER} title="SW Tool — SWToolButton / SWToolGroup"
|
||||
description="새 디자인 값 없이 기존 SW 버튼 3종을 공개 버튼으로 씁니다. text = 속성Bar·속성창 글자 토글, pill = 인쇄·K 버튼, document = 파일명 면. SWToolGroup은 상세보기 묶음(text) 또는 인쇄·K pill(pill)이며 selection="single"이면 Model / Layout 같은 단일 선택(radiogroup, 화살표 키)입니다." />
|
||||
<p className="sw-story-log" aria-live="polite" data-callback-log="">Callback: {log.length ? log.join(" → ") : "없음"}</p>
|
||||
<StorySection title="SWHeader tools 슬롯 안" description="객체 수정 영역의 메뉴 뒤에 도구 막대를 둡니다.">
|
||||
<Bar><SWHeader documentTitle="C0020101-006-평면및종단면도(06)" logoSrc={placeholderLogo} logoAlt="임시 로고"
|
||||
hiddenControls={["lineStyle", "textStyle", "dimensionStyle", "details", "propertyBar", "propertyPanel"]}
|
||||
tools={<>{viewGroup}{displayGroup}{fit}</>} /></Bar>
|
||||
</StorySection>
|
||||
<StorySection title="조합형 막대 (SWTheme)" description="Header 없이 같은 부품을 SWTheme 안에 배치합니다. 배치 CSS만 소비 프로젝트 소유입니다.">
|
||||
<Bar>
|
||||
<SWTheme className="sw-story-composed-bar" data-tool-bar="">
|
||||
<SWHeaderHome logoSrc={placeholderLogo} logoAlt="임시 로고" />
|
||||
<SWToolButton appearance="document" onClick={() => record("open")}>Open</SWToolButton>
|
||||
<div className="sw-story-composed-surface">{viewGroup}{displayGroup}{fit}</div>
|
||||
</SWTheme>
|
||||
</Bar>
|
||||
</StorySection>
|
||||
<StorySection title="상태" description="text: Hover·Selected 글자 #FFC600, Disabled 40%. pill: Hover 노란 테두리, hoverIcon 교체. document: 글자만 Hover #FFC600.">
|
||||
<Bar>
|
||||
<SWTheme className="sw-story-composed-bar" data-tool-states="">
|
||||
<SWHeaderHome logoSrc={placeholderLogo} logoAlt="임시 로고" interactive={false} />
|
||||
<SWToolButton appearance="document" disabled>Disabled</SWToolButton>
|
||||
<div className="sw-story-composed-surface">
|
||||
<SWToolGroup label="text"><SWToolButton>Default</SWToolButton><SWToolButton pressed>Pressed</SWToolButton><SWToolButton disabled>Disabled</SWToolButton></SWToolGroup>
|
||||
<SWToolGroup appearance="pill" aria-label="pill">
|
||||
<SWToolButton appearance="pill" icon={<FitIcon color="#B6D0C9" />} hoverIcon={<FitIcon color="var(--hm-sw-header-selected-color)" />}>Fit</SWToolButton>
|
||||
<SWToolButton appearance="pill" icon={<FitIcon color="#B6D0C9" />} disabled>Fit disabled</SWToolButton>
|
||||
</SWToolGroup>
|
||||
</div>
|
||||
</SWTheme>
|
||||
</Bar>
|
||||
</StorySection>
|
||||
</StoryPage>
|
||||
)
|
||||
}
|
||||
|
||||
export const ToolButtons: Story = { name: "Tool Buttons", render: () => <ToolPage /> }
|
||||
Reference in new issue
Block a user