import React, { useRef, useState } from 'react'; import type { TabsProps } from 'antd'; import { Tabs } from 'antd'; import { DndProvider, useDrag, useDrop } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; const type = 'DraggableTabNode'; interface DraggableTabPaneProps extends React.HTMLAttributes { index: React.Key; moveNode: (dragIndex: React.Key, hoverIndex: React.Key) => void; } const DraggableTabNode = ({ index, children, moveNode }: DraggableTabPaneProps) => { const ref = useRef(null); const [{ isOver }, drop] = useDrop({ accept: type, collect: (monitor) => { const { index: dragIndex } = monitor.getItem() || {}; if (dragIndex === index) { return {}; } return { isOver: monitor.isOver(), }; }, drop: (item: { index: React.Key }) => { moveNode(item.index, index); }, }); const [, drag] = useDrag({ type, item: { index }, collect: (monitor) => ({ isDragging: monitor.isDragging(), }), }); drop(drag(ref)); // Style const style: React.CSSProperties = { marginRight: 24 }; if (isOver) { style.transition = 'all 0.3s'; } return (
{children}
); }; const DraggableTabs: React.FC = (props) => { const { items = [] } = props; const [order, setOrder] = useState([]); const moveTabNode = (dragKey: React.Key, hoverKey: React.Key) => { const newOrder = order.slice(); items.forEach((item) => { if (item.key && newOrder.indexOf(item.key) === -1) { newOrder.push(item.key); } }); const dragIndex = newOrder.indexOf(dragKey); const hoverIndex = newOrder.indexOf(hoverKey); newOrder.splice(dragIndex, 1); newOrder.splice(hoverIndex, 0, dragKey); setOrder(newOrder); }; const renderTabBar: TabsProps['renderTabBar'] = (tabBarProps, DefaultTabBar) => ( {(node) => ( {node} )} ); const orderItems = [...items].sort((a, b) => { const orderA = order.indexOf(a.key!); const orderB = order.indexOf(b.key!); if (orderA !== -1 && orderB !== -1) { return orderA - orderB; } if (orderA !== -1) { return -1; } if (orderB !== -1) { return 1; } const ia = items.indexOf(a); const ib = items.indexOf(b); return ia - ib; }); return ( ); }; const App: React.FC = () => ( { const id = String(i + 1); return { label: `tab ${id}`, key: id, children: `Content of Tab Pane ${id}`, }; })} /> ); export default App;