Skip to content

Commit 0e5add7

Browse files
author
Claudéric Demers
authored
Merge pull request #378 from clauderic/fix-mobile-issues
Fix issues with distance and pressThreshold props on mobile
2 parents 4f2aff3 + 41cf851 commit 0e5add7

File tree

2 files changed

+124
-114
lines changed

2 files changed

+124
-114
lines changed

src/SortableContainer/index.js

+50-114
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ import {
99
events,
1010
vendorPrefix,
1111
limit,
12+
getEdgeOffset,
1213
getElementMargin,
14+
getLockPixelOffset,
15+
getPosition,
1316
provideDisplayName,
1417
omit,
1518
} from '../utils';
@@ -145,20 +148,17 @@ export default function sortableContainer(WrappedComponent, config = {withRef: f
145148
}
146149
}
147150

148-
handleStart = e => {
151+
handleStart = event => {
149152
const {distance, shouldCancelStart} = this.props;
150153

151-
if (e.button === 2 || shouldCancelStart(e)) {
154+
if (event.button === 2 || shouldCancelStart(event)) {
152155
return false;
153156
}
154157

155158
this._touched = true;
156-
this._pos = {
157-
x: e.pageX,
158-
y: e.pageY,
159-
};
159+
this._pos = getPosition(event);
160160

161-
const node = closest(e.target, el => el.sortableInfo != null);
161+
const node = closest(event.target, el => el.sortableInfo != null);
162162

163163
if (
164164
node &&
@@ -170,7 +170,7 @@ export default function sortableContainer(WrappedComponent, config = {withRef: f
170170
const {index, collection} = node.sortableInfo;
171171

172172
if (
173-
useDragHandle && !closest(e.target, el => el.sortableHandle != null)
173+
useDragHandle && !closest(event.target, el => el.sortableHandle != null)
174174
)
175175
return;
176176

@@ -181,16 +181,16 @@ export default function sortableContainer(WrappedComponent, config = {withRef: f
181181
* prevent subsequent 'mousemove' events from being fired
182182
* (see https://github.com/clauderic/react-sortable-hoc/issues/118)
183183
*/
184-
if (e.target.tagName.toLowerCase() === 'a') {
185-
e.preventDefault();
184+
if (event.target.tagName.toLowerCase() === 'a') {
185+
event.preventDefault();
186186
}
187187

188188
if (!distance) {
189189
if (this.props.pressDelay === 0) {
190-
this.handlePress(e);
190+
this.handlePress(event);
191191
} else {
192192
this.pressTimer = setTimeout(
193-
() => this.handlePress(e),
193+
() => this.handlePress(event),
194194
this.props.pressDelay
195195
);
196196
}
@@ -202,21 +202,22 @@ export default function sortableContainer(WrappedComponent, config = {withRef: f
202202
return node.sortableInfo.manager === this.manager;
203203
};
204204

205-
handleMove = e => {
205+
handleMove = event => {
206206
const {distance, pressThreshold} = this.props;
207207

208208
if (!this.state.sorting && this._touched) {
209-
this._delta = {
210-
x: this._pos.x - e.pageX,
211-
y: this._pos.y - e.pageY,
209+
const position = getPosition(event);
210+
const delta = this._delta = {
211+
x: this._pos.x - position.x,
212+
y: this._pos.y - position.y,
212213
};
213-
const delta = Math.abs(this._delta.x) + Math.abs(this._delta.y);
214+
const combinedDelta = Math.abs(delta.x) + Math.abs(delta.y);
214215

215-
if (!distance && (!pressThreshold || pressThreshold && delta >= pressThreshold)) {
216+
if (!distance && (!pressThreshold || pressThreshold && combinedDelta >= pressThreshold)) {
216217
clearTimeout(this.cancelTimer);
217218
this.cancelTimer = setTimeout(this.cancel, 0);
218-
} else if (distance && delta >= distance && this.manager.isActive()) {
219-
this.handlePress(e);
219+
} else if (distance && combinedDelta >= distance && this.manager.isActive()) {
220+
this.handlePress(event);
220221
}
221222
}
222223
};
@@ -238,7 +239,7 @@ export default function sortableContainer(WrappedComponent, config = {withRef: f
238239
}
239240
};
240241

241-
handlePress = e => {
242+
handlePress = event => {
242243
const active = this.manager.getActive();
243244

244245
if (active) {
@@ -274,8 +275,8 @@ export default function sortableContainer(WrappedComponent, config = {withRef: f
274275
x: axis.indexOf('x') >= 0,
275276
y: axis.indexOf('y') >= 0,
276277
};
277-
this.offsetEdge = this.getEdgeOffset(node);
278-
this.initialOffset = this.getOffset(e);
278+
this.offsetEdge = getEdgeOffset(node, this.container);
279+
this.initialOffset = getPosition(event);
279280
this.initialScroll = {
280281
top: this.container.scrollTop,
281282
left: this.container.scrollLeft,
@@ -345,7 +346,7 @@ export default function sortableContainer(WrappedComponent, config = {withRef: f
345346
this.helper.classList.add(...helperClass.split(' '));
346347
}
347348

348-
this.listenerNode = e.touches ? node : this.contentWindow;
349+
this.listenerNode = event.touches ? node : this.contentWindow;
349350
events.move.forEach(eventName =>
350351
this.listenerNode.addEventListener(
351352
eventName,
@@ -364,22 +365,26 @@ export default function sortableContainer(WrappedComponent, config = {withRef: f
364365
sortingIndex: index,
365366
});
366367

367-
if (onSortStart) onSortStart({node, index, collection}, e);
368+
if (onSortStart) {
369+
onSortStart({node, index, collection}, event);
370+
}
368371
}
369372
};
370373

371-
handleSortMove = e => {
374+
handleSortMove = event => {
372375
const {onSortMove} = this.props;
373-
e.preventDefault(); // Prevent scrolling on mobile
376+
event.preventDefault(); // Prevent scrolling on mobile
374377

375-
this.updatePosition(e);
378+
this.updatePosition(event);
376379
this.animateNodes();
377380
this.autoscroll();
378381

379-
if (onSortMove) onSortMove(e);
382+
if (onSortMove) {
383+
onSortMove(event);
384+
}
380385
};
381386

382-
handleSortEnd = e => {
387+
handleSortEnd = event => {
383388
const {hideSortableGhost, onSortEnd} = this.props;
384389
const {collection} = this.manager.active;
385390

@@ -434,113 +439,44 @@ export default function sortableContainer(WrappedComponent, config = {withRef: f
434439
newIndex: this.newIndex,
435440
collection,
436441
},
437-
e
442+
event
438443
);
439444
}
440445

441446
this._touched = false;
442447
};
443448

444-
getEdgeOffset(node, offset = {top: 0, left: 0}) {
445-
// Get the actual offsetTop / offsetLeft value, no matter how deep the node is nested
446-
if (node) {
447-
const nodeOffset = {
448-
top: offset.top + node.offsetTop,
449-
left: offset.left + node.offsetLeft,
450-
};
451-
if (node.parentNode !== this.container) {
452-
return this.getEdgeOffset(node.parentNode, nodeOffset);
453-
} else {
454-
return nodeOffset;
455-
}
456-
}
457-
}
458-
459-
getOffset(e) {
460-
if (e.touches && e.touches.length) {
461-
return {
462-
x: e.touches[0].pageX,
463-
y: e.touches[0].pageY,
464-
};
465-
} else if (e.changedTouches && e.changedTouches.length) {
466-
return {
467-
x: e.changedTouches[0].pageX,
468-
y: e.changedTouches[0].pageY,
469-
};
470-
} else {
471-
return {
472-
x: e.pageX,
473-
y: e.pageY,
474-
};
475-
}
476-
}
477-
478449
getLockPixelOffsets() {
479-
let {lockOffset} = this.props;
480-
481-
if (!Array.isArray(lockOffset)) {
482-
lockOffset = [lockOffset, lockOffset];
483-
}
450+
const {width, height} = this;
451+
const {lockOffset} = this.props;
452+
const offsets = Array.isArray(lockOffset)
453+
? lockOffset
454+
: [lockOffset, lockOffset];
484455

485456
invariant(
486-
lockOffset.length === 2,
457+
offsets.length === 2,
487458
'lockOffset prop of SortableContainer should be a single ' +
488459
'value or an array of exactly two values. Given %s',
489460
lockOffset
490461
);
491462

492-
const [minLockOffset, maxLockOffset] = lockOffset;
463+
const [minLockOffset, maxLockOffset] = offsets;
493464

494465
return [
495-
this.getLockPixelOffset(minLockOffset),
496-
this.getLockPixelOffset(maxLockOffset),
466+
getLockPixelOffset({offset: minLockOffset, width, height}),
467+
getLockPixelOffset({offset: maxLockOffset, width, height}),
497468
];
498469
}
499470

500-
getLockPixelOffset(lockOffset) {
501-
let offsetX = lockOffset;
502-
let offsetY = lockOffset;
503-
let unit = 'px';
504-
505-
if (typeof lockOffset === 'string') {
506-
const match = /^[+-]?\d*(?:\.\d*)?(px|%)$/.exec(lockOffset);
507-
508-
invariant(
509-
match !== null,
510-
'lockOffset value should be a number or a string of a ' +
511-
'number followed by "px" or "%". Given %s',
512-
lockOffset
513-
);
514-
515-
offsetX = (offsetY = parseFloat(lockOffset));
516-
unit = match[1];
517-
}
518-
519-
invariant(
520-
isFinite(offsetX) && isFinite(offsetY),
521-
'lockOffset value should be a finite. Given %s',
522-
lockOffset
523-
);
524-
525-
if (unit === '%') {
526-
offsetX = offsetX * this.width / 100;
527-
offsetY = offsetY * this.height / 100;
528-
}
529-
530-
return {
531-
x: offsetX,
532-
y: offsetY,
533-
};
534-
}
535-
536-
updatePosition(e) {
471+
updatePosition(event) {
537472
const {lockAxis, lockToContainerEdges} = this.props;
538473

539-
const offset = this.getOffset(e);
474+
const offset = getPosition(event);
540475
const translate = {
541476
x: offset.x - this.initialOffset.x,
542477
y: offset.y - this.initialOffset.y,
543478
};
479+
544480
// Adjust for window scroll
545481
translate.y -= (window.pageYOffset - this.initialWindowScroll.top);
546482
translate.x -= (window.pageXOffset - this.initialWindowScroll.left);
@@ -617,7 +553,7 @@ export default function sortableContainer(WrappedComponent, config = {withRef: f
617553

618554
// If we haven't cached the node's offsetTop / offsetLeft value
619555
if (!edgeOffset) {
620-
nodes[i].edgeOffset = (edgeOffset = this.getEdgeOffset(node));
556+
nodes[i].edgeOffset = (edgeOffset = getEdgeOffset(node, this.container));
621557
}
622558

623559
// Get a reference to the next and previous node
@@ -627,7 +563,7 @@ export default function sortableContainer(WrappedComponent, config = {withRef: f
627563
// Also cache the next node's edge offset if needed.
628564
// We need this for calculating the animation in a grid setup
629565
if (nextNode && !nextNode.edgeOffset) {
630-
nextNode.edgeOffset = this.getEdgeOffset(nextNode.node);
566+
nextNode.edgeOffset = getEdgeOffset(nextNode.node, this.container);
631567
}
632568

633569
// If the node is the one we're currently animating, skip it

src/utils.js

+74
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import invariant from 'invariant';
2+
13
export function arrayMove(arr, previousIndex, newIndex) {
24
const array = arr.slice(0);
35
if (newIndex >= array.length) {
@@ -80,3 +82,75 @@ export function provideDisplayName(prefix, Component) {
8082

8183
return componentName ? `${prefix}(${componentName})` : prefix;
8284
}
85+
86+
export function getPosition(event) {
87+
if (event.touches && event.touches.length) {
88+
return {
89+
x: event.touches[0].pageX,
90+
y: event.touches[0].pageY,
91+
};
92+
} else if (event.changedTouches && event.changedTouches.length) {
93+
return {
94+
x: event.changedTouches[0].pageX,
95+
y: event.changedTouches[0].pageY,
96+
};
97+
} else {
98+
return {
99+
x: event.pageX,
100+
y: event.pageY,
101+
};
102+
}
103+
}
104+
105+
export function getEdgeOffset(node, parent, offset = {top: 0, left: 0}) {
106+
// Get the actual offsetTop / offsetLeft value, no matter how deep the node is nested
107+
if (node) {
108+
const nodeOffset = {
109+
top: offset.top + node.offsetTop,
110+
left: offset.left + node.offsetLeft,
111+
};
112+
113+
if (node.parentNode !== parent) {
114+
return getEdgeOffset(node.parentNode, parent, nodeOffset);
115+
} else {
116+
return nodeOffset;
117+
}
118+
}
119+
}
120+
121+
122+
export function getLockPixelOffset({lockOffset, width, height}) {
123+
let offsetX = lockOffset;
124+
let offsetY = lockOffset;
125+
let unit = 'px';
126+
127+
if (typeof lockOffset === 'string') {
128+
const match = /^[+-]?\d*(?:\.\d*)?(px|%)$/.exec(lockOffset);
129+
130+
invariant(
131+
match !== null,
132+
'lockOffset value should be a number or a string of a ' +
133+
'number followed by "px" or "%". Given %s',
134+
lockOffset
135+
);
136+
137+
offsetX = (offsetY = parseFloat(lockOffset));
138+
unit = match[1];
139+
}
140+
141+
invariant(
142+
isFinite(offsetX) && isFinite(offsetY),
143+
'lockOffset value should be a finite. Given %s',
144+
lockOffset
145+
);
146+
147+
if (unit === '%') {
148+
offsetX = offsetX * width / 100;
149+
offsetY = offsetY * height / 100;
150+
}
151+
152+
return {
153+
x: offsetX,
154+
y: offsetY,
155+
};
156+
}

0 commit comments

Comments
 (0)