Skip to content

はじめに(バージョン2)

インストール

ターミナルに以下を入力してください:

sh
# npm
npm i effdnd

# pnpm
pnpm add effdnd

# yarn
yarn add effdnd

クイックスタート

簡単に言うと、effdnd は2つのカスタムWebコンポーネントを使用します。

  • effdnd trigger はドラッグ&ドロップをトリガーします。
  • effdnd-actor は、ドラッグ&ドロップ処理に参加するレイアウト領域(役割を担う領域)を示します。

Webコンポーネント effdnd-actor は、以下の複数の役割を担うことができます。

  • item:移動するアイテム、
  • target:移動先、
  • scope:移動範囲。

役割を設定するには、effdnd-actor 要素に同名の属性を設定する必要があります。1つの要素に複数の役割を設定できます。属性値は、effdnd-trigger コンポーネントによってドラッグ&ドロップの参加者を識別するために使用されます。

ドラッグ&ドロップの開始時、effdnd-trigger Webコンポーネントは、その属性を使用してプロセスに参加する要素(アクター)を選択します。

  • item属性を使用すると、移動するアイテムを選択できます。この属性が指定されていない場合は、指定されたitem属性を持つツリー内の最も近い要素<effdnd-actor item='...'>が使用されます。値が#の属性が設定されている場合(<effdnd-trigger item='#'>)、または上位のDOMツリーに<effdnd-actor item='...'>が存在しない場合は、トリガー自体が移動します。トリガーにclone属性が設定されている場合は、移動のためにHTML要素のクローンが作成されます。

  • scope属性を使用すると、移動可能な領域を選択できます。この属性が指定されていない場合は、指定されたscope属性を持つツリー内の最も近い要素<effdnd-actor scope='...'>が使用されます。値が # の属性が設定されている場合 (<effdnd-trigger scope='#'>)、または上記の DOM ツリーに <effdnd-actor scope='...'> が存在しない場合、スコープ領域は document.body になります。

target 属性を使用すると、使用可能な移動ターゲットを選択できます。移動ターゲットは、ドラッグ アンド ドロップが終了したときに特別なイベントを生成します。scope 領域内にあるすべての <effdnd-actor target='...'> 要素は移動ターゲットとみなされ、その名前はトリガーの target 属性の値で始まります。つまり、属性が指定されていない場合は、<effdnd-actor scope='...'> 内のすべての <effdnd-actor target='...'> が使用可能になります。

両方の Web コンポーネントを定義するには、useDnD 関数を呼び出し、呼び出し結果を使用してイベントリスナーを作成します。

jsx
import { useRef } from 'react';
import { useDnD } from 'effdnd';

// useDnD にスタイルパラメータを渡すことで、移動パラメータを上書きできます(詳細については、型 `TUseDnD` を参照してください。)
const { observe } = useDnD();

export const Component = () => {
    const ref = useRef();
    useEffect(() => {
      // ドラッグ&ドロップイベントに登録できます
      const unobserve = observe((e) => {
        // イベントはここで処理されています
      }, ref.current);
      // 購読を解除できます
      return () => unobserve();
    });
    return <effdnd-actor scope='top' ref={ref} >
        <div className="targets-wrapper">
            <effdnd-actor target='target-1'>...</effdnd-actor>
            <effdnd-actor target='target-2'>...</effdnd-actor>
        </div>
        <div id="items-wrapper">
            <effdnd-actor item='item-1'>
                <effdnd-trigger>Trigger #1</effdnd-trigger>
            </effdnd-actor>
            <effdnd-actor item='item-2'>
                <effdnd-trigger>Trigger #2</effdnd-trigger>
            </effdnd-actor>
        </div>
    </effdnd-actor>;
}

アクティブ要素とパッシブ要素

ドラッグ&ドロップ中、effdnd-trigger は選択された effdnd-actor 要素に動的な state 属性を設定します。つまり、トリガーは最初に、移動対象 (item)、移動範囲 (scope)、移動先 (target) を決定します。要素は、以下のいずれかの状態になります。

  • 状態なし、
  • パッシブ状態 (state="passive")、
  • アクティブ状態 (state="active")。

item ロールを持つ要素は、移動中は アクティブ状態になります。さらに、item ロールを持つ要素は、クローンがアクティブ状態の場合、クローン状態 (state="cloned") になることもあります。

scope ロールを持つ要素は、item がその内部を移動している間は パッシブ状態になります。

scopeロールを持つ要素は、passive状態にあるときにitemがその範囲を超えようとすると、active状態になります。この状態は、ユーザーに移動可能な範囲を示します。

targetロールを持つ要素は、scope内のactive状態またはpassive状態にあるときに、passive状態になります。

