@weasel-js/diagram 1.10.1 → 1.11.1

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/index.d.ts CHANGED
@@ -1,57 +1,144 @@
1
- import { P as Port, a as PortsOptions, D as DiagramNodeLike, b as DiagramNodeReader, c as PortAnchor, d as DiagramGroup, R as Row, O as Outline, e as PortSpec, B as BodySpec, f as DiagramNode, L as LayoutFn, g as LayoutOptions, M as MeasureRowText, G as GraphSource, F as ForceOptions, h as LayoutResult, i as Graph, j as LayoutDirection } from './layout.entry-BUkiRKuX.js';
2
- export { k as BodyFloor, l as BodyNodeSpec, m as Bounds, n as BuildBodyOptions, o as BuildGraphOptions, C as COMPASS, p as DEFAULT_GROUP_INSET, q as DEFAULT_NODE_GAP, r as DEFAULT_PORTS, s as DEFAULT_RANK_GAP, t as DIAGRAM_TRAIT_KEY, u as DiagramNodeEntry, v as ForceBody, w as ForceRelaxation, x as Forest, y as GraphEdge, z as GraphGroup, A as GraphNode, E as GraphNodeLike, H as GroupInset, I as LayoutAxes, J as RowBox, K as RowNodeData, N as RowPort, Q as RowPortBox, S as RowTextStyle, T as Slot, U as axesFor, V as backEdges, W as bodyOutline, X as bodyTrait, Y as boxForContent, Z as buildBody, _ as buildGraph, $ as canvasMeasure, a0 as contentBox, a1 as createDiagramNodes, a2 as dataKeyReader, a3 as diagramNodeOf, a4 as expandGroupEdges, a5 as force, a6 as forceRelaxation, a7 as forestOf, a8 as graphOrder, a9 as insetOf, aa as isPinned, ab as layered, ac as layoutBody, ad as layoutRowPorts, ae as measureBody, af as outlinePath, ag as outlinePolyline, ah as packAcross, ai as packClusters, aj as pinnedSet, ak as portOf, al as portsOf, am as portsOnOutline, an as rankGaps, ao as ranksOf, ap as rayHit, aq as seededOrder, ar as settle, as as sizeToBody, at as translated, au as tree, av as untilSettled } from './layout.entry-BUkiRKuX.js';
3
- import { Vec2, DerivedDep, Path, SceneRegistry, PoseDescriptor, ChromeState, CommandFill, CommandStroke, CursorSpec, Affordance, InvocationCtx, Stroke, GestureBinding, Action, Contribution, RenderLayer, MarkerRef, AddNodeSpec, RectPose, Scene, NodeId, Fill, NodeShapeEntry, Paint, View, SelectionApi } from '@weasel-js/core';
4
- import { Vec2 as Vec2$1 } from '@weasel-js/core/math';
1
+ import { g as Port, h as DiagramNodeLike, i as DiagramNodeReader, O as Outline, a as Row, M as MeasureRowText, C as ContainerRole, j as DiagramContainer, k as ContainerHeader, c as DiagramLabel, l as LabelSpot, E as EdgeHop, R as RowTextStyle, m as Bounds$2, e as LayoutOptions, n as LayoutResult, G as Graph, d as LayoutFn, o as GraphSource, p as LayoutPlanner, q as LayoutDirection, L as LayoutPorts, r as LayoutPlan, s as GraphNodeLike, S as StyleField, F as FontField } from './types-BbHunLXm.js';
2
+ export { t as BodyFloor, u as BodyNodeSpec, B as BodySpec, v as BuildBodyOptions, w as BuildGraphOptions, x as DEFAULT_GROUP_INSET, y as DEFAULT_HOP_SIZE, z as DEFAULT_NODE_GAP, A as DEFAULT_RANK_GAP, H as DIAGRAM_TRAIT_KEY, D as DiagramGroup, f as DiagramNode, I as DiagramNodeEntry, J as EdgeLabelRoom, K as GraphEdge, N as GraphGroup, Q as GraphNode, T as GroupInset, U as HOPS_DOC_KEY, V as HopsDocValue, W as LABEL_PLACEMENT, X as LayoutAxes, Y as PORT_LABEL_GAP, Z as PerimeterPortLabelBox, P as PortAnchor, _ as PortLabelPlacement, $ as PortSite, b as PortSpec, a0 as RowBox, a1 as RowNodeData, a2 as RowPort, a3 as RowPortBox, a4 as Slot, a5 as anchorOffset, a6 as axesFor, a7 as bodyBox, a8 as bodyOutline, a9 as bodyTrait, aa as boxForContent, ab as buildBody, ac as buildGraph, ad as canvasMeasure, ae as contentBox, af as createDiagramNodes, ag as dataKeyReader, ah as diagramContainerOf, ai as diagramLabelOf, aj as diagramNodeOf, ak as expandGroupEdges, al as graphOrder, am as headerBox, an as insetOf, ao as isPinned, ap as layoutBody, aq as layoutRowPorts, ar as marginOf, as as measureBody, at as outlinePath, au as packAcross, av as packClusters, aw as pinnedSet, ax as planOf, ay as plannerPlan, az as portLabelBox, aA as portLabelsOf, aB as rankGaps, aC as seededOrder, aD as settle, aE as sizeToBody, aF as titleIdOf, aG as translated, aH as untilSettled } from './types-BbHunLXm.js';
3
+ import { P as PortsOptions, A as AvoidInput, a as AvoidRouter, b as AvoidOptions, c as AvoidRoutes, d as PlaceLabelsOptions, F as ForceOptions } from './layout.entry-CH9gc0CY.js';
4
+ export { e as AVOID_DEFAULTS, f as AvoidEdge, g as AvoidEnd, h as AvoidLabel, i as AvoidObstacle, j as AvoidPort, k as AvoidUpdateOptions, C as COMPASS, D as DEFAULT_PORTS, l as ForceBody, m as ForceRelaxation, n as Forest, L as LabelPlacements, o as LayeredPlan, p as PlaceLabel, q as PlaceLabelsInput, r as PlaceRoute, s as backEdges, t as chain, u as createAvoidRouter, v as edgeHops, w as footprintNode, x as force, y as forceRelaxation, z as forestOf, B as labelCenter, E as layered, G as layeredPlan, H as outlinePolyline, I as placeLabels, J as portOf, K as portSitesOf, M as portsOf, N as portsOnOutline, O as ranksByLength, Q as ranksOf, R as rayHit, S as routeHolds, T as tree } from './layout.entry-CH9gc0CY.js';
5
+ import { Vec2, ActionDeps, Action, InvocationCtx, TargetPredicate, GestureBinding, Contribution, DerivedDep, Path, SceneRegistry, paintsLayer, PoseDescriptor, ChromeState, CommandFill, CommandStroke, CursorSpec, Affordance, Stroke, Tool, Op, AddNodeSpec, RectPose, NodeId, Scene, LayoutStrategy, ContainerBounds, RenderLayer, TransformFollower, PlacedPage, Bounds as Bounds$3, GatedLayer, Fill, NodeShapeEntry, Paint, View, SelectionApi } from '@weasel-js/core';
6
+ import { Vec2 as Vec2$1, Path as Path$2 } from '@weasel-js/core/math';
7
+ import { c as DataEdge, a as DiagramData, b as DiagramSceneOptions, f as DiagramSpec, g as EdgeEnd, N as NodeStyle, h as DiagramSceneData, i as DiagramEdge, O as OffPageSplit, D as DiagramTheme, j as DataContainer, E as EdgeStyle, d as DataNode } from './dataTypes-B-iEwKZp.js';
8
+ export { A as ANCHOR_DERIVE_POSE, k as DEFAULT_LANE_SIZE, l as DEFAULT_POOL_ACROSS, m as DIAGRAM_ANCHOR, n as DIAGRAM_GROUP, o as DIAGRAM_ROLES, p as DIAGRAM_THEME_KEY, q as DataGroup, r as DataLane, s as DataMark, t as DiagramAnchor, u as DiagramDerivePose, v as DiagramFont, w as DiagramMark, x as DiagramRole, e as DiagramRouter, y as DiagramTextStyle, z as EDGE_STROKE_WIDTH, G as GROUP_DERIVE_POSE, B as GroupPoseOptions, L as LANE_STROKE_WIDTH, C as NODE_STROKE_WIDTH, F as OffPageTag, H as anchorDerivePose, I as boxAround, J as diagramAnchorOf, K as diagramEdgeOf, M as diagramGroupOf, P as diagramMarkOf, Q as groupDerivePose, R as layoutOwnsPort, S as layoutOwnsRoute, T as layoutWritesRoute, U as markShape, V as offPageTagId, W as offPageTagOf, X as registerMarkShape, Y as rowTextStyle } from './dataTypes-B-iEwKZp.js';
9
+ import { IconRef } from '@weasel-js/icons';
10
+ import { Path as Path$1, Placement } from '@weasel-js/geom';
5
11
  import { EasingFn } from '@weasel-js/animator';
6
12
  import * as react from 'react';
7
- import '@weasel-js/geom';
13
+ import { ReactNode } from 'react';
8
14
  import '@weasel-js/simulation';
9
15
 
16
+ /** The scene node id `diagramScene` gives an edge: its `id` when set, else one
17
+ * built from its ends, ports, and label. Two edges differing in any of those
18
+ * get different ids, an empty port or label included: a `.`, `>`, `:`, `/` or
19
+ * `\` in one of them is escaped with a backslash. */
20
+ declare const edgeIdOf: (e: DataEdge) => string;
21
+
22
+ /** Every spec carries an id — a node's own, `<id>/<k>` for its text,
23
+ * `<id>/mark:<i>` for its marks, `<edge id>/label`, a group's own and
24
+ * `<group id>/label`, a region's own and `<region id>/title` — so a later call's
25
+ * specs can be reconciled against this one's. Throws on a repeated id among
26
+ * nodes, groups, containers and lanes, which names two things as one. An edge whose
27
+ * end is not a node is dropped, and so is a repeat of an earlier edge with
28
+ * the same ends, ports and label: it would draw exactly on top of the first. */
29
+ declare function diagramScene<TLayer extends string>(data: DiagramData, opts: DiagramSceneOptions<TLayer> & {
30
+ layer: TLayer;
31
+ }): DiagramSpec<TLayer>[];
32
+ declare function diagramScene(data: DiagramData, opts?: DiagramSceneOptions): DiagramSpec[];
33
+
10
34
  /**
11
- * `DiagramEdge` — a connection between two participants.
12
- *
13
- * An edge is an ordinary leaf scene node with `dependsOn: [from, to]` and a
14
- * `derivePath` that runs a **router**. Being a scene node rather than a
15
- * plugin-owned render layer buys selection, hit-testing, hover, styling,
16
- * z-order, SVG export, undo, and copy/paste. The cost is that an edge costs
17
- * what a node costs — right for tens to hundreds of edges, wrong for a
18
- * 10k-edge force graph.
19
- *
20
- * **Author-dragged waypoints are data on the edge and the router routes
21
- * through them**, so a moved endpoint still re-routes.
22
- *
23
- * Arrowheads are not here. They are stroke markers, the same
24
- * `markerStart` / `markerEnd` any other stroke carries.
35
+ * The `'slide'` look of a reorder: the carried item under the pointer and the
36
+ * others in the places they would take, published as pose overrides so
37
+ * everything that derives its pose from them follows.
25
38
  */
26
39
 
