@grafana/ui
Version:
Grafana Components Library
364 lines (361 loc) • 15.3 kB
JavaScript
import { jsx } from 'react/jsx-runtime';
import { css } from '@emotion/css';
import { useRef, useState, useLayoutEffect } from 'react';
import { useMountedState } from 'react-use';
import { DashboardCursorSync, getDisplayProcessor, FALLBACK_COLOR, getFieldDisplayName, formattedValueToString, FieldType, arrayUtils } from '@grafana/data';
import { TooltipDisplayMode, SortOrder } from '@grafana/schema';
import '../../../components/FormField/FormField.mjs';
import '../../../components/Forms/Legacy/Input/Input.mjs';
import 'react-select';
import '../../../components/Icon/Icon.mjs';
import '../../../components/Forms/Legacy/Select/Select.mjs';
import '../../../components/Forms/Legacy/Switch/Switch.mjs';
import '../../../components/SecretFormField/SecretFormField.mjs';
import '../../../components/IconButton/IconButton.mjs';
import '../../../components/ConfirmButton/ConfirmButton.mjs';
import '../../../components/Button/Button.mjs';
import '../../../components/Button/ButtonGroup.mjs';
import '../../../components/Tooltip/Tooltip.mjs';
import '@floating-ui/react';
import { useTheme2, useStyles2 } from '../../../themes/ThemeContext.mjs';
import 'micro-memoize';
import '@emotion/react';
import 'tinycolor2';
import '../../../utils/skeleton.mjs';
import { Portal } from '../../../components/Portal/Portal.mjs';
import '../../../components/Toggletip/Toggletip.mjs';
import 'react-custom-scrollbars-2';
import '../../../components/Tabs/Tab.mjs';
import '../../../components/Tabs/TabsBar.mjs';
import '../../../components/Layout/Box/Box.mjs';
import '../../../components/ScrollContainer/ScrollContainer.mjs';
import '../../../utils/i18n.mjs';
import '../../../components/Cascader/Cascader.mjs';
import '../../../components/Alert/Alert.mjs';
import '../../../components/ButtonCascader/ButtonCascader.mjs';
import 'react-inlinesvg';
import '../../../utils/keyframes.mjs';
import '../../../components/ColorPicker/ColorPicker.mjs';
import '../../../components/ColorPicker/ColorPickerInput.mjs';
import '../../../components/ColorPicker/SeriesColorPickerPopover.mjs';
import '../../../components/Layout/Stack/Stack.mjs';
import '../../../components/Text/Text.mjs';
import '../../../components/EmptyState/GrotCTA/GrotCTA.mjs';
import '../../../components/EmptyState/GrotNotFound/GrotNotFound.mjs';
import '../../../components/StatsPicker/StatsPicker.mjs';
import '../../../components/RefreshPicker/RefreshPicker.mjs';
import '../../../components/DateTimePickers/TimeRangePicker.mjs';
import '../../../components/DateTimePickers/TimeRangeContext.mjs';
import '../../../components/DateTimePickers/TimeRangePicker/TimeRangeLabel.mjs';
import 'rc-picker';
import 'rc-picker/lib/generate/moment';
import 'rc-picker/lib/locale/en_US';
import 'rc-picker/assets/index.css';
import 'lodash';
import 'react-select/async';
import 'react-select/async-creatable';
import 'react-select/creatable';
import '../../../components/Select/IndicatorsContainer.mjs';
import '../../../components/Select/InputControl.mjs';
import '../../../components/Select/getSelectStyles.mjs';
import '../../../components/Input/Input.mjs';
import '../../../components/Select/SelectMenu.mjs';
import 'react-transition-group';
import '../../../components/Select/ValueContainer.mjs';
import '@grafana/e2e-selectors';
import '@tanstack/react-virtual';
import 'downshift';
import '../../../components/Input/AutoSizeInput.mjs';
import '../../../components/Forms/Checkbox.mjs';
import '../../../components/Combobox/filter.mjs';
import '../../../utils/dom.mjs';
import '../../../utils/colors.mjs';
import 'slate';
import '../../../utils/logger.mjs';
import '../../../components/DateTimePickers/DatePicker/DatePicker.mjs';
import '../../../components/DateTimePickers/DateTimePicker/DateTimePicker.mjs';
import '../../../components/List/AbstractList.mjs';
import 'react-table';
import '../../../components/InteractiveTable/Expander/index.mjs';
import '../../../components/AutoSaveField/AutoSaveField.mjs';
import '../../../components/Tags/Tag.mjs';
import '../../../components/Tags/TagList.mjs';
import '../../../components/Modal/Modal.mjs';
import 'react-hook-form';
import '../../../components/Forms/Field.mjs';
import '../../../components/QueryField/QueryField.mjs';
import '../../../components/Monaco/CodeEditor.mjs';
import '../../../components/ErrorBoundary/ErrorWithStack.mjs';
import '../../../components/Modal/ModalsContext.mjs';
import '../../../components/PageLayout/PageToolbar.mjs';
import 'rxjs';
import 'rxjs/operators';
import '../../../components/Table/TableRT/Table.mjs';
import '@react-aria/dialog';
import '@react-aria/focus';
import '@react-aria/overlays';
import 'rc-drawer';
import 'rc-drawer/assets/index.css';
import '../../../components/TableInputCSV/TableInputCSV.mjs';
import '../../../components/Tabs/VerticalTab.mjs';
import '../../../components/BigValue/BigValue.mjs';
import '../../../components/Sparkline/Sparkline.mjs';
import '../../../components/Gauge/Gauge.mjs';
import '../../../components/BarGauge/BarGauge.mjs';
import '../../../components/VizTooltip/VizTooltip.mjs';
import { VizTooltipContainer } from '../../../components/VizTooltip/VizTooltipContainer.mjs';
import { SeriesTable } from '../../../components/VizTooltip/SeriesTable.mjs';
import '../../../components/VizRepeater/VizRepeater.mjs';
import '../../../components/PanelChrome/index.mjs';
import '../../../components/VizLayout/VizLayout.mjs';
import '../../../components/VizLegend/VizLegend.mjs';
import '../../../components/VizLegend/VizLegendListItem.mjs';
import '../../../components/Collapse/Collapse.mjs';
import '../../../components/ClickOutsideWrapper/ClickOutsideWrapper.mjs';
import '../../../components/ContextMenu/ContextMenu.mjs';
import '../../../components/Menu/Menu.mjs';
import '../../../components/Menu/MenuGroup.mjs';
import '../../../components/Menu/MenuItem.mjs';
import '../../../components/DataLinks/DataLinkEditor.mjs';
import '@hello-pangea/dnd';
import '../../../components/Badge/Badge.mjs';
import '../../../components/DataLinks/DataLinkInput.mjs';
import '../../../components/VizLegend/SeriesIcon.mjs';
import '../../../components/InfoBox/InfoBox.mjs';
import '../../../components/InfoBox/FeatureInfoBox.mjs';
import '../../../components/JSONFormatter/JSONFormatter.mjs';
import '../../../components/ErrorBoundary/ErrorBoundary.mjs';
import '../../../components/Forms/InlineField.mjs';
import '../../../components/Forms/RadioButtonGroup/RadioButtonGroup.mjs';
import '../../../components/Switch/Switch.mjs';
import '../../../components/DataSourceSettings/CustomHeadersSettings.mjs';
import '../../../components/TextArea/TextArea.mjs';
import 'react-use/lib/useClickAway';
import '../../../components/Slider/Slider.mjs';
import '../../../components/Slider/RangeSlider.mjs';
import '../../../components/ToolbarButton/ToolbarButton.mjs';
import '../../../components/ToolbarButton/ToolbarButtonRow.mjs';
import '../../../components/MatchersUI/fieldMatchersUI.mjs';
import '../../../components/Link/Link.mjs';
import '../../../components/Link/TextLink.mjs';
import '../../../components/Layout/Grid/Grid.mjs';
import '../../../components/Forms/InlineSegmentGroup.mjs';
import '../../../components/Combobox/ValuePill.mjs';
import '../../../components/FilterInput/FilterInput.mjs';
import 'uuid';
import 'react-dropzone';
import '../../../components/DateTimePickers/TimeRangePicker/TimePickerContent.mjs';
import '../../../components/DateTimePickers/RelativeTimeRangePicker/RelativeTimeRangePicker.mjs';
import '../../../components/Card/Card.mjs';
import '../../../components/FormattedValueDisplay/FormattedValueDisplay.mjs';
import '../../../components/Dropdown/ButtonSelect.mjs';
import '../../../components/Dropdown/Dropdown.mjs';
import '../../../components/PluginSignatureBadge/PluginSignatureBadge.mjs';
import 'classnames';
import '../../../components/Divider/Divider.mjs';
import '../../../components/uPlot/config.mjs';
import 'uplot';
import { findMidPointYPosition } from '../../../components/uPlot/utils.mjs';
import 'uplot/dist/uPlot.min.css';
import '../../../components/uPlot/PlotLegend.mjs';
import 'react-dom';
import '../../../components/BrowserLabel/Label.mjs';
import '../../Graph/Graph.mjs';
import '../../GraphNG/GraphNG.mjs';
import '../../TimeSeries/TimeSeries.mjs';
import '../../GraphNG/hooks.mjs';
import '../../../components/ElementSelectionContext/ElementSelectionContext.mjs';
const TOOLTIP_OFFSET = 10;
const TooltipPlugin = ({
mode = TooltipDisplayMode.Single,
sortOrder = SortOrder.None,
sync,
timeZone,
config,
renderTooltip,
...otherProps
}) => {
var _a, _b, _c, _d, _e;
const plotInstance = useRef();
const theme = useTheme2();
const [focusedSeriesIdx, setFocusedSeriesIdx] = useState(null);
const [focusedPointIdx, setFocusedPointIdx] = useState(null);
const [focusedPointIdxs, setFocusedPointIdxs] = useState([]);
const [coords, setCoords] = useState(null);
const [isActive, setIsActive] = useState(false);
const isMounted = useMountedState();
let parentWithFocus = null;
const style = useStyles2(getStyles);
useLayoutEffect(() => {
let bbox = void 0;
const plotEnter = () => {
var _a2;
if (!isMounted()) {
return;
}
setIsActive(true);
(_a2 = plotInstance.current) == null ? void 0 : _a2.root.classList.add("plot-active");
};
const plotLeave = () => {
var _a2;
if (!isMounted()) {
return;
}
setCoords(null);
setIsActive(false);
(_a2 = plotInstance.current) == null ? void 0 : _a2.root.classList.remove("plot-active");
};
config.addHook("syncRect", (u, rect) => bbox = rect);
config.addHook("init", (u) => {
plotInstance.current = u;
u.over.addEventListener("mouseenter", plotEnter);
u.over.addEventListener("mouseleave", plotLeave);
parentWithFocus = u.root.closest("[tabindex]");
if (parentWithFocus) {
parentWithFocus.addEventListener("focus", plotEnter);
parentWithFocus.addEventListener("blur", plotLeave);
}
if (sync && sync() === DashboardCursorSync.Crosshair) {
u.root.classList.add("shared-crosshair");
}
});
config.addHook("setLegend", (u) => {
if (!isMounted()) {
return;
}
setFocusedPointIdx(u.legend.idx);
setFocusedPointIdxs(u.legend.idxs.slice());
});
config.addHook("setCursor", (u) => {
if (!bbox || !isMounted()) {
return;
}
const { x, y } = positionTooltip(u, bbox);
if (x !== void 0 && y !== void 0) {
setCoords({ x, y });
} else {
setCoords(null);
}
});
config.addHook("setSeries", (_, idx) => {
if (!isMounted()) {
return;
}
setFocusedSeriesIdx(idx);
});
return () => {
setCoords(null);
if (plotInstance.current) {
plotInstance.current.over.removeEventListener("mouseleave", plotLeave);
plotInstance.current.over.removeEventListener("mouseenter", plotEnter);
if (parentWithFocus) {
parentWithFocus.removeEventListener("focus", plotEnter);
parentWithFocus.removeEventListener("blur", plotLeave);
}
}
};
}, [config, setCoords, setIsActive, setFocusedPointIdx, setFocusedPointIdxs]);
if (focusedPointIdx === null || !isActive && sync && sync() === DashboardCursorSync.Crosshair) {
return null;
}
let xField = otherProps.data.fields[0];
if (!xField) {
return null;
}
const xFieldFmt = xField.display || getDisplayProcessor({ field: xField, timeZone, theme });
let tooltip = null;
let xVal = xFieldFmt(xField.values[focusedPointIdx]).text;
if (!renderTooltip) {
if (mode === TooltipDisplayMode.Single && focusedSeriesIdx !== null) {
const field = otherProps.data.fields[focusedSeriesIdx];
if (!field) {
return null;
}
const dataIdx = (_a = focusedPointIdxs == null ? void 0 : focusedPointIdxs[focusedSeriesIdx]) != null ? _a : focusedPointIdx;
xVal = xFieldFmt(xField.values[dataIdx]).text;
const fieldFmt = field.display || getDisplayProcessor({ field, timeZone, theme });
const display = fieldFmt(field.values[dataIdx]);
tooltip = /* @__PURE__ */ jsx(
SeriesTable,
{
series: [
{
color: display.color || FALLBACK_COLOR,
label: getFieldDisplayName(field, otherProps.data, otherProps.frames),
value: display ? formattedValueToString(display) : null
}
],
timestamp: xVal
}
);
}
if (mode === TooltipDisplayMode.Multi) {
let series = [];
const frame = otherProps.data;
const fields = frame.fields;
const sortIdx = [];
for (let i = 0; i < fields.length; i++) {
const field = frame.fields[i];
if (!field || field === xField || field.type === FieldType.time || field.type !== FieldType.number || ((_c = (_b = field.config.custom) == null ? void 0 : _b.hideFrom) == null ? void 0 : _c.tooltip) || ((_e = (_d = field.config.custom) == null ? void 0 : _d.hideFrom) == null ? void 0 : _e.viz)) {
continue;
}
const v = otherProps.data.fields[i].values[focusedPointIdxs[i]];
const display = field.display(v);
sortIdx.push(v);
series.push({
color: display.color || FALLBACK_COLOR,
label: getFieldDisplayName(field, frame, otherProps.frames),
value: display ? formattedValueToString(display) : null,
isActive: focusedSeriesIdx === i
});
}
if (sortOrder !== SortOrder.None) {
const sortRef = [...series];
const sortFn = arrayUtils.sortValues(sortOrder);
series.sort((a, b) => {
const aIdx = sortRef.indexOf(a);
const bIdx = sortRef.indexOf(b);
return sortFn(sortIdx[aIdx], sortIdx[bIdx]);
});
}
tooltip = /* @__PURE__ */ jsx(SeriesTable, { series, timestamp: xVal });
}
} else {
tooltip = renderTooltip(otherProps.data, focusedSeriesIdx, focusedPointIdx);
}
return /* @__PURE__ */ jsx(Portal, { className: isActive ? style.tooltipWrapper : void 0, children: tooltip && coords && /* @__PURE__ */ jsx(VizTooltipContainer, { position: { x: coords.x, y: coords.y }, offset: { x: TOOLTIP_OFFSET, y: TOOLTIP_OFFSET }, children: tooltip }) });
};
function isCursorOutsideCanvas({ left, top }, canvas) {
if (left === void 0 || top === void 0) {
return false;
}
return left < 0 || left > canvas.width || top < 0 || top > canvas.height;
}
function positionTooltip(u, bbox) {
let x, y;
const cL = u.cursor.left || 0;
const cT = u.cursor.top || 0;
if (isCursorOutsideCanvas(u.cursor, bbox)) {
const idx = u.posToIdx(cL);
if (cT < 0 || cT > bbox.height) {
let pos = findMidPointYPosition(u, idx);
if (pos) {
y = bbox.top + pos;
if (cL >= 0 && cL <= bbox.width) {
x = bbox.left + u.valToPos(u.data[0][u.posToIdx(cL)], u.series[0].scale);
}
}
}
} else {
x = bbox.left + cL;
y = bbox.top + cT;
}
return { x, y };
}
const getStyles = (theme) => ({
tooltipWrapper: css({
"z-index": theme.zIndex.portal + 1 + " !important"
})
});
export { TooltipPlugin, positionTooltip };
//# sourceMappingURL=TooltipPlugin.mjs.map