import { Check, CheckSquare, Download, Folder, Square, Trash2, X, } from 'lucide-react'; import type { Dispatch, PointerEvent as ReactPointerEvent, RefObject, SetStateAction, } from 'react'; import { useEffect, useState } from 'react'; import { PlatformActionButton } from '../common/PlatformActionButton'; import { PlatformBatchActionToolbar } from '../common/PlatformBatchActionToolbar'; import { PlatformDangerConfirmDialog } from '../common/PlatformDangerConfirmDialog'; import { PlatformTextField } from '../common/PlatformTextField'; import { ImageCanvasAssetFolderSectionView } from './ImageCanvasAssetFolderSectionView'; import { EditorIconButton } from './ImageCanvasEditorPrimitives'; import type { AssetMarqueeState, AssetPointerDragState, EditorAsset, EditorAssetFolder, UploadTarget, } from './ImageCanvasEditorTypes'; import { type AssetSelectionInteraction, countHiddenSelectedAssets, } from './useImageCanvasAssetSelection'; export type GroupedEditorAssetFolder = EditorAssetFolder & { assets: EditorAsset[]; }; export type UploadFilesOptions = { folderId?: string; canvasPoint?: { x: number; y: number }; addToCanvas?: boolean; }; export type UploadRequestOptions = { folderId?: string; addToCanvas?: boolean; }; export type ImageCanvasAssetLibraryPanelViewProps = { assetListRef: RefObject; assetPointerDragRef: { current: AssetPointerDragState | null }; suppressAssetClickRef: { current: boolean }; groupedAssets: GroupedEditorAssetFolder[]; assetFolders: EditorAssetFolder[]; isAssetSelectionMode: boolean; selectedAssetIds: Set; visibleAssetIds: string[]; assetMoveDropFolderId: string | null; pinnedAssetMoveFolderId: string | null; creatingFolder: boolean; newFolderName: string; renamingFolder: { folderId: string; value: string } | null; renamingAsset: { assetId: string; value: string } | null; allVisibleAssetsSelected: boolean; isExportingSelectedAssets: boolean; assetMarquee: AssetMarqueeState | null; setCreatingFolder: Dispatch>; setNewFolderName: Dispatch>; setRenamingFolder: Dispatch< SetStateAction<{ folderId: string; value: string } | null> >; setRenamingAsset: Dispatch< SetStateAction<{ assetId: string; value: string } | null> >; setActiveUploadFolderId: Dispatch>; setUploadDropTarget: Dispatch>; setAssetPointerDrag: Dispatch>; onAssetMarqueePointerDown: (event: ReactPointerEvent) => void; onAssetMarqueePointerMove: (event: ReactPointerEvent) => void; onAssetMarqueePointerUp: (event: ReactPointerEvent) => void; onAssetMarqueePointerCancel: ( event: ReactPointerEvent, ) => void; onAssetMarqueeLostPointerCapture: ( event: ReactPointerEvent, ) => void; updateAssetMoveDropFolder: (folderId: string | null) => void; addUploadedFiles: ( files: FileList | File[], options?: UploadFilesOptions, ) => void; requestUpload: (target: UploadTarget, options?: UploadRequestOptions) => void; moveAssetToFolder: (assetId: string, folderId: string) => void; commitNewAssetFolder: () => void | Promise; toggleAssetFolder: (folderId: string) => void; startRenamingFolder: (folder: EditorAssetFolder) => void; commitFolderRename: (folder: EditorAssetFolder) => void; deleteAssetFolder: (folder: EditorAssetFolder) => void; startRenamingAsset: (asset: EditorAsset) => void; commitAssetRename: (asset: EditorAsset) => void; deleteUploadedAsset: (asset: EditorAsset) => void; submitAssetToShowcase: (asset: EditorAsset) => void; toggleAssetSelected: ( assetId: string, interaction: AssetSelectionInteraction, ) => void; addAssetLayer: (asset: EditorAsset) => void; onDownloadAsset: (asset: EditorAsset) => void; toggleAllAssetsSelected: (visibleAssetIds: string[]) => void; downloadSelectedAssets: () => void | Promise; deleteSelectedAssets: (assetIds?: ReadonlySet) => void; closeAssetSelectionMode: () => void; }; export function ImageCanvasAssetLibraryPanelView({ assetListRef, assetPointerDragRef, suppressAssetClickRef, groupedAssets, assetFolders, isAssetSelectionMode, selectedAssetIds, visibleAssetIds, assetMoveDropFolderId, pinnedAssetMoveFolderId, creatingFolder, newFolderName, renamingFolder, renamingAsset, allVisibleAssetsSelected, isExportingSelectedAssets, assetMarquee, setCreatingFolder, setNewFolderName, setRenamingFolder, setRenamingAsset, setActiveUploadFolderId, setUploadDropTarget, setAssetPointerDrag, onAssetMarqueePointerDown, onAssetMarqueePointerMove, onAssetMarqueePointerUp, onAssetMarqueePointerCancel, onAssetMarqueeLostPointerCapture, updateAssetMoveDropFolder, addUploadedFiles, requestUpload, moveAssetToFolder, commitNewAssetFolder, toggleAssetFolder, startRenamingFolder, commitFolderRename, deleteAssetFolder, startRenamingAsset, commitAssetRename, deleteUploadedAsset, submitAssetToShowcase, toggleAssetSelected, addAssetLayer, onDownloadAsset, toggleAllAssetsSelected, downloadSelectedAssets, deleteSelectedAssets, closeAssetSelectionMode, }: ImageCanvasAssetLibraryPanelViewProps) { const [hiddenSelectionDeleteSnapshot, setHiddenSelectionDeleteSnapshot] = useState<{ assetIds: Set; visibleAssetIds: string[]; hiddenAssetCount: number; } | null>(null); let selectionToggleActionText = '全选'; if (allVisibleAssetsSelected) { selectionToggleActionText = '取消全选'; } let selectionToggleLabel = selectionToggleActionText; if (selectedAssetIds.size > 0) { selectionToggleLabel = `${selectionToggleActionText} · 已选 ${selectedAssetIds.size}`; } const hiddenSelectedAssetCount = countHiddenSelectedAssets( selectedAssetIds, visibleAssetIds, ); useEffect(() => { if (!hiddenSelectionDeleteSnapshot) { return; } const selectedIdsUnchanged = hiddenSelectionDeleteSnapshot.assetIds.size === selectedAssetIds.size && [...hiddenSelectionDeleteSnapshot.assetIds].every((assetId) => selectedAssetIds.has(assetId), ); const visibleIdsUnchanged = hiddenSelectionDeleteSnapshot.visibleAssetIds.length === visibleAssetIds.length && hiddenSelectionDeleteSnapshot.visibleAssetIds.every( (assetId, index) => assetId === visibleAssetIds[index], ); if ( !isAssetSelectionMode || !selectedIdsUnchanged || !visibleIdsUnchanged ) { setHiddenSelectionDeleteSnapshot(null); } }, [ hiddenSelectionDeleteSnapshot, isAssetSelectionMode, selectedAssetIds, visibleAssetIds, ]); const requestDeleteSelectedAssets = () => { if (hiddenSelectedAssetCount > 0) { setHiddenSelectionDeleteSnapshot({ assetIds: new Set(selectedAssetIds), visibleAssetIds: [...visibleAssetIds], hiddenAssetCount: hiddenSelectedAssetCount, }); return; } deleteSelectedAssets(); }; return (
{pinnedAssetMoveFolderId ? ( ) : null} {creatingFolder ? (
{ event.preventDefault(); void commitNewAssetFolder(); }} > setNewFolderName(event.target.value)} onKeyDown={(event) => { if (event.key === 'Escape') { event.preventDefault(); setCreatingFolder(false); setNewFolderName(''); } }} /> { setCreatingFolder(false); setNewFolderName(''); }} /> ) : null} {groupedAssets.map((folder) => ( ))} {assetMarquee ? ( {isAssetSelectionMode ? ( toggleAllAssetsSelected(visibleAssetIds)} > {allVisibleAssetsSelected ? ( ) : ( )} {selectionToggleLabel} void downloadSelectedAssets()} > {isExportingSelectedAssets ? '下载中' : '下载'} 删除 取消 ) : null} setHiddenSelectionDeleteSnapshot(null)} onConfirm={() => { const targetAssetIds = hiddenSelectionDeleteSnapshot?.assetIds; setHiddenSelectionDeleteSnapshot(null); if (targetAssetIds) { deleteSelectedAssets(targetAssetIds); } }} > 删除后不可恢复。
); }