Skip to content

Commit d70a101

Browse files
author
Emily
authored
Merge pull request #517 from primer/details-event-fix
Only close Details on click outside
2 parents 507612d + 6b059a6 commit d70a101

File tree

3 files changed

+62
-19
lines changed

3 files changed

+62
-19
lines changed

src/Details.js

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, {useState, useEffect} from 'react'
1+
import React, {useState, useEffect, useRef} from 'react'
22
import PropTypes from 'prop-types'
33
import styled from 'styled-components'
44
import {COMMON} from './constants'
@@ -18,29 +18,31 @@ function getRenderer(children) {
1818

1919
function DetailsBase({children, overlay, render = getRenderer(children), defaultOpen = false, ...rest}) {
2020
const [open, setOpen] = useState(defaultOpen)
21+
const ref = useRef(null)
2122

22-
useEffect(
23-
() => {
24-
if (overlay && open) {
25-
document.addEventListener('click', closeMenu)
26-
return () => {
27-
document.removeEventListener('click', closeMenu)
28-
}
23+
useEffect(() => {
24+
if (overlay && open) {
25+
document.addEventListener('click', closeMenu)
26+
return () => {
27+
document.removeEventListener('click', closeMenu)
2928
}
30-
},
31-
[open, overlay]
32-
)
29+
}
30+
}, [open, overlay])
3331

3432
function toggle(event) {
3533
setOpen(event.target.open)
3634
}
3735

3836
function closeMenu(event) {
39-
setOpen(false)
37+
// only close the menu if we're clicking outside
38+
if (event && event.target.closest('details') !== ref.current) {
39+
setOpen(false)
40+
document.removeEventListener('click', closeMenu)
41+
}
4042
}
4143

4244
return (
43-
<DetailsReset {...rest} open={open} onToggle={toggle} overlay={overlay}>
45+
<DetailsReset {...rest} ref={ref} open={open} onToggle={toggle} overlay={overlay}>
4446
{render({open})}
4547
</DetailsReset>
4648
)

src/__tests__/Details.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,47 @@ describe('Details', () => {
4040
expect(dom.hasAttribute('open')).toEqual(false)
4141
expect(summary.text()).toEqual('open')
4242

43+
summary.simulate('click')
44+
})
45+
46+
it('Toggles when you click outside', () => {
47+
const wrapper = mount(<Details>{({open}) => <summary>{open ? 'close' : 'open'}</summary>}</Details>)
48+
49+
document.body.click()
50+
51+
const dom = wrapper.getDOMNode()
52+
const summary = wrapper.find('summary')
53+
54+
expect(dom.hasAttribute('open')).toEqual(false)
55+
expect(summary.text()).toEqual('open')
56+
57+
wrapper.unmount()
58+
})
59+
60+
xit('Does not toggle or prevent click events when you click inside', () => {
61+
const wrapper = mount(
62+
<Details open>
63+
{({open}) => (
64+
<>
65+
<summary>{open ? 'close' : 'open'}</summary>
66+
<div>content</div>
67+
</>
68+
)}
69+
</Details>
70+
)
71+
72+
document.body.click()
73+
74+
const dom = wrapper.getDOMNode()
75+
const content = dom.querySelector('div')
76+
77+
let clickEvent
78+
content.addEventListener('click', event => (clickEvent = event))
79+
content.click()
80+
81+
expect(dom.hasAttribute('open')).toEqual(true)
82+
expect(clickEvent.defaultPrevented).toBe(false)
83+
4384
wrapper.unmount()
4485
})
4586
})

src/__tests__/Dropdown.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,18 @@ describe('Dropdown.Menu', () => {
3838
expect(
3939
render(
4040
<Dropdown.Menu>
41-
<li>1</li>
42-
<li>2</li>
43-
<li>3</li>
41+
<li key="a">1</li>
42+
<li key="b">2</li>
43+
<li key="c">3</li>
4444
</Dropdown.Menu>
4545
)
4646
).toMatchSnapshot()
4747
expect(
4848
render(
4949
<Dropdown.Menu>
50-
<li>1</li>
51-
<li>2</li>
52-
<li>3</li>
50+
<li key={1}>1</li>
51+
<li key={2}>2</li>
52+
<li key={3}>3</li>
5353
</Dropdown.Menu>
5454
)
5555
).toMatchSnapshot()

0 commit comments

Comments
 (0)