Skip to content
Closed
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
1 change: 1 addition & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
- `DropdownMenuV2`: do not collapse suffix width ([#57238](https://github.com/WordPress/gutenberg/pull/57238)).
- `DateTimePicker`: Adjustment of the dot position on DayButton and expansion of the button area. ([#55502](https://github.com/WordPress/gutenberg/pull/55502)).
- `Modal`: Improve application of body class names ([#55430](https://github.com/WordPress/gutenberg/pull/55430)).
- `Tooltip`: add `hideOnBlur` prop ([#57204](https://github.com/WordPress/gutenberg/pull/57204)).

### Experimental

Expand Down
9 changes: 9 additions & 0 deletions packages/components/src/tooltip/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ The amount of time in milliseconds to wait before showing the tooltip.
- Required: No
- Default: `700`

#### `hideOnBlur`: `boolean`

By default, the tooltip will close when interacting with other elements in the same `window`. This means that the tooltip will stay open when the whole `window` loses focus — for example, this happens when the whole browser loses keyboard focus, or even when moving focus to/from an iframe.

This flag, when set to `true`, will force the tooltip to always hide when the anchor is blurred.

- Required: No
- Default: `false`

#### `hideOnClick`: `boolean`

Option to hide the tooltip when the anchor is clicked.
Expand Down
5 changes: 4 additions & 1 deletion packages/components/src/tooltip/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ function Tooltip( props: TooltipProps ) {
children,
delay = TOOLTIP_DELAY,
hideOnClick = true,
hideOnBlur = false,
placement,
position,
shortcut,
Expand Down Expand Up @@ -66,12 +67,14 @@ function Tooltip( props: TooltipProps ) {

const tooltipStore = Ariakit.useTooltipStore( {
placement: computedPlacement,
timeout: delay,
showTimeout: delay,
hideTimeout: 0,
Comment on lines +70 to +71
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks closer to what the Tooltip's delay prop is described as

} );

return (
<>
<Ariakit.TooltipAnchor
onBlur={ hideOnBlur ? tooltipStore.hide : undefined }
onClick={ hideOnClick ? tooltipStore.hide : undefined }
store={ tooltipStore }
render={ isOnlyChild ? children : undefined }
Expand Down
33 changes: 25 additions & 8 deletions packages/components/src/tooltip/test/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,35 +50,52 @@ describe( 'Tooltip', () => {
).not.toBeInTheDocument();
} );

it( 'should render the tooltip when focusing on the tooltip anchor via tab', async () => {
it( 'should show the tooltip when the tooltip anchor receives focus, and hide it when the anchor loses focus when the hideOnBlur prop is `true`', async () => {
const user = userEvent.setup();

render( <Tooltip { ...props } /> );
render( <Tooltip { ...props } hideOnBlur /> );

const tooltipAnchor = screen.getByRole( 'button', { name: /Button/i } );

await user.tab();

expect(
screen.getByRole( 'button', { name: /Button/i } )
).toHaveFocus();
expect( tooltipAnchor ).toHaveFocus();

expect(
await screen.findByRole( 'tooltip', { name: /tooltip text/i } )
).toBeVisible();

await cleanupTooltip( user );

expect( tooltipAnchor ).not.toHaveFocus();

expect(
screen.queryByRole( 'tooltip', { name: /tooltip text/i } )
).not.toBeInTheDocument();
} );

it( 'should render the tooltip when the tooltip anchor is hovered', async () => {
it( 'should show the tooltip when the tooltip anchor is hovered, and hide it when the anchor is not hovered anymore', async () => {
const user = userEvent.setup();

render( <Tooltip { ...props } /> );
render(
<>
<Tooltip { ...props } />
<button>Hover me</button>
</>
);

await user.hover( screen.getByRole( 'button', { name: /Button/i } ) );

expect(
await screen.findByRole( 'tooltip', { name: /tooltip text/i } )
).toBeVisible();

await user.hover( screen.getByRole( 'button', { name: /Hover me/i } ) );

expect(
screen.queryByRole( 'tooltip', { name: /tooltip text/i } )
).not.toBeInTheDocument();

await cleanupTooltip( user );
} );

Expand Down Expand Up @@ -263,7 +280,7 @@ describe( 'Tooltip', () => {
await cleanupTooltip( user );
} );

it( 'esc should close modal even when tooltip is visible', async () => {
it( 'should close a parent Modal even when tooltip is visible when pressing the Escape key', async () => {
const user = userEvent.setup();
const onRequestClose = jest.fn();
render(
Expand Down
11 changes: 11 additions & 0 deletions packages/components/src/tooltip/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ export type TooltipProps = {
* @default true
*/
hideOnClick?: boolean;
/**
* By default, the tooltip will close when interacting with other elements
* in the same `window`. This means that the tooltip will stay open when the
* whole `window` loses focus — for example, this happens when the whole
* browser loses keyboard focus, or even when moving focus to/from an iframe.
* This flag, when set to `true`, will force the tooltip to always hide when
* the anchor is blurred.
*
* @default false
*/
hideOnBlur?: boolean;
/**
* The amount of time in milliseconds to wait before showing the tooltip.
*
Expand Down