Departmental swimlanes
Each department is an ordinary frame. Tasks belong to that frame through their saved parentId; connections keep their task bindings when lanes move.
Swimlanes use the same parenting, unparenting, movement and optional collapse as frames. Clipping is a separate choice: enable clipsChildren on the definition and clipContent on a lane to hide overflow while expanded. This example leaves clipping disabled. arrangeLanes arranges the frames, not the tasks inside them.
Loading interactive example…Open in new tab ↗
For domain review, choose Task ownership → Detach review task, then Run checks. Select the finding to locate the task and Quality department. Assign review to Quality repairs the ownership; run checks again to clear the finding. Undo restores the draft. This host-defined rule reports incomplete work without blocking edits or adding domain policy to the engine.
- Arrange columns places departments side by side. Their frames change size; task sizes stay unchanged.
- Arrange rows restores horizontal lanes in Production, Quality, Release order. Both arrangements leave a 32-unit gap between departments.
- Collapse Quality shows the department summary and redirects external links. Expand Quality restores its task before arranging the lanes again.
- Undo restores an entire lane arrangement in one step.
- Command-drag a task to transfer it between departments, or outside all departments to release it. Use Control on other platforms. Its bounds only need to intersect the destination; the destination outline is highlighted. Ordinary dragging keeps its current parent. Escape cancels movement and ownership changes.
dart
session.arrangeLanes(
['production', 'quality', 'release'],
direction: DiagramLaneDirection.rows,
laneSize: const DiagramSize(720, 180),
gap: 32,
);The ID order determines lane order. Omit laneSize to preserve existing sizes; gap defaults to zero. The arrangement starts at the current lanes' upper-left corner. Lanes must be expanded, unrotated sibling frames. Moving a locked or fixed child rejects the whole operation. Resizing a lane does not automatically fit its contents: hosts choose the lane size and clipping behavior explicitly.
Transfer ownership with session.reparentElements(['task'], parentId: 'quality'). This preserves world positions; it changes membership without silently laying out the task. Pass no parent to return objects to the root. Transfers, lane movement, deletion, save/load and undo use the ordinary document commands.
To move and transfer together, pass a world-coordinate delta. The engine carries descendants without resizing them and records the entire operation as one undo:
dart
session.reparentElements(
['task'],
parentId: 'quality',
delta: const DiagramPoint(32, 48),
).requireAllowed();A locked descendant rejects the movement without partially changing ownership or positions. Omit delta to change membership while preserving world positions.
On macOS, Command+G groups a selection, Command+Option+G frames it, and Command+Shift+G removes selected groups or frames while keeping their contents. Use Control instead of Command on other platforms. Removing a collapsed frame releases its children as well; Undo restores the container and membership.
Source
dart
actions: {
'Arrange rows': (s) => s
.arrangeLanes(laneIds, laneSize: const DiagramSize(720, 180), gap: 32)
.requireAllowed(),
'Arrange columns': (s) => s
.arrangeLanes(
laneIds,
direction: DiagramLaneDirection.columns,
laneSize: const DiagramSize(240, 540),
gap: 32,
)
.requireAllowed(),
'Collapse Quality': (s) =>
s.setFrameCollapsed('quality', true).requireAllowed(),
'Expand Quality': (s) =>
s.setFrameCollapsed('quality', false).requireAllowed(),
},