2024-04-26 09:40:25 +08:00
|
|
|
import React, { useContext, useMemo } from 'react';
|
2024-04-24 11:48:15 +08:00
|
|
|
import { HolderOutlined } from '@ant-design/icons';
|
2023-02-02 10:54:13 +08:00
|
|
|
import type { DragEndEvent } from '@dnd-kit/core';
|
|
|
|
import { DndContext } from '@dnd-kit/core';
|
2024-04-24 11:48:15 +08:00
|
|
|
import type { SyntheticListenerMap } from '@dnd-kit/core/dist/hooks/utilities';
|
2023-05-31 13:36:20 +08:00
|
|
|
import { restrictToVerticalAxis } from '@dnd-kit/modifiers';
|
2023-02-02 10:54:13 +08:00
|
|
|
import {
|
|
|
|
arrayMove,
|
|
|
|
SortableContext,
|
|
|
|
useSortable,
|
|
|
|
verticalListSortingStrategy,
|
|
|
|
} from '@dnd-kit/sortable';
|
|
|
|
import { CSS } from '@dnd-kit/utilities';
|
2024-04-24 11:48:15 +08:00
|
|
|
import { Button, Table } from 'antd';
|
2023-02-02 10:54:13 +08:00
|
|
|
import type { ColumnsType } from 'antd/es/table';
|
|
|
|
|
2024-04-26 09:40:25 +08:00
|
|
|
interface DataType {
|
|
|
|
key: string;
|
|
|
|
name: string;
|
|
|
|
age: number;
|
|
|
|
address: string;
|
|
|
|
}
|
|
|
|
|
2024-04-24 11:48:15 +08:00
|
|
|
interface RowContextProps {
|
|
|
|
setActivatorNodeRef?: (element: HTMLElement | null) => void;
|
|
|
|
listeners?: SyntheticListenerMap;
|
|
|
|
}
|
|
|
|
|
2024-04-25 14:22:35 +08:00
|
|
|
const RowContext = React.createContext<RowContextProps>({});
|
2024-04-24 11:48:15 +08:00
|
|
|
|
2024-04-26 09:40:25 +08:00
|
|
|
const DragHandle: React.FC = () => {
|
2024-04-24 11:48:15 +08:00
|
|
|
const { setActivatorNodeRef, listeners } = useContext(RowContext);
|
|
|
|
return (
|
|
|
|
<Button
|
|
|
|
type="text"
|
|
|
|
size="small"
|
|
|
|
icon={<HolderOutlined />}
|
|
|
|
style={{ cursor: 'move' }}
|
|
|
|
ref={setActivatorNodeRef}
|
|
|
|
{...listeners}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2023-02-02 10:54:13 +08:00
|
|
|
const columns: ColumnsType<DataType> = [
|
2024-04-26 09:40:25 +08:00
|
|
|
{ key: 'sort', align: 'center', width: 80, render: () => <DragHandle /> },
|
|
|
|
{ title: 'Name', dataIndex: 'name' },
|
|
|
|
{ title: 'Age', dataIndex: 'age' },
|
|
|
|
{ title: 'Address', dataIndex: 'address' },
|
|
|
|
];
|
|
|
|
|
|
|
|
const initialData: DataType[] = [
|
|
|
|
{ key: '1', name: 'John Brown', age: 32, address: 'Long text Long' },
|
|
|
|
{ key: '2', name: 'Jim Green', age: 42, address: 'London No. 1 Lake Park' },
|
|
|
|
{ key: '3', name: 'Joe Black', age: 32, address: 'Sidney No. 1 Lake Park' },
|
2023-02-02 10:54:13 +08:00
|
|
|
];
|
|
|
|
|
|
|
|
interface RowProps extends React.HTMLAttributes<HTMLTableRowElement> {
|
|
|
|
'data-row-key': string;
|
|
|
|
}
|
|
|
|
|
2024-04-26 09:40:25 +08:00
|
|
|
const Row: React.FC<RowProps> = (props) => {
|
2023-02-02 10:54:13 +08:00
|
|
|
const {
|
|
|
|
attributes,
|
|
|
|
listeners,
|
|
|
|
setNodeRef,
|
|
|
|
setActivatorNodeRef,
|
|
|
|
transform,
|
|
|
|
transition,
|
|
|
|
isDragging,
|
2024-04-26 09:40:25 +08:00
|
|
|
} = useSortable({ id: props['data-row-key'] });
|
2023-02-02 10:54:13 +08:00
|
|
|
|
|
|
|
const style: React.CSSProperties = {
|
|
|
|
...props.style,
|
2024-04-24 11:48:15 +08:00
|
|
|
transform: CSS.Translate.toString(transform),
|
2023-02-02 10:54:13 +08:00
|
|
|
transition,
|
|
|
|
...(isDragging ? { position: 'relative', zIndex: 9999 } : {}),
|
|
|
|
};
|
|
|
|
|
2024-04-26 09:40:25 +08:00
|
|
|
const contextValue = useMemo<RowContextProps>(
|
|
|
|
() => ({ setActivatorNodeRef, listeners }),
|
2024-04-24 11:48:15 +08:00
|
|
|
[setActivatorNodeRef, listeners],
|
|
|
|
);
|
|
|
|
|
2023-02-02 10:54:13 +08:00
|
|
|
return (
|
2024-04-24 11:48:15 +08:00
|
|
|
<RowContext.Provider value={contextValue}>
|
|
|
|
<tr {...props} ref={setNodeRef} style={style} {...attributes} />
|
|
|
|
</RowContext.Provider>
|
2023-02-02 10:54:13 +08:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
const App: React.FC = () => {
|
2024-04-26 09:40:25 +08:00
|
|
|
const [dataSource, setDataSource] = React.useState<DataType[]>(initialData);
|
2023-02-02 10:54:13 +08:00
|
|
|
|
|
|
|
const onDragEnd = ({ active, over }: DragEndEvent) => {
|
|
|
|
if (active.id !== over?.id) {
|
2024-04-26 09:40:25 +08:00
|
|
|
setDataSource((prevState) => {
|
|
|
|
const activeIndex = prevState.findIndex((record) => record.key === active?.id);
|
|
|
|
const overIndex = prevState.findIndex((record) => record.key === over?.id);
|
|
|
|
return arrayMove(prevState, activeIndex, overIndex);
|
2023-02-02 10:54:13 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
2023-05-31 13:36:20 +08:00
|
|
|
<DndContext modifiers={[restrictToVerticalAxis]} onDragEnd={onDragEnd}>
|
2024-04-26 09:40:25 +08:00
|
|
|
<SortableContext items={dataSource.map((i) => i.key)} strategy={verticalListSortingStrategy}>
|
2023-02-02 10:54:13 +08:00
|
|
|
<Table
|
|
|
|
rowKey="key"
|
2024-04-26 09:40:25 +08:00
|
|
|
components={{ body: { row: Row } }}
|
2023-02-02 10:54:13 +08:00
|
|
|
columns={columns}
|
|
|
|
dataSource={dataSource}
|
|
|
|
/>
|
|
|
|
</SortableContext>
|
|
|
|
</DndContext>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default App;
|