はじめに(バージョン1)
インストール
ターミナルに以下を入力してください:
sh
# npm
npm i effdnd
# pnpm
pnpm add effdnd
# yarn
yarn add effdndクイックスタート
簡単に言うと、effdnd はデータ属性を使って、通常の HTML 要素の役割を設定します。
- ドラッグする要素
item、 - ドラッグする対象
target、 - ドラッグ範囲
scope。
カスタム要素 effdnd-trigger は、最も近い item に対してドラッグ&ドロップを開始します。属性を使って設定できます(詳細は ITriggerAttrs インターフェースを参照)。effdnd-trigger 自体も item の役割を持つことができ、つまり、独自のドラッグを開始できます。
useDnD 関数を呼び出して effdnd-trigger を定義し、その結果を使って特別なデータ属性を作成するだけです。
jsx
import { useDnD } from 'effdnd';
// useDnDにスタイルパラメータを渡すことで、DnD要素のグローバルCSSを上書きできます(詳細は`TUseDnD`型を参照してください)。
const { scope, item, target, css, observe } = useDnD();
// `scope`属性を作成します
const scopeAttrs = scope('local');
// `target`属性を作成します
const fisrtTargetAttrs = target('first');
// ターゲットはグループ化できます
const secondTargetAttrs = target('second', 'group');
// `item`属性を作成します
const fisrtItemAttrs = item('first');
const secondItemAttrs = item('second');
// さまざまなD&D要素ごとに個別のスタイルを設定することもできます。
const separateStyleAttrs = css({
passiveTarget: 'border: 4px solid grey',
});
export const Component = () => {
const ref = useRef();
useEffect(() => {
// DnDイベントを観察できます
const unobserve = observe((e) => {
// DnDイベントの反応
}, ref.current);
// そして、あなたは観察を中止することができます
return () => unobserve();
})
// 準備完了の属性を適用するだけで、魔法のように動作します。
// アイテム内で `effdnd-trigger` を使用することを忘れないでください
return <div ref={ref} {...scopeAttrs}>
<div className="targets-wrapper">
<div {...fisrtTargetAttrs}>...</div>
<div {...secondTargetAttrs} {...separateStyleAttrs}>...</div>
</div>
<div id="items-wrapper">
<div {...fisrtItemAttrs}>
<effdnd-trigger>Trigger #1</effdnd-trigger>
</div>
<div {...secondItemAttrs}>
<effdnd-trigger>Trigger #2</effdnd-trigger>
</div>
</div>
</div>;
}アクティブ要素とパッシブ要素
ドラッグ中、effdnd は要素の状態を示す動的な属性を設定します。要素は、
- 状態なし、
- パッシブ状態、
- アクティブ状態のいずれかになります。
item はドラッグ中はアクティブ状態です。
scope は、ドラッグ中の item がスコープ内にあり、かつ以下の条件のうち少なくとも 1 つが真である場合にパッシブ状態になります。
effdnd-triggerにscopeのキーと等しい値のscope属性が含まれている場合、effdnd-triggerにscope属性が含まれておらず、かつscopeが最も近いscopeである場合。
scope 要素がパッシブ状態であり、item がその範囲を超えようとすると、scope 要素はアクティブ状態になります。この状態は、ユーザーにドラッグ可能な範囲を示すのに役立ちます。
target要素は、scope内にあり、active状態またはpassive状態のいずれかで、かつ以下のいずれかの条件を満たす場合にpassive状態となります。
effdnd-triggerに、target要素のグループと同じ値が設定されたtarget属性が含まれている場合。effdnd-triggerにtarget属性が含まれていない場合(すべてのtarget要素が該当します)。
target要素は、passive状態にあるときにitemがその上にドラッグされるとactive状態になります。
useDnD
この関数は、最初の引数としてトランジション設定を、2番目の引数としてカスタムスタイルを受け取ります。そして、属性リゾルバーとイベントハンドラーを返します。
ts
type TEventDetail = {
type: TEventType;
refs: TRefs;
keys: TKeys;
event: MouseEvent | TouchEvent;
};
interface TDnDEvent extends CustomEvent {
detail: TEventDetail;
}
type TDnDCallback = (event: TDnDEvent) => void;
type TDynamicAttrs = Partial<{
/**
* Active DnD item styles
*/
activeItem: string;
/**
* Passive DnD target styles
*/
passiveTarget: string;
/**
* Active DnD target styles
*/
activeTarget: string;
/**
* Passive DnD scope styles
*/
passiveScope: string;
/**
* Active DnD scope styles
*/
activeScope: string;
}>;
type TUseDnD = {
(transition?: Partial<{
/**
* Duration
*/
dur: string | number;
/**
* Delay
*/
del: string | number;
/**
* Transition-timing-function
*/
tf: string;
}>, css?: TDynamicAttrs): {
/**
* 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;
/**
* Use DnD item
* @param key - item key
*/
item: (key: string) => object;
/**
* Use DnD target
* @param key - target key
*/
target: (key: string, group?: string) => object;
/**
* Use DnD scope
* @param key - scope key
*/
scope: (key?: string) => object;
/**
* Use different CSS for DnD elements
*/
css: (params: TDynamicAttrs) => object;
};
customCount?: number;
stylesheet?: CSSStyleSheet;
}effdnd-trigger
要素は属性によって設定できます。
ts
interface ITriggerAttrs {
/**
* Bounding scope key
*/
scope?: string;
/**
* Targets group
*/
target?: string;
/**
* Triggering distance
*/
dist?: string;
/**
* Triggering event
* @description
* Both 'touch' and 'mouse' by default
*/
event?: 'touch' | 'mouse';
}