targetロールを持つアイテムは、passive状態にあるときにitemがその上を通過すると、active状態になります。

コンポーネントのスタイル

<effdnd-actor item='...'> の外観は、移動中にトリガーが属性を使用して設定します。属性を使用して、アニメーションパラメータ、移動軸、最小発射距離を設定することもできます。

ts
/**
 * DnD trigger attributes
 */
export interface ITriggerAttrs {
    /**
     * Item name
     * @description
     * If the value is "#" then it will use `effnd-trigger` as item
     */
    item?: string;
    /**
     * Bounding scope name
     * @description
     * If the value is "#" then it will use `document.body` as scope
     */
    scope?: string;
    /**
     * Target name or its prefix
     */
    target?: string;
    /**
     * Triggering distance
     */
    dist?: string;
    /**
     * DnD axis
     */
    axis?: string;
    /**
     * Triggering event
     * @description
     * Both 'touch' and 'mouse' by default
     */
    event?: 'touch' | 'mouse';
    /**
     * Transition duration
     */
    dur?: string;
    /**
     * Transition delay
     */
    del?: string;
    /**
     * Transition timing-function
     */
    tf?: string;
    /**
     * Item z-index in active state
     */
    zi?: string;
    /**
     * Item opacity in active state
     */
    opacity?: string;
    /**
     * Use item clone while dragging
     */
    clone?: boolean;
}

ウェブコンポーネントeffdnd-actorには、targetscopeの両方のパッシブ状態とアクティブ状態の初期スタイルが既に含まれていますが、unstyled属性を使用してそれらをキャンセルすることもできます。同時に、<effdnd-actor unstyled="target">targetの組み込みスタイルのみをキャンセルし、<effdnd-actor unstyled="scope">scopeの組み込みスタイルのみをキャンセルし、<effdnd-actor unstyled>はすべての組み込みスタイルをキャンセルします。

ts
/**
 * DnD actor attributes
 */
export interface IActorAttrs {
    /**
     * Item name
     */
    item?: string;
    /**
     * Scope name
     */
    scope?: string;
    /**
     * Target name
     */
    target?: string;
    /**
     * Actor state
     */
    state?: 'active' | 'passive';
    /**
     * Reset target state styles
     */
    unstyled?: boolean | 'target' | 'scope';
    /**
     * Display contents
     */
    contents?: boolean;
}

contents属性を使用すると、display:contents;スタイルを設定できます。unstyled属性を追加すると、さまざまな状態に対して独自のCSSスタイルを設定できます。

css
effdnd-actor[target][state=passive] .custom-dnd-target {
  outline: 4px solid #646cffaa;
}
effdnd-actor[target][state=active] .custom-dnd-target {
  outline: 4px solid #646cffaa;
  background: #646cffaa;
}

useDnD

この関数は、最初の引数としてトランジション設定を、2番目の引数としてカスタムスタイルを受け取ります。カスタムイベントをリッスンするための関数を返します。

ts
export type TEventDetail = {
    type: TEventType;
    refs: TRefs;
    keys: TKeys;
    event: MouseEvent | TouchEvent;
};

interface TDnDEvent extends CustomEvent {
    detail: TEventDetail;
}

export type TDnDCallback = (event: TDnDEvent) => void;

export type TUseDnD = (defs?: Partial<{
    /**
     * Duration
     */
    dur: number;
    /**
     * Delay
     */
    del: number;
    /**
     * Transition-timing-function
     */
    tf: string;
    /**
     * Active DnD item z-index
     */
    zi: number;
    /**
     * Active DnD item opacity
     */
    opacity: number;
}>) => {
    /**
     * Observe DnD events
     * @param callback - event handler
     * @param element - HTML element
     */
    observe: (callback: TDnDCallback, element?: HTMLElement) => () => void;
    /**
     * Unobserve DnD events
     * @param callback - event handler
     * @param element - HTML element
     */
    unobserve: (callback: TDnDCallback, element?: HTMLElement) => void;
};

effdnd trigger

トリガーWebコンポーネントには、いくつかの便利なメソッドとプロパティが含まれています。

ts
/**
 * DnD trigger element 
 */
export interface ITriggerElement extends HTMLElement {
    /**
     * DnD item y-offset
     */
    dndY: number;
    /**
     * DnD item x-offset
     */
    dndX: number;
    /**
     * DnD item
     */
    dndItem: HTMLElement;
    /**
     * DnD scope
     */
    dndScope: HTMLElement;
    /**
     * DnD targets
     */
    dndTargets: Set<HTMLElement>;
    /**
     * Reset DnD transforms
     */
    resetDnD(options?: KeyframeAnimationOptions): Promise<void>;
}

Apache License 2.0に基づいて公開されています。