From 945b8133348ef9c34d78ff682a06d813c324a120 Mon Sep 17 00:00:00 2001 From: kdletters Date: Sun, 21 Jun 2026 19:56:27 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=94=BB=E5=B8=83=E7=B4=A0?= =?UTF-8?q?=E6=9D=90=E6=A0=87=E7=AD=BE=E8=8F=9C=E5=8D=95=E4=BA=A4=E4=BA=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 素材标签菜单拦截滚轮事件,避免画布滚动抢占 点击菜单外空白区域自动关闭素材标签菜单 补充画布素材标签菜单交互测试 --- .../ImageCanvasWorldView.test.tsx | 28 ++++++++++++++ .../image-editor/ImageCanvasWorldView.tsx | 38 +++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/src/components/image-editor/ImageCanvasWorldView.test.tsx b/src/components/image-editor/ImageCanvasWorldView.test.tsx index a35816958..3f2739fea 100644 --- a/src/components/image-editor/ImageCanvasWorldView.test.tsx +++ b/src/components/image-editor/ImageCanvasWorldView.test.tsx @@ -823,6 +823,34 @@ describe('ImageCanvasWorldView', () => { ); }); + it('keeps the layer type menu scrollable and closes it when clicking outside', () => { + const layer = createLayer({ assetKind: 'character' }); + const documentWheel = vi.fn(); + document.addEventListener('wheel', documentWheel); + + try { + renderWorldView({ layers: [layer] }); + + fireEvent.click(screen.getByRole('button', { name: '素材标签:角色' })); + + const menu = screen.getByRole('menu', { name: '选择素材标签' }); + fireEvent.wheel(menu, { deltaY: 120 }); + + expect(documentWheel).not.toHaveBeenCalled(); + expect(screen.getByRole('menu', { name: '选择素材标签' })).toBeTruthy(); + + fireEvent.pointerDown(menu); + expect(screen.getByRole('menu', { name: '选择素材标签' })).toBeTruthy(); + + fireEvent.pointerDown(document.body); + expect( + screen.queryByRole('menu', { name: '选择素材标签' }), + ).toBeNull(); + } finally { + document.removeEventListener('wheel', documentWheel); + } + }); + it('hides resolution and duration text for focused audio generation frames', () => { const dialog = createGenerationDialog({ id: 'dialog-audio', diff --git a/src/components/image-editor/ImageCanvasWorldView.tsx b/src/components/image-editor/ImageCanvasWorldView.tsx index 759b834b5..709a0465f 100644 --- a/src/components/image-editor/ImageCanvasWorldView.tsx +++ b/src/components/image-editor/ImageCanvasWorldView.tsx @@ -651,6 +651,8 @@ export function ImageCanvasWorldView({ const [openLayerKindMenuId, setOpenLayerKindMenuId] = useState( null, ); + const openLayerKindTriggerRef = useRef(null); + const openLayerKindMenuRef = useRef(null); const visibleLayers = useMemo( () => layers @@ -660,6 +662,34 @@ export function ImageCanvasWorldView({ [layers], ); + useEffect(() => { + if (!openLayerKindMenuId) { + return undefined; + } + + const closeKindMenuWhenClickingOutside = (event: PointerEvent) => { + const target = event.target; + if (!(target instanceof Node)) { + return; + } + if ( + openLayerKindMenuRef.current?.contains(target) || + openLayerKindTriggerRef.current?.contains(target) + ) { + return; + } + setOpenLayerKindMenuId(null); + }; + + document.addEventListener('pointerdown', closeKindMenuWhenClickingOutside); + return () => { + document.removeEventListener( + 'pointerdown', + closeKindMenuWhenClickingOutside, + ); + }; + }, [openLayerKindMenuId]); + return (
{openLayerKindMenuId === layer.id ? (
event.stopPropagation()} + onWheel={(event) => event.stopPropagation()} > {CANVAS_ASSET_KIND_TAG_OPTIONS.map((option) => (