Commit 56652ff1 authored by Andrey Azov's avatar Andrey Azov
Browse files

Enable click handling, as well as hover, on QuestionButton

parent 5f3b1ec6
Pipeline #196197 passed with stages
in 4 minutes and 29 seconds
......@@ -13,6 +13,7 @@
align-items: center;
margin-bottom: 0.5em;
margin-left: -22px;
user-select: none;
}
.selectedAssembly {
......
......@@ -3,6 +3,8 @@
.questionButton {
position: relative;
display: inline-block;
user-select: none;
cursor: pointer;
padding: 2px;
font-size: 0;
......
/**
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { render, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import QuestionButton from './QuestionButton';
import { TOOLTIP_TIMEOUT } from 'src/shared/components/tooltip/tooltip-constants';
describe('<QuestionButton />', () => {
const helpMessage = 'I am a helpful message that will appear in the tooltip';
const helpText = <span>{helpMessage}</span>;
beforeAll(() => {
jest.useFakeTimers();
});
describe('on hover', () => {
it('shows the tooltip after a delay', async () => {
const { container, queryByText } = render(
<QuestionButton helpText={helpText} />
);
const questionButton = container.querySelector(
'.questionButton'
) as HTMLElement;
userEvent.hover(questionButton);
expect(questionButton.querySelector('.pointerBox')).toBeFalsy();
act(() => {
jest.advanceTimersByTime(TOOLTIP_TIMEOUT + 10);
});
expect(queryByText(helpMessage)).toBeTruthy();
});
});
describe('on click', () => {
it('toggles the tooltip', () => {
const { container, queryByText } = render(
<QuestionButton helpText={helpText} />
);
const questionButton = container.querySelector(
'.questionButton'
) as HTMLElement;
userEvent.click(questionButton);
act(() => {
// give the Tooltip component a little time to complete its async tasks
jest.advanceTimersByTime(10);
});
expect(queryByText(helpMessage)).toBeTruthy();
// clicking again to hide the tooltip
userEvent.click(questionButton);
expect(queryByText(helpMessage)).toBeFalsy();
});
it('takes precedence over hover', () => {
const { container, queryByText } = render(
<QuestionButton helpText={helpText} />
);
const questionButton = container.querySelector(
'.questionButton'
) as HTMLElement;
userEvent.hover(questionButton); // would start the timer
userEvent.click(questionButton); // would clear the timer and toggle the state to show the tooltip
act(() => {
// give the Tooltip component a little time to complete its async tasks
jest.advanceTimersByTime(10);
});
expect(queryByText(helpMessage)).toBeTruthy();
});
});
});
......@@ -19,6 +19,8 @@ import classNames from 'classnames';
import useHover from 'src/shared/hooks/useHover';
import { TOOLTIP_TIMEOUT } from 'src/shared/components/tooltip/tooltip-constants';
import Tooltip from 'src/shared/components/tooltip/Tooltip';
import { ReactComponent as QuestionIcon } from './question_circle.svg';
......@@ -39,15 +41,33 @@ type Props = {
const QuestionButton = (props: Props) => {
const [hoverRef, isHovered] = useHover<HTMLDivElement>();
const [shouldShowTooltip, setShouldShowTooltip] = useState(isHovered);
let timeoutId: number | null = null;
useEffect(() => {
setShouldShowTooltip(isHovered);
if (isHovered) {
timeoutId = window.setTimeout(() => {
setShouldShowTooltip(isHovered);
}, TOOLTIP_TIMEOUT);
}
return () => {
timeoutId && clearTimeout(timeoutId);
};
}, [isHovered]);
const handleClick = () => {
timeoutId && clearTimeout(timeoutId); // overrides the timer started by hover
timeoutId = null;
setShouldShowTooltip(!shouldShowTooltip);
};
const hideTooltip = () => {
// tooltip will detect when user starts scrolling
// and will send a signal to the parent component so that it can be removed
setShouldShowTooltip(false);
setTimeout(() => {
// bump this to the next event loop to give the click event time to register and call the click handler
shouldShowTooltip && setShouldShowTooltip(false);
}, 0);
};
const className = classNames(
......@@ -59,13 +79,14 @@ const QuestionButton = (props: Props) => {
);
return (
<div ref={hoverRef} className={className}>
<div ref={hoverRef} className={className} onClick={handleClick}>
<QuestionIcon />
{shouldShowTooltip && (
<Tooltip
anchor={hoverRef.current}
autoAdjust={true}
onClose={hideTooltip}
delay={0}
>
{props.helpText}
</Tooltip>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment