Giter VIP home page Giter VIP logo

react-dragtastic's Introduction

react-dragtastic

react-dragtastic

npm version npm version code style: prettier

A simple drag and drop library for React which uses the more stable mouseDown/mouseUp pattern instead of the problematic HTML5 drag and drop API.

Drag and drop interfaces are complicated and difficult to properly program, this package attempts to alleviate some of the common hangups with drag and drop libraries. It should be noted that there are more mature solutions available such as the excellent react-dnd package, however for many simple drag and drop applications, the implementation of such packages can quickly become arduous.

  • Warning, version 2 represents a significant rewrite of version 1 of react-dragtastic. The API is completely different, but with the changes come several stability improvements, primitive mobile support, and significantly increased render flexibility. Be sure you're ready to rewrite your drag-and-drop implementation before upgrading from version 1.

Example

Demo Site More examples coming soon

Code Sandbox Example

Installation

npm install --save react-dragtastic
or
yarn add react-dragtastic

Usage

For ES6 and up
import {
  Draggable,
  Droppable,
  DragComponent,
  DragState
} from "react-dragtastic"
For ES5
var dnd = require("react-dragtastic")
var Draggable = dnd.Draggable
var Droppable = dnd.Droppable
var DragComponent = dnd.DragComponent

Overview

react-dragtastic makes use of three different components, a <Draggable/> component which defines a zone on a page which can then trigger drag events, a <Droppable/> component, which defines zones which trigger drop events, and a <DragComponent/> component which defines the component that follows the user's pointer around the page while dragging.

react-dragtastic uses the "function-as-child" component pattern to give you full control over the rendering details of each component.

Draggable

This defines a draggable zone. At a minimum, spread the events over the element that should be draggable (usually the root element).

  • id: An id which will be used in the draggable zone's target <DragComponent/>
  • type: A string, or array of strings, used to limit which droppable zones will accept <DragComponent/>'s attached to this draggable.
  • data: Data of any type which will be passed to the onDrop function of any <Droppable/> which accepts this <Draggable/>'s type.
  • onDragStart: A function which will be called when the <Draggable/> zone is activated (The user started dragging).
  • onDragEnd: A function which will be called when the <Draggable/> zone is deactivated (The user stopped dragging).
  • onDrag: A function which will be called every time the user's cursor moves while dragging.
  • delay: An optional int representing the distance in pixels the user's pointer must travel to activate the draggable. Defaults to 8
  • subscribeTo: An optional array of strings. For performance reasons you can limit which keys in the dragState your component subscribes to. For example, you may pass ['type', 'data'] to only rerender if these keys change.

Properties available from dragState:

  • All the properties listed in the dragState section.
  • isActive: A boolean representing if the draggable is currently active.
class DraggableZone extends React.Component {
  render() {
    return (
      <Draggable id="unique-id" type="apple">
        {dragState => <div {...dragState.events}>I'm a draggable zone</div>}
      </Draggable>
    )
  }
}

Droppable

This defines a droppable zone. At a minimum, spread the events over the element that should be droppable (usually the root element).

  • accepts: A string type corresponding to the type property of the <Draggable/> zone for which this <Droppable/> should accept drop events.
  • onDrop: A function which will be called when a user drops a <DragComponent/> on this <Droppable/> with an accepted type.
  • onDragEnter: A function which will be called when the user's cursor enters the <Droppable/> while dragging. This function will be called regardless of whether the droppable accepts the draggable currently being dragged.
  • onDragLeave: A function which will be called when the user's cursor leaves the <Droppable/> while dragging. This function will be called regardless of whether the droppable accepts the draggable currently being dragged.
  • subscribeTo: An optional array of strings. For performance reasons you can limit which keys in the dragState your component subscribes to. For example, you may pass ['type', 'data'] to only rerender if these keys change.

Properties available from dragState:

  • All the properties listed in the dragState section.
  • isOver: A boolean representing if the user is currently hovering the <Droppable/>.
  • willAccept: A boolean representing if this droppable will accept the currently dragging <DragComponent/>.
class DroppableZone extends React.Component {
  render() {
    return (
      <Droppable accepts="apple">
        {dragState => <div {...dragState.events}>I'm a droppable zone</div>}
      </Droppable>
    )
  }
}

DragComponent

By default, children passed to this component will only render if the user is currently dragging, but this can be overridden.

  • for: A string corresponding to the id property of the <Draggable/> zone that should trigger this component to start rendering.
  • onDrag: A function which will be called every time a user drags.
  • alwaysRender: A boolean determining whether or not the DragComponent should always render. Defaults to false.
  • subscribeTo: An optional array of strings. For performance reasons you can limit which keys in the dragState your component subscribes to. For example, you may pass ['type', 'data'] to only rerender if these keys change.

Properties available from dragState:

