Skip to content

WIP: fix(Modal|Popup|Dropdown): fix in handling events #3734

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions gulp/plugins/util/getComponentInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ const getComponentInfo = (filepath) => {
const componentType = path.basename(path.dirname(dir)).replace(/s$/, '')

// start with react-docgen info
const components = parse(contents, resolver.findAllComponentDefinitions, [
...defaultHandlers,
parserCustomHandler,
])
const components = parse(
contents,
resolver.findAllComponentDefinitions,
[...defaultHandlers, parserCustomHandler],
{ filename: filepath },
)
if (!components.length) {
throw new Error(`Could not find a component definition in "${filepath}".`)
}
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@
"dependencies": {
"@babel/runtime": "^7.1.2",
"@semantic-ui-react/event-stack": "^3.1.0",
"@stardust-ui/react-component-event-listener": "~0.35.0",
"@stardust-ui/react-component-nesting-registry": "~0.35.0",
"classnames": "^2.2.6",
"keyboard-key": "^1.0.4",
"lodash": "^4.17.15",
Expand Down Expand Up @@ -152,7 +154,7 @@
"react": "^16.8.6",
"react-ace": "^6.4.0",
"react-codesandboxer": "^3.1.3",
"react-docgen": "^4.1.0",
"react-docgen": "^4.1.1",
"react-dom": "^16.8.6",
"react-hot-loader": "^4.12.10",
"react-router": "^5.0.0",
Expand Down
51 changes: 17 additions & 34 deletions src/addons/Portal/Portal.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import EventStack from '@semantic-ui-react/event-stack'
import keyboardKey from 'keyboard-key'
import _ from 'lodash'
import PropTypes from 'prop-types'
Expand Down Expand Up @@ -53,9 +52,6 @@ class Portal extends Component {
/** Initial value of open. */
defaultOpen: PropTypes.bool,

/** Event pool namespace that is used to handle component events */
eventPool: PropTypes.string,

/** The node where the portal should mount. */
mountNode: PropTypes.any,

Expand Down Expand Up @@ -119,7 +115,6 @@ class Portal extends Component {
static defaultProps = {
closeOnDocumentClick: true,
closeOnEscape: true,
eventPool: 'default',
openOnTriggerClick: true,
}

Expand Down Expand Up @@ -166,11 +161,12 @@ class Portal extends Component {
}
}

handleEscape = (e) => {
handleDocumentKeyDown = (e) => {
if (!this.props.closeOnEscape) return
if (keyboardKey.getCode(e) !== keyboardKey.Escape) return

debug('handleEscape()')
debug('handleDocumentKeyDown()')
e.stopPropagation()
this.close(e)
}

Expand Down Expand Up @@ -333,38 +329,25 @@ class Portal extends Component {
}

render() {
const { children, eventPool, mountNode, trigger } = this.props
const { children, mountNode, trigger } = this.props
const { open } = this.state

return (
<Fragment>
{open && (
<Fragment>
<PortalInner
innerRef={this.contentRef}
mountNode={mountNode}
onMount={this.handleMount}
onUnmount={this.handleUnmount}
>
{children}
</PortalInner>

<EventStack
name='mouseleave'
on={this.handlePortalMouseLeave}
pool={eventPool}
target={this.contentRef}
/>
<EventStack
name='mouseenter'
on={this.handlePortalMouseEnter}
pool={eventPool}
target={this.contentRef}
/>
<EventStack name='mousedown' on={this.handleDocumentMouseDown} pool={eventPool} />
<EventStack name='click' on={this.handleDocumentClick} pool={eventPool} />
<EventStack name='keydown' on={this.handleEscape} pool={eventPool} />
</Fragment>
<PortalInner
innerRef={this.contentRef}
mountNode={mountNode}
onDocumentClick={this.handleDocumentClick}
onDocumentMouseDown={this.handleDocumentMouseDown}
onDocumentKeyDown={this.handleDocumentKeyDown}
onMouseEnter={this.handlePortalMouseEnter}
onMouseLeave={this.handlePortalMouseLeave}
onMount={this.handleMount}
onUnmount={this.handleUnmount}
>
{children}
</PortalInner>
)}
{trigger && (
<Ref innerRef={this.handleTriggerRef}>
Expand Down
169 changes: 116 additions & 53 deletions src/addons/Portal/PortalInner.js
Original file line number Diff line number Diff line change
@@ -1,65 +1,128 @@
import { documentRef } from '@stardust-ui/react-component-event-listener'
import useEventListener from '@stardust-ui/react-component-event-listener/dist/commonjs/hooks/useEventListener'
import _ from 'lodash'
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import React from 'react'
import { createPortal } from 'react-dom'

import { customPropTypes, handleRef, isBrowser, makeDebugger } from '../../lib'
import { customPropTypes, handleRef } from '../../lib'
import Ref from '../Ref'

const debug = makeDebugger('portalInner')

/**
* An inner component that allows you to render children outside their parent.
*/
class PortalInner extends Component {
static propTypes = {
/** Primary content. */
children: PropTypes.node.isRequired,

/** Called with a ref to the inner node. */
innerRef: customPropTypes.ref,

/** The node where the portal should mount. */
mountNode: PropTypes.any,

/**
* Called when the portal is mounted on the DOM
*
* @param {null}
* @param {object} data - All props.
*/
onMount: PropTypes.func,

/**
* Called when the portal is unmounted from the DOM
*
* @param {null}
* @param {object} data - All props.
*/
onUnmount: PropTypes.func,
}

componentDidMount() {
debug('componentDidMount()')
_.invoke(this.props, 'onMount', null, this.props)
}

componentWillUnmount() {
debug('componentWillUnmount()')
_.invoke(this.props, 'onUnmount', null, this.props)
}

handleRef = (c) => {
debug('handleRef', c)
handleRef(this.props.innerRef, c)
}

render() {
if (!isBrowser()) return null
const { children, mountNode = document.body } = this.props

return createPortal(<Ref innerRef={this.handleRef}>{children}</Ref>, mountNode)
}
function PortalInner(props) {
const { children, innerRef, mountNode = document.body } = props

const contentRef = React.useRef()
const handleContentRef = React.useCallback(
(c) => {
contentRef.current = c
handleRef(innerRef, c)
},
[innerRef],
)
React.useLayoutEffect(() => {
_.invoke(props, 'onMount', null, props)

return () => {
_.invoke(props, 'onUnmount', null, props)
}
}, [])

useEventListener({
listener: props.onMouseLeave,
type: 'mouseleave',
targetRef: contentRef,
})
useEventListener({
listener: props.onMouseEnter,
targetRef: contentRef,
type: 'mouseenter',
})
useEventListener({
listener: props.onDocumentClick,
type: 'click',
targetRef: documentRef,
})
useEventListener({
listener: props.onDocumentKeyDown,
targetRef: documentRef,
type: 'keydown',
})
useEventListener({
listener: props.onDocumentMouseDown,
targetRef: documentRef,
type: 'mousedown',
})

return (
<React.Fragment>
{createPortal(<Ref innerRef={handleContentRef}>{children}</Ref>, mountNode)}
</React.Fragment>
)
}

PortalInner.propTypes = {
/** Primary content. */
children: PropTypes.node.isRequired,

/** Called with a ref to the inner node. */
innerRef: customPropTypes.ref,

/** The node where the portal should mount. */
mountNode: PropTypes.any,

/**
* Called on a document click.
*
* @param {MouseEvent} event
*/
onDocumentClick: PropTypes.func,

/**
* Called on document key down.
*
* @param {KeyboardEvent} event
*/
onDocumentKeyDown: PropTypes.func,

/**
* Called on a document mouse down.
*
* @param {MouseEvent} event
*/
onDocumentMouseDown: PropTypes.func,

/**
* Called when the portal is mounted on the DOM.
*
* @param {null}
* @param {object} data - All props.
*/
onMount: PropTypes.func,

/**
* Called when mouse leaves the portal.
*
* @param {MouseEvent} event
*/
onMouseLeave: PropTypes.func,

/**
* Called when mouse enters the portal.
*
* @param {MouseEvent} event
*/
onMouseEnter: PropTypes.func,

/**
* Called when the portal is unmounted from the DOM.
*
* @param {null}
* @param {object} data - All props.
*/
onUnmount: PropTypes.func,
}

export default PortalInner
1 change: 1 addition & 0 deletions src/modules/Dropdown/Dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@ export default class Dropdown extends Component {
if (!this.props.closeOnEscape) return
if (keyboardKey.getCode(e) !== keyboardKey.Escape) return
e.preventDefault()
e.stopPropagation()

debug('closeOnEscape()')
this.close(e)
Expand Down
Loading