diff --git a/packages/menus/src/containers/MenuContainer.js b/packages/menus/src/containers/MenuContainer.js index d849bcfd83e..9f3413b4a41 100644 --- a/packages/menus/src/containers/MenuContainer.js +++ b/packages/menus/src/containers/MenuContainer.js @@ -150,18 +150,22 @@ class MenuContainer extends ControlledComponent { }; } - componentDidMount() { + attachClickOutsideHandler() { this.getDocuments().forEach(doc => { - doc.addEventListener('mousedown', this.handleOutsideMouseDown); + doc.addEventListener('mousedown', this.handleOutsideMouseDown, true /* use capture */); }); } - componentWillUnmount() { + detachClickOutsideHandler() { this.getDocuments().forEach(doc => { - doc.removeEventListener('mousedown', this.handleOutsideMouseDown); + doc.removeEventListener('mousedown', this.handleOutsideMouseDown, true /* use capture */); }); } + componentWillUnmount() { + this.detachClickOutsideHandler(); + } + componentDidUpdate(prevProps, prevState) { const { isOpen, closedByBlur } = this.getControlledState(); const previousisOpen = this.isControlledProp('isOpen') ? prevProps.isOpen : prevState.isOpen; @@ -173,6 +177,8 @@ class MenuContainer extends ControlledComponent { if (!closedByBlur) { this.triggerReference && this.triggerReference.focus(); } + + this.detachClickOutsideHandler(); } /** @@ -192,6 +198,8 @@ class MenuContainer extends ControlledComponent { setTimeout(() => { this.menuReference && this.menuReference.focus(); }, 0); + + this.attachClickOutsideHandler(); } } diff --git a/packages/menus/src/containers/MenuContainer.spec.js b/packages/menus/src/containers/MenuContainer.spec.js index b5d4a63827c..e24907398e3 100644 --- a/packages/menus/src/containers/MenuContainer.spec.js +++ b/packages/menus/src/containers/MenuContainer.spec.js @@ -254,17 +254,41 @@ describe('MenuContainer', () => { }); }); - describe('componentWillUnmount', () => { - it('removes mousedown event listener', () => { - const removeEventListenerSpy = jest.fn(); + describe('when the menu is open', () => { + beforeEach(() => { + jest.spyOn(document, 'removeEventListener'); - document.removeEventListener = removeEventListenerSpy; wrapper = mountWithTheme(basicExample({ onChange: onChangeSpy }), { enzymeOptions: { attachTo: document.body } }); - wrapper.unmount(); - expect(removeEventListenerSpy).toHaveBeenCalled(); + findTrigger(wrapper).simulate('click'); + }); + + afterEach(() => { + document.removeEventListener.mockRestore(); + }); + + describe('when clicking outside', () => { + it('closes the menu', () => { + wrapper.simulate('click'); + + expect(findMenu(wrapper)).not.toExist(); + }); + + it('removes click outside event listener', () => { + wrapper.simulate('click'); + + expect(document.removeEventListener).toHaveBeenCalled(); + }); + }); + + describe('componentWillUnmount()', () => { + it('removes click outside event listener', () => { + wrapper.unmount(); + + expect(document.removeEventListener).toHaveBeenCalled(); + }); }); });