Electron과 NextUI 통합 시 발생하는 focus 오류
문제 설명
Electron
과 NextUI
를 함께 사용할 때 간헐적으로 NextUI
가 작동하지 않음
오류의 원인
내부적인 Focus 여부 - isFocusWithin
NextUI
는 내부적으로 포커싱을 isFocusWithin
으로 처리하여 시각화 및 처리에 사용한다.
키보드를 이용한 포커스에 대한 ‘시각화’나 포커스된 Input
의 감춰진 ‘입력 요소’의 등장 등에 내부적인 포커싱 여부값을 판단한다.
그래서 원론적인 포커싱을 한다해도 의미가 없다.
개발자 콘손을 통해서 NextUI
의 Input Component에서 입력부분에 focus
함수를 실행하여도 반응이 없을 것이다.
Electron의 BrowserWindow
는 일반적인 Browser와 다르다
Electron역시 chromium browser를 사용하지만 Node와 통합되어있으며,alert
, confirm
등의 함수가 os
에 맞는 메시지 박스가 표기된다.
이 과정에서 alert
과 confirm
등으로 포커스를 뺏긴 경우 문제가 발생한다.
다시 기존 활성window에 포커스(alert과 confirm등이 닫힌 경우)가 되어도 NextUI
의 내부적인 포커스(isFocusWithin
)는 더 이상 작동하지 않는다.
오류의 증상
Button
과 같은 Component는 focus
여부에 따라 실제 입력 요소가 달라지지 않기 때문에,
키보드를 이용한 포커스가 제대로 표기되지 않더라도 스페이스바
등의 입력으로 정상 작동한다.
다만 Input
과 같이 focus
여부에 따라 실제 입력 요소가 노출되는 등의 행동을 가진 Component라면 문제가 발생하게 된다.
키보드 또는 마우스로 해당 Component에 포커싱을 하여도 NextUI
의 내부적인 포커스(isFocusWithin
)는 이를 감지 하지 못하게 된다.
해결 방안
사용자가 이를 인지하였을 경우 간단한 해결 방법이 존재하는데, 다른 창으로 포커스를 전환하였다가 복귀하는 것이다. (windows 기준 alt + Tab
과 같은 동작)
이러면 NextUI
의 Component가 다시 isFocusWithin
에 제대로 값을 할당하기 시작한다.
하지만 사용성을 고려해 이러한 상황이 발생할 때
프로그래밍 적으로 활성창에서 포커스를 잃게하고 다시 포커스를 잡아준다면 더 좋을 같다.
ipcMain
/ ipcRenderder
Electron
에서는 renderer process(Browser)와 main process(Node.js)의 가용 기능이 다르다.
그렇기에 ipc채널을 통해 renderer process에서 사용이 가능하게 구성하였다.
// src/ipcMethods.ts
ipcMain.handle( 'forceFocus', async () => {
const temp = new BrowserWindow( { height: 0, width: 0 } )
temp.close()
return
} )
// src/**/사용할 곳.ts(x)?
function foo() {
window.alert( /* ... */ ) // or window.confirm
ipcRenderer.invoke( 'forceFocus' )
}
이렇게 되면 자연스럽게 메세지 박스가 닫힌 이후 활성창에 정상적으로 포커스를 획득할 수 있다.
예방 전략
alert
과 confirm
과 같은 함수를 실행할 때 마다 위와 같은 핸들링을 해줄 필요 없이Electron
의 preload(renderder process와 같이 브라우저 맥락이다)에서 핸들링이 필요한 함수를 오버라이딩 하자.
// preload.ts
import { useIpcRenderer } from './react/hooks/useIpcRenderer'
/*
여기서 useIpcRenderer는 react hooks의 기능이 사용되지 않아, 외부에서 호출하여도 문제 없다.
일반적인 ipcRenderer와 동일하나, handle에 등록한 체널에 대한 자동완성과
전달인자 혹은 return 되는 값등에 type을 명시하기 위한 장치이다.
(기본 ipcRenderder.invoke함수의 ArgsType과 ReturnType은 각각 any[], Promise<any> 이다)
*/
const oldFn = {
alert,
confirm,
}
const PreLoad = () => {
const { ipcRenderer } = useIpcRenderer()
;( { alert: window.alert, confirm: window.confirm } = Object.fromEntries(
Object.entries( oldFn ).map( ( [key, fn] ) => [
key,
( ...arg: any[] ) => {
try {
return fn( ...arg )
} finally {
ipcRenderer.invoke( 'forceFocus' )
}
},
] ),
) as typeof oldFn )
}
PreLoad()
결론
Electron
과 NextUI
를 함께 사용할 때 발생하는 focus 오류는 사용자 경험에 큰 영향을 미칠 수 있는 중요한 문제로,
이 문제의 주요 원인은 NextUI
의 내부적인 focus 처리 방식과 Electron
의 특수한 window 관리 방식의 충돌에 있다.
이를 해결하기 위해 아래의 방법을 진행했다.
- 문제의 원인을 파악하고 분석
Electron
의 ipcMain과 ipcRenderer를 활용하여 프로그래밍적으로 focus를 재설정하는 방법을 구성alert
과confirm
함수를 오버라이딩하여 자동으로 focus 문제를 해결하도록 구현
이러한 해결책은 사용자가 별도의 조치를 취하지 않아도 자연스럽게 UI 상호작용이 가능하도록 한다.
또한, 이 접근 방식은 다른 유사한 상황에서도 응용될 수 있어, Electron과 다양한 UI 라이브러리를 통합할 때 발생할 수 있는 문제들에 대한 방안이 될 수도 있을 것 같다.
'JavaScript | 자바스크립트 > Electron' 카테고리의 다른 글
Electron IPC 통신 사용성 올리기 (2) | 2024.11.15 |
---|
댓글