diff --git a/src/js/components/Fields/Commands.js b/src/js/components/Fields/Commands.js index 88ccb82f..e7a0554a 100644 --- a/src/js/components/Fields/Commands.js +++ b/src/js/components/Fields/Commands.js @@ -1,9 +1,86 @@ -import React, { useState, useEffect } from 'react'; -import { ReactSortable } from 'react-sortablejs'; +import React, { useState, useEffect, useRef, useCallback } from 'react'; +import { useDrop, useDrag } from 'react-dnd'; import Icon from '../Icon'; import Link from '../Link'; import { sortItems, indexToArray } from '../../util/arrays'; +const DRAGGABLE_TYPE = 'COMMAND'; + +const Command = ({ + index, + onExecute, + onDrag, + onDragEnd, + command: { + id, + url, + name, + icon, + colour, + } = {}, +}) => { + const ref = useRef(null); + + const [{ isDragging }, dragRef] = useDrag({ + type: DRAGGABLE_TYPE, + item: { index }, + collect: (monitor) => ({ + isDragging: monitor.isDragging(), + }), + end: onDragEnd, + }); + + const [_dropProps, dropRef] = useDrop({ + accept: DRAGGABLE_TYPE, + hover: (item, monitor) => { + const dragIndex = item.index; + const hoverIndex = index; + const hoverBoundingRect = ref.current?.getBoundingClientRect() + const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; + const hoverActualY = monitor.getClientOffset().y - hoverBoundingRect.top; + + // if dragging down, continue only when hover is smaller than middle Y + if (dragIndex < hoverIndex && hoverActualY < hoverMiddleY) return; + // if dragging up, continue only when hover is bigger than middle Y + if (dragIndex > hoverIndex && hoverActualY > hoverMiddleY) return; + + onDrag(dragIndex, hoverIndex); + item.index = hoverIndex; + }, + }) + + let className = 'list__item commands-setup__item'; + if (isDragging) className += ' list__item--dragging'; + + return ( +
+
+
+ +
+
+ + +
+
+ {name || {url}} +
+
+
+ onExecute(id, true)}> + + + + + +
+
+ ); +} + const Commands = ({ commands, runCommand, @@ -18,58 +95,44 @@ const Commands = ({ useEffect(() => { setList(sortItems(indexToArray(commands), 'sort_order')); }, []); - - const onSort = () => { - const nextCommands = {}; - if (!list || !list.length) return; + const onDrag = useCallback((dragIndex, hoverIndex) => { + setList((prev) => { + const next = [...prev]; + const dragItem = next[dragIndex]; + const hoverItem = next[hoverIndex]; + next[dragIndex] = hoverItem; + next[hoverIndex] = dragItem; + return next; + }); + }, [list]); + + const onDragEnd = () => { + if (!list || !list.length) return; + const nextCommands = {}; list.forEach((item, index) => { nextCommands[item.id] = { ...item, sort_order: index, }; }); - onChange(nextCommands); }; return ( - - { - list.map((command) => ( -
-
- -
- - -
-
- {command.name ? command.name : {command.url}} -
-
-
- runCommand(command.id, true)}> - - - - - -
-
- )) - } -
+
+ {list.map((command, index) => ( + + ))} +
); -} +}; export default Commands;