Getting started (V1)
Installation
Type in your terminal:
# npm
npm i effdnd
# pnpm
pnpm add effdnd
# yarn
yarn add effdndQuick start
In short, effdnd uses data attributes to set the roles of regular HTML elements:
- dragging element
item, - dragging target
target, - the dragging area
scope.
Custom element effdnd-trigger will start drag-and drop for closest item. It can be configured via attributes (see ITriggerAttrs interface for details). The effdnd-trigger itself can also have the item role, meaning it can initiate its own dragging.
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
During dragging, effdnd sets dynamic attributes that show the state of the elements. The elements can be
- without a state,
- in a passive state,
- in an active state.
The item is active while dragging.
The scope is passive when dragging item is inside it and at least one condition is truthy
effdnd-triggercontains the scope attribute with a value equal to the key ofscope,effdnd-triggerdoes not contain the scope attribute, and this is the closestscopeto it.
The scope element becomes active if it is in a passive state and the item tries to go beyond it. This state helps to show the user the available drag limits.
The target element is passive when it is inside the scope with an active or passive state and any of the conditions are met
effdnd-triggercontains the target attribute with a value equal to the group of thetargetelement,effdnd-triggerdoes not contain the target attribute (alltargetelements are suitable).
The target element becomes active if it is in a passive state and the item is dragged over 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';
}