import { useDndMonitor } from '@dnd-kit/core' import { useSortable } from '@dnd-kit/sortable' import { GripVertical } from 'lucide-react' import type { CSSProperties, PropsWithChildren, ReactNode } from 'react' import { useEffect, useRef, useState } from 'react' import { Button, cn, DropdownMenu, DropdownMenuTrigger } from 'ui' export const SortableSection = ({ id, children, actions, gripClassName, gripDropdownContent, }: PropsWithChildren<{ id: string gripClassName?: string actions?: ReactNode gripDropdownContent?: ReactNode }>) => { const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id, }) const [menuOpen, setMenuOpen] = useState(false) const isDraggingRef = useRef(false) const openTimeoutRef = useRef>(undefined) useDndMonitor({ onDragStart: (event) => { if (event.active.id === id) { isDraggingRef.current = true clearTimeout(openTimeoutRef.current) setMenuOpen(false) } }, onDragEnd: (event) => { if (event.active.id === id) isDraggingRef.current = false }, onDragCancel: (event) => { if (event.active.id === id) isDraggingRef.current = false }, }) useEffect(() => () => clearTimeout(openTimeoutRef.current), []) const style: CSSProperties = { transform: transform ? `translate3d(${Math.round(transform.x)}px, ${Math.round(transform.y)}px, 0)` : undefined, transition, } return (
{actions} { clearTimeout(openTimeoutRef.current) if (!open) { setMenuOpen(false) return } openTimeoutRef.current = setTimeout(() => { if (!isDraggingRef.current) setMenuOpen(true) }, 150) }} >
{children}
) }