mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Chore: replace react-popper
with @floating-ui/react
in DataSourcePicker
(#82528)
* replace react-popper with floating-ui in DataSourcePicker * don't need {force:true}
This commit is contained in:
parent
94f544c9f6
commit
691115da7a
@ -10,7 +10,7 @@ const addDataSource = () => {
|
|||||||
e2e.components.DataSource.Prometheus.configPage.exemplarsAddButton().click();
|
e2e.components.DataSource.Prometheus.configPage.exemplarsAddButton().click();
|
||||||
e2e.components.DataSource.Prometheus.configPage.internalLinkSwitch().check({ force: true });
|
e2e.components.DataSource.Prometheus.configPage.internalLinkSwitch().check({ force: true });
|
||||||
e2e.components.DataSource.Prometheus.configPage.connectionSettings().type('http://prom-url:9090');
|
e2e.components.DataSource.Prometheus.configPage.connectionSettings().type('http://prom-url:9090');
|
||||||
e2e.components.DataSourcePicker.inputV2().click({ force: true }).should('have.focus');
|
e2e.components.DataSourcePicker.inputV2().click().should('have.focus');
|
||||||
|
|
||||||
cy.contains('gdev-tempo').scrollIntoView().should('be.visible').click();
|
cy.contains('gdev-tempo').scrollIntoView().should('be.visible').click();
|
||||||
},
|
},
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
|
import { autoUpdate, flip, offset, shift, size, useFloating } from '@floating-ui/react';
|
||||||
import { useDialog } from '@react-aria/dialog';
|
import { useDialog } from '@react-aria/dialog';
|
||||||
import { FocusScope } from '@react-aria/focus';
|
import { FocusScope } from '@react-aria/focus';
|
||||||
import { useOverlay } from '@react-aria/overlays';
|
import { useOverlay } from '@react-aria/overlays';
|
||||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { usePopper } from 'react-popper';
|
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
import { DataSourceInstanceSettings, GrafanaTheme2 } from '@grafana/data';
|
import { DataSourceInstanceSettings, GrafanaTheme2 } from '@grafana/data';
|
||||||
@ -21,7 +21,6 @@ import { useDatasource } from '../../hooks';
|
|||||||
import { DataSourceList } from './DataSourceList';
|
import { DataSourceList } from './DataSourceList';
|
||||||
import { DataSourceLogo, DataSourceLogoPlaceHolder } from './DataSourceLogo';
|
import { DataSourceLogo, DataSourceLogoPlaceHolder } from './DataSourceLogo';
|
||||||
import { DataSourceModal } from './DataSourceModal';
|
import { DataSourceModal } from './DataSourceModal';
|
||||||
import { applyMaxSize, maxSize } from './popperModifiers';
|
|
||||||
import { dataSourceLabel, matchDataSourceWithSearch } from './utils';
|
import { dataSourceLabel, matchDataSourceWithSearch } from './utils';
|
||||||
|
|
||||||
const INTERACTION_EVENT_NAME = 'dashboards_dspicker_clicked';
|
const INTERACTION_EVENT_NAME = 'dashboards_dspicker_clicked';
|
||||||
@ -81,8 +80,6 @@ export function DataSourcePicker(props: DataSourcePickerProps) {
|
|||||||
|
|
||||||
// Used to position the popper correctly and to bring back the focus when navigating from footer to input
|
// Used to position the popper correctly and to bring back the focus when navigating from footer to input
|
||||||
const [markerElement, setMarkerElement] = useState<HTMLInputElement | null>();
|
const [markerElement, setMarkerElement] = useState<HTMLInputElement | null>();
|
||||||
// Used to position the popper correctly
|
|
||||||
const [selectorElement, setSelectorElement] = useState<HTMLDivElement | null>();
|
|
||||||
// Used to move the focus to the footer when tabbing from the input
|
// Used to move the focus to the footer when tabbing from the input
|
||||||
const [footerRef, setFooterRef] = useState<HTMLElement | null>();
|
const [footerRef, setFooterRef] = useState<HTMLElement | null>();
|
||||||
const currentDataSourceInstanceSettings = useDatasource(current);
|
const currentDataSourceInstanceSettings = useDatasource(current);
|
||||||
@ -91,20 +88,43 @@ export function DataSourcePicker(props: DataSourcePickerProps) {
|
|||||||
const prefixIcon =
|
const prefixIcon =
|
||||||
filterTerm && isOpen ? <DataSourceLogoPlaceHolder /> : <DataSourceLogo dataSource={currentValue} />;
|
filterTerm && isOpen ? <DataSourceLogoPlaceHolder /> : <DataSourceLogo dataSource={currentValue} />;
|
||||||
|
|
||||||
const popper = usePopper(markerElement, selectorElement, {
|
// the order of middleware is important!
|
||||||
placement: 'bottom-start',
|
const middleware = [
|
||||||
modifiers: [
|
offset(4),
|
||||||
{
|
size({
|
||||||
name: 'offset',
|
apply({ availableHeight, elements }) {
|
||||||
options: {
|
const margin = 20;
|
||||||
offset: [0, 4],
|
const minSize = 200;
|
||||||
},
|
elements.floating.style.maxHeight = `${Math.max(minSize, availableHeight - margin)}px`;
|
||||||
|
elements.floating.style.minHeight = `${minSize}px`;
|
||||||
},
|
},
|
||||||
maxSize,
|
}),
|
||||||
applyMaxSize,
|
flip({
|
||||||
],
|
fallbackStrategy: 'initialPlacement',
|
||||||
|
// see https://floating-ui.com/docs/flip#combining-with-shift
|
||||||
|
crossAxis: false,
|
||||||
|
boundary: document.body,
|
||||||
|
}),
|
||||||
|
shift(),
|
||||||
|
];
|
||||||
|
|
||||||
|
const { refs, floatingStyles } = useFloating({
|
||||||
|
open: isOpen,
|
||||||
|
placement: 'bottom-start',
|
||||||
|
onOpenChange: setOpen,
|
||||||
|
middleware,
|
||||||
|
whileElementsMounted: autoUpdate,
|
||||||
|
strategy: 'fixed',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleReference = useCallback(
|
||||||
|
(element: HTMLInputElement | null) => {
|
||||||
|
refs.setReference(element);
|
||||||
|
setMarkerElement(element);
|
||||||
|
},
|
||||||
|
[refs]
|
||||||
|
);
|
||||||
|
|
||||||
const onClose = useCallback(() => {
|
const onClose = useCallback(() => {
|
||||||
setFilterTerm('');
|
setFilterTerm('');
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
@ -215,7 +235,7 @@ export function DataSourcePicker(props: DataSourcePickerProps) {
|
|||||||
openDropdown();
|
openDropdown();
|
||||||
setFilterTerm(e.currentTarget.value);
|
setFilterTerm(e.currentTarget.value);
|
||||||
}}
|
}}
|
||||||
ref={setMarkerElement}
|
ref={handleReference}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
></Input>
|
></Input>
|
||||||
</div>
|
</div>
|
||||||
@ -225,9 +245,8 @@ export function DataSourcePicker(props: DataSourcePickerProps) {
|
|||||||
<div ref={ref} {...overlayProps} {...dialogProps}>
|
<div ref={ref} {...overlayProps} {...dialogProps}>
|
||||||
<PickerContent
|
<PickerContent
|
||||||
{...restProps}
|
{...restProps}
|
||||||
{...popper.attributes.popper}
|
style={floatingStyles}
|
||||||
style={popper.styles.popper}
|
ref={refs.setFloating}
|
||||||
ref={setSelectorElement}
|
|
||||||
footerRef={setFooterRef}
|
footerRef={setFooterRef}
|
||||||
current={currentValue}
|
current={currentValue}
|
||||||
filterTerm={filterTerm}
|
filterTerm={filterTerm}
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
import { detectOverflow, Modifier, ModifierArguments } from '@popperjs/core';
|
|
||||||
|
|
||||||
const MODAL_MARGIN = 20;
|
|
||||||
const FLIP_THRESHOLD = 200;
|
|
||||||
|
|
||||||
export const maxSize: Modifier<'maxSize', {}> = {
|
|
||||||
name: 'maxSize',
|
|
||||||
enabled: true,
|
|
||||||
phase: 'main',
|
|
||||||
requires: ['offset', 'preventOverflow', 'flip'],
|
|
||||||
fn({ state, name, options }: ModifierArguments<{}>) {
|
|
||||||
const overflow = detectOverflow(state, options);
|
|
||||||
const { x, y } = state.modifiersData.preventOverflow || { x: 0, y: 0 };
|
|
||||||
const { width: contentW, height: contentH } = state.rects.popper;
|
|
||||||
const { width: triggerW } = state.rects.reference;
|
|
||||||
const [basePlacement] = state.placement.split('-');
|
|
||||||
|
|
||||||
const widthProp = basePlacement === 'left' ? 'left' : 'right';
|
|
||||||
const heightProp = basePlacement === 'top' ? 'top' : 'bottom';
|
|
||||||
|
|
||||||
state.modifiersData[name] = {
|
|
||||||
maxWidth: contentW - overflow[widthProp] - x,
|
|
||||||
maxHeight: contentH - overflow[heightProp] - y,
|
|
||||||
minWidth: triggerW,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const applyMaxSize: Modifier<'applyMaxSize', {}> = {
|
|
||||||
name: 'applyMaxSize',
|
|
||||||
enabled: true,
|
|
||||||
phase: 'beforeWrite',
|
|
||||||
requires: ['maxSize'],
|
|
||||||
fn({ state }: ModifierArguments<{}>) {
|
|
||||||
const { maxHeight, maxWidth, minWidth } = state.modifiersData.maxSize;
|
|
||||||
|
|
||||||
state.styles.popper.maxHeight ??= `${maxHeight - MODAL_MARGIN}px`;
|
|
||||||
state.styles.popper.minHeight ??= `${FLIP_THRESHOLD}px`;
|
|
||||||
state.styles.popper.maxWidth ??= maxWidth;
|
|
||||||
state.styles.popper.minWidth ??= minWidth;
|
|
||||||
},
|
|
||||||
};
|
|
Loading…
Reference in New Issue
Block a user