Files
superset2/superset-frontend/src/explore/components/controls/DndColumnSelectControl/OptionWrapper.tsx
Geido a1e18ed110 fix(Explore): Show the tooltip only when label does not fit the container in METRICS/FILTERS/GROUP BY/SORT BY of the DATA panel (#16060)
* Implement dynamic tooltip

* Normalize and consolidate

* Clean up

* Refactor and clean up

* Remove unnecessary var

* Fix type import

* Update superset-frontend/src/explore/components/controls/OptionControls/index.tsx

Co-authored-by: Michael S. Molina <70410625+michael-s-molina@users.noreply.github.com>

* Remove unnecessary styled span

* Show full tooltip title

* Force show tooltip

* Force show tooltip D&D off

Co-authored-by: Ville Brofeldt <ville.v.brofeldt@gmail.com>
Co-authored-by: Michael S. Molina <70410625+michael-s-molina@users.noreply.github.com>
2021-08-12 11:48:16 -06:00

185 lines
4.8 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, { useMemo, useRef } from 'react';
import {
useDrag,
useDrop,
DropTargetMonitor,
DragSourceMonitor,
} from 'react-dnd';
import { DragContainer } from 'src/explore/components/controls/OptionControls';
import {
OptionProps,
OptionItemInterface,
} from 'src/explore/components/controls/DndColumnSelectControl/types';
import { Tooltip } from 'src/components/Tooltip';
import { StyledColumnOption } from 'src/explore/components/optionRenderers';
import { styled } from '@superset-ui/core';
import { ColumnMeta } from '@superset-ui/chart-controls';
import Option from './Option';
export const OptionLabel = styled.div`
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;
export default function OptionWrapper(
props: OptionProps & {
type: string;
onShiftOptions: (dragIndex: number, hoverIndex: number) => void;
},
) {
const {
index,
label,
tooltipTitle,
column,
type,
onShiftOptions,
clickClose,
withCaret,
isExtra,
canDelete = true,
...rest
} = props;
const ref = useRef<HTMLDivElement>(null);
const labelRef = useRef<HTMLDivElement>(null);
const item: OptionItemInterface = useMemo(
() => ({
dragIndex: index,
type,
}),
[index, type],
);
const [{ isDragging }, 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;
},
});
const shouldShowTooltip =
(!isDragging && tooltipTitle && label && tooltipTitle !== label) ||
(!isDragging &&
labelRef &&
labelRef.current &&
labelRef.current.scrollWidth > labelRef.current.clientWidth);
const LabelContent = () => {
if (!shouldShowTooltip) {
return <span>{label}</span>;
}
return (
<Tooltip title={tooltipTitle || label}>
<span>{label}</span>
</Tooltip>
);
};
const ColumnOption = () => (
<StyledColumnOption
column={column as ColumnMeta}
labelRef={labelRef}
showTooltip={!!shouldShowTooltip}
showType
/>
);
const Label = () => {
if (label) {
return (
<OptionLabel ref={labelRef}>
<LabelContent />
</OptionLabel>
);
}
if (column) {
return (
<OptionLabel>
<ColumnOption />
</OptionLabel>
);
}
return null;
};
drag(drop(ref));
return (
<DragContainer ref={ref} {...rest}>
<Option
index={index}
clickClose={clickClose}
withCaret={withCaret}
isExtra={isExtra}
canDelete={canDelete}
>
<Label />
</Option>
</DragContainer>
);
}