锁定音频预设轨道时禁用手动横向滚动
锁定态给预设轨道加 --locked 修饰类,收紧为不可滚动容器并只放行纵向手势。 补齐 BGM 与 SFX 跑马灯锁定态的轨道滚动与相位保留断言。
This commit is contained in:
@@ -394,7 +394,13 @@ export function ImageCanvasAudioPresetMarquee<
|
||||
</button>
|
||||
<div
|
||||
ref={viewportRef}
|
||||
className="image-canvas-editor__background-music-presets-viewport"
|
||||
// 锁定要停的是整条轨道的滚动,不只是自动循环:轨道本身仍是可滚动容器,
|
||||
// 不收紧就还能被触摸、触控板和 Shift+滚轮横向拖动。
|
||||
className={`image-canvas-editor__background-music-presets-viewport${
|
||||
isLocked
|
||||
? ' image-canvas-editor__background-music-presets-viewport--locked'
|
||||
: ''
|
||||
}`}
|
||||
onPointerMove={handleViewportPointerMove}
|
||||
onPointerLeave={handleViewportPointerLeave}
|
||||
onPointerDown={beginTouchScroll}
|
||||
|
||||
@@ -438,6 +438,53 @@ describe('ImageCanvasBackgroundMusicPresetMarquee', () => {
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('stops the track from being scrolled by hand while the panel is locked', () => {
|
||||
const onSelectPreset = vi.fn();
|
||||
const { container, rerender } = renderMarquee({ onSelectPreset });
|
||||
expand();
|
||||
const viewport = getViewport(container);
|
||||
|
||||
// 未锁定时轨道就是可滚动容器,交给原生横向滚动。
|
||||
expect(
|
||||
viewport.classList.contains(
|
||||
'image-canvas-editor__background-music-presets-viewport--locked',
|
||||
),
|
||||
).toBe(false);
|
||||
|
||||
rerender(
|
||||
<ImageCanvasBackgroundMusicPresetMarquee
|
||||
presets={BACKGROUND_MUSIC_PROMPT_PRESETS}
|
||||
isLocked
|
||||
onSelectPreset={onSelectPreset}
|
||||
/>,
|
||||
);
|
||||
|
||||
// 锁定时不只停自动循环,轨道本身也不再接受触摸 / 触控板的横向滚动。
|
||||
expect(frameCallbacks.size).toBe(0);
|
||||
expect(
|
||||
viewport.classList.contains(
|
||||
'image-canvas-editor__background-music-presets-viewport--locked',
|
||||
),
|
||||
).toBe(true);
|
||||
// 相位保留:解锁后从原处继续,不跳回队列头。
|
||||
expect(viewport.scrollLeft).toBe(QUEUE_WIDTH);
|
||||
|
||||
rerender(
|
||||
<ImageCanvasBackgroundMusicPresetMarquee
|
||||
presets={BACKGROUND_MUSIC_PROMPT_PRESETS}
|
||||
isLocked={false}
|
||||
onSelectPreset={onSelectPreset}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(
|
||||
viewport.classList.contains(
|
||||
'image-canvas-editor__background-music-presets-viewport--locked',
|
||||
),
|
||||
).toBe(false);
|
||||
expect(viewport.scrollLeft).toBe(QUEUE_WIDTH);
|
||||
});
|
||||
|
||||
it('never starts the loop under reduced motion and reacts to runtime changes', () => {
|
||||
prefersReducedMotion = true;
|
||||
const { container } = renderMarquee();
|
||||
|
||||
@@ -44,7 +44,7 @@ describe('ImageCanvasSoundEffectPresetMarquee', () => {
|
||||
expect(onSelectPreset).toHaveBeenCalledWith(SOUND_EFFECT_PROMPT_PRESETS[0]);
|
||||
});
|
||||
|
||||
it('keeps expansion and preset controls truly disabled while locked', () => {
|
||||
it('keeps expansion, preset controls and the track scroll truly disabled while locked', () => {
|
||||
const view = render(
|
||||
<ImageCanvasSoundEffectPresetMarquee
|
||||
presets={SOUND_EFFECT_PROMPT_PRESETS}
|
||||
@@ -72,5 +72,11 @@ describe('ImageCanvasSoundEffectPresetMarquee', () => {
|
||||
}) as HTMLButtonElement
|
||||
).disabled,
|
||||
).toBe(true);
|
||||
// 「优化中锁定滚动」按轨道自身不可被手动横向滚动验收,不只是停掉自动循环。
|
||||
expect(
|
||||
view.container.querySelector(
|
||||
'.image-canvas-editor__background-music-presets-viewport--locked',
|
||||
),
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17105,6 +17105,13 @@ button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.image-canvas-editor__background-music-presets-viewport--locked {
|
||||
/* 锁定期间轨道不再是用户可滚动容器,但保留 scrollLeft 相位,解锁后循环从原处继续。 */
|
||||
overflow-x: hidden;
|
||||
/* 横向手势不再作用于轨道,纵向手势仍旧交给画布。 */
|
||||
touch-action: pan-y;
|
||||
}
|
||||
|
||||
.image-canvas-editor__background-music-presets-queue {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
|
||||
Reference in New Issue
Block a user