diff --git a/packages/sw/ai/COMPOSITION_PATTERNS.md b/packages/sw/ai/COMPOSITION_PATTERNS.md
index 8ecc588..061fb2c 100644
--- a/packages/sw/ai/COMPOSITION_PATTERNS.md
+++ b/packages/sw/ai/COMPOSITION_PATTERNS.md
@@ -155,8 +155,7 @@ const groups: SWViewerHeaderGroup[] = [
setAbout(true)} />
>} />
- setOptionsOpen(false)} width={340} height="auto"
- footer={적용}>
+ setOptionsOpen(false)} width={340} height="auto">
{id => }
}>
diff --git a/packages/sw/ai/VIEWER.md b/packages/sw/ai/VIEWER.md
index e23d974..56c390f 100644
--- a/packages/sw/ai/VIEWER.md
+++ b/packages/sw/ai/VIEWER.md
@@ -107,6 +107,7 @@
- 클릭하면 그 레이어 하나의 가시성만 바꾸고 프로그램의 가시성 Callback·상태를 그대로 호출합니다. 아이콘만 그리고 기능을 빼지 않습니다.
- 전체 레이어 Switch(2026-10-22 제목 형식): ``. 제목은 기존 Section 제목(`.hm-sw-viewer-section__title`, 12px 700)을 그대로 쓰고 별도 제목 CSS·Prop을 만들지 않습니다. 제목과 Switch를 한 줄에 두는 것은 소비 앱 자기 class(예: `section.app-viewer-all-layers { flex-direction: row; align-items: center; justify-content: space-between; min-height: 20px }`, 예제 `example-layout.css`)로 하고 `hm-sw-viewer-*` class는 덮지 않습니다. `checked`는 모든 레이어가 표시 중일 때만 `true`이고, 일부만 표시 중이면 `false`로 보이며 누르면 전체 표시가 됩니다. ON → 전체 표시, OFF → 전체 숨김. 별도 상태를 두지 않고 레이어 가시성 상태에서 계산하므로 개별 전환 시 자동으로 맞춰집니다. 이전의 `전체 켜기`·`전체 끄기` 버튼 두 개는 쓰지 않습니다.
- 그 밖의 `SWViewerSwitch`는 옵션 패널의 ON/OFF 설정(그리드·2.5D 등)에 씁니다.
+- **옵션(설정) 패널(2026-10-22):** 하단 `취소`·`적용` 버튼이 없습니다(`footer` 미사용 → Footer 영역·구분선도 없음). 토글·Input·Slider는 바뀌는 즉시 프로그램 상태에 반영하고, 기본값 복원은 제목 막대의 초기화(`headerActions`) 버튼입니다. 확인이 필요한 입력 팝업(축척 지정 등)의 `footer`는 그대로 씁니다.
### 4.2 패널 콘텐츠 글자 기준 (2026-10-22)
diff --git a/packages/sw/ai/examples/ExampleH-ViewerMode.tsx b/packages/sw/ai/examples/ExampleH-ViewerMode.tsx
index 36a9537..975b653 100644
--- a/packages/sw/ai/examples/ExampleH-ViewerMode.tsx
+++ b/packages/sw/ai/examples/ExampleH-ViewerMode.tsx
@@ -98,8 +98,7 @@ export function ExampleHViewerMode({ onEvent }: { onEvent?: (name: string) => vo
- setPanels({ ...panels, options: false })} width={340} height="auto" inset={{ side: 356 }}
- footer={ { onEvent?.("options:apply"); setPanels({ ...panels, options: false }) }}>적용}>
+ setPanels({ ...panels, options: false })} width={340} height="auto" inset={{ side: 356 }}>
{id => }
}>
diff --git a/src/sw/sw-viewer-fixture.tsx b/src/sw/sw-viewer-fixture.tsx
index c66e693..0c45eb3 100644
--- a/src/sw/sw-viewer-fixture.tsx
+++ b/src/sw/sw-viewer-fixture.tsx
@@ -157,13 +157,13 @@ function SliderRow({ label, unit, value, min, max, step, disabled, onChange }: {
)
}
-export function OptionsPanel({ demo, footer, ...placement }: { demo: ViewerDemo; footer?: boolean } & PanelPlacement) {
+export function OptionsPanel({ demo, ...placement }: { demo: ViewerDemo } & PanelPlacement) {
const { options, setOptions } = demo
const set = (patch: Partial) => setOptions({ ...options, ...patch })
return (
demo.toggle("options", false)} width={340} height={520} {...placement}
- headerActions={ { setOptions(DEFAULT_OPTIONS); demo.record("options:reset") }}>}
- footer={footer ? <> demo.toggle("options", false)}>취소 { demo.record("options:apply"); demo.toggle("options", false) }}>적용> : undefined}>
+ headerActions={ { setOptions(DEFAULT_OPTIONS); demo.record("options:reset") }}>}>
+ {/* 2026-10-22: no 취소 / 적용 footer — every toggle, input and slider applies at once. */}
{/* 2026-10-22 options image: LWDISPLAY toggle; scale input + px/mm unit on the label row, slider below. */}
{id => set({ lineweightOn })} />}
diff --git a/src/sw/sw-viewer.stories.tsx b/src/sw/sw-viewer.stories.tsx
index c516570..f66779a 100644
--- a/src/sw/sw-viewer.stories.tsx
+++ b/src/sw/sw-viewer.stories.tsx
@@ -261,7 +261,7 @@ export const SettingsPanel: Story = {
}>
-
+
)
@@ -291,7 +291,7 @@ export const ContentVariants: Story = {
{id => demo.record(`unit=${value}`)} data-sw-select="unit" />}
-
+
{!inputOpen && }