fix(desktop): 네이티브 위젯 picker를 창 전체 뷰로 전환

portal/overlay 대신 widget-main에서 picker 전용 화면으로 전환해
macOS·Windows WebView 모두에서 위젯 선택 팝업이 보이도록 합니다.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Macbook
2026-06-15 16:49:25 +09:00
parent 1804328b9b
commit 36b4679c9a
4 changed files with 130 additions and 73 deletions
@@ -24,7 +24,9 @@ interface Props {
onUpdateGridFr: (rowFr: number[], colFr: number[]) => void;
/** Tauri OS 창 — 네이티브 타이틀·리사이즈 사용, 내부 플로팅 크롬 숨김 */
nativeShell?: boolean;
/** 위젯 선택 팝업 열림/닫힘 (네이티브 창 크기 조절 — 완료 후 picker 표시) */
/** 네이티브 위젯 창 — picker는 부모(widget-main)에서 전환 렌더 */
onNativePickRequest?: (slotId: string) => void;
/** 위젯 선택 팝업 열림/닫힘 (웹 플로팅 레이어용) */
onPickerOpenChange?: (open: boolean) => void | Promise<void>;
}
@@ -37,27 +39,22 @@ const FloatingWidgetWindow: React.FC<Props> = ({
onUpdateSize,
onUpdateGridFr,
nativeShell = false,
onNativePickRequest,
onPickerOpenChange,
}) => {
const [pickSlotId, setPickSlotId] = useState<string | null>(null);
const nativePickerExternal = nativeShell && Boolean(onNativePickRequest);
const openPicker = useCallback((slotId: string) => {
if (nativePickerExternal) {
onNativePickRequest!(slotId);
return;
}
setPickSlotId(slotId);
if (nativeShell) {
document.documentElement.classList.add('fw-native-picker-open');
}
if (nativeShell && onPickerOpenChange) {
void Promise.resolve(onPickerOpenChange(true)).catch(err => {
console.warn('[FloatingWidgetWindow] picker window resize failed', err);
});
}
}, [nativeShell, onPickerOpenChange]);
}, [nativePickerExternal, onNativePickRequest]);
const closePicker = useCallback(async () => {
setPickSlotId(null);
if (nativeShell) {
document.documentElement.classList.remove('fw-native-picker-open');
}
if (nativeShell && onPickerOpenChange) {
try {
await onPickerOpenChange(false);
@@ -66,9 +63,6 @@ const FloatingWidgetWindow: React.FC<Props> = ({
}
}
}, [nativeShell, onPickerOpenChange]);
useEffect(() => () => {
document.documentElement.classList.remove('fw-native-picker-open');
}, []);
const bodyWrapRef = useRef<HTMLDivElement>(null);
const bodyRef = useRef<HTMLDivElement>(null);
@@ -265,7 +259,7 @@ const FloatingWidgetWindow: React.FC<Props> = ({
<WidgetSlotView
slot={slot}
zoneId="center"
onPickWidget={id => { void openPicker(id); }}
onPickWidget={id => { openPicker(id); }}
onClearWidget={id => clearWidget(id)}
/>
</div>
@@ -322,7 +316,7 @@ const FloatingWidgetWindow: React.FC<Props> = ({
</>
);
const pickerModal = pickSlotId != null ? (
const pickerModal = !nativePickerExternal && pickSlotId != null ? (
<WidgetPickerModal
open
category="all"
@@ -333,12 +327,7 @@ const FloatingWidgetWindow: React.FC<Props> = ({
) : null;
if (nativeShell) {
return (
<>
{content}
{pickerModal && createPortal(pickerModal, document.body)}
</>
);
return content;
}
return createPortal(