diff --git a/web/src/components/model-picker.tsx b/web/src/components/model-picker.tsx index 748bf5585..4e31f2f7e 100644 --- a/web/src/components/model-picker.tsx +++ b/web/src/components/model-picker.tsx @@ -62,6 +62,19 @@ export function ModelPicker({ config, value, onChange, capability, className, fu return () => window.removeEventListener("model-picker-open", closeOtherPicker); }, [pickerId]); + useEffect(() => { + if (!open) return; + // 画布拖拽从 pointerdown 开始,须在捕获阶段关闭 Portal 菜单,避免菜单与触发器分离。 + const closeOnOutsidePointer = (event: PointerEvent) => { + const target = event.target; + if (!(target instanceof Node)) return; + if (triggerRef.current?.contains(target) || menuRef.current?.contains(target)) return; + setOpen(false); + }; + window.addEventListener("pointerdown", closeOnOutsidePointer, true); + return () => window.removeEventListener("pointerdown", closeOnOutsidePointer, true); + }, [open]); + const setPickerOpen = (nextOpen: boolean) => { if (nextOpen && !options.length && config.channelMode === "local") onMissingConfig?.(); if (nextOpen) window.dispatchEvent(new CustomEvent("model-picker-open", { detail: pickerId }));