From 208c7738447a3f7f27a9ec06cc894aaeab2310a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Kaln=C3=BD?= Date: Mon, 5 Jul 2021 12:14:45 +0200 Subject: [PATCH 1/2] added preventDefault prop --- CHANGELOG.md | 4 ++ README.md | 10 +++- example/example.js | 5 ++ lib/DraggableCore.js | 7 ++- specs/draggable.spec.jsx | 122 ++++++++++++++++++++++++++++++++------- 5 files changed, 123 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd8eb515..6763732b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +### 4.4.4 (July 4, 2021) + +- Add `preventDefault` prop to allow touch scroll + ### 4.4.3 (June 8, 2020) - Add `nodeRef` to TypeScript definitions diff --git a/README.md b/README.md index 772ff368..aed795be 100644 --- a/README.md +++ b/README.md @@ -264,7 +264,12 @@ positionOffset: {x: number | string, y: number | string}, // Specifies the scale of the canvas your are dragging this element on. This allows // you to, for example, get the correct drag deltas while you are zoomed in or out via // a transform or matrix in the parent of this element. -scale: number +scale: number, + +// If set to false, the input event will not be default-prevented. +// You should call `.preventDefault() `within the `onStart`, `onDrag`, and `onEnd` event handlers. +// This allows for touch scrolling to work when the event originates on a draggable element. +preventDefault: boolean } ``` @@ -321,7 +326,8 @@ on itself and thus must have callbacks attached to be useful. onDrag: DraggableEventHandler, onStop: DraggableEventHandler, onMouseDown: (e: MouseEvent) => void, - scale: number + scale: number, + preventDefault: boolean } ``` diff --git a/example/example.js b/example/example.js index e5effe93..09783ffe 100644 --- a/example/example.js +++ b/example/example.js @@ -150,6 +150,11 @@ class App extends React.Component { Both parent padding and child margin work properly. + +
+ I don't prevent touches from scrolling the container. +
+
diff --git a/lib/DraggableCore.js b/lib/DraggableCore.js index c5a3da8f..4961a2cf 100644 --- a/lib/DraggableCore.js +++ b/lib/DraggableCore.js @@ -55,6 +55,7 @@ export type DraggableCoreDefaultProps = { onDrag: DraggableEventHandler, onStop: DraggableEventHandler, onMouseDown: (e: MouseEvent) => void, + preventDefault: true, scale: number, }; @@ -65,6 +66,7 @@ export type DraggableCoreProps = { offsetParent: HTMLElement, grid: [number, number], handle: string, + preventDefault: boolean, nodeRef?: ?React.ElementRef, }; @@ -208,6 +210,8 @@ export default class DraggableCore extends React.Component ); - simulateMovementFromTo(drag, 0, 0, 100, 100); + simulateMouseFromTo(drag, 0, 0, 100, 100); }); it('should throw when setting className', function () { @@ -249,7 +249,7 @@ describe('react-draggable', function () { ); const node = ReactDOM.findDOMNode(drag); - simulateMovementFromTo(drag, 0, 0, 100, 100); + simulateMouseFromTo(drag, 0, 0, 100, 100); const style = node.getAttribute('style'); assert(dragged === true); @@ -265,7 +265,7 @@ describe('react-draggable', function () { ); const node = ReactDOM.findDOMNode(drag); - simulateMovementFromTo(drag, 0, 0, 100, 100); + simulateMouseFromTo(drag, 0, 0, 100, 100); const style = node.getAttribute('style'); assert(dragged === true); @@ -281,7 +281,7 @@ describe('react-draggable', function () { ); const node = ReactDOM.findDOMNode(drag); - simulateMovementFromTo(drag, 0, 0, 100, 100); + simulateMouseFromTo(drag, 0, 0, 100, 100); const style = node.getAttribute('style'); assert(dragged === true); @@ -297,7 +297,7 @@ describe('react-draggable', function () { ); const node = ReactDOM.findDOMNode(drag); - simulateMovementFromTo(drag, 0, 0, 100, 100); + simulateMouseFromTo(drag, 0, 0, 100, 100); const style = node.getAttribute('style'); assert(dragged === true); @@ -313,7 +313,7 @@ describe('react-draggable', function () { ); const node = ReactDOM.findDOMNode(drag); - simulateMovementFromTo(drag, 0, 0, 100, 100); + simulateMouseFromTo(drag, 0, 0, 100, 100); const style = node.getAttribute('style'); assert(dragged === true); @@ -348,7 +348,7 @@ describe('react-draggable', function () { ); const node = ReactDOM.findDOMNode(drag); - simulateMovementFromTo(drag, 0, 0, 100, 100); + simulateMouseFromTo(drag, 0, 0, 100, 100); const transform = node.getAttribute('transform'); assert(transform.indexOf('translate(100,100)') >= 0); @@ -461,7 +461,7 @@ describe('react-draggable', function () { const body = iframeDoc.body; const node = body.querySelector('.react-draggable'); if (!node) return setTimeout(checkIframe, 50); - simulateMovementFromTo(node, 0, 0, 100, 100); + simulateMouseFromTo(node, 0, 0, 100, 100); const style = node.getAttribute('style'); assert(dragged === true); @@ -711,6 +711,48 @@ describe('react-draggable', function () { done(); }, 50); }); + + // it('should allow touch scrolling parent', function (done) { + // let dragCalled = false; + // function onDrag(event, data) { + // dragCalled = true; + // // assert(data.x === 100); + // // assert(data.y === 100); + // // assert(data.deltaX === 100); + // // assert(data.deltaY === 100); + // } + + // const scrollParent = fragmentFromString(` + //
+ //
+ //
+ //
+ // `); + + // drag = TestUtils.renderIntoDocument( + // + //
+ // + // ); + // const node = ReactDOM.findDOMNode(drag); + + // transplantNodeInto(node, scrollParent, (f) => f.children[0]); + + // const scrollParentNode = ReactDOM.findDOMNode(scrollParent); + + // simulateTouchFromTo(node, 200, 200, 100, 100); + + // setTimeout(() => { + // console.log(node); + // assert(dragCalled, 'onDrag was not called'); + // assert(scrollParentNode.scrollTop !== 0 && scrollParentNode.scrollLeft !== 0, 'parent didn\'t scroll on touch'); + // assert(scrollParentNode.scrollTop === 100, 'parent vertical scroll is off'); + // assert(scrollParentNode.scrollLeft === 100, 'parent horizontal scroll is off'); + // // cleanup + // document.body.removeChild(scrollParent); + // done(); + // }, 50); + // }); }); describe('draggable callbacks', function () { @@ -729,7 +771,7 @@ describe('react-draggable', function () { ); // (element, fromX, fromY, toX, toY) - simulateMovementFromTo(drag, 0, 0, 100, 100); + simulateMouseFromTo(drag, 0, 0, 100, 100); }); it('should call back with correct dom node with nodeRef', function () { @@ -748,7 +790,7 @@ describe('react-draggable', function () { ); // (element, fromX, fromY, toX, toY) - simulateMovementFromTo(drag, 0, 0, 100, 100); + simulateMouseFromTo(drag, 0, 0, 100, 100); }); it('should call back on drag, with values within the defined bounds', function(){ @@ -765,7 +807,7 @@ describe('react-draggable', function () { ); // (element, fromX, fromY, toX, toY) - simulateMovementFromTo(drag, 0, 0, 100, 100); + simulateMouseFromTo(drag, 0, 0, 100, 100); }); @@ -782,7 +824,7 @@ describe('react-draggable', function () { ); - simulateMovementFromTo(drag, 200, 200, 300, 300); + simulateMouseFromTo(drag, 200, 200, 300, 300); }); it('should call back with correct position when parent element is 2x scaled', function() { @@ -801,7 +843,7 @@ describe('react-draggable', function () { ); // (element, fromX, fromY, toX, toY) - simulateMovementFromTo(drag, 0, 0, 100, 100); + simulateMouseFromTo(drag, 0, 0, 100, 100); }); it('should call back with correct position when parent element is 0.5x scaled', function() { @@ -820,7 +862,7 @@ describe('react-draggable', function () { ); // (element, fromX, fromY, toX, toY) - simulateMovementFromTo(drag, 0, 0, 100, 100); + simulateMouseFromTo(drag, 0, 0, 100, 100); }); it('should not throw an error if unmounted during a callback', function () { @@ -847,7 +889,7 @@ describe('react-draggable', function () { ); // (element, fromX, fromY, toX, toY) - simulateMovementFromTo(dragRef.current, 0, 0, 100, 100); + simulateMouseFromTo(dragRef.current, 0, 0, 100, 100); // ok, was a setstate warning thrown? // Assert unmounted @@ -872,7 +914,7 @@ describe('react-draggable', function () { ); // (element, fromX, fromY, toX, toY) - simulateMovementFromTo(drag, 0, 0, 100, 100); + simulateMouseFromTo(drag, 0, 0, 100, 100); }); it('should call back with correct position when parent element is 2x scaled', function() { @@ -891,7 +933,7 @@ describe('react-draggable', function () { ); // (element, fromX, fromY, toX, toY) - simulateMovementFromTo(drag, 0, 0, 100, 100); + simulateMouseFromTo(drag, 0, 0, 100, 100); }); it('should call back with correct position when parent element is 0.5x scaled', function() { @@ -910,11 +952,10 @@ describe('react-draggable', function () { ); // (element, fromX, fromY, toX, toY) - simulateMovementFromTo(drag, 0, 0, 100, 100); + simulateMouseFromTo(drag, 0, 0, 100, 100); }); }); - describe('validation', function () { it('should result with invariant when there isn\'t a child', function () { const renderer = new ShallowRenderer(); @@ -951,15 +992,52 @@ function mouseMove(x, y, node) { return evt; } +function createClientXY(x, y) { + return { clientX: x, clientY: y }; +} + +function touchMove(x, y, node) { + const touchObj = new Touch({ + identifier: Date.now(), + target: node, + clientX: x, + clientY: y, + radiusX: 2.5, + radiusY: 2.5, + rotationAngle: 10, + force: 0.5, + }); + + const touchEvent = new TouchEvent('touchmove', { + cancelable: true, + bubbles: true, + touches: [touchObj], + targetTouches: [], + changedTouches: [touchObj], + shiftKey: true, + }); + + node.dispatchEvent(touchEvent); +} + -function simulateMovementFromTo(drag, fromX, fromY, toX, toY) { +function simulateMouseFromTo(drag, fromX, fromY, toX, toY) { const node = ReactDOM.findDOMNode(drag); - TestUtils.Simulate.mouseDown(node, {clientX: fromX, clientY: fromY}); + TestUtils.Simulate.mouseDown(node, createClientXY(fromX, fromY)); mouseMove(toX, toY, node); TestUtils.Simulate.mouseUp(node); } +// // Does not work, cannot figure out how to correctly simulate touches +// function simulateTouchFromTo(drag, fromX, fromY, toX, toY) { +// const node = ReactDOM.findDOMNode(drag); + +// TestUtils.Simulate.touchStart(node, { touches: [createClientXY(fromX, fromY)] }); +// touchMove(toX, toY, node); +// TestUtils.Simulate.touchEnd(node, { touches: [createClientXY(toX, toY)], changedTouches: [createClientXY(toX, toY)]}); +// } + function fragmentFromString(strHTML) { var temp = document.createElement('div'); temp.innerHTML = strHTML; From 475c99c7503481f54383769a12a3de2c885dd382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Kaln=C3=BD?= Date: Mon, 5 Jul 2021 12:16:43 +0200 Subject: [PATCH 2/2] release v4.4.4 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 79ac1d0e..fb898d84 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-draggable", - "version": "4.4.3", + "version": "4.4.4", "description": "React draggable component", "main": "build/cjs/cjs.js", "unpkg": "build/web/react-draggable.min.js", @@ -96,4 +96,4 @@ "react": ">= 16.3.0", "react-dom": ">= 16.3.0" } -} +} \ No newline at end of file