Chore: remove react-popper-tooltip in favour of @floating-ui/react (#79465)

* use floating-ui instead of react-popper-tooltip in Tooltip

* remove useTheme2 usage

* remove escape handling logic in favour of useDismiss

* don't need this useEffect anymore

* convert Toggletip to use floating-ui

* use explicit version

* convert OperationInfoButton to use Toggletip

* convert nestedFolderPicker to use floating-ui

* convert Dropdown to use floating-ui and remove react-popper-tooltip

* fix Modal/Tooltip tests

* revert to old toggletip behaviour

* revert OperationInfoButton to not use Toggletip

* add mock for requestAnimationFrame

* remove requestAnimationFrame mock

* remove fakeTimers where they're not used

* use floating-ui in ButtonSelect

* Fix filters unit tests

* only attach description if label is different

* use 'fixed' strategy for Toggletip

* use stroke and strokeWidth

* set move: false to only show the tooltip if a hover event occurs

* update type for onClose
This commit is contained in:
Ashley Harrison
2024-01-03 12:42:26 +00:00
committed by GitHub
parent 9c9a055c3e
commit 9de79fb5e9
19 changed files with 429 additions and 392 deletions

View File

@@ -57,7 +57,7 @@ export function AppChromeMenu({}: Props) {
classNames={animationStyles.overlay}
timeout={{ enter: animationSpeed, exit: 0 }}
>
<FocusScope contain autoFocus>
<FocusScope contain autoFocus restoreFocus>
<MegaMenu className={styles.menu} onClose={onClose} ref={ref} {...overlayProps} {...dialogProps} />
</FocusScope>
</CSSTransition>

View File

@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { autoUpdate, flip, useClick, useDismiss, useFloating, useInteractions } from '@floating-ui/react';
import React, { useCallback, useId, useMemo, useState } from 'react';
import { usePopperTooltip } from 'react-popper-tooltip';
import { useAsync } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
@@ -85,13 +85,19 @@ export function NestedFolderPicker({
const rootCollection = useSelector(rootItemsSelector);
const childrenCollections = useSelector(childrenByParentUIDSelector);
const { getTooltipProps, setTooltipRef, setTriggerRef, visible, triggerRef } = usePopperTooltip({
visible: overlayOpen,
// the order of middleware is important!
const middleware = [
flip({
// see https://floating-ui.com/docs/flip#combining-with-shift
crossAxis: false,
boundary: document.body,
}),
];
const { context, refs, floatingStyles, elements } = useFloating({
open: overlayOpen,
placement: 'bottom',
interactive: true,
offset: [0, 0],
trigger: 'click',
onVisibleChange: (value: boolean) => {
onOpenChange: (value) => {
// ensure state is clean on opening the overlay
if (value) {
setSearch('');
@@ -99,8 +105,15 @@ export function NestedFolderPicker({
}
setOverlayOpen(value);
},
middleware,
whileElementsMounted: autoUpdate,
});
const click = useClick(context);
const dismiss = useDismiss(context);
const { getReferenceProps, getFloatingProps } = useInteractions([dismiss, click]);
const handleFolderExpand = useCallback(
async (uid: string, newOpenState: boolean) => {
setFolderOpenState((old) => ({ ...old, [uid]: newOpenState }));
@@ -209,7 +222,7 @@ export function NestedFolderPicker({
handleFolderExpand,
idPrefix: overlayId,
search,
visible,
visible: overlayOpen,
});
let label = selectedFolder.data?.title;
@@ -217,14 +230,14 @@ export function NestedFolderPicker({
label = 'Dashboards';
}
if (!visible) {
if (!overlayOpen) {
return (
<Trigger
label={label}
invalid={invalid}
isLoading={selectedFolder.isLoading}
autoFocus={autoFocusButton}
ref={setTriggerRef}
ref={refs.setReference}
aria-label={
label
? t('browse-dashboards.folder-picker.accessible-label', 'Select folder: {{ label }} currently selected', {
@@ -232,6 +245,7 @@ export function NestedFolderPicker({
})
: undefined
}
{...getReferenceProps()}
/>
);
}
@@ -239,14 +253,13 @@ export function NestedFolderPicker({
return (
<>
<Input
ref={setTriggerRef}
ref={refs.setReference}
autoFocus
prefix={label ? <Icon name="folder" /> : null}
placeholder={label ?? t('browse-dashboards.folder-picker.search-placeholder', 'Search folders')}
value={search}
invalid={invalid}
className={styles.search}
onKeyDown={handleKeyDown}
onChange={(e) => setSearch(e.currentTarget.value)}
aria-autocomplete="list"
aria-expanded
@@ -256,16 +269,18 @@ export function NestedFolderPicker({
aria-activedescendant={getDOMId(overlayId, flatTree[focusedItemIndex]?.item.uid)}
role="combobox"
suffix={<Icon name="search" />}
{...getReferenceProps()}
onKeyDown={handleKeyDown}
/>
<fieldset
ref={setTooltipRef}
ref={refs.setFloating}
id={overlayId}
{...getTooltipProps({
className: styles.tableWrapper,
style: {
width: triggerRef?.clientWidth,
},
})}
className={styles.tableWrapper}
style={{
...floatingStyles,
width: elements.domReference?.clientWidth,
}}
{...getFloatingProps()}
>
{error ? (
<Alert