071faa482c
纳入 AGC Cargo workspace 的统一 rustfmt 检查与格式化入口 完成项目 TypeScript/Prettier 与 Rust 全量格式化 修复 Pingora expected executable 门禁的空白敏感误报 同步开发运维文档与 AGC skill pack 格式化忽略规则
137 lines
3.5 KiB
TypeScript
137 lines
3.5 KiB
TypeScript
import {
|
|
type Dispatch,
|
|
type DragEvent as ReactDragEvent,
|
|
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],
|
|
);
|
|
}
|