diff --git a/packages/retail-ui/components/RenderLayer/RenderLayer.tsx b/packages/retail-ui/components/RenderLayer/RenderLayer.tsx index 94e7c5e73c9..c0955137725 100644 --- a/packages/retail-ui/components/RenderLayer/RenderLayer.tsx +++ b/packages/retail-ui/components/RenderLayer/RenderLayer.tsx @@ -10,6 +10,17 @@ export interface RenderLayerProps { } class RenderLayer extends React.Component { + public static propTypes = { + active(props: RenderLayerProps, propName: keyof RenderLayerProps, componentName: string) { + const { active, onClickOutside, onFocusOutside } = props; + if (active && !(onClickOutside || onFocusOutside)) { + return new Error( + `[${componentName}]: using the component without either 'onClickOutside' or 'onFocusOutside' callback is pointless.`, + ); + } + }, + }; + public static defaultProps = { active: true, }; @@ -44,14 +55,9 @@ class RenderLayer extends React.Component { } private attachListeners() { - if (this.props.onFocusOutside) { - this.focusOutsideListenerToken = listenFocusOutside(() => [this.getDomNode()], this.handleFocusOutside); - window.addEventListener('blur', this.handleFocusOutside); - } - - if (this.props.onClickOutside) { - document.addEventListener('mousedown', this.handleNativeDocClick); - } + this.focusOutsideListenerToken = listenFocusOutside(() => [this.getDomNode()], this.handleFocusOutside); + window.addEventListener('blur', this.handleFocusOutside); + document.addEventListener('mousedown', this.handleNativeDocClick); } private detachListeners() { diff --git a/packages/retail-ui/components/Tooltip/Tooltip.tsx b/packages/retail-ui/components/Tooltip/Tooltip.tsx index 96605cee90b..1e46a607500 100644 --- a/packages/retail-ui/components/Tooltip/Tooltip.tsx +++ b/packages/retail-ui/components/Tooltip/Tooltip.tsx @@ -181,7 +181,7 @@ class Tooltip extends React.Component { public render() { const props = this.props; const content = this.renderContent(); - const { popupProps, layerProps = {} } = this.getProps(); + const { popupProps, layerProps = { active: false } } = this.getProps(); const anchorElement = props.children || props.anchorElement; const popup = this.renderPopup(anchorElement, popupProps, content); diff --git a/packages/retail-ui/components/Tooltip/__tests__/Tooltip-test.tsx b/packages/retail-ui/components/Tooltip/__tests__/Tooltip-test.tsx index 21478e705ae..fc1f0f779d0 100644 --- a/packages/retail-ui/components/Tooltip/__tests__/Tooltip-test.tsx +++ b/packages/retail-ui/components/Tooltip/__tests__/Tooltip-test.tsx @@ -1,8 +1,15 @@ // tslint:disable:jsx-no-lambda -import { mount } from 'enzyme'; +import { mount, ReactWrapper } from 'enzyme'; import * as React from 'react'; import Button from '../../Button'; -import Tooltip, { TooltipProps } from '../Tooltip'; +import Tooltip, { TooltipProps, TooltipState } from '../Tooltip'; + +function clickOutside() { + const event = document.createEvent('HTMLEvents'); + event.initEvent('mousedown', true, true); + + document.body.dispatchEvent(event); +} describe('Tooltip', () => { const render = () => ''; @@ -118,4 +125,40 @@ describe('Tooltip', () => { wrapper.setProps({ trigger: 'hover' }); expect(wrapper.find(Content).length).toBe(0); }); + + describe('calls onCloseRequest on clickOutside when tooltip is opened', () => { + const Content = () =>
; + const onCloseRequest = jest.fn(); + let wrapper: ReactWrapper; + + beforeEach(() => { + onCloseRequest.mockClear(); + wrapper = mount( + } onCloseRequest={onCloseRequest}> + + , + ); + }); + + it('with "click" trigger', () => { + wrapper.setProps({ trigger: 'click' }); + wrapper.setState({ opened: true }); + wrapper.update(); + expect(wrapper.find(Content).length).toBe(1); + + clickOutside(); + + expect(onCloseRequest).toHaveBeenCalledTimes(1); + }); + + it('with "opened" trigger', () => { + wrapper.setProps({ trigger: 'opened' }); + wrapper.update(); + expect(wrapper.find(Content).length).toBe(1); + + clickOutside(); + + expect(onCloseRequest).toHaveBeenCalledTimes(1); + }); + }); });