@formicoidea/labre-framework-bpmn 0.58.0 → 0.59.0
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/dist/actions.d.ts +76 -6
- package/dist/actions.js +145 -10
- package/dist/background.js +26 -1
- package/dist/commands-manifest.js +16 -0
- package/dist/commands.js +35 -3
- package/dist/element-renderer.d.ts +16 -8
- package/dist/element-renderer.js +67 -3
- package/dist/element-view.d.ts +30 -4
- package/dist/element-view.js +85 -7
- package/dist/pool-hit.d.ts +63 -4
- package/dist/pool-hit.js +57 -8
- package/dist/toolbar/config.d.ts +18 -2
- package/dist/toolbar/config.js +11 -7
- package/dist/toolbar/icons.d.ts +4 -0
- package/dist/toolbar/icons.js +14 -0
- package/package.json +2 -2
package/dist/actions.d.ts
CHANGED
|
@@ -19,7 +19,9 @@ export declare function createBpmnPool(std: BlockStdScope): void;
|
|
|
19
19
|
/**
|
|
20
20
|
* Arm the native connector tool, pre-styled for a BPMN sequence flow:
|
|
21
21
|
* orthogonal, solid, with a filled triangle head. The user then draws from
|
|
22
|
-
* one node to another
|
|
22
|
+
* one node to another, attaching at the anchor of each outline they pick (a
|
|
23
|
+
* gateway's corners, an activity's side midpoints, an event's cardinal points;
|
|
24
|
+
* `BPMN_CENTRE_ANCHORED`).
|
|
23
25
|
*/
|
|
24
26
|
export declare function activateBpmnSequenceFlow(std: BlockStdScope): void;
|
|
25
27
|
/**
|
|
@@ -102,12 +104,14 @@ export declare function bpmnPoolsForLaneEdit(std: BlockStdScope): BpmnPoolElemen
|
|
|
102
104
|
*/
|
|
103
105
|
export declare function addBpmnLane(std: BlockStdScope): void;
|
|
104
106
|
/**
|
|
105
|
-
* Remove the
|
|
107
|
+
* Remove the FOCUSED lane of every selected pool, or its LAST lane when none is
|
|
108
|
+
* focused.
|
|
106
109
|
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
110
|
+
* Focused and not selected, because a lane is not selectable: it is a slice of
|
|
111
|
+
* the pool's plot, painted by the background primitive, with no element of its
|
|
112
|
+
* own. A single click on its title strip, in a selected pool, focuses it
|
|
113
|
+
* ({@link bpmnFocusedLaneIndex}). With nothing focused, removing from the end
|
|
114
|
+
* is the gesture that undoes the one that added it.
|
|
111
115
|
*
|
|
112
116
|
* ## Nothing moves
|
|
113
117
|
*
|
|
@@ -221,3 +225,69 @@ export declare function importBpmnSvgFile(std: BlockStdScope): Promise<void>;
|
|
|
221
225
|
* same thing that only the bytes can tell apart.
|
|
222
226
|
*/
|
|
223
227
|
export declare function renameBpmnLane(std: BlockStdScope, model: BpmnPoolElementModel, index: number, name: string): void;
|
|
228
|
+
/**
|
|
229
|
+
* Move the lane at `from` to `to` inside `pool`, carrying what is drawn in it.
|
|
230
|
+
*
|
|
231
|
+
* A lane is a slice of the pool's plot, and what is "in" it is decided by
|
|
232
|
+
* geometry: the centre of an artefact, read by {@link bpmnLaneOf}. Reordering
|
|
233
|
+
* the `lanes` array alone would leave every task where it was on the canvas and
|
|
234
|
+
* silently hand it to whichever lane now covers that spot — the user moves the
|
|
235
|
+
* Sales lane up and finds their sales tasks filed under Ops. So the gesture
|
|
236
|
+
* moves both: the array is reordered, and every unlocked artefact wholly inside
|
|
237
|
+
* the pool is translated by the vertical shift of the lane its centre was in.
|
|
238
|
+
* Connectors attached to them follow through the connector watcher, as on any
|
|
239
|
+
* other move.
|
|
240
|
+
*
|
|
241
|
+
* A GESTURE-time write, not a cascade: it runs once, on the author's client,
|
|
242
|
+
* from a command, and a peer receives the reorder and the moves as ordinary
|
|
243
|
+
* updates. No stored-format change either: the same `lanes` array, the same
|
|
244
|
+
* `xywh` props.
|
|
245
|
+
*
|
|
246
|
+
* One `captureSync`, then one `transact`, so the reorder and every move are ONE
|
|
247
|
+
* undo step. Refused — and nothing written, so no empty undo entry — on a
|
|
248
|
+
* read-only document, a locked pool, an index that names no lane, or a move to
|
|
249
|
+
* where the lane already is. Returns whether it wrote.
|
|
250
|
+
*
|
|
251
|
+
* ponytail: a connector attached to nothing, drawn inside a lane, stays where
|
|
252
|
+
* it is, and a locked artefact is left behind; the upgrade is to translate the
|
|
253
|
+
* free endpoints too, here and nowhere else.
|
|
254
|
+
*/
|
|
255
|
+
export declare function moveBpmnLane(std: BlockStdScope, pool: BpmnPoolElementModel, from: number, to: number): boolean;
|
|
256
|
+
/**
|
|
257
|
+
* Something that knows which lane of a pool is FOCUSED — the pool's view
|
|
258
|
+
* (`BpmnPoolView`) in an editor, a plain object in a test.
|
|
259
|
+
*
|
|
260
|
+
* A lane is not an element, so it cannot be selected; the lane commands need
|
|
261
|
+
* another way to know which lane the user means. The focus is set by a single
|
|
262
|
+
* click on a lane's title strip in a selected pool, and it is on-screen state
|
|
263
|
+
* and nothing more: held by the view, never stored, never synced, dropped when
|
|
264
|
+
* the pool is deselected. Another viewer of the same document has their own or
|
|
265
|
+
* none. An id rather than an index, so the focus follows the lane it names
|
|
266
|
+
* through a move.
|
|
267
|
+
*/
|
|
268
|
+
export interface BpmnLaneFocusHolder {
|
|
269
|
+
readonly focusedLaneId: string | null;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* The index of `pool`'s focused lane in this editor, or `null` when none is
|
|
273
|
+
* focused or the focused one is gone (removed by a peer, undone away).
|
|
274
|
+
*
|
|
275
|
+
* Read through {@link BpmnLaneFocusHolder} rather than the view class, so the
|
|
276
|
+
* commands do not import the view.
|
|
277
|
+
*/
|
|
278
|
+
export declare function bpmnFocusedLaneIndex(std: BlockStdScope, pool: BpmnPoolElementModel): number | null;
|
|
279
|
+
/**
|
|
280
|
+
* The selected pool whose focused lane can move one step `by` (`-1` up, `1`
|
|
281
|
+
* down), and the lane's index — `null` when no such pool is selected.
|
|
282
|
+
*
|
|
283
|
+
* The first one that qualifies: a lane is focused by clicking it, on one pool
|
|
284
|
+
* at a time, so a selection holding two pools still names at most one lane.
|
|
285
|
+
*/
|
|
286
|
+
export declare function bpmnLaneToMove(std: BlockStdScope, by: -1 | 1): {
|
|
287
|
+
pool: BpmnPoolElementModel;
|
|
288
|
+
index: number;
|
|
289
|
+
} | null;
|
|
290
|
+
/** Move the focused lane of the selected pool one step up. */
|
|
291
|
+
export declare function moveBpmnLaneUp(std: BlockStdScope): void;
|
|
292
|
+
/** Move the focused lane of the selected pool one step down. */
|
|
293
|
+
export declare function moveBpmnLaneDown(std: BlockStdScope): void;
|
package/dist/actions.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { DefaultTool, EdgelessCRUDIdentifier, generateElementId, materializeInterchangeImport, reportInterchangeImport, runInterchangeImportFile, } from '@formicoidea/labre-core/blocks/surface';
|
|
1
|
+
import { backgroundInstanceZones, backgroundPlot, DefaultTool, EdgelessCRUDIdentifier, generateElementId, materializeInterchangeImport, reportInterchangeImport, runInterchangeImportFile, } from '@formicoidea/labre-core/blocks/surface';
|
|
2
2
|
import { ConnectorTool } from '@formicoidea/labre-core/gfx/connector';
|
|
3
3
|
import { createGroupCommand } from '@formicoidea/labre-core/gfx/group';
|
|
4
|
-
import { BpmnPoolElementModel, ConnectorMode, } from '@formicoidea/labre-core/model';
|
|
4
|
+
import { BpmnPoolElementModel, ConnectorElementModel, ConnectorMode, } from '@formicoidea/labre-core/model';
|
|
5
5
|
import { NotificationProvider, translateKey, } from '@formicoidea/labre-core/shared/services';
|
|
6
6
|
import { downloadBlob } from '@formicoidea/labre-core/shared/utils';
|
|
7
7
|
import { Bound } from '@formicoidea/labre-core/global/gfx';
|
|
8
|
-
import { GfxControllerIdentifier } from '@formicoidea/labre-core/std/gfx';
|
|
8
|
+
import { GfxControllerIdentifier, GfxGroupLikeElementModel, } from '@formicoidea/labre-core/std/gfx';
|
|
9
|
+
import { BPMN_POOL_BACKGROUND } from './background.js';
|
|
9
10
|
import { BPMN_EDGE_STYLE, bpmnLabelMode, LANE_NAME_FALLBACK, LANE_NAME_KEY, NODE_LABEL, nodeLabelKey, NODE_SIZE, POOL_NAME_FALLBACK, POOL_NAME_KEY, } from './consts.js';
|
|
10
11
|
import { BPMN_FORMAT_ID, exportBpmnXmlWithWarnings, } from './export.js';
|
|
12
|
+
import { bpmnLaneOf } from './facts.js';
|
|
11
13
|
import { BPMN_SVG_IMPORT, BPMN_XML_EXPORT, BPMN_XML_FORMAT, BPMN_XML_IMPORT, bpmnBoardFrom, bpmnSafeFilename, } from './interchange.js';
|
|
12
14
|
import { bpmnLabelBoxFor, bpmnLabelProps, bpmnNodeProps, bpmnPoolProps, } from './presets.js';
|
|
13
15
|
import { BPMN_ROLE } from './roles.js';
|
|
@@ -105,7 +107,9 @@ export function createBpmnPool(std) {
|
|
|
105
107
|
/**
|
|
106
108
|
* Arm the native connector tool, pre-styled for a BPMN sequence flow:
|
|
107
109
|
* orthogonal, solid, with a filled triangle head. The user then draws from
|
|
108
|
-
* one node to another
|
|
110
|
+
* one node to another, attaching at the anchor of each outline they pick (a
|
|
111
|
+
* gateway's corners, an activity's side midpoints, an event's cardinal points;
|
|
112
|
+
* `BPMN_CENTRE_ANCHORED`).
|
|
109
113
|
*/
|
|
110
114
|
export function activateBpmnSequenceFlow(std) {
|
|
111
115
|
gfxOf(std).tool.setTool(ConnectorTool, {
|
|
@@ -280,12 +284,14 @@ export function addBpmnLane(std) {
|
|
|
280
284
|
}
|
|
281
285
|
}
|
|
282
286
|
/**
|
|
283
|
-
* Remove the
|
|
287
|
+
* Remove the FOCUSED lane of every selected pool, or its LAST lane when none is
|
|
288
|
+
* focused.
|
|
284
289
|
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
290
|
+
* Focused and not selected, because a lane is not selectable: it is a slice of
|
|
291
|
+
* the pool's plot, painted by the background primitive, with no element of its
|
|
292
|
+
* own. A single click on its title strip, in a selected pool, focuses it
|
|
293
|
+
* ({@link bpmnFocusedLaneIndex}). With nothing focused, removing from the end
|
|
294
|
+
* is the gesture that undoes the one that added it.
|
|
289
295
|
*
|
|
290
296
|
* ## Nothing moves
|
|
291
297
|
*
|
|
@@ -304,7 +310,13 @@ export function removeBpmnLane(std) {
|
|
|
304
310
|
return;
|
|
305
311
|
std.store.captureSync();
|
|
306
312
|
for (const model of withLanes) {
|
|
307
|
-
|
|
313
|
+
const lanes = bpmnLanesOf(model);
|
|
314
|
+
// The FOCUSED lane when the user picked one (a click on its title strip),
|
|
315
|
+
// the last one otherwise — which is still the one the previous "Add lane"
|
|
316
|
+
// added.
|
|
317
|
+
const focused = bpmnFocusedLaneIndex(std, model);
|
|
318
|
+
const gone = focused ?? lanes.length - 1;
|
|
319
|
+
writeLanes(std, model, lanes.filter((_, i) => i !== gone));
|
|
308
320
|
}
|
|
309
321
|
}
|
|
310
322
|
/* ── Export (BPMN 2.0 XML) ────────────────────────────────────────────── */
|
|
@@ -510,3 +522,126 @@ export function renameBpmnLane(std, model, index, name) {
|
|
|
510
522
|
std.store.captureSync();
|
|
511
523
|
writeLanes(std, model, next);
|
|
512
524
|
}
|
|
525
|
+
/**
|
|
526
|
+
* Move the lane at `from` to `to` inside `pool`, carrying what is drawn in it.
|
|
527
|
+
*
|
|
528
|
+
* A lane is a slice of the pool's plot, and what is "in" it is decided by
|
|
529
|
+
* geometry: the centre of an artefact, read by {@link bpmnLaneOf}. Reordering
|
|
530
|
+
* the `lanes` array alone would leave every task where it was on the canvas and
|
|
531
|
+
* silently hand it to whichever lane now covers that spot — the user moves the
|
|
532
|
+
* Sales lane up and finds their sales tasks filed under Ops. So the gesture
|
|
533
|
+
* moves both: the array is reordered, and every unlocked artefact wholly inside
|
|
534
|
+
* the pool is translated by the vertical shift of the lane its centre was in.
|
|
535
|
+
* Connectors attached to them follow through the connector watcher, as on any
|
|
536
|
+
* other move.
|
|
537
|
+
*
|
|
538
|
+
* A GESTURE-time write, not a cascade: it runs once, on the author's client,
|
|
539
|
+
* from a command, and a peer receives the reorder and the moves as ordinary
|
|
540
|
+
* updates. No stored-format change either: the same `lanes` array, the same
|
|
541
|
+
* `xywh` props.
|
|
542
|
+
*
|
|
543
|
+
* One `captureSync`, then one `transact`, so the reorder and every move are ONE
|
|
544
|
+
* undo step. Refused — and nothing written, so no empty undo entry — on a
|
|
545
|
+
* read-only document, a locked pool, an index that names no lane, or a move to
|
|
546
|
+
* where the lane already is. Returns whether it wrote.
|
|
547
|
+
*
|
|
548
|
+
* ponytail: a connector attached to nothing, drawn inside a lane, stays where
|
|
549
|
+
* it is, and a locked artefact is left behind; the upgrade is to translate the
|
|
550
|
+
* free endpoints too, here and nowhere else.
|
|
551
|
+
*/
|
|
552
|
+
export function moveBpmnLane(std, pool, from, to) {
|
|
553
|
+
if (std.store.readonly || pool.isLocked())
|
|
554
|
+
return false;
|
|
555
|
+
if (from === to)
|
|
556
|
+
return false;
|
|
557
|
+
const lanes = bpmnLanesOf(pool);
|
|
558
|
+
if (!lanes[from] || !lanes[to])
|
|
559
|
+
return false;
|
|
560
|
+
const next = [...lanes];
|
|
561
|
+
const [moved] = next.splice(from, 1);
|
|
562
|
+
next.splice(to, 0, moved);
|
|
563
|
+
// Each band's top, before and after, read off the painted partition: the
|
|
564
|
+
// normalisation the renderer and the audit use, so an artefact moves by
|
|
565
|
+
// exactly the distance its lane moves on the canvas.
|
|
566
|
+
const frame = pool.elementBound;
|
|
567
|
+
const plot = backgroundPlot(BPMN_POOL_BACKGROUND, frame.w, frame.h);
|
|
568
|
+
const topsOf = (rows) => new Map(backgroundInstanceZones(BPMN_POOL_BACKGROUND, { lanes: rows }).map(zone => [zone.id, zone.rect.y * plot.height]));
|
|
569
|
+
const before = topsOf(lanes);
|
|
570
|
+
const after = topsOf(next);
|
|
571
|
+
const prefix = BPMN_POOL_BACKGROUND.instanceZones?.idPrefix ?? 'lane';
|
|
572
|
+
// Membership BEFORE the write: once the array is reordered the bands are
|
|
573
|
+
// where the lanes are going, and a centre would read the wrong lane.
|
|
574
|
+
const moves = [];
|
|
575
|
+
for (const element of gfxOf(std).grid.search(frame, { strict: true })) {
|
|
576
|
+
if (element === pool || element.isLocked())
|
|
577
|
+
continue;
|
|
578
|
+
// A connector follows its endpoints; a group or a mind map derives its
|
|
579
|
+
// bound from its children, which are moved on their own.
|
|
580
|
+
if (element instanceof ConnectorElementModel)
|
|
581
|
+
continue;
|
|
582
|
+
if (element instanceof GfxGroupLikeElementModel)
|
|
583
|
+
continue;
|
|
584
|
+
const bound = Bound.deserialize(element.xywh);
|
|
585
|
+
const lane = bpmnLaneOf(pool, bound);
|
|
586
|
+
if (!lane)
|
|
587
|
+
continue;
|
|
588
|
+
const key = `${prefix}:${lane.id}`;
|
|
589
|
+
const dy = (after.get(key) ?? 0) - (before.get(key) ?? 0);
|
|
590
|
+
if (dy === 0)
|
|
591
|
+
continue;
|
|
592
|
+
moves.push({ id: element.id, xywh: bound.moveDelta(0, dy).serialize() });
|
|
593
|
+
}
|
|
594
|
+
std.store.captureSync();
|
|
595
|
+
std.store.transact(() => {
|
|
596
|
+
writeLanes(std, pool, next);
|
|
597
|
+
const crud = std.get(EdgelessCRUDIdentifier);
|
|
598
|
+
for (const { id, xywh } of moves)
|
|
599
|
+
crud.updateElement(id, { xywh });
|
|
600
|
+
});
|
|
601
|
+
return true;
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* The index of `pool`'s focused lane in this editor, or `null` when none is
|
|
605
|
+
* focused or the focused one is gone (removed by a peer, undone away).
|
|
606
|
+
*
|
|
607
|
+
* Read through {@link BpmnLaneFocusHolder} rather than the view class, so the
|
|
608
|
+
* commands do not import the view.
|
|
609
|
+
*/
|
|
610
|
+
export function bpmnFocusedLaneIndex(std, pool) {
|
|
611
|
+
const holder = gfxOf(std).view?.get(pool.id);
|
|
612
|
+
const id = holder?.focusedLaneId;
|
|
613
|
+
if (!id)
|
|
614
|
+
return null;
|
|
615
|
+
const index = bpmnLanesOf(pool).findIndex(lane => lane.id === id);
|
|
616
|
+
return index < 0 ? null : index;
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* The selected pool whose focused lane can move one step `by` (`-1` up, `1`
|
|
620
|
+
* down), and the lane's index — `null` when no such pool is selected.
|
|
621
|
+
*
|
|
622
|
+
* The first one that qualifies: a lane is focused by clicking it, on one pool
|
|
623
|
+
* at a time, so a selection holding two pools still names at most one lane.
|
|
624
|
+
*/
|
|
625
|
+
export function bpmnLaneToMove(std, by) {
|
|
626
|
+
for (const pool of bpmnPoolsForLaneEdit(std)) {
|
|
627
|
+
const index = bpmnFocusedLaneIndex(std, pool);
|
|
628
|
+
if (index === null)
|
|
629
|
+
continue;
|
|
630
|
+
if (!bpmnLanesOf(pool)[index + by])
|
|
631
|
+
continue;
|
|
632
|
+
return { pool, index };
|
|
633
|
+
}
|
|
634
|
+
return null;
|
|
635
|
+
}
|
|
636
|
+
/** Move the focused lane of the selected pool one step up. */
|
|
637
|
+
export function moveBpmnLaneUp(std) {
|
|
638
|
+
const target = bpmnLaneToMove(std, -1);
|
|
639
|
+
if (target)
|
|
640
|
+
moveBpmnLane(std, target.pool, target.index, target.index - 1);
|
|
641
|
+
}
|
|
642
|
+
/** Move the focused lane of the selected pool one step down. */
|
|
643
|
+
export function moveBpmnLaneDown(std) {
|
|
644
|
+
const target = bpmnLaneToMove(std, 1);
|
|
645
|
+
if (target)
|
|
646
|
+
moveBpmnLane(std, target.pool, target.index, target.index + 1);
|
|
647
|
+
}
|
package/dist/background.js
CHANGED
|
@@ -26,7 +26,15 @@ import { BPMN_ROLE } from './roles.js';
|
|
|
26
26
|
*
|
|
27
27
|
* The left margin IS the name band: `margin.left` is both the room the flow
|
|
28
28
|
* area gives up and the width of the strip the participant name is written in
|
|
29
|
-
* (see `BackgroundSideBandDef`).
|
|
29
|
+
* (see `BackgroundSideBandDef`) — its MINIMUM width. The name WRAPS up the band
|
|
30
|
+
* (`fit: 'wrap'`), on words, into as many as three lines side by side, and the
|
|
31
|
+
* band thickens to hold them: one line fits the declared 28 units, every
|
|
32
|
+
* further line adds one line height. The PO preferred this to the ellipsis cut
|
|
33
|
+
* PR #532 shipped (2026-10-27): a band that grows with its name reads as a
|
|
34
|
+
* title, a name cut short reads as a bug. A name past three lines is still cut
|
|
35
|
+
* with "…" on the last one, so a pasted paragraph does not eat the pool. The
|
|
36
|
+
* thickness is derived at paint time (`backgroundBandWidths`) and never
|
|
37
|
+
* stored, and the stored name stays whole.
|
|
30
38
|
*
|
|
31
39
|
* ## The lanes
|
|
32
40
|
*
|
|
@@ -43,6 +51,10 @@ import { BPMN_ROLE } from './roles.js';
|
|
|
43
51
|
*
|
|
44
52
|
* Each lane wears its own title band inside the pool's — a narrower strip, no
|
|
45
53
|
* fill, one divider, the name turned on its side, exactly as BPMN 2.0 draws it.
|
|
54
|
+
* A lane name wraps the same way, up to two lines, and every lane's strip takes
|
|
55
|
+
* the thickness the most demanding name needs (PO, 2026-10-27): strips of
|
|
56
|
+
* different widths would stagger the lanes' leading edges, and lanes of one
|
|
57
|
+
* pool are siblings, so they share one edge.
|
|
46
58
|
* The strip is CHROME inside the lane and not a smaller lane: a task dropped on
|
|
47
59
|
* a lane's title band is in that lane, because in BPMN the band belongs to it.
|
|
48
60
|
*/
|
|
@@ -99,6 +111,13 @@ export const BPMN_POOL_BACKGROUND = {
|
|
|
99
111
|
// pool is the same stroke, so the lanes read as the frame continued.
|
|
100
112
|
divider: { color: '@frame', width: POOL_FRAME_WIDTH },
|
|
101
113
|
},
|
|
114
|
+
// Wrapped across the strip, which grows to hold the lines — every lane's
|
|
115
|
+
// strip to the same thickness. Two lines at most: a lane title is a
|
|
116
|
+
// label, and past two a third line would cost the flow area more than
|
|
117
|
+
// the name gains; past that it is cut with "…". The stored name stays
|
|
118
|
+
// whole, and the rename editor shows it in full.
|
|
119
|
+
fit: 'wrap',
|
|
120
|
+
maxLines: 2,
|
|
102
121
|
style: {
|
|
103
122
|
size: POOL_LANE_NAME_FONT_SIZE,
|
|
104
123
|
color: '@name',
|
|
@@ -151,6 +170,12 @@ export const BPMN_POOL_BACKGROUND = {
|
|
|
151
170
|
},
|
|
152
171
|
// Read bottom-to-top, as the spec draws a vertical pool name.
|
|
153
172
|
vertical: true,
|
|
173
|
+
// Wrapped up the band, which grows to hold the lines (three at
|
|
174
|
+
// most, the last cut with "…" if the name is longer still). The
|
|
175
|
+
// anchor stays half the DECLARED width in from the plot edge; the
|
|
176
|
+
// primitive keeps it in the middle of the grown band.
|
|
177
|
+
fit: 'wrap',
|
|
178
|
+
maxLines: 3,
|
|
154
179
|
},
|
|
155
180
|
},
|
|
156
181
|
],
|
|
@@ -199,6 +199,22 @@ export const bpmnCommandsManifest = [
|
|
|
199
199
|
scope: 'edgeless',
|
|
200
200
|
defaultKeys: { mac: [], other: [] },
|
|
201
201
|
},
|
|
202
|
+
{
|
|
203
|
+
id: 'bpmn.moveLaneUp',
|
|
204
|
+
owner: 'bpmn',
|
|
205
|
+
labelKey: 'com.labre.commands.bpmn.moveLaneUp',
|
|
206
|
+
labelFallback: 'Move lane up',
|
|
207
|
+
scope: 'edgeless',
|
|
208
|
+
defaultKeys: { mac: [], other: [] },
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
id: 'bpmn.moveLaneDown',
|
|
212
|
+
owner: 'bpmn',
|
|
213
|
+
labelKey: 'com.labre.commands.bpmn.moveLaneDown',
|
|
214
|
+
labelFallback: 'Move lane down',
|
|
215
|
+
scope: 'edgeless',
|
|
216
|
+
defaultKeys: { mac: [], other: [] },
|
|
217
|
+
},
|
|
202
218
|
{
|
|
203
219
|
id: 'bpmn.exportXml',
|
|
204
220
|
owner: 'bpmn',
|
package/dist/commands.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { StrokeStyle } from '@formicoidea/labre-core/model';
|
|
2
|
-
import { activateBpmnAssociation, activateBpmnMessageFlow, activateBpmnSequenceFlow, addBpmnLane, bpmnLanesOf, bpmnPoolsForLaneEdit, bpmnPoolsSelected, createBpmnNode, createBpmnPool, exportBpmnXmlFile, importBpmnSvgFile, importBpmnXmlFile, removeBpmnLane, } from './actions.js';
|
|
2
|
+
import { activateBpmnAssociation, activateBpmnMessageFlow, activateBpmnSequenceFlow, addBpmnLane, bpmnLanesOf, bpmnPoolsForLaneEdit, bpmnPoolsSelected, createBpmnNode, createBpmnPool, exportBpmnXmlFile, importBpmnSvgFile, importBpmnXmlFile, bpmnLaneToMove, moveBpmnLaneDown, moveBpmnLaneUp, removeBpmnLane, } from './actions.js';
|
|
3
3
|
import { BPMN_EDGE_STYLE, NODE_FILL, NODE_SIZE, } from './consts.js';
|
|
4
4
|
import { bpmnNodeProps } from './presets.js';
|
|
5
5
|
import { BPMN_ROLE, BPMN_ROLE_OF_KIND } from './roles.js';
|
|
6
|
-
import { bpmnAssociationIcon, bpmnCallActivityIcon, bpmnDataObjectIcon, bpmnDataStoreIcon, bpmnEndIcon, bpmnEndMessageIcon, bpmnEndTerminateIcon, bpmnExportXmlIcon, bpmnGatewayIcon, bpmnGatewayParallelIcon, bpmnGroupIcon, bpmnImportSvgIcon, bpmnImportXmlIcon, bpmnLaneAddIcon, bpmnLaneRemoveIcon, bpmnMessageIcon, bpmnPoolIcon, bpmnSequenceIcon, bpmnStartIcon, bpmnStartMessageIcon, bpmnStartTimerIcon, bpmnSubProcessIcon, bpmnTaskIcon, bpmnTaskServiceIcon, bpmnTaskUserIcon, bpmnTextAnnotationIcon, bpmnToolbarIcon, } from './toolbar/icons.js';
|
|
6
|
+
import { bpmnAssociationIcon, bpmnCallActivityIcon, bpmnDataObjectIcon, bpmnDataStoreIcon, bpmnEndIcon, bpmnEndMessageIcon, bpmnEndTerminateIcon, bpmnExportXmlIcon, bpmnGatewayIcon, bpmnGatewayParallelIcon, bpmnGroupIcon, bpmnImportSvgIcon, bpmnImportXmlIcon, bpmnLaneAddIcon, bpmnLaneDownIcon, bpmnLaneRemoveIcon, bpmnLaneUpIcon, bpmnMessageIcon, bpmnPoolIcon, bpmnSequenceIcon, bpmnStartIcon, bpmnStartMessageIcon, bpmnStartTimerIcon, bpmnSubProcessIcon, bpmnTaskIcon, bpmnTaskServiceIcon, bpmnTaskUserIcon, bpmnTextAnnotationIcon, bpmnToolbarIcon, } from './toolbar/icons.js';
|
|
7
7
|
/**
|
|
8
8
|
* What a spec DOES — its own gesture, or the one its {@link Spec.node} implies.
|
|
9
9
|
*
|
|
@@ -493,7 +493,7 @@ const laneCommands = [
|
|
|
493
493
|
labelKey: 'com.labre.commands.bpmn.removeLane',
|
|
494
494
|
labelFallback: 'Remove lane',
|
|
495
495
|
descriptionKey: 'com.labre.commands.bpmn.removeLane.description',
|
|
496
|
-
descriptionFallback: 'Remove the
|
|
496
|
+
descriptionFallback: 'Remove the focused lane of the selected pool, or its last lane. Nothing drawn in it moves.',
|
|
497
497
|
iconKey: 'bpmn.lane-remove',
|
|
498
498
|
order: SPECS.length + 1,
|
|
499
499
|
run: removeBpmnLane,
|
|
@@ -501,6 +501,36 @@ const laneCommands = [
|
|
|
501
501
|
// …and additionally: a pool with no lane has none to remove.
|
|
502
502
|
when: std => bpmnPoolsForLaneEdit(std).some(model => bpmnLanesOf(model).length > 0),
|
|
503
503
|
},
|
|
504
|
+
// The two REORDER commands act on the FOCUSED lane — the one a single click
|
|
505
|
+
// on its title strip picked in the selected pool (`bpmnFocusedLaneIndex`).
|
|
506
|
+
// A lane is not an element and cannot be selected, so without a focus there
|
|
507
|
+
// is no lane to move and the commands are not offered at all.
|
|
508
|
+
{
|
|
509
|
+
...LANE_COMMON,
|
|
510
|
+
id: 'bpmn.moveLaneUp',
|
|
511
|
+
labelKey: 'com.labre.commands.bpmn.moveLaneUp',
|
|
512
|
+
labelFallback: 'Move lane up',
|
|
513
|
+
descriptionKey: 'com.labre.commands.bpmn.moveLaneUp.description',
|
|
514
|
+
descriptionFallback: 'Move the focused lane above the one before it, with everything drawn in it.',
|
|
515
|
+
iconKey: 'bpmn.lane-up',
|
|
516
|
+
order: SPECS.length + 5,
|
|
517
|
+
run: moveBpmnLaneUp,
|
|
518
|
+
telemetry: { framework: 'bpmn', element: 'pool:lane-move-up' },
|
|
519
|
+
when: std => bpmnLaneToMove(std, -1) !== null,
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
...LANE_COMMON,
|
|
523
|
+
id: 'bpmn.moveLaneDown',
|
|
524
|
+
labelKey: 'com.labre.commands.bpmn.moveLaneDown',
|
|
525
|
+
labelFallback: 'Move lane down',
|
|
526
|
+
descriptionKey: 'com.labre.commands.bpmn.moveLaneDown.description',
|
|
527
|
+
descriptionFallback: 'Move the focused lane below the one after it, with everything drawn in it.',
|
|
528
|
+
iconKey: 'bpmn.lane-down',
|
|
529
|
+
order: SPECS.length + 6,
|
|
530
|
+
run: moveBpmnLaneDown,
|
|
531
|
+
telemetry: { framework: 'bpmn', element: 'pool:lane-move-down' },
|
|
532
|
+
when: std => bpmnLaneToMove(std, 1) !== null,
|
|
533
|
+
},
|
|
504
534
|
];
|
|
505
535
|
/**
|
|
506
536
|
* The EXPORT — the first BPMN command whose subject is the whole board.
|
|
@@ -721,6 +751,8 @@ export const bpmnCommandIcons = {
|
|
|
721
751
|
'bpmn.pool': bpmnPoolIcon,
|
|
722
752
|
'bpmn.lane-add': bpmnLaneAddIcon,
|
|
723
753
|
'bpmn.lane-remove': bpmnLaneRemoveIcon,
|
|
754
|
+
'bpmn.lane-up': bpmnLaneUpIcon,
|
|
755
|
+
'bpmn.lane-down': bpmnLaneDownIcon,
|
|
724
756
|
'bpmn.export-xml': bpmnExportXmlIcon,
|
|
725
757
|
'bpmn.import-xml': bpmnImportXmlIcon,
|
|
726
758
|
'bpmn.import-svg': bpmnImportSvgIcon,
|
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
import { type ElementRenderer } from '@formicoidea/labre-core/blocks/surface';
|
|
2
2
|
import type { BpmnPoolElementModel } from '@formicoidea/labre-core/model';
|
|
3
3
|
/**
|
|
4
|
-
* Canvas renderer for the BPMN pool
|
|
4
|
+
* Canvas renderer for the BPMN pool: the declared background, then the outline
|
|
5
|
+
* of the FOCUSED lane, if this editor has one (`BpmnLaneFocusHolder`, held by
|
|
6
|
+
* the pool's view and never stored).
|
|
5
7
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* The outline is the editor talking about the drawing — "this is the lane the
|
|
9
|
+
* reorder commands will move" — not part of it, so it is the theme's accent
|
|
10
|
+
* (`--affine-primary-color`, resolved through the renderer) rather than a
|
|
11
|
+
* notation colour. It is painted only onto the editor's OWN canvases: the SVG
|
|
12
|
+
* and PNG exports paint through this same renderer into a context of their
|
|
13
|
+
* own, and a file must not carry an on-screen focus. A renderer with no editor
|
|
14
|
+
* behind it (a bare unit test) paints none either, and a host that defines no
|
|
15
|
+
* accent gets none.
|
|
16
|
+
*
|
|
17
|
+
* Painted in the transform the primitive left on the context — element-local
|
|
18
|
+
* units, rotated about the centre like the rest of the pool.
|
|
11
19
|
*
|
|
12
20
|
* Exported as a function as well as an extension because the fidelity suite
|
|
13
21
|
* drives it directly with a canvas stub.
|
|
14
22
|
*/
|
|
15
23
|
export declare const bpmnPool: ElementRenderer<BpmnPoolElementModel>;
|
|
16
|
-
export declare const BpmnPoolRendererExtension: import("@formicoidea/labre-core/_pkgs/store").ExtensionType & {
|
|
17
|
-
identifier: import("@formicoidea/labre-core/_pkgs/global/di").ServiceIdentifier<ElementRenderer<BpmnPoolElementModel>>;
|
|
24
|
+
export declare const BpmnPoolRendererExtension: import("@formicoidea/labre-core/_pkgs/store/index.js").ExtensionType & {
|
|
25
|
+
identifier: import("@formicoidea/labre-core/_pkgs/global/di/types.js").ServiceIdentifier<ElementRenderer<BpmnPoolElementModel>>;
|
|
18
26
|
};
|
package/dist/element-renderer.js
CHANGED
|
@@ -1,16 +1,80 @@
|
|
|
1
|
-
import { createFrameworkBackgroundRenderer, ElementRendererExtension, } from '@formicoidea/labre-core/blocks/surface';
|
|
1
|
+
import { backgroundInstanceZones, backgroundPlot, createFrameworkBackgroundRenderer, ElementRendererExtension, } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import { GfxControllerIdentifier } from '@formicoidea/labre-core/std/gfx';
|
|
2
3
|
import { BPMN_POOL_BACKGROUND } from './background.js';
|
|
4
|
+
import { bpmnPoolLayout, cachePaintedBands } from './pool-hit.js';
|
|
3
5
|
/**
|
|
4
|
-
*
|
|
6
|
+
* The pool as the framework-background primitive paints it.
|
|
5
7
|
*
|
|
6
8
|
* There is no BPMN drawing code any more: the pool is an INSTANTIATION of the
|
|
7
9
|
* framework-background primitive, configured by the `BPMN_POOL_BACKGROUND`
|
|
8
10
|
* declaration. What used to be ninety lines of hand-traced rounded rectangle,
|
|
9
11
|
* filled band and rotated name is now a declaration any other framework can
|
|
10
12
|
* write for itself.
|
|
13
|
+
*/
|
|
14
|
+
const paintPool = createFrameworkBackgroundRenderer(BPMN_POOL_BACKGROUND, {
|
|
15
|
+
// The model cannot measure text, so picking would select by the DECLARED
|
|
16
|
+
// band widths while a long name paints them wider. Cache what was painted
|
|
17
|
+
// on the model's `@local()` `paintedBands` (never stored), and only when
|
|
18
|
+
// it changed: a local write is an `elementUpdated`, which repaints. The
|
|
19
|
+
// view writes the same cache before any paint (`element-view.ts`).
|
|
20
|
+
onBands: (model, layout) => {
|
|
21
|
+
cachePaintedBands(model, layout);
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
/** Width of the focused lane's outline, in model units. */
|
|
25
|
+
const FOCUS_OUTLINE_WIDTH = 2;
|
|
26
|
+
/**
|
|
27
|
+
* Canvas renderer for the BPMN pool: the declared background, then the outline
|
|
28
|
+
* of the FOCUSED lane, if this editor has one (`BpmnLaneFocusHolder`, held by
|
|
29
|
+
* the pool's view and never stored).
|
|
30
|
+
*
|
|
31
|
+
* The outline is the editor talking about the drawing — "this is the lane the
|
|
32
|
+
* reorder commands will move" — not part of it, so it is the theme's accent
|
|
33
|
+
* (`--affine-primary-color`, resolved through the renderer) rather than a
|
|
34
|
+
* notation colour. It is painted only onto the editor's OWN canvases: the SVG
|
|
35
|
+
* and PNG exports paint through this same renderer into a context of their
|
|
36
|
+
* own, and a file must not carry an on-screen focus. A renderer with no editor
|
|
37
|
+
* behind it (a bare unit test) paints none either, and a host that defines no
|
|
38
|
+
* accent gets none.
|
|
39
|
+
*
|
|
40
|
+
* Painted in the transform the primitive left on the context — element-local
|
|
41
|
+
* units, rotated about the centre like the rest of the pool.
|
|
11
42
|
*
|
|
12
43
|
* Exported as a function as well as an extension because the fidelity suite
|
|
13
44
|
* drives it directly with a canvas stub.
|
|
14
45
|
*/
|
|
15
|
-
export const bpmnPool =
|
|
46
|
+
export const bpmnPool = (model, ctx, matrix, renderer, rc, viewportBound) => {
|
|
47
|
+
paintPool(model, ctx, matrix, renderer, rc, viewportBound);
|
|
48
|
+
const canvas = renderer;
|
|
49
|
+
if (!canvas?.std)
|
|
50
|
+
return;
|
|
51
|
+
const onScreen = ctx.canvas === canvas.canvas ||
|
|
52
|
+
canvas.stackingCanvas.includes(ctx.canvas);
|
|
53
|
+
if (!onScreen)
|
|
54
|
+
return;
|
|
55
|
+
const holder = canvas.std
|
|
56
|
+
.getOptional(GfxControllerIdentifier)
|
|
57
|
+
?.view?.get(model.id);
|
|
58
|
+
const id = holder?.focusedLaneId;
|
|
59
|
+
if (!id)
|
|
60
|
+
return;
|
|
61
|
+
const [, , w, h] = model.deserializedXYWH;
|
|
62
|
+
// The outline hugs the flow area as PAINTED, i.e. right of a participant
|
|
63
|
+
// band a long name may have widened.
|
|
64
|
+
const plot = backgroundPlot(BPMN_POOL_BACKGROUND, w, h, bpmnPoolLayout(model).margin);
|
|
65
|
+
const prefix = BPMN_POOL_BACKGROUND.instanceZones?.idPrefix ?? 'lane';
|
|
66
|
+
const zone = backgroundInstanceZones(BPMN_POOL_BACKGROUND, model).find(candidate => candidate.id === `${prefix}:${id}`);
|
|
67
|
+
if (!zone)
|
|
68
|
+
return;
|
|
69
|
+
const accent = canvas.getPropertyValue('--affine-primary-color').trim();
|
|
70
|
+
if (!accent)
|
|
71
|
+
return;
|
|
72
|
+
const inset = FOCUS_OUTLINE_WIDTH / 2;
|
|
73
|
+
ctx.save();
|
|
74
|
+
ctx.strokeStyle = accent;
|
|
75
|
+
ctx.lineWidth = FOCUS_OUTLINE_WIDTH;
|
|
76
|
+
ctx.setLineDash([]);
|
|
77
|
+
ctx.strokeRect(plot.x0 + inset, plot.y0 + zone.rect.y * plot.height + inset, plot.width - FOCUS_OUTLINE_WIDTH, zone.rect.h * plot.height - FOCUS_OUTLINE_WIDTH);
|
|
78
|
+
ctx.restore();
|
|
79
|
+
};
|
|
16
80
|
export const BpmnPoolRendererExtension = ElementRendererExtension(BPMN_POOL_BACKGROUND.type, bpmnPool);
|
package/dist/element-view.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { BpmnPoolElementModel } from '@formicoidea/labre-core/model';
|
|
|
2
2
|
import type { EditorHost } from '@formicoidea/labre-core/std';
|
|
3
3
|
import type { PointTestOptions } from '@formicoidea/labre-core/std/gfx';
|
|
4
4
|
import { GfxElementModelView } from '@formicoidea/labre-core/std/gfx';
|
|
5
|
+
import { type BpmnLaneFocusHolder } from './actions.js';
|
|
5
6
|
/**
|
|
6
7
|
* View for a BPMN pool. Three direct gestures live here:
|
|
7
8
|
*
|
|
@@ -14,7 +15,11 @@ import { GfxElementModelView } from '@formicoidea/labre-core/std/gfx';
|
|
|
14
15
|
* renderer paints the name in, rather than a second set of metrics that would
|
|
15
16
|
* one day disagree with it;
|
|
16
17
|
* - **drag on an internal lane boundary** moves the separator, taking from one
|
|
17
|
-
* lane and giving to the other
|
|
18
|
+
* lane and giving to the other;
|
|
19
|
+
* - **click in a lane's title band of a SELECTED pool** focuses that lane —
|
|
20
|
+
* the lane "Move lane up / down" and "Remove lane" act on. On-screen state
|
|
21
|
+
* only ({@link BpmnLaneFocusHolder}): never stored, outlined on the canvas
|
|
22
|
+
* by the renderer, dropped when the pool leaves the selection.
|
|
18
23
|
*
|
|
19
24
|
* Both renames are ZONED to their band (PO recette, 2026-08-26). The whole pool
|
|
20
25
|
* used to open the participant editor, which was right while a pool had one
|
|
@@ -55,14 +60,18 @@ import { GfxElementModelView } from '@formicoidea/labre-core/std/gfx';
|
|
|
55
60
|
* local point by `-model.rotate` about the element centre, at the one function
|
|
56
61
|
* that has the element in hand (`_localPoint`), not a new declared field.
|
|
57
62
|
*/
|
|
58
|
-
export declare class BpmnPoolView extends GfxElementModelView<BpmnPoolElementModel> {
|
|
63
|
+
export declare class BpmnPoolView extends GfxElementModelView<BpmnPoolElementModel> implements BpmnLaneFocusHolder {
|
|
59
64
|
static type: string;
|
|
60
65
|
private _nameEditor;
|
|
66
|
+
private _focusedLaneId;
|
|
67
|
+
/** The focused lane's id — see {@link BpmnLaneFocusHolder}. */
|
|
68
|
+
get focusedLaneId(): string | null;
|
|
61
69
|
/** The boundary the pointer is over, and the handlers armed for it. */
|
|
62
70
|
private _armed;
|
|
63
71
|
/** Everything a separator drag needs, frozen at `dragstart`. */
|
|
64
72
|
private _drag;
|
|
65
73
|
onCreated(): void;
|
|
74
|
+
private _refreshPaintedBands;
|
|
66
75
|
onDestroyed(): void;
|
|
67
76
|
/** Hand the cursor back on the way out; nothing here owns it for long. */
|
|
68
77
|
private _leave;
|
|
@@ -90,9 +99,14 @@ export declare class BpmnPoolView extends GfxElementModelView<BpmnPoolElementMod
|
|
|
90
99
|
* - the internal LANE SEPARATORS, twelve-unit strips in the middle of the
|
|
91
100
|
* flow area, which arm the drag that moves them;
|
|
92
101
|
* - the zoom-GROWN rename targets, which reach past the painted bands when
|
|
93
|
-
* the board is small on screen so a fingertip can still land on one
|
|
102
|
+
* the board is small on screen so a fingertip can still land on one;
|
|
103
|
+
* - the part of a title band a long name has WIDENED past its declared
|
|
104
|
+
* width (the name wraps onto more lines and the band grows with it,
|
|
105
|
+
* `backgroundBandWidths`). The model selects by the declared widths, since
|
|
106
|
+
* it cannot measure text; the rename double-click must still land on every
|
|
107
|
+
* line painted, so `pool-hit.ts` aims at the band as painted.
|
|
94
108
|
*
|
|
95
|
-
*
|
|
109
|
+
* None is a selection zone — a click in the flow area still goes to
|
|
96
110
|
* whatever the user dropped there, because picking asks the MODEL. This
|
|
97
111
|
* override only decides where the pool's own gestures are heard, which is why
|
|
98
112
|
* it is declared here, beside the code that draws and handles them, rather
|
|
@@ -115,6 +129,18 @@ export declare class BpmnPoolView extends GfxElementModelView<BpmnPoolElementMod
|
|
|
115
129
|
private _onDragStart;
|
|
116
130
|
private _onDragMove;
|
|
117
131
|
private _onDragEnd;
|
|
132
|
+
/**
|
|
133
|
+
* A press in a lane's title band of a SELECTED pool focuses that lane; a
|
|
134
|
+
* press in the participant band clears the focus. Anywhere else leaves it.
|
|
135
|
+
*
|
|
136
|
+
* On `pointerdown`, which this view already listens to, and NOT on `click`:
|
|
137
|
+
* a view that registers a handler reports the event as handled, and a
|
|
138
|
+
* registered `click` would take click-to-select away from the default tool.
|
|
139
|
+
* Selected first, for the reason the separator drag gives: a first click on
|
|
140
|
+
* a pool is "work on this pool", not "pick this lane".
|
|
141
|
+
*/
|
|
142
|
+
private _focusAt;
|
|
143
|
+
private _setFocus;
|
|
118
144
|
/**
|
|
119
145
|
* A double-click renames whatever TITLE BAND it landed in, and nothing
|
|
120
146
|
* otherwise (PO recette, 2026-08-26).
|
package/dist/element-view.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
import { EdgelessCRUDIdentifier } from '@formicoidea/labre-core/blocks/surface';
|
|
1
|
+
import { EdgelessCRUDIdentifier, } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import { ToolbarFlag, ToolbarRegistryIdentifier, } from '@formicoidea/labre-core/shared/services';
|
|
2
3
|
import { GfxElementModelView } from '@formicoidea/labre-core/std/gfx';
|
|
3
|
-
import { bpmnLanesOf, renameBpmnLane } from './actions.js';
|
|
4
|
+
import { bpmnLanesOf, renameBpmnLane, } from './actions.js';
|
|
4
5
|
import { POOL_LANE_MIN_HEIGHT } from './consts.js';
|
|
5
|
-
import { bpmnLaneBoundaryAt, bpmnPoolBands, bpmnPoolTargetAt, } from './pool-hit.js';
|
|
6
|
+
import { bpmnLaneBoundaryAt, bpmnPoolBands, bpmnPoolMeasuredLayout, bpmnPoolTargetAt, cachePaintedBands, } from './pool-hit.js';
|
|
7
|
+
/**
|
|
8
|
+
* The props whose change moves a title band: the names it is sized by, and the
|
|
9
|
+
* box whose height a name wraps along. `paintedBands` itself is NOT here — the
|
|
10
|
+
* cache's own write must never re-enter the code that writes it.
|
|
11
|
+
*/
|
|
12
|
+
const BAND_PROPS = new Set(['name', 'lanes', 'xywh']);
|
|
6
13
|
/**
|
|
7
14
|
* View for a BPMN pool. Three direct gestures live here:
|
|
8
15
|
*
|
|
@@ -15,7 +22,11 @@ import { bpmnLaneBoundaryAt, bpmnPoolBands, bpmnPoolTargetAt, } from './pool-hit
|
|
|
15
22
|
* renderer paints the name in, rather than a second set of metrics that would
|
|
16
23
|
* one day disagree with it;
|
|
17
24
|
* - **drag on an internal lane boundary** moves the separator, taking from one
|
|
18
|
-
* lane and giving to the other
|
|
25
|
+
* lane and giving to the other;
|
|
26
|
+
* - **click in a lane's title band of a SELECTED pool** focuses that lane —
|
|
27
|
+
* the lane "Move lane up / down" and "Remove lane" act on. On-screen state
|
|
28
|
+
* only ({@link BpmnLaneFocusHolder}): never stored, outlined on the canvas
|
|
29
|
+
* by the renderer, dropped when the pool leaves the selection.
|
|
19
30
|
*
|
|
20
31
|
* Both renames are ZONED to their band (PO recette, 2026-08-26). The whole pool
|
|
21
32
|
* used to open the participant editor, which was right while a pool had one
|
|
@@ -60,18 +71,49 @@ export class BpmnPoolView extends GfxElementModelView {
|
|
|
60
71
|
constructor() {
|
|
61
72
|
super(...arguments);
|
|
62
73
|
this._nameEditor = null;
|
|
74
|
+
this._focusedLaneId = null;
|
|
63
75
|
/** The boundary the pointer is over, and the handlers armed for it. */
|
|
64
76
|
this._armed = null;
|
|
65
77
|
/** Everything a separator drag needs, frozen at `dragstart`. */
|
|
66
78
|
this._drag = null;
|
|
67
79
|
}
|
|
68
80
|
static { this.type = 'bpmnPool'; }
|
|
81
|
+
/** The focused lane's id — see {@link BpmnLaneFocusHolder}. */
|
|
82
|
+
get focusedLaneId() {
|
|
83
|
+
return this._focusedLaneId;
|
|
84
|
+
}
|
|
69
85
|
onCreated() {
|
|
70
86
|
super.onCreated();
|
|
87
|
+
// Picking asks the MODEL, which selects by `paintedBands`. The renderer
|
|
88
|
+
// writes it after each paint, but a hidden tab never paints and the first
|
|
89
|
+
// click can come before the first frame: the view measures it now, and
|
|
90
|
+
// again whenever a band can have moved, so picking never waits for a
|
|
91
|
+
// frame. One measure per update; the renderer's write after the next
|
|
92
|
+
// paint lands on the same numbers and writes nothing.
|
|
93
|
+
this._refreshPaintedBands();
|
|
94
|
+
this.disposable.add(this.model.propsUpdated.subscribe(({ key }) => {
|
|
95
|
+
if (BAND_PROPS.has(key))
|
|
96
|
+
this._refreshPaintedBands();
|
|
97
|
+
}));
|
|
71
98
|
this.on('dblclick', e => this._onDblClick(e));
|
|
72
99
|
this.on('pointermove', e => this._updateHover(e));
|
|
73
|
-
this.on('pointerdown', e =>
|
|
100
|
+
this.on('pointerdown', e => {
|
|
101
|
+
this._updateHover(e);
|
|
102
|
+
this._focusAt(e);
|
|
103
|
+
});
|
|
74
104
|
this.on('pointerleave', () => this._leave());
|
|
105
|
+
// The focus belongs to a pool the user is working on: once it leaves the
|
|
106
|
+
// selection, there is no lane to act on and nothing to outline.
|
|
107
|
+
this.disposable.add(this.gfx.selection.slots.updated.subscribe(() => {
|
|
108
|
+
if (this._focusedLaneId === null)
|
|
109
|
+
return;
|
|
110
|
+
if (this.gfx.selection.selectedIds.includes(this.model.id))
|
|
111
|
+
return;
|
|
112
|
+
this._setFocus(null);
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
_refreshPaintedBands() {
|
|
116
|
+
cachePaintedBands(this.model, bpmnPoolMeasuredLayout(this.model));
|
|
75
117
|
}
|
|
76
118
|
onDestroyed() {
|
|
77
119
|
this._closeEditor();
|
|
@@ -121,9 +163,14 @@ export class BpmnPoolView extends GfxElementModelView {
|
|
|
121
163
|
* - the internal LANE SEPARATORS, twelve-unit strips in the middle of the
|
|
122
164
|
* flow area, which arm the drag that moves them;
|
|
123
165
|
* - the zoom-GROWN rename targets, which reach past the painted bands when
|
|
124
|
-
* the board is small on screen so a fingertip can still land on one
|
|
166
|
+
* the board is small on screen so a fingertip can still land on one;
|
|
167
|
+
* - the part of a title band a long name has WIDENED past its declared
|
|
168
|
+
* width (the name wraps onto more lines and the band grows with it,
|
|
169
|
+
* `backgroundBandWidths`). The model selects by the declared widths, since
|
|
170
|
+
* it cannot measure text; the rename double-click must still land on every
|
|
171
|
+
* line painted, so `pool-hit.ts` aims at the band as painted.
|
|
125
172
|
*
|
|
126
|
-
*
|
|
173
|
+
* None is a selection zone — a click in the flow area still goes to
|
|
127
174
|
* whatever the user dropped there, because picking asks the MODEL. This
|
|
128
175
|
* override only decides where the pool's own gestures are heard, which is why
|
|
129
176
|
* it is declared here, beside the code that draws and handles them, rather
|
|
@@ -255,6 +302,37 @@ export class BpmnPoolView extends GfxElementModelView {
|
|
|
255
302
|
this.model.pop('lanes');
|
|
256
303
|
this._disarm();
|
|
257
304
|
}
|
|
305
|
+
/* ── Lane focus ────────────────────────────────────────────────────── */
|
|
306
|
+
/**
|
|
307
|
+
* A press in a lane's title band of a SELECTED pool focuses that lane; a
|
|
308
|
+
* press in the participant band clears the focus. Anywhere else leaves it.
|
|
309
|
+
*
|
|
310
|
+
* On `pointerdown`, which this view already listens to, and NOT on `click`:
|
|
311
|
+
* a view that registers a handler reports the event as handled, and a
|
|
312
|
+
* registered `click` would take click-to-select away from the default tool.
|
|
313
|
+
* Selected first, for the reason the separator drag gives: a first click on
|
|
314
|
+
* a pool is "work on this pool", not "pick this lane".
|
|
315
|
+
*/
|
|
316
|
+
_focusAt(e) {
|
|
317
|
+
if (!this.gfx.selection.selectedIds.includes(this.model.id))
|
|
318
|
+
return;
|
|
319
|
+
const target = this._targetAt(this._localPoint(e));
|
|
320
|
+
if (target === null)
|
|
321
|
+
return;
|
|
322
|
+
const lane = target.kind === 'lane' ? bpmnLanesOf(this.model)[target.index] : null;
|
|
323
|
+
this._setFocus(lane?.id ?? null);
|
|
324
|
+
}
|
|
325
|
+
_setFocus(id) {
|
|
326
|
+
if (this._focusedLaneId === id)
|
|
327
|
+
return;
|
|
328
|
+
this._focusedLaneId = id;
|
|
329
|
+
// The outline is painted by the canvas renderer, and the toolbar decides
|
|
330
|
+
// whether to offer the reorder commands: both have to be told.
|
|
331
|
+
this.gfx.surfaceComponent?.refresh();
|
|
332
|
+
this.gfx.std
|
|
333
|
+
.getOptional(ToolbarRegistryIdentifier)
|
|
334
|
+
?.flags.refresh(ToolbarFlag.Surface);
|
|
335
|
+
}
|
|
258
336
|
/* ── In-place naming ───────────────────────────────────────────────── */
|
|
259
337
|
/**
|
|
260
338
|
* A double-click renames whatever TITLE BAND it landed in, and nothing
|
package/dist/pool-hit.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type BackgroundRect, backgroundPlot } from '@formicoidea/labre-core/blocks/surface';
|
|
1
|
+
import { type BackgroundInset, type BackgroundRect, backgroundPlot } from '@formicoidea/labre-core/blocks/surface';
|
|
2
2
|
/**
|
|
3
3
|
* Where a pointer is on a pool, in ELEMENT-LOCAL model units.
|
|
4
4
|
*
|
|
@@ -9,8 +9,18 @@ import { type BackgroundRect, backgroundPlot } from '@formicoidea/labre-core/blo
|
|
|
9
9
|
*
|
|
10
10
|
* Every box is derived from `backgroundInstanceZones` /
|
|
11
11
|
* `backgroundInstanceZoneBand` — the same two functions the renderer paints
|
|
12
|
-
* from and the audit reports from
|
|
13
|
-
*
|
|
12
|
+
* from and the audit reports from — at the band widths `backgroundBandWidths`
|
|
13
|
+
* resolves, the one resolver the renderer sizes the bands with. A long name
|
|
14
|
+
* WIDENS its band (it wraps onto more lines), and the rename target widens with
|
|
15
|
+
* it: a double-click on the second line of a participant name is a
|
|
16
|
+
* double-click on that name. Measured with `measureBackgroundText`, the same
|
|
17
|
+
* metrics the canvas paints with wherever a document exists. Nothing here
|
|
18
|
+
* restates a coordinate, so a target cannot drift away from the thing it is a
|
|
19
|
+
* target for.
|
|
20
|
+
*
|
|
21
|
+
* The model's own `includesPoint` (`affine-model`, headless, no text
|
|
22
|
+
* measurement) still selects by the DECLARED widths; the grown part of a band
|
|
23
|
+
* answers the pool's gestures through the view, which asks these functions.
|
|
14
24
|
*
|
|
15
25
|
* ponytail: a ROTATED pool is not accounted for — the caller converts by
|
|
16
26
|
* subtraction, so every box assumes an upright pool. Same reserve
|
|
@@ -18,11 +28,60 @@ import { type BackgroundRect, backgroundPlot } from '@formicoidea/labre-core/blo
|
|
|
18
28
|
* framework background today. Upgrade: rotate the local point by
|
|
19
29
|
* `-model.rotate` about the element centre, in the caller that has the element.
|
|
20
30
|
*/
|
|
21
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* What these functions need of a pool: its box, its lanes and its name — the
|
|
33
|
+
* name and the lane names size the bands.
|
|
34
|
+
*/
|
|
22
35
|
export interface BpmnPoolGeometry {
|
|
23
36
|
deserializedXYWH: readonly number[];
|
|
24
37
|
lanes?: unknown;
|
|
38
|
+
name?: unknown;
|
|
39
|
+
/** What the renderer last painted — `BpmnPoolElementModel.paintedBands`. */
|
|
40
|
+
paintedBands?: {
|
|
41
|
+
margin: number;
|
|
42
|
+
zoneBandWidth: number;
|
|
43
|
+
};
|
|
25
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* The pool's bands as painted: the margin and strip width the names need.
|
|
47
|
+
*
|
|
48
|
+
* The widths the renderer cached on the model when it has painted the pool —
|
|
49
|
+
* the very numbers the model's `includesPoint` selects by, so a rename target
|
|
50
|
+
* and a selection click agree to the unit; measured here otherwise (a pool not
|
|
51
|
+
* painted yet, a headless caller).
|
|
52
|
+
*/
|
|
53
|
+
export declare function bpmnPoolLayout(model: BpmnPoolGeometry): {
|
|
54
|
+
margin: BackgroundInset;
|
|
55
|
+
zoneBandWidth: number | undefined;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* The pool's bands MEASURED now, from its name and lanes, ignoring any cache:
|
|
59
|
+
* what the view writes into `paintedBands` before the first paint and after
|
|
60
|
+
* every change that moves a band.
|
|
61
|
+
*/
|
|
62
|
+
export declare function bpmnPoolMeasuredLayout(model: BpmnPoolGeometry): {
|
|
63
|
+
margin: BackgroundInset;
|
|
64
|
+
zoneBandWidth: number | undefined;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Write the band widths into the model's `paintedBands` cache — the one place
|
|
68
|
+
* that does, for both writers: the renderer after each paint (the measured
|
|
69
|
+
* truth on the canvas) and the view on creation and on every change that moves
|
|
70
|
+
* a band, so picking never waits for a frame (a hidden tab never paints).
|
|
71
|
+
*
|
|
72
|
+
* Writes ONLY when a width changed and returns whether it wrote: a `@local()`
|
|
73
|
+
* write emits `elementUpdated`, which repaints, so writing an equal value on
|
|
74
|
+
* every paint would repaint forever.
|
|
75
|
+
*/
|
|
76
|
+
export declare function cachePaintedBands(model: {
|
|
77
|
+
paintedBands?: {
|
|
78
|
+
margin: number;
|
|
79
|
+
zoneBandWidth: number;
|
|
80
|
+
};
|
|
81
|
+
}, layout: {
|
|
82
|
+
margin: BackgroundInset;
|
|
83
|
+
zoneBandWidth: number | undefined;
|
|
84
|
+
}): boolean;
|
|
26
85
|
/** A lane band and, when the declaration asks for one, its title strip. */
|
|
27
86
|
export interface BpmnLaneBand {
|
|
28
87
|
top: number;
|
package/dist/pool-hit.js
CHANGED
|
@@ -1,10 +1,59 @@
|
|
|
1
|
-
import { backgroundInstanceZoneBand, backgroundInstanceZones, backgroundPlot, } from '@formicoidea/labre-core/blocks/surface';
|
|
1
|
+
import { backgroundBandWidths, backgroundInstanceZoneBand, backgroundInstanceZones, backgroundPlot, measureBackgroundText, } from '@formicoidea/labre-core/blocks/surface';
|
|
2
2
|
import { BPMN_POOL_BACKGROUND } from './background.js';
|
|
3
|
-
import { POOL_LANE_GRAB } from './consts.js';
|
|
3
|
+
import { POOL_LANE_BAND_WIDTH, POOL_LANE_GRAB } from './consts.js';
|
|
4
|
+
/**
|
|
5
|
+
* The pool's bands as painted: the margin and strip width the names need.
|
|
6
|
+
*
|
|
7
|
+
* The widths the renderer cached on the model when it has painted the pool —
|
|
8
|
+
* the very numbers the model's `includesPoint` selects by, so a rename target
|
|
9
|
+
* and a selection click agree to the unit; measured here otherwise (a pool not
|
|
10
|
+
* painted yet, a headless caller).
|
|
11
|
+
*/
|
|
12
|
+
export function bpmnPoolLayout(model) {
|
|
13
|
+
const declared = BPMN_POOL_BACKGROUND.geometry.margin;
|
|
14
|
+
const painted = model.paintedBands;
|
|
15
|
+
if (painted) {
|
|
16
|
+
return {
|
|
17
|
+
margin: { ...declared, left: painted.margin },
|
|
18
|
+
zoneBandWidth: painted.zoneBandWidth,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
return bpmnPoolMeasuredLayout(model);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The pool's bands MEASURED now, from its name and lanes, ignoring any cache:
|
|
25
|
+
* what the view writes into `paintedBands` before the first paint and after
|
|
26
|
+
* every change that moves a band.
|
|
27
|
+
*/
|
|
28
|
+
export function bpmnPoolMeasuredLayout(model) {
|
|
29
|
+
const [, , w, h] = model.deserializedXYWH;
|
|
30
|
+
return backgroundBandWidths(BPMN_POOL_BACKGROUND, model, w, h, measureBackgroundText);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Write the band widths into the model's `paintedBands` cache — the one place
|
|
34
|
+
* that does, for both writers: the renderer after each paint (the measured
|
|
35
|
+
* truth on the canvas) and the view on creation and on every change that moves
|
|
36
|
+
* a band, so picking never waits for a frame (a hidden tab never paints).
|
|
37
|
+
*
|
|
38
|
+
* Writes ONLY when a width changed and returns whether it wrote: a `@local()`
|
|
39
|
+
* write emits `elementUpdated`, which repaints, so writing an equal value on
|
|
40
|
+
* every paint would repaint forever.
|
|
41
|
+
*/
|
|
42
|
+
export function cachePaintedBands(model, layout) {
|
|
43
|
+
const margin = layout.margin.left;
|
|
44
|
+
const zoneBandWidth = layout.zoneBandWidth ?? POOL_LANE_BAND_WIDTH;
|
|
45
|
+
const previous = model.paintedBands;
|
|
46
|
+
if (previous?.margin === margin && previous.zoneBandWidth === zoneBandWidth) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
model.paintedBands = { margin, zoneBandWidth };
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
4
52
|
/** The lane bands of this pool, or `null` when it has no usable partition. */
|
|
5
53
|
export function bpmnPoolBands(model) {
|
|
6
54
|
const [, , w, h] = model.deserializedXYWH;
|
|
7
|
-
const
|
|
55
|
+
const layout = bpmnPoolLayout(model);
|
|
56
|
+
const plot = backgroundPlot(BPMN_POOL_BACKGROUND, w, h, layout.margin);
|
|
8
57
|
if (!(plot.width > 0) || !(plot.height > 0))
|
|
9
58
|
return null;
|
|
10
59
|
const zones = backgroundInstanceZones(BPMN_POOL_BACKGROUND, model);
|
|
@@ -15,7 +64,7 @@ export function bpmnPoolBands(model) {
|
|
|
15
64
|
bands: zones.map(zone => ({
|
|
16
65
|
top: plot.y0 + zone.rect.y * plot.height,
|
|
17
66
|
height: zone.rect.h * plot.height,
|
|
18
|
-
strip: backgroundInstanceZoneBand(BPMN_POOL_BACKGROUND, zone, plot),
|
|
67
|
+
strip: backgroundInstanceZoneBand(BPMN_POOL_BACKGROUND, zone, plot, layout.zoneBandWidth),
|
|
19
68
|
})),
|
|
20
69
|
};
|
|
21
70
|
}
|
|
@@ -94,10 +143,10 @@ export function bpmnLaneTitleBandAt(model, local, zoom) {
|
|
|
94
143
|
*/
|
|
95
144
|
export function bpmnInPoolTitleBand(model, local, zoom) {
|
|
96
145
|
const [, , w, h] = model.deserializedXYWH;
|
|
97
|
-
|
|
98
|
-
//
|
|
99
|
-
//
|
|
100
|
-
const painted = Math.min(
|
|
146
|
+
// The band IS the margin — as wide as the wrapped name needs — clamped to a
|
|
147
|
+
// pool narrower than its own margin, the same degenerate case the renderer
|
|
148
|
+
// clamps.
|
|
149
|
+
const painted = Math.min(bpmnPoolLayout(model).margin.left, w);
|
|
101
150
|
if (!(painted > 0))
|
|
102
151
|
return false;
|
|
103
152
|
// Grown rightwards, capped at twice the margin: past that lies the lane
|
package/dist/toolbar/config.d.ts
CHANGED
|
@@ -24,6 +24,22 @@ export declare const bpmnPoolToolbarConfig: {
|
|
|
24
24
|
tooltip: string;
|
|
25
25
|
run: (runCtx: ToolbarContext) => void;
|
|
26
26
|
};
|
|
27
|
+
}, {
|
|
28
|
+
id: string;
|
|
29
|
+
when: (ctx: ToolbarContext) => boolean;
|
|
30
|
+
generate: (ctx: ToolbarContext) => {
|
|
31
|
+
icon: TemplateResult;
|
|
32
|
+
tooltip: string;
|
|
33
|
+
run: (runCtx: ToolbarContext) => void;
|
|
34
|
+
};
|
|
35
|
+
}, {
|
|
36
|
+
id: string;
|
|
37
|
+
when: (ctx: ToolbarContext) => boolean;
|
|
38
|
+
generate: (ctx: ToolbarContext) => {
|
|
39
|
+
icon: TemplateResult;
|
|
40
|
+
tooltip: string;
|
|
41
|
+
run: (runCtx: ToolbarContext) => void;
|
|
42
|
+
};
|
|
27
43
|
}, import("@formicoidea/labre-core/shared/services").ToolbarActionGenerator];
|
|
28
44
|
readonly when: (ctx: ToolbarContext) => boolean;
|
|
29
45
|
};
|
|
@@ -35,8 +51,8 @@ export declare const bpmnPoolToolbarExtension: import("@formicoidea/labre-core/_
|
|
|
35
51
|
* up — the same merge C4's board makes for the same reason).
|
|
36
52
|
*
|
|
37
53
|
* `c.legend` and not `b.legend`: the toolbar sorts lexicographically by id
|
|
38
|
-
* after partitioning by placement, and `'b.add
|
|
39
|
-
* 'b.remove
|
|
54
|
+
* after partitioning by placement, and `'b.lane-1-add' < 'b.legend' <
|
|
55
|
+
* 'b.lane-4-remove'` would wedge the button between the two lane gestures. `c.`
|
|
40
56
|
* puts it where it belongs — resize · add lane · remove lane · **Legend** ·
|
|
41
57
|
* Validation, with Export XML in the "⋮".
|
|
42
58
|
*
|
package/dist/toolbar/config.js
CHANGED
|
@@ -3,7 +3,7 @@ import { BpmnPoolElementModel } from '@formicoidea/labre-core/model';
|
|
|
3
3
|
import { BOARD_RESIZE_TOGGLE, commandMoreAction, ToolbarModuleExtension, translateKey, } from '@formicoidea/labre-core/shared/services';
|
|
4
4
|
import { BlockFlavourIdentifier, getRegisteredCommands, runCommand, } from '@formicoidea/labre-core/std';
|
|
5
5
|
import { html } from 'lit';
|
|
6
|
-
import { bpmnExportXmlIcon, bpmnLaneAddIcon, bpmnLaneRemoveIcon, } from './icons.js';
|
|
6
|
+
import { bpmnExportXmlIcon, bpmnLaneAddIcon, bpmnLaneDownIcon, bpmnLaneRemoveIcon, bpmnLaneUpIcon, } from './icons.js';
|
|
7
7
|
const ResizeIcon = html `<svg
|
|
8
8
|
width="24"
|
|
9
9
|
height="24"
|
|
@@ -90,10 +90,14 @@ export const bpmnPoolToolbarConfig = {
|
|
|
90
90
|
booleanToggle('a.toggle-resize', BOARD_RESIZE_TOGGLE, ResizeIcon, 'resizeEnabled'),
|
|
91
91
|
// The two lane gestures, next to the resize toggle: everything on this row
|
|
92
92
|
// is about the SHAPE of the pool rather than about what is drawn in it.
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
commandAction('b.add
|
|
96
|
-
commandAction('b.remove
|
|
93
|
+
// Actions sort by id: add, move up, move down, remove — the order a lane
|
|
94
|
+
// is handled in, with remove last because it is the destructive one.
|
|
95
|
+
commandAction('b.lane-1-add', 'bpmn.addLane', 'com.labre.commands.bpmn.addLane', 'Add lane', bpmnLaneAddIcon),
|
|
96
|
+
commandAction('b.lane-4-remove', 'bpmn.removeLane', 'com.labre.commands.bpmn.removeLane', 'Remove lane', bpmnLaneRemoveIcon),
|
|
97
|
+
// Reorder, beside add and remove: they act on the FOCUSED lane (a click on
|
|
98
|
+
// its title strip) and only show while one is focused and can move.
|
|
99
|
+
commandAction('b.lane-2-up', 'bpmn.moveLaneUp', 'com.labre.commands.bpmn.moveLaneUp', 'Move lane up', bpmnLaneUpIcon),
|
|
100
|
+
commandAction('b.lane-3-down', 'bpmn.moveLaneDown', 'com.labre.commands.bpmn.moveLaneDown', 'Move lane down', bpmnLaneDownIcon),
|
|
97
101
|
// …and, in the "⋮", the one thing you do to a finished process rather than
|
|
98
102
|
// to the shape of a pool: take it away as a file.
|
|
99
103
|
commandMoreAction('z.export-xml', 'bpmn.exportXml', 'com.labre.commands.bpmn.exportXml', 'Export BPMN XML', bpmnExportXmlIcon),
|
|
@@ -111,8 +115,8 @@ export const bpmnPoolToolbarExtension = ToolbarModuleExtension({
|
|
|
111
115
|
* up — the same merge C4's board makes for the same reason).
|
|
112
116
|
*
|
|
113
117
|
* `c.legend` and not `b.legend`: the toolbar sorts lexicographically by id
|
|
114
|
-
* after partitioning by placement, and `'b.add
|
|
115
|
-
* 'b.remove
|
|
118
|
+
* after partitioning by placement, and `'b.lane-1-add' < 'b.legend' <
|
|
119
|
+
* 'b.lane-4-remove'` would wedge the button between the two lane gestures. `c.`
|
|
116
120
|
* puts it where it belongs — resize · add lane · remove lane · **Legend** ·
|
|
117
121
|
* Validation, with Export XML in the "⋮".
|
|
118
122
|
*
|
package/dist/toolbar/icons.d.ts
CHANGED
|
@@ -87,3 +87,7 @@ export declare const bpmnPoolIcon: import("lit-html").TemplateResult<2>;
|
|
|
87
87
|
export declare const bpmnLaneAddIcon: import("lit-html").TemplateResult<2>;
|
|
88
88
|
/** Remove lane — the same pool, with a minus on the band that goes. */
|
|
89
89
|
export declare const bpmnLaneRemoveIcon: import("lit-html").TemplateResult<2>;
|
|
90
|
+
/** Move lane up — the pool cut in two, with an arrow rising out of the lower band. */
|
|
91
|
+
export declare const bpmnLaneUpIcon: import("lit-html").TemplateResult<2>;
|
|
92
|
+
/** Move lane down — the same pool, with an arrow falling out of the upper band. */
|
|
93
|
+
export declare const bpmnLaneDownIcon: import("lit-html").TemplateResult<2>;
|
package/dist/toolbar/icons.js
CHANGED
|
@@ -179,3 +179,17 @@ export const bpmnLaneRemoveIcon = svg `<svg width="24" height="24" viewBox="0 0
|
|
|
179
179
|
<path d="M8 12 H20.5" stroke="currentColor" stroke-width="1.6"/>
|
|
180
180
|
<path d="M12.4 15.1 H16.1" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/>
|
|
181
181
|
</svg>`;
|
|
182
|
+
/** Move lane up — the pool cut in two, with an arrow rising out of the lower band. */
|
|
183
|
+
export const bpmnLaneUpIcon = svg `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
184
|
+
<rect x="3.5" y="5.5" width="17" height="13" rx="1.5" stroke="currentColor" stroke-width="1.6"/>
|
|
185
|
+
<path d="M8 5.5 V18.5" stroke="currentColor" stroke-width="1.6"/>
|
|
186
|
+
<path d="M8 12 H20.5" stroke="currentColor" stroke-width="1.6"/>
|
|
187
|
+
<path d="M14.25 16.6 V13.6 M12.6 15 L14.25 13.4 L15.9 15" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
|
|
188
|
+
</svg>`;
|
|
189
|
+
/** Move lane down — the same pool, with an arrow falling out of the upper band. */
|
|
190
|
+
export const bpmnLaneDownIcon = svg `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
191
|
+
<rect x="3.5" y="5.5" width="17" height="13" rx="1.5" stroke="currentColor" stroke-width="1.6"/>
|
|
192
|
+
<path d="M8 5.5 V18.5" stroke="currentColor" stroke-width="1.6"/>
|
|
193
|
+
<path d="M8 12 H20.5" stroke="currentColor" stroke-width="1.6"/>
|
|
194
|
+
<path d="M14.25 7.4 V10.4 M12.6 9 L14.25 10.6 L15.9 9" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
|
|
195
|
+
</svg>`;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@formicoidea/labre-framework-bpmn",
|
|
3
3
|
"description": "Labre bpmn framework for @formicoidea/labre-core.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.59.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"author": "lajola",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"dist"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@formicoidea/labre-core": "0.
|
|
38
|
+
"@formicoidea/labre-core": "0.59.0",
|
|
39
39
|
"lit": "^3.2.0"
|
|
40
40
|
}
|
|
41
41
|
}
|