SortableSection.tsx36 lines · main
1import { useSortable } from '@dnd-kit/sortable'
2import { GripVertical } from 'lucide-react'
3import type { CSSProperties, ReactNode } from 'react'
4import { cn } from 'ui'
5
6type SortableSectionProps = {
7 id: string
8 children: ReactNode
9}
10
11export const SortableSection = ({ id, children }: SortableSectionProps) => {
12 const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
13 id,
14 })
15
16 const style: CSSProperties = {
17 transform: transform
18 ? `translate3d(${Math.round(transform.x)}px, ${Math.round(transform.y)}px, 0)`
19 : undefined,
20 transition,
21 }
22
23 return (
24 <div ref={setNodeRef} style={style} className="relative will-change-transform">
25 <button
26 aria-label="Drag to reorder section"
27 className="absolute -left-6 top-2 text-foreground-muted hover:text-foreground focus:outline-hidden cursor-grab active:cursor-grabbing"
28 {...attributes}
29 {...listeners}
30 >
31 <GripVertical size={14} />
32 </button>
33 <div className={cn(isDragging && 'opacity-70')}>{children}</div>
34 </div>
35 )
36}