SCALE — Build Lab
開発パターン · REACT HOOK

ドラッグ中オートスクロール

CATEGORY開発パターン TYPEReact Hook EFFORT60〜180分 DIFFICULTY
PRIMARY CODE
ts · lib/use-drag-autoscroll.ts
import { useEffect } from 'react';

/**
 * ドラッグ中に画面端に近づいたら自動でスクロールするフック。
 * isDragging が true の間だけ document の dragover を listen。
 * 端に近いほど速くスクロールするため、ドラッグしながら一気に画面外まで移動できる。
 *
 * このアプリは main 要素(id="app-scroll")が overflow:auto のスクロールコンテナなので
 * window ではなくその要素を scrollBy する。
 */
export function useDragAutoScroll(isDragging: boolean) {
  useEffect(() => {
    if (!isDragging) return;
    const handler = (e: DragEvent) => {
      const y = e.clientY;
      // スクロール対象を取得(main要素 → fallbackで window)
      const scroller = document.getElementById('app-scroll') as HTMLElement | null;
      const top = scroller ? scroller.getBoundingClientRect().top : 0;
      const bottom = scroller ? scroller.getBoundingClientRect().bottom : window.innerHeight;
      const threshold = 100;
      // 上端付近
      if (y < top + threshold) {
        const speed = Math.ceil((top + threshold - y) / 5);
        if (scroller) scroller.scrollBy(0, -speed); else window.scrollBy(0, -speed);
      } else if (y > bottom - threshold) {
        const speed = Math.ceil((y - (bottom - threshold)) / 5);
        if (scroller) scroller.scrollBy(0, speed); else window.scrollBy(0, speed);
      }
    };
    document.addEventListener('dragover', handler);
    return () => document.removeEventListener('dragover', handler);
  }, [isDragging]);
}

前提条件
Tailwind CSS v4TypeScript 5
USE CASES
  • カンバンボード
  • タスクリスト

ドラッグ中オートスクロール

:LiTarget: 用途

D&D中に画面端でオートスクロールする React Hook。

:LiSparkle: 特徴

  • 上下端自動スクロール
  • 速度可変
  • シンプルAPI

:LiCode: 実コード(SCALE Base より自動抽出)

:LiInfo: lib/use-drag-autoscroll.ts の中身そのもの。コピペ即可。

import { useEffect } from 'react';

/**
 * ドラッグ中に画面端に近づいたら自動でスクロールするフック。
 * isDragging が true の間だけ document の dragover を listen。
 * 端に近いほど速くスクロールするため、ドラッグしながら一気に画面外まで移動できる。
 *
 * このアプリは main 要素(id="app-scroll")が overflow:auto のスクロールコンテナなので
 * window ではなくその要素を scrollBy する。
 */
export function useDragAutoScroll(isDragging: boolean) {
  useEffect(() => {
    if (!isDragging) return;
    const handler = (e: DragEvent) => {
      const y = e.clientY;
      // スクロール対象を取得(main要素 → fallbackで window)
      const scroller = document.getElementById('app-scroll') as HTMLElement | null;
      const top = scroller ? scroller.getBoundingClientRect().top : 0;
      const bottom = scroller ? scroller.getBoundingClientRect().bottom : window.innerHeight;
      const threshold = 100;
      // 上端付近
      if (y < top + threshold) {
        const speed = Math.ceil((top + threshold - y) / 5);
        if (scroller) scroller.scrollBy(0, -speed); else window.scrollBy(0, -speed);
      } else if (y > bottom - threshold) {
        const speed = Math.ceil((y - (bottom - threshold)) / 5);
        if (scroller) scroller.scrollBy(0, speed); else window.scrollBy(0, speed);
      }
    };
    document.addEventListener('dragover', handler);
    return () => document.removeEventListener('dragover', handler);
  }, [isDragging]);
}

:LiFolder: ソースファイルのパス

/Users/oogushiyuuki/Library/CloudStorage/GoogleDrive-y-ogushi@scale-group.co.jp/マイドライブ/AI/scale-base/lib/use-drag-autoscroll.ts

:LiHandPointer: 使い方

対象プロジェクトに該当ファイルをコピーして、props を流し込むだけ。

:LiAlertCircle: 注意事項

  • 依存パッケージを忘れず追加