Skip to content

Commit 72fff9e

Browse files
committed
Fix usePopover event handler cleanup
1 parent 42fc105 commit 72fff9e

File tree

3 files changed

+22
-31
lines changed

3 files changed

+22
-31
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [UNRELEASED]
9+
10+
### Fixed
11+
12+
- `usePopover` event handlers not getting properly cleaned up
13+
814
## [0.7.19] - 2020-02-24
915

1016
### Added

packages/components/src/Popover/Popover.tsx

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ import React, {
3232
RefObject,
3333
Ref,
3434
SyntheticEvent,
35-
useRef,
3635
} from 'react'
3736
import { Popper } from 'react-popper'
3837
import { Box } from '../Layout'
@@ -236,7 +235,9 @@ function usePopoverToggle(
236235
triggerElement: HTMLElement | null
237236
): [boolean, (value: boolean) => void] {
238237
const [uncontrolledIsOpen, uncontrolledSetOpen] = useState(controlledIsOpen)
239-
const mouseDownTarget = useRef<EventTarget | null>()
238+
const [mouseDownTarget, setMouseDownTarget] = useState<EventTarget | null>(
239+
null
240+
)
240241
const isControlled = useControlWarn({
241242
controllingProps: ['setOpen'],
242243
isControlledCheck: () => controlledSetOpen !== undefined,
@@ -255,9 +256,9 @@ function usePopoverToggle(
255256
// outside the popover as this is preferable to a bug where another
256257
// component triggers a scroll animation resulting in an
257258
// unintentional drag, which closes the popover
258-
if (portalElement && mouseDownTarget.current) {
259+
if (portalElement && mouseDownTarget) {
259260
const relationship = portalElement.compareDocumentPosition(
260-
mouseDownTarget.current as Node
261+
mouseDownTarget as Node
261262
)
262263
if (
263264
relationship === Node.DOCUMENT_POSITION_FOLLOWING ||
@@ -303,7 +304,7 @@ function usePopoverToggle(
303304
}
304305

305306
function handleMouseDown(event: MouseEvent) {
306-
mouseDownTarget.current = event.target
307+
setMouseDownTarget(event.target)
307308
checkCloseAndStopEvent(event)
308309
}
309310

@@ -312,20 +313,16 @@ function usePopoverToggle(
312313
}
313314

314315
function handleMouseUp() {
315-
window.requestAnimationFrame(() => {
316-
mouseDownTarget.current = null
317-
document.removeEventListener('click', handleClickOutside, true)
318-
document.removeEventListener('mouseup', handleMouseUp, true)
319-
})
316+
setMouseDownTarget(null)
320317
}
321318

322319
if (isOpen) {
323320
document.addEventListener('mousedown', handleMouseDown, true)
324-
if (!mouseDownTarget.current) {
325-
document.addEventListener('click', handleClickOutside, true)
326-
}
327-
} else if (mouseDownTarget.current) {
328321
document.addEventListener('click', handleClickOutside, true)
322+
} else if (mouseDownTarget) {
323+
// popover was closed via mousedown, but still need to cancel next click
324+
document.addEventListener('click', handleClickOutside, true)
325+
// and then cleanup mouseDownTarget
329326
document.addEventListener('mouseup', handleMouseUp, true)
330327
}
331328

@@ -342,6 +339,7 @@ function usePopoverToggle(
342339
triggerElement,
343340
portalElement,
344341
triggerToggle,
342+
mouseDownTarget,
345343
])
346344

347345
return [isOpen, setOpen]

packages/playground/src/index.tsx

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,17 @@
2020

2121
import React from 'react'
2222
import ReactDOM from 'react-dom'
23-
import { GlobalStyle, Field, FieldText } from '@looker/components'
23+
import { GlobalStyle } from '@looker/components'
2424
import { theme } from '@looker/design-tokens'
2525
import { ThemeProvider } from 'styled-components'
2626

27+
import { SelectDemo } from './Select/SelectDemo'
28+
2729
const App: React.FC = () => {
2830
return (
2931
<ThemeProvider theme={theme}>
3032
<GlobalStyle />
31-
<Field required description="description" detail="0/50" label="First" />
32-
<FieldText
33-
required
34-
description="description"
35-
detail="0/50"
36-
label="First"
37-
name="firstName"
38-
/>
39-
<FieldText
40-
width="480px"
41-
required
42-
description="description"
43-
detail="0/50"
44-
label="First"
45-
name="firstName"
46-
/>
33+
<SelectDemo />
4734
</ThemeProvider>
4835
)
4936
}

0 commit comments

Comments
 (0)