npm package: @sougabriel/react-drag-and-drop
Description: A minimalistic drag and drop library with focus in customization
Author: Gabriel de Souza
Latest version: 1.0.1

# React Drag and Drop

Just a minimalistic drag and drop library with focus in customization.

## Getting Started

### Install

NPM:

```bash
npm i @sougabriel/react-drag-and-drop
```

YARN:

```bash
yarn add @sougabriel/react-drag-and-drop
```

### Usage Exemple

Complete example bellow:

```typescript
import { useCallback, useState } from 'react';
import { DragAndDropProvider, Draggable, DropZone, type DragItem } from '@sougabriel/react-drag-and-drop';
import '../styles/index.css';

interface Task {
    id: number;
    title: string;
    description: string;
}

const initialTasks: Record<string, Task[]> = {
    todo: [
        { id: 1, title: 'Task 1', description: 'task description' },
        { id: 2, title: 'Task 2', description: 'task description' },
    ],
    doing: [{ id: 3, title: 'Task 3', description: 'task description' }],
    done: [{ id: 4, title: 'Task 4', description: 'task description' }],
    blocked: [],
    archived: [],
};

const TASK_TYPE = 'TASK';
const ARCHIVE_TYPE = 'ARCHIVED_TASK';
const BLOCKED_TYPE = 'BLOCKED_TASK';

export default function App() {
    const [tasks, setTasks] = useState(initialTasks);

    const handleDrop = useCallback((item: DragItem<Task>, targetZoneId: string) => {
        if (item.sourceZoneId === targetZoneId) return;

        setTasks((prevTasks) => {
            const newTasks = { ...prevTasks };
            const sourceColumn = prevTasks[item.sourceZoneId];
            const targetColumn = prevTasks[targetZoneId];

            const taskIndex = sourceColumn.findIndex((task) => task.id === item.value.id);
            if (taskIndex === -1) return prevTasks;

            const newSourceColumn = [...sourceColumn];
            newSourceColumn.splice(taskIndex, 1);

            const newTargetColumn = [...targetColumn, item.value];

            newTasks[item.sourceZoneId] = newSourceColumn;
            newTasks[targetZoneId] = newTargetColumn;

            return newTasks;
        });
    }, []);

    const handleTaskClick = useCallback((task: Task) => {
        alert('You clicked on task:', task.title);
    }, []);

    const canDropOnDone = useCallback((item: DragItem<Task>): boolean => {
        return item.sourceZoneId === 'doing';
    }, []);

    return (
        <DragAndDropProvider>
            <div className='kanban-board'>
                <div className='kanban-column'>
                    <DropZone<Task>
                        zoneId='todo'
                        accepts={[TASK_TYPE, BLOCKED_TYPE]}
                        onDropItem={handleDrop}
                        isOverAllowedClassName='over-allowed'
                        isOverDeniedClassName='over-denied'
                    >
                        {tasks.todo.map((task) => (
                            <Draggable<Task>
                                key={task.id}
                                item={{ value: task, type: TASK_TYPE, sourceZoneId: 'todo' }}
                                onClick={handleTaskClick}
                            >
                                <div className='card'>{task.description}</div>
                            </Draggable>
                        ))}
                    </DropZone>
                </div>

                <div className='kanban-column'>
                    <DropZone<Task>
                        zoneId='doing'
                        accepts={[TASK_TYPE, BLOCKED_TYPE]}
                        onDropItem={handleDrop}
                        isOverAllowedClassName='over-allowed'
                        isOverDeniedClassName='over-denied'
                    >
                        {tasks.doing.map((task) => (
                            <Draggable<Task>
                                key={task.id}
                                item={{ value: task, type: TASK_TYPE, sourceZoneId: 'doing' }}
                            >
                                <div className='card'>{task.description}</div>
                            </Draggable>
                        ))}
                    </DropZone>
                </div>

                <div className='kanban-column'>
                    <DropZone<Task> zoneId='blocked' accepts={[TASK_TYPE, ARCHIVE_TYPE]} onDropItem={handleDrop}>
                        {tasks.blocked.map((task) => (
                            <Draggable<Task>
                                key={task.id}
                                item={{ value: task, type: BLOCKED_TYPE, sourceZoneId: 'blocked' }}
                            >
                                <div className='card'>{task.description}</div>
                            </Draggable>
                        ))}
                    </DropZone>
                </div>

                <div className='kanban-column'>
                    <DropZone<Task> zoneId='done' accepts={[TASK_TYPE]} onDropItem={handleDrop} canDrop={canDropOnDone}>
                        {tasks.done.map((task) => (
                            <Draggable<Task>
                                key={task.id}
                                item={{ value: task, type: ARCHIVE_TYPE, sourceZoneId: 'done' }}
                            >
                                <div className='card'>{task.description}</div>
                            </Draggable>
                        ))}
                    </DropZone>
                </div>

                <div className='kanban-column'>
                    <DropZone<Task> zoneId='archived' accepts={[ARCHIVE_TYPE, BLOCKED_TYPE]} onDropItem={handleDrop}>
                        {tasks.archived.map((task) => (
                            <Draggable<Task>
                                key={task.id}
                                item={{ value: task, type: ARCHIVE_TYPE, sourceZoneId: 'archived' }}
                            >
                                <div className='card'>{task.description}</div>
                            </Draggable>
                        ))}
                    </DropZone>
                </div>
            </div>
        </DragAndDropProvider>
    );
}
```

## Contact

### Repository

You can contribute to this library through its GitHub repository: [sougabriel/ngx-libraries](https://github.com/sougabriel/ngx-libraries).

### Author

<div>
    <a href="https://github.com/sougabriel">
        <img src="https://skillicons.dev/icons?i=github" height="32px" alt="GitHub Logo" /> github.com/sougabriel
    </a><br>
    <a href="mailto:gabriel.dsouzapro@gmail.com">
        <img src="https://skillicons.dev/icons?i=gmail" height="32px" alt="Gmail Logo" /> gabriel.dsouzapro@gmail.com
    </a><br>
    <a href="https://www.linkedin.com/in/sougabriels/">
        <img src="https://skillicons.dev/icons?i=linkedin" height="32px" alt="LinkedIn Logo" /> linkedin.com/in/sougabriels
    <a><br>
</div>