├── .github └── workflows │ └── CI.yml ├── .gitignore ├── README.md ├── bpmn-properties ├── README.md ├── karma.conf.js ├── package.json └── test │ ├── TestHelper.js │ └── spec │ ├── BpmnPropertiesSpec.js │ └── diagram.bpmn ├── bundling ├── README.md ├── package.json ├── resources │ ├── pizza-collaboration.bpmn │ └── screenshot.png ├── src │ ├── app.js │ └── index.html ├── webpack.config.js └── webpack.es5.config.js ├── colors ├── README.md ├── index.html ├── resources │ └── pizza-collaboration.bpmn └── screenshot.png ├── commenting ├── README.md ├── docs │ └── screenshot.png ├── package.json ├── resources │ ├── pizza-collaboration-annotated.bpmn │ └── pizza-collaboration.bpmn ├── src │ ├── app.js │ ├── font │ │ ├── LICENSE.txt │ │ ├── bpmn-js-comments.eot │ │ ├── bpmn-js-comments.svg │ │ ├── bpmn-js-comments.ttf │ │ ├── bpmn-js-comments.woff │ │ └── config.json │ ├── index.html │ └── style.css └── webpack.config.js ├── custom-bower-bundle └── README.md ├── custom-bundle ├── README.md ├── index.html ├── package.json ├── rollup.config.js └── src │ ├── custom-viewer.js │ └── features │ └── logging │ ├── InteractionLogger.js │ └── index.js ├── custom-elements ├── README.md └── docs │ ├── screenshot-custom-editor-controls.png │ ├── screenshot-custom-elements.png │ ├── screenshot-custom-rendering.png │ └── screenshot-model-extension.png ├── custom-meta-model ├── README.md ├── package.json ├── resources │ ├── qa.json │ ├── sample.bpmn │ └── screenshot.png ├── src │ ├── app.js │ └── index.html └── webpack.config.js ├── custom-modeling-rules ├── README.md ├── karma.conf.js ├── lib │ └── custom-rules │ │ ├── CustomRules.js │ │ └── index.js ├── package.json └── test │ ├── TestHelper.js │ └── spec │ ├── CustomRulesSpec.js │ └── diagram.bpmn ├── deep-linking ├── README.md ├── package.json ├── resources │ ├── nested-subprocesses.bpmn │ └── screenshot.png ├── src │ ├── app.js │ └── index.html └── webpack.config.js ├── embedding ├── .gitignore ├── README.md ├── docs │ └── screenshot.png ├── package-lock.json ├── package.json ├── src │ ├── app.js │ ├── diagrams │ │ ├── first.bpmn │ │ ├── overview.bpmn │ │ └── second.bpmn │ ├── index.html │ └── style.css └── webpack.config.js ├── eslint.config.mjs ├── i18n ├── README.md ├── package.json ├── resources │ ├── newDiagram.bpmn │ └── screenshot.png ├── src │ ├── app.js │ ├── customTranslate │ │ ├── customTranslate.js │ │ └── translations.js │ └── index.html └── webpack.config.js ├── interaction ├── README.md └── index.html ├── lerna.json ├── minimap ├── README.md ├── docs │ └── screenshot.png ├── package.json ├── resources │ └── pizza-collaboration.bpmn ├── src │ ├── app.js │ ├── index.html │ └── style.css └── webpack.config.js ├── modeler ├── .gitignore ├── README.md ├── docs │ └── screenshot.png ├── package.json ├── resources │ └── newDiagram.bpmn ├── src │ ├── app.js │ ├── index.html │ └── style.css └── webpack.config.js ├── modeling-api ├── README.md ├── docs │ └── screenshot.png ├── package.json ├── resources │ ├── diagram.bpmn │ └── editingElements.bpmn ├── src │ ├── app.js │ ├── index.html │ ├── snippets │ │ ├── businessObjects.js │ │ ├── collaborations.js │ │ ├── connectingShapes.js │ │ ├── creatingShapes.js │ │ ├── editingElements.js │ │ ├── index.js │ │ └── introduction.js │ └── style.css └── webpack.config.js ├── overlays ├── README.md ├── docs │ ├── qr-code.gif │ └── qr-code.png ├── package.json ├── resources │ └── qr-code.bpmn ├── src │ ├── app.js │ └── index.html └── webpack.config.js ├── package-lock.json ├── package.json ├── pre-packaged └── README.md ├── properties-panel-async-extension ├── README.md ├── docs │ └── screencapture.gif ├── package.json ├── resources │ └── newDiagram.bpmn ├── server.js ├── src │ ├── app.js │ ├── descriptors │ │ └── magic.json │ ├── index.html │ ├── provider │ │ └── magic │ │ │ ├── MagicPropertiesProvider.js │ │ │ ├── index.js │ │ │ └── parts │ │ │ └── SpellProps.js │ └── style.less └── webpack.config.js ├── properties-panel-extension ├── README.md ├── docs │ └── screenshot.png ├── package.json ├── resources │ └── newDiagram.bpmn ├── src │ ├── app.js │ ├── descriptors │ │ └── magic.json │ ├── index.html │ ├── provider │ │ └── magic │ │ │ ├── MagicPropertiesProvider.js │ │ │ ├── index.js │ │ │ └── parts │ │ │ └── SpellProps.js │ └── style.less └── webpack.config.js ├── properties-panel-list-extension ├── .gitignore ├── README.md ├── docs │ └── screenshot.png ├── package.json ├── resources │ └── newDiagram.bpmn ├── src │ ├── app.js │ ├── descriptors │ │ └── magic.json │ ├── index.html │ ├── provider │ │ └── magic │ │ │ ├── MagicPropertiesProvider.js │ │ │ ├── index.js │ │ │ ├── parts │ │ │ ├── ExtensionList.js │ │ │ ├── ExtensionProps.js │ │ │ ├── ParameterProps.js │ │ │ └── ParametersProps.js │ │ │ └── util.js │ └── style.less └── webpack.config.js ├── properties-panel ├── README.md ├── docs │ └── screenshot.png ├── package.json ├── resources │ └── newDiagram.bpmn ├── src │ ├── app.js │ ├── index.html │ └── style.less └── webpack.config.js ├── renovate.json ├── simple-bower └── README.md ├── simple-commonjs └── README.md ├── starter ├── README.md ├── diagram.bpmn ├── modeler.html ├── viewer.html └── viewer.png ├── theming ├── README.md ├── docs │ └── screenshot.png ├── index.html ├── package.json ├── resources │ ├── kitchen-sink.bpmn │ └── pizza-collaboration.bpmn ├── rollup.config.js └── src │ └── custom-viewer.js ├── transaction-boundaries ├── README.md ├── docs │ └── screenshot.png ├── package.json ├── resources │ └── transaction-boundaries.bpmn ├── src │ ├── app.js │ ├── index.html │ └── style.css └── webpack.config.js ├── types ├── README.md ├── package.json ├── src │ ├── app.js │ └── app.ts └── tsconfig.json └── url-viewer ├── README.md ├── index.html └── resources ├── pizza-collaboration.bpmn └── screenshot.png /.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 | runs-on: ${{ matrix.os }} 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v4 14 | - name: Use Node.js 15 | uses: actions/setup-node@v4 16 | with: 17 | node-version: ${{ matrix.node-version }} 18 | cache: 'npm' 19 | - name: Install dependencies 20 | run: npm ci 21 | - name: Project setup 22 | uses: bpmn-io/actions/setup@latest 23 | - name: Build examples 24 | run: npm run build 25 | - name: Lint examples 26 | run: npm run lint 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | public/ 3 | dist/ 4 | .idea 5 | *.iml 6 | .DS_Store 7 | npm-debug.log -------------------------------------------------------------------------------- /bpmn-properties/README.md: -------------------------------------------------------------------------------- 1 | # bpmn properties 2 | 3 | This example shows how to use [bpmn-js](https://github.com/bpmn-io/bpmn-js) to access BPMN properties behind certain diagram elements. 4 | 5 | 6 | ## About 7 | 8 | Each diagram element stores a reference to the underlying BPMN element via the `businessObject` property. The business object is the actual element that gets imported from BPMN 2.0 XML and serialized during export. Use the business object to read and write BPMN specific properties. 9 | 10 | 11 | #### Reading BPMN Properties 12 | 13 | To read BPMN properties, obtain a reference to a diagram elements business object. 14 | 15 | ```javascript 16 | var elementRegistry = bpmnJS.get('elementRegistry'); 17 | 18 | var sequenceFlowElement = elementRegistry.get('SequenceFlow_1'), 19 | sequenceFlow = sequenceFlowElement.businessObject; 20 | 21 | sequenceFlow.name; // 'YES' 22 | sequenceFlow.conditionExpression; // ModdleElement { $type: 'bpmn:FormalExpression', ... } 23 | ``` 24 | 25 | 26 | #### Writing BPMN properties 27 | 28 | To write a BPMN property, simply set it on the business object. 29 | 30 | > Check out the [`bpmn.json` meta-model descriptor](https://github.com/bpmn-io/bpmn-moddle/blob/main/resources/bpmn/json/bpmn.json) to learn about BPMN types, their properties and relationships. 31 | 32 | ```javascript 33 | var moddle = bpmnJS.get('moddle'); 34 | 35 | // create a BPMN element that can be serialized to XML during export 36 | var newCondition = moddle.create('bpmn:FormalExpression', { 37 | body: '${ value > 100 }' 38 | }); 39 | 40 | // write property, no undo support 41 | sequenceFlow.conditionExpression = newCondition; 42 | ``` 43 | 44 | In order to get undo/redo support you need to dispatch the property update through our modeling stack: 45 | 46 | ```javascript 47 | var modeling = bpmnJS.get('modeling'); 48 | 49 | modeling.updateProperties(sequenceFlowElement, { 50 | conditionExpression: newCondition 51 | }); 52 | ``` 53 | 54 | > Implement your own [`CommandHandler`](https://github.com/bpmn-io/diagram-js/blob/main/lib/command/CommandHandler.js) to perform more advanced atomic updates. 55 | 56 | Both ways will eventually serialize the condition to XML. 57 | 58 | To learn more, check out [an example diagram](./test/spec/diagram.bpmn) and the accompanying [test cases](./test/spec/BpmnPropertiesSpec.js). 59 | 60 | 61 | ## Building 62 | 63 | One time installation of all dependencies via [npm](https://npmjs.org): 64 | 65 | ``` 66 | npm install 67 | ``` 68 | 69 | 70 | Execute the test suite to spin up the example in your browser: 71 | 72 | ``` 73 | npm run dev 74 | ``` 75 | 76 | Go to [localhost:9876/debug.html](http://localhost:9876/debug.html) to inspect the example in your Browser. 77 | 78 | 79 | ## License 80 | 81 | MIT -------------------------------------------------------------------------------- /bpmn-properties/karma.conf.js: -------------------------------------------------------------------------------- 1 | // use puppeteer provided Chrome for testing 2 | process.env.CHROME_BIN = require('puppeteer').executablePath(); 3 | 4 | // configures browsers to run test against 5 | // any of [ 'ChromeHeadless', 'Chrome', 'Firefox', 'Safari' ] 6 | const browsers = (process.env.TEST_BROWSERS || 'ChromeHeadless').split(','); 7 | 8 | module.exports = function(karma) { 9 | karma.set({ 10 | 11 | frameworks: [ 12 | 'webpack', 13 | 'mocha', 14 | 'chai' 15 | ], 16 | 17 | files: [ 18 | 'test/spec/**/*Spec.js' 19 | ], 20 | 21 | reporters: [ 'dots' ], 22 | 23 | preprocessors: { 24 | 'test/spec/**/*Spec.js': [ 'webpack' ] 25 | }, 26 | 27 | browsers, 28 | 29 | singleRun: true, 30 | autoWatch: false, 31 | 32 | webpack: { 33 | mode: 'development', 34 | module: { 35 | rules: [ 36 | { 37 | test: /\.css|\.bpmn$/, 38 | type: 'asset/source' 39 | } 40 | ] 41 | }, 42 | devtool: 'eval-source-map' 43 | } 44 | }); 45 | }; 46 | -------------------------------------------------------------------------------- /bpmn-properties/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bpmn-js-example-bpmn-properties", 3 | "version": "0.0.0", 4 | "description": "An example how to read and write custom BPMN 2.0 extensions", 5 | "scripts": { 6 | "all": "run-s test", 7 | "dev": "npm test -- --auto-watch --no-single-run", 8 | "test": "karma start" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/bpmn-io/bpmn-js-examples" 13 | }, 14 | "keywords": [ 15 | "bpmnjs-example" 16 | ], 17 | "author": { 18 | "name": "Nico Rehwaldt", 19 | "url": "https://github.com/nikku" 20 | }, 21 | "contributors": [ 22 | { 23 | "name": "bpmn.io contributors", 24 | "url": "https://github.com/bpmn-io" 25 | } 26 | ], 27 | "license": "MIT", 28 | "devDependencies": { 29 | "chai": "^4.5.0", 30 | "karma": "^6.4.4", 31 | "karma-browserify": "^8.0.0", 32 | "karma-chai": "^0.1.0", 33 | "karma-chrome-launcher": "^3.2.0", 34 | "karma-firefox-launcher": "^2.1.3", 35 | "karma-mocha": "^2.0.0", 36 | "karma-webpack": "^5.0.1", 37 | "mocha": "^10.8.2", 38 | "mocha-test-container-support": "^0.2.0", 39 | "npm-run-all2": "^8.0.0", 40 | "puppeteer": "^24.0.0", 41 | "webpack": "^5.97.1" 42 | }, 43 | "dependencies": { 44 | "bpmn-js": "^18.6.2" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /bpmn-properties/test/TestHelper.js: -------------------------------------------------------------------------------- 1 | export * from 'bpmn-js/test/helper'; 2 | 3 | import { 4 | insertCSS 5 | } from 'bpmn-js/test/helper'; 6 | 7 | insertCSS('diagram-js.css', require('bpmn-js/dist/assets/diagram-js.css')); 8 | insertCSS('bpmn-embedded.css', require('bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css')); 9 | 10 | insertCSS('diagram-js-testing.css', 11 | '.test-container .result { height: 500px; }' + '.test-container > div' 12 | ); -------------------------------------------------------------------------------- /bpmn-properties/test/spec/BpmnPropertiesSpec.js: -------------------------------------------------------------------------------- 1 | import { 2 | bootstrapModeler, 3 | inject 4 | } from '../TestHelper'; 5 | 6 | import coreModule from 'bpmn-js/lib/core'; 7 | import modelingModule from 'bpmn-js/lib/features/modeling'; 8 | 9 | 10 | describe('bpmn properties', function() { 11 | 12 | var testModules = [ 13 | coreModule, 14 | modelingModule 15 | ]; 16 | 17 | 18 | var diagramXML = require('./diagram.bpmn'); 19 | 20 | beforeEach(bootstrapModeler(diagramXML, { 21 | modules: testModules 22 | })); 23 | 24 | 25 | describe('read properties', function() { 26 | 27 | it('should read name', inject(function(elementRegistry) { 28 | 29 | // given 30 | var sequenceFlowElement = elementRegistry.get('SequenceFlow_1'), 31 | sequenceFlow = sequenceFlowElement.businessObject; 32 | 33 | // when 34 | var name = sequenceFlow.name; 35 | 36 | // then 37 | expect(name).to.eql('FOO > BAR?'); 38 | })); 39 | 40 | 41 | it('should read conditionExpression', inject(function(elementRegistry) { 42 | 43 | // given 44 | var sequenceFlowElement = elementRegistry.get('SequenceFlow_1'), 45 | sequenceFlow = sequenceFlowElement.businessObject; 46 | 47 | // when 48 | var condition = sequenceFlow.conditionExpression; 49 | 50 | // then 51 | expect(condition.body).to.eql('${foo > bar}'); 52 | })); 53 | 54 | }); 55 | 56 | 57 | describe('write properties', function() { 58 | 59 | it('should write conditionExpression', inject( 60 | function(elementRegistry, moddle, modeling) { 61 | 62 | // given 63 | var sequenceFlowElement = elementRegistry.get('SequenceFlow_2'), 64 | sequenceFlow = sequenceFlowElement.businessObject; 65 | 66 | var newCondition = moddle.create('bpmn:FormalExpression', { 67 | body: '${ value > 100 }' 68 | }); 69 | 70 | // assume 71 | expect(sequenceFlow.conditionExpression).not.to.exist; 72 | 73 | // when 74 | modeling.updateProperties(sequenceFlowElement, { 75 | conditionExpression: newCondition 76 | }); 77 | 78 | // then 79 | expect(sequenceFlow.conditionExpression).to.equal(newCondition); 80 | } 81 | )); 82 | 83 | 84 | it('should undo write conditionExpression', inject( 85 | function(elementRegistry, moddle, modeling, commandStack) { 86 | 87 | // given 88 | var sequenceFlowElement = elementRegistry.get('SequenceFlow_2'), 89 | sequenceFlow = sequenceFlowElement.businessObject; 90 | 91 | var newCondition = moddle.create('bpmn:FormalExpression', { 92 | body: '${ value > 100 }' 93 | }); 94 | 95 | modeling.updateProperties(sequenceFlowElement, { 96 | conditionExpression: newCondition 97 | }); 98 | 99 | 100 | // when 101 | commandStack.undo(); 102 | 103 | // then 104 | expect(sequenceFlow.conditionExpression).not.to.exist; 105 | } 106 | )); 107 | 108 | }); 109 | 110 | }); 111 | -------------------------------------------------------------------------------- /bpmn-properties/test/spec/diagram.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SequenceFlow_1 6 | 7 | 8 | SequenceFlow_1 9 | SequenceFlow_2 10 | 11 | 12 | bar}]]> 13 | 14 | 15 | SequenceFlow_2 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /bundling/README.md: -------------------------------------------------------------------------------- 1 | 2 | # bpmn-js bundling example 3 | 4 | This example showcases how add and bundle [bpmn-js](https://github.com/bpmn-io/bpmn-js) 5 | along with a node-style web application using [Webpack](https://webpack.js.org). 6 | 7 | 8 | ## About 9 | 10 | This example uses bpmn-js to embed the [pizza collaboration](http://demo.bpmn.io/s/pizza-collaboration) diagram into a web application. 11 | 12 | ![example screenshot](./resources/screenshot.png "Screenshot of the example application") 13 | 14 | 15 | ## Usage Summary 16 | 17 | Install bpmn-js via [npm](http://npmjs.org) 18 | 19 | ``` 20 | npm install --save bpmn-js 21 | ``` 22 | 23 | Use it in your application 24 | 25 | ```javascript 26 | import BpmnViewer from 'bpmn-js'; 27 | 28 | var viewer = new BpmnViewer({ 29 | container: '#canvas' 30 | }); 31 | 32 | 33 | viewer.importXML(pizzaDiagram).then(function(result) { 34 | 35 | const { warnings } = result; 36 | 37 | console.log('success !', warnings); 38 | 39 | viewer.get('canvas').zoom('fit-viewport'); 40 | }).catch(function(err) { 41 | 42 | const { warnings, message } = err; 43 | 44 | console.log('something went wrong:', warnings, message); 45 | }); 46 | ``` 47 | 48 | Bundle the `src/app.js` file for the browser with Webpack: 49 | 50 | ``` 51 | webpack ./src/app.js -o public/app.bundled.js --mode development 52 | ``` 53 | 54 | To learn about more bundling options, checkout the [webpack-cli documentation](https://webpack.js.org/api/cli/). 55 | 56 | __Note:__ You may use another ES module aware bundler such as [Rollup](https://rollupjs.org), too. 57 | Browserify may also be used but must be properly configured via a global babelify transform. 58 | 59 | ### Bundling to ES5 60 | 61 | If your application needs to support old browsers, you need to transpile the code to ES5. 62 | This can be achieved via 63 | 64 | ``` 65 | npm run build:es5 66 | ``` 67 | 68 | After the operation finishes, run 69 | 70 | ``` 71 | npm run open 72 | ``` 73 | 74 | to open the application in the browser. 75 | 76 | Inspect [webpack.es5.config.js](webpack.es5.config.js) to check how webpack can be configured to transpile your application with [babel](https://babeljs.io/). 77 | 78 | ## Building the Example 79 | 80 | Install the project dependencies via 81 | 82 | ``` 83 | npm install 84 | ``` 85 | 86 | To create the sample distribution in the `public` folder run 87 | 88 | ``` 89 | npm run all 90 | ``` 91 | 92 | 93 | ## License 94 | 95 | MIT 96 | -------------------------------------------------------------------------------- /bundling/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bundling", 3 | "version": "0.0.0", 4 | "description": "An example how to bundle an app using bpmn-js for the browser", 5 | "scripts": { 6 | "all": "run-s build build:es5", 7 | "build": "webpack", 8 | "build:es5": "webpack --config webpack.es5.config.js", 9 | "build:watch": "webpack -w", 10 | "open": "open-cli ./public/index.html", 11 | "dev": "run-p bundle:watch open" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/bpmn-io/bpmn-js-examples" 16 | }, 17 | "keywords": [ 18 | "bpmnjs-example" 19 | ], 20 | "author": { 21 | "name": "Nico Rehwaldt", 22 | "url": "https://github.com/nikku" 23 | }, 24 | "contributors": [ 25 | { 26 | "name": "bpmn.io contributors", 27 | "url": "https://github.com/bpmn-io" 28 | } 29 | ], 30 | "license": "MIT", 31 | "devDependencies": { 32 | "@babel/core": "^7.26.0", 33 | "@babel/preset-env": "^7.26.0", 34 | "babel-loader": "^10.0.0", 35 | "copy-webpack-plugin": "^13.0.0", 36 | "npm-run-all2": "^8.0.0", 37 | "open-cli": "^8.0.0", 38 | "webpack": "^5.97.1", 39 | "webpack-cli": "^6.0.1" 40 | }, 41 | "dependencies": { 42 | "bpmn-js": "^18.6.2" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /bundling/resources/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/bundling/resources/screenshot.png -------------------------------------------------------------------------------- /bundling/src/app.js: -------------------------------------------------------------------------------- 1 | // we use stringify to inline an example XML document 2 | import pizzaDiagram from '../resources/pizza-collaboration.bpmn'; 3 | 4 | 5 | // make sure you added bpmn-js to your your project 6 | // dependencies via npm install --save bpmn-js 7 | import BpmnViewer from 'bpmn-js'; 8 | 9 | var viewer = new BpmnViewer({ 10 | container: '#canvas' 11 | }); 12 | 13 | 14 | viewer.importXML(pizzaDiagram).then(function(result) { 15 | 16 | const { warnings } = result; 17 | 18 | console.log('success !', warnings); 19 | 20 | viewer.get('canvas').zoom('fit-viewport'); 21 | }).catch(function(err) { 22 | 23 | const { warnings, message } = err; 24 | 25 | console.log('something went wrong:', warnings, message); 26 | }); 27 | -------------------------------------------------------------------------------- /bundling/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 14 | 15 | 16 | 17 | 18 | 22 | 23 | npm/browserify example - bpmn-js-examples 24 | 25 | 26 | 27 |

Pizza Collaboration Viewer

28 | 29 |
30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /bundling/webpack.config.js: -------------------------------------------------------------------------------- 1 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 2 | 3 | const path = require('path'); 4 | 5 | module.exports = { 6 | mode: 'development', 7 | entry: './src/app.js', 8 | output: { 9 | path: path.resolve(__dirname, 'public'), 10 | filename: 'app.js' 11 | }, 12 | module: { 13 | rules: [ 14 | { 15 | test: /\.bpmn$/, 16 | type: 'asset/source' 17 | } 18 | ] 19 | }, 20 | plugins: [ 21 | new CopyWebpackPlugin({ 22 | patterns: [ 23 | { from: 'src/index.html', to: '.' } 24 | ] 25 | }) 26 | ] 27 | }; -------------------------------------------------------------------------------- /bundling/webpack.es5.config.js: -------------------------------------------------------------------------------- 1 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 2 | 3 | const path = require('path'); 4 | 5 | module.exports = { 6 | mode: 'development', 7 | entry: './src/app.js', 8 | output: { 9 | path: path.resolve(__dirname, 'public'), 10 | filename: 'app.js' 11 | }, 12 | module: { 13 | rules: [ 14 | { 15 | test: /\.bpmn$/, 16 | type: 'asset/source' 17 | }, 18 | { 19 | test: /\.m?js$/, 20 | exclude: /(node_modules)/, 21 | use: { 22 | loader: 'babel-loader', 23 | options: { 24 | presets: [ '@babel/preset-env' ] 25 | } 26 | } 27 | } 28 | ] 29 | }, 30 | plugins: [ 31 | new CopyWebpackPlugin({ 32 | patterns: [ 33 | { from: 'src/index.html', to: '.' } 34 | ] 35 | }) 36 | ] 37 | }; -------------------------------------------------------------------------------- /colors/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 24 | 25 | 28 | 29 | bpmn-js colors example - bpmn-js-examples 30 | 31 | 32 | 33 |

