<!DOCTYPE html>
<html>
<head>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="root"></div>
<script src="script.js"></script>
</body>
</html>
/* Styles go here */
body{
font-family: initial;
font-size: 14px;
}
.custom-context{
border: solid 1px #ccc;
display: inline-block;
margin: 5px;
background: #FFF;
color: #000;
font-family: sans-serif;
cursor: pointer;
font-size: 12px;
}
.custom-context-item{
border-bottom: dotted 1px #ccc;
padding: 5px 25px;
}
.custom-context-item-last{
padding: 5px 25px;
}
class App extends React.Component {
constructor(props) {
super(props);
this.state={
"menu":[
{"label": "Item 1", "callback": this.itemCallback},
{"label": "Menu item 2", "callback": this.item2Callback},
{"label": "Apple", "callback": this.appleCallback},
{"label": "This is orange", "callback": this.orangeCallback},
{"label": "Conetxt menu is fun", },
{"label": "Cool", "callback": this.coolCallback}
]
}
}
itemCallback() {
alert("clicked on Item 1")
}
item2Callback() {
alert("clicked on Item 2")
}
appleCallback() {
alert("clicked on Apple")
}
orangeCallback() {
alert("clicked on Orange")
}
coolCallback(){
alert("clicked on Cool")
}
render() {
return (<div>
<h1>Hello, React</h1>
<p>Implementing custom context menu in react.js</p>
<p> Right click anywhere on the screen to see the menu defined below</p>
{JSON.stringify(this.state.menu)}
<CustomContext items={this.state.menu}>
</CustomContext>
</div>
)
}
}
class CustomContext extends React.Component{
constructor(props) {
super(props);
this.contextRef = React.createRef();
this.returnMenu = this.returnMenu.bind(this);
this.state={
visible: false,
x: 0,
y: 0
};
}
componentDidMount(){
var self=this;
document.addEventListener('contextmenu', function(event){
event.preventDefault();
const clickX = event.clientX;
const clickY = event.clientY;
self.setState({ visible: true, x: clickX, y: clickY });
});
document.addEventListener('click', function(event){
if(self.contextRef.current.id=='customcontext'){
self.click(event.target.getAttribute('index'));
}
event.preventDefault();
self.setState({ visible: false, x:0, y:0});
});
}
click(index) {
if(this.props.items[index].callback)
this.props.items[index].callback();
else{
console.log("callback not registered for the menu item")
}
}
returnMenu(items){
var myStyle = {
'position': 'absolute',
'top': `${this.state.y}px`,
'left':`${this.state.x+5}px`
}
var self=this;
return <div className='custom-context' id='customcontext' style={myStyle} ref={this.contextRef}>
{items.map((item, index, arr) =>{
if(arr.length-1==index){
return <div key={index} className='custom-context-item-last' index={index}>{item.label}</div>
}else{
return <div key={index} className='custom-context-item' index={index}>{item.label}</div>
}
})}
</div>;
}
render() {
return (<div id='cmenu'>
{this.state.visible ? this.returnMenu(this.props.items): null}
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);