AI documents (packages/sw/ai)
- SWPopupPropertyRow, SWSelect, SWSlider in the catalog, usage table,
composition patterns and design rules; SWViewerSlider noted as SWSlider panel.
- Rule: the SWHeader layer / color dropdowns are header-only; popup layer /
color / line style use SWPopupPropertyRow (property window pickers).
- Footer rules: gra-border-orange surfaces, Model / Layout text unchanged on
hover, side button hover, vacant surface limited to the slot row.
- Header rules: measured More growing behavior (hysteresis fix A).
- Example E (custom popup) uses SWPopupPropertyRow, SWSelect and SWSlider
instead of SWHeaderLayerMenu in the popup.
Tests (packages/sw/tests)
- New footer-popup-viewer-refinement.browser.mjs (47 checks: footer stories,
hover / gradient / tab text / pocket, popup pickers vs property window rows,
SWSlider, unit SWSelect parity, Popup B, header trace, viewer title art).
- integrated-popup / integrated-consumer: popup pickers and SWSelect instead of
the header dropdown and the HM UI Select (same overlay / callback / Escape
requirements).
- integrated-improvement: default sections skip the retired SW/Tool story
('tool' still runs by name); storybook-inventory / simplification record the
retired footer IDs; theme-inheritance widths use sw-footer--full-footer.
Docs (docs/sw)
- sw-footer-popup-viewer-refinement-2026-10-20.md: causes, decisions (the
first-pass "header dropdown in popup" change is marked withdrawn),
verification and baseline failures; evidence footer-popup-viewer-refinement-qa
(47/47). Footer mapping document updated for the removed sections.
Baseline failures (unchanged by this work): home-menu-integration 1,
storybook-unused-removal 5 (10-19 snapshot comparisons), range-cross-browser and
property-panel-comparison open stories retired on 2026-10-19.
54 lines
3.4 KiB
TypeScript
54 lines
3.4 KiB
TypeScript
// Example E — the SW popup frame with project content (no Header). SWPopup keeps the property window design;
|
|
// children are free: SWPopupSection / SWPopupRow rows with SWHeaderInput, the unit SWSelect, the SWSlider gauge and the
|
|
// popup layer / color pickers (SWPopupPropertyRow). The SWHeader field dropdowns are header-only: never in a popup.
|
|
import { useId, useState } from "react"
|
|
import { SWHeaderInput, SWPopup, SWPopupPropertyRow, SWPopupRow, SWPopupSection, SWSelect, SWSlider, SWTheme } from "@hm-design/sw"
|
|
import { colors, layers } from "./sample-data"
|
|
|
|
export function ExampleECustomPopup({ onEvent }: { onEvent?: (name: string) => void }) {
|
|
const [open, setOpen] = useState(true)
|
|
const nameId = useId()
|
|
const [name, setName] = useState("평면도-01")
|
|
const [scale, setScale] = useState("100")
|
|
const [x, setX] = useState("1200.5")
|
|
const unitId = useId()
|
|
const [unit, setUnit] = useState("mm")
|
|
const [opacity, setOpacity] = useState(60)
|
|
const [activeLayerId, setActiveLayerId] = useState("0")
|
|
const [color, setColor] = useState("255,0,0")
|
|
if (!open) return <button type="button" onClick={() => setOpen(true)}>설정 열기</button>
|
|
return (
|
|
<SWTheme>
|
|
<SWPopup title="도면 설정" onClose={() => { setOpen(false); onEvent?.("popup:close") }}>
|
|
<SWPopupSection title="도면">
|
|
<SWPopupRow label="이름" htmlFor={nameId}>
|
|
<SWHeaderInput id={nameId} value={name} onCommit={next => { setName(next); onEvent?.(`name:${next}`) }} />
|
|
</SWPopupRow>
|
|
<SWPopupRow label="축척" unit="%" numeric>
|
|
<SWHeaderInput aria-label="축척" valueType="number" value={scale} onCommit={next => { setScale(next); onEvent?.(`scale:${next}`) }} />
|
|
</SWPopupRow>
|
|
<SWPopupRow label="단위" htmlFor={unitId} field="none">
|
|
<SWSelect id={unitId} value={unit} options={[{ value: "mm" }, { value: "cm" }, { value: "m" }]} onValueChange={next => { setUnit(next); onEvent?.(`unit:${next}`) }} />
|
|
</SWPopupRow>
|
|
<SWPopupRow label="투명도" field="none" unit="%">
|
|
<SWSlider aria-label="투명도" value={opacity} step={10} onValueChange={setOpacity} onValueCommit={next => onEvent?.(`opacity:${next}`)} />
|
|
</SWPopupRow>
|
|
</SWPopupSection>
|
|
<SWPopupSection title="객체 정보">
|
|
<SWPopupRow label="타입" readOnly><SWHeaderInput aria-label="타입" value="Line" readOnly /></SWPopupRow>
|
|
<SWPopupRow label="X" unit="mm" numeric>
|
|
<SWHeaderInput aria-label="X" valueType="number" value={x} onCommit={next => { setX(next); onEvent?.(`x:${next}`) }} />
|
|
</SWPopupRow>
|
|
</SWPopupSection>
|
|
<SWPopupSection title="레이어 · 색상">
|
|
{/* The property window pickers; their lists open as a fixed overlay, so the scrolling body never clips them. */}
|
|
<SWPopupPropertyRow property={{ id: "layer", name: "레이어", value: activeLayerId, type: "select", groupId: "popup", picker: "layer", options: layers.map(({ id, name }) => ({ id, name })) }}
|
|
menus={{ layers }} onPropertyChange={(_, value) => { setActiveLayerId(value); onEvent?.(`layer:${value}`) }} />
|
|
<SWPopupPropertyRow property={{ id: "color", name: "색상", value: color, type: "color", groupId: "popup" }}
|
|
menus={{ colors }} onPropertyChange={(_, value) => { setColor(value); onEvent?.(`color:${value}`) }} />
|
|
</SWPopupSection>
|
|
</SWPopup>
|
|
</SWTheme>
|
|
)
|
|
}
|