Files
buzz/app/(ui)/admin/tl/components/sortable-grid.tsx
T
dmgnr 8c14999c59
Build and Push Image / build-backend (push) Successful in 6m13s
Build and Push Image / build-frontend (push) Successful in 7m33s
Build and Push Image / push (push) Successful in 1m16s
feat(admin): tierlist editor
2026-08-06 03:00:13 +07:00

93 lines
2.1 KiB
TypeScript

"use client";
import {
closestCenter,
DndContext,
type DragEndEvent,
type DraggableAttributes,
DragOverlay,
} from "@dnd-kit/core";
import type { SyntheticListenerMap } from "@dnd-kit/core/dist/hooks/utilities";
import {
rectSortingStrategy,
SortableContext,
useSortable,
} from "@dnd-kit/sortable";
import type { ReactNode } from "react";
import { useState } from "react";
export function SortableGrid({
items,
onReorder,
children,
overlay,
disabled = false,
}: {
items: string[];
onReorder: (activeId: string, overId: string) => void;
children?: ReactNode;
overlay?: (id: string) => ReactNode;
disabled?: boolean;
}) {
const [dragging, setDragging] = useState<string | null>(null);
function handleDragEnd(event: DragEndEvent) {
setDragging(null);
if (disabled || !event.over) return;
onReorder(event.active.id as string, event.over.id as string);
}
return (
<DndContext
collisionDetection={closestCenter}
onDragStart={(event) => setDragging(event.active.id as string)}
onDragCancel={() => setDragging(null)}
onDragEnd={handleDragEnd}
>
<SortableContext items={items} strategy={rectSortingStrategy}>
{children}
</SortableContext>
<DragOverlay>{dragging && overlay?.(dragging)}</DragOverlay>
</DndContext>
);
}
export function SortableGridItem({
id,
disabled = false,
children,
}: {
id: string;
disabled?: boolean;
children: (props: {
listeners: SyntheticListenerMap | undefined;
attributes: DraggableAttributes | undefined;
setNodeRef: (node: HTMLElement | null) => void;
style: React.CSSProperties | undefined;
isDragging: boolean;
}) => ReactNode;
}) {
const {
attributes,
listeners,
setNodeRef,
transform,
transition,
isDragging,
} = useSortable({ id, disabled });
return children({
listeners,
attributes,
setNodeRef,
isDragging,
style: {
transform: transform
? `translate3d(${transform.x}px, ${transform.y}px, 0) scaleX(${transform.scaleX}) scaleY(${transform.scaleY})`
: undefined,
transition,
opacity: isDragging ? 0.5 : 1,
},
});
}