#142·swapy

错误: 无法访问属性"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;