import React, { ReactNode, useState, useCallback, useMemo } from 'react'; import { createPortal } from 'react-dom'; import { CSS as cssDndKit } from '@dnd-kit/utilities'; import cls from 'classnames'; import { closestCenter, DragOverlay, DndContext, MouseSensor, TouchSensor, useSensor, useSensors, KeyboardSensor, TraversalOrder, } from '@dnd-kit/core'; import type { UniqueIdentifier, PointerActivationConstraint, CollisionDetection, } from '@dnd-kit/core'; import { useSortable, SortableContext, rectSortingStrategy, sortableKeyboardCoordinates, } from '@dnd-kit/sortable'; import type { SortingStrategy, AnimateLayoutChanges, NewIndexGetter, } from '@dnd-kit/sortable'; import type { SortableTransition } from '@dnd-kit/sortable/dist/hooks/types'; import { isNull } from 'lodash'; const defaultPrefix = 'semi-sortable'; interface OnSortEndProps { oldIndex: number; newIndex: number } export type OnSortEnd = (props: OnSortEndProps) => void; export interface RenderItemProps { id?: string | number; sortableHandle?: any; [x: string]: any } export interface SortableProps { onSortEnd?: OnSortEnd; // Set drag and drop trigger conditions activationConstraint?: PointerActivationConstraint; // Collision detection algorithm, for drag and drop sorting, use closestCenter to meet most scenarios collisionDetection?: CollisionDetection; // the dragged items,The content in items cannot be the number 0 items?: any[]; // Function that renders the item that is allowed to be dragged renderItem?: (props: RenderItemProps) => React.ReactNode; // Drag and drop strategy strategy?: SortingStrategy; // Whether to use a separate drag layer for items that move with the mouse useDragOverlay?: boolean; // A container for all elements that are allowed to be dragged container?: any; // Whether to change the size of the item being dragged adjustScale?: boolean; // Whether to use animation during dragging transition?: SortableTransition | null; // prefix prefix?: string; // The className of the item that moves with the mouse during the drag dragOverlayCls?: string } interface SortableItemProps { animateLayoutChanges?: AnimateLayoutChanges; getNewIndex?: NewIndexGetter; id: UniqueIdentifier; index: number; useDragOverlay?: boolean; renderItem?: (props: RenderItemProps) => ReactNode; prefix?: string; transition?: SortableTransition | null } function DefaultContainer(props) { return
; } const defaultKeyBoardOptions = { coordinateGetter: sortableKeyboardCoordinates, }; export function Sortable({ items, onSortEnd, adjustScale, renderItem, transition, collisionDetection = closestCenter, strategy = rectSortingStrategy, useDragOverlay = true, dragOverlayCls, container: Container = DefaultContainer, prefix = defaultPrefix, }: SortableProps) { const [activeId, setActiveId] = useState