/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import React, { useRef } from 'react'; import { useDrag, useDrop, DropTargetMonitor, DragSourceMonitor, } from 'react-dnd'; import { DragContainer } from 'src/explore/components/controls/OptionControls'; import { DndItemType } from 'src/explore/components/DndItemType'; import { OptionProps, OptionItemInterface, } from 'src/explore/components/controls/DndColumnSelectControl/types'; import Option from './Option'; export default function OptionWrapper( props: OptionProps & { type: DndItemType; onShiftOptions: (dragIndex: number, hoverIndex: number) => void; }, ) { const { index, type, onShiftOptions, clickClose, withCaret, isExtra, canDelete = true, children, ...rest } = props; const ref = useRef(null); const item: OptionItemInterface = { dragIndex: index, type, }; const [, drag] = useDrag({ item, collect: (monitor: DragSourceMonitor) => ({ isDragging: monitor.isDragging(), }), }); const [, drop] = useDrop({ accept: type, hover: (item: OptionItemInterface, monitor: DropTargetMonitor) => { if (!ref.current) { return; } const { dragIndex } = item; const hoverIndex = index; // Don't replace items with themselves if (dragIndex === hoverIndex) { return; } // Determine rectangle on screen const hoverBoundingRect = ref.current?.getBoundingClientRect(); // Get vertical middle const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; // Determine mouse position const clientOffset = monitor.getClientOffset(); // Get pixels to the top const hoverClientY = clientOffset?.y ? clientOffset?.y - hoverBoundingRect.top : 0; // Only perform the move when the mouse has crossed half of the items height // When dragging downwards, only move when the cursor is below 50% // When dragging upwards, only move when the cursor is above 50% // Dragging downwards if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { return; } // Dragging upwards if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { return; } // Time to actually perform the action onShiftOptions(dragIndex, hoverIndex); // eslint-disable-next-line no-param-reassign item.dragIndex = hoverIndex; }, }); drag(drop(ref)); return ( ); }