diff --git a/lib/interviewer/behaviours/DragAndDrop/DragManager.js b/lib/interviewer/behaviours/DragAndDrop/DragManager.js index 1d542d2d..c58a87a4 100644 --- a/lib/interviewer/behaviours/DragAndDrop/DragManager.js +++ b/lib/interviewer/behaviours/DragAndDrop/DragManager.js @@ -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 }) { @@ -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'; @@ -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; @@ -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; @@ -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(); @@ -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(); @@ -163,7 +168,7 @@ class dragManager { x, y, }; - } + }; onMove = (e) => { if (this.state.moveStart === true) { @@ -188,7 +193,7 @@ class dragManager { t, }; } - } + }; onMoveEnd = (e) => { this.removeMouseTracking(); @@ -202,7 +207,7 @@ class dragManager { } else { this.state = { ...initalState }; } - } + }; isDragging = () => this.state.dragStart === true; } diff --git a/lib/interviewer/behaviours/DragAndDrop/DragSource.js b/lib/interviewer/behaviours/DragAndDrop/DragSource.js index 145db5d4..a8737f61 100644 --- a/lib/interviewer/behaviours/DragAndDrop/DragSource.js +++ b/lib/interviewer/behaviours/DragAndDrop/DragSource.js @@ -1,4 +1,4 @@ -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'; @@ -6,73 +6,70 @@ 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( @@ -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, @@ -118,32 +109,21 @@ const dragSource = (WrappedComponent) => { cleanupPreview(); cleanupDragManager(); }; - }, [ - node, - allowDrag, - cleanupPreview, - onDragEnd, - onDragMove, - onDragStart, - scrollDirection, - ]); + }, [node, allowDrag]); const styles = () => (isDragging ? { visibility: 'hidden' } : {}); return ( - <> -
- -
+
+ {preview && (
{ {preview}
)} - +
); }; - return DragSourceInner; + DragSourceComponent.displayName = `DragSource(${getDisplayName( + WrappedComponent, + )})`; + + return DragSourceComponent; }; export default dragSource; diff --git a/lib/interviewer/behaviours/DragAndDrop/DropTarget.js b/lib/interviewer/behaviours/DragAndDrop/DropTarget.js index ce9963f4..3576d36d 100644 --- a/lib/interviewer/behaviours/DragAndDrop/DropTarget.js +++ b/lib/interviewer/behaviours/DragAndDrop/DropTarget.js @@ -1,4 +1,4 @@ -/* eslint-disable react/no-find-dom-node, react/jsx-props-no-spreading */ +/* eslint-disable react/no-find-dom-node */ import React, { Component } from 'react'; import { findDOMNode } from 'react-dom'; @@ -33,12 +33,9 @@ const dropTarget = (WrappedComponent) => { update = () => { this.updateTarget(); - // this.interval = setTimeout( - // () => { - // this.animationFrame = requestAnimationFrame(this.update); - // }, - // 1000 / maxFramesPerSecond, - // ); + this.interval = setTimeout(() => { + this.animationFrame = requestAnimationFrame(this.update); + }, 1000 / maxFramesPerSecond); }; updateTarget = () => { @@ -49,6 +46,7 @@ const dropTarget = (WrappedComponent) => { const { id, onDrop, onDrag, onDragEnd, accepts, meta } = this.props; const boundingClientRect = getAbsoluteBoundingRect(this.node); + store.dispatch( actions.upsertTarget({ id, @@ -56,7 +54,7 @@ const dropTarget = (WrappedComponent) => { onDrag, onDragEnd, accepts, - meta: meta?.(), + meta: meta(), width: boundingClientRect.width, height: boundingClientRect.height, y: boundingClientRect.top, @@ -66,7 +64,7 @@ const dropTarget = (WrappedComponent) => { }; render() { - const { ...props } = this.props; + const { accepts, meta, ...props } = this.props; return ( { meta: PropTypes.func, }; + DropTarget.defaultProps = { + meta: () => ({}), + accepts: () => false, + onDrop: () => ({}), + onDrag: () => ({}), + onDragEnd: () => ({}), + }; + return DropTarget; }; diff --git a/lib/interviewer/components/MultiNodeBucket.js b/lib/interviewer/components/MultiNodeBucket.js index b21888d9..c02726ec 100644 --- a/lib/interviewer/components/MultiNodeBucket.js +++ b/lib/interviewer/components/MultiNodeBucket.js @@ -63,7 +63,7 @@ const MultiNodeBucket = (props) => { }, [nodes, sortOrder, listId, currentListId]); return ( - + {sortedNodes.slice(0, 3).map((node, index) => ( { MultiNodeBucket.propTypes = { nodes: PropTypes.array, - nodeColor: PropTypes.string, itemType: PropTypes.string, label: PropTypes.func, listId: PropTypes.string.isRequired,