2021-03-26 13:03:51 +00:00
|
|
|
import React, { Component } from "react";
|
2020-10-16 13:16:01 +00:00
|
|
|
import PropTypes from "prop-types";
|
2021-03-26 13:03:51 +00:00
|
|
|
import DomHelpers from "../utils/domHelpers";
|
|
|
|
import ObjectUtils from "../utils/objectUtils";
|
|
|
|
import { classNames } from "../utils/classNames";
|
|
|
|
import { CSSTransition } from "react-transition-group";
|
2021-03-30 07:42:10 +00:00
|
|
|
import { ReactSVG } from "react-svg";
|
2021-03-26 13:03:51 +00:00
|
|
|
import Portal from "../portal";
|
|
|
|
import StyledContextMenu from "./styled-context-menu";
|
2021-03-30 07:42:10 +00:00
|
|
|
import ArrowIcon from "./svg/arrow.right.react.svg";
|
2019-08-29 13:00:01 +00:00
|
|
|
|
2021-03-26 13:03:51 +00:00
|
|
|
class ContextMenuSub extends Component {
|
2019-08-29 13:00:01 +00:00
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
2021-03-26 13:03:51 +00:00
|
|
|
activeItem: null,
|
2019-08-29 13:00:01 +00:00
|
|
|
};
|
2021-03-26 13:03:51 +00:00
|
|
|
|
|
|
|
this.onEnter = this.onEnter.bind(this);
|
2021-04-01 10:22:37 +00:00
|
|
|
|
2021-03-26 13:03:51 +00:00
|
|
|
this.submenuRef = React.createRef();
|
2019-08-29 13:00:01 +00:00
|
|
|
}
|
|
|
|
|
2021-03-26 13:03:51 +00:00
|
|
|
onItemMouseEnter(e, item) {
|
|
|
|
if (item.disabled) {
|
|
|
|
e.preventDefault();
|
|
|
|
return;
|
|
|
|
}
|
2019-08-29 13:00:01 +00:00
|
|
|
|
2021-03-26 13:03:51 +00:00
|
|
|
this.setState({
|
|
|
|
activeItem: item,
|
|
|
|
});
|
2019-08-29 13:00:01 +00:00
|
|
|
}
|
|
|
|
|
2021-10-21 14:53:28 +00:00
|
|
|
onItemClick(item, e) {
|
2021-03-26 13:03:51 +00:00
|
|
|
if (item.disabled) {
|
|
|
|
e.preventDefault();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!item.url) {
|
|
|
|
e.preventDefault();
|
|
|
|
}
|
|
|
|
|
2021-04-01 10:22:37 +00:00
|
|
|
if (item.onClick) {
|
|
|
|
item.onClick({
|
2021-03-26 13:03:51 +00:00
|
|
|
originalEvent: e,
|
2021-04-05 13:44:55 +00:00
|
|
|
action: item.action,
|
2021-03-26 13:03:51 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!item.items) {
|
|
|
|
this.props.onLeafClick(e);
|
|
|
|
}
|
2019-08-29 13:00:01 +00:00
|
|
|
}
|
|
|
|
|
2021-03-26 13:03:51 +00:00
|
|
|
position() {
|
|
|
|
const parentItem = this.submenuRef.current.parentElement;
|
|
|
|
const containerOffset = DomHelpers.getOffset(
|
|
|
|
this.submenuRef.current.parentElement
|
|
|
|
);
|
|
|
|
const viewport = DomHelpers.getViewport();
|
|
|
|
const sublistWidth = this.submenuRef.current.offsetParent
|
|
|
|
? this.submenuRef.current.offsetWidth
|
|
|
|
: DomHelpers.getHiddenElementOuterWidth(this.submenuRef.current);
|
|
|
|
const itemOuterWidth = DomHelpers.getOuterWidth(parentItem.children[0]);
|
2019-08-29 13:00:01 +00:00
|
|
|
|
2021-03-26 13:03:51 +00:00
|
|
|
this.submenuRef.current.style.top = "0px";
|
2020-01-22 11:39:20 +00:00
|
|
|
|
2021-03-26 13:03:51 +00:00
|
|
|
if (
|
|
|
|
parseInt(containerOffset.left, 10) + itemOuterWidth + sublistWidth >
|
|
|
|
viewport.width - DomHelpers.calculateScrollbarWidth()
|
|
|
|
) {
|
|
|
|
this.submenuRef.current.style.left = -1 * sublistWidth + "px";
|
|
|
|
} else {
|
|
|
|
this.submenuRef.current.style.left = itemOuterWidth + "px";
|
|
|
|
}
|
|
|
|
}
|
2019-08-29 13:00:01 +00:00
|
|
|
|
2021-03-26 13:03:51 +00:00
|
|
|
onEnter() {
|
|
|
|
this.position();
|
|
|
|
}
|
2019-11-11 11:55:05 +00:00
|
|
|
|
2021-03-26 13:03:51 +00:00
|
|
|
isActive() {
|
|
|
|
return this.props.root || !this.props.resetMenu;
|
|
|
|
}
|
2019-11-11 11:55:05 +00:00
|
|
|
|
2021-03-26 13:03:51 +00:00
|
|
|
static getDerivedStateFromProps(nextProps, prevState) {
|
|
|
|
if (nextProps.resetMenu === true) {
|
|
|
|
return {
|
|
|
|
activeItem: null,
|
|
|
|
};
|
2019-08-29 13:00:01 +00:00
|
|
|
}
|
|
|
|
|
2021-03-26 13:03:51 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidUpdate() {
|
|
|
|
if (this.isActive()) {
|
|
|
|
this.position();
|
2019-11-11 11:55:05 +00:00
|
|
|
}
|
2021-03-26 13:03:51 +00:00
|
|
|
}
|
2020-01-20 12:32:19 +00:00
|
|
|
|
2021-03-26 13:03:51 +00:00
|
|
|
renderSeparator(index) {
|
|
|
|
return (
|
|
|
|
<li
|
|
|
|
key={"separator_" + index}
|
2021-05-20 09:54:16 +00:00
|
|
|
className="p-menu-separator not-selectable"
|
2021-03-26 13:03:51 +00:00
|
|
|
role="separator"
|
|
|
|
></li>
|
2020-10-16 13:16:01 +00:00
|
|
|
);
|
2021-03-26 13:03:51 +00:00
|
|
|
}
|
2019-11-11 11:55:05 +00:00
|
|
|
|
2021-03-26 13:03:51 +00:00
|
|
|
renderSubmenu(item) {
|
|
|
|
if (item.items) {
|
|
|
|
return (
|
|
|
|
<ContextMenuSub
|
|
|
|
model={item.items}
|
|
|
|
resetMenu={item !== this.state.activeItem}
|
|
|
|
onLeafClick={this.props.onLeafClick}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
2019-08-29 13:00:01 +00:00
|
|
|
|
2021-03-26 13:03:51 +00:00
|
|
|
return null;
|
|
|
|
}
|
2019-08-29 13:00:01 +00:00
|
|
|
|
2021-03-26 13:03:51 +00:00
|
|
|
renderMenuitem(item, index) {
|
2021-04-02 14:54:52 +00:00
|
|
|
if (item.disabled) return; //TODO: Not render disabled items
|
2021-03-26 13:03:51 +00:00
|
|
|
const active = this.state.activeItem === item;
|
|
|
|
const className = classNames(
|
|
|
|
"p-menuitem",
|
|
|
|
{ "p-menuitem-active": active },
|
|
|
|
item.className
|
|
|
|
);
|
2021-05-20 09:54:16 +00:00
|
|
|
const linkClassName = classNames("p-menuitem-link", "not-selectable", {
|
2021-03-26 13:03:51 +00:00
|
|
|
"p-disabled": item.disabled,
|
|
|
|
});
|
2021-03-30 07:42:10 +00:00
|
|
|
const iconClassName = classNames("p-menuitem-icon", {
|
|
|
|
"p-disabled": item.disabled,
|
|
|
|
});
|
|
|
|
const submenuIconClassName = "p-submenu-icon";
|
|
|
|
const icon = item.icon && (
|
|
|
|
<ReactSVG
|
|
|
|
wrapper="span"
|
|
|
|
className={iconClassName}
|
|
|
|
src={item.icon}
|
|
|
|
></ReactSVG>
|
|
|
|
);
|
2021-03-26 13:03:51 +00:00
|
|
|
const label = item.label && (
|
2021-05-20 09:54:16 +00:00
|
|
|
<span className="p-menuitem-text not-selectable">{item.label}</span>
|
2021-03-26 13:03:51 +00:00
|
|
|
);
|
|
|
|
const submenuIcon = item.items && (
|
2021-03-30 07:42:10 +00:00
|
|
|
<ArrowIcon className={submenuIconClassName} />
|
2021-03-26 13:03:51 +00:00
|
|
|
);
|
|
|
|
const submenu = this.renderSubmenu(item);
|
2021-04-23 12:02:57 +00:00
|
|
|
const dataKeys = Object.fromEntries(
|
|
|
|
Object.entries(item).filter((el) => el[0].indexOf("data-") === 0)
|
|
|
|
);
|
2021-10-21 14:53:28 +00:00
|
|
|
const onClick = (e) => {
|
|
|
|
this.onItemClick(item, e);
|
|
|
|
};
|
2021-03-26 13:03:51 +00:00
|
|
|
let content = (
|
|
|
|
<a
|
|
|
|
href={item.url || "#"}
|
|
|
|
className={linkClassName}
|
|
|
|
target={item.target}
|
2021-04-23 12:02:57 +00:00
|
|
|
{...dataKeys}
|
2021-10-21 14:53:28 +00:00
|
|
|
onClick={onClick}
|
2021-03-26 13:03:51 +00:00
|
|
|
role="menuitem"
|
|
|
|
>
|
|
|
|
{icon}
|
|
|
|
{label}
|
|
|
|
{submenuIcon}
|
|
|
|
</a>
|
|
|
|
);
|
2020-02-06 12:02:20 +00:00
|
|
|
|
2021-03-26 13:03:51 +00:00
|
|
|
if (item.template) {
|
|
|
|
const defaultContentOptions = {
|
2021-10-21 14:53:28 +00:00
|
|
|
onClick,
|
2021-03-26 13:03:51 +00:00
|
|
|
className: linkClassName,
|
|
|
|
labelClassName: "p-menuitem-text",
|
|
|
|
iconClassName,
|
|
|
|
submenuIconClassName,
|
|
|
|
element: content,
|
|
|
|
props: this.props,
|
|
|
|
active,
|
|
|
|
};
|
|
|
|
|
|
|
|
content = ObjectUtils.getJSXElement(
|
|
|
|
item.template,
|
|
|
|
item,
|
|
|
|
defaultContentOptions
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<li
|
|
|
|
key={item.label + "_" + index}
|
|
|
|
role="none"
|
|
|
|
className={className}
|
|
|
|
style={item.style}
|
|
|
|
onMouseEnter={(event) => this.onItemMouseEnter(event, item)}
|
|
|
|
>
|
|
|
|
{content}
|
|
|
|
{submenu}
|
|
|
|
</li>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
renderItem(item, index) {
|
2021-04-05 15:10:26 +00:00
|
|
|
if (!item) return null;
|
2021-04-01 10:22:37 +00:00
|
|
|
if (item.isSeparator) return this.renderSeparator(index);
|
2021-03-26 13:03:51 +00:00
|
|
|
else return this.renderMenuitem(item, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
renderMenu() {
|
|
|
|
if (this.props.model) {
|
|
|
|
return this.props.model.map((item, index) => {
|
|
|
|
return this.renderItem(item, index);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
2020-02-06 12:02:20 +00:00
|
|
|
|
2019-08-29 13:00:01 +00:00
|
|
|
render() {
|
2021-03-26 13:03:51 +00:00
|
|
|
const className = classNames({ "p-submenu-list": !this.props.root });
|
|
|
|
const submenu = this.renderMenu();
|
|
|
|
const isActive = this.isActive();
|
2019-08-29 13:00:01 +00:00
|
|
|
|
2020-10-16 13:16:01 +00:00
|
|
|
return (
|
2021-03-26 13:03:51 +00:00
|
|
|
<CSSTransition
|
|
|
|
nodeRef={this.submenuRef}
|
|
|
|
classNames="p-contextmenusub"
|
|
|
|
in={isActive}
|
|
|
|
timeout={{ enter: 0, exit: 0 }}
|
2021-04-01 10:22:37 +00:00
|
|
|
unmountOnExit={true}
|
2021-03-26 13:03:51 +00:00
|
|
|
onEnter={this.onEnter}
|
|
|
|
>
|
2021-05-20 09:54:16 +00:00
|
|
|
<ul ref={this.submenuRef} className={`${className} not-selectable`}>
|
2021-03-26 13:03:51 +00:00
|
|
|
{submenu}
|
|
|
|
</ul>
|
|
|
|
</CSSTransition>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ContextMenuSub.propTypes = {
|
|
|
|
model: PropTypes.any,
|
|
|
|
root: PropTypes.bool,
|
|
|
|
className: PropTypes.string,
|
|
|
|
resetMenu: PropTypes.bool,
|
|
|
|
onLeafClick: PropTypes.func,
|
|
|
|
};
|
|
|
|
|
|
|
|
ContextMenuSub.defaultProps = {
|
|
|
|
model: null,
|
|
|
|
root: false,
|
|
|
|
className: null,
|
|
|
|
resetMenu: false,
|
|
|
|
onLeafClick: null,
|
|
|
|
};
|
|
|
|
|
|
|
|
class ContextMenu extends Component {
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
this.state = {
|
|
|
|
visible: false,
|
|
|
|
reshow: false,
|
|
|
|
resetMenu: false,
|
|
|
|
};
|
|
|
|
|
|
|
|
this.onMenuClick = this.onMenuClick.bind(this);
|
|
|
|
this.onLeafClick = this.onLeafClick.bind(this);
|
|
|
|
this.onMenuMouseEnter = this.onMenuMouseEnter.bind(this);
|
|
|
|
this.onEnter = this.onEnter.bind(this);
|
|
|
|
this.onEntered = this.onEntered.bind(this);
|
|
|
|
this.onExit = this.onExit.bind(this);
|
|
|
|
this.onExited = this.onExited.bind(this);
|
|
|
|
|
|
|
|
this.menuRef = React.createRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
onMenuClick() {
|
|
|
|
this.setState({
|
|
|
|
resetMenu: false,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
onMenuMouseEnter() {
|
|
|
|
this.setState({
|
|
|
|
resetMenu: false,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
show(e) {
|
|
|
|
if (!(e instanceof Event)) {
|
|
|
|
e.persist();
|
|
|
|
}
|
|
|
|
|
|
|
|
e.stopPropagation();
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
|
|
this.currentEvent = e;
|
|
|
|
|
|
|
|
if (this.state.visible) {
|
|
|
|
this.setState({ reshow: true });
|
|
|
|
} else {
|
|
|
|
this.setState({ visible: true }, () => {
|
|
|
|
if (this.props.onShow) {
|
|
|
|
this.props.onShow(this.currentEvent);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidUpdate(prevProps, prevState) {
|
|
|
|
if (this.state.visible && prevState.reshow !== this.state.reshow) {
|
|
|
|
let event = this.currentEvent;
|
|
|
|
this.setState(
|
|
|
|
{
|
|
|
|
visible: false,
|
|
|
|
reshow: false,
|
|
|
|
rePosition: false,
|
|
|
|
resetMenu: true,
|
|
|
|
},
|
|
|
|
() => this.show(event)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
hide(e) {
|
|
|
|
if (!(e instanceof Event)) {
|
|
|
|
e.persist();
|
|
|
|
}
|
|
|
|
|
|
|
|
this.currentEvent = e;
|
|
|
|
this.setState({ visible: false, reshow: false }, () => {
|
|
|
|
if (this.props.onHide) {
|
|
|
|
this.props.onHide(this.currentEvent);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
onEnter() {
|
|
|
|
if (this.props.autoZIndex) {
|
|
|
|
this.menuRef.current.style.zIndex = String(
|
|
|
|
this.props.baseZIndex + DomHelpers.generateZIndex()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.position(this.currentEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
onEntered() {
|
|
|
|
this.bindDocumentListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
onExit() {
|
|
|
|
this.currentEvent = null;
|
|
|
|
this.unbindDocumentListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
onExited() {
|
|
|
|
DomHelpers.revertZIndex();
|
|
|
|
}
|
|
|
|
|
|
|
|
position(event) {
|
|
|
|
if (event) {
|
|
|
|
let left = event.pageX + 1;
|
|
|
|
let top = event.pageY + 1;
|
|
|
|
let width = this.menuRef.current.offsetParent
|
|
|
|
? this.menuRef.current.offsetWidth
|
|
|
|
: DomHelpers.getHiddenElementOuterWidth(this.menuRef.current);
|
|
|
|
let height = this.menuRef.current.offsetParent
|
|
|
|
? this.menuRef.current.offsetHeight
|
|
|
|
: DomHelpers.getHiddenElementOuterHeight(this.menuRef.current);
|
|
|
|
let viewport = DomHelpers.getViewport();
|
|
|
|
|
|
|
|
//flip
|
|
|
|
if (left + width - document.body.scrollLeft > viewport.width) {
|
|
|
|
left -= width;
|
|
|
|
}
|
|
|
|
|
|
|
|
//flip
|
|
|
|
if (top + height - document.body.scrollTop > viewport.height) {
|
|
|
|
top -= height;
|
|
|
|
}
|
|
|
|
|
|
|
|
//fit
|
|
|
|
if (left < document.body.scrollLeft) {
|
|
|
|
left = document.body.scrollLeft;
|
|
|
|
}
|
|
|
|
|
|
|
|
//fit
|
|
|
|
if (top < document.body.scrollTop) {
|
|
|
|
top = document.body.scrollTop;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.menuRef.current.style.left = left + "px";
|
|
|
|
this.menuRef.current.style.top = top + "px";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onLeafClick(e) {
|
|
|
|
this.setState({
|
|
|
|
resetMenu: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
this.hide(e);
|
|
|
|
|
|
|
|
e.stopPropagation();
|
|
|
|
}
|
|
|
|
|
|
|
|
isOutsideClicked(e) {
|
|
|
|
return (
|
|
|
|
this.menuRef &&
|
|
|
|
this.menuRef.current &&
|
|
|
|
!(
|
|
|
|
this.menuRef.current.isSameNode(e.target) ||
|
|
|
|
this.menuRef.current.contains(e.target)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
bindDocumentListeners() {
|
|
|
|
this.bindDocumentResizeListener();
|
|
|
|
this.bindDocumentClickListener();
|
|
|
|
}
|
|
|
|
|
|
|
|
unbindDocumentListeners() {
|
|
|
|
this.unbindDocumentResizeListener();
|
|
|
|
this.unbindDocumentClickListener();
|
|
|
|
}
|
|
|
|
|
|
|
|
bindDocumentClickListener() {
|
|
|
|
if (!this.documentClickListener) {
|
|
|
|
this.documentClickListener = (e) => {
|
2021-10-11 09:56:17 +00:00
|
|
|
if (this.isOutsideClicked(e)) {
|
|
|
|
//TODO: (&& e.button !== 2) restore after global usage
|
2021-03-26 13:03:51 +00:00
|
|
|
this.hide(e);
|
|
|
|
|
|
|
|
this.setState({
|
|
|
|
resetMenu: true,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
document.addEventListener("click", this.documentClickListener);
|
2021-10-10 20:29:01 +00:00
|
|
|
document.addEventListener("mousedown", this.documentClickListener);
|
2021-03-26 13:03:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bindDocumentContextMenuListener() {
|
|
|
|
if (!this.documentContextMenuListener) {
|
|
|
|
this.documentContextMenuListener = (e) => {
|
|
|
|
this.show(e);
|
|
|
|
};
|
|
|
|
|
|
|
|
document.addEventListener(
|
|
|
|
"contextmenu",
|
|
|
|
this.documentContextMenuListener
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bindDocumentResizeListener() {
|
|
|
|
if (!this.documentResizeListener) {
|
|
|
|
this.documentResizeListener = (e) => {
|
|
|
|
if (this.state.visible) {
|
|
|
|
this.hide(e);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
window.addEventListener("resize", this.documentResizeListener);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unbindDocumentClickListener() {
|
|
|
|
if (this.documentClickListener) {
|
|
|
|
document.removeEventListener("click", this.documentClickListener);
|
2021-10-10 20:29:01 +00:00
|
|
|
document.removeEventListener("mousedown", this.documentClickListener);
|
2021-03-26 13:03:51 +00:00
|
|
|
this.documentClickListener = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unbindDocumentContextMenuListener() {
|
|
|
|
if (this.documentContextMenuListener) {
|
|
|
|
document.removeEventListener(
|
|
|
|
"contextmenu",
|
|
|
|
this.documentContextMenuListener
|
|
|
|
);
|
|
|
|
this.documentContextMenuListener = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unbindDocumentResizeListener() {
|
|
|
|
if (this.documentResizeListener) {
|
|
|
|
window.removeEventListener("resize", this.documentResizeListener);
|
|
|
|
this.documentResizeListener = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
if (this.props.global) {
|
|
|
|
this.bindDocumentContextMenuListener();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
this.unbindDocumentListeners();
|
|
|
|
this.unbindDocumentContextMenuListener();
|
|
|
|
|
|
|
|
DomHelpers.revertZIndex();
|
|
|
|
}
|
|
|
|
|
|
|
|
renderContextMenu() {
|
|
|
|
const className = classNames(
|
|
|
|
"p-contextmenu p-component",
|
|
|
|
this.props.className
|
|
|
|
);
|
|
|
|
|
|
|
|
return (
|
2021-03-30 07:42:10 +00:00
|
|
|
<StyledContextMenu>
|
|
|
|
<CSSTransition
|
|
|
|
nodeRef={this.menuRef}
|
|
|
|
classNames="p-contextmenu"
|
|
|
|
in={this.state.visible}
|
|
|
|
timeout={{ enter: 250, exit: 0 }}
|
|
|
|
unmountOnExit
|
|
|
|
onEnter={this.onEnter}
|
|
|
|
onEntered={this.onEntered}
|
|
|
|
onExit={this.onExit}
|
|
|
|
onExited={this.onExited}
|
2020-10-16 13:16:01 +00:00
|
|
|
>
|
2021-03-30 07:42:10 +00:00
|
|
|
<div
|
|
|
|
ref={this.menuRef}
|
|
|
|
id={this.props.id}
|
|
|
|
className={className}
|
|
|
|
style={this.props.style}
|
|
|
|
onClick={this.onMenuClick}
|
|
|
|
onMouseEnter={this.onMenuMouseEnter}
|
|
|
|
>
|
|
|
|
<ContextMenuSub
|
|
|
|
model={this.props.model}
|
|
|
|
root
|
|
|
|
resetMenu={this.state.resetMenu}
|
|
|
|
onLeafClick={this.onLeafClick}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</CSSTransition>
|
|
|
|
</StyledContextMenu>
|
2020-10-16 13:16:01 +00:00
|
|
|
);
|
2019-09-09 13:44:37 +00:00
|
|
|
}
|
2021-03-26 13:03:51 +00:00
|
|
|
|
|
|
|
render() {
|
|
|
|
const element = this.renderContextMenu();
|
|
|
|
|
|
|
|
return <Portal element={element} appendTo={this.props.appendTo} />;
|
|
|
|
}
|
2019-08-29 13:00:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ContextMenu.propTypes = {
|
2021-04-01 10:22:37 +00:00
|
|
|
/** Unique identifier of the element */
|
2019-11-27 13:06:48 +00:00
|
|
|
id: PropTypes.string,
|
2021-04-01 10:22:37 +00:00
|
|
|
/** An array of menuitems */
|
2021-03-26 13:03:51 +00:00
|
|
|
model: PropTypes.array,
|
2021-04-01 10:22:37 +00:00
|
|
|
/** Inline style of the component */
|
2021-03-26 13:03:51 +00:00
|
|
|
style: PropTypes.object,
|
2021-04-01 10:22:37 +00:00
|
|
|
/** Style class of the component */
|
2021-03-26 13:03:51 +00:00
|
|
|
className: PropTypes.string,
|
2021-04-01 10:22:37 +00:00
|
|
|
/** Attaches the menu to document instead of a particular item */
|
2021-03-26 13:03:51 +00:00
|
|
|
global: PropTypes.bool,
|
2021-04-01 10:22:37 +00:00
|
|
|
/** Base zIndex value to use in layering */
|
2021-03-26 13:03:51 +00:00
|
|
|
autoZIndex: PropTypes.bool,
|
2021-04-01 10:22:37 +00:00
|
|
|
/** Whether to automatically manage layering */
|
2021-03-26 13:03:51 +00:00
|
|
|
baseZIndex: PropTypes.number,
|
2021-04-01 10:22:37 +00:00
|
|
|
/** DOM element instance where the menu should be mounted */
|
2021-03-26 13:03:51 +00:00
|
|
|
appendTo: PropTypes.any,
|
2021-04-01 10:22:37 +00:00
|
|
|
/** Callback to invoke when a popup menu is shown */
|
2021-03-26 13:03:51 +00:00
|
|
|
onShow: PropTypes.func,
|
2021-04-01 10:22:37 +00:00
|
|
|
/** Callback to invoke when a popup menu is hidden */
|
2021-03-26 13:03:51 +00:00
|
|
|
onHide: PropTypes.func,
|
2019-08-29 13:00:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
ContextMenu.defaultProps = {
|
2021-03-26 13:03:51 +00:00
|
|
|
id: null,
|
|
|
|
model: null,
|
|
|
|
style: null,
|
|
|
|
className: null,
|
|
|
|
global: false,
|
|
|
|
autoZIndex: true,
|
|
|
|
baseZIndex: 0,
|
|
|
|
appendTo: null,
|
|
|
|
onShow: null,
|
|
|
|
onHide: null,
|
2019-08-29 13:00:01 +00:00
|
|
|
};
|
|
|
|
|
2020-10-16 13:16:01 +00:00
|
|
|
export default ContextMenu;
|