Skip to content

Commit c1a5bb3

Browse files
committed
Bugfix: <Draggable> should call back with offset, not client position. Fixes RGL bug
1 parent 3be049f commit c1a5bb3

File tree

3 files changed

+63
-16
lines changed

3 files changed

+63
-16
lines changed

lib/Draggable.es6

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,22 +146,22 @@ export default class Draggable extends DraggableCore {
146146
// Kills start event on core as well, so move handlers are never bound.
147147
if (shouldStart === false) return false;
148148

149-
this.setState({
150-
dragging: true
151-
});
149+
this.setState({dragging: true});
152150
};
153151

154152
onDrag = (e, coreEvent) => {
155153
if (!this.state.dragging) return false;
156154
log('Draggable: onDrag: %j', coreEvent.position);
157155

156+
let uiEvent = createUIEvent(this, coreEvent);
157+
158158
// Short-circuit if user's callback killed it.
159-
let shouldUpdate = this.props.onDrag(e, createUIEvent(this, coreEvent));
159+
let shouldUpdate = this.props.onDrag(e, uiEvent);
160160
if (shouldUpdate === false) return false;
161161

162162
let newState = {
163-
clientX: this.state.clientX + coreEvent.position.deltaX,
164-
clientY: this.state.clientY + coreEvent.position.deltaY
163+
clientX: uiEvent.position.left,
164+
clientY: uiEvent.position.top
165165
};
166166

167167
// Keep within bounds.

lib/utils/domFns.es6

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@ export function createUIEvent(draggable, coreEvent) {
153153
return {
154154
node: ReactDOM.findDOMNode(draggable),
155155
position: {
156-
top: coreEvent.position.clientY,
157-
left: coreEvent.position.clientX
156+
left: draggable.state.clientX + coreEvent.position.deltaX,
157+
top: draggable.state.clientY + coreEvent.position.deltaY
158158
},
159159
deltaX: coreEvent.position.deltaX,
160160
deltaY: coreEvent.position.deltaY

specs/draggable.spec.jsx

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -220,14 +220,7 @@ describe('react-draggable', function () {
220220
var node = ReactDOM.findDOMNode(drag);
221221

222222
TestUtils.Simulate.mouseDown(node, {clientX: 0, clientY: 0});
223-
// Simulate a movement; can't use TestUtils here because it uses react's event system only,
224-
// but <DraggableCore> attaches event listeners directly to the document.
225-
// Would love to new MouseEvent() here but it doesn't work with PhantomJS / old browsers.
226-
// var e = new MouseEvent('mousemove', {clientX: 100, clientY: 100});
227-
var evt = document.createEvent('MouseEvents');
228-
evt.initMouseEvent('mousemove', true, true, window,
229-
0, 0, 0, 100, 100, false, false, false, false, 0, null);
230-
document.dispatchEvent(evt);
223+
mouseMove(node, 100, 100);
231224
TestUtils.Simulate.mouseUp(node);
232225

233226
var transform = node.getAttribute('transform');
@@ -353,6 +346,48 @@ describe('react-draggable', function () {
353346
});
354347
});
355348

349+
describe('draggable callbacks', function () {
350+
it('should call back on drag', function () {
351+
function onDrag(event, data) {
352+
expect(data.position.left).toEqual(100);
353+
expect(data.position.top).toEqual(100);
354+
expect(data.deltaX).toEqual(100);
355+
expect(data.deltaY).toEqual(100);
356+
}
357+
drag = TestUtils.renderIntoDocument(
358+
<Draggable onDrag={onDrag}>
359+
<div />
360+
</Draggable>
361+
);
362+
363+
var node = ReactDOM.findDOMNode(drag);
364+
365+
TestUtils.Simulate.mouseDown(node, {clientX: 0, clientY: 0});
366+
var moveEvt = mouseMove(node, 100, 100);
367+
TestUtils.Simulate.mouseUp(node);
368+
});
369+
370+
it('should call back with offset left/top, not client', function () {
371+
function onDrag(event, data) {
372+
expect(data.position.left).toEqual(100);
373+
expect(data.position.top).toEqual(100);
374+
expect(data.deltaX).toEqual(100);
375+
expect(data.deltaY).toEqual(100);
376+
}
377+
drag = TestUtils.renderIntoDocument(
378+
<Draggable onDrag={onDrag} style={{position: 'relative', top: '200px', left: '200px'}}>
379+
<div />
380+
</Draggable>
381+
);
382+
383+
var node = ReactDOM.findDOMNode(drag);
384+
385+
TestUtils.Simulate.mouseDown(node, {clientX: 200, clientY: 200});
386+
var moveEvt = mouseMove(node, 300, 300);
387+
TestUtils.Simulate.mouseUp(node);
388+
});
389+
});
390+
356391
describe('validation', function () {
357392
it('should result with invariant when there isn\'t a child', function () {
358393
drag = (<Draggable/>);
@@ -385,3 +420,15 @@ describe('react-draggable', function () {
385420
function renderToHTML(component) {
386421
return ReactDOM.findDOMNode(TestUtils.renderIntoDocument(component)).outerHTML;
387422
}
423+
424+
// Simulate a movement; can't use TestUtils here because it uses react's event system only,
425+
// but <DraggableCore> attaches event listeners directly to the document.
426+
// Would love to new MouseEvent() here but it doesn't work with PhantomJS / old browsers.
427+
// var e = new MouseEvent('mousemove', {clientX: 100, clientY: 100});
428+
function mouseMove(node, x, y) {
429+
var evt = document.createEvent('MouseEvents');
430+
evt.initMouseEvent('mousemove', true, true, window,
431+
0, 0, 0, x, y, false, false, false, false, 0, null);
432+
document.dispatchEvent(evt);
433+
return evt;
434+
}

0 commit comments

Comments
 (0)