@dragger/core
v1.0.9
Published
A simple, performant drag and drop library for React
Downloads
31
Maintainers
Readme
@dragger/core
Overview
- Simple Architecture - there are only two components for you to worry about:
<Draggable />
and<Droppable />
. Use them anywhere, no context provider needed. - Unobtrusive - dragger automatically renders dragged components outside the normal document flow. No need to worry about transforms and z-index fighting, and no need to rewrite all your components in a seperate drag layer - it sorts everything out for you
- Performance - animations are performed outside of the React render loop to ensure everything runs smoothly
- Customisable - use your own collision algorithms or modify our ones. Each
<Draggable />
can have a different collision algorithm, and a different response to a dropped item - Typescript Support - everything is typed straight out of the box. You can define your own type for
data
, which will apply to the whole instance
Getting Started
First, create a dragger instance
The instance returns <Draggable />
and <Droppable />
components, which can be used anywhere you want.
import dragger from "@dragger/core";
const { Draggable, Droppable } = dragger();
Create a draggable component
When a draggable is dragged, it's children will be rendered twice - on a seperate layer as an overlay
, and in the normal document flow as a placeholder
. The <Draggable />
tells its children which one of these it is.
It also passes two additional props: drag
and handle
. drag
should be attached to the component you want to move with the drag, and handle
should be used on the component you want to activate the drag. They can be attached to the same component.
function Item() {
return (
<Draggable>
{({ drag, handle, overlay, placeholder }) => (
<div
{...drag}
{...handle}
style={{
opacity: overlay ? 0.2 : 1,
boxShadow: placeholder
? "0px 15px 15px 0 rgba(34, 33, 81, 0.25)"
: undefined,
}}
>
<p>draggable</p>
</div>
)}
</Draggable>
);
}
Create a droppable component
<Droppable />
components accept an onDrop
callback. They also accept an id
, which must be unique and will be automatically generated if not given, and a collision
callback - see the "Collision Algorithms" section below.
The <Droppable />
also gives props to it's children. The drop
prop should be attached to the component you want to act as the droppable container. The over
prop tells them if an item is currently being dragged over it.
function Item() {
return (
<Droppable onDrop={() => console.log("dropped!")}>
{({ drop, over }) => (
<div {...drop} style={{ backgroundColor: over ? "#f9f9f9" : "#ffffff" }} />
)}
</Draggable>
);
}
Draggable Data
Each <Draggable />
component can be given a data
attribute that can be used by onDrop
callbacks and collision algorithms.
When using TypeScript, all draggable data should be expressed in a single type. You can use a union type if you want there to be multiple types.
The Draggable Data type should be given to dragger()
when creating the instance.
import dragger from "@dragger/core";
interface Data {
name: string;
}
const { Draggable, Droppable } = dragger<Data>();
The <Draggable />
component returned by the instance will require data of this type as a prop.
<Draggable data={{ name: string }}>
Collision Algorithms
The default collision algorithm chooses the smallest droppable that the mouse is currently over. You can use different collision algorithms on each <Droppable />
, including your own custom ones.
Collision algorithms accept the active element and the droppable rect as parameters, and should return either true
to definitely choose the current droppable, false
to skip the current droppable, or a numerical score (e.g distance) if it should be considered for comparison. If no collision algorithms return true
, the one with the lowest score will be chosen.
type CollisionAlgorithm<Data> = (
active: {
data: Data;
rect: Rect;
mousePosition: Position;
},
rect: Rect
) => boolean | number;