You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
118 lines
3.4 KiB
118 lines
3.4 KiB
import { UploadOutlined } from '@ant-design/icons';
|
|
import type { DragEndEvent } from '@dnd-kit/core';
|
|
import { DndContext, PointerSensor, useSensor } from '@dnd-kit/core';
|
|
import {
|
|
arrayMove,
|
|
SortableContext,
|
|
useSortable,
|
|
verticalListSortingStrategy,
|
|
} from '@dnd-kit/sortable';
|
|
import { CSS } from '@dnd-kit/utilities';
|
|
import { css } from '@emotion/css';
|
|
import { Button, Upload } from 'antd';
|
|
import type { UploadFile, UploadProps } from 'antd/es/upload/interface';
|
|
import React, { useState } from 'react';
|
|
|
|
interface DraggableUploadListItemProps {
|
|
originNode: React.ReactElement<any, string | React.JSXElementConstructor<any>>;
|
|
file: UploadFile<any>;
|
|
}
|
|
|
|
const DraggableUploadListItem = ({ originNode, file }: DraggableUploadListItemProps) => {
|
|
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
|
|
id: file.uid,
|
|
});
|
|
|
|
const style: React.CSSProperties = {
|
|
transform: CSS.Transform.toString(transform),
|
|
transition,
|
|
cursor: 'move',
|
|
};
|
|
|
|
// prevent preview event when drag end
|
|
const className = isDragging
|
|
? css`
|
|
a {
|
|
pointer-events: none;
|
|
}
|
|
`
|
|
: '';
|
|
|
|
return (
|
|
<div ref={setNodeRef} style={style} className={className} {...attributes} {...listeners}>
|
|
{/* hide error tooltip when dragging */}
|
|
{file.status === 'error' && isDragging ? originNode.props.children : originNode}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const App: React.FC = () => {
|
|
const [fileList, setFileList] = useState<UploadFile[]>([
|
|
{
|
|
uid: '-1',
|
|
name: 'image1.png',
|
|
status: 'done',
|
|
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
|
},
|
|
{
|
|
uid: '-2',
|
|
name: 'image2.png',
|
|
status: 'done',
|
|
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
|
},
|
|
{
|
|
uid: '-3',
|
|
name: 'image3.png',
|
|
status: 'done',
|
|
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
|
},
|
|
{
|
|
uid: '-4',
|
|
name: 'image4.png',
|
|
status: 'done',
|
|
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
|
},
|
|
{
|
|
uid: '-5',
|
|
name: 'image.png',
|
|
status: 'error',
|
|
},
|
|
]);
|
|
|
|
const sensor = useSensor(PointerSensor, {
|
|
activationConstraint: { distance: 10 },
|
|
});
|
|
|
|
const onDragEnd = ({ active, over }: DragEndEvent) => {
|
|
if (active.id !== over?.id) {
|
|
setFileList((prev) => {
|
|
const activeIndex = prev.findIndex((i) => i.uid === active.id);
|
|
const overIndex = prev.findIndex((i) => i.uid === over?.id);
|
|
return arrayMove(prev, activeIndex, overIndex);
|
|
});
|
|
}
|
|
};
|
|
|
|
const onChange: UploadProps['onChange'] = ({ fileList: newFileList }) => {
|
|
setFileList(newFileList);
|
|
};
|
|
|
|
return (
|
|
<DndContext sensors={[sensor]} onDragEnd={onDragEnd}>
|
|
<SortableContext items={fileList.map((i) => i.uid)} strategy={verticalListSortingStrategy}>
|
|
<Upload
|
|
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
|
|
fileList={fileList}
|
|
onChange={onChange}
|
|
itemRender={(originNode, file) => (
|
|
<DraggableUploadListItem originNode={originNode} file={file} />
|
|
)}
|
|
>
|
|
<Button icon={<UploadOutlined />}>Click to Upload</Button>
|
|
</Upload>
|
|
</SortableContext>
|
|
</DndContext>
|
|
);
|
|
};
|
|
|
|
export default App;
|
|
|