import { DragDropProvider, DragOverlay } from "@dnd-kit/react"; import { isSortable } from "@dnd-kit/react/sortable"; import React, { forwardRef, isValidElement } from "react"; import { VStack } from "../../../primitives/stack"; import DataDragAndDropItem, { DataDragAndDropItemProps, } from "../item/DataDragAndDropItem"; import { DataDragAndDropContext } from "./DataDragAndDrop.context"; interface DataDragAndDropProps extends React.HTMLAttributes { children: any[]; setItems: React.Dispatch>; } interface DataDragAndDropRootComponent extends React.ForwardRefExoticComponent< DataDragAndDropProps & React.RefAttributes > { /** * @see 🏷️ {@link DataDragAndDropItemProps} * * @example * ```jsx * * * ... * * * ``` */ Item: typeof DataDragAndDropItem; } const DataDragAndDrop = forwardRef( ({ setItems, children, ...rest }, forwardedRef) => { const [inputMethod, setInputMethod] = React.useState< "mouse" | "keyboard" | null >(null); const setItemOrder = (initalIndex: number, targetIndex: number) => { setItems((items) => { const newItems = [...items]; const [movedItem] = newItems.splice(initalIndex, 1); newItems.splice(targetIndex, 0, movedItem); return newItems; }); }; return ( setInputMethod( event.operation.activatorEvent?.type === "pointerdown" ? "mouse" : "keyboard", ) } onDragOver={(event) => { if (event.operation.activatorEvent?.type === "pointerdown") { // Prevents items to rearrange while dragging with mouse, but allows keyboard dragging to work as intended event.preventDefault(); } }} onDragEnd={(event) => { const { source, target } = event.operation; if (!isSortable(source) || !isSortable(target)) return; setItemOrder(source.initialIndex, target.index); }} >
{children}
{(source) => { // Overlay not needed and causes glitching when using keyboard if (inputMethod === "keyboard") return null; if (!isSortable(source)) return null; if (isValidElement(children[source.initialIndex])) { return children[source.initialIndex]; } return null; }}
); }, ) as DataDragAndDropRootComponent; DataDragAndDrop.Item = DataDragAndDropItem; export { DataDragAndDrop, DataDragAndDropItem }; export default DataDragAndDrop; export type { DataDragAndDropItemProps, DataDragAndDropProps };