bpmn-js Colors

34 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /colors/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/colors/screenshot.png -------------------------------------------------------------------------------- /commenting/README.md: -------------------------------------------------------------------------------- 1 | # A simple discussion app 2 | 3 | [bpmn-js](https://github.com/bpmn-io/bpmn-js) is the BPMN 2.0 diagram modeling and rendering toolkit that powers [bpmn.io](http://bpmn.io). 4 | 5 | This example showcases how to build a simple discussion app based on [bpmn-js](https://github.com/bpmn-io/bpmn-js) and the [bpmn-js-embedded-comments](https://github.com/bpmn-io/bpmn-js-embedded-comments) extension. 6 | 7 | 8 | ## About 9 | 10 | This example uses bpmn-js to embed the [pizza collaboration](http://demo.bpmn.io/s/pizza-collaboration) diagram into a web application and add the ability to put comments on individual tasks. 11 | 12 | ![demo application screenshot](https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/main/commenting/docs/screenshot.png "Screenshot of the example application") 13 | 14 | The comments are added to an elements `` tag and may be downloaded along with the element. 15 | 16 | 17 | ## Building 18 | 19 | One time installation of all dependencies via [npm](https://npmjs.org): 20 | 21 | ``` 22 | npm install 23 | ``` 24 | 25 | 26 | Building the app into the `public` directory and opening it in a browser: 27 | 28 | ``` 29 | npm run dev 30 | ``` 31 | 32 | 33 | ## License 34 | 35 | MIT -------------------------------------------------------------------------------- /commenting/docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/commenting/docs/screenshot.png -------------------------------------------------------------------------------- /commenting/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bpmn-js-example-commenting", 3 | "version": "0.0.0", 4 | "description": "A simple commenting app based on bpmn-js", 5 | "scripts": { 6 | "all": "webpack", 7 | "dev": "webpack-dev-server" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/bpmn-io/bpmn-js-examples" 12 | }, 13 | "keywords": [ 14 | "bpmnjs-example" 15 | ], 16 | "author": { 17 | "name": "Nico Rehwaldt", 18 | "url": "https://github.com/nikku" 19 | }, 20 | "contributors": [ 21 | { 22 | "name": "bpmn.io contributors", 23 | "url": "https://github.com/bpmn-io" 24 | } 25 | ], 26 | "license": "MIT", 27 | "devDependencies": { 28 | "css-loader": "^7.1.2", 29 | "style-loader": "^4.0.0", 30 | "webpack": "^5.97.1", 31 | "webpack-cli": "^6.0.1", 32 | "webpack-dev-server": "^5.2.0" 33 | }, 34 | "dependencies": { 35 | "bpmn-js": "^18.6.2", 36 | "bpmn-js-embedded-comments": "^0.7.0", 37 | "diagram-js": "^15.1.0", 38 | "jquery": "^3.3.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /commenting/src/font/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Font license info 2 | 3 | 4 | ## Entypo 5 | 6 | Copyright (C) 2012 by Daniel Bruce 7 | 8 | Author: Daniel Bruce 9 | License: SIL (http://scripts.sil.org/OFL) 10 | Homepage: http://www.entypo.com 11 | 12 | 13 | -------------------------------------------------------------------------------- /commenting/src/font/bpmn-js-comments.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/commenting/src/font/bpmn-js-comments.eot -------------------------------------------------------------------------------- /commenting/src/font/bpmn-js-comments.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Copyright (C) 2014 by original authors @ fontello.com 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /commenting/src/font/bpmn-js-comments.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/commenting/src/font/bpmn-js-comments.ttf -------------------------------------------------------------------------------- /commenting/src/font/bpmn-js-comments.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/commenting/src/font/bpmn-js-comments.woff -------------------------------------------------------------------------------- /commenting/src/font/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bpmn-js-comments", 3 | "css_prefix_text": "icon-", 4 | "css_use_suffix": false, 5 | "hinting": true, 6 | "units_per_em": 1000, 7 | "ascent": 850, 8 | "glyphs": [ 9 | { 10 | "uid": "c709da589c923ba3c2ad48d9fc563e93", 11 | "css": "delete", 12 | "code": 59394, 13 | "src": "entypo" 14 | }, 15 | { 16 | "uid": "16890362e811b4cb8de36282b071fe30", 17 | "css": "comment", 18 | "code": 59392, 19 | "src": "entypo" 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /commenting/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 59 | 60 | 64 | 65 | BPMN 2.0 comments 66 | 67 | 68 | 69 |
70 |

BPMN 2.0 comments

