<!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')
);