// src/main/suggestion-overlay-policy.ts // // 제안 오버레이 표시 전략 (순수 함수) — bootstrap.ts 의 suggestion.on('updated', ...) // 배선에서 쓴다. Electron/서비스 의존이 없는 별도 파일로 뺀 이유: bootstrap.ts 는 // 최상위에서 electron/서비스 모듈을 다수 import 하므로 그대로는 단위 테스트하기 // 어렵다 — 이 판단 로직만 독립적으로 테스트한다. /** * 제안 오버레이를 이번 'updated' 이벤트에 어떻게 반영할지 결정한다. * * 스트리밍 중에는 ~120ms 마다 'updated' 가 온다. 매번 show(=setBounds+present)를 * 부르면 X 클릭이 재present 에 가로채여 먹히지 않고 패널이 튀었다(실측). 오버레이가 * 이미 떠 있으면 내용만 갱신하고, 새로 띄우거나 숨길 때만 위치를 다시 계산한다. */ export function decideSuggestionOverlayAction( overlayVisible: boolean, shouldPresent: boolean ): 'show' | 'update' | 'hide' { if (!shouldPresent) return 'hide' return overlayVisible ? 'update' : 'show' } /** * 평범한 Esc(수정자 없음) keydown 을 제안 닫기로 연결할지 결정한다. * * Escape 는 단독 바인딩이 불가능해(KEY_CATALOG 의 requiresModifier) 등록된 키바인딩 * 경로로는 절대 들어오지 않는다 — bootstrap 이 원본 keydown 을 직접 듣고 이 함수로 * 판단한다. 오버레이가 아무것도 보여주지 않을 때는 반응하지 않는다 — 그때 Esc 를 * 다른 용도로 쓰는 사용자 조작(예: 다른 앱의 대화상자 닫기)을 가로채지 않기 위해서다. * 수정자가 하나라도 눌려 있으면(Ctrl+Esc 등) 평범한 Esc 가 아니므로 반응하지 않는다. */ export function shouldDismissOnEscape( isPresentationActive: boolean, modifiers: { ctrl: boolean; alt: boolean; shift: boolean; meta: boolean } ): boolean { if (!isPresentationActive) return false return !modifiers.ctrl && !modifiers.alt && !modifiers.shift && !modifiers.meta }