71 |
72 | 73 |
74 | 75 |
76 | 77 |
78 | Download 79 |
80 | 81 |
82 | 83 |
84 | 85 |
86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /commenting/src/style.css: -------------------------------------------------------------------------------- 1 | body, html { 2 | font-family: sans-serif; 3 | } 4 | 5 | .comments-overlay { 6 | background: #52B415; 7 | font-size: 12px; 8 | 9 | color: white; 10 | display: none; 11 | padding: 5px; 12 | } 13 | 14 | .selected .comments-overlay, 15 | .comments-overlay.with-comments { 16 | display: block; 17 | } 18 | 19 | .comments-overlay .edit { 20 | margin: 2px 0 0 0; 21 | padding-top: 2px; 22 | } 23 | 24 | .comments-overlay .edit textarea { 25 | border: none; 26 | margin: 0; 27 | } 28 | 29 | .comments-overlay .icon-comment:hover { 30 | color: #EEE; 31 | } 32 | 33 | .comments-overlay .comment { 34 | border-top-color: white; 35 | } 36 | 37 | 38 | .comments-overlay .icon-comment { 39 | margin-right: 2px; 40 | } 41 | 42 | .comments-overlay .icon-delete { 43 | color: white; 44 | float: right; 45 | } 46 | 47 | 48 | /** fonts **/ 49 | 50 | @font-face { 51 | font-family: 'bpmn-js-comments'; 52 | src: url('font/bpmn-js-comments.eot?23532594'); 53 | src: url('font/bpmn-js-comments.eot?23532594#iefix') format('embedded-opentype'), 54 | url('font/bpmn-js-comments.woff?23532594') format('woff'), 55 | url('font/bpmn-js-comments.ttf?23532594') format('truetype'), 56 | url('font/bpmn-js-comments.svg?23532594#bpmn-js-comments') format('svg'); 57 | font-weight: normal; 58 | font-style: normal; 59 | } 60 | 61 | [class^="icon-"]:before, 62 | [class*=" icon-"]:before { 63 | font-family: "bpmn-js-comments"; 64 | font-style: normal; 65 | font-weight: normal; 66 | speak: none; 67 | 68 | display: inline-block; 69 | text-decoration: inherit; 70 | width: 1em; 71 | text-align: center; 72 | 73 | font-variant: normal; 74 | text-transform: none; 75 | 76 | line-height: 1em; 77 | } 78 | 79 | .icon-comment:before { content: '\e800'; } 80 | .icon-delete:before { content: '\e802'; } -------------------------------------------------------------------------------- /commenting/webpack.config.js: -------------------------------------------------------------------------------- 1 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 2 | 3 | module.exports = { 4 | entry: { 5 | bundle: [ './src/app.js' ] 6 | }, 7 | output: { 8 | path: __dirname + '/public', 9 | filename: 'app.js' 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.css$/, 15 | use: [ 16 | 'style-loader', 17 | 'css-loader', 18 | ] 19 | }, 20 | { 21 | test: /\.bpmn$/, 22 | use: 'raw-loader' 23 | } 24 | ] 25 | }, 26 | plugins: [ 27 | new CopyWebpackPlugin({ 28 | patterns: [ 29 | { from: 'src/index.html', to: '.' }, 30 | { from: 'src/font/**/*', to: 'font' } 31 | ] 32 | }) 33 | ], 34 | mode: 'development', 35 | devtool: 'source-map' 36 | }; 37 | -------------------------------------------------------------------------------- /custom-bower-bundle/README.md: -------------------------------------------------------------------------------- 1 | > Removed as of `bpmn-js@0.27.0`. 2 | 3 | Checkout [custom bundle example](../custom-bundle) for alternative. -------------------------------------------------------------------------------- /custom-bundle/README.md: -------------------------------------------------------------------------------- 1 | # custom-bundle example 2 | 3 | How to role a customized, pre-packaged version of [bpmn-js](https://github.com/bpmn-io/bpmn-js). 4 | 5 | __Note:__ This is an __advanced__ topic. 6 | 7 | ## About 8 | 9 | This example extends the [bpmn-js](https://github.com/bpmn-io/bpmn-js) viewer via custom modules and shows how [Rollup](https://rollupjs.org) can be used to generate a UMD bundle of that custom viewer. 10 | 11 | 12 | ## In a Nutshell 13 | 14 | Create a sub-class of `Viewer` or `Modeler`, depending on which variant you 15 | would like to extend: 16 | 17 | ```javascript 18 | import inherits from 'inherits'; 19 | 20 | import Viewer from 'bpmn-js/lib/Viewer'; 21 | 22 | import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll'; 23 | import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas'; 24 | 25 | import CustomLoggingModule from './features/logging'; 26 | 27 | 28 | /** 29 | * A viewer that includes mouse navigation and other goodies. 30 | * 31 | * @param {Object} options 32 | */ 33 | function CustomViewer(options) { 34 | Viewer.call(this, options); 35 | } 36 | 37 | inherits(CustomViewer, Viewer); 38 | 39 | module.exports = CustomViewer; 40 | ``` 41 | 42 | Add additional modules to your custom bpmn-js prototype: 43 | 44 | ```javascript 45 | 46 | CustomViewer.prototype._customModules = [ 47 | ZoomScrollModule, 48 | MoveCanvasModule, 49 | CustomLoggingModule 50 | ]; 51 | 52 | CustomViewer.prototype._modules = [].concat( 53 | Viewer.prototype._modules, 54 | CustomViewer.prototype._customModules 55 | ); 56 | ``` 57 | 58 | Package the file as UMD for the browser, using a module bundler such as [Rollup](https://rollupjs.org/), [Browserify](https://browserify.org) or Webpack. 59 | 60 | We're using rollup to bundle the files based on [this configuration](./rollup.config.js): 61 | 62 | ``` 63 | rollup -c 64 | ``` 65 | 66 | Include the bundle in your webpage, as you would include our [pre-package distributions](../pre-packaged): 67 | 68 | ```html 69 | 70 | 77 | ``` 78 | 79 | 80 | ## Build this Example 81 | 82 | ``` 83 | npm install 84 | npm run all 85 | ``` 86 | 87 | 88 | ## License 89 | 90 | MIT 91 | -------------------------------------------------------------------------------- /custom-bundle/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hello World 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 40 | 41 | 42 |
43 | 44 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /custom-bundle/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "custom-bundle", 3 | "version": "0.0.0", 4 | "description": "Bundle a custom version of bpmn-js", 5 | "scripts": { 6 | "all": "run-s build", 7 | "dev": "run-s build open", 8 | "build": "rollup -c --bundleConfigAsCjs", 9 | "open": "open-cli ./index.html" 10 | }, 11 | "dependencies": { 12 | "bpmn-js": "^18.6.2", 13 | "diagram-js": "^15.1.0", 14 | "inherits-browser": "^0.1.0" 15 | }, 16 | "devDependencies": { 17 | "@rollup/plugin-commonjs": "^28.0.2", 18 | "@rollup/plugin-json": "^6.1.0", 19 | "@rollup/plugin-node-resolve": "^16.0.0", 20 | "npm-run-all2": "^8.0.0", 21 | "open-cli": "^8.0.0", 22 | "rollup": "^4.30.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /custom-bundle/rollup.config.js: -------------------------------------------------------------------------------- 1 | import commonjs from '@rollup/plugin-commonjs'; 2 | import json from '@rollup/plugin-json'; 3 | import nodeResolve from '@rollup/plugin-node-resolve'; 4 | 5 | export default { 6 | input: 'src/custom-viewer.js', 7 | output: { 8 | file: 'dist/custom-viewer.bundled.js', 9 | name: 'CustomBpmnJS', 10 | format: 'umd' 11 | }, 12 | plugins: [ 13 | nodeResolve({ 14 | browser: true 15 | }), 16 | commonjs(), 17 | json() 18 | ] 19 | }; -------------------------------------------------------------------------------- /custom-bundle/src/custom-viewer.js: -------------------------------------------------------------------------------- 1 | import inherits from 'inherits-browser'; 2 | 3 | import Viewer from 'bpmn-js/lib/Viewer'; 4 | 5 | import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll'; 6 | import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas'; 7 | 8 | import CustomLoggingModule from './features/logging'; 9 | 10 | 11 | /** 12 | * A viewer that includes mouse navigation and other goodies. 13 | * 14 | * @param {Object} options 15 | */ 16 | export default function CustomViewer(options) { 17 | Viewer.call(this, options); 18 | } 19 | 20 | inherits(CustomViewer, Viewer); 21 | 22 | CustomViewer.prototype._customModules = [ 23 | ZoomScrollModule, 24 | MoveCanvasModule, 25 | CustomLoggingModule 26 | ]; 27 | 28 | CustomViewer.prototype._modules = [].concat( 29 | Viewer.prototype._modules, 30 | CustomViewer.prototype._customModules 31 | ); -------------------------------------------------------------------------------- /custom-bundle/src/features/logging/InteractionLogger.js: -------------------------------------------------------------------------------- 1 | var HIGH_PRIORITY = 1500; 2 | 3 | 4 | export default function InteractionLogger(eventBus) { 5 | 6 | // we log user clicks 7 | eventBus.on('element.click', HIGH_PRIORITY, function(evt) { 8 | console.log('user clicked', evt.element); 9 | }); 10 | 11 | } 12 | 13 | InteractionLogger.$inject = [ 'eventBus' ]; -------------------------------------------------------------------------------- /custom-bundle/src/features/logging/index.js: -------------------------------------------------------------------------------- 1 | import InteractionLogger from './InteractionLogger'; 2 | 3 | export default { 4 | __init__: [ 'interactionLogger' ], 5 | interactionLogger: [ 'type', InteractionLogger ] 6 | }; -------------------------------------------------------------------------------- /custom-elements/docs/screenshot-custom-editor-controls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/custom-elements/docs/screenshot-custom-editor-controls.png -------------------------------------------------------------------------------- /custom-elements/docs/screenshot-custom-elements.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/custom-elements/docs/screenshot-custom-elements.png -------------------------------------------------------------------------------- /custom-elements/docs/screenshot-custom-rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/custom-elements/docs/screenshot-custom-rendering.png -------------------------------------------------------------------------------- /custom-elements/docs/screenshot-model-extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/custom-elements/docs/screenshot-model-extension.png -------------------------------------------------------------------------------- /custom-meta-model/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "custom-meta-model", 3 | "version": "0.0.0", 4 | "description": "An bpmn-js modeler extended with a custom meta-model", 5 | "scripts": { 6 | "all": "webpack", 7 | "dev": "webpack-dev-server" 8 | }, 9 | "keywords": [ 10 | "bpmnjs-example" 11 | ], 12 | "author": { 13 | "name": "Nico Rehwaldt", 14 | "url": "https://github.com/nikku" 15 | }, 16 | "contributors": [ 17 | { 18 | "name": "bpmn.io contributors", 19 | "url": "https://github.com/bpmn-io" 20 | } 21 | ], 22 | "license": "MIT", 23 | "devDependencies": { 24 | "css-loader": "^7.1.2", 25 | "style-loader": "^4.0.0", 26 | "webpack": "^5.97.1", 27 | "webpack-cli": "^6.0.1", 28 | "webpack-dev-server": "^5.2.0" 29 | }, 30 | "dependencies": { 31 | "bpmn-js": "^18.6.2", 32 | "diagram-js": "^15.1.0", 33 | "jquery": "^3.3.1" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /custom-meta-model/resources/qa.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "QualityAssurance", 3 | "uri": "http://some-company/schema/bpmn/qa", 4 | "prefix": "qa", 5 | "xml": { 6 | "tagAlias": "lowerCase" 7 | }, 8 | "types": [ 9 | { 10 | "name": "AnalyzedNode", 11 | "extends": [ 12 | "bpmn:FlowNode" 13 | ], 14 | "properties": [ 15 | { 16 | "name": "suitable", 17 | "isAttr": true, 18 | "type": "Float" 19 | } 20 | ] 21 | }, 22 | { 23 | "name": "AnalysisDetails", 24 | "superClass": [ "Element" ], 25 | "properties": [ 26 | { 27 | "name": "lastChecked", 28 | "isAttr": true, 29 | "type": "String" 30 | }, 31 | { 32 | "name": "nextCheck", 33 | "isAttr": true, 34 | "type": "String" 35 | }, 36 | { 37 | "name": "comments", 38 | "isMany": true, 39 | "type": "Comment" 40 | } 41 | ] 42 | }, 43 | { 44 | "name": "Comment", 45 | "properties": [ 46 | { 47 | "name": "author", 48 | "isAttr": true, 49 | "type": "String" 50 | }, 51 | { 52 | "name": "text", 53 | "isBody": true, 54 | "type": "String" 55 | } 56 | ] 57 | } 58 | ], 59 | "emumerations": [], 60 | "associations": [] 61 | } 62 | -------------------------------------------------------------------------------- /custom-meta-model/resources/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/custom-meta-model/resources/screenshot.png -------------------------------------------------------------------------------- /custom-meta-model/src/app.js: -------------------------------------------------------------------------------- 1 | import 'bpmn-js/dist/assets/diagram-js.css'; 2 | import 'bpmn-js/dist/assets/bpmn-js.css'; 3 | 4 | import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'; 5 | 6 | import BpmnViewer from 'bpmn-js'; 7 | 8 | import sampleProcess from '../resources/sample.bpmn'; 9 | 10 | import qaPackage from '../resources/qa'; 11 | 12 | var viewer = new BpmnViewer({ 13 | container: '#canvas', 14 | moddleExtensions: { 15 | qa: qaPackage 16 | } 17 | }); 18 | 19 | viewer.importXML(sampleProcess); 20 | 21 | function getExtension(element, type) { 22 | if (!element.extensionElements) { 23 | return null; 24 | } 25 | 26 | return element.extensionElements.values.filter(function(e) { 27 | return e.$instanceOf(type); 28 | })[0]; 29 | } 30 | 31 | viewer.on('element.click', function(event) { 32 | var element = event.element, 33 | moddle = viewer.get('moddle'), 34 | 35 | // the underlaying BPMN 2.0 element 36 | businessObject = element.businessObject, 37 | analysis, 38 | score, 39 | message; 40 | 41 | // do not allow on root element 42 | if (!element.parent) { 43 | return; 44 | } 45 | 46 | // we can access extension attribute properties 47 | score = businessObject.suitable; 48 | 49 | analysis = getExtension(businessObject, 'qa:AnalysisDetails'); 50 | 51 | // right click 52 | if (event.originalEvent.ctrlKey) { 53 | var result = parseFloat(window.prompt('assign a new suitability score to ' + businessObject.id), 10); 54 | 55 | if (isNaN(result)) { 56 | return; 57 | } 58 | 59 | businessObject.suitable = result; 60 | 61 | if (!analysis) { 62 | analysis = moddle.create('qa:AnalysisDetails'); 63 | businessObject.extensionElements = businessObject.extensionElements || moddle.create('bpmn:ExtensionElements'); 64 | businessObject.extensionElements.get('values').push(analysis); 65 | } 66 | 67 | analysis.lastChecked = new Date().toString(); 68 | } else { 69 | 70 | if (isNaN(score)) { 71 | message = 'No suitability score yet, CTRL+Click to assign one'; 72 | } else { 73 | message = 'Diagram element has a suitability score of ' + score; 74 | } 75 | 76 | if (analysis) { 77 | message += '\n Last analyzed at ' + analysis.lastChecked; 78 | } 79 | 80 | window.alert(message); 81 | } 82 | }); 83 | 84 | 85 | document.querySelector('#export-to-console').addEventListener('click', async function(e) { 86 | 87 | try { 88 | 89 | const { xml } = await viewer.saveXML({ format: true }); 90 | 91 | console.log(xml); 92 | } catch (err) { 93 | console.error(err); 94 | } 95 | 96 | e.preventDefault(); 97 | }); 98 | -------------------------------------------------------------------------------- /custom-meta-model/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | custom-meta-model example 4 | 5 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /custom-meta-model/webpack.config.js: -------------------------------------------------------------------------------- 1 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 2 | 3 | module.exports = { 4 | entry: { 5 | bundle: [ './src/app.js' ] 6 | }, 7 | output: { 8 | path: __dirname + '/public', 9 | filename: 'app.js' 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.css$/, 15 | use: [ 16 | 'style-loader', 17 | 'css-loader', 18 | ] 19 | }, 20 | { 21 | test: /\.bpmn$/, 22 | use: 'raw-loader' 23 | } 24 | ] 25 | }, 26 | plugins: [ 27 | new CopyWebpackPlugin({ 28 | patterns: [ 29 | { from: 'src/index.html', to: '.' } 30 | ] 31 | }) 32 | ], 33 | mode: 'development', 34 | devtool: 'source-map' 35 | }; 36 | -------------------------------------------------------------------------------- /custom-modeling-rules/README.md: -------------------------------------------------------------------------------- 1 | # Custom Modeling Rules 2 | 3 | This example shows how to implement custom modeling rules in [bpmn-js](https://github.com/bpmn-io/bpmn-js). 4 | 5 | 6 | ## About 7 | 8 | This example extends the [bpmn-js](https://github.com/bpmn-io/bpmn-js) modeler with custom modeling rules. 9 | 10 | The rules are added via a [custom rules provider](https://github.com/bpmn-io/bpmn-js-examples/blob/main/custom-modeling-rules/lib/custom-rules/CustomRules.js). The provider hooks into the rule evaluation for `shape.create` and restricts it to elements annotated with a `vendor:allowDrop` extension attribute. 11 | 12 | ```javascript 13 | this.addRule('shape.create', function(context) { 14 | 15 | var shape = context.shape, 16 | target = context.parent; 17 | 18 | var shapeBo = shape.businessObject, 19 | targetBo = target.businessObject; 20 | 21 | var allowDrop = targetBo.get('vendor:allowDrop'); 22 | 23 | if (!allowDrop || !shapeBo.$instanceOf(allowDrop)) { 24 | return false; 25 | } 26 | }); 27 | ``` 28 | 29 | Using these custom rules users are able to insert tasks on the following sequence flow: 30 | 31 | ```xml 32 | 33 | ``` 34 | 35 | They would not be able to insert anything if the `allowDrop` annotation is missing: 36 | 37 | ```xml 38 | 39 | ``` 40 | 41 | To learn more, check out [an example diagram](https://github.com/bpmn-io/bpmn-js-examples/blob/main/custom-modeling-rules/test/spec/diagram.bpmn) and the accompanying [test cases](https://github.com/bpmn-io/bpmn-js-examples/blob/custom-rules/custom-modeling-rules/test/spec/CustomRulesSpec.js). 42 | 43 | 44 | ## Building 45 | 46 | One time installation of all dependencies via [npm](https://npmjs.org): 47 | 48 | ``` 49 | npm install 50 | ``` 51 | 52 | 53 | Execute the test suite to spin up the example in your browser: 54 | 55 | ``` 56 | npm run dev 57 | ``` 58 | 59 | Go to [localhost:9876/debug.html](http://localhost:9876/debug.html) to inspect the example in your Browser. 60 | 61 | 62 | ## License 63 | 64 | MIT -------------------------------------------------------------------------------- /custom-modeling-rules/karma.conf.js: -------------------------------------------------------------------------------- 1 | // use puppeteer provided Chrome for testing 2 | process.env.CHROME_BIN = require('puppeteer').executablePath(); 3 | 4 | // configures browsers to run test against 5 | // any of [ 'ChromeHeadless', 'Chrome', 'Firefox', 'Safari' ] 6 | const browsers = (process.env.TEST_BROWSERS || 'ChromeHeadless').split(','); 7 | 8 | module.exports = function(karma) { 9 | karma.set({ 10 | 11 | frameworks: [ 12 | 'webpack', 13 | 'mocha', 14 | 'chai' 15 | ], 16 | 17 | files: [ 18 | 'test/spec/**/*Spec.js' 19 | ], 20 | 21 | reporters: [ 'dots' ], 22 | 23 | preprocessors: { 24 | 'test/spec/**/*Spec.js': [ 'webpack' ] 25 | }, 26 | 27 | browsers: browsers, 28 | 29 | singleRun: true, 30 | autoWatch: false, 31 | 32 | webpack: { 33 | mode: 'development', 34 | module: { 35 | rules: [ 36 | { 37 | test: /\.css|\.bpmn$/, 38 | type: 'asset/source' 39 | } 40 | ] 41 | }, 42 | devtool: 'eval-source-map' 43 | } 44 | }); 45 | }; 46 | -------------------------------------------------------------------------------- /custom-modeling-rules/lib/custom-rules/CustomRules.js: -------------------------------------------------------------------------------- 1 | import inherits from 'inherits-browser'; 2 | 3 | import RuleProvider from 'diagram-js/lib/features/rules/RuleProvider'; 4 | 5 | 6 | /** 7 | * A custom rule provider that decides what elements can be 8 | * dropped where based on a `vendor:allowDrop` BPMN extension. 9 | * 10 | * See {@link BpmnRules} for the default implementation 11 | * of BPMN 2.0 modeling rules provided by bpmn-js. 12 | * 13 | * @param {EventBus} eventBus 14 | */ 15 | export default function CustomRules(eventBus) { 16 | RuleProvider.call(this, eventBus); 17 | } 18 | 19 | inherits(CustomRules, RuleProvider); 20 | 21 | CustomRules.$inject = [ 'eventBus' ]; 22 | 23 | 24 | CustomRules.prototype.init = function() { 25 | 26 | // there exist a number of modeling actions 27 | // that are identified by a unique ID. We 28 | // can hook into each one of them and make sure 29 | // they are only allowed if we say so 30 | this.addRule('shape.create', function(context) { 31 | 32 | var shape = context.shape, 33 | target = context.target; 34 | 35 | // we check for a custom vendor:allowDrop attribute 36 | // to be present on the BPMN 2.0 xml of the target 37 | // node 38 | // 39 | // we could practically check for other things too, 40 | // such as incoming / outgoing connections, element 41 | // types, ... 42 | var shapeBo = shape.businessObject, 43 | targetBo = target.businessObject; 44 | 45 | var allowDrop = targetBo.get('vendor:allowDrop'); 46 | 47 | if (!allowDrop || !shapeBo.$instanceOf(allowDrop)) { 48 | return false; 49 | } 50 | 51 | // not returning anything means other rule 52 | // providers can still do their work 53 | // 54 | // this allows us to reuse the existing BPMN rules 55 | }); 56 | }; -------------------------------------------------------------------------------- /custom-modeling-rules/lib/custom-rules/index.js: -------------------------------------------------------------------------------- 1 | import CustomRules from './CustomRules'; 2 | 3 | export default { 4 | __init__: [ 'customRules' ], 5 | customRules: [ 'type', CustomRules ] 6 | }; -------------------------------------------------------------------------------- /custom-modeling-rules/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bpmn-js-example-custom-modeling-rules", 3 | "version": "0.0.0", 4 | "description": "An example how to read and write custom BPMN 2.0 extensions", 5 | "scripts": { 6 | "all": "npm test", 7 | "dev": "npm test -- --auto-watch --no-single-run", 8 | "test": "karma start" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/bpmn-io/bpmn-js-examples" 13 | }, 14 | "keywords": [ 15 | "bpmnjs-example" 16 | ], 17 | "author": { 18 | "name": "Nico Rehwaldt", 19 | "url": "https://github.com/nikku" 20 | }, 21 | "contributors": [ 22 | { 23 | "name": "bpmn.io contributors", 24 | "url": "https://github.com/bpmn-io" 25 | } 26 | ], 27 | "license": "MIT", 28 | "devDependencies": { 29 | "chai": "^4.5.0", 30 | "karma": "^6.4.4", 31 | "karma-chai": "^0.1.0", 32 | "karma-chrome-launcher": "^3.2.0", 33 | "karma-firefox-launcher": "^2.1.3", 34 | "karma-mocha": "^2.0.0", 35 | "karma-webpack": "^5.0.1", 36 | "mocha": "^10.8.2", 37 | "mocha-test-container-support": "^0.2.0", 38 | "puppeteer": "^24.0.0", 39 | "webpack": "^5.97.1" 40 | }, 41 | "dependencies": { 42 | "bpmn-js": "^18.6.2", 43 | "diagram-js": "^15.1.0", 44 | "inherits-browser": "^0.1.0" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /custom-modeling-rules/test/TestHelper.js: -------------------------------------------------------------------------------- 1 | export * from 'bpmn-js/test/helper'; 2 | 3 | import { 4 | insertCSS 5 | } from 'bpmn-js/test/helper'; 6 | 7 | insertCSS('diagram-js.css', require('bpmn-js/dist/assets/diagram-js.css')); 8 | insertCSS('bpmn-embedded.css', require('bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css')); 9 | 10 | insertCSS('diagram-js-testing.css', 11 | '.test-container .result { height: 500px; }' + '.test-container > div' 12 | ); -------------------------------------------------------------------------------- /custom-modeling-rules/test/spec/CustomRulesSpec.js: -------------------------------------------------------------------------------- 1 | import { 2 | bootstrapModeler, 3 | inject 4 | } from '../TestHelper'; 5 | 6 | import coreModule from 'bpmn-js/lib/core'; 7 | import bpmnPaletteModule from 'bpmn-js/lib/features/palette'; 8 | import modelingModule from 'bpmn-js/lib/features/modeling'; 9 | 10 | import customRulesModule from '../../lib/custom-rules'; 11 | 12 | 13 | describe('custom-rules', function() { 14 | 15 | var testModules = [ 16 | 17 | // prepend our custom rules to hook into the 18 | // rule evaluation before the default rules 19 | // get applied 20 | customRulesModule, 21 | 22 | // add default interaction features 23 | coreModule, 24 | modelingModule, 25 | bpmnPaletteModule 26 | ]; 27 | 28 | 29 | var diagramXML = require('./diagram.bpmn'); 30 | 31 | beforeEach(bootstrapModeler(diagramXML, { 32 | modules: testModules 33 | })); 34 | 35 | 36 | describe('shape.create', function() { 37 | 38 | it('should reject per default', inject( 39 | function(rules, elementRegistry, elementFactory) { 40 | 41 | // given 42 | var newEventShape = elementFactory.create('shape', { type: 'bpmn:StartEvent' }); 43 | var targetElement = elementRegistry.get('Process_1'); 44 | 45 | // when 46 | var canCreate = rules.allowed('shape.create', { 47 | shape: newEventShape, 48 | target: targetElement 49 | }); 50 | 51 | // then 52 | expect(canCreate).to.be.false; 53 | } 54 | )); 55 | 56 | 57 | it('should reject drop non bpmn:Task on special flow', inject( 58 | function(rules, elementRegistry, elementFactory) { 59 | 60 | // given 61 | var newEventShape = elementFactory.create('shape', { type: 'bpmn:StartEvent' }); 62 | var specialFlowElement = elementRegistry.get('SequenceFlow_1'); 63 | 64 | // when 65 | var canCreate = rules.allowed('shape.create', { 66 | shape: newEventShape, 67 | target: specialFlowElement 68 | }); 69 | 70 | // then 71 | expect(canCreate).to.be.false; 72 | } 73 | )); 74 | 75 | 76 | it('should allow drop bpmn:Task on special flow', inject( 77 | function(rules, elementRegistry, elementFactory) { 78 | 79 | // given 80 | var newTaskShape = elementFactory.create('shape', { type: 'bpmn:Task' }); 81 | var specialFlowElement = elementRegistry.get('SequenceFlow_1'); 82 | 83 | // when 84 | var canCreate = rules.allowed('shape.create', { 85 | shape: newTaskShape, 86 | target: specialFlowElement 87 | }); 88 | 89 | // then 90 | expect(canCreate).to.be.true; 91 | } 92 | )); 93 | 94 | }); 95 | 96 | }); 97 | -------------------------------------------------------------------------------- /custom-modeling-rules/test/spec/diagram.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SequenceFlow_1 6 | 7 | 8 | SequenceFlow_1 9 | SequenceFlow_2 10 | 11 | 12 | 13 | SequenceFlow_2 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /deep-linking/README.md: -------------------------------------------------------------------------------- 1 | # bpmn-js deep-linking example 2 | 3 | This example shows how to use the [rootElements API](https://github.com/bpmn-io/diagram-js/blob/main/lib/core/Canvas.js) of [bpmn-js](https://github.com/bpmn-io/bpmn-js) to switch between different diagram layers. 4 | 5 | ![Screenshot](resources/screenshot.png) 6 | 7 | ## About 8 | 9 | The example loads a process diagram with nested subprocesses and changes the browser location changing drilling into. 10 | Opening the generated link will take you to the selected subprocess view directly. 11 | 12 | 13 | ## Usage summary 14 | 15 | Access the [`Canvas`](https://github.com/bpmn-io/diagram-js/blob/main/lib/core/Canvas.js) service via `bpmnViewer.get('canvas')` and set root elements by id using the `Canvas#setRootElement` method. For collapsed subprocesses, the root element is suffixed with `_plane`. 16 | 17 | ```javascript 18 | var canvas = bpmnViewer.get('canvas'); 19 | 20 | // switch to a collapsed subprocess 21 | canvas.setRootElement('collapsedProcess_plane'); 22 | ``` 23 | 24 | ## Setting up bpmn-js 25 | 26 | Grab [bpmn-js](https://github.com/bpmn-io/bpmn-js) [pre-packaged](../pre-packaged) or [via npm](../bundling): 27 | 28 | To use `canvas` and other services provided by bpmn-js instantiate bpmn-js (this time the viewer) via 29 | 30 | ```javascript 31 | var bpmnViewer = new BpmnViewer({ 32 | container: '#canvas', 33 | width: '100%', 34 | height: '100%' 35 | }); 36 | ``` 37 | 38 | Import a BPMN 2.0 diagram and add the overlays in the `done` callback: 39 | 40 | ```javascript 41 | await bpmnViewer.importXML(diagramXML); 42 | 43 | // retrieve services and work with them 44 | bpmnViewer.get('canvas').setRootElement('...'); 45 | ``` 46 | 47 | 48 | ## Building the Project 49 | 50 | Initialize the project dependencies via 51 | 52 | ``` 53 | npm install 54 | ``` 55 | 56 | To create the sample distribution in the `dist` folder run 57 | 58 | ``` 59 | npm run all 60 | ``` 61 | 62 | To bootstrap a development setup that spawns a small webserver and rebuilds your app on changes run 63 | 64 | ``` 65 | npm run dev 66 | ``` 67 | 68 | 69 | ## License 70 | 71 | MIT 72 | -------------------------------------------------------------------------------- /deep-linking/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bpmn-js-example-deep-linking", 3 | "version": "0.0.0", 4 | "description": "An example how to bundle an app using bpmn-js for the browser", 5 | "scripts": { 6 | "all": "run-s build", 7 | "build": "webpack --mode=production", 8 | "dev": "webpack-dev-server --static=public --open", 9 | "start": "npm run dev" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/bpmn-io/bpmn-js-examples" 14 | }, 15 | "keywords": [ 16 | "bpmnjs-example" 17 | ], 18 | "contributors": [ 19 | { 20 | "name": "bpmn.io contributors", 21 | "url": "https://github.com/bpmn-io" 22 | } 23 | ], 24 | "license": "MIT", 25 | "devDependencies": { 26 | "css-loader": "^7.1.2", 27 | "npm-run-all2": "^8.0.0", 28 | "raw-loader": "^4.0.0", 29 | "style-loader": "^4.0.0", 30 | "webpack": "^5.97.1", 31 | "webpack-cli": "^6.0.1" 32 | }, 33 | "dependencies": { 34 | "bpmn-js": "^18.6.2", 35 | "webpack-dev-server": "^5.2.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /deep-linking/resources/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/deep-linking/resources/screenshot.png -------------------------------------------------------------------------------- /deep-linking/src/app.js: -------------------------------------------------------------------------------- 1 | import 'bpmn-js/dist/assets/diagram-js.css'; 2 | import 'bpmn-js/dist/assets/bpmn-js.css'; 3 | 4 | import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'; 5 | 6 | // we use stringify to inline an example XML document 7 | import nestedDiagram from '../resources/nested-subprocesses.bpmn'; 8 | 9 | // make sure you added bpmn-js to your your project 10 | // dependencies via npm install --save bpmn-js 11 | import BpmnViewer from 'bpmn-js'; 12 | 13 | var viewer = new BpmnViewer({ 14 | container: '#canvas' 15 | }); 16 | 17 | var canvas = viewer.get('canvas'); 18 | var eventBus = viewer.get('eventBus'); 19 | 20 | var search = new URLSearchParams(window.location.search); 21 | var browserNavigationInProgress; 22 | 23 | // update the URL and browser history when switching to another root element 24 | eventBus.on('root.set', function(event) { 25 | 26 | // location is already updated through the browser history API 27 | if (browserNavigationInProgress) { 28 | return; 29 | } 30 | 31 | var rootElement = event.element; 32 | 33 | search.set('rootElement', rootElement.id); 34 | window.history.pushState({ element: rootElement.id }, null, 'index.html?' + search.toString()); 35 | }); 36 | 37 | // listen to browser navigation and change the root element accordingly 38 | window.addEventListener('popstate', (event) => { 39 | var rootElement = event.state && event.state.element; 40 | 41 | if (!rootElement) { 42 | return; 43 | } 44 | 45 | browserNavigationInProgress = true; 46 | canvas.setRootElement(canvas.findRoot(rootElement)); 47 | browserNavigationInProgress = false; 48 | }); 49 | 50 | // import the diagram and set the root element from the search params 51 | browserNavigationInProgress = !!search.get('rootElement'); 52 | viewer.importXML(nestedDiagram).then(function() { 53 | var root = search.get('rootElement'); 54 | if (root) { 55 | canvas.setRootElement(canvas.findRoot(root)); 56 | } 57 | 58 | browserNavigationInProgress = false; 59 | }); 60 | -------------------------------------------------------------------------------- /deep-linking/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 14 | 15 | Deep linking example - bpmn-js 16 | 17 | 18 | 19 |

Deep Linking Example

20 | 21 |
22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /deep-linking/webpack.config.js: -------------------------------------------------------------------------------- 1 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 2 | 3 | const path = require('path'); 4 | 5 | module.exports = { 6 | mode: 'development', 7 | entry: './src/app.js', 8 | output: { 9 | path: path.resolve(__dirname, 'public'), 10 | filename: 'app.js' 11 | }, 12 | module: { 13 | rules: [ 14 | { 15 | test: /\.css$/, 16 | use: [ 17 | 'style-loader', 18 | 'css-loader', 19 | ] 20 | }, 21 | { 22 | test: /\.bpmn$/, 23 | use: { 24 | loader: 'raw-loader' 25 | } 26 | } 27 | ] 28 | }, 29 | plugins: [ 30 | new CopyWebpackPlugin({ 31 | patterns: [ 32 | { from: 'src/index.html', to: '.' } 33 | ] 34 | }) 35 | ] 36 | }; -------------------------------------------------------------------------------- /embedding/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | public/ -------------------------------------------------------------------------------- /embedding/README.md: -------------------------------------------------------------------------------- 1 | # bpmn-js embedding example 2 | 3 | This example shows how different versions of the toolkit can be embedded easily into a HTML page. 4 | 5 | > [!NOTE] 6 | > Starting with [bpmn-js@18](https://github.com/bpmn-io/bpmn-js/blob/develop/CHANGELOG.md#1800) diagram containers are focusable elements that play nicely with others. 7 | 8 | ## About 9 | 10 | This example embedds different variants of the BPMN toolkit into a larger website. You can see how each instance of modeler only captures keyboard shortcuts when it's focused and doesn't interfer with other (native or custom) elements. 11 | 12 | ![demo application screenshot](https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/main/embedding/docs/screenshot.png "Screenshot of the example application") 13 | 14 | ## Building 15 | 16 | You need a [NodeJS](http://nodejs.org) development stack with [npm](https://npmjs.org) installed to build the project. 17 | 18 | To install all project dependencies execute 19 | 20 | ``` 21 | npm install 22 | ``` 23 | 24 | Spawn the demo by executing 25 | 26 | ``` 27 | npm start 28 | ``` 29 | 30 | Both tasks generate the distribution ready client-side modeler application into the `public` folder. 31 | -------------------------------------------------------------------------------- /embedding/docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/embedding/docs/screenshot.png -------------------------------------------------------------------------------- /embedding/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bpmn-js-example-implicit-keyboard-bind", 3 | "version": "0.0.0", 4 | "description": "Demo of implicit keyboard binding in bpmn-js", 5 | "scripts": { 6 | "all": "run-s build", 7 | "build": "webpack --mode production", 8 | "dev": "webpack-dev-server --static=public --open", 9 | "start": "run-s dev" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/bpmn-io/bpmn-js-examples" 14 | }, 15 | "keywords": [ 16 | "bpmnjs-example" 17 | ], 18 | "author": { 19 | "name": "Jarek Danielak", 20 | "url": "https://github.com/jarekdanielak" 21 | }, 22 | "contributors": [ 23 | { 24 | "name": "bpmn.io contributors", 25 | "url": "https://github.com/bpmn-io" 26 | } 27 | ], 28 | "license": "MIT", 29 | "devDependencies": { 30 | "copy-webpack-plugin": "^13.0.0", 31 | "css-loader": "^7.1.2", 32 | "npm-run-all2": "^8.0.0", 33 | "raw-loader": "^4.0.0", 34 | "style-loader": "^4.0.0", 35 | "webpack": "^5.97.1", 36 | "webpack-cli": "^6.0.1", 37 | "webpack-dev-server": "^5.2.0" 38 | }, 39 | "dependencies": { 40 | "bpmn-js": "^18.6.2", 41 | "diagram-js": "^15.2.3", 42 | "jquery": "^3.3.1" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /embedding/src/app.js: -------------------------------------------------------------------------------- 1 | import 'bpmn-js/dist/assets/diagram-js.css'; 2 | import 'bpmn-js/dist/assets/bpmn-js.css'; 3 | 4 | import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'; 5 | 6 | import './style.css'; 7 | 8 | import BpmnModeler from 'bpmn-js/lib/Modeler'; 9 | import BpmnViewer from 'bpmn-js/lib/Viewer'; 10 | import BpmnNavigatedViewer from 'bpmn-js/lib/NavigatedViewer'; 11 | 12 | import Clipboard from 'diagram-js/lib/features/clipboard/Clipboard'; 13 | 14 | const editorMap = { 15 | 'editor': BpmnModeler, 16 | 'viewer': BpmnViewer, 17 | 'navigated-viewer': BpmnNavigatedViewer 18 | }; 19 | 20 | const sharedClipboard = { 21 | 'clipboard': [ 'value', new Clipboard() ] 22 | }; 23 | 24 | const additionalModulesMap = { 25 | 'first-modeler': [ 26 | sharedClipboard 27 | ], 28 | 'second-modeler': [ 29 | sharedClipboard 30 | ] 31 | }; 32 | 33 | const modelers = new Map(); 34 | 35 | function createModeler(viewerType, config, id) { 36 | 37 | const BpmnJS = editorMap[viewerType] || BpmnModeler; 38 | 39 | const additionalModules = additionalModulesMap[id] || []; 40 | 41 | return new BpmnJS({ 42 | ...config, 43 | additionalModules 44 | }); 45 | } 46 | 47 | async function openDiagram(element) { 48 | 49 | const diagramURL = element.dataset.diagram; 50 | const viewerType = element.dataset.editor; 51 | const id = element.id || '__default'; 52 | 53 | const modeler = createModeler(viewerType, { container: element }, id); 54 | 55 | modelers.set(element, modeler); 56 | 57 | const diagramXML = await fetch(diagramURL).then(response => response.text()); 58 | 59 | await modeler.importXML(diagramXML); 60 | } 61 | 62 | const elements = document.querySelectorAll('[data-diagram]'); 63 | 64 | for (const element of elements) { 65 | openDiagram(element).catch(err => console.error); 66 | } 67 | -------------------------------------------------------------------------------- /embedding/src/diagrams/first.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /embedding/src/diagrams/overview.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /embedding/src/diagrams/second.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /embedding/src/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body, html { 6 | padding: 0; 7 | margin: 0; 8 | } 9 | 10 | figure { 11 | margin: 30px 0; 12 | } 13 | 14 | figcaption { 15 | margin-top: .85em; 16 | text-align: center; 17 | } 18 | 19 | :focus { 20 | outline-color: cornflowerblue; 21 | } 22 | 23 | .container { 24 | width: 80%; 25 | max-width: 1200px; 26 | height: 100%; 27 | margin: 0 auto; 28 | } 29 | 30 | .diagram-grid { 31 | display: flex; 32 | flex-direction: row; 33 | } 34 | 35 | .diagram-grid:not(.single) { 36 | margin-left: -30px; 37 | margin-right: -30px; 38 | } 39 | 40 | .canvas { 41 | height: 400px; 42 | width: 100%; 43 | border-radius: 5px; 44 | border: solid 3px #eee; 45 | } 46 | 47 | .diagram-grid > * { 48 | flex: 1; 49 | } 50 | 51 | .diagram-grid > * + * { 52 | margin-left: 2em; 53 | } 54 | 55 | hr { 56 | margin: 30px 0; 57 | } -------------------------------------------------------------------------------- /embedding/webpack.config.js: -------------------------------------------------------------------------------- 1 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 2 | 3 | module.exports = { 4 | entry: { 5 | bundle: [ './src/app.js' ] 6 | }, 7 | output: { 8 | path: __dirname + '/public', 9 | filename: 'app.js' 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.css$/, 15 | use: [ 16 | 'style-loader', 17 | 'css-loader', 18 | ] 19 | }, 20 | { 21 | test: /\.bpmn$/, 22 | use: 'raw-loader' 23 | } 24 | ] 25 | }, 26 | plugins: [ 27 | new CopyWebpackPlugin({ 28 | patterns: [ 29 | { from: 'src/index.html', to: '.' }, 30 | { context: 'src', from: 'diagrams/*.bpmn', to: '.' } 31 | ] 32 | }) 33 | ], 34 | mode: 'development', 35 | devtool: 'source-map' 36 | }; 37 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import bpmnIoPlugin from 'eslint-plugin-bpmn-io'; 2 | 3 | export default [ 4 | { 5 | ignores: [ '**/public', '**/dist' ], 6 | }, 7 | ...bpmnIoPlugin.configs.browser, 8 | ...bpmnIoPlugin.configs.node.map(config => { 9 | return { 10 | ...config, 11 | files: [ 12 | '**/*.config.js', 13 | '**/*.conf.js', 14 | '**/server.js', 15 | '**/test/**/*.js', 16 | ] 17 | }; 18 | }), 19 | ...bpmnIoPlugin.configs.mocha.map(config => { 20 | return { 21 | ...config, 22 | files: [ 23 | '**/test/**/*.js', 24 | ] 25 | }; 26 | }), 27 | { 28 | files: [ '**/*.js', '**/*.mjs' ], 29 | } 30 | ]; -------------------------------------------------------------------------------- /i18n/README.md: -------------------------------------------------------------------------------- 1 | # bpmn-js i18n Example 2 | 3 | This example shows how to translate the strings displayed in [bpmn-js](https://github.com/bpmn-io/bpmn-js) to another language or domain. 4 | 5 | ![Screenshot](resources/screenshot.png) 6 | 7 | ## Usage Summary 8 | 9 | The custom translation function is provided as an additional module when [bpmn-js](https://github.com/bpmn-io/bpmn-js) is instantiated. The default translation implementation is thereby overwritten. 10 | 11 | ```javascript 12 | var customTranslate = { 13 | translate: [ 'value', require('./custom-translate/custom-translate') ] 14 | }; 15 | 16 | var modeler = new BpmnModeler({ 17 | // ... 18 | additionalModules: [ 19 | customTranslate 20 | ] 21 | }); 22 | ``` 23 | 24 | You can use your own implementation for translation. The function has two arguments (a template string and an optional object with replacements) and must return the translated string. The example provides two main functionalities: translating and replacing template strings. 25 | 26 | Translating a string: 27 | 28 | ```javascript 29 | var translations = { 30 | 'Append': 'Anhängen' 31 | }; 32 | 33 | //... 34 | 35 | translate('Append'); // Returns 'Anhängen' 36 | ``` 37 | 38 | Translating a template string: 39 | 40 | ```javascript 41 | var translations = { 42 | 'Append {element}': '{element} anhängen' 43 | }; 44 | 45 | //... 46 | 47 | translate('Append {element}', {element: 'Gateway'}); // Returns 'Gateway anhängen' 48 | ``` 49 | 50 | A list of all available template strings of [bpmn-js](https://github.com/bpmn-io/bpmn-js) as well as existing translations can be found in the [bpmn-js-i18n repository](https://github.com/bpmn-io/bpmn-js-i18n). 51 | 52 | 53 | ## Run the Example 54 | 55 | You need a [NodeJS](http://nodejs.org) development stack with [npm](https://npmjs.org) installed to build the project. 56 | 57 | To install all project dependencies execute 58 | 59 | ```sh 60 | npm install 61 | ``` 62 | 63 | To start the example execute 64 | 65 | ```sh 66 | npm start 67 | ``` 68 | 69 | To build the example into the `public` folder execute 70 | 71 | ```sh 72 | npm run all 73 | ``` 74 | -------------------------------------------------------------------------------- /i18n/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bpmn-js-example-i18n", 3 | "version": "0.0.0", 4 | "description": "Simple i18n with bpmn-js", 5 | "scripts": { 6 | "all": "run-s build", 7 | "build": "webpack --mode production", 8 | "dev": "webpack-dev-server --static=public --open", 9 | "start": "run-s dev" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/bpmn-io/bpmn-js-examples" 14 | }, 15 | "keywords": [ 16 | "bpmnjs-example" 17 | ], 18 | "author": { 19 | "name": "Nico Rehwaldt", 20 | "url": "https://github.com/nikku" 21 | }, 22 | "contributors": [ 23 | { 24 | "name": "bpmn.io contributors", 25 | "url": "https://github.com/bpmn-io" 26 | } 27 | ], 28 | "license": "MIT", 29 | "devDependencies": { 30 | "copy-webpack-plugin": "^13.0.0", 31 | "css-loader": "^7.1.2", 32 | "npm-run-all2": "^8.0.0", 33 | "raw-loader": "^4.0.0", 34 | "style-loader": "^4.0.0", 35 | "webpack": "^5.97.1", 36 | "webpack-cli": "^6.0.1", 37 | "webpack-dev-server": "^5.2.0" 38 | }, 39 | "dependencies": { 40 | "bpmn-js": "^18.6.2" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /i18n/resources/newDiagram.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /i18n/resources/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/i18n/resources/screenshot.png -------------------------------------------------------------------------------- /i18n/src/app.js: -------------------------------------------------------------------------------- 1 | import 'bpmn-js/dist/assets/diagram-js.css'; 2 | import 'bpmn-js/dist/assets/bpmn-js.css'; 3 | 4 | import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'; 5 | 6 | import BpmnModeler from 'bpmn-js/lib/Modeler'; 7 | 8 | import customTranslate from './customTranslate/customTranslate'; 9 | 10 | import diagramXML from '../resources/newDiagram.bpmn'; 11 | 12 | 13 | // Our custom translation module 14 | // We need to use the array syntax that is used by bpmn-js internally 15 | // 'value' tells bmpn-js to use the function instead of trying to instanciate it 16 | var customTranslateModule = { 17 | translate: [ 'value', customTranslate ] 18 | }; 19 | 20 | // Spin up an instance of the modeler that uses our custom translation module 21 | var modeler = new BpmnModeler({ 22 | container: '#canvas', 23 | additionalModules: [ 24 | customTranslateModule 25 | ] 26 | }); 27 | 28 | // Import our diagram 29 | modeler.importXML(diagramXML).then(function() { 30 | 31 | console.log('Success!'); 32 | }).catch(function(err) { 33 | 34 | console.error('Error', err); 35 | }); 36 | -------------------------------------------------------------------------------- /i18n/src/customTranslate/customTranslate.js: -------------------------------------------------------------------------------- 1 | import translations from './translations'; 2 | 3 | 4 | export default function customTranslate(template, replacements) { 5 | replacements = replacements || {}; 6 | 7 | // Translate 8 | template = translations[template] || template; 9 | 10 | // Replace 11 | return template.replace(/{([^}]+)}/g, function(_, key) { 12 | return replacements[key] || '{' + key + '}'; 13 | }); 14 | } -------------------------------------------------------------------------------- /i18n/src/customTranslate/translations.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a sample file that should be replaced with the actual translation. 3 | * 4 | * Checkout https://github.com/bpmn-io/bpmn-js-i18n for a list of available 5 | * translations and labels to translate. 6 | */ 7 | export default { 8 | 'Exclusive Gateway': 'Exklusives Gateway', 9 | 'Parallel Gateway': 'Paralleles Gateway', 10 | 'Inclusive Gateway': 'Inklusives Gateway', 11 | 'Complex Gateway': 'Komplexes Gateway', 12 | 'Event based Gateway': 'Ereignis-basiertes Gateway', 13 | 'Message Start Event': '消息启动事件', 14 | 'Timer Start Event': '定时启动事件', 15 | 'Conditional Start Event': '条件启动事件', 16 | 'Signal Start Event': '信号启动事件', 17 | 'Error Start Event': '错误启动事件', 18 | 'Escalation Start Event': '升级启动事件', 19 | 'Compensation Start Event': '补偿启动事件', 20 | 'Message Start Event (non-interrupting)': '消息启动事件 (非中断)', 21 | 'Timer Start Event (non-interrupting)': '定时启动事件 (非中断)', 22 | 'Conditional Start Event (non-interrupting)': '条件启动事件 (非中断)', 23 | 'Signal Start Event (non-interrupting)': '信号启动事件 (非中断)', 24 | 'Escalation Start Event (non-interrupting)': '升级启动事件 (非中断)', 25 | }; -------------------------------------------------------------------------------- /i18n/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | bpmn-js i18n demo 5 | 6 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /i18n/webpack.config.js: -------------------------------------------------------------------------------- 1 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 2 | 3 | module.exports = { 4 | entry: { 5 | bundle: [ './src/app.js' ] 6 | }, 7 | output: { 8 | path: __dirname + '/public', 9 | filename: 'app.js' 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.css$/, 15 | use: [ 16 | 'style-loader', 17 | 'css-loader', 18 | ] 19 | }, 20 | { 21 | test: /\.bpmn$/, 22 | use: 'raw-loader' 23 | } 24 | ] 25 | }, 26 | plugins: [ 27 | new CopyWebpackPlugin({ 28 | patterns: [ 29 | { from: 'src/index.html', to: '.' } 30 | ] 31 | }) 32 | ], 33 | mode: 'development', 34 | devtool: 'source-map' 35 | }; 36 | -------------------------------------------------------------------------------- /interaction/README.md: -------------------------------------------------------------------------------- 1 | # bpmn-js interaction example 2 | 3 | An example that showcases the different ways to enable user interaction with 4 | BPMN diagrams using [bpmn-js](https://github.com/bpmn-io/bpmn-js). 5 | 6 | [__Try out__](https://cdn.statically.io/gh/bpmn-io/bpmn-js-examples/main/interaction/index.html). 7 | 8 | 9 | ## About 10 | 11 | The embeds a BPMN viewer, opens a BPMN 2.0 diagram and logs user interactions. 12 | 13 | 14 | ## Usage summary 15 | 16 | You may attach interaction event listeners to a BPMN viewer/modeler as soon as 17 | it has a diagram loaded: 18 | 19 | 20 | ```javascript 21 | var viewer = new BpmnJS({ container: SOME_CONTAINER }); 22 | 23 | try { 24 | await viewer.importXML(diagramXM); 25 | 26 | // diagram is loaded, add interaction to it now 27 | // see below for options 28 | // ... 29 | } catch (err) { 30 | console.error('Error happened: ', err); 31 | } 32 | ``` 33 | 34 | Two options exists for making your diagram interactive. 35 | 36 | 37 | ### Hook into diagram events 38 | 39 | Use the `eventBus` service to hook into `element.*` interaction events. 40 | [bpmn-js](https://github.com/bpmn-io/bpmn-js) makes sure the events are 41 | properly dispatched, even if the user works on a touch device. 42 | 43 | ```javascript 44 | var eventBus = viewer.get('eventBus'); 45 | 46 | // you may hook into any of the following events 47 | var events = [ 48 | 'element.hover', 49 | 'element.out', 50 | 'element.click', 51 | 'element.dblclick', 52 | 'element.mousedown', 53 | 'element.mouseup' 54 | ]; 55 | 56 | events.forEach(function(event) { 57 | 58 | eventBus.on(event, function(e) { 59 | // e.element = the model element 60 | // e.gfx = the graphical element 61 | 62 | log(event, 'on', e.element.id); 63 | }); 64 | }); 65 | ``` 66 | 67 | 68 | ### Directly attach listener to DOM 69 | 70 | You have more control on which elements you would like to address by directly 71 | attaching listeners to the underlying DOM (i.e. HTML/SVG) nodes. 72 | 73 | You can do so by searching for selectors like `[data-element-id=ID_OF_ELEMENT]`: 74 | 75 | ```javascript 76 | // each model element a data-element-id attribute attached to 77 | // it in HTML 78 | 79 | // select the end event 80 | var endEventNode = document.querySelector('[data-element-id=END_EVENT]'); 81 | endEventNode.addEventListener('click', function(e) { 82 | alert('clicked the end event!'); 83 | }); 84 | ``` 85 | 86 | Both options allow you to intercept user interaction with the diagram and 87 | handle it accordingly. 88 | 89 | 90 | ## Run this Example 91 | 92 | Download and open the [example HTML page](https://cdn.statically.io/gh/bpmn-io/bpmn-js-examples/main/interaction/index.html). 93 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "node_modules/lerna/schemas/lerna-schema.json", 3 | "version": "0.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /minimap/README.md: -------------------------------------------------------------------------------- 1 | # bpmn-js Minimap Example 2 | 3 | This example uses [bpmn-js](https://github.com/bpmn-io/bpmn-js) and [diagram-js-minimap](https://github.com/bpmn-io/diagram-js-minimap). It implements a BPMN 2.0 modeler with a minimap that lets you navigate the diagram. 4 | 5 | ![demo application screenshot](docs/screenshot.png) 6 | 7 | 8 | ## Usage 9 | 10 | Add [diagram-js-minimap](https://github.com/bpmn-io/diagram-js-minimap) to your project: 11 | 12 | ```sh 13 | npm install --save diagram-js-minimap 14 | ``` 15 | 16 | Now load the minimap module along with the [bpmn-js](https://github.com/bpmm-io/bpmn-js) instance: 17 | 18 | ```javascript 19 | import BpmnModeler from 'bpmn-js/lib/Modeler'; 20 | 21 | import minimapModule from 'diagram-js-minimap'; 22 | 23 | var bpmnModeler = new BpmnModeler({ 24 | container: '#canvas', 25 | additionalModules: [ 26 | minimapModule 27 | ] 28 | }); 29 | 30 | await bpmnModeler.importXML(xml); 31 | 32 | console.log('Awesome! Ready to navigate!'); 33 | ``` 34 | 35 | Checkout [`src/app.js`](src/app.js) for details. 36 | 37 | 38 | ## Run the Example 39 | 40 | You need a [NodeJS](http://nodejs.org) development stack with [npm](https://npmjs.org) installed to build the project. 41 | 42 | To install all project dependencies execute 43 | 44 | ```sh 45 | npm install 46 | ``` 47 | 48 | To start the example execute 49 | 50 | ```sh 51 | npm start 52 | ``` 53 | 54 | To build the example into the `public` folder execute 55 | 56 | ```sh 57 | npm run all 58 | ``` 59 | -------------------------------------------------------------------------------- /minimap/docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/minimap/docs/screenshot.png -------------------------------------------------------------------------------- /minimap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bpmn-js-example-minimap", 3 | "version": "0.0.0", 4 | "description": "Use the diagram-js minimap with the bpmn-js modeler", 5 | "scripts": { 6 | "all": "run-s build", 7 | "build": "webpack --mode production", 8 | "dev": "webpack-dev-server --static=public --open", 9 | "start": "run-s dev" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/bpmn-io/bpmn-js-examples" 14 | }, 15 | "keywords": [ 16 | "bpmnjs-example" 17 | ], 18 | "author": { 19 | "name": "Philipp Fromme", 20 | "url": "https://github.com/philippfromme" 21 | }, 22 | "contributors": [ 23 | { 24 | "name": "bpmn.io contributors", 25 | "url": "https://github.com/bpmn-io" 26 | } 27 | ], 28 | "license": "MIT", 29 | "devDependencies": { 30 | "copy-webpack-plugin": "^13.0.0", 31 | "css-loader": "^7.1.2", 32 | "npm-run-all2": "^8.0.0", 33 | "raw-loader": "^4.0.0", 34 | "style-loader": "^4.0.0", 35 | "webpack": "^5.97.1", 36 | "webpack-cli": "^6.0.1", 37 | "webpack-dev-server": "^5.2.0" 38 | }, 39 | "dependencies": { 40 | "bpmn-js": "^18.6.2", 41 | "diagram-js-minimap": "^5.0.0", 42 | "jquery": "^3.3.1" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /minimap/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | bpmn-js minimap demo 5 | 6 | 7 |
8 | 9 |
10 |
11 |

Ooops, we could not display the BPMN 2.0 diagram.

12 | 13 |
14 | cause of the problem 15 |

16 |         
17 |
18 |
19 | 20 |
21 |
22 | 23 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /minimap/src/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body, html { 6 | 7 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 8 | 9 | font-size: 12px; 10 | 11 | height: 100%; 12 | padding: 0; 13 | margin: 0; 14 | } 15 | 16 | a:link { 17 | text-decoration: none; 18 | } 19 | 20 | .content, 21 | .content > div { 22 | width: 100%; 23 | height: 100%; 24 | position: relative; 25 | } 26 | 27 | .content > .message { 28 | text-align: center; 29 | display: table; 30 | 31 | font-size: 16px; 32 | color: #111; 33 | } 34 | 35 | .content > .message .note { 36 | vertical-align: middle; 37 | text-align: center; 38 | display: table-cell; 39 | } 40 | 41 | .content .error .details { 42 | max-width: 500px; 43 | font-size: 12px; 44 | margin: 20px auto; 45 | text-align: left; 46 | } 47 | 48 | .content .error pre { 49 | border: solid 1px #CCC; 50 | background: #EEE; 51 | padding: 10px; 52 | } 53 | 54 | .content:not(.with-error) .error, 55 | .content.with-error .intro, 56 | .content.with-diagram .intro { 57 | display: none; 58 | } 59 | 60 | 61 | .content .canvas, 62 | .content.with-error .canvas { 63 | visibility: hidden; 64 | } 65 | 66 | .content.with-diagram .canvas { 67 | visibility: visible; 68 | } 69 | 70 | .buttons { 71 | position: fixed; 72 | bottom: 20px; 73 | left: 20px; 74 | 75 | padding: 0; 76 | margin: 0; 77 | list-style: none; 78 | } 79 | 80 | .buttons > li { 81 | display: inline-block; 82 | margin-right: 10px; 83 | } 84 | .buttons > li > a { 85 | background: #DDD; 86 | border: solid 1px #666; 87 | display: inline-block; 88 | padding: 5px; 89 | } 90 | 91 | .buttons a { 92 | opacity: 0.3; 93 | } 94 | 95 | .buttons a.active { 96 | opacity: 1.0; 97 | } 98 | -------------------------------------------------------------------------------- /minimap/webpack.config.js: -------------------------------------------------------------------------------- 1 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 2 | 3 | module.exports = { 4 | entry: { 5 | bundle: [ './src/app.js' ] 6 | }, 7 | output: { 8 | path: __dirname + '/public', 9 | filename: 'app.js' 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.css$/, 15 | use: [ 16 | 'style-loader', 17 | 'css-loader', 18 | ] 19 | }, 20 | { 21 | test: /\.bpmn$/, 22 | use: 'raw-loader' 23 | } 24 | ] 25 | }, 26 | plugins: [ 27 | new CopyWebpackPlugin({ 28 | patterns: [ 29 | { from: 'src/index.html', to: '.' } 30 | ] 31 | }) 32 | ], 33 | mode: 'development', 34 | devtool: 'source-map' 35 | }; 36 | -------------------------------------------------------------------------------- /modeler/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | public/ -------------------------------------------------------------------------------- /modeler/README.md: -------------------------------------------------------------------------------- 1 | # bpmn-js Modeler Example 2 | 3 | This example uses [bpmn-js](https://github.com/bpmn-io/bpmn-js) to implement a modeler for BPMN 2.0 process diagrams. It serves as the basis of the bpmn-js demo application available at [demo.bpmn.io](http://demo.bpmn.io). 4 | 5 | ## About 6 | 7 | This example is a node-style web application that builds a user interface around the bpmn-js BPMN 2.0 modeler. 8 | 9 | ![demo application screenshot](https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/main/modeler/docs/screenshot.png "Screenshot of the example application") 10 | 11 | 12 | ## Building 13 | 14 | You need a [NodeJS](http://nodejs.org) development stack with [npm](https://npmjs.org) installed to build the project. 15 | 16 | To install all project dependencies execute 17 | 18 | ``` 19 | npm install 20 | ``` 21 | 22 | Build the application (including [bpmn-js](https://github.com/bpmn-io/bpmn-js)) via 23 | 24 | ``` 25 | npm run all 26 | ``` 27 | 28 | You may also spawn a development setup by executing 29 | 30 | ``` 31 | npm run dev 32 | ``` 33 | 34 | Both tasks generate the distribution ready client-side modeler application into the `public` folder. 35 | 36 | Serve the application locally or via a web server (nginx, apache, embedded). -------------------------------------------------------------------------------- /modeler/docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/modeler/docs/screenshot.png -------------------------------------------------------------------------------- /modeler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bpmn-js-example-modeler", 3 | "version": "0.0.0", 4 | "description": "A simple modeler built with bpmn-js", 5 | "scripts": { 6 | "all": "run-s build", 7 | "build": "webpack --mode production", 8 | "dev": "webpack-dev-server --static=public --open", 9 | "start": "run-s dev" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/bpmn-io/bpmn-js-examples" 14 | }, 15 | "keywords": [ 16 | "bpmnjs-example" 17 | ], 18 | "author": { 19 | "name": "Nico Rehwaldt", 20 | "url": "https://github.com/nikku" 21 | }, 22 | "contributors": [ 23 | { 24 | "name": "bpmn.io contributors", 25 | "url": "https://github.com/bpmn-io" 26 | } 27 | ], 28 | "license": "MIT", 29 | "devDependencies": { 30 | "copy-webpack-plugin": "^13.0.0", 31 | "css-loader": "^7.1.2", 32 | "npm-run-all2": "^8.0.0", 33 | "raw-loader": "^4.0.0", 34 | "style-loader": "^4.0.0", 35 | "webpack": "^5.97.1", 36 | "webpack-cli": "^6.0.1", 37 | "webpack-dev-server": "^5.2.0" 38 | }, 39 | "dependencies": { 40 | "bpmn-js": "^18.6.2", 41 | "diagram-js": "^15.1.0", 42 | "jquery": "^3.3.1" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /modeler/resources/newDiagram.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /modeler/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | bpmn-js modeler demo 5 | 6 | 7 |
8 | 9 |
10 |
11 | Drop BPMN diagram from your desktop or create a new diagram to get started. 12 |
13 |
14 | 15 |
16 |
17 |

Ooops, we could not display the BPMN 2.0 diagram.

18 | 19 |
20 | cause of the problem 21 |

22 |         
23 |
24 |
25 | 26 |
27 |
28 | 29 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /modeler/src/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body, html { 6 | 7 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 8 | 9 | font-size: 12px; 10 | 11 | height: 100%; 12 | padding: 0; 13 | margin: 0; 14 | } 15 | 16 | a:link { 17 | text-decoration: none; 18 | } 19 | 20 | .content, 21 | .content > div { 22 | width: 100%; 23 | height: 100%; 24 | overflow: hidden; 25 | } 26 | 27 | .content > .message { 28 | text-align: center; 29 | display: table; 30 | 31 | font-size: 16px; 32 | color: #111; 33 | } 34 | 35 | .content > .message .note { 36 | vertical-align: middle; 37 | text-align: center; 38 | display: table-cell; 39 | } 40 | 41 | .content > .error .details { 42 | max-width: 500px; 43 | font-size: 12px; 44 | margin: 20px auto; 45 | text-align: left; 46 | } 47 | 48 | .content > .error pre { 49 | border: solid 1px #CCC; 50 | background: #EEE; 51 | padding: 10px; 52 | } 53 | 54 | .content:not(.with-error) > .error, 55 | .content.with-error > .intro, 56 | .content.with-diagram > .intro { 57 | display: none; 58 | } 59 | 60 | 61 | .content .canvas, 62 | .content.with-error .canvas { 63 | visibility: hidden; 64 | } 65 | 66 | .content.with-diagram .canvas { 67 | visibility: visible; 68 | } 69 | 70 | .buttons { 71 | position: fixed; 72 | bottom: 20px; 73 | left: 20px; 74 | 75 | padding: 0; 76 | margin: 0; 77 | list-style: none; 78 | } 79 | 80 | .buttons > li { 81 | display: inline-block; 82 | margin-right: 10px; 83 | } 84 | .buttons > li > a { 85 | background: #DDD; 86 | border: solid 1px #666; 87 | display: inline-block; 88 | padding: 5px; 89 | } 90 | 91 | .buttons a { 92 | opacity: 0.3; 93 | } 94 | 95 | .buttons a.active { 96 | opacity: 1.0; 97 | } -------------------------------------------------------------------------------- /modeler/webpack.config.js: -------------------------------------------------------------------------------- 1 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 2 | 3 | module.exports = { 4 | entry: { 5 | bundle: [ './src/app.js' ] 6 | }, 7 | output: { 8 | path: __dirname + '/public', 9 | filename: 'app.js' 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.css$/, 15 | use: [ 16 | 'style-loader', 17 | 'css-loader', 18 | ] 19 | }, 20 | { 21 | test: /\.bpmn$/, 22 | use: 'raw-loader' 23 | } 24 | ] 25 | }, 26 | plugins: [ 27 | new CopyWebpackPlugin({ 28 | patterns: [ 29 | { from: 'src/index.html', to: '.' } 30 | ] 31 | }) 32 | ], 33 | mode: 'development', 34 | devtool: 'source-map' 35 | }; 36 | -------------------------------------------------------------------------------- /modeling-api/README.md: -------------------------------------------------------------------------------- 1 | # bpmn-js Example: Modeling Using the Api 2 | 3 | A step-by-step introduction to modeling using the API. You'll learn how create and edit shapes and connections. 4 | 5 | ![Screenshot of the example](docs/screenshot.png "Screenshot of the example") 6 | 7 | ## About This Example 8 | 9 | This example is built as a webpage that introduces you to the basics of working with bpmn-js' API, including: 10 | 11 | * creating and editing shapes and connections 12 | * editing the BPMN properties of an element 13 | * creating collaborations, participants and lanes 14 | 15 | ## Running the Example 16 | 17 | Install the dependencies: 18 | 19 | ``` 20 | npm install 21 | ``` 22 | 23 | Build and open the example in the browser: 24 | 25 | ``` 26 | npm start 27 | ``` 28 | 29 | ## License 30 | 31 | MIT 32 | -------------------------------------------------------------------------------- /modeling-api/docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/modeling-api/docs/screenshot.png -------------------------------------------------------------------------------- /modeling-api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "modeling-api", 3 | "version": "0.0.0", 4 | "description": "Modeling bpmn-js using the API", 5 | "scripts": { 6 | "all": "run-s build", 7 | "build": "webpack --mode production", 8 | "dev": "webpack-dev-server --static=public --open", 9 | "start": "run-s dev" 10 | }, 11 | "devDependencies": { 12 | "copy-webpack-plugin": "^13.0.0", 13 | "css-loader": "^7.1.2", 14 | "npm-run-all2": "^8.0.0", 15 | "raw-loader": "^4.0.0", 16 | "style-loader": "^4.0.0", 17 | "webpack": "^5.97.1", 18 | "webpack-cli": "^6.0.1", 19 | "webpack-dev-server": "^5.2.0" 20 | }, 21 | "dependencies": { 22 | "bpmn-js": "^18.6.2", 23 | "diagram-js": "^15.1.0", 24 | "highlight.js": "^11.10.0", 25 | "min-dom": "^4.2.1" 26 | }, 27 | "repository": { 28 | "type": "git", 29 | "url": "https://github.com/bpmn-io/bpmn-js-examples" 30 | }, 31 | "keywords": [ 32 | "bpmnjs-example" 33 | ], 34 | "author": { 35 | "name": "bpmn.io team", 36 | "url": "https://github.com/bpmn-io" 37 | }, 38 | "license": "MIT" 39 | } 40 | -------------------------------------------------------------------------------- /modeling-api/resources/diagram.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /modeling-api/src/app.js: -------------------------------------------------------------------------------- 1 | import 'bpmn-js/dist/assets/diagram-js.css'; 2 | import 'bpmn-js/dist/assets/bpmn-js.css'; 3 | 4 | import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'; 5 | 6 | import './style.css'; 7 | 8 | import BpmnModeler from 'bpmn-js/lib/Modeler'; 9 | 10 | import hljs from 'highlight.js/lib/core'; 11 | import javascript from 'highlight.js/lib/languages/javascript'; 12 | 13 | import diagram from '../resources/diagram.bpmn'; 14 | 15 | import { domify } from 'min-dom'; 16 | 17 | import snippets from './snippets'; 18 | 19 | hljs.registerLanguage('javascript', javascript); 20 | hljs.initHighlightingOnLoad(); 21 | 22 | const container = document.querySelector('.modeler'); 23 | 24 | const modeler = new BpmnModeler({ 25 | container 26 | }); 27 | 28 | async function openDiagram(xml) { 29 | return modeler.importXML(xml).catch(err => { 30 | console.log(err); 31 | }); 32 | } 33 | 34 | /** 35 | * Load snippet, display code and show resulting diagram. 36 | * 37 | * @param {Function} fn 38 | * @param {String} diagram 39 | */ 40 | function loadSnippet(fn, diagram) { 41 | openDiagram(diagram).then(() => { 42 | 43 | // (1) Reset zoom 44 | modeler.get('canvas').zoom('fit-viewport'); 45 | 46 | // (2) Execute snippet 47 | fn(modeler); 48 | 49 | // (3) Display snippet code 50 | let code = formatSnippetCode(fn.toString()); 51 | 52 | document.querySelector('.snippet__code').textContent = code; 53 | 54 | hljs.highlightBlock(document.querySelector('.snippet__code')); 55 | 56 | // (4) Export to console 57 | modeler.saveXML({ format: true }).then(({ xml }) => console.info(xml)); 58 | }); 59 | } 60 | 61 | /** 62 | * Set up snippets. 63 | * 64 | * @param {Array} snippets 65 | */ 66 | function setUpSnippets(snippets) { 67 | const snippetsList = document.getElementsByClassName('snippets__list')[ 0 ]; 68 | 69 | function handleSnippetClick(snippetsListItem, snippet) { 70 | snippetsListItems.forEach(({ classList })=> classList.remove('snippets__list-item--active')); 71 | 72 | snippetsListItem.classList.add('snippets__list-item--active'); 73 | 74 | loadSnippet(snippet.fn, snippet.diagram || diagram); 75 | } 76 | 77 | const snippetsListItems = snippets.map(snippet => { 78 | const snippetsListItem = domify( 79 | `
  • ${ snippet.name }

    ${ snippet.description }

  • `); 80 | 81 | snippetsListItem.addEventListener('click', () => { 82 | handleSnippetClick(snippetsListItem, snippet); 83 | }); 84 | 85 | snippetsList.appendChild(snippetsListItem); 86 | 87 | return snippetsListItem; 88 | }); 89 | 90 | handleSnippetClick(snippetsListItems[ 0 ], snippets[ 0 ]); 91 | } 92 | 93 | /** 94 | * Format snippet code by removing first and last line and 95 | * removing unnecessary indentation. 96 | * 97 | * @param {string} snippetCode 98 | * 99 | * @return {string} 100 | */ 101 | function formatSnippetCode(snippetCode) { 102 | let lines = snippetCode.split('\n'); 103 | 104 | // (1) Remove surrounding function block 105 | lines = lines.slice(1, lines.length - 1); 106 | 107 | // (2) Remove unnecessary indentation 108 | const indentation = lines.reduce((indentation, line) => { 109 | line = line.search(/\S/); 110 | 111 | return (line != -1 && line < indentation) ? line : indentation; 112 | }, Infinity); 113 | 114 | return lines.map(line => line.substring(indentation)).join('\n'); 115 | } 116 | 117 | setUpSnippets(snippets); -------------------------------------------------------------------------------- /modeling-api/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Modeling using the API 7 | 8 | 9 |
    10 |
      11 |
      12 |
      13 |
      14 | 15 | 16 | -------------------------------------------------------------------------------- /modeling-api/src/snippets/businessObjects.js: -------------------------------------------------------------------------------- 1 | function fn(modeler) { 2 | 3 | /** 4 | * Business objects are the model objects that hold all the BPMN-related properties of a shape or 5 | * connection. They can be accessed through an element's `businessObject` property. Not all model 6 | * objects are visible as shapes or connections. An event definition for example is a model object 7 | * that is part of an event shape's business object. 8 | * 9 | * The entire BPMN model can be found here: https://github.com/bpmn-io/bpmn-moddle/blob/main/resources/bpmn/json/bpmn.json 10 | * 11 | * The modules used in this example are: 12 | * 13 | * * BpmnFactory: Creates new business objects. 14 | * * ElementFactory: Creates new shapes and connections. 15 | * * ElementRegistry: A registry of all shapes and connections of the diagram. 16 | * * Modeling: The main module for modeling. 17 | * 18 | * We will use these modules to create a new business object representing a shape, 19 | * add it to the diagram, and connect it to an existing shape. 20 | */ 21 | 22 | // (1) Get the modules 23 | const bpmnFactory = modeler.get('bpmnFactory'), 24 | elementFactory = modeler.get('elementFactory'), 25 | elementRegistry = modeler.get('elementRegistry'), 26 | modeling = modeler.get('modeling'); 27 | 28 | // (2) Get the existing process and the start event 29 | const process = elementRegistry.get('Process_1'), 30 | startEvent = elementRegistry.get('StartEvent_1'); 31 | 32 | // You can access the start event's business object 33 | console.log(startEvent.businessObject); // { "$type": "bpmn:StartEvent", ... } 34 | 35 | // (3) Instead of relying on the element factory to automatically create a business object use 36 | // the BPMN factory to create one 37 | const taskBusinessObject = bpmnFactory.create('bpmn:Task', { id: 'Task_1', name: 'Task' }); 38 | 39 | // (4) Create a new diagram shape using the business object you just created 40 | const task = elementFactory.createShape({ type: 'bpmn:Task', businessObject: taskBusinessObject }); 41 | 42 | // (5) Add the new task to the diagram 43 | modeling.createShape(task, { x: 400, y: 100 }, process); 44 | 45 | // Using the `id` property we specified you can now access the new task through the element registry 46 | console.log(elementRegistry.get('Task_1')); // Shape { "type": "bpmn:Task", ... } 47 | } 48 | 49 | export default { 50 | id: 'businessObjects', 51 | name: 'Business Objects', 52 | description: 'What business objects are and how you can work with them.', 53 | fn 54 | }; -------------------------------------------------------------------------------- /modeling-api/src/snippets/collaborations.js: -------------------------------------------------------------------------------- 1 | function fn(modeler) { 2 | 3 | /** 4 | * So far we've worked with processes. Let's have a look at collaborations. 5 | * 6 | * The modules used in this example are: 7 | * 8 | * * ElementFactory: Creates new shapes and connections. 9 | * * ElementRegistry: A registry of all shapes and connections of the diagram. 10 | * * Modeling: The main module for modeling. 11 | * 12 | * We will use these modules to create Participants, add them to the diagram (thereby 13 | * turning the process into a collaboration), create lanes and connect participants 14 | * using Message Flows. 15 | */ 16 | 17 | // (1) Get the modules 18 | const elementFactory = modeler.get('elementFactory'), 19 | elementRegistry = modeler.get('elementRegistry'), 20 | modeling = modeler.get('modeling'); 21 | 22 | // (2) Get the existing process and the start event 23 | const process = elementRegistry.get('Process_1'), 24 | startEvent = elementRegistry.get('StartEvent_1'); 25 | 26 | // (3) Create a new participant shape using `createParticipantShape` 27 | const participant = elementFactory.createParticipantShape({ type: 'bpmn:Participant' }); 28 | 29 | // (4) Add the new participant to the diagram turning the process into a collaboration 30 | modeling.createShape(participant, { x: 400, y: 100 }, process); 31 | 32 | // The existing start event is now a child of the participant 33 | console.log(startEvent.parent); // Shape { "type": "bpmn:Participant", ... } 34 | 35 | // (5) Create a lane 36 | const lane = modeling.addLane(participant, 'bottom'); 37 | 38 | // (6) Create two nested lanes 39 | modeling.splitLane(lane, 2); 40 | 41 | // (7) Create another participant shape that is collapsed 42 | const collapsedParticipant = elementFactory 43 | .createParticipantShape({ type: 'bpmn:Participant', isExpanded: false }); 44 | 45 | // (8) Add the participant to the diagram 46 | modeling.createShape(collapsedParticipant, { x: 300, y: 500 }, process); 47 | 48 | // (9) Connect the two participants through a message flow 49 | modeling.connect(collapsedParticipant, participant); 50 | } 51 | 52 | export default { 53 | id: 'collaborations', 54 | name: 'Collaborations', 55 | description: 'Working with collaborations.', 56 | fn 57 | }; -------------------------------------------------------------------------------- /modeling-api/src/snippets/connectingShapes.js: -------------------------------------------------------------------------------- 1 | function fn(modeler) { 2 | 3 | /** 4 | * Now let's look at the different ways of connecting shapes to each other. 5 | * 6 | * The modules used in this example are: 7 | * 8 | * * ElementFactory: Creates new shapes and connections. 9 | * * ElementRegistry: A registry of all shapes and connections of the diagram. 10 | * * Modeling: The main module for modeling. 11 | * 12 | * We will use these modules to create shapes and connect them on two different ways. 13 | */ 14 | 15 | // (1) Get the modules 16 | const elementFactory = modeler.get('elementFactory'), 17 | elementRegistry = modeler.get('elementRegistry'), 18 | modeling = modeler.get('modeling'); 19 | 20 | // (2) Get the existing process and the start event 21 | const process = elementRegistry.get('Process_1'), 22 | startEvent = elementRegistry.get('StartEvent_1'); 23 | 24 | // (3) Create a task shape 25 | const task = elementFactory.createShape({ type: 'bpmn:Task' }); 26 | 27 | // (4) Add the new service task shape to the diagram 28 | modeling.createShape(task, { x: 400, y: 100 }, process); 29 | 30 | // (5) Connect the existing start event to new task using `connect` 31 | modeling.connect(startEvent, task); 32 | 33 | // (6) Create a end event shape 34 | const endEvent = elementFactory.createShape({ type: 'bpmn:EndEvent' }); 35 | 36 | // (7) Add the new end event shape to the diagram 37 | modeling.createShape(endEvent, { x: 600, y: 100 }, process); 38 | 39 | // (8) Create a new sequence flow connection that connects the task to the end event 40 | modeling.createConnection(task, endEvent, { type: 'bpmn:SequenceFlow' }, process); 41 | } 42 | 43 | export default { 44 | id: 'connectingShapes', 45 | name: 'Connecting Shapes', 46 | description: 'Various ways of connecting shapes.', 47 | fn 48 | }; -------------------------------------------------------------------------------- /modeling-api/src/snippets/editingElements.js: -------------------------------------------------------------------------------- 1 | import diagram from '../../resources/editingElements.bpmn'; 2 | 3 | function fn(modeler) { 4 | 5 | /** 6 | * Now, let's have a look at how you can edit existing elements. 7 | * 8 | * The modules used in this example are: 9 | * 10 | * * BpmnFactory: Creates new business objects. 11 | * * ElementRegistry: A registry of all shapes and connections of the diagram. 12 | * * Modeling: The main module for modeling. 13 | * 14 | * We will use these modules to update the properties of two existing shapes. 15 | */ 16 | 17 | // (1) Get the modules 18 | const bpmnFactory = modeler.get('bpmnFactory'), 19 | elementRegistry = modeler.get('elementRegistry'), 20 | modeling = modeler.get('modeling'); 21 | 22 | // (2) Get the shapes 23 | const startEvent = elementRegistry.get('StartEvent_1'), 24 | exclusiveGateway = elementRegistry.get('ExclusiveGateway_1'), 25 | sequenceFlow = elementRegistry.get('SequenceFlow_3'), 26 | task = elementRegistry.get('Task_1'); 27 | 28 | // (3) Change the start event's `name` property using `updateProperties` 29 | modeling.updateProperties(startEvent, { name: 'Foo' }); 30 | 31 | // (4) Change the `defaultFlow` property of a gateway 32 | modeling.updateProperties(exclusiveGateway, { 33 | default: sequenceFlow.businessObject 34 | }); 35 | 36 | // (5) Change a task to be multi-instance 37 | const multiInstanceLoopCharacteristics = bpmnFactory.create('bpmn:MultiInstanceLoopCharacteristics'); 38 | 39 | modeling.updateProperties(task, { 40 | loopCharacteristics: multiInstanceLoopCharacteristics 41 | }); 42 | } 43 | 44 | export default { 45 | id: 'editingElements', 46 | name: 'Editing Elements', 47 | description: 'How to edit existing elements.', 48 | diagram, 49 | fn 50 | }; -------------------------------------------------------------------------------- /modeling-api/src/snippets/index.js: -------------------------------------------------------------------------------- 1 | import introduction from './introduction.js'; 2 | import businessObjects from './businessObjects.js'; 3 | import creatingShapes from './creatingShapes.js'; 4 | import connectingShapes from './connectingShapes.js'; 5 | import collaborations from './collaborations.js'; 6 | import editingElements from './editingElements.js'; 7 | 8 | export default [ 9 | introduction, 10 | businessObjects, 11 | creatingShapes, 12 | connectingShapes, 13 | collaborations, 14 | editingElements 15 | ]; -------------------------------------------------------------------------------- /modeling-api/src/snippets/introduction.js: -------------------------------------------------------------------------------- 1 | function fn(modeler) { 2 | 3 | /** 4 | * After creating a new instance of bpmn-js you can access any module of bpmn-js using 5 | * modeler#get. 6 | * 7 | * The modules used in this example are: 8 | * 9 | * * ElementFactory: Creates new shapes and connections. 10 | * * ElementRegistry: A registry of all shapes and connections of the diagram. 11 | * * Modeling: The main module for modeling. 12 | * 13 | * We will use these modules to create a new shape, add it to the diagram, and 14 | * connect it to an existing shape. 15 | */ 16 | 17 | // (1) Get the modules 18 | const elementFactory = modeler.get('elementFactory'), 19 | elementRegistry = modeler.get('elementRegistry'), 20 | modeling = modeler.get('modeling'); 21 | 22 | // (2) Get the existing process and the start event 23 | const process = elementRegistry.get('Process_1'), 24 | startEvent = elementRegistry.get('StartEvent_1'); 25 | 26 | // (3) Create a new diagram shape 27 | const task = elementFactory.createShape({ type: 'bpmn:Task' }); 28 | 29 | // (4) Add the new task to the diagram 30 | modeling.createShape(task, { x: 400, y: 100 }, process); 31 | 32 | // You can now access the new task through the element registry 33 | console.log(elementRegistry.get(task.id)); // Shape { "type": "bpmn:Task", ... } 34 | 35 | // (5) Connect the existing start event to new task 36 | modeling.connect(startEvent, task); 37 | } 38 | 39 | export default { 40 | id: 'introduction', 41 | name: 'Introduction', 42 | description: 'An introduction to the modules of bpmn-js that can be used to create and connect shapes.', 43 | fn 44 | }; -------------------------------------------------------------------------------- /modeling-api/webpack.config.js: -------------------------------------------------------------------------------- 1 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 2 | 3 | module.exports = { 4 | entry: { 5 | bundle: [ './src/app.js' ] 6 | }, 7 | output: { 8 | path: __dirname + '/public', 9 | filename: 'app.js' 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.css$/, 15 | use: [ 16 | 'style-loader', 17 | 'css-loader', 18 | ] 19 | }, 20 | { 21 | test: /\.bpmn$/, 22 | use: 'raw-loader' 23 | } 24 | ] 25 | }, 26 | plugins: [ 27 | new CopyWebpackPlugin({ 28 | patterns: [ 29 | { from: 'src/index.html', to: '.' } 30 | ] 31 | }) 32 | ], 33 | mode: 'development', 34 | devtool: 'source-map' 35 | }; 36 | -------------------------------------------------------------------------------- /overlays/docs/qr-code.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/overlays/docs/qr-code.gif -------------------------------------------------------------------------------- /overlays/docs/qr-code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/overlays/docs/qr-code.png -------------------------------------------------------------------------------- /overlays/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bpmn-js-example-overlay-api", 3 | "version": "0.0.0", 4 | "description": "An example how to use the Overlay API", 5 | "scripts": { 6 | "all": "run-s build", 7 | "build": "webpack --mode production", 8 | "dev": "webpack-dev-server --static=public --open", 9 | "start": "run-s dev" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/bpmn-io/bpmn-js-examples" 14 | }, 15 | "keywords": [ 16 | "bpmnjs-example" 17 | ], 18 | "author": { 19 | "name": "Joerg Dotzki", 20 | "url": "https://github.com/ISO50" 21 | }, 22 | "contributors": [ 23 | { 24 | "name": "bpmn.io contributors", 25 | "url": "https://github.com/bpmn-io" 26 | } 27 | ], 28 | "devDependencies": { 29 | "css-loader": "^7.1.2", 30 | "style-loader": "^4.0.0", 31 | "webpack": "^5.97.1", 32 | "webpack-cli": "^6.0.1", 33 | "webpack-dev-server": "^5.2.0" 34 | }, 35 | "license": "MIT", 36 | "dependencies": { 37 | "bpmn-js": "^18.6.2", 38 | "min-dash": "^4.0.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /overlays/src/app.js: -------------------------------------------------------------------------------- 1 | // we use stringify to inline an example XML document. 2 | import qrDiagram from '../resources/qr-code.bpmn'; 3 | 4 | import BpmnViewer from 'bpmn-js/lib/NavigatedViewer'; 5 | 6 | 7 | var bpmnViewer = new BpmnViewer({ 8 | container: '#canvas', 9 | 10 | /* uncomment to configure defaults for all overlays 11 | overlays: { 12 | defaults: { 13 | show: { minZoom: 1 }, 14 | scale: true 15 | } 16 | } 17 | */ 18 | }); 19 | 20 | 21 | // import qr diagram 22 | 23 | bpmnViewer.importXML(qrDiagram).then(function() { 24 | 25 | var canvas = bpmnViewer.get('canvas'), 26 | overlays = bpmnViewer.get('overlays'); 27 | 28 | 29 | // zoom to fit full viewport 30 | canvas.zoom('fit-viewport'); 31 | 32 | // attach an overlay to a node 33 | overlays.add('SCAN_OK', 'note', { 34 | position: { 35 | bottom: 0, 36 | right: 0 37 | }, 38 | html: '
      Mixed up the labels?
      ' 39 | }); 40 | 41 | 42 | // configure scale=false to use non-scaling overlays 43 | overlays.add('START_PROCESS', 'note', { 44 | position: { 45 | bottom: 0, 46 | right: 0 47 | }, 48 | scale: false, 49 | html: '
      I don\'t scale
      ' 50 | }); 51 | 52 | // configure scale={ min: 1 } to use non-shrinking overlays 53 | overlays.add('SCAN_QR_CODE', 'note', { 54 | position: { 55 | bottom: 0, 56 | right: 0 57 | }, 58 | scale: { min: 1 }, 59 | html: '
      I don\'t shrink beyond 100%
      ' 60 | }); 61 | 62 | 63 | 64 | // configure show={ minZoom: 0.6 } to hide overlays at low zoom levels 65 | overlays.add('END_PROCESS', 'note', { 66 | position: { 67 | bottom: 0, 68 | right: 0 69 | }, 70 | show: { 71 | minZoom: 0.7 72 | }, 73 | html: '
      I hide at low zoom levels
      ' 74 | }); 75 | 76 | }).catch(function(err) { 77 | 78 | console.error('could not import BPMN 2.0 diagram', err); 79 | }); 80 | -------------------------------------------------------------------------------- /overlays/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 41 | 42 | Using the Overlay API 43 | 44 | 45 | 46 |

      Overlay API example

      47 | 48 |
      49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /overlays/webpack.config.js: -------------------------------------------------------------------------------- 1 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 2 | 3 | const path = require('path'); 4 | 5 | module.exports = { 6 | mode: 'development', 7 | entry: './src/app.js', 8 | output: { 9 | path: path.resolve(__dirname, 'public'), 10 | filename: 'app.js' 11 | }, 12 | module: { 13 | rules: [ 14 | { 15 | test: /\.css$/, 16 | use: [ 17 | 'style-loader', 18 | 'css-loader', 19 | ] 20 | }, 21 | { 22 | test: /\.bpmn$/, 23 | use: { 24 | loader: 'raw-loader' 25 | } 26 | } 27 | ] 28 | }, 29 | plugins: [ 30 | new CopyWebpackPlugin({ 31 | patterns: [ 32 | { from: 'src/index.html', to: '.' } 33 | ] 34 | }) 35 | ] 36 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bpmn-js-examples", 3 | "version": "0.0.0", 4 | "private": true, 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/bpmn-io/bpmn-js-examples" 8 | }, 9 | "keywords": [ 10 | "bpmn-js-example" 11 | ], 12 | "scripts": { 13 | "all": "run-s lint build", 14 | "build": "lerna run all --stream", 15 | "lint": "eslint ." 16 | }, 17 | "contributors": [ 18 | { 19 | "name": "bpmn.io contributors", 20 | "url": "https://github.com/bpmn-io" 21 | } 22 | ], 23 | "license": "MIT", 24 | "devDependencies": { 25 | "eslint": "^9.17.0", 26 | "eslint-plugin-bpmn-io": "^2.0.2", 27 | "eslint-plugin-mocha": "^10.5.0", 28 | "lerna": "^8.1.9", 29 | "npm-run-all2": "^8.0.0" 30 | }, 31 | "workspaces": [ 32 | "bpmn-properties", 33 | "bundling", 34 | "commenting", 35 | "custom-bundle", 36 | "custom-meta-model", 37 | "custom-modeling-rules", 38 | "deep-linking", 39 | "embedding", 40 | "i18n", 41 | "minimap", 42 | "modeler", 43 | "modeling-api", 44 | "overlays", 45 | "properties-panel", 46 | "properties-panel-async-extension", 47 | "properties-panel-extension", 48 | "properties-panel-list-extension", 49 | "theming", 50 | "transaction-boundaries", 51 | "types" 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /pre-packaged/README.md: -------------------------------------------------------------------------------- 1 | # bpmn-js pre-packaged example 2 | 3 | This example showcases how to use the pre-packaged version(s) of [bpmn-js](https://github.com/bpmn-io/bpmn-js). 4 | 5 | 6 | ## About 7 | 8 | We provide pre-packaged versions of our toolkit via [unpkg](https://unpkg.com/bpmn-js/dist/). 9 | 10 | This example shows how to embed these resources to integrate a BPMN viewer or editor 11 | into a website. 12 | 13 | 14 | ## Embed pre-packaged Assets 15 | 16 | Download or simply include the relevant dependencies into your website: 17 | 18 | #### Viewer 19 | 20 | ```html 21 | 22 | 23 | 24 | 25 | ``` 26 | 27 | Download the complete [viewer example](https://cdn.statically.io/gh/bpmn-io/bpmn-js-examples/main/starter/viewer.html). 28 | 29 | #### Modeler 30 | 31 | ```html 32 | 33 | 34 | 35 | 36 | 37 | 38 | ``` 39 | 40 | Download the complete [modeler example](https://cdn.statically.io/gh/bpmn-io/bpmn-js-examples/main/starter/modeler.html). 41 | 42 | 43 | ## Use the Library 44 | 45 | The library is bundled as an UMD bundle and binds itself to the global `BpmnJS` 46 | variable. 47 | 48 | ```javascript 49 | var bpmnJS = new BpmnJS({ 50 | container: '#canvas' 51 | }); 52 | 53 | try { 54 | 55 | await bpmnJS.importXML(someDiagram); 56 | 57 | console.log('success!'); 58 | viewer.get('canvas').zoom('fit-viewport'); 59 | } catch (err) { 60 | 61 | console.error('something went wrong:', err); 62 | } 63 | ``` 64 | 65 | ## License 66 | 67 | MIT 68 | -------------------------------------------------------------------------------- /properties-panel-async-extension/README.md: -------------------------------------------------------------------------------- 1 | > Extending the properties panel changed significantly with `bpmn-js-properties-panel>=1`. For the `0.x` version of the library, check out [the old version of this example](https://github.com/bpmn-io/bpmn-js-examples/tree/b20919ac2231abf3df45b9dc9a2561010009b4a2/properties-panel-extension). 2 | 3 | # Properties Panel Async Extension Example 4 | 5 | This example is based on [the properties panel extension example](../properties-panel-extension). 6 | Its goal is to present how the 1.x series of [bpmn-js-properties-panel](https://github.com/bpmn-io/bpmn-js-properties-panel) support asynchronous data loading. 7 | 8 | For an advanced async extension example, check out [this repository](https://github.com/bpmn-io/properties-panel-async-example). 9 | 10 | ![properties panel async extension capture](./docs/screencapture.gif "Screen capture of the properties panel async extension example") 11 | 12 | ## Prerequisites 13 | 14 | * You know how to extend the properties panel. Check out [the properties panel extension example](../properties-panel-extension) for guidance. 15 | * You have basic knowledge on [Preact hooks](https://preactjs.com/guide/v10/hooks/). 16 | * You know how to use [the Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch). 17 | 18 | ## About 19 | 20 | Most of the code of this example is a copy of [the properties panel extension example](../properties-panel-extension). 21 | Here, we will only refer to what is added on top of that. 22 | 23 | In this example, the spells are provided by a simple [express](https://expressjs.com/) server. Source code of the server is located in [server.js](./server.js). 24 | 25 | The properties panel extension loads data asynchronously with [the Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch). It is made available in the component via [Preact hooks](https://preactjs.com/guide/v10/hooks/). 26 | 27 | ```javascript 28 | const [ spells, setSpells ] = useState([]); 29 | 30 | useEffect(() => { 31 | function fetchSpells() { 32 | fetch('http://localhost:1234/spell') 33 | .then(res => res.json()) 34 | .then(spellbook => setSpells(spellbook)) 35 | .catch(error => console.error(error)); 36 | } 37 | 38 | fetchSpells(); 39 | }, [ setSpells ]); 40 | 41 | const getOptions = () => { 42 | return [ 43 | { label: '', value: undefined }, 44 | ...spells.map(spell => ({ 45 | label: spell, 46 | value: spell 47 | })) 48 | ]; 49 | } 50 | ``` 51 | 52 | Note that the hooks need to be imported from preact vendored in [@bpmn-io/properties-panel](https://github.com/bpmn-io/properties-panel): 53 | 54 | ```javascript 55 | import { useEffect, useState } from '@bpmn-io/properties-panel/preact/hooks'; 56 | ``` 57 | 58 | ## Running the Example 59 | 60 | Install all required dependencies: 61 | 62 | ``` 63 | npm install 64 | ``` 65 | 66 | Build and run the project 67 | 68 | ``` 69 | npm start 70 | ``` 71 | 72 | 73 | ## License 74 | 75 | MIT 76 | -------------------------------------------------------------------------------- /properties-panel-async-extension/docs/screencapture.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/properties-panel-async-extension/docs/screencapture.gif -------------------------------------------------------------------------------- /properties-panel-async-extension/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bpmn-js-example-properties-panel-async-extension", 3 | "version": "0.0.0", 4 | "description": "A properties panel async extension example", 5 | "scripts": { 6 | "all": "run-s build", 7 | "build": "webpack --mode production", 8 | "build:watch": "webpack-dev-server --static=public --open", 9 | "dev": "run-p build:watch serve", 10 | "start": "npm run dev", 11 | "serve": "node server.js" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/bpmn-io/bpmn-js-examples", 16 | "directory": "properties-panel-async-extension" 17 | }, 18 | "keywords": [ 19 | "bpmnjs-example", 20 | "bpmn-js-properties-panel" 21 | ], 22 | "author": { 23 | "name": "Maciej Barelkowski", 24 | "url": "https://github.com/barmac" 25 | }, 26 | "contributors": [ 27 | { 28 | "name": "bpmn.io contributors", 29 | "url": "https://github.com/bpmn-io" 30 | } 31 | ], 32 | "license": "MIT", 33 | "devDependencies": { 34 | "copy-webpack-plugin": "^13.0.0", 35 | "css-loader": "^7.1.2", 36 | "less": "^4.1.2", 37 | "less-loader": "^12.0.0", 38 | "npm-run-all2": "^8.0.0", 39 | "raw-loader": "^4.0.2", 40 | "style-loader": "^4.0.0", 41 | "webpack": "^5.97.1", 42 | "webpack-cli": "^6.0.1", 43 | "webpack-dev-server": "^5.2.0" 44 | }, 45 | "dependencies": { 46 | "@bpmn-io/properties-panel": "^3.23.0", 47 | "bpmn-js": "^18.6.2", 48 | "bpmn-js-properties-panel": "^5.23.0", 49 | "cors": "^2.8.5", 50 | "express": "^5.0.0", 51 | "htm": "^3.1.1", 52 | "jquery": "^3.5.1", 53 | "min-dash": "^4.1.1" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /properties-panel-async-extension/resources/newDiagram.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /properties-panel-async-extension/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const cors = require('cors'); 3 | 4 | const spells = [ 5 | 'Avada Kedavra', 6 | 'Crucio', 7 | 'Vulnera Sanentur', 8 | 'Vingardium Leviosa', 9 | 'Alohomora' 10 | ]; 11 | 12 | // express server which returns spells 13 | const app = express(); 14 | 15 | app.use(cors()); 16 | app.options('*', cors()); 17 | 18 | app.get('/spell', (req, res) => { 19 | res.json(spells); 20 | }); 21 | 22 | app.listen(1234, () => { 23 | console.log('Listening on port 1234'); 24 | }); 25 | -------------------------------------------------------------------------------- /properties-panel-async-extension/src/descriptors/magic.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Magic", 3 | "prefix": "magic", 4 | "uri": "http://magic", 5 | "xml": { 6 | "tagAlias": "lowerCase" 7 | }, 8 | "associations": [], 9 | "types": [ 10 | { 11 | "name": "BewitchedStartEvent", 12 | "extends": [ 13 | "bpmn:StartEvent" 14 | ], 15 | "properties": [ 16 | { 17 | "name": "spell", 18 | "isAttr": true, 19 | "type": "String" 20 | } 21 | ] 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /properties-panel-async-extension/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | bpmn-js-properties-panel extension demo 5 | 6 | 7 |
      8 | 9 |
      10 |
      11 | Drop BPMN diagram from your desktop or create a new diagram to get started. 12 |
      13 |
      14 | 15 |
      16 |
      17 |

      Ooops, we could not display the BPMN 2.0 diagram.

      18 | 19 |
      20 | cause of the problem 21 |
      
      22 |         
      23 |
      24 |
      25 | 26 |
      27 |
      28 |
      29 | 30 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /properties-panel-async-extension/src/provider/magic/MagicPropertiesProvider.js: -------------------------------------------------------------------------------- 1 | // Import your custom property entries. 2 | // The entry is a text input field with logic attached to create, 3 | // update and delete the "spell" property. 4 | import spellProps from './parts/SpellProps'; 5 | 6 | import { is } from 'bpmn-js/lib/util/ModelUtil'; 7 | 8 | const LOW_PRIORITY = 500; 9 | 10 | 11 | /** 12 | * A provider with a `#getGroups(element)` method 13 | * that exposes groups for a diagram element. 14 | * 15 | * @param {PropertiesPanel} propertiesPanel 16 | * @param {Function} translate 17 | */ 18 | export default function MagicPropertiesProvider(propertiesPanel, translate) { 19 | 20 | // API //////// 21 | 22 | /** 23 | * Return the groups provided for the given element. 24 | * 25 | * @param {DiagramElement} element 26 | * 27 | * @return {(Object[]) => (Object[])} groups middleware 28 | */ 29 | this.getGroups = function(element) { 30 | 31 | /** 32 | * We return a middleware that modifies 33 | * the existing groups. 34 | * 35 | * @param {Object[]} groups 36 | * 37 | * @return {Object[]} modified groups 38 | */ 39 | return function(groups) { 40 | 41 | // Add the "magic" group 42 | if (is(element, 'bpmn:StartEvent')) { 43 | groups.push(createMagicGroup(element, translate)); 44 | } 45 | 46 | return groups; 47 | }; 48 | }; 49 | 50 | 51 | // registration //////// 52 | 53 | // Register our custom magic properties provider. 54 | // Use a lower priority to ensure it is loaded after 55 | // the basic BPMN properties. 56 | propertiesPanel.registerProvider(LOW_PRIORITY, this); 57 | } 58 | 59 | MagicPropertiesProvider.$inject = [ 'propertiesPanel', 'translate' ]; 60 | 61 | // Create the custom magic group 62 | function createMagicGroup(element, translate) { 63 | 64 | // create a group called "Magic properties". 65 | const magicGroup = { 66 | id: 'magic', 67 | label: translate('Magic properties'), 68 | entries: spellProps(element) 69 | }; 70 | 71 | return magicGroup; 72 | } 73 | -------------------------------------------------------------------------------- /properties-panel-async-extension/src/provider/magic/index.js: -------------------------------------------------------------------------------- 1 | import MagicPropertiesProvider from './MagicPropertiesProvider'; 2 | 3 | export default { 4 | __init__: [ 'magicPropertiesProvider' ], 5 | magicPropertiesProvider: [ 'type', MagicPropertiesProvider ] 6 | }; -------------------------------------------------------------------------------- /properties-panel-async-extension/src/provider/magic/parts/SpellProps.js: -------------------------------------------------------------------------------- 1 | import { html } from 'htm/preact'; 2 | 3 | import { SelectEntry, isSelectEntryEdited } from '@bpmn-io/properties-panel'; 4 | import { useService } from 'bpmn-js-properties-panel'; 5 | 6 | // import hooks from the vendored preact package 7 | import { useEffect, useState } from '@bpmn-io/properties-panel/preact/hooks'; 8 | 9 | export default function(element) { 10 | 11 | return [ 12 | { 13 | id: 'spell', 14 | element, 15 | component: Spell, 16 | isEdited: isSelectEntryEdited 17 | } 18 | ]; 19 | } 20 | 21 | function Spell(props) { 22 | const { element, id } = props; 23 | 24 | const modeling = useService('modeling'); 25 | const translate = useService('translate'); 26 | const debounce = useService('debounceInput'); 27 | 28 | 29 | const getValue = () => { 30 | return element.businessObject.spell || ''; 31 | }; 32 | 33 | const setValue = value => { 34 | return modeling.updateProperties(element, { 35 | spell: value 36 | }); 37 | }; 38 | 39 | const [ spells, setSpells ] = useState([]); 40 | 41 | useEffect(() => { 42 | function fetchSpells() { 43 | fetch('http://localhost:1234/spell') 44 | .then(res => res.json()) 45 | .then(spellbook => setSpells(spellbook)) 46 | .catch(error => console.error(error)); 47 | } 48 | 49 | fetchSpells(); 50 | }, [ setSpells ]); 51 | 52 | const getOptions = () => { 53 | return [ 54 | { label: '', value: undefined }, 55 | ...spells.map(spell => ({ 56 | label: spell, 57 | value: spell 58 | })) 59 | ]; 60 | }; 61 | 62 | return html`<${SelectEntry} 63 | id=${ id } 64 | element=${ element } 65 | description=${ translate('Apply a black magic spell') } 66 | label=${ translate('Spell') } 67 | getValue=${ getValue } 68 | setValue=${ setValue } 69 | getOptions=${ getOptions } 70 | debounce=${ debounce } 71 | />`; 72 | } 73 | -------------------------------------------------------------------------------- /properties-panel-async-extension/src/style.less: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body, 6 | html { 7 | 8 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 9 | 10 | font-size: 12px; 11 | 12 | height: 100%; 13 | max-height: 100%; 14 | padding: 0; 15 | margin: 0; 16 | } 17 | 18 | a:link { 19 | text-decoration: none; 20 | } 21 | 22 | .content { 23 | position: relative; 24 | width: 100%; 25 | height: 100%; 26 | 27 | > .message { 28 | width: 100%; 29 | height: 100%; 30 | text-align: center; 31 | display: table; 32 | 33 | font-size: 16px; 34 | color: #111; 35 | 36 | .note { 37 | vertical-align: middle; 38 | text-align: center; 39 | display: table-cell; 40 | } 41 | 42 | .error { 43 | .details { 44 | max-width: 500px; 45 | font-size: 12px; 46 | margin: 20px auto; 47 | text-align: left; 48 | } 49 | 50 | pre { 51 | border: solid 1px #CCC; 52 | background: #EEE; 53 | padding: 10px; 54 | } 55 | } 56 | } 57 | &:not(.with-error) .error, 58 | &.with-error .intro, 59 | &.with-diagram .intro { 60 | display: none; 61 | } 62 | 63 | .canvas { 64 | position: absolute; 65 | top: 0; 66 | left: 0; 67 | right: 0; 68 | bottom: 0; 69 | } 70 | 71 | .canvas, 72 | &.with-error .canvas { 73 | visibility: hidden; 74 | } 75 | 76 | &.with-diagram .canvas { 77 | visibility: visible; 78 | } 79 | } 80 | 81 | 82 | .buttons { 83 | position: fixed; 84 | bottom: 20px; 85 | left: 20px; 86 | 87 | padding: 0; 88 | margin: 0; 89 | list-style: none; 90 | 91 | > li { 92 | display: inline-block; 93 | margin-right: 10px; 94 | 95 | > a { 96 | background: #DDD; 97 | border: solid 1px #666; 98 | display: inline-block; 99 | padding: 5px; 100 | } 101 | } 102 | 103 | a { 104 | opacity: 0.3; 105 | } 106 | 107 | a.active { 108 | opacity: 1.0; 109 | } 110 | } 111 | 112 | #js-properties-panel { 113 | position: absolute; 114 | top: 0; 115 | bottom: 0; 116 | right: 0; 117 | width: 260px; 118 | z-index: 10; 119 | border-left: 1px solid #ccc; 120 | overflow: auto; 121 | &:empty { 122 | display: none; 123 | } 124 | > .djs-properties-panel { 125 | padding-bottom: 70px; 126 | min-height:100%; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /properties-panel-async-extension/webpack.config.js: -------------------------------------------------------------------------------- 1 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 2 | 3 | const path = require('path'); 4 | 5 | module.exports = { 6 | mode: 'development', 7 | entry: './src/app.js', 8 | output: { 9 | path: path.resolve(__dirname, 'public'), 10 | filename: 'app.js' 11 | }, 12 | devtool: 'source-map', 13 | module: { 14 | rules: [ 15 | { 16 | test: /\.less$/, 17 | use: [ 18 | 'style-loader', 19 | 'css-loader', 20 | 'less-loader', 21 | ], 22 | }, 23 | { 24 | test: /\.css$/, 25 | use: [ 26 | 'style-loader', 27 | 'css-loader', 28 | ] 29 | }, 30 | { 31 | test: /\.bpmn$/, 32 | use: { 33 | loader: 'raw-loader' 34 | } 35 | } 36 | ] 37 | }, 38 | plugins: [ 39 | new CopyWebpackPlugin({ 40 | patterns: [ 41 | { from: 'src/index.html', to: '.' } 42 | ] 43 | }) 44 | ] 45 | }; -------------------------------------------------------------------------------- /properties-panel-extension/docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/properties-panel-extension/docs/screenshot.png -------------------------------------------------------------------------------- /properties-panel-extension/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bpmn-js-example-properties-panel-extension", 3 | "version": "0.0.0", 4 | "description": "A properties panel extension example", 5 | "scripts": { 6 | "all": "run-s build", 7 | "build": "webpack --mode production", 8 | "dev": "webpack-dev-server --static=public --open", 9 | "start": "run-s dev" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/bpmn-io/bpmn-js-examples", 14 | "directory": "properties-panel-extension" 15 | }, 16 | "keywords": [ 17 | "bpmnjs-example", 18 | "bpmn-js-properties-panel" 19 | ], 20 | "author": { 21 | "name": "Patrick Dehn", 22 | "url": "https://github.com/pedesen" 23 | }, 24 | "contributors": [ 25 | { 26 | "name": "bpmn.io contributors", 27 | "url": "https://github.com/bpmn-io" 28 | } 29 | ], 30 | "license": "MIT", 31 | "devDependencies": { 32 | "copy-webpack-plugin": "^13.0.0", 33 | "css-loader": "^7.1.2", 34 | "less": "^4.1.2", 35 | "less-loader": "^12.0.0", 36 | "npm-run-all2": "^8.0.0", 37 | "raw-loader": "^4.0.2", 38 | "style-loader": "^4.0.0", 39 | "webpack": "^5.97.1", 40 | "webpack-cli": "^6.0.1", 41 | "webpack-dev-server": "^5.2.0" 42 | }, 43 | "dependencies": { 44 | "@bpmn-io/properties-panel": "^3.23.0", 45 | "bpmn-js": "^18.6.2", 46 | "bpmn-js-properties-panel": "^5.23.0", 47 | "htm": "^3.1.1", 48 | "jquery": "^3.5.1", 49 | "min-dash": "^4.1.1" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /properties-panel-extension/resources/newDiagram.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /properties-panel-extension/src/descriptors/magic.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Magic", 3 | "prefix": "magic", 4 | "uri": "http://magic", 5 | "xml": { 6 | "tagAlias": "lowerCase" 7 | }, 8 | "associations": [], 9 | "types": [ 10 | { 11 | "name": "BewitchedStartEvent", 12 | "extends": [ 13 | "bpmn:StartEvent" 14 | ], 15 | "properties": [ 16 | { 17 | "name": "spell", 18 | "isAttr": true, 19 | "type": "String" 20 | } 21 | ] 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /properties-panel-extension/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | bpmn-js-properties-panel extension demo 5 | 6 | 7 |
      8 | 9 |
      10 |
      11 | Drop BPMN diagram from your desktop or create a new diagram to get started. 12 |
      13 |
      14 | 15 |
      16 |
      17 |

      Ooops, we could not display the BPMN 2.0 diagram.

      18 | 19 |
      20 | cause of the problem 21 |
      
      22 |         
      23 |
      24 |
      25 | 26 |
      27 |
      28 |
      29 | 30 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /properties-panel-extension/src/provider/magic/MagicPropertiesProvider.js: -------------------------------------------------------------------------------- 1 | // Import your custom property entries. 2 | // The entry is a text input field with logic attached to create, 3 | // update and delete the "spell" property. 4 | import spellProps from './parts/SpellProps'; 5 | 6 | import { is } from 'bpmn-js/lib/util/ModelUtil'; 7 | 8 | const LOW_PRIORITY = 500; 9 | 10 | 11 | /** 12 | * A provider with a `#getGroups(element)` method 13 | * that exposes groups for a diagram element. 14 | * 15 | * @param {PropertiesPanel} propertiesPanel 16 | * @param {Function} translate 17 | */ 18 | export default function MagicPropertiesProvider(propertiesPanel, translate) { 19 | 20 | // API //////// 21 | 22 | /** 23 | * Return the groups provided for the given element. 24 | * 25 | * @param {DiagramElement} element 26 | * 27 | * @return {(Object[]) => (Object[])} groups middleware 28 | */ 29 | this.getGroups = function(element) { 30 | 31 | /** 32 | * We return a middleware that modifies 33 | * the existing groups. 34 | * 35 | * @param {Object[]} groups 36 | * 37 | * @return {Object[]} modified groups 38 | */ 39 | return function(groups) { 40 | 41 | // Add the "magic" group 42 | if (is(element, 'bpmn:StartEvent')) { 43 | groups.push(createMagicGroup(element, translate)); 44 | } 45 | 46 | return groups; 47 | }; 48 | }; 49 | 50 | 51 | // registration //////// 52 | 53 | // Register our custom magic properties provider. 54 | // Use a lower priority to ensure it is loaded after 55 | // the basic BPMN properties. 56 | propertiesPanel.registerProvider(LOW_PRIORITY, this); 57 | } 58 | 59 | MagicPropertiesProvider.$inject = [ 'propertiesPanel', 'translate' ]; 60 | 61 | // Create the custom magic group 62 | function createMagicGroup(element, translate) { 63 | 64 | // create a group called "Magic properties". 65 | const magicGroup = { 66 | id: 'magic', 67 | label: translate('Magic properties'), 68 | entries: spellProps(element), 69 | tooltip: translate('Make sure you know what you are doing!') 70 | }; 71 | 72 | return magicGroup; 73 | } 74 | -------------------------------------------------------------------------------- /properties-panel-extension/src/provider/magic/index.js: -------------------------------------------------------------------------------- 1 | import MagicPropertiesProvider from './MagicPropertiesProvider'; 2 | 3 | export default { 4 | __init__: [ 'magicPropertiesProvider' ], 5 | magicPropertiesProvider: [ 'type', MagicPropertiesProvider ] 6 | }; -------------------------------------------------------------------------------- /properties-panel-extension/src/provider/magic/parts/SpellProps.js: -------------------------------------------------------------------------------- 1 | import { html } from 'htm/preact'; 2 | 3 | import { TextFieldEntry, isTextFieldEntryEdited } from '@bpmn-io/properties-panel'; 4 | import { useService } from 'bpmn-js-properties-panel'; 5 | 6 | export default function(element) { 7 | 8 | return [ 9 | { 10 | id: 'spell', 11 | element, 12 | component: Spell, 13 | isEdited: isTextFieldEntryEdited 14 | } 15 | ]; 16 | } 17 | 18 | function Spell(props) { 19 | const { element, id } = props; 20 | 21 | const modeling = useService('modeling'); 22 | const translate = useService('translate'); 23 | const debounce = useService('debounceInput'); 24 | 25 | const getValue = () => { 26 | return element.businessObject.spell || ''; 27 | }; 28 | 29 | const setValue = value => { 30 | return modeling.updateProperties(element, { 31 | spell: value 32 | }); 33 | }; 34 | 35 | return html`<${TextFieldEntry} 36 | id=${ id } 37 | element=${ element } 38 | description=${ translate('Apply a black magic spell') } 39 | label=${ translate('Spell') } 40 | getValue=${ getValue } 41 | setValue=${ setValue } 42 | debounce=${ debounce } 43 | tooltip=${ translate('Check available spells in the spellbook.') } 44 | />`; 45 | } 46 | -------------------------------------------------------------------------------- /properties-panel-extension/src/style.less: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body, 6 | html { 7 | 8 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 9 | 10 | font-size: 12px; 11 | 12 | height: 100%; 13 | max-height: 100%; 14 | padding: 0; 15 | margin: 0; 16 | } 17 | 18 | a:link { 19 | text-decoration: none; 20 | } 21 | 22 | .content { 23 | position: relative; 24 | width: 100%; 25 | height: 100%; 26 | 27 | > .message { 28 | width: 100%; 29 | height: 100%; 30 | text-align: center; 31 | display: table; 32 | 33 | font-size: 16px; 34 | color: #111; 35 | 36 | .note { 37 | vertical-align: middle; 38 | text-align: center; 39 | display: table-cell; 40 | } 41 | 42 | .error { 43 | .details { 44 | max-width: 500px; 45 | font-size: 12px; 46 | margin: 20px auto; 47 | text-align: left; 48 | } 49 | 50 | pre { 51 | border: solid 1px #CCC; 52 | background: #EEE; 53 | padding: 10px; 54 | } 55 | } 56 | } 57 | &:not(.with-error) .error, 58 | &.with-error .intro, 59 | &.with-diagram .intro { 60 | display: none; 61 | } 62 | 63 | .canvas { 64 | position: absolute; 65 | top: 0; 66 | left: 0; 67 | right: 0; 68 | bottom: 0; 69 | } 70 | 71 | .canvas, 72 | &.with-error .canvas { 73 | visibility: hidden; 74 | } 75 | 76 | &.with-diagram .canvas { 77 | visibility: visible; 78 | } 79 | } 80 | 81 | 82 | .buttons { 83 | position: fixed; 84 | bottom: 20px; 85 | left: 20px; 86 | 87 | padding: 0; 88 | margin: 0; 89 | list-style: none; 90 | 91 | > li { 92 | display: inline-block; 93 | margin-right: 10px; 94 | 95 | > a { 96 | background: #DDD; 97 | border: solid 1px #666; 98 | display: inline-block; 99 | padding: 5px; 100 | } 101 | } 102 | 103 | a { 104 | opacity: 0.3; 105 | } 106 | 107 | a.active { 108 | opacity: 1.0; 109 | } 110 | } 111 | 112 | #js-properties-panel { 113 | position: absolute; 114 | top: 0; 115 | bottom: 0; 116 | right: 0; 117 | width: 260px; 118 | z-index: 10; 119 | border-left: 1px solid #ccc; 120 | overflow: auto; 121 | &:empty { 122 | display: none; 123 | } 124 | > .djs-properties-panel { 125 | padding-bottom: 70px; 126 | min-height:100%; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /properties-panel-extension/webpack.config.js: -------------------------------------------------------------------------------- 1 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 2 | 3 | const path = require('path'); 4 | 5 | module.exports = { 6 | mode: 'development', 7 | entry: './src/app.js', 8 | output: { 9 | path: path.resolve(__dirname, 'public'), 10 | filename: 'app.js' 11 | }, 12 | devtool: 'source-map', 13 | module: { 14 | rules: [ 15 | { 16 | test: /\.less$/, 17 | use: [ 18 | 'style-loader', 19 | 'css-loader', 20 | 'less-loader', 21 | ], 22 | }, 23 | { 24 | test: /\.css$/, 25 | use: [ 26 | 'style-loader', 27 | 'css-loader', 28 | ] 29 | }, 30 | { 31 | test: /\.bpmn$/, 32 | use: { 33 | loader: 'raw-loader' 34 | } 35 | } 36 | ] 37 | }, 38 | plugins: [ 39 | new CopyWebpackPlugin({ 40 | patterns: [ 41 | { from: 'src/index.html', to: '.' } 42 | ] 43 | }) 44 | ] 45 | }; -------------------------------------------------------------------------------- /properties-panel-list-extension/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /public 3 | /tmp -------------------------------------------------------------------------------- /properties-panel-list-extension/docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/properties-panel-list-extension/docs/screenshot.png -------------------------------------------------------------------------------- /properties-panel-list-extension/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bpmn-js-example-properties-panel-list-extension", 3 | "version": "0.0.0", 4 | "description": "A properties panel list extension example", 5 | "scripts": { 6 | "all": "run-s build", 7 | "build": "webpack --mode production", 8 | "dev": "webpack-dev-server --static=public --open", 9 | "start": "run-s dev" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/bpmn-io/bpmn-js-examples", 14 | "directory": "properties-panel-list-extension" 15 | }, 16 | "keywords": [ 17 | "bpmnjs-example", 18 | "bpmn-js-properties-panel" 19 | ], 20 | "author": { 21 | "name": "Niklas Kiefer", 22 | "url": "https://github.com/pinussilvestrus" 23 | }, 24 | "contributors": [ 25 | { 26 | "name": "bpmn.io contributors", 27 | "url": "https://github.com/bpmn-io" 28 | } 29 | ], 30 | "license": "MIT", 31 | "devDependencies": { 32 | "copy-webpack-plugin": "^13.0.0", 33 | "css-loader": "^7.1.2", 34 | "less": "^4.1.2", 35 | "less-loader": "^12.0.0", 36 | "npm-run-all2": "^8.0.0", 37 | "raw-loader": "^4.0.2", 38 | "style-loader": "^4.0.0", 39 | "webpack": "^5.97.1", 40 | "webpack-cli": "^6.0.1", 41 | "webpack-dev-server": "^5.2.0" 42 | }, 43 | "dependencies": { 44 | "@bpmn-io/properties-panel": "^3.23.0", 45 | "bpmn-js": "^18.6.2", 46 | "bpmn-js-properties-panel": "^5.23.0", 47 | "camunda-bpmn-js-behaviors": "^1.6.1", 48 | "htm": "^3.1.1", 49 | "ids": "^1.0.0", 50 | "jquery": "^3.5.1", 51 | "min-dash": "^4.1.1", 52 | "zeebe-bpmn-moddle": "^1.6.0" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /properties-panel-list-extension/resources/newDiagram.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /properties-panel-list-extension/src/descriptors/magic.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Magic", 3 | "prefix": "magic", 4 | "uri": "http://magic", 5 | "xml": { 6 | "tagAlias": "lowerCase" 7 | }, 8 | "associations": [], 9 | "types": [ 10 | { 11 | "name": "Parameters", 12 | "superClass": [ "Element" ], 13 | "properties": [ 14 | { 15 | "name": "values", 16 | "isMany": true, 17 | "type": "Parameter" 18 | } 19 | ] 20 | }, 21 | { 22 | "name": "Parameter", 23 | "properties": [ 24 | { 25 | "name": "name", 26 | "isAttr": true, 27 | "type": "String" 28 | }, 29 | { 30 | "name": "value", 31 | "isAttr": true, 32 | "type": "String" 33 | }, 34 | { 35 | "name": "extensions", 36 | "type": "Extensions" 37 | } 38 | ] 39 | }, 40 | { 41 | "name": "Extensions", 42 | "superClass": [ "Element" ], 43 | "properties": [ 44 | { 45 | "name": "extensions", 46 | "isMany": true, 47 | "type": "Extension" 48 | } 49 | ] 50 | }, 51 | { 52 | "name": "Extension", 53 | "properties": [ 54 | { 55 | "name": "key", 56 | "isAttr": true, 57 | "type": "String" 58 | } 59 | ] 60 | } 61 | ] 62 | } -------------------------------------------------------------------------------- /properties-panel-list-extension/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | bpmn-js-properties-panel extension demo 5 | 6 | 7 |
      8 | 9 |
      10 |
      11 | Drop BPMN diagram from your desktop or create a new diagram to get started. 12 |
      13 |
      14 | 15 |
      16 |
      17 |

      Ooops, we could not display the BPMN 2.0 diagram.

      18 | 19 |
      20 | cause of the problem 21 |
      
      22 |         
      23 |
      24 |
      25 | 26 |
      27 |
      28 |
      29 | 30 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /properties-panel-list-extension/src/provider/magic/MagicPropertiesProvider.js: -------------------------------------------------------------------------------- 1 | // Import your custom list group entries. 2 | import parametersProps from './parts/ParametersProps'; 3 | 4 | // Import the properties panel list group component. 5 | import { ListGroup } from '@bpmn-io/properties-panel'; 6 | 7 | import { is } from 'bpmn-js/lib/util/ModelUtil'; 8 | 9 | const LOW_PRIORITY = 500; 10 | 11 | 12 | /** 13 | * A provider with a `#getGroups(element)` method 14 | * that exposes groups for a diagram element. 15 | * 16 | * @param {PropertiesPanel} propertiesPanel 17 | * @param {Function} translate 18 | */ 19 | export default function MagicPropertiesProvider(propertiesPanel, injector, translate) { 20 | 21 | // API //////// 22 | 23 | /** 24 | * Return the groups provided for the given element. 25 | * 26 | * @param {DiagramElement} element 27 | * 28 | * @return {(Object[]) => (Object[])} groups middleware 29 | */ 30 | this.getGroups = function(element) { 31 | 32 | /** 33 | * We return a middleware that modifies 34 | * the existing groups. 35 | * 36 | * @param {Object[]} groups 37 | * 38 | * @return {Object[]} modified groups 39 | */ 40 | return function(groups) { 41 | 42 | if (is(element, 'bpmn:StartEvent')) { 43 | groups.push(createParametersGroup(element, injector, translate)); 44 | } 45 | 46 | return groups; 47 | }; 48 | }; 49 | 50 | 51 | // registration //////// 52 | 53 | // Register our custom magic properties provider. 54 | // Use a lower priority to ensure it is loaded after 55 | // the basic BPMN properties. 56 | propertiesPanel.registerProvider(LOW_PRIORITY, this); 57 | } 58 | 59 | MagicPropertiesProvider.$inject = [ 'propertiesPanel', 'injector', 'translate' ]; 60 | 61 | // Create the custom parameters list group. 62 | function createParametersGroup(element, injector, translate) { 63 | 64 | // Create a group called "parameters". 65 | const parametersGroup = { 66 | id: 'parameters', 67 | label: translate('Magic parameters'), 68 | component: ListGroup, 69 | ...parametersProps({ element, injector }) 70 | }; 71 | 72 | return parametersGroup; 73 | } 74 | -------------------------------------------------------------------------------- /properties-panel-list-extension/src/provider/magic/index.js: -------------------------------------------------------------------------------- 1 | import MagicPropertiesProvider from './MagicPropertiesProvider'; 2 | 3 | export default { 4 | __init__: [ 'magicPropertiesProvider' ], 5 | magicPropertiesProvider: [ 'type', MagicPropertiesProvider ] 6 | }; -------------------------------------------------------------------------------- /properties-panel-list-extension/src/provider/magic/parts/ExtensionList.js: -------------------------------------------------------------------------------- 1 | import { html } from 'htm/preact'; 2 | 3 | import { without } from 'min-dash'; 4 | 5 | import { getBusinessObject } from 'bpmn-js/lib/util/ModelUtil'; 6 | 7 | import { 8 | CollapsibleEntry, 9 | ListEntry 10 | } from '@bpmn-io/properties-panel'; 11 | 12 | import { useService } from 'bpmn-js-properties-panel'; 13 | 14 | import ExtensionProps from './ExtensionProps'; 15 | 16 | import { 17 | createElement 18 | } from '../util'; 19 | 20 | 21 | export default function ExtensionList(props) { 22 | const { 23 | element, 24 | idPrefix, 25 | parameter 26 | } = props; 27 | 28 | const id = `${ idPrefix }-extensions`; 29 | 30 | const bpmnFactory = useService('bpmnFactory'); 31 | const commandStack = useService('commandStack'); 32 | const translate = useService('translate'); 33 | 34 | const businessObject = getBusinessObject(element); 35 | 36 | let extensions = parameter.get('extensions'); 37 | 38 | const extensionsList = (extensions && extensions.get('extensions')) || []; 39 | 40 | function addExtension() { 41 | const commands = []; 42 | 43 | // (1) ensure extensions 44 | if (!extensions) { 45 | extensions = createElement( 46 | 'magic:Extensions', 47 | { }, 48 | businessObject, 49 | bpmnFactory 50 | ); 51 | 52 | commands.push({ 53 | cmd: 'element.updateModdleProperties', 54 | context: { 55 | element, 56 | moddleElement: parameter, 57 | properties: { extensions } 58 | } 59 | }); 60 | } 61 | 62 | // (2) add extension 63 | const extension = createElement( 64 | 'magic:Extension', 65 | { key: undefined }, 66 | extensions, 67 | bpmnFactory 68 | ); 69 | 70 | commands.push({ 71 | cmd: 'element.updateModdleProperties', 72 | context: { 73 | element, 74 | moddleElement: extensions, 75 | properties: { 76 | extensions: [ ...extensions.get('extensions'), extension ] 77 | } 78 | } 79 | }); 80 | 81 | // (3) commit updates 82 | commandStack.execute('properties-panel.multi-command-executor', commands); 83 | } 84 | 85 | function removeExtension(extension) { 86 | commandStack.execute('element.updateModdleProperties', { 87 | element, 88 | moddleElement: extensions, 89 | properties: { 90 | extensions: without(extensions.get('extensions'), extension) 91 | } 92 | }); 93 | } 94 | 95 | return html`<${ListEntry} 96 | element=${ element } 97 | autoFocusEntry=${ `[data-entry-id="${id}-extension-${extensionsList.length - 1}"] input` } 98 | id=${ id } 99 | label=${ translate('Extensions') } 100 | items=${ extensionsList } 101 | component=${ Extension } 102 | onAdd=${ addExtension } 103 | onRemove=${ removeExtension } />`; 104 | } 105 | 106 | function Extension(props) { 107 | const { 108 | element, 109 | id: idPrefix, 110 | index, 111 | item: extension, 112 | open 113 | } = props; 114 | 115 | const translate = useService('translate'); 116 | 117 | const id = `${ idPrefix }-extension-${ index }`; 118 | 119 | return html` 120 | <${CollapsibleEntry} 121 | id=${ id } 122 | element=${ element } 123 | entries=${ ExtensionProps({ 124 | extension, 125 | element, 126 | idPrefix: id 127 | }) } 128 | label=${ extension.get('key') || translate('') } 129 | open=${ open } 130 | />`; 131 | } -------------------------------------------------------------------------------- /properties-panel-list-extension/src/provider/magic/parts/ExtensionProps.js: -------------------------------------------------------------------------------- 1 | import { TextFieldEntry } from '@bpmn-io/properties-panel'; 2 | 3 | import { useService } from 'bpmn-js-properties-panel'; 4 | 5 | 6 | export default function ExtensionProps(props) { 7 | 8 | const { 9 | extension, 10 | element, 11 | idPrefix 12 | } = props; 13 | 14 | const entries = [ 15 | { 16 | id: idPrefix + '-key', 17 | component: Key, 18 | extension, 19 | idPrefix, 20 | element 21 | } 22 | ]; 23 | 24 | return entries; 25 | } 26 | 27 | function Key(props) { 28 | const { 29 | idPrefix, 30 | element, 31 | extension 32 | } = props; 33 | 34 | const commandStack = useService('commandStack'), 35 | translate = useService('translate'), 36 | debounce = useService('debounceInput'); 37 | 38 | const setValue = (value) => { 39 | commandStack.execute('element.updateModdleProperties', { 40 | element, 41 | moddleElement: extension, 42 | properties: { 43 | key: value 44 | } 45 | }); 46 | }; 47 | 48 | const getValue = () => { 49 | return extension.key; 50 | }; 51 | 52 | return TextFieldEntry({ 53 | element: extension, 54 | id: idPrefix + '-key', 55 | label: translate('Key'), 56 | getValue, 57 | setValue, 58 | debounce 59 | }); 60 | } 61 | -------------------------------------------------------------------------------- /properties-panel-list-extension/src/provider/magic/parts/ParameterProps.js: -------------------------------------------------------------------------------- 1 | import { TextFieldEntry } from '@bpmn-io/properties-panel'; 2 | 3 | import { useService } from 'bpmn-js-properties-panel'; 4 | 5 | import ExtensionList from './ExtensionList'; 6 | 7 | 8 | export default function ParameterProps(props) { 9 | 10 | const { 11 | idPrefix, 12 | parameter 13 | } = props; 14 | 15 | const entries = [ 16 | { 17 | id: idPrefix + '-name', 18 | component: Name, 19 | idPrefix, 20 | parameter 21 | }, 22 | { 23 | id: idPrefix + '-value', 24 | component: Value, 25 | idPrefix, 26 | parameter 27 | }, 28 | { 29 | id: idPrefix + '-extensions', 30 | component: ExtensionList, 31 | idPrefix, 32 | parameter 33 | } 34 | ]; 35 | 36 | return entries; 37 | } 38 | 39 | function Name(props) { 40 | const { 41 | idPrefix, 42 | element, 43 | parameter 44 | } = props; 45 | 46 | const commandStack = useService('commandStack'); 47 | const translate = useService('translate'); 48 | const debounce = useService('debounceInput'); 49 | 50 | const setValue = (value) => { 51 | commandStack.execute('element.updateModdleProperties', { 52 | element, 53 | moddleElement: parameter, 54 | properties: { 55 | name: value 56 | } 57 | }); 58 | }; 59 | 60 | const getValue = (parameter) => { 61 | return parameter.name; 62 | }; 63 | 64 | return TextFieldEntry({ 65 | element: parameter, 66 | id: idPrefix + '-name', 67 | label: translate('Name'), 68 | getValue, 69 | setValue, 70 | debounce 71 | }); 72 | } 73 | 74 | function Value(props) { 75 | const { 76 | idPrefix, 77 | element, 78 | parameter 79 | } = props; 80 | 81 | const commandStack = useService('commandStack'); 82 | const translate = useService('translate'); 83 | const debounce = useService('debounceInput'); 84 | 85 | const setValue = (value) => { 86 | commandStack.execute('element.updateModdleProperties', { 87 | element, 88 | moddleElement: parameter, 89 | properties: { 90 | value: value 91 | } 92 | }); 93 | }; 94 | 95 | const getValue = (parameter) => { 96 | return parameter.value; 97 | }; 98 | 99 | return TextFieldEntry({ 100 | element: parameter, 101 | id: idPrefix + '-value', 102 | label: translate('Value'), 103 | getValue, 104 | setValue, 105 | debounce 106 | }); 107 | } -------------------------------------------------------------------------------- /properties-panel-list-extension/src/provider/magic/util.js: -------------------------------------------------------------------------------- 1 | import Ids from 'ids'; 2 | 3 | import { getBusinessObject } from 'bpmn-js/lib/util/ModelUtil'; 4 | 5 | export function getParametersExtension(element) { 6 | const businessObject = getBusinessObject(element); 7 | return getExtension(businessObject, 'magic:Parameters'); 8 | } 9 | 10 | export function getParameters(element) { 11 | const parameters = getParametersExtension(element); 12 | return parameters && parameters.get('values'); 13 | } 14 | 15 | export function getExtension(element, type) { 16 | if (!element.extensionElements) { 17 | return null; 18 | } 19 | 20 | return element.extensionElements.values.filter(function(e) { 21 | return e.$instanceOf(type); 22 | })[0]; 23 | } 24 | 25 | export function createElement(elementType, properties, parent, factory) { 26 | const element = factory.create(elementType, properties); 27 | 28 | if (parent) { 29 | element.$parent = parent; 30 | } 31 | 32 | return element; 33 | } 34 | 35 | export function createParameters(properties, parent, bpmnFactory) { 36 | return createElement('magic:Parameters', properties, parent, bpmnFactory); 37 | } 38 | 39 | 40 | export function nextId(prefix) { 41 | const ids = new Ids([ 32,32,1 ]); 42 | 43 | return ids.nextPrefixed(prefix); 44 | } -------------------------------------------------------------------------------- /properties-panel-list-extension/src/style.less: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body, 6 | html { 7 | 8 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 9 | 10 | font-size: 12px; 11 | 12 | height: 100%; 13 | max-height: 100%; 14 | padding: 0; 15 | margin: 0; 16 | } 17 | 18 | a:link { 19 | text-decoration: none; 20 | } 21 | 22 | .content { 23 | position: relative; 24 | width: 100%; 25 | height: 100%; 26 | 27 | > .message { 28 | width: 100%; 29 | height: 100%; 30 | text-align: center; 31 | display: table; 32 | 33 | font-size: 16px; 34 | color: #111; 35 | 36 | .note { 37 | vertical-align: middle; 38 | text-align: center; 39 | display: table-cell; 40 | } 41 | 42 | .error { 43 | .details { 44 | max-width: 500px; 45 | font-size: 12px; 46 | margin: 20px auto; 47 | text-align: left; 48 | } 49 | 50 | pre { 51 | border: solid 1px #CCC; 52 | background: #EEE; 53 | padding: 10px; 54 | } 55 | } 56 | } 57 | &:not(.with-error) .error, 58 | &.with-error .intro, 59 | &.with-diagram .intro { 60 | display: none; 61 | } 62 | 63 | .canvas { 64 | position: absolute; 65 | top: 0; 66 | left: 0; 67 | right: 0; 68 | bottom: 0; 69 | } 70 | 71 | .canvas, 72 | &.with-error .canvas { 73 | visibility: hidden; 74 | } 75 | 76 | &.with-diagram .canvas { 77 | visibility: visible; 78 | } 79 | } 80 | 81 | 82 | .buttons { 83 | position: fixed; 84 | bottom: 20px; 85 | left: 20px; 86 | 87 | padding: 0; 88 | margin: 0; 89 | list-style: none; 90 | 91 | > li { 92 | display: inline-block; 93 | margin-right: 10px; 94 | 95 | > a { 96 | background: #DDD; 97 | border: solid 1px #666; 98 | display: inline-block; 99 | padding: 5px; 100 | } 101 | } 102 | 103 | a { 104 | opacity: 0.3; 105 | } 106 | 107 | a.active { 108 | opacity: 1.0; 109 | } 110 | } 111 | 112 | #js-properties-panel { 113 | position: absolute; 114 | top: 0; 115 | bottom: 0; 116 | right: 0; 117 | width: 260px; 118 | z-index: 10; 119 | border-left: 1px solid #ccc; 120 | overflow: auto; 121 | &:empty { 122 | display: none; 123 | } 124 | > .djs-properties-panel { 125 | padding-bottom: 70px; 126 | min-height:100%; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /properties-panel-list-extension/webpack.config.js: -------------------------------------------------------------------------------- 1 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 2 | 3 | const path = require('path'); 4 | 5 | module.exports = { 6 | mode: 'development', 7 | entry: './src/app.js', 8 | output: { 9 | path: path.resolve(__dirname, 'public'), 10 | filename: 'app.js' 11 | }, 12 | devtool: 'source-map', 13 | module: { 14 | rules: [ 15 | { 16 | test: /\.css$/, 17 | use: [ 18 | 'style-loader', 19 | 'css-loader' 20 | ], 21 | }, 22 | { 23 | test: /\.less$/i, 24 | use: [ 25 | 'style-loader', 26 | 'css-loader', 27 | 'less-loader', 28 | ], 29 | }, 30 | { 31 | test: /\.bpmn$/, 32 | use: { 33 | loader: 'raw-loader' 34 | } 35 | } 36 | ] 37 | }, 38 | resolve: { 39 | mainFields: [ 40 | 'browser', 41 | 'module', 42 | 'main' 43 | ], 44 | alias: { 45 | 'react': '@bpmn-io/properties-panel/preact/compat' 46 | } 47 | }, 48 | plugins: [ 49 | new CopyWebpackPlugin({ 50 | patterns: [ 51 | { from: 'src/index.html', to: '.' } 52 | ] 53 | }) 54 | ] 55 | }; -------------------------------------------------------------------------------- /properties-panel/docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/properties-panel/docs/screenshot.png -------------------------------------------------------------------------------- /properties-panel/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bpmn-js-example-properties-panel", 3 | "version": "0.0.0", 4 | "description": "A bpmn-js modeler + properties panel example", 5 | "scripts": { 6 | "all": "run-s build", 7 | "build": "webpack --mode production", 8 | "dev": "webpack-dev-server --static=public --open", 9 | "start": "run-s dev" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/bpmn-io/bpmn-js-examples", 14 | "directory": "properties-panel" 15 | }, 16 | "keywords": [ 17 | "bpmnjs-example", 18 | "bpmn-js-properties-panel" 19 | ], 20 | "author": { 21 | "name": "Nico Rehwaldt", 22 | "url": "https://github.com/nikku" 23 | }, 24 | "contributors": [ 25 | { 26 | "name": "bpmn.io contributors", 27 | "url": "https://github.com/bpmn-io" 28 | } 29 | ], 30 | "license": "MIT", 31 | "dependencies": { 32 | "@bpmn-io/properties-panel": "^3.23.0", 33 | "bpmn-js": "^18.6.2", 34 | "bpmn-js-properties-panel": "^5.23.0", 35 | "jquery": "^3.5.1", 36 | "min-dash": "^4.1.1" 37 | }, 38 | "devDependencies": { 39 | "copy-webpack-plugin": "^13.0.0", 40 | "css-loader": "^7.1.2", 41 | "less-loader": "^12.2.0", 42 | "npm-run-all2": "^8.0.0", 43 | "raw-loader": "^4.0.2", 44 | "sirv-cli": "^3.0.0", 45 | "style-loader": "^4.0.0", 46 | "webpack": "^5.97.1", 47 | "webpack-cli": "^6.0.1", 48 | "webpack-dev-server": "^5.2.0" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /properties-panel/resources/newDiagram.bpmn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /properties-panel/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bpmn-js properties panel demo 6 | 7 | 8 | 9 | 10 |
      11 | 12 |
      13 |
      14 | Drop BPMN diagram from your desktop or create a new diagram to get started. 15 |
      16 |
      17 | 18 |
      19 |
      20 |

      Ooops, we could not display the BPMN 2.0 diagram.

      21 | 22 |
      23 | Import Error Details 24 |
      
      25 |         
      26 |
      27 |
      28 | 29 |
      30 |
      31 |
      32 | 33 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /properties-panel/src/style.less: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body, 6 | html { 7 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 8 | 9 | font-size: 12px; 10 | 11 | height: 100%; 12 | max-height: 100%; 13 | padding: 0; 14 | margin: 0; 15 | } 16 | 17 | #js-properties-panel { 18 | width: 400px; 19 | } 20 | 21 | a:link { 22 | text-decoration: none; 23 | } 24 | 25 | .content { 26 | position: relative; 27 | width: 100%; 28 | height: 100%; 29 | display: flex; 30 | 31 | > .message { 32 | width: 100%; 33 | height: 100%; 34 | text-align: center; 35 | display: table; 36 | 37 | font-size: 16px; 38 | color: #111; 39 | 40 | .note { 41 | vertical-align: middle; 42 | text-align: center; 43 | display: table-cell; 44 | } 45 | 46 | &.error { 47 | .details { 48 | max-width: 500px; 49 | font-size: 12px; 50 | margin: 20px auto; 51 | text-align: left; 52 | color: #BD2828; 53 | } 54 | 55 | pre { 56 | border: solid 1px #BD2828; 57 | background: #fefafa; 58 | padding: 10px; 59 | color: #BD2828; 60 | } 61 | } 62 | } 63 | &:not(.with-error) .error, 64 | &.with-error .intro, 65 | &.with-diagram .intro { 66 | display: none; 67 | } 68 | 69 | .canvas { 70 | width: 100%; 71 | } 72 | 73 | .canvas, 74 | .properties-panel-parent { 75 | display: none; 76 | } 77 | 78 | &.with-diagram { 79 | .canvas, 80 | .properties-panel-parent { 81 | display: block; 82 | } 83 | } 84 | } 85 | 86 | 87 | .buttons { 88 | position: fixed; 89 | bottom: 20px; 90 | left: 20px; 91 | 92 | padding: 0; 93 | margin: 0; 94 | list-style: none; 95 | 96 | > li { 97 | display: inline-block; 98 | margin-right: 10px; 99 | 100 | > a { 101 | background: #DDD; 102 | border: solid 1px #666; 103 | display: inline-block; 104 | padding: 5px; 105 | } 106 | } 107 | 108 | a { 109 | opacity: 0.3; 110 | } 111 | 112 | a.active { 113 | opacity: 1.0; 114 | } 115 | } 116 | 117 | .properties-panel-parent { 118 | border-left: 1px solid #ccc; 119 | overflow: auto; 120 | &:empty { 121 | display: none; 122 | } 123 | > .djs-properties-panel { 124 | padding-bottom: 70px; 125 | min-height:100%; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /properties-panel/webpack.config.js: -------------------------------------------------------------------------------- 1 | var CopyWebpackPlugin = require('copy-webpack-plugin'); 2 | 3 | var path = require('path'); 4 | 5 | module.exports = { 6 | mode: 'development', 7 | entry: './src/app.js', 8 | output: { 9 | path: path.resolve(__dirname, 'public'), 10 | filename: 'app.js' 11 | }, 12 | module: { 13 | rules: [ 14 | { 15 | test: /\.less/, 16 | use: [ 17 | 'style-loader', 18 | 'css-loader', 19 | 'less-loader' 20 | ] 21 | }, 22 | { 23 | test: /\.css$/, 24 | use: [ 25 | 'style-loader', 26 | 'css-loader', 27 | ] 28 | }, 29 | { 30 | test: /\.bpmn$/, 31 | use: { 32 | loader: 'raw-loader' 33 | } 34 | } 35 | ] 36 | }, 37 | plugins: [ 38 | new CopyWebpackPlugin({ 39 | patterns: [ 40 | { from: 'src/index.html', to: '.' } 41 | ] 42 | }) 43 | ] 44 | }; -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "github>bpmn-io/renovate-config:recommended" 5 | ], 6 | "packageRules": [ 7 | { 8 | "matchPackagePatterns": [ 9 | "bpmn-js.*", 10 | "diagram-js.*" 11 | ], 12 | "groupName": "bpmn-js dependencies", 13 | "groupSlug": "bpmn-js" 14 | }, 15 | { 16 | "matchPackagePatterns": [ 17 | "properties-panel.*", 18 | "@bpmn-io/properties-panel.*", 19 | "bpmn-js-properties-panel.*" 20 | ], 21 | "groupName": "bpmn-properties-panel dependencies", 22 | "groupSlug": "bpmn-js-properties-panel" 23 | } 24 | ] 25 | } -------------------------------------------------------------------------------- /simple-bower/README.md: -------------------------------------------------------------------------------- 1 | > Removed as of `bpmn-js@0.27.0`. 2 | 3 | We've discontinued bower bundles with our `0.27.0` release of bpmn-js. 4 | 5 | Checkout our [pre-packaged example](../pre-packaged) for alternative. -------------------------------------------------------------------------------- /simple-commonjs/README.md: -------------------------------------------------------------------------------- 1 | > Removed as of `bpmn-js@0.27.0`. 2 | 3 | Checkout [bundling example](../bundling) for alternative. -------------------------------------------------------------------------------- /starter/README.md: -------------------------------------------------------------------------------- 1 | # bpmn-js starter 2 | 3 | Try out our toolkit by downloading the [viewer](https://cdn.statically.io/gh/bpmn-io/bpmn-js-examples/main/starter/viewer.html) or [modeler](https://cdn.statically.io/gh/bpmn-io/bpmn-js-examples/main/starter/modeler.html) example. 4 | 5 | 6 | [![viewer example screenshot](./viewer.png)](https://cdn.statically.io/gh/bpmn-io/bpmn-js-examples/main/starter/viewer.html) 7 | 8 | _Screenshot of the [viewer example](https://cdn.statically.io/gh/bpmn-io/bpmn-js-examples/main/starter/viewer.html)._ -------------------------------------------------------------------------------- /starter/viewer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/starter/viewer.png -------------------------------------------------------------------------------- /theming/README.md: -------------------------------------------------------------------------------- 1 | # bpmn-js theming 2 | 3 | This example showcases the different aspects of theming bpmn-js. 4 | 5 | ![Screenshot](docs/screenshot.png) 6 | 7 | ## Theming bpmn-js 8 | 9 | ### Custom Renderer 10 | 11 | This example uses [bpmn-js-sketchy](https://github.com/bpmn-io/bpmn-js-sketchy) to replace the default renderer. You can also roll your own renderer as shown in the [custom elements example](https://github.com/bpmn-io/bpmn-js-examples/blob/main/custom-elements/src/custom-modeler/custom/CustomRenderer.js) or [bpmn-js-nyan](https://github.com/bpmn-io/bpmn-js-nyan/blob/main/lib/nyan/draw/NyanRenderer.js). 12 | 13 | ### Custom Font 14 | 15 | You can specify which font bpmn-js should use: 16 | 17 | ```javascript 18 | var bpmnViewer = new CustomBpmnJS({ 19 | // ... 20 | textRenderer: { 21 | defaultStyle: { 22 | fontFamily: '"Nothing You Could Do"' 23 | } 24 | } 25 | }); 26 | ``` 27 | 28 | __Note:__ Make sure the font has been loaded before rendering a diagram. 29 | 30 | ### Custom Colors 31 | 32 | Customizing the colors is very simple: 33 | 34 | ```javascript 35 | var bpmnViewer = new CustomBpmnJS({ 36 | // ... 37 | bpmnRenderer: { 38 | defaultFillColor: '#333', 39 | defaultStrokeColor: '#fff' 40 | } 41 | }); 42 | ``` 43 | 44 | ### Custom CSS 45 | 46 | bpmn-js comes with a [default stylesheet](https://github.com/bpmn-io/diagram-js/blob/main/assets/diagram-js.css). Of course you can override any of these styles. 47 | 48 | ## Run this example 49 | 50 | ``` 51 | npm install 52 | npm run all 53 | ``` 54 | 55 | ## License 56 | 57 | MIT 58 | -------------------------------------------------------------------------------- /theming/docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/theming/docs/screenshot.png -------------------------------------------------------------------------------- /theming/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bpmn-js Theming 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 25 | 26 | 27 |
      28 | 29 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /theming/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "theming", 3 | "version": "0.0.0", 4 | "description": "bpmn-js theming", 5 | "scripts": { 6 | "all": "run-s build", 7 | "dev": "run-s build open", 8 | "build": "rollup -c --bundleConfigAsCjs", 9 | "open": "open-cli ./index.html" 10 | }, 11 | "dependencies": { 12 | "bpmn-js": "^18.6.2", 13 | "bpmn-js-sketchy": "^0.7.0", 14 | "diagram-js": "^15.1.0", 15 | "inherits-browser": "^0.1.0" 16 | }, 17 | "devDependencies": { 18 | "@rollup/plugin-commonjs": "^28.0.2", 19 | "@rollup/plugin-json": "^6.1.0", 20 | "@rollup/plugin-node-resolve": "^16.0.0", 21 | "npm-run-all2": "^8.0.0", 22 | "open-cli": "^8.0.0", 23 | "rollup": "^4.30.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /theming/rollup.config.js: -------------------------------------------------------------------------------- 1 | import commonjs from '@rollup/plugin-commonjs'; 2 | import json from '@rollup/plugin-json'; 3 | import nodeResolve from '@rollup/plugin-node-resolve'; 4 | 5 | export default { 6 | input: 'src/custom-viewer.js', 7 | output: { 8 | file: 'dist/custom-viewer.bundled.js', 9 | name: 'CustomBpmnJS', 10 | format: 'umd' 11 | }, 12 | plugins: [ 13 | nodeResolve({ 14 | browser: true 15 | }), 16 | commonjs(), 17 | json() 18 | ] 19 | }; -------------------------------------------------------------------------------- /theming/src/custom-viewer.js: -------------------------------------------------------------------------------- 1 | import inherits from 'inherits-browser'; 2 | 3 | import Viewer from 'bpmn-js/lib/Viewer'; 4 | 5 | import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll'; 6 | import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas'; 7 | 8 | import SketchyRendererModule from 'bpmn-js-sketchy'; 9 | 10 | 11 | /** 12 | * A viewer that includes mouse navigation and a sketchy renderer. 13 | * 14 | * @param {Object} options 15 | */ 16 | export default function CustomViewer(options) { 17 | Viewer.call(this, options); 18 | } 19 | 20 | inherits(CustomViewer, Viewer); 21 | 22 | CustomViewer.prototype._customModules = [ 23 | ZoomScrollModule, 24 | MoveCanvasModule, 25 | SketchyRendererModule 26 | ]; 27 | 28 | CustomViewer.prototype._modules = [].concat( 29 | Viewer.prototype._modules, 30 | CustomViewer.prototype._customModules 31 | ); -------------------------------------------------------------------------------- /transaction-boundaries/README.md: -------------------------------------------------------------------------------- 1 | # bpmn-js Transaction Boundaries Example 2 | 3 | This example uses [bpmn-js](https://github.com/bpmn-io/bpmn-js) and [camunda-transaction-boundaries](https://github.com/bpmn-io/camunda-transaction-boundaries). It implements a BPMN 2.0 modeler that allows you to visualize transaction boundaries in the diagram. 4 | 5 | ![demo application screenshot](docs/screenshot.png "Screenshot of the modeler + transaction boundaries example") 6 | 7 | 8 | ## Usage 9 | 10 | Add [camunda-transaction-boundaries](https://github.com/bpmn-io/camunda-transaction-boundaries) to your project: 11 | 12 | ``` 13 | npm install --save camunda-transaction-boundaries 14 | ``` 15 | 16 | Now extend the [bpmn-js](https://github.com/bpmm-io/bpmn-js) modeler with the transaction boundaries module (cf. [`src/app.js`](src/app.js#L14) for details). 17 | 18 | ```javascript 19 | import BpmnModeler from 'bpmn-js/lib/Modeler'; 20 | 21 | import transactionBoundariesModule from 'camunda-transaction-boundaries'; 22 | 23 | var canvas = $('#js-canvas'); 24 | 25 | var bpmnModeler = new BpmnModeler({ 26 | container: canvas, 27 | additionalModules: [ 28 | transactionBoundariesModule 29 | ] 30 | }); 31 | 32 | await bpmnModeler.importXML(xml); 33 | 34 | var transactionBoundaries = bpmnModeler.get('transactionBoundaries'); 35 | transactionBoundaries.show(); 36 | 37 | ``` 38 | 39 | 40 | ## Building the Example 41 | 42 | You need a [NodeJS](http://nodejs.org) development stack with [npm](https://npmjs.org) installed to build the project. 43 | 44 | To install all project dependencies execute 45 | 46 | ``` 47 | npm install 48 | ``` 49 | 50 | Build the example using [webpack](https://webpack.js.org/) via 51 | 52 | ``` 53 | npm run all 54 | ``` 55 | 56 | You may also spawn a development setup by executing 57 | 58 | ``` 59 | npm run dev 60 | ``` 61 | 62 | Both tasks generate the distribution ready client-side modeler application into the `public` folder. 63 | 64 | Serve the application locally or via a web server (nginx, apache, embedded). 65 | -------------------------------------------------------------------------------- /transaction-boundaries/docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/transaction-boundaries/docs/screenshot.png -------------------------------------------------------------------------------- /transaction-boundaries/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bpmn-js-example-transaction-boundaries", 3 | "version": "0.0.0", 4 | "description": "Integrate the transaction boundaries extension in bpmn-js modeler", 5 | "scripts": { 6 | "all": "run-s build", 7 | "build": "webpack", 8 | "start": "run-s build serve", 9 | "dev": "run-p \"build -- --watch\" serve", 10 | "serve": "sirv public --dev" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/bpmn-io/bpmn-js-examples", 15 | "directory": "transaction-boundaries" 16 | }, 17 | "keywords": [ 18 | "bpmnjs-example" 19 | ], 20 | "author": { 21 | "name": "Patrick Dehn", 22 | "url": "https://github.com/pedesen" 23 | }, 24 | "contributors": [ 25 | { 26 | "name": "bpmn.io contributors", 27 | "url": "https://github.com/bpmn-io" 28 | } 29 | ], 30 | "license": "MIT", 31 | "devDependencies": { 32 | "@babel/core": "^7.26.0", 33 | "@babel/preset-env": "^7.26.0", 34 | "babel-loader": "^10.0.0", 35 | "copy-webpack-plugin": "^13.0.0", 36 | "css-loader": "^7.1.2", 37 | "npm-run-all2": "^8.0.0", 38 | "sirv-cli": "^3.0.0", 39 | "style-loader": "^4.0.0", 40 | "webpack": "^5.97.1", 41 | "webpack-cli": "^6.0.1" 42 | }, 43 | "dependencies": { 44 | "bpmn-js": "^18.6.2", 45 | "camunda-transaction-boundaries": "^1.1.2", 46 | "diagram-js": "^15.1.0", 47 | "jquery": "^3.6.1", 48 | "min-dash": "^4.0.0" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /transaction-boundaries/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | camunda transaction boundaries demo 5 | 6 | 7 |
      8 | 9 |
      10 |
      11 |

      Ooops, we could not display the BPMN 2.0 diagram.

      12 | 13 |
      14 | cause of the problem 15 |
      
      16 |         
      17 |
      18 |
      19 | 20 |
      21 |
      22 |
      23 | 24 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /transaction-boundaries/src/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body, html { 6 | 7 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 8 | 9 | font-size: 12px; 10 | 11 | height: 100%; 12 | padding: 0; 13 | margin: 0; 14 | } 15 | 16 | a:link { 17 | text-decoration: none; 18 | } 19 | 20 | .content, 21 | .content > div { 22 | width: 100%; 23 | height: 100%; 24 | position: relative; 25 | } 26 | 27 | .content > .message { 28 | text-align: center; 29 | display: table; 30 | 31 | font-size: 16px; 32 | color: #111; 33 | } 34 | 35 | .content > .message .note { 36 | vertical-align: middle; 37 | text-align: center; 38 | display: table-cell; 39 | } 40 | 41 | .content .error .details { 42 | max-width: 500px; 43 | font-size: 12px; 44 | margin: 20px auto; 45 | text-align: left; 46 | } 47 | 48 | .content .error pre { 49 | border: solid 1px #CCC; 50 | background: #EEE; 51 | padding: 10px; 52 | } 53 | 54 | .content:not(.with-error) .error, 55 | .content.with-error .intro, 56 | .content.with-diagram .intro { 57 | display: none; 58 | } 59 | 60 | 61 | .content .canvas, 62 | .content.with-error .canvas { 63 | visibility: hidden; 64 | } 65 | 66 | .content.with-diagram .canvas { 67 | visibility: visible; 68 | } 69 | 70 | .buttons { 71 | position: fixed; 72 | bottom: 20px; 73 | left: 20px; 74 | 75 | padding: 0; 76 | margin: 0; 77 | list-style: none; 78 | } 79 | 80 | .buttons > li { 81 | display: inline-block; 82 | margin-right: 10px; 83 | } 84 | .buttons > li > a { 85 | background: #DDD; 86 | border: solid 1px #666; 87 | display: inline-block; 88 | padding: 5px; 89 | } 90 | 91 | .buttons a { 92 | opacity: 0.3; 93 | } 94 | 95 | .buttons a.active { 96 | opacity: 1.0; 97 | } 98 | -------------------------------------------------------------------------------- /transaction-boundaries/webpack.config.js: -------------------------------------------------------------------------------- 1 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 2 | 3 | const path = require('path'); 4 | 5 | module.exports = { 6 | mode: 'development', 7 | entry: './src/app.js', 8 | output: { 9 | path: path.resolve(__dirname, 'public'), 10 | filename: 'app.js' 11 | }, 12 | devtool: 'source-map', 13 | module: { 14 | rules: [ 15 | { 16 | test: /\.bpmn$/, 17 | type: 'asset/source' 18 | }, 19 | { 20 | test: /\.css$/, 21 | use: [ 22 | 'style-loader', 23 | 'css-loader', 24 | ] 25 | } 26 | ] 27 | }, 28 | plugins: [ 29 | new CopyWebpackPlugin({ 30 | patterns: [ 31 | { from: 'src/index.html', to: '.' } 32 | ] 33 | }) 34 | ] 35 | }; -------------------------------------------------------------------------------- /types/README.md: -------------------------------------------------------------------------------- 1 | # Types 2 | 3 | [bpmn-js](https://github.com/bpmn-io/bpmn-js) and [diagram-js](https://github.com/bpmn-io/diagram-js) expose type declarations. Editor tooling picks up these declarations to offer advanced completion, and validation. This example shows you to use the type declarations as you embed the libraries. 4 | 5 | ## Usage 6 | 7 | Ensure you enabled your editor and environment to provide type hints. 8 | 9 | #### With JavaScript 10 | 11 | ```javascript 12 | import BpmnViewer from 'bpmn-js/lib/Viewer'; 13 | 14 | /** 15 | * @typedef { import('diagram-js/lib/core/ElementRegistry').default } ElementRegistry 16 | */ 17 | 18 | /** 19 | * @type { HTMLElement } 20 | */ 21 | const container = document.querySelector('#canvas'); 22 | 23 | const viewer = new BpmnViewer({ 24 | container 25 | }); 26 | 27 | // type-safe access to components 28 | 29 | /** 30 | * @type { ElementRegistry } 31 | */ 32 | const elementRegistry = viewer.get('elementRegistry'); 33 | 34 | const element = elementRegistry.get('MY_TASK'); 35 | 36 | console.log(element.id); // MY_TASK 37 | ``` 38 | 39 | Checkout the [full example](./src/app.js). 40 | 41 | 42 | #### With [TypeScript](https://www.typescriptlang.org/) 43 | 44 | ```typescript 45 | import BpmnViewer from 'bpmn-js/lib/Viewer'; 46 | 47 | import ElementRegistry from 'diagram-js/lib/core/ElementRegistry'; 48 | 49 | const container = document.querySelector('#canvas') as HTMLElement; 50 | 51 | const viewer = new BpmnViewer({ 52 | container 53 | }); 54 | 55 | // type-safe access to components 56 | const elementRegistry = viewer.get('elementRegistry'); 57 | 58 | const element = elementRegistry.get('MY_TASK')!; 59 | 60 | console.log(element.id); // MY_TASK 61 | ``` 62 | 63 | Checkout the [full example](./src/app.ts). 64 | 65 | 66 | ## Validation 67 | 68 | Use `tsc` in validation mode to check that you use bpmn-js in an intended manner: 69 | 70 | ```sh 71 | # ensure you have typescript installed 72 | npm install typescript 73 | 74 | # check if types are properly used 75 | npx tsc --noEmit --checkJs **/*.js 76 | ``` 77 | 78 | See also [configuring TypeScript](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html). 79 | -------------------------------------------------------------------------------- /types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "types", 3 | "version": "0.0.0", 4 | "description": "Example how to use typings provided with bpmn-js", 5 | "license": "MIT", 6 | "scripts": { 7 | "all": "npm run lint", 8 | "lint": "tsc --noEmit" 9 | }, 10 | "dependencies": { 11 | "bpmn-js": "^18.6.2" 12 | }, 13 | "devDependencies": { 14 | "typescript": "^5.5.4" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /types/src/app.js: -------------------------------------------------------------------------------- 1 | import BpmnViewer from 'bpmn-js/lib/Viewer'; 2 | 3 | /** 4 | * @typedef { import('diagram-js/lib/core/Types').ElementLike } ElementLike 5 | * @typedef { import('diagram-js/lib/core/ElementRegistry').default } ElementRegistry 6 | * @typedef { import('diagram-js/lib/core/EventBus').Event } Event 7 | */ 8 | 9 | /** 10 | * @type { HTMLElement } 11 | */ 12 | const container = document.querySelector('#canvas'); 13 | 14 | const viewer = new BpmnViewer({ 15 | container 16 | }); 17 | 18 | // type-safe event handler 19 | viewer.on('element.hover', (/** @type { { element: ElementLike } & Event } */ event) => { 20 | 21 | if (event.element.id === 'MY_TASK') { 22 | console.log('hovered MY_TASK'); 23 | 24 | event.preventDefault(); 25 | } 26 | }); 27 | 28 | // type-safe access to components 29 | 30 | /** 31 | * @type { ElementRegistry } 32 | */ 33 | const elementRegistry = viewer.get('elementRegistry'); 34 | 35 | const element = elementRegistry.get('MY_TASK'); 36 | 37 | console.log(element.id); // MY_TASK -------------------------------------------------------------------------------- /types/src/app.ts: -------------------------------------------------------------------------------- 1 | import BpmnViewer from 'bpmn-js/lib/Viewer'; 2 | 3 | import { 4 | ElementLike 5 | } from 'diagram-js/lib/core/Types'; 6 | 7 | import ElementRegistry from 'diagram-js/lib/core/ElementRegistry'; 8 | 9 | const container = document.querySelector('#canvas') as HTMLElement; 10 | 11 | const viewer = new BpmnViewer({ 12 | container 13 | }); 14 | 15 | // type-safe event handler 16 | viewer.on<{ 17 | element: ElementLike 18 | }>('element.hover', event => { 19 | 20 | if (event.element.id === 'MY_TASK') { 21 | console.log('hovered MY_TASK'); 22 | 23 | event.preventDefault(); 24 | } 25 | }); 26 | 27 | // type-safe access to components 28 | const elementRegistry = viewer.get('elementRegistry'); 29 | 30 | const element = elementRegistry.get('MY_TASK')!; 31 | 32 | console.log(element.id); // MY_TASK -------------------------------------------------------------------------------- /types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": [ 4 | "DOM", 5 | "ES2018" 6 | ], 7 | "checkJs": true, 8 | "strict": true 9 | }, 10 | "include": [ 11 | "./src/*.js", 12 | "./src/*.ts" 13 | ] 14 | } -------------------------------------------------------------------------------- /url-viewer/README.md: -------------------------------------------------------------------------------- 1 | # bpmn-js Url Viewer Example 2 | 3 | This example uses [bpmn-js](https://github.com/bpmn-io/bpmn-js) to implement a 4 | simple viewer for BPMN 2.0 process diagrams that can be loaded via their URL. 5 | 6 | [__Try out__](https://cdn.statically.io/gh/bpmn-io/bpmn-js-examples/main/url-viewer/index.html). 7 | 8 | 9 | ## About 10 | 11 | The demo includes the [pre-packaged](../pre-packaged) BPMN viewer. 12 | It allows the user to input a url to fetch a process diagram from. 13 | 14 | ![demo application screenshot](./resources/screenshot.png "Screenshot of the example application") 15 | 16 | Make sure you serve the application via a web server (nginx, apache, embedded) and ensure that the diagrams you want to access are either on the same server or [CORS](https://en.wikipedia.org/wiki/Cross-Origin_Resource_Sharing) enabled. 17 | 18 | 19 | ## Run the Example 20 | 21 | Download and open the [example HTML page](https://cdn.statically.io/gh/bpmn-io/bpmn-js-examples/main/url-viewer/index.html). -------------------------------------------------------------------------------- /url-viewer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | bpmn-js url viewer demo 4 | 5 | 6 | 7 | 8 | 29 | 30 | 31 | 32 |
      33 |

      Open BPMN 2.0 diagram from URL

      34 |

      35 | 36 |

      37 |

      38 | Hint: try https://cdn.statically.io/gh/bpmn-io/bpmn-js-examples/dfceecba/url-viewer/resources/pizza-collaboration.bpmn 39 |

      40 |
      41 | 42 |
      43 |
      44 |
      45 | 46 |
      47 |

      Console

      48 | 49 |
      50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 109 | 110 | -------------------------------------------------------------------------------- /url-viewer/resources/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpmn-io/bpmn-js-examples/e2ab40bea617a33ed181573e89dee0167c11c528/url-viewer/resources/screenshot.png --------------------------------------------------------------------------------