@weasel-js/diagram 1.9.4 → 1.10.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,26 +1,24 @@
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-DyKFfHG5.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 GraphEdge, x as GraphGroup, y as GraphNode, z as GraphNodeLike, A as GroupInset, E as LayoutAxes, H as LayoutDirection, I as RowBox, J as RowNodeData, K as RowPort, N as RowPortBox, Q as RowTextStyle, S as Slot, T as axesFor, U as backEdges, V as bodyOutline, W as bodyTrait, X as boxForContent, Y as buildBody, Z as buildGraph, _ as canvasMeasure, $ as contentBox, a0 as createDiagramNodes, a1 as dataKeyReader, a2 as diagramNodeOf, a3 as expandGroupEdges, a4 as force, a5 as forceRelaxation, a6 as forestOf, a7 as graphOrder, a8 as insetOf, a9 as isPinned, aa as layered, ab as layoutBody, ac as layoutRowPorts, ad as measureBody, ae as outlinePath, af as outlinePolyline, ag as packAcross, ah as packClusters, ai as pinnedSet, aj as portOf, ak as portsOf, al as portsOnOutline, am as rankGaps, an as ranksOf, ao as rayHit, ap as seededOrder, aq as settle, ar as sizeToBody, as as translated, at as tree, au as untilSettled } from './layout.entry-DyKFfHG5.js';
3
- import { Vec2, DerivedDep, Path, SceneRegistry, PoseDescriptor, ChromeState, CommandFill, CommandStroke, CursorSpec, Affordance, InvocationCtx, Stroke, GestureBinding, Action, Contribution, RenderLayer, MarkerRef, AddNodeSpec, RectPose, Scene, EasingFn, NodeId, FillStyle, NodeShapeEntry, View, SelectionApi } from '@weasel-js/core';
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
4
  import { Vec2 as Vec2$1 } from '@weasel-js/core/math';
5
+ import { EasingFn } from '@weasel-js/animator';
5
6
  import * as react from 'react';
6
7
  import '@weasel-js/geom';
8
+ import '@weasel-js/simulation';
7
9
 
8
10
  /**
9
11
  * `DiagramEdge` — a connection between two participants.
10
12
  *
11
13
  * An edge is an ordinary leaf scene node with `dependsOn: [from, to]` and a
12
- * `derivePath` that runs a **router**. Making it a scene node rather than a
13
- * plugin-owned render layer is the load-bearing choice: it buys selection,
14
- * hit-testing, hover, styling, z-order, SVG export, undo and copy/paste
15
- * without implementing any of them. The cost is that an edge costs what a node
16
- * costs — right for diagrams of tens to hundreds of edges, wrong for a
17
- * 10k-edge force graph, which keeps its render layer.
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.
18
19
  *
19
20
  * **Author-dragged waypoints are data on the edge and the router routes
20
- * through them.** Manual control never authors the path; it authors
21
- * constraints on the path. That is what keeps derived geometry and hand-tuning
22
- * compatible — a moved endpoint still re-routes, through the waypoints the
23
- * author put there.
21
+ * through them**, so a moved endpoint still re-routes.
24
22
  *
25
23
  * Arrowheads are not here. They are stroke markers, the same
26
24
  * `markerStart` / `markerEnd` any other stroke carries.
@@ -52,11 +50,10 @@ interface RouteRequest {
52
50
  waypoints: readonly Vec2[];
53
51
  }
54
52
  /** A router returns the points the edge runs through, `from.point` first and
55
- * `to.point` last. Turning those into a `Path` is `edgePath`'s job, so a
56
- * router never has to know about path encodings. */
57
- type Router$1 = (req: RouteRequest) => readonly Vec2[];
53
+ * `to.point` last. */
54
+ type Router = (req: RouteRequest) => readonly Vec2[];
58
55
  /** The straight run between the two ends, through any waypoints. */
59
- declare const straight: Router$1;
56
+ declare const straight: Router;
60
57
  /**
61
58
  * An axis-aligned route: leave along the departing end's normal and arrive
62
59
  * against the receiving one's.
@@ -64,24 +61,19 @@ declare const straight: Router$1;
64
61
  * A leg is one elbow where the two ends face different axes and two where they
65
62
  * face the same one, turning at the midpoint of the axis they share. Arriving
66
63
  * along the port's own facing is what makes the arrowhead point *into* the
67
- * shape — a route that lands on a west-facing port from above puts its marker
68
- * across the corner, which reads as aimed at nothing.
64
+ * shape.
69
65
  */
