2020-02-28 15:20:47 +00:00
|
|
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
|
|
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
2020-03-11 23:56:18 +00:00
|
|
|
import { Manager, Reference, Popper } from 'react-popper'
|
2020-02-28 15:20:47 +00:00
|
|
|
import classnames from 'classnames/bind'
|
|
|
|
import Overlay from 'react-overlays/lib/Overlay'
|
|
|
|
import spring from 'react-motion/lib/spring'
|
|
|
|
import Motion from '../../features/ui/util/optional_motion'
|
|
|
|
import { openPopover, closePopover } from '../../actions/popover'
|
|
|
|
import { openModal, closeModal } from '../../actions/modal'
|
|
|
|
import { isUserTouching } from '../../utils/is_mobile'
|
|
|
|
|
|
|
|
const cx = classnames.bind(_s)
|
|
|
|
|
|
|
|
let id = 0
|
|
|
|
|
|
|
|
const mapStateToProps = state => ({
|
|
|
|
isModalOpen: state.get('modal').modalType === 'ACTIONS',
|
|
|
|
popoverPlacement: state.getIn(['popover', 'placement']),
|
|
|
|
openPopoverType: state.getIn(['popover', 'popoverType']),
|
|
|
|
openedViaKeyboard: state.getIn(['popover', 'keyboard']),
|
|
|
|
})
|
|
|
|
|
|
|
|
const mapDispatchToProps = (dispatch, { status, items }) => ({
|
|
|
|
onOpen(id, onItemClick, popoverPlacement, keyboard) {
|
|
|
|
dispatch(isUserTouching() ? openModal('ACTIONS', {
|
|
|
|
status,
|
|
|
|
actions: items,
|
|
|
|
onClick: onItemClick,
|
|
|
|
}) : openPopover(id, popoverPlacement, keyboard))
|
|
|
|
},
|
|
|
|
onClose(id) {
|
|
|
|
dispatch(closeModal())
|
|
|
|
dispatch(closePopover(id))
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
export default
|
|
|
|
@connect(mapStateToProps, mapDispatchToProps)
|
|
|
|
class PopoverBase extends ImmutablePureComponent {
|
|
|
|
|
|
|
|
static contextTypes = {
|
|
|
|
router: PropTypes.object,
|
|
|
|
}
|
|
|
|
|
|
|
|
static propTypes = {
|
|
|
|
icon: PropTypes.string.isRequired,
|
|
|
|
items: PropTypes.array.isRequired,
|
|
|
|
size: PropTypes.number.isRequired,
|
|
|
|
title: PropTypes.string,
|
|
|
|
disabled: PropTypes.bool,
|
|
|
|
status: ImmutablePropTypes.map,
|
|
|
|
isUserTouching: PropTypes.func,
|
|
|
|
isModalOpen: PropTypes.bool.isRequired,
|
|
|
|
onOpen: PropTypes.func.isRequired,
|
|
|
|
onClose: PropTypes.func.isRequired,
|
2020-03-11 23:56:18 +00:00
|
|
|
position: PropTypes.string,
|
2020-02-28 15:20:47 +00:00
|
|
|
openPopoverType: PropTypes.number,
|
|
|
|
openedViaKeyboard: PropTypes.bool,
|
|
|
|
visible: PropTypes.bool,
|
2020-03-11 23:56:18 +00:00
|
|
|
targetRef: PropTypes.node,
|
2020-02-28 15:20:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static defaultProps = {
|
|
|
|
title: 'Menu',
|
2020-03-11 23:56:18 +00:00
|
|
|
position: 'bottom',
|
2020-02-28 15:20:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
state = {
|
|
|
|
id: id++,
|
|
|
|
}
|
|
|
|
|
|
|
|
handleClick = ({ target, type }) => {
|
|
|
|
if (this.state.id === this.props.openPopoverType) {
|
|
|
|
this.handleClose()
|
|
|
|
} else {
|
|
|
|
const { top } = target.getBoundingClientRect()
|
|
|
|
const placement = top * 2 < innerHeight ? 'bottom' : 'top'
|
|
|
|
|
|
|
|
this.props.onOpen(this.state.id, this.handleItemClick, placement, type !== 'click')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
handleClose = () => {
|
|
|
|
this.props.onClose(this.state.id)
|
|
|
|
}
|
|
|
|
|
|
|
|
handleKeyDown = e => {
|
|
|
|
switch (e.key) {
|
|
|
|
case ' ':
|
|
|
|
case 'Enter':
|
|
|
|
this.handleClick(e)
|
|
|
|
e.preventDefault()
|
|
|
|
break
|
|
|
|
case 'Escape':
|
|
|
|
this.handleClose()
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
handleItemClick = e => {
|
|
|
|
const i = Number(e.currentTarget.getAttribute('data-index'))
|
|
|
|
const { action, to } = this.props.items[i]
|
|
|
|
|
|
|
|
this.handleClose()
|
|
|
|
|
|
|
|
if (typeof action === 'function') {
|
|
|
|
e.preventDefault()
|
|
|
|
action()
|
|
|
|
} else if (to) {
|
|
|
|
e.preventDefault()
|
|
|
|
this.context.router.history.push(to)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setTargetRef = c => {
|
|
|
|
this.target = c
|
|
|
|
}
|
|
|
|
|
|
|
|
findTarget = () => {
|
|
|
|
return this.target
|
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount = () => {
|
|
|
|
if (this.state.id === this.props.openPopoverType) {
|
|
|
|
this.handleClose()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
2020-03-11 23:56:18 +00:00
|
|
|
const {
|
|
|
|
icon,
|
|
|
|
children,
|
|
|
|
visible,
|
|
|
|
items,
|
|
|
|
size,
|
|
|
|
title,
|
|
|
|
disabled,
|
|
|
|
position,
|
|
|
|
openPopoverType,
|
|
|
|
openedViaKeyboard,
|
|
|
|
targetRef,
|
|
|
|
} = this.props
|
2020-02-28 15:20:47 +00:00
|
|
|
const open = this.state.id === openPopoverType
|
|
|
|
|
|
|
|
const containerClasses = cx({
|
|
|
|
default: 1,
|
|
|
|
z4: 1,
|
|
|
|
displayNone: !visible,
|
|
|
|
})
|
|
|
|
|
|
|
|
return (
|
2020-03-11 23:56:18 +00:00
|
|
|
<Manager>
|
|
|
|
<Popper
|
|
|
|
placement={position}
|
|
|
|
referenceElement={targetRef}
|
|
|
|
>
|
|
|
|
{({ ref, style, placement, arrowProps }) => (
|
|
|
|
<div ref={ref} style={style} data-placement={placement}>
|
|
|
|
<div ref={arrowProps.ref} style={arrowProps.style} />
|
|
|
|
<div data-popover='true' onKeyDown={this.handleKeyDown} className={containerClasses}>
|
|
|
|
{children}
|
|
|
|
{ /* <div show={open} placement={popoverPlacement} target={this.findTarget}>
|
|
|
|
<PopoverMenu items={items} onClose={this.handleClose} openedViaKeyboard={openedViaKeyboard} />
|
|
|
|
</div> */}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</Popper>
|
|
|
|
</Manager>
|
2020-02-28 15:20:47 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|