From 901534519fb235dd76a746f07a1a8d11b00dc5d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Thu, 20 Aug 2026 11:42:27 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8F=A0=E5=8A=A0=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E5=AD=90=E8=8A=82=E7=82=B9=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 从互斥模式切回叠加模式时恢复全部直接子节点可见 补充模式切换回归测试并同步实施合同 --- .../src/view/ui-editor/useUiEditorPage.ts | 13 +++++++++++++ .../tests/uiEditorPage.test.ts | 7 +++++++ ...术方案】AI游戏创作智能体App实施计划-2026-06-24.md | 2 +- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/apps/ai-game-creator-shell/src/view/ui-editor/useUiEditorPage.ts b/apps/ai-game-creator-shell/src/view/ui-editor/useUiEditorPage.ts index d58bcf6df..a269f7cd8 100644 --- a/apps/ai-game-creator-shell/src/view/ui-editor/useUiEditorPage.ts +++ b/apps/ai-game-creator-shell/src/view/ui-editor/useUiEditorPage.ts @@ -741,11 +741,24 @@ export function useUiEditorSession( function setNodeChildrenDisplayMode(mode: ChildrenDisplayMode) { if (!activeImageId || !selectedNodeId) return; + const selectedNode = treeForActiveImage + ? findUiNodeLocation(treeForActiveImage.root, selectedNodeId)?.node + : null; const result = editor.setNodeChildrenDisplayMode( activeImageId, selectedNodeId, mode, ); + if (result.ok && mode === 'Stack' && selectedNode) { + setHiddenNodeIds((current) => { + if (!selectedNode.children.some((child) => current.has(child.id))) { + return current; + } + const next = new Set(current); + for (const child of selectedNode.children) next.delete(child.id); + return next; + }); + } if (!result.ok) setStatus('子节点显示模式更新失败。'); return result; } diff --git a/apps/ai-game-creator-shell/tests/uiEditorPage.test.ts b/apps/ai-game-creator-shell/tests/uiEditorPage.test.ts index 07f4f7606..832dbc3ca 100644 --- a/apps/ai-game-creator-shell/tests/uiEditorPage.test.ts +++ b/apps/ai-game-creator-shell/tests/uiEditorPage.test.ts @@ -436,6 +436,13 @@ describe('UiEditorPage', () => { act(() => result.current.canvas.selectExclusiveChild(childAId!)); expect(result.current.canvas.isNodePreviewVisible(childAId!)).toBe(true); expect(result.current.canvas.isNodePreviewVisible(childBId!)).toBe(false); + + act(() => result.current.inspector.setNodeChildrenDisplayMode('Stack')); + expect(result.current.canvas.isNodePreviewVisible(childAId!)).toBe(true); + expect(result.current.canvas.isNodePreviewVisible(childBId!)).toBe(true); + expect( + result.current.canvas.isNodePreviewVisible(childBDescendantId!), + ).toBe(true); }); it('shows a page-level save failure and allows a retry', async () => { diff --git a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md index 55cafc47b..9566b0997 100644 --- a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md +++ b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md @@ -4,7 +4,7 @@ ## 2026-08-20 UI Editor 最终预览互斥子节点 -最终预览中,选中一个 `Exclusive` 父节点时,它的子节点切换条必须在该父节点自身的预览坐标空间内、紧贴节点上方悬浮;不得固定在预览容器左上角,也不得另行按屏幕坐标换算。点击 tab 必须显式选中对应子节点,不能按通用“切换可见性”语义把当前分支隐藏。切换条始终按内容宽度展开并允许溢出节点边界,不设最大宽度或内部滚动区域。切换条仅改变现有子节点可见性状态,不能触发参考图重读、视口重新适配或预览树的异步重建。 +最终预览中,选中一个 `Exclusive` 父节点时,它的子节点切换条必须在该父节点自身的预览坐标空间内、紧贴节点上方悬浮;不得固定在预览容器左上角,也不得另行按屏幕坐标换算。点击 tab 必须显式选中对应子节点,不能按通用“切换可见性”语义把当前分支隐藏。切换条始终按内容宽度展开并允许溢出节点边界,不设最大宽度或内部滚动区域。从 `Exclusive` 切回 `Stack` 时必须清除全部直接子节点因互斥选择产生的隐藏状态并立即显示所有子节点,后代节点自身的独立隐藏状态保持不变。切换条仅改变现有子节点可见性状态,不能触发参考图重读、视口重新适配或预览树的异步重建。 `BestFit` 文本测量的 effect 只依赖字号模式的标量值、文本测量键和实际容器,不能依赖整个 `FontSizing` 对象引用。UI State 对任意节点(包括切换 `children_display_mode`)的不可变更新会 clone 整棵树;等值 clone 不得重新创建 `ResizeObserver` 或同步重复二分测量,以避免最终预览已显示时出现明显的“重新加载”。