diff --git a/frontend/src/metadata/components/popover/groupbys-popover/groupbys/groupby-item.js b/frontend/src/metadata/components/popover/groupbys-popover/groupbys/groupby-item.js index e8cc5f0c0d..b434dcce39 100644 --- a/frontend/src/metadata/components/popover/groupbys-popover/groupbys/groupby-item.js +++ b/frontend/src/metadata/components/popover/groupbys-popover/groupbys/groupby-item.js @@ -21,7 +21,7 @@ const GroupbyItem = ({ showDragBtn, index, readOnly, groupby, columns, onDelete, const [dropPosition, setDropPosition] = useState(null); - const [, drag] = useDrag({ + const [, drag, preview] = useDrag({ type: 'sfMetadataGroupbyItem', item: () => ({ idx: index, @@ -54,7 +54,7 @@ const GroupbyItem = ({ showDragBtn, index, readOnly, groupby, columns, onDelete, }) }); - const dragDropRef = drag(drop(ref)); + drop(preview(ref)); const column = useMemo(() => { return getColumnByKey(columns, groupby.column_key); @@ -160,7 +160,7 @@ const GroupbyItem = ({ showDragBtn, index, readOnly, groupby, columns, onDelete, return (
{!readOnly && showDragBtn && ( -
+
)} diff --git a/frontend/src/metadata/components/popover/options-popover/option/index.css b/frontend/src/metadata/components/popover/options-popover/option/index.css index 310cf6f8f7..5f83cb5f26 100644 --- a/frontend/src/metadata/components/popover/options-popover/option/index.css +++ b/frontend/src/metadata/components/popover/options-popover/option/index.css @@ -49,19 +49,28 @@ fill: #212529; } -.sf-metadata-edit-option-container.sf-metadata-edit-option-can-drop { - border-bottom: 1px solid #666; -} - -.sf-metadata-edit-option-container.sf-metadata-edit-option-can-drop-top::before { +.sf-metadata-edit-option-container.sf-metadata-edit-option-drop-over-top::before { content: ''; - width: 100%; - height: 1px; - background: #666; - display: block; position: absolute; top: 0; left: 0; + width: 100%; + height: 2px; + background-color: rgb(200, 220, 240); + border-radius: 2px; + z-index: 1; +} + +.sf-metadata-edit-option-container.sf-metadata-edit-option-drop-over-bottom::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 2px; + background-color: rgb(200, 220, 240); + border-radius: 2px; + z-index: 1; } .sf-metadata-edit-option-container.sf-metadata-edit-deleting-option, diff --git a/frontend/src/metadata/components/popover/options-popover/option/index.js b/frontend/src/metadata/components/popover/options-popover/option/index.js index 4a181d0a1d..ecdb5ae916 100644 --- a/frontend/src/metadata/components/popover/options-popover/option/index.js +++ b/frontend/src/metadata/components/popover/options-popover/option/index.js @@ -1,4 +1,4 @@ -import React, { useCallback } from 'react'; +import React, { useCallback, useRef, useState } from 'react'; import PropTypes from 'prop-types'; import { useDrag, useDrop } from 'react-dnd'; import classnames from 'classnames'; @@ -9,74 +9,50 @@ import Name from './name'; import './index.css'; -// const dragSource = { -// beginDrag: props => { -// return { idx: props.index, data: props.option, mode: 'sfMetadataSingleSelectOption' }; -// }, -// endDrag(props, monitor) { -// const optionSource = monitor.getItem(); -// const didDrop = monitor.didDrop(); -// let optionTarget = {}; -// if (!didDrop) { -// return { optionSource, optionTarget }; -// } -// }, -// isDragging(props, monitor) { -// const { index, dragged } = props; -// const { idx } = dragged; -// return idx > index; -// } -// }; - -// const dragCollect = (connect, monitor) => ({ -// connectDragSource: connect.dragSource(), -// connectDragPreview: connect.dragPreview(), -// isDragging: monitor.isDragging() -// }); - -// const dropTarget = { -// drop(props, monitor) { -// const optionSource = monitor.getItem(); -// const { index: targetIdx } = props; -// if (targetIdx !== optionSource.idx) { -// const optionTarget = { idx: targetIdx, data: props.option }; -// props.onMove(optionSource, optionTarget); -// } -// } -// }; - -// const dropCollect = (connect, monitor) => ({ -// connectDropTarget: connect.dropTarget(), -// isOver: monitor.isOver(), -// canDrop: monitor.canDrop(), -// dragged: monitor.getItem() -// }); - const Option = ({ isViewing, isDeleting, isEditing, isPredefined, - option, - onDelete: propsDelete, onUpdate, + option, index, + onDelete: propsDelete, onUpdate, onMove, onMouseLeave, onMouseEnter: propsMouseEnter, onToggleFreeze, onOpenNameEditor, onCloseNameEditor, }) => { - const [{ isDragging }, drag] = useDrag({ + const ref = useRef(null); + const [dropPosition, setDropPosition] = useState(null); + + const [, drag, preview] = useDrag({ type: 'sfMetadataSingleSelectOption', item: () => ({ - idx: option.id, + idx: index, data: option, }), - collect: (monitor) => ({ - isDragging: monitor.isDragging(), - }), }); const [{ isOver, canDrop }, drop] = useDrop({ accept: 'sfMetadataSingleSelectOption', + hover: (item, monitor) => { + if (!ref.current) return; + + const hoverBoundingRect = ref.current.getBoundingClientRect(); + const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; + const clientOffset = monitor.getClientOffset(); + const hoverClientY = clientOffset.y - hoverBoundingRect.top; + + const newPosition = hoverClientY < hoverMiddleY ? 'top' : 'bottom'; + setDropPosition(newPosition); + }, + drop: (item) => { + if (item.idx === index) return; + if (item.idx === index - 1 && dropPosition === 'top') return; + if (item.idx === index + 1 && dropPosition === 'bottom') return; + onMove(item, { idx: index, data: option }); + }, collect: (monitor) => ({ isOver: monitor.isOver(), canDrop: monitor.canDrop(), }) }); + drop(preview(ref)); + const onDelete = useCallback((event) => { event.nativeEvent.stopImmediatePropagation(); propsDelete(option.id); @@ -88,11 +64,11 @@ const Option = ({ return (
drag(drop(node))} + ref={ref} className={classnames('sf-metadata-edit-option-container', { - 'sf-metadata-edit-option-can-drop': isOver && canDrop && !isDragging, 'sf-metadata-edit-deleting-option': isDeleting, - 'sf-metadata-edit-option-can-drop-top': isOver && canDrop && isDragging, + 'sf-metadata-edit-option-drop-over-top': isOver && canDrop && dropPosition === 'top', + 'sf-metadata-edit-option-drop-over-bottom': isOver && canDrop && dropPosition === 'bottom', 'sf-metadata-edit-option-viewing': isViewing, 'sf-metadata-edit-option-editing': isEditing, 'sf-metadata-edit-option-disabled': isPredefined, @@ -100,7 +76,7 @@ const Option = ({ onMouseEnter={() => onMouseEnter()} onMouseLeave={onMouseLeave} > -
+
@@ -125,7 +101,6 @@ const Option = ({ }; Option.propTypes = { - // normal option: PropTypes.object, index: PropTypes.number, isPredefined: PropTypes.bool, @@ -140,14 +115,6 @@ Option.propTypes = { onToggleFreeze: PropTypes.func, onOpenNameEditor: PropTypes.func.isRequired, onCloseNameEditor: PropTypes.func.isRequired, - - // // drag - // isOver: PropTypes.bool, - // canDrop: PropTypes.bool, - // dragged: PropTypes.object, - // connectDragSource: PropTypes.func.isRequired, - // connectDropTarget: PropTypes.func.isRequired, - // connectDragPreview: PropTypes.func.isRequired, }; export default Option;