Skip to content

Commit 888b2f7

Browse files
authored
fix(Portal): fix event handling for mouseEnter/mouseLeave (#4445)
* fix: typo for mouseEnterTimer (#4442) * fix: typo for mouseLeaveTimer
1 parent ba4b720 commit 888b2f7

File tree

3 files changed

+82
-2
lines changed

3 files changed

+82
-2
lines changed

src/addons/Portal/Portal.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ function Portal(props) {
215215
}
216216

217217
const handleTriggerMouseLeave = (e, ...rest) => {
218-
clearTimeout(mouseEnterTimer)
218+
clearTimeout(mouseEnterTimer.current)
219219

220220
// Call original event handler
221221
_.invoke(trigger, 'props.onMouseLeave', e, ...rest)
@@ -229,7 +229,7 @@ function Portal(props) {
229229
}
230230

231231
const handleTriggerMouseEnter = (e, ...rest) => {
232-
clearTimeout(mouseLeaveTimer)
232+
clearTimeout(mouseLeaveTimer.current)
233233

234234
// Call original event handler
235235
_.invoke(trigger, 'props.onMouseEnter', e, ...rest)

test/specs/addons/Portal/Portal-test.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as common from 'test/specs/commonTests'
77
import { domEvent, sandbox } from 'test/utils'
88
import Portal from 'src/addons/Portal/Portal'
99
import PortalInner from 'src/addons/Portal/PortalInner'
10+
import wait from 'test/utils/wait'
1011

1112
let wrapper
1213

@@ -371,6 +372,38 @@ describe('Portal', () => {
371372
done()
372373
}, 1)
373374
})
375+
376+
/**
377+
* e--l--d--v
378+
* ^: mouseenter
379+
* ^: BEFORE_DELAY: mouseleave
380+
* ^: expected DELAY
381+
* ^: final validation
382+
*/
383+
it('does not open the portal when leave before delay', async () => {
384+
const DELAY = 20
385+
const BEFORE_DELAY = 10
386+
387+
wrapperMount(
388+
<Portal trigger={<button />} openOnTriggerMouseEnter mouseEnterDelay={DELAY}>
389+
<p />
390+
</Portal>,
391+
)
392+
393+
wrapper.should.not.have.descendants(PortalInner)
394+
wrapper.find('button').simulate('mouseenter')
395+
396+
await wait(BEFORE_DELAY)
397+
398+
wrapper.update()
399+
wrapper.should.not.have.descendants(PortalInner)
400+
wrapper.find('button').simulate('mouseleave')
401+
402+
await wait(DELAY)
403+
404+
wrapper.update()
405+
wrapper.should.not.have.descendants(PortalInner)
406+
})
374407
})
375408

376409
describe('closeOnTriggerMouseLeave', () => {
@@ -407,6 +440,50 @@ describe('Portal', () => {
407440
done()
408441
}, 1)
409442
})
443+
444+
/**
445+
* e--l--e--d--v
446+
* ^: mouseenter
447+
* ^: mouseleave
448+
* ^: BEFORE_DELAY: reenter
449+
* ^: expected DELAY
450+
* ^: final validation
451+
*/
452+
it('does not close the portal when reenter before delay', async () => {
453+
const DELAY = 20
454+
const BEFORE_DELAY = 10
455+
456+
wrapperMount(
457+
<Portal
458+
trigger={<button />}
459+
openOnTriggerMouseEnter
460+
closeOnTriggerMouseLeave
461+
mouseLeaveDelay={DELAY}
462+
>
463+
<p />
464+
</Portal>,
465+
)
466+
467+
wrapper.should.not.have.descendants(PortalInner)
468+
wrapper.find('button').simulate('mouseenter')
469+
470+
await wait(BEFORE_DELAY)
471+
472+
wrapper.update()
473+
wrapper.should.have.descendants(PortalInner)
474+
wrapper.find('button').simulate('mouseleave')
475+
476+
await wait(BEFORE_DELAY)
477+
478+
wrapper.update()
479+
wrapper.should.have.descendants(PortalInner)
480+
wrapper.find('button').simulate('mouseenter')
481+
482+
await wait(DELAY)
483+
484+
wrapper.update()
485+
wrapper.should.have.descendants(PortalInner)
486+
})
410487
})
411488

412489
describe('closeOnPortalMouseLeave', () => {

test/utils/wait.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function wait(timeout) {
2+
return new Promise((resolve) => setTimeout(resolve, timeout))
3+
}

0 commit comments

Comments
 (0)