Tips & Tricks

Como Implementar Drag and Drop com Claude Code

Aprenda a implement drag and drop usando o Claude Code. Inclui exemplos praticos de codigo e orientacao passo a passo.

ドラッグ&ドロップの実装パターン

ドラッグ&ドロップは直感的なUIを実現する重要な機能です。リスト並べ替え、カンバンボード、ファイルアップロードなど多くの場面で使われます。Claude Codeを使えば、アクセシブルで堅牢なドラッグ&ドロップを効率よく実装できます。

カスタムフックによる基本実装

> HTML Drag and Drop APIを使ったReactのカスタムフックを作って。
> リストの並べ替えに対応して。
import { useState, useCallback, DragEvent } from 'react';

function useSortable<T extends { id: string }>(initialItems: T[]) {
  const [items, setItems] = useState(initialItems);
  const [draggedId, setDraggedId] = useState<string | null>(null);

  const handleDragStart = useCallback((e: DragEvent, id: string) => {
    setDraggedId(id);
    e.dataTransfer.effectAllowed = 'move';
    e.dataTransfer.setData('text/plain', id);
  }, []);

  const handleDragOver = useCallback((e: DragEvent, targetId: string) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = 'move';

    if (draggedId === null || draggedId === targetId) return;

    setItems((prev) => {
      const dragIndex = prev.findIndex((item) => item.id === draggedId);
      const targetIndex = prev.findIndex((item) => item.id === targetId);
      const newItems = [...prev];
      const [removed] = newItems.splice(dragIndex, 1);
      newItems.splice(targetIndex, 0, removed);
      return newItems;
    });
  }, [draggedId]);

  const handleDragEnd = useCallback(() => {
    setDraggedId(null);
  }, []);

  return { items, draggedId, handleDragStart, handleDragOver, handleDragEnd, setItems };
}

ソート可能なリストコンポーネント

function SortableList({ initialTasks }: { initialTasks: Task[] }) {
  const { items, draggedId, handleDragStart, handleDragOver, handleDragEnd } =
    useSortable(initialTasks);

  return (
    <ul role="listbox" aria-label="タスク一覧(並べ替え可能)">
      {items.map((task) => (
        <li
          key={task.id}
          draggable
          role="option"
          aria-grabbed={draggedId === task.id}
          onDragStart={(e) => handleDragStart(e, task.id)}
          onDragOver={(e) => handleDragOver(e, task.id)}
          onDragEnd={handleDragEnd}
          className={`p-3 mb-2 rounded border cursor-grab ${
            draggedId === task.id ? 'opacity-50 border-blue-400' : 'border-gray-200'
          }`}
        >
          <span>{task.title}</span>
        </li>
      ))}
    </ul>
  );
}

ファイルドロップゾーン

> ファイルをドラッグ&ドロップでアップロードできるコンポーネントを作って。
> プレビュー表示とバリデーションも。
function FileDropZone({ onFiles, accept, maxSize = 5 * 1024 * 1024 }: DropZoneProps) {
  const [isDragging, setIsDragging] = useState(false);
  const [errors, setErrors] = useState<string[]>([]);

  const validateFiles = (files: File[]): File[] => {
    const errs: string[] = [];
    const valid = files.filter((file) => {
      if (accept && !accept.includes(file.type)) {
        errs.push(`${file.name}: 対応していないファイル形式です`);
        return false;
      }
      if (file.size > maxSize) {
        errs.push(`${file.name}: ファイルサイズが上限を超えています`);
        return false;
      }
      return true;
    });
    setErrors(errs);
    return valid;
  };

  const handleDrop = (e: DragEvent<HTMLDivElement>) => {
    e.preventDefault();
    setIsDragging(false);
    const files = Array.from(e.dataTransfer.files);
    const valid = validateFiles(files);
    if (valid.length > 0) onFiles(valid);
  };

  return (
    <div
      onDragOver={(e) => { e.preventDefault(); setIsDragging(true); }}
      onDragLeave={() => setIsDragging(false)}
      onDrop={handleDrop}
      className={`border-2 border-dashed rounded-lg p-8 text-center transition-colors ${
        isDragging ? 'border-blue-500 bg-blue-50' : 'border-gray-300'
      }`}
    >
      <p>ファイルをここにドロップ、またはクリックして選択</p>
      {errors.map((err, i) => (
        <p key={i} className="text-red-500 text-sm mt-1">{err}</p>
      ))}
    </div>
  );
}

キーボード操作のサポート

アクセシビリティのためにキーボードでも操作できるようにします。

const handleKeyDown = (e: React.KeyboardEvent, index: number) => {
  if (e.key === ' ' || e.key === 'Enter') {
    e.preventDefault();
    toggleGrabbed(index);
  }
  if (e.key === 'ArrowUp' && isGrabbed) {
    e.preventDefault();
    moveItem(index, index - 1);
  }
  if (e.key === 'ArrowDown' && isGrabbed) {
    e.preventDefault();
    moveItem(index, index + 1);
  }
};

Summary

Claude Codeを使えば、リスト並べ替えからファイルアップロードまで、多様なドラッグ&ドロップ実装を効率的に構築できます。ファイルアップロードの詳細はファイルアップロード実装を、アクセシビリティ対応はアクセシビリティガイドを参照してください。

HTML Drag and Drop APIの仕様はMDN Web Docsをご覧ください。

#Claude Code #drag and drop #React #UI #interaction