Skip to content

Commit

Permalink
Merge pull request #64 from complexdatacollective/fix/drag-drop
Browse files Browse the repository at this point in the history
Fix/drag drop
  • Loading branch information
jthrilly authored Feb 1, 2024
2 parents da41553 + 8f27342 commit a976ce3
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 116 deletions.
45 changes: 25 additions & 20 deletions lib/interviewer/behaviours/DragAndDrop/DragManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function moveDelta(start, end) {
}

function moveDistance({ dx, dy }) {
return ((dx ** 2) + (dy ** 2)) ** 0.5;
return (dx ** 2 + dy ** 2) ** 0.5;
}

function moveAngle({ dx, dy }) {
Expand All @@ -48,12 +48,18 @@ function axisProximityFromAngle(angle) {
function determineMoveType(movement, scrollDirection) {
switch (scrollDirection) {
case VERTICAL_SCROLL:
if (movement.axisProximity > 0.9 || movement.velocity / movement.axisProximity < 0.15) {
if (
movement.axisProximity > 0.9 ||
movement.velocity / movement.axisProximity < 0.15
) {
return 'SWIPE';
}
return 'DRAG';
case HORIZONTAL_SCROLL:
if (movement.axisProximity < 0.1 || movement.velocity / (1 - movement.axisProximity) < 0.15) {
if (
movement.axisProximity < 0.1 ||
movement.velocity / (1 - movement.axisProximity) < 0.15
) {
return 'SWIPE';
}
return 'DRAG';
Expand All @@ -69,13 +75,7 @@ const initalState = {
};

class dragManager {
constructor({
el,
onDragStart,
onDragMove,
onDragEnd,
scrollDirection,
}) {
constructor({ el, onDragStart, onDragMove, onDragEnd, scrollDirection }) {
this.state = { ...initalState };
this.el = el;
this.onDragStart = onDragStart;
Expand All @@ -102,12 +102,12 @@ class dragManager {
trackMouse = () => {
window.addEventListener('mousemove', this.onMove, { passive: false });
window.addEventListener('mouseup', this.onMoveEnd, { passive: true });
}
};

removeMouseTracking = () => {
window.removeEventListener('mousemove', this.onMove);
window.removeEventListener('mouseup', this.onMoveEnd);
}
};

movementFromEvent = (e) => {
const { state } = this;
Expand All @@ -129,10 +129,11 @@ class dragManager {
axisProximity,
angle,
};
}
};

detectMoveType = (e, movement) => {
const moveType = this.state.type || determineMoveType(movement, this.scrollDirection);
const moveType =
this.state.type || determineMoveType(movement, this.scrollDirection);

if (moveType === 'DRAG') {
e.preventDefault();
Expand All @@ -141,14 +142,18 @@ class dragManager {
if (!this.state.type) {
this.state.type = moveType;
}
}
};

detectDragStart = (movement) => {
if (this.state.type === 'DRAG' && this.state.dragStart === false && movement.distance > 4) {
if (
this.state.type === 'DRAG' &&
this.state.dragStart === false &&
movement.distance > 4
) {
this.state.dragStart = true;
this.onDragStart(movement);
}
}
};

onMoveStart = (e) => {
this.trackMouse();
Expand All @@ -163,7 +168,7 @@ class dragManager {
x,
y,
};
}
};

onMove = (e) => {
if (this.state.moveStart === true) {
Expand All @@ -188,7 +193,7 @@ class dragManager {
t,
};
}
}
};

onMoveEnd = (e) => {
this.removeMouseTracking();
Expand All @@ -202,7 +207,7 @@ class dragManager {
} else {
this.state = { ...initalState };
}
}
};

isDragging = () => this.state.dragStart === true;
}
Expand Down
154 changes: 69 additions & 85 deletions lib/interviewer/behaviours/DragAndDrop/DragSource.js
Original file line number Diff line number Diff line change
@@ -1,78 +1,75 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { throttle } from 'lodash';
import DragPreview from './DragPreview';
import DragManager, { VERTICAL_SCROLL } from './DragManager';
import { actionCreators as actions } from './reducer';
import store from './store';

const dragSource = (WrappedComponent) => {
const DragSourceInner = ({
const getDisplayName = (WrappedComponent) => {
return WrappedComponent.displayName || WrappedComponent.name || 'Component';
};

const DragSourceComponent = ({
allowDrag = true,
meta = () => ({}),
scrollDirection = VERTICAL_SCROLL,
preview,
onClick,
...rest
}) => {
const node = useRef();
const previewRef = useRef();
const dragManager = useRef(null);
const previewEl = useRef(null);

const node = useRef(null);
const previewRef = useRef(null);
const dragManagerRef = useRef(null);
const previewElRef = useRef(null);
const [isDragging, setIsDragging] = useState(false);

const cleanupDragManager = () => {
if (dragManager.current) {
dragManager.current.unmount();
dragManager.current = null;
if (dragManagerRef.current) {
dragManagerRef.current.unmount();
dragManagerRef.current = null;
}
};

const cleanupPreview = useCallback(() => {
if (previewEl.current) {
previewEl.current.cleanup();
previewEl.current = null;
const cleanupPreview = () => {
if (previewElRef.current) {
previewElRef.current.cleanup();
previewElRef.current = null;
}
}, []);
};

const createPreview = useCallback(() => {
const createPreview = () => {
if (!preview) {
previewEl.current = new DragPreview(node.current);
previewElRef.current = new DragPreview(node.current);
return;
}

previewEl.current = new DragPreview(previewRef.current);
}, [preview]);
previewElRef.current = new DragPreview(previewRef.current);
};

const updatePreview = useCallback(
({ x, y }) => {
if (previewEl.current) {
previewEl.current.position({ x, y });
}
},
[previewEl],
);
const updatePreview = ({ x, y }) => {
if (previewElRef.current) {
previewElRef.current.position({ x, y });
}
};

const setValidMove = (valid) => {
if (!previewEl.current) return;
previewEl.current.setValidMove(valid);
if (previewElRef.current) {
previewElRef.current.setValidMove(valid);
}
};

const onDragStart = useCallback(
(movement) => {
createPreview();
const onDragStart = (movement) => {
createPreview();

store.dispatch(
actions.dragStart({
...movement,
meta: meta(),
}),
);
store.dispatch(
actions.dragStart({
...movement,
meta: meta(),
}),
);

setIsDragging(true);
},
[createPreview, meta],
);
setIsDragging(true);
};

const throttledDragAction = throttle(({ x, y, ...other }) => {
store.dispatch(
Expand All @@ -83,29 +80,23 @@ const dragSource = (WrappedComponent) => {
...other,
}),
);
}, 250);

const onDragMove = useCallback(
({ x, y, ...other }) => {
updatePreview({ x, y });
throttledDragAction({ x, y, ...other });
},
[throttledDragAction, updatePreview],
);
}, 60);

const onDragEnd = useCallback(
(movement) => {
cleanupPreview();
setIsDragging(false);
const onDragMove = ({ x, y, ...other }) => {
updatePreview({ x, y });
throttledDragAction({ x, y, ...other });
};

store.dispatch(actions.dragEnd(movement));
},
[cleanupPreview],
);
const onDragEnd = (movement) => {
cleanupPreview();
setIsDragging(false);

store.dispatch(actions.dragEnd(movement));
};

useEffect(() => {
if (node.current && allowDrag) {
dragManager.current = new DragManager({
dragManagerRef.current = new DragManager({
el: node.current,
onDragStart,
onDragMove,
Expand All @@ -118,32 +109,21 @@ const dragSource = (WrappedComponent) => {
cleanupPreview();
cleanupDragManager();
};
}, [
node,
allowDrag,
cleanupPreview,
onDragEnd,
onDragMove,
onDragStart,
scrollDirection,
]);
}, [node, allowDrag]);

const styles = () => (isDragging ? { visibility: 'hidden' } : {});

return (
<>
<div
styles={styles()}
className={`draggable ${!allowDrag ? 'draggable--disabled' : ''}`}
ref={node}
onClick={onClick}
>
<WrappedComponent
{...rest}
allowDrag={allowDrag}
scrollDirection={scrollDirection}
/>
</div>
<div
style={styles()}
className={`draggable ${!allowDrag ? 'draggable--disabled' : ''}`}
ref={node}
>
<WrappedComponent
{...rest}
allowDrag={allowDrag}
scrollDirection={scrollDirection}
/>
{preview && (
<div
ref={previewRef}
Expand All @@ -157,11 +137,15 @@ const dragSource = (WrappedComponent) => {
{preview}
</div>
)}
</>
</div>
);
};

return DragSourceInner;
DragSourceComponent.displayName = `DragSource(${getDisplayName(
WrappedComponent,
)})`;

return DragSourceComponent;
};

export default dragSource;
Loading

0 comments on commit a976ce3

Please sign in to comment.