├── .babelrc ├── .gitignore ├── README.md ├── examples ├── functionAsChildren │ ├── App.css │ └── App.js ├── simple │ ├── App.css │ └── App.js └── using types │ ├── App.css │ └── App.js ├── lib └── react-simple-dnd.js ├── package.json ├── rollup.config.js └── src ├── DragSource.js ├── DropTarget.js ├── HTML5DragDrop.js ├── constants.js └── index.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "react", 4 | [ 5 | "es2015", 6 | { 7 | "modules": false 8 | } 9 | ] 10 | ], 11 | "plugins": [ 12 | "transform-object-rest-spread", 13 | "external-helpers" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React-simple-dnd 2 | 3 | This Library is simply a bunch of wrappers around another library: [React DnD (by Dan Abramov)](http://gaearon.github.io/react-dnd/). 4 | 5 | React DnD is a library that implements Drag'nDrop in a “React way”: It doesn't touch the DOM, embraces unidirectional data flow and, most importantly, defines dragging logic as pure data. 6 | 7 | React DnD is powerful and flexible enough to support virtually any scenarios involving Drag'nDrop, but this comes at a cost: React DnD requires a lot of boilerplate even for the most simple use cases. 8 | 9 | React-simple-dnd is less flexible, but let you create Drag and Drop interfaces with fewer boilerplate and reduced complexity. 10 | 11 | ## Installing 12 | 13 | ```bash 14 | $ npm install react-simple-dnd 15 | ``` 16 | 17 | ## How to Use 18 | 19 | There are two elements available: `` and ``. 20 | 21 | Additionaly, there's the `HTML5DragDrop` Higher Order Component that must be wrap the root component of your application and set up the Drag and Drop support. 22 | 23 | See the [examples](https://github.com/cassiozen/react-simple-dnd/tree/master/examples) for complete usage cases. 24 | 25 | ### `` 26 | 27 | #### Usage 28 | 29 | ##### Simple 30 | 31 | ```js 32 | 33 |
34 | Drag Me 35 |
36 |
37 | ``` 38 | 39 | ##### Function as Children 40 | 41 | You can have access to isDragging through function-as-children 42 | 43 | ```js 44 | 45 | {(isDragging) => ( 46 |
47 | Drag Me 48 |
49 | )} 50 |
51 | ``` 52 | 53 | 54 | #### Props 55 | 56 | type: Optional. String. Only the drop targets registered for the same type will react to drag source. If not provided, a default value will be assigned. 57 | 58 | onBeginDrag: Optional. Function. Called when the dragging starts. 59 | 60 | onEndDrag: Optional. Function. Called when the dragging stops. 61 | 62 | **Important** React-DnD defines dragging logic as pure data. All other props passed to drag source will be made available to the DropTarget when dropped. 63 | 64 | 65 | ### `` 66 | 67 | #### Usage 68 | 69 | ##### Simple 70 | 71 | ```js 72 | 73 |
74 | Drop on me. 75 |
76 |
77 | ``` 78 | 79 | ##### Function as Children 80 | 81 | You can have access to isOver (true if user is dragging a DragSource over this target) through function-as-children 82 | 83 | ```js 84 | 85 | {(isOver) => ( 86 |
87 | Drag Me 88 |
89 | )} 90 |
91 | ``` 92 | 93 | 94 | #### Props 95 | 96 | types: Optional. String or Array of Strings. This drop target will only react to the drag sources of the specified type or types. 97 | 98 | onDrop: Optional. Function. Called when the user Drops a Drag source on this target. The "type" and any custom props included on will be passed as args when invoking this function. 99 | 100 | canDrop: Optional. Function. Called when the user tries to drop a Drag source on this target. Should return true or false whether the can be dropped in this target. The "type" and any custom props included on will be passed as args when invoking this function. 101 | 102 | 103 | ### HTML5DragDrop 104 | 105 | Wrap the root component of your application with DragDropContext to set up React DnD. 106 | This sets up the shared DnD state behind the scenes. 107 | 108 | #### Usage 109 | 110 | ```js 111 | import { HTML5DragDrop } from 'react-simple-dnd'; 112 | 113 | class YourApp { 114 | /* ... */ 115 | } 116 | 117 | export default HTML5DragDrop(YourApp); 118 | ``` 119 | -------------------------------------------------------------------------------- /examples/functionAsChildren/App.css: -------------------------------------------------------------------------------- 1 | .drag { 2 | display: inline-block; 3 | padding: 10px; 4 | margin: 10px; 5 | border: 5px solid #d9d9d9; 6 | background: #f7f7f7; 7 | height: 50px; 8 | width: 50px; 9 | border-radius: 10px; 10 | cursor: pointer; 11 | text-align: center; 12 | } 13 | 14 | .drag.invisible { 15 | color: #f7f7f7; 16 | border: 5px solid #f7f7f7; 17 | } 18 | 19 | .drop-target { 20 | width: 700px; 21 | height: 100px; 22 | padding: 150px 10px; 23 | border: 5px dashed #d9d9d9; 24 | border-radius: 10px; 25 | text-align: center; 26 | } 27 | 28 | 29 | .drop-target.over { 30 | background: #d7ffd7; 31 | } 32 | -------------------------------------------------------------------------------- /examples/functionAsChildren/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { DropTarget, DragSource, HTML5DragDrop } from 'react-simple-dnd'; 3 | import './App.css'; 4 | 5 | 6 | class App extends Component { 7 | handleDrop(draggedProps) { 8 | console.log('You Dropped', draggedProps.name); 9 | } 10 | 11 | render() { 12 | return ( 13 |
14 | 15 | {(isDragging) => ( 16 |
17 | Drag Item 1 18 |
19 | )} 20 |
21 | 22 | 23 | {(isDragging) => ( 24 |
25 | Drag Item 2 26 |
27 | )} 28 |
29 | 30 | 31 | {(isOver) => ( 32 |
33 | Drop on Me 34 |
35 | )} 36 |
37 |
38 | ); 39 | } 40 | } 41 | 42 | export default HTML5DragDrop(App); 43 | -------------------------------------------------------------------------------- /examples/simple/App.css: -------------------------------------------------------------------------------- 1 | .drag { 2 | display: inline-block; 3 | padding: 10px; 4 | margin: 10px; 5 | border: 5px solid #d9d9d9; 6 | background: #f7f7f7; 7 | height: 50px; 8 | width: 50px; 9 | border-radius: 10px; 10 | cursor: pointer; 11 | text-align: center; 12 | } 13 | 14 | .drop-target { 15 | width: 700px; 16 | height: 100px; 17 | padding: 150px 10px; 18 | border: 5px dashed #d9d9d9; 19 | border-radius: 10px; 20 | text-align: center; 21 | } 22 | -------------------------------------------------------------------------------- /examples/simple/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { DropTarget, DragSource, HTML5DragDrop } from 'react-simple-dnd'; 3 | import './App.css'; 4 | 5 | class App extends Component { 6 | handleDrop(draggedProps) { 7 | console.log('You Dropped', draggedProps.name); 8 | } 9 | 10 | render() { 11 | return ( 12 |
13 | 14 |
Drag Item 1
15 |
16 | 17 | 18 |
Drag Item 2
19 |
20 | 21 | 22 |
Drop on Me
23 |
24 |
25 | ); 26 | } 27 | } 28 | 29 | export default HTML5DragDrop(App); 30 | -------------------------------------------------------------------------------- /examples/using types/App.css: -------------------------------------------------------------------------------- 1 | .drag { 2 | display: inline-block; 3 | padding: 10px; 4 | margin: 10px; 5 | border: 5px solid #d9d9d9; 6 | background: #f7f7f7; 7 | height: 50px; 8 | width: 50px; 9 | border-radius: 10px; 10 | cursor: pointer; 11 | text-align: center; 12 | } 13 | 14 | .drop-target { 15 | float: left; 16 | width: 130px; 17 | height: 100px; 18 | margin: 10px; 19 | padding: 150px 10px; 20 | border: 5px dashed #d9d9d9; 21 | border-radius: 10px; 22 | text-align: center; 23 | } 24 | 25 | .drop-target.over { 26 | background: #d7ffd7; 27 | } 28 | -------------------------------------------------------------------------------- /examples/using types/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { DropTarget, DragSource, HTML5DragDrop } from 'react-simple-dnd'; 3 | import './App.css'; 4 | 5 | 6 | class App extends Component { 7 | handleDrop(draggedProps) { 8 | console.log('You Dropped', draggedProps.name); 9 | } 10 | 11 | render() { 12 | return ( 13 |
14 | 15 |
16 | Drag (Type “A”) 17 |
18 |
19 | 20 | 21 |
22 | Drag (Type “B”) 23 |
24 |
25 | 26 |
27 | 28 | {(isOver) => ( 29 |
30 | Only Drops type “A” 31 |
32 | )} 33 |
34 | 35 | 36 | {(isOver) => ( 37 |
38 | Only Drops type “B” 39 |
40 | )} 41 |
42 | 43 | 44 | {(isOver) => ( 45 |
46 | Drop anything on Me 47 |
48 | )} 49 |
50 |
51 |
52 | ); 53 | } 54 | } 55 | 56 | export default HTML5DragDrop(App); 57 | -------------------------------------------------------------------------------- /lib/react-simple-dnd.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { value: true }); 4 | 5 | function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } 6 | 7 | var React = require('react'); 8 | var React__default = _interopDefault(React); 9 | var reactDnd = require('react-dnd'); 10 | var HTML5Backend = _interopDefault(require('react-dnd-html5-backend')); 11 | 12 | var classCallCheck = function (instance, Constructor) { 13 | if (!(instance instanceof Constructor)) { 14 | throw new TypeError("Cannot call a class as a function"); 15 | } 16 | }; 17 | 18 | var createClass = function () { 19 | function defineProperties(target, props) { 20 | for (var i = 0; i < props.length; i++) { 21 | var descriptor = props[i]; 22 | descriptor.enumerable = descriptor.enumerable || false; 23 | descriptor.configurable = true; 24 | if ("value" in descriptor) descriptor.writable = true; 25 | Object.defineProperty(target, descriptor.key, descriptor); 26 | } 27 | } 28 | 29 | return function (Constructor, protoProps, staticProps) { 30 | if (protoProps) defineProperties(Constructor.prototype, protoProps); 31 | if (staticProps) defineProperties(Constructor, staticProps); 32 | return Constructor; 33 | }; 34 | }(); 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | var inherits = function (subClass, superClass) { 45 | if (typeof superClass !== "function" && superClass !== null) { 46 | throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); 47 | } 48 | 49 | subClass.prototype = Object.create(superClass && superClass.prototype, { 50 | constructor: { 51 | value: subClass, 52 | enumerable: false, 53 | writable: true, 54 | configurable: true 55 | } 56 | }); 57 | if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; 58 | }; 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | var objectWithoutProperties = function (obj, keys) { 69 | var target = {}; 70 | 71 | for (var i in obj) { 72 | if (keys.indexOf(i) >= 0) continue; 73 | if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; 74 | target[i] = obj[i]; 75 | } 76 | 77 | return target; 78 | }; 79 | 80 | var possibleConstructorReturn = function (self, call) { 81 | if (!self) { 82 | throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); 83 | } 84 | 85 | return call && (typeof call === "object" || typeof call === "function") ? call : self; 86 | }; 87 | 88 | 89 | 90 | var set = function set(object, property, value, receiver) { 91 | var desc = Object.getOwnPropertyDescriptor(object, property); 92 | 93 | if (desc === undefined) { 94 | var parent = Object.getPrototypeOf(object); 95 | 96 | if (parent !== null) { 97 | set(parent, property, value, receiver); 98 | } 99 | } else if ("value" in desc && desc.writable) { 100 | desc.value = value; 101 | } else { 102 | var setter = desc.set; 103 | 104 | if (setter !== undefined) { 105 | setter.call(receiver, value); 106 | } 107 | } 108 | 109 | return value; 110 | }; 111 | 112 | function HTML5DragDrop(WrappedComponent) { 113 | var HTML5DragDrop = function (_Component) { 114 | inherits(HTML5DragDrop, _Component); 115 | 116 | function HTML5DragDrop() { 117 | classCallCheck(this, HTML5DragDrop); 118 | return possibleConstructorReturn(this, (HTML5DragDrop.__proto__ || Object.getPrototypeOf(HTML5DragDrop)).apply(this, arguments)); 119 | } 120 | 121 | createClass(HTML5DragDrop, [{ 122 | key: 'render', 123 | value: function render() { 124 | return React__default.createElement(WrappedComponent, this.props); 125 | } 126 | }]); 127 | return HTML5DragDrop; 128 | }(React.Component); 129 | 130 | return reactDnd.DragDropContext(HTML5Backend)(HTML5DragDrop); 131 | } 132 | 133 | var DEFAULT_TYPE = '---default---'; 134 | 135 | var noop = function noop() {}; 136 | 137 | var DragComponent = function (_Component) { 138 | inherits(DragComponent, _Component); 139 | 140 | function DragComponent() { 141 | classCallCheck(this, DragComponent); 142 | return possibleConstructorReturn(this, (DragComponent.__proto__ || Object.getPrototypeOf(DragComponent)).apply(this, arguments)); 143 | } 144 | 145 | createClass(DragComponent, [{ 146 | key: 'render', 147 | value: function render() { 148 | var isDragging = this.props.isDragging; 149 | 150 | var child = void 0; 151 | if (typeof this.props.children === "function") { 152 | child = this.props.children(isDragging); 153 | } else { 154 | child = React__default.Children.only(this.props.children); 155 | } 156 | return this.props.connectDragComponent(child); 157 | } 158 | }]); 159 | return DragComponent; 160 | }(React.Component); 161 | 162 | DragComponent.propTypes = { 163 | children: React__default.PropTypes.oneOfType([React__default.PropTypes.func, React__default.PropTypes.element]).isRequired, 164 | // Injected by React DnD: 165 | isDragging: React__default.PropTypes.bool.isRequired, 166 | connectDragComponent: React__default.PropTypes.func.isRequired 167 | }; 168 | 169 | var DragSource$1 = function (_Component2) { 170 | inherits(DragSource$$1, _Component2); 171 | 172 | function DragSource$$1(props) { 173 | classCallCheck(this, DragSource$$1); 174 | 175 | var _this2 = possibleConstructorReturn(this, (DragSource$$1.__proto__ || Object.getPrototypeOf(DragSource$$1)).call(this, props)); 176 | 177 | var dragSourceSpec = { 178 | beginDrag: function beginDrag(_ref) { 179 | var children = _ref.children; 180 | var isDragging = _ref.isDragging; 181 | var connectDragComponent = _ref.connectDragComponent; 182 | var ownProps = objectWithoutProperties(_ref, ['children', 'isDragging', 'connectDragComponent']); 183 | 184 | props.onBeginDrag(); 185 | return ownProps; 186 | }, 187 | endDrag: function endDrag() { 188 | props.onEndDrag(); 189 | } 190 | }; 191 | 192 | _this2.DecoratedDragComponent = reactDnd.DragSource(props.type, dragSourceSpec, _this2.dragSourceCollect)(DragComponent); 193 | return _this2; 194 | } 195 | 196 | createClass(DragSource$$1, [{ 197 | key: 'dragSourceCollect', 198 | value: function dragSourceCollect(connect, monitor) { 199 | return { 200 | connectDragComponent: connect.dragSource(), 201 | isDragging: monitor.isDragging() 202 | }; 203 | } 204 | }, { 205 | key: 'render', 206 | value: function render() { 207 | var _props = this.props; 208 | var children = _props.children; 209 | var onBeginDrag = _props.onBeginDrag; 210 | var onEndDrag = _props.onEndDrag; 211 | var props = objectWithoutProperties(_props, ['children', 'onBeginDrag', 'onEndDrag']); 212 | 213 | return React__default.createElement(this.DecoratedDragComponent, props, children); 214 | } 215 | }]); 216 | return DragSource$$1; 217 | }(React.Component); 218 | 219 | DragSource$1.propTypes = { 220 | children: React__default.PropTypes.oneOfType([React__default.PropTypes.func, React__default.PropTypes.element]).isRequired, 221 | type: React__default.PropTypes.string, 222 | onBeginDrag: React__default.PropTypes.func, 223 | onEndDrag: React__default.PropTypes.func 224 | }; 225 | 226 | DragSource$1.defaultProps = { 227 | type: DEFAULT_TYPE, 228 | onBeginDrag: noop, 229 | onEndDrag: noop 230 | }; 231 | 232 | var noop$1 = function noop$1() {}; 233 | var returnTrue = function returnTrue() { 234 | return true; 235 | }; 236 | 237 | var DropComponent = function (_Component) { 238 | inherits(DropComponent, _Component); 239 | 240 | function DropComponent() { 241 | classCallCheck(this, DropComponent); 242 | return possibleConstructorReturn(this, (DropComponent.__proto__ || Object.getPrototypeOf(DropComponent)).apply(this, arguments)); 243 | } 244 | 245 | createClass(DropComponent, [{ 246 | key: 'render', 247 | value: function render() { 248 | var isOver = this.props.isOver; 249 | 250 | var child = void 0; 251 | if (typeof this.props.children === "function") { 252 | child = this.props.children(isOver); 253 | } else { 254 | child = React__default.Children.only(this.props.children); 255 | } 256 | return this.props.connectDropTarget(child); 257 | } 258 | }]); 259 | return DropComponent; 260 | }(React.Component); 261 | 262 | DropComponent.propTypes = { 263 | children: React__default.PropTypes.oneOfType([React__default.PropTypes.func, React__default.PropTypes.element]).isRequired, 264 | // Injected by React DnD: 265 | isOver: React__default.PropTypes.bool.isRequired, 266 | connectDropTarget: React__default.PropTypes.func.isRequired 267 | }; 268 | 269 | var DropTarget$1 = function (_Component2) { 270 | inherits(DropTarget$$1, _Component2); 271 | 272 | function DropTarget$$1(props) { 273 | classCallCheck(this, DropTarget$$1); 274 | 275 | var _this2 = possibleConstructorReturn(this, (DropTarget$$1.__proto__ || Object.getPrototypeOf(DropTarget$$1)).call(this, props)); 276 | 277 | var dropTargetSpec = { 278 | drop: function drop(ownProps, monitor) { 279 | props.onDrop(monitor.getItem()); 280 | }, 281 | canDrop: function canDrop(ownProps, monitor) { 282 | return props.canDrop(monitor.getItem()); 283 | } 284 | }; 285 | 286 | _this2.DecoratedDropComponent = reactDnd.DropTarget(props.types, dropTargetSpec, _this2.dropTargetCollect)(DropComponent); 287 | return _this2; 288 | } 289 | 290 | createClass(DropTarget$$1, [{ 291 | key: 'dropTargetCollect', 292 | value: function dropTargetCollect(connect, monitor) { 293 | return { 294 | connectDropTarget: connect.dropTarget(), 295 | isOver: monitor.isOver() 296 | }; 297 | } 298 | }, { 299 | key: 'render', 300 | value: function render() { 301 | var children = this.props.children; 302 | 303 | return React__default.createElement(this.DecoratedDropComponent, null, children); 304 | } 305 | }]); 306 | return DropTarget$$1; 307 | }(React.Component); 308 | 309 | DropTarget$1.propTypes = { 310 | children: React__default.PropTypes.oneOfType([React__default.PropTypes.func, React__default.PropTypes.element]).isRequired, 311 | types: React__default.PropTypes.oneOfType([React__default.PropTypes.string, React__default.PropTypes.array]), 312 | canDrop: React__default.PropTypes.func, 313 | onDrop: React__default.PropTypes.func 314 | }; 315 | 316 | DropTarget$1.defaultProps = { 317 | types: DEFAULT_TYPE, 318 | canDrop: returnTrue, 319 | onDrop: noop$1 320 | }; 321 | 322 | exports.HTML5DragDrop = HTML5DragDrop; 323 | exports.DragSource = DragSource$1; 324 | exports.DropTarget = DropTarget$1; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-simple-dnd", 3 | "version": "0.1.2", 4 | "description": "Wrapper around react-dnd", 5 | "main": "lib/react-simple-dnd", 6 | "scripts": { 7 | "build": "rollup --config rollup.config.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "Cássio M. Antonio", 11 | "license": "MIT", 12 | "repository": { 13 | "type": "git", 14 | "url": "git://github.com/cassiozen/react-simple-dnd.git" 15 | }, 16 | "dependencies": { 17 | "react-dnd": "^2.1.4", 18 | "react-dnd-html5-backend": "^2.1.2" 19 | }, 20 | "devDependencies": { 21 | "babel-plugin-external-helpers": "^6.8.0", 22 | "babel-plugin-transform-object-rest-spread": "^6.8.0", 23 | "babel-preset-es2015": "^6.14.0", 24 | "babel-preset-react": "^6.11.1", 25 | "rollup": "^0.35.10", 26 | "rollup-plugin-babel": "^2.6.1" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | 3 | export default { 4 | entry: 'src/index.js', 5 | format: 'cjs', 6 | plugins: [ babel() ], 7 | dest: 'lib/react-simple-dnd.js' 8 | }; 9 | -------------------------------------------------------------------------------- /src/DragSource.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { DEFAULT_TYPE } from './constants'; 3 | import { DragSource as reactDndDragSource } from 'react-dnd'; 4 | 5 | const noop = function() {}; 6 | 7 | class DragComponent extends Component { 8 | render() { 9 | const { isDragging } = this.props; 10 | let child; 11 | if (typeof this.props.children === "function") { 12 | child = this.props.children(isDragging); 13 | } else { 14 | child = React.Children.only(this.props.children); 15 | } 16 | return this.props.connectDragComponent(child); 17 | } 18 | } 19 | DragComponent.propTypes = { 20 | children: React.PropTypes.oneOfType([ 21 | React.PropTypes.func, 22 | React.PropTypes.element 23 | ]).isRequired, 24 | // Injected by React DnD: 25 | isDragging: React.PropTypes.bool.isRequired, 26 | connectDragComponent: React.PropTypes.func.isRequired 27 | }; 28 | 29 | 30 | export default class DragSource extends Component { 31 | constructor(props) { 32 | super(props); 33 | 34 | const dragSourceSpec = { 35 | beginDrag({ children, isDragging, connectDragComponent, ...ownProps }) { 36 | props.onBeginDrag(); 37 | return ownProps; 38 | }, 39 | endDrag() { 40 | props.onEndDrag(); 41 | } 42 | }; 43 | 44 | this.DecoratedDragComponent = reactDndDragSource(props.type, dragSourceSpec, this.dragSourceCollect)(DragComponent); 45 | } 46 | 47 | dragSourceCollect(connect, monitor) { 48 | return { 49 | connectDragComponent: connect.dragSource(), 50 | isDragging: monitor.isDragging() 51 | }; 52 | } 53 | 54 | render() { 55 | const { children, onBeginDrag, onEndDrag, ...props } = this.props; 56 | return React.createElement(this.DecoratedDragComponent, props, children); 57 | } 58 | } 59 | 60 | DragSource.propTypes = { 61 | children: React.PropTypes.oneOfType([ 62 | React.PropTypes.func, 63 | React.PropTypes.element 64 | ]).isRequired, 65 | type: React.PropTypes.string, 66 | onBeginDrag: React.PropTypes.func, 67 | onEndDrag: React.PropTypes.func, 68 | }; 69 | 70 | DragSource.defaultProps = { 71 | type: DEFAULT_TYPE, 72 | onBeginDrag: noop, 73 | onEndDrag: noop 74 | }; 75 | -------------------------------------------------------------------------------- /src/DropTarget.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { DEFAULT_TYPE } from './constants'; 3 | import { DropTarget as reactDndDropTarget } from 'react-dnd'; 4 | 5 | const noop = function() {}; 6 | const returnTrue = function() { return true; }; 7 | 8 | class DropComponent extends Component { 9 | render() { 10 | const { isOver } = this.props; 11 | let child; 12 | if (typeof this.props.children === "function") { 13 | child = this.props.children(isOver); 14 | } else { 15 | child = React.Children.only(this.props.children); 16 | } 17 | return this.props.connectDropTarget(child); 18 | } 19 | } 20 | DropComponent.propTypes = { 21 | children: React.PropTypes.oneOfType([ 22 | React.PropTypes.func, 23 | React.PropTypes.element 24 | ]).isRequired, 25 | // Injected by React DnD: 26 | isOver: React.PropTypes.bool.isRequired, 27 | connectDropTarget: React.PropTypes.func.isRequired 28 | }; 29 | 30 | export default class DropTarget extends Component { 31 | constructor(props) { 32 | super(props); 33 | 34 | const dropTargetSpec = { 35 | drop(ownProps, monitor) { 36 | props.onDrop(monitor.getItem()); 37 | }, 38 | canDrop(ownProps, monitor) { 39 | return props.canDrop(monitor.getItem()); 40 | } 41 | }; 42 | 43 | this.DecoratedDropComponent = reactDndDropTarget(props.types, dropTargetSpec, this.dropTargetCollect)(DropComponent); 44 | } 45 | 46 | dropTargetCollect(connect, monitor) { 47 | return { 48 | connectDropTarget: connect.dropTarget(), 49 | isOver: monitor.isOver() 50 | }; 51 | } 52 | 53 | render() { 54 | const { children } = this.props; 55 | return React.createElement(this.DecoratedDropComponent, null, children); 56 | } 57 | } 58 | 59 | DropTarget.propTypes = { 60 | children: React.PropTypes.oneOfType([ 61 | React.PropTypes.func, 62 | React.PropTypes.element 63 | ]).isRequired, 64 | types: React.PropTypes.oneOfType([ 65 | React.PropTypes.string, 66 | React.PropTypes.array 67 | ]), 68 | canDrop: React.PropTypes.func, 69 | onDrop: React.PropTypes.func, 70 | }; 71 | 72 | DropTarget.defaultProps = { 73 | types: DEFAULT_TYPE, 74 | canDrop: returnTrue, 75 | onDrop: noop 76 | }; 77 | -------------------------------------------------------------------------------- /src/HTML5DragDrop.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { DragDropContext } from 'react-dnd'; 3 | import HTML5Backend from 'react-dnd-html5-backend'; 4 | 5 | export default function HTML5DragDrop(WrappedComponent) { 6 | class HTML5DragDrop extends Component { 7 | render() { 8 | return ; 9 | } 10 | } 11 | 12 | return DragDropContext(HTML5Backend)(HTML5DragDrop); 13 | } 14 | -------------------------------------------------------------------------------- /src/constants.js: -------------------------------------------------------------------------------- 1 | export const DEFAULT_TYPE = '---default---'; 2 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export { default as HTML5DragDrop } from './HTML5DragDrop'; 2 | export { default as DragSource } from './DragSource'; 3 | export { default as DropTarget } from './DropTarget'; 4 | --------------------------------------------------------------------------------