Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/eui/changelogs/upcoming/9626.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
- Updated `EuiToolTip` show animation to opacity-only with a 150ms grace period delay, preventing visual flickering when quickly hovering over multiple tooltip triggers

**Bug fixes**

- Fixed `EuiToolTip` self-hiding when the mouse moves over child elements within the trigger

**Breaking changes**

- Removed `delay` prop and `ToolTipDelay` type from `EuiToolTip` and `EuiIconTip`
- Removed `waitForEuiToolTipVisible` and `waitForEuiToolTipHidden` RTL test helpers; tooltip show/hide is now synchronous so direct assertions can be used instead
Comment thread
weronikaolejniczak marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import {
render,
waitForEuiPopoverOpen,
waitForEuiPopoverClose,
waitForEuiToolTipVisible,
waitForEuiToolTipHidden,
} from '../../test/rtl';

import { CollapsedItemActions } from './collapsed_item_actions';
Expand Down Expand Up @@ -80,7 +78,6 @@ describe('CollapsedItemActions', () => {
expect(getByTestSubject('xyz-link')).toHaveAttribute('href', '#/xyz');
expect(getByTestSubject('xyz-link')).toHaveTextContent('name xyz');
fireEvent.mouseEnter(getByTestSubject('xyz-link'));
await waitForEuiToolTipVisible();
expect(getByText('description xyz')).toBeInTheDocument();

fireEvent.click(getByTestSubject('defaultAction'));
Expand Down Expand Up @@ -229,19 +226,16 @@ describe('CollapsedItemActions', () => {

const actionDifferent = getByTestSubject('different');
fireEvent.mouseOver(actionDifferent);
await waitForEuiToolTipVisible();
const tooltipDifferent = getByRole('tooltip');
expect(tooltipDifferent).toHaveTextContent('different');
expect(actionDifferent).toHaveAttribute('aria-describedby');
expect(actionDifferent.getAttribute('aria-describedby')).toEqual(
tooltipDifferent.id
);
fireEvent.mouseOut(actionDifferent);
await waitForEuiToolTipHidden();

const actionSame = getByTestSubject('same');
fireEvent.mouseOver(actionSame);
await waitForEuiToolTipVisible();
const tooltipSame = getByRole('tooltip');
expect(tooltipSame).toHaveTextContent('same');
expect(actionSame).not.toHaveAttribute('aria-describedby');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ export const CollapsedItemActions = <T extends {}>({
}}
toolTipContent={toolTipContent}
toolTipProps={{
delay: 'long',
// Avoid screen-readers announcing the same text twice
disableScreenReaderOutput:
typeof buttonContent === 'string' &&
Expand Down Expand Up @@ -148,9 +147,7 @@ export const CollapsedItemActions = <T extends {}>({
);

const withTooltip = !actionsDisabled && (
<EuiToolTip content={allActionsTooltip} delay="long">
{popoverButton}
</EuiToolTip>
<EuiToolTip content={allActionsTooltip}>{popoverButton}</EuiToolTip>
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@

import React from 'react';
import { fireEvent } from '@testing-library/react';
import {
render,
waitForEuiToolTipVisible,
waitForEuiToolTipHidden,
} from '../../test/rtl';
import { render } from '../../test/rtl';

import { DefaultItemAction } from './default_item_action';
import {
Expand Down Expand Up @@ -79,7 +75,7 @@ describe('DefaultItemAction', () => {
expect(container.querySelector('.euiButtonEmpty')).toBeInTheDocument();
});

test('props that can be functions', async () => {
test('props that can be functions', () => {
const action: EmptyButtonAction<Item> = {
name: ({ id }) =>
id === 'hello' ? <span>Hello</span> : <span>world</span>,
Expand Down Expand Up @@ -113,17 +109,14 @@ describe('DefaultItemAction', () => {
expect(secondAction).toHaveAttribute('href', '#/world');

fireEvent.mouseOver(firstAction);
await waitForEuiToolTipVisible();
expect(getByText('hello tooltip')).toBeInTheDocument();
fireEvent.mouseOut(firstAction);
await waitForEuiToolTipHidden();

fireEvent.mouseOver(secondAction);
await waitForEuiToolTipVisible();
expect(getByText('goodbye tooltip')).toBeInTheDocument();
});

it('is described by the tooltip via aria-describedby', async () => {
it('is described by the tooltip via aria-describedby', () => {
const actionWithDifferentNameAndDescription: EmptyButtonAction<Item> = {
name: 'same',
description: 'different',
Expand All @@ -141,7 +134,6 @@ describe('DefaultItemAction', () => {

const action = getByTestSubject('different');
fireEvent.mouseOver(action);
await waitForEuiToolTipVisible();
const tooltip = getByRole('tooltip');
expect(tooltip).toHaveTextContent('different');
expect(tooltip).toBeInTheDocument();
Expand All @@ -151,7 +143,7 @@ describe('DefaultItemAction', () => {

// If `name` and `description` are exactly the same
// we don't want screen readers announcing the same text twice
it('has visual-only tooltip when `name` equals `description`', async () => {
it('has visual-only tooltip when `name` equals `description`', () => {
const actionWithEqualNameAndDescription: EmptyButtonAction<Item> = {
name: 'same',
description: 'same',
Expand All @@ -169,7 +161,6 @@ describe('DefaultItemAction', () => {

const action = getByTestSubject('same');
fireEvent.mouseOver(action);
await waitForEuiToolTipVisible();
const tooltip = getByRole('tooltip');
expect(tooltip).toBeInTheDocument();
expect(tooltip).toHaveTextContent('same');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ export const DefaultItemAction = <T extends object>({
const tooltipContent = callWithItemIfFunction(item)(action.description);
const tooltipProps: Omit<EuiToolTipProps, 'position' | 'children'> = {
content: tooltipContent,
delay: 'long',
// Avoid screen-readers announcing the same text twice
disableScreenReaderOutput:
typeof actionContent === 'string' && actionContent === tooltipContent,
Expand Down
5 changes: 2 additions & 3 deletions packages/eui/src/components/basic_table/table_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,8 @@ export type EuiTableColumnNameTooltipProps = {
icon?: IconType;
/** Additional props for EuiIcon */
iconProps?: EuiIconTipProps['iconProps'];
/** Additional props for the EuiToolip */
tooltipProps?: Omit<EuiToolTipProps, 'children' | 'delay' | 'position'> & {
delay?: EuiToolTipProps['delay'];
/** Additional props for the EuiToolTip */
tooltipProps?: Omit<EuiToolTipProps, 'children' | 'position'> & {
position?: EuiToolTipProps['position'];
};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { disableStorybookControls } from '../../../../.storybook/utils';

import { LOKI_SELECTORS } from '../../../../.storybook/loki';
import { EuiSpacer } from '../../spacer';
import { ToolTipDelay } from '../../tool_tip/tool_tip';
import {
EuiButtonGroup,
EuiButtonGroupProps,
Expand Down Expand Up @@ -145,18 +144,14 @@ export const WithTooltips: Story = {
label: 'Standard tooltip',
toolTipContent: 'Hello world',
autoFocus: true, // dev-only usage to showcase tooltip on load
toolTipProps: {
delay: 'none' as ToolTipDelay, // passing a (not-yet) supported value to hackishly force a lower delay for VRT
},
} as EuiButtonGroupOptionProps,
Comment thread
weronikaolejniczak marked this conversation as resolved.
{
id: 'customToolTipProps',
iconType: 'securitySignalDetected',
label: 'Custom tooltip',
toolTipContent: 'Custom tooltip position and delay',
toolTipContent: 'Custom tooltip position',
toolTipProps: {
position: 'right',
delay: 'long',
title: 'Hello world',
},
// Consumers could also opt to hide titles if preferred
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@
import React from 'react';
import { css } from '@emotion/react';
import { fireEvent } from '@testing-library/react';
import {
render,
waitForEuiToolTipHidden,
waitForEuiToolTipVisible,
focusEuiToolTipTrigger,
} from '../../../test/rtl';
import { render, focusEuiToolTipTrigger } from '../../../test/rtl';
import { requiredProps as commonProps } from '../../../test';
import { shouldRenderCustomStyles } from '../../../test/internal';

Expand Down Expand Up @@ -262,19 +257,15 @@ describe('EuiButtonGroup', () => {
/>
);
fireEvent.mouseOver(getByTestSubject('buttonWithTooltip'));
await waitForEuiToolTipVisible();

expect(getByRole('tooltip')).toHaveTextContent('I am a tooltip');

fireEvent.mouseOut(getByTestSubject('buttonWithTooltip'));
await waitForEuiToolTipHidden();

const cleanup = focusEuiToolTipTrigger(
getByTestSubject('buttonWithTooltip')
);
await waitForEuiToolTipVisible();
fireEvent.blur(getByTestSubject('buttonWithTooltip'));
await waitForEuiToolTipHidden();
cleanup();
});

Expand All @@ -299,23 +290,19 @@ describe('EuiButtonGroup', () => {
// NOTE: uses `parentElement` as the hover event is triggered on the tooltip wrapper.
// The button itself doesn't allow mouse events when disabled.
fireEvent.mouseOver(getByTestSubject('buttonWithTooltip').parentElement!);
await waitForEuiToolTipVisible();

expect(await findByRole('tooltip')).toHaveTextContent('I am a tooltip');

fireEvent.mouseOut(getByTestSubject('buttonWithTooltip').parentElement!);
await waitForEuiToolTipHidden();

const cleanup = focusEuiToolTipTrigger(
getByTestSubject('buttonWithTooltip')
);
await waitForEuiToolTipVisible();
fireEvent.blur(getByTestSubject('buttonWithTooltip'));
await waitForEuiToolTipHidden();
cleanup();
});

it('allows customizing the tooltip via `toolTipProps`', async () => {
it('allows customizing the tooltip via `toolTipProps`', () => {
const { getByTestSubject } = render(
<EuiButtonGroup
{...requiredMultiProps}
Expand All @@ -328,15 +315,14 @@ describe('EuiButtonGroup', () => {
toolTipContent: 'I am a tooltip',
toolTipProps: {
position: 'right',
delay: 'regular',

'data-test-subj': 'toolTipTest',
},
},
]}
/>
);
fireEvent.mouseOver(getByTestSubject('buttonWithTooltip'));
await waitForEuiToolTipVisible();

expect(getByTestSubject('toolTipTest')).toHaveAttribute(
'data-position',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { EuiSpacer } from '../../spacer';
import { EuiFlexGroup } from '../../flex';
import { EuiWrappingPopover } from '../../popover';
import { EuiContextMenu } from '../../context_menu';
import { ToolTipDelay } from '../../tool_tip/tool_tip';
import { EuiSplitButton, EuiSplitButtonProps } from './split_button';

const decorators: Meta<EuiSplitButtonProps>['decorators'] = [
Expand Down Expand Up @@ -90,7 +89,6 @@ export const WithTooltip: Story = {
aria-label="Secondary action"
tooltipProps={{
content: 'Tooltip content',
Comment thread
weronikaolejniczak marked this conversation as resolved.
delay: 'none' as ToolTipDelay, // passing a not (yet) supported value to hackishly force a lower delay for VRT
}}
autoFocus={true} // VRT-only workaround to ensure an opened tooltip
/>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@
import React from 'react';
import { fireEvent } from '@testing-library/react';

import {
render,
waitForEuiToolTipHidden,
waitForEuiToolTipVisible,
} from '../../../test/rtl';
import { render } from '../../../test/rtl';
import { shouldRenderCustomStyles } from '../../../test/internal';
import { EuiToolTip } from '../../tool_tip';
import { EuiSplitButton, EuiSplitButtonProps } from './split_button';
Expand Down Expand Up @@ -294,7 +290,7 @@ describe('EuiSplitButton', () => {
consoleErrorSpy.mockRestore();
});

it('renders a tooltip', async () => {
it('renders a tooltip', () => {
const { getByTestSubject } = render(
<EuiSplitButton size="s">
<EuiSplitButton.ActionPrimary
Expand All @@ -315,15 +311,12 @@ describe('EuiSplitButton', () => {
);

fireEvent.mouseOver(getByTestSubject('primary-action'));
await waitForEuiToolTipVisible();

expect(getByTestSubject('primary-action-tooltip')).toBeInTheDocument();

fireEvent.mouseLeave(getByTestSubject('primary-action'));
await waitForEuiToolTipHidden();

fireEvent.mouseOver(getByTestSubject('secondary-action'));
await waitForEuiToolTipVisible();

expect(
getByTestSubject('secondary-action-tooltip')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import React from 'react';
import { fireEvent, waitFor } from '@testing-library/react';
import { render, waitForEuiToolTipVisible } from '../../../../test/rtl';
import { render } from '../../../../test/rtl';
import { shouldRenderCustomStyles } from '../../../../test/internal';
import { requiredProps } from '../../../../test';

Expand All @@ -19,17 +19,17 @@ describe('EuiCollapsedNavButton', () => {
childProps: ['linkProps'],
});

it('renders a tooltip around the icon button', async () => {
it('renders a tooltip around the icon button', () => {
const { baseElement, getByTestSubject } = render(
<EuiCollapsedNavButton {...requiredProps} title="Nav item" />
);

fireEvent.mouseOver(getByTestSubject('euiCollapsedNavButton'));
await waitForEuiToolTipVisible();

expect(baseElement).toMatchSnapshot();
});

it('renders isSelected', async () => {
it('renders isSelected', () => {
const { container } = render(
<EuiCollapsedNavButton title="Nav item" href="#" isSelected={true} />
);
Expand Down
Loading