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.internalLinkSwitch().check({ force: true });
|
||||
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();
|
||||
},
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { autoUpdate, flip, offset, shift, size, useFloating } from '@floating-ui/react';
|
||||
import { useDialog } from '@react-aria/dialog';
|
||||
import { FocusScope } from '@react-aria/focus';
|
||||
import { useOverlay } from '@react-aria/overlays';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { usePopper } from 'react-popper';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { DataSourceInstanceSettings, GrafanaTheme2 } from '@grafana/data';
|
||||
@ -21,7 +21,6 @@ import { useDatasource } from '../../hooks';
|
||||
import { DataSourceList } from './DataSourceList';
|
||||
import { DataSourceLogo, DataSourceLogoPlaceHolder } from './DataSourceLogo';
|
||||
import { DataSourceModal } from './DataSourceModal';
|
||||
import { applyMaxSize, maxSize } from './popperModifiers';
|
||||
import { dataSourceLabel, matchDataSourceWithSearch } from './utils';
|
||||
|
||||
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
|
||||
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
|
||||
const [footerRef, setFooterRef] = useState<HTMLElement | null>();
|
||||
const currentDataSourceInstanceSettings = useDatasource(current);
|
||||
@ -91,20 +88,43 @@ export function DataSourcePicker(props: DataSourcePickerProps) {
|
||||
const prefixIcon =
|
||||
filterTerm && isOpen ? <DataSourceLogoPlaceHolder /> : <DataSourceLogo dataSource={currentValue} />;
|
||||
|
||||
const popper = usePopper(markerElement, selectorElement, {
|
||||
placement: 'bottom-start',
|
||||
modifiers: [
|
||||
{
|
||||
name: 'offset',
|
||||
options: {
|
||||
offset: [0, 4],
|
||||
},
|
||||
// the order of middleware is important!
|
||||
const middleware = [
|
||||
offset(4),
|
||||
size({
|
||||
apply({ availableHeight, elements }) {
|
||||
const margin = 20;
|
||||
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(() => {
|
||||
setFilterTerm('');
|
||||
setOpen(false);
|
||||
@ -215,7 +235,7 @@ export function DataSourcePicker(props: DataSourcePickerProps) {
|
||||
openDropdown();
|
||||
setFilterTerm(e.currentTarget.value);
|
||||
}}
|
||||
ref={setMarkerElement}
|
||||
ref={handleReference}
|
||||
disabled={disabled}
|
||||
></Input>
|
||||
</div>
|
||||
@ -225,9 +245,8 @@ export function DataSourcePicker(props: DataSourcePickerProps) {
|
||||
<div ref={ref} {...overlayProps} {...dialogProps}>
|
||||
<PickerContent
|
||||
{...restProps}
|
||||
{...popper.attributes.popper}
|
||||
style={popper.styles.popper}
|
||||
ref={setSelectorElement}
|
||||
style={floatingStyles}
|
||||
ref={refs.setFloating}
|
||||
footerRef={setFooterRef}
|
||||
current={currentValue}
|
||||
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