Repository URL to install this package:
|
Version:
3.0.6-working.1 ▾
|
import React from 'react'
import { MouseEvent, ReactChild } from 'react'
import toClassName from 'classnames'
import { isFunction } from 'exotic'
import { ClickBoundaryProps, ClickBoundaryRef } from './typings'
import { onClick } from './deps'
class ClickBoundary extends React.PureComponent<ClickBoundaryProps> {
isListening: boolean = false
isActive: boolean = false
dom: ClickBoundaryRef
/**
* only happens in browser, `willMount` in server
*/
subscribeListener() {
if (this.isActive && !this.isListening) {
// @note - document.body
window.addEventListener('click', this.handleClick)
window.addEventListener('ontouchstart', this.handleClick)
this.isListening = true
}
}
/**
* only happens browser
*/
unSubscribeListener() {
if (this.isListening) {
// remember to remove all events to avoid memory leaks
window.removeEventListener('click', this.handleClick)
window.removeEventListener('ontouchstart', this.handleClick)
this.isListening = false
}
}
/**
* @todo update with forwardRef
*/
setRef = (dom: Element | any) => {
this.dom = dom
if (isFunction(this.props.innerRef)) {
this.props.innerRef(dom)
}
}
handleMouseEnter = () => {
this.isActive = false
}
handleMouseLeave = () => {
this.isActive = true
this.subscribeListener()
}
handleClick = (event: MouseEvent<any> | any) => {
onClick(event, this.props, this.dom)
this.isActive = false
this.unSubscribeListener()
}
renderChildren(children: any, attributes: any) {
const onChild = (child: ReactChild) => {
// 2. safety
if (typeof child === 'string' || typeof child === 'number') {
return child
}
// 3. merge props
const props = {
...attributes,
...child.props,
}
return React.cloneElement(child, props)
}
return React.Children.map(children, onChild)
}
render() {
const {
className,
children,
onClickOutside,
nowrap,
...remainingProps
} = this.props
const attributes = {
...remainingProps,
isActive: this.isActive,
onMouseEnter: this.handleMouseEnter,
onMouseLeave: this.handleMouseLeave,
className: toClassName('click-boundary', className),
}
if (nowrap) {
return this.renderChildren(children, attributes)
} else {
return (
<div {...attributes} ref={this.setRef}>
{this.props.children}
</div>
)
}
}
}
export default ClickBoundary
export { ClickBoundary }