Getting started
Installation
Type in your terminal:
# npm
npm i effdnd
# pnpm
pnpm add effdnd
# yarn
yarn add effdnd
Quick start
In short, scope is used to limit the area of DnD, target is used as the destination of DnD, item is the element that is being moved. Custom element effdnd-trigger
will start DnD for closest item. It can be configured via effdnd-trigger
attributes (see ITriggerAttrs
interface for details).
Just call useDnD
function to define effdnd-trigger
and use its result to create special data-attributes.
import { useDnD } from 'effdnd';
// you can pass style params to useDnD to override global CSS for DnD elements (see `TUseDnD` type for details)
const { scope, item, target, css, observe } = useDnD();
// create scope attrs
const scopeAttrs = scope('local');
// create target attrs
const fisrtTargetAttrs = target('first');
// targets can be grouped
const secondTargetAttrs = target('second', 'group');
// create item attrs
const fisrtItemAttrs = item('first');
const secondItemAttrs = item('second');
// you can even set up separate styles for different DnD elements
const separateStyleAttrs = css({
passiveTarget: 'border: 4px solid grey',
});
export const Component = () => {
const ref = useRef();
useEffect(() => {
// you can observe DnD events
const unobserve = observe((e) => {
// DnD event reaction
}, ref.current);
// and you can unobserve
return () => unobserve();
})
// just apply ready attrs - and magic happen
// don't forget to use `<effdnd-trigger>` inside items
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>;
}
Active and passive elements
When dragging effdnd
set special dynamic attributes indicating the activity of the element.
The item is active while dragging.
The scope is passive when the drag item is inside it and at least one condition is truthy
effdnd-trigger
has noscope
attribute (closest scope is suitable)effdnd-trigger
hasscope
attribute and its value is equal to scope key
The scope becomes active when it is passive and the drag item is trying to get out.
The target is passive when it is inside scope and at least one condition is truthy
effdnd-trigger
has notarget
attribute (all targets are suitable)effdnd-trigger
hastarget
attribute and its value is equal to target group
The target becomes active when it is passive and the drag item is trying to get on top of it.
useDnD
The function accepts transition settings as the first argument and custom styles as the second one. It returns attribute resolvers and event handlers:
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
The element can be configured via attributes:
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';
}