├── .github
└── workflows
│ └── CI.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── colors
├── ColorContextPadProvider.js
├── ColorPopupProvider.js
├── color-picker.css
└── index.js
├── eslint.config.mjs
├── example
├── app.js
├── index.html
├── newDiagram.bpmn
└── style.css
├── package-lock.json
├── package.json
├── renovate.json
├── resources
└── screenshot.png
└── webpack.config.js
/.github/workflows/CI.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on: [ push, pull_request ]
3 | jobs:
4 | Build:
5 |
6 | strategy:
7 | matrix:
8 | os: [ ubuntu-latest ]
9 | node-version: [ 20 ]
10 |
11 | runs-on: ${{ matrix.os }}
12 |
13 | steps:
14 | - name: Checkout
15 | uses: actions/checkout@v4
16 | - name: Use Node.js
17 | uses: actions/setup-node@v4
18 | with:
19 | node-version: ${{ matrix.node-version }}
20 | cache: 'npm'
21 | - name: Install dependencies
22 | run: npm ci
23 | - name: Build
24 | run: npm run all
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | public/
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to [bpmn-js-color-picker](https://github.com/bpmn-io/bpmn-js-color-picker) are documented here. We use [semantic versioning](http://semver.org/) for releases.
4 |
5 | ## Unreleased
6 |
7 | ___Note:__ Yet to be released changes appear here._
8 |
9 | ## 0.7.1
10 |
11 | * `FIX`: correct positioning of color picker ([#40](https://github.com/bpmn-io/bpmn-js-color-picker/issues/40))
12 |
13 | ## 0.7.0
14 |
15 | * `FEAT`: sentence-case labels ([`325dd81`](https://github.com/bpmn-io/bpmn-js-color-picker/commit/325dd813c3fc784df92fa27104bc5290d15aa190))
16 | * `FEAT`: use `imageHtml` for icon rendering ([`36b39a9`](https://github.com/bpmn-io/bpmn-js-color-picker/commit/36b39a9267c19f61b415b384123a711ca38e3a38))
17 | * `FEAT`: add `module` export
18 |
19 | ## 0.6.1
20 |
21 | * `CHORE`: add LICENSE
22 |
23 | ## 0.6.0
24 |
25 | * `FEAT`: allow icon hover styling ([#24](https://github.com/bpmn-io/bpmn-js-color-picker/pull/24), [#27](https://github.com/bpmn-io/bpmn-js-color-picker/pull/27))
26 | * `FEAT`: respect default renderer fill and stoke color ([#26](https://github.com/bpmn-io/bpmn-js-color-picker/pull/26))
27 |
28 | ## 0.5.0
29 |
30 | * `FEAT`: improve default color contrast ([#9](https://github.com/bpmn-io/bpmn-js-color-picker/pull/9))
31 | * `FEAT`: integrate with new popup menu ([#10](https://github.com/bpmn-io/bpmn-js-color-picker/issues/10))
32 | * `FEAT`: integrate with multi-element context pad ([#13](https://github.com/bpmn-io/bpmn-js-color-picker/issues/13))
33 | * `FEAT`: dynamically generate entry colors ([#12](https://github.com/bpmn-io/bpmn-js-color-picker/issues/12))
34 | * `FEAT`: be able to provide custom colors ([#11](https://github.com/bpmn-io/bpmn-js-color-picker/issues/11))
35 | * `DEPS`: update to `bpmn-js@11`
36 |
37 | ## 0.4.0
38 |
39 | * `FEAT`: simplify color picker
40 | * `FEAT`: translate color picker entries
41 |
42 | ## ...
43 |
44 | Check `git log` for earlier history.
45 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016-present Camunda Services GmbH
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # bpmn-js Color Picker
2 |
3 | [](https://github.com/bpmn-io/bpmn-js-color-picker/actions/workflows/CI.yml)
4 |
5 | This [bpmn-js](https://github.com/bpmn-io/bpmn-js) extension adds a simple color picker to an elements context pad. Colors are serialized to BPMN 2.0 according to the [BPMN in Color proposal](https://github.com/bpmn-miwg/bpmn-in-color).
6 |
7 | 
8 |
9 |
10 | ## Features
11 |
12 | * Add color picker to the context pad
13 | * Color single and multiple elements
14 | * Serialize colors to BPMN 2.0
15 | * Render colors (built-in `bpmn-js@8.7+`)
16 |
17 |
18 | ## Use Extension
19 |
20 | Fetch `bpmn-js-color-picker` as a dependency:
21 |
22 | ```
23 | npm install bpmn-js-color-picker --save
24 | ```
25 |
26 | Extend your BPMN modeler with colors:
27 |
28 | ```javascript
29 | import BpmnModeler from 'bpmn-js/lib/Modeler';
30 |
31 | import BpmnColorPickerModule from 'bpmn-js-color-picker';
32 |
33 | const modeler = new BpmnModeler({
34 | additionalModules: [
35 | BpmnColorPickerModule
36 | ]
37 | });
38 | ```
39 |
40 | Add diagram-js, bpmn-font and [color picker](./colors/color-picker.css) stylesheets:
41 |
42 | ```html
43 |
44 |
45 |
46 | ```
47 |
48 |
49 | ## Build Demo
50 |
51 | To run the live demo in the [`./example` directory](./example) (as shown in the screenshot above) execute:
52 |
53 | ```
54 | npm start
55 | ```
56 |
57 |
58 | ## Useful Resources
59 |
60 | * [Introduction to bpmn-js](https://bpmn.io/toolkit/bpmn-js/walkthrough/)
61 | * [Colors are here](https://bpmn.io/blog/posts/2016-colors-bpmn-js.html)
62 |
--------------------------------------------------------------------------------
/colors/ColorContextPadProvider.js:
--------------------------------------------------------------------------------
1 | const colorImageSvg = ``;
4 |
5 |
6 | export default function ColorContextPadProvider(contextPad, popupMenu, canvas, translate) {
7 |
8 | this._contextPad = contextPad;
9 | this._popupMenu = popupMenu;
10 | this._canvas = canvas;
11 | this._translate = translate;
12 |
13 | contextPad.registerProvider(this);
14 | }
15 |
16 |
17 | ColorContextPadProvider.$inject = [
18 | 'contextPad',
19 | 'popupMenu',
20 | 'canvas',
21 | 'translate'
22 | ];
23 |
24 |
25 | ColorContextPadProvider.prototype.getContextPadEntries = function(element) {
26 | return this._createPopupAction([ element ]);
27 | };
28 |
29 |
30 | ColorContextPadProvider.prototype.getMultiElementContextPadEntries = function(elements) {
31 |
32 | return this._createPopupAction(elements);
33 | };
34 |
35 | ColorContextPadProvider.prototype._createPopupAction = function(elements) {
36 |
37 | const translate = this._translate;
38 | const contextPad = this._contextPad;
39 | const popupMenu = this._popupMenu;
40 |
41 | return {
42 | 'set-color': {
43 | group: 'edit',
44 | className: 'bpmn-icon-color',
45 | title: translate('Set color'),
46 | html: `
${colorImageSvg}
`,
47 | action: {
48 | click: (event, element) => {
49 |
50 | // get start popup draw start position
51 | var position = {
52 | ...getStartPosition(contextPad, elements),
53 | cursor: {
54 | x: event.x,
55 | y: event.y
56 | }
57 | };
58 |
59 | // open new color-picker popup
60 | popupMenu.open(elements, 'color-picker', position);
61 | }
62 | }
63 | }
64 | };
65 |
66 | };
67 |
68 |
69 | // helpers //////////////////////
70 |
71 | function getStartPosition(contextPad, elements) {
72 |
73 | var Y_OFFSET = 5;
74 |
75 | var pad = contextPad.getPad(elements).html;
76 |
77 | var padRect = pad.getBoundingClientRect();
78 |
79 | var pos = {
80 | x: padRect.left,
81 | y: padRect.bottom + Y_OFFSET
82 | };
83 |
84 | return pos;
85 | }
86 |
--------------------------------------------------------------------------------
/colors/ColorPopupProvider.js:
--------------------------------------------------------------------------------
1 | const COLORS = [ {
2 | label: 'Default',
3 | fill: undefined,
4 | stroke: undefined
5 | }, {
6 | label: 'Blue',
7 | fill: '#BBDEFB',
8 | stroke: '#0D4372'
9 | }, {
10 | label: 'Orange',
11 | fill: '#FFE0B2',
12 | stroke: '#6B3C00'
13 | }, {
14 | label: 'Green',
15 | fill: '#C8E6C9',
16 | stroke: '#205022'
17 | }, {
18 | label: 'Red',
19 | fill: '#FFCDD2',
20 | stroke: '#831311'
21 | }, {
22 | label: 'Purple',
23 | fill: '#E1BEE7',
24 | stroke: '#5B176D'
25 | } ];
26 |
27 |
28 | export default function ColorPopupProvider(config, bpmnRendererConfig, popupMenu, modeling, translate) {
29 | this._popupMenu = popupMenu;
30 | this._modeling = modeling;
31 | this._translate = translate;
32 |
33 | this._colors = config && config.colors || COLORS;
34 | this._defaultFillColor = bpmnRendererConfig && bpmnRendererConfig.defaultFillColor || 'white';
35 | this._defaultStrokeColor = bpmnRendererConfig && bpmnRendererConfig.defaultStrokeColor || 'rgb(34, 36, 42)';
36 |
37 | this._popupMenu.registerProvider('color-picker', this);
38 | }
39 |
40 |
41 | ColorPopupProvider.$inject = [
42 | 'config.colorPicker',
43 | 'config.bpmnRenderer',
44 | 'popupMenu',
45 | 'modeling',
46 | 'translate'
47 | ];
48 |
49 |
50 | ColorPopupProvider.prototype.getEntries = function(elements) {
51 | var self = this;
52 |
53 | var colorIconHtml = `
54 |
57 | `;
58 |
59 | var entries = this._colors.map(function(color) {
60 |
61 | var entryColorIconHtml = colorIconHtml.replace('var(--fill-color)', color.fill || self._defaultFillColor)
62 | .replace('var(--stroke-color)', color.stroke || self._defaultStrokeColor);
63 |
64 | return {
65 | title: self._translate(color.label),
66 | id: color.label.toLowerCase() + '-color',
67 | imageHtml: entryColorIconHtml,
68 | action: createAction(self._modeling, elements, color)
69 | };
70 | });
71 |
72 | return entries;
73 | };
74 |
75 |
76 | function createAction(modeling, element, color) {
77 | return function() {
78 | modeling.setColor(element, color);
79 | };
80 | }
--------------------------------------------------------------------------------
/colors/color-picker.css:
--------------------------------------------------------------------------------
1 | /* COLOR PICKER */
2 |
3 | .djs-popup.color-picker .entry {
4 | margin: 0;
5 | }
6 |
7 | .djs-popup.color-picker .djs-popup-group {
8 | display: grid;
9 | grid: auto-flow / 1fr 1fr 1fr;
10 | }
--------------------------------------------------------------------------------
/colors/index.js:
--------------------------------------------------------------------------------
1 | import ColorContextPadProvider from './ColorContextPadProvider';
2 | import ColorPopupProvider from './ColorPopupProvider';
3 |
4 | export default {
5 | __init__: [
6 | 'colorContextPadProvider',
7 | 'colorPopupProvider'
8 | ],
9 | colorContextPadProvider: [ 'type', ColorContextPadProvider ],
10 | colorPopupProvider: [ 'type', ColorPopupProvider ]
11 | };
--------------------------------------------------------------------------------
/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import bpmnIoPlugin from 'eslint-plugin-bpmn-io';
2 |
3 | const files = {
4 | ignored: [ 'dist' ],
5 | build: [
6 | '*.js',
7 | '*.mjs'
8 | ]
9 | };
10 |
11 | export default [
12 | {
13 | ignores: files.ignored,
14 | },
15 | ...bpmnIoPlugin.configs.browser.map(config => {
16 | return {
17 | ...config,
18 | ignores: files.build
19 | };
20 | }),
21 | ...bpmnIoPlugin.configs.node.map(config => {
22 | return {
23 | ...config,
24 | files: files.build
25 | };
26 | })
27 | ];
--------------------------------------------------------------------------------
/example/app.js:
--------------------------------------------------------------------------------
1 | import newDiagramXML from './newDiagram.bpmn';
2 |
3 | import ColorPickerModule from '..';
4 |
5 | import BpmnModeler from 'bpmn-js/lib/Modeler';
6 |
7 |
8 | const canvas = document.querySelector('#canvas');
9 |
10 | const modeler = new BpmnModeler({
11 | container: canvas,
12 | additionalModules: [
13 | ColorPickerModule
14 | ]
15 | });
16 |
17 | modeler.importXML(newDiagramXML).then(result => {
18 |
19 | const {
20 | warnings = []
21 | } = result;
22 |
23 | if (warnings.length) {
24 | console.log('imported with warnings', warnings);
25 | }
26 | }).catch(error => {
27 | console.error('import error', error);
28 | });
29 |
30 |
31 | // hook up with UI elements
32 | document.querySelector('#export-to-console').addEventListener('click', function(e) {
33 |
34 | e.preventDefault();
35 |
36 | modeler.saveXML({
37 | format: true
38 | }).then(result => {
39 | console.log(result.xml);
40 | }).catch(err => {
41 | console.error(err);
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Bpmn-js In Color
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/example/newDiagram.bpmn:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/example/style.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | height: 100%;
3 | width: 100%;
4 | margin: 0;
5 | padding: 0;
6 | }
7 |
8 | .canvas {
9 | position: absolute;
10 | left: 0;
11 | top: 0;
12 | bottom: 0;
13 | right: 0;
14 | }
15 |
16 | /* EXPORT TO CONSOLE */
17 | .export {
18 | position: absolute;
19 | top: 20px;
20 | right: 50%;
21 | }
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bpmn-js-color-picker",
3 | "version": "0.7.1",
4 | "description": "A color picker for bpmn-js",
5 | "scripts": {
6 | "dev": "npm start",
7 | "all": "run-s lint test",
8 | "start": "webpack serve --open",
9 | "lint": "eslint .",
10 | "test": "echo 'no tests ;-)'"
11 | },
12 | "repository": "https://github.com/bpmn-io/bpmn-js-color-picker.git",
13 | "keywords": [
14 | "bpmn-js-example",
15 | "bpmn-in-color",
16 | "bpmn"
17 | ],
18 | "module": "./colors/index.js",
19 | "engines": {
20 | "node": "*"
21 | },
22 | "author": {
23 | "name": "Vladimirs Katusenoks",
24 | "url": "https://github.com/vkatushenok"
25 | },
26 | "license": "MIT",
27 | "devDependencies": {
28 | "bpmn-js": "^18.6.1",
29 | "copy-webpack-plugin": "^13.0.0",
30 | "eslint": "^9.27.0",
31 | "eslint-plugin-bpmn-io": "^2.2.0",
32 | "npm-run-all2": "^8.0.0",
33 | "webpack": "^5.99.8",
34 | "webpack-cli": "^6.0.0",
35 | "webpack-dev-server": "^5.0.0"
36 | },
37 | "peerDependencies": {
38 | "bpmn-js": ">= 14"
39 | },
40 | "files": [
41 | "colors/*",
42 | "index.js"
43 | ]
44 | }
45 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": [
4 | "github>bpmn-io/renovate-config:recommended"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/resources/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bpmn-io/bpmn-js-color-picker/418e829215aa0e34d6457d8cbd05a591a937473c/resources/screenshot.png
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const CopyPlugin = require('copy-webpack-plugin');
4 |
5 | module.exports = {
6 | mode: 'development',
7 | entry: './example/app.js',
8 | output: {
9 | path: path.join(__dirname, 'public'),
10 | filename: 'app.js',
11 | },
12 | module: {
13 | rules: [
14 | {
15 | test: /\.css$/,
16 | type: 'asset/source'
17 | },
18 | {
19 | test: /\.bpmn$/,
20 | type: 'asset/source'
21 | }
22 | ]
23 | },
24 | plugins: [
25 | new CopyPlugin({
26 | patterns: [
27 | { from: '*.{html,css}', context: 'example', to: '.' },
28 | { from: 'bpmn-js/dist/assets/**/*', context: 'node_modules', to: './vendor' },
29 | { from: '*.css', context: 'colors', to: './vendor/bpmn-js-color-picker' }
30 | ],
31 | }),
32 | ],
33 | devtool: 'eval-source-map'
34 | };
--------------------------------------------------------------------------------