错误: 无法访问属性"relativeX", t.dragEvent() 为空
作者: MrLolok创建于 2025年7月14日更新于 2025年7月14日
import type { Swapy } from "swapy"; import type { SwappableGridProps, SwapyEvent } from "./types";
import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { createSwapy, utils } from "swapy";
import { cn } from "../../utils/cn";
const SwappableGrid = <T,>({ items, keyAttribute, onReorder, renderItem, className }: SwappableGridProps) => { const containerRef = useRef(null); const swapyRef = useRef<Swapy | null>(null);
const [slotItemMap, setSlotItemMap] = useState(utils.initSlotItemMap(items, keyAttribute));
const slottedItems = useMemo(
() => utils.toSlottedItems(items, keyAttribute, slotItemMap),
[items, keyAttribute, slotItemMap],
);
const handleSwap = useCallback(
(event: SwapyEvent) => {
const newMap = event.newSlotItemMap.asArray;
setSlotItemMap(newMap);
const reorderedItems = utils
.toSlottedItems(items, keyAttribute, newMap)
.map(({ item }) => item)
.filter((item): item is T => item !== null);
onReorder(reorderedItems);
},
[items, keyAttribute, onReorder],
);
useEffect(() => {
const containerElement = containerRef.current;
if (containerElement) {
swapyRef.current = createSwapy(containerElement, {
swapMode: "hover",
manualSwap: true,
});
swapyRef.current.onSwap(handleSwap);
}
return () => {
swapyRef.current?.destroy();
};
}, [handleSwap]);
useEffect(() => {
utils.dynamicSwapy(swapyRef.current, items, keyAttribute, slotItemMap, setSlotItemMap);
}, [items, keyAttribute]);
return (
<div ref={containerRef} className={cn("container", className)}>
{slottedItems.map(({ slotId, itemId, item }) => {
if (!item) return null;
return (
<div key={slotId} data-swapy-slot={slotId} className="aspect-square">
<div
key={itemId}
data-swapy-item={itemId}
className="h-full w-full Cursor-grab active:Cursor-grabbing"
>
{renderItem(item)}
</div>
</div>
);
})}
</div>
);
};
SwappableGrid.displayName = "SwappableGrid"; export default SwappableGrid;
内容来源: TahaSh/swapy