This is a library for creating custom drop-zones. Elements that are inside those drop-zones are draggable and Dropzone into other ones.
- JavaScript
- TypeScript
- DragDropProvider
- DropZone
- Works in React.js applications
- Prop
states
(array of objects: [{state: , setState: }, {...}, ...]) needs to be present onDragDropProvider
component
import { DropZone, DragDropProvider } from 'react-drag-drop-zones';
import { useState } from 'react';
export type ElementType = {
id: number;
title: string;
};
function App() {
const [elements_0, setElements_0] = useState<ElementType[]>([
{ id: 1, title: "Element 1" },
{ id: 2, title: "Element 2" },
]);
const [elements_1, setElements_1] = useState<ElementType[]>([
{ id: 3, title: "Element 3" },
{ id: 4, title: "Element 4" },
]);
const [elements_2, setElements_2] = useState<ElementType[]>([
{ id: 5, title: "Element 5" },
{ id: 6, title: "Element 6" },
]);
const states = [
{ state: elements_0, setState: setElements_0 },
{ state: elements_1, setState: setElements_1 },
{ state: elements_2, setState: setElements_2 },
];
return (
<DragDropProvider states={states}>
<DropZone>
{elements_0.map(el => (<div key={el.id}>{el.title}</div>) )}
</DropZone>
<DropZone>
{elements_1.map(el => (<div key={el.id}>{el.title}</div>) )}
</DropZone>
<DropZone>
{elements_2.map(el => (<div key={el.id}>{el.title}</div>) )}
</DropZone>
</DragDropProvider>
);
}
export default App;
- CSS native:
- Inline styling. Passing a
style
(object)
- as a prop to any component provided by library
- as an attribute to any draggable element provided by user
- Passing
className
(string)
- as a prop to any component provided by this library
- as an attribute to any draggable element provided by user
- styles by selectors in .css file
- Tailwind, SCSS or any other styling library acceptable.
const inlineCSS = {
display: "flex",
flexDirection: "column",
gap: "1rem",
backgroundColor: "red",
// ...
}
<DragDropProvider className="flex flex-col gap-3 bg-green-500 ..." > // styling by tailwind clasNames
<DropZone className="flex flex-col gap-2 bg-blue-300 ..."> // styling by tailwind clasNames
{elements_0.map(el => (<div key={el.id}>{el.title}</div>) )}
</DropZone>
<DropZone style={inlineCSS}> // styling by inline CSS
{elements_1.map(el => (<div key={el.id}>{el.title}</div>) )}
</DropZone>
<DropZone className="customClassDropZone"> // styling by custom css
{elements_2.map(el => (<div key={el.id}>{el.title}</div>) )}
</DropZone>
</DragDropProvider>
-
afterDrop
function (optional) that will be executed after element is droped in one of theDropZone
's * FunctionafterDrop
receives one argument (object of type:AfterDropType
) that contains information(indexes) about dragged and droppedelement
and it'sDropzone
. It contains:- indexes of source and destination
Dropzone
(relatively to it's parent-DragDropProvider
) - index of dragged element where it was dragged from (relatively to it's parent- source
Dropzone
) - index(position) of dragged element where it was dropped into (relatively to destination
Dropzone
). If you drop element between elements with indexes 1 and 2 so index of a dropped element will be 2 (distance between elements starts and ends in the middle of them)
- indexes of source and destination
export type AfterDropType = {
sourceDropzoneIndex: number;
destinationDropzoneIndex: number;
draggedElementIndex: number;
positionDestinationIndex: number;
};
function customAfter(data: AfterDropType) { /*logic*/ }
- sourceDropzoneIndex : Index of
Dropzone
component (relatively to it's parent :DragDropProvider
) whereelement
was dragged from - destinationDropzoneIndex : Index of
Dropzone
component (relatively to it's parent :DragDropProvider
) whereelement
was dropped into - draggedElementIndex : Index of a dragged
element
(relatively to it's parent : sourceDropzone
) where it was dragged from - positionDestinationIndex : Index of a dropped
element
(relatively to it's parent : destinationDropzone
) where it was dropped into
Steps and example :
- Import
AfterDropType
: -
afterDrop
prop =>DragDropProvider
- create
customAfter
function and associate it to theafterDrop
prop
import { DropZone, DragDropProvider, AfterDropType } from 'react-drag-drop-zones';
function App() {
// ...
const customAfter = (data: AfterDropType) => {/*logic*/}
return (
<DragDropProvider
afterDrop={customAfter}
states={states}
>
{/* DropZones logic */}
</DragDropProvider>
);
}
export default App;
-
customStatesManipulation
(optional) prop(of typeboolean
) inDragDropProvider
* If prop is passed toDragDropProvider
astrue
the sates will remain unchanged and it is up to the user to make proper states manipulation thanks to an object thatafterDrop
receives. Example:
import { DropZone, DragDropProvider, AfterDropType } from 'react-drag-drop-zones';
function App() {
// ...
const customAfter = (data: AfterDropType) => {/*logic*/}
return (
<DragDropProvider
customStatesManipulation = {true}
afterDrop={customAfter}
states={states}
>
{/* DropZones logic */}
</DragDropProvider>
);
}
export default App;
import { DropZone, DragDropProvider, AfterDropType } from 'react-drag-drop-zones';
import { useState } from 'react';
export type ElementType = {
id: number;
title: string;
};
function App() {
const [elements_0, setElements_0] = useState<ElementType[]>([
{ id: 1, title: "Element 1" },
{ id: 2, title: "Element 2" },
]);
const [elements_1, setElements_1] = useState<ElementType[]>([
{ id: 3, title: "Element 3" },
{ id: 4, title: "Element 4" },
]);
const [elements_2, setElements_2] = useState<ElementType[]>([
{ id: 5, title: "Element 5" },
{ id: 6, title: "Element 6" },
]);
const states = [
{ state: elements_0, setState: setElements_0 },
{ state: elements_1, setState: setElements_1 },
{ state: elements_2, setState: setElements_2 },
];
const afterDrop = (data: AfterDropType) => {
console.log(data)
/*after drop logic if needed*/
/*for example states manipulation
if `customStatesManipulation` is `true` and is passed to `DragDropProvider`
*/
}
return (
<DragDropProvider
afterDrop={customAfter}
// customStatesManipulation = {true}
// style={{ display: 'flex', flexDirection: 'column', gap: '2rem' }} // inline CSS
className='flex gap-5 p-5 flex-col' // tailwind
states={states}
>
<DropZone className="flex flex-col gap-2 bg-blue-300 ..."> // styling by tailwind clasNames
{elements_0.map(el => (<div key={el.id}>{el.title}</div>) )}
</DropZone>
<DropZone style={inlineCSS}> // styling by inline CSS
{elements_1.map(el => (<div key={el.id}>{el.title}</div>) )}
</DropZone>
<DropZone className="customClassDropZone"> // styling by custom css
{elements_2.map(el => (<div key={el.id}>{el.title}</div>) )}
</DropZone>
</DragDropProvider>
);
}
export default App;
-
DragDropProvider
Propsprop optional description states
no An array of state objects. Each object should have a state
andsetState
propertyafterDrop
yes A function that is executed at the end of a drag & drop action. It receives an argument(object of type AfterDropType
) containing information about the dropcustomStatesManipulation
yes A boolean flag. If set to true, the drop action will not modify the states, and it's up to the user to handle state modifications in the afterDrop function -
types
-
AfterDropType
type description sourceDropzoneIndex
Index of Dropzone
component (relatively to it's parent :DragDropProvider
) whereelement
was dragged fromdestinationDropzoneIndex
Index of Dropzone
component (relatively to it's parent :DragDropProvider
) whereelement
was dropped intodraggedElementIndex
Index of a dragged element
(relatively to it's parent : sourceDropzone
) where it was dragged frompositionDestinationIndex
Index of a dropped element
(relatively to it's parent : destinationDropzone
) where it was dropped into
-
-
DragDropProvider
andDropzone
Propsprop optional description className
yes A string representing the a className
for theDragDropProvider
componentstyle
yes An object containing CSS properties to inline style the DragDropProvider
andDropZone
components
This project is licensed under the MIT License - see the LICENSE file for details.