修复画布音频拖放与拖拽热区
素材库显式拖放不再叠加级联偏移,音频卡中心落在鼠标松手位置 将音频播放按钮热区收紧到中央,释放卡片主体用于选择与拖拽 补充模型、桥接和画布交互回归测试并同步音频设计文档
This commit is contained in:
@@ -169,7 +169,7 @@ describe('ImageCanvasEditorModel', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('creates a layer from an account asset at the requested screen point', () => {
|
||||
it('creates a cascaded layer from an account asset near the requested screen point', () => {
|
||||
const asset: EditorAsset = {
|
||||
id: 'asset-1',
|
||||
label: '角色草图',
|
||||
@@ -210,6 +210,31 @@ describe('ImageCanvasEditorModel', () => {
|
||||
expect(layer.y).toBe(12);
|
||||
});
|
||||
|
||||
it('centers a dropped asset exactly at the requested screen point', () => {
|
||||
const asset: EditorAsset = {
|
||||
id: 'asset-drop',
|
||||
label: '投放素材',
|
||||
src: 'data:image/png;base64,drop',
|
||||
width: 640,
|
||||
height: 480,
|
||||
folderId: 'project',
|
||||
sourceKind: 'uploaded',
|
||||
sourceType: 'uploaded',
|
||||
persisted: true,
|
||||
};
|
||||
|
||||
const layer = createLayerFromAsset(
|
||||
asset,
|
||||
3,
|
||||
{ x: 20, y: 40, scale: 2 },
|
||||
{ x: 420, y: 340 },
|
||||
{ applyCascadeOffset: false },
|
||||
);
|
||||
|
||||
expect(layer.x + layer.width / 2).toBe(200);
|
||||
expect(layer.y + layer.height / 2).toBe(150);
|
||||
});
|
||||
|
||||
it('preserves source resource ids from the persisted asset library', () => {
|
||||
const library = normalizeAssetLibrary({
|
||||
folders: [
|
||||
|
||||
@@ -138,6 +138,7 @@ export function createLayerFromAsset(
|
||||
index: number,
|
||||
viewport: CanvasViewport,
|
||||
screenCenter: { x: number; y: number },
|
||||
options: { applyCascadeOffset?: boolean } = {},
|
||||
): CanvasLayer {
|
||||
const { width, height } = resolveLayerResolutionSize(
|
||||
asset.width,
|
||||
@@ -151,7 +152,7 @@ export function createLayerFromAsset(
|
||||
};
|
||||
const worldCenterX = (safeScreenCenter.x - viewport.x) / safeScale;
|
||||
const worldCenterY = (safeScreenCenter.y - viewport.y) / safeScale;
|
||||
const offset = index * 34;
|
||||
const offset = options.applyCascadeOffset === false ? 0 : index * 34;
|
||||
const assetKind: CanvasAssetKind | undefined =
|
||||
asset.mediaType === 'video'
|
||||
? 'video'
|
||||
|
||||
@@ -934,6 +934,50 @@ describe('ImageCanvasWorldView', () => {
|
||||
expect(props.onLayerClick).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('starts layer dragging from the audio card outside playback controls', () => {
|
||||
const layer = createLayer({
|
||||
title: '拖拽音效',
|
||||
src: 'data:audio/mpeg;base64,audio',
|
||||
mediaType: 'audio',
|
||||
assetKind: 'sound-effect',
|
||||
width: 420,
|
||||
height: 120,
|
||||
originalWidth: 420,
|
||||
originalHeight: 120,
|
||||
durationSeconds: 12,
|
||||
});
|
||||
const { props } = renderWorldView({
|
||||
layers: [layer],
|
||||
hoveredLayerId: layer.id,
|
||||
});
|
||||
|
||||
const layerButton = screen.getByRole('button', { name: '选择拖拽音效' });
|
||||
const audioCard = layerButton.querySelector(
|
||||
'.image-canvas-editor__audio-card',
|
||||
);
|
||||
const playbackButton = within(layerButton).getByRole('button', {
|
||||
name: '播放拖拽音效',
|
||||
});
|
||||
const controls = layerButton.querySelector(
|
||||
'.image-canvas-editor__audio-card-controls',
|
||||
);
|
||||
|
||||
expect(audioCard).toBeTruthy();
|
||||
expect(controls).toBeTruthy();
|
||||
|
||||
fireEvent.pointerDown(audioCard as HTMLElement);
|
||||
|
||||
expect(props.onLayerPointerDown).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
layer,
|
||||
);
|
||||
|
||||
fireEvent.pointerDown(playbackButton);
|
||||
fireEvent.pointerDown(controls as HTMLElement);
|
||||
|
||||
expect(props.onLayerPointerDown).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('places layer type labels to the left of the information action', () => {
|
||||
const layer = createLayer({ assetKind: 'character' });
|
||||
const { props } = renderWorldView({ layers: [layer] });
|
||||
|
||||
@@ -134,7 +134,7 @@ function AssetCanvasBridgeHarness({
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => bridge.addAssetLayer(asset, { x: 450, y: 320 })}
|
||||
onClick={() => bridge.addAssetLayer(asset)}
|
||||
>
|
||||
添加到画布
|
||||
</button>
|
||||
@@ -234,7 +234,11 @@ describe('useImageCanvasAssetCanvasBridge', () => {
|
||||
});
|
||||
|
||||
expect(appendCanvasLayersWithResources).toHaveBeenCalledWith([
|
||||
expect.objectContaining({ sourceAssetId: 'asset-1' }),
|
||||
expect.objectContaining({
|
||||
sourceAssetId: 'asset-1',
|
||||
x: 75,
|
||||
y: 190,
|
||||
}),
|
||||
]);
|
||||
expect(screen.getByTestId('drag').textContent).toBe('none');
|
||||
expect(screen.getByTestId('drop-target').textContent).toBe('-');
|
||||
|
||||
@@ -139,6 +139,7 @@ export function useImageCanvasAssetCanvasBridge({
|
||||
x: position?.x ?? canvasSize.width / 2,
|
||||
y: position?.y ?? canvasSize.height / 2,
|
||||
},
|
||||
{ applyCascadeOffset: position === undefined },
|
||||
);
|
||||
captureCanvasHistory();
|
||||
appendCanvasLayersWithResources([nextLayer]);
|
||||
|
||||
+6
-1
@@ -5714,14 +5714,19 @@ html[data-mobile-keyboard-open='true'] .platform-mobile-bottom-dock {
|
||||
|
||||
.image-canvas-editor__audio-card-playback {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
z-index: 1;
|
||||
display: grid;
|
||||
width: 2.75rem;
|
||||
height: 2.75rem;
|
||||
place-items: center;
|
||||
border: 0;
|
||||
border-radius: 999px;
|
||||
background: transparent;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
cursor: pointer;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.image-canvas-editor__audio-card-playback:hover {
|
||||
|
||||
Reference in New Issue
Block a user