Context menu - Rete.js

Context menu

This guide is based on the Basic guide. It is recommended to review it for a comprehensive understanding of this guide.

Context menuPlugin

Install dependencies

bash
npm i rete-context-menu-plugin

Prepare nodes

To improve convenience and code reusability, it is recommended to create separate classes for nodes:

ts
class NodeA extends ClassicPreset.Node {
  constructor(socket: ClassicPreset.Socket) {
    super("NodeA");

    this.addControl("port", new ClassicPreset.InputControl("text", {}));
    this.addOutput("port", new ClassicPreset.Output(socket));
  }
}

/// class NodeB extends ...

type Node = NodeA | NodeB;
type Schemes = GetSchemes<Node, Connection<Node, Node>>;

Plugin connection

For a simple solution, use the classic preset and specify a list of labeled items along with a function that returns the required node

ts
import { ContextMenuExtra, ContextMenuPlugin, Presets as ContextMenuPresets } from "rete-context-menu-plugin";

type AreaExtra = ReactArea2D<Schemes> | ContextMenuExtra;

const contextMenu = new ContextMenuPlugin<Schemes>({
  items: ContextMenuPresets.classic.setup([
    ["NodeA", () => new NodeA(socket)],
    ["NodeB", () => new NodeB(socket)]
  ])
});

area.use(contextMenu);

But this is not sufficient as the render plugin is responsible for visualization

Rendering the context menu

Currently, the visualization of the context menu is possible using rendering plugins for React.js, Vue.js, Angular, Svelte and Lit.

ts
import { Presets } from "rete-react-plugin"; // or  rete-vue-plugin, rete-angular-plugin, rete-svelte-plugin, @retejs/lit-plugin

render.addPreset(Presets.contextMenu.setup());

For a comprehensive guide on how to connect a specific renderer plugin to your stack version, please follow the guide for React.js, Vue.js, Angular, Svelte or Lit

Clicking on the free space opens up a menu that displays the available nodes for creation, or simply click on an existing node to delete it.

Subitems

In order to specify node item as subitem, you can use the same definition using an array instead of a factory function:

ts
const contextMenu = new ContextMenuPlugin<Schemes>({
  items: ContextMenuPresets.classic.setup([
    ["Math", [
      ["Number", () => new NumberNode()],
    ]]
  ])
})

Custom preset

While the classic preset lets you briefly specify items for the main menu and node-specific menu, it might not offer enough flexibility. In such cases, you can define your own menu items:

ts
const contextMenu = new ContextMenuPlugin<Schemes>({
  items(context, plugin) {
    if (context === 'root') {
      return {
        searchBar: false,
        list: [
          { label: 'Custom', key: '1', handler: () => console.log('Custom') },
          {
            label: 'Collection', key: '1', handler: () => null,
            subitems: [
              { label: 'Subitem', key: '1', handler: () => console.log('Subitem') }
            ]
          }
        ]
      }
    }
    return {
      searchBar: false,
      list: []
    }
  }
})

where context is 'root', node instance or connection instance

Check out the complete result on the Context menu example page.