Skip to content

Commit

Permalink
fix(Portal): pass additional agruments to trigger handlers (#2234)
Browse files Browse the repository at this point in the history
  • Loading branch information
layershifter authored and levithomason committed Oct 29, 2017
1 parent f53c663 commit fe0188e
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 13 deletions.
20 changes: 10 additions & 10 deletions src/addons/Portal/Portal.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,11 +226,11 @@ class Portal extends Component {
clearTimeout(this.mouseLeaveTimer)
}

handleTriggerBlur = (e) => {
handleTriggerBlur = (e, ...rest) => {
const { trigger, closeOnTriggerBlur } = this.props

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

// do not close if focus is given to the portal
const didFocusPortal = _.invoke(this, 'rootNode.contains', e.relatedTarget)
Expand All @@ -241,12 +241,12 @@ class Portal extends Component {
this.close(e)
}

handleTriggerClick = (e) => {
handleTriggerClick = (e, ...rest) => {
const { trigger, closeOnTriggerClick, openOnTriggerClick } = this.props
const { open } = this.state

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

if (open && closeOnTriggerClick) {
debug('handleTriggerClick() - close')
Expand All @@ -259,39 +259,39 @@ class Portal extends Component {
}
}

handleTriggerFocus = (e) => {
handleTriggerFocus = (e, ...rest) => {
const { trigger, openOnTriggerFocus } = this.props

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

if (!openOnTriggerFocus) return

debug('handleTriggerFocus()')
this.open(e)
}

handleTriggerMouseLeave = (e) => {
handleTriggerMouseLeave = (e, ...rest) => {
clearTimeout(this.mouseEnterTimer)

const { trigger, closeOnTriggerMouseLeave, mouseLeaveDelay } = this.props

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

if (!closeOnTriggerMouseLeave) return

debug('handleTriggerMouseLeave()')
this.mouseLeaveTimer = this.closeWithTimeout(e, mouseLeaveDelay)
}

handleTriggerMouseEnter = (e) => {
handleTriggerMouseEnter = (e, ...rest) => {
clearTimeout(this.mouseLeaveTimer)

const { trigger, mouseEnterDelay, openOnTriggerMouseEnter } = this.props

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

if (!openOnTriggerMouseEnter) return

Expand Down
40 changes: 37 additions & 3 deletions test/specs/addons/Portal/Portal-test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import _ from 'lodash'
import PropTypes from 'prop-types'
import React from 'react'
import React, { Component } from 'react'
import { unmountComponentAtNode } from 'react-dom'

import * as common from 'test/specs/commonTests'
Expand All @@ -9,6 +10,20 @@ import Portal from 'src/addons/Portal/Portal'
let attachTo
let wrapper

const createHandlingComponent = eventName => class HandlingComponent extends Component {
static propTypes = {
handler: PropTypes.func,
}

handleEvent = e => this.props.handler(e, this.props)

render() {
const buttonProps = { [eventName]: this.handleEvent }

return <button {...buttonProps} />
}
}

const wrapperMount = (node, opts) => {
wrapper = mount(node, opts)
return wrapper
Expand Down Expand Up @@ -188,9 +203,9 @@ describe('Portal', () => {
})

it('maintains ref to DOM node with React component', () => {
const Component = () => <p />
const EmptyComponent = () => <p />

wrapperMount(<Portal open><Component /></Portal>)
wrapperMount(<Portal open><EmptyComponent /></Portal>)
wrapper.instance().portalNode.tagName.should.equal('P')
})
})
Expand All @@ -209,6 +224,25 @@ describe('Portal', () => {

wrapper.text().should.equal(text)
})

_.forEach(['onBlur', 'onClick', 'onFocus', 'onMouseLeave', 'onMouseEnter'], (handlerName) => {
it(`handles ${handlerName} on trigger and passes all arguments`, () => {
const event = { target: null }
const handler = sandbox.spy()
const Trigger = createHandlingComponent(handlerName)
const trigger = <Trigger color='blue' handler={handler} />

wrapperMount(<Portal trigger={trigger}><p /></Portal>)
.find('button')
.simulate(_.toLower(handlerName.substring(2)), event)

handler.should.have.been.calledOnce()
handler.should.have.been.calledWithMatch(event, {
handler,
color: 'blue',
})
})
})
})

describe('mountNode', () => {
Expand Down

0 comments on commit fe0188e

Please sign in to comment.