From 3deebf0e90ef7fc127902b141d586c1735f7182e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Thu, 3 Sep 2026 14:45:58 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=A2=84=E8=A7=88=E6=89=8B?= =?UTF-8?q?=E5=8A=BF=E5=8F=96=E6=B6=88=E5=90=8E=E7=9A=84=E7=82=B9=E5=87=BB?= =?UTF-8?q?=E6=8A=91=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 取消、失焦、树切换和无效几何统一清理点击抑制状态 补充 pointercancel 后点击状态回归测试 同步 UI 编辑器预览交互技术方案 --- .../components/preview/useNodeTransformInteraction.ts | 9 ++++++--- .../tests/useNodeTransformInteraction.test.tsx | 1 + .../【技术方案】UI编辑器Godot容器布局模型-2026-08-18.md | 2 ++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/ai-game-creator-shell/src/view/ui-editor/components/preview/useNodeTransformInteraction.ts b/apps/ai-game-creator-shell/src/view/ui-editor/components/preview/useNodeTransformInteraction.ts index fe7edab39..5e14abb66 100644 --- a/apps/ai-game-creator-shell/src/view/ui-editor/components/preview/useNodeTransformInteraction.ts +++ b/apps/ai-game-creator-shell/src/view/ui-editor/components/preview/useNodeTransformInteraction.ts @@ -140,6 +140,7 @@ export function useNodeTransformInteraction({ const gesture = activeGestureRef.current; if (gesture) releasePointer(gesture.target, gesture.pointerId); activeGestureRef.current = null; + suppressNextNodeClickRef.current = false; }, []); useEffect(() => cancelGesture, [cancelGesture]); @@ -250,12 +251,14 @@ export function useNodeTransformInteraction({ const gesture = activeGestureRef.current; if (!gesture || !acceptsGestureEvent(event)) return; event.stopPropagation(); - if (gesture.hasMoved) suppressNextNodeClickRef.current = true; - if (!gesture.hasMoved && isInsidePreview(event, previewRef)) { + const cleanPointerUpInside = + !gesture.hasMoved && isInsidePreview(event, previewRef); + const suppressClick = gesture.hasMoved || cleanPointerUpInside; + if (cleanPointerUpInside) { canvas.selectNode(gesture.hitNodeId); - suppressNextNodeClickRef.current = true; } cancelGesture(); + if (suppressClick) suppressNextNodeClickRef.current = true; }, [acceptsGestureEvent, cancelGesture, canvas, previewRef], ); diff --git a/apps/ai-game-creator-shell/tests/useNodeTransformInteraction.test.tsx b/apps/ai-game-creator-shell/tests/useNodeTransformInteraction.test.tsx index d6d854eb4..6098d858c 100644 --- a/apps/ai-game-creator-shell/tests/useNodeTransformInteraction.test.tsx +++ b/apps/ai-game-creator-shell/tests/useNodeTransformInteraction.test.tsx @@ -188,6 +188,7 @@ describe('useNodeTransformInteraction', () => { result.current.onNodePointerCancel(pointerEvent(target, 2, 0, 0)); }); expect(canvasProjection.selectNode).not.toHaveBeenCalled(); + expect(result.current.consumeNodeClick()).toBe(false); }); it('does not select when a clean pointerup lands outside the preview', () => { diff --git a/docs/technical/【技术方案】UI编辑器Godot容器布局模型-2026-08-18.md b/docs/technical/【技术方案】UI编辑器Godot容器布局模型-2026-08-18.md index d6f828055..ec137834f 100644 --- a/docs/technical/【技术方案】UI编辑器Godot容器布局模型-2026-08-18.md +++ b/docs/technical/【技术方案】UI编辑器Godot容器布局模型-2026-08-18.md @@ -43,4 +43,6 @@ Container 专属数据是互斥 tagged union:HBox/VBox 存 `alignment + separa Preview 的节点选择采用“松开确认”语义:节点或调整手柄按下时只建立指针手势,不立即改变选择;沿用现有 `2px` 屏幕位移阈值(达到阈值即视为拖动),未达到阈值且在预览区域内松开时才选择按下命中的节点,发生拖动、取消、失焦或在区域外松开均不选择。发生拖动时,Transform 更新作用于按下前已选中的节点;没有当前选择时才回退到按下节点。拖动外层节点时,嵌套 child 产生的后续 click 也不得重新选择;未发生拖动时,嵌套 child 仍按实际命中节点选择。 +取消、失焦、树切换或无效几何导致的手势终止会同时清理下一次 click 抑制状态;只有正常 pointerup 才会根据拖动结果抑制后续 click。 + 预览节点层禁止浏览器原生文字选择;拖动手势开始时阻止默认行为,避免 pointer drag 被浏览器解释为文本选取。