import { useDraggable, useDroppable } from "@dnd-kit/react"; import { pointerIntersection } from "@dnd-kit/collision"; import { GripVertical } from "lucide-react"; import type { CSSProperties, ReactNode } from "react"; function chartSlotPosition(index: number, columns: number): CSSProperties { return { gridRow: Math.floor(index / columns) + 1, gridColumn: index % columns + 1 }; } export function ChartDropSlot({ index, columns, occupied }: { index: number; columns: number; occupied: boolean }) { const { ref, isDropTarget } = useDroppable({ id: `slot:${index}`, type: "slot", accept: "chart", data: { slot: index }, collisionDetector: pointerIntersection }); return
{!occupied ?

位置 {index + 1}拖动图表到这里

: null}
; } /** The chart stays under the same grid parent when its CSS position changes. */ export function ManagedChartSlot({ id, title, index, columns, located, helpId, register, children }: { id: string; title: string; index: number; columns: number; located: boolean; helpId: string; register: (id: string, element: HTMLElement | null) => void; children: ReactNode; }) { const { ref, handleRef, isDragSource } = useDraggable({ id, type: "chart", data: { title } }); return
{ ref(node); register(id, node); }} tabIndex={-1} data-managed-chart={id} data-chart-title={title} data-slot-index={index} data-chart-located={located} data-chart-dragging={isDragSource} aria-label={`图表窗口 ${title}`} style={chartSlotPosition(index, columns)} className="group/chart-slot relative z-0 flex min-h-0 min-w-0 flex-col rounded-xl outline-hidden">
{children}
; }