mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
DataSourcePicker: fix flickering datasource dropdown (#67206)
* fix flickering * refactor onClose/onOpen * do not set value of input, make the placeholder look like the value instead * Show search icon when the dropdown is open --------- Co-authored-by: Ivan Ortega <ivanortegaalba@gmail.com>
This commit is contained in:
parent
926abcf6aa
commit
044d7f61c7
@ -1,6 +1,5 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import { useDialog } from '@react-aria/dialog';
|
import { useDialog } from '@react-aria/dialog';
|
||||||
import { FocusScope } from '@react-aria/focus';
|
|
||||||
import { useOverlay } from '@react-aria/overlays';
|
import { useOverlay } from '@react-aria/overlays';
|
||||||
import React, { useCallback, useRef, useState } from 'react';
|
import React, { useCallback, useRef, useState } from 'react';
|
||||||
import { usePopper } from 'react-popper';
|
import { usePopper } from 'react-popper';
|
||||||
@ -37,6 +36,7 @@ export function DataSourceDropdown(props: DataSourceDropdownProps) {
|
|||||||
const openDropdown = () => {
|
const openDropdown = () => {
|
||||||
reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.OPEN_DROPDOWN });
|
reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.OPEN_DROPDOWN });
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
|
markerElement?.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
const currentDataSourceInstanceSettings = useDatasource(current);
|
const currentDataSourceInstanceSettings = useDatasource(current);
|
||||||
@ -45,13 +45,15 @@ export function DataSourceDropdown(props: DataSourceDropdownProps) {
|
|||||||
placement: 'bottom-start',
|
placement: 'bottom-start',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const onClose = useCallback(() => {
|
||||||
|
setOpen(false);
|
||||||
|
markerElement?.blur();
|
||||||
|
}, [setOpen, markerElement]);
|
||||||
|
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
const { overlayProps, underlayProps } = useOverlay(
|
const { overlayProps, underlayProps } = useOverlay(
|
||||||
{
|
{
|
||||||
onClose: () => {
|
onClose: onClose,
|
||||||
setFilterTerm(undefined);
|
|
||||||
setOpen(false);
|
|
||||||
},
|
|
||||||
isDismissable: true,
|
isDismissable: true,
|
||||||
isOpen,
|
isOpen,
|
||||||
shouldCloseOnInteractOutside: (element) => {
|
shouldCloseOnInteractOutside: (element) => {
|
||||||
@ -66,56 +68,46 @@ export function DataSourceDropdown(props: DataSourceDropdownProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
|
<div tabIndex={0} onFocus={openDropdown} role={'button'} className={styles.trigger} onClick={openDropdown}>
|
||||||
|
<Input
|
||||||
|
className={isOpen ? undefined : styles.input}
|
||||||
|
prefix={
|
||||||
|
filterTerm && isOpen ? (
|
||||||
|
<DataSourceLogoPlaceHolder />
|
||||||
|
) : (
|
||||||
|
<DataSourceLogo dataSource={currentDataSourceInstanceSettings} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
suffix={<Icon name={isOpen ? 'search' : 'angle-down'} />}
|
||||||
|
placeholder={dataSourceLabel(currentDataSourceInstanceSettings)}
|
||||||
|
onFocus={openDropdown}
|
||||||
|
onClick={openDropdown}
|
||||||
|
onChange={(e) => {
|
||||||
|
setFilterTerm(e.currentTarget.value);
|
||||||
|
}}
|
||||||
|
ref={setMarkerElement}
|
||||||
|
></Input>
|
||||||
|
</div>
|
||||||
{isOpen ? (
|
{isOpen ? (
|
||||||
<FocusScope contain autoFocus restoreFocus>
|
<Portal>
|
||||||
<Input
|
<div {...underlayProps} />
|
||||||
prefix={
|
<div ref={ref} {...overlayProps} {...dialogProps}>
|
||||||
filterTerm ? (
|
<PickerContent
|
||||||
<DataSourceLogoPlaceHolder />
|
filterTerm={filterTerm}
|
||||||
) : (
|
onChange={(ds: DataSourceInstanceSettings<DataSourceJsonData>) => {
|
||||||
<DataSourceLogo dataSource={currentDataSourceInstanceSettings} />
|
onClose();
|
||||||
)
|
onChange(ds);
|
||||||
}
|
}}
|
||||||
suffix={<Icon name={filterTerm ? 'search' : 'angle-down'} />}
|
onClose={onClose}
|
||||||
placeholder={dataSourceLabel(currentDataSourceInstanceSettings)}
|
current={currentDataSourceInstanceSettings}
|
||||||
onChange={(e) => {
|
style={popper.styles.popper}
|
||||||
setFilterTerm(e.currentTarget.value);
|
ref={setSelectorElement}
|
||||||
}}
|
{...restProps}
|
||||||
ref={setMarkerElement}
|
onDismiss={onClose}
|
||||||
></Input>
|
></PickerContent>
|
||||||
<Portal>
|
</div>
|
||||||
<div {...underlayProps} />
|
</Portal>
|
||||||
<div ref={ref} {...overlayProps} {...dialogProps}>
|
) : null}
|
||||||
<PickerContent
|
|
||||||
filterTerm={filterTerm}
|
|
||||||
onChange={(ds: DataSourceInstanceSettings<DataSourceJsonData>) => {
|
|
||||||
setFilterTerm(undefined);
|
|
||||||
setOpen(false);
|
|
||||||
onChange(ds);
|
|
||||||
}}
|
|
||||||
onClose={() => {
|
|
||||||
setOpen(false);
|
|
||||||
}}
|
|
||||||
current={currentDataSourceInstanceSettings}
|
|
||||||
style={popper.styles.popper}
|
|
||||||
ref={setSelectorElement}
|
|
||||||
{...restProps}
|
|
||||||
onDismiss={() => {}}
|
|
||||||
></PickerContent>
|
|
||||||
</div>
|
|
||||||
</Portal>
|
|
||||||
</FocusScope>
|
|
||||||
) : (
|
|
||||||
<div className={styles.trigger} onClick={openDropdown}>
|
|
||||||
<Input
|
|
||||||
className={styles.input}
|
|
||||||
prefix={<DataSourceLogo dataSource={currentDataSourceInstanceSettings} />}
|
|
||||||
suffix={<Icon name="angle-down" />}
|
|
||||||
value={dataSourceLabel(currentDataSourceInstanceSettings)}
|
|
||||||
onFocus={openDropdown}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -132,6 +124,9 @@ function getStylesDropdown(theme: GrafanaTheme2) {
|
|||||||
input {
|
input {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
input::placeholder {
|
||||||
|
color: ${theme.colors.text.primary};
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user