From 65e06c480804eca5da72496cf8c04d1ba0b04f6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Tue, 22 Sep 2026 15:25:32 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=B0=E5=BD=95=E9=A2=84=E8=A7=88=E7=94=BB?= =?UTF-8?q?=E5=B8=83=E5=8F=B3=E9=94=AE=E6=8B=96=E6=8B=BD=E5=B9=B3=E7=A7=BB?= =?UTF-8?q?=E7=9A=84=E4=BA=A4=E4=BA=92=E7=BA=A6=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - decision-log 新增 2026-09-22 条目:右键拖拽平移的判定链、菜单改到抬起弹出、按下即拦截 contextmenu 的实测依据与代价 - 【UI编辑器】拖动变换提交边界补「视口平移不写 State、不进历史」以及右键平移与节点菜单按同一拖动阈值互斥的约定 - 同一文档的实现边界补拖动阈值落点 previewDragThreshold.ts 与右键裁决落点 previewRightPanGesture.ts --- docs/project-memory/shared-memory/decision-log.md | 8 ++++++++ docs/【UI编辑器】拖动变换提交边界-2026-09-03.md | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 96c7654be..cd04aecea 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -1,5 +1,13 @@ # 决策记录 +## 2026-09-22 UI 编辑器预览画布补上右键拖拽平移,节点菜单改为右键抬起弹出 + +- 背景:预览画布此前只有中键与空格+左键平移,右键整段留给节点操作菜单(`UiTreeRenderer.onContextMenu` 直接弹 `UiNodeContextMenu`)。这次要补右键拖拽平移,并要求"拖拽过就不许再触发右键菜单"。实测(Linux Chromium 151 / Firefox 151,真实 X11 输入)确认 `contextmenu` 在**按下**瞬间触发,且原生菜单一旦弹出,页面之后收不到任何 `pointermove` / `pointerup` / `mouseup` / `auxclick`,所以"先让菜单弹、拖拽时再关"在浏览器层面不可行;headless 没有原生菜单,Playwright 复现不出该行为。macOS 的 `contextmenu` 在 mouseup 触发(本容器无法实测),但同一条实现路径对两种时序都成立。 +- 决策:预览视口在捕获阶段拦截按钮 2 的 `contextmenu`(`preventDefault` + `stopPropagation`),右键手势改由预览自己裁决:按下时记录起点、`setPointerCapture` 并交焦点;移动越过与左键拖拽共用的 `DRAG_THRESHOLD_SCREEN_PX`(2px)后本次手势定死为平移,按"按下点全量 delta"更新视口(光标复用共享 `CanvasViewport` 的 `isPanning` → `cursor: grabbing`,三个平移绑定一起生效);未越阈值且在预览内抬起时,用 `[data-node-id]` 加树容器 `data-tree-id` 命中节点并打开 `UiNodeContextMenu`,保留"右键即选中该节点"的既有语义;空白处干净右键不做事(原生菜单已被抑制)。中键、空格+左键平移不变,macOS ctrl+左键与键盘菜单键继续走原有即时菜单路径;平移是纯视图操作,不写 State、不进历史、不受 `isLocked` 与空格按住态限制。 +- 原因:右键同时承载菜单与视图平移,只能等到手势结束再裁决;把判定放进预览,是因为树、节点命中、预览边界与拖动阈值都在预览手里,而 `useNodeTransformInteraction` 应保持左键变换的单一职责;`[data-node-id]` 命中也已是 `resolveHitNodeId` 的既有模式。 +- 代价与取舍:右键从"按下即弹菜单"变成"抬起才弹"(与 Windows 自身右键菜单一致);预览内空白处的浏览器原生菜单被永久抑制;右键平移与节点菜单互斥(越过阈值后抬起不再弹菜单);`grabbing` 光标在悬停到节点上时仍会被节点自身的 `cursor-move` 覆盖,与共享画布现状一致。本次只改 UI 编辑器预览:AGC 美术画布仍只有空格/中键平移,资源画布保留自己的右键平移实现,都不动,也不抽 `packages/shared`。 +- 验证方式:新增 `previewRightPanGesture` 纯状态机单测(阈值跨越、起点全量 delta、拖拽吞菜单 / 干净抬起开菜单、取消与失焦清理),并在 `previewWorkspaceZoom.test.tsx`、`uiEditorPreview.test.tsx` 补右键回归;运行 `npx vitest run`(定向文件)、`apps/ai-game-creator-shell` `npm run typecheck`、`npm run lint:eslint`、`npm run check:encoding`、`git diff --check`。 + ## 2026-09-21 合并 origin/master:Supervisor 永久退役,策划 V1V2 退役落到当前两条产品路径 - 背景:`refactor/split-direct-project`(DirectProject 独立聊天容器)与 `origin/master`(#355 退役策划 Agent V1/V2)在 2026-09-18 之后各走一条线:本分支删掉 Supervisor 前端链路、把立项策划收敛到 `view/project-development/planning/`,master 删掉整套策划 V1/V2(前端会话 / 审批卡 / 适配器 / 类型与 Rust `planning_*_v2` 命令、`planning_gdd_model.rs`、`planning_policy_v2.rs`、`planning_session_v2.rs`)只保留 Design Agent。两边都在删 Supervisor,冲突集中在 `App.tsx`、聊天视图(`PlanningChatView`、`DirectProjectTurn`、`ToolCallGroup`)、Direct composer / 引用输入区、`styles.css`、Rust direct user item 与 appSurface 用例。 diff --git a/docs/【UI编辑器】拖动变换提交边界-2026-09-03.md b/docs/【UI编辑器】拖动变换提交边界-2026-09-03.md index 6988d039d..0126fa762 100644 --- a/docs/【UI编辑器】拖动变换提交边界-2026-09-03.md +++ b/docs/【UI编辑器】拖动变换提交边界-2026-09-03.md @@ -6,9 +6,13 @@ UI 编辑器预览中的节点拖动和缩放在指针移动期间只更新预 指针取消、页面切换、树切换、组件卸载或没有超过拖动阈值时,不提交变换,并清理临时预览值。指针松开后的最终变换属于正常 State 修改,会参与脏状态、保存和后端持久化;仅拖动期间的临时变换不会进入这些流程。资产文件也不会因该交互被删除。 +画布视口平移(空格+左键、中键、右键拖拽)属于视图操作:只改前端视口,不写编辑器 State,也不进撤销重做历史。右键同时承载节点菜单,两者按同一个拖动阈值互斥——按下后越过阈值即判定为平移,抬起时不再弹菜单;未越阈值且在预览内抬起才弹节点菜单。预览内按钮 2 的 `contextmenu` 由预览拦截(按下即触发,不能等到手势结束),因此右键菜单在指针抬起时才出现。 + ## 实现边界 - `useNodeTransformInteraction` 保存手势起始变换和最后一次有效变换。 - `UiTreeRenderer` 通过 `previewTransforms` 渲染临时变换。 - `canvas.updateNodeTransform` 仅在 `pointerup` 提交,`pointercancel` 不提交。 - 拖动和缩放继续共用单指针捕获与有限数校验。 +- 拖动阈值抽到 `previewDragThreshold.ts`,左键拖动与右键平移共用同一个 `DRAG_THRESHOLD_SCREEN_PX`。 +- 右键平移与菜单裁决放在预览的 `previewRightPanGesture.ts` 纯状态机里,`useNodeTransformInteraction` 只负责左键拖动与缩放。