createContextMenu.ts 2.11 KB
import { NodeMouseEvent } from '@vue-flow/core';
import ContextMenuVue from './index.vue';
import { isClient } from '/@/utils/is';
import { createVNode, render, getCurrentInstance, onUnmounted, toRaw, unref } from 'vue';

const menuManager: {
  domList: Element[];
  resolve: Fn;
} = {
  domList: [],
  resolve: () => {},
};

const createContextMenu = function (
  options: NodeMouseEvent,
  params?: InstanceType<typeof ContextMenuVue>['$props']
) {
  const { event } = options || {};

  if (!(params?.items && params?.items.length)) return;

  event && event?.preventDefault();

  if (!isClient) {
    return;
  }

  return new Promise((resolve) => {
    const body = document.body;

    const container = document.createElement('div');
    const propsData: Partial<InstanceType<typeof ContextMenuVue>['$props']> = {
      ...params,
    };

    if (options.event) {
      const { clientX, clientY } = options.event as MouseEvent;
      propsData.axis = { x: clientX, y: clientY };
    }

    if (options.node) {
      propsData.nodeData = toRaw(unref(options.node.data));
    }

    const vm = createVNode(ContextMenuVue, propsData);
    render(vm, container);

    const handleClick = function () {
      menuManager.resolve('');
    };

    menuManager.domList.push(container);

    const remove = function () {
      menuManager.domList.forEach((dom: Element) => {
        try {
          dom && body.removeChild(dom);
        } catch (error) {}
      });
      body.removeEventListener('click', handleClick);
      body.removeEventListener('scroll', handleClick);
    };

    menuManager.resolve = function (arg) {
      remove();
      resolve(arg);
    };
    remove();
    body.appendChild(container);
    body.addEventListener('click', handleClick);
    body.addEventListener('scroll', handleClick);
  });
};

const destroyContextMenu = function () {
  if (menuManager) {
    menuManager.resolve('');
    menuManager.domList = [];
  }
};

export function useContextMenu(authRemove = true) {
  if (getCurrentInstance() && authRemove) {
    onUnmounted(() => {
      destroyContextMenu();
    });
  }
  return [createContextMenu, destroyContextMenu];
}