@weasel-js/diagram 1.5.0 → 1.5.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/chunk-M34HI5RG.js +862 -0
- package/dist/chunk-M34HI5RG.js.map +1 -0
- package/dist/index.d.ts +5 -746
- package/dist/index.js +6 -865
- package/dist/index.js.map +1 -1
- package/dist/layout.d.ts +3 -0
- package/dist/layout.entry-BO7d72yq.d.ts +749 -0
- package/dist/layout.js +3 -0
- package/dist/layout.js.map +1 -0
- package/package.json +6 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,425 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* The shapes a built body can wear, as paths in the node's bounds.
|
|
6
|
-
*
|
|
7
|
-
* These are the flowchart vocabulary — a decision is a diamond, an I/O step a
|
|
8
|
-
* parallelogram, a terminator a stadium — plus `'rect'` for everything else and
|
|
9
|
-
* a `Path` escape hatch for a shape the vocabulary does not have. The path is
|
|
10
|
-
* built in world coordinates from the bounds it is given, the same way the
|
|
11
|
-
* kit's own `clipFromPose` factories are.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
/** An axis-aligned box, in the shape `PoseDescriptor.getBounds` returns. */
|
|
15
|
-
interface Bounds {
|
|
16
|
-
x: number;
|
|
17
|
-
y: number;
|
|
18
|
-
width: number;
|
|
19
|
-
height: number;
|
|
20
|
-
}
|
|
21
|
-
/** A named flowchart shape, or a path a consumer built themselves. */
|
|
22
|
-
type Outline = 'rect' | 'diamond' | 'stadium' | 'parallelogram' | Path;
|
|
23
|
-
/** The path `outline` describes inside `bounds`. A zero-area box gives a
|
|
24
|
-
* zero-area rect rather than a degenerate polygon. */
|
|
25
|
-
declare function outlinePath(outline: Outline, bounds: Bounds): Path;
|
|
26
|
-
/**
|
|
27
|
-
* The largest axis-aligned box a shape's content can occupy without leaving
|
|
28
|
-
* the shape. Rows lay out in here, not in the bounds — a diamond's corners and
|
|
29
|
-
* a parallelogram's lean are outside its own box, and a label placed against
|
|
30
|
-
* the bounding box lands there and gets clipped away by the silhouette.
|
|
31
|
-
*
|
|
32
|
-
* Conservative rather than exact: the inscribed rect of a rhombus is exact,
|
|
33
|
-
* and a stadium reports the flat span between its rounded ends, which gives up
|
|
34
|
-
* a little height near them.
|
|
35
|
-
*/
|
|
36
|
-
declare function contentBox(outline: Outline, bounds: Bounds): Bounds;
|
|
37
|
-
/**
|
|
38
|
-
* The box whose {@link contentBox} is at least `content` — the inverse, for
|
|
39
|
-
* sizing a node to what its rows measured.
|
|
40
|
-
*
|
|
41
|
-
* The stadium case is the only inexact one: its inset depends on the height it
|
|
42
|
-
* is solving for, so it assumes the wide orientation and adds one height's
|
|
43
|
-
* worth of end caps.
|
|
44
|
-
*/
|
|
45
|
-
declare function boxForContent(outline: Outline, content: {
|
|
46
|
-
width: number;
|
|
47
|
-
height: number;
|
|
48
|
-
}): {
|
|
49
|
-
width: number;
|
|
50
|
-
height: number;
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Where a port sits on its node, in **normalized bounds coordinates**:
|
|
55
|
-
* `(0, 0)` is the top-left corner of the node's AABB and `(1, 1)` the
|
|
56
|
-
* bottom-right. `COMPASS` names the eight positions almost everything wants.
|
|
57
|
-
*
|
|
58
|
-
* Normalized rather than absolute because a node's size is authored data that
|
|
59
|
-
* resize, align and distribute all write — a port fixed at an offset would
|
|
60
|
-
* drift off the shape the first time one of them ran.
|
|
61
|
-
*/
|
|
62
|
-
interface PortAnchor {
|
|
63
|
-
u: number;
|
|
64
|
-
v: number;
|
|
65
|
-
}
|
|
66
|
-
/** One attachment point declared on a node. */
|
|
67
|
-
interface PortSpec {
|
|
68
|
-
/** Unique within the node. Edges name this, so it outlives a re-layout. */
|
|
69
|
-
id: string;
|
|
70
|
-
at: PortAnchor;
|
|
71
|
-
/** Consulted by a connect gesture's validity predicate. Uninterpreted here. */
|
|
72
|
-
type?: string;
|
|
73
|
-
/** The direction an edge leaves along, overriding the one the anchor
|
|
74
|
-
* implies. `null` means "no preferred direction" — a router goes straight
|
|
75
|
-
* at it. */
|
|
76
|
-
normal?: Vec2 | null;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* The trait that makes an existing scene node a diagram participant.
|
|
80
|
-
*
|
|
81
|
-
* Attached to a node's `data`, not a node kind the plugin mints: a text block,
|
|
82
|
-
* an image, a path, a group or a plain rect all take part by carrying this,
|
|
83
|
-
* and nothing has to be authored through this package to be connectable.
|
|
84
|
-
*/
|
|
85
|
-
interface DiagramNode {
|
|
86
|
-
/** Defaults to {@link DEFAULT_PORTS} — the four edge midpoints of the
|
|
87
|
-
* node's own bounds, which every node has. */
|
|
88
|
-
ports?: readonly PortSpec[];
|
|
89
|
-
/** Layout must not move this node. */
|
|
90
|
-
pinned?: boolean;
|
|
91
|
-
/** What the node is *drawn* as. Present on a built body; absent on a
|
|
92
|
-
* participant that already had a look of its own — a text block, an image,
|
|
93
|
-
* a path — which keeps whatever painter it already matched. */
|
|
94
|
-
outline?: Outline;
|
|
95
|
-
}
|
|
96
|
-
/** A port resolved against a node's current pose: where it is in world
|
|
97
|
-
* coordinates, and which way an edge leaves it. */
|
|
98
|
-
interface Port {
|
|
99
|
-
id: string;
|
|
100
|
-
/** The node this port belongs to. */
|
|
101
|
-
nodeId: string;
|
|
102
|
-
/** World point an edge attaches to. */
|
|
103
|
-
point: Vec2;
|
|
104
|
-
/** Unit vector pointing away from the node, or `null` when the port
|
|
105
|
-
* declared no direction. Rotated with the node. */
|
|
106
|
-
normal: Vec2 | null;
|
|
107
|
-
type?: string;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/** One line of body content. */
|
|
111
|
-
type Row =
|
|
112
|
-
/** Text. `label` is the node's name; `field` is a named value. */
|
|
113
|
-
{
|
|
114
|
-
kind: 'label';
|
|
115
|
-
text: string;
|
|
116
|
-
style?: RowTextStyle;
|
|
117
|
-
} | {
|
|
118
|
-
kind: 'field';
|
|
119
|
-
label: string;
|
|
120
|
-
value: string;
|
|
121
|
-
style?: RowTextStyle;
|
|
122
|
-
}
|
|
123
|
-
/** A row that carries ports on its own left and right edges — the
|
|
124
|
-
* visual-programming shape, where an operator's inputs line up with the
|
|
125
|
-
* rows they feed. */
|
|
126
|
-
| {
|
|
127
|
-
kind: 'ports';
|
|
128
|
-
left?: readonly RowPort[];
|
|
129
|
-
right?: readonly RowPort[];
|
|
130
|
-
height?: number;
|
|
131
|
-
}
|
|
132
|
-
/** Reserved space a consumer paints into. */
|
|
133
|
-
| {
|
|
134
|
-
kind: 'slot';
|
|
135
|
-
height: number;
|
|
136
|
-
id?: string;
|
|
137
|
-
};
|
|
138
|
-
/** A port declared on a row rather than on the node's perimeter. */
|
|
139
|
-
interface RowPort {
|
|
140
|
-
id: string;
|
|
141
|
-
/** Label shown beside it, and what the row measures against. */
|
|
142
|
-
label?: string;
|
|
143
|
-
type?: string;
|
|
144
|
-
}
|
|
145
|
-
/** The subset of a text style the body measures against. Deliberately small:
|
|
146
|
-
* a full `ResolvedTextStyle` belongs to whatever paints the row. */
|
|
147
|
-
interface RowTextStyle {
|
|
148
|
-
fontSize?: number;
|
|
149
|
-
fontFamily?: string;
|
|
150
|
-
bold?: boolean;
|
|
151
|
-
}
|
|
152
|
-
/** Measures one run of text. Returns its advance width and its line height. */
|
|
153
|
-
type MeasureRowText = (text: string, style: RowTextStyle) => {
|
|
154
|
-
width: number;
|
|
155
|
-
height: number;
|
|
156
|
-
};
|
|
157
|
-
interface BodySpec {
|
|
158
|
-
outline: Outline;
|
|
159
|
-
rows: readonly Row[];
|
|
160
|
-
/** Space between the outline and its rows. Default 8. */
|
|
161
|
-
padding?: number;
|
|
162
|
-
/** Space between adjacent rows. Default 4. */
|
|
163
|
-
gap?: number;
|
|
164
|
-
}
|
|
165
|
-
/** What {@link buildBody} emits: the `AddNodeSpec` fields it fills in. Named
|
|
166
|
-
* structurally rather than imported so a consumer whose scene is typed
|
|
167
|
-
* differently can still spread one. */
|
|
168
|
-
interface BodyNodeSpec<TData, TLayer extends string, TPose> {
|
|
169
|
-
kind: 'container' | 'leaf';
|
|
170
|
-
layer: TLayer;
|
|
171
|
-
pose: TPose;
|
|
172
|
-
data: TData;
|
|
173
|
-
id?: string;
|
|
174
|
-
parent?: string;
|
|
175
|
-
/** Set `false` on every leaf the builder emits: the innermost hit wins, so a
|
|
176
|
-
* row that answers a press is a body that cannot be dragged. */
|
|
177
|
-
pickable?: boolean;
|
|
178
|
-
}
|
|
179
|
-
/** The floor a body's content puts under its node's size. */
|
|
180
|
-
interface BodyFloor {
|
|
181
|
-
minWidth: number;
|
|
182
|
-
minHeight: number;
|
|
183
|
-
}
|
|
184
|
-
/** Where one row landed, in the same frame as the bounds it was laid out in.
|
|
185
|
-
* A `ports` row's own ports anchor to this box. */
|
|
186
|
-
interface RowBox extends Bounds {
|
|
187
|
-
row: Row;
|
|
188
|
-
index: number;
|
|
189
|
-
}
|
|
190
|
-
/** Where one row port's label sits, in the same frame as the row box it was
|
|
191
|
-
* laid out in. Its vertical center is also where the port itself attaches, so
|
|
192
|
-
* a label and the port it names cannot drift apart. */
|
|
193
|
-
interface RowPortBox extends Bounds {
|
|
194
|
-
port: RowPort;
|
|
195
|
-
side: 'left' | 'right';
|
|
196
|
-
/** Position within its own side, top to bottom. */
|
|
197
|
-
index: number;
|
|
198
|
-
}
|
|
199
|
-
/** Adapts the kit's `measureText` for a caller holding a 2D context. Pass the
|
|
200
|
-
* same context the renderer measures with, or the floor will not match what
|
|
201
|
-
* is painted. */
|
|
202
|
-
declare function canvasMeasure(ctx: {
|
|
203
|
-
measureText(text: string): {
|
|
204
|
-
width: number;
|
|
205
|
-
};
|
|
206
|
-
font: string;
|
|
207
|
-
}): MeasureRowText;
|
|
208
|
-
/**
|
|
209
|
-
* The smallest box `spec`'s rows fit in. A node's pose is maxed against this,
|
|
210
|
-
* never set to it.
|
|
211
|
-
*/
|
|
212
|
-
declare function measureBody(spec: BodySpec, measure?: MeasureRowText): BodyFloor;
|
|
213
|
-
/**
|
|
214
|
-
* The authored size, grown to fit the body. Never shrinks: a row removed
|
|
215
|
-
* leaves the node the size the author last saw it at, which is the only
|
|
216
|
-
* behavior that survives a resize the author did on purpose.
|
|
217
|
-
*/
|
|
218
|
-
declare function sizeToBody<TPose extends Bounds>(pose: TPose, floor: BodyFloor): TPose;
|
|
219
|
-
/** Where each row sits inside `bounds`, top to bottom. Rows keep their
|
|
220
|
-
* measured heights; the leftover goes unclaimed at the bottom rather than
|
|
221
|
-
* being distributed, so a row does not move when a sibling grows. */
|
|
222
|
-
declare function layoutBody(spec: BodySpec, bounds: Bounds, measure?: MeasureRowText): RowBox[];
|
|
223
|
-
/**
|
|
224
|
-
* Where each of a `ports` row's ports goes inside `box`, on the same terms
|
|
225
|
-
* `layoutBody` gives one box per row.
|
|
226
|
-
*
|
|
227
|
-
* Both sides are cut into the same number of slots — the longer side's count —
|
|
228
|
-
* so the nth input faces the nth output whichever side has more. A label box
|
|
229
|
-
* is as wide as its own text and pinned to its own edge of the row; an
|
|
230
|
-
* unlabeled port gets a zero-width box there, which is still where it attaches.
|
|
231
|
-
*/
|
|
232
|
-
declare function layoutRowPorts(row: Extract<Row, {
|
|
233
|
-
kind: 'ports';
|
|
234
|
-
}>, box: Bounds, measure?: MeasureRowText): RowPortBox[];
|
|
235
|
-
/**
|
|
236
|
-
* The `DiagramNode` trait a built body implies: perimeter ports for the
|
|
237
|
-
* outline, plus one port per `ports`-row entry, anchored to that row's own
|
|
238
|
-
* left or right edge.
|
|
239
|
-
*
|
|
240
|
-
* Anchors are normalized against `bounds`, so they survive the node being
|
|
241
|
-
* resized — which is the whole reason `PortAnchor` is normalized.
|
|
242
|
-
*
|
|
243
|
-
* **A row port on a side takes that side's compass default with it.** Both sit
|
|
244
|
-
* on the same edge, and a row near the vertical middle puts one exactly on top
|
|
245
|
-
* of `w` or `e` — where the later region wins the hit and the other is
|
|
246
|
-
* grabbable nowhere. A body that declares where its inputs attach has said what
|
|
247
|
-
* that side is for.
|
|
248
|
-
*/
|
|
249
|
-
declare function bodyTrait(spec: BodySpec, bounds: Bounds, measure?: MeasureRowText): DiagramNode;
|
|
250
|
-
/** The outline path for a built body at `bounds` — what paints it, and what a
|
|
251
|
-
* perimeter-hugging port will eventually be placed on. */
|
|
252
|
-
declare function bodyOutline(spec: BodySpec, bounds: Bounds): _weasel_js_core.Path;
|
|
253
|
-
/** What a built body's rows are handed to, one call per row.
|
|
254
|
-
*
|
|
255
|
-
* `text` is the row's content already formatted — a `label`'s own text, or a
|
|
256
|
-
* `field`'s `"label: value"` — so the common case needs no discrimination.
|
|
257
|
-
* Return `null` for a row the consumer paints itself; `ports` and `slot` rows
|
|
258
|
-
* arrive with `text` empty and are the usual ones to decline. */
|
|
259
|
-
type RowNodeData<TData> = (text: string, box: RowBox) => TData | null;
|
|
260
|
-
interface BuildBodyOptions<TData, TLayer extends string, TPose extends Bounds> {
|
|
261
|
-
layer: TLayer;
|
|
262
|
-
/** The container's id. Edges name it, so pass one for anything an edge or a
|
|
263
|
-
* layout `pin` will refer to. */
|
|
264
|
-
id?: string;
|
|
265
|
-
measure?: MeasureRowText;
|
|
266
|
-
/** The container's own data, given the trait the builder computed and the
|
|
267
|
-
* pose it was computed against. */
|
|
268
|
-
body: (trait: DiagramNode, pose: TPose) => TData;
|
|
269
|
-
/** One row's data, or `null` to leave that row undrawn. */
|
|
270
|
-
row: RowNodeData<TData>;
|
|
271
|
-
/** One row port's label, or `null` to leave it undrawn. Ports with no
|
|
272
|
-
* `label` are never offered. Omit to draw none — a body whose ports are
|
|
273
|
-
* named only for the width they claim needs nothing here. */
|
|
274
|
-
portLabel?: (text: string, box: RowPortBox) => TData | null;
|
|
275
|
-
}
|
|
276
|
-
/**
|
|
277
|
-
* The scene nodes a built body is: one container carrying the trait, and one
|
|
278
|
-
* leaf per row that wants drawing.
|
|
279
|
-
*
|
|
280
|
-
* Rows are ordinary scene nodes rather than something this package paints, so
|
|
281
|
-
* the kit's own text painter draws them and text editing, styling and
|
|
282
|
-
* selection work on them unchanged. The walk that places them is
|
|
283
|
-
* `layoutBody` — the same one `bodyTrait` anchors its row ports against, which
|
|
284
|
-
* is why a label and its ports cannot drift apart.
|
|
285
|
-
*
|
|
286
|
-
* The pose is `sizeToBody(at, measureBody(spec))`: the body measures a floor
|
|
287
|
-
* and the authored size is grown to clear it, never shrunk.
|
|
288
|
-
*/
|
|
289
|
-
declare function buildBody<TData, TLayer extends string, TPose extends Bounds>(spec: BodySpec, at: TPose, opts: BuildBodyOptions<TData, TLayer, TPose>): {
|
|
290
|
-
pose: TPose;
|
|
291
|
-
specs: BodyNodeSpec<TData, TLayer, TPose>[];
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Reading the `DiagramNode` trait off a scene node.
|
|
296
|
-
*
|
|
297
|
-
* Two ways to attach it, both of which this module's default reader answers:
|
|
298
|
-
*
|
|
299
|
-
* - **On the node.** `data.diagram` holds the trait. One node, one answer;
|
|
300
|
-
* what a connect gesture writes when the author drags a new edge.
|
|
301
|
-
* - **By kind.** A consumer declares once which data shapes take part, and
|
|
302
|
-
* every matching node gets the trait without being stamped. This mirrors
|
|
303
|
-
* `createNodeRouting` in the kit — a predicate over `data`, first match
|
|
304
|
-
* wins — and is the shape to reach for when the participants are a class
|
|
305
|
-
* of node rather than a hand-picked set.
|
|
306
|
-
*
|
|
307
|
-
* A reader is a plain function, so a consumer whose data lives somewhere else
|
|
308
|
-
* entirely passes their own and never touches either form.
|
|
309
|
-
*/
|
|
310
|
-
|
|
311
|
-
/** The key on a node's `data` the default reader looks under. */
|
|
312
|
-
declare const DIAGRAM_TRAIT_KEY = "diagram";
|
|
313
|
-
/** All a reader looks at. Deliberately not `SceneNode`: naming `TPose` there
|
|
314
|
-
* would put it in a contravariant position for no gain, since nothing here
|
|
315
|
-
* reads a pose. */
|
|
316
|
-
interface DiagramNodeLike {
|
|
317
|
-
id: string;
|
|
318
|
-
kind: 'leaf' | 'container';
|
|
319
|
-
data: unknown;
|
|
320
|
-
}
|
|
321
|
-
/** Answers "is this node a diagram participant, and on what terms" — `null`
|
|
322
|
-
* for a node that takes no part. */
|
|
323
|
-
type DiagramNodeReader = (node: DiagramNodeLike) => DiagramNode | null;
|
|
324
|
-
/** One class of participant, declared once for every node whose data matches.
|
|
325
|
-
* Mirrors `NodeRoutingEntry`. */
|
|
326
|
-
interface DiagramNodeEntry {
|
|
327
|
-
/** Unique within a reader; the same vocabulary as `NodeRoutingEntry.name`. */
|
|
328
|
-
name: string;
|
|
329
|
-
matches: (data: unknown) => boolean;
|
|
330
|
-
/** The trait every matching node carries. A function when it varies with the
|
|
331
|
-
* node's own data — a pipeline stage whose ports come from its rows. */
|
|
332
|
-
trait: DiagramNode | ((data: unknown) => DiagramNode);
|
|
333
|
-
}
|
|
334
|
-
/** The trait on the node's own `data.diagram`, or `null`.
|
|
335
|
-
*
|
|
336
|
-
* An edge's trait lives under the same key, so `from` and `to` are what tells
|
|
337
|
-
* the two apart. Without that test an edge reads as a participant declaring
|
|
338
|
-
* no ports, and collects the four defaults on the degenerate pose an edge
|
|
339
|
-
* carries — four grabbable ports in the middle of nowhere. */
|
|
340
|
-
declare const dataKeyReader: DiagramNodeReader;
|
|
341
|
-
/**
|
|
342
|
-
* A reader over declared kinds. A trait on the node's own data still wins, so
|
|
343
|
-
* a single node can opt out of, or override, whatever its kind says.
|
|
344
|
-
*
|
|
345
|
-
* Throws on a duplicate `name`, for the reason `mergeContributions` does: a
|
|
346
|
-
* class of node silently losing its ports is what this registry exists to make
|
|
347
|
-
* loud.
|
|
348
|
-
*/
|
|
349
|
-
declare function createDiagramNodes(entries: readonly DiagramNodeEntry[]): DiagramNodeReader;
|
|
350
|
-
/** The trait `node` carries, through `read` (default: its own `data.diagram`). */
|
|
351
|
-
declare function diagramNodeOf(node: DiagramNodeLike, read?: DiagramNodeReader): DiagramNode | null;
|
|
352
|
-
/** True when layout must leave this node where it is. */
|
|
353
|
-
declare function isPinned(node: DiagramNodeLike, read?: DiagramNodeReader): boolean;
|
|
354
|
-
|
|
355
|
-
/**
|
|
356
|
-
* Where a node's ports are, in world coordinates.
|
|
357
|
-
*
|
|
358
|
-
* A port is placed in the node's **unrotated** bounds, then carried through
|
|
359
|
-
* the pose's rotation — the same pivot every other kit reader uses, the AABB
|
|
360
|
-
* center. Bounds come from the pose descriptor rather than from `pose.width`
|
|
361
|
-
* and friends, so a node whose pose is a path, an ellipse or anything else a
|
|
362
|
-
* consumer wired is connectable on the same terms as a rect.
|
|
363
|
-
*/
|
|
364
|
-
|
|
365
|
-
/** The eight anchors almost everything wants, named the way a compass is. */
|
|
366
|
-
declare const COMPASS: {
|
|
367
|
-
readonly nw: {
|
|
368
|
-
readonly u: 0;
|
|
369
|
-
readonly v: 0;
|
|
370
|
-
};
|
|
371
|
-
readonly n: {
|
|
372
|
-
readonly u: 0.5;
|
|
373
|
-
readonly v: 0;
|
|
374
|
-
};
|
|
375
|
-
readonly ne: {
|
|
376
|
-
readonly u: 1;
|
|
377
|
-
readonly v: 0;
|
|
378
|
-
};
|
|
379
|
-
readonly e: {
|
|
380
|
-
readonly u: 1;
|
|
381
|
-
readonly v: 0.5;
|
|
382
|
-
};
|
|
383
|
-
readonly se: {
|
|
384
|
-
readonly u: 1;
|
|
385
|
-
readonly v: 1;
|
|
386
|
-
};
|
|
387
|
-
readonly s: {
|
|
388
|
-
readonly u: 0.5;
|
|
389
|
-
readonly v: 1;
|
|
390
|
-
};
|
|
391
|
-
readonly sw: {
|
|
392
|
-
readonly u: 0;
|
|
393
|
-
readonly v: 1;
|
|
394
|
-
};
|
|
395
|
-
readonly w: {
|
|
396
|
-
readonly u: 0;
|
|
397
|
-
readonly v: 0.5;
|
|
398
|
-
};
|
|
399
|
-
};
|
|
400
|
-
/**
|
|
401
|
-
* What a node carrying no `ports` gets: the four edge midpoints of its own
|
|
402
|
-
* bounds. Every node has bounds, so every node is connectable without saying
|
|
403
|
-
* anything.
|
|
404
|
-
*/
|
|
405
|
-
declare const DEFAULT_PORTS: readonly PortSpec[];
|
|
406
|
-
interface PortsOptions<TPose> {
|
|
407
|
-
/** Reads the AABB a port is placed in, and the node's rotation. Defaults to
|
|
408
|
-
* the kit's `AUTO_POSE_DESCRIPTOR`, which handles rect and path poses. */
|
|
409
|
-
geometry?: PoseDescriptor<TPose>;
|
|
410
|
-
/** How the `DiagramNode` trait is read off a node. */
|
|
411
|
-
read?: DiagramNodeReader;
|
|
412
|
-
}
|
|
413
|
-
/**
|
|
414
|
-
* Every port on `node`, resolved against `pose`.
|
|
415
|
-
*
|
|
416
|
-
* Pass the pose the node is **painted** at — `effectivePose(scene, node)` —
|
|
417
|
-
* not `node.pose`. A port that answers from the document pose while the node
|
|
418
|
-
* is mid-drag puts an edge somewhere the user can see the node is not.
|
|
419
|
-
*/
|
|
420
|
-
declare function portsOf<TPose>(node: DiagramNodeLike, pose: TPose, opts?: PortsOptions<TPose>): Port[];
|
|
421
|
-
/** One named port, or `undefined` when the node has no such port. */
|
|
422
|
-
declare function portOf<TPose>(node: DiagramNodeLike, pose: TPose, portId: string, opts?: PortsOptions<TPose>): Port | undefined;
|
|
1
|
+
import { P as Port, a as PortsOptions, D as DiagramNodeLike, b as DiagramNodeReader, L as LayoutFn, c as LayoutOptions, F as ForceOptions, d as LayoutResult, G as GraphSource, e as Graph } from './layout.entry-BO7d72yq.js';
|
|
2
|
+
export { B as BodyFloor, f as BodyNodeSpec, g as BodySpec, h as Bounds, i as BuildBodyOptions, j as BuildGraphOptions, C as COMPASS, k as DEFAULT_NODE_GAP, l as DEFAULT_PORTS, m as DEFAULT_RANK_GAP, n as DIAGRAM_TRAIT_KEY, o as DiagramNode, p as DiagramNodeEntry, q as ForceRelaxation, r as GraphEdge, s as GraphNode, t as GraphNodeLike, u as LayoutAxes, v as LayoutDirection, M as MeasureRowText, O as Outline, w as PortAnchor, x as PortSpec, R as Row, y as RowBox, z as RowNodeData, A as RowPort, E as RowPortBox, H as RowTextStyle, S as Slot, I as axesFor, J as backEdges, K as bodyOutline, N as bodyTrait, Q as boxForContent, T as buildBody, U as buildGraph, V as canvasMeasure, W as contentBox, X as createDiagramNodes, Y as dataKeyReader, Z as diagramNodeOf, _ as force, $ as forceRelaxation, a0 as forestOf, a1 as graphOrder, a2 as isPinned, a3 as layered, a4 as layoutBody, a5 as layoutRowPorts, a6 as measureBody, a7 as outlinePath, a8 as outlinePolyline, a9 as packAcross, aa as pinnedSet, ab as portOf, ac as portsOf, ad as portsOnOutline, ae as ranksOf, af as rayHit, ag as seededOrder, ah as settle, ai as sizeToBody, aj as translated, ak as tree } from './layout.entry-BO7d72yq.js';
|
|
3
|
+
import { Vec2, DerivedDep, Path, SceneRegistry, PoseDescriptor, ChromeState, FillStyle, Stroke, CursorSpec, Affordance, InvocationCtx, GestureBinding, Action, Contribution, RenderLayer, EasingFn, NodeId, Scene, NodeShapeEntry } from '@weasel-js/core';
|
|
4
|
+
import '@weasel-js/core/math';
|
|
423
5
|
|
|
424
6
|
/**
|
|
425
7
|
* `DiagramEdge` — a connection between two participants.
|
|
@@ -776,78 +358,6 @@ declare function diagramPorts<TPose>(opts: DiagramContributionOptions<TPose>): {
|
|
|
776
358
|
contribution: Contribution;
|
|
777
359
|
};
|
|
778
360
|
|
|
779
|
-
/**
|
|
780
|
-
* `Graph` — the adjacency index a layout runs over.
|
|
781
|
-
*
|
|
782
|
-
* The scene is the document, so there is no second graph kept in sync with it:
|
|
783
|
-
* this one is built from the scene on demand, used, and thrown away. Rebuilding
|
|
784
|
-
* per layout invocation is deliberate — a maintained index is a cache to
|
|
785
|
-
* invalidate on every add, delete, reparent and `dependsOn` edit, and layout is
|
|
786
|
-
* not on the hot path. Measure before changing that.
|
|
787
|
-
*
|
|
788
|
-
* A node's *identity* is its id and its *size* is its bounds; where it currently
|
|
789
|
-
* sits is here too, because a re-layout that ignores where things already are
|
|
790
|
-
* scrambles a diagram the author has arranged.
|
|
791
|
-
*/
|
|
792
|
-
|
|
793
|
-
/** A scene node as the graph reads it. `dependsOn` is what an edge's two
|
|
794
|
-
* endpoints are: the edge trait names *ports*, and the nodes those ports are
|
|
795
|
-
* on are the dependencies the derivation already runs on. */
|
|
796
|
-
interface GraphNodeLike extends DiagramNodeLike {
|
|
797
|
-
dependsOn?: readonly string[] | 'children';
|
|
798
|
-
}
|
|
799
|
-
/** Where the graph gets its nodes. The same thunk shape the port affordance
|
|
800
|
-
* takes, so one source answers both. */
|
|
801
|
-
type GraphSource<TPose> = () => Iterable<{
|
|
802
|
-
node: GraphNodeLike;
|
|
803
|
-
pose: TPose;
|
|
804
|
-
}>;
|
|
805
|
-
/** One participant. */
|
|
806
|
-
interface GraphNode {
|
|
807
|
-
id: string;
|
|
808
|
-
/** Where it is now, in world coordinates. */
|
|
809
|
-
bounds: Bounds;
|
|
810
|
-
/** Layout must not move it. */
|
|
811
|
-
pinned: boolean;
|
|
812
|
-
}
|
|
813
|
-
/** One connection. `id` is the edge node's own id, so a caller can go back to
|
|
814
|
-
* the scene for its trait. */
|
|
815
|
-
interface GraphEdge {
|
|
816
|
-
id: string;
|
|
817
|
-
from: string;
|
|
818
|
-
to: string;
|
|
819
|
-
}
|
|
820
|
-
/**
|
|
821
|
-
* Nodes, edges, and the two adjacency reads a layout needs.
|
|
822
|
-
*
|
|
823
|
-
* Every list is in source order — render order, when the source is a scene —
|
|
824
|
-
* which is what a layout's tiebreaks resolve against. There is no RNG anywhere
|
|
825
|
-
* downstream of this, and this is where that starts.
|
|
826
|
-
*/
|
|
827
|
-
interface Graph {
|
|
828
|
-
readonly nodes: readonly GraphNode[];
|
|
829
|
-
readonly edges: readonly GraphEdge[];
|
|
830
|
-
node(id: string): GraphNode | undefined;
|
|
831
|
-
/** Edges leaving `id`, in source order. */
|
|
832
|
-
outgoing(id: string): readonly GraphEdge[];
|
|
833
|
-
/** Edges arriving at `id`, in source order. */
|
|
834
|
-
incoming(id: string): readonly GraphEdge[];
|
|
835
|
-
}
|
|
836
|
-
interface BuildGraphOptions<TPose> {
|
|
837
|
-
read?: DiagramNodeReader;
|
|
838
|
-
geometry?: PoseDescriptor<TPose>;
|
|
839
|
-
}
|
|
840
|
-
/**
|
|
841
|
-
* Read a graph out of a source of scene nodes.
|
|
842
|
-
*
|
|
843
|
-
* A node is an edge if it carries the edge trait and names exactly two
|
|
844
|
-
* dependencies; a participant if the reader hands back a `DiagramNode`;
|
|
845
|
-
* neither, and it is not in the diagram at all. An edge whose endpoints are not
|
|
846
|
-
* both participants is dropped — a dangling edge should not be ranking
|
|
847
|
-
* anything.
|
|
848
|
-
*/
|
|
849
|
-
declare function buildGraph<TPose>(source: GraphSource<TPose>, opts?: BuildGraphOptions<TPose>): Graph;
|
|
850
|
-
|
|
851
361
|
/**
|
|
852
362
|
* A label on an edge: an ordinary leaf node that derives its *pose* from the
|
|
853
363
|
* route it sits on.
|
|
@@ -896,177 +406,6 @@ declare const LABEL_DERIVE_POSE: (node: {
|
|
|
896
406
|
data: unknown;
|
|
897
407
|
}, deps: readonly (DerivedDep<unknown> | undefined)[]) => unknown;
|
|
898
408
|
|
|
899
|
-
/**
|
|
900
|
-
* Layout: where the participants go.
|
|
901
|
-
*
|
|
902
|
-
* A layout is a pure function of the graph — no scene, no ops, no history. It
|
|
903
|
-
* hands back the new top-left for every node that **moves**, and a node already
|
|
904
|
-
* standing where the layout wants it is simply absent from the answer. That is
|
|
905
|
-
* what makes re-running a layout free rather than destructive, and it is the
|
|
906
|
-
* property the idempotence test asserts.
|
|
907
|
-
*
|
|
908
|
-
* Three rules keep re-layout non-destructive, and all three live here rather
|
|
909
|
-
* than in each algorithm:
|
|
910
|
-
*
|
|
911
|
-
* - **No RNG anywhere.** Every tiebreak falls back to the graph's own node
|
|
912
|
-
* order, which is the source's order — render order, for a scene.
|
|
913
|
-
* - **Within-rank order is seeded from where the nodes already are**, read
|
|
914
|
-
* off the cross axis, rather than from crossing-minimization. An author who
|
|
915
|
-
* dragged two boxes into an order gets that order back.
|
|
916
|
-
* - **A pin set nothing moves.** Pinned nodes are never in the result, and
|
|
917
|
-
* the rest of the layout is translated to sit around them.
|
|
918
|
-
*
|
|
919
|
-
* `layered` and `tree` are idempotent by construction: the second run reads the
|
|
920
|
-
* order the first run produced and computes the same slots. `force` is an
|
|
921
|
-
* iterative relaxation and makes no such claim — re-running it keeps relaxing.
|
|
922
|
-
*/
|
|
923
|
-
|
|
924
|
-
/** Which way the ranks stack. `force` ignores it. */
|
|
925
|
-
type LayoutDirection = 'down' | 'up' | 'right' | 'left';
|
|
926
|
-
interface LayoutOptions {
|
|
927
|
-
/** Default `'down'`. */
|
|
928
|
-
direction?: LayoutDirection;
|
|
929
|
-
/** Between neighbors within a rank, in world units. Default 48. */
|
|
930
|
-
nodeGap?: number;
|
|
931
|
-
/** Between one rank and the next. Default 96. */
|
|
932
|
-
rankGap?: number;
|
|
933
|
-
/** Ids layout must not move, on top of whatever carries `pinned: true`. */
|
|
934
|
-
pin?: Iterable<string>;
|
|
935
|
-
/** How far a node has to move to be worth moving, in world units. Default
|
|
936
|
-
* `1e-6` — a float-noise floor, not a snapping quantum. Raise it to let a
|
|
937
|
-
* `force` pass that has stopped doing anything useful commit nothing. */
|
|
938
|
-
tolerance?: number;
|
|
939
|
-
}
|
|
940
|
-
/** The new top-left for each node that moves. A node that is already there is
|
|
941
|
-
* absent, so an empty result means "nothing to do". */
|
|
942
|
-
type LayoutResult = ReadonlyMap<string, Vec2>;
|
|
943
|
-
/** Every layout in this package has this shape, and so does a consumer's. */
|
|
944
|
-
type LayoutFn = (graph: Graph, opts?: LayoutOptions) => LayoutResult;
|
|
945
|
-
declare const DEFAULT_NODE_GAP = 48;
|
|
946
|
-
declare const DEFAULT_RANK_GAP = 96;
|
|
947
|
-
/** Which world axis carries ranks, which carries within-rank order, and
|
|
948
|
-
* whether ranks grow toward positive world coordinates. */
|
|
949
|
-
interface LayoutAxes {
|
|
950
|
-
rank: 'x' | 'y';
|
|
951
|
-
cross: 'x' | 'y';
|
|
952
|
-
/** `-1` for `'up'` and `'left'`, where the canonical frame is mirrored. */
|
|
953
|
-
sign: 1 | -1;
|
|
954
|
-
}
|
|
955
|
-
declare function axesFor(direction?: LayoutDirection): LayoutAxes;
|
|
956
|
-
/** Every id layout must leave alone. */
|
|
957
|
-
declare function pinnedSet(graph: Graph, opts?: LayoutOptions): Set<string>;
|
|
958
|
-
/**
|
|
959
|
-
* A placement in the canonical `(cross, rank)` frame, before it is turned into
|
|
960
|
-
* world coordinates. `cross` and `rank` are the node's low corner along each.
|
|
961
|
-
*/
|
|
962
|
-
interface Slot {
|
|
963
|
-
cross: number;
|
|
964
|
-
rank: number;
|
|
965
|
-
}
|
|
966
|
-
/**
|
|
967
|
-
* Turn canonical slots into the positions to write.
|
|
968
|
-
*
|
|
969
|
-
* Three steps, in order: map the canonical frame onto the world axes the
|
|
970
|
-
* direction names; translate the whole layout so it lands where the graph
|
|
971
|
-
* already is; drop everything that is pinned or that would not move.
|
|
972
|
-
*
|
|
973
|
-
* The translation is what makes the layout non-destructive, and it is chosen so
|
|
974
|
-
* that a second run lands on the same answer. With a pin, it is whatever keeps
|
|
975
|
-
* the first pinned node exactly where it is. Without one, it is whatever puts
|
|
976
|
-
* the layout's own bounding box where the graph's bounding box already starts —
|
|
977
|
-
* which the first run then makes true, so the second run computes the same
|
|
978
|
-
* translation and writes nothing.
|
|
979
|
-
*/
|
|
980
|
-
declare function settle(graph: Graph, slots: ReadonlyMap<string, Slot>, opts?: LayoutOptions): LayoutResult;
|
|
981
|
-
/**
|
|
982
|
-
* {@link settle}'s second half, for a layout that already works in world
|
|
983
|
-
* coordinates — `force` does, since the integrator moves points around rather
|
|
984
|
-
* than filling slots.
|
|
985
|
-
*/
|
|
986
|
-
declare function translated(graph: Graph, placed: ReadonlyMap<string, Vec2>, pinned: ReadonlySet<string>, tolerance?: number): LayoutResult;
|
|
987
|
-
/**
|
|
988
|
-
* Lay a list of nodes out along the cross axis, in the order given, and hand
|
|
989
|
-
* back each one's low corner plus the total span.
|
|
990
|
-
*
|
|
991
|
-
* Shared by `layered`'s ranks and `tree`'s sibling rows, which pack a row the
|
|
992
|
-
* same way and differ only in what decides the order.
|
|
993
|
-
*/
|
|
994
|
-
declare function packAcross(nodes: readonly GraphNode[], axis: 'x' | 'y', gap: number): {
|
|
995
|
-
at: Map<string, number>;
|
|
996
|
-
span: number;
|
|
997
|
-
};
|
|
998
|
-
/** Order within a rank: where the nodes already sit on the cross axis, with
|
|
999
|
-
* graph order breaking a tie. Never a comparison that could reverse between
|
|
1000
|
-
* two runs on the same input. */
|
|
1001
|
-
declare function seededOrder(nodes: readonly GraphNode[], axis: 'x' | 'y', indexOf: (id: string) => number): GraphNode[];
|
|
1002
|
-
/** Each node's position in `graph.nodes`, for tiebreaks. */
|
|
1003
|
-
declare function graphOrder(graph: Graph): (id: string) => number;
|
|
1004
|
-
|
|
1005
|
-
/**
|
|
1006
|
-
* `force` — relaxation, for a graph with no direction to read it in.
|
|
1007
|
-
*
|
|
1008
|
-
* Seeded from where the nodes already are rather than from a fresh random
|
|
1009
|
-
* scatter: an author who has arranged half a diagram gets that arrangement
|
|
1010
|
-
* relaxed, not replaced. There is no RNG in it at all — two coincident nodes
|
|
1011
|
-
* are separated along a golden-angle spiral keyed to their index, which is what
|
|
1012
|
-
* a random jiggle is for elsewhere.
|
|
1013
|
-
*
|
|
1014
|
-
* The integrator is the kit's own `createSimulation`, the same one
|
|
1015
|
-
* `useSimulation` runs a frame at a time. Only the forces are local, and they
|
|
1016
|
-
* are the naive O(n²) kind — right for the tens-to-hundreds of nodes an
|
|
1017
|
-
* edge-per-scene-node diagram is already sized for, wrong for a 10k-node graph,
|
|
1018
|
-
* which wants d3-force's Barnes–Hut through `useSimulation` and its own render
|
|
1019
|
-
* layer.
|
|
1020
|
-
*
|
|
1021
|
-
* **This is the one layout that is not idempotent.** A relaxation re-run from
|
|
1022
|
-
* its own output keeps relaxing; `direction` means nothing to it. Pins and the
|
|
1023
|
-
* `tolerance` option are what keep a second pass from scrambling a settled
|
|
1024
|
-
* diagram.
|
|
1025
|
-
*/
|
|
1026
|
-
|
|
1027
|
-
interface ForceOptions extends LayoutOptions {
|
|
1028
|
-
/** Ticks to run. Default 300 — one full cooling schedule. */
|
|
1029
|
-
iterations?: number;
|
|
1030
|
-
/** Rest length of an edge, in world units. Default 160. */
|
|
1031
|
-
linkDistance?: number;
|
|
1032
|
-
/** How hard an edge pulls, 0..1. Default 0.35. */
|
|
1033
|
-
linkStrength?: number;
|
|
1034
|
-
/** Pairwise repulsion. Negative repels; default -3000. */
|
|
1035
|
-
charge?: number;
|
|
1036
|
-
/** How hard the graph is held around its own centroid. Default 0.02. */
|
|
1037
|
-
gravity?: number;
|
|
1038
|
-
/** Clear space kept between two boxes, in world units. Default 24. */
|
|
1039
|
-
padding?: number;
|
|
1040
|
-
}
|
|
1041
|
-
interface Body extends SimulationNode {
|
|
1042
|
-
id: string;
|
|
1043
|
-
/** Half the node's box, so separation can work on the shape the author sees
|
|
1044
|
-
* rather than on a point. */
|
|
1045
|
-
hw: number;
|
|
1046
|
-
hh: number;
|
|
1047
|
-
}
|
|
1048
|
-
/**
|
|
1049
|
-
* The bodies and the force list, wound up and ready to tick.
|
|
1050
|
-
*
|
|
1051
|
-
* Shared by the one-shot `force` below and the live relaxation in `live.ts`,
|
|
1052
|
-
* which ticks it a frame at a time. Two copies of a force list drift, and the
|
|
1053
|
-
* only thing that would say so is the arrangement they produce.
|
|
1054
|
-
*/
|
|
1055
|
-
interface ForceRelaxation {
|
|
1056
|
-
bodies: Body[];
|
|
1057
|
-
byId: Map<string, Body>;
|
|
1058
|
-
/** Ids the caller must not move: declared pins, held as `fx`/`fy`. */
|
|
1059
|
-
pinned: ReadonlySet<string>;
|
|
1060
|
-
sim: ReturnType<typeof createSimulation<Body>>;
|
|
1061
|
-
/** Where a body's node's top-left sits, given the body's center. */
|
|
1062
|
-
placed(): Map<string, {
|
|
1063
|
-
x: number;
|
|
1064
|
-
y: number;
|
|
1065
|
-
}>;
|
|
1066
|
-
}
|
|
1067
|
-
declare function forceRelaxation(graph: Graph, opts?: ForceOptions): ForceRelaxation;
|
|
1068
|
-
declare const force: (graph: Graph, opts?: ForceOptions) => LayoutResult;
|
|
1069
|
-
|
|
1070
409
|
/** What a live producer is told, and what it answers with. */
|
|
1071
410
|
interface LiveLayoutCtx<TPose> {
|
|
1072
411
|
/** Nodes another gesture is moving, and where each is drawn. */
|
|
@@ -1164,31 +503,6 @@ declare function useLiveLayout<TPose>(opts: UseLiveLayoutOptions<TPose>): LiveLa
|
|
|
1164
503
|
/** The layouts that ease rather than relax, for a consumer choosing one. */
|
|
1165
504
|
declare const EASED_LAYOUTS: Readonly<Record<string, LayoutFn>>;
|
|
1166
505
|
|
|
1167
|
-
/**
|
|
1168
|
-
* `layered` — ranks running one way, nodes running across.
|
|
1169
|
-
*
|
|
1170
|
-
* The flowchart / pipeline layout: an edge points from one rank to the next, so
|
|
1171
|
-
* reading down the page is reading the order things happen in. Ranks come from
|
|
1172
|
-
* longest-path layering, which puts every node as far along as its deepest
|
|
1173
|
-
* predecessor allows.
|
|
1174
|
-
*
|
|
1175
|
-
* Cycles do not disqualify a graph. A depth-first walk in graph order names the
|
|
1176
|
-
* edges that close a cycle, layering ignores those, and they draw as edges
|
|
1177
|
-
* running back up the page — which is what a reader expects a loop to look
|
|
1178
|
-
* like. Which edges get named depends only on the node order, so it is the same
|
|
1179
|
-
* every run.
|
|
1180
|
-
*
|
|
1181
|
-
* This is not crossing-minimization: within a rank, nodes keep the order they
|
|
1182
|
-
* already have on the cross axis. An author who dragged two branches into an
|
|
1183
|
-
* order gets that order back, and re-running the layout is free.
|
|
1184
|
-
*/
|
|
1185
|
-
|
|
1186
|
-
/** Edge ids that close a cycle, found by a depth-first walk in graph order. */
|
|
1187
|
-
declare function backEdges(graph: Graph): Set<string>;
|
|
1188
|
-
/** Longest-path rank per node: one past its deepest predecessor. */
|
|
1189
|
-
declare function ranksOf(graph: Graph, back: ReadonlySet<string>): Map<string, number>;
|
|
1190
|
-
declare const layered: LayoutFn;
|
|
1191
|
-
|
|
1192
506
|
/**
|
|
1193
507
|
* Running a layout against a scene: `LAYOUTS`, one batch of pose writes, and
|
|
1194
508
|
* the action that reaches both.
|
|
@@ -1258,61 +572,6 @@ interface LayoutActionOptions<TPose> {
|
|
|
1258
572
|
*/
|
|
1259
573
|
declare function createLayoutAction<TPose>(opts: LayoutActionOptions<TPose>): Action;
|
|
1260
574
|
|
|
1261
|
-
/**
|
|
1262
|
-
* `tree` — a parent centered over the block its children occupy.
|
|
1263
|
-
*
|
|
1264
|
-
* The hierarchy layout: org charts, file trees, decision trees. Depth is the
|
|
1265
|
-
* rank axis, so every child sits one band past its parent, and a subtree is
|
|
1266
|
-
* packed as a solid block so two siblings' descendants never interleave.
|
|
1267
|
-
*
|
|
1268
|
-
* A graph that is not a tree still lays out. Roots are the nodes nothing points
|
|
1269
|
-
* at, in graph order; a node reachable from two parents belongs to whichever
|
|
1270
|
-
* the depth-first walk reaches first; and anything the walk never reaches — a
|
|
1271
|
-
* disconnected part, or a pure cycle — becomes a root of its own. So the answer
|
|
1272
|
-
* is always a forest, and which forest depends only on the node order.
|
|
1273
|
-
*
|
|
1274
|
-
* The block packing is deliberately not Reingold–Tilford: it never slides a
|
|
1275
|
-
* deep subtree under a shallow neighbor's overhang. That costs horizontal
|
|
1276
|
-
* space and buys an invariant an author can rely on — a subtree's extent is a
|
|
1277
|
-
* rectangle, and dragging one never lands it inside another.
|
|
1278
|
-
*/
|
|
1279
|
-
|
|
1280
|
-
interface Forest {
|
|
1281
|
-
roots: GraphNode[];
|
|
1282
|
-
children: Map<string, GraphNode[]>;
|
|
1283
|
-
depth: Map<string, number>;
|
|
1284
|
-
}
|
|
1285
|
-
/** The forest a depth-first walk in graph order finds. Exported because "which
|
|
1286
|
-
* node ended up whose child" is the question anyone debugging a tree layout
|
|
1287
|
-
* asks first. */
|
|
1288
|
-
declare function forestOf(graph: Graph, crossAxis: 'x' | 'y'): Forest;
|
|
1289
|
-
declare const tree: LayoutFn;
|
|
1290
|
-
|
|
1291
|
-
/** The outline as a closed polyline: `[x0, y0, x1, y1, …]`. */
|
|
1292
|
-
declare function outlinePolyline(outline: Outline, bounds: Bounds): number[];
|
|
1293
|
-
/**
|
|
1294
|
-
* Where the ray from `center` through `point` last crosses `poly`, or `null`
|
|
1295
|
-
* when it never does.
|
|
1296
|
-
*
|
|
1297
|
-
* The *last* crossing rather than the first: a concave outline can be crossed
|
|
1298
|
-
* more than once, and the far side is the boundary an edge should attach to.
|
|
1299
|
-
*/
|
|
1300
|
-
declare function rayHit(poly: readonly number[], center: {
|
|
1301
|
-
x: number;
|
|
1302
|
-
y: number;
|
|
1303
|
-
}, point: {
|
|
1304
|
-
x: number;
|
|
1305
|
-
y: number;
|
|
1306
|
-
}): {
|
|
1307
|
-
x: number;
|
|
1308
|
-
y: number;
|
|
1309
|
-
} | null;
|
|
1310
|
-
/**
|
|
1311
|
-
* Every port moved onto `outline`. A port the ray misses — one at the node's
|
|
1312
|
-
* dead center, with no direction to cast along — is left where it was.
|
|
1313
|
-
*/
|
|
1314
|
-
declare function portsOnOutline(ports: readonly Port[], outline: Outline, bounds: Bounds): Port[];
|
|
1315
|
-
|
|
1316
575
|
/**
|
|
1317
576
|
* The port affordance, composed into a layer and pointed at a scene.
|
|
1318
577
|
*
|
|
@@ -1400,4 +659,4 @@ declare function diagramShape<TPose>(opts?: DiagramShapeOptions<TPose>): NodeSha
|
|
|
1400
659
|
*/
|
|
1401
660
|
declare function registerDiagramShape<TPose>(opts?: DiagramShapeOptions<TPose>): () => void;
|
|
1402
661
|
|
|
1403
|
-
export { type ApplyLayoutOptions,
|
|
662
|
+
export { type ApplyLayoutOptions, CONNECT_ACTION_ID, type CanConnect, type ConnectActionOptions, DEFAULT_EDGE_STROKE, DIAGRAM_EDGE, DIAGRAM_LABEL, type DiagramContributionOptions, type DiagramEdge, type DiagramLabel, DiagramNodeLike, DiagramNodeReader, type DiagramShapeOptions, EASED_LAYOUTS, EDGE_DERIVE_PATH, type EasedProducerOptions, type EdgeEnd, type EdgeRouteOptions, ForceOptions, type ForceProducerOptions, GRAB_PORT_ACTION_ID, Graph, GraphSource, LABEL_DERIVE_POSE, LAYOUTS, LAYOUT_ACTION_ID, type LabelPoseOptions, type LayoutActionOptions, LayoutFn, LayoutOptions, LayoutResult, type LiveLayout, type LiveLayoutCtx, type LiveLayoutFrame, type LiveLayoutProducer, PORT_AFFORDANCE_KIND, PORT_LAYER_ID, type ParticipantPose, type ParticipantScene, type ParticipantSource, type PendingEdge, Port, type PortAffordanceOptions, type PortScratch, PortsOptions, ROUTERS, type RouteRequest, type Router, type UseLiveLayoutOptions, applyLayout, bezier, commitEdgeToScene, connectBinding, createConnectAction, createDiagramContribution, createLayoutAction, createPortAffordance, defaultCanConnect, diagramEdgeOf, diagramLabelOf, diagramPorts, diagramShape, easedProducer, edgeDerivePath, forceProducer, grabPortAction, grabPortBindings, labelDerivePose, layoutPoses, orthogonal, portLayer, portScratchOf, registerDiagramShape, resolveEnd, sceneParticipants, straight, useLiveLayout, withDiagramRegistry };
|