27
- /** Where an edge attaches at one end. */
28
- interface EdgeEnd {
29
- /** The port to leave from, when the endpoint declares one. Falls back to
30
- * the nearest port, so an edge drawn before ports were thought about still
31
- * meets the shape. */
32
- port?: string;
40
+ type Box$3 = {
41
+ x: number;
42
+ y: number;
43
+ width: number;
44
+ height: number;
45
+ };
46
+
47
+ /**
48
+ * Reorder: dragging one item of a drawn sequence — boxes in a row, rows in a
49
+ * column, the members of a group — to another place in it. The item follows
50
+ * the pointer along the sequence's axis and lands in the gap nearest its
51
+ * middle. A `'bar'` drag marks that gap with an insertion bar; a `'slide'`
52
+ * drag slides the other items into the places they would take. Either way
53
+ * the release hands the move to a commit, and nothing is written to the scene.
54
+ */
55
+
56
+ /** The action that drags an item of a sequence to another place in it. */
57
+ declare const REORDER_ACTION_ID = "diagram.reorder";
58
+ /** One item of a sequence, in world units. */
59
+ interface ReorderItem {
60
+ /** The scene node drawn for it. */
61
+ id: string;
62
+ bounds: Box$3;
63
+ /** Where a press picks it up. Default `bounds`; `null` never picks it up, though it keeps its gaps. */
64
+ grip?: Box$3 | null;
65
+ /** The scene nodes that move with it, in either `show` mode. Default `[id]`. */
66
+ carries?: readonly string[];
33
67
  }
34
- /** The trait on an edge's `data`, under the same key participants use. */
35
- interface DiagramEdge {
36
- from: EdgeEnd;
37
- to: EdgeEnd;
38
- /** Registry key for the router. Resolved by whoever builds the edge's
39
- * `derivePath`; unknown keys fall back to `straight`. */
40
- router?: string;
41
- /** Points in world coordinates the route must pass through, in order. The
42
- * author owns these; the router owns everything between them. */
43
- waypoints?: readonly Vec2[];
68
+ /** A place an item can land: before `items[index]`, or after the last at `items.length`. */
69
+ interface ReorderGap {
70
+ index: number;
71
+ /** The insertion bar's two ends. */
72
+ a: Vec2;
73
+ b: Vec2;
74
+ }
75
+ /** A drawn sequence: its items in order along `axis`, and the gaps between them. */
76
+ interface ReorderSlots {
77
+ axis: 'x' | 'y';
78
+ items: readonly ReorderItem[];
79
+ gaps: readonly ReorderGap[];
80
+ }
81
+ /** The item at index `from` dropped in gap `to`, and every item's id in the order that leaves. */
82
+ interface ReorderMove {
83
+ id: string;
84
+ from: number;
85
+ to: number;
86
+ order: readonly string[];
44
87
  }
45
- /** What a router is given: the two resolved ends, and the author's waypoints
46
- * between them. */
88
+ /** Options for {@link createReorderAction}. */
89
+ interface ReorderOptions {
90
+ /** Default {@link REORDER_ACTION_ID}. */
91
+ id?: string;
92
+ /** Default 'Reorder'. */
93
+ label?: string;
94
+ /** The sequence a press at `at` picks from, as drawn now, or `null` when there is none. */
95
+ slots: (deps: ActionDeps, at: Vec2) => ReorderSlots | null;
96
+ /** Deps `slots` reads beyond `scene`. */
97
+ requires?: Action['requires'];
98
+ /**
99
+ * `'bar'` (default) carries the item and draws an insertion bar at its
100
+ * gap. `'slide'` carries everything each item `carries` as pose overrides,
101
+ * so what derives from them follows, and slides the others into place; the
102
+ * overrides stay after a commit until the scene next changes.
103
+ */
104
+ show?: 'bar' | 'slide';
105
+ /** Whether a drop may land. The bar draws refused, or nothing slides, where not. Default: every drop. */
106
+ canDrop?: (move: ReorderMove) => boolean;
107
+ /** Called once, on release over a gap that is not the item's own and that `canDrop` allows. */
108
+ commit: (move: ReorderMove, ctx: InvocationCtx) => void;
109
+ }
110
+ /**
111
+ * The slots of items laid out in order along `axis`: a gap halfway between
112
+ * each pair, its bar spanning both across the axis, and one beyond each end,
113
+ * as far out as the nearest interior gap's half, or `END_GAP / 2` with none.
114
+ */
115
+ declare function sequenceSlots(axis: 'x' | 'y', items: readonly ReorderItem[]): ReorderSlots;
116
+ /** The `diagram.reorder` action: an ongoing drag carrying one item of a sequence. */
117
+ declare function createReorderAction(opts: ReorderOptions): Action;
118
+ /** The binding that starts a reorder: a drag pressed on `on`, by default anywhere; the action declines off an item's grip. */
119
+ declare function reorderBinding(actionId?: string, on?: TargetPredicate): GestureBinding;
120
+ /** The reorder action and its binding, to pass as `ambient`. */
121
+ declare function reorderContribution(opts: ReorderOptions & {
122
+ on?: TargetPredicate;
123
+ }): Contribution;
124
+
125
+ /**
126
+ * The routers an edge is drawn with: functions from two resolved ends and the
127
+ * waypoints between them to the points the edge runs through. `edge` resolves
128
+ * the ends and calls one by the key the edge names.
129
+ */
130
+
131
+ /** What a router is given: the two resolved ends, the author's waypoints
132
+ * between them, and the route stored on the edge, when it holds one. */
47
133
  interface RouteRequest {
48
134
  from: Port;
49
135
  to: Port;
50
- waypoints: readonly Vec2[];
136
+ waypoints: readonly Vec2$1[];
137
+ route?: readonly Vec2$1[] | undefined;
51
138
  }
52
139
  /** A router returns the points the edge runs through, `from.point` first and
53
140
  * `to.point` last. */
54
- type Router = (req: RouteRequest) => readonly Vec2[];
141
+ type Router = (req: RouteRequest) => readonly Vec2$1[];
55
142
  /** The straight run between the two ends, through any waypoints. */
56
143
  declare const straight: Router;
57
144
  /**
@@ -73,15 +160,36 @@ declare const orthogonal: Router;
73
160
  * same thing.
74
161
  */
75
162
  declare const bezier: Router;
163
+ /**
164
+ * The route the obstacle-avoiding router stored on the edge, while it still
165
+ * fits the ends and passes every waypoint; else `orthogonal` through the stops,
166
+ * so an end moved by something that did not reroute still draws sensibly.
167
+ * The route itself is computed at edit time (`useAvoidRouting`).
168
+ */
169
+ declare const avoid: Router;
76
170
  /** The routers this package ships. A consumer's own go in the same shape. */
77
171
  declare const ROUTERS: Readonly<Record<string, Router>>;
78
- /** The edge trait on a node's data, or `null`. */
79
- declare function diagramEdgeOf(node: {
80
- data: unknown;
81
- }): DiagramEdge | null;
172
+
173
+ /**
174
+ * `DiagramEdge` — a connection between two participants.
175
+ *
176
+ * An edge is an ordinary leaf scene node with `dependsOn: [from, to]` and a
177
+ * `derivePath` that runs a **router**. Being a scene node rather than a
178
+ * plugin-owned render layer buys selection, hit-testing, hover, styling,
179
+ * z-order, SVG export, undo, and copy/paste. The cost is that an edge costs
180
+ * what a node costs — right for tens to hundreds of edges, wrong for a
181
+ * 10k-edge force graph.
182
+ *
183
+ * **Author-dragged waypoints are data on the edge and the router routes
184
+ * through them**, so a moved endpoint still re-routes.
185
+ *
186
+ * Arrowheads are not here. They are stroke markers, the same
187
+ * `markerStart` / `markerEnd` any other stroke carries.
188
+ */
189
+
82
190
  /**
83
- * The port an end resolves to: the one it named, else the port facing the
84
- * other end most directly.
191
+ * The port an end resolves to: the one it named, at whichever of its places
192
+ * faces `toward` most directly, else the port facing `toward` most directly.
85
193
  *
86
194
  * "Facing" rather than "nearest": a port on the far side of a wide node can be
87
195
  * closer in a straight line than the one pointing at the target.
@@ -102,12 +210,36 @@ interface EdgeRouteOptions<TPose> extends PortsOptions<TPose> {
102
210
  * sides {@link selfLoop} picks, and where the author set no waypoints the
103
211
  * router is handed that rule's point outside the node as one.
104
212
  *
213
+ * An edge carrying `hops` bows over each one that still lies on its route.
214
+ *
105
215
  * Returns `null` — nothing to draw — when the node is not an edge, when either
106
216
  * dependency is gone, or when an endpoint offers no ports at all.
107
217
  */
108
218
  declare function edgeDerivePath<TPose>(opts?: EdgeRouteOptions<TPose>): (node: {
109
219
  data: unknown;
110
220
  }, deps: readonly (DerivedDep<TPose> | undefined)[]) => Path | null;
221
+ /** An edge's route as {@link edgeDerivePath} draws it, before it becomes a path. */
222
+ interface ResolvedRoute {
223
+ /** The two ends, resolved. */
224
+ from: Port;
225
+ to: Port;
226
+ /** What the router was handed between them: the author's waypoints, or a
227
+ * self-loop's turning point. */
228
+ waypoints: readonly Vec2[];
229
+ /** The router's answer, `from.point` first and `to.point` last. */
230
+ points: readonly Vec2[];
231
+ /** Set while the edge is split across pages (`DiagramEdge.offPage`): the
232
+ * two runs drawn in place of `points`, one out of `from` to its tag's
233
+ * side and one from the other tag's side into `to`. */
234
+ stubs?: readonly [readonly Vec2[], readonly Vec2[]];
235
+ }
236
+ /** How far a split edge's stub runs out of its shape, in world units. */
237
+ declare const OFF_PAGE_STUB = 24;
238
+ /** Routes an edge between its two dependencies the way {@link edgeDerivePath}
239
+ * does, answering the route itself; null where that draws nothing. */
240
+ declare function edgeRouter<TPose>(opts?: EdgeRouteOptions<TPose>): (node: {
241
+ data: unknown;
242
+ }, deps: readonly (DerivedDep<TPose> | undefined)[]) => ResolvedRoute | null;
111
243
  /** Registry key for {@link EDGE_DERIVE_PATH}. */
112
244
  declare const DIAGRAM_EDGE = "diagram:edge";
113
245
  /** The default edge router, as one stable function reference so `toJSON` can
@@ -153,7 +285,23 @@ declare const PORT_AFFORDANCE_KIND: "layer:diagram-ports";
153
285
  interface ParticipantPose<TPose> {
154
286
  node: DiagramNodeLike;
155
287
  pose: TPose;
288
+ /** Not drawn: on a hidden layer, or hidden on its own or by an ancestor.
289
+ * `sceneParticipants` answers it from the scene's `nodeGates`. */
290
+ hidden?: boolean;
291
+ /** Out of reach: locked, or on a locked layer. */
292
+ locked?: boolean;
293
+ /** The scene layer the node is painted on, which the asking view may not
294
+ * paint (`ChromeState.layerIsPainted`, `ViewApi.layerIsPainted`). */
295
+ layer?: string;
156
296
  }
297
+ /** Whether a participant's ports are drawn, grabbed and landed on. A hidden
298
+ * or locked node gets none, as it gets no selection or hover chrome either,
299
+ * and nor does one on a layer the asking view does not paint. */
300
+ declare function offersPorts(p: {
301
+ hidden?: boolean;
302
+ locked?: boolean;
303
+ layer?: string;
304
+ }, view?: Parameters<typeof paintsLayer>[0]): boolean;
157
305
  /** Where the affordance gets its participants. A thunk rather than a scene so
158
306
  * the geometry is testable without one, and so a consumer whose participants
159
307
  * come from somewhere else needs no adapter. */
@@ -178,13 +326,21 @@ interface PortAffordanceOptions<TPose> {
178
326
  /** Which participants show their ports. Default: all of them. Gate on
179
327
  * selection or hover by reading `state`. */
180
328
  shows?: (node: DiagramNodeLike, state: ChromeState) => boolean;
329
+ /** Which of a participant's ports show. Default: all of them. A port
330
+ * this turns away is not painted or grabbable, and passed with the connect
331
+ * options (as `diagramPorts` and `DiagramView` do), no connect lands on it. */
332
+ showsPort?: (port: Port) => boolean;
181
333
  /** Screen-pixel hit radius. Default 8, the kit's `HANDLE_BASE_PX`. */
182
334
  hitRadiusPx?: number;
183
- /** Screen-pixel side of the painted square. Default 7. Omit `paint` entirely
184
- * by passing 0 — a port the consumer draws itself is still hittable. */
335
+ /** Screen-pixel size of the painted mark: a square's side, or a circle's
336
+ * diameter. Default 7. Omit `paint` entirely by passing 0 — a port the
337
+ * consumer draws itself is still hittable. */
185
338
  sizePx?: number;
186
- fill?: CommandFill;
339
+ /** One fill for every port, or a function of the port — its `type`, say. */
340
+ fill?: CommandFill | ((port: Port) => CommandFill);
187
341
  stroke?: CommandStroke;
342
+ /** Default `'square'`. */
343
+ shape?: 'square' | 'circle';
188
344
  cursor?: CursorSpec;
189
345
  /** Default `'exclusive'` on pointer gestures: a drag from a port is a
190
346
  * connect, never a move of the node underneath it. */
@@ -201,6 +357,36 @@ declare function portScratchOf(hit: {
201
357
  */
202
358
  declare function createPortAffordance<TPose>(participants: ParticipantSource<TPose>, opts?: PortAffordanceOptions<TPose>): Affordance;
203
359
 
360
+ /** An end on a participant's body rather than on one of its ports. `point` is
361
+ * where the pointer was, in world coordinates. */
362
+ interface BodyEnd {
363
+ kind: 'body';
364
+ nodeId: string;
365
+ point: Vec2$1;
366
+ }
367
+ /** Either end of a connect. */
368
+ type ConnectEnd = Port | BodyEnd;
369
+ /** Whether a connect end lands on a node's body rather than a port. */
370
+ declare function isBodyEnd(end: ConnectEnd): end is BodyEnd;
371
+ /** A body under the pointer, and the participant it belongs to. */
372
+ interface BodyHit<TPose> {
373
+ end: BodyEnd;
374
+ participant: ParticipantPose<TPose>;
375
+ }
376
+ /** The view a connect started in, which decides what layers it may reach. */
377
+ type ConnectView = Parameters<typeof offersPorts>[1];
378
+ /**
379
+ * The topmost participant whose body contains `at`, or `null`.
380
+ *
381
+ * Its outline when it declares one, else its bounds, both taken in the pose's
382
+ * unrotated frame. Edges, edge labels and group boxes are not bodies, and nor
383
+ * is anything the reader does not take as a participant or that `offersPorts`
384
+ * turns away.
385
+ */
386
+ declare function bodyAt<TPose>(participants: ParticipantSource<TPose>, at: Vec2$1, opts?: PortsOptions<TPose> & {
387
+ view?: ConnectView;
388
+ }): BodyHit<TPose> | null;
389
+
204
390
  /**
205
391
  * The connect gesture — dragging one port onto another to author an edge.
206
392
  *
@@ -217,17 +403,26 @@ declare function createPortAffordance<TPose>(participants: ParticipantSource<TPo
217
403
  *
218
404
  * One resolver answers both the live preview and the commit, so the preview
219
405
  * cannot lie about what releasing will do.
406
+ *
407
+ * With `bodies`, a release over a participant's body away from any port lands
408
+ * on the body (`connectTargets`); with `startFrom: 'body'`, so can the press.
220
409
  */
221
410
 
222
411
  /** The default action id, and what {@link connectBinding} points at. */
223
412
  declare const CONNECT_ACTION_ID = "diagram.connect";
224
- /** Whether an edge may run from `from` to `to`. */
225
- type CanConnect = (from: Port, to: Port) => boolean;
226
- /** The edge a finished connect describes. Both ends are resolved ports, so a
227
- * consumer minting the node has nothing left to look up. */
413
+ /** The edge end a reconnect is carrying: the scene id of the edge, and which end. */
414
+ interface MovingEnd {
415
+ edge: string;
416
+ end: 'from' | 'to';
417
+ }
418
+ /** Whether an edge may run from `from` to `to`. `moving` is the end being
419
+ * dragged when the edge already exists, and absent for a new connect. */
420
+ type CanConnect = (from: ConnectEnd, to: ConnectEnd, moving?: MovingEnd) => boolean;
421
+ /** The edge a finished connect describes. Each end is a resolved port, or a
422
+ * body whose port the edge picks each time it is routed. */
228
423
  interface PendingEdge {
229
- from: Port;
230
- to: Port;
424
+ from: ConnectEnd;
425
+ to: ConnectEnd;
231
426
  /** Registry key for the router the new edge should name. */
232
427
  router: string;
233
428
  }
@@ -236,7 +431,8 @@ interface PendingEdge {
236
431
  * declare a `type` must declare the same one.
237
432
  *
238
433
  * A port with no type joins anything. Two different ports on the *same node*
239
- * may be joined: a self-edge is meaningful in a state machine.
434
+ * may be joined: a self-edge is meaningful in a state machine. A body is
435
+ * untyped, and never joins its own node.
240
436
  */
241
437
  declare const defaultCanConnect: CanConnect;
242
438
  /** Options for {@link createConnectAction}. Only `participants` is required. */
@@ -250,6 +446,10 @@ interface ConnectActionOptions<TPose> {
250
446
  geometry?: PoseDescriptor<TPose>;
251
447
  /** Default {@link defaultCanConnect}. */
252
448
  canConnect?: CanConnect;
449
+ /** Which ports a connect may land on: a port this turns away is never a
450
+ * target. The port affordance's option of the same name, so a port that is
451
+ * not shown cannot be dropped onto. Default: all of them. */
452
+ showsPort?: (port: Port) => boolean;
253
453
  /** How near the pointer must come to a port, in world units, before the
254
454
  * edge snaps to it. Default 16. */
255
455
  snapRadius?: number;
@@ -257,13 +457,22 @@ interface ConnectActionOptions<TPose> {
257
457
  * Default `'straight'`. */
258
458
  router?: string;
259
459
  routers?: Readonly<Record<string, Router>>;
460
+ /** A release over a participant's body, with no port in reach, lands on the
461
+ * body. Default false. */
462
+ bodies?: boolean;
463
+ /** `'body'`: a press that is not on a port starts from the participant
464
+ * under it. Default `'port'`, where such a press falls through. */
465
+ startFrom?: 'port' | 'body';
260
466
  /**
261
- * Mints and commits the edge. Called once, on release over a valid port.
467
+ * Mints and commits the edge. Called once, on release over a valid target.
262
468
  *
263
469
  * Defaults to {@link commitEdgeToScene} against `deps.scene`. Override it to
264
470
  * choose the edge node's data, its layer, or its stroke.
265
471
  */
266
472
  commit?: (edge: PendingEdge, ctx: InvocationCtx) => void;
473
+ /** What the default commit draws the edge with. Default {@link DEFAULT_EDGE_STROKE}.
474
+ * Ignored when `commit` is given. */
475
+ edgeStroke?: Stroke;
267
476
  }
268
477
  /** What a connect-authored edge is drawn with, when the consumer overrides
269
478
  * nothing. */
@@ -289,21 +498,722 @@ declare const GRAB_PORT_ACTION_ID = "diagram.grabPort";
289
498
  * happens.
290
499
  */
291
500
  declare function grabPortAction(id?: string): Action;
292
- /** The two bindings that keep a port's claim from dropping the press. */
293
- declare function grabPortBindings(actionId?: string): GestureBinding[];
501
+ /** The two bindings that keep a port's claim from dropping the press. `kind`
502
+ * names another affordance that claims the press protocol the same way. */
503
+ declare function grabPortBindings(actionId?: string, kind?: string): GestureBinding[];
294
504
  /**
295
505
  * The default commit: one leaf node carrying the edge trait, added to
296
506
  * `deps.scene`. One `add` is one history entry, so the edge undoes in one.
297
507
  *
298
508
  * The edge lands on the **source node's** layer rather than the bottom one.
299
509
  */
300
- declare function commitEdgeToScene(edge: PendingEdge, ctx: InvocationCtx): void;
510
+ declare function commitEdgeToScene(edge: PendingEdge, ctx: InvocationCtx, opts?: {
511
+ stroke?: Stroke;
512
+ }): void;
301
513
  /**
302
514
  * The `diagram.connect` action: an ongoing drag whose preview is an ephemeral
303
515
  * edge and whose commit is one op batch.
304
516
  */
305
517
  declare function createConnectAction<TPose>(opts: ConnectActionOptions<TPose>): Action;
306
518
 
519
+ /** The connector tool's id. */
520
+ declare const CONNECTOR_TOOL_ID = "diagram.connector";
521
+ /** The action the connector tool binds a drag to. */
522
+ declare const CONNECTOR_ACTION_ID = "diagram.connectorDraw";
523
+ /** The connector tool's definition, outside React. `id`, `startFrom` and
524
+ * `bodies` are the tool's own. */
525
+ declare function connectorTool<TPose>(opts: ConnectActionOptions<TPose>): Tool;
526
+ /** {@link connectorTool}, rebuilt when one of its options changes rather than
527
+ * when the bag holding them does. */
528
+ declare function useConnectorTool<TPose>(opts: ConnectActionOptions<TPose>): Tool;
529
+
530
+ /**
531
+ * Stencils: the shapes a palette offers, as data, and what one becomes when it
532
+ * is drawn — a `buildBody` body whose rows are ordinary text nodes.
533
+ */
534
+
535
+ /** One shape a palette offers. `size` is what a click places; `rows` default
536
+ * to one empty label, so the body has a text node to type into. `icon` is its
537
+ * tool's glyph in a palette. */
538
+ interface DiagramStencil {
539
+ id: string;
540
+ label: string;
541
+ outline: Outline;
542
+ size: {
543
+ width: number;
544
+ height: number;
545
+ };
546
+ rows?: readonly Row[];
547
+ icon?: IconRef;
548
+ }
549
+ /** The basic flowchart symbols. */
550
+ declare const FLOWCHART_STENCILS: readonly DiagramStencil[];
551
+ /** The insert kind a stencil's tool passes to the `insert` dep. */
552
+ declare const stencilKind: (id: string) => string;
553
+ /** The stencil id an insert kind names, or `null` for a kind that is no stencil's. */
554
+ declare function stencilIdOf(kind: string): string | null;
555
+ type Bounds$1 = {
556
+ x: number;
557
+ y: number;
558
+ width: number;
559
+ height: number;
560
+ };
561
+ /**
562
+ * The ops that insert `stencil` at `bounds`: its container first, then one
563
+ * text node per text row. Applied as one batch, they are one undo entry.
564
+ * `style` colors the body and its text; default `diagramScene`'s node style.
565
+ * `font` is the face its text rows fall back on; default 12px sans-serif.
566
+ * `parent` is the container the body goes in; default the top level.
567
+ */
568
+ declare function stencilBuild<TLayer extends string>(stencil: DiagramStencil, bounds: Bounds$1, opts: {
569
+ layer: TLayer;
570
+ newId: () => string;
571
+ measure?: MeasureRowText;
572
+ style?: NodeStyle;
573
+ font?: {
574
+ fontFamily: string;
575
+ fontSize: number;
576
+ };
577
+ parent?: string | null;
578
+ }): {
579
+ id: string;
580
+ ops: Op[];
581
+ };
582
+
583
+ /**
584
+ * The node specs of a region — a container, a pool, or a lane — and its title,
585
+ * which a stencil drawn on the canvas and a `DiagramData` container both build
586
+ * from.
587
+ */
588
+
589
+ /** A region's node spec, always with an id. */
590
+ type RegionSpec<TLayer extends string> = AddNodeSpec<DiagramSceneData, TLayer, RectPose> & {
591
+ id: NodeId;
592
+ };
593
+ /** Options for `containerBuild`. */
594
+ interface ContainerBuildOptions<TLayer extends string> {
595
+ layer: TLayer;
596
+ newId: () => string;
597
+ /** The box's fill, stroke and title colors. Default `diagramScene`'s node style. */
598
+ style?: NodeStyle;
599
+ /** The container the new one goes in. Default the top level. */
600
+ parent?: string | null;
601
+ /** A pool's header colors and its lanes' bodies in turn. Default `style` for both. */
602
+ laneStyles?: {
603
+ header: NodeStyle;
604
+ bodies: readonly NodeStyle[];
605
+ };
606
+ }
607
+ /** Options for {@link regionSpecs}. */
608
+ interface RegionOptions<TLayer extends string> {
609
+ id: string;
610
+ layer: TLayer;
611
+ /** Default the top level. */
612
+ parent?: string | null;
613
+ /** Default `diagramScene`'s node style. */
614
+ style?: NodeStyle;
615
+ /** Marks a region whose box is fitted to its members each time it is built from data. */
616
+ fitted?: boolean;
617
+ /** The title's family. Default sans-serif. */
618
+ fontFamily?: string;
619
+ }
620
+ /** The node specs of one region, and its title unless `title` is null. */
621
+ declare function regionSpecs<TLayer extends string>(role: ContainerRole, axis: 'x' | 'y', pose: RectPose, title: string | null, opts: RegionOptions<TLayer>): RegionSpec<TLayer>[];
622
+ /** The lane specs a new pool at `at` starts with. */
623
+ declare function firstLanes<TLayer extends string>(poolId: string, axis: 'x' | 'y', at: RectPose, opts: ContainerBuildOptions<TLayer>): RegionSpec<TLayer>[];
624
+
625
+ /**
626
+ * The container stencils a palette offers, what one becomes when it is drawn,
627
+ * and the edits on one: adding a lane to a pool, and releasing a container's
628
+ * members.
629
+ */
630
+
631
+ /** One container a palette offers. A pool stacks its lanes along `axis`. */
632
+ interface ContainerStencil {
633
+ id: string;
634
+ label: string;
635
+ role: 'container' | 'pool';
636
+ axis?: 'x' | 'y';
637
+ size: {
638
+ width: number;
639
+ height: number;
640
+ };
641
+ /** The glyph a palette draws on its button. */
642
+ icon?: IconRef;
643
+ }
644
+ /** A titled box, and pools of rows and of columns. */
645
+ declare const CONTAINER_STENCILS: readonly ContainerStencil[];
646
+ type Bounds = {
647
+ x: number;
648
+ y: number;
649
+ width: number;
650
+ height: number;
651
+ };
652
+ type AnyScene$3 = Scene<unknown, string, unknown>;
653
+ /** The ops that insert `stencil` at `bounds`: the region and its title, and a
654
+ * pool's first lanes. Applied as one batch, they are one undo entry. */
655
+ declare function containerBuild<TLayer extends string>(stencil: ContainerStencil, bounds: Bounds, opts: ContainerBuildOptions<TLayer>): {
656
+ id: string;
657
+ ops: Op[];
658
+ };
659
+ /** The axis a pool stacks its lanes along, read off its header. */
660
+ declare const poolAxisOf: (pool: DiagramContainer) => "x" | "y";
661
+ /** The lanes of `poolId`, in the order they stack. */
662
+ declare function lanesOf(scene: AnyScene$3, poolId: string): NodeId[];
663
+ /**
664
+ * Add a lane to `poolId` before the lane at `index`, or at the end of the
665
+ * stack, as one history entry. The pool grows to hold it. Returns the new
666
+ * lane's id, or null when `poolId` is not a pool.
667
+ */
668
+ declare function addLane(scene: AnyScene$3, poolId: string, index?: number, style?: NodeStyle): string | null;
669
+ /**
670
+ * Remove container `id` and keep its members, which take its place in its
671
+ * parent, as one history entry. A pool's members are its lanes' members, and
672
+ * a lane's go past its pool. Connectors on what is removed go with it.
673
+ */
674
+ declare function releaseMembers(scene: AnyScene$3, id: string): void;
675
+
676
+ /** The tool that draws `stencil`, a shape's or a container's: its id is the stencil's insert kind. */
677
+ declare function stencilTool(stencil: Pick<DiagramStencil, 'id' | 'label' | 'icon'>): Tool;
678
+ /** {@link stencilTool}, rebuilt only when the stencil changes. */
679
+ declare function useStencilTool(stencil: Pick<DiagramStencil, 'id' | 'label' | 'icon'>): Tool;
680
+ /** Options for {@link useStencilInsert}. */
681
+ interface StencilInsertOptions {
682
+ /** The layer bodies are inserted on. Default: the scene's first layer. */
683
+ layer?: string;
684
+ measure?: MeasureRowText;
685
+ /** The body's fill, stroke and text colors. Default `diagramScene`'s node style. */
686
+ style?: NodeStyle;
687
+ /** The face the body's text rows fall back on. Default 12px sans-serif. */
688
+ font?: {
689
+ fontFamily: string;
690
+ fontSize: number;
691
+ };
692
+ /** Container stencils to draw beside the shapes (`CONTAINER_STENCILS`). */
693
+ containers?: readonly ContainerStencil[];
694
+ /** Container stencils' box and title colors. Default `style`. */
695
+ containerStyle?: NodeStyle;
696
+ /** A new pool's header colors and its lanes' bodies in turn. Default `containerStyle`. */
697
+ laneStyles?: {
698
+ header: NodeStyle;
699
+ bodies: readonly NodeStyle[];
700
+ };
701
+ }
702
+ /**
703
+ * Registers the `insert` dep for stencil kinds. Any other kind goes to the
704
+ * `insert` dep this one displaced, so core's rect, ellipse and text tools
705
+ * keep working beside the stencils. A stencil drawn inside a container or a
706
+ * lane becomes its member (`diagramDropParentAt`).
707
+ */
708
+ declare function useStencilInsert(stencils: readonly DiagramStencil[], opts?: StencilInsertOptions): void;
709
+
710
+ type Box$2 = {
711
+ x: number;
712
+ y: number;
713
+ width: number;
714
+ height: number;
715
+ };
716
+ /** Where a container's title sits: its header strip, turned a quarter to run
717
+ * up a left header. */
718
+ declare function titlePose(bounds: Box$2, header: ContainerHeader | undefined): RectPose;
719
+
720
+ /**
721
+ * `diagramContainerLayout` — free placement under a header. A member stays
722
+ * wherever it is dropped or the container is resized to; only the title is
723
+ * placed, in the header.
724
+ *
725
+ * A strategy sees ids and poses, never data, so it cannot tell a lane from a
726
+ * shape. Which nodes a container admits is `diagramCanDropInto`'s call.
727
+ */
728
+
729
+ /** Options for {@link diagramContainerLayout}. */
730
+ interface ContainerLayoutOptions {
731
+ /** Where the title sits; matches the container trait's own `header`. */
732
+ header?: ContainerHeader;
733
+ }
734
+ /** A free-placement layout whose drops land in the body below or beside `header`. */
735
+ declare function diagramContainerLayout(opts?: ContainerLayoutOptions): LayoutStrategy<RectPose>;
736
+
737
+ /**
738
+ * `laneStackLayout` — a pool's lanes, stacked along one axis in the order they
739
+ * sit and stretched across the body past the header. The pool's size along
740
+ * the stack is the sum of its lanes; its size across is the author's.
741
+ *
742
+ * Like every strategy it sees ids and poses only: the title is told apart by
743
+ * its name, and which nodes a pool admits (lanes) is `diagramCanDropInto`'s call.
744
+ */
745
+
746
+ /** Options for {@link laneStackLayout}. */
747
+ interface LaneStackOptions {
748
+ /** The axis lanes stack along: `'y'` for a pool of rows, `'x'` for columns. */
749
+ axis: 'x' | 'y';
750
+ /** The header's depth, across the stack. Default {@link POOL_HEADER_SIZE}. */
751
+ headerSize?: number;
752
+ }
753
+ /** A pool header's default depth. */
754
+ declare const POOL_HEADER_SIZE = 32;
755
+ /** The least a lane is along the stack. */
756
+ declare const MIN_LANE_SIZE = 40;
757
+ /** The header a pool stacking along `axis` has: across the stack, at its start. */
758
+ declare const poolHeader: (axis: "x" | "y", size?: number) => ContainerHeader;
759
+ /** Where lanes of the given sizes sit, in order, in a pool at `bounds`. */
760
+ declare function stackedLanes(axis: 'x' | 'y', bounds: ContainerBounds, header: ContainerHeader, lanes: readonly {
761
+ id: string;
762
+ size: number;
763
+ }[]): Map<string, RectPose>;
764
+ /** A pool stacking its lanes along `axis`. */
765
+ declare function laneStackLayout(opts: LaneStackOptions): LayoutStrategy<RectPose>;
766
+
767
+ /**
768
+ * The container layouts by registry key, as stable references so a saved
769
+ * scene finds them again (`withDiagramRegistry`).
770
+ */
771
+
772
+ /** A plain container's header. */
773
+ declare const CONTAINER_HEADER: ContainerHeader;
774
+ /** A lane's header depth, across its pool's stack. */
775
+ declare const LANE_HEADER_SIZE = 28;
776
+ /** The header a lane of a pool stacking along `axis` has. */
777
+ declare const laneHeader: (axis: "x" | "y") => ContainerHeader;
778
+ /** A titled container's layout key: free placement in the body below its header. */
779
+ declare const DIAGRAM_CONTAINER_LAYOUT = "diagram:container";
780
+ /** A pool's layout key when its lanes stack as rows, top to bottom. */
781
+ declare const DIAGRAM_POOL_ROWS_LAYOUT = "diagram:pool-rows";
782
+ /** A pool's layout key when its lanes stack as columns, left to right. */
783
+ declare const DIAGRAM_POOL_COLUMNS_LAYOUT = "diagram:pool-columns";
784
+ /** The layout key of a lane in a pool of rows: free placement beside its left header. */
785
+ declare const DIAGRAM_LANE_ROWS_LAYOUT = "diagram:lane-rows";
786
+ /** The layout key of a lane in a pool of columns: free placement below its top header. */
787
+ declare const DIAGRAM_LANE_COLUMNS_LAYOUT = "diagram:lane-columns";
788
+ /** Every container layout this package registers, by key. */
789
+ declare const CONTAINER_LAYOUTS: Readonly<Record<string, LayoutStrategy<RectPose>>>;
790
+ /** The layout key and header for a container of `role`; a pool or lane's
791
+ * follow the axis its pool stacks along. */
792
+ declare function containerShape(role: ContainerRole, axis?: 'x' | 'y'): {
793
+ layout: string;
794
+ header: ContainerHeader;
795
+ };
796
+
797
+ type SceneLike = {
798
+ get(id: never): {
799
+ id: string;
800
+ kind: 'leaf' | 'container';
801
+ data: unknown;
802
+ } | undefined;
803
+ };
804
+ /**
805
+ * The `canDropInto` dep for a diagram scene. A container or a lane takes
806
+ * shapes and other containers, a pool takes only lanes, and a lane goes
807
+ * nowhere but a pool. A stencil body, an edge, or a label takes nothing, and
808
+ * edges and labels are never dropped in: they stay where they are, drawn from
809
+ * what they are attached to. Any other container — a plain group — takes
810
+ * anything but a lane.
811
+ */
812
+ declare function diagramCanDropInto(scene: SceneLike): (parent: string, ids: readonly string[]) => boolean;
813
+ /** What {@link diagramDropParentAt} walks. */
814
+ interface DropParentScene {
815
+ readonly roots: readonly string[];
816
+ childrenOf(id: never): readonly string[];
817
+ get(id: never): {
818
+ id: string;
819
+ kind: 'leaf' | 'container';
820
+ data: unknown;
821
+ pose: unknown;
822
+ } | undefined;
823
+ }
824
+ /**
825
+ * The innermost container or lane whose body holds `point`, that would admit
826
+ * a new node of `role` (`null` for a shape): where an insert at `point` goes.
827
+ * Null for the top level — always so for a pool.
828
+ */
829
+ declare function diagramDropParentAt(scene: DropParentScene, point: {
830
+ x: number;
831
+ y: number;
832
+ }, role: ContainerRole | null): string | null;
833
+
834
+ /**
835
+ * The lane affordances on every pool: the boundary after each lane, which a
836
+ * drag moves to resize that lane, and the add-lane button past the end of the
837
+ * stack. Built the way the edge-end handles are: regions with a `null`
838
+ * `targetId`, composed into a layer whose id is the kind a press reports.
839
+ */
840
+
841
+ /** The layer id the lane affordances are composed into. */
842
+ declare const LANE_LAYER_ID = "diagram-lanes";
843
+ /** The affordance kind a press on a lane affordance reports. */
844
+ declare const LANE_AFFORDANCE_KIND: "layer:diagram-lanes";
845
+ /** What a press on a lane affordance hands the action: the boundary after
846
+ * `laneId`, or, with no lane, the add-lane button. */
847
+ interface LaneScratch {
848
+ targetId: string;
849
+ poolId: string;
850
+ laneId?: string;
851
+ }
852
+ /** Read a lane press's scratch back off the hit an action was handed. */
853
+ declare function laneScratchOf(hit: {
854
+ payload?: unknown;
855
+ } | null | undefined): LaneScratch | null;
856
+ type AnyScene$2 = Scene<unknown, string, unknown>;
857
+ /** A pool as the affordances see it: its box, the axis it stacks along, and its lanes in order. */
858
+ interface PoolLanes {
859
+ id: string;
860
+ axis: 'x' | 'y';
861
+ pose: RectPose;
862
+ lanes: {
863
+ id: string;
864
+ pose: RectPose;
865
+ }[];
866
+ }
867
+ /** Every pool in `scene` that is drawn and not locked. */
868
+ declare function poolsOf(scene: AnyScene$2): PoolLanes[];
869
+ /** Options for {@link laneLayer}. */
870
+ interface LaneLayerOptions {
871
+ /** Screen-pixel reach of a boundary either side of it. Default 4. */
872
+ hitRadiusPx?: number;
873
+ /** Screen-pixel diameter of the add-lane button. Default 14; 0 hides it. */
874
+ addSizePx?: number;
875
+ fill?: CommandFill;
876
+ stroke?: CommandStroke;
877
+ }
878
+ /** The affordance: a boundary region after each lane of each pool, and an add-lane button per pool. */
879
+ declare function createLaneAffordance(scene: AnyScene$2, opts?: LaneLayerOptions): Affordance;
880
+ /** The composed layer, for `CanvasExtensionApi.registerLayer`. */
881
+ declare function laneLayer(scene: AnyScene$2, opts?: LaneLayerOptions): RenderLayer<unknown>;
882
+
883
+ /**
884
+ * The container actions: dragging the boundary after a lane resizes it, the
885
+ * add-lane button adds one at the end of the stack, and Release members
886
+ * removes a container and keeps what it holds. The two lane gestures take a
887
+ * swappable commit; the default writes the scene.
888
+ */
889
+
890
+ /** The action that drags a lane's boundary. */
891
+ declare const LANE_RESIZE_ACTION_ID = "diagram.resizeLane";
892
+ /** The action the add-lane button runs. */
893
+ declare const ADD_LANE_ACTION_ID = "diagram.addLane";
894
+ /** The command that removes the selected containers and keeps their members. */
895
+ declare const RELEASE_MEMBERS_ACTION_ID = "diagram.releaseMembers";
896
+ type AnyScene$1 = Scene<unknown, string, unknown>;
897
+ /** A lane resized: its new size along its pool's stack. */
898
+ interface LaneResize {
899
+ poolId: string;
900
+ laneId: string;
901
+ size: number;
902
+ }
903
+ /** The default commit: the lane's and the pool's new size, as one history
904
+ * entry labeled "Resize lane". The pool's layout restacks the lanes after it. */
905
+ declare function commitLaneResizeToScene(resize: LaneResize, ctx: InvocationCtx): void;
906
+ /** Where everything stands with the lane at `index` of `pool` resized to `size`: the
907
+ * lane, its title, the pool and its title, and every later lane with what it holds. */
908
+ declare function laneResizeFrame(scene: AnyScene$1, pool: PoolLanes, index: number, size: number): Map<string, RectPose>;
909
+ /** Options for the container actions. */
910
+ interface LaneActionOptions extends LaneLayerOptions {
911
+ scene: AnyScene$1;
912
+ /** The selected ids, which Release members reads. */
913
+ selected?: () => readonly string[];
914
+ /** Defaults to {@link commitLaneResizeToScene}. */
915
+ commitResize?: (resize: LaneResize, ctx: InvocationCtx) => void;
916
+ /** Defaults to `addLane` on `deps.scene`, at the end of the stack. */
917
+ commitAddLane?: (poolId: string, ctx: InvocationCtx) => void;
918
+ /** Runs for each selected region in place of `releaseMembers`. */
919
+ commitRelease?: (id: string) => void;
920
+ }
921
+ /** The `diagram.resizeLane` action: an ongoing drag moving one lane's far boundary. */
922
+ declare function createLaneResizeAction(opts: LaneActionOptions): Action;
923
+ /** The `diagram.addLane` action: the add-lane button's click. */
924
+ declare function createAddLaneAction(opts: LaneActionOptions): Action;
925
+ /** The `diagram.releaseMembers` command: removes each selected container and
926
+ * keeps what it holds, in one history entry. */
927
+ declare function createReleaseMembersAction(opts: LaneActionOptions): Action;
928
+ /**
929
+ * Both halves of container editing: the lane layer to `registerLayer`, and
930
+ * the contribution to pass as `ambient`, which carries the lane boundary
931
+ * drag, the add-lane click, and the `diagram.releaseMembers` command. Like
932
+ * `diagramPorts`, one without the other fails quietly.
933
+ */
934
+ declare function diagramContainers(opts: LaneActionOptions): {
935
+ layer: RenderLayer<unknown>;
936
+ contribution: Contribution;
937
+ };
938
+
939
+ /**
940
+ * A double-click on a region's header: the action that reports which region's
941
+ * title to edit, and its binding.
942
+ */
943
+
944
+ /** The action a double-click on a region's header runs. */
945
+ declare const EDIT_CONTAINER_TITLE_ACTION_ID = "diagram.editContainerTitle";
946
+ /** The container, pool, or lane whose header holds `at`: the node under it, or a region around that. */
947
+ declare function regionHeaderAt(deps: ActionDeps | undefined, at: {
948
+ x: number;
949
+ y: number;
950
+ } | undefined): string | null;
951
+ /** The action that hands `commit` the region whose header a double-click landed on. It declines anywhere else. */
952
+ declare function editContainerTitleAction(commit: (id: string) => void): Action;
953
+ /** A double-click on a node's body; the action declines unless it lands in a region's header. */
954
+ declare function editContainerTitleBinding(): GestureBinding;
955
+
956
+ /**
957
+ * Moving an edge label along and beside its edge.
958
+ *
959
+ * The label layer (`labelDragLayer`) claims the press; this action moves the
960
+ * label. The drag previews the label's own data at the station the pointer
961
+ * proposes, and the pose that data derives, so the preview stands where the
962
+ * commit will.
963
+ */
964
+
965
+ /** The action that drags an edge label. */
966
+ declare const MOVE_LABEL_ACTION_ID = "diagram.moveLabel";
967
+ /** A label placed: where it now sits on its edge, or `null` to reset it to {@link LABEL_PLACEMENT}. */
968
+ interface LabelEdit {
969
+ labelId: string;
970
+ edgeId: string;
971
+ placement: DiagramLabel | null;
972
+ }
973
+ /** Options for {@link createLabelDragAction}. */
974
+ interface LabelDragOptions {
975
+ /** Defaults to {@link commitLabelToScene} against `deps.scene`. */
976
+ commit?: (edit: LabelEdit, ctx: InvocationCtx) => void;
977
+ id?: string;
978
+ }
979
+ /** `data` with its label trait at `spot`, owned by the author from now on:
980
+ * placement's `placed` is dropped, and placement won't move it again. */
981
+ declare function movedLabelData(data: unknown, spot: LabelSpot): Record<string, unknown>;
982
+ /** The default commit: the label's placement in `data.diagram.label`, as one
983
+ * history entry labeled "Move label", or "Reset label" for a `null` placement. */
984
+ declare function commitLabelToScene(edit: LabelEdit, ctx: InvocationCtx): void;
985
+ /** The `diagram.moveLabel` action: an ongoing drag moving one edge label along and beside its edge. */
986
+ declare function createLabelDragAction(opts?: LabelDragOptions): Action;
987
+
988
+ /**
989
+ * Handles on the ends of a selected edge — what makes an edge's end grabbable,
990
+ * so a drag can carry it onto another shape (`reconnect`).
991
+ *
992
+ * Built the way the port affordance is: point regions with a `null`
993
+ * `targetId` and no `hitKind`, composed into a layer whose id is the kind a
994
+ * press reports. See `portAffordance` for why both matter.
995
+ */
996
+
997
+ /** The layer id the edge-end handles are composed into. */
998
+ declare const EDGE_END_LAYER_ID = "diagram-edge-ends";
999
+ /** The affordance kind a press on an edge-end handle reports. */
1000
+ declare const EDGE_END_AFFORDANCE_KIND: "layer:diagram-edge-ends";
1001
+ /** What a press on an edge-end handle hands the reconnect action, as
1002
+ * `InvocationCtx.drag.affordance.payload`. */
1003
+ interface EdgeEndScratch {
1004
+ targetId: string;
1005
+ edgeId: string;
1006
+ end: 'from' | 'to';
1007
+ }
1008
+ /** Read an edge-end press's scratch back off the hit an action was handed. */
1009
+ declare function edgeEndScratchOf(hit: {
1010
+ payload?: unknown;
1011
+ } | null | undefined): EdgeEndScratch | null;
1012
+ /** An edge as it stands: its trait, the participants at its two ends, and
1013
+ * where its routed path starts and ends. */
1014
+ interface EdgeEnds<TPose> {
1015
+ edge: ParticipantPose<TPose>;
1016
+ trait: DiagramEdge;
1017
+ from: ParticipantPose<TPose>;
1018
+ to: ParticipantPose<TPose>;
1019
+ points: {
1020
+ from: Vec2$1;
1021
+ to: Vec2$1;
1022
+ };
1023
+ /** The route as the edge's own `derivePath` draws it. */
1024
+ route: ResolvedRoute;
1025
+ }
1026
+ /** Options shared by the edge-end affordance and the reconnect action. */
1027
+ interface EdgeEndOptions<TPose> extends PortsOptions<TPose> {
1028
+ routers?: Readonly<Record<string, Router>>;
1029
+ }
1030
+ /** Options for {@link createEdgeEndAffordance}. */
1031
+ interface EdgeEndAffordanceOptions<TPose> extends EdgeEndOptions<TPose> {
1032
+ /** Also the chrome-caps visibility id. Default {@link EDGE_END_LAYER_ID}. */
1033
+ id?: string;
1034
+ /** Screen-pixel hit radius. Default 8. */
1035
+ hitRadiusPx?: number;
1036
+ /** Screen-pixel side of the painted square. Default 8; 0 paints nothing. */
1037
+ sizePx?: number;
1038
+ fill?: CommandFill;
1039
+ stroke?: CommandStroke;
1040
+ cursor?: CursorSpec;
1041
+ }
1042
+ /** The affordance: one point region on each end of each selected edge. */
1043
+ declare function createEdgeEndAffordance<TPose>(participants: ParticipantSource<TPose>, selected: () => readonly string[], opts?: EdgeEndAffordanceOptions<TPose>): Affordance;
1044
+ /** The composed layer, for `CanvasExtensionApi.registerLayer`. Register it
1045
+ * after the port layer: the last-registered layer is hit first, and an edge's
1046
+ * end sits on a port. */
1047
+ declare function edgeEndLayer<TPose>(participants: ParticipantSource<TPose>, selected: () => readonly string[], opts?: EdgeEndAffordanceOptions<TPose>): RenderLayer<unknown>;
1048
+
1049
+ /**
1050
+ * Route editing — dragging a selected edge's waypoints and segments.
1051
+ *
1052
+ * The route handles (`waypointLayer`) claim the press; this action reshapes
1053
+ * the route. The drag previews the edge's own data with the new waypoints,
1054
+ * so its `derivePath` draws the preview exactly as the commit will.
1055
+ */
1056
+
1057
+ /** The action that drags a route handle. */
1058
+ declare const ROUTE_EDIT_ACTION_ID = "diagram.editRoute";
1059
+ /** An edge's route edited: its waypoints as they now stand. */
1060
+ interface RouteEdit {
1061
+ edgeId: string;
1062
+ waypoints: readonly Vec2$1[];
1063
+ }
1064
+ /** Options for the route-editing actions: the drag, the double-click that removes, and Reset route. */
1065
+ interface RouteEditOptions<TPose> extends EdgeEndOptions<TPose> {
1066
+ participants: ParticipantSource<TPose>;
1067
+ /** The selected edge ids, whose routes show handles. */
1068
+ selected: () => readonly string[];
1069
+ /** Screen pixels within which a dragged handle lines up with a neighbor
1070
+ * or a port's axis. Default 6. */
1071
+ snapPx?: number;
1072
+ /** Screen-pixel reach of a handle, as the handle layer's `hitRadiusPx`. Default 7. */
1073
+ hitRadiusPx?: number;
1074
+ /** Defaults to {@link commitRouteToScene} against `deps.scene`. */
1075
+ commit?: (edit: RouteEdit, ctx: InvocationCtx) => void;
1076
+ id?: string;
1077
+ }
1078
+ /** `data` with its edge trait routed through `waypoints`: owned by the author
1079
+ * from now on, so layout's mark is dropped, and no waypoints at all when there are none. */
1080
+ declare function routedData(data: unknown, trait: DiagramEdge, waypoints: readonly Vec2$1[]): Record<string, unknown>;
1081
+ /** The default commit: the edge's new waypoints in `data.diagram`, as one history entry labeled "Edit route". */
1082
+ declare function commitRouteToScene(edit: RouteEdit, ctx: InvocationCtx): void;
1083
+ /** The `diagram.editRoute` action: an ongoing drag reshaping one edge's route. */
1084
+ declare function createRouteEditAction<TPose>(opts: RouteEditOptions<TPose>): Action;
1085
+
1086
+ /** Polyline arithmetic shared by the routers and route editing. */
1087
+
1088
+ /** `points` without repeats, and without any interior point lying straight
1089
+ * between its neighbors. The first and last always stay. */
1090
+ declare function simplifyStops(points: readonly Vec2$1[]): Vec2$1[];
1091
+
1092
+ /**
1093
+ * Waypoint editing as pure math on an edge's route.
1094
+ *
1095
+ * The **stops** are the points a route must pass through: its `from` end, the
1096
+ * author's waypoints, and its `to` end. The **drawn** route is what the router
1097
+ * made of them. Every shipped router passes through each stop exactly, so the
1098
+ * drawn polyline splits at the stops and a leg's middle is found on it.
1099
+ *
1100
+ * Each edit answers the edge's new waypoints, never the whole route.
1101
+ */
1102
+
1103
+ /** A handle a selected edge shows along its route. `at` is where it sits, in world units. */
1104
+ type RouteHandle =
1105
+ /** Waypoint `index`: dragging moves it. */
1106
+ {
1107
+ kind: 'vertex';
1108
+ index: number;
1109
+ at: Vec2$1;
1110
+ }
1111
+ /** The middle of leg `leg`, between stops `leg` and `leg + 1`: dragging inserts a waypoint there. */
1112
+ | {
1113
+ kind: 'insert';
1114
+ leg: number;
1115
+ at: Vec2$1;
1116
+ }
1117
+ /** Segment `index` of an orthogonal route, which runs along `axis`: dragging slides it across. */
1118
+ | {
1119
+ kind: 'segment';
1120
+ index: number;
1121
+ axis: 'x' | 'y';
1122
+ at: Vec2$1;
1123
+ };
1124
+ /** The axis a segment runs along, or null when it is a point or slanted. */
1125
+ declare function segmentAxis(a: Vec2$1, b: Vec2$1): 'x' | 'y' | null;
1126
+ /** The handles an edge shows: a bar per segment under `orthogonal` and
1127
+ * `avoid`, else a dot per waypoint and a hollow dot per leg. */
1128
+ declare function routeHandles(drawn: readonly Vec2$1[], stops: readonly Vec2$1[], router: Router): RouteHandle[];
1129
+ /** The waypoints with waypoint `index` moved to `to`. */
1130
+ declare function dragVertex(stops: readonly Vec2$1[], index: number, to: Vec2$1): Vec2$1[];
1131
+ /** The waypoints with one at `at` inserted on leg `leg`: it becomes waypoint `leg`. */
1132
+ declare function insertWaypoint(stops: readonly Vec2$1[], leg: number, at: Vec2$1): Vec2$1[];
1133
+ /** The waypoints without waypoint `index`. */
1134
+ declare function removeWaypoint(stops: readonly Vec2$1[], index: number): Vec2$1[];
1135
+ /**
1136
+ * The waypoints of `drawn`, an orthogonal route, with segment `index` slid
1137
+ * `offset` across its axis: every interior bend of the new route, since the
1138
+ * orthogonal router recomputes elbows between stops. A segment touching a
1139
+ * port keeps a short stub there and jogs over, so the port end stays square.
1140
+ */
1141
+ declare function dragSegment(drawn: readonly Vec2$1[], index: number, offset: number): Vec2$1[];
1142
+ /**
1143
+ * The waypoints of an `avoid` route with segment `index` of `drawn` slid
1144
+ * `offset` across its axis and pinned there: its two ends join the author's
1145
+ * waypoints, in route order, and the router keeps the rest. A waypoint at one
1146
+ * of its ends moves with it, and a segment meeting a port jogs off it so the
1147
+ * port end stays square.
1148
+ */
1149
+ declare function pinSegment(drawn: readonly Vec2$1[], stops: readonly Vec2$1[], index: number, offset: number): Vec2$1[];
1150
+ /** The waypoints of an `avoid` route without those at either end of segment
1151
+ * `index`, which hands the segment back to the router; null when neither end is one. */
1152
+ declare function unpinSegment(drawn: readonly Vec2$1[], stops: readonly Vec2$1[], index: number): Vec2$1[] | null;
1153
+ /**
1154
+ * The waypoints with segment `index` straightened away: its neighbors run in
1155
+ * parallel, and the one touching no port slides onto the other's line. Null
1156
+ * when it is the first or last segment, or both neighbors touch a port.
1157
+ */
1158
+ declare function removeSegment(drawn: readonly Vec2$1[], index: number): Vec2$1[] | null;
1159
+
1160
+ /**
1161
+ * Handles along a selected edge's route — what makes its waypoints and
1162
+ * segments grabbable, so a drag can reshape the route (`waypointAction`).
1163
+ *
1164
+ * Built the way the edge-end handles are: point regions with a `null`
1165
+ * `targetId` and no `hitKind`, composed into a layer whose id is the kind a
1166
+ * press reports.
1167
+ */
1168
+
1169
+ /** The layer id the route handles are composed into. */
1170
+ declare const WAYPOINT_LAYER_ID = "diagram-waypoints";
1171
+ /** The affordance kind a press on a route handle reports. */
1172
+ declare const WAYPOINT_AFFORDANCE_KIND: "layer:diagram-waypoints";
1173
+ /** What a press on a route handle hands the route-edit actions, as the hit's `payload`. */
1174
+ interface WaypointScratch {
1175
+ targetId: string;
1176
+ edgeId: string;
1177
+ handle: RouteHandle;
1178
+ }
1179
+ /** Read a route-handle press's scratch back off the hit an action was handed. */
1180
+ declare function waypointScratchOf(hit: {
1181
+ payload?: unknown;
1182
+ } | null | undefined): WaypointScratch | null;
1183
+ /** An edge's route as the handles read it: its resolved ends, its stops, the
1184
+ * route drawn through them, the router that drew it, and the handles it shows. */
1185
+ interface EdgeRouteState {
1186
+ from: Port;
1187
+ to: Port;
1188
+ stops: readonly Vec2$1[];
1189
+ drawn: readonly Vec2$1[];
1190
+ router: Router;
1191
+ handles: readonly RouteHandle[];
1192
+ }
1193
+ /** The route state of an edge whose ends `ends` resolved. */
1194
+ declare function routeStateOf(ends: EdgeEnds<unknown>, routers?: Readonly<Record<string, Router>>): EdgeRouteState;
1195
+ /** Options for {@link createWaypointAffordance}. */
1196
+ interface WaypointAffordanceOptions<TPose> extends EdgeEndOptions<TPose> {
1197
+ /** Also the chrome-caps visibility id. Default {@link WAYPOINT_LAYER_ID}. */
1198
+ id?: string;
1199
+ /** Screen-pixel hit radius. Default 7. */
1200
+ hitRadiusPx?: number;
1201
+ /** Screen-pixel diameter of a waypoint's dot; an insert dot is three
1202
+ * quarters of it, and a segment bar twice as long. Default 8; 0 paints nothing. */
1203
+ sizePx?: number;
1204
+ fill?: CommandFill;
1205
+ stroke?: CommandStroke;
1206
+ cursor?: CursorSpec;
1207
+ }
1208
+ /** A route handle's default screen-pixel hit radius. */
1209
+ declare const WAYPOINT_HIT_PX = 7;
1210
+ /** The affordance: a region on each route handle of each selected edge. */
1211
+ declare function createWaypointAffordance<TPose>(participants: ParticipantSource<TPose>, selected: () => readonly string[], opts?: WaypointAffordanceOptions<TPose>): Affordance;
1212
+ /** The composed layer, for `CanvasExtensionApi.registerLayer`. Register it
1213
+ * after the port layer and before the edge-end layer: the last registered is
1214
+ * hit first, and an edge's end handle must win over a handle beside it. */
1215
+ declare function waypointLayer<TPose>(participants: ParticipantSource<TPose>, selected: () => readonly string[], opts?: WaypointAffordanceOptions<TPose>): RenderLayer<unknown>;
1216
+
307
1217
  /**
308
1218
  * The plugin as a `Contribution` bundle — one object a consumer hands to
309
1219
  * `<SceneCanvas ambient={…}>`.
@@ -335,6 +1245,347 @@ declare function diagramPorts<TPose>(opts: DiagramContributionOptions<TPose>): {
335
1245
  layer: RenderLayer<unknown>;
336
1246
  contribution: Contribution;
337
1247
  };
1248
+ /** The action id that absorbs the rest of a press on a route handle. */
1249
+ declare const GRAB_WAYPOINT_ACTION_ID = "diagram.grabWaypoint";
1250
+ /**
1251
+ * Both halves of route editing: the handle layer to `registerLayer` — after
1252
+ * the port layer and before the edge-end layer, so an end handle wins over a
1253
+ * route handle beside it — and the contribution to pass as `ambient`, which
1254
+ * carries the drag, the double-click that removes, the
1255
+ * `diagram.resetRoute` command, the commands that set the selected
1256
+ * connectors' router (`SET_ROUTER_ACTION_IDS`), and the line jumps toggle
1257
+ * (`SET_HOPS_ACTION_ID`). Like `diagramPorts`, one without the other
1258
+ * fails quietly.
1259
+ */
1260
+ declare function diagramWaypoints<TPose>(opts: RouteEditOptions<TPose> & Omit<WaypointAffordanceOptions<TPose>, 'id'>): {
1261
+ layer: RenderLayer<unknown>;
1262
+ contribution: Contribution;
1263
+ };
1264
+ /** The action id that absorbs a press on an edge label, so it reaches neither marquee nor pan. */
1265
+ declare const GRAB_LABEL_ACTION_ID = "diagram.grabLabel";
1266
+ /** The action id that selects a clicked label's edge. */
1267
+ declare const SELECT_LABEL_EDGE_ACTION_ID = "diagram.selectLabelEdge";
1268
+ /**
1269
+ * Both halves of label dragging: the label layer to `registerLayer` — before
1270
+ * the port layer, so a port or a route handle wins over a label beside it —
1271
+ * and the contribution to pass as `ambient`, which carries the drag
1272
+ * (`diagram.moveLabel`), a click that selects the label's edge, and a
1273
+ * double-click that edits the label's text through
1274
+ * `EDIT_EDGE_LABEL_ACTION_ID`, which the host registers. Like `diagramPorts`,
1275
+ * one without the other fails quietly.
1276
+ */
1277
+ declare function diagramLabelDrag(opts: LabelDragOptions & {
1278
+ scene: Scene<unknown, string, unknown>;
1279
+ selected: () => readonly string[];
1280
+ cursor?: CursorSpec;
1281
+ }): {
1282
+ layer: RenderLayer<unknown>;
1283
+ contribution: Contribution;
1284
+ };
1285
+
1286
+ /**
1287
+ * The route edits that are not drags: a double-click on a route handle, and
1288
+ * the Reset route command.
1289
+ */
1290
+
1291
+ /** The action that removes a waypoint, straightens a segment, or unpins an
1292
+ * `avoid` connector's segment, on a double-click of its handle. */
1293
+ declare const REMOVE_WAYPOINT_ACTION_ID = "diagram.removeWaypoint";
1294
+ /** The command that clears the selected edges' waypoints. */
1295
+ declare const RESET_ROUTE_ACTION_ID = "diagram.resetRoute";
1296
+ /** The `diagram.removeWaypoint` action: a double-click on a waypoint's dot
1297
+ * removes it, and on a segment's bar straightens that jog away. Where it
1298
+ * would remove nothing it declines, so the double-click reaches whatever is
1299
+ * under the handle, an edge's label editing among them. */
1300
+ declare function createRemoveWaypointAction<TPose>(opts: RouteEditOptions<TPose>): Action;
1301
+ /** The `diagram.resetRoute` command: clears the selected edges' waypoints,
1302
+ * in one history entry when they commit to the scene. */
1303
+ declare function createResetRouteAction<TPose>(opts: RouteEditOptions<TPose>): Action;
1304
+
1305
+ /**
1306
+ * The commands that set the selected connectors' router: Around shapes,
1307
+ * Orthogonal, Straight, and Curved. Leaving `avoid` drops the stored route;
1308
+ * joining it leaves the route to the edit pass `useAvoidRouting` installs,
1309
+ * which routes the connectors in the same history entry.
1310
+ */
1311
+
1312
+ /** The router commands' ids, by router key. */
1313
+ declare const SET_ROUTER_ACTION_IDS: {
1314
+ readonly avoid: "diagram.router.avoid";
1315
+ readonly orthogonal: "diagram.router.orthogonal";
1316
+ readonly straight: "diagram.router.straight";
1317
+ readonly bezier: "diagram.router.bezier";
1318
+ };
1319
+ /** Each shipped router's name in a menu. */
1320
+ declare const ROUTER_LABELS: Readonly<Record<keyof typeof SET_ROUTER_ACTION_IDS, string>>;
1321
+ /** One connector's router changed. */
1322
+ interface RouterEdit {
1323
+ edgeId: string;
1324
+ router: string;
1325
+ }
1326
+ /** Options for {@link createSetRouterAction}. */
1327
+ interface SetRouterOptions<TPose> {
1328
+ participants: ParticipantSource<TPose>;
1329
+ /** The selected ids; the connectors among them are set. */
1330
+ selected: () => readonly string[];
1331
+ /** Defaults to {@link commitRouterToScene} against `deps.scene`. */
1332
+ commit?: (edit: RouterEdit, ctx: InvocationCtx) => void;
1333
+ }
1334
+ /** `data` with its edge trait on `router`, its stored route dropped. */
1335
+ declare function withRouter(data: unknown, trait: DiagramEdge, router: string): Record<string, unknown>;
1336
+ /** The default commit: the connector's `data.diagram.router`, written to the scene. */
1337
+ declare function commitRouterToScene(edit: RouterEdit, ctx: InvocationCtx): void;
1338
+ /** The command that puts the selected connectors on `router`, in one history
1339
+ * entry. Active while every selected connector is on it already. */
1340
+ declare function createSetRouterAction<TPose>(router: keyof typeof SET_ROUTER_ACTION_IDS, opts: SetRouterOptions<TPose>): Action;
1341
+ /** One command per shipped router, in menu order. */
1342
+ declare function routerActions<TPose>(opts: SetRouterOptions<TPose>): Action[];
1343
+
1344
+ /**
1345
+ * Waypoints ride along with a move: when a whole-node transform carries both
1346
+ * ends of an edge by the same offset, the edge's waypoints go with them.
1347
+ * Otherwise they stay put — a route the author placed is not bent by moving
1348
+ * one end.
1349
+ */
1350
+
1351
+ /**
1352
+ * The transform follower that carries waypoints along with a move, for the
1353
+ * `transformFollowers` dep (`useTransformFollower`). `geometry` reads a pose's
1354
+ * bounds; default `AUTO_POSE_DESCRIPTOR`.
1355
+ */
1356
+ declare function waypointFollower<TPose>(scene: Scene<unknown, string, TPose>, geometry?: PoseDescriptor<TPose>): TransformFollower;
1357
+
1358
+ /**
1359
+ * A diagram scene as the avoid router reads it: every participant, container,
1360
+ * pool, group box, and header as an obstacle, and every `avoid` connector not
1361
+ * split across pages, with the ports each end may use and its label. A split
1362
+ * connector's label, on its first stub, is an obstacle of its own.
1363
+ */
1364
+
1365
+ /** How a scene is read for routing. */
1366
+ interface AvoidSceneOptions<TPose> extends PortsOptions<TPose> {
1367
+ /** The router key whose connectors are routed. Default `'avoid'`. */
1368
+ routerKey?: string;
1369
+ }
1370
+ /** The id of a container's header obstacle. */
1371
+ declare const headerIdOf: (id: string) => string;
1372
+ /**
1373
+ * What the router reads off `scene`: its obstacles and its `avoid` connectors,
1374
+ * each node at the pose `poseOf` gives it, else the one the document holds.
1375
+ */
1376
+ declare function avoidSceneInput<TPose>(scene: Scene<unknown, string, TPose>, opts?: AvoidSceneOptions<TPose>, poseOf?: (id: string) => TPose | undefined): AvoidInput;
1377
+
1378
+ /**
1379
+ * Obstacle-avoiding routing on a live scene: a scene edit pass that reroutes
1380
+ * whatever an edit disturbed, in that edit's own history entry, and a
1381
+ * transform follower that reroutes the connectors near a dragged shape each
1382
+ * frame.
1383
+ */
1384
+
1385
+ /** Options for {@link installAvoidRouting} and `useAvoidRouting`. */
1386
+ interface AvoidRoutingOptions<TPose> extends AvoidSceneOptions<TPose>, AvoidOptions {
1387
+ /** World units one screen pixel covers now. A drag frame that moves
1388
+ * nothing further than this does no work. Default 1. */
1389
+ pixelSize?: () => number;
1390
+ /** Milliseconds one drag frame may spend rerouting. Default 4. */
1391
+ frameBudgetMs?: number;
1392
+ }
1393
+ /** Routing installed on a scene. */
1394
+ interface AvoidRouting {
1395
+ router: AvoidRouter;
1396
+ /** The drag half, for the `transformFollowers` dep (`useTransformFollower`). */
1397
+ follower: TransformFollower;
1398
+ /** Remove the edit pass. */
1399
+ dispose(): void;
1400
+ }
1401
+ /** The data writes that store `routes` on their edges, skipping any unchanged. */
1402
+ declare function routeDataOps(scene: Scene<unknown, string, unknown>, routes: AvoidRoutes): Op[];
1403
+ /**
1404
+ * Route `scene`'s `avoid` connectors around its shapes from now on. Every
1405
+ * live edit reroutes what it disturbed, in its own history entry; on install
1406
+ * nothing reroutes, and the routes the scene holds stand. A host without
1407
+ * React calls this; a component calls `useAvoidRouting`.
1408
+ */
1409
+ declare function installAvoidRouting<TPose>(scene: Scene<unknown, string, TPose>, opts?: AvoidRoutingOptions<TPose>): AvoidRouting;
1410
+
1411
+ /**
1412
+ * Where each of the diagram's scene edit passes runs among the others
1413
+ * (`scene.addEditPass`'s `order`). Each pass hears what the ones before it
1414
+ * wrote: markers are placed before routing sees them, routes before labels
1415
+ * dodge them, and line jumps last, on the routes as they end up.
1416
+ */
1417
+ declare const DIAGRAM_PASS_ORDER: {
1418
+ readonly offPage: 100;
1419
+ readonly avoid: 200;
1420
+ readonly labels: 300;
1421
+ readonly hops: 400;
1422
+ };
1423
+
1424
+ /**
1425
+ * Route `scene`'s `avoid` connectors around its shapes for the life of the
1426
+ * calling component: each edit reroutes what it disturbed in its own history
1427
+ * entry, and a drag reroutes the connectors near what it moves each frame.
1428
+ * Mount it as a child of `<SceneCanvas>`, where the drag's follower is heard,
1429
+ * after any `waypointFollower`, whose carried waypoints the drag routes through.
1430
+ * Options are read when the scene changes; `pixelSize` defaults to the
1431
+ * canvas's own view.
1432
+ */
1433
+ declare function useAvoidRouting<TPose>(scene: Scene<unknown, string, TPose>, opts?: AvoidRoutingOptions<TPose>): void;
1434
+
1435
+ /**
1436
+ * A function from specs to the same specs with each edge on `avoid` and
1437
+ * holding its route. It holds one router across calls, so each call reroutes
1438
+ * only the edges the change since the last one disturbed.
1439
+ */
1440
+ declare function createSpecRouter(options?: AvoidOptions): (specs: readonly DiagramSpec[]) => DiagramSpec[];
1441
+
1442
+ /**
1443
+ * A connector's route drawn with its hops: each one a half circle in place of
1444
+ * the stretch of route it spans.
1445
+ */
1446
+
1447
+ /**
1448
+ * The open path through `points`, bowing over each of `hops` in a half circle
1449
+ * of its radius. A hop more than half a unit off the route, or too near a bend
1450
+ * or an end for its half circle to fit on one segment, is stale and does not
1451
+ * draw; nor does one overlapping the hop before it.
1452
+ */
1453
+ declare function withHops(points: readonly Vec2$1[], hops: readonly EdgeHop[]): Path$1;
1454
+
1455
+ /**
1456
+ * Line jumps on a live scene: an edit pass that recomputes the hops an edit
1457
+ * disturbed, in that edit's own history entry, while the document's
1458
+ * line-jump setting is on.
1459
+ */
1460
+
1461
+ /** Options for {@link installHops} and `useHops`: how a connector routes, as
1462
+ * its own `derivePath` does. */
1463
+ type HopsOptions<TPose> = EdgeRouteOptions<TPose>;
1464
+ /** Line jumps installed on a scene. */
1465
+ interface Hops {
1466
+ /** The drag half, for the `transformFollowers` dep (`useTransformFollower`). */
1467
+ follower: TransformFollower;
1468
+ /** Remove the edit pass. */
1469
+ dispose(): void;
1470
+ }
1471
+ /**
1472
+ * Hop `scene`'s crossing connectors while its `HOPS_DOC_KEY` value is set.
1473
+ * Turning the value on or off, or changing its size, recomputes or clears
1474
+ * every connector in that same entry; any other edit recomputes the
1475
+ * connectors it rerouted and those whose routes meet theirs. Installing
1476
+ * writes nothing. A host without React calls this; a component calls `useHops`.
1477
+ */
1478
+ declare function installHops<TPose>(scene: Scene<unknown, string, TPose>, opts?: HopsOptions<TPose>): Hops;
1479
+
1480
+ /**
1481
+ * The transform follower that hides hops while a drag is in progress: each
1482
+ * frame previews the connectors it moves, and every connector hopping over
1483
+ * one, without their hops. A hop stays where the edit pass put it, so it
1484
+ * would sit off a moving route; on release the pass recomputes them in the
1485
+ * drag's entry. Register it after any follower that reroutes connectors, whose
1486
+ * previewed data it keeps.
1487
+ */
1488
+ declare function hopFollower<TPose>(scene: Scene<unknown, string, TPose>): TransformFollower;
1489
+
1490
+ /**
1491
+ * Hop `scene`'s crossing connectors for the life of the calling component,
1492
+ * while its line-jump setting is on: each edit recomputes the hops it
1493
+ * disturbed in its own history entry, and a drag hides the hops on what it
1494
+ * moves. Mount it as a child of `<SceneCanvas>`, after any routing hook, so its
1495
+ * follower hears the routes that one previews. Options are read when the scene
1496
+ * changes.
1497
+ */
1498
+ declare function useHops<TPose>(scene: Scene<unknown, string, TPose>, opts?: HopsOptions<TPose>): void;
1499
+
1500
+ /** The line jumps command's id. */
1501
+ declare const SET_HOPS_ACTION_ID = "diagram.hops";
1502
+ /** Options for {@link createSetHopsAction}. */
1503
+ interface SetHopsOptions {
1504
+ /** The radius hops take when the command turns them on. Default
1505
+ * {@link DEFAULT_HOP_SIZE}. */
1506
+ size?: number;
1507
+ }
1508
+ /**
1509
+ * The command that turns line jumps on for the whole document, or off, by
1510
+ * writing its `HOPS_DOC_KEY` value: one history entry, which the hop pass
1511
+ * (`useHops`) joins with every connector's hops. Active while they are on.
1512
+ */
1513
+ declare function createSetHopsAction(opts?: SetHopsOptions): Action;
1514
+
1515
+ /** A function from specs to the same specs with every edge's hops of radius
1516
+ * `r`, edges hopping those earlier in the list. An edge split across pages
1517
+ * takes no part. */
1518
+ declare function createSpecHops(r: number): (specs: readonly DiagramSpec[]) => DiagramSpec[];
1519
+
1520
+ /**
1521
+ * Reconnect — dragging a selected edge's end onto another port or shape.
1522
+ *
1523
+ * The edge-end handles (`edgeEndLayer`) claim the press; this action carries
1524
+ * the end. It lands where a connect from the edge's other end would land, by
1525
+ * the same resolver and the same `canConnect`, asked with the edge's from/to
1526
+ * order kept, so a reconnect can never make an edge a connect could not.
1527
+ */
1528
+
1529
+ /** The action that drags an edge end onto a new port or body. */
1530
+ declare const RECONNECT_ACTION_ID = "diagram.reconnect";
1531
+ /** The action id that absorbs a press on an edge-end handle. */
1532
+ declare const GRAB_EDGE_END_ACTION_ID = "diagram.grabEdgeEnd";
1533
+ /** One end of one edge, moved onto `target`. */
1534
+ interface EndChange {
1535
+ edgeId: string;
1536
+ end: 'from' | 'to';
1537
+ target: ConnectEnd;
1538
+ }
1539
+ /** Options for {@link createReconnectAction}. `bodies` defaults to true: an end
1540
+ * may be dropped on a shape's body. */
1541
+ interface ReconnectOptions<TPose> extends Omit<ConnectActionOptions<TPose>, 'commit' | 'startFrom'> {
1542
+ /** The selected edge ids whose ends show handles. */
1543
+ selected: () => readonly string[];
1544
+ /** Defaults to {@link commitReconnectToScene} against `deps.scene`. */
1545
+ commit?: (change: EndChange, ctx: InvocationCtx) => void;
1546
+ }
1547
+ /**
1548
+ * The default commit: rewrites the moved end in `data.diagram` — `{ port }`,
1549
+ * or `{}` for a body — and points the edge's `dependsOn` at the new node, as
1550
+ * one history entry.
1551
+ */
1552
+ declare function commitReconnectToScene(change: EndChange, ctx: InvocationCtx): void;
1553
+ /** The `diagram.reconnect` action: an ongoing drag carrying one edge end. */
1554
+ declare function createReconnectAction<TPose>(opts: ReconnectOptions<TPose>): Action;
1555
+ /** The binding that starts a reconnect: a drag pressed on an edge-end handle. */
1556
+ declare function reconnectBinding(actionId?: string): GestureBinding;
1557
+ /**
1558
+ * Both halves of reconnect: the handle layer to `registerLayer` — after the
1559
+ * port layer, since an edge's end sits on a port — and the contribution to
1560
+ * pass as `ambient`. Like `diagramPorts`, one without the other fails quietly.
1561
+ */
1562
+ declare function diagramEdgeEnds<TPose>(opts: ReconnectOptions<TPose> & Omit<EdgeEndAffordanceOptions<TPose>, 'id'>): {
1563
+ layer: RenderLayer<unknown>;
1564
+ contribution: Contribution;
1565
+ };
1566
+
1567
+ /**
1568
+ * Reordering a group marked `reorder`: a member dragged along that axis among
1569
+ * its siblings, which slide into the places they would take, or the selected
1570
+ * one stepped with Alt and an arrow key. Nothing is written: the host hears
1571
+ * the new order, writes it to its data, and layout keeps it.
1572
+ */
1573
+
1574
+ /** Alt and an arrow key: the selected member one place along. */
1575
+ declare const STEP_REORDER_ACTION_ID = "diagram.stepReorder";
1576
+ /** A reorderable group's members in their new order. */
1577
+ interface ReorderChange {
1578
+ group: string;
1579
+ order: readonly string[];
1580
+ }
1581
+ /** The members of the reorderable group a press at `at` carries one of, each
1582
+ * with everything drawn with it, or `null` off any such group. */
1583
+ declare function groupReorderSlots(deps: ActionDeps, at: Vec2): ReorderSlots | null;
1584
+ /** Steps the selected node's member one place toward the start (`-1`) or the end (`1`). */
1585
+ declare function createStepReorderAction(report: (change: ReorderChange) => void): Action;
1586
+ /** Everything `DiagramView` installs for `onReorder`: the reorder drag,
1587
+ * sliding, pressed on a node's body, and the step action. */
1588
+ declare function groupReorderContribution(report: (change: ReorderChange) => void): Contribution;
338
1589
 
339
1590
  /** How a self-edge with no ports named leaves its node and comes back. */
340
1591
  interface SelfLoop {
@@ -355,6 +1606,111 @@ interface SelfLoop {
355
1606
  */
356
1607
  declare function selfLoop(ports: readonly Port[], standoff: number): SelfLoop | null;
357
1608
 
1609
+ /**
1610
+ * Edge labels: the one place a label node's spec is made, and the action that
1611
+ * adds or edits an edge's label on a double-click.
1612
+ */
1613
+
1614
+ /** The box a label's text takes: measured width, and a height of the font size
1615
+ * whatever the measure reports. */
1616
+ declare function labelSize(text: string, style: RowTextStyle, measure?: MeasureRowText): {
1617
+ width: number;
1618
+ height: number;
1619
+ };
1620
+ /** Options for {@link edgeLabelSpec}. */
1621
+ interface EdgeLabelOptions<TLayer extends string> {
1622
+ layer: TLayer;
1623
+ /** Where along the edge it sits. Default {@link LABEL_PLACEMENT}. */
1624
+ label?: DiagramLabel;
1625
+ style?: RowTextStyle;
1626
+ /** Text color. */
1627
+ fill?: string;
1628
+ /** Sizes the box. Default: a per-character estimate. */
1629
+ measure?: MeasureRowText;
1630
+ }
1631
+ /** The label node for edge `edgeId`: a leaf that derives its pose from the edge's route. */
1632
+ declare function edgeLabelSpec<TLayer extends string>(edgeId: string, text: string, opts: EdgeLabelOptions<TLayer>): AddNodeSpec<unknown, TLayer, RectPose>;
1633
+ /**
1634
+ * Removes node `id` if it is an edge label left with no text, and says whether
1635
+ * it did. The default edit adds a label before its text is typed, so a host
1636
+ * passes this as its text edit's `onEnd` to drop one that ends empty.
1637
+ */
1638
+ declare function dropEmptyEdgeLabel(scene: Scene<unknown, string, unknown>, id: string): boolean;
1639
+ /** The action that adds or edits an edge's label. */
1640
+ declare const EDIT_EDGE_LABEL_ACTION_ID = "diagram.editEdgeLabel";
1641
+ /** Options for {@link editEdgeLabelAction}. */
1642
+ interface EditEdgeLabelOptions {
1643
+ /** Runs in place of the default add-then-edit. */
1644
+ commit?: (edgeId: string, ctx: InvocationCtx) => void;
1645
+ /** The face a new label is set in. Default the diagram's, two sizes down. Ignored when `commit` is given. */
1646
+ style?: RowTextStyle;
1647
+ /** A new label's text color. Ignored when `commit` is given. */
1648
+ fill?: string;
1649
+ }
1650
+ /**
1651
+ * Creates an edge's label, or edits the one it has, where a double-click
1652
+ * lands on the edge. It declines a double-click on anything else.
1653
+ *
1654
+ * An immediate invoker is handed no `InvocationCtx`, so `commit` gets one
1655
+ * built from the deps and the click point.
1656
+ */
1657
+ declare function editEdgeLabelAction(opts?: EditEdgeLabelOptions): Action;
1658
+ /** A double-click on a node's body; the action itself declines unless that node is an edge. */
1659
+ declare function editEdgeLabelBinding(actionId?: string): GestureBinding;
1660
+
1661
+ /**
1662
+ * What makes an edge label grabbable, so a drag can move it along and beside
1663
+ * its edge (`labelDragAction`).
1664
+ *
1665
+ * Built the way the route handles are: rect regions with a `null` `targetId`
1666
+ * and no paint, composed into a layer whose id is the kind a press reports.
1667
+ */
1668
+
1669
+ /** The layer id the label regions are composed into. */
1670
+ declare const LABEL_DRAG_LAYER_ID = "diagram-edge-labels";
1671
+ /** The affordance kind a press on an edge label reports. */
1672
+ declare const LABEL_DRAG_AFFORDANCE_KIND: "layer:diagram-edge-labels";
1673
+ /** What a press on an edge label hands the label actions, as the hit's `payload`. */
1674
+ interface LabelScratch {
1675
+ targetId: string;
1676
+ labelId: string;
1677
+ edgeId: string;
1678
+ }
1679
+ /** Read a label press's scratch back off the hit an action was handed. */
1680
+ declare function labelScratchOf(hit: {
1681
+ payload?: unknown;
1682
+ } | null | undefined): LabelScratch | null;
1683
+ /** A label a press can pick up: its box as the document places it, and its edge's route. */
1684
+ interface DraggableLabel {
1685
+ labelId: string;
1686
+ edgeId: string;
1687
+ box: Bounds$2;
1688
+ path: Path$2;
1689
+ }
1690
+ /** Every editable label in `scene` whose edge derives a path, in render order. */
1691
+ declare function draggableLabels(scene: Scene<unknown, string, unknown>): Iterable<DraggableLabel>;
1692
+ /** The topmost draggable label whose box holds `at`, as its press scratch. */
1693
+ declare function labelUnder(scene: Scene<unknown, string, unknown>, at: Vec2$1): LabelScratch | null;
1694
+ /** The composed layer, for `CanvasExtensionApi.registerLayer`. Register it
1695
+ * before the port layer: the last registered is hit first, and a port or a
1696
+ * route handle must win over a label beside it. */
1697
+ declare function labelDragLayer(scene: Scene<unknown, string, unknown>, opts?: {
1698
+ cursor?: CursorSpec;
1699
+ }): RenderLayer<unknown>;
1700
+
1701
+ /**
1702
+ * The label edit that is not a drag: the Reset label command.
1703
+ */
1704
+
1705
+ /** The command that puts the selected edges' dragged labels back where placement puts them. */
1706
+ declare const RESET_LABEL_ACTION_ID = "diagram.resetLabel";
1707
+ /** The `diagram.resetLabel` command: sets each selected edge's dragged label
1708
+ * back to `LABEL_PLACEMENT`, in one history entry when they commit to the scene. */
1709
+ declare function createResetLabelAction(opts: {
1710
+ selected: () => readonly string[];
1711
+ commit?: (edit: LabelEdit, ctx: InvocationCtx) => void;
1712
+ }): Action;
1713
+
358
1714
  /**
359
1715
  * A label on an edge: an ordinary leaf node that derives its *pose* from the
360
1716
  * route it sits on.
@@ -365,285 +1721,329 @@ declare function selfLoop(ports: readonly Port[], standoff: number): SelfLoop |
365
1721
  * data, styling, z-order and selection.
366
1722
  */
367
1723
 
368
- /** Where along an edge a label sits. */
369
- interface DiagramLabel {
370
- /** `'start'`, `'mid'` and `'end'` are 0, 0.5 and 1; a number is that
371
- * fraction of the route's length. */
372
- at: 'start' | 'mid' | 'end' | number;
373
- /** World units between the route and the label's near side, to the **left
374
- * of the direction of travel** — above a left-to-right edge. Default 0,
375
- * which centers the label on the line. */
376
- offset?: number;
377
- }
378
- /** The label trait on a node's data, or `null`. */
379
- declare function diagramLabelOf(node: {
380
- data: unknown;
381
- }): DiagramLabel | null;
382
1724
  /** Options for {@link labelDerivePose}. `geometry` defaults to the kit's
383
1725
  * `AUTO_POSE_DESCRIPTOR`. */
384
1726
  interface LabelPoseOptions<TPose> {
385
1727
  geometry?: PoseDescriptor<TPose>;
386
1728
  }
387
1729
  /**
388
- * A `derivePose` that stations a label along its dependency's path.
389
- *
390
- * Returns `null` — nothing derived, so the node keeps its authored pose —
391
- * when the node carries no label trait, when the dependency is gone, or when
392
- * the dependency derives no path. A label that snapped to the origin because
393
- * its edge was deleted is worse than one that stayed where the author left it.
1730
+ * A `derivePose` that stations a label along its dependency's path.
1731
+ *
1732
+ * Returns `null` — nothing derived, so the node keeps its authored pose —
1733
+ * when the node carries no label trait, when the dependency is gone, or when
1734
+ * the dependency derives no path. A label that snapped to the origin because
1735
+ * its edge was deleted is worse than one that stayed where the author left it.
1736
+ */
1737
+ declare function labelDerivePose<TPose>(opts?: LabelPoseOptions<TPose>): (node: {
1738
+ pose: TPose;
1739
+ data: unknown;
1740
+ }, deps: readonly (DerivedDep<TPose> | undefined)[]) => TPose | null;
1741
+ /** Registry key for {@link LABEL_DERIVE_POSE}. */
1742
+ declare const DIAGRAM_LABEL = "diagram:label";
1743
+ /** The default label derivation, as one stable function reference so `toJSON`
1744
+ * can find its key. */
1745
+ declare const LABEL_DERIVE_POSE: (node: {
1746
+ pose: unknown;
1747
+ data: unknown;
1748
+ }, deps: readonly (DerivedDep<unknown, unknown, string> | undefined)[]) => unknown;
1749
+
1750
+ /**
1751
+ * Label placement on a live scene: a scene edit pass that moves the labels
1752
+ * an edit covered to the nearest clear station, in that edit's own history
1753
+ * entry. It runs after routing, so labels dodge the routes the edit made.
1754
+ */
1755
+
1756
+ /** Options for {@link installLabelPlacement} and `useLabelPlacement`. */
1757
+ interface LabelPlacementOptions<TPose> extends PlaceLabelsOptions {
1758
+ geometry?: PoseDescriptor<TPose>;
1759
+ /** How a node's diagram trait is read. Default its own `data.diagram`. */
1760
+ read?: DiagramNodeReader;
1761
+ /** Sizes a label to the text an edit gives it. Default a per-character estimate. */
1762
+ measure?: MeasureRowText;
1763
+ }
1764
+ /** Placement installed on a scene. */
1765
+ interface LabelPlacement {
1766
+ /** Remove the edit pass. */
1767
+ dispose(): void;
1768
+ }
1769
+ /**
1770
+ * Move `scene`'s edge labels off whatever an edit leaves covering them, from
1771
+ * now on: each live edit places the labels it may have covered, in its own
1772
+ * history entry. Labels hold still during a drag and settle on release. A
1773
+ * host without React calls this; a component calls `useLabelPlacement`.
1774
+ */
1775
+ declare function installLabelPlacement<TPose>(scene: Scene<unknown, string, TPose>, opts?: LabelPlacementOptions<TPose>): LabelPlacement;
1776
+
1777
+ /**
1778
+ * Move `scene`'s edge labels off whatever an edit leaves covering them, for
1779
+ * the life of the calling component, each edit's moves in its own history
1780
+ * entry. Options are read when the scene changes.
1781
+ */
1782
+ declare function useLabelPlacement<TPose>(scene: Scene<unknown, string, TPose>, opts?: LabelPlacementOptions<TPose>): void;
1783
+
1784
+ /**
1785
+ * A function from specs to the same specs with each edge label placed off
1786
+ * whatever covers it. Every label is placed afresh, in id order, whenever
1787
+ * the shapes, routes, or labels change, and the last answer is reused while
1788
+ * they do not. Run it after any router, so labels dodge the routes drawn.
1789
+ */
1790
+ declare function createSpecLabelPlacer(opts?: PlaceLabelsOptions): (specs: readonly DiagramSpec[]) => DiagramSpec[];
1791
+
1792
+ /**
1793
+ * An off-page tag: a text leaf with a background that names the far page and
1794
+ * the reference, and stations itself past the tip of its connector's stub.
1795
+ */
1796
+
1797
+ /** How a tag is drawn: its face, its text color, and the box behind the text. */
1798
+ interface OffPageTagLook {
1799
+ style: RowTextStyle;
1800
+ fill: string;
1801
+ background: string;
1802
+ /** World units between the box and the text. Default {@link OFF_PAGE_TAG_PADDING}. */
1803
+ padding?: number;
1804
+ /** Sizes the text. Default: a per-character estimate. */
1805
+ measure?: MeasureRowText;
1806
+ }
1807
+ /** A tag's default padding, in world units. */
1808
+ declare const OFF_PAGE_TAG_PADDING = 3;
1809
+ /** A tag's look under `theme`: the theme's connector-label face and color, on its page color. */
1810
+ declare const offPageTagLook: (theme: DiagramTheme) => OffPageTagLook;
1811
+ /** What a tag reads: the far page's name and the connector's reference. */
1812
+ declare const offPageTagText: (pageName: string, ref: string) => string;
1813
+ /** What the tag at `end` of a split reads: the page at the other end, by name or place, else its raw id, and the reference. */
1814
+ declare function offPageFarText(pages: readonly PlacedPage[], split: OffPageSplit, end: 'from' | 'to'): string;
1815
+ /** The box a tag of `text` takes in `look`. */
1816
+ declare function offPageTagSize(text: string, look: OffPageTagLook): {
1817
+ width: number;
1818
+ height: number;
1819
+ };
1820
+ /** The tag `data` for end `end` of `edgeId`, reading `text` in `look`. */
1821
+ declare function offPageTagData(edgeId: string, end: 'from' | 'to', text: string, look: OffPageTagLook): {
1822
+ diagram: {
1823
+ offPageTag: {
1824
+ edge: string;
1825
+ end: "from" | "to";
1826
+ };
1827
+ };
1828
+ text: string;
1829
+ style: RowTextStyle;
1830
+ fill: {
1831
+ paint: {
1832
+ color: string;
1833
+ };
1834
+ };
1835
+ background: {
1836
+ paint: {
1837
+ color: string;
1838
+ };
1839
+ };
1840
+ padding: number;
1841
+ };
1842
+ /** The tag node at end `end` of connector `edgeId`, on `layer`: it derives its pose from the connector's stub. */
1843
+ declare function offPageTagSpec<TLayer extends string>(edgeId: string, end: 'from' | 'to', text: string, look: OffPageTagLook & {
1844
+ layer: TLayer;
1845
+ }): AddNodeSpec<unknown, TLayer, RectPose>;
1846
+ /** A split connector's two tag specs, `from` then `to`. */
1847
+ declare function offPageTagSpecs<TLayer extends string>(edgeId: string, split: OffPageSplit, pages: readonly PlacedPage[], look: OffPageTagLook & {
1848
+ layer: TLayer;
1849
+ }): AddNodeSpec<unknown, TLayer, RectPose>[];
1850
+ /**
1851
+ * A `derivePose` that stations a tag just past its stub's tip, on the far
1852
+ * side from the shape. `null`, so the tag keeps its authored pose, while its
1853
+ * connector draws no stub at that end.
394
1854
  */
395
- declare function labelDerivePose<TPose>(opts?: LabelPoseOptions<TPose>): (node: {
1855
+ declare function offPageTagDerivePose<TPose>(opts?: {
1856
+ geometry?: PoseDescriptor<TPose>;
1857
+ }): (node: {
396
1858
  pose: TPose;
397
1859
  data: unknown;
398
1860
  }, deps: readonly (DerivedDep<TPose> | undefined)[]) => TPose | null;
399
- /** Registry key for {@link LABEL_DERIVE_POSE}. */
400
- declare const DIAGRAM_LABEL = "diagram:label";
401
- /** The default label derivation, as one stable function reference so `toJSON`
402
- * can find its key. */
403
- declare const LABEL_DERIVE_POSE: (node: {
1861
+ /** Registry key for {@link OFF_PAGE_TAG_DERIVE_POSE}. */
1862
+ declare const DIAGRAM_OFF_PAGE_TAG = "diagram:offPageTag";
1863
+ /** The default tag derivation, as one stable function reference so `toJSON` can find its key. */
1864
+ declare const OFF_PAGE_TAG_DERIVE_POSE: (node: {
404
1865
  pose: unknown;
405
1866
  data: unknown;
406
1867
  }, deps: readonly (DerivedDep<unknown, unknown, string> | undefined)[]) => unknown;
407
1868
 
1869
+ /** The pages a {@link DiagramData} is drawn on, and the connectors that cross between them. */
1870
+
1871
+ /** `data`'s pages, placed in world space. */
1872
+ declare function diagramPages(data: DiagramData): PlacedPage[];
408
1873
  /**
409
- * A group's box, and anything pinned to a point on another node.
410
- *
411
- * The box is an ordinary node that depends on its members and derives its pose
412
- * from theirs: their union, grown by the inset. Drag a member and the box
413
- * follows; lay the diagram out and the box lands around wherever the members
414
- * went. Nothing has to keep it in sync, because nothing stores it.
415
- *
416
- * An anchored node — a group's title is the first — derives its pose from one
417
- * dependency's bounds the same way, so it travels with the box it labels.
418
- */
419
-
420
- /** Where an anchored node sits on its dependency. */
421
- interface DiagramAnchor {
422
- /** The point on the dependency's bounds, normalized as a port's is. */
423
- at: PortAnchor;
424
- /** The point on the node's own bounds that lands there. Default `at`, so
425
- * `{ u: 0, v: 0 }` puts the node's top-left on the dependency's. */
426
- self?: PortAnchor;
427
- /** Then moved by this much, in world units. */
428
- offset?: Vec2$1;
429
- }
430
- /** The group trait on a node's data, or `null`. */
431
- declare function diagramGroupOf(node: {
432
- data: unknown;
433
- }): DiagramGroup | null;
434
- /** The anchor trait on a node's data, or `null`. */
435
- declare function diagramAnchorOf(node: {
436
- data: unknown;
437
- }): DiagramAnchor | null;
438
- /** Options for {@link groupDerivePose} and {@link anchorDerivePose}.
439
- * `geometry` defaults to the kit's `AUTO_POSE_DESCRIPTOR`. */
440
- interface GroupPoseOptions<TPose> {
441
- geometry?: PoseDescriptor<TPose>;
442
- }
443
- /** A `derivePose` function as the scene calls it: the node, then what it depends on, in `dependsOn` order. */
444
- type DiagramDerivePose<TPose> = (node: {
445
- pose: TPose;
446
- data: unknown;
447
- }, deps: readonly (DerivedDep<TPose> | undefined)[]) => TPose | null;
1874
+ * Which of `edges` cross between `pages`, lettered in their order, and the two
1875
+ * off-page tags of each that does. An edge with an end `boxOf` has no box for
1876
+ * is left whole.
1877
+ */
1878
+ declare function dataOffPage(edges: readonly {
1879
+ id: string;
1880
+ from: string;
1881
+ to: string;
1882
+ }[], pages: readonly PlacedPage[], boxOf: (id: string) => Bounds$3 | undefined, look: OffPageTagLook): {
1883
+ splits: ReadonlyMap<string, OffPageSplit>;
1884
+ tags: DiagramSpec[];
1885
+ };
1886
+
448
1887
  /**
449
- * A `derivePose` that draws a group's box around its members: their union,
450
- * grown by the trait's inset. `null` — the authored pose stands — when the node
451
- * carries no group trait or every member is gone.
1888
+ * Which connectors cross from one page to another, as arithmetic: page
1889
+ * rects and end boxes in, splits out. Nothing here reads a scene.
452
1890
  */
453
- declare function groupDerivePose<TPose>(opts?: GroupPoseOptions<TPose>): DiagramDerivePose<TPose>;
454
- /** A group's box around the union of its members: grown by its inset, and
455
- * widened evenly to its `minWidth`. */
456
- declare function boxAround(union: {
457
- x: number;
458
- y: number;
459
- width: number;
460
- height: number;
461
- }, group: DiagramGroup): {
1891
+
1892
+ type Box$1 = {
462
1893
  x: number;
463
1894
  y: number;
464
1895
  width: number;
465
1896
  height: number;
466
1897
  };
1898
+ /** One connector as {@link offPageSplits} reads it: its two ends' world boxes,
1899
+ * and the split it holds now, if any. */
1900
+ interface OffPageEdgeInput {
1901
+ id: string;
1902
+ from: Box$1;
1903
+ to: Box$1;
1904
+ offPage?: OffPageSplit | undefined;
1905
+ }
1906
+ /** What {@link offPageSplits} reads. */
1907
+ interface OffPageSplitInput {
1908
+ pages: readonly PlacedPage[];
1909
+ edges: readonly OffPageEdgeInput[];
1910
+ /** Refs held by split connectors not in `edges`, which no edge here may take. */
1911
+ used?: Iterable<string>;
1912
+ }
1913
+ /** The first ref, in A…Z, AA… order, that `used` does not hold. */
1914
+ declare function nextOffPageRef(used: ReadonlySet<string>): string;
467
1915
  /**
468
- * A `derivePose` that keeps a node at a point on its dependency's bounds.
469
- * `null` when the node carries no anchor trait or the dependency is gone.
1916
+ * Each connector's split, or `null` where it stays whole. A connector splits
1917
+ * when its two ends belong to different pages (`pageOfBounds`); an end in a
1918
+ * gap belongs to none, and never splits. A split keeps the ref it holds while
1919
+ * no earlier connector here or `used` holds it too; a new one takes the next
1920
+ * free ref.
470
1921
  */
471
- declare function anchorDerivePose<TPose>(opts?: GroupPoseOptions<TPose>): DiagramDerivePose<TPose>;
472
- /** Registry key for {@link GROUP_DERIVE_POSE}. */
473
- declare const DIAGRAM_GROUP = "diagram:group";
474
- /** Registry key for {@link ANCHOR_DERIVE_POSE}. */
475
- declare const DIAGRAM_ANCHOR = "diagram:anchor";
476
- /** The default group derivation, a stable reference so `toJSON` can find its key. */
477
- declare const GROUP_DERIVE_POSE: DiagramDerivePose<unknown>;
478
- /** The default anchor derivation, a stable reference for the same reason. */
479
- declare const ANCHOR_DERIVE_POSE: DiagramDerivePose<unknown>;
1922
+ declare function offPageSplits(input: OffPageSplitInput): Map<string, OffPageSplit | null>;
1923
+
1924
+ /** The box `node` has in document space, which is where pages are: its pose through every ancestor's transform. */
1925
+ declare function documentBoundsOf<TPose>(scene: Scene<unknown, string, TPose>, node: {
1926
+ id: string;
1927
+ }, geometry?: PoseDescriptor<unknown>): Bounds$3;
480
1928
 
481
1929
  /**
482
- * `diagramScene` — a laid-out diagram from plain `{ nodes, edges }`.
483
- *
484
- * Every box is a `buildBody` body, so a data node can say anything a body
485
- * can: outline, rows, padding, ports. Sizes are estimated from character
486
- * counts unless `measure` is given, so layout runs without a canvas and gives
487
- * the same answer in node and in a browser.
1930
+ * Off-page markers on a live scene: an edit pass that splits a connector
1931
+ * whose ends land on different pages, joins one whose ends share a page
1932
+ * again, and keeps each split connector's two tags, all in the entry of the
1933
+ * edit that caused it.
488
1934
  */
489
1935
 
490
- /** One node of a {@link DiagramData}: its rows of text, and optionally its outline, ports, size, and starting place. */
491
- interface DataNode {
492
- id: string;
493
- /** Shorthand for one `label` row per line. Ignored when `rows` is given. */
494
- lines?: readonly string[];
495
- rows?: readonly Row[];
496
- /** Default `DiagramSceneOptions.outline`, which defaults to `'rect'`. */
497
- outline?: Outline;
498
- /** Perimeter ports, replacing the four compass midpoints. */
499
- ports?: readonly PortSpec[];
500
- /** Layout leaves this node at `at`. */
501
- pinned?: boolean;
502
- /** Where the node starts, before layout. Unset, nodes start on the
503
- * diagonal in source order, which is what within-rank order is seeded
504
- * from. */
505
- at?: Vec2$1;
506
- /** The smallest the box may be. Its content grows it past this. */
507
- width?: number;
508
- height?: number;
509
- /** Default `DiagramSceneOptions.padding`. */
510
- padding?: number;
511
- /** Default `DiagramSceneOptions.gap`. */
512
- gap?: number;
513
- /** Default `DiagramSceneOptions.verticalAlign`. */
514
- verticalAlign?: BodySpec['verticalAlign'];
515
- }
516
- /** One edge of a {@link DiagramData}, between two nodes or groups by id. */
517
- interface DataEdge {
518
- /** A node's id, or a group's: an edge naming a group meets its box. */
519
- from: string;
520
- to: string;
521
- /** The port to leave from or arrive at. Unset, the end facing the other
522
- * node most directly. */
523
- fromPort?: string;
524
- toPort?: string;
525
- label?: string;
526
- /** Where along the edge the label sits. Default `DiagramSceneOptions.labelPlacement`. */
527
- labelPlacement?: DiagramLabel;
528
- /** Default `DiagramSceneOptions.router`. */
529
- router?: DiagramRouter;
530
- /** World points the route passes through. Layout does not move them. */
531
- waypoints?: readonly Vec2$1[];
532
- }
533
- /** A box drawn around some nodes, which layout keeps together. */
534
- interface DataGroup {
535
- /** Shares one namespace with node ids. */
536
- id: string;
537
- /** Node ids, and the ids of groups nested in this one. A node or group a
538
- * later group also names stays in this one; an id that is neither is
539
- * ignored, and so is one that would put a group inside itself. */
540
- members: readonly string[];
541
- /** Drawn inside the box, above its members. */
542
- label?: string;
543
- /** Between the box and its members, and around the label. Default
544
- * `DiagramSceneOptions.groupPadding`. */
545
- padding?: number;
1936
+ /** Options for {@link installOffPageMarkers} and `useOffPageMarkers`. */
1937
+ interface OffPageMarkerOptions<TPose> {
1938
+ /** How node poses are measured. Default `AUTO_POSE_DESCRIPTOR`. */
1939
+ geometry?: PoseDescriptor<TPose>;
1940
+ /** The look a tag is given as it is made or retexted. Default the scene's
1941
+ * theme (`diagram:theme`), else `theme`. */
1942
+ look?: () => OffPageTagLook;
1943
+ /** The theme a scene naming none is drawn in. */
1944
+ theme?: DiagramTheme;
546
1945
  }
547
- /** A diagram as plain data, the input to `diagramScene`. */
548
- interface DiagramData {
549
- nodes: readonly DataNode[];
550
- edges: readonly DataEdge[];
551
- /** A group may be a member of another. `layered`, `tree`, and `force` keep
552
- * each group's members together; `'none'` ignores groups but still draws
553
- * them. */
554
- groups?: readonly DataGroup[];
555
- }
556
- /** The colors and outline a node is drawn with. */
557
- interface NodeStyle {
558
- fill: string;
559
- stroke: string;
560
- text: string;
561
- strokeWidth?: number;
562
- dash?: number[];
1946
+ /**
1947
+ * The ops that split, join, and tag the connectors `edges` names (every one,
1948
+ * for `'all'`), so each is split exactly when its ends sit on different
1949
+ * pages. Empty when nothing changes. The edit pass runs this; a host can run
1950
+ * it once over a document saved before it had off-page markers.
1951
+ */
1952
+ declare function offPageOps<TPose>(scene: Scene<unknown, string, TPose>, edges: Iterable<string> | 'all', opts?: OffPageMarkerOptions<TPose>): Op[];
1953
+ /**
1954
+ * Split `scene`'s connectors across pages from now on: every live edit that
1955
+ * moves a connector's end, adds or rewrites a connector, or changes the pages
1956
+ * splits, joins, and retags what it reached, in its own history entry. On
1957
+ * install nothing is recomputed. Returns the remover. A host without React
1958
+ * calls this; a component calls `useOffPageMarkers`.
1959
+ */
1960
+ declare function installOffPageMarkers<TPose>(scene: Scene<unknown, string, TPose>, opts?: OffPageMarkerOptions<TPose>): () => void;
1961
+
1962
+ /**
1963
+ * Split `scene`'s connectors across pages for the life of the calling
1964
+ * component: each edit that moves a connector's end or changes the pages
1965
+ * splits, joins, and retags what it reached, in its own history entry.
1966
+ * Options are read when the scene changes.
1967
+ */
1968
+ declare function useOffPageMarkers<TPose>(scene: Scene<unknown, string, TPose>, opts?: OffPageMarkerOptions<TPose>): void;
1969
+
1970
+ /**
1971
+ * Following a connector off the page: a double-click on an off-page tag goes
1972
+ * to the page at the connector's far end and selects the shape there.
1973
+ */
1974
+
1975
+ /** The action that follows an off-page tag to its far page. */
1976
+ declare const FOLLOW_OFF_PAGE_ACTION_ID = "diagram.followOffPage";
1977
+ /** Where a tag leads: the shape at its connector's far end, and that shape's page. */
1978
+ interface OffPageTarget {
1979
+ tag: string;
1980
+ edge: string;
1981
+ node: string;
1982
+ page: string;
563
1983
  }
564
- /** The stroke, markers, and label color an edge is drawn with. */
565
- interface EdgeStyle {
566
- stroke: string;
567
- width?: number;
568
- dash?: number[];
569
- /** `null` for none. Default none. */
570
- markerStart?: MarkerRef | null;
571
- /** `null` for none. Default `'arrow'`. */
572
- markerEnd?: MarkerRef | null;
573
- /** Default `stroke`. */
574
- label?: string;
1984
+ type SceneReads = NonNullable<ActionDeps['scene']>;
1985
+ /** Where tag `tagId` leads, or `null` when it is no tag of a split connector. */
1986
+ declare function offPageTargetOf(scene: SceneReads, tagId: string): OffPageTarget | null;
1987
+ /** Options for {@link createFollowOffPageAction}. */
1988
+ interface FollowOffPageOptions {
1989
+ /** Runs in place of the default, which selects `target.node` and fits the view to `target.page`. */
1990
+ follow?: (target: OffPageTarget, ctx: InvocationCtx) => void;
1991
+ /** Screen pixels the default leaves around the page it fits. Default 24. */
1992
+ padding?: number;
575
1993
  }
576
- /** How an edge is drawn between its ends. */
577
- type DiagramRouter = 'straight' | 'bezier' | 'orthogonal';
578
- /** The face a diagram node's text is set in. */
579
- type DiagramTextStyle = {
580
- fontFamily: string;
581
- fontSize: number;
582
- fontWeight?: number;
1994
+ /**
1995
+ * Goes to the far page of the off-page tag a double-click lands on, and
1996
+ * selects the shape at the connector's far end there. It declines a
1997
+ * double-click on anything else.
1998
+ */
1999
+ declare function createFollowOffPageAction(opts?: FollowOffPageOptions): Action;
2000
+ /** A double-click on a node's body; the action itself declines unless that node is an off-page tag. */
2001
+ declare function followOffPageBinding(actionId?: string): GestureBinding;
2002
+ /** Following off-page tags, as a contribution to pass as `ambient`. */
2003
+ declare function diagramOffPage(opts?: FollowOffPageOptions): {
2004
+ contribution: Contribution;
583
2005
  };
584
- /** The `data` of a scene node `diagramScene` makes: its diagram role, and what it paints. */
585
- interface DiagramSceneData {
586
- diagram?: DiagramNode | DiagramEdge | {
587
- label: DiagramLabel;
588
- } | {
589
- anchor: DiagramAnchor;
590
- };
591
- fill?: {
592
- paint: {
593
- color: string;
594
- };
595
- };
596
- stroke?: Stroke;
597
- text?: string;
598
- style?: DiagramTextStyle;
599
- }
600
- /** A scene node spec, as `diagramScene` returns them. */
601
- type DiagramSpec = AddNodeSpec<DiagramSceneData, 'main', RectPose>;
602
- /** How `diagramScene` lays out, routes, and styles a {@link DiagramData}. */
603
- interface DiagramSceneOptions {
604
- /** A layout by name, or any `LayoutFn`. Default `'layered'`. `'none'`
605
- * leaves every node at its `at`. */
606
- layout?: 'layered' | 'tree' | 'force' | 'none' | LayoutFn;
607
- /** Merged over `{ order: 'barycenter' }`. */
608
- layoutOptions?: LayoutOptions;
609
- /** Default `'bezier'`. */
610
- router?: DiagramRouter;
611
- /** The text style rows fall back on. Default 12px sans-serif. */
612
- font?: {
613
- fontFamily: string;
614
- fontSize: number;
615
- };
616
- /** Measures one run of text. Default an estimate from character count, so
617
- * layout needs no canvas; pass `canvasMeasure(ctx)` for real widths. */
618
- measure?: MeasureRowText;
619
- /** Default `'rect'`. */
620
- outline?: Outline;
621
- /** Between a box's outline and its rows. Default 8. */
622
- padding?: number;
623
- /** Between adjacent rows. Default 4. */
624
- gap?: number;
625
- /** Where a box's rows sit when it is taller than they need. Default `'center'`. */
626
- verticalAlign?: BodySpec['verticalAlign'];
627
- /** The narrowest a box may be. Default 64. */
628
- minWidth?: number;
629
- /** Where edge labels sit. Default `{ at: 'mid', offset: 9 }`. */
630
- labelPlacement?: DiagramLabel;
631
- nodeStyle?: (node: DataNode) => NodeStyle;
632
- /** Default 12. */
633
- groupPadding?: number;
634
- /** A group's box and label. `text` colors the label. */
635
- groupStyle?: (group: DataGroup) => NodeStyle;
636
- edgeStyle?: (edge: DataEdge) => EdgeStyle;
637
- }
638
- /** The scene node id `diagramScene` gives an edge, built from its ends, ports, and label. */
639
- declare const edgeIdOf: (e: DataEdge) => string;
640
- /** Every spec carries an id — a node's own, `<id>/<k>` for its text,
641
- * `<edge id>/label`, a group's own and `<group id>/label` — so a later call's
642
- * specs can be reconciled against this one's. Throws on a repeated id among
643
- * nodes and groups, which names two things as one. An edge whose
644
- * end is not a node is dropped, and so is a repeat of an earlier edge with
645
- * the same ends, ports and label: it would draw exactly on top of the first. */
646
- declare function diagramScene(data: DiagramData, opts?: DiagramSceneOptions): DiagramSpec[];
2006
+
2007
+ /** Subpath `index` of `path` as a path of its own: the whole path for index 0
2008
+ * of one with a single subpath, or of a shape with no commands; null past the last. */
2009
+ declare function subpathOf(path: Path$1, index: number): Path$1 | null;
2010
+
2011
+ /**
2012
+ * `<SceneCanvas selectTool={{ resize: { resizable } }}>` for a diagram scene:
2013
+ * edges and edge labels take their geometry from what they are attached to,
2014
+ * so their own pose is a placeholder, and a resize handle on it sits at the
2015
+ * origin and resizes nothing. A group's box is its members' union, and a
2016
+ * pool's lane is sized by its pool's stack and resized by dragging its
2017
+ * boundary.
2018
+ */
2019
+ declare function diagramResizable(scene: {
2020
+ get(id: never): {
2021
+ data: unknown;
2022
+ } | undefined;
2023
+ }): (id: string) => boolean;
2024
+
2025
+ /** A node's style: its colors over its role's under `theme`, else over {@link NODE}. */
2026
+ declare function dataNodeStyle(node: Pick<DataNode, 'style' | 'colors'>, theme?: DiagramTheme): NodeStyle;
2027
+ /** An edge's style: its colors over its role's stroke under `theme`, else over the theme's connector, else over {@link EDGE}. */
2028
+ declare function dataEdgeStyle(edge: Pick<DataEdge, 'style' | 'colors'>, theme?: DiagramTheme): EdgeStyle;
2029
+ /** A region as {@link dataRegionStyle} reads it: a container, a pool, or a lane. */
2030
+ interface StyledRegion {
2031
+ role: DataContainer['role'] | 'lane';
2032
+ style?: string;
2033
+ colors?: Partial<NodeStyle>;
2034
+ }
2035
+ /**
2036
+ * A region's style: its colors over its theme role's, else over the theme's
2037
+ * container, its pool header, or the lane body at `laneIndex` in turn; with no
2038
+ * theme, over {@link NODE}.
2039
+ */
2040
+ declare function dataRegionStyle(region: StyledRegion, theme?: DiagramTheme, laneIndex?: number): NodeStyle;
2041
+
2042
+ /**
2043
+ * A live layout's producers: what each frame of a run says about where the
2044
+ * participants are. `forceProducer` relaxes; `easedProducer` walks to a
2045
+ * destination it knows. `useLiveLayout` (`live.ts`) runs them.
2046
+ */
647
2047
 
648
2048
  /** What a live producer is told, and what it answers with. */
649
2049
  interface LiveLayoutCtx<TPose> {
@@ -700,14 +2100,16 @@ interface EasedProducerOptions {
700
2100
  * over.
701
2101
  */
702
2102
  declare function easedProducer<TPose>(graph: Graph, algorithm: LayoutFn, opts?: EasedProducerOptions): LiveLayoutProducer<TPose>;
2103
+
703
2104
  /** Options for {@link useLiveLayout}. Only `scene` and `source` are required. */
704
2105
  interface UseLiveLayoutOptions<TPose> {
705
2106
  scene: Scene<unknown, string, TPose>;
706
2107
  /** Where the graph is read from. The same thunk the port affordance takes. */
707
2108
  source: GraphSource<TPose>;
708
- /** A key in `LAYOUTS`, or a layout of the consumer's own. `'force'` relaxes
709
- * continuously; anything else eases to its answer. Default `'force'`. */
710
- algorithm?: string | LayoutFn;
2109
+ /** A key in `LAYOUTS`, a layout of the consumer's own, or a planner that
2110
+ * answers later. `'force'` relaxes continuously; anything else eases to its
2111
+ * answer. Default `'force'`. */
2112
+ algorithm?: string | LayoutFn | LayoutPlanner;
711
2113
  layout?: LayoutOptions;
712
2114
  /** The relaxation's forces, and when a live run of it counts as at rest. */
713
2115
  force?: Omit<ForceProducerOptions<TPose>, 'geometry'>;
@@ -721,6 +2123,9 @@ interface UseLiveLayoutOptions<TPose> {
721
2123
  /** Fires once the run has settled or been stopped and its poses are in the
722
2124
  * document, with how many participants moved. */
723
2125
  onSettle?: (moved: number) => void;
2126
+ /** Hears why a `LayoutPlanner` failed to answer, and no run starts. Unset,
2127
+ * the failure goes to `console.error`. */
2128
+ onError?: (error: unknown) => void;
724
2129
  /** Whether a node or edge appearing or disappearing re-heats the run.
725
2130
  * Default true — a diagram that ignores a new edge looks broken. */
726
2131
  reheatOnGraphChange?: boolean;
@@ -730,9 +2135,11 @@ interface UseLiveLayoutOptions<TPose> {
730
2135
  }
731
2136
  /** Controls for a live layout run, from {@link useLiveLayout}. */
732
2137
  interface LiveLayout {
733
- /** Heat and run. Idempotent while running. */
2138
+ /** Heat and run. Idempotent while running, which includes waiting on a
2139
+ * planner's answer. */
734
2140
  start(): void;
735
- /** Finish now: commit where the nodes stand. */
2141
+ /** Finish now: commit where the nodes stand. A planner's answer still to
2142
+ * come is dropped. */
736
2143
  stop(): void;
737
2144
  /** Abandon: the document keeps the poses it had. */
738
2145
  cancel(): void;
@@ -756,20 +2163,11 @@ declare const EASED_LAYOUTS: Readonly<Record<string, LayoutFn>>;
756
2163
  *
757
2164
  * An edge running down the ranks leaves its source by the face toward the
758
2165
  * next rank and arrives at its target's face toward the last, so it reads
759
- * along the direction the diagram flows. An edge that skips ranks gets
760
- * waypoints through the gaps in each rank it crosses, so it goes around the
761
- * nodes between its ends rather than through them.
762
- *
763
- * An edge running back up the ranks, or within one, is left to the ends'
764
- * facing rule.
2166
+ * along the direction the diagram flows; one running back up the ranks does
2167
+ * the same the other way round. An edge that spans ranks runs through the
2168
+ * waypoints `layeredPlan` placed for it.
765
2169
  */
766
2170
 
767
- type Rect = {
768
- x: number;
769
- y: number;
770
- width: number;
771
- height: number;
772
- };
773
2171
  /** One edge to route, by the ids of its ends: a node's or a group's. */
774
2172
  interface RouteEdge {
775
2173
  id: string;
@@ -782,27 +2180,73 @@ interface LayeredRoute {
782
2180
  fromPort?: string;
783
2181
  toPort?: string;
784
2182
  waypoints?: readonly Vec2$1[];
2183
+ /** The point on the route layout left the edge's label room beside, as a
2184
+ * `DiagramLabel`'s `{ near }`. */
2185
+ labelAt?: Vec2$1;
785
2186
  }
786
- /** What {@link layeredRoutes} reads: the ranked graph, and where everything landed. */
2187
+ /** What {@link layeredRoutes} reads: where `layeredPlan` put things. */
787
2188
  interface LayeredRouteInput {
788
- /** The graph layout ranked, for which rank each node is in. */
789
- graph: Graph;
790
2189
  edges: readonly RouteEdge[];
791
- /** Every node and group box where it was placed. */
792
- boxes: ReadonlyMap<string, Rect>;
2190
+ /** Each node's rank, from `layeredPlan`. Empty for a layout with none,
2191
+ * which names no ports. */
2192
+ ranks: ReadonlyMap<string, number>;
2193
+ /** Each spanning edge's waypoints, from `layeredPlan`. */
2194
+ waypoints: ReadonlyMap<string, readonly Vec2$1[]>;
2195
+ /** Where each labeled edge's label room is among its waypoints, from
2196
+ * `layeredPlan`. */
2197
+ labels?: ReadonlyMap<string, Vec2$1>;
793
2198
  /** Each group's node members, through nested groups. */
794
2199
  members: ReadonlyMap<string, readonly string[]>;
795
2200
  /** Ids whose ports are the four compass midpoints, which are the only ones
796
2201
  * a route names. */
797
2202
  compass: ReadonlySet<string>;
798
2203
  direction?: LayoutDirection;
799
- /** How far a route keeps from the boxes it passes. */
800
- clearance: number;
801
2204
  }
802
2205
  /** Ports and waypoints for each edge of a laid-out `layered` diagram that
803
2206
  * needs any, keyed by edge id. */
804
2207
  declare function layeredRoutes(input: LayeredRouteInput): Map<string, LayeredRoute>;
805
2208
 
2209
+ /**
2210
+ * The edge half of writing a layout to a scene: each edge's waypoints, and
2211
+ * where its label sits among them.
2212
+ *
2213
+ * Layout writes only what it owns. An edge's route is its own while the edge
2214
+ * has no waypoints or still has the ones layout last wrote (`laidOut`), and
2215
+ * is not an `avoid` connector, which only gets its ports named; a
2216
+ * label's place is its own while the label sits at the default middle or at a
2217
+ * `{ near }`, and its edge's route is layout's.
2218
+ */
2219
+
2220
+ /** Edge routes for `applyLayout` to write alongside a layout's moves. */
2221
+ interface LayoutRoutes {
2222
+ /** Every edge the layout laid out. Each one layout owns gets its route
2223
+ * from `waypoints`, or loses the one a layout gave it before. */
2224
+ edges: ReadonlySet<string>;
2225
+ waypoints: ReadonlyMap<string, readonly Vec2$1[]>;
2226
+ labels?: ReadonlyMap<string, Vec2$1>;
2227
+ /** The ports layout names. Each end layout owns gets its port from here,
2228
+ * or loses the one a layout named before. */
2229
+ ports?: ReadonlyMap<string, LayoutPorts>;
2230
+ }
2231
+ /** The routes `plan` laid out for `graph`'s edges. A layout that routes
2232
+ * nothing routes every edge straight, taking back what `layered` wrote. */
2233
+ declare function routesOf(graph: Graph, plan: LayoutPlan): LayoutRoutes;
2234
+ /** A scene as {@link routeWrites} reads it. */
2235
+ interface RoutedScene {
2236
+ get(id: never): {
2237
+ data: unknown;
2238
+ } | undefined;
2239
+ isLocked(id: never): boolean;
2240
+ renderOrderNodes(): readonly {
2241
+ id: string;
2242
+ data: unknown;
2243
+ dependsOn?: readonly string[] | 'children';
2244
+ }[];
2245
+ }
2246
+ /** The new `data` for every edge and label whose route or place changes. A
2247
+ * locked edge or label is left as it is. */
2248
+ declare function routeWrites(scene: RoutedScene, routes: LayoutRoutes): Map<string, unknown>;
2249
+
806
2250
  /**
807
2251
  * Running a layout against a scene: `LAYOUTS`, one batch of pose writes, and
808
2252
  * the action that reaches both. A layout is a pure function of the graph;
@@ -816,12 +2260,14 @@ interface ApplyLayoutOptions<TPose> {
816
2260
  geometry?: PoseDescriptor<TPose>;
817
2261
  /** The undo entry's name. Default `'Layout'`. */
818
2262
  label?: string;
2263
+ /** Edge routes to write in the same batch, from `routesOf`. */
2264
+ routes?: LayoutRoutes;
819
2265
  }
820
2266
  /**
821
2267
  * Write a layout's answer to the scene, as one undoable batch.
822
2268
  *
823
- * Returns how many nodes moved, which is zero for a layout that had nothing to
824
- * do — nothing is written and no history entry is pushed.
2269
+ * Returns how many nodes moved. A layout with nothing to do, nodes or routes,
2270
+ * writes nothing and pushes no history entry.
825
2271
  *
826
2272
  * Nodes are **translated**, never re-posed from the layout's numbers: a node's
827
2273
  * pose can be a path or anything else a consumer wired, and only its own
@@ -869,11 +2315,18 @@ declare function createLayoutAction<TPose>(opts: LayoutActionOptions<TPose>): Ac
869
2315
  */
870
2316
 
871
2317
  /** The minimum a participant source needs from a scene. Narrower than `Scene`
872
- * so a consumer can pass anything that answers these two. */
2318
+ * so a consumer can pass anything that answers these. `layers` and each
2319
+ * node's `layer`, `parent`, `hidden` and `locked` feed `nodeGates`; a stand-in
2320
+ * without them gates nothing. */
873
2321
  interface ParticipantScene<TPose> {
2322
+ readonly layers?: readonly GatedLayer[];
874
2323
  renderOrderNodes(): readonly {
875
2324
  id: string;
876
2325
  kind: 'leaf' | 'container';
2326
+ layer?: string;
2327
+ parent?: string | null;
2328
+ hidden?: boolean;
2329
+ locked?: boolean;
877
2330
  data: unknown;
878
2331
  pose: TPose;
879
2332
  dependsOn?: readonly string[] | 'children';
@@ -887,7 +2340,11 @@ interface ParticipantScene<TPose> {
887
2340
  childrenOf(id: string): readonly string[];
888
2341
  }
889
2342
  /**
890
- * Every node in `scene`, at the pose it is **painted** at.
2343
+ * Every node in `scene`, at the pose it is **painted** at, marked `hidden` or
2344
+ * `locked` where the scene's `nodeGates` says so, and carrying its `layer` so
2345
+ * a view that does not paint that layer can turn its ports away too. The
2346
+ * marks keep ports off such a node; the graph reads past them, so a hidden
2347
+ * node is still laid out.
891
2348
  *
892
2349
  * `effectivePose`, not `node.pose`: an override is what a gesture is currently
893
2350
  * showing, and a port that answers from the document pose while its node is
@@ -895,7 +2352,9 @@ interface ParticipantScene<TPose> {
895
2352
  *
896
2353
  * One source answers both the ports and the graph.
897
2354
  */
898
- declare function sceneParticipants<TPose>(scene: ParticipantScene<TPose>): GraphSource<TPose>;
2355
+ declare function sceneParticipants<TPose>(scene: ParticipantScene<TPose>): () => Iterable<ParticipantPose<TPose> & {
2356
+ node: GraphNodeLike;
2357
+ }>;
899
2358
  /**
900
2359
  * The composed layer, ready for `CanvasExtensionApi.registerLayer` — the only
901
2360
  * attach route that is hit-tested. Handing this to `SceneCanvas`'s `layers`
@@ -937,11 +2396,139 @@ declare function diagramShape<TPose>(opts?: DiagramShapeOptions<TPose>): NodeSha
937
2396
  */
938
2397
  declare function registerDiagramShape<TPose>(opts?: DiagramShapeOptions<TPose>): () => void;
939
2398
 
940
- /** Where a moved node now stands. */
2399
+ /**
2400
+ * DOM pinned to a diagram's nodes and edges: a settings card beside the picked
2401
+ * node, a button on an edge's midpoint. Each overlay is placed after every
2402
+ * paint, so it follows a pan, a zoom, a resize and a layout run's every frame.
2403
+ */
2404
+
2405
+ /** One piece of DOM held against a node, a group or an edge. */
2406
+ interface DiagramOverlay {
2407
+ /** The node, group or edge it is held against. While no such id is in the
2408
+ * diagram it is not shown. */
2409
+ target: string;
2410
+ /** Beside the target's box, kept inside the view and flipped to the far
2411
+ * side when the near one has no room; or `'center'`, centered on it.
2412
+ * Default `'center'`. */
2413
+ placement?: Placement | 'center';
2414
+ /** Gap between the target's box and the overlay, in CSS pixels. Default 0. */
2415
+ offset?: number;
2416
+ /** Tells two overlays on one target apart. Default `target`. */
2417
+ key?: string;
2418
+ content: ReactNode;
2419
+ }
2420
+
2421
+ /**
2422
+ * The regions half of `DiagramView`'s sync: where each container, pool, and
2423
+ * lane stands, and the region edits a change to that is reported as.
2424
+ */
2425
+
2426
+ type Box = {
2427
+ x: number;
2428
+ y: number;
2429
+ width: number;
2430
+ height: number;
2431
+ };
2432
+ /**
2433
+ * A region edit, which `DiagramView` reports and does not keep: `box`, a
2434
+ * container or pool moved or resized (`parent` present when a drop changed
2435
+ * the region it is in, `null` for the top level); `lanes`, a pool's lanes
2436
+ * resized, reordered, or added to, every lane in stacking order with its size
2437
+ * (a new lane's id is minted by the view); `release`, Release members run on
2438
+ * a region; `title`, a double-click on a region's header.
2439
+ */
2440
+ type ContainerEdit = {
2441
+ kind: 'box';
2442
+ id: string;
2443
+ box: Box;
2444
+ parent?: string | null;
2445
+ } | {
2446
+ kind: 'lanes';
2447
+ pool: string;
2448
+ lanes: readonly {
2449
+ id: string;
2450
+ size: number;
2451
+ }[];
2452
+ } | {
2453
+ kind: 'release';
2454
+ id: string;
2455
+ } | {
2456
+ kind: 'title';
2457
+ id: string;
2458
+ };
2459
+
2460
+ /**
2461
+ * `DiagramView`'s two-way sync with the data it was built from: new specs are
2462
+ * reconciled into the scene, and what a drag or a layout run changed is
2463
+ * reported back, so a consumer keeping the diagram as data can store it.
2464
+ * `diagramLayoutOf` reads the same report off a `diagramScene` build.
2465
+ */
2466
+
2467
+ /** Where a moved node now stands. `parent` is present when a drop changed
2468
+ * the region it is in: that container's or lane's id, or `null` for the top
2469
+ * level. The host moves the id from one `members` list to the other. */
941
2470
  interface NodeMove {
942
2471
  id: string;
943
2472
  x: number;
944
2473
  y: number;
2474
+ parent?: string | null;
2475
+ }
2476
+ /** An edge whose route or ports a layout run rewrote. `id` is the edge's
2477
+ * scene id, `edgeIdOf` of its data edge; `waypoints` is empty when the run
2478
+ * took a route away and left the edge straight, and `ports` names the ends
2479
+ * layout owns. Store them as the data edge's `routed` and `routedPorts`,
2480
+ * which stay layout's, not as `waypoints`, `fromPort` and `toPort`, which
2481
+ * would be the author's and rename the edge. */
2482
+ interface EdgeRoute {
2483
+ id: string;
2484
+ waypoints: readonly Vec2$1[];
2485
+ ports: LayoutPorts;
2486
+ }
2487
+ /** What layout placed in a `diagramScene` build, in the shapes `DiagramView`
2488
+ * reports: every node not pinned, where it stands, every edge whose route
2489
+ * or ports layout wrote, and the box of every container and pool not pinned
2490
+ * whose box is its own rather than fitted. Store them the way `onMove` and
2491
+ * `onEditContainer` say and the next build leaves them where they are. */
2492
+ declare function diagramLayoutOf(specs: readonly DiagramSpec[]): {
2493
+ moves: NodeMove[];
2494
+ routes: EdgeRoute[];
2495
+ containers: ContainerEdit[];
2496
+ };
2497
+
2498
+ /** One end of a data edge moved onto node `node`, at `port` or on its body. */
2499
+ interface ReconnectChange {
2500
+ /** The data edge's id, `edgeIdOf` of it. */
2501
+ edge: string;
2502
+ end: 'from' | 'to';
2503
+ node: string;
2504
+ port?: string;
2505
+ }
2506
+ /** A data edge's route as a drag or a double-click left it. */
2507
+ interface RouteChange {
2508
+ /** The data edge's id, `edgeIdOf` of it. */
2509
+ edge: string;
2510
+ /** Empty when the edge no longer has any. */
2511
+ waypoints: readonly Vec2$1[];
2512
+ }
2513
+ /** Where a drag left a data edge's label, or `null` for Reset label. */
2514
+ interface LabelMove {
2515
+ /** The data edge's id, `edgeIdOf` of it. */
2516
+ edge: string;
2517
+ placement: DiagramLabel | null;
2518
+ }
2519
+ /** A node's box as a resize handle's drag left it: its place too, since a
2520
+ * handle on its top or left edge moves it. */
2521
+ interface NodeResize {
2522
+ id: string;
2523
+ x: number;
2524
+ y: number;
2525
+ width: number;
2526
+ height: number;
2527
+ }
2528
+ /** What a delete would take: the data nodes, and every data edge that goes with them. */
2529
+ interface DeleteReport {
2530
+ nodes: readonly string[];
2531
+ edges: readonly string[];
945
2532
  }
946
2533
  /** Props for `DiagramView`. */
947
2534
  interface DiagramViewProps {
@@ -950,24 +2537,104 @@ interface DiagramViewProps {
950
2537
  * selection and anything moved since stay put unless the new specs change
951
2538
  * them. Pass a new `key` to start over instead. */
952
2539
  specs: readonly DiagramSpec[];
953
- width: number;
954
- height: number;
2540
+ /** `'avoid'` routes every edge around the shapes, holding one router across
2541
+ * new `specs` so each reroutes only what it disturbed. The routes derive
2542
+ * from the specs and are never reported. */
2543
+ router?: 'avoid';
2544
+ /** `'dodge'` moves each edge label off whatever covers it, along its
2545
+ * route or across it, after any `router` has run. Placement derives from
2546
+ * the specs and is never reported. */
2547
+ labels?: 'dodge';
2548
+ /** Line jumps of this radius: where two edges cross, the later one bows
2549
+ * over the earlier in a half circle. Applied after `router` and `labels`; derived from
2550
+ * the specs and never reported. */
2551
+ hops?: number;
2552
+ /** The view opens fitted to the diagram, and fits again when the size or a
2553
+ * fit option changes or a layout run settles, until the user pans or zooms;
2554
+ * from then on the view is theirs. Omit both to fill the parent, which
2555
+ * then needs a size of its own; a resize of the parent is a size change. */
2556
+ width?: number;
2557
+ height?: number;
955
2558
  /** A participant id, or null for none. */
956
2559
  selected?: string | null;
957
2560
  /** Reports what each click leaves picked, `null` for none — a re-click on the
958
2561
  * picked node reports it again. The canvas keeps the pick even if
959
2562
  * `selected` does not follow it; only a change to `selected` is pushed in. */
960
2563
  onSelect?: (id: string | null) => void;
2564
+ /** Reports the node, group or edge the pointer comes to be over, and `null`
2565
+ * once it is over none or leaves the canvas. An edge answers only while
2566
+ * edges are picked (`pickEdges`). */
2567
+ onHover?: (id: string | null) => void;
2568
+ /** Whether a click or a hover can land on an edge, which is then picked
2569
+ * like a node. Default: on when `onReconnect`, `onEditRoute`, `onDelete`,
2570
+ * `onEditLabel` or `onMoveLabel` is set. */
2571
+ pickEdges?: boolean;
2572
+ /** DOM held against nodes, groups and edges, kept in place through pans,
2573
+ * zooms, resizes and layout runs. The view's box is their containing
2574
+ * block; their content takes the pointer, and the canvas beneath does not
2575
+ * see it. */
2576
+ overlays?: readonly DiagramOverlay[];
961
2577
  /** Set to let nodes be dragged. Reports every node a drag or a layout run
962
- * moved. Store each as the data node's `at` with `pinned: true`, or the
963
- * next `diagramScene` lays it out again. */
964
- onMove?: (moves: readonly NodeMove[]) => void;
965
- /** Set to make ports grabbable. Dragging one port onto another reports the
966
- * edge it describes and draws nothing; add it to the data to keep it. */
2578
+ * moved, and every edge whose route or ports a layout run rewrote. Store
2579
+ * each move as the data node's `at` with `pinned: true`, and each route as
2580
+ * the data edge's `routed` and `routedPorts`, or the next `diagramScene`
2581
+ * lays them out again. */
2582
+ onMove?: (moves: readonly NodeMove[], routes: readonly EdgeRoute[]) => void;
2583
+ /** Set to give a selected node resize handles. The box resizes live while
2584
+ * a handle is dragged; on release the new box is reported and the view
2585
+ * draws it only once the specs do. Store it as the data node's `width`,
2586
+ * `height`, and `at` with `pinned: true`; the size is a minimum, so a box
2587
+ * dragged smaller than its rows grows back to them. */
2588
+ onResize?: (resizes: readonly NodeResize[]) => void;
2589
+ /** Ports are grabbable when this is set, unless `ports` says otherwise. Dragging one port onto another reports the
2590
+ * edge it describes and draws nothing; add it to the data to keep it. An
2591
+ * end on a shape's body (`connectBodies`) has no port field. */
967
2592
  onConnect?: (edge: DataEdge) => void;
2593
+ /** Set to let a selected edge's ends be dragged onto another port, or with
2594
+ * `connectBodies` onto a shape's body. Reports the move and draws nothing; change the data edge to keep it. */
2595
+ onReconnect?: (change: ReconnectChange) => void;
2596
+ /** Set to give a selected edge handles along its route: drag one to move or
2597
+ * insert a waypoint, or slide an orthogonal segment; double-click one to
2598
+ * remove it. Reports the edge's new waypoints and draws nothing; store them
2599
+ * as the data edge's `waypoints` and clear its `routed`. */
2600
+ onEditRoute?: (change: RouteChange) => void;
2601
+ /** Set to let Delete and Backspace remove the selection. Reports the
2602
+ * selected data nodes (a selected group, not its members; a selected
2603
+ * container, pool, or lane with everything inside it) and every edge
2604
+ * selected or ending on one of them, and removes nothing. */
2605
+ onDelete?: (removed: DeleteReport) => void;
2606
+ /** Set to let a member of a group marked `reorder` be dragged along that
2607
+ * axis among its siblings, or the selected one stepped with Alt and an
2608
+ * arrow key. Reports the members' new order and moves nothing: write it to
2609
+ * the group's `members`, which layered layout keeps. */
2610
+ onReorder?: (change: ReorderChange) => void;
2611
+ /** Set to report a double-click on an edge, for its label to be edited. */
2612
+ onEditLabel?: (edge: string) => void;
2613
+ /** Set to let an edge's label be dragged along and beside it, and to enable
2614
+ * Reset label for the selected edge. Reports the placement and draws
2615
+ * nothing; store it as the data edge's `labelPlacement`, and delete that
2616
+ * field for `null`. */
2617
+ onMoveLabel?: (change: LabelMove) => void;
2618
+ /** Set to edit `DiagramData` containers and pools: drag a lane's boundary,
2619
+ * click a pool's add-lane button, drag a lane by its header to reorder,
2620
+ * move or resize a region, double-click a header, or run Release members.
2621
+ * Each is reported and nothing is kept until the specs follow. A region's
2622
+ * move also reports what it carried to `onMove`, and a lane resize the
2623
+ * members of the lanes it shifts. Store a `box` edit as the container's
2624
+ * `box` with `pinned: true`. */
2625
+ onEditContainer?: (edit: ContainerEdit) => void;
2626
+ /** Whether a connect or a reconnect may end on a shape's body, away from
2627
+ * its ports. Default false. */
2628
+ connectBodies?: boolean;
2629
+ /** Contributions to install after the view's own: a tool's bindings, a key. */
2630
+ ambient?: readonly Contribution[];
2631
+ /** Whether ports are drawn. `'connect'` draws them and lets one be dragged
2632
+ * onto another; `'show'` only draws them. Default: `'connect'` when
2633
+ * `onConnect` is set, else `'none'`. */
2634
+ ports?: 'connect' | 'show' | 'none';
968
2635
  /** Whether the canvas's keyboard shortcuts — held Space to pan among them —
969
2636
  * run. They listen page-wide, so a view-only diagram beside other UI would
970
- * claim keys meant for the page. Default: on when `onMove` or `onConnect`
2637
+ * claim keys meant for the page. Default: on when any callback that edits
971
2638
  * is set. */
972
2639
  enableKeybindings?: boolean;
973
2640
  /** Which ports may be joined. Default: a port may not join itself, and two
@@ -975,28 +2642,35 @@ interface DiagramViewProps {
975
2642
  canConnect?: CanConnect;
976
2643
  /** How ports look and answer the pointer, and the router a connect's
977
2644
  * preview draws with. */
978
- portOptions?: Pick<DiagramContributionOptions<RectPose>, 'fill' | 'stroke' | 'sizePx' | 'hitRadiusPx' | 'cursor' | 'shows' | 'snapRadius' | 'router'>;
2645
+ portOptions?: Pick<DiagramContributionOptions<RectPose>, 'fill' | 'stroke' | 'shape' | 'sizePx' | 'hitRadiusPx' | 'cursor' | 'shows' | 'showsPort' | 'snapRadius' | 'router'>;
979
2646
  /** How a layout run from {@link DiagramViewApi.layout} behaves: its forces,
980
- * how many frames an eased layout takes, its easing. */
2647
+ * how many frames an eased layout takes, its easing, and `onError`, which
2648
+ * hears a `LayoutPlanner` that failed to answer. */
981
2649
  live?: Omit<UseLiveLayoutOptions<RectPose>, 'scene' | 'source' | 'algorithm'>;
982
- /** The smallest scale the initial fit may use. Unset, the whole diagram fits
2650
+ /** The smallest scale the fit may use. Unset, the whole diagram fits
983
2651
  * however small that makes it; set, it stops here and the rest is a pan away. */
984
2652
  minScale?: number;
985
- /** The largest scale the initial fit may use. Default 1, so a small
2653
+ /** The largest scale the fit may use. Default 1, so a small
986
2654
  * diagram opens at its own size rather than blown up. */
987
2655
  maxScale?: number;
988
2656
  /** Which part of a diagram too big for the box it opens on: its middle
989
2657
  * (default) or its top-left, where a layered flow begins. */
990
2658
  anchor?: 'center' | 'start';
991
- /** Space kept clear around the diagram by the initial fit, in CSS pixels.
2659
+ /** Space kept clear around the diagram by the fit, in CSS pixels.
992
2660
  * Default 16. */
993
2661
  fitPadding?: number;
994
2662
  /** What the canvas paints behind the diagram. Unset, it is transparent. */
995
2663
  background?: Paint;
996
- /** The view, controlled. Set it and the initial fit is skipped; pair it
2664
+ /** Sheets painted under the diagram, one filled rect per page; `diagramPages(data)`
2665
+ * places them. The default fit takes in every page. */
2666
+ pages?: {
2667
+ placed: readonly PlacedPage[];
2668
+ fill: string;
2669
+ };
2670
+ /** The view, controlled. Set it and the fit is skipped; pair it
997
2671
  * with `onViewChange` or panning does nothing. */
998
2672
  view?: View;
999
- /** Every view change, from a pan, a zoom or the initial fit. */
2673
+ /** Every view change, from a pan, a zoom or a refit. */
1000
2674
  onViewChange?: (view: View) => void;
1001
2675
  className?: string;
1002
2676
  }
@@ -1004,13 +2678,42 @@ interface DiagramViewProps {
1004
2678
  interface DiagramViewApi {
1005
2679
  /** Lay the diagram out again from where its nodes stand, animated. `'force'`
1006
2680
  * (default) relaxes until it settles; any other layout eases to its answer.
1007
- * What moved is reported to `onMove` once the run settles. */
1008
- layout(algorithm?: 'layered' | 'tree' | 'force' | LayoutFn): void;
2681
+ * A `LayoutPlanner` is handed the diagram's graph and eased to once it
2682
+ * answers; a drag, an edit or another `layout` call before then drops the
2683
+ * answer. What moved is reported to `onMove` once the run settles. */
2684
+ layout(algorithm?: DiagramLayout): void;
1009
2685
  /** The run `layout` started: stop it where it stands, or cancel it. */
1010
2686
  live: LiveLayout;
2687
+ /** The world point under a client point: where a drop from outside the canvas lands. */
2688
+ worldAt(clientX: number, clientY: number): Vec2$1;
2689
+ /** The world rect the canvas shows, or `null` before it has a size. */
2690
+ visible(): {
2691
+ x: number;
2692
+ y: number;
2693
+ width: number;
2694
+ height: number;
2695
+ } | null;
2696
+ /** Where a node, group or edge is drawn, in client coordinates — for an
2697
+ * edge, an empty rect at the midpoint along its route. `null` for an id the
2698
+ * diagram does not hold, or before the canvas mounts. Read it again from
2699
+ * {@link subscribeFrame}, after every paint. */
2700
+ rectOf(id: string): {
2701
+ x: number;
2702
+ y: number;
2703
+ width: number;
2704
+ height: number;
2705
+ } | null;
2706
+ /** Run `fn` after every paint: a pan, a zoom, a layout frame, a change of
2707
+ * specs. Returns an unsubscribe; a call before the canvas mounts returns one
2708
+ * and never runs `fn`. */
2709
+ subscribeFrame(fn: () => void): () => void;
1011
2710
  }
2711
+ /** What {@link DiagramViewApi.layout} runs. */
2712
+ type DiagramLayout = 'layered' | 'tree' | 'force' | 'chain' | LayoutFn | LayoutPlanner;
2713
+
1012
2714
  /** A diagram: drag or wheel to pan, zoom, and pick a node; drag nodes with
1013
- * `onMove`, join ports with `onConnect`. Labels paint only in a registered
2715
+ * `onMove`, join ports with `onConnect`. Every edit is reported, never
2716
+ * written: change the specs to keep it. Labels paint only in a registered
1014
2717
  * font family; `diagramScene` defaults to sans-serif, so call
1015
2718
  * `registerCanvasFont('sans-serif')` or text renders blank. */
1016
2719
  declare const DiagramView: react.ForwardRefExoticComponent<DiagramViewProps & react.RefAttributes<DiagramViewApi>>;
@@ -1021,4 +2724,216 @@ declare const DiagramView: react.ForwardRefExoticComponent<DiagramViewProps & re
1021
2724
  * `<SceneCanvas onClick>`. */
1022
2725
  declare function useMirroredSelection(selection: Pick<SelectionApi, 'get' | 'set'>, selected: string | null | undefined, onSelect: ((id: string | null) => void) | undefined): () => void;
1023
2726
 
1024
- export { ANCHOR_DERIVE_POSE, type ApplyLayoutOptions, BodySpec, CONNECT_ACTION_ID, type CanConnect, type ConnectActionOptions, DEFAULT_EDGE_STROKE, DIAGRAM_ANCHOR, DIAGRAM_EDGE, DIAGRAM_GROUP, DIAGRAM_LABEL, type DataEdge, type DataGroup, type DataNode, type DiagramAnchor, type DiagramContributionOptions, type DiagramData, type DiagramDerivePose, type DiagramEdge, DiagramGroup, type DiagramLabel, DiagramNode, DiagramNodeLike, DiagramNodeReader, type DiagramRouter, type DiagramSceneData, type DiagramSceneOptions, type DiagramShapeOptions, type DiagramSpec, type DiagramTextStyle, DiagramView, type DiagramViewApi, type DiagramViewProps, EASED_LAYOUTS, EDGE_DERIVE_PATH, type EasedProducerOptions, type EdgeEnd, type EdgeRouteOptions, type EdgeStyle, ForceOptions, type ForceProducerOptions, GRAB_PORT_ACTION_ID, GROUP_DERIVE_POSE, Graph, GraphSource, type GroupPoseOptions, LABEL_DERIVE_POSE, LAYOUTS, LAYOUT_ACTION_ID, type LabelPoseOptions, type LayeredRoute, type LayeredRouteInput, type LayoutActionOptions, LayoutDirection, LayoutFn, LayoutOptions, LayoutResult, type LiveLayout, type LiveLayoutCtx, type LiveLayoutFrame, type LiveLayoutProducer, MeasureRowText, type NodeMove, type NodeStyle, Outline, PORT_AFFORDANCE_KIND, PORT_LAYER_ID, type ParticipantPose, type ParticipantScene, type ParticipantSource, type PendingEdge, Port, type PortAffordanceOptions, PortAnchor, type PortScratch, PortSpec, PortsOptions, ROUTERS, type RouteEdge, type RouteRequest, type Router, Row, type SelfLoop, type UseLiveLayoutOptions, anchorDerivePose, applyLayout, bezier, boxAround, commitEdgeToScene, connectBinding, createConnectAction, createDiagramContribution, createLayoutAction, createPortAffordance, defaultCanConnect, diagramAnchorOf, diagramEdgeOf, diagramGroupOf, diagramLabelOf, diagramPorts, diagramScene, diagramShape, easedProducer, edgeDerivePath, edgeIdOf, forceProducer, grabPortAction, grabPortBindings, groupDerivePose, labelDerivePose, layeredRoutes, layoutPoses, orthogonal, portLayer, portScratchOf, registerDiagramShape, resolveEnd, sceneParticipants, selfLoop, straight, useLiveLayout, useMirroredSelection, withDiagramRegistry };
2727
+ /** The themes that ship, by id, in the order a picker lists them. `paper` is ink on white;
2728
+ * `night` is the effect looks' own dark colors. */
2729
+ declare const DIAGRAM_THEMES: Readonly<Record<string, DiagramTheme>>;
2730
+
2731
+ /**
2732
+ * A theme matching its host's chrome, built from resolved `--wzl-*` values:
2733
+ * `read` answers a custom property's value, as `getComputedStyle(el)
2734
+ * .getPropertyValue` does. A token that reads empty takes `paper`'s color.
2735
+ */
2736
+ declare function diagramThemeFromTokens(read: (token: string) => string, opts?: {
2737
+ id?: string;
2738
+ name?: string;
2739
+ }): DiagramTheme;
2740
+
2741
+ /** The style a shape naming `role` is drawn in: that role's, or the theme's default role's. */
2742
+ declare function roleStyle(theme: DiagramTheme, role?: string): NodeStyle;
2743
+ /** The style a connector naming `role` is drawn in: the role's stroke, its label in that stroke too;
2744
+ * with no role, the theme's own connector and label colors. */
2745
+ declare function roleEdgeStyle(theme: DiagramTheme, role?: string): EdgeStyle;
2746
+ /** The stroke a connector drawn under `theme` starts with, for a connect action's `edgeStroke`. */
2747
+ declare function themeEdgeStroke(theme: DiagramTheme): Stroke;
2748
+ /** The theme's face as `diagramScene` and the stencils take one. */
2749
+ declare const themeFont: (theme: DiagramTheme) => {
2750
+ fontFamily: string;
2751
+ fontSize: number;
2752
+ };
2753
+ /** The face edge labels are sized from, before `labelStyleOf` takes two sizes off: the theme's label
2754
+ * face where it names one, else `font`. */
2755
+ declare const themeLabelFont: (theme: DiagramTheme, font?: {
2756
+ fontFamily: string;
2757
+ fontSize: number;
2758
+ }) => {
2759
+ fontFamily: string;
2760
+ fontSize: number;
2761
+ };
2762
+ /** The face a new connector label is set in under `theme`. */
2763
+ declare const themeLabelStyle: (theme: DiagramTheme) => {
2764
+ fontSize: number;
2765
+ fontFamily: string;
2766
+ };
2767
+ /** The theme a document value names: a shipped theme by id, or a whole theme. `fallback` for none,
2768
+ * or for an id no shipped theme has. */
2769
+ declare function diagramThemeFrom(value: unknown, fallback?: DiagramTheme): DiagramTheme;
2770
+ /** The theme a scene's `diagram:theme` value names. */
2771
+ declare function diagramThemeOf(scene: {
2772
+ doc: {
2773
+ get(key: string): unknown;
2774
+ };
2775
+ }, fallback?: DiagramTheme): DiagramTheme;
2776
+ /** What `diagram:theme` holds for `theme`: a shipped theme's id, or the whole theme. */
2777
+ declare const themeDocValue: (theme: DiagramTheme) => string | DiagramTheme;
2778
+
2779
+ /** A scene node as {@link themeWrites} reads it. */
2780
+ interface ThemedNode {
2781
+ id: string;
2782
+ parent: string | null;
2783
+ data: unknown;
2784
+ dependsOn?: readonly string[] | 'children';
2785
+ }
2786
+ /** A scene as {@link themeWrites} reads it. */
2787
+ interface ThemedScene {
2788
+ get(id: never): ThemedNode | undefined;
2789
+ renderOrderNodes(): readonly ThemedNode[];
2790
+ childrenOf(id: never): readonly string[];
2791
+ }
2792
+ /**
2793
+ * The new `data` for every node `theme` recolors: shapes, their text rows,
2794
+ * groups and containers and their titles, connectors and their labels. Given
2795
+ * `ids`, only those boxes and connectors, and the text that belongs to them.
2796
+ * Given `from`, the theme the scene was in, text moves by the step between the
2797
+ * two themes' sizes, except where its owner's author set the size. A node
2798
+ * already as the theme draws it is left out.
2799
+ */
2800
+ declare function themeWrites(scene: ThemedScene, theme: DiagramTheme, ids?: ReadonlySet<string>, from?: DiagramTheme): Map<string, unknown>;
2801
+
2802
+ /**
2803
+ * Measures a row's text as the kit's text renderer lays it out, from the
2804
+ * registered font's metrics, so a body sized by it holds the text it draws.
2805
+ * The line height is 1.2 sizes, as `canvasMeasure`'s is. Needs the family
2806
+ * registered; an unregistered one measures as the fallback glyph.
2807
+ */
2808
+ declare const rendererMeasure: MeasureRowText;
2809
+
2810
+ /**
2811
+ * Laying a built body out again once its text changes size. A body whose
2812
+ * rows are all text records how it stacks them (`DiagramNode.body`), and each
2813
+ * text row records its place (`bodyRow`), so the rows can be read back from
2814
+ * the scene and handed to the same layout `buildBody` used.
2815
+ */
2816
+
2817
+ /** A scene as {@link relayoutBodies} reads and writes it. */
2818
+ interface RelayoutScene {
2819
+ get(id: never): {
2820
+ pose: unknown;
2821
+ data: unknown;
2822
+ } | undefined;
2823
+ childrenOf(id: never): readonly string[];
2824
+ setPose(id: never, pose: never): void;
2825
+ }
2826
+ /**
2827
+ * Lays each body among `ids` out again from its text rows as they are now:
2828
+ * the body grows to what its rows need, never shrinks, and its rows are
2829
+ * stacked again inside it. Anything that is not a body carrying a `body`
2830
+ * record is left alone. Call inside the batch that changed the text, so it is
2831
+ * the same undo entry.
2832
+ */
2833
+ declare function relayoutBodies(scene: RelayoutScene, ids: Iterable<string>, measure?: MeasureRowText): void;
2834
+
2835
+ /**
2836
+ * The edits a theme makes to a scene, each one undo entry: applying a theme,
2837
+ * naming a shape's or connector's role, and setting a color by hand.
2838
+ */
2839
+
2840
+ type AnyScene = Scene<unknown, string, unknown>;
2841
+ /** What a styleable node says about its style: a shape or a connector, the role it names, and the
2842
+ * colors its author set by hand. */
2843
+ interface DiagramStyleState {
2844
+ kind: 'shape' | 'connector';
2845
+ role?: string;
2846
+ own: readonly StyleField[];
2847
+ /** The parts of its text face the author set: a theme's size change leaves those. */
2848
+ ownFont: readonly FontField[];
2849
+ }
2850
+ /** The style state of a shape (a body) or a connector, or `null` for anything else — a text row,
2851
+ * a label, a group, a container. */
2852
+ declare function diagramStyleOf(node: {
2853
+ data: unknown;
2854
+ }): DiagramStyleState | null;
2855
+ /** Options for {@link applyDiagramTheme}. */
2856
+ interface ApplyDiagramThemeOptions {
2857
+ /** Fold this apply into the undo entry before it when that one was made under the same key, so a
2858
+ * run of applies, such as a theme color dragged, undoes as one. See `scene.batch`. */
2859
+ coalesceKey?: string;
2860
+ /** The theme the scene is in now, whose font size text moves from. Default the scene's own
2861
+ * `diagram:theme`; a host that draws a scene naming none in another theme passes that. */
2862
+ from?: DiagramTheme;
2863
+ /** Measures text, for laying out again a body whose text changed size. Default an estimate. */
2864
+ measure?: MeasureRowText;
2865
+ }
2866
+ /** Recolors the whole scene in `theme` and saves it as the `diagram:theme` document value, as one
2867
+ * undo entry. Colors the author set by hand stay. */
2868
+ declare function applyDiagramTheme(scene: AnyScene, theme: DiagramTheme, label?: string, opts?: ApplyDiagramThemeOptions): void;
2869
+ /** Options for {@link setDiagramStyle} and {@link setDiagramColor}. */
2870
+ interface DiagramStyleEditOptions {
2871
+ /** The theme to color by. Default the scene's own `diagram:theme`. */
2872
+ theme?: DiagramTheme;
2873
+ label?: string;
2874
+ }
2875
+ /**
2876
+ * Names `role` on every shape and connector among `ids` and recolors them in
2877
+ * it, as one undo entry. Choosing a role hands back any color the author had
2878
+ * set, so the role shows.
2879
+ */
2880
+ declare function setDiagramStyle(scene: AnyScene, ids: readonly string[], role: string, opts?: DiagramStyleEditOptions): void;
2881
+ /**
2882
+ * Sets `field` to `color` on every shape and connector among `ids` — `text`
2883
+ * reaching a shape's rows and a connector's label — and records it in their
2884
+ * `ownStyle`, so a theme change leaves it. One undo entry. A connector has no
2885
+ * fill, and ignores one.
2886
+ */
2887
+ declare function setDiagramColor(scene: AnyScene, ids: readonly string[], field: StyleField, color: string, opts?: Pick<DiagramStyleEditOptions, 'label'>): void;
2888
+ /**
2889
+ * Sets the text of every shape and connector among `ids` — a shape's rows, a
2890
+ * connector's label — to `size`, and records it in their `ownFont`, so a
2891
+ * theme's size change leaves it. One undo entry.
2892
+ */
2893
+ declare function setDiagramFontSize(scene: AnyScene, ids: readonly string[], size: number, opts?: Pick<DiagramStyleEditOptions, 'label'> & {
2894
+ measure?: MeasureRowText;
2895
+ }): void;
2896
+
2897
+ type BoxField = 'fill' | 'stroke' | 'text';
2898
+ /** Where one value sits in a {@link DiagramTheme}. */
2899
+ type ThemePath = readonly ['roles', string, BoxField] | readonly ['edge', 'stroke'] | readonly ['label', 'fill'] | readonly ['container', BoxField] | readonly ['lane', 'header', BoxField] | readonly ['lane', 'bodies', number, BoxField] | readonly ['page'] | readonly ['font', 'family'] | readonly ['font', 'size'] | readonly ['series', number];
2900
+ /** Whether `theme` is one of {@link DIAGRAM_THEMES} itself, which no edit may change. */
2901
+ declare const isShippedTheme: (theme: DiagramTheme) => boolean;
2902
+ /** A custom copy of `theme`, named "<name> (edited)", for a document to keep and change. */
2903
+ declare function forkTheme(theme: DiagramTheme): DiagramTheme;
2904
+ /** `theme` when it is already a custom theme, else a fork of it: what the first edit to a shipped
2905
+ * theme starts from. */
2906
+ declare const editableTheme: (theme: DiagramTheme) => DiagramTheme;
2907
+ /** The value at `path` in `theme`. */
2908
+ declare function themeValue(theme: DiagramTheme, path: ThemePath): unknown;
2909
+ /** `theme` with `value` at `path`; everything else shared with it. */
2910
+ declare const setThemeValue: (theme: DiagramTheme, path: ThemePath, value: string | number) => DiagramTheme;
2911
+ /** Every role `theme` styles with the name a picker shows: the shipped roles first, in their order,
2912
+ * then the theme's own. */
2913
+ declare function themeRoles(theme: DiagramTheme): {
2914
+ id: string;
2915
+ label: string;
2916
+ }[];
2917
+ /** `theme` with a role named `label`, in the default role's colors, and the id it was given. */
2918
+ declare function addThemeRole(theme: DiagramTheme, label: string): {
2919
+ theme: DiagramTheme;
2920
+ id: string;
2921
+ };
2922
+ /** `theme` with role `id` shown as `label`. The id, which shapes name the role by, stays. */
2923
+ declare const renameThemeRole: (theme: DiagramTheme, id: string, label: string) => DiagramTheme;
2924
+ /** `theme` without role `id`; its shapes fall to the default role when the theme is next applied.
2925
+ * The default role stays: `theme` comes back unchanged. */
2926
+ declare function removeThemeRole(theme: DiagramTheme, id: string): DiagramTheme;
2927
+
2928
+ /** The extension a theme file is saved with. */
2929
+ declare const DIAGRAM_THEME_EXTENSION = ".weasel-theme.json";
2930
+ /** `theme` as the text of a theme file. */
2931
+ declare const themeToJson: (theme: DiagramTheme) => string;
2932
+ /** The theme a theme file holds, or what is wrong with it, each error naming where. */
2933
+ declare function parseDiagramTheme(json: string): {
2934
+ theme: DiagramTheme;
2935
+ } | {
2936
+ errors: string[];
2937
+ };
2938
+
2939
+ export { ADD_LANE_ACTION_ID, type ApplyDiagramThemeOptions, type ApplyLayoutOptions, AvoidInput, AvoidOptions, AvoidRouter, AvoidRoutes, type AvoidRouting, type AvoidRoutingOptions, type AvoidSceneOptions, type BodyEnd, type BodyHit, Bounds$2 as Bounds, CONNECTOR_ACTION_ID, CONNECTOR_TOOL_ID, CONNECT_ACTION_ID, CONTAINER_HEADER, CONTAINER_LAYOUTS, CONTAINER_STENCILS, type CanConnect, type ConnectActionOptions, type ConnectEnd, type ConnectView, type ContainerBuildOptions, type ContainerEdit, ContainerHeader, type ContainerLayoutOptions, ContainerRole, type ContainerStencil, DEFAULT_EDGE_STROKE, DIAGRAM_CONTAINER_LAYOUT, DIAGRAM_EDGE, DIAGRAM_LABEL, DIAGRAM_LANE_COLUMNS_LAYOUT, DIAGRAM_LANE_ROWS_LAYOUT, DIAGRAM_OFF_PAGE_TAG, DIAGRAM_PASS_ORDER, DIAGRAM_POOL_COLUMNS_LAYOUT, DIAGRAM_POOL_ROWS_LAYOUT, DIAGRAM_THEMES, DIAGRAM_THEME_EXTENSION, DataContainer, DataEdge, DataNode, type DeleteReport, DiagramContainer, type DiagramContributionOptions, DiagramData, DiagramEdge, DiagramLabel, type DiagramLayout, DiagramNodeLike, DiagramNodeReader, type DiagramOverlay, DiagramSceneData, DiagramSceneOptions, type DiagramShapeOptions, DiagramSpec, type DiagramStencil, type DiagramStyleEditOptions, type DiagramStyleState, DiagramTheme, DiagramView, type DiagramViewApi, type DiagramViewProps, type DraggableLabel, type DropParentScene, EASED_LAYOUTS, EDGE_DERIVE_PATH, EDGE_END_AFFORDANCE_KIND, EDGE_END_LAYER_ID, EDIT_CONTAINER_TITLE_ACTION_ID, EDIT_EDGE_LABEL_ACTION_ID, type EasedProducerOptions, EdgeEnd, type EdgeEndAffordanceOptions, type EdgeEndScratch, EdgeHop, type EdgeLabelOptions, type EdgeRoute, type EdgeRouteOptions, type EdgeRouteState, EdgeStyle, type EditEdgeLabelOptions, type EndChange, FLOWCHART_STENCILS, FOLLOW_OFF_PAGE_ACTION_ID, type FollowOffPageOptions, FontField, ForceOptions, type ForceProducerOptions, GRAB_EDGE_END_ACTION_ID, GRAB_LABEL_ACTION_ID, GRAB_PORT_ACTION_ID, GRAB_WAYPOINT_ACTION_ID, Graph, GraphNodeLike, GraphSource, type Hops, type HopsOptions, LABEL_DERIVE_POSE, LABEL_DRAG_AFFORDANCE_KIND, LABEL_DRAG_LAYER_ID, LANE_AFFORDANCE_KIND, LANE_HEADER_SIZE, LANE_LAYER_ID, LANE_RESIZE_ACTION_ID, LAYOUTS, LAYOUT_ACTION_ID, type LabelDragOptions, type LabelEdit, type LabelMove, type LabelPlacement, type LabelPlacementOptions, type LabelPoseOptions, type LabelScratch, LabelSpot, type LaneActionOptions, type LaneLayerOptions, type LaneResize, type LaneScratch, type LaneStackOptions, type LayeredRoute, type LayeredRouteInput, type LayoutActionOptions, LayoutDirection, LayoutFn, LayoutOptions, LayoutPlan, LayoutPlanner, LayoutPorts, LayoutResult, type LayoutRoutes, type LiveLayout, type LiveLayoutCtx, type LiveLayoutFrame, type LiveLayoutProducer, MIN_LANE_SIZE, MOVE_LABEL_ACTION_ID, MeasureRowText, type MovingEnd, type NodeMove, type NodeResize, NodeStyle, OFF_PAGE_STUB, OFF_PAGE_TAG_DERIVE_POSE, OFF_PAGE_TAG_PADDING, type OffPageEdgeInput, type OffPageMarkerOptions, OffPageSplit, type OffPageSplitInput, type OffPageTagLook, type OffPageTarget, Outline, POOL_HEADER_SIZE, PORT_AFFORDANCE_KIND, PORT_LAYER_ID, type ParticipantPose, type ParticipantScene, type ParticipantSource, type PendingEdge, PlaceLabelsOptions, type PoolLanes, Port, type PortAffordanceOptions, type PortScratch, PortsOptions, RECONNECT_ACTION_ID, RELEASE_MEMBERS_ACTION_ID, REMOVE_WAYPOINT_ACTION_ID, REORDER_ACTION_ID, RESET_LABEL_ACTION_ID, RESET_ROUTE_ACTION_ID, ROUTERS, ROUTER_LABELS, ROUTE_EDIT_ACTION_ID, type ReconnectChange, type ReconnectOptions, type RegionOptions, type RegionSpec, type RelayoutScene, type ReorderChange, type ReorderGap, type ReorderItem, type ReorderMove, type ReorderOptions, type ReorderSlots, type ResolvedRoute, type RouteChange, type RouteEdge, type RouteEdit, type RouteEditOptions, type RouteHandle, type RouteRequest, type RoutedScene, type Router, type RouterEdit, Row, RowTextStyle, SELECT_LABEL_EDGE_ACTION_ID, SET_HOPS_ACTION_ID, SET_ROUTER_ACTION_IDS, STEP_REORDER_ACTION_ID, type SelfLoop, type SetHopsOptions, type SetRouterOptions, type StencilInsertOptions, StyleField, type StyledRegion, type ThemePath, type ThemedNode, type ThemedScene, type UseLiveLayoutOptions, WAYPOINT_AFFORDANCE_KIND, WAYPOINT_HIT_PX, WAYPOINT_LAYER_ID, type WaypointAffordanceOptions, type WaypointScratch, addLane, addThemeRole, applyDiagramTheme, applyLayout, avoid, avoidSceneInput, bezier, bodyAt, commitEdgeToScene, commitLabelToScene, commitLaneResizeToScene, commitReconnectToScene, commitRouteToScene, commitRouterToScene, connectBinding, connectorTool, containerBuild, containerShape, createAddLaneAction, createConnectAction, createDiagramContribution, createEdgeEndAffordance, createFollowOffPageAction, createLabelDragAction, createLaneAffordance, createLaneResizeAction, createLayoutAction, createPortAffordance, createReconnectAction, createReleaseMembersAction, createRemoveWaypointAction, createReorderAction, createResetLabelAction, createResetRouteAction, createRouteEditAction, createSetHopsAction, createSetRouterAction, createSpecHops, createSpecLabelPlacer, createSpecRouter, createStepReorderAction, createWaypointAffordance, dataEdgeStyle, dataNodeStyle, dataOffPage, dataRegionStyle, defaultCanConnect, diagramCanDropInto, diagramContainerLayout, diagramContainers, diagramDropParentAt, diagramEdgeEnds, diagramLabelDrag, diagramLayoutOf, diagramOffPage, diagramPages, diagramPorts, diagramResizable, diagramScene, diagramShape, diagramStyleOf, diagramThemeFrom, diagramThemeFromTokens, diagramThemeOf, diagramWaypoints, documentBoundsOf, dragSegment, dragVertex, draggableLabels, dropEmptyEdgeLabel, easedProducer, edgeDerivePath, edgeEndLayer, edgeEndScratchOf, edgeIdOf, edgeLabelSpec, edgeRouter, editContainerTitleAction, editContainerTitleBinding, editEdgeLabelAction, editEdgeLabelBinding, editableTheme, firstLanes, followOffPageBinding, forceProducer, forkTheme, grabPortAction, grabPortBindings, groupReorderContribution, groupReorderSlots, headerIdOf, hopFollower, insertWaypoint, installAvoidRouting, installHops, installLabelPlacement, installOffPageMarkers, isBodyEnd, isShippedTheme, labelDerivePose, labelDragLayer, labelScratchOf, labelSize, labelUnder, laneHeader, laneLayer, laneResizeFrame, laneScratchOf, laneStackLayout, lanesOf, layeredRoutes, layoutPoses, movedLabelData, nextOffPageRef, offPageFarText, offPageOps, offPageSplits, offPageTagData, offPageTagDerivePose, offPageTagLook, offPageTagSize, offPageTagSpec, offPageTagSpecs, offPageTagText, offPageTargetOf, orthogonal, parseDiagramTheme, pinSegment, poolAxisOf, poolHeader, poolsOf, portLayer, portScratchOf, reconnectBinding, regionHeaderAt, regionSpecs, registerDiagramShape, relayoutBodies, releaseMembers, removeSegment, removeThemeRole, removeWaypoint, renameThemeRole, rendererMeasure, reorderBinding, reorderContribution, resolveEnd, roleEdgeStyle, roleStyle, routeDataOps, routeHandles, routeStateOf, routeWrites, routedData, routerActions, routesOf, sceneParticipants, segmentAxis, selfLoop, sequenceSlots, setDiagramColor, setDiagramFontSize, setDiagramStyle, setThemeValue, simplifyStops, stackedLanes, stencilBuild, stencilIdOf, stencilKind, stencilTool, straight, subpathOf, themeDocValue, themeEdgeStroke, themeFont, themeLabelFont, themeLabelStyle, themeRoles, themeToJson, themeValue, themeWrites, titlePose, unpinSegment, useAvoidRouting, useConnectorTool, useHops, useLabelPlacement, useLiveLayout, useMirroredSelection, useOffPageMarkers, useStencilInsert, useStencilTool, waypointFollower, waypointLayer, waypointScratchOf, withDiagramRegistry, withHops, withRouter };