mirror of
https://github.com/apache/superset.git
synced 2026-04-19 16:14:52 +00:00
124 lines
3.5 KiB
TypeScript
124 lines
3.5 KiB
TypeScript
/**
|
|
* 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<HTMLDivElement>(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 (
|
|
<DragContainer ref={ref} {...rest}>
|
|
<Option
|
|
index={index}
|
|
clickClose={clickClose}
|
|
withCaret={withCaret}
|
|
isExtra={isExtra}
|
|
canDelete={canDelete}
|
|
>
|
|
{children}
|
|
</Option>
|
|
</DragContainer>
|
|
);
|
|
}
|