ドラッグ&ドロップ
:LiTarget: 用途
カンバン・並び替え・ファイルアップロードのD&Dパターン。
:LiSparkle: 特徴
- 並び替え
- カンバン
- ファイルD&D
- タッチ対応
:LiCode: コード(コピペ用)
'use client';
import { useState } from 'react';
// シンプル並び替え(HTML5 Drag & Drop API・外部ライブラリ不要)
export function SortableList<T extends { id: string }>({
items, onChange, render,
}: {
items: T[];
onChange: (newOrder: T[]) => void;
render: (item: T) => React.ReactNode;
}) {
const [dragId, setDragId] = useState<string | null>(null);
const [overId, setOverId] = useState<string | null>(null);
const reorder = (from: string, to: string) => {
const fromIdx = items.findIndex((i) => i.id === from);
const toIdx = items.findIndex((i) => i.id === to);
if (fromIdx < 0 || toIdx < 0 || fromIdx === toIdx) return;
const next = [...items];
const [moved] = next.splice(fromIdx, 1);
next.splice(toIdx, 0, moved);
onChange(next);
};
return (
<div>
{items.map((it) => (
<div key={it.id}
draggable
onDragStart={() => setDragId(it.id)}
onDragOver={(e) => { e.preventDefault(); setOverId(it.id); }}
onDragLeave={() => setOverId(null)}
onDrop={() => { if (dragId) reorder(dragId, it.id); setDragId(null); setOverId(null); }}
onDragEnd={() => { setDragId(null); setOverId(null); }}
className={`cursor-move transition-all ${
dragId === it.id ? 'opacity-40' : ''
} ${
overId === it.id && dragId !== it.id ? 'border-t-2 border-indigo-500' : ''
}`}>
{render(it)}
</div>
))}
</div>
);
}
// ファイル D&D アップロード
export function FileDropzone({ onDrop }: { onDrop: (files: File[]) => void }) {
const [over, setOver] = useState(false);
return (
<div
onDragOver={(e) => { e.preventDefault(); setOver(true); }}
onDragLeave={() => setOver(false)}
onDrop={(e) => { e.preventDefault(); setOver(false); onDrop(Array.from(e.dataTransfer.files)); }}
className={`border-2 border-dashed rounded-xl p-8 text-center transition-colors ${
over ? 'border-indigo-500 bg-indigo-500/10' : 'border-zinc-700 bg-zinc-900/40'
}`}>
<p className="text-sm text-zinc-400">ファイルをここにドロップ</p>
</div>
);
}
:LiHandPointer: 使い方
対象プロジェクトに該当ファイルをコピーして、props を流し込むだけ。
:LiAlertCircle: 注意事項
- 依存パッケージを忘れず追加