新增画布拖拽 drop workflow,承接素材库图片和本地文件拖入画布分流 补充拖拽入画布 hook 测试,覆盖遮罩、默认文件夹和无关拖拽不拦截 更新前端拆分文档和 TRACKING 浏览器回归记录
132 lines
3.5 KiB
TypeScript
132 lines
3.5 KiB
TypeScript
import {
|
|
type DragEvent as ReactDragEvent,
|
|
type Dispatch,
|
|
type SetStateAction,
|
|
useCallback,
|
|
useMemo,
|
|
} from 'react';
|
|
|
|
import {
|
|
ASSET_DRAG_MIME_TYPE,
|
|
getDraggedAssetId,
|
|
hasDataTransferType,
|
|
} from './ImageCanvasEditorModel';
|
|
import type { EditorAsset, EditorAssetFolder } from './ImageCanvasEditorTypes';
|
|
|
|
type UploadFilesToCanvasOptions = {
|
|
folderId?: string;
|
|
canvasPoint: { x: number; y: number };
|
|
addToCanvas: true;
|
|
};
|
|
|
|
type UseImageCanvasCanvasDropWorkflowOptions = {
|
|
assets: EditorAsset[];
|
|
assetFolders: EditorAssetFolder[];
|
|
setUploadDropTarget: Dispatch<SetStateAction<'canvas' | 'assets' | null>>;
|
|
updateAssetMoveDropFolder: (folderId: string | null) => void;
|
|
getCanvasDropPoint: (clientX: number, clientY: number) => {
|
|
x: number;
|
|
y: number;
|
|
};
|
|
addAssetLayer: (
|
|
asset: EditorAsset,
|
|
position?: { x: number; y: number },
|
|
) => void;
|
|
addUploadedFiles: (
|
|
files: FileList | File[],
|
|
options: UploadFilesToCanvasOptions,
|
|
) => void;
|
|
};
|
|
|
|
export function useImageCanvasCanvasDropWorkflow({
|
|
assets,
|
|
assetFolders,
|
|
setUploadDropTarget,
|
|
updateAssetMoveDropFolder,
|
|
getCanvasDropPoint,
|
|
addAssetLayer,
|
|
addUploadedFiles,
|
|
}: UseImageCanvasCanvasDropWorkflowOptions) {
|
|
const handleCanvasDragOver = useCallback(
|
|
(event: ReactDragEvent<HTMLDivElement>) => {
|
|
if (hasDataTransferType(event.dataTransfer, ASSET_DRAG_MIME_TYPE)) {
|
|
event.preventDefault();
|
|
setUploadDropTarget('canvas');
|
|
event.dataTransfer.dropEffect = 'copy';
|
|
return;
|
|
}
|
|
if (hasDataTransferType(event.dataTransfer, 'Files')) {
|
|
event.preventDefault();
|
|
setUploadDropTarget('canvas');
|
|
event.dataTransfer.dropEffect = 'copy';
|
|
}
|
|
},
|
|
[setUploadDropTarget],
|
|
);
|
|
|
|
const handleCanvasDragLeave = useCallback(
|
|
(event: ReactDragEvent<HTMLDivElement>) => {
|
|
if (!event.currentTarget.contains(event.relatedTarget as Node | null)) {
|
|
setUploadDropTarget((currentTarget) =>
|
|
currentTarget === 'canvas' ? null : currentTarget,
|
|
);
|
|
}
|
|
},
|
|
[setUploadDropTarget],
|
|
);
|
|
|
|
const handleCanvasDrop = useCallback(
|
|
(event: ReactDragEvent<HTMLDivElement>) => {
|
|
const draggedAssetId = getDraggedAssetId(event.dataTransfer);
|
|
if (draggedAssetId) {
|
|
const draggedAsset = assets.find((asset) => asset.id === draggedAssetId);
|
|
if (!draggedAsset) {
|
|
return;
|
|
}
|
|
event.preventDefault();
|
|
setUploadDropTarget(null);
|
|
updateAssetMoveDropFolder(null);
|
|
addAssetLayer(
|
|
draggedAsset,
|
|
getCanvasDropPoint(event.clientX, event.clientY),
|
|
);
|
|
return;
|
|
}
|
|
|
|
const files = event.dataTransfer.files;
|
|
if (!files.length) {
|
|
return;
|
|
}
|
|
event.preventDefault();
|
|
setUploadDropTarget(null);
|
|
updateAssetMoveDropFolder(null);
|
|
const canvasPoint = getCanvasDropPoint(event.clientX, event.clientY);
|
|
const defaultFolder =
|
|
assetFolders.find((folder) => folder.systemDefault) ?? assetFolders[0];
|
|
addUploadedFiles(files, {
|
|
folderId: defaultFolder?.id,
|
|
canvasPoint,
|
|
addToCanvas: true,
|
|
});
|
|
},
|
|
[
|
|
addAssetLayer,
|
|
addUploadedFiles,
|
|
assetFolders,
|
|
assets,
|
|
getCanvasDropPoint,
|
|
setUploadDropTarget,
|
|
updateAssetMoveDropFolder,
|
|
],
|
|
);
|
|
|
|
return useMemo(
|
|
() => ({
|
|
handleCanvasDragOver,
|
|
handleCanvasDragLeave,
|
|
handleCanvasDrop,
|
|
}),
|
|
[handleCanvasDragLeave, handleCanvasDragOver, handleCanvasDrop],
|
|
);
|
|
}
|