@weasel-js/diagram 1.9.2 → 1.9.4
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/README.md +16 -0
- package/dist/{chunk-UBM2J3HJ.js → chunk-EDSBULQM.js} +368 -25
- package/dist/chunk-EDSBULQM.js.map +1 -0
- package/dist/index.d.ts +135 -9
- package/dist/index.js +312 -17
- package/dist/index.js.map +1 -1
- package/dist/layout.d.ts +1 -1
- package/dist/{layout.entry-W-8PYfGM.d.ts → layout.entry-DyKFfHG5.d.ts} +349 -273
- package/dist/layout.js +1 -1
- package/package.json +4 -3
- package/dist/chunk-UBM2J3HJ.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,11 +1,73 @@
|
|
|
1
|
-
import { layered, portOf, outlinePath, diagramNodeOf, forceRelaxation, center, force, tree,
|
|
2
|
-
export { COMPASS, DEFAULT_NODE_GAP, DEFAULT_PORTS, DEFAULT_RANK_GAP, DIAGRAM_TRAIT_KEY, axesFor, backEdges, bodyOutline, bodyTrait, boxForContent, buildBody, canvasMeasure, contentBox, createDiagramNodes, dataKeyReader, diagramNodeOf, force, forceRelaxation, forestOf, graphOrder, isPinned, layered, layoutBody, layoutRowPorts, measureBody, outlinePath, outlinePolyline, packAcross, pinnedSet, portOf, portsOf, portsOnOutline, ranksOf, rayHit, seededOrder, settle, sizeToBody, translated, tree } from './chunk-
|
|
3
|
-
import { dragPanContribution, WeaselProvider, useScene, useSelection, useLatest, reconcileSpecs, SceneCanvas, fitViewToBounds, AUTO_POSE_DESCRIPTOR,
|
|
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';
|
|
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
7
|
import { jsx } from 'react/jsx-runtime';
|
|
8
8
|
|
|
9
|
+
function traitOf(node) {
|
|
10
|
+
const data = node.data;
|
|
11
|
+
if (data === null || typeof data !== "object") return null;
|
|
12
|
+
const trait = data[DIAGRAM_TRAIT_KEY];
|
|
13
|
+
return trait !== null && typeof trait === "object" ? trait : null;
|
|
14
|
+
}
|
|
15
|
+
function diagramGroupOf(node) {
|
|
16
|
+
const group = traitOf(node)?.group;
|
|
17
|
+
return group !== null && typeof group === "object" ? group : null;
|
|
18
|
+
}
|
|
19
|
+
function diagramAnchorOf(node) {
|
|
20
|
+
const anchor = traitOf(node)?.anchor;
|
|
21
|
+
return anchor !== null && typeof anchor === "object" && "at" in anchor ? anchor : null;
|
|
22
|
+
}
|
|
23
|
+
function groupDerivePose(opts = {}) {
|
|
24
|
+
const geometry = opts.geometry ?? AUTO_POSE_DESCRIPTOR;
|
|
25
|
+
return (node, deps) => {
|
|
26
|
+
const group = diagramGroupOf(node);
|
|
27
|
+
if (group === null) return null;
|
|
28
|
+
let x0 = Infinity;
|
|
29
|
+
let y0 = Infinity;
|
|
30
|
+
let x1 = -Infinity;
|
|
31
|
+
let y1 = -Infinity;
|
|
32
|
+
for (const dep of deps) {
|
|
33
|
+
if (dep === void 0) continue;
|
|
34
|
+
const b = geometry.getBounds(dep.pose);
|
|
35
|
+
x0 = Math.min(x0, b.x);
|
|
36
|
+
y0 = Math.min(y0, b.y);
|
|
37
|
+
x1 = Math.max(x1, b.x + b.width);
|
|
38
|
+
y1 = Math.max(y1, b.y + b.height);
|
|
39
|
+
}
|
|
40
|
+
if (!Number.isFinite(x0)) return null;
|
|
41
|
+
const inset = insetOf(group.inset);
|
|
42
|
+
return geometry.fromBounds(
|
|
43
|
+
{
|
|
44
|
+
x: x0 - inset.left,
|
|
45
|
+
y: y0 - inset.top,
|
|
46
|
+
width: x1 - x0 + inset.left + inset.right,
|
|
47
|
+
height: y1 - y0 + inset.top + inset.bottom
|
|
48
|
+
},
|
|
49
|
+
node.pose
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function anchorDerivePose(opts = {}) {
|
|
54
|
+
const geometry = opts.geometry ?? AUTO_POSE_DESCRIPTOR;
|
|
55
|
+
return (node, deps) => {
|
|
56
|
+
const anchor = diagramAnchorOf(node);
|
|
57
|
+
const dep = deps[0];
|
|
58
|
+
if (anchor === null || dep === void 0) return null;
|
|
59
|
+
const target = geometry.getBounds(dep.pose);
|
|
60
|
+
const own = geometry.getBounds(node.pose);
|
|
61
|
+
const self = anchor.self ?? anchor.at;
|
|
62
|
+
const x = target.x + anchor.at.u * target.width + (anchor.offset?.x ?? 0) - self.u * own.width;
|
|
63
|
+
const y = target.y + anchor.at.v * target.height + (anchor.offset?.y ?? 0) - self.v * own.height;
|
|
64
|
+
return translatePoseViaDescriptor(node.pose, x - own.x, y - own.y, geometry);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
var DIAGRAM_GROUP = "diagram:group";
|
|
68
|
+
var DIAGRAM_ANCHOR = "diagram:anchor";
|
|
69
|
+
var GROUP_DERIVE_POSE = groupDerivePose();
|
|
70
|
+
var ANCHOR_DERIVE_POSE = anchorDerivePose();
|
|
9
71
|
var NAMED = { start: 0, mid: 0.5, end: 1 };
|
|
10
72
|
function diagramLabelOf(node) {
|
|
11
73
|
const data = node.data;
|
|
@@ -41,6 +103,23 @@ function labelDerivePose(opts = {}) {
|
|
|
41
103
|
var DIAGRAM_LABEL = "diagram:label";
|
|
42
104
|
var LABEL_DERIVE_POSE = labelDerivePose();
|
|
43
105
|
|
|
106
|
+
// src/selfLoop.ts
|
|
107
|
+
var dot = (a, b) => a.x * b.x + a.y * b.y;
|
|
108
|
+
function selfLoop(ports, standoff) {
|
|
109
|
+
const facing = ports.filter((p) => p.normal !== null);
|
|
110
|
+
const most = (dir, among) => among.reduce(
|
|
111
|
+
(best, p) => best === void 0 || dot(p.normal, dir) > dot(best.normal, dir) ? p : best,
|
|
112
|
+
void 0
|
|
113
|
+
);
|
|
114
|
+
const from = most({ x: 1, y: 0 }, facing);
|
|
115
|
+
if (from === void 0) return null;
|
|
116
|
+
const to = most({ x: 0, y: -1 }, facing.filter((p) => Math.abs(dot(p.normal, from.normal)) < 0.5));
|
|
117
|
+
if (to === void 0) return null;
|
|
118
|
+
const out = { x: from.point.x + from.normal.x * standoff, y: from.point.y + from.normal.y * standoff };
|
|
119
|
+
const reach = dot({ x: to.point.x - out.x, y: to.point.y - out.y }, to.normal) + standoff;
|
|
120
|
+
return { from, to, via: { x: out.x + to.normal.x * reach, y: out.y + to.normal.y * reach } };
|
|
121
|
+
}
|
|
122
|
+
|
|
44
123
|
// src/edge.ts
|
|
45
124
|
var straight = (req) => [req.from.point, ...req.waypoints, req.to.point];
|
|
46
125
|
var orthogonal = (req) => {
|
|
@@ -61,12 +140,15 @@ var orthogonal = (req) => {
|
|
|
61
140
|
out.push(b);
|
|
62
141
|
continue;
|
|
63
142
|
}
|
|
143
|
+
const prev = out.length > 1 ? out[out.length - 2] : null;
|
|
64
144
|
if (leaveHorizontal) {
|
|
65
145
|
const mid = (a.x + b.x) / 2;
|
|
66
|
-
|
|
146
|
+
if (prev !== null && (mid - a.x) * (a.x - prev.x) < 0) out.push({ x: a.x, y: b.y }, b);
|
|
147
|
+
else out.push({ x: mid, y: a.y }, { x: mid, y: b.y }, b);
|
|
67
148
|
} else {
|
|
68
149
|
const mid = (a.y + b.y) / 2;
|
|
69
|
-
|
|
150
|
+
if (prev !== null && (mid - a.y) * (a.y - prev.y) < 0) out.push({ x: b.x, y: a.y }, b);
|
|
151
|
+
else out.push({ x: a.x, y: mid }, { x: b.x, y: mid }, b);
|
|
70
152
|
}
|
|
71
153
|
}
|
|
72
154
|
return out;
|
|
@@ -136,17 +218,24 @@ function edgeDerivePath(opts = {}) {
|
|
|
136
218
|
const b = geometry.getBounds(d.pose);
|
|
137
219
|
return { x: b.x + b.width / 2, y: b.y + b.height / 2 };
|
|
138
220
|
};
|
|
221
|
+
const standoffOf = (d) => {
|
|
222
|
+
const b = geometry.getBounds(d.pose);
|
|
223
|
+
return Math.min(b.width, b.height) / 2;
|
|
224
|
+
};
|
|
139
225
|
return (node, deps) => {
|
|
140
226
|
const edge = diagramEdgeOf(node);
|
|
141
227
|
if (edge === null) return null;
|
|
142
228
|
const [fromDep, toDep] = deps;
|
|
143
229
|
if (fromDep === void 0 || toDep === void 0) return null;
|
|
144
|
-
const
|
|
145
|
-
const
|
|
230
|
+
const loop = fromDep.node.id === toDep.node.id && edge.from.port === void 0 && edge.to.port === void 0 ? selfLoop(allPorts(fromDep), opts.selfLoopStandoff ?? standoffOf(fromDep)) : null;
|
|
231
|
+
const from = loop?.from ?? resolveEnd(edge.from, fromDep, centerOf(toDep), portOpts, allPorts);
|
|
232
|
+
const to = loop?.to ?? resolveEnd(edge.to, toDep, centerOf(fromDep), portOpts, allPorts);
|
|
146
233
|
if (from === void 0 || to === void 0) return null;
|
|
234
|
+
const authored = edge.waypoints ?? [];
|
|
235
|
+
const waypoints = loop !== null && authored.length === 0 ? [loop.via] : authored;
|
|
147
236
|
const routers = opts.routers ?? ROUTERS;
|
|
148
237
|
const router = edge.router !== void 0 && routers[edge.router] || straight;
|
|
149
|
-
const points = router({ from, to, waypoints
|
|
238
|
+
const points = router({ from, to, waypoints });
|
|
150
239
|
return points.length < 2 ? null : polylineFromPoints(points);
|
|
151
240
|
};
|
|
152
241
|
}
|
|
@@ -161,6 +250,8 @@ function withDiagramRegistry(registry = {}) {
|
|
|
161
250
|
},
|
|
162
251
|
derivePose: {
|
|
163
252
|
[DIAGRAM_LABEL]: LABEL_DERIVE_POSE,
|
|
253
|
+
[DIAGRAM_GROUP]: GROUP_DERIVE_POSE,
|
|
254
|
+
[DIAGRAM_ANCHOR]: ANCHOR_DERIVE_POSE,
|
|
164
255
|
...registry.derivePose
|
|
165
256
|
}
|
|
166
257
|
};
|
|
@@ -398,11 +489,64 @@ function diagramPorts(opts) {
|
|
|
398
489
|
contribution: createDiagramContribution(opts)
|
|
399
490
|
};
|
|
400
491
|
}
|
|
492
|
+
|
|
493
|
+
// src/groupTree.ts
|
|
494
|
+
function nestGroups(declared, isNode) {
|
|
495
|
+
const groupIds = new Set(declared.map((g) => g.id));
|
|
496
|
+
const parentOf = /* @__PURE__ */ new Map();
|
|
497
|
+
const claimedNodes = /* @__PURE__ */ new Set();
|
|
498
|
+
const direct = /* @__PURE__ */ new Map();
|
|
499
|
+
const isAncestorOrSelf = (candidate, of) => {
|
|
500
|
+
for (let at = of; at !== void 0; at = parentOf.get(at)) {
|
|
501
|
+
if (at === candidate) return true;
|
|
502
|
+
}
|
|
503
|
+
return false;
|
|
504
|
+
};
|
|
505
|
+
for (const group of declared) {
|
|
506
|
+
const own = [];
|
|
507
|
+
for (const id of group.members) {
|
|
508
|
+
if (isNode(id)) {
|
|
509
|
+
if (claimedNodes.has(id)) continue;
|
|
510
|
+
claimedNodes.add(id);
|
|
511
|
+
own.push(id);
|
|
512
|
+
} else if (groupIds.has(id) && !parentOf.has(id) && !isAncestorOrSelf(id, group.id)) {
|
|
513
|
+
parentOf.set(id, group.id);
|
|
514
|
+
own.push(id);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
direct.set(group.id, own);
|
|
518
|
+
}
|
|
519
|
+
const flat = /* @__PURE__ */ new Map();
|
|
520
|
+
const flatten = (id) => {
|
|
521
|
+
const known = flat.get(id);
|
|
522
|
+
if (known !== void 0) return known;
|
|
523
|
+
const out = [];
|
|
524
|
+
for (const member of direct.get(id)) {
|
|
525
|
+
if (groupIds.has(member)) out.push(...flatten(member));
|
|
526
|
+
else out.push(member);
|
|
527
|
+
}
|
|
528
|
+
flat.set(id, out);
|
|
529
|
+
return out;
|
|
530
|
+
};
|
|
531
|
+
const live = new Set(declared.filter((g) => flatten(g.id).length > 0).map((g) => g.id));
|
|
532
|
+
return declared.filter((g) => live.has(g.id)).map((g) => {
|
|
533
|
+
const parent = parentOf.get(g.id);
|
|
534
|
+
return {
|
|
535
|
+
id: g.id,
|
|
536
|
+
direct: direct.get(g.id).filter((id) => !groupIds.has(id) || live.has(id)),
|
|
537
|
+
members: flat.get(g.id),
|
|
538
|
+
...parent !== void 0 ? { parent } : {}
|
|
539
|
+
};
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// src/graph.ts
|
|
401
544
|
function buildGraph(source, opts = {}) {
|
|
402
545
|
const geometry = opts.geometry ?? AUTO_POSE_DESCRIPTOR$1;
|
|
403
546
|
const nodes = [];
|
|
404
547
|
const byId = /* @__PURE__ */ new Map();
|
|
405
548
|
const candidates = [];
|
|
549
|
+
const groupNodes = [];
|
|
406
550
|
for (const { node, pose } of source()) {
|
|
407
551
|
if (diagramEdgeOf(node) !== null) {
|
|
408
552
|
const deps = node.dependsOn;
|
|
@@ -413,6 +557,15 @@ function buildGraph(source, opts = {}) {
|
|
|
413
557
|
}
|
|
414
558
|
const trait = diagramNodeOf(node, opts.read);
|
|
415
559
|
if (trait === null) continue;
|
|
560
|
+
if (trait.group !== void 0) {
|
|
561
|
+
const deps = node.dependsOn;
|
|
562
|
+
groupNodes.push({
|
|
563
|
+
id: node.id,
|
|
564
|
+
members: Array.isArray(deps) ? deps : [],
|
|
565
|
+
inset: insetOf(trait.group.inset)
|
|
566
|
+
});
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
416
569
|
const entry = {
|
|
417
570
|
id: node.id,
|
|
418
571
|
bounds: geometry.getBounds(pose),
|
|
@@ -421,7 +574,21 @@ function buildGraph(source, opts = {}) {
|
|
|
421
574
|
nodes.push(entry);
|
|
422
575
|
byId.set(entry.id, entry);
|
|
423
576
|
}
|
|
424
|
-
const
|
|
577
|
+
const insets = new Map(groupNodes.map((g) => [g.id, g.inset]));
|
|
578
|
+
const live = nestGroups(groupNodes, (id) => byId.has(id)).map((g) => {
|
|
579
|
+
for (const id of g.direct) {
|
|
580
|
+
const node = byId.get(id);
|
|
581
|
+
if (node !== void 0) node.group = g.id;
|
|
582
|
+
}
|
|
583
|
+
return {
|
|
584
|
+
id: g.id,
|
|
585
|
+
members: g.members,
|
|
586
|
+
inset: insets.get(g.id),
|
|
587
|
+
...g.parent !== void 0 ? { parent: g.parent } : {}
|
|
588
|
+
};
|
|
589
|
+
});
|
|
590
|
+
const known = (id) => byId.has(id) || live.some((g) => g.id === id);
|
|
591
|
+
const edges = expandGroupEdges(candidates.filter((e) => known(e.from) && known(e.to)), live);
|
|
425
592
|
const out = /* @__PURE__ */ new Map();
|
|
426
593
|
const into = /* @__PURE__ */ new Map();
|
|
427
594
|
for (const edge of edges) {
|
|
@@ -432,6 +599,7 @@ function buildGraph(source, opts = {}) {
|
|
|
432
599
|
return {
|
|
433
600
|
nodes,
|
|
434
601
|
edges,
|
|
602
|
+
groups: live,
|
|
435
603
|
node: (id) => byId.get(id),
|
|
436
604
|
outgoing: (id) => out.get(id) ?? NONE,
|
|
437
605
|
incoming: (id) => into.get(id) ?? NONE
|
|
@@ -443,17 +611,106 @@ function push(index, key, edge) {
|
|
|
443
611
|
else list.push(edge);
|
|
444
612
|
}
|
|
445
613
|
|
|
614
|
+
// src/dataGroups.ts
|
|
615
|
+
function resolveGroups(groups, ids, nodeIds, opts) {
|
|
616
|
+
for (const group of groups) {
|
|
617
|
+
if (ids.has(group.id)) throw new Error(`diagramScene: group id "${group.id}" is already a node or group id`);
|
|
618
|
+
ids.add(group.id);
|
|
619
|
+
}
|
|
620
|
+
const declared = new Map(groups.map((g) => [g.id, g]));
|
|
621
|
+
const nested = nestGroups(groups, (id) => nodeIds.has(id));
|
|
622
|
+
const depthOf = /* @__PURE__ */ new Map();
|
|
623
|
+
const byId = new Map(nested.map((g) => [g.id, g]));
|
|
624
|
+
const depth = (id) => {
|
|
625
|
+
const parent = byId.get(id).parent;
|
|
626
|
+
let d = depthOf.get(id);
|
|
627
|
+
if (d === void 0) depthOf.set(id, d = parent === void 0 ? 0 : depth(parent) + 1);
|
|
628
|
+
return d;
|
|
629
|
+
};
|
|
630
|
+
return nested.map((g, i) => ({ g, i })).sort((a, b) => depth(a.g.id) - depth(b.g.id) || a.i - b.i).map(({ g }) => {
|
|
631
|
+
const group = declared.get(g.id);
|
|
632
|
+
const pad = group.padding ?? opts.padding;
|
|
633
|
+
const title = group.label ? opts.title(group.label) : null;
|
|
634
|
+
const inset = { top: pad + (title ? title.height + pad / 2 : 0), right: pad, bottom: pad, left: pad };
|
|
635
|
+
return {
|
|
636
|
+
group,
|
|
637
|
+
direct: g.direct,
|
|
638
|
+
members: g.members,
|
|
639
|
+
inset,
|
|
640
|
+
pad,
|
|
641
|
+
title,
|
|
642
|
+
...g.parent !== void 0 ? { parent: g.parent } : {}
|
|
643
|
+
};
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
function groupSpecs(groups, placedAt, styleOf) {
|
|
647
|
+
const byId = new Map(groups.map((g) => [g.group.id, g]));
|
|
648
|
+
const boxes = /* @__PURE__ */ new Map();
|
|
649
|
+
const boxOf = (id) => {
|
|
650
|
+
const known = boxes.get(id);
|
|
651
|
+
if (known !== void 0) return known;
|
|
652
|
+
const g = byId.get(id);
|
|
653
|
+
const rs = g.direct.map((m) => byId.has(m) ? boxOf(m) : placedAt.get(m));
|
|
654
|
+
const x = Math.min(...rs.map((r) => r.x)) - g.inset.left;
|
|
655
|
+
const y = Math.min(...rs.map((r) => r.y)) - g.inset.top;
|
|
656
|
+
const box = {
|
|
657
|
+
x,
|
|
658
|
+
y,
|
|
659
|
+
width: Math.max(...rs.map((r) => r.x + r.width)) + g.inset.right - x,
|
|
660
|
+
height: Math.max(...rs.map((r) => r.y + r.height)) + g.inset.bottom - y
|
|
661
|
+
};
|
|
662
|
+
boxes.set(id, box);
|
|
663
|
+
return box;
|
|
664
|
+
};
|
|
665
|
+
const specs = [];
|
|
666
|
+
for (const g of groups) {
|
|
667
|
+
const { style, text } = styleOf(g.group);
|
|
668
|
+
const { x, y, width, height } = boxOf(g.group.id);
|
|
669
|
+
specs.push({
|
|
670
|
+
id: g.group.id,
|
|
671
|
+
kind: "leaf",
|
|
672
|
+
layer: "main",
|
|
673
|
+
pose: { x, y, width, height },
|
|
674
|
+
data: {
|
|
675
|
+
diagram: { outline: "rect", group: { inset: g.inset } },
|
|
676
|
+
fill: { color: style.fill },
|
|
677
|
+
stroke: {
|
|
678
|
+
paint: { color: style.stroke },
|
|
679
|
+
width: style.strokeWidth ?? 1,
|
|
680
|
+
...style.dash ? { dash: style.dash } : {}
|
|
681
|
+
}
|
|
682
|
+
},
|
|
683
|
+
dependsOn: g.direct,
|
|
684
|
+
derivePose: GROUP_DERIVE_POSE
|
|
685
|
+
});
|
|
686
|
+
if (g.title === null || !g.group.label) continue;
|
|
687
|
+
const anchor = { at: { u: 0, v: 0 }, offset: { x: g.pad, y: g.pad } };
|
|
688
|
+
specs.push({
|
|
689
|
+
id: `${g.group.id}/label`,
|
|
690
|
+
kind: "leaf",
|
|
691
|
+
layer: "main",
|
|
692
|
+
pickable: false,
|
|
693
|
+
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 } },
|
|
695
|
+
dependsOn: [g.group.id],
|
|
696
|
+
derivePose: ANCHOR_DERIVE_POSE
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
return specs;
|
|
700
|
+
}
|
|
701
|
+
|
|
446
702
|
// src/fromData.ts
|
|
447
703
|
var FONT = { fontFamily: "sans-serif", fontSize: 12 };
|
|
448
704
|
var NODE = { fill: "#16222c", stroke: "#7ba7c7", text: "#dbe7f2" };
|
|
449
705
|
var EDGE = { stroke: "#7ba7c7" };
|
|
706
|
+
var GROUP = { fill: "rgba(123, 167, 199, 0.08)", stroke: "#7ba7c7", text: "#9fbdd6", strokeWidth: 1, dash: [4, 3] };
|
|
450
707
|
var LABEL_PLACEMENT = { at: "mid", offset: 9 };
|
|
451
708
|
var LINE = 1.4;
|
|
452
709
|
var GLYPH = 0.6;
|
|
453
710
|
var MIN_WIDTH = 64;
|
|
454
711
|
var LAYOUTS = { layered, tree, force };
|
|
455
712
|
var edgeIdOf = (e) => `edge:${e.from}${e.fromPort ? `.${e.fromPort}` : ""}->${e.to}${e.toPort ? `.${e.toPort}` : ""}${e.label ? `:${e.label}` : ""}`;
|
|
456
|
-
function graphOf(nodes, edges) {
|
|
713
|
+
function graphOf(nodes, edges, groups = []) {
|
|
457
714
|
const byId = new Map(nodes.map((n) => [n.id, n]));
|
|
458
715
|
const out = /* @__PURE__ */ new Map();
|
|
459
716
|
const inc = /* @__PURE__ */ new Map();
|
|
@@ -464,6 +721,7 @@ function graphOf(nodes, edges) {
|
|
|
464
721
|
return {
|
|
465
722
|
nodes,
|
|
466
723
|
edges,
|
|
724
|
+
groups,
|
|
467
725
|
node: (id) => byId.get(id),
|
|
468
726
|
outgoing: (id) => out.get(id) ?? [],
|
|
469
727
|
incoming: (id) => inc.get(id) ?? []
|
|
@@ -485,6 +743,12 @@ function diagramScene(data, opts = {}) {
|
|
|
485
743
|
if (ids.has(n.id)) throw new Error(`diagramScene: node id "${n.id}" appears more than once`);
|
|
486
744
|
ids.add(n.id);
|
|
487
745
|
}
|
|
746
|
+
const nodeIds = new Set(ids);
|
|
747
|
+
const titleStyle = { ...font, fontSize: font.fontSize - 1 };
|
|
748
|
+
const groups = resolveGroups(data.groups ?? [], ids, nodeIds, {
|
|
749
|
+
padding: opts.groupPadding ?? DEFAULT_GROUP_INSET,
|
|
750
|
+
title: (text) => measure(text, titleStyle)
|
|
751
|
+
});
|
|
488
752
|
const seen = /* @__PURE__ */ new Set();
|
|
489
753
|
const edges = data.edges.filter((e) => {
|
|
490
754
|
const id = edgeIdOf(e);
|
|
@@ -507,13 +771,39 @@ function diagramScene(data, opts = {}) {
|
|
|
507
771
|
);
|
|
508
772
|
return { id: n.id, bounds: pose, pinned: n.pinned === true };
|
|
509
773
|
});
|
|
510
|
-
const
|
|
774
|
+
const graphGroups = groups.map((g) => ({
|
|
775
|
+
id: g.group.id,
|
|
776
|
+
members: g.members,
|
|
777
|
+
inset: g.inset,
|
|
778
|
+
...g.parent !== void 0 ? { parent: g.parent } : {}
|
|
779
|
+
}));
|
|
780
|
+
const seedOf = new Map(seeds.map((n) => [n.id, n]));
|
|
781
|
+
for (const g of groups) {
|
|
782
|
+
for (const m of g.direct) {
|
|
783
|
+
const seed = seedOf.get(m);
|
|
784
|
+
if (seed !== void 0) seed.group = g.group.id;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
const graph = graphOf(
|
|
788
|
+
seeds,
|
|
789
|
+
expandGroupEdges(edges.map((e) => ({ id: edgeIdOf(e), from: e.from, to: e.to })), graphGroups),
|
|
790
|
+
graphGroups
|
|
791
|
+
);
|
|
511
792
|
const layout = typeof opts.layout === "function" ? opts.layout : opts.layout === "none" ? null : LAYOUTS[opts.layout ?? "layered"];
|
|
512
793
|
const moved = layout === null ? /* @__PURE__ */ new Map() : layout(graph, { order: "barycenter", ...opts.layoutOptions });
|
|
513
794
|
const specs = [];
|
|
514
|
-
|
|
795
|
+
const placedAt = new Map(data.nodes.map((n, i) => {
|
|
515
796
|
const seed = seeds[i].bounds;
|
|
516
797
|
const at = moved.get(n.id) ?? seed;
|
|
798
|
+
return [n.id, { x: at.x, y: at.y, width: seed.width, height: seed.height }];
|
|
799
|
+
}));
|
|
800
|
+
specs.push(...groupSpecs(groups, placedAt, (g) => ({
|
|
801
|
+
style: opts.groupStyle?.(g) ?? GROUP,
|
|
802
|
+
text: styleOf(titleStyle)
|
|
803
|
+
})));
|
|
804
|
+
for (const [i, n] of data.nodes.entries()) {
|
|
805
|
+
const seed = seeds[i].bounds;
|
|
806
|
+
const at = placedAt.get(n.id);
|
|
517
807
|
const style = opts.nodeStyle?.(n) ?? NODE;
|
|
518
808
|
const textData = (text, s) => ({ text, style: styleOf(s), fill: { color: style.text } });
|
|
519
809
|
const built = buildBody(
|
|
@@ -829,11 +1119,14 @@ function diagramShape(opts = {}) {
|
|
|
829
1119
|
const outline = outlineOf(node);
|
|
830
1120
|
if (outline === void 0) return [];
|
|
831
1121
|
const d = node.data;
|
|
832
|
-
const
|
|
833
|
-
const
|
|
1122
|
+
const box = geometry.getBounds(pose);
|
|
1123
|
+
const declaredFill = d.fill === void 0 ? opts.defaultFill : d.fill;
|
|
1124
|
+
const declaredStroke = d.stroke === void 0 ? opts.defaultStroke : d.stroke;
|
|
1125
|
+
const fill = declaredFill && commandFill(declaredFill, box);
|
|
1126
|
+
const stroke = declaredStroke && commandStroke(declaredStroke, box);
|
|
834
1127
|
return [{
|
|
835
1128
|
kind: "path",
|
|
836
|
-
path: outlinePath(outline,
|
|
1129
|
+
path: outlinePath(outline, box),
|
|
837
1130
|
...fill ? { fill } : {},
|
|
838
1131
|
...stroke ? { stroke } : {}
|
|
839
1132
|
}];
|
|
@@ -874,6 +1167,7 @@ function Inner({
|
|
|
874
1167
|
onSelect,
|
|
875
1168
|
onMove,
|
|
876
1169
|
onConnect,
|
|
1170
|
+
enableKeybindings,
|
|
877
1171
|
canConnect,
|
|
878
1172
|
portOptions,
|
|
879
1173
|
live: liveOpts,
|
|
@@ -972,6 +1266,7 @@ function Inner({
|
|
|
972
1266
|
scene,
|
|
973
1267
|
selection,
|
|
974
1268
|
features: onMove ? ["view", "pick", "move"] : ["view", "pick"],
|
|
1269
|
+
enableKeybindings: enableKeybindings ?? (onMove !== void 0 || onConnect !== void 0),
|
|
975
1270
|
ambient,
|
|
976
1271
|
onClick,
|
|
977
1272
|
width,
|
|
@@ -985,7 +1280,7 @@ function Inner({
|
|
|
985
1280
|
);
|
|
986
1281
|
}
|
|
987
1282
|
function fitDiagram(specs, size, fit = {}) {
|
|
988
|
-
const boxes = specs.filter((s) => s.kind === "container").map((s) => s.pose);
|
|
1283
|
+
const boxes = specs.filter((s) => s.kind === "container" || diagramGroupOf(s) !== null).map((s) => s.pose);
|
|
989
1284
|
if (boxes.length === 0) return void 0;
|
|
990
1285
|
const x = Math.min(...boxes.map((b) => b.x));
|
|
991
1286
|
const y = Math.min(...boxes.map((b) => b.y));
|
|
@@ -1003,6 +1298,6 @@ function fitDiagram(specs, size, fit = {}) {
|
|
|
1003
1298
|
});
|
|
1004
1299
|
}
|
|
1005
1300
|
|
|
1006
|
-
export { CONNECT_ACTION_ID, DEFAULT_EDGE_STROKE, DIAGRAM_EDGE, DIAGRAM_LABEL, DiagramView, EASED_LAYOUTS, EDGE_DERIVE_PATH, GRAB_PORT_ACTION_ID, LABEL_DERIVE_POSE, LAYOUTS2 as LAYOUTS, LAYOUT_ACTION_ID, PORT_AFFORDANCE_KIND, PORT_LAYER_ID, ROUTERS, applyLayout, bezier, buildGraph, commitEdgeToScene, connectBinding, createConnectAction, createDiagramContribution, createLayoutAction, createPortAffordance, defaultCanConnect, diagramEdgeOf, diagramLabelOf, diagramPorts, diagramScene, diagramShape, easedProducer, edgeDerivePath, edgeIdOf, forceProducer, grabPortAction, grabPortBindings, labelDerivePose, layoutPoses, orthogonal, portLayer, portScratchOf, registerDiagramShape, resolveEnd, sceneParticipants, straight, useLiveLayout, useMirroredSelection, withDiagramRegistry };
|
|
1301
|
+
export { ANCHOR_DERIVE_POSE, CONNECT_ACTION_ID, DEFAULT_EDGE_STROKE, DIAGRAM_ANCHOR, DIAGRAM_EDGE, DIAGRAM_GROUP, DIAGRAM_LABEL, DiagramView, EASED_LAYOUTS, EDGE_DERIVE_PATH, GRAB_PORT_ACTION_ID, GROUP_DERIVE_POSE, LABEL_DERIVE_POSE, LAYOUTS2 as LAYOUTS, LAYOUT_ACTION_ID, PORT_AFFORDANCE_KIND, PORT_LAYER_ID, ROUTERS, anchorDerivePose, applyLayout, bezier, buildGraph, 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 };
|
|
1007
1302
|
//# sourceMappingURL=index.js.map
|
|
1008
1303
|
//# sourceMappingURL=index.js.map
|