"use client" import { createContext, CSSProperties, ReactNode, useContext, useEffect, useId, useMemo, useRef, useState, } from "react" import { useDataGrid } from "@/components/reui/data-grid/data-grid" import { DataGridTableBase, DataGridTableBody, DataGridTableBodyRow, DataGridTableBodyRowCell, DataGridTableBodyRowSkeleton, DataGridTableBodyRowSkeletonCell, DataGridTableEmpty, DataGridTableFoot, DataGridTableHead, DataGridTableHeadRow, DataGridTableHeadRowCell, DataGridTableHeadRowCellResize, DataGridTableRowSpacer, DataGridTableViewport, } from "@/components/reui/data-grid/data-grid-table" import { closestCenter, DndContext, KeyboardSensor, MouseSensor, TouchSensor, UniqueIdentifier, useSensor, useSensors, type DragEndEvent, type Modifier, } from "@dnd-kit/core" import { restrictToVerticalAxis } from "@dnd-kit/modifiers" import { SortableContext, useSortable, verticalListSortingStrategy, } from "@dnd-kit/sortable" import { CSS } from "@dnd-kit/utilities" import { Cell, flexRender, HeaderGroup, Row } from "@tanstack/react-table" import { cn } from "@evobgp/ui/lib/utils" import { Button } from "@evobgp/ui/components/button" import { GripHorizontalIcon } from "lucide-react" // Context to share sortable listeners from row to handle type SortableContextValue = ReturnType const SortableRowContext = createContext | null>(null) function DataGridTableDndRowHandle({ className }: { className?: string }) { const context = useContext(SortableRowContext) if (!context) { // Fallback if context is not available (shouldn't happen in normal usage) return ( ) } return ( ) } function DataGridTableDndRow({ row }: { row: Row }) { const { transform, transition, setNodeRef, isDragging, attributes, listeners, } = useSortable({ id: row.id, }) const style: CSSProperties = { transform: CSS.Transform.toString(transform), transition: transition, opacity: isDragging ? 0.8 : 1, zIndex: isDragging ? 1 : 0, position: "relative", cursor: isDragging ? "grabbing" : undefined, } return ( {row.getVisibleCells().map((cell: Cell) => { return ( {flexRender(cell.column.columnDef.cell, cell.getContext())} ) })} ) } function DataGridTableDndRows({ handleDragEnd, dataIds, footerContent, }: { handleDragEnd: (event: DragEndEvent) => void dataIds: UniqueIdentifier[] footerContent?: ReactNode }) { const { table, isLoading, props } = useDataGrid() const pagination = table.getState().pagination const tableContainerRef = useRef(null) const [isDraggingRow, setIsDraggingRow] = useState(false) const sensors = useSensors( useSensor(MouseSensor, {}), useSensor(TouchSensor, {}), useSensor(KeyboardSensor, {}) ) useEffect(() => { if (!isDraggingRow) return const { body, documentElement } = document const previousBodyCursor = body.style.cursor const previousDocumentCursor = documentElement.style.cursor body.style.cursor = "grabbing" documentElement.style.cursor = "grabbing" return () => { body.style.cursor = previousBodyCursor documentElement.style.cursor = previousDocumentCursor } }, [isDraggingRow]) const modifiers = useMemo(() => { const restrictToTableContainer: Modifier = ({ transform, draggingNodeRect, }) => { if (!tableContainerRef.current || !draggingNodeRect) { return transform } const containerRect = tableContainerRef.current.getBoundingClientRect() const { x, y } = transform const minX = containerRect.left - draggingNodeRect.left const maxX = containerRect.right - draggingNodeRect.right const minY = containerRect.top - draggingNodeRect.top const maxY = containerRect.bottom - draggingNodeRect.bottom return { ...transform, x: Math.max(minX, Math.min(maxX, x)), y: Math.max(minY, Math.min(maxY, y)), } } return [restrictToVerticalAxis, restrictToTableContainer] }, []) return ( setIsDraggingRow(false)} onDragEnd={(event) => { setIsDraggingRow(false) handleDragEnd(event) }} onDragStart={() => setIsDraggingRow(true)} sensors={sensors} > {table .getHeaderGroups() .map((headerGroup: HeaderGroup, index) => { return ( {headerGroup.headers.map((header, index) => { const { column } = header return ( {header.isPlaceholder ? null : props.tableLayout ?.columnsResizable && column.getCanResize() ? (
{flexRender( header.column.columnDef.header, header.getContext() )}
) : ( flexRender( header.column.columnDef.header, header.getContext() ) )} {props.tableLayout?.columnsResizable && column.getCanResize() && ( )}
) })}
) })}
{(props.tableLayout?.stripped || !props.tableLayout?.rowBorder) && ( )} {props.loadingMode === "skeleton" && isLoading && pagination?.pageSize ? ( Array.from({ length: pagination.pageSize }).map((_, rowIndex) => ( {table.getVisibleFlatColumns().map((column, colIndex) => { return ( {column.columnDef.meta?.skeleton} ) })} )) ) : table.getRowModel().rows.length ? ( {table.getRowModel().rows.map((row: Row) => { return })} ) : ( )} {footerContent && ( {footerContent} )}
) } export { DataGridTableDndRowHandle, DataGridTableDndRows }