diff --git a/desktop/src/widget-main.tsx b/desktop/src/widget-main.tsx index 147df9e..4663047 100644 --- a/desktop/src/widget-main.tsx +++ b/desktop/src/widget-main.tsx @@ -139,33 +139,39 @@ const WidgetApp: React.FC = () => { const handlePickerOpenChange = useCallback(async (open: boolean): Promise => { const win = getCurrentWindow(); - if (open) { - const size = await win.innerSize(); - sizeBeforePickerRef.current = { width: size.width, height: size.height }; - const maxW = Math.max(480, window.screen.availWidth - 48); - const maxH = Math.max(520, window.screen.availHeight - 48); - const w = Math.min(NATIVE_WIDGET_PICKER_WINDOW.width, maxW); - const h = Math.min(NATIVE_WIDGET_PICKER_WINDOW.height, maxH); - await win.setSize(new LogicalSize(w, h)); - await win.center(); - await new Promise(resolve => { - let settled = false; - const finish = () => { - if (settled) return; - settled = true; - unlisten?.(); - resolve(); - }; - let unlisten: (() => void) | undefined; - void win.onResized(finish).then(fn => { unlisten = fn; }); - window.setTimeout(finish, 150); - }); - return; + try { + if (open) { + const size = await win.innerSize(); + sizeBeforePickerRef.current = { width: size.width, height: size.height }; + const maxW = Math.max(480, window.screen.availWidth - 48); + const maxH = Math.max(520, window.screen.availHeight - 48); + const w = Math.min(NATIVE_WIDGET_PICKER_WINDOW.width, maxW); + const h = Math.min(NATIVE_WIDGET_PICKER_WINDOW.height, maxH); + await win.setSize(new LogicalSize(w, h)); + await win.center(); + await Promise.race([ + new Promise(resolve => { + let settled = false; + const finish = () => { + if (settled) return; + settled = true; + unlisten?.(); + resolve(); + }; + let unlisten: (() => void) | undefined; + void win.onResized(finish).then(fn => { unlisten = fn; }); + }), + new Promise(resolve => { window.setTimeout(resolve, 400); }), + ]); + return; + } + const prev = sizeBeforePickerRef.current; + if (!prev) return; + sizeBeforePickerRef.current = null; + await win.setSize(new LogicalSize(prev.width, prev.height)); + } catch (err) { + console.warn('[widget-main] picker window resize failed', err); } - const prev = sizeBeforePickerRef.current; - if (!prev) return; - sizeBeforePickerRef.current = null; - await win.setSize(new LogicalSize(prev.width, prev.height)); }, []); if (!instance) { diff --git a/frontend/src/components/floatingWidgets/FloatingWidgetWindow.tsx b/frontend/src/components/floatingWidgets/FloatingWidgetWindow.tsx index 8354c07..a1114ef 100644 --- a/frontend/src/components/floatingWidgets/FloatingWidgetWindow.tsx +++ b/frontend/src/components/floatingWidgets/FloatingWidgetWindow.tsx @@ -40,29 +40,36 @@ const FloatingWidgetWindow: React.FC = ({ onPickerOpenChange, }) => { const [pickSlotId, setPickSlotId] = useState(null); - const [pickerOpening, setPickerOpening] = useState(false); - const openPicker = useCallback(async (slotId: string) => { - if (nativeShell && onPickerOpenChange) { - setPickerOpening(true); - try { - await onPickerOpenChange(true); - await new Promise(resolve => { - requestAnimationFrame(() => requestAnimationFrame(() => resolve())); - }); - } finally { - setPickerOpening(false); - } - } + const openPicker = useCallback((slotId: string) => { setPickSlotId(slotId); + if (nativeShell) { + document.documentElement.classList.add('fw-native-picker-open'); + } + if (nativeShell && onPickerOpenChange) { + void onPickerOpenChange(true).catch(err => { + console.warn('[FloatingWidgetWindow] picker window resize failed', err); + }); + } }, [nativeShell, onPickerOpenChange]); const closePicker = useCallback(async () => { setPickSlotId(null); + if (nativeShell) { + document.documentElement.classList.remove('fw-native-picker-open'); + } if (nativeShell && onPickerOpenChange) { - await onPickerOpenChange(false); + try { + await onPickerOpenChange(false); + } catch (err) { + console.warn('[FloatingWidgetWindow] picker window restore failed', err); + } } }, [nativeShell, onPickerOpenChange]); + useEffect(() => () => { + document.documentElement.classList.remove('fw-native-picker-open'); + }, []); + const bodyWrapRef = useRef(null); const bodyRef = useRef(null); const [bodySize, setBodySize] = useState({ width: 0, height: 0 }); @@ -312,23 +319,35 @@ const FloatingWidgetWindow: React.FC = ({ )} - - {(pickerOpening || pickSlotId != null) && ( - { void closePicker(); }} - onSelect={applyWidgetType} - /> - )} - {pickerOpening && pickSlotId == null && nativeShell && ( -
위젯 목록 준비 중…
- )} ); - return nativeShell ? content : createPortal(content, document.body); + const pickerModal = pickSlotId != null ? ( + { void closePicker(); }} + onSelect={applyWidgetType} + /> + ) : null; + + if (nativeShell) { + return ( + <> + {content} + {pickerModal && createPortal(pickerModal, document.body)} + + ); + } + + return createPortal( + <> + {content} + {pickerModal} + , + document.body, + ); }; export default FloatingWidgetWindow; diff --git a/frontend/src/styles/widgetDashboard.css b/frontend/src/styles/widgetDashboard.css index 654d388..141d1b2 100644 --- a/frontend/src/styles/widgetDashboard.css +++ b/frontend/src/styles/widgetDashboard.css @@ -1329,6 +1329,16 @@ html.fw-native-widget .wd-picker-native-loading { font-size: 13px; } +html.fw-native-widget.fw-native-picker-open .fw-widget-native-root .fw-window { + visibility: hidden; + pointer-events: none; +} + +html.fw-native-widget.fw-native-picker-open .wd-picker-native-overlay { + padding: 0; + background: var(--bg, #1a1b26); +} + .bps-page--wd-no-left .bps-side-wrap--left, .bps-page--wd-no-left .bps-side-wrap--left + .bps-splitter { display: none !important;