feat: allow to type services and events

This PR builds on upon diagram-js provided service and event typing:

* https://github.com/bpmn-io/diagram-js/pull/862

It allows you to specify (public) types exposed by your BPMN toolkit
trough a ServiceMap. Events exposed are parsed from the EventBus
dynamic types.

Closes #2121
This commit is contained in:
Nico Rehwaldt
2024-04-26 17:49:13 +02:00
committed by Nico Rehwaldt
parent 4d0c0f4f65
commit edfec4cdc8
10 changed files with 252 additions and 12 deletions

View File

@ -15,7 +15,11 @@ import BaseViewer from './BaseViewer';
/**
* A base modeler for BPMN 2.0 diagrams.
*
* See {@link Modeler} for a fully-featured modeler.
* See {@link bpmn-js/lib/Modeler} for a fully-featured modeler.
*
* @template [ServiceMap=null]
*
* @extends BaseViewer<ServiceMap>
*
* @param {BaseViewerOptions} [options] The options to configure the modeler.
*/

View File

@ -1,3 +1,6 @@
import Canvas from 'diagram-js/lib/core/Canvas';
import EventBus from 'diagram-js/lib/core/EventBus';
import BaseModeler from './BaseModeler';
import { testViewer } from './BaseViewer.spec';
@ -19,4 +22,38 @@ const extendedModeler = new BaseModeler({
propertiesPanel: {
attachTo: '#properties-panel'
}
});
});
// typed API usage
type FooEvent = {
/**
* Very cool field!
*/
foo: string;
};
type EventMap = {
foo: FooEvent
};
type TypeMap = {
canvas: Canvas,
eventBus: EventBus<EventMap>
};
const typedModeler = new BaseModeler<TypeMap>();
const bus = typedModeler.get('eventBus');
const canvas = typedModeler.get('canvas');
canvas.zoom('fit-viewport');
typedModeler.on('foo', event => {
console.log(event.foo);
});
typedModeler.get('eventBus').on('foo', e => console.log(e.foo));

View File

@ -31,6 +31,12 @@ import {
importBpmnDiagram
} from './import/Importer';
/**
* @template T
*
* @typedef { import('diagram-js/lib/core/EventBus').default<T> } EventBus
*/
/**
* @template T
*
@ -116,12 +122,22 @@ import {
* } } SaveSVGDoneEvent
*/
/**
* @template Type
*
* @typedef { Type extends { eventBus: EventBus<infer X> } ? X : never } EventMap
*/
/**
* A base viewer for BPMN 2.0 diagrams.
*
* Have a look at {@link Viewer}, {@link NavigatedViewer} or {@link Modeler} for
* Have a look at {@link bpmn-js/lib/Viewer}, {@link bpmn-js/lib/NavigatedViewer} or {@link bpmn-js/lib/Modeler} for
* bundles that include actual features.
*
* @template [ServiceMap=null]
*
* @extends Diagram<ServiceMap>
*
* @param {BaseViewerOptions} [options] The options to configure the viewer.
*/
export default function BaseViewer(options) {
@ -542,9 +558,18 @@ BaseViewer.prototype.destroy = function() {
};
/**
* Register an event listener.
* @overlord
*
* Remove an event listener via {@link BaseViewer#off}.
* Register an event listener for events with the given name.
*
* The callback will be invoked with `event, ...additionalArguments`
* that have been passed to {@link EventBus#fire}.
*
* Returning false from a listener will prevent the events default action
* (if any is specified). To stop an event from being processed further in
* other listeners execute {@link Event#stopPropagation}.
*
* Returning anything but `undefined` from a listener will stop the listener propagation.
*
* @template T
*
@ -553,6 +578,25 @@ BaseViewer.prototype.destroy = function() {
* @param {EventBusEventCallback<T>} callback The callback.
* @param {any} [that] Value of `this` the callback will be called with.
*/
/**
* Register an event listener for events with the given name.
*
* The callback will be invoked with `event, ...additionalArguments`
* that have been passed to {@link EventBus#fire}.
*
* Returning false from a listener will prevent the events default action
* (if any is specified). To stop an event from being processed further in
* other listeners execute {@link Event#stopPropagation}.
*
* Returning anything but `undefined` from a listener will stop the listener propagation.
*
* @template {keyof EventMap<ServiceMap>} EventName
*
* @param {EventName} events to subscribe to
* @param {number} [priority=1000] listen priority
* @param {EventBusEventCallback<(EventMap<ServiceMap>)[EventName]>} callback
* @param {any} [that] callback context
*/
BaseViewer.prototype.on = function(events, priority, callback, that) {
return this.get('eventBus').on(events, priority, callback, that);
};

View File

@ -1,6 +1,6 @@
import CommandStack from 'diagram-js/lib/command/CommandStack';
import { Event } from 'diagram-js/lib/core/EventBus';
import EventBus, { Event } from 'diagram-js/lib/core/EventBus';
import BaseViewer, {
ImportDoneEvent,
@ -11,6 +11,7 @@ import BaseViewer, {
} from './BaseViewer';
import OverlaysModule from 'diagram-js/lib/features/overlays';
import Canvas from 'diagram-js/lib/core/Canvas';
const viewer = new BaseViewer();
@ -170,4 +171,37 @@ export function testViewer(viewer: BaseViewer) {
});
viewer.on<Event>('detach', () => {});
}
}
// typed API usage
type FooEvent = {
/**
* Very cool field!
*/
foo: string;
};
type EventMap = {
foo: FooEvent
};
type TypeMap = {
canvas: Canvas,
eventBus: EventBus<EventMap>
};
const typedViewer = new BaseViewer<TypeMap>();
const bus = typedViewer.get('eventBus');
const canvas = typedViewer.get('canvas');
canvas.zoom('fit-viewport');
typedViewer.on('foo', event => {
console.log(event.foo);
});
typedViewer.get('eventBus').on('foo', e => console.log(e.foo));