70
- declare const orthogonal: Router$1;
66
+ declare const orthogonal: Router;
71
67
  /**
72
68
  * A smooth route, sampled into points.
73
69
  *
74
70
  * Each leg is a cubic that leaves along the departing end's normal and arrives
75
- * against the receiving one's, which is what makes a bezier edge read as
76
- * plugged into its port rather than aimed at it. The rule is `portCurvePoints`
77
- * in `@weasel-js/geom`, which states it over loose components so the 3D kernel
78
- * can route by the same one. Sampled rather than emitted as curve commands so
79
- * every router returns the same thing; `edgePath` is free to emit curves later
80
- * without changing the contract.
71
+ * against the receiving one's. Sampled rather than emitted as curve commands so
72
+ * every router returns the same thing.
81
73
  */
82
- declare const bezier: Router$1;
74
+ declare const bezier: Router;
83
75
  /** The routers this package ships. A consumer's own go in the same shape. */
84
- declare const ROUTERS: Readonly<Record<string, Router$1>>;
76
+ declare const ROUTERS: Readonly<Record<string, Router>>;
85
77
  /** The edge trait on a node's data, or `null`. */
86
78
  declare function diagramEdgeOf(node: {
87
79
  data: unknown;
@@ -91,14 +83,13 @@ declare function diagramEdgeOf(node: {
91
83
  * other end most directly.
92
84
  *
93
85
  * "Facing" rather than "nearest": a port on the far side of a wide node can be
94
- * closer in a straight line than the one pointing at the target, and an edge
95
- * that leaves through its own node reads as a bug however short it is.
86
+ * closer in a straight line than the one pointing at the target.
96
87
  */
97
88
  declare function resolveEnd<TPose>(end: EdgeEnd, dep: DerivedDep<TPose>, toward: Vec2, opts: PortsOptions<TPose>, allPorts: (d: DerivedDep<TPose>) => Port[]): Port | undefined;
98
89
  /** Options for {@link edgeDerivePath}. */
99
90
  interface EdgeRouteOptions<TPose> extends PortsOptions<TPose> {
100
91
  /** Routers by key. Defaults to {@link ROUTERS}. */
101
- routers?: Readonly<Record<string, Router$1>>;
92
+ routers?: Readonly<Record<string, Router>>;
102
93
  /** How far outside its node a self-edge with no ports named turns, in
103
94
  * world units. Defaults to half the node's shorter side. */
104
95
  selfLoopStandoff?: number;
@@ -111,9 +102,7 @@ interface EdgeRouteOptions<TPose> extends PortsOptions<TPose> {
111
102
  * router is handed that rule's point outside the node as one.
112
103
  *
113
104
  * Returns `null` — nothing to draw — when the node is not an edge, when either
114
- * dependency is gone, or when an endpoint offers no ports at all. A dangling
115
- * edge painting a line to the origin is worse than a dangling edge painting
116
- * nothing.
105
+ * dependency is gone, or when an endpoint offers no ports at all.
117
106
  */
118
107
  declare function edgeDerivePath<TPose>(opts?: EdgeRouteOptions<TPose>): (node: {
119
108
  data: unknown;
@@ -135,10 +124,9 @@ declare function withDiagramRegistry<TPose, TData = unknown, TLayer extends stri
135
124
  *
136
125
  * A port is declared as an `AffordanceRegion`, so the kit's own region walk
137
126
  * supplies the hit-test, the screen-pixel hit radius, the cursor and the
138
- * exclusive claim that keeps a port drag out of the select tool's hands. That
139
- * is the "visible chrome is always hittable" rule doing the work: the walk runs
140
- * on every pointerdown before any tool sees the event, so a port answers
141
- * whatever tool happens to be active.
127
+ * exclusive claim that keeps a port drag out of the select tool's hands. The
128
+ * walk runs on every pointerdown before any tool sees the event, so a port
129
+ * answers whatever tool happens to be active.
142
130
  *
143
131
  * Two things about this are easy to get wrong, and both fail silently.
144
132
  *
@@ -217,26 +205,17 @@ declare function createPortAffordance<TPose>(participants: ParticipantSource<TPo
217
205
  *
218
206
  * Connect is an ordinary drag binding, not a mode and not a tool of its own:
219
207
  * the binding is gated on a press landing on a port affordance, so a connect
220
- * starts from whatever tool happens to be active. The gate lives in the
221
- * binding's `target`, which is what lets a press that is *not* on a port fall
222
- * through to the tool that wants it instead of being swallowed here.
208
+ * starts from whatever tool happens to be active, and a press that is *not* on
209
+ * a port falls through to the tool that wants it.
223
210
  *
224
- * **Where validity is decided.** The two halves are decided in different
225
- * places, and conflating them is the mistake this package is written to avoid:
211
+ * *Which presses start a connect* is routing, and belongs to the binding spec.
212
+ * *Which ports a live connect may land on* cannot be routing — the dispatcher
213
+ * never re-reads the affordance under a moving pointer — so `canConnect`
214
+ * filters the candidate set: the preview will not snap to an illegal port and
215
+ * a release over it commits nothing.
226
216
  *
227
- * - *Which presses start a connect* is routing, and belongs to the binding
228
- * spec. `connectBinding` names the port layer's affordance kind; nothing in
229
- * the action body re-checks what was pressed.
230
- * - *Which ports a live connect may land on* cannot be routing — the
231
- * dispatcher never re-reads the affordance under a moving pointer, so a
232
- * spec has no vocabulary for it. It is decided by `canConnect` filtering
233
- * the **candidate set**: an illegal port is never a candidate, so the
234
- * preview will not snap to it and a release over it commits nothing. That
235
- * is a narrower thing than an action body that inspects a hit and bails.
236
- *
237
- * One resolver answers both the live preview and the commit, for the reason
238
- * `insertAction` does the same: a preview computed separately from the commit
239
- * is a preview that can lie about what releasing will do.
217
+ * One resolver answers both the live preview and the commit, so the preview
218
+ * cannot lie about what releasing will do.
240
219
  */
241
220
 
242
221
  /** The default action id, and what {@link connectBinding} points at. */
@@ -255,11 +234,8 @@ interface PendingEdge {
255
234
  * The shipped policy: a port may not join itself, and two ports that both
256
235
  * declare a `type` must declare the same one.
257
236
  *
258
- * A port with no type joins anything — `PortSpec.type` is uninterpreted by this
259
- * package, so an untyped diagram stays fully connectable without opting out.
260
- * Two ports on the *same node* may be joined: a self-edge between two different
261
- * ports is meaningful in a state machine, and refusing it here would be policy
262
- * masquerading as a rule.
237
+ * A port with no type joins anything. Two different ports on the *same node*
238
+ * may be joined: a self-edge is meaningful in a state machine.
263
239
  */
264
240
  declare const defaultCanConnect: CanConnect;
265
241
  /** Options for {@link createConnectAction}. Only `participants` is required. */
@@ -279,14 +255,12 @@ interface ConnectActionOptions<TPose> {
279
255
  /** Registry key the new edge names, and the router the preview draws with.
280
256
  * Default `'straight'`. */
281
257
  router?: string;
282
- routers?: Readonly<Record<string, Router$1>>;
258
+ routers?: Readonly<Record<string, Router>>;
283
259
  /**
284
260
  * Mints and commits the edge. Called once, on release over a valid port.
285
261
  *
286
- * Defaults to {@link commitEdgeToScene} against `deps.scene`, which is what
287
- * makes the gesture work with nothing wired. Override it the way a consumer
288
- * overrides the kit's `insert` dep — to choose the edge node's data, its
289
- * layer, or its stroke.
262
+ * Defaults to {@link commitEdgeToScene} against `deps.scene`. Override it to
263
+ * choose the edge node's data, its layer, or its stroke.
290
264
  */
291
265
  commit?: (edge: PendingEdge, ctx: InvocationCtx) => void;
292
266
  }
@@ -298,8 +272,7 @@ declare const DEFAULT_EDGE_STROKE: Stroke;
298
272
  * layer's own chrome.
299
273
  *
300
274
  * The string form of `target` rather than a predicate, because it ranks higher
301
- * in specificity — a bare `{ kind: 'drag' }` on the select tool cannot outrank
302
- * it, so no tool needs a predicate of its own to keep out of the way.
275
+ * in specificity: a bare `{ kind: 'drag' }` on the select tool cannot outrank it.
303
276
  */
304
277
  declare function connectBinding(actionId?: string): GestureBinding;
305
278
  /** The action id that absorbs a press on a port. */
@@ -312,8 +285,7 @@ declare const GRAB_PORT_ACTION_ID = "diagram.grabPort";
312
285
  * claim bars every binding whose target does not consult the affordance. So a
313
286
  * bundle that binds only `drag` leaves the pointerdown with nowhere to go, and
314
287
  * the dispatcher drops the press — the drag it would have grown into never
315
- * happens. Absorbing the press is also the behavior you want on its own: a
316
- * press on a port should not pick or deselect the node underneath it.
288
+ * happens.
317
289
  */
318
290
  declare function grabPortAction(id?: string): Action;
319
291
  /** The two bindings that keep a port's claim from dropping the press. */
@@ -322,20 +294,12 @@ declare function grabPortBindings(actionId?: string): GestureBinding[];
322
294
  * The default commit: one leaf node carrying the edge trait, added to
323
295
  * `deps.scene`. One `add` is one history entry, so the edge undoes in one.
324
296
  *
325
- * The edge lands on the **source node's** layer rather than the bottom one: an
326
- * edge between two nodes on a `wires` layer belongs on `wires`, and picking the
327
- * first layer in the stack would quietly move it somewhere the author did not
328
- * put its endpoints.
297
+ * The edge lands on the **source node's** layer rather than the bottom one.
329
298
  */
330
299
  declare function commitEdgeToScene(edge: PendingEdge, ctx: InvocationCtx): void;
331
300
  /**
332
301
  * The `diagram.connect` action: an ongoing drag whose preview is an ephemeral
333
302
  * edge and whose commit is one op batch.
334
- *
335
- * A factory rather than a singleton because every input it needs — which nodes
336
- * are droppable, what counts as a legal pair, how an edge node is shaped — is
337
- * the consumer's, and this package has no scene at module scope. Same reason
338
- * `edgeDerivePath` and `diagramShape` are factories.
339
303
  */
340
304
  declare function createConnectAction<TPose>(opts: ConnectActionOptions<TPose>): Action;
341
305
 
@@ -343,17 +307,14 @@ declare function createConnectAction<TPose>(opts: ConnectActionOptions<TPose>):
343
307
  * The plugin as a `Contribution` bundle — one object a consumer hands to
344
308
  * `<SceneCanvas ambient={…}>`.
345
309
  *
346
- * **Ambient, not a tool.** Connect is not a mode the author enters: a port is
347
- * grabbable whatever tool is active, which is the same reason `@weasel-js/hud`
348
- * ships `eligibility: { claimed: true }`. `claimed` is what makes the bundle
349
- * live for a press the port layer's affordance claimed, and dormant otherwise.
310
+ * **Ambient, not a tool.** A port is grabbable whatever tool is active:
311
+ * `claimed` makes the bundle live for a press the port layer's affordance
312
+ * claimed, and dormant otherwise.
350
313
  *
351
314
  * **The layer is not in here, on purpose.** `Contribution.overlay` is painted
352
315
  * and never hit-tested — only `CanvasExtensionApi.registerLayer` gets a
353
- * `hitTest` call. Shipping the port layer as an overlay would paint every port
354
- * and make none of them grabbable, which is exactly the state this arc started
355
- * from. {@link diagramPorts} hands back the bundle and the layer together so
356
- * the two cannot be wired half-way.
316
+ * `hitTest` call — so the port layer as an overlay would paint every port and
317
+ * make none of them grabbable. {@link diagramPorts} hands back both.
357
318
  */
358
319
 
359
320
  /** The connect action's options and the port affordance's, in one bag. */
@@ -478,7 +439,8 @@ declare function diagramAnchorOf(node: {
478
439
  interface GroupPoseOptions<TPose> {
479
440
  geometry?: PoseDescriptor<TPose>;
480
441
  }
481
- type DerivePose<TPose> = (node: {
442
+ /** A `derivePose` function as the scene calls it: the node, then what it depends on, in `dependsOn` order. */
443
+ type DiagramDerivePose<TPose> = (node: {
482
444
  pose: TPose;
483
445
  data: unknown;
484
446
  }, deps: readonly (DerivedDep<TPose> | undefined)[]) => TPose | null;
@@ -487,20 +449,20 @@ type DerivePose<TPose> = (node: {
487
449
  * grown by the trait's inset. `null` — the authored pose stands — when the node
488
450
  * carries no group trait or every member is gone.
489
451
  */
490
- declare function groupDerivePose<TPose>(opts?: GroupPoseOptions<TPose>): DerivePose<TPose>;
452
+ declare function groupDerivePose<TPose>(opts?: GroupPoseOptions<TPose>): DiagramDerivePose<TPose>;
491
453
  /**
492
454
  * A `derivePose` that keeps a node at a point on its dependency's bounds.
493
455
  * `null` when the node carries no anchor trait or the dependency is gone.
494
456
  */
495
- declare function anchorDerivePose<TPose>(opts?: GroupPoseOptions<TPose>): DerivePose<TPose>;
457
+ declare function anchorDerivePose<TPose>(opts?: GroupPoseOptions<TPose>): DiagramDerivePose<TPose>;
496
458
  /** Registry key for {@link GROUP_DERIVE_POSE}. */
497
459
  declare const DIAGRAM_GROUP = "diagram:group";
498
460
  /** Registry key for {@link ANCHOR_DERIVE_POSE}. */
499
461
  declare const DIAGRAM_ANCHOR = "diagram:anchor";
500
462
  /** The default group derivation, a stable reference so `toJSON` can find its key. */
501
- declare const GROUP_DERIVE_POSE: DerivePose<unknown>;
463
+ declare const GROUP_DERIVE_POSE: DiagramDerivePose<unknown>;
502
464
  /** The default anchor derivation, a stable reference for the same reason. */
503
- declare const ANCHOR_DERIVE_POSE: DerivePose<unknown>;
465
+ declare const ANCHOR_DERIVE_POSE: DiagramDerivePose<unknown>;
504
466
 
505
467
  /**
506
468
  * `diagramScene` — a laid-out diagram from plain `{ nodes, edges }`.
@@ -550,7 +512,7 @@ interface DataEdge {
550
512
  /** Where along the edge the label sits. Default `DiagramSceneOptions.labelPlacement`. */
551
513
  labelPlacement?: DiagramLabel;
552
514
  /** Default `DiagramSceneOptions.router`. */
553
- router?: Router;
515
+ router?: DiagramRouter;
554
516
  /** World points the route passes through. Layout does not move them. */
555
517
  waypoints?: readonly Vec2$1[];
556
518
  }
@@ -597,8 +559,10 @@ interface EdgeStyle {
597
559
  /** Default `stroke`. */
598
560
  label?: string;
599
561
  }
600
- type Router = 'straight' | 'bezier' | 'orthogonal';
601
- type TextStyle = {
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 = {
602
566
  fontFamily: string;
603
567
  fontSize: number;
604
568
  fontWeight?: number;
@@ -611,11 +575,13 @@ interface DiagramSceneData {
611
575
  anchor: DiagramAnchor;
612
576
  };
613
577
  fill?: {
614
- color: string;
578
+ paint: {
579
+ color: string;
580
+ };
615
581
  };
616
582
  stroke?: Stroke;
617
583
  text?: string;
618
- style?: TextStyle;
584
+ style?: DiagramTextStyle;
619
585
  }
620
586
  /** A scene node spec, as `diagramScene` returns them. */
621
587
  type DiagramSpec = AddNodeSpec<DiagramSceneData, 'main', RectPose>;
@@ -627,7 +593,7 @@ interface DiagramSceneOptions {
627
593
  /** Merged over `{ order: 'barycenter' }`. */
628
594
  layoutOptions?: LayoutOptions;
629
595
  /** Default `'bezier'`. */
630
- router?: Router;
596
+ router?: DiagramRouter;
631
597
  /** The text style rows fall back on. Default 12px sans-serif. */
632
598
  font?: {
633
599
  fontFamily: string;
@@ -695,21 +661,13 @@ interface ForceProducerOptions<TPose> extends ForceOptions {
695
661
  /**
696
662
  * A relaxation, one tick a frame, done when the graph stops moving.
697
663
  *
698
- * Motion ends long before alpha cools — a few dozen ticks against three
699
- * hundred — so a run that waited for alpha would sit visibly still for
700
- * seconds while still reporting itself running. It finishes on whichever
701
- * comes first: `restTicks` ticks in a row with no node moving `restDistance`,
702
- * or the cooling schedule running out. Nothing rests while a node is held.
664
+ * Motion ends long before alpha cools, so it finishes on whichever comes
665
+ * first: `restTicks` ticks in a row with no node moving `restDistance`, or the
666
+ * cooling schedule running out. Nothing rests while a node is held.
703
667
  *
704
- * The forces are `forceRelaxation`'s — the same ones the one-shot `force`
705
- * runs, wound up once here and ticked rather than run to completion.
706
- *
707
- * It does **not** re-anchor the way the one-shot does. That translation exists
708
- * so a single 300-tick jump does not move the diagram off where the author left
709
- * it; a live run cannot jump, every frame being one step from the last, and
710
- * gravity holds the graph around the centroid it was seeded from. Re-anchoring
711
- * per frame would also fight a drag: the anchor is measured from where the
712
- * nodes were, and a pinned node is deliberately somewhere else.
668
+ * It does **not** re-anchor the way the one-shot `force` does. Re-anchoring
669
+ * per frame would fight a drag: the anchor is measured from where the nodes
670
+ * were, and a pinned node is deliberately somewhere else.
713
671
  */
714
672
  declare function forceProducer<TPose>(graph: Graph, opts?: ForceProducerOptions<TPose>): LiveLayoutProducer<TPose>;
715
673
  /** Options for {@link easedProducer}. */
@@ -781,12 +739,8 @@ declare const EASED_LAYOUTS: Readonly<Record<string, LayoutFn>>;
781
739
 
782
740
  /**
783
741
  * Running a layout against a scene: `LAYOUTS`, one batch of pose writes, and
784
- * the action that reaches both.
785
- *
786
- * The split is the point. A layout is a pure function of the graph and is
787
- * tested as one; `applyLayout` is the only thing that touches a scene, and it
788
- * writes every move inside a single `scene.batch`, so a re-layout is one undo
789
- * entry rather than one per node.
742
+ * the action that reaches both. A layout is a pure function of the graph;
743
+ * `applyLayout` is the only thing that touches a scene.
790
744
  */
791
745
 
792
746
  /** The layouts this package ships. A consumer's own go in the same shape. */
@@ -808,18 +762,16 @@ interface ApplyLayoutOptions<TPose> {
808
762
  * descriptor knows how to move one.
809
763
  *
810
764
  * A participant that is a container takes its whole subtree along. `setPose`
811
- * does not cascade — poses are absolute — so a built body would otherwise walk
812
- * out from under its own label rows with every test green.
765
+ * does not cascade — poses are absolute.
813
766
  */
814
767
  declare function applyLayout<TPose>(scene: Scene<unknown, string, TPose>, result: LayoutResult, opts?: ApplyLayoutOptions<TPose>): number;
815
768
  /**
816
769
  * The poses a layout result implies, without writing any of them: each moved
817
770
  * node translated to its new top-left, and its subtree translated with it.
818
771
  *
819
- * Split out because a *live* layout needs the same answer every frame and must
820
- * not write it — it publishes to the override channel and commits once. The
821
- * translation is measured from the node's document pose, which a run in flight
822
- * never changes, so a frame's answer does not depend on the frame before it.
772
+ * The translation is measured from the node's document pose, which a live run
773
+ * in flight never changes, so a frame's answer does not depend on the frame
774
+ * before it.
823
775
  */
824
776
  declare function layoutPoses<TPose>(scene: Scene<unknown, string, TPose>, result: LayoutResult, geometry?: PoseDescriptor<TPose>): Map<string, TPose>;
825
777
  /** The default action id. */
@@ -843,18 +795,11 @@ interface LayoutActionOptions<TPose> {
843
795
  }
844
796
  /**
845
797
  * `diagram.layout` — rebuild the graph, run a layout, write the result.
846
- *
847
- * A factory rather than a singleton for the reason every other entry point in
848
- * this package is one: which nodes are in the diagram is the consumer's, and
849
- * this package has no scene at module scope.
850
798
  */
851
799
  declare function createLayoutAction<TPose>(opts: LayoutActionOptions<TPose>): Action;
852
800
 
853
801
  /**
854
802
  * The port affordance, composed into a layer and pointed at a scene.
855
- *
856
- * Two conveniences over {@link createPortAffordance}, both of which encode a
857
- * rule that is easy to get wrong rather than merely saving a line.
858
803
  */
859
804
 
860
805
  /** The minimum a participant source needs from a scene. Narrower than `Scene`
@@ -880,12 +825,9 @@ interface ParticipantScene<TPose> {
880
825
  *
881
826
  * `effectivePose`, not `node.pose`: an override is what a gesture is currently
882
827
  * showing, and a port that answers from the document pose while its node is
883
- * mid-drag sits somewhere the user can see the node is not. Nodes that carry no
884
- * participant trait cost one reader call each and contribute no regions.
828
+ * mid-drag sits somewhere the user can see the node is not.
885
829
  *
886
- * One source answers both the ports and the graph — `GraphSource` is a
887
- * `ParticipantSource` that also carries `dependsOn`, which is where an edge's
888
- * two endpoints live.
830
+ * One source answers both the ports and the graph.
889
831
  */
890
832
  declare function sceneParticipants<TPose>(scene: ParticipantScene<TPose>): GraphSource<TPose>;
891
833
  /**
@@ -893,27 +835,18 @@ declare function sceneParticipants<TPose>(scene: ParticipantScene<TPose>): Graph
893
835
  * attach route that is hit-tested. Handing this to `SceneCanvas`'s `layers`
894
836
  * prop, or to a `Contribution.overlay`, paints the ports and makes none of them
895
837
  * grabbable.
896
- *
897
- * The cast is `composeAffordanceLayer` typing its data slot as `ChromeState`
898
- * while the layer registry takes `RenderLayer<unknown>`; both are handed the
899
- * same live `CanvasHelpers` envelope at runtime.
900
838
  */
901
839
  declare function portLayer<TPose>(participants: ParticipantSource<TPose>, opts?: PortAffordanceOptions<TPose>): RenderLayer<unknown> & {
902
840
  hitTest: NonNullable<RenderLayer<unknown>['hitTest']>;
903
841
  };
904
842
 
905
843
  /**
906
- * The painter for a node whose trait names an `outline`.
907
- *
908
- * Registered the way every other trait's renderer is — a `NodeShapeEntry` with
909
- * a `matches` over the node's data — so a diagram body is picked, clipped and
910
- * area-selected by the same walk as everything else, and a participant that
844
+ * The painter for a node whose trait names an `outline`. A participant that
911
845
  * already had a look of its own (a text block, an image, a path) keeps it by
912
846
  * naming no outline at all.
913
847
  *
914
848
  * Rows are **not** painted here. A built body's rows are ordinary scene nodes
915
- * under the container, so the kit's own text painter draws them and text
916
- * editing, selection and styling work on them without a special case.
849
+ * under the container, so the kit's own text painter draws them.
917
850
  */
918
851
 
919
852
  /** Options for {@link diagramShape} and {@link registerDiagramShape}. */
@@ -926,7 +859,7 @@ interface DiagramShapeOptions<TPose> {
926
859
  /** Reads the box the outline is built in. Default `RECT_POSE_DESCRIPTOR`. */
927
860
  geometry?: PoseDescriptor<TPose>;
928
861
  /** Painted when the node's data declares neither. */
929
- defaultFill?: FillStyle | null;
862
+ defaultFill?: Fill | null;
930
863
  defaultStroke?: Stroke | null;
931
864
  }
932
865
  /** The entry, for a consumer composing their own painter list. */
@@ -993,7 +926,7 @@ interface DiagramViewProps {
993
926
  * Default 16. */
994
927
  fitPadding?: number;
995
928
  /** What the canvas paints behind the diagram. Unset, it is transparent. */
996
- background?: FillStyle;
929
+ background?: Paint;
997
930
  /** The view, controlled. Set it and the initial fit is skipped; pair it
998
931
  * with `onViewChange` or panning does nothing. */
999
932
  view?: View;
@@ -1022,4 +955,4 @@ declare const DiagramView: react.ForwardRefExoticComponent<DiagramViewProps & re
1022
955
  * `<SceneCanvas onClick>`. */
1023
956
  declare function useMirroredSelection(selection: Pick<SelectionApi, 'get' | 'set'>, selected: string | null | undefined, onSelect: ((id: string | null) => void) | undefined): () => void;
1024
957
 
1025
- 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 DiagramEdge, DiagramGroup, type DiagramLabel, DiagramNode, DiagramNodeLike, DiagramNodeReader, type DiagramSceneData, type DiagramSceneOptions, type DiagramShapeOptions, type DiagramSpec, 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$1 as 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 };
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 };
package/dist/index.js CHANGED
@@ -1,9 +1,10 @@
1
- import { insetOf, layered, portsOf, portOf, outlinePath, diagramNodeOf, expandGroupEdges, forceRelaxation, center, force, tree, DIAGRAM_TRAIT_KEY, DEFAULT_GROUP_INSET, sizeToBody, measureBody, buildBody } from './chunk-EDSBULQM.js';
2
- export { COMPASS, DEFAULT_GROUP_INSET, DEFAULT_NODE_GAP, DEFAULT_PORTS, DEFAULT_RANK_GAP, DIAGRAM_TRAIT_KEY, axesFor, backEdges, bodyOutline, bodyTrait, boxForContent, buildBody, canvasMeasure, contentBox, createDiagramNodes, dataKeyReader, diagramNodeOf, expandGroupEdges, force, forceRelaxation, forestOf, graphOrder, insetOf, isPinned, layered, layoutBody, layoutRowPorts, measureBody, outlinePath, outlinePolyline, packAcross, packClusters, pinnedSet, portOf, portsOf, portsOnOutline, rankGaps, ranksOf, rayHit, seededOrder, settle, sizeToBody, translated, tree, untilSettled } from './chunk-EDSBULQM.js';
1
+ import { insetOf, layered, portsOf, portOf, outlinePath, diagramNodeOf, expandGroupEdges, forceRelaxation, center, force, tree, DIAGRAM_TRAIT_KEY, DEFAULT_GROUP_INSET, sizeToBody, measureBody, buildBody } from './chunk-BWQJYEA3.js';
2
+ export { COMPASS, DEFAULT_GROUP_INSET, DEFAULT_NODE_GAP, DEFAULT_PORTS, DEFAULT_RANK_GAP, DIAGRAM_TRAIT_KEY, axesFor, backEdges, bodyOutline, bodyTrait, boxForContent, buildBody, canvasMeasure, contentBox, createDiagramNodes, dataKeyReader, diagramNodeOf, expandGroupEdges, force, forceRelaxation, forestOf, graphOrder, insetOf, isPinned, layered, layoutBody, layoutRowPorts, measureBody, outlinePath, outlinePolyline, packAcross, packClusters, pinnedSet, portOf, portsOf, portsOnOutline, rankGaps, ranksOf, rayHit, seededOrder, settle, sizeToBody, translated, tree, untilSettled } from './chunk-BWQJYEA3.js';
3
3
  import { dragPanContribution, WeaselProvider, useScene, useSelection, useLatest, reconcileSpecs, SceneCanvas, fitViewToBounds, AUTO_POSE_DESCRIPTOR, translatePoseViaDescriptor, pointAlongPath, polylineFromPoints, registerNodeShape, effectivePose, usePoseRun, RECT_POSE_DESCRIPTOR, commandFill, commandStroke, composeAffordanceLayer } from '@weasel-js/core';
4
4
  import { portCurvePoints } from '@weasel-js/geom';
5
5
  import { AUTO_POSE_DESCRIPTOR as AUTO_POSE_DESCRIPTOR$1 } from '@weasel-js/core/math';
6
6
  import { forwardRef, useEffect, useMemo, useRef, useState, useImperativeHandle, useCallback } from 'react';
7
+ import '@weasel-js/animator';
7
8
  import { jsx } from 'react/jsx-runtime';
8
9
 
9
10
  function traitOf(node) {
@@ -364,9 +365,6 @@ function commitEdgeToScene(edge, ctx) {
364
365
  kind: "leaf",
365
366
  layer: source?.layer ?? scene.layers[0].id,
366
367
  pose: { x: 0, y: 0, width: 0, height: 0 },
367
- // An edge runs *from* one node *to* another, and a plain line does not say
368
- // so. The arrowhead is an ordinary stroke marker, which is why nothing in
369
- // this package draws one.
370
368
  data: { diagram: trait, stroke: DEFAULT_EDGE_STROKE },
371
369
  dependsOn: [edge.from.nodeId, edge.to.nodeId],
372
370
  // Without this the edge re-resolves on every dependency move and paints
@@ -673,7 +671,7 @@ function groupSpecs(groups, placedAt, styleOf) {
673
671
  pose: { x, y, width, height },
674
672
  data: {
675
673
  diagram: { outline: "rect", group: { inset: g.inset } },
676
- fill: { color: style.fill },
674
+ fill: { paint: { color: style.fill } },
677
675
  stroke: {
678
676
  paint: { color: style.stroke },
679
677
  width: style.strokeWidth ?? 1,
@@ -691,7 +689,7 @@ function groupSpecs(groups, placedAt, styleOf) {
691
689
  layer: "main",
692
690
  pickable: false,
693
691
  pose: { x: x + g.pad, y: y + g.pad, width: g.title.width, height: g.title.height },
694
- data: { diagram: { anchor }, text: g.group.label, style: text, fill: { color: style.text } },
692
+ data: { diagram: { anchor }, text: g.group.label, style: text, fill: { paint: { color: style.text } } },
695
693
  dependsOn: [g.group.id],
696
694
  derivePose: ANCHOR_DERIVE_POSE
697
695
  });
@@ -805,7 +803,7 @@ function diagramScene(data, opts = {}) {
805
803
  const seed = seeds[i].bounds;
806
804
  const at = placedAt.get(n.id);
807
805
  const style = opts.nodeStyle?.(n) ?? NODE;
808
- const textData = (text, s) => ({ text, style: styleOf(s), fill: { color: style.text } });
806
+ const textData = (text, s) => ({ text, style: styleOf(s), fill: { paint: { color: style.text } } });
809
807
  const built = buildBody(
810
808
  bodies[i],
811
809
  { x: at.x, y: at.y, width: seed.width, height: seed.height },
@@ -815,7 +813,7 @@ function diagramScene(data, opts = {}) {
815
813
  measure,
816
814
  body: (trait) => ({
817
815
  diagram: n.pinned === true ? { ...trait, pinned: true } : trait,
818
- fill: { color: style.fill },
816
+ fill: { paint: { color: style.fill } },
819
817
  stroke: {
820
818
  paint: { color: style.stroke },
821
819
  width: style.strokeWidth ?? 2,
@@ -871,7 +869,7 @@ function diagramScene(data, opts = {}) {
871
869
  diagram: { label: e.labelPlacement ?? opts.labelPlacement ?? LABEL_PLACEMENT },
872
870
  text: e.label,
873
871
  style: labelStyle,
874
- fill: { color: style.label ?? style.stroke }
872
+ fill: { paint: { color: style.label ?? style.stroke } }
875
873
  },
876
874
  dependsOn: [id],
877
875
  derivePose: LABEL_DERIVE_POSE