diff --git a/apps/desktop/src/renderer/src/components/SidePanel.tsx b/apps/desktop/src/renderer/src/components/SidePanel.tsx index 043ac04..8013d40 100644 --- a/apps/desktop/src/renderer/src/components/SidePanel.tsx +++ b/apps/desktop/src/renderer/src/components/SidePanel.tsx @@ -70,18 +70,26 @@ export function SidePanel({ onWidthChange(Math.min(PANEL_MAX_WIDTH, Math.max(PANEL_MIN_WIDTH, dragRef.current.startWidth + delta))) } const onUp = (): void => { + if (!dragRef.current) return dragRef.current = null + document.body.style.userSelect = '' } window.addEventListener('pointermove', onMove) window.addEventListener('pointerup', onUp) return () => { window.removeEventListener('pointermove', onMove) window.removeEventListener('pointerup', onUp) + document.body.style.userSelect = '' } }, [onWidthChange]) const startResize = (e: React.PointerEvent): void => { + // preventDefault 必须在 pointerdown 上:否则 Chromium 会把它当作文本选择 + // 手势的锚点,拖动经过聊天区/面板文字时把沿途内容选中;拖拽期间再对 + // body 全局禁选(双保险,覆盖手势未被拦截的边缘情况),松手恢复 + e.preventDefault() dragRef.current = { startX: e.clientX, startWidth: width } + document.body.style.userSelect = 'none' } // 菜单打开时 Esc 关闭