Skip to content

Commit

Permalink
fix(tooltip): ensure esc closes tooltip, avoid bubbling beyond the bo…
Browse files Browse the repository at this point in the history
…dy (#10220)

Co-authored-by: Abbey Hart <[email protected]>
  • Loading branch information
tay1orjones and abbeyhrt committed Dec 3, 2021
1 parent 505af19 commit 48cec74
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 29 deletions.
17 changes: 17 additions & 0 deletions packages/react/src/components/Modal/Modal-story.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
text,
withKnobs,
} from '@storybook/addon-knobs';
import { settings } from 'carbon-components';
import Modal from '../Modal';
import Button from '../Button';
import Select from '../Select';
Expand All @@ -24,6 +25,9 @@ import Dropdown from '../Dropdown';
import SelectItem from '../SelectItem';
import TextInput from '../TextInput';
import mdx from './Modal.mdx';
import Tooltip from '../Tooltip';

const { prefix } = settings;

const sizes = {
'Extra small (xs)': 'xs',
Expand Down Expand Up @@ -319,6 +323,19 @@ export const WithStateManager = () => {
Custom domains direct requests for your apps in this Cloud Foundry
organization to a URL that you own. A custom domain can be a shared
domain, a shared subdomain, or a shared domain and host.
<Tooltip tooltipBodyId="tooltip-body">
<p id="tooltip-body">
This is some tooltip text. This box shows the maximum amount of
text that should appear inside. If more room is needed please
use a modal instead.
</p>
<div className={`${prefix}--tooltip__footer`}>
<a href="/" className={`${prefix}--link`}>
Learn More
</a>
<Button size="small">Create</Button>
</div>
</Tooltip>
</p>
<TextInput
data-modal-primary-focus
Expand Down
6 changes: 0 additions & 6 deletions packages/react/src/components/Tooltip/Tooltip-story.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,6 @@ export const DefaultBottom = () => (
that should appear inside. If more room is needed please use a modal
instead.
</p>
<div className={`${prefix}--tooltip__footer`}>
<a href="/" className={`${prefix}--link`}>
Learn More
</a>
<Button size="small">Create</Button>
</div>
</Tooltip>
</div>
);
Expand Down
50 changes: 36 additions & 14 deletions packages/react/src/components/Tooltip/Tooltip-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,22 +194,44 @@ describe('Tooltip', () => {
// Enzyme doesn't seem to allow state() in a forwardRef-wrapped class component
expect(rootWrapper.find('Tooltip').instance().state.open).toEqual(false);
});
});

it('escape key keyDown should not bubble outside the tooltip', () => {
const onKeyDown = jest.fn();
render(
<>
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
<div onKeyDown={onKeyDown}>
<Tooltip triggerText="Tooltip" />
</div>
</>
);
it('escape key keyDown should not bubble outside the tooltip', () => {
const onKeyDown = jest.fn();
render(
<>
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
<div onKeyDown={onKeyDown}>
<Tooltip triggerText="Tooltip" />
</div>
</>
);

userEvent.click(screen.getAllByRole('button')[0]);
userEvent.keyboard('{esc}');

expect(onKeyDown).not.toHaveBeenCalled();
});

userEvent.click(screen.getAllByRole('button')[0]);
userEvent.keyboard('{esc}');
it('should close the tooltip when escape key is pressed', () => {
render(
<Tooltip triggerText="trigger text" tooltipBodyId="tooltip-body">
<p id="tooltip-body">tooltip body</p>
</Tooltip>
);

expect(screen.queryByText('trigger text')).toBeInTheDocument();
expect(screen.queryByText('tooltip body')).not.toBeInTheDocument();

const triggerButton = screen.getByRole('button');
userEvent.click(triggerButton);
// I am unsure why, but the trigger must be clicked a second time for the tooltip body to appear
userEvent.click(triggerButton);

expect(onKeyDown).not.toHaveBeenCalled();
expect(screen.queryByText('tooltip body')).toBeInTheDocument();

userEvent.keyboard('{esc}');

expect(screen.queryByText('tooltip body')).not.toBeInTheDocument();
});
});
});
10 changes: 1 addition & 9 deletions packages/react/src/components/Tooltip/Tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,6 @@ class Tooltip extends Component {
if (!this._debouncedHandleFocus) {
this._debouncedHandleFocus = debounce(this._handleFocus, 200);
}

document.addEventListener('keydown', this.handleEscKeyPress, false);
}

componentDidUpdate(prevProps, prevState) {
Expand Down Expand Up @@ -443,8 +441,6 @@ class Tooltip extends Component {
this._debouncedHandleFocus.cancel();
this._debouncedHandleFocus = null;
}

document.removeEventListener('keydown', this.handleEscKeyPress, false);
}

static getDerivedStateFromProps({ open }, state) {
Expand Down Expand Up @@ -707,11 +703,7 @@ class Tooltip extends Component {
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
<div
className={tooltipClasses}
onKeyDown={(event) => {
if (keyDownMatch(event, [keys.Escape])) {
event.stopPropagation();
}
}}
onKeyDown={this.handleEscKeyPress}
{...other}
id={this._tooltipId}
data-floating-menu-direction={storedDirection}
Expand Down

0 comments on commit 48cec74

Please sign in to comment.