  • All the properties listed in the dragState section.
  • isOverAccepted: a boolean representing whether the user is currently hovering a <Droppable/> that accepts the type of the currently active <Draggable/>
class DragComponentWrapper extends React.Component {
  render() {
    return (
      <DragComponent for="unique-id">
        {dragState => (
          <div
            style={{
              position: "fixed",
              left: dragState.x,
              top: dragState.y,
              pointerEvents: "none"
            }}
          >
            I will render when my Draggable zone is activated
          </div>
        )}
      </DragComponent>
    )
  }
}

DragState

All components imported from react-dragtastic have access the global dragState with the following properties:

  • x: The user's current horizontal position on the page.
  • y: The user's current vertical position on the page.
  • startingX: The user's initial horizontal position on the page when they started dragging.
  • startingy: The user's initial vertical position on the page when they started dragging.
  • isDragging: A boolean representing whether the user is currently dragging.
  • currentlyDraggingId: The id of the currently dragging element.
  • currentlyHoveredDroppableId: The id of the <Droppable/> currently being hovered.
  • currentlyHoveredDroppableAccepts: The accepts property of the <Droppable/> currently being hovered.
  • data: Data from the data property of the <Draggable/> which is currently active. null if not dragging.
  • type: The type of the component being currently dragged. null if not dragging.
  • subscribeTo: An optional array of strings. For performance reasons you can limit which keys in the dragState your component subscribes to. For example, you may pass ['type', 'data'] to only rerender if these keys change.

Occasionally you may need to notify a component about changes in the dragState without making that component a draggable or droppable zone. For these cases there is a fourth component available called <DragState/>. This component is used just like a draggable or droppable, but does not accept or trigger any drag events.

class CompWithDragState extends React.Component {
  render() {
    return (
      <DragState>
        {dragState => (
          <div style={{ background: dragState.isDragging ? "red" : "blue" }}>
            I always render, and have access to the global dragState.
          </div>
        )}
      </DragState>
    )
  }
}

Troubleshooting

My Droppables aren't working!

  • You most likely need to set pointer-events: none in the css of your DragComponent. This allows droppables to receive drop events when the user's pointer is directly on top of the DragComponent as it is being dragged. This property is well supported.

My app is slow when I have a lot of Draggables or Droppables

  • In this case the easiest fix is to use the subscribeTo prop to pass an array of dragState keys you want to subscribe to.

Coming Soon

  • A project website with live examples.
  • Screencast showing basic implementation examples.
  • Improved mobile support.
  • Additional event hooks

Contributing

Contributions of any kind are welcome. Please feel free to file issues, submit pull-requests, or drop us a line with feature requests.

react-dragtastic's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

react-dragtastic's Issues

Typescript types for DefinitelyTyped repository

Hello!

Before anything else: thanks for this great library! I spent so much time looking for a way to cleanly handle d&d I started to believe there was no easy way.

I would very much like to use this on my TypeScript projects, but I noticed there is no type definition published for it on DefinitelyTyped, so I took the liberty of translating the .js.flow file to a TypeScript module and made a pull request (you can find it here).

I hope this is OK with you and, of course, if you want to review the pull request and add your own feedback, it would be very welcome.

Best regards.

Nested Droppable

I have a large Droppable which has multiple smaller Droppables inside of it. Either are valid targets.

Once the mouse moves into the parent Droppable, isOver gets set to true. Once the mouse moves into a child Droppable, isOver on the parent gets set to false, and isOver on the child gets set to true, as you'd expect. However, when I move out of the child (and the cursor is still within the parent), then my parent does not get isOver set back to true.

Any thoughts? Thanks.

My parent droppable is very straightforward:

<Droppable id={date} accepts={ACCEPTS} onDrop={this.handleDrop}>
        {dragState => {
          return (
            <div {...dragState.events}>
              <Day
                {...this.props}
                isHoveredOver={dragState.isOver}
              />
            </div>
          );
        }}
      </Droppable>

isOver impacts all Droppables

I have a basic a calendar where each Day is a Droppable. However if I drag an item onto any day, then ALL Droppables think isOver is true, when only the Droppable I'm hovering over should have isOver === true.

Pass `dragState` to `onX` callbacks

I need to access attributes of dragState in some of the callbacks, e.g. onDrop, but the callbacks either receive no arguments or dragState.data. Would you be open to passing dragState to all onX callbacks?

Version 3 Master Ticket

This issue is intended to track progress on version 3.

The main goals for version 3:

  • Add new hooks API
  • Clear up any existing issues as of the creation of this ticket
  • Full Mobile Support
  • Better performance

New prop for disabling draggable

I've found in my use-case scenarios that it would be nice to pass a boolean prop to the <Draggable/> that could disable it. This is especially useful in cases where a child of the Draggable also needs to be able to handle click or tap events.

Setstate needs to test if it's mounted before running

Currently the components don't test if they're mounted before firing a setState. This leads to an occasional case where components throw React's setState error. Each component should internally track their mounted state as described here

Mobile support

Hi Chris,

I can't seem to make the library work for mobile. Dragging is fine in most devices I tried, but it seems like no event gets fired once I drop a draggable on a droppable.
I was preparing a code example, but seems like the demo site examples don't work for me either, so you could check from there.

Is there any workaround to make the events work (I only need the onDrop event) or perhaps some extra configuration (like the pointer-events: none) that would work for mobile?

Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.