View File

@ -64,7 +64,6 @@ var initialDiagram =
/**
* A modeler for BPMN 2.0 diagrams.
*
*
* ## Extending the Modeler
*
* In order to extend the viewer pass extension modules to bootstrap via the
@ -125,6 +124,10 @@ var initialDiagram =
* var bpmnModeler = new Modeler({ additionalModules: [ overrideModule ]});
* ```
*
* @template [ServiceMap=null]
*
* @extends BaseModeler<ServiceMap>
*
* @param {BaseViewerOptions} [options] The options to configure the modeler.
*/
export default function Modeler(options) {

View File

@ -1,3 +1,6 @@
import Canvas from 'diagram-js/lib/core/Canvas';
import EventBus from 'diagram-js/lib/core/EventBus';
import Modeler from './Modeler';
import { testViewer } from './BaseViewer.spec';
@ -21,4 +24,38 @@ const extendedModeler = new Modeler({
propertiesPanel: {
attachTo: '#properties-panel'
}
});
});
// typed API usage
type FooEvent = {
/**
* Very cool field!
*/
foo: string;
};
type EventMap = {
foo: FooEvent
};
type TypeMap = {
canvas: Canvas,
eventBus: EventBus<EventMap>
};
const typedViewer = new Modeler<TypeMap>();
const bus = typedViewer.get('eventBus');
const canvas = typedViewer.get('canvas');
canvas.zoom('fit-viewport');
typedViewer.on('foo', event => {
console.log(event.foo);
});
typedViewer.get('eventBus').on('foo', e => console.log(e.foo));

View File

@ -13,6 +13,10 @@ import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll';
/**
* A viewer with mouse and keyboard navigation features.
*
* @template [ServiceMap=null]
*
* @extends Viewer<ServiceMap>
*
* @param {BaseViewerOptions} [options]
*/
export default function NavigatedViewer(options) {

View File

@ -1,3 +1,6 @@
import Canvas from 'diagram-js/lib/core/Canvas';
import EventBus from 'diagram-js/lib/core/EventBus';
import NavigatedViewer from './NavigatedViewer';
import { testViewer } from './BaseViewer.spec';
@ -14,4 +17,37 @@ const extendedViewer = new NavigatedViewer({
propertiesPanel: {
attachTo: '#properties-panel'
}
});
});
// typed API usage
type FooEvent = {
/**
* Very cool field!
*/
foo: string;
};
type EventMap = {
foo: FooEvent
};
type TypeMap = {
canvas: Canvas,
eventBus: EventBus<EventMap>
};
const typedViewer = new NavigatedViewer<TypeMap>();
const bus = typedViewer.get('eventBus');
const canvas = typedViewer.get('canvas');
canvas.zoom('fit-viewport');
typedViewer.on('foo', event => {
console.log(event.foo);
});
typedViewer.get('eventBus').on('foo', e => console.log(e.foo));

View File

@ -17,7 +17,7 @@ import BaseViewer from './BaseViewer';
/**
* A viewer for BPMN 2.0 diagrams.
*
* Have a look at {@link NavigatedViewer} or {@link Modeler} for bundles that include
* Have a look at {@link bpmn-js/lib/NavigatedViewer} or {@link bpmn-js/lib/Modeler} for bundles that include
* additional features.
*
*
@ -53,6 +53,10 @@ import BaseViewer from './BaseViewer';
* bpmnViewer.importXML(...);
* ```
*
* @template [ServiceMap=null]
*
* @extends BaseViewer<ServiceMap>
*
* @param {BaseViewerOptions} [options] The options to configure the viewer.
*/
export default function Viewer(options) {

View File

@ -1,3 +1,6 @@
import Canvas from 'diagram-js/lib/core/Canvas';
import EventBus from 'diagram-js/lib/core/EventBus';
import Viewer from './Viewer';
import { testViewer } from './BaseViewer.spec';
@ -14,4 +17,38 @@ const extendedViewer = new Viewer({
propertiesPanel: {
attachTo: '#properties-panel'
}
});
});
// typed API usage
type FooEvent = {
/**
* Very cool field!
*/
foo: string;
};
type EventMap = {
foo: FooEvent
};
type TypeMap = {
canvas: Canvas,
eventBus: EventBus<EventMap>
};
const typedViewer = new Viewer<TypeMap>();
const bus = typedViewer.get('eventBus');
const canvas = typedViewer.get('canvas');
canvas.zoom('fit-viewport');
typedViewer.on('foo', event => {
console.log(event.foo);
});
typedViewer.get('eventBus').on('foo', e => console.log(e.foo));