vkbansal / react-contextmenu

Project is no longer maintained
MIT License
1.4k stars 375 forks source link

<ContextMenuTrigger> without creating additional <div> #323

Closed koutsenko closed 4 years ago

koutsenko commented 4 years ago

Can we attach trigger to already existing DOM element?

vkbansal commented 4 years ago

Sorry. This is not supported in the current version.

jkmcclinton commented 4 years ago

Are there any plans to add this as a feature? I just had to do a hotfix/workaround for a <tr> context menu by simply extracting some of the code from the ContextTrigger and the global event dispatcher... but it would be nice if there were some sort of bind function that allows you to apply this directly to components or DOMs

vkbansal commented 4 years ago

I might add this feature in next major release.

volodymyrlytvyn commented 4 years ago

Are there any plans to add this as a feature? I just had to do a hotfix/workaround for a <tr> context menu by simply extracting some of the code from the ContextTrigger and the global event dispatcher... but it would be nice if there were some sort of bind function that allows you to apply this directly to components or DOMs

Kryptiique, Could you please share how you did a workaround I am also tryib to use this menu with material-ui table (TableRow), but adding ContextMenuTrigger breaks the table. It is not breaken if I use renderTag='tr' but I need TableRow as I have logic related to it

jkmcclinton commented 4 years ago

@volodymyrlytvyn I'm not sure about your specific case, but here's what I did for my workaround. Please note this solution isn't very extensible and I just used it for a single component. In my row component I added a modified version of handleContextClick():


import { callIfExists, store } from 'react-contextmenu/modules/helpers'

export default class Row extends Component {

// ...

handleContextClick = (event, id) => {
  if (this.props.disable) return;
  // if (this.props.disableIfShiftIsPressed && event.shiftKey) return;

  event.preventDefault();
  event.stopPropagation();

  let x = event.clientX || (event.touches && event.touches[0].pageX);
  let y = event.clientY || (event.touches && event.touches[0].pageY);

  if (this.props.posX) {
      x -= this.props.posX;
  }
  if (this.props.posY) {
      y -= this.props.posY;
  }

  hideMenu();

  let data = callIfExists(this.props.collect, this.props);
  let showMenuConfig = {
      position: { x, y },
      target: this.elem,
      id: `ctx-${ id }`
  };
  if (data && (typeof data.then === 'function')) {
      // it's a promise
      data.then((resp) => {
          showMenuConfig.data = Object.assign({}, resp, {
              target: event.target
          });
          showMenu(showMenuConfig);
      });
  } else {
      showMenuConfig.data = Object.assign({}, data, {
          target: event.target
      });
      showMenu(showMenuConfig);
  }
}

Then I copied this code from react-contextmenu/actions.js and modified it a bit:

export const MENU_SHOW = 'REACT_CONTEXTMENU_SHOW';
export const MENU_HIDE = 'REACT_CONTEXTMENU_HIDE';

export function dispatchGlobalEvent(eventName, opts, target = window) {
  let event;

  if (typeof window.CustomEvent === 'function') {
    event = new window.CustomEvent(eventName, { detail: opts });
  } else {
    event = document.createEvent('CustomEvent');
    event.initCustomEvent(eventName, false, true, opts);
  }

  if (target) {
    target.dispatchEvent(event)
    Object.assign(store, opts)
  }
}

export function showMenu(opts = {}, target) {
  dispatchGlobalEvent(MENU_SHOW, Object.assign(opts, { type: MENU_SHOW }), target);
}

export function hideMenu(opts = {}, target) {
  dispatchGlobalEvent(MENU_HIDE, Object.assign(opts, { type: MENU_HIDE }), target);
}
vkbansal commented 4 years ago

closing issue see #339