mirror of https://github.com/grafana/grafana.git
Floating UI: Update to use the `.main-view` as a boundary (#111089)
* fix(Dropdown): update the boundary to the `.main-view` * apply floating-ui changes everywhere * remove some unused imports * up timeout on this test cause it's unbelievably slow * don't spread when not necessary * fix case in panel edit on small screens --------- Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
This commit is contained in:
parent
3cc99ba811
commit
1564a49373
|
|
@ -1,21 +1,12 @@
|
|||
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationInfoButton.tsx
|
||||
import { css } from '@emotion/css';
|
||||
import {
|
||||
autoUpdate,
|
||||
flip,
|
||||
offset,
|
||||
shift,
|
||||
useClick,
|
||||
useDismiss,
|
||||
useFloating,
|
||||
useInteractions,
|
||||
} from '@floating-ui/react';
|
||||
import { autoUpdate, offset, useClick, useDismiss, useFloating, useInteractions } from '@floating-ui/react';
|
||||
import { memo, useState } from 'react';
|
||||
|
||||
import { GrafanaTheme2, renderMarkdown } from '@grafana/data';
|
||||
import { t } from '@grafana/i18n';
|
||||
import { FlexItem } from '@grafana/plugin-ui';
|
||||
import { Button, Portal, useStyles2 } from '@grafana/ui';
|
||||
import { Button, floatingUtils, Portal, useStyles2 } from '@grafana/ui';
|
||||
|
||||
import { QueryBuilderOperation, QueryBuilderOperationDef } from './types';
|
||||
|
||||
|
|
@ -29,16 +20,7 @@ export const OperationInfoButton = memo<Props>(({ def, operation }) => {
|
|||
const [show, setShow] = useState(false);
|
||||
|
||||
// the order of middleware is important!
|
||||
const middleware = [
|
||||
offset(16),
|
||||
flip({
|
||||
fallbackAxisSideDirection: 'end',
|
||||
// see https://floating-ui.com/docs/flip#combining-with-shift
|
||||
crossAxis: false,
|
||||
boundary: document.body,
|
||||
}),
|
||||
shift(),
|
||||
];
|
||||
const middleware = [offset(16), ...floatingUtils.getPositioningMiddleware()];
|
||||
|
||||
const { context, refs, floatingStyles } = useFloating({
|
||||
open: show,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { autoUpdate, autoPlacement, size, useFloating } from '@floating-ui/react';
|
||||
import { useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { BOUNDARY_ELEMENT_ID } from '../../utils/floating';
|
||||
import { measureText } from '../../utils/measureText';
|
||||
|
||||
import {
|
||||
|
|
@ -36,7 +37,7 @@ export const useComboboxFloat = (items: Array<ComboboxOption<string | number>>,
|
|||
autoPlacement({
|
||||
// see https://floating-ui.com/docs/autoplacement
|
||||
allowedPlacements: ['bottom-start', 'bottom-end', 'top-start', 'top-end'],
|
||||
boundary: document.body,
|
||||
boundary: document.getElementById(BOUNDARY_ELEMENT_ID) ?? undefined,
|
||||
crossAxis: true,
|
||||
}),
|
||||
size({
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { css, cx } from '@emotion/css';
|
||||
import { autoUpdate, flip, offset, shift, useFloating } from '@floating-ui/react';
|
||||
import { autoUpdate, offset, useFloating } from '@floating-ui/react';
|
||||
import Prism, { Grammar, LanguageMap } from 'prismjs';
|
||||
import { memo, useEffect, useRef, useState } from 'react';
|
||||
import * as React from 'react';
|
||||
|
|
@ -12,6 +12,7 @@ import { DataLinkBuiltInVars, GrafanaTheme2, VariableOrigin, VariableSuggestion
|
|||
|
||||
import { SlatePrism } from '../../slate-plugins/slate-prism';
|
||||
import { useStyles2 } from '../../themes/ThemeContext';
|
||||
import { getPositioningMiddleware } from '../../utils/floating';
|
||||
import { SCHEMA, makeValue } from '../../utils/slate';
|
||||
import { getInputStyles } from '../Input/Input';
|
||||
import { Portal } from '../Portal/Portal';
|
||||
|
|
@ -97,13 +98,7 @@ export const DataLinkInput = memo(
|
|||
offset(({ rects }) => ({
|
||||
alignmentAxis: rects.reference.width,
|
||||
})),
|
||||
flip({
|
||||
fallbackAxisSideDirection: 'start',
|
||||
// see https://floating-ui.com/docs/flip#combining-with-shift
|
||||
crossAxis: false,
|
||||
boundary: document.body,
|
||||
}),
|
||||
shift(),
|
||||
...getPositioningMiddleware(),
|
||||
];
|
||||
|
||||
const { refs, floatingStyles } = useFloating({
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import { css } from '@emotion/css';
|
||||
import { autoUpdate, flip, shift, useClick, useDismiss, useFloating, useInteractions } from '@floating-ui/react';
|
||||
import { autoUpdate, useClick, useDismiss, useFloating, useInteractions } from '@floating-ui/react';
|
||||
import { ChangeEvent, forwardRef, useImperativeHandle, useState } from 'react';
|
||||
|
||||
import { GrafanaTheme2, dateTime } from '@grafana/data';
|
||||
|
||||
import { useStyles2 } from '../../../themes/ThemeContext';
|
||||
import { getPositioningMiddleware } from '../../../utils/floating';
|
||||
import { Props as InputProps, Input } from '../../Input/Input';
|
||||
import { DatePicker } from '../DatePicker/DatePicker';
|
||||
|
||||
|
|
@ -31,21 +32,15 @@ export const DatePickerWithInput = forwardRef<HTMLInputElement, DatePickerWithIn
|
|||
({ value, minDate, maxDate, onChange, closeOnSelect, placeholder = 'Date', ...rest }, ref) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const styles = useStyles2(getStyles);
|
||||
const placement = 'bottom-start';
|
||||
|
||||
// the order of middleware is important!
|
||||
// see https://floating-ui.com/docs/arrow#order
|
||||
const middleware = [
|
||||
flip({
|
||||
// see https://floating-ui.com/docs/flip#combining-with-shift
|
||||
crossAxis: false,
|
||||
boundary: document.body,
|
||||
}),
|
||||
shift(),
|
||||
];
|
||||
const middleware = getPositioningMiddleware(placement);
|
||||
|
||||
const { context, refs, floatingStyles } = useFloating<HTMLInputElement>({
|
||||
open,
|
||||
placement: 'bottom-start',
|
||||
placement,
|
||||
onOpenChange: setOpen,
|
||||
middleware,
|
||||
whileElementsMounted: autoUpdate,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { css, cx } from '@emotion/css';
|
||||
import { autoUpdate, flip, shift, useFloating } from '@floating-ui/react';
|
||||
import { autoUpdate, useFloating } from '@floating-ui/react';
|
||||
import { useDialog } from '@react-aria/dialog';
|
||||
import { FocusScope } from '@react-aria/focus';
|
||||
import { useOverlay } from '@react-aria/overlays';
|
||||
|
|
@ -22,6 +22,7 @@ import { Components } from '@grafana/e2e-selectors';
|
|||
import { t, Trans } from '@grafana/i18n';
|
||||
|
||||
import { useStyles2, useTheme2 } from '../../../themes/ThemeContext';
|
||||
import { getPositioningMiddleware } from '../../../utils/floating';
|
||||
import { Button } from '../../Button/Button';
|
||||
import { InlineField } from '../../Forms/InlineField';
|
||||
import { Icon } from '../../Icon/Icon';
|
||||
|
|
@ -92,22 +93,16 @@ export const DateTimePicker = ({
|
|||
const theme = useTheme2();
|
||||
const { modalBackdrop } = useStyles2(getModalStyles);
|
||||
const isFullscreen = useMedia(`(min-width: ${theme.breakpoints.values.lg}px)`);
|
||||
const placement = 'bottom-start';
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
// the order of middleware is important!
|
||||
// see https://floating-ui.com/docs/arrow#order
|
||||
const middleware = [
|
||||
flip({
|
||||
// see https://floating-ui.com/docs/flip#combining-with-shift
|
||||
crossAxis: false,
|
||||
boundary: document.body,
|
||||
}),
|
||||
shift(),
|
||||
];
|
||||
const middleware = getPositioningMiddleware(placement);
|
||||
|
||||
const { refs, floatingStyles } = useFloating({
|
||||
open: isOpen,
|
||||
placement: 'bottom-start',
|
||||
placement,
|
||||
onOpenChange: setOpen,
|
||||
middleware,
|
||||
whileElementsMounted: autoUpdate,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { css, cx } from '@emotion/css';
|
||||
import { autoUpdate, flip, shift, useClick, useDismiss, useFloating, useInteractions } from '@floating-ui/react';
|
||||
import { autoUpdate, useClick, useDismiss, useFloating, useInteractions } from '@floating-ui/react';
|
||||
import { useDialog } from '@react-aria/dialog';
|
||||
import { FocusScope } from '@react-aria/focus';
|
||||
import { useOverlay } from '@react-aria/overlays';
|
||||
|
|
@ -9,6 +9,7 @@ import { RelativeTimeRange, GrafanaTheme2, TimeOption } from '@grafana/data';
|
|||
import { t, Trans } from '@grafana/i18n';
|
||||
|
||||
import { useStyles2 } from '../../../themes/ThemeContext';
|
||||
import { getPositioningMiddleware } from '../../../utils/floating';
|
||||
import { Button } from '../../Button/Button';
|
||||
import { Field } from '../../Forms/Field';
|
||||
import { Icon } from '../../Icon/Icon';
|
||||
|
|
@ -56,21 +57,15 @@ export function RelativeTimeRangePicker(props: RelativeTimeRangePickerProps) {
|
|||
);
|
||||
const { dialogProps } = useDialog({}, ref);
|
||||
const validOptions = getQuickOptions().filter((o) => isRelativeFormat(o.from));
|
||||
const placement = 'bottom-start';
|
||||
|
||||
// the order of middleware is important!
|
||||
// see https://floating-ui.com/docs/arrow#order
|
||||
const middleware = [
|
||||
flip({
|
||||
// see https://floating-ui.com/docs/flip#combining-with-shift
|
||||
crossAxis: false,
|
||||
boundary: document.body,
|
||||
}),
|
||||
shift(),
|
||||
];
|
||||
const middleware = getPositioningMiddleware(placement);
|
||||
|
||||
const { context, refs, floatingStyles } = useFloating({
|
||||
open: isOpen,
|
||||
placement: 'bottom-start',
|
||||
placement,
|
||||
onOpenChange: setIsOpen,
|
||||
middleware,
|
||||
whileElementsMounted: autoUpdate,
|
||||
|
|
|
|||
|
|
@ -1,20 +1,12 @@
|
|||
import { css } from '@emotion/css';
|
||||
import {
|
||||
autoUpdate,
|
||||
flip,
|
||||
offset,
|
||||
shift,
|
||||
useClick,
|
||||
useDismiss,
|
||||
useFloating,
|
||||
useInteractions,
|
||||
} from '@floating-ui/react';
|
||||
import { autoUpdate, offset, useClick, useDismiss, useFloating, useInteractions } from '@floating-ui/react';
|
||||
import { FocusScope } from '@react-aria/focus';
|
||||
import { memo, HTMLAttributes, useState } from 'react';
|
||||
|
||||
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
||||
|
||||
import { useStyles2 } from '../../themes/ThemeContext';
|
||||
import { getPositioningMiddleware } from '../../utils/floating';
|
||||
import { Menu } from '../Menu/Menu';
|
||||
import { MenuItem } from '../Menu/MenuItem';
|
||||
import { ToolbarButton, ToolbarButtonVariant } from '../ToolbarButton/ToolbarButton';
|
||||
|
|
@ -39,22 +31,14 @@ const ButtonSelectComponent = <T,>(props: Props<T>) => {
|
|||
const { className, options, value, onChange, narrow, variant, ...restProps } = props;
|
||||
const styles = useStyles2(getStyles);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const placement = 'bottom-end';
|
||||
|
||||
// the order of middleware is important!
|
||||
const middleware = [
|
||||
offset(0),
|
||||
flip({
|
||||
fallbackAxisSideDirection: 'end',
|
||||
// see https://floating-ui.com/docs/flip#combining-with-shift
|
||||
crossAxis: false,
|
||||
boundary: document.body,
|
||||
}),
|
||||
shift(),
|
||||
];
|
||||
const middleware = [offset(0), ...getPositioningMiddleware(placement)];
|
||||
|
||||
const { context, refs, floatingStyles } = useFloating({
|
||||
open: isOpen,
|
||||
placement: 'bottom-end',
|
||||
placement,
|
||||
onOpenChange: setIsOpen,
|
||||
middleware,
|
||||
whileElementsMounted: autoUpdate,
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@ import { css } from '@emotion/css';
|
|||
import {
|
||||
FloatingFocusManager,
|
||||
autoUpdate,
|
||||
flip,
|
||||
offset as floatingUIOffset,
|
||||
shift,
|
||||
useClick,
|
||||
useDismiss,
|
||||
useFloating,
|
||||
|
|
@ -17,6 +15,7 @@ import { CSSTransition } from 'react-transition-group';
|
|||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
|
||||
import { useStyles2 } from '../../themes/ThemeContext';
|
||||
import { getPositioningMiddleware } from '../../utils/floating';
|
||||
import { renderOrCallToRender } from '../../utils/reactUtils';
|
||||
import { getPlacement } from '../../utils/tooltipUtils';
|
||||
import { Portal } from '../Portal/Portal';
|
||||
|
|
@ -34,6 +33,7 @@ export interface Props {
|
|||
export const Dropdown = React.memo(({ children, overlay, placement, offset, onVisibleChange }: Props) => {
|
||||
const [show, setShow] = useState(false);
|
||||
const transitionRef = useRef(null);
|
||||
const floatingUIPlacement = getPlacement(placement);
|
||||
|
||||
const handleOpenChange = useCallback(
|
||||
(newState: boolean) => {
|
||||
|
|
@ -49,18 +49,12 @@ export const Dropdown = React.memo(({ children, overlay, placement, offset, onVi
|
|||
mainAxis: offset?.[0] ?? 8,
|
||||
crossAxis: offset?.[1] ?? 0,
|
||||
}),
|
||||
flip({
|
||||
fallbackAxisSideDirection: 'end',
|
||||
// see https://floating-ui.com/docs/flip#combining-with-shift
|
||||
crossAxis: false,
|
||||
boundary: document.body,
|
||||
}),
|
||||
shift(),
|
||||
...getPositioningMiddleware(floatingUIPlacement),
|
||||
];
|
||||
|
||||
const { context, refs, floatingStyles } = useFloating({
|
||||
open: show,
|
||||
placement: getPlacement(placement),
|
||||
placement: floatingUIPlacement,
|
||||
onOpenChange: handleOpenChange,
|
||||
middleware,
|
||||
whileElementsMounted: autoUpdate,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { css, cx } from '@emotion/css';
|
||||
import { autoUpdate, flip, offset, shift, Side, useFloating, useTransitionStyles } from '@floating-ui/react';
|
||||
import { autoUpdate, offset, Side, useFloating, useTransitionStyles } from '@floating-ui/react';
|
||||
import { useLayoutEffect } from 'react';
|
||||
import * as React from 'react';
|
||||
|
||||
|
|
@ -7,6 +7,7 @@ import { GrafanaTheme2 } from '@grafana/data';
|
|||
|
||||
import { useStyles2, useTheme2 } from '../../themes/ThemeContext';
|
||||
import { IconName } from '../../types/icon';
|
||||
import { getPositioningMiddleware } from '../../utils/floating';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
import { Portal } from '../Portal/Portal';
|
||||
|
||||
|
|
@ -30,16 +31,7 @@ export function InlineToast({ referenceElement, children, suffixIcon, placement
|
|||
// the order of middleware is important!
|
||||
// `arrow` should almost always be at the end
|
||||
// see https://floating-ui.com/docs/arrow#order
|
||||
const middleware = [
|
||||
offset(8),
|
||||
flip({
|
||||
fallbackAxisSideDirection: 'end',
|
||||
// see https://floating-ui.com/docs/flip#combining-with-shift
|
||||
crossAxis: false,
|
||||
boundary: document.body,
|
||||
}),
|
||||
shift(),
|
||||
];
|
||||
const middleware = [offset(8), ...getPositioningMiddleware(placement)];
|
||||
|
||||
const { context, refs, floatingStyles } = useFloating({
|
||||
open: true,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import { css } from '@emotion/css';
|
||||
import { flip, shift, useDismiss, useFloating, useInteractions } from '@floating-ui/react';
|
||||
import { useDismiss, useFloating, useInteractions } from '@floating-ui/react';
|
||||
import { useMemo, ReactNode } from 'react';
|
||||
|
||||
import { ActionModel, GrafanaTheme2, LinkModel } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import { useStyles2, useTheme2 } from '../../themes/ThemeContext';
|
||||
import { getPositioningMiddleware } from '../../utils/floating';
|
||||
import { Portal } from '../Portal/Portal';
|
||||
import { VizTooltipFooter } from '../VizTooltip/VizTooltipFooter';
|
||||
import { VizTooltipWrapper } from '../VizTooltip/VizTooltipWrapper';
|
||||
|
|
@ -27,17 +28,10 @@ interface Props {
|
|||
export const DataLinksActionsTooltip = ({ links, actions, value, coords, onTooltipClose }: Props) => {
|
||||
const theme = useTheme2();
|
||||
const styles = useStyles2(getStyles);
|
||||
const placement = 'right-start';
|
||||
|
||||
// the order of middleware is important!
|
||||
const middleware = [
|
||||
flip({
|
||||
fallbackAxisSideDirection: 'end',
|
||||
// see https://floating-ui.com/docs/flip#combining-with-shift
|
||||
crossAxis: false,
|
||||
boundary: document.body,
|
||||
}),
|
||||
shift(),
|
||||
];
|
||||
const middleware = getPositioningMiddleware(placement);
|
||||
|
||||
const virtual = useMemo(() => {
|
||||
const { clientX, clientY } = coords;
|
||||
|
|
@ -66,7 +60,7 @@ export const DataLinksActionsTooltip = ({ links, actions, value, coords, onToolt
|
|||
|
||||
const { context, refs, floatingStyles } = useFloating({
|
||||
open: true,
|
||||
placement: 'right-start',
|
||||
placement,
|
||||
onOpenChange: onTooltipClose,
|
||||
middleware,
|
||||
// whileElementsMounted: autoUpdate,
|
||||
|
|
|
|||
|
|
@ -2,11 +2,9 @@ import { css, cx } from '@emotion/css';
|
|||
import {
|
||||
arrow,
|
||||
autoUpdate,
|
||||
flip,
|
||||
FloatingArrow,
|
||||
FloatingFocusManager,
|
||||
offset,
|
||||
shift,
|
||||
useClick,
|
||||
useDismiss,
|
||||
useFloating,
|
||||
|
|
@ -19,6 +17,7 @@ import { GrafanaTheme2 } from '@grafana/data';
|
|||
import { t } from '@grafana/i18n';
|
||||
|
||||
import { useStyles2, useTheme2 } from '../../themes/ThemeContext';
|
||||
import { getPositioningMiddleware } from '../../utils/floating';
|
||||
import { buildTooltipTheme, getPlacement } from '../../utils/tooltipUtils';
|
||||
import { IconButton } from '../IconButton/IconButton';
|
||||
|
||||
|
|
@ -69,19 +68,14 @@ export const Toggletip = memo(
|
|||
const style = styles[theme];
|
||||
const [controlledVisible, setControlledVisible] = useState(show);
|
||||
const isOpen = show ?? controlledVisible;
|
||||
const floatingUIPlacement = getPlacement(placement);
|
||||
|
||||
// the order of middleware is important!
|
||||
// `arrow` should almost always be at the end
|
||||
// see https://floating-ui.com/docs/arrow#order
|
||||
const middleware = [
|
||||
offset(8),
|
||||
flip({
|
||||
fallbackAxisSideDirection: 'end',
|
||||
// see https://floating-ui.com/docs/flip#combining-with-shift
|
||||
crossAxis: false,
|
||||
boundary: document.body,
|
||||
}),
|
||||
shift(),
|
||||
...getPositioningMiddleware(floatingUIPlacement),
|
||||
arrow({
|
||||
element: arrowRef,
|
||||
}),
|
||||
|
|
@ -89,7 +83,7 @@ export const Toggletip = memo(
|
|||
|
||||
const { context, refs, floatingStyles } = useFloating({
|
||||
open: isOpen,
|
||||
placement: getPlacement(placement),
|
||||
placement: floatingUIPlacement,
|
||||
onOpenChange: (open) => {
|
||||
if (show === undefined) {
|
||||
setControlledVisible(open);
|
||||
|
|
|
|||
|
|
@ -1,17 +1,9 @@
|
|||
import {
|
||||
FloatingArrow,
|
||||
arrow,
|
||||
autoUpdate,
|
||||
flip,
|
||||
offset,
|
||||
shift,
|
||||
useFloating,
|
||||
useTransitionStyles,
|
||||
} from '@floating-ui/react';
|
||||
import { FloatingArrow, arrow, autoUpdate, offset, useFloating, useTransitionStyles } from '@floating-ui/react';
|
||||
import { useLayoutEffect, useRef } from 'react';
|
||||
import * as React from 'react';
|
||||
|
||||
import { useTheme2 } from '../../themes/ThemeContext';
|
||||
import { getPositioningMiddleware } from '../../utils/floating';
|
||||
import { getPlacement } from '../../utils/tooltipUtils';
|
||||
import { Portal } from '../Portal/Portal';
|
||||
|
||||
|
|
@ -42,20 +34,12 @@ export function Popover({
|
|||
}: Props) {
|
||||
const theme = useTheme2();
|
||||
const arrowRef = useRef(null);
|
||||
const floatingUIPlacement = getPlacement(placement);
|
||||
|
||||
// the order of middleware is important!
|
||||
// `arrow` should almost always be at the end
|
||||
// see https://floating-ui.com/docs/arrow#order
|
||||
const middleware = [
|
||||
offset(8),
|
||||
flip({
|
||||
fallbackAxisSideDirection: 'end',
|
||||
// see https://floating-ui.com/docs/flip#combining-with-shift
|
||||
crossAxis: false,
|
||||
boundary: document.body,
|
||||
}),
|
||||
shift(),
|
||||
];
|
||||
const middleware = [offset(8), ...getPositioningMiddleware(floatingUIPlacement)];
|
||||
|
||||
if (renderArrow) {
|
||||
middleware.push(
|
||||
|
|
@ -67,7 +51,7 @@ export function Popover({
|
|||
|
||||
const { context, refs, floatingStyles } = useFloating({
|
||||
open: show,
|
||||
placement: getPlacement(placement),
|
||||
placement: floatingUIPlacement,
|
||||
middleware,
|
||||
whileElementsMounted: autoUpdate,
|
||||
strategy: 'fixed',
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
import {
|
||||
arrow,
|
||||
autoUpdate,
|
||||
flip,
|
||||
FloatingArrow,
|
||||
offset,
|
||||
shift,
|
||||
useDismiss,
|
||||
useFloating,
|
||||
useFocus,
|
||||
|
|
@ -18,6 +16,7 @@ import { GrafanaTheme2 } from '@grafana/data';
|
|||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import { useStyles2 } from '../../themes/ThemeContext';
|
||||
import { getPositioningMiddleware } from '../../utils/floating';
|
||||
import { buildTooltipTheme, getPlacement } from '../../utils/tooltipUtils';
|
||||
import { Portal } from '../Portal/Portal';
|
||||
|
||||
|
|
@ -40,19 +39,14 @@ export const Tooltip = forwardRef<HTMLElement, TooltipProps>(
|
|||
const arrowRef = useRef(null);
|
||||
const [controlledVisible, setControlledVisible] = useState(show);
|
||||
const isOpen = show ?? controlledVisible;
|
||||
const floatingUIPlacement = getPlacement(placement);
|
||||
|
||||
// the order of middleware is important!
|
||||
// `arrow` should almost always be at the end
|
||||
// see https://floating-ui.com/docs/arrow#order
|
||||
const middleware = [
|
||||
offset(8),
|
||||
flip({
|
||||
fallbackAxisSideDirection: 'end',
|
||||
// see https://floating-ui.com/docs/flip#combining-with-shift
|
||||
crossAxis: false,
|
||||
boundary: document.body,
|
||||
}),
|
||||
shift(),
|
||||
...getPositioningMiddleware(floatingUIPlacement),
|
||||
arrow({
|
||||
element: arrowRef,
|
||||
}),
|
||||
|
|
@ -60,7 +54,7 @@ export const Tooltip = forwardRef<HTMLElement, TooltipProps>(
|
|||
|
||||
const { context, refs, floatingStyles } = useFloating({
|
||||
open: isOpen,
|
||||
placement: getPlacement(placement),
|
||||
placement: floatingUIPlacement,
|
||||
onOpenChange: setControlledVisible,
|
||||
middleware,
|
||||
whileElementsMounted: autoUpdate,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { SecretFormField } from './components/SecretFormField/SecretFormField';
|
|||
import * as commonOptionsBuilder from './options/builder';
|
||||
import * as styleMixins from './themes/mixins';
|
||||
import * as DOMUtil from './utils/dom';
|
||||
import * as floatingUtils from './utils/floating';
|
||||
import * as ReactUtils from './utils/reactUtils';
|
||||
|
||||
export { Icon } from './components/Icon/Icon';
|
||||
|
|
@ -437,7 +438,7 @@ export { NodeGraphDataFrameFieldNames } from './utils/nodeGraph';
|
|||
export { fuzzyMatch } from './utils/fuzzy';
|
||||
export { logOptions } from './utils/logOptions';
|
||||
|
||||
export { DOMUtil, ReactUtils };
|
||||
export { DOMUtil, ReactUtils, floatingUtils };
|
||||
|
||||
export { ThemeContext } from '@grafana/data';
|
||||
export {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
import { flip, Placement, shift } from '@floating-ui/react';
|
||||
|
||||
export const BOUNDARY_ELEMENT_ID = 'floating-boundary';
|
||||
|
||||
export function getPositioningMiddleware(placement?: Placement) {
|
||||
const middleware = [];
|
||||
|
||||
const flipMiddleware = flip({
|
||||
// Ensure we flip to the perpendicular axis if it doesn't fit
|
||||
// on narrow viewports.
|
||||
crossAxis: 'alignment',
|
||||
fallbackAxisSideDirection: 'end',
|
||||
boundary: document.getElementById(BOUNDARY_ELEMENT_ID) ?? undefined,
|
||||
});
|
||||
const shiftMiddleware = shift();
|
||||
|
||||
// Prioritize flip over shift for edge-aligned placements only.
|
||||
if (placement?.includes('-')) {
|
||||
middleware.push(flipMiddleware, shiftMiddleware);
|
||||
} else {
|
||||
middleware.push(shiftMiddleware, flipMiddleware);
|
||||
}
|
||||
|
||||
return middleware;
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ import { PropsWithChildren, useEffect } from 'react';
|
|||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Trans } from '@grafana/i18n';
|
||||
import { locationSearchToObject, locationService, useScopes } from '@grafana/runtime';
|
||||
import { ErrorBoundaryAlert, getDragStyles, LinkButton, useStyles2 } from '@grafana/ui';
|
||||
import { ErrorBoundaryAlert, floatingUtils, getDragStyles, LinkButton, useStyles2 } from '@grafana/ui';
|
||||
import { useGrafana } from 'app/core/context/GrafanaContext';
|
||||
import { useMediaQueryMinWidth } from 'app/core/hooks/useMediaQueryMinWidth';
|
||||
import store from 'app/core/store';
|
||||
|
|
@ -87,6 +87,7 @@ export function AppChrome({ children }: Props) {
|
|||
// doesn't get re-mounted when chromeless goes from true to false.
|
||||
return (
|
||||
<div
|
||||
id={floatingUtils.BOUNDARY_ELEMENT_ID}
|
||||
className={classNames('main-view', {
|
||||
'main-view--chrome-hidden': state.chromeless,
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import * as React from 'react';
|
|||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { t } from '@grafana/i18n';
|
||||
import { Alert, Icon, Input, LoadingBar, Stack, Text, useStyles2 } from '@grafana/ui';
|
||||
import { Alert, floatingUtils, Icon, Input, LoadingBar, Stack, Text, useStyles2 } from '@grafana/ui';
|
||||
import { useGetFolderQueryFacade } from 'app/api/clients/folder/v1beta1/hooks';
|
||||
import { getStatusFromError } from 'app/core/utils/errors';
|
||||
import { DashboardViewItemWithUIItems, DashboardsTreeItem } from 'app/features/browse-dashboards/types';
|
||||
|
|
@ -150,7 +150,7 @@ export function NestedFolderPicker({
|
|||
flip({
|
||||
// see https://floating-ui.com/docs/flip#combining-with-shift
|
||||
crossAxis: false,
|
||||
boundary: document.body,
|
||||
boundary: document.getElementById(floatingUtils.BOUNDARY_ELEMENT_ID) ?? undefined,
|
||||
}),
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -216,6 +216,7 @@ function getStyles(theme: GrafanaTheme2) {
|
|||
gridTemplateColumns: 'minmax(470px, 1fr) 330px',
|
||||
gridTemplateRows: '1fr',
|
||||
gap: theme.spacing(1),
|
||||
position: 'static',
|
||||
width: '100%',
|
||||
},
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { css } from '@emotion/css';
|
||||
import { autoUpdate, flip, offset, shift, size, useFloating } from '@floating-ui/react';
|
||||
import { autoUpdate, offset, size, useFloating } from '@floating-ui/react';
|
||||
import { useDialog } from '@react-aria/dialog';
|
||||
import { FocusScope } from '@react-aria/focus';
|
||||
import { useOverlay } from '@react-aria/overlays';
|
||||
|
|
@ -13,7 +13,7 @@ import { selectors } from '@grafana/e2e-selectors';
|
|||
import { Trans, t } from '@grafana/i18n';
|
||||
import { reportInteraction, useFavoriteDatasources } from '@grafana/runtime';
|
||||
import { DataQuery, DataSourceJsonData, DataSourceRef } from '@grafana/schema';
|
||||
import { Button, Icon, Input, ModalsController, Portal, ScrollContainer, useStyles2 } from '@grafana/ui';
|
||||
import { Button, floatingUtils, Icon, Input, ModalsController, Portal, ScrollContainer, useStyles2 } from '@grafana/ui';
|
||||
import config from 'app/core/config';
|
||||
import { useKeyNavigationListener } from 'app/features/search/hooks/useSearchKeyboardSelection';
|
||||
import { defaultFileUploadQuery, GrafanaQuery } from 'app/plugins/datasource/grafana/types';
|
||||
|
|
@ -116,6 +116,7 @@ export function DataSourcePicker(props: DataSourcePickerProps) {
|
|||
variables: props.variables,
|
||||
});
|
||||
const favoriteDataSources = useFavoriteDatasources();
|
||||
const placement = 'bottom-start';
|
||||
|
||||
// the order of middleware is important!
|
||||
const middleware = [
|
||||
|
|
@ -128,18 +129,12 @@ export function DataSourcePicker(props: DataSourcePickerProps) {
|
|||
elements.floating.style.minHeight = `${minSize}px`;
|
||||
},
|
||||
}),
|
||||
flip({
|
||||
fallbackStrategy: 'initialPlacement',
|
||||
// see https://floating-ui.com/docs/flip#combining-with-shift
|
||||
crossAxis: false,
|
||||
boundary: document.body,
|
||||
}),
|
||||
shift(),
|
||||
...floatingUtils.getPositioningMiddleware(placement),
|
||||
];
|
||||
|
||||
const { refs, floatingStyles } = useFloating({
|
||||
open: isOpen,
|
||||
placement: 'bottom-start',
|
||||
placement,
|
||||
onOpenChange: setOpen,
|
||||
middleware,
|
||||
whileElementsMounted: autoUpdate,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,18 @@
|
|||
import { css } from '@emotion/css';
|
||||
import { autoUpdate, flip, shift, useFloating } from '@floating-ui/react';
|
||||
import { autoUpdate, useFloating } from '@floating-ui/react';
|
||||
import { FormEvent, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import * as React from 'react';
|
||||
|
||||
import { GrafanaTheme2, VariableSuggestion } from '@grafana/data';
|
||||
import { FieldValidationMessage, Input, Portal, ScrollContainer, TextArea, useTheme2 } from '@grafana/ui';
|
||||
import {
|
||||
FieldValidationMessage,
|
||||
floatingUtils,
|
||||
Input,
|
||||
Portal,
|
||||
ScrollContainer,
|
||||
TextArea,
|
||||
useTheme2,
|
||||
} from '@grafana/ui';
|
||||
import { DataLinkSuggestions } from '@grafana/ui/internal';
|
||||
|
||||
const modulo = (a: number, n: number) => a - n * Math.floor(a / n);
|
||||
|
|
@ -64,6 +72,7 @@ export const SuggestionsInput = ({
|
|||
const [scrollTop, setScrollTop] = useState(0);
|
||||
const [inputHeight, setInputHeight] = useState<number>(0);
|
||||
const [startPos, setStartPos] = useState<number>(0);
|
||||
const placement = 'bottom-start';
|
||||
|
||||
const theme = useTheme2();
|
||||
const styles = getStyles(theme, inputHeight);
|
||||
|
|
@ -75,19 +84,11 @@ export const SuggestionsInput = ({
|
|||
}, [scrollTop]);
|
||||
|
||||
// the order of middleware is important!
|
||||
const middleware = [
|
||||
flip({
|
||||
fallbackAxisSideDirection: 'start',
|
||||
// see https://floating-ui.com/docs/flip#combining-with-shift
|
||||
crossAxis: false,
|
||||
boundary: document.body,
|
||||
}),
|
||||
shift(),
|
||||
];
|
||||
const middleware = floatingUtils.getPositioningMiddleware(placement);
|
||||
|
||||
const { refs, floatingStyles } = useFloating({
|
||||
open: showingSuggestions,
|
||||
placement: 'bottom-start',
|
||||
placement,
|
||||
onOpenChange: setShowingSuggestions,
|
||||
middleware,
|
||||
whileElementsMounted: autoUpdate,
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ describe(`Traces Filters`, () => {
|
|||
{ property: 'client_Browser', filters: [{ count: 100, value: 'test-client' }], operation: 'ne', index: 1 },
|
||||
rerender
|
||||
);
|
||||
});
|
||||
}, 10000);
|
||||
|
||||
it('should delete a trace filter', async () => {
|
||||
let mockQuery = createMockQuery({ azureTraces: { traceTypes: ['customEvents'] } });
|
||||
|
|
|
|||
|
|
@ -1,21 +1,12 @@
|
|||
import { css, cx } from '@emotion/css';
|
||||
import {
|
||||
autoUpdate,
|
||||
flip,
|
||||
safePolygon,
|
||||
shift,
|
||||
useDismiss,
|
||||
useFloating,
|
||||
useHover,
|
||||
useInteractions,
|
||||
} from '@floating-ui/react';
|
||||
import { autoUpdate, safePolygon, useDismiss, useFloating, useHover, useInteractions } from '@floating-ui/react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import * as React from 'react';
|
||||
|
||||
import { DataFrame, Field, formattedValueToString, GrafanaTheme2, LinkModel } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { TimeZone } from '@grafana/schema';
|
||||
import { Portal, UPlotConfigBuilder, useStyles2 } from '@grafana/ui';
|
||||
import { floatingUtils, Portal, UPlotConfigBuilder, useStyles2 } from '@grafana/ui';
|
||||
import { VizTooltipItem } from '@grafana/ui/internal';
|
||||
import { CloseButton } from 'app/core/components/CloseButton/CloseButton';
|
||||
import { ExemplarTooltip } from 'app/features/visualization/data-hover/ExemplarTooltip';
|
||||
|
|
@ -50,21 +41,14 @@ export const ExemplarMarker = ({
|
|||
const styles = useStyles2(getExemplarMarkerStyles, maxWidth);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [isLocked, setIsLocked] = useState(false);
|
||||
const placement = 'bottom';
|
||||
|
||||
// the order of middleware is important!
|
||||
const middleware = [
|
||||
flip({
|
||||
fallbackAxisSideDirection: 'end',
|
||||
// see https://floating-ui.com/docs/flip#combining-with-shift
|
||||
crossAxis: false,
|
||||
boundary: document.body,
|
||||
}),
|
||||
shift(),
|
||||
];
|
||||
const middleware = floatingUtils.getPositioningMiddleware(placement);
|
||||
|
||||
const { context, refs, floatingStyles } = useFloating({
|
||||
open: isOpen,
|
||||
placement: 'bottom',
|
||||
placement,
|
||||
onOpenChange: setIsOpen,
|
||||
middleware,
|
||||
whileElementsMounted: autoUpdate,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { css } from '@emotion/css';
|
||||
import { flip, shift, autoUpdate } from '@floating-ui/dom';
|
||||
import { autoUpdate } from '@floating-ui/dom';
|
||||
import { useFloating } from '@floating-ui/react';
|
||||
import { useState } from 'react';
|
||||
import * as React from 'react';
|
||||
|
|
@ -8,7 +8,7 @@ import { createPortal } from 'react-dom';
|
|||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { TimeZone } from '@grafana/schema';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
import { floatingUtils, useStyles2 } from '@grafana/ui';
|
||||
|
||||
import { AnnotationEditor2 } from './AnnotationEditor2';
|
||||
import { AnnotationTooltip2 } from './AnnotationTooltip2';
|
||||
|
|
@ -37,20 +37,13 @@ export const AnnotationMarker2 = ({
|
|||
portalRoot,
|
||||
}: AnnoBoxProps) => {
|
||||
const styles = useStyles2(getStyles);
|
||||
const placement = 'bottom';
|
||||
|
||||
const [state, setState] = useState(exitWipEdit != null ? STATE_EDITING : STATE_DEFAULT);
|
||||
const { refs, floatingStyles } = useFloating({
|
||||
open: true,
|
||||
placement: 'bottom',
|
||||
middleware: [
|
||||
flip({
|
||||
fallbackAxisSideDirection: 'end',
|
||||
// see https://floating-ui.com/docs/flip#combining-with-shift
|
||||
crossAxis: false,
|
||||
boundary: document.body,
|
||||
}),
|
||||
shift(),
|
||||
],
|
||||
placement,
|
||||
middleware: floatingUtils.getPositioningMiddleware(placement),
|
||||
whileElementsMounted: autoUpdate,
|
||||
strategy: 'fixed',
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue