@bpmnkit/canvas 0.0.29 → 0.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/canvas.d.ts +4 -3
- package/dist/canvas.js +33 -18
- package/dist/keyboard.d.ts +5 -0
- package/dist/keyboard.js +20 -0
- package/dist/renderer.js +3 -2
- package/dist/scene.d.ts +9 -0
- package/dist/scene.js +31 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
[](https://github.com/bpmnkit/monorepo)
|
|
10
10
|
[](https://github.com/bpmnkit/monorepo)
|
|
11
11
|
|
|
12
|
-
[Website](https://bpmnkit.com) · [Documentation](https://
|
|
12
|
+
[Website](https://bpmnkit.com) · [Documentation](https://bpmnkit.com/docs) · [GitHub](https://github.com/bpmnkit/monorepo) · [Changelog](https://github.com/bpmnkit/monorepo/blob/main/packages/canvas/CHANGELOG.md)
|
|
13
13
|
</div>
|
|
14
14
|
|
|
15
15
|
---
|
|
@@ -122,10 +122,12 @@ const myPlugin: CanvasPlugin = {
|
|
|
122
122
|
| [`@bpmnkit/plugins`](https://www.npmjs.com/package/@bpmnkit/plugins) | 22 composable canvas plugins |
|
|
123
123
|
| [`@bpmnkit/api`](https://www.npmjs.com/package/@bpmnkit/api) | Camunda 8 REST API TypeScript client |
|
|
124
124
|
| [`@bpmnkit/ascii`](https://www.npmjs.com/package/@bpmnkit/ascii) | Render BPMN diagrams as Unicode ASCII art |
|
|
125
|
+
| [`@bpmnkit/docspack`](https://www.npmjs.com/package/@bpmnkit/docspack) | BPMN Kit docs as an offline docspack package for AI agents |
|
|
125
126
|
| [`@bpmnkit/ui`](https://www.npmjs.com/package/@bpmnkit/ui) | Shared design tokens and UI components |
|
|
126
127
|
| [`@bpmnkit/profiles`](https://www.npmjs.com/package/@bpmnkit/profiles) | Shared auth, profile storage, and client factories for CLI & proxy |
|
|
127
128
|
| [`@bpmnkit/operate`](https://www.npmjs.com/package/@bpmnkit/operate) | Monitoring & operations frontend for Camunda clusters |
|
|
128
129
|
| [`@bpmnkit/connector-gen`](https://www.npmjs.com/package/@bpmnkit/connector-gen) | Generate connector templates from OpenAPI specs |
|
|
130
|
+
| [`@bpmnkit/connectors`](https://www.npmjs.com/package/@bpmnkit/connectors) | Camunda 8 OOTB connector catalog and deterministic template application |
|
|
129
131
|
| [`@bpmnkit/cli`](https://www.npmjs.com/package/@bpmnkit/cli) | Camunda 8 command-line interface (casen) |
|
|
130
132
|
| [`@bpmnkit/proxy`](https://www.npmjs.com/package/@bpmnkit/proxy) | Local AI bridge and Camunda API proxy server |
|
|
131
133
|
| [`@bpmnkit/patterns`](https://www.npmjs.com/package/@bpmnkit/patterns) | Domain process patterns for BPMNKit AIKit |
|
package/dist/canvas.d.ts
CHANGED
|
@@ -237,9 +237,10 @@ export declare class BpmnCanvas {
|
|
|
237
237
|
private _updateBreadcrumb;
|
|
238
238
|
/**
|
|
239
239
|
* Resolves the BPMN element id under a pointer/mouse event, or `null`.
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
240
|
+
* The event target answers directly for most moves; `elementFromPoint`
|
|
241
|
+
* (which forces a layout and hit-test flush) is only consulted when native
|
|
242
|
+
* SVG hit-testing handed us the root `<svg>`, as it does in some flex/scroll
|
|
243
|
+
* containers.
|
|
243
244
|
*/
|
|
244
245
|
private _elementIdForEvent;
|
|
245
246
|
/** Diagram-coordinate bounds of a shape (from DI) or edge (waypoint bbox). */
|
package/dist/canvas.js
CHANGED
|
@@ -445,7 +445,9 @@ export class BpmnCanvas {
|
|
|
445
445
|
this._scene.updateElement(id);
|
|
446
446
|
this._shapes = this._scene.getShapes();
|
|
447
447
|
this._edges = this._scene.getEdges();
|
|
448
|
-
this.
|
|
448
|
+
const updated = this._scene.getElement(id);
|
|
449
|
+
if (updated && "shape" in updated)
|
|
450
|
+
this._keyboard.updateShape(updated);
|
|
449
451
|
this._overlays.reposition();
|
|
450
452
|
}
|
|
451
453
|
/** Zooms in by 25% centred on the canvas. */
|
|
@@ -765,32 +767,45 @@ export class BpmnCanvas {
|
|
|
765
767
|
}
|
|
766
768
|
/**
|
|
767
769
|
* Resolves the BPMN element id under a pointer/mouse event, or `null`.
|
|
768
|
-
*
|
|
769
|
-
*
|
|
770
|
-
*
|
|
770
|
+
* The event target answers directly for most moves; `elementFromPoint`
|
|
771
|
+
* (which forces a layout and hit-test flush) is only consulted when native
|
|
772
|
+
* SVG hit-testing handed us the root `<svg>`, as it does in some flex/scroll
|
|
773
|
+
* containers.
|
|
771
774
|
*/
|
|
772
775
|
_elementIdForEvent(e) {
|
|
776
|
+
const fromTarget = e.target?.closest("[data-bpmnkit-id]");
|
|
777
|
+
if (fromTarget)
|
|
778
|
+
return fromTarget.getAttribute("data-bpmnkit-id");
|
|
773
779
|
const fromPoint = document.elementFromPoint(e.clientX, e.clientY);
|
|
774
|
-
|
|
775
|
-
e.target?.closest("[data-bpmnkit-id]");
|
|
776
|
-
return target?.getAttribute("data-bpmnkit-id") ?? null;
|
|
780
|
+
return fromPoint?.closest("[data-bpmnkit-id]")?.getAttribute("data-bpmnkit-id") ?? null;
|
|
777
781
|
}
|
|
778
782
|
/** Diagram-coordinate bounds of a shape (from DI) or edge (waypoint bbox). */
|
|
779
783
|
_diagramBounds(id) {
|
|
780
|
-
const
|
|
781
|
-
if (
|
|
782
|
-
|
|
784
|
+
const el = this._scene.getElement(id);
|
|
785
|
+
if (!el)
|
|
786
|
+
return null;
|
|
787
|
+
if ("shape" in el) {
|
|
788
|
+
const { x, y, width, height } = el.shape.bounds;
|
|
783
789
|
return { x, y, width, height };
|
|
784
790
|
}
|
|
785
|
-
const
|
|
786
|
-
if (
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
791
|
+
const waypoints = el.edge.waypoints;
|
|
792
|
+
if (waypoints.length === 0)
|
|
793
|
+
return null;
|
|
794
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
795
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
796
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
797
|
+
let maxY = Number.NEGATIVE_INFINITY;
|
|
798
|
+
for (const w of waypoints) {
|
|
799
|
+
if (w.x < minX)
|
|
800
|
+
minX = w.x;
|
|
801
|
+
if (w.y < minY)
|
|
802
|
+
minY = w.y;
|
|
803
|
+
if (w.x > maxX)
|
|
804
|
+
maxX = w.x;
|
|
805
|
+
if (w.y > maxY)
|
|
806
|
+
maxY = w.y;
|
|
792
807
|
}
|
|
793
|
-
return
|
|
808
|
+
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
794
809
|
}
|
|
795
810
|
_applyTheme(theme) {
|
|
796
811
|
const resolved = theme === "auto"
|
package/dist/keyboard.d.ts
CHANGED
|
@@ -30,6 +30,11 @@ export declare class KeyboardHandler {
|
|
|
30
30
|
constructor(_container: HTMLElement, _viewport: ViewportController, _onFit: () => void, _onActivate: (id: string) => void, _onFocus: (id: string) => void, _onBlur: () => void);
|
|
31
31
|
/** Updates the navigable shape list after a diagram (re)load. */
|
|
32
32
|
setShapes(shapes: RenderedShape[]): void;
|
|
33
|
+
/**
|
|
34
|
+
* Swaps in the re-rendered graphics of one shape after an incremental
|
|
35
|
+
* update, keeping focus position and avoiding a DOM read per shape.
|
|
36
|
+
*/
|
|
37
|
+
updateShape(shape: RenderedShape): void;
|
|
33
38
|
/** Removes all keyboard event listeners. */
|
|
34
39
|
destroy(): void;
|
|
35
40
|
private _focusShape;
|
package/dist/keyboard.js
CHANGED
|
@@ -42,6 +42,26 @@ export class KeyboardHandler {
|
|
|
42
42
|
this._shapes = shapes.filter((s) => s.element.getAttribute("tabindex") === "-1");
|
|
43
43
|
this._focusIndex = -1;
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Swaps in the re-rendered graphics of one shape after an incremental
|
|
47
|
+
* update, keeping focus position and avoiding a DOM read per shape.
|
|
48
|
+
*/
|
|
49
|
+
updateShape(shape) {
|
|
50
|
+
const focusable = shape.element.getAttribute("tabindex") === "-1";
|
|
51
|
+
const index = this._shapes.findIndex((s) => s.id === shape.id);
|
|
52
|
+
if (index === -1) {
|
|
53
|
+
if (focusable)
|
|
54
|
+
this._shapes.push(shape);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (focusable)
|
|
58
|
+
this._shapes[index] = shape;
|
|
59
|
+
else {
|
|
60
|
+
this._shapes.splice(index, 1);
|
|
61
|
+
if (this._focusIndex >= this._shapes.length)
|
|
62
|
+
this._focusIndex = -1;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
45
65
|
/** Removes all keyboard event listeners. */
|
|
46
66
|
destroy() {
|
|
47
67
|
this._container.removeEventListener("keydown", this._onKeyDown);
|
package/dist/renderer.js
CHANGED
|
@@ -763,8 +763,9 @@ function renderEdge(edge, flow, instanceId, isDefault, isConditional, waypoints)
|
|
|
763
763
|
if (waypoints.length < 2)
|
|
764
764
|
return g;
|
|
765
765
|
const path = svgEl("path");
|
|
766
|
+
const d = waypointsToRoundedPath(waypoints);
|
|
766
767
|
const pathAttrs = {
|
|
767
|
-
d
|
|
768
|
+
d,
|
|
768
769
|
class: "bpmnkit-edge-path",
|
|
769
770
|
"marker-end": `url(#${ids.arrow})`,
|
|
770
771
|
};
|
|
@@ -777,7 +778,7 @@ function renderEdge(edge, flow, instanceId, isDefault, isConditional, waypoints)
|
|
|
777
778
|
// Wide transparent stroke so the edge is easy to click
|
|
778
779
|
const hitPath = svgEl("path");
|
|
779
780
|
attr(hitPath, {
|
|
780
|
-
d
|
|
781
|
+
d,
|
|
781
782
|
fill: "none",
|
|
782
783
|
stroke: "transparent",
|
|
783
784
|
"stroke-width": "12",
|
package/dist/scene.d.ts
CHANGED
|
@@ -23,6 +23,15 @@ export declare class Scene {
|
|
|
23
23
|
private _defs;
|
|
24
24
|
private _plane;
|
|
25
25
|
private _drillableIds;
|
|
26
|
+
/**
|
|
27
|
+
* Model index and docking geometry, built once per {@link render}. The
|
|
28
|
+
* model is expected to be mutated in place between incremental updates
|
|
29
|
+
* (the scene already keeps `_defs`/`_plane` by reference), so rebuilding the
|
|
30
|
+
* whole index for every single-element update was pure waste.
|
|
31
|
+
*/
|
|
32
|
+
private _ctx;
|
|
33
|
+
private readonly _shapeById;
|
|
34
|
+
private readonly _edgeById;
|
|
26
35
|
constructor(_layers: SceneLayers, _instanceId: string);
|
|
27
36
|
/** Renders a plane from scratch, replacing any current content. */
|
|
28
37
|
render(defs: BpmnDefinitions, plane: BpmnDiPlane, drillableIds?: ReadonlySet<string>): void;
|
package/dist/scene.js
CHANGED
|
@@ -15,6 +15,15 @@ export class Scene {
|
|
|
15
15
|
_defs = null;
|
|
16
16
|
_plane = null;
|
|
17
17
|
_drillableIds = new Set();
|
|
18
|
+
/**
|
|
19
|
+
* Model index and docking geometry, built once per {@link render}. The
|
|
20
|
+
* model is expected to be mutated in place between incremental updates
|
|
21
|
+
* (the scene already keeps `_defs`/`_plane` by reference), so rebuilding the
|
|
22
|
+
* whole index for every single-element update was pure waste.
|
|
23
|
+
*/
|
|
24
|
+
_ctx = null;
|
|
25
|
+
_shapeById = new Map();
|
|
26
|
+
_edgeById = new Map();
|
|
18
27
|
constructor(_layers, _instanceId) {
|
|
19
28
|
this._layers = _layers;
|
|
20
29
|
this._instanceId = _instanceId;
|
|
@@ -25,6 +34,11 @@ export class Scene {
|
|
|
25
34
|
this._defs = defs;
|
|
26
35
|
this._plane = plane;
|
|
27
36
|
this._drillableIds = drillableIds;
|
|
37
|
+
this._ctx = null;
|
|
38
|
+
for (const shape of plane.shapes)
|
|
39
|
+
this._shapeById.set(shape.bpmnElement, shape);
|
|
40
|
+
for (const edge of plane.edges)
|
|
41
|
+
this._edgeById.set(edge.bpmnElement, edge);
|
|
28
42
|
const ctx = this._context();
|
|
29
43
|
for (const edge of plane.edges) {
|
|
30
44
|
const g = renderEdgeGroup(edge, ctx);
|
|
@@ -50,6 +64,9 @@ export class Scene {
|
|
|
50
64
|
this._layers.shapes.replaceChildren();
|
|
51
65
|
this._layers.labels.replaceChildren();
|
|
52
66
|
this._registry.clear();
|
|
67
|
+
this._shapeById.clear();
|
|
68
|
+
this._edgeById.clear();
|
|
69
|
+
this._ctx = null;
|
|
53
70
|
}
|
|
54
71
|
/** Returns the registered shape or edge for an id, or `undefined`. */
|
|
55
72
|
getElement(id) {
|
|
@@ -96,7 +113,7 @@ export class Scene {
|
|
|
96
113
|
.split(/\s+/)
|
|
97
114
|
.filter(Boolean);
|
|
98
115
|
if (entry.kind === "edge") {
|
|
99
|
-
const edge = this.
|
|
116
|
+
const edge = this._edgeById.get(id);
|
|
100
117
|
if (!edge)
|
|
101
118
|
return;
|
|
102
119
|
const g = renderEdgeGroup(edge, ctx);
|
|
@@ -106,9 +123,17 @@ export class Scene {
|
|
|
106
123
|
this._registry.set(id, { rendered: { id, element: g, edge }, label: null, kind: "edge" });
|
|
107
124
|
return;
|
|
108
125
|
}
|
|
109
|
-
const shape = this.
|
|
126
|
+
const shape = this._shapeById.get(id);
|
|
110
127
|
if (!shape)
|
|
111
128
|
return;
|
|
129
|
+
// A moved or resized shape must dock its edges against its new bounds.
|
|
130
|
+
const geom = ctx.geomById.get(id);
|
|
131
|
+
if (geom) {
|
|
132
|
+
geom.x = shape.bounds.x;
|
|
133
|
+
geom.y = shape.bounds.y;
|
|
134
|
+
geom.width = shape.bounds.width;
|
|
135
|
+
geom.height = shape.bounds.height;
|
|
136
|
+
}
|
|
112
137
|
const { group, layer, label, rendered } = renderShapeGroup(shape, ctx);
|
|
113
138
|
for (const c of oldClasses)
|
|
114
139
|
group.classList.add(c);
|
|
@@ -131,10 +156,13 @@ export class Scene {
|
|
|
131
156
|
this._registry.delete(id);
|
|
132
157
|
}
|
|
133
158
|
_context() {
|
|
159
|
+
if (this._ctx)
|
|
160
|
+
return this._ctx;
|
|
134
161
|
if (!this._defs || !this._plane) {
|
|
135
162
|
throw new Error("Scene has no rendered plane");
|
|
136
163
|
}
|
|
137
|
-
|
|
164
|
+
this._ctx = buildRenderContext(this._defs, this._plane, this._drillableIds, this._instanceId);
|
|
165
|
+
return this._ctx;
|
|
138
166
|
}
|
|
139
167
|
}
|
|
140
168
|
//# sourceMappingURL=scene.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bpmnkit/canvas",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.31",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"dist/**/*.d.ts"
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@bpmnkit/core": "0.
|
|
20
|
+
"@bpmnkit/core": "0.2.0"
|
|
21
21
|
},
|
|
22
22
|
"description": "Zero-dependency SVG BPMN viewer with pan/zoom, theming, and a plugin API",
|
|
23
23
|
"keywords": [
|