Custom popup menu entries

Hi everyone,

im currently trying to customize a popup-menu. More precisely i am trying to add an entry to the color picker module, to give users the ability to define and use a custom color.

What i’ve got so far:

  1. Embedded the color picker module
  2. Register a popup menu provider for the color-picker module (see code below)
class CustomPopupMenuProvider {

    static $inject: string[] = ['popupMenu'];

    constructor(popupMenu) {
        popupMenu.registerProvider('color-picker', this);
    }

    getPopupMenuEntries() {
        // return some custom entry here
    }
}

export default {
    __init__: ["customPopupMenuProvider"],
    customPopupMenuProvider: ["type", CustomPopupMenuProvider],
}

Where i’m stuck:

The entry should have textfield/color input to define custom colors (e.g. fill color and text color). The following picture gives an idea of what it should look like inside the custom popup:

Bildschirm­foto 2023-09-15 um 10.29.31

I am wondering about the best approach to realize this kind of functionality. Is there a way to integrate such a feature using bpmn-js/diagram-js?

Thanks in advance,
Luka :slight_smile:

Hi,

You could check out the color picker plugin we built for bpmn-js: GitHub - bpmn-io/bpmn-js-color-picker: A simple color picker for your BPMN elements.

I’m trying to extend the functionality of bpmn-js to add a custom color picker using a PopupMenu. However, if I implement the getPopupMenuEntries method as required by PopupMenuProvider, the example stops working. Specifically, my custom ContextPadProvider functionality (which opens the color picker menu) disappears.

Here’s the code I’m using:

import { PopupMenu } from "bpmn-js/lib/features/context-pad/ContextPadProvider";

import Modeling from "bpmn-js/lib/features/modeling/Modeling";

import { Attrs, BpmnRendererConfig } from "bpmn-js/lib/draw/BpmnRenderer";
import { CSSProperties } from "react";
import { ModdleElement } from "bpmn-js/lib/BaseViewer";
import { Element } from "bpmn-js/lib/model/Types";

const COLORS = [
  {
    label: "Default",
    fill: undefined,
    stroke: undefined,
  },
  {
    label: "Blue",
    fill: "#BBDEFB",
    stroke: "#0D4372",
  },
  {
    label: "Orange",
    fill: "#FFE0B2",
    stroke: "#6B3C00",
  },
  {
    label: "Green",
    fill: "#C8E6C9",
    stroke: "#205022",
  },
  {
    label: "Red",
    fill: "#FFCDD2",
    stroke: "#831311",
  },
  {
    label: "Purple",
    fill: "#E1BEE7",
    stroke: "#5B176D",
  },
];

interface ConfigType extends Attrs {
  label?: string;
}

export default class ColorPopupProvider {
  private _popupMenu: PopupMenu;
  private _modeling: Modeling;
  private _colors: ConfigType[];
  private _defaultFillColor: CSSProperties["fill"];
  private _defaultStrokeColor: CSSProperties["stroke"];

  constructor(
    config: Element,
    bpmnRendererConfig: BpmnRendererConfig,
    popupMenu: PopupMenu,
    modeling: Modeling
  ) {
    this._popupMenu = popupMenu;
    this._modeling = modeling;

    this._colors = (config && config.colors) || COLORS;
    this._defaultFillColor =
      (bpmnRendererConfig && bpmnRendererConfig.defaultFillColor) || "white";
    this._defaultStrokeColor =
      (bpmnRendererConfig && bpmnRendererConfig.defaultStrokeColor) ||
      "rgb(34, 36, 42)";
    // @ts-expect-error: Ignoramos este error porque TypeScript no reconoce que el registro funcionará sin getPopupMenuEntries
    this._popupMenu.registerProvider("color-picker", this);
  }

  getEntries(elements: ModdleElement[]) {
    const colorIconHtml = `
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 25" height="100%" width="100%">
        <rect rx="2" x="1" y="1" width="22" height="22" fill="var(--fill-color)" stroke="var(--stroke-color)" style="stroke-width:2"></rect>
      </svg>
    `;

    return this._colors.map((color) => {
      const entryColorIconHtml = colorIconHtml
        .replace(
          "var(--fill-color)",
          color.fill || this._defaultFillColor || "white"
        )
        .replace(
          "var(--stroke-color)",
          color.stroke || this._defaultStrokeColor || "black"
        );

      return {
        title: color.label,
        id: color?.label?.toLowerCase() + "-color",
        imageHtml: entryColorIconHtml,
        action: this._createAction(elements, color),
      };
    });
  }

  _createAction(elements: ModdleElement[], color: Attrs) {
    return () => {
      this._modeling.setColor(elements, color);
    };
  }
  // getPopupMenuEntries(element: Element): Record<string, any> {
  //   return {};
  // }

  static $inject = [
    "config.colorPicker",
    "config.bpmnRenderer",
    "popupMenu",
    "modeling",
  ];
}

Please do not necrobump old topics. Instead link to this thread from new topic.