React Logoreact-draggable

react-draggable is a React component that makes any of its children draggable. It provides a simple and flexible way to add drag-and-drop functionality to elements within a React application. It's built on top of the excellent 'Draggable' library but specifically designed for React, taking advantage of React's component-based architecture.

Key Features and Concepts:

1. Simple Integration: You wrap the component you want to make draggable with the `<Draggable>` component.
2. Controlled vs. Uncontrolled:
* Uncontrolled: Using `defaultPosition` allows the Draggable component to manage its own position internally. This is simpler for basic use cases.
* Controlled: Using `position` requires you to manage the draggable item's position in your component's state. You must also provide `onDrag` or `onStop` callbacks to update this state, giving you precise control over the element's movement.
3. Axis Restriction: The `axis` prop ('x', 'y', 'both', 'none') allows you to restrict movement to horizontal, vertical, or no axis.
4. Bounds: The `bounds` prop can restrict the draggable element's movement to a specific area. This can be a parent container ('parent'), an object with {left, top, right, bottom} coordinates, or a CSS selector string.
5. Handles and Cancels:
* The `handle` prop (a CSS selector) specifies which part of the draggable element can be used to initiate dragging.
* The `cancel` prop (a CSS selector) specifies elements within the draggable area that, when clicked, will *not* initiate dragging.
6. Grid Snapping: The `grid` prop takes an array `[x, y]` to snap the draggable element's position to a grid.
7. Callbacks: It provides several callback functions for different stages of the drag event:
* `onStart`: Called when dragging starts.
* `onDrag`: Called continuously while dragging.
* `onStop`: Called when dragging stops.
* These callbacks receive event objects and data objects containing information like current x, y positions.

Use Cases:

* Creating interactive dashboards where users can rearrange widgets.
* Implementing draggable modals or dialog boxes.
* Building puzzle games or drag-and-drop interfaces.
* Developing tools where elements need to be positioned freely by the user.

Installation:

`npm install react-draggable` or `yarn add react-draggable`

Example Code

import React, { useState } from 'react';
import Draggable from 'react-draggable';
import './App.css'; // Assuming you have some basic CSS for styling

function App() {
  const [activeDrags, setActiveDrags] = useState(0);
  const [deltaPosition, setDeltaPosition] = useState({
    x: 0, y: 0
  });

  const handleStart = () => {
    setActiveDrags(prev => prev + 1);
  };

  const handleDrag = (e, ui) => {
    const { x, y } = deltaPosition;
    setDeltaPosition({
      x: x + ui.deltaX,
      y: y + ui.deltaY,
    });
  };

  const handleStop = () => {
    setActiveDrags(prev => prev - 1);
  };

  const dragHandlers = { onStart: handleStart, onStop: handleStop };

  return (
    <div className="App">
      <h1>React Draggable Examples</h1>

      <h2>Basic Draggable (Uncontrolled)</h2>
      <div className="draggable-container" style={{ height: '200px', width: '300px', border: '2px solid blue', position: 'relative', overflow: 'hidden' }}>
        <Draggable {...dragHandlers} defaultPosition={{x: 25, y: 25}} bounds="parent">
          <div className="box">
            <div>Drag Me!</div>
            <p>I'm restricted to my parent.</p>
          </div>
        </Draggable>
      </div>

      <h2>Draggable with Custom Handle</h2>
      <Draggable {...dragHandlers} handle=".handle" defaultPosition={{x: 0, y: 100}}>
        <div className="box" style={{ background: '#e0ffe0', border: '1px solid green' }}>
          <div className="handle" style={{ background: 'green', color: 'white', padding: '5px', cursor: 'grab' }}>Drag Handle</div>
          <p>You can only drag me by the green handle.</p>
        </div>
      </Draggable>

      <h2>Controlled Draggable</h2>
      <Draggable position={deltaPosition} onDrag={handleDrag} {...dragHandlers}>
        <div className="box" style={{ background: '#ffe0e0', border: '1px solid red' }}>
          <p>I'm controlled by state.</p>
          <p>x: {deltaPosition.x.toFixed(0)}, y: {deltaPosition.y.toFixed(0)}</p>
        </div>
      </Draggable>

      <div className="status">
        <p>Number of active drags: {activeDrags}</p>
      </div>
    </div>
  );
}

export default App;

/* App.css for basic styling */
/*
.App {
  font-family: sans-serif;
  text-align: center;
  padding: 20px;
}

.draggable-container {
  margin: 20px auto;
  background-color: #f0f0f0;
}

.box {
  width: 150px;
  height: 80px;
  border: 1px solid #ccc;
  background-color: #fff;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  cursor: grab;
  box-shadow: 2px 2px 5px rgba(0,0,0,0.2);
  user-select: none; 
  position: relative; 
}

.box:active {
  cursor: grabbing;
}

.status {
  margin-top: 40px;
  font-size: 0.9em;
  color: #555;
}
*/