mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Toggletip: Add support to programmatically close it (#75846)
This commit is contained in:
parent
c869844a78
commit
586c78a636
@ -8,8 +8,9 @@ import { Toggletip } from './Toggletip';
|
|||||||
|
|
||||||
describe('Toggletip', () => {
|
describe('Toggletip', () => {
|
||||||
it('should display toggletip after click on "Click me!" button', async () => {
|
it('should display toggletip after click on "Click me!" button', async () => {
|
||||||
|
const onOpen = jest.fn();
|
||||||
render(
|
render(
|
||||||
<Toggletip placement="auto" content="Tooltip text">
|
<Toggletip placement="auto" content="Tooltip text" onOpen={onOpen}>
|
||||||
<Button type="button" data-testid="myButton">
|
<Button type="button" data-testid="myButton">
|
||||||
Click me!
|
Click me!
|
||||||
</Button>
|
</Button>
|
||||||
@ -20,12 +21,70 @@ describe('Toggletip', () => {
|
|||||||
await userEvent.click(button);
|
await userEvent.click(button);
|
||||||
|
|
||||||
expect(screen.getByTestId('toggletip-content')).toBeInTheDocument();
|
expect(screen.getByTestId('toggletip-content')).toBeInTheDocument();
|
||||||
|
expect(onOpen).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display toggletip if configured as `show=true`', async () => {
|
||||||
|
render(
|
||||||
|
<Toggletip placement="auto" content="Tooltip text" show={true}>
|
||||||
|
<Button type="button" data-testid="myButton">
|
||||||
|
Click me!
|
||||||
|
</Button>
|
||||||
|
</Toggletip>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(await screen.findByTestId('toggletip-content')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not close if configured as `show=true`', async () => {
|
||||||
|
const onClose = jest.fn();
|
||||||
|
render(
|
||||||
|
<Toggletip placement="auto" content="Tooltip text" show={true} onClose={onClose}>
|
||||||
|
<Button type="button" data-testid="myButton">
|
||||||
|
Click me!
|
||||||
|
</Button>
|
||||||
|
</Toggletip>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(await screen.findByTestId('toggletip-content')).toBeInTheDocument();
|
||||||
|
|
||||||
|
// Close button should not close the toggletip
|
||||||
|
const closeButton = screen.getByTestId('toggletip-header-close');
|
||||||
|
expect(closeButton).toBeInTheDocument();
|
||||||
|
await userEvent.click(closeButton);
|
||||||
|
expect(onClose).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
// Escape should not close the toggletip
|
||||||
|
const button = screen.getByTestId('myButton');
|
||||||
|
await userEvent.click(button);
|
||||||
|
await userEvent.keyboard('{escape}');
|
||||||
|
expect(onClose).toHaveBeenCalledTimes(2);
|
||||||
|
|
||||||
|
// Either way, the toggletip should still be visible
|
||||||
|
expect(await screen.findByTestId('toggletip-content')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not open if configured as `show=false`', async () => {
|
||||||
|
const onOpen = jest.fn();
|
||||||
|
render(
|
||||||
|
<Toggletip placement="auto" content="Tooltip text" show={false} onOpen={onOpen}>
|
||||||
|
<Button type="button" data-testid="myButton">
|
||||||
|
Click me!
|
||||||
|
</Button>
|
||||||
|
</Toggletip>
|
||||||
|
);
|
||||||
|
|
||||||
|
const button = screen.getByTestId('myButton');
|
||||||
|
await userEvent.click(button);
|
||||||
|
|
||||||
|
expect(await screen.queryByTestId('toggletip-content')).not.toBeInTheDocument();
|
||||||
|
expect(onOpen).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should close toggletip after click on close button', async () => {
|
it('should close toggletip after click on close button', async () => {
|
||||||
const closeSpy = jest.fn();
|
const onClose = jest.fn();
|
||||||
render(
|
render(
|
||||||
<Toggletip placement="auto" content="Tooltip text" onClose={closeSpy}>
|
<Toggletip placement="auto" content="Tooltip text" onClose={onClose}>
|
||||||
<Button type="button" data-testid="myButton">
|
<Button type="button" data-testid="myButton">
|
||||||
Click me!
|
Click me!
|
||||||
</Button>
|
</Button>
|
||||||
@ -40,13 +99,13 @@ describe('Toggletip', () => {
|
|||||||
expect(closeButton).toBeInTheDocument();
|
expect(closeButton).toBeInTheDocument();
|
||||||
await userEvent.click(closeButton);
|
await userEvent.click(closeButton);
|
||||||
|
|
||||||
expect(closeSpy).toHaveBeenCalledTimes(1);
|
expect(onClose).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should close toggletip after press ESC', async () => {
|
it('should close toggletip after press ESC', async () => {
|
||||||
const closeSpy = jest.fn();
|
const onClose = jest.fn();
|
||||||
render(
|
render(
|
||||||
<Toggletip placement="auto" content="Tooltip text" onClose={closeSpy}>
|
<Toggletip placement="auto" content="Tooltip text" onClose={onClose}>
|
||||||
<Button type="button" data-testid="myButton">
|
<Button type="button" data-testid="myButton">
|
||||||
Click me!
|
Click me!
|
||||||
</Button>
|
</Button>
|
||||||
@ -59,13 +118,13 @@ describe('Toggletip', () => {
|
|||||||
|
|
||||||
await userEvent.keyboard('{escape}');
|
await userEvent.keyboard('{escape}');
|
||||||
|
|
||||||
expect(closeSpy).toHaveBeenCalledTimes(1);
|
expect(onClose).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display the toggletip after press ENTER', async () => {
|
it('should display the toggletip after press ENTER', async () => {
|
||||||
const closeSpy = jest.fn();
|
const onOpen = jest.fn();
|
||||||
render(
|
render(
|
||||||
<Toggletip placement="auto" content="Tooltip text" onClose={closeSpy}>
|
<Toggletip placement="auto" content="Tooltip text" onOpen={onOpen}>
|
||||||
<Button type="button" data-testid="myButton">
|
<Button type="button" data-testid="myButton">
|
||||||
Click me!
|
Click me!
|
||||||
</Button>
|
</Button>
|
||||||
@ -80,15 +139,16 @@ describe('Toggletip', () => {
|
|||||||
await userEvent.keyboard('{enter}');
|
await userEvent.keyboard('{enter}');
|
||||||
|
|
||||||
expect(screen.getByTestId('toggletip-content')).toBeInTheDocument();
|
expect(screen.getByTestId('toggletip-content')).toBeInTheDocument();
|
||||||
|
expect(onOpen).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to focus toggletip content next in DOM order - forwards and backwards', async () => {
|
it('should be able to focus toggletip content next in DOM order - forwards and backwards', async () => {
|
||||||
const closeSpy = jest.fn();
|
const onClose = jest.fn();
|
||||||
const afterInDom = 'Outside of toggletip';
|
const afterInDom = 'Outside of toggletip';
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<>
|
<>
|
||||||
<Toggletip placement="auto" content="Tooltip text" onClose={closeSpy}>
|
<Toggletip placement="auto" content="Tooltip text" onClose={onClose}>
|
||||||
<Button type="button" data-testid="myButton">
|
<Button type="button" data-testid="myButton">
|
||||||
Click me!
|
Click me!
|
||||||
</Button>
|
</Button>
|
||||||
@ -134,9 +194,9 @@ describe('Toggletip', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should restore focus to the button that opened the toggletip when closed from within the toggletip', async () => {
|
it('should restore focus to the button that opened the toggletip when closed from within the toggletip', async () => {
|
||||||
const closeSpy = jest.fn();
|
const onClose = jest.fn();
|
||||||
render(
|
render(
|
||||||
<Toggletip placement="auto" content="Tooltip text" onClose={closeSpy}>
|
<Toggletip placement="auto" content="Tooltip text" onClose={onClose}>
|
||||||
<Button type="button" data-testid="myButton">
|
<Button type="button" data-testid="myButton">
|
||||||
Click me!
|
Click me!
|
||||||
</Button>
|
</Button>
|
||||||
@ -156,12 +216,12 @@ describe('Toggletip', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT restore focus to the button that opened the toggletip when closed from outside the toggletip', async () => {
|
it('should NOT restore focus to the button that opened the toggletip when closed from outside the toggletip', async () => {
|
||||||
const closeSpy = jest.fn();
|
const onClose = jest.fn();
|
||||||
const afterInDom = 'Outside of toggletip';
|
const afterInDom = 'Outside of toggletip';
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<>
|
<>
|
||||||
<Toggletip placement="auto" content="Tooltip text" onClose={closeSpy}>
|
<Toggletip placement="auto" content="Tooltip text" onClose={onClose}>
|
||||||
<Button type="button" data-testid="myButton">
|
<Button type="button" data-testid="myButton">
|
||||||
Click me!
|
Click me!
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -30,6 +30,10 @@ export interface ToggletipProps {
|
|||||||
children: JSX.Element;
|
children: JSX.Element;
|
||||||
/** Determine whether the toggletip should fit its content or not */
|
/** Determine whether the toggletip should fit its content or not */
|
||||||
fitContent?: boolean;
|
fitContent?: boolean;
|
||||||
|
/** Determine whether the toggletip should be shown or not */
|
||||||
|
show?: boolean;
|
||||||
|
/** Callback function to be called when the toggletip is opened */
|
||||||
|
onOpen?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Toggletip = React.memo(
|
export const Toggletip = React.memo(
|
||||||
@ -43,24 +47,31 @@ export const Toggletip = React.memo(
|
|||||||
onClose,
|
onClose,
|
||||||
footer,
|
footer,
|
||||||
fitContent = false,
|
fitContent = false,
|
||||||
|
onOpen,
|
||||||
|
show,
|
||||||
}: ToggletipProps) => {
|
}: ToggletipProps) => {
|
||||||
const styles = useStyles2(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
const style = styles[theme];
|
const style = styles[theme];
|
||||||
const contentRef = useRef(null);
|
const contentRef = useRef(null);
|
||||||
const [controlledVisible, setControlledVisible] = React.useState(false);
|
const [controlledVisible, setControlledVisible] = React.useState(show);
|
||||||
|
|
||||||
const { getArrowProps, getTooltipProps, setTooltipRef, setTriggerRef, visible, update, tooltipRef, triggerRef } =
|
const { getArrowProps, getTooltipProps, setTooltipRef, setTriggerRef, visible, update, tooltipRef, triggerRef } =
|
||||||
usePopperTooltip(
|
usePopperTooltip(
|
||||||
{
|
{
|
||||||
visible: controlledVisible,
|
visible: show ?? controlledVisible,
|
||||||
placement: placement,
|
placement: placement,
|
||||||
interactive: true,
|
interactive: true,
|
||||||
offset: [0, 8],
|
offset: [0, 8],
|
||||||
|
// If show is undefined, the toggletip will be shown on click
|
||||||
trigger: 'click',
|
trigger: 'click',
|
||||||
onVisibleChange: (value: boolean) => {
|
onVisibleChange: (visible: boolean) => {
|
||||||
setControlledVisible(value);
|
if (show === undefined) {
|
||||||
if (!value) {
|
setControlledVisible(visible);
|
||||||
|
}
|
||||||
|
if (!visible) {
|
||||||
onClose?.();
|
onClose?.();
|
||||||
|
} else {
|
||||||
|
onOpen?.();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user