@weasel-js/diagram 1.10.0 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,8 +1,12 @@
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 } from './layout.entry-CIdRpG2i.js';
2
- export { j as BodyFloor, k as BodyNodeSpec, l as Bounds, m as BuildBodyOptions, n as BuildGraphOptions, C as COMPASS, o as DEFAULT_GROUP_INSET, p as DEFAULT_NODE_GAP, q as DEFAULT_PORTS, r as DEFAULT_RANK_GAP, s as DIAGRAM_TRAIT_KEY, t as DiagramNodeEntry, u as ForceBody, v as ForceRelaxation, w as Forest, x as GraphEdge, y as GraphGroup, z as GraphNode, A as GraphNodeLike, E as GroupInset, H as LayoutAxes, I as LayoutDirection, 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-CIdRpG2i.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 { f as Port, g as DiagramNodeLike, h as DiagramNodeReader, d as LayoutOptions, i as LayoutResult, G as Graph, c as LayoutFn, j as GraphSource, k as LayoutPlanner, l as LayoutDirection, L as LayoutPorts, m as LayoutPlan, n as GraphNodeLike } from './body-2lC7IiIA.js';
2
+ export { o as BodyFloor, p as BodyNodeSpec, B as BodySpec, q as Bounds, r as BuildBodyOptions, s as BuildGraphOptions, t as DEFAULT_GROUP_INSET, u as DEFAULT_NODE_GAP, v as DEFAULT_RANK_GAP, w as DIAGRAM_TRAIT_KEY, D as DiagramGroup, e as DiagramNode, x as DiagramNodeEntry, E as EdgeLabelRoom, y as GraphEdge, z as GraphGroup, A as GraphNode, C as GroupInset, F as LayoutAxes, M as MeasureRowText, O as Outline, H as PORT_LABEL_GAP, I as PerimeterPortLabelBox, P as PortAnchor, J as PortLabelPlacement, K as PortSite, b as PortSpec, a as Row, N as RowBox, Q as RowNodeData, S as RowPort, T as RowPortBox, R as RowTextStyle, U as Slot, V as anchorOffset, W as axesFor, X as bodyOutline, Y as bodyTrait, Z as boxForContent, _ as buildBody, $ as buildGraph, a0 as canvasMeasure, a1 as contentBox, a2 as createDiagramNodes, a3 as dataKeyReader, a4 as diagramNodeOf, a5 as expandGroupEdges, a6 as graphOrder, a7 as insetOf, a8 as isPinned, a9 as layoutBody, aa as layoutRowPorts, ab as marginOf, ac as measureBody, ad as outlinePath, ae as packAcross, af as packClusters, ag as pinnedSet, ah as planOf, ai as plannerPlan, aj as portLabelBox, ak as portLabelsOf, al as rankGaps, am as seededOrder, an as settle, ao as sizeToBody, ap as translated, aq as untilSettled } from './body-2lC7IiIA.js';
3
+ import { P as PortsOptions, F as ForceOptions } from './layout.entry-BoWFcR4G.js';
4
+ export { C as COMPASS, D as DEFAULT_PORTS, a as ForceBody, b as ForceRelaxation, c as Forest, L as LayeredPlan, d as backEdges, e as chain, f as footprintNode, g as force, h as forceRelaxation, i as forestOf, l as layered, j as layeredPlan, o as outlinePolyline, p as portOf, k as portSitesOf, m as portsOf, n as portsOnOutline, r as ranksByLength, q as ranksOf, s as rayHit, t as tree } from './layout.entry-BoWFcR4G.js';
5
+ import { Vec2, DerivedDep, Path, SceneRegistry, PoseDescriptor, ChromeState, CommandFill, CommandStroke, CursorSpec, Affordance, InvocationCtx, Stroke, GestureBinding, Action, Contribution, RenderLayer, NodeId, Scene, GatedLayer, Fill, NodeShapeEntry, RectPose, Paint, View, SelectionApi } from '@weasel-js/core';
6
+ import { f as EdgeEnd, e as DiagramSpec, b as DataEdge } from './fromData-GKqRgPFs.js';
7
+ export { A as ANCHOR_DERIVE_POSE, g as DIAGRAM_ANCHOR, h as DIAGRAM_GROUP, i as DataGroup, j as DataMark, c as DataNode, k as DiagramAnchor, D as DiagramData, l as DiagramDerivePose, m as DiagramEdge, n as DiagramLabel, o as DiagramMark, d as DiagramRouter, p as DiagramSceneData, a as DiagramSceneOptions, q as DiagramTextStyle, E as EdgeStyle, G as GROUP_DERIVE_POSE, r as GroupPoseOptions, N as NodeStyle, s as anchorDerivePose, t as boxAround, u as diagramAnchorOf, v as diagramEdgeOf, w as diagramGroupOf, x as diagramLabelOf, y as diagramMarkOf, z as diagramScene, B as edgeIdOf, C as groupDerivePose, F as layoutOwnsPort, H as layoutOwnsRoute, I as markShape, J as registerMarkShape } from './fromData-GKqRgPFs.js';
5
8
  import { EasingFn } from '@weasel-js/animator';
9
+ import { Vec2 as Vec2$1 } from '@weasel-js/core/math';
6
10
  import * as react from 'react';
7
11
  import '@weasel-js/geom';
8
12
  import '@weasel-js/simulation';
@@ -24,24 +28,6 @@ import '@weasel-js/simulation';
24
28
  * `markerStart` / `markerEnd` any other stroke carries.
25
29
  */
26
30
 
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;
33
- }
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[];
44
- }
45
31
  /** What a router is given: the two resolved ends, and the author's waypoints
46
32
  * between them. */
47
33
  interface RouteRequest {
@@ -68,19 +54,16 @@ declare const orthogonal: Router;
68
54
  * A smooth route, sampled into points.
69
55
  *
70
56
  * Each leg is a cubic that leaves along the departing end's normal and arrives
71
- * against the receiving one's. Sampled rather than emitted as curve commands so
72
- * every router returns the same thing.
57
+ * against the receiving one's, and passes each waypoint without a corner.
58
+ * Sampled rather than emitted as curve commands so every router returns the
59
+ * same thing.
73
60
  */
74
61
  declare const bezier: Router;
75
62
  /** The routers this package ships. A consumer's own go in the same shape. */
76
63
  declare const ROUTERS: Readonly<Record<string, Router>>;
77
- /** The edge trait on a node's data, or `null`. */
78
- declare function diagramEdgeOf(node: {
79
- data: unknown;
80
- }): DiagramEdge | null;
81
64
  /**
82
- * The port an end resolves to: the one it named, else the port facing the
83
- * other end most directly.
65
+ * The port an end resolves to: the one it named, at whichever of its places
66
+ * faces `toward` most directly, else the port facing `toward` most directly.
84
67
  *
85
68
  * "Facing" rather than "nearest": a port on the far side of a wide node can be
86
69
  * closer in a straight line than the one pointing at the target.
@@ -152,6 +135,14 @@ declare const PORT_AFFORDANCE_KIND: "layer:diagram-ports";
152
135
  interface ParticipantPose<TPose> {
153
136
  node: DiagramNodeLike;
154
137
  pose: TPose;
138
+ /** Not drawn: on a hidden layer, or hidden on its own or by an ancestor.
139
+ * `sceneParticipants` answers it from the scene's `nodeGates`. */
140
+ hidden?: boolean;
141
+ /** Out of reach: locked, or on a locked layer. */
142
+ locked?: boolean;
143
+ /** The scene layer the node is painted on, which the asking view may not
144
+ * paint (`ChromeState.layerIsPainted`, `ViewApi.layerIsPainted`). */
145
+ layer?: string;
155
146
  }
156
147
  /** Where the affordance gets its participants. A thunk rather than a scene so
157
148
  * the geometry is testable without one, and so a consumer whose participants
@@ -177,13 +168,21 @@ interface PortAffordanceOptions<TPose> {
177
168
  /** Which participants show their ports. Default: all of them. Gate on
178
169
  * selection or hover by reading `state`. */
179
170
  shows?: (node: DiagramNodeLike, state: ChromeState) => boolean;
171
+ /** Which of a participant's ports show. Default: all of them. A port
172
+ * this turns away is not painted or grabbable, and passed with the connect
173
+ * options (as `diagramPorts` and `DiagramView` do), no connect lands on it. */
174
+ showsPort?: (port: Port) => boolean;
180
175
  /** Screen-pixel hit radius. Default 8, the kit's `HANDLE_BASE_PX`. */
181
176
  hitRadiusPx?: number;
182
- /** Screen-pixel side of the painted square. Default 7. Omit `paint` entirely
183
- * by passing 0 — a port the consumer draws itself is still hittable. */
177
+ /** Screen-pixel size of the painted mark: a square's side, or a circle's
178
+ * diameter. Default 7. Omit `paint` entirely by passing 0 — a port the
179
+ * consumer draws itself is still hittable. */
184
180
  sizePx?: number;
185
- fill?: CommandFill;
181
+ /** One fill for every port, or a function of the port — its `type`, say. */
182
+ fill?: CommandFill | ((port: Port) => CommandFill);
186
183
  stroke?: CommandStroke;
184
+ /** Default `'square'`. */
185
+ shape?: 'square' | 'circle';
187
186
  cursor?: CursorSpec;
188
187
  /** Default `'exclusive'` on pointer gestures: a drag from a port is a
189
188
  * connect, never a move of the node underneath it. */
@@ -249,6 +248,10 @@ interface ConnectActionOptions<TPose> {
249
248
  geometry?: PoseDescriptor<TPose>;
250
249
  /** Default {@link defaultCanConnect}. */
251
250
  canConnect?: CanConnect;
251
+ /** Which ports a connect may land on: a port this turns away is never a
252
+ * target. The port affordance's option of the same name, so a port that is
253
+ * not shown cannot be dropped onto. Default: all of them. */
254
+ showsPort?: (port: Port) => boolean;
252
255
  /** How near the pointer must come to a port, in world units, before the
253
256
  * edge snaps to it. Default 16. */
254
257
  snapRadius?: number;
@@ -364,20 +367,6 @@ declare function selfLoop(ports: readonly Port[], standoff: number): SelfLoop |
364
367
  * data, styling, z-order and selection.
365
368
  */
366
369
 
367
- /** Where along an edge a label sits. */
368
- interface DiagramLabel {
369
- /** `'start'`, `'mid'` and `'end'` are 0, 0.5 and 1; a number is that
370
- * fraction of the route's length. */
371
- at: 'start' | 'mid' | 'end' | number;
372
- /** World units perpendicular to the route, to the **left of the direction of
373
- * travel** — above a left-to-right edge. Default 0, which centers the label
374
- * on the line. */
375
- offset?: number;
376
- }
377
- /** The label trait on a node's data, or `null`. */
378
- declare function diagramLabelOf(node: {
379
- data: unknown;
380
- }): DiagramLabel | null;
381
370
  /** Options for {@link labelDerivePose}. `geometry` defaults to the kit's
382
371
  * `AUTO_POSE_DESCRIPTOR`. */
383
372
  interface LabelPoseOptions<TPose> {
@@ -405,232 +394,11 @@ declare const LABEL_DERIVE_POSE: (node: {
405
394
  }, deps: readonly (DerivedDep<unknown, unknown, string> | undefined)[]) => unknown;
406
395
 
407
396
  /**
408
- * A group's box, and anything pinned to a point on another node.
409
- *
410
- * The box is an ordinary node that depends on its members and derives its pose
411
- * from theirs: their union, grown by the inset. Drag a member and the box
412
- * follows; lay the diagram out and the box lands around wherever the members
413
- * went. Nothing has to keep it in sync, because nothing stores it.
414
- *
415
- * An anchored node — a group's title is the first — derives its pose from one
416
- * dependency's bounds the same way, so it travels with the box it labels.
417
- */
418
-
419
- /** Where an anchored node sits on its dependency. */
420
- interface DiagramAnchor {
421
- /** The point on the dependency's bounds, normalized as a port's is. */
422
- at: PortAnchor;
423
- /** The point on the node's own bounds that lands there. Default `at`, so
424
- * `{ u: 0, v: 0 }` puts the node's top-left on the dependency's. */
425
- self?: PortAnchor;
426
- /** Then moved by this much, in world units. */
427
- offset?: Vec2$1;
428
- }
429
- /** The group trait on a node's data, or `null`. */
430
- declare function diagramGroupOf(node: {
431
- data: unknown;
432
- }): DiagramGroup | null;
433
- /** The anchor trait on a node's data, or `null`. */
434
- declare function diagramAnchorOf(node: {
435
- data: unknown;
436
- }): DiagramAnchor | null;
437
- /** Options for {@link groupDerivePose} and {@link anchorDerivePose}.
438
- * `geometry` defaults to the kit's `AUTO_POSE_DESCRIPTOR`. */
439
- interface GroupPoseOptions<TPose> {
440
- geometry?: PoseDescriptor<TPose>;
441
- }
442
- /** A `derivePose` function as the scene calls it: the node, then what it depends on, in `dependsOn` order. */
443
- type DiagramDerivePose<TPose> = (node: {
444
- pose: TPose;
445
- data: unknown;
446
- }, deps: readonly (DerivedDep<TPose> | undefined)[]) => TPose | null;
447
- /**
448
- * A `derivePose` that draws a group's box around its members: their union,
449
- * grown by the trait's inset. `null` — the authored pose stands — when the node
450
- * carries no group trait or every member is gone.
451
- */
452
- declare function groupDerivePose<TPose>(opts?: GroupPoseOptions<TPose>): DiagramDerivePose<TPose>;
453
- /**
454
- * A `derivePose` that keeps a node at a point on its dependency's bounds.
455
- * `null` when the node carries no anchor trait or the dependency is gone.
456
- */
457
- declare function anchorDerivePose<TPose>(opts?: GroupPoseOptions<TPose>): DiagramDerivePose<TPose>;
458
- /** Registry key for {@link GROUP_DERIVE_POSE}. */
459
- declare const DIAGRAM_GROUP = "diagram:group";
460
- /** Registry key for {@link ANCHOR_DERIVE_POSE}. */
461
- declare const DIAGRAM_ANCHOR = "diagram:anchor";
462
- /** The default group derivation, a stable reference so `toJSON` can find its key. */
463
- declare const GROUP_DERIVE_POSE: DiagramDerivePose<unknown>;
464
- /** The default anchor derivation, a stable reference for the same reason. */
465
- declare const ANCHOR_DERIVE_POSE: DiagramDerivePose<unknown>;
466
-
467
- /**
468
- * `diagramScene` — a laid-out diagram from plain `{ nodes, edges }`.
469
- *
470
- * Every box is a `buildBody` body, so a data node can say anything a body
471
- * can: outline, rows, padding, ports. Sizes are estimated from character
472
- * counts unless `measure` is given, so layout runs without a canvas and gives
473
- * the same answer in node and in a browser.
397
+ * A live layout's producers: what each frame of a run says about where the
398
+ * participants are. `forceProducer` relaxes; `easedProducer` walks to a
399
+ * destination it knows. `useLiveLayout` (`live.ts`) runs them.
474
400
  */
475
401
 
476
- /** One node of a {@link DiagramData}: its rows of text, and optionally its outline, ports, size, and starting place. */
477
- interface DataNode {
478
- id: string;
479
- /** Shorthand for one `label` row per line. Ignored when `rows` is given. */
480
- lines?: readonly string[];
481
- rows?: readonly Row[];
482
- /** Default `DiagramSceneOptions.outline`, which defaults to `'rect'`. */
483
- outline?: Outline;
484
- /** Perimeter ports, replacing the four compass midpoints. */
485
- ports?: readonly PortSpec[];
486
- /** Layout leaves this node at `at`. */
487
- pinned?: boolean;
488
- /** Where the node starts, before layout. Unset, nodes start on the
489
- * diagonal in source order, which is what within-rank order is seeded
490
- * from. */
491
- at?: Vec2$1;
492
- /** The smallest the box may be. Its content grows it past this. */
493
- width?: number;
494
- height?: number;
495
- /** Default `DiagramSceneOptions.padding`. */
496
- padding?: number;
497
- /** Default `DiagramSceneOptions.gap`. */
498
- gap?: number;
499
- /** Default `DiagramSceneOptions.verticalAlign`. */
500
- verticalAlign?: BodySpec['verticalAlign'];
501
- }
502
- /** One edge of a {@link DiagramData}, between two nodes or groups by id. */
503
- interface DataEdge {
504
- /** A node's id, or a group's: an edge naming a group meets its box. */
505
- from: string;
506
- to: string;
507
- /** The port to leave from or arrive at. Unset, the end facing the other
508
- * node most directly. */
509
- fromPort?: string;
510
- toPort?: string;
511
- label?: string;
512
- /** Where along the edge the label sits. Default `DiagramSceneOptions.labelPlacement`. */
513
- labelPlacement?: DiagramLabel;
514
- /** Default `DiagramSceneOptions.router`. */
515
- router?: DiagramRouter;
516
- /** World points the route passes through. Layout does not move them. */
517
- waypoints?: readonly Vec2$1[];
518
- }
519
- /** A box drawn around some nodes, which layout keeps together. */
520
- interface DataGroup {
521
- /** Shares one namespace with node ids. */
522
- id: string;
523
- /** Node ids, and the ids of groups nested in this one. A node or group a
524
- * later group also names stays in this one; an id that is neither is
525
- * ignored, and so is one that would put a group inside itself. */
526
- members: readonly string[];
527
- /** Drawn inside the box, above its members. */
528
- label?: string;
529
- /** Between the box and its members, and around the label. Default
530
- * `DiagramSceneOptions.groupPadding`. */
531
- padding?: number;
532
- }
533
- /** A diagram as plain data, the input to `diagramScene`. */
534
- interface DiagramData {
535
- nodes: readonly DataNode[];
536
- edges: readonly DataEdge[];
537
- /** A group may be a member of another. `layered`, `tree`, and `force` keep
538
- * each group's members together; `'none'` ignores groups but still draws
539
- * them. */
540
- groups?: readonly DataGroup[];
541
- }
542
- /** The colors and outline a node is drawn with. */
543
- interface NodeStyle {
544
- fill: string;
545
- stroke: string;
546
- text: string;
547
- strokeWidth?: number;
548
- dash?: number[];
549
- }
550
- /** The stroke, markers, and label color an edge is drawn with. */
551
- interface EdgeStyle {
552
- stroke: string;
553
- width?: number;
554
- dash?: number[];
555
- /** `null` for none. Default none. */
556
- markerStart?: MarkerRef | null;
557
- /** `null` for none. Default `'arrow'`. */
558
- markerEnd?: MarkerRef | null;
559
- /** Default `stroke`. */
560
- label?: string;
561
- }
562
- /** How an edge is drawn between its ends. */
563
- type DiagramRouter = 'straight' | 'bezier' | 'orthogonal';
564
- /** The face a diagram node's text is set in. */
565
- type DiagramTextStyle = {
566
- fontFamily: string;
567
- fontSize: number;
568
- fontWeight?: number;
569
- };
570
- /** The `data` of a scene node `diagramScene` makes: its diagram role, and what it paints. */
571
- interface DiagramSceneData {
572
- diagram?: DiagramNode | DiagramEdge | {
573
- label: DiagramLabel;
574
- } | {
575
- anchor: DiagramAnchor;
576
- };
577
- fill?: {
578
- paint: {
579
- color: string;
580
- };
581
- };
582
- stroke?: Stroke;
583
- text?: string;
584
- style?: DiagramTextStyle;
585
- }
586
- /** A scene node spec, as `diagramScene` returns them. */
587
- type DiagramSpec = AddNodeSpec<DiagramSceneData, 'main', RectPose>;
588
- /** How `diagramScene` lays out, routes, and styles a {@link DiagramData}. */
589
- interface DiagramSceneOptions {
590
- /** A layout by name, or any `LayoutFn`. Default `'layered'`. `'none'`
591
- * leaves every node at its `at`. */
592
- layout?: 'layered' | 'tree' | 'force' | 'none' | LayoutFn;
593
- /** Merged over `{ order: 'barycenter' }`. */
594
- layoutOptions?: LayoutOptions;
595
- /** Default `'bezier'`. */
596
- router?: DiagramRouter;
597
- /** The text style rows fall back on. Default 12px sans-serif. */
598
- font?: {
599
- fontFamily: string;
600
- fontSize: number;
601
- };
602
- /** Measures one run of text. Default an estimate from character count, so
603
- * layout needs no canvas; pass `canvasMeasure(ctx)` for real widths. */
604
- measure?: MeasureRowText;
605
- /** Default `'rect'`. */
606
- outline?: Outline;
607
- /** Between a box's outline and its rows. Default 8. */
608
- padding?: number;
609
- /** Between adjacent rows. Default 4. */
610
- gap?: number;
611
- /** Where a box's rows sit when it is taller than they need. Default `'center'`. */
612
- verticalAlign?: BodySpec['verticalAlign'];
613
- /** The narrowest a box may be. Default 64. */
614
- minWidth?: number;
615
- /** Where edge labels sit. Default `{ at: 'mid', offset: 9 }`. */
616
- labelPlacement?: DiagramLabel;
617
- nodeStyle?: (node: DataNode) => NodeStyle;
618
- /** Default 12. */
619
- groupPadding?: number;
620
- /** A group's box and label. `text` colors the label. */
621
- groupStyle?: (group: DataGroup) => NodeStyle;
622
- edgeStyle?: (edge: DataEdge) => EdgeStyle;
623
- }
624
- /** The scene node id `diagramScene` gives an edge, built from its ends, ports, and label. */
625
- declare const edgeIdOf: (e: DataEdge) => string;
626
- /** Every spec carries an id — a node's own, `<id>/<k>` for its text,
627
- * `<edge id>/label`, a group's own and `<group id>/label` — so a later call's
628
- * specs can be reconciled against this one's. Throws on a repeated id among
629
- * nodes and groups, which names two things as one. An edge whose
630
- * end is not a node is dropped, and so is a repeat of an earlier edge with
631
- * the same ends, ports and label: it would draw exactly on top of the first. */
632
- declare function diagramScene(data: DiagramData, opts?: DiagramSceneOptions): DiagramSpec[];
633
-
634
402
  /** What a live producer is told, and what it answers with. */
635
403
  interface LiveLayoutCtx<TPose> {
636
404
  /** Nodes another gesture is moving, and where each is drawn. */
@@ -686,14 +454,16 @@ interface EasedProducerOptions {
686
454
  * over.
687
455
  */
688
456
  declare function easedProducer<TPose>(graph: Graph, algorithm: LayoutFn, opts?: EasedProducerOptions): LiveLayoutProducer<TPose>;
457
+
689
458
  /** Options for {@link useLiveLayout}. Only `scene` and `source` are required. */
690
459
  interface UseLiveLayoutOptions<TPose> {
691
460
  scene: Scene<unknown, string, TPose>;
692
461
  /** Where the graph is read from. The same thunk the port affordance takes. */
693
462
  source: GraphSource<TPose>;
694
- /** A key in `LAYOUTS`, or a layout of the consumer's own. `'force'` relaxes
695
- * continuously; anything else eases to its answer. Default `'force'`. */
696
- algorithm?: string | LayoutFn;
463
+ /** A key in `LAYOUTS`, a layout of the consumer's own, or a planner that
464
+ * answers later. `'force'` relaxes continuously; anything else eases to its
465
+ * answer. Default `'force'`. */
466
+ algorithm?: string | LayoutFn | LayoutPlanner;
697
467
  layout?: LayoutOptions;
698
468
  /** The relaxation's forces, and when a live run of it counts as at rest. */
699
469
  force?: Omit<ForceProducerOptions<TPose>, 'geometry'>;
@@ -707,6 +477,9 @@ interface UseLiveLayoutOptions<TPose> {
707
477
  /** Fires once the run has settled or been stopped and its poses are in the
708
478
  * document, with how many participants moved. */
709
479
  onSettle?: (moved: number) => void;
480
+ /** Hears why a `LayoutPlanner` failed to answer, and no run starts. Unset,
481
+ * the failure goes to `console.error`. */
482
+ onError?: (error: unknown) => void;
710
483
  /** Whether a node or edge appearing or disappearing re-heats the run.
711
484
  * Default true — a diagram that ignores a new edge looks broken. */
712
485
  reheatOnGraphChange?: boolean;
@@ -716,9 +489,11 @@ interface UseLiveLayoutOptions<TPose> {
716
489
  }
717
490
  /** Controls for a live layout run, from {@link useLiveLayout}. */
718
491
  interface LiveLayout {
719
- /** Heat and run. Idempotent while running. */
492
+ /** Heat and run. Idempotent while running, which includes waiting on a
493
+ * planner's answer. */
720
494
  start(): void;
721
- /** Finish now: commit where the nodes stand. */
495
+ /** Finish now: commit where the nodes stand. A planner's answer still to
496
+ * come is dropped. */
722
497
  stop(): void;
723
498
  /** Abandon: the document keeps the poses it had. */
724
499
  cancel(): void;
@@ -737,6 +512,94 @@ declare function useLiveLayout<TPose>(opts: UseLiveLayoutOptions<TPose>): LiveLa
737
512
  /** The layouts that ease rather than relax, for a consumer choosing one. */
738
513
  declare const EASED_LAYOUTS: Readonly<Record<string, LayoutFn>>;
739
514
 
515
+ /**
516
+ * Routes for a laid-out `layered` diagram.
517
+ *
518
+ * An edge running down the ranks leaves its source by the face toward the
519
+ * next rank and arrives at its target's face toward the last, so it reads
520
+ * along the direction the diagram flows; one running back up the ranks does
521
+ * the same the other way round. An edge that spans ranks runs through the
522
+ * waypoints `layeredPlan` placed for it.
523
+ */
524
+
525
+ /** One edge to route, by the ids of its ends: a node's or a group's. */
526
+ interface RouteEdge {
527
+ id: string;
528
+ from: string;
529
+ to: string;
530
+ }
531
+ /** What {@link layeredRoutes} hands an edge. A field is absent where the
532
+ * default does as well. */
533
+ interface LayeredRoute {
534
+ fromPort?: string;
535
+ toPort?: string;
536
+ waypoints?: readonly Vec2$1[];
537
+ /** The point on the route layout left the edge's label room beside, as a
538
+ * `DiagramLabel`'s `{ near }`. */
539
+ labelAt?: Vec2$1;
540
+ }
541
+ /** What {@link layeredRoutes} reads: where `layeredPlan` put things. */
542
+ interface LayeredRouteInput {
543
+ edges: readonly RouteEdge[];
544
+ /** Each node's rank, from `layeredPlan`. Empty for a layout with none,
545
+ * which names no ports. */
546
+ ranks: ReadonlyMap<string, number>;
547
+ /** Each spanning edge's waypoints, from `layeredPlan`. */
548
+ waypoints: ReadonlyMap<string, readonly Vec2$1[]>;
549
+ /** Where each labeled edge's label room is among its waypoints, from
550
+ * `layeredPlan`. */
551
+ labels?: ReadonlyMap<string, Vec2$1>;
552
+ /** Each group's node members, through nested groups. */
553
+ members: ReadonlyMap<string, readonly string[]>;
554
+ /** Ids whose ports are the four compass midpoints, which are the only ones
555
+ * a route names. */
556
+ compass: ReadonlySet<string>;
557
+ direction?: LayoutDirection;
558
+ }
559
+ /** Ports and waypoints for each edge of a laid-out `layered` diagram that
560
+ * needs any, keyed by edge id. */
561
+ declare function layeredRoutes(input: LayeredRouteInput): Map<string, LayeredRoute>;
562
+
563
+ /**
564
+ * The edge half of writing a layout to a scene: each edge's waypoints, and
565
+ * where its label sits among them.
566
+ *
567
+ * Layout writes only what it owns. An edge's route is its own while the edge
568
+ * has no waypoints or still has the ones layout last wrote (`laidOut`); a
569
+ * label's place is its own while the label sits at the default middle or at a
570
+ * `{ near }`, and its edge's route is layout's.
571
+ */
572
+
573
+ /** Edge routes for `applyLayout` to write alongside a layout's moves. */
574
+ interface LayoutRoutes {
575
+ /** Every edge the layout laid out. Each one layout owns gets its route
576
+ * from `waypoints`, or loses the one a layout gave it before. */
577
+ edges: ReadonlySet<string>;
578
+ waypoints: ReadonlyMap<string, readonly Vec2$1[]>;
579
+ labels?: ReadonlyMap<string, Vec2$1>;
580
+ /** The ports layout names. Each end layout owns gets its port from here,
581
+ * or loses the one a layout named before. */
582
+ ports?: ReadonlyMap<string, LayoutPorts>;
583
+ }
584
+ /** The routes `plan` laid out for `graph`'s edges. A layout that routes
585
+ * nothing routes every edge straight, taking back what `layered` wrote. */
586
+ declare function routesOf(graph: Graph, plan: LayoutPlan): LayoutRoutes;
587
+ /** A scene as {@link routeWrites} reads it. */
588
+ interface RoutedScene {
589
+ get(id: never): {
590
+ data: unknown;
591
+ } | undefined;
592
+ isLocked(id: never): boolean;
593
+ renderOrderNodes(): readonly {
594
+ id: string;
595
+ data: unknown;
596
+ dependsOn?: readonly string[] | 'children';
597
+ }[];
598
+ }
599
+ /** The new `data` for every edge and label whose route or place changes. A
600
+ * locked edge or label is left as it is. */
601
+ declare function routeWrites(scene: RoutedScene, routes: LayoutRoutes): Map<string, unknown>;
602
+
740
603
  /**
741
604
  * Running a layout against a scene: `LAYOUTS`, one batch of pose writes, and
742
605
  * the action that reaches both. A layout is a pure function of the graph;
@@ -750,12 +613,14 @@ interface ApplyLayoutOptions<TPose> {
750
613
  geometry?: PoseDescriptor<TPose>;
751
614
  /** The undo entry's name. Default `'Layout'`. */
752
615
  label?: string;
616
+ /** Edge routes to write in the same batch, from `routesOf`. */
617
+ routes?: LayoutRoutes;
753
618
  }
754
619
  /**
755
620
  * Write a layout's answer to the scene, as one undoable batch.
756
621
  *
757
- * Returns how many nodes moved, which is zero for a layout that had nothing to
758
- * do — nothing is written and no history entry is pushed.
622
+ * Returns how many nodes moved. A layout with nothing to do, nodes or routes,
623
+ * writes nothing and pushes no history entry.
759
624
  *
760
625
  * Nodes are **translated**, never re-posed from the layout's numbers: a node's
761
626
  * pose can be a path or anything else a consumer wired, and only its own
@@ -803,11 +668,18 @@ declare function createLayoutAction<TPose>(opts: LayoutActionOptions<TPose>): Ac
803
668
  */
804
669
 
805
670
  /** The minimum a participant source needs from a scene. Narrower than `Scene`
806
- * so a consumer can pass anything that answers these two. */
671
+ * so a consumer can pass anything that answers these. `layers` and each
672
+ * node's `layer`, `parent`, `hidden` and `locked` feed `nodeGates`; a stand-in
673
+ * without them gates nothing. */
807
674
  interface ParticipantScene<TPose> {
675
+ readonly layers?: readonly GatedLayer[];
808
676
  renderOrderNodes(): readonly {
809
677
  id: string;
810
678
  kind: 'leaf' | 'container';
679
+ layer?: string;
680
+ parent?: string | null;
681
+ hidden?: boolean;
682
+ locked?: boolean;
811
683
  data: unknown;
812
684
  pose: TPose;
813
685
  dependsOn?: readonly string[] | 'children';
@@ -821,7 +693,11 @@ interface ParticipantScene<TPose> {
821
693
  childrenOf(id: string): readonly string[];
822
694
  }
823
695
  /**
824
- * Every node in `scene`, at the pose it is **painted** at.
696
+ * Every node in `scene`, at the pose it is **painted** at, marked `hidden` or
697
+ * `locked` where the scene's `nodeGates` says so, and carrying its `layer` so
698
+ * a view that does not paint that layer can turn its ports away too. The
699
+ * marks keep ports off such a node; the graph reads past them, so a hidden
700
+ * node is still laid out.
825
701
  *
826
702
  * `effectivePose`, not `node.pose`: an override is what a gesture is currently
827
703
  * showing, and a port that answers from the document pose while its node is
@@ -829,7 +705,9 @@ interface ParticipantScene<TPose> {
829
705
  *
830
706
  * One source answers both the ports and the graph.
831
707
  */
832
- declare function sceneParticipants<TPose>(scene: ParticipantScene<TPose>): GraphSource<TPose>;
708
+ declare function sceneParticipants<TPose>(scene: ParticipantScene<TPose>): () => Iterable<ParticipantPose<TPose> & {
709
+ node: GraphNodeLike;
710
+ }>;
833
711
  /**
834
712
  * The composed layer, ready for `CanvasExtensionApi.registerLayer` — the only
835
713
  * attach route that is hit-tested. Handing this to `SceneCanvas`'s `layers`
@@ -871,12 +749,39 @@ declare function diagramShape<TPose>(opts?: DiagramShapeOptions<TPose>): NodeSha
871
749
  */
872
750
  declare function registerDiagramShape<TPose>(opts?: DiagramShapeOptions<TPose>): () => void;
873
751
 
752
+ /**
753
+ * `DiagramView`'s two-way sync with the data it was built from: new specs are
754
+ * reconciled into the scene, and what a drag or a layout run changed is
755
+ * reported back, so a consumer keeping the diagram as data can store it.
756
+ * `diagramLayoutOf` reads the same report off a `diagramScene` build.
757
+ */
758
+
874
759
  /** Where a moved node now stands. */
875
760
  interface NodeMove {
876
761
  id: string;
877
762
  x: number;
878
763
  y: number;
879
764
  }
765
+ /** An edge whose route or ports a layout run rewrote. `id` is the edge's
766
+ * scene id, `edgeIdOf` of its data edge; `waypoints` is empty when the run
767
+ * took a route away and left the edge straight, and `ports` names the ends
768
+ * layout owns. Store them as the data edge's `routed` and `routedPorts`,
769
+ * which stay layout's, not as `waypoints`, `fromPort` and `toPort`, which
770
+ * would be the author's and rename the edge. */
771
+ interface EdgeRoute {
772
+ id: string;
773
+ waypoints: readonly Vec2$1[];
774
+ ports: LayoutPorts;
775
+ }
776
+ /** What layout placed in a `diagramScene` build, in the shape `DiagramView`'s
777
+ * `onMove` reports: every node not pinned, where it stands, and every edge
778
+ * whose route or ports layout wrote. Store them the way `onMove` says and
779
+ * the next build leaves those nodes where they are. */
780
+ declare function diagramLayoutOf(specs: readonly DiagramSpec[]): {
781
+ moves: NodeMove[];
782
+ routes: EdgeRoute[];
783
+ };
784
+
880
785
  /** Props for `DiagramView`. */
881
786
  interface DiagramViewProps {
882
787
  /** Every spec needs an id, which `diagramScene` gives them. A new array is
@@ -884,8 +789,12 @@ interface DiagramViewProps {
884
789
  * selection and anything moved since stay put unless the new specs change
885
790
  * them. Pass a new `key` to start over instead. */
886
791
  specs: readonly DiagramSpec[];
887
- width: number;
888
- height: number;
792
+ /** The view opens fitted to the diagram, and fits again when the size or a
793
+ * fit option changes or a layout run settles, until the user pans or zooms;
794
+ * from then on the view is theirs. Omit both to fill the parent, which
795
+ * then needs a size of its own; a resize of the parent is a size change. */
796
+ width?: number;
797
+ height?: number;
889
798
  /** A participant id, or null for none. */
890
799
  selected?: string | null;
891
800
  /** Reports what each click leaves picked, `null` for none — a re-click on the
@@ -893,12 +802,18 @@ interface DiagramViewProps {
893
802
  * `selected` does not follow it; only a change to `selected` is pushed in. */
894
803
  onSelect?: (id: string | null) => void;
895
804
  /** Set to let nodes be dragged. Reports every node a drag or a layout run
896
- * moved. Store each as the data node's `at` with `pinned: true`, or the
897
- * next `diagramScene` lays it out again. */
898
- onMove?: (moves: readonly NodeMove[]) => void;
899
- /** Set to make ports grabbable. Dragging one port onto another reports the
805
+ * moved, and every edge whose route or ports a layout run rewrote. Store
806
+ * each move as the data node's `at` with `pinned: true`, and each route as
807
+ * the data edge's `routed` and `routedPorts`, or the next `diagramScene`
808
+ * lays them out again. */
809
+ onMove?: (moves: readonly NodeMove[], routes: readonly EdgeRoute[]) => void;
810
+ /** Ports are grabbable when this is set, unless `ports` says otherwise. Dragging one port onto another reports the
900
811
  * edge it describes and draws nothing; add it to the data to keep it. */
901
812
  onConnect?: (edge: DataEdge) => void;
813
+ /** Whether ports are drawn. `'connect'` draws them and lets one be dragged
814
+ * onto another; `'show'` only draws them. Default: `'connect'` when
815
+ * `onConnect` is set, else `'none'`. */
816
+ ports?: 'connect' | 'show' | 'none';
902
817
  /** Whether the canvas's keyboard shortcuts — held Space to pan among them —
903
818
  * run. They listen page-wide, so a view-only diagram beside other UI would
904
819
  * claim keys meant for the page. Default: on when `onMove` or `onConnect`
@@ -909,28 +824,29 @@ interface DiagramViewProps {
909
824
  canConnect?: CanConnect;
910
825
  /** How ports look and answer the pointer, and the router a connect's
911
826
  * preview draws with. */
912
- portOptions?: Pick<DiagramContributionOptions<RectPose>, 'fill' | 'stroke' | 'sizePx' | 'hitRadiusPx' | 'cursor' | 'shows' | 'snapRadius' | 'router'>;
827
+ portOptions?: Pick<DiagramContributionOptions<RectPose>, 'fill' | 'stroke' | 'shape' | 'sizePx' | 'hitRadiusPx' | 'cursor' | 'shows' | 'showsPort' | 'snapRadius' | 'router'>;
913
828
  /** How a layout run from {@link DiagramViewApi.layout} behaves: its forces,
914
- * how many frames an eased layout takes, its easing. */
829
+ * how many frames an eased layout takes, its easing, and `onError`, which
830
+ * hears a `LayoutPlanner` that failed to answer. */
915
831
  live?: Omit<UseLiveLayoutOptions<RectPose>, 'scene' | 'source' | 'algorithm'>;
916
- /** The smallest scale the initial fit may use. Unset, the whole diagram fits
832
+ /** The smallest scale the fit may use. Unset, the whole diagram fits
917
833
  * however small that makes it; set, it stops here and the rest is a pan away. */
918
834
  minScale?: number;
919
- /** The largest scale the initial fit may use. Default 1, so a small
835
+ /** The largest scale the fit may use. Default 1, so a small
920
836
  * diagram opens at its own size rather than blown up. */
921
837
  maxScale?: number;
922
838
  /** Which part of a diagram too big for the box it opens on: its middle
923
839
  * (default) or its top-left, where a layered flow begins. */
924
840
  anchor?: 'center' | 'start';
925
- /** Space kept clear around the diagram by the initial fit, in CSS pixels.
841
+ /** Space kept clear around the diagram by the fit, in CSS pixels.
926
842
  * Default 16. */
927
843
  fitPadding?: number;
928
844
  /** What the canvas paints behind the diagram. Unset, it is transparent. */
929
845
  background?: Paint;
930
- /** The view, controlled. Set it and the initial fit is skipped; pair it
846
+ /** The view, controlled. Set it and the fit is skipped; pair it
931
847
  * with `onViewChange` or panning does nothing. */
932
848
  view?: View;
933
- /** Every view change, from a pan, a zoom or the initial fit. */
849
+ /** Every view change, from a pan, a zoom or a refit. */
934
850
  onViewChange?: (view: View) => void;
935
851
  className?: string;
936
852
  }
@@ -938,11 +854,15 @@ interface DiagramViewProps {
938
854
  interface DiagramViewApi {
939
855
  /** Lay the diagram out again from where its nodes stand, animated. `'force'`
940
856
  * (default) relaxes until it settles; any other layout eases to its answer.
941
- * What moved is reported to `onMove` once the run settles. */
942
- layout(algorithm?: 'layered' | 'tree' | 'force' | LayoutFn): void;
857
+ * A `LayoutPlanner` is handed the diagram's graph and eased to once it
858
+ * answers; a drag, an edit or another `layout` call before then drops the
859
+ * answer. What moved is reported to `onMove` once the run settles. */
860
+ layout(algorithm?: DiagramLayout): void;
943
861
  /** The run `layout` started: stop it where it stands, or cancel it. */
944
862
  live: LiveLayout;
945
863
  }
864
+ /** What {@link DiagramViewApi.layout} runs. */
865
+ type DiagramLayout = 'layered' | 'tree' | 'force' | 'chain' | LayoutFn | LayoutPlanner;
946
866
  /** A diagram: drag or wheel to pan, zoom, and pick a node; drag nodes with
947
867
  * `onMove`, join ports with `onConnect`. Labels paint only in a registered
948
868
  * font family; `diagramScene` defaults to sans-serif, so call
@@ -955,4 +875,4 @@ declare const DiagramView: react.ForwardRefExoticComponent<DiagramViewProps & re
955
875
  * `<SceneCanvas onClick>`. */
956
876
  declare function useMirroredSelection(selection: Pick<SelectionApi, 'get' | 'set'>, selected: string | null | undefined, onSelect: ((id: string | null) => void) | undefined): () => void;
957
877
 
958
- 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 LayoutActionOptions, 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 RouteRequest, type Router, Row, type SelfLoop, type UseLiveLayoutOptions, anchorDerivePose, applyLayout, bezier, commitEdgeToScene, connectBinding, createConnectAction, createDiagramContribution, createLayoutAction, createPortAffordance, defaultCanConnect, diagramAnchorOf, diagramEdgeOf, diagramGroupOf, diagramLabelOf, diagramPorts, diagramScene, diagramShape, easedProducer, edgeDerivePath, edgeIdOf, forceProducer, grabPortAction, grabPortBindings, groupDerivePose, labelDerivePose, layoutPoses, orthogonal, portLayer, portScratchOf, registerDiagramShape, resolveEnd, sceneParticipants, selfLoop, straight, useLiveLayout, useMirroredSelection, withDiagramRegistry };
878
+ export { type ApplyLayoutOptions, CONNECT_ACTION_ID, type CanConnect, type ConnectActionOptions, DEFAULT_EDGE_STROKE, DIAGRAM_EDGE, DIAGRAM_LABEL, DataEdge, type DiagramContributionOptions, type DiagramLayout, DiagramNodeLike, DiagramNodeReader, type DiagramShapeOptions, DiagramSpec, DiagramView, type DiagramViewApi, type DiagramViewProps, EASED_LAYOUTS, EDGE_DERIVE_PATH, type EasedProducerOptions, EdgeEnd, type EdgeRoute, type EdgeRouteOptions, ForceOptions, type ForceProducerOptions, GRAB_PORT_ACTION_ID, Graph, GraphNodeLike, GraphSource, LABEL_DERIVE_POSE, LAYOUTS, LAYOUT_ACTION_ID, type LabelPoseOptions, type LayeredRoute, type LayeredRouteInput, type LayoutActionOptions, LayoutDirection, LayoutFn, LayoutOptions, LayoutPlan, LayoutPlanner, LayoutPorts, LayoutResult, type LayoutRoutes, type LiveLayout, type LiveLayoutCtx, type LiveLayoutFrame, type LiveLayoutProducer, type NodeMove, PORT_AFFORDANCE_KIND, PORT_LAYER_ID, type ParticipantPose, type ParticipantScene, type ParticipantSource, type PendingEdge, Port, type PortAffordanceOptions, type PortScratch, PortsOptions, ROUTERS, type RouteEdge, type RouteRequest, type RoutedScene, type Router, type SelfLoop, type UseLiveLayoutOptions, applyLayout, bezier, commitEdgeToScene, connectBinding, createConnectAction, createDiagramContribution, createLayoutAction, createPortAffordance, defaultCanConnect, diagramLayoutOf, diagramPorts, diagramShape, easedProducer, edgeDerivePath, forceProducer, grabPortAction, grabPortBindings, labelDerivePose, layeredRoutes, layoutPoses, orthogonal, portLayer, portScratchOf, registerDiagramShape, resolveEnd, routeWrites, routesOf, sceneParticipants, selfLoop, straight, useLiveLayout, useMirroredSelection, withDiagramRegistry };