修复画布素材标签菜单交互

素材标签菜单拦截滚轮事件,避免画布滚动抢占
点击菜单外空白区域自动关闭素材标签菜单
补充画布素材标签菜单交互测试
This commit is contained in:
2026-06-21 19:56:27 +08:00
parent 976561d385
commit 945b813334
2 changed files with 66 additions and 0 deletions
@@ -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',
@@ -651,6 +651,8 @@ export function ImageCanvasWorldView({
const [openLayerKindMenuId, setOpenLayerKindMenuId] = useState<string | null>(
null,
);
const openLayerKindTriggerRef = useRef<HTMLSpanElement | null>(null);
const openLayerKindMenuRef = useRef<HTMLDivElement | null>(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 (
<div
className="image-canvas-editor__world"
@@ -755,6 +785,11 @@ export function ImageCanvasWorldView({
)}
{kindLabel ? (
<span
ref={
openLayerKindMenuId === layer.id
? openLayerKindTriggerRef
: undefined
}
role="button"
tabIndex={0}
aria-label={`素材标签:${kindLabel}`}
@@ -812,6 +847,7 @@ export function ImageCanvasWorldView({
</LayerElement>
{openLayerKindMenuId === layer.id ? (
<div
ref={openLayerKindMenuRef}
className="image-canvas-editor__kind-menu-anchor"
style={{
left: layer.x + layer.width,
@@ -824,6 +860,8 @@ export function ImageCanvasWorldView({
label="选择素材标签"
placement="bottom-end"
className="image-canvas-editor__kind-menu"
onWheelCapture={(event) => event.stopPropagation()}
onWheel={(event) => event.stopPropagation()}
>
{CANVAS_ASSET_KIND_TAG_OPTIONS.map((option) => (
<PlatformFloatingMenuItem