From 126a35d60d24b6131570afe55367e75366be1ebb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=88=98=ED=98=84?= Date: Tue, 20 Oct 2026 15:19:56 +0900 Subject: [PATCH] feat(sw): popup controls, SWSelect / SWSlider, footer and viewer design fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Components (new public exports, existing APIs unchanged) - SWPopupPropertyRow: the property window row (layer / color / line style pickers, Figma 26:12250 / 26:12170) for SWPopup content. The SWHeader field dropdowns stay header-only; Popup B and 도면 설정 now use the popup pickers. - SWSelect: native panel select (28px, 1px #948871, radius 4, #F1ECE1, 12px), used by Popup 도면 설정 단위 and Viewer 축척 지정 단위 (replaces the HM UI Select there and the story-only .sw-viewer-story-select CSS). - SWSlider: appearance "panel" (default, the gauge the popup used) or "property" (the property window gauge), same value / events. Shares the property gauge CSS; SWViewerSlider renders SWSlider panel with viewer tokens. Footer - --hm-sw-footer-gra-border-orange (Figma gra-border-orange; the aux selected border token now references it): Model selected / hover, Layout hover and Layout + hover surfaces; 보조기능 / 명령어 전체보기 hover lights both lines and an orange ring; category + hover in #FF5C00 (menu-add-hover.svg). - Model / Layout text stays the Default text (#161410, 12px, 400, no outline) on hover and on the orange surface: only the surface changes. - bg_vacant covers the slot row only: the open pocket of a category tab no longer splits where it crosses the last command (e.g. 수정 with one command). Viewer - Panel title art keeps 308px (max-width: none against host img resets), so panels under 312px (250 x auto, 300px) paint the title from the left edge. Storybook - SW/Footer: 기본 Footer (sw-footer--default) and States (sw-footer--states) removed; full-footer keeps the live composition only, responsive keeps the widths (reference / Figma image sections removed, image files kept); the aux Figma comparison moved to the verification Story figma-variants. - SW/Popup: unit SWSelect, SWSlider A / B section, popup pickers, Popup B state. --- .../sw-footer/assets/menu-add-hover.svg | 12 ++ .../components/SWHeaderPropertyPanel.tsx | 3 +- .../sw/src/components/sw-popup/SWPopup.tsx | 25 ++- .../sw/src/components/sw-select/SWSelect.tsx | 35 +++++ .../sw/src/components/sw-slider/SWSlider.tsx | 51 ++++++ .../components/sw-viewer/SWViewerControls.tsx | 15 +- packages/sw/src/index.ts | 8 +- packages/sw/src/theme/sw-footer.css | 86 +++++++--- packages/sw/src/theme/sw-viewer.css | 28 ++-- packages/sw/src/theme/sw.css | 56 +++++-- src/sw/sw-footer-stories.css | 7 - src/sw/sw-footer.stories.tsx | 148 +++--------------- src/sw/sw-popup.stories.tsx | 79 +++++++--- src/sw/sw-viewer-stories.css | 1 - src/sw/sw-viewer.stories.tsx | 4 +- 15 files changed, 349 insertions(+), 209 deletions(-) create mode 100644 packages/sw/src/components/sw-footer/assets/menu-add-hover.svg create mode 100644 packages/sw/src/components/sw-select/SWSelect.tsx create mode 100644 packages/sw/src/components/sw-slider/SWSlider.tsx diff --git a/packages/sw/src/components/sw-footer/assets/menu-add-hover.svg b/packages/sw/src/components/sw-footer/assets/menu-add-hover.svg new file mode 100644 index 0000000..8b6dc9b --- /dev/null +++ b/packages/sw/src/components/sw-footer/assets/menu-add-hover.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/packages/sw/src/components/sw-header/components/SWHeaderPropertyPanel.tsx b/packages/sw/src/components/sw-header/components/SWHeaderPropertyPanel.tsx index 21b42c2..6aa568d 100644 --- a/packages/sw/src/components/sw-header/components/SWHeaderPropertyPanel.tsx +++ b/packages/sw/src/components/sw-header/components/SWHeaderPropertyPanel.tsx @@ -176,7 +176,8 @@ export function useSWHeaderOverlay(anchorRef: RefObject | un return { panelRef, style } } -function PropertyEditor({ property, onChange, menus }: { property: SWHeaderProperty; onChange?: SWHeaderPropertyPanelProps["onPropertyChange"]; menus?: SWHeaderPropertyMenus }) { +/** One property window row (label + field / picker). Also SWPopupPropertyRow (2026-10-20). */ +export function PropertyEditor({ property, onChange, menus }: { property: SWHeaderProperty; onChange?: SWHeaderPropertyPanelProps["onPropertyChange"]; menus?: SWHeaderPropertyMenus }) { const inputId = useId() const inputRef = useRef(null) const { type, value, disabled, mixed, readOnly, unit } = property diff --git a/packages/sw/src/components/sw-popup/SWPopup.tsx b/packages/sw/src/components/sw-popup/SWPopup.tsx index 71b1c59..8e68fa8 100644 --- a/packages/sw/src/components/sw-popup/SWPopup.tsx +++ b/packages/sw/src/components/sw-popup/SWPopup.tsx @@ -1,5 +1,5 @@ import { cloneElement, isValidElement, type HTMLAttributes, type MouseEvent, type ReactNode, type RefObject } from "react" -import { SWPopupFrame } from "../sw-header/components/SWHeaderPropertyPanel" +import { PropertyEditor, SWPopupFrame, type SWHeaderProperty, type SWHeaderPropertyMenus } from "../sw-header/components/SWHeaderPropertyPanel" export interface SWPopupProps extends Omit, "title"> { /** Title text (700, #FFC600, ellipsis). */ @@ -99,3 +99,26 @@ export function SWPopupRow({ label, htmlFor, unit, field = "box", numeric, readO ) } + +export interface SWPopupPropertyRowProps { + /** One property (the SWHeaderPropertyPanel record): name, value, type and, for layer / color / line style, `picker`. */ + property: SWHeaderProperty + /** Lists and callbacks of the field dropdowns (layers, colors, line types …), as in SWHeaderPropertyPanel. */ + menus?: SWHeaderPropertyMenus + /** Validated commit of the row (value = the chosen row id or the entered value). The host updates `property`. */ + onPropertyChange?: (property: SWHeaderProperty, value: string) => void + className?: string +} + +/** + * A property window row inside SWPopup / SWPopupSection (2026-10-20): the popup field controls of the property window + * (Figma 26:12250 layer, 26:12170 color, 26:12388 line style, number / text / select fields) with their popup look + * and behavior. Use it for layer / color pickers in a popup; the SWHeader field dropdowns are header-only. + */ +export function SWPopupPropertyRow({ property, menus, onPropertyChange, className }: SWPopupPropertyRowProps) { + return ( +
+ +
+ ) +} diff --git a/packages/sw/src/components/sw-select/SWSelect.tsx b/packages/sw/src/components/sw-select/SWSelect.tsx new file mode 100644 index 0000000..26652ed --- /dev/null +++ b/packages/sw/src/components/sw-select/SWSelect.tsx @@ -0,0 +1,35 @@ +import { forwardRef, type ReactNode, type SelectHTMLAttributes } from "react" + +export interface SWSelectOption { + value: string + /** Shown text. Default `value`. */ + label?: string + disabled?: boolean +} + +export interface SWSelectProps extends Omit, "value" | "defaultValue" | "onChange"> { + /** Controlled value. */ + value?: string + /** Uncontrolled initial value. */ + defaultValue?: string + /** Options as data. `children` (`