From b52cb23f99f87db67292ffa9f9433501bfdcc13b Mon Sep 17 00:00:00 2001 From: Thomas Willheim Date: Thu, 8 Aug 2024 12:20:33 -0700 Subject: [PATCH 1/4] fix: add doNotPreventMobileScroll prop to allow for clicks to optionally pass through on mobile --- README.md | 1 + lib/DraggableCore.js | 2 +- typings/index.d.ts | 1 + typings/test.tsx | 4 +++- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 50cfefd6..9d5c6126 100644 --- a/README.md +++ b/README.md @@ -327,6 +327,7 @@ on itself and thus must have callbacks attached to be useful. cancel: string, disabled: boolean, enableUserSelectHack: boolean, + doNotPreventMobileScroll: boolean, offsetParent: HTMLElement, grid: [number, number], handle: string, diff --git a/lib/DraggableCore.js b/lib/DraggableCore.js index 6b464aa0..35376286 100644 --- a/lib/DraggableCore.js +++ b/lib/DraggableCore.js @@ -288,7 +288,7 @@ export default class DraggableCore extends React.Component { // Prevent scrolling on mobile devices, like ipad/iphone. // Important that this is after handle/cancel. - if (e.type === 'touchstart') e.preventDefault(); + if (e.type === 'touchstart' && !this.props.doNotPreventMobileScroll) e.preventDefault(); // Set touch identifier in component state if this is a touch event. This allows us to // distinguish between individual touches on multitouch screens by identifying which diff --git a/typings/index.d.ts b/typings/index.d.ts index bcbc6ff3..54a34285 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -46,6 +46,7 @@ declare module 'react-draggable' { children?: React.ReactNode, disabled: boolean, enableUserSelectHack: boolean, + doNotPreventMobileScroll: boolean, offsetParent: HTMLElement, grid: [number, number], handle: string, diff --git a/typings/test.tsx b/typings/test.tsx index 87562d49..7277bebe 100644 --- a/typings/test.tsx +++ b/typings/test.tsx @@ -24,6 +24,7 @@ ReactDOM.render( onMouseDown={handleMouseDown} disabled={true} enableUserSelectHack={false} + doNotPreventMobileScroll={false} bounds={false} defaultClassName={'draggable'} defaultClassNameDragging={'dragging'} @@ -54,7 +55,8 @@ ReactDOM.render( onDrag={handleDrag} onStop={handleStop} offsetParent={document.body} - enableUserSelectHack={false}> + enableUserSelectHack={false} + doNotPreventMobileScroll={false}>
From 73a9b70d96320f3f1eb3577f1d6e412665cb88d2 Mon Sep 17 00:00:00 2001 From: Thomas Willheim Date: Thu, 8 Aug 2024 12:36:28 -0700 Subject: [PATCH 2/4] fix: switch doNotPreventMobileScroll to allowMobileScroll --- README.md | 2 +- typings/index.d.ts | 2 +- typings/test.tsx | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9d5c6126..1fdc6e42 100644 --- a/README.md +++ b/README.md @@ -327,7 +327,7 @@ on itself and thus must have callbacks attached to be useful. cancel: string, disabled: boolean, enableUserSelectHack: boolean, - doNotPreventMobileScroll: boolean, + allowMobileScroll: boolean, offsetParent: HTMLElement, grid: [number, number], handle: string, diff --git a/typings/index.d.ts b/typings/index.d.ts index 54a34285..70517d96 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -46,7 +46,7 @@ declare module 'react-draggable' { children?: React.ReactNode, disabled: boolean, enableUserSelectHack: boolean, - doNotPreventMobileScroll: boolean, + allowMobileScroll: boolean, offsetParent: HTMLElement, grid: [number, number], handle: string, diff --git a/typings/test.tsx b/typings/test.tsx index 7277bebe..b1fc5247 100644 --- a/typings/test.tsx +++ b/typings/test.tsx @@ -24,7 +24,7 @@ ReactDOM.render( onMouseDown={handleMouseDown} disabled={true} enableUserSelectHack={false} - doNotPreventMobileScroll={false} + allowMobileScroll={false} bounds={false} defaultClassName={'draggable'} defaultClassNameDragging={'dragging'} @@ -56,7 +56,7 @@ ReactDOM.render( onStop={handleStop} offsetParent={document.body} enableUserSelectHack={false} - doNotPreventMobileScroll={false}> + allowMobileScroll={false}>
From c00cd6fbab14f9c9dc9ded678325a59443f2489d Mon Sep 17 00:00:00 2001 From: Thomas Willheim Date: Fri, 9 Aug 2024 09:20:58 -0700 Subject: [PATCH 3/4] fix: update prop in draggable core to allowMobileScroll --- lib/DraggableCore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/DraggableCore.js b/lib/DraggableCore.js index 35376286..20aa8ddb 100644 --- a/lib/DraggableCore.js +++ b/lib/DraggableCore.js @@ -288,7 +288,7 @@ export default class DraggableCore extends React.Component { // Prevent scrolling on mobile devices, like ipad/iphone. // Important that this is after handle/cancel. - if (e.type === 'touchstart' && !this.props.doNotPreventMobileScroll) e.preventDefault(); + if (e.type === 'touchstart' && !this.props.allowMobileScroll) e.preventDefault(); // Set touch identifier in component state if this is a touch event. This allows us to // distinguish between individual touches on multitouch screens by identifying which From 0d51c938cf44221ec26d1d7f90245f83ecde2617 Mon Sep 17 00:00:00 2001 From: Samuel Reed Date: Sat, 10 Aug 2024 12:01:41 -0400 Subject: [PATCH 4/4] chore(allowMobileScroll): update readme and tests --- README.md | 13 ++++++++++++- lib/DraggableCore.js | 11 +++++++++++ specs/draggable.spec.jsx | 12 ++++++++++++ typings/index.d.ts | 2 +- typings/test.tsx | 4 ++-- 5 files changed, 38 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1fdc6e42..cdffebc0 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,14 @@ type DraggableData = { // If set to `true`, will allow dragging on non left-button clicks. allowAnyClick: boolean, +// Default `false` and default behavior before 4.5.0. +// If set to `true`, the 'touchstart' event will not be prevented, +// which will allow scrolling inside containers. We recommend +// using the 'handle' / 'cancel' props when possible instead of enabling this. +// +// See https://github.com/react-grid-layout/react-draggable/issues/728 +allowMobileScroll: boolean, + // Determines which axis the draggable can move. This only affects // flushing to the DOM. Callbacks will still include all values. // Accepted values: @@ -202,6 +210,9 @@ defaultPosition: {x: number, y: number}, // If true, will not call any drag handlers. disabled: boolean, +// Default `true`. Adds "user-select: none" while dragging to avoid selecting text. +enableUserSelectHack: boolean, + // Specifies the x and y that dragging should snap to. grid: [number, number], @@ -324,10 +335,10 @@ on itself and thus must have callbacks attached to be useful. ```js { allowAnyClick: boolean, + allowMobileScroll: boolean, cancel: string, disabled: boolean, enableUserSelectHack: boolean, - allowMobileScroll: boolean, offsetParent: HTMLElement, grid: [number, number], handle: string, diff --git a/lib/DraggableCore.js b/lib/DraggableCore.js index 20aa8ddb..cae61661 100644 --- a/lib/DraggableCore.js +++ b/lib/DraggableCore.js @@ -42,6 +42,7 @@ export type PositionOffsetControlPosition = {x: number|string, y: number|string} export type DraggableCoreDefaultProps = { allowAnyClick: boolean, + allowMobileScroll: boolean, disabled: boolean, enableUserSelectHack: boolean, onStart: DraggableEventHandler, @@ -81,6 +82,15 @@ export default class DraggableCore extends React.Component { */ allowAnyClick: PropTypes.bool, + /** + * `allowMobileScroll` turns off cancellation of the 'touchstart' event + * on mobile devices. Only enable this if you are having trouble with click + * events. Prefer using 'handle' / 'cancel' instead. + * + * Defaults to `false`. + */ + allowMobileScroll: PropTypes.bool, + children: PropTypes.node.isRequired, /** @@ -213,6 +223,7 @@ export default class DraggableCore extends React.Component { static defaultProps: DraggableCoreDefaultProps = { allowAnyClick: false, // by default only accept left click + allowMobileScroll: false, disabled: false, enableUserSelectHack: true, onStart: function(){}, diff --git a/specs/draggable.spec.jsx b/specs/draggable.spec.jsx index 51ed3b4d..143eae96 100644 --- a/specs/draggable.spec.jsx +++ b/specs/draggable.spec.jsx @@ -622,6 +622,18 @@ describe('react-draggable', function () { assert.equal(drag.state.dragging, true); }); + it('should *not* call preventDefault on touchStart event if "allowMobileScroll"', function () { + drag = TestUtils.renderIntoDocument(
); + + const e = new Event('touchstart'); + // Oddly `e.defaultPrevented` is not changing here. Maybe because we're not mounted to a real doc? + let pdCalled = false; + e.preventDefault = function() { pdCalled = true; }; + ReactDOM.findDOMNode(drag).dispatchEvent(e); + assert(!pdCalled); + assert.equal(drag.state.dragging, true); + }); + it('should not call preventDefault on touchStart event if not on handle', function () { drag = TestUtils.renderIntoDocument( diff --git a/typings/index.d.ts b/typings/index.d.ts index 70517d96..2ad9ec79 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -42,11 +42,11 @@ declare module 'react-draggable' { export interface DraggableCoreProps { allowAnyClick: boolean, + allowMobileScroll: boolean, cancel: string, children?: React.ReactNode, disabled: boolean, enableUserSelectHack: boolean, - allowMobileScroll: boolean, offsetParent: HTMLElement, grid: [number, number], handle: string, diff --git a/typings/test.tsx b/typings/test.tsx index b1fc5247..0532f949 100644 --- a/typings/test.tsx +++ b/typings/test.tsx @@ -20,11 +20,11 @@ ReactDOM.render( onDrag={handleDrag} onStop={handleStop} offsetParent={document.body} - allowAnyClick={true} onMouseDown={handleMouseDown} + allowAnyClick={true} + allowMobileScroll={false} disabled={true} enableUserSelectHack={false} - allowMobileScroll={false} bounds={false} defaultClassName={'draggable'} defaultClassNameDragging={'dragging'}