package/src/components/ContextMenu/ContextMenu.jsx (93 lines of code) (raw):
import React, { PureComponent } from 'react'
import { Menu, Dropdown } from 'antd'
import 'antd/lib/menu/style/index.less'
import 'antd/lib/dropdown/style/index.less'
import PropTypes from 'prop-types'
import ReactDOM from 'react-dom'
import { optionShape } from '@/models/Option'
import { DropdownPosition } from './ContextMenu.styles'
const DEFAULT_ANIMATION_TIME = 300
class ContextMenu extends PureComponent {
static propTypes = {
x: PropTypes.number.isRequired,
y: PropTypes.number.isRequired,
options: PropTypes.arrayOf(optionShape).isRequired,
context: PropTypes.any,
onSelection: PropTypes.func.isRequired,
unmount: PropTypes.func.isRequired
}
state = {
visible: true
}
componentDidUpdate = () => {
if (this.state.visible) {
return
}
setTimeout(this.props.unmount, DEFAULT_ANIMATION_TIME)
}
close = () => this.setState({
visible: false
})
onClick = (e) => {
this.props.onSelection(e.key, this.props.context)
this.close()
}
onVisibleChange = (visible) => {
!visible && this.close()
}
getMenu = () => (
<Menu
onClick={this.onClick}
>
{
this.props.options.map((option) => (
<Menu.Item
key={option.value}
disabled={option.disabled}
>
{option.text}
</Menu.Item>
))
}
</Menu>
)
render = () => this.state.visible && (
<DropdownPosition
x={this.props.x}
y={this.props.y}
>
<Dropdown
trigger="click"
visible={this.state.visible}
overlay={this.getMenu()}
onVisibleChange={this.onVisibleChange}
>
<div />
</Dropdown>
</DropdownPosition>
)
}
const openMenu = (x, y, options, context, onSelection) => {
const root = document.getRootNode()
const menu = document.createElement('div')
menu.setAttribute('style', 'position: absolute; top: 0; left: 0')
root.body.appendChild(menu)
const unmount = () => {
ReactDOM.unmountComponentAtNode(menu)
menu.remove()
}
ReactDOM.render(
<ContextMenu
x={x}
y={y}
options={options}
onSelection={onSelection}
context={context}
unmount={unmount}
/>,
menu
)
}
export {
openMenu
}