@weasel-js/diagram 1.14.2 → 1.15.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/README.md +114 -5
- package/dist/{chunk-GR2DK4S2.js → chunk-EIHPPOAM.js} +1480 -229
- package/dist/chunk-EIHPPOAM.js.map +1 -0
- package/dist/{chunk-AXL4JQBM.js → chunk-EIT4BFDK.js} +3 -3
- package/dist/{chunk-AXL4JQBM.js.map → chunk-EIT4BFDK.js.map} +1 -1
- package/dist/{chunk-DE7UILJA.js → chunk-NEX4QKQQ.js} +183 -23
- package/dist/chunk-NEX4QKQQ.js.map +1 -0
- package/dist/{chunk-FDCODMFW.js → chunk-UOFQBGJY.js} +904 -599
- package/dist/chunk-UOFQBGJY.js.map +1 -0
- package/dist/{chunk-IYUU5KUY.js → chunk-UUMLQEMR.js} +8 -96
- package/dist/chunk-UUMLQEMR.js.map +1 -0
- package/dist/{dataTypes-BIkhAOc4.d.ts → dataTypes-1ch6cMtq.d.ts} +12 -3
- package/dist/effect-audio.d.ts +2 -2
- package/dist/effect-audio.js +3 -3
- package/dist/effect.d.ts +5 -5
- package/dist/effect.js +7 -7
- package/dist/effect.js.map +1 -1
- package/dist/icons.table.js +44 -0
- package/dist/icons.table.js.map +1 -1
- package/dist/icons.table.json +44 -0
- package/dist/index.d.ts +938 -37
- package/dist/index.js +708 -34
- package/dist/index.js.map +1 -1
- package/dist/{labelTrait-BBjRgxbz.d.ts → labelTrait-moIciyXr.d.ts} +4 -0
- package/dist/layout.d.ts +3 -3
- package/dist/{layout.entry-CbmGuqE-.d.ts → layout.entry-zstuljAl.d.ts} +2 -2
- package/dist/layout.js +2 -2
- package/dist/{stageTypes-UiO25hcn.d.ts → stageTypes-B7oF8Lww.d.ts} +1 -1
- package/dist/{types-B0n2CNTW.d.ts → types-D5ybp8Xh.d.ts} +32 -1
- package/package.json +11 -11
- package/dist/chunk-DE7UILJA.js.map +0 -1
- package/dist/chunk-FDCODMFW.js.map +0 -1
- package/dist/chunk-GR2DK4S2.js.map +0 -1
- package/dist/chunk-IYUU5KUY.js.map +0 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { createAvoidRouter, placeLabels, edgeHops,
|
|
2
|
-
import { edgeRouter, registerMarkShape, withDiagramRegistry, diagramLabelOf, editEdgeLabelBinding, editEdgeLabelAction, diagramGroupOf, diagramContainerOf, headerBox,
|
|
3
|
-
import { diagramEdgeOf, isPromise, diagramNodeOf, portsOf, portSitesOf, outlinePath, outlineDetail, samePoints, layoutWritesRoute, plannerPlan, planOf, layered, dataKeyReader, layoutBody, forceRelaxation, center,
|
|
4
|
-
import { bodyPredicate, dragPanContribution, WeaselProvider, useScene, useSelection, useLatest, SceneCanvas, useDepSource, RIGID_POSE_COMPOSITION, registerNodeShape, reconcileSpecs, pagesBounds, pagesLayer,
|
|
1
|
+
import { createAvoidRouter, placeLabels, edgeHops, DEFAULT_HOP_SIZE, HOPS_DOC_KEY, simplifyStops } from './chunk-UUMLQEMR.js';
|
|
2
|
+
import { edgeRouter, registerMarkShape, withDiagramRegistry, diagramLabelOf, routesOf, layoutPoses, routeWrites, editEdgeLabelBinding, editEdgeLabelAction, diagramGroupOf, diagramContainerOf, headerBox, buildGraph, LAYOUTS, LABEL_DRAG_AFFORDANCE_KIND, EDIT_EDGE_LABEL_ACTION_ID, labelDragLayer, laneOutlineOf, recordedRows, keyedIndex, boxIndex, boxesMeeting, routerOf, labelScratchOf, ROUTERS, avoid, LABEL_PLACEMENT, editableLabels, titleIdOf, orthogonal, diagramAnchorOf, MIN_LANE_SIZE, EDGE_DERIVE_PATH, titleInFrame, regionSpecs, DIAGRAM_THEME_KEY, diagramThemeOf, endAims, resolveEnd, themeLabelFamily, diagramThemeFrom, themeFont, bodyBox, boxCenter, roleEdgeStyle, DEFAULT_FONT, withColors, roleStyle, GLYPH, themeLabelFont, firstLanes, DEFAULT_LANE_SIZE } from './chunk-NEX4QKQQ.js';
|
|
3
|
+
import { diagramEdgeOf, isPromise, diagramNodeOf, portsOf, portSitesOf, outlinePath, outlineDetail, outlineSolid, samePoints, layoutWritesRoute, plannerPlan, planOf, layered, dataKeyReader, layoutBody, forceRelaxation, center, portOf, labelCenter, labelSpotAt, contentBox, boxForContent, grid, chain, tree, isPinned, layoutOwnsRoute } from './chunk-UOFQBGJY.js';
|
|
4
|
+
import { bodyPredicate, dragPanContribution, WeaselProvider, useScene, useSelection, useLatest, SceneCanvas, useDepSource, RIGID_POSE_COMPOSITION, registerNodeShape, reconcileSpecs, pagesBounds, pagesLayer, usePoseRun, drawnBoundsScene, pointAlongPath, scenePoseAdapter, drawnAABBOf, composeWorldPose, worldPosesOf, RECT_POSE_DESCRIPTOR, resolveFill, resolveStroke, commandFill, commandStroke, nodeGates, scenePoseFrame, fitViewToBounds, clampView, AUTO_POSE_DESCRIPTOR, composeAffordanceLayer, createResizeAction, createDeleteAction, isTextData, effectivePose, polylineFromPoints, SNAP_ROLES, ActionDisabledReason, commitDeleteToScene, refusalOf, snapMods, documentDepOf, translatePoseViaDescriptor, definesFrame, paintsLayer, viewToTransform, ellipsePath, carriedDescendants, sceneCarrySource, derivedDepOf, localizeWorldPoses, PathBuilder, startCarry, createInsertOp, createSetDataOp, documentPose } from '@weasel-js/core';
|
|
5
5
|
import { createSettledCache } from '@weasel-js/geom/nd';
|
|
6
6
|
import { AUTO_POSE_DESCRIPTOR as AUTO_POSE_DESCRIPTOR$1, rotatePoint } from '@weasel-js/core/math';
|
|
7
7
|
import { clampRectWithin, placeRect, pathContainsPoint } from '@weasel-js/geom';
|
|
8
|
-
import { nudgeGap, moveItems, nearestGap, isNoopDrop } from '@weasel-js/
|
|
8
|
+
import { nudgeGap, moveItems, nearestGap, isNoopDrop } from '@weasel-js/ui-logic';
|
|
9
9
|
import { forwardRef, useMemo, useEffect, useState, useRef, useCallback, useImperativeHandle, useLayoutEffect } from 'react';
|
|
10
10
|
import { useLatest as useLatest$1, adoptCssOnce } from '@weasel-js/react';
|
|
11
11
|
import '@weasel-js/animator';
|
|
@@ -109,10 +109,10 @@ function createPortAffordance(participants, opts = {}) {
|
|
|
109
109
|
const built = index();
|
|
110
110
|
const rx = hitRadiusPx / Math.abs(view.scale.x);
|
|
111
111
|
const ry = hitRadiusPx / Math.abs(view.scale.y);
|
|
112
|
-
const
|
|
113
|
-
if (!built || !
|
|
112
|
+
const near = built && boxesMeeting(built.boxes, wx - rx, wy - ry, wx + rx, wy + ry);
|
|
113
|
+
if (!built || !near) return regions(state);
|
|
114
114
|
const out = [];
|
|
115
|
-
for (const i of
|
|
115
|
+
for (const i of near) {
|
|
116
116
|
const entry = built.at[i];
|
|
117
117
|
if (shown(entry.participant, state) && showsPort(entry.port)) out.push(regionAt(entry));
|
|
118
118
|
}
|
|
@@ -507,8 +507,8 @@ function createReorderAction(opts) {
|
|
|
507
507
|
if (slots === null || picked === null) return {};
|
|
508
508
|
const held = { slots, ...picked };
|
|
509
509
|
const { axis } = slots;
|
|
510
|
-
const
|
|
511
|
-
const leaves = (at) =>
|
|
510
|
+
const region2 = opts.region?.(ctx.deps, held.item) ?? null;
|
|
511
|
+
const leaves = (at) => region2 !== null && !inside(at, region2);
|
|
512
512
|
let by = ctx.world[axis] - start[axis];
|
|
513
513
|
let open = true;
|
|
514
514
|
const verdicts = /* @__PURE__ */ new Map();
|
|
@@ -920,6 +920,7 @@ function themeWrites(scene, theme, ids, from) {
|
|
|
920
920
|
const data = node.data;
|
|
921
921
|
if (data === null || typeof data !== "object") continue;
|
|
922
922
|
const trait = traitOf(data);
|
|
923
|
+
if (trait !== null && ("seq" in trait || "sequence" in trait)) continue;
|
|
923
924
|
if (trait !== null && "from" in trait && "to" in trait) {
|
|
924
925
|
if (ids !== void 0 && !ids.has(node.id)) continue;
|
|
925
926
|
const look2 = edgeLook(trait, theme);
|
|
@@ -980,7 +981,7 @@ function containerBuild(stencil, bounds, opts) {
|
|
|
980
981
|
const id = opts.newId();
|
|
981
982
|
const axis = stencil.axis ?? "y";
|
|
982
983
|
const at = placedBounds(stencil, bounds);
|
|
983
|
-
const title = stencil.role === "pool" ? "Pool" : stencil.label;
|
|
984
|
+
const title = stencil.title ?? (stencil.role === "pool" ? "Pool" : stencil.label);
|
|
984
985
|
const style = stencil.role === "pool" && opts.laneStyles ? opts.laneStyles.header : opts.style;
|
|
985
986
|
const specs = [
|
|
986
987
|
...regionSpecs(stencil.role, axis, at, title, {
|
|
@@ -989,7 +990,7 @@ function containerBuild(stencil, bounds, opts) {
|
|
|
989
990
|
parent: opts.parent ?? null,
|
|
990
991
|
...style ? { style } : {}
|
|
991
992
|
}),
|
|
992
|
-
...stencil.role === "pool" ? firstLanes(id, axis, at, opts) : []
|
|
993
|
+
...stencil.role === "pool" ? firstLanes(id, axis, at, opts, stencil.lanes) : []
|
|
993
994
|
];
|
|
994
995
|
const label = `Insert ${stencil.label}`;
|
|
995
996
|
const stored = localizeWorldPoses(specs, RIGID_POSE_COMPOSITION);
|
|
@@ -1442,19 +1443,19 @@ function createLabelDragAction(opts = {}) {
|
|
|
1442
1443
|
if (p === null) return {};
|
|
1443
1444
|
let spot = null;
|
|
1444
1445
|
let open = true;
|
|
1445
|
-
const
|
|
1446
|
+
const proposed2 = () => open ? spot : null;
|
|
1446
1447
|
return {
|
|
1447
1448
|
kind: "diagram-move-label",
|
|
1448
1449
|
onMove(moveCtx) {
|
|
1449
1450
|
spot = spotAt(p, moveCtx);
|
|
1450
1451
|
},
|
|
1451
|
-
previewIds: () =>
|
|
1452
|
+
previewIds: () => proposed2() === null ? null : [p.labelId],
|
|
1452
1453
|
previewPose: (id) => {
|
|
1453
|
-
const next =
|
|
1454
|
+
const next = proposed2();
|
|
1454
1455
|
return id === p.labelId && next !== null ? poseAt(p, next) : null;
|
|
1455
1456
|
},
|
|
1456
1457
|
previewData: (id) => {
|
|
1457
|
-
const next =
|
|
1458
|
+
const next = proposed2();
|
|
1458
1459
|
return id === p.labelId && next !== null ? movedLabelData(p.data, next) : null;
|
|
1459
1460
|
},
|
|
1460
1461
|
onEnd(endCtx, reason) {
|
|
@@ -1928,16 +1929,16 @@ function createRouteEditAction(opts) {
|
|
|
1928
1929
|
const session = beginSnap(ctx, p, snapPx);
|
|
1929
1930
|
let waypoints = null;
|
|
1930
1931
|
let open = true;
|
|
1931
|
-
const
|
|
1932
|
+
const proposed2 = () => open ? waypoints : null;
|
|
1932
1933
|
return {
|
|
1933
1934
|
kind: "diagram-edit-route",
|
|
1934
1935
|
onMove(moveCtx) {
|
|
1935
1936
|
waypoints = waypointsAt(p, moveOf2(p, session, moveCtx));
|
|
1936
1937
|
},
|
|
1937
|
-
previewIds: () =>
|
|
1938
|
-
previewPose: (id) => id === p.edgeId &&
|
|
1938
|
+
previewIds: () => proposed2() === null ? null : [p.edgeId],
|
|
1939
|
+
previewPose: (id) => id === p.edgeId && proposed2() !== null ? p.pose : null,
|
|
1939
1940
|
previewData: (id) => {
|
|
1940
|
-
const next =
|
|
1941
|
+
const next = proposed2();
|
|
1941
1942
|
return id === p.edgeId && next !== null ? routedData(p.data, p.trait, next) : null;
|
|
1942
1943
|
},
|
|
1943
1944
|
onEnd(endCtx, reason) {
|
|
@@ -2255,8 +2256,8 @@ function avoidSceneInput(scene, opts = {}, poseOf) {
|
|
|
2255
2256
|
const header = container === null ? null : headerBox(box, container.header);
|
|
2256
2257
|
if (header !== null) obstacles.push({ id: headerIdOf(node.id), kind: "shape", box: header });
|
|
2257
2258
|
if (container?.role === "lane") continue;
|
|
2258
|
-
const
|
|
2259
|
-
obstacles.push(
|
|
2259
|
+
const region2 = container !== null || diagramGroupOf(node) !== null;
|
|
2260
|
+
obstacles.push(region2 ? { id: node.id, kind: "region", box, members: members(sc, node, /* @__PURE__ */ new Set()) } : { id: node.id, kind: "shape", box });
|
|
2260
2261
|
}
|
|
2261
2262
|
for (const id of split) {
|
|
2262
2263
|
const node = labelNodes.get(id);
|
|
@@ -2315,13 +2316,13 @@ function obstaclesOf(specs, world) {
|
|
|
2315
2316
|
for (const spec of specs) {
|
|
2316
2317
|
const node = { id: spec.id, kind: spec.kind, data: spec.data };
|
|
2317
2318
|
if (spec.derivePose !== void 0 || diagramEdgeOf(spec) !== null) continue;
|
|
2318
|
-
const
|
|
2319
|
-
if (diagramNodeOf(node) === null &&
|
|
2319
|
+
const region2 = diagramContainerOf(spec);
|
|
2320
|
+
if (diagramNodeOf(node) === null && region2?.role !== "lane") continue;
|
|
2320
2321
|
const box = world.get(node.id) ?? spec.pose;
|
|
2321
|
-
const header =
|
|
2322
|
+
const header = region2 === null ? null : headerBox(box, region2.header);
|
|
2322
2323
|
if (header !== null) out.push({ id: headerIdOf(node.id), kind: "shape", box: header });
|
|
2323
|
-
if (
|
|
2324
|
-
out.push(
|
|
2324
|
+
if (region2?.role === "lane") continue;
|
|
2325
|
+
out.push(region2 === null ? { id: node.id, kind: "shape", box } : { id: node.id, kind: "region", box, members: inside2(node.id, /* @__PURE__ */ new Set()) });
|
|
2325
2326
|
}
|
|
2326
2327
|
return out;
|
|
2327
2328
|
}
|
|
@@ -2684,168 +2685,27 @@ function createSpecLabelPlacer(opts = {}) {
|
|
|
2684
2685
|
};
|
|
2685
2686
|
}
|
|
2686
2687
|
|
|
2688
|
+
// src/sequence/trait.ts
|
|
2689
|
+
var traitOf2 = (node) => {
|
|
2690
|
+
const data = node.data;
|
|
2691
|
+
if (data === null || typeof data !== "object") return null;
|
|
2692
|
+
const trait = data.diagram;
|
|
2693
|
+
return trait !== null && typeof trait === "object" ? trait : null;
|
|
2694
|
+
};
|
|
2695
|
+
function sequenceRootOf(node) {
|
|
2696
|
+
const trait = traitOf2(node);
|
|
2697
|
+
return trait !== null && "sequence" in trait && "geometry" in trait ? trait : null;
|
|
2698
|
+
}
|
|
2699
|
+
function sequencePartOf(node) {
|
|
2700
|
+
const seq = traitOf2(node)?.seq;
|
|
2701
|
+
return seq !== null && typeof seq === "object" && typeof seq.root === "string" ? seq : null;
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2687
2704
|
// src/resizable.ts
|
|
2688
2705
|
function diagramResizable(scene) {
|
|
2689
2706
|
return (id) => {
|
|
2690
2707
|
const node = scene.get(id);
|
|
2691
|
-
return node === void 0 || diagramEdgeOf(node) === null && diagramLabelOf(node) === null && diagramGroupOf(node) === null && diagramContainerOf(node)?.role !== "lane";
|
|
2692
|
-
};
|
|
2693
|
-
}
|
|
2694
|
-
|
|
2695
|
-
// src/routeWrites.ts
|
|
2696
|
-
var ROUTE_TOLERANCE = 1e-3;
|
|
2697
|
-
function routesOf(graph, plan) {
|
|
2698
|
-
return {
|
|
2699
|
-
edges: new Set(graph.edges.map((e) => e.origin?.id ?? e.id)),
|
|
2700
|
-
waypoints: plan.waypoints ?? /* @__PURE__ */ new Map(),
|
|
2701
|
-
...plan.labels !== void 0 ? { labels: plan.labels } : {},
|
|
2702
|
-
...plan.ports !== void 0 ? { ports: plan.ports } : {}
|
|
2703
|
-
};
|
|
2704
|
-
}
|
|
2705
|
-
function routeWrites(scene, routes) {
|
|
2706
|
-
const out = /* @__PURE__ */ new Map();
|
|
2707
|
-
const owned = /* @__PURE__ */ new Set();
|
|
2708
|
-
for (const id of routes.edges) {
|
|
2709
|
-
const node = scene.get(id);
|
|
2710
|
-
const edge = node === void 0 ? null : diagramEdgeOf(node);
|
|
2711
|
-
if (node === void 0 || edge === null || scene.isLocked(id)) {
|
|
2712
|
-
if (edge !== null && layoutWritesRoute(edge)) owned.add(id);
|
|
2713
|
-
continue;
|
|
2714
|
-
}
|
|
2715
|
-
let next = edge;
|
|
2716
|
-
if (layoutWritesRoute(edge)) {
|
|
2717
|
-
owned.add(id);
|
|
2718
|
-
next = rerouted(edge, routes.waypoints.get(id));
|
|
2719
|
-
}
|
|
2720
|
-
const ports = routes.ports?.get(id);
|
|
2721
|
-
const from = renamed(edge.from, ports?.from);
|
|
2722
|
-
const to = renamed(edge.to, ports?.to);
|
|
2723
|
-
if (from !== edge.from || to !== edge.to) next = { ...next, from, to };
|
|
2724
|
-
if (next !== edge) out.set(id, withTrait(node.data, next));
|
|
2725
|
-
}
|
|
2726
|
-
const stationed = /* @__PURE__ */ new Set();
|
|
2727
|
-
for (const node of scene.renderOrderNodes()) {
|
|
2728
|
-
const label = diagramLabelOf(node);
|
|
2729
|
-
const deps = node.dependsOn;
|
|
2730
|
-
if (label === null || !Array.isArray(deps) || deps.length !== 1 || !owned.has(deps[0])) continue;
|
|
2731
|
-
if (!labelFollowsLayout(label.at) || stationed.has(deps[0])) continue;
|
|
2732
|
-
stationed.add(deps[0]);
|
|
2733
|
-
const near2 = routes.labels?.get(deps[0]);
|
|
2734
|
-
const at = near2 === void 0 ? "mid" : { near: near2 };
|
|
2735
|
-
if (sameAt(label.at, at) || scene.isLocked(node.id)) continue;
|
|
2736
|
-
out.set(node.id, withTrait(node.data, { ...label, at }, "label"));
|
|
2737
|
-
}
|
|
2738
|
-
return out;
|
|
2739
|
-
}
|
|
2740
|
-
function rerouted(edge, route) {
|
|
2741
|
-
if (route === void 0 || route.length === 0) {
|
|
2742
|
-
if ((edge.waypoints ?? []).length === 0 && edge.laidOut === void 0) return edge;
|
|
2743
|
-
const { waypoints: _w, laidOut: _l, ...rest } = edge;
|
|
2744
|
-
return rest;
|
|
2745
|
-
}
|
|
2746
|
-
if (edge.waypoints !== void 0 && near(edge.waypoints, route)) return edge;
|
|
2747
|
-
return { ...edge, waypoints: route, laidOut: route };
|
|
2748
|
-
}
|
|
2749
|
-
function renamed(end, port) {
|
|
2750
|
-
if (!layoutOwnsPort(end) || end.port === port && (port === void 0 || end.laidOut === port)) return end;
|
|
2751
|
-
const { port: _p, laidOut: _l, ...rest } = end;
|
|
2752
|
-
return port === void 0 ? rest : { ...rest, port, laidOut: port };
|
|
2753
|
-
}
|
|
2754
|
-
function near(a, b) {
|
|
2755
|
-
return a.length === b.length && a.every((p, i) => Math.abs(p.x - b[i].x) <= ROUTE_TOLERANCE && Math.abs(p.y - b[i].y) <= ROUTE_TOLERANCE);
|
|
2756
|
-
}
|
|
2757
|
-
function sameAt(a, b) {
|
|
2758
|
-
if (typeof a === "object" && typeof b === "object") return near([a.near], [b.near]);
|
|
2759
|
-
return a === b;
|
|
2760
|
-
}
|
|
2761
|
-
function withTrait(data, value, key) {
|
|
2762
|
-
const own = data;
|
|
2763
|
-
const diagram = key === void 0 ? value : { ...own.diagram, [key]: value };
|
|
2764
|
-
return { ...own, diagram };
|
|
2765
|
-
}
|
|
2766
|
-
var LAYOUTS = Object.freeze({
|
|
2767
|
-
layered,
|
|
2768
|
-
tree,
|
|
2769
|
-
force,
|
|
2770
|
-
chain,
|
|
2771
|
-
radial
|
|
2772
|
-
});
|
|
2773
|
-
function applyLayout(scene, result, opts = {}) {
|
|
2774
|
-
const poses = layoutPoses(scene, result, opts.geometry);
|
|
2775
|
-
const data = opts.routes === void 0 ? /* @__PURE__ */ new Map() : routeWrites(scene, opts.routes);
|
|
2776
|
-
if (poses.size === 0 && data.size === 0) return 0;
|
|
2777
|
-
const open = [...poses].filter(([id]) => !scene.isLocked(id));
|
|
2778
|
-
if (open.length === 0 && data.size === 0) return 0;
|
|
2779
|
-
scene.batch(opts.label ?? "Layout", () => {
|
|
2780
|
-
for (const [id, pose] of open) scene.setPose(id, pose);
|
|
2781
|
-
for (const [id, d] of data) scene.update(id, { data: d });
|
|
2782
|
-
});
|
|
2783
|
-
const wrote = new Set(open.map(([id]) => id));
|
|
2784
|
-
let moved = 0;
|
|
2785
|
-
for (const id of result.keys()) if (wrote.has(id)) moved++;
|
|
2786
|
-
return moved;
|
|
2787
|
-
}
|
|
2788
|
-
function layoutPoses(scene, result, geometry = AUTO_POSE_DESCRIPTOR) {
|
|
2789
|
-
const sc = scene;
|
|
2790
|
-
const { compose, decompose } = sc.composition;
|
|
2791
|
-
const stored = scenePoseAdapter(sc);
|
|
2792
|
-
const out = /* @__PURE__ */ new Map();
|
|
2793
|
-
const decided = { ...stored, getPose: (id) => out.has(id) ? out.get(id) : stored.getPose(id) };
|
|
2794
|
-
const depth = (id) => {
|
|
2795
|
-
let d = 0;
|
|
2796
|
-
for (let at = scene.get(id)?.parent; at != null; at = scene.get(at)?.parent) d++;
|
|
2797
|
-
return d;
|
|
2798
|
-
};
|
|
2799
|
-
const ids = [...result.keys()].filter((id) => scene.get(id) !== void 0).sort((a, b) => depth(a) - depth(b));
|
|
2800
|
-
for (const id of ids) {
|
|
2801
|
-
const at = result.get(id);
|
|
2802
|
-
const world = composeWorldPose(stored, id, compose);
|
|
2803
|
-
const bounds = geometry.getBounds(world);
|
|
2804
|
-
const dx = at.x - bounds.x;
|
|
2805
|
-
const dy = at.y - bounds.y;
|
|
2806
|
-
if (dx === 0 && dy === 0) continue;
|
|
2807
|
-
const parent = scene.get(id).parent;
|
|
2808
|
-
out.set(id, rebaseLocalPose(decided, translatePoseViaDescriptor(world, dx, dy, geometry), parent, compose, decompose));
|
|
2809
|
-
const carried = carriedDescendants(sceneCarrySource(sc), id, (w) => translatePoseViaDescriptor(w, dx, dy, geometry));
|
|
2810
|
-
for (const [d, pose] of carried) out.set(d, pose);
|
|
2811
|
-
}
|
|
2812
|
-
return out;
|
|
2813
|
-
}
|
|
2814
|
-
var LAYOUT_ACTION_ID = "diagram.layout";
|
|
2815
|
-
function layoutDiagram(scene, source, algorithm, opts = {}) {
|
|
2816
|
-
const fn = typeof algorithm === "function" ? algorithm : LAYOUTS[algorithm] ?? layered;
|
|
2817
|
-
const graph = buildGraph(source, {
|
|
2818
|
-
...opts.read ? { read: opts.read } : {},
|
|
2819
|
-
...opts.geometry ? { geometry: opts.geometry } : {}
|
|
2820
|
-
});
|
|
2821
|
-
const plan = planOf(fn, graph, opts.layout);
|
|
2822
|
-
return applyLayout(scene, plan.moves, {
|
|
2823
|
-
...opts.geometry ? { geometry: opts.geometry } : {},
|
|
2824
|
-
...opts.label ? { label: opts.label } : {},
|
|
2825
|
-
routes: routesOf(graph, plan)
|
|
2826
|
-
});
|
|
2827
|
-
}
|
|
2828
|
-
function createLayoutAction(opts) {
|
|
2829
|
-
const { read, geometry, layout, label } = opts;
|
|
2830
|
-
const options = {
|
|
2831
|
-
...read ? { read } : {},
|
|
2832
|
-
...geometry ? { geometry } : {},
|
|
2833
|
-
...layout ? { layout } : {},
|
|
2834
|
-
...label ? { label } : {}
|
|
2835
|
-
};
|
|
2836
|
-
return {
|
|
2837
|
-
id: opts.id ?? LAYOUT_ACTION_ID,
|
|
2838
|
-
label: opts.label ?? "Lay out diagram",
|
|
2839
|
-
group: opts.group ?? "diagram",
|
|
2840
|
-
requires: ["scene"],
|
|
2841
|
-
invoker: {
|
|
2842
|
-
timing: "immediate",
|
|
2843
|
-
run: (deps) => {
|
|
2844
|
-
const scene = deps["scene"];
|
|
2845
|
-
if (scene !== void 0) layoutDiagram(scene, opts.source, opts.algorithm ?? "layered", options);
|
|
2846
|
-
}
|
|
2847
|
-
},
|
|
2848
|
-
enabled: () => true
|
|
2708
|
+
return node === void 0 || diagramEdgeOf(node) === null && diagramLabelOf(node) === null && diagramGroupOf(node) === null && diagramContainerOf(node)?.role !== "lane" && sequencePartOf(node) === null;
|
|
2849
2709
|
};
|
|
2850
2710
|
}
|
|
2851
2711
|
var EASE_FRAMES = 24;
|
|
@@ -2880,14 +2740,14 @@ function forceProducer(graph, opts = {}) {
|
|
|
2880
2740
|
}
|
|
2881
2741
|
relaxation.sim.alphaTarget(pinned.size > 0 ? dragAlpha : 0);
|
|
2882
2742
|
relaxation.sim.tick();
|
|
2883
|
-
let
|
|
2743
|
+
let moved2 = 0;
|
|
2884
2744
|
relaxation.bodies.forEach((body, i) => {
|
|
2885
2745
|
const at = was[i];
|
|
2886
|
-
|
|
2746
|
+
moved2 = Math.max(moved2, Math.hypot(body.x - at.x, body.y - at.y));
|
|
2887
2747
|
at.x = body.x;
|
|
2888
2748
|
at.y = body.y;
|
|
2889
2749
|
});
|
|
2890
|
-
still = pinned.size === 0 &&
|
|
2750
|
+
still = pinned.size === 0 && moved2 < restDistance ? still + 1 : 0;
|
|
2891
2751
|
const done = still >= restTicks || relaxation.sim.isSettled();
|
|
2892
2752
|
return { result: relaxation.placed(), done };
|
|
2893
2753
|
};
|
|
@@ -3143,7 +3003,7 @@ function useLiveLayout(opts) {
|
|
|
3143
3003
|
const o = optsRef.current;
|
|
3144
3004
|
producerFrame.current = 0;
|
|
3145
3005
|
held.current = false;
|
|
3146
|
-
routes.current = routesOf(graph, plan ?? { });
|
|
3006
|
+
routes.current = routesOf(graph, plan ?? { moves: /* @__PURE__ */ new Map() });
|
|
3147
3007
|
eased.set(routeEasings(o.scene, graph, routes.current));
|
|
3148
3008
|
producer.current = producerFor(graph, plan, o);
|
|
3149
3009
|
}, [optsRef, eased]);
|
|
@@ -3168,9 +3028,9 @@ function useLiveLayout(opts) {
|
|
|
3168
3028
|
scene: opts.scene,
|
|
3169
3029
|
step,
|
|
3170
3030
|
// Eased routes go once the routes are in the document, so no frame shows the old ones.
|
|
3171
|
-
onCommit: (
|
|
3031
|
+
onCommit: (moved2) => {
|
|
3172
3032
|
eased.drop();
|
|
3173
|
-
optsRef.current.onSettle?.(
|
|
3033
|
+
optsRef.current.onSettle?.(moved2);
|
|
3174
3034
|
},
|
|
3175
3035
|
// Routes match where the layout was going, so only a run that got there
|
|
3176
3036
|
// with nothing held along the way writes them.
|
|
@@ -3237,7 +3097,8 @@ function useLiveLayout(opts) {
|
|
|
3237
3097
|
var EASED_LAYOUTS = Object.freeze({
|
|
3238
3098
|
layered,
|
|
3239
3099
|
tree,
|
|
3240
|
-
chain
|
|
3100
|
+
chain,
|
|
3101
|
+
grid
|
|
3241
3102
|
});
|
|
3242
3103
|
function bodyRules(trait, box) {
|
|
3243
3104
|
const layout = trait.body;
|
|
@@ -3254,7 +3115,7 @@ function bodyRules(trait, box) {
|
|
|
3254
3115
|
// src/shape.ts
|
|
3255
3116
|
function diagramShape(opts = {}) {
|
|
3256
3117
|
const geometry = opts.geometry ?? RECT_POSE_DESCRIPTOR;
|
|
3257
|
-
const outlineOf2 = (node) => diagramNodeOf(node, opts.read)?.outline ?? laneOutlineOf(node);
|
|
3118
|
+
const outlineOf2 = (node) => diagramNodeOf(node, opts.read)?.outline ?? laneOutlineOf(node) ?? sequenceOutlineOf(node);
|
|
3258
3119
|
return {
|
|
3259
3120
|
id: opts.id ?? "diagram:outline",
|
|
3260
3121
|
matches: (node) => outlineOf2(node) !== void 0,
|
|
@@ -3271,6 +3132,9 @@ function diagramShape(opts = {}) {
|
|
|
3271
3132
|
const divider = header === null || !stroke ? [] : [{ kind: "path", path: dividerPath(box, header), stroke }];
|
|
3272
3133
|
const detailPath = stroke ? outlineDetail(outline, box) : null;
|
|
3273
3134
|
const detail = stroke && detailPath ? [{ kind: "path", path: detailPath, stroke }] : [];
|
|
3135
|
+
const solidPath = declaredStroke ? outlineSolid(outline, box) : null;
|
|
3136
|
+
const solidFill = declaredStroke && solidPath ? commandFill({ paint: declaredStroke.paint }, box) : null;
|
|
3137
|
+
const solid = solidPath && solidFill ? [{ kind: "path", path: solidPath, fill: solidFill }] : [];
|
|
3274
3138
|
const trait = diagramNodeOf(node, opts.read);
|
|
3275
3139
|
const rules = stroke && trait !== null ? bodyRules(trait, box).map((path) => ({ kind: "path", path, stroke })) : [];
|
|
3276
3140
|
return [{
|
|
@@ -3278,7 +3142,7 @@ function diagramShape(opts = {}) {
|
|
|
3278
3142
|
path: outlinePath(outline, box),
|
|
3279
3143
|
...fill ? { fill } : {},
|
|
3280
3144
|
...stroke ? { stroke } : {}
|
|
3281
|
-
}, ...detail, ...rules, ...divider];
|
|
3145
|
+
}, ...solid, ...detail, ...rules, ...divider];
|
|
3282
3146
|
},
|
|
3283
3147
|
// The drawn boundary, so picking and clipping follow the diamond rather
|
|
3284
3148
|
// than its bounding box.
|
|
@@ -3288,6 +3152,10 @@ function diagramShape(opts = {}) {
|
|
|
3288
3152
|
}
|
|
3289
3153
|
};
|
|
3290
3154
|
}
|
|
3155
|
+
function sequenceOutlineOf(node) {
|
|
3156
|
+
if (sequencePartOf(node) === null) return void 0;
|
|
3157
|
+
return node.data.diagram?.outline;
|
|
3158
|
+
}
|
|
3291
3159
|
function dividerPath(box, header) {
|
|
3292
3160
|
return header.width < box.width ? polylineFromPoints([{ x: header.x + header.width, y: box.y }, { x: header.x + header.width, y: box.y + box.height }]) : polylineFromPoints([{ x: box.x, y: header.y + header.height }, { x: box.x + box.width, y: header.y + header.height }]);
|
|
3293
3161
|
}
|
|
@@ -3298,6 +3166,1348 @@ function registerDiagramShape(opts = {}) {
|
|
|
3298
3166
|
// src/bodyNode.ts
|
|
3299
3167
|
var isDiagramBody = (node) => diagramContainerOf(node) === null && diagramGroupOf(node) === null && dataKeyReader(node) !== null;
|
|
3300
3168
|
var isBodyOrRegion = (node) => diagramContainerOf(node) !== null || isDiagramBody(node);
|
|
3169
|
+
|
|
3170
|
+
// src/sequence/edit.ts
|
|
3171
|
+
var hasId = (s) => "id" in s;
|
|
3172
|
+
function stepListOf(steps, parent) {
|
|
3173
|
+
if (parent === null) return steps;
|
|
3174
|
+
const frag = findStep(steps, parent.fragment);
|
|
3175
|
+
return frag?.kind === "fragment" ? frag.sections[parent.section]?.steps ?? null : null;
|
|
3176
|
+
}
|
|
3177
|
+
function findStep(steps, id) {
|
|
3178
|
+
for (const s of steps) {
|
|
3179
|
+
if (hasId(s) && s.id === id) return s;
|
|
3180
|
+
if (s.kind === "fragment") {
|
|
3181
|
+
for (const section of s.sections) {
|
|
3182
|
+
const found = findStep(section.steps, id);
|
|
3183
|
+
if (found !== null) return found;
|
|
3184
|
+
}
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
return null;
|
|
3188
|
+
}
|
|
3189
|
+
function placeOf(steps, id, parent = null) {
|
|
3190
|
+
for (const [index, s] of steps.entries()) {
|
|
3191
|
+
if (hasId(s) && s.id === id) return { parent, index };
|
|
3192
|
+
if (s.kind === "fragment") {
|
|
3193
|
+
for (const [k, section] of s.sections.entries()) {
|
|
3194
|
+
const found = placeOf(section.steps, id, { fragment: s.id, section: k });
|
|
3195
|
+
if (found !== null) return found;
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
3198
|
+
}
|
|
3199
|
+
return null;
|
|
3200
|
+
}
|
|
3201
|
+
function mapSteps(steps, fn) {
|
|
3202
|
+
let changed = false;
|
|
3203
|
+
const out = steps.map((s) => {
|
|
3204
|
+
let next = fn(s);
|
|
3205
|
+
if (next.kind === "fragment") {
|
|
3206
|
+
const frag = next;
|
|
3207
|
+
const sections = frag.sections.map((section) => {
|
|
3208
|
+
const inner = mapSteps(section.steps, fn);
|
|
3209
|
+
return inner === section.steps ? section : { ...section, steps: inner };
|
|
3210
|
+
});
|
|
3211
|
+
if (sections.some((sec, k) => sec !== frag.sections[k])) next = { ...frag, sections };
|
|
3212
|
+
}
|
|
3213
|
+
if (next !== s) changed = true;
|
|
3214
|
+
return next;
|
|
3215
|
+
});
|
|
3216
|
+
return changed ? out : steps;
|
|
3217
|
+
}
|
|
3218
|
+
function pruneSteps(steps, fn) {
|
|
3219
|
+
let changed = false;
|
|
3220
|
+
const out = [];
|
|
3221
|
+
for (const s of steps) {
|
|
3222
|
+
let step = s;
|
|
3223
|
+
if (s.kind === "fragment") {
|
|
3224
|
+
const sections = s.sections.map((sec) => {
|
|
3225
|
+
const inner = pruneSteps(sec.steps, fn);
|
|
3226
|
+
return inner === sec.steps ? sec : { ...sec, steps: inner };
|
|
3227
|
+
});
|
|
3228
|
+
if (sections.some((sec, k) => sec !== s.sections[k])) step = { ...s, sections };
|
|
3229
|
+
}
|
|
3230
|
+
const next = fn(step);
|
|
3231
|
+
if (next !== s) changed = true;
|
|
3232
|
+
if (next !== null) out.push(next);
|
|
3233
|
+
}
|
|
3234
|
+
return changed ? out : steps;
|
|
3235
|
+
}
|
|
3236
|
+
function withList(steps, parent, fn) {
|
|
3237
|
+
if (parent === null) return fn(steps);
|
|
3238
|
+
return mapSteps(steps, (s) => {
|
|
3239
|
+
if (s.kind !== "fragment" || s.id !== parent.fragment) return s;
|
|
3240
|
+
const sections = s.sections.map((sec, k) => k === parent.section ? { ...sec, steps: fn(sec.steps) } : sec);
|
|
3241
|
+
return { ...s, sections };
|
|
3242
|
+
});
|
|
3243
|
+
}
|
|
3244
|
+
var contains = (step, id) => step.kind === "fragment" && step.sections.some((sec) => sec.steps.some((s) => hasId(s) && s.id === id || contains(s, id)));
|
|
3245
|
+
function moveStep(data, id, to) {
|
|
3246
|
+
const from = placeOf(data.steps, id);
|
|
3247
|
+
const step = findStep(data.steps, id);
|
|
3248
|
+
if (from === null || step === null) return data;
|
|
3249
|
+
if (to.parent !== null && (to.parent.fragment === id || contains(step, to.parent.fragment))) return data;
|
|
3250
|
+
if (stepListOf(data.steps, to.parent) === null) return data;
|
|
3251
|
+
const sameList = JSON.stringify(from.parent) === JSON.stringify(to.parent);
|
|
3252
|
+
if (sameList && (to.index === from.index || to.index === from.index + 1)) return data;
|
|
3253
|
+
const removed = withList(data.steps, from.parent, (list) => list.filter((_, i) => i !== from.index));
|
|
3254
|
+
const index = sameList && to.index > from.index ? to.index - 1 : to.index;
|
|
3255
|
+
const steps = withList(removed, to.parent, (list) => [...list.slice(0, index), step, ...list.slice(index)]);
|
|
3256
|
+
return { ...data, steps };
|
|
3257
|
+
}
|
|
3258
|
+
function moveParticipant(data, id, index) {
|
|
3259
|
+
const from = data.participants.findIndex((p2) => p2.id === id);
|
|
3260
|
+
if (from < 0 || index === from || index === from + 1) return data;
|
|
3261
|
+
const p = data.participants[from];
|
|
3262
|
+
const rest = data.participants.filter((_, i) => i !== from);
|
|
3263
|
+
const at = index > from ? index - 1 : index;
|
|
3264
|
+
return { ...data, participants: [...rest.slice(0, at), p, ...rest.slice(at)] };
|
|
3265
|
+
}
|
|
3266
|
+
function reconnectMessage(data, id, end, participant) {
|
|
3267
|
+
const step = findStep(data.steps, id);
|
|
3268
|
+
if (step?.kind !== "message" || step[end] === participant || !data.participants.some((p) => p.id === participant)) return data;
|
|
3269
|
+
return { ...data, steps: mapSteps(data.steps, (s) => s === step ? { ...step, [end]: participant } : s) };
|
|
3270
|
+
}
|
|
3271
|
+
function setSequenceText(data, target, text) {
|
|
3272
|
+
if ("participant" in target) {
|
|
3273
|
+
const at = data.participants.findIndex((p2) => p2.id === target.participant);
|
|
3274
|
+
const p = data.participants[at];
|
|
3275
|
+
if (p === void 0 || (p.label ?? p.id) === text) return data;
|
|
3276
|
+
const { label: _label, ...rest } = p;
|
|
3277
|
+
const next = text === "" || text === p.id ? rest : { ...rest, label: text };
|
|
3278
|
+
return { ...data, participants: data.participants.map((q, i) => i === at ? next : q) };
|
|
3279
|
+
}
|
|
3280
|
+
if ("box" in target) {
|
|
3281
|
+
const boxes = data.boxes?.map((b) => {
|
|
3282
|
+
if (b.id !== target.box || (b.label ?? "") === text) return b;
|
|
3283
|
+
const { label: _label, ...rest } = b;
|
|
3284
|
+
return text === "" ? rest : { ...rest, label: text };
|
|
3285
|
+
});
|
|
3286
|
+
return boxes === void 0 || boxes.every((b, i) => b === data.boxes[i]) ? data : { ...data, boxes };
|
|
3287
|
+
}
|
|
3288
|
+
if ("fragment" in target) {
|
|
3289
|
+
const steps2 = mapSteps(data.steps, (s) => {
|
|
3290
|
+
if (s.kind !== "fragment" || s.id !== target.fragment) return s;
|
|
3291
|
+
const section = s.sections[target.section];
|
|
3292
|
+
if (section === void 0 || (section.label ?? "") === text) return s;
|
|
3293
|
+
const { label: _label, ...rest } = section;
|
|
3294
|
+
const next = text === "" ? rest : { ...rest, label: text };
|
|
3295
|
+
return { ...s, sections: s.sections.map((sec, k) => k === target.section ? next : sec) };
|
|
3296
|
+
});
|
|
3297
|
+
return steps2 === data.steps ? data : { ...data, steps: steps2 };
|
|
3298
|
+
}
|
|
3299
|
+
const steps = mapSteps(data.steps, (s) => {
|
|
3300
|
+
if (s.kind === "note" && s.id === target.step && s.text !== text) return { ...s, text };
|
|
3301
|
+
if (s.kind !== "message" || s.id !== target.step || (s.text ?? "") === text) return s;
|
|
3302
|
+
const { text: _text, ...rest } = s;
|
|
3303
|
+
return text === "" ? rest : { ...rest, text };
|
|
3304
|
+
});
|
|
3305
|
+
return steps === data.steps ? data : { ...data, steps };
|
|
3306
|
+
}
|
|
3307
|
+
function sequenceTextOf(data, target) {
|
|
3308
|
+
if ("participant" in target) {
|
|
3309
|
+
const p = data.participants.find((q) => q.id === target.participant);
|
|
3310
|
+
return p === void 0 ? null : p.label ?? p.id;
|
|
3311
|
+
}
|
|
3312
|
+
if ("box" in target) {
|
|
3313
|
+
const b = data.boxes?.find((q) => q.id === target.box);
|
|
3314
|
+
return b === void 0 ? null : b.label ?? "";
|
|
3315
|
+
}
|
|
3316
|
+
if ("fragment" in target) {
|
|
3317
|
+
const f = findStep(data.steps, target.fragment);
|
|
3318
|
+
const section = f?.kind === "fragment" ? f.sections[target.section] : void 0;
|
|
3319
|
+
return section === void 0 ? null : section.label ?? "";
|
|
3320
|
+
}
|
|
3321
|
+
const s = findStep(data.steps, target.step);
|
|
3322
|
+
return s?.kind === "message" ? s.text ?? "" : s?.kind === "note" ? s.text : null;
|
|
3323
|
+
}
|
|
3324
|
+
|
|
3325
|
+
// src/sequence/metrics.ts
|
|
3326
|
+
var SEQ = {
|
|
3327
|
+
/** Around the whole diagram. */
|
|
3328
|
+
margin: 12,
|
|
3329
|
+
/** Between a head's outline and its text. */
|
|
3330
|
+
headPad: 10,
|
|
3331
|
+
headMinWidth: 80,
|
|
3332
|
+
headMinHeight: 36,
|
|
3333
|
+
/** The least room between two heads. */
|
|
3334
|
+
columnGap: 32,
|
|
3335
|
+
/** Either side of a message's text along its line. */
|
|
3336
|
+
textPad: 10,
|
|
3337
|
+
/** Above every row. */
|
|
3338
|
+
rowGap: 14,
|
|
3339
|
+
/** Between a message's text and its line. */
|
|
3340
|
+
textGap: 3,
|
|
3341
|
+
/** A self-message's loop: how far it reaches right, and how tall it is. */
|
|
3342
|
+
loopWidth: 32,
|
|
3343
|
+
loopHeight: 20,
|
|
3344
|
+
/** An activation bar's width, and how far each nested one steps right. */
|
|
3345
|
+
barWidth: 10,
|
|
3346
|
+
barStep: 5,
|
|
3347
|
+
notePad: 6,
|
|
3348
|
+
noteMinWidth: 60,
|
|
3349
|
+
/** Between a lifeline and a note beside it. */
|
|
3350
|
+
noteGap: 10,
|
|
3351
|
+
/** How far a note over two lifelines reaches past them. */
|
|
3352
|
+
noteOverhang: 16,
|
|
3353
|
+
/** Between a fragment's box and the lifelines it holds, and between nested boxes. */
|
|
3354
|
+
fragmentPad: 14,
|
|
3355
|
+
fragmentNest: 8,
|
|
3356
|
+
/** Around a fragment's type label in its tab. */
|
|
3357
|
+
tabPad: 6,
|
|
3358
|
+
/** Between a box's border and the heads it holds. */
|
|
3359
|
+
boxPad: 10,
|
|
3360
|
+
/** Below the last row. */
|
|
3361
|
+
footer: 16,
|
|
3362
|
+
/** The X at a destroyed lifeline's end. */
|
|
3363
|
+
cross: 12
|
|
3364
|
+
};
|
|
3365
|
+
function seqMeasure(measure, font = DEFAULT_FONT) {
|
|
3366
|
+
const line = measure ?? ((text, s) => {
|
|
3367
|
+
const size = s.fontSize ?? font.fontSize;
|
|
3368
|
+
return { width: text.length * GLYPH * size, height: Math.ceil(1.4 * size) };
|
|
3369
|
+
});
|
|
3370
|
+
return {
|
|
3371
|
+
font,
|
|
3372
|
+
text: (text, style = {}) => {
|
|
3373
|
+
const s = { ...style, fontFamily: style.fontFamily ?? font.fontFamily, fontSize: style.fontSize ?? font.fontSize };
|
|
3374
|
+
const sizes = text.split("\n").map((l) => line(l, s));
|
|
3375
|
+
return { width: Math.max(0, ...sizes.map((z) => z.width)), height: sizes.reduce((h, z) => h + z.height, 0) };
|
|
3376
|
+
}
|
|
3377
|
+
};
|
|
3378
|
+
}
|
|
3379
|
+
function headSize(p, m) {
|
|
3380
|
+
const t = m.text(p.label ?? p.id);
|
|
3381
|
+
const outline = p.outline ?? "rect";
|
|
3382
|
+
const box = boxForContent(outline, { width: t.width + SEQ.headPad * 2, height: t.height + SEQ.headPad * 2 });
|
|
3383
|
+
return { width: Math.max(SEQ.headMinWidth, Math.ceil(box.width)), height: Math.max(SEQ.headMinHeight, Math.ceil(box.height)) };
|
|
3384
|
+
}
|
|
3385
|
+
|
|
3386
|
+
// src/sequence/columns.ts
|
|
3387
|
+
function* flatSteps(steps) {
|
|
3388
|
+
for (const s of steps) {
|
|
3389
|
+
yield s;
|
|
3390
|
+
if (s.kind === "fragment") for (const section of s.sections) yield* flatSteps(section.steps);
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
function noteNeeds(over, side, width, half) {
|
|
3394
|
+
const [a, b] = [Math.min(...over), Math.max(...over)];
|
|
3395
|
+
const room = width + SEQ.noteGap * 2;
|
|
3396
|
+
if (side === "right") return [{ a, b: a + 1, room: room + half(a + 1) }];
|
|
3397
|
+
if (side === "left") return [{ a: a - 1, b: a, room: room + half(a - 1) }];
|
|
3398
|
+
if (a === b) return [{ a: a - 1, b: a, room: width / 2 + half(a - 1) + SEQ.noteGap }, { a, b: a + 1, room: width / 2 + half(a + 1) + SEQ.noteGap }];
|
|
3399
|
+
return [{ a, b, room: width - SEQ.noteOverhang * 2 }];
|
|
3400
|
+
}
|
|
3401
|
+
function needsOf(data, m, index, half) {
|
|
3402
|
+
const out = [];
|
|
3403
|
+
const numbered = data.autonumber !== void 0;
|
|
3404
|
+
for (const s of flatSteps(data.steps)) {
|
|
3405
|
+
if (s.kind === "message") {
|
|
3406
|
+
const a = index.get(s.from);
|
|
3407
|
+
const b = index.get(s.to);
|
|
3408
|
+
if (a === void 0 || b === void 0) continue;
|
|
3409
|
+
const text = (s.text ?? "") === "" ? 0 : m.text(s.text).width;
|
|
3410
|
+
const room = text + SEQ.textPad * 2 + SEQ.barWidth * 2 + (numbered ? SEQ.textPad * 2 : 0);
|
|
3411
|
+
if (a === b) out.push({ a, b: a + 1, room: SEQ.loopWidth + room + half(a + 1) });
|
|
3412
|
+
else out.push({ a: Math.min(a, b), b: Math.max(a, b), room });
|
|
3413
|
+
} else if (s.kind === "note") {
|
|
3414
|
+
const over = s.over.map((id) => index.get(id)).filter((i) => i !== void 0);
|
|
3415
|
+
if (over.length > 0) out.push(...noteNeeds(over, s.side, Math.max(SEQ.noteMinWidth, m.text(s.text).width + SEQ.notePad * 2), half));
|
|
3416
|
+
}
|
|
3417
|
+
}
|
|
3418
|
+
return out;
|
|
3419
|
+
}
|
|
3420
|
+
function columnsOf(data, m, left) {
|
|
3421
|
+
const ps = data.participants;
|
|
3422
|
+
const heads = ps.map((p) => headSize(p, m));
|
|
3423
|
+
const index = new Map(ps.map((p, i) => [p.id, i]));
|
|
3424
|
+
const boxOf = /* @__PURE__ */ new Map();
|
|
3425
|
+
for (const b of data.boxes ?? []) for (const id of b.members) if (!boxOf.has(id)) boxOf.set(id, b.id);
|
|
3426
|
+
const half = (i) => (heads[i]?.width ?? 0) / 2;
|
|
3427
|
+
const boxPad = (i) => i >= 0 && i < ps.length && boxOf.has(ps[i].id) ? SEQ.boxPad : 0;
|
|
3428
|
+
const gaps = Array.from({ length: ps.length + 1 }, (_, i) => {
|
|
3429
|
+
if (i === 0) return half(0) + boxPad(0);
|
|
3430
|
+
if (i === ps.length) return half(i - 1) + boxPad(i - 1);
|
|
3431
|
+
const split = boxOf.get(ps[i - 1].id) !== boxOf.get(ps[i].id);
|
|
3432
|
+
return half(i - 1) + half(i) + SEQ.columnGap + (split ? boxPad(i - 1) + boxPad(i) : 0);
|
|
3433
|
+
});
|
|
3434
|
+
const needs = needsOf(data, m, index, half).sort((p, q) => p.b - p.a - (q.b - q.a));
|
|
3435
|
+
for (const { a, b, room } of needs) {
|
|
3436
|
+
const lo = Math.max(a, -1) + 1;
|
|
3437
|
+
const hi = Math.min(b, ps.length) + 1;
|
|
3438
|
+
let have = 0;
|
|
3439
|
+
for (let i = lo; i < hi; i++) have += gaps[i];
|
|
3440
|
+
const lack = room - have;
|
|
3441
|
+
if (lack > 0) for (let i = lo; i < hi; i++) gaps[i] += lack / (hi - lo);
|
|
3442
|
+
}
|
|
3443
|
+
const x = [];
|
|
3444
|
+
let at = left;
|
|
3445
|
+
for (let i = 0; i < ps.length; i++) {
|
|
3446
|
+
at += gaps[i];
|
|
3447
|
+
x.push(at);
|
|
3448
|
+
}
|
|
3449
|
+
return { x, heads, right: at + gaps[ps.length] };
|
|
3450
|
+
}
|
|
3451
|
+
|
|
3452
|
+
// src/sequence/rows.ts
|
|
3453
|
+
var spanOf = (rects) => {
|
|
3454
|
+
const x0 = Math.min(...rects.map((r) => r.x));
|
|
3455
|
+
return { x0, x1: Math.max(...rects.map((r) => r.x + r.width)) };
|
|
3456
|
+
};
|
|
3457
|
+
var RowWalk = class {
|
|
3458
|
+
constructor(data, m, cols, top) {
|
|
3459
|
+
this.data = data;
|
|
3460
|
+
this.m = m;
|
|
3461
|
+
this.cols = cols;
|
|
3462
|
+
this.index = new Map(data.participants.map((p, i) => [p.id, i]));
|
|
3463
|
+
this.created = new Set(flatMarks(data.steps, "create"));
|
|
3464
|
+
this.number = data.autonumber;
|
|
3465
|
+
const shown = data.participants.filter((p) => !this.created.has(p.id));
|
|
3466
|
+
const tall = Math.max(SEQ.headMinHeight, ...shown.map((p) => cols.heads[this.index.get(p.id)].height));
|
|
3467
|
+
for (const p of shown) this.placeHead(p.id, top + tall - cols.heads[this.index.get(p.id)].height, false);
|
|
3468
|
+
for (const l of this.lifeline.values()) l.y0 = top + tall;
|
|
3469
|
+
this.y = top + tall;
|
|
3470
|
+
}
|
|
3471
|
+
data;
|
|
3472
|
+
m;
|
|
3473
|
+
cols;
|
|
3474
|
+
out = { heads: [], lifelines: [], messages: [], activations: [], notes: [], fragments: [], slots: [], bottom: 0 };
|
|
3475
|
+
index;
|
|
3476
|
+
created;
|
|
3477
|
+
lifeline = /* @__PURE__ */ new Map();
|
|
3478
|
+
bars = /* @__PURE__ */ new Map();
|
|
3479
|
+
/** Lifelines a `destroy` ends at the next message to them, each with where it ends if none comes. */
|
|
3480
|
+
destroying = /* @__PURE__ */ new Map();
|
|
3481
|
+
frames = [];
|
|
3482
|
+
last = null;
|
|
3483
|
+
number;
|
|
3484
|
+
y;
|
|
3485
|
+
cx(id) {
|
|
3486
|
+
return this.cols.x[this.index.get(id)];
|
|
3487
|
+
}
|
|
3488
|
+
headRect(id) {
|
|
3489
|
+
const size = this.cols.heads[this.index.get(id)];
|
|
3490
|
+
return { x: this.cx(id) - size.width / 2, y: 0, width: size.width, height: 0 };
|
|
3491
|
+
}
|
|
3492
|
+
placeHead(id, y, created) {
|
|
3493
|
+
const size = this.cols.heads[this.index.get(id)];
|
|
3494
|
+
this.out.heads.push({ id, box: { x: this.cx(id) - size.width / 2, y, width: size.width, height: size.height }, created });
|
|
3495
|
+
const line = { id, x: this.cx(id), y0: y + size.height, y1: null };
|
|
3496
|
+
this.lifeline.set(id, line);
|
|
3497
|
+
this.out.lifelines.push(line);
|
|
3498
|
+
return y + size.height;
|
|
3499
|
+
}
|
|
3500
|
+
/** Into every open fragment's reach. */
|
|
3501
|
+
touch(rect) {
|
|
3502
|
+
for (const f of this.frames) f.push(rect);
|
|
3503
|
+
}
|
|
3504
|
+
/** Where a line meets `id`'s lifeline from `side`: the edge of its innermost open activation. */
|
|
3505
|
+
endX(id, side) {
|
|
3506
|
+
const depth = this.bars.get(id)?.length ?? 0;
|
|
3507
|
+
if (depth === 0) return this.cx(id);
|
|
3508
|
+
return this.cx(id) + side * (SEQ.barWidth / 2) + (depth - 1) * SEQ.barStep;
|
|
3509
|
+
}
|
|
3510
|
+
open(id, y, opener) {
|
|
3511
|
+
const stack = this.bars.get(id) ?? [];
|
|
3512
|
+
stack.push({ y, opener });
|
|
3513
|
+
this.bars.set(id, stack);
|
|
3514
|
+
}
|
|
3515
|
+
close(id, y, closer) {
|
|
3516
|
+
const stack = this.bars.get(id);
|
|
3517
|
+
const bar = stack?.pop();
|
|
3518
|
+
if (bar === void 0) return;
|
|
3519
|
+
const start = bar.y;
|
|
3520
|
+
const depth = stack.length;
|
|
3521
|
+
const x = this.cx(id) - SEQ.barWidth / 2 + depth * SEQ.barStep;
|
|
3522
|
+
const box = { x, y: start, width: SEQ.barWidth, height: Math.max(y, start + 8) - start };
|
|
3523
|
+
this.out.activations.push({ participant: id, depth, box, opener: bar.opener, ...closer ? { closer } : {} });
|
|
3524
|
+
}
|
|
3525
|
+
steps(list, parent) {
|
|
3526
|
+
list.forEach((step, index) => {
|
|
3527
|
+
this.out.slots.push({ y: this.y, place: { parent, index } });
|
|
3528
|
+
if (step.kind === "message") this.message(step);
|
|
3529
|
+
else if (step.kind === "note") this.note(step);
|
|
3530
|
+
else if (step.kind === "fragment") this.fragment(step);
|
|
3531
|
+
else this.mark(step, { parent, index });
|
|
3532
|
+
});
|
|
3533
|
+
this.out.slots.push({ y: this.y, place: { parent, index: list.length } });
|
|
3534
|
+
}
|
|
3535
|
+
message(s) {
|
|
3536
|
+
if (!this.index.has(s.from) || !this.index.has(s.to)) return;
|
|
3537
|
+
this.y += SEQ.rowGap;
|
|
3538
|
+
const text = (s.text ?? "") === "" ? null : this.m.text(s.text);
|
|
3539
|
+
const lineY = this.y + Math.max(text === null ? 0 : text.height + SEQ.textGap, 6);
|
|
3540
|
+
if (s.activate !== void 0) this.open(s[s.activate], lineY, { message: s.id, flag: "activate" });
|
|
3541
|
+
const self = s.from === s.to;
|
|
3542
|
+
const dir = self ? 1 : Math.sign(this.cx(s.to) - this.cx(s.from));
|
|
3543
|
+
const x1 = this.endX(s.from, dir);
|
|
3544
|
+
const x2 = self ? x1 : this.endX(s.to, -dir);
|
|
3545
|
+
const place2 = { id: s.id, y: lineY, x1, x2 };
|
|
3546
|
+
if (self) place2.loopY = lineY + SEQ.loopHeight;
|
|
3547
|
+
if (text !== null) {
|
|
3548
|
+
const x = self ? x1 + SEQ.textGap + 2 : (x1 + x2) / 2 - text.width / 2;
|
|
3549
|
+
place2.text = { x, y: lineY - SEQ.textGap - text.height, ...text };
|
|
3550
|
+
this.touch(place2.text);
|
|
3551
|
+
}
|
|
3552
|
+
if (this.number !== void 0) {
|
|
3553
|
+
const n = this.m.text(String(this.number), { fontSize: Math.max(8, this.m.font.fontSize - 2) });
|
|
3554
|
+
const d = Math.max(16, n.width + 6);
|
|
3555
|
+
place2.number = { n: this.number++, box: { x: x1 - d / 2, y: lineY - d / 2, width: d, height: d } };
|
|
3556
|
+
}
|
|
3557
|
+
this.out.messages.push(place2);
|
|
3558
|
+
this.touch(this.headRect(s.from));
|
|
3559
|
+
this.touch(this.headRect(s.to));
|
|
3560
|
+
if (self) this.touch({ x: x1, y: lineY, width: SEQ.loopWidth, height: 0 });
|
|
3561
|
+
if (s.deactivate !== void 0) this.close(s[s.deactivate], self ? place2.loopY : lineY, { message: s.id, flag: "deactivate" });
|
|
3562
|
+
for (const id of /* @__PURE__ */ new Set([s.from, s.to])) {
|
|
3563
|
+
if (!this.destroying.delete(id)) continue;
|
|
3564
|
+
const line = this.lifeline.get(id);
|
|
3565
|
+
if (line !== void 0) line.y1 = self ? place2.loopY : lineY;
|
|
3566
|
+
}
|
|
3567
|
+
this.y = place2.loopY ?? lineY;
|
|
3568
|
+
this.last = { y: this.y, ends: [s.from, s.to] };
|
|
3569
|
+
}
|
|
3570
|
+
note(s) {
|
|
3571
|
+
const over = s.over.filter((id) => this.index.has(id));
|
|
3572
|
+
if (over.length === 0) return;
|
|
3573
|
+
this.y += SEQ.rowGap;
|
|
3574
|
+
const t = this.m.text(s.text);
|
|
3575
|
+
const width = Math.max(SEQ.noteMinWidth, t.width + SEQ.notePad * 2);
|
|
3576
|
+
const height = t.height + SEQ.notePad * 2;
|
|
3577
|
+
const xs = over.map((id) => this.cx(id));
|
|
3578
|
+
const [lo, hi] = [Math.min(...xs), Math.max(...xs)];
|
|
3579
|
+
const x = s.side === "right" ? lo + SEQ.barWidth / 2 + SEQ.noteGap : s.side === "left" ? lo - SEQ.barWidth / 2 - SEQ.noteGap - width : lo === hi ? lo - width / 2 : Math.min(lo - SEQ.noteOverhang, (lo + hi) / 2 - width / 2);
|
|
3580
|
+
const box = { x, y: this.y, width: s.side === void 0 && lo !== hi ? Math.max(width, hi - lo + SEQ.noteOverhang * 2) : width, height };
|
|
3581
|
+
this.out.notes.push({ id: s.id, box });
|
|
3582
|
+
this.touch(box);
|
|
3583
|
+
for (const id of over) this.touch(this.headRect(id));
|
|
3584
|
+
this.y += height;
|
|
3585
|
+
this.last = null;
|
|
3586
|
+
}
|
|
3587
|
+
mark(s, at) {
|
|
3588
|
+
if (!this.index.has(s.participant)) return;
|
|
3589
|
+
this.touch(this.headRect(s.participant));
|
|
3590
|
+
const y = this.last?.ends.includes(s.participant) ? this.last.y : this.y + SEQ.rowGap / 2;
|
|
3591
|
+
if (s.kind === "activate") this.open(s.participant, y, { place: at });
|
|
3592
|
+
else if (s.kind === "deactivate") this.close(s.participant, y, { place: at });
|
|
3593
|
+
else if (s.kind === "destroy") {
|
|
3594
|
+
this.destroying.set(s.participant, this.last?.ends.includes(s.participant) ? this.last.y : null);
|
|
3595
|
+
const line = this.lifeline.get(s.participant);
|
|
3596
|
+
if (line !== void 0) line.destroyedBy = at;
|
|
3597
|
+
} else if (this.out.heads.every((h) => h.id !== s.participant)) {
|
|
3598
|
+
this.y = this.placeHead(s.participant, this.y + SEQ.rowGap, true);
|
|
3599
|
+
this.last = null;
|
|
3600
|
+
}
|
|
3601
|
+
}
|
|
3602
|
+
fragment(s) {
|
|
3603
|
+
this.y += SEQ.rowGap;
|
|
3604
|
+
const top = this.y;
|
|
3605
|
+
const tabText = s.type === "region" ? null : this.m.text(s.type, { bold: true });
|
|
3606
|
+
const tab = tabText === null ? null : { width: tabText.width + SEQ.tabPad * 2, height: tabText.height + SEQ.tabPad };
|
|
3607
|
+
const labels = s.sections.map((sec) => (sec.label ?? "") === "" ? null : this.m.text(sec.label));
|
|
3608
|
+
this.y += Math.max(tab?.height ?? 0, (labels[0]?.height ?? 0) + 4, 8);
|
|
3609
|
+
const frame = [];
|
|
3610
|
+
this.frames.push(frame);
|
|
3611
|
+
const sections = [];
|
|
3612
|
+
s.sections.forEach((sec, k) => {
|
|
3613
|
+
if (k > 0) {
|
|
3614
|
+
this.y += SEQ.rowGap / 2;
|
|
3615
|
+
sections.push({ y: this.y, height: 0 });
|
|
3616
|
+
this.y += (labels[k]?.height ?? 0) + 4;
|
|
3617
|
+
} else sections.push({ y: top, height: 0 });
|
|
3618
|
+
this.steps(sec.steps, { fragment: s.id, section: k });
|
|
3619
|
+
this.last = null;
|
|
3620
|
+
});
|
|
3621
|
+
this.frames.pop();
|
|
3622
|
+
this.y += SEQ.rowGap / 2;
|
|
3623
|
+
const reach = frame.length > 0 ? spanOf(frame) : { x0: this.cols.x[0] ?? 0, x1: this.cols.x.at(-1) ?? 0 };
|
|
3624
|
+
const minWidth = (tab?.width ?? 0) + (labels[0]?.width ?? 0) + SEQ.tabPad * 4;
|
|
3625
|
+
const x0 = reach.x0 - SEQ.fragmentPad / 2;
|
|
3626
|
+
const width = Math.max(reach.x1 - reach.x0 + SEQ.fragmentPad, minWidth);
|
|
3627
|
+
const box = { x: x0, y: top, width, height: this.y - top };
|
|
3628
|
+
const place2 = {
|
|
3629
|
+
id: s.id,
|
|
3630
|
+
type: s.type,
|
|
3631
|
+
box,
|
|
3632
|
+
sections: sections.map((sec, k) => {
|
|
3633
|
+
const l = labels[k];
|
|
3634
|
+
if (l === null || l === void 0) return { y: sec.y };
|
|
3635
|
+
const label = k === 0 ? { x: x0 + (tab?.width ?? 0) + SEQ.tabPad * 2, y: top + 2, ...l } : { x: x0 + width / 2 - l.width / 2, y: sec.y + 2, ...l };
|
|
3636
|
+
return { y: sec.y, label };
|
|
3637
|
+
})
|
|
3638
|
+
};
|
|
3639
|
+
if (tab !== null) place2.tab = { x: x0, y: top, ...tab };
|
|
3640
|
+
this.out.fragments.push(place2);
|
|
3641
|
+
this.touch({ x: box.x - SEQ.fragmentNest, y: top, width: box.width + SEQ.fragmentNest * 2, height: 0 });
|
|
3642
|
+
}
|
|
3643
|
+
};
|
|
3644
|
+
function flatMarks(steps, kind) {
|
|
3645
|
+
const out = [];
|
|
3646
|
+
for (const s of steps) {
|
|
3647
|
+
if (s.kind === kind) out.push(s.participant);
|
|
3648
|
+
if (s.kind === "fragment") for (const sec of s.sections) out.push(...flatMarks(sec.steps, kind));
|
|
3649
|
+
}
|
|
3650
|
+
return out;
|
|
3651
|
+
}
|
|
3652
|
+
function walkRows(data, m, cols, top) {
|
|
3653
|
+
const walk = new RowWalk(data, m, cols, top);
|
|
3654
|
+
walk.steps(data.steps, null);
|
|
3655
|
+
const bottom = walk.y + SEQ.rowGap;
|
|
3656
|
+
for (const [id, fallback] of walk.destroying) {
|
|
3657
|
+
const line = walk.lifeline.get(id);
|
|
3658
|
+
if (line !== void 0) line.y1 = fallback ?? bottom;
|
|
3659
|
+
}
|
|
3660
|
+
for (const [id, stack] of walk.bars) while (stack.length > 0) walk.close(id, bottom + SEQ.footer);
|
|
3661
|
+
walk.out.bottom = bottom;
|
|
3662
|
+
return walk.out;
|
|
3663
|
+
}
|
|
3664
|
+
|
|
3665
|
+
// src/sequence/layout.ts
|
|
3666
|
+
function unionRect(rects) {
|
|
3667
|
+
if (rects.length === 0) return null;
|
|
3668
|
+
const x = Math.min(...rects.map((r) => r.x));
|
|
3669
|
+
const y = Math.min(...rects.map((r) => r.y));
|
|
3670
|
+
return {
|
|
3671
|
+
x,
|
|
3672
|
+
y,
|
|
3673
|
+
width: Math.max(...rects.map((r) => r.x + r.width)) - x,
|
|
3674
|
+
height: Math.max(...rects.map((r) => r.y + r.height)) - y
|
|
3675
|
+
};
|
|
3676
|
+
}
|
|
3677
|
+
function sequenceLayout(data, opts = {}) {
|
|
3678
|
+
const m = seqMeasure(opts.measure, opts.font);
|
|
3679
|
+
const boxLabelHeight = Math.max(0, ...(data.boxes ?? []).map((b) => (b.label ?? "") === "" ? 0 : m.text(b.label).height + 4));
|
|
3680
|
+
const cols = columnsOf(data, m, SEQ.margin);
|
|
3681
|
+
const top = SEQ.margin + (data.boxes?.length ? SEQ.boxPad : 0) + boxLabelHeight;
|
|
3682
|
+
const rows = walkRows(data, m, cols, top);
|
|
3683
|
+
const columns = data.participants.map((p, i) => ({ id: p.id, x: cols.x[i] }));
|
|
3684
|
+
const foot = rows.bottom + SEQ.footer;
|
|
3685
|
+
const lifelines = rows.lifelines.map((l) => ({ ...l, y1: l.y1 ?? foot, destroyed: l.y1 !== null }));
|
|
3686
|
+
const boxes = (data.boxes ?? []).flatMap((b) => {
|
|
3687
|
+
const heads = rows.heads.filter((h) => b.members.includes(h.id)).map((h) => h.box);
|
|
3688
|
+
const around = unionRect(heads);
|
|
3689
|
+
if (around === null) return [];
|
|
3690
|
+
const label = (b.label ?? "") === "" ? null : m.text(b.label);
|
|
3691
|
+
const x = around.x - SEQ.boxPad;
|
|
3692
|
+
const width = around.width + SEQ.boxPad * 2;
|
|
3693
|
+
const y = SEQ.margin;
|
|
3694
|
+
const box = { x, y, width, height: foot + SEQ.boxPad - y };
|
|
3695
|
+
return [{ id: b.id, box, ...label ? { label: { x: x + (width - label.width) / 2, y: y + 2, ...label } } : {} }];
|
|
3696
|
+
});
|
|
3697
|
+
const all = unionRect([
|
|
3698
|
+
...rows.heads.map((h) => h.box),
|
|
3699
|
+
...rows.notes.map((n) => n.box),
|
|
3700
|
+
...rows.fragments.map((f) => f.box),
|
|
3701
|
+
...boxes.map((b) => b.box),
|
|
3702
|
+
...rows.messages.flatMap((msg) => msg.text ? [msg.text] : []),
|
|
3703
|
+
{ x: 0, y: 0, width: cols.right, height: foot }
|
|
3704
|
+
]);
|
|
3705
|
+
return {
|
|
3706
|
+
width: Math.ceil(all.x + all.width + SEQ.margin),
|
|
3707
|
+
height: Math.ceil(Math.max(foot, all.y + all.height) + SEQ.margin),
|
|
3708
|
+
columns,
|
|
3709
|
+
heads: rows.heads,
|
|
3710
|
+
lifelines,
|
|
3711
|
+
messages: rows.messages,
|
|
3712
|
+
activations: rows.activations,
|
|
3713
|
+
notes: rows.notes,
|
|
3714
|
+
fragments: rows.fragments,
|
|
3715
|
+
boxes,
|
|
3716
|
+
slots: rows.slots
|
|
3717
|
+
};
|
|
3718
|
+
}
|
|
3719
|
+
var SEQUENCE_ROLES = { note: "warning", number: "accent" };
|
|
3720
|
+
var DASH = [6, 4];
|
|
3721
|
+
var LIFELINE_DASH = [4, 4];
|
|
3722
|
+
var MARKERS = { arrow: "arrow", open: "arrow-open", cross: null, none: null };
|
|
3723
|
+
var PartSpecs = class {
|
|
3724
|
+
constructor(root, at, font) {
|
|
3725
|
+
this.root = root;
|
|
3726
|
+
this.at = at;
|
|
3727
|
+
this.font = font;
|
|
3728
|
+
}
|
|
3729
|
+
root;
|
|
3730
|
+
at;
|
|
3731
|
+
font;
|
|
3732
|
+
specs = [];
|
|
3733
|
+
place(r) {
|
|
3734
|
+
return { x: this.at.x + r.x, y: this.at.y + r.y, width: r.width, height: r.height };
|
|
3735
|
+
}
|
|
3736
|
+
push(id, seq, r, data) {
|
|
3737
|
+
this.specs.push({
|
|
3738
|
+
id: `${this.root}/${id}`,
|
|
3739
|
+
kind: "mark",
|
|
3740
|
+
layer: "main",
|
|
3741
|
+
parent: this.root,
|
|
3742
|
+
pickable: false,
|
|
3743
|
+
pose: this.place(r),
|
|
3744
|
+
data: { ...data, diagram: { ...data.diagram, seq: { root: this.root, ...seq } } }
|
|
3745
|
+
});
|
|
3746
|
+
}
|
|
3747
|
+
body(id, part, of, r, outline, style, dash) {
|
|
3748
|
+
const lines = dash ?? style.dash;
|
|
3749
|
+
this.push(id, { part, ...of !== void 0 ? { id: of } : {} }, r, {
|
|
3750
|
+
diagram: { outline },
|
|
3751
|
+
fill: { paint: { color: style.fill } },
|
|
3752
|
+
stroke: { paint: { color: style.stroke }, width: style.strokeWidth ?? 1.5, ...lines !== void 0 && lines.length > 0 ? { dash: lines } : {} }
|
|
3753
|
+
});
|
|
3754
|
+
}
|
|
3755
|
+
line(id, part, of, r, d, stroke, fill) {
|
|
3756
|
+
this.push(id, { part, ...of !== void 0 ? { id: of } : {} }, r, {
|
|
3757
|
+
diagram: { mark: { d } },
|
|
3758
|
+
stroke,
|
|
3759
|
+
...fill !== void 0 ? { fill: { paint: { color: fill } } } : {}
|
|
3760
|
+
});
|
|
3761
|
+
}
|
|
3762
|
+
/** The marks the part just pushed draws, onto its trait. */
|
|
3763
|
+
marks(refs) {
|
|
3764
|
+
const seq = this.specs.at(-1).data.diagram.seq;
|
|
3765
|
+
seq.marks = refs;
|
|
3766
|
+
}
|
|
3767
|
+
text(id, r, text, color, target, face = {}, centered = true) {
|
|
3768
|
+
const box = { ...r, x: r.x - 1, width: r.width + 2 };
|
|
3769
|
+
this.push(id, { part: "text", ...target ? { target } : {} }, box, {
|
|
3770
|
+
text,
|
|
3771
|
+
style: { ...this.font, ...centered ? { align: "center" } : {}, ...face },
|
|
3772
|
+
verticalAlign: "center",
|
|
3773
|
+
fill: { paint: { color } }
|
|
3774
|
+
});
|
|
3775
|
+
}
|
|
3776
|
+
};
|
|
3777
|
+
function participantSpecs(out, data, layout, theme) {
|
|
3778
|
+
for (const l of layout.lifelines) {
|
|
3779
|
+
const p = data.participants.find((q) => q.id === l.id);
|
|
3780
|
+
const style = withColors(roleStyle(theme, p.style), p.colors);
|
|
3781
|
+
out.line(
|
|
3782
|
+
`life:${l.id}`,
|
|
3783
|
+
"lifeline",
|
|
3784
|
+
l.id,
|
|
3785
|
+
{ x: l.x - 1, y: l.y0, width: 2, height: Math.max(l.y1 - l.y0, 0) },
|
|
3786
|
+
"M0.5 0V1",
|
|
3787
|
+
{ paint: { color: style.stroke }, width: 1, dash: LIFELINE_DASH }
|
|
3788
|
+
);
|
|
3789
|
+
if (l.destroyed) {
|
|
3790
|
+
const c = SEQ.cross;
|
|
3791
|
+
out.line(
|
|
3792
|
+
`destroy:${l.id}`,
|
|
3793
|
+
"destroy",
|
|
3794
|
+
l.id,
|
|
3795
|
+
{ x: l.x - c / 2, y: l.y1 - c / 2, width: c, height: c },
|
|
3796
|
+
"M0 0L1 1M1 0L0 1",
|
|
3797
|
+
{ paint: { color: style.stroke }, width: 2 }
|
|
3798
|
+
);
|
|
3799
|
+
if (l.destroyedBy) out.marks([{ place: l.destroyedBy }]);
|
|
3800
|
+
}
|
|
3801
|
+
}
|
|
3802
|
+
for (const [i, a] of layout.activations.entries()) {
|
|
3803
|
+
const p = data.participants.find((q) => q.id === a.participant);
|
|
3804
|
+
out.body(`act:${i}`, "activation", a.participant, a.box, "rect", withColors(roleStyle(theme, p.style), p.colors));
|
|
3805
|
+
out.marks(a.closer ? [a.opener, a.closer] : [a.opener]);
|
|
3806
|
+
}
|
|
3807
|
+
}
|
|
3808
|
+
function headSpecs(out, data, layout, theme) {
|
|
3809
|
+
for (const h of layout.heads) {
|
|
3810
|
+
const p = data.participants.find((q) => q.id === h.id);
|
|
3811
|
+
const style = withColors(roleStyle(theme, p.style), p.colors);
|
|
3812
|
+
const outline = p.outline ?? "rect";
|
|
3813
|
+
out.body(`head:${p.id}`, "head", p.id, h.box, outline, style);
|
|
3814
|
+
out.text(`head:${p.id}/text`, contentBox(outline, h.box), p.label ?? p.id, style.text, { participant: p.id });
|
|
3815
|
+
}
|
|
3816
|
+
}
|
|
3817
|
+
function messageSpecs(out, steps, layout, theme) {
|
|
3818
|
+
const byId = new Map(layout.messages.map((m) => [m.id, m]));
|
|
3819
|
+
const edge = roleEdgeStyle(theme);
|
|
3820
|
+
const width = edge.width ?? 1.5;
|
|
3821
|
+
for (const msg of flatSteps(steps)) {
|
|
3822
|
+
const at = msg.kind === "message" ? byId.get(msg.id) : void 0;
|
|
3823
|
+
if (at === void 0 || msg.kind !== "message") continue;
|
|
3824
|
+
const s = msg;
|
|
3825
|
+
const marker = MARKERS[msg.head];
|
|
3826
|
+
const stroke = {
|
|
3827
|
+
paint: { color: edge.stroke },
|
|
3828
|
+
width,
|
|
3829
|
+
...msg.line === "dashed" ? { dash: DASH } : {},
|
|
3830
|
+
...marker !== null ? { markerEnd: marker } : {},
|
|
3831
|
+
...marker !== null && msg.both ? { markerStart: marker } : {}
|
|
3832
|
+
};
|
|
3833
|
+
if (at.loopY !== void 0) {
|
|
3834
|
+
out.line(`msg:${s.id}`, "message", s.id, { x: at.x1, y: at.y, width: SEQ.loopWidth, height: at.loopY - at.y }, "M0 0H1V1H0", stroke);
|
|
3835
|
+
} else {
|
|
3836
|
+
const d = at.x2 >= at.x1 ? "M0 0H1" : "M1 0H0";
|
|
3837
|
+
out.line(`msg:${s.id}`, "message", s.id, { x: Math.min(at.x1, at.x2), y: at.y, width: Math.abs(at.x2 - at.x1), height: 0 }, d, stroke);
|
|
3838
|
+
}
|
|
3839
|
+
if (msg.head === "cross") {
|
|
3840
|
+
const c = SEQ.cross * 0.8;
|
|
3841
|
+
const end = { x: at.x2, y: at.loopY ?? at.y };
|
|
3842
|
+
out.line(
|
|
3843
|
+
`msg:${s.id}/cross`,
|
|
3844
|
+
"message",
|
|
3845
|
+
s.id,
|
|
3846
|
+
{ x: end.x - c / 2, y: end.y - c / 2, width: c, height: c },
|
|
3847
|
+
"M0 0L1 1M1 0L0 1",
|
|
3848
|
+
{ paint: { color: edge.stroke }, width }
|
|
3849
|
+
);
|
|
3850
|
+
}
|
|
3851
|
+
if (at.text) out.text(`msg:${s.id}/text`, at.text, msg.text ?? "", edge.label ?? edge.stroke, { step: s.id }, {}, msg.from !== msg.to);
|
|
3852
|
+
if (at.number) {
|
|
3853
|
+
const style = roleStyle(theme, SEQUENCE_ROLES.number);
|
|
3854
|
+
out.body(`msg:${s.id}/number`, "number", s.id, at.number.box, "ellipse", style);
|
|
3855
|
+
out.text(`msg:${s.id}/number/text`, at.number.box, String(at.number.n), style.text, void 0, { fontSize: Math.max(8, out.font.fontSize - 2) });
|
|
3856
|
+
}
|
|
3857
|
+
}
|
|
3858
|
+
}
|
|
3859
|
+
function noteSpecs(out, steps, layout, theme) {
|
|
3860
|
+
const byId = new Map(layout.notes.map((n) => [n.id, n]));
|
|
3861
|
+
const style = roleStyle(theme, SEQUENCE_ROLES.note);
|
|
3862
|
+
for (const s of flatSteps(steps)) {
|
|
3863
|
+
const at = s.kind === "note" ? byId.get(s.id) : void 0;
|
|
3864
|
+
if (at === void 0 || s.kind !== "note") continue;
|
|
3865
|
+
out.body(`note:${s.id}`, "note", s.id, at.box, "note", style);
|
|
3866
|
+
out.text(`note:${s.id}/text`, contentBox("note", at.box), s.text, style.text, { step: s.id });
|
|
3867
|
+
}
|
|
3868
|
+
}
|
|
3869
|
+
function fragmentSpecs(out, steps, layout, theme, boxesOnly) {
|
|
3870
|
+
const byId = new Map(layout.fragments.map((f) => [f.id, f]));
|
|
3871
|
+
for (const s of flatSteps(steps)) {
|
|
3872
|
+
const at = s.kind === "fragment" ? byId.get(s.id) : void 0;
|
|
3873
|
+
if (at === void 0 || s.kind !== "fragment") continue;
|
|
3874
|
+
const style = withColors({ ...theme.container, ...s.type === "region" ? {} : { fill: "transparent" } }, s.colors);
|
|
3875
|
+
if (boxesOnly) {
|
|
3876
|
+
out.body(`frag:${s.id}`, "fragment", s.id, at.box, "rect", { ...style, strokeWidth: 1 }, []);
|
|
3877
|
+
continue;
|
|
3878
|
+
}
|
|
3879
|
+
at.sections.forEach((sec, k) => {
|
|
3880
|
+
if (k > 0) {
|
|
3881
|
+
out.line(
|
|
3882
|
+
`frag:${s.id}/divider:${k}`,
|
|
3883
|
+
"divider",
|
|
3884
|
+
s.id,
|
|
3885
|
+
{ x: at.box.x, y: sec.y, width: at.box.width, height: 0 },
|
|
3886
|
+
"M0 0H1",
|
|
3887
|
+
{ paint: { color: style.stroke }, width: 1, dash: DASH }
|
|
3888
|
+
);
|
|
3889
|
+
}
|
|
3890
|
+
if (sec.label) out.text(`frag:${s.id}/label:${k}`, sec.label, s.sections[k].label ?? "", style.text, { fragment: s.id, section: k });
|
|
3891
|
+
});
|
|
3892
|
+
if (at.tab) {
|
|
3893
|
+
out.line(`frag:${s.id}/tab`, "fragment", s.id, at.tab, "M0 0H1V0.6L0.85 1H0Z", { paint: { color: style.stroke }, width: 1 }, theme.container.fill);
|
|
3894
|
+
out.text(`frag:${s.id}/type`, at.tab, s.type, style.text, void 0, { fontWeight: 700 });
|
|
3895
|
+
}
|
|
3896
|
+
}
|
|
3897
|
+
}
|
|
3898
|
+
function boxSpecs(out, data, layout, theme) {
|
|
3899
|
+
for (const b of layout.boxes) {
|
|
3900
|
+
const own = data.boxes?.find((q) => q.id === b.id);
|
|
3901
|
+
const style = withColors(theme.container, own?.colors);
|
|
3902
|
+
out.body(`box:${b.id}`, "box", b.id, b.box, "rect", { ...style, strokeWidth: 1 }, []);
|
|
3903
|
+
if (b.label) out.text(`box:${b.id}/text`, b.label, own?.label ?? "", style.text, { box: b.id });
|
|
3904
|
+
}
|
|
3905
|
+
}
|
|
3906
|
+
var geometryOf = (layout) => ({
|
|
3907
|
+
columns: layout.columns,
|
|
3908
|
+
slots: layout.slots,
|
|
3909
|
+
messages: layout.messages,
|
|
3910
|
+
notes: layout.notes,
|
|
3911
|
+
heads: layout.heads.map(({ id, box }) => ({ id, box })),
|
|
3912
|
+
fragments: layout.fragments.map(({ id, box, tab }) => ({ id, grip: tab ?? { ...box, height: Math.min(box.height, SEQ.rowGap) } })),
|
|
3913
|
+
boxes: layout.boxes.map(({ id, box, label }) => ({ id, grip: { ...box, height: (label?.height ?? 0) + SEQ.boxPad } })),
|
|
3914
|
+
marks: [
|
|
3915
|
+
...layout.activations.map((a, i) => ({ id: `act:${i}`, grip: a.box })),
|
|
3916
|
+
...layout.lifelines.flatMap((l) => l.destroyedBy === void 0 ? [] : [{ id: `destroy:${l.id}`, grip: crossGrip(l.x, l.y1) }])
|
|
3917
|
+
]
|
|
3918
|
+
});
|
|
3919
|
+
var crossGrip = (x, y) => {
|
|
3920
|
+
const c = Math.max(SEQ.cross, 12);
|
|
3921
|
+
return { x: x - c / 2, y: y - c / 2, width: c, height: c };
|
|
3922
|
+
};
|
|
3923
|
+
function sequenceSpecs(data, opts) {
|
|
3924
|
+
const theme = opts.theme ?? diagramThemeFrom(void 0);
|
|
3925
|
+
const font = opts.font ?? themeFont(theme);
|
|
3926
|
+
const layout = sequenceLayout(data, { font, ...opts.measure ? { measure: opts.measure } : {} });
|
|
3927
|
+
const at = opts.at ?? { x: 0, y: 0 };
|
|
3928
|
+
const out = new PartSpecs(opts.id, at, font);
|
|
3929
|
+
out.specs.push({
|
|
3930
|
+
id: opts.id,
|
|
3931
|
+
kind: "mark",
|
|
3932
|
+
layer: "main",
|
|
3933
|
+
pose: out.place({ x: 0, y: 0, width: layout.width, height: layout.height }),
|
|
3934
|
+
data: { diagram: { sequence: data, geometry: geometryOf(layout) } }
|
|
3935
|
+
});
|
|
3936
|
+
boxSpecs(out, data, layout, theme);
|
|
3937
|
+
fragmentSpecs(out, data.steps, layout, theme, true);
|
|
3938
|
+
participantSpecs(out, data, layout, theme);
|
|
3939
|
+
messageSpecs(out, data.steps, layout, theme);
|
|
3940
|
+
noteSpecs(out, data.steps, layout, theme);
|
|
3941
|
+
headSpecs(out, data, layout, theme);
|
|
3942
|
+
fragmentSpecs(out, data.steps, layout, theme, false);
|
|
3943
|
+
const layer = opts.layer ?? "main";
|
|
3944
|
+
return localizeWorldPoses(out.specs, opts.composition ?? RIGID_POSE_COMPOSITION).map((s) => ({ ...s, layer }));
|
|
3945
|
+
}
|
|
3946
|
+
var worldPose = (scene, id) => composeWorldPose(scenePoseAdapter(scene), id, scene.composition.compose);
|
|
3947
|
+
function rebuild(scene, id, data, opts) {
|
|
3948
|
+
const root = scene.get(id);
|
|
3949
|
+
const at = worldPose(scene, id);
|
|
3950
|
+
const [own, ...parts] = sequenceSpecs(data, {
|
|
3951
|
+
id,
|
|
3952
|
+
at,
|
|
3953
|
+
theme: opts.theme ?? diagramThemeOf(scene),
|
|
3954
|
+
layer: root.layer,
|
|
3955
|
+
composition: scene.composition,
|
|
3956
|
+
...opts.measure ? { measure: opts.measure } : {}
|
|
3957
|
+
});
|
|
3958
|
+
const selected = scene.getSelection();
|
|
3959
|
+
scene.removeMany([...scene.childrenOf(id)]);
|
|
3960
|
+
const pose = root.pose;
|
|
3961
|
+
scene.update(id, { data: own.data });
|
|
3962
|
+
scene.setPose(id, { ...pose, width: own.pose.width, height: own.pose.height });
|
|
3963
|
+
for (const part of parts) scene.add(part);
|
|
3964
|
+
const kept = selected.filter((s) => scene.get(s) !== void 0);
|
|
3965
|
+
if (kept.length !== scene.getSelection().length) scene.setSelection(kept);
|
|
3966
|
+
}
|
|
3967
|
+
function commitSequence(scene, id, data, label, opts = {}) {
|
|
3968
|
+
const node = scene.get(id);
|
|
3969
|
+
if (node === void 0 || sequenceRootOf(node) === null) return;
|
|
3970
|
+
scene.batch(label, () => rebuild(scene, id, data, opts));
|
|
3971
|
+
}
|
|
3972
|
+
function startSequence(scene, at, data, label, opts = {}) {
|
|
3973
|
+
const id = scene.mintId();
|
|
3974
|
+
const layer = opts.layer ?? scene.layers[0]?.id ?? "main";
|
|
3975
|
+
const specs = sequenceSpecs(data, {
|
|
3976
|
+
id,
|
|
3977
|
+
at,
|
|
3978
|
+
theme: opts.theme ?? diagramThemeOf(scene),
|
|
3979
|
+
layer,
|
|
3980
|
+
composition: scene.composition,
|
|
3981
|
+
...opts.measure ? { measure: opts.measure } : {}
|
|
3982
|
+
});
|
|
3983
|
+
scene.batch(label, () => {
|
|
3984
|
+
for (const spec of specs) scene.add(spec);
|
|
3985
|
+
});
|
|
3986
|
+
return id;
|
|
3987
|
+
}
|
|
3988
|
+
function redrawSequences(scene, opts = {}) {
|
|
3989
|
+
for (const node of scene.renderOrderNodes()) {
|
|
3990
|
+
const root = sequenceRootOf(node);
|
|
3991
|
+
if (root !== null) rebuild(scene, node.id, root.sequence, opts);
|
|
3992
|
+
}
|
|
3993
|
+
}
|
|
3994
|
+
function foldSequenceText(scene, textId, commit) {
|
|
3995
|
+
const node = scene.get(textId);
|
|
3996
|
+
const part = node === void 0 ? null : sequencePartOf(node);
|
|
3997
|
+
const root = part === null ? void 0 : scene.get(part.root);
|
|
3998
|
+
const held = root === void 0 ? null : sequenceRootOf(root);
|
|
3999
|
+
if (part === null || held === null || part.target === void 0) return;
|
|
4000
|
+
const text = node.data.text;
|
|
4001
|
+
if (typeof text !== "string") return;
|
|
4002
|
+
const next = setSequenceText(held.sequence, part.target, text);
|
|
4003
|
+
if (next === held.sequence) return;
|
|
4004
|
+
scene.undo();
|
|
4005
|
+
commit({ id: part.root, data: next, label: "Edit text" });
|
|
4006
|
+
}
|
|
4007
|
+
function sequenceCommitOf(opts) {
|
|
4008
|
+
return opts.commit ?? ((edit, ctx) => {
|
|
4009
|
+
const scene = ctx.deps.scene;
|
|
4010
|
+
if (scene !== void 0) commitSequence(scene, edit.id, edit.data, edit.label, opts);
|
|
4011
|
+
});
|
|
4012
|
+
}
|
|
4013
|
+
|
|
4014
|
+
// src/sequence/author.ts
|
|
4015
|
+
function idsOf(data) {
|
|
4016
|
+
const ids = new Set(data.participants.map((p) => p.id));
|
|
4017
|
+
for (const s of flatSteps(data.steps)) if (hasId(s)) ids.add(s.id);
|
|
4018
|
+
for (const b of data.boxes ?? []) ids.add(b.id);
|
|
4019
|
+
return ids;
|
|
4020
|
+
}
|
|
4021
|
+
var seqIdTaken = (data, id) => idsOf(data).has(id);
|
|
4022
|
+
function freshSeqId(data, prefix) {
|
|
4023
|
+
const ids = idsOf(data);
|
|
4024
|
+
let n = 1;
|
|
4025
|
+
while (ids.has(`${prefix}${n}`)) n++;
|
|
4026
|
+
return `${prefix}${n}`;
|
|
4027
|
+
}
|
|
4028
|
+
function newParticipant(data, kind = "participant") {
|
|
4029
|
+
const id = freshSeqId(data, kind === "actor" ? "A" : "P");
|
|
4030
|
+
const label = `${kind === "actor" ? "Actor" : "Participant"} ${id.slice(1)}`;
|
|
4031
|
+
return { id, label, ...kind === "actor" ? { outline: "actor" } : {} };
|
|
4032
|
+
}
|
|
4033
|
+
function addParticipant(data, p, index = data.participants.length) {
|
|
4034
|
+
if (seqIdTaken(data, p.id)) return data;
|
|
4035
|
+
const at = Math.max(0, Math.min(index, data.participants.length));
|
|
4036
|
+
return { ...data, participants: [...data.participants.slice(0, at), p, ...data.participants.slice(at)] };
|
|
4037
|
+
}
|
|
4038
|
+
function removeParticipant(data, id) {
|
|
4039
|
+
if (!data.participants.some((p) => p.id === id)) return data;
|
|
4040
|
+
const steps = pruneSteps(data.steps, (s) => {
|
|
4041
|
+
if (s.kind === "message") return s.from === id || s.to === id ? null : s;
|
|
4042
|
+
if (s.kind === "note") {
|
|
4043
|
+
if (!s.over.includes(id)) return s;
|
|
4044
|
+
const over = s.over.filter((q) => q !== id);
|
|
4045
|
+
return over.length === 0 ? null : { ...s, over };
|
|
4046
|
+
}
|
|
4047
|
+
if (s.kind === "fragment") return s;
|
|
4048
|
+
return s.participant === id ? null : s;
|
|
4049
|
+
});
|
|
4050
|
+
const boxes = data.boxes?.flatMap((b) => {
|
|
4051
|
+
if (!b.members.includes(id)) return [b];
|
|
4052
|
+
const members2 = b.members.filter((m) => m !== id);
|
|
4053
|
+
return members2.length === 0 ? [] : [{ ...b, members: members2 }];
|
|
4054
|
+
});
|
|
4055
|
+
const { boxes: _boxes, ...rest } = data;
|
|
4056
|
+
return {
|
|
4057
|
+
...rest,
|
|
4058
|
+
participants: data.participants.filter((p) => p.id !== id),
|
|
4059
|
+
steps,
|
|
4060
|
+
...boxes !== void 0 && boxes.length > 0 ? { boxes } : {}
|
|
4061
|
+
};
|
|
4062
|
+
}
|
|
4063
|
+
function setParticipantOutline(data, id, outline) {
|
|
4064
|
+
const at = data.participants.findIndex((p2) => p2.id === id);
|
|
4065
|
+
const p = data.participants[at];
|
|
4066
|
+
const next = outline === "rect" ? void 0 : outline;
|
|
4067
|
+
if (p === void 0 || p.outline === next) return data;
|
|
4068
|
+
const { outline: _outline, ...rest } = p;
|
|
4069
|
+
const q = next === void 0 ? rest : { ...rest, outline: next };
|
|
4070
|
+
return { ...data, participants: data.participants.map((r, i) => i === at ? q : r) };
|
|
4071
|
+
}
|
|
4072
|
+
function addBox(data, box) {
|
|
4073
|
+
const members2 = data.participants.filter((p) => box.members.includes(p.id));
|
|
4074
|
+
if (members2.length === 0 || seqIdTaken(data, box.id)) return data;
|
|
4075
|
+
const taken = new Set(members2.map((p) => p.id));
|
|
4076
|
+
const first = data.participants.findIndex((p) => taken.has(p.id));
|
|
4077
|
+
const before = data.participants.slice(0, first).filter((p) => !taken.has(p.id));
|
|
4078
|
+
const after = data.participants.slice(first).filter((p) => !taken.has(p.id));
|
|
4079
|
+
const others = (data.boxes ?? []).flatMap((b) => {
|
|
4080
|
+
const left = b.members.filter((m) => !taken.has(m));
|
|
4081
|
+
return left.length === 0 ? [] : [left.length === b.members.length ? b : { ...b, members: left }];
|
|
4082
|
+
});
|
|
4083
|
+
return {
|
|
4084
|
+
...data,
|
|
4085
|
+
participants: [...before, ...members2, ...after],
|
|
4086
|
+
boxes: [...others, { ...box, members: members2.map((p) => p.id) }]
|
|
4087
|
+
};
|
|
4088
|
+
}
|
|
4089
|
+
function removeBox(data, id) {
|
|
4090
|
+
if (!data.boxes?.some((b) => b.id === id)) return data;
|
|
4091
|
+
const boxes = data.boxes.filter((b) => b.id !== id);
|
|
4092
|
+
const { boxes: _boxes, ...rest } = data;
|
|
4093
|
+
return boxes.length === 0 ? rest : { ...rest, boxes };
|
|
4094
|
+
}
|
|
4095
|
+
function setAutonumber(data, from) {
|
|
4096
|
+
if (data.autonumber === from) return data;
|
|
4097
|
+
const { autonumber: _n, ...rest } = data;
|
|
4098
|
+
return from === void 0 ? rest : { ...rest, autonumber: from };
|
|
4099
|
+
}
|
|
4100
|
+
|
|
4101
|
+
// src/sequence/authorSteps.ts
|
|
4102
|
+
var SEQ_ARROWS = {
|
|
4103
|
+
/** A call: a solid line, a filled head. */
|
|
4104
|
+
sync: { line: "solid", head: "arrow" },
|
|
4105
|
+
/** An answer: a dashed line, a filled head. */
|
|
4106
|
+
reply: { line: "dashed", head: "arrow" },
|
|
4107
|
+
/** Sent without waiting: a solid line, an open head. */
|
|
4108
|
+
async: { line: "solid", head: "open", async: true },
|
|
4109
|
+
/** Lost or refused: a solid line ending in a cross. */
|
|
4110
|
+
lost: { line: "solid", head: "cross" },
|
|
4111
|
+
/** A plain solid line. */
|
|
4112
|
+
line: { line: "solid", head: "none" },
|
|
4113
|
+
/** A plain dashed line. */
|
|
4114
|
+
dashed: { line: "dashed", head: "none" },
|
|
4115
|
+
/** Both ways: a solid line, filled heads at both ends. */
|
|
4116
|
+
both: { line: "solid", head: "arrow", both: true }
|
|
4117
|
+
};
|
|
4118
|
+
var SEQ_MULTI_SECTION = /* @__PURE__ */ new Set(["alt", "par", "critical"]);
|
|
4119
|
+
function insertStep(data, step, at) {
|
|
4120
|
+
const list = stepListOf(data.steps, at.parent);
|
|
4121
|
+
if (list === null || hasId(step) && seqIdTaken(data, step.id)) return data;
|
|
4122
|
+
const index = Math.max(0, Math.min(at.index, list.length));
|
|
4123
|
+
return { ...data, steps: withList(data.steps, at.parent, (l) => [...l.slice(0, index), step, ...l.slice(index)]) };
|
|
4124
|
+
}
|
|
4125
|
+
var known = (data, ...ids) => ids.every((id) => data.participants.some((p) => p.id === id));
|
|
4126
|
+
function insertMessage(data, m) {
|
|
4127
|
+
if (!known(data, m.from, m.to)) return data;
|
|
4128
|
+
const arrow = typeof m.arrow === "object" ? m.arrow : SEQ_ARROWS[m.arrow ?? "sync"];
|
|
4129
|
+
const step = {
|
|
4130
|
+
kind: "message",
|
|
4131
|
+
id: m.id ?? freshSeqId(data, "m"),
|
|
4132
|
+
from: m.from,
|
|
4133
|
+
to: m.to,
|
|
4134
|
+
...arrow,
|
|
4135
|
+
...m.text ? { text: m.text } : {}
|
|
4136
|
+
};
|
|
4137
|
+
return insertStep(data, step, m.at);
|
|
4138
|
+
}
|
|
4139
|
+
function insertNote(data, n) {
|
|
4140
|
+
if (n.over.length === 0 || !known(data, ...n.over)) return data;
|
|
4141
|
+
const step = {
|
|
4142
|
+
kind: "note",
|
|
4143
|
+
id: n.id ?? freshSeqId(data, "n"),
|
|
4144
|
+
over: n.side === void 0 ? [...n.over] : [n.over[0]],
|
|
4145
|
+
...n.side ? { side: n.side } : {},
|
|
4146
|
+
text: n.text ?? "Note"
|
|
4147
|
+
};
|
|
4148
|
+
return insertStep(data, step, n.at);
|
|
4149
|
+
}
|
|
4150
|
+
function insertMark(data, mark, at) {
|
|
4151
|
+
if (!known(data, mark.participant)) return data;
|
|
4152
|
+
if (mark.kind === "create" && hasMark(data.steps, "create", mark.participant)) return data;
|
|
4153
|
+
return insertStep(data, { kind: mark.kind, participant: mark.participant }, at);
|
|
4154
|
+
}
|
|
4155
|
+
function hasMark(steps, kind, participant) {
|
|
4156
|
+
return steps.some((s) => s.kind === kind && s.participant === participant || s.kind === "fragment" && s.sections.some((sec) => hasMark(sec.steps, kind, participant)));
|
|
4157
|
+
}
|
|
4158
|
+
function removeStep(data, id) {
|
|
4159
|
+
if (findStep(data.steps, id) === null) return data;
|
|
4160
|
+
return { ...data, steps: pruneSteps(data.steps, (s) => hasId(s) && s.id === id ? null : s) };
|
|
4161
|
+
}
|
|
4162
|
+
function removeStepAt(data, at) {
|
|
4163
|
+
const list = stepListOf(data.steps, at.parent);
|
|
4164
|
+
if (list === null || at.index < 0 || at.index >= list.length) return data;
|
|
4165
|
+
return { ...data, steps: withList(data.steps, at.parent, (l) => l.filter((_, i) => i !== at.index)) };
|
|
4166
|
+
}
|
|
4167
|
+
function removeMarks(data, refs) {
|
|
4168
|
+
const key = (p) => p === null ? "" : `${p.fragment}/${p.section}`;
|
|
4169
|
+
const places = refs.flatMap((r) => "place" in r ? [r.place] : []).filter((p) => {
|
|
4170
|
+
const s = stepListOf(data.steps, p.parent)?.[p.index];
|
|
4171
|
+
return s !== void 0 && !hasId(s);
|
|
4172
|
+
}).sort((a, b) => key(a.parent) === key(b.parent) ? b.index - a.index : key(a.parent) < key(b.parent) ? -1 : 1);
|
|
4173
|
+
let next = places.reduce((d, p) => removeStepAt(d, p), data);
|
|
4174
|
+
for (const r of refs) if ("message" in r) next = setMessageActivation(next, r.message, { [r.flag]: void 0 });
|
|
4175
|
+
return next;
|
|
4176
|
+
}
|
|
4177
|
+
function removeMarksOf(data, kind, participant) {
|
|
4178
|
+
const steps = pruneSteps(data.steps, (s) => s.kind === kind && s.participant === participant ? null : s);
|
|
4179
|
+
return steps === data.steps ? data : { ...data, steps };
|
|
4180
|
+
}
|
|
4181
|
+
function wrapSteps(data, parent, start, end, f) {
|
|
4182
|
+
const list = stepListOf(data.steps, parent);
|
|
4183
|
+
const id = f.id ?? freshSeqId(data, "f");
|
|
4184
|
+
if (list === null || seqIdTaken(data, id)) return data;
|
|
4185
|
+
const lo = Math.max(0, Math.min(start, end, list.length));
|
|
4186
|
+
const hi = Math.max(lo, Math.min(Math.max(start, end), list.length));
|
|
4187
|
+
const frag = {
|
|
4188
|
+
kind: "fragment",
|
|
4189
|
+
id,
|
|
4190
|
+
type: f.type,
|
|
4191
|
+
sections: [{ ...f.label ? { label: f.label } : {}, steps: list.slice(lo, hi) }]
|
|
4192
|
+
};
|
|
4193
|
+
return { ...data, steps: withList(data.steps, parent, (l) => [...l.slice(0, lo), frag, ...l.slice(hi)]) };
|
|
4194
|
+
}
|
|
4195
|
+
function unwrapFragment(data, id) {
|
|
4196
|
+
const place2 = placeOf(data.steps, id);
|
|
4197
|
+
const frag = findStep(data.steps, id);
|
|
4198
|
+
if (place2 === null || frag?.kind !== "fragment") return data;
|
|
4199
|
+
const inner = frag.sections.flatMap((sec) => sec.steps);
|
|
4200
|
+
return { ...data, steps: withList(data.steps, place2.parent, (l) => [...l.slice(0, place2.index), ...inner, ...l.slice(place2.index + 1)]) };
|
|
4201
|
+
}
|
|
4202
|
+
function withFragment(data, id, fn) {
|
|
4203
|
+
const steps = mapSteps(data.steps, (s) => s.kind === "fragment" && s.id === id ? fn(s) : s);
|
|
4204
|
+
return steps === data.steps ? data : { ...data, steps };
|
|
4205
|
+
}
|
|
4206
|
+
function addSection(data, id, label, index) {
|
|
4207
|
+
return withFragment(data, id, (f) => {
|
|
4208
|
+
if (!SEQ_MULTI_SECTION.has(f.type)) return f;
|
|
4209
|
+
const at = Math.max(1, Math.min(index ?? f.sections.length, f.sections.length));
|
|
4210
|
+
const section = { ...label ? { label } : {}, steps: [] };
|
|
4211
|
+
return { ...f, sections: [...f.sections.slice(0, at), section, ...f.sections.slice(at)] };
|
|
4212
|
+
});
|
|
4213
|
+
}
|
|
4214
|
+
function removeSection(data, id, index) {
|
|
4215
|
+
return withFragment(data, id, (f) => f.sections.length < 2 || f.sections[index] === void 0 ? f : { ...f, sections: f.sections.filter((_, k) => k !== index) });
|
|
4216
|
+
}
|
|
4217
|
+
function setFragmentType(data, id, type) {
|
|
4218
|
+
return withFragment(data, id, (f) => f.type === type || f.sections.length > 1 && !SEQ_MULTI_SECTION.has(type) ? f : { ...f, type });
|
|
4219
|
+
}
|
|
4220
|
+
function withMessage(data, id, fn) {
|
|
4221
|
+
const steps = mapSteps(data.steps, (s) => s.kind === "message" && s.id === id ? fn(s) : s);
|
|
4222
|
+
return steps === data.steps ? data : { ...data, steps };
|
|
4223
|
+
}
|
|
4224
|
+
function setMessageArrow(data, id, arrow) {
|
|
4225
|
+
const next = typeof arrow === "object" ? arrow : SEQ_ARROWS[arrow];
|
|
4226
|
+
return withMessage(data, id, (m) => {
|
|
4227
|
+
if (m.line === next.line && m.head === next.head && m.both === next.both && m.async === next.async) return m;
|
|
4228
|
+
const { both: _both, async: _async, ...rest } = m;
|
|
4229
|
+
return { ...rest, line: next.line, head: next.head, ...next.both ? { both: true } : {}, ...next.async ? { async: true } : {} };
|
|
4230
|
+
});
|
|
4231
|
+
}
|
|
4232
|
+
function setMessageActivation(data, id, flags) {
|
|
4233
|
+
return withMessage(data, id, (m) => {
|
|
4234
|
+
const activate = "activate" in flags ? flags.activate : m.activate;
|
|
4235
|
+
const deactivate = "deactivate" in flags ? flags.deactivate : m.deactivate;
|
|
4236
|
+
if (activate === m.activate && deactivate === m.deactivate) return m;
|
|
4237
|
+
const { activate: _a, deactivate: _d, ...rest } = m;
|
|
4238
|
+
return { ...rest, ...activate ? { activate } : {}, ...deactivate ? { deactivate } : {} };
|
|
4239
|
+
});
|
|
4240
|
+
}
|
|
4241
|
+
var SEQUENCE_LAYER_ID = "diagram-sequence";
|
|
4242
|
+
var SEQUENCE_AFFORDANCE_KIND = `layer:${SEQUENCE_LAYER_ID}`;
|
|
4243
|
+
function sequenceScratchOf(hit) {
|
|
4244
|
+
const p = hit?.payload;
|
|
4245
|
+
return p !== void 0 && typeof p.root === "string" && typeof p.id === "string" && typeof p.part === "string" ? p : null;
|
|
4246
|
+
}
|
|
4247
|
+
function placedSequences(scene) {
|
|
4248
|
+
const out = [];
|
|
4249
|
+
const poses = scenePoseAdapter(scene);
|
|
4250
|
+
for (const node of scene.renderOrderNodes()) {
|
|
4251
|
+
const root = sequenceRootOf(node);
|
|
4252
|
+
if (root === null || scene.isLocked(node.id) || scene.isHidden(node.id)) continue;
|
|
4253
|
+
const at = composeWorldPose(poses, node.id, scene.composition.compose);
|
|
4254
|
+
out.push({ id: node.id, origin: { x: at.x, y: at.y }, width: at.width, height: at.height, geometry: root.geometry });
|
|
4255
|
+
}
|
|
4256
|
+
return out;
|
|
4257
|
+
}
|
|
4258
|
+
var REACH = 6;
|
|
4259
|
+
var END = 7;
|
|
4260
|
+
var moved = (r, o) => ({ x: r.x + o.x, y: r.y + o.y, width: r.width, height: r.height });
|
|
4261
|
+
function messageReach(m) {
|
|
4262
|
+
const x0 = Math.min(m.x1, m.x2);
|
|
4263
|
+
const x1 = m.loopY !== void 0 ? m.x1 + 32 : Math.max(m.x1, m.x2);
|
|
4264
|
+
const y1 = (m.loopY ?? m.y) + REACH;
|
|
4265
|
+
const top = Math.min(m.y - REACH, m.text?.y ?? Infinity);
|
|
4266
|
+
const left = Math.min(x0, m.text?.x ?? Infinity);
|
|
4267
|
+
const right = Math.max(x1, m.text ? m.text.x + m.text.width : -Infinity);
|
|
4268
|
+
return { x: left, y: top, width: right - left, height: y1 - top };
|
|
4269
|
+
}
|
|
4270
|
+
function region(id, r, scratch, cursor) {
|
|
4271
|
+
return {
|
|
4272
|
+
id,
|
|
4273
|
+
targetId: null,
|
|
4274
|
+
shape: { kind: "rect", x: r.x, y: r.y, width: r.width, height: r.height },
|
|
4275
|
+
cursor,
|
|
4276
|
+
strength: "exclusive",
|
|
4277
|
+
claimedKinds: ["pointer"],
|
|
4278
|
+
bind: () => ({ initialScratch: scratch })
|
|
4279
|
+
};
|
|
4280
|
+
}
|
|
4281
|
+
function regionsOf(all) {
|
|
4282
|
+
const parts = [];
|
|
4283
|
+
const ends = [];
|
|
4284
|
+
for (const { id: root, origin, geometry } of all) {
|
|
4285
|
+
const base = { targetId: root, root };
|
|
4286
|
+
for (const h of geometry.heads) parts.push(region(`${root}/head:${h.id}`, moved(h.box, origin), { ...base, part: "head", id: h.id }, "ew-resize"));
|
|
4287
|
+
for (const m of geometry.marks ?? []) parts.push(region(`${root}/${m.id}`, moved(m.grip, origin), { ...base, part: "mark", id: m.id }, "default"));
|
|
4288
|
+
for (const b of geometry.boxes ?? []) parts.push(region(`${root}/box:${b.id}`, moved(b.grip, origin), { ...base, part: "box", id: b.id }, "default"));
|
|
4289
|
+
for (const f of geometry.fragments ?? []) parts.push(region(`${root}/frag:${f.id}`, moved(f.grip, origin), { ...base, part: "step", id: f.id }, "ns-resize"));
|
|
4290
|
+
for (const n of geometry.notes) parts.push(region(`${root}/note:${n.id}`, moved(n.box, origin), { ...base, part: "step", id: n.id }, "ns-resize"));
|
|
4291
|
+
for (const m of geometry.messages) {
|
|
4292
|
+
parts.push(region(`${root}/msg:${m.id}`, moved(messageReach(m), origin), { ...base, part: "step", id: m.id }, "ns-resize"));
|
|
4293
|
+
const at = [["from", m.x1, m.y], ["to", m.x2, m.loopY ?? m.y]];
|
|
4294
|
+
for (const [end, x, y] of at) {
|
|
4295
|
+
const r = { x: x - END + origin.x, y: y - END + origin.y, width: END * 2, height: END * 2 };
|
|
4296
|
+
ends.push(region(`${root}/msg:${m.id}/${end}`, r, { ...base, part: "end", id: m.id, end }, "crosshair"));
|
|
4297
|
+
}
|
|
4298
|
+
}
|
|
4299
|
+
}
|
|
4300
|
+
return { parts, ends };
|
|
4301
|
+
}
|
|
4302
|
+
var INDEXES = /* @__PURE__ */ new WeakMap();
|
|
4303
|
+
function regionsIn(scene) {
|
|
4304
|
+
let index = INDEXES.get(scene);
|
|
4305
|
+
if (index === void 0) {
|
|
4306
|
+
index = keyedIndex(
|
|
4307
|
+
() => typeof scene.getVersion === "function" ? [scene.getVersion()] : void 0,
|
|
4308
|
+
() => regionsOf(placedSequences(scene))
|
|
4309
|
+
);
|
|
4310
|
+
INDEXES.set(scene, index);
|
|
4311
|
+
}
|
|
4312
|
+
return index() ?? regionsOf(placedSequences(scene));
|
|
4313
|
+
}
|
|
4314
|
+
function sequenceLayer(scene) {
|
|
4315
|
+
const parts = { id: SEQUENCE_LAYER_ID, regions: () => regionsIn(scene).parts };
|
|
4316
|
+
const ends = { id: `${SEQUENCE_LAYER_ID}-ends`, regions: () => regionsIn(scene).ends };
|
|
4317
|
+
return composeAffordanceLayer(SEQUENCE_LAYER_ID, "Sequence diagram parts", [parts, ends]);
|
|
4318
|
+
}
|
|
4319
|
+
var SELECT_SEQUENCE_PART_ACTION_ID = "diagram.sequence.select";
|
|
4320
|
+
function sequencePartNodeOf(scene, s) {
|
|
4321
|
+
if (s.part === "mark") return scene.get(`${s.root}/${s.id}`) === void 0 ? null : `${s.root}/${s.id}`;
|
|
4322
|
+
const names = s.part === "head" ? [`head:${s.id}`] : s.part === "box" ? [`box:${s.id}`] : s.part === "end" ? [`msg:${s.id}`] : [`msg:${s.id}`, `note:${s.id}`, `frag:${s.id}`];
|
|
4323
|
+
return names.map((n) => `${s.root}/${n}`).find((id) => scene.get(id) !== void 0) ?? null;
|
|
4324
|
+
}
|
|
4325
|
+
var selectSequencePartAction = {
|
|
4326
|
+
id: SELECT_SEQUENCE_PART_ACTION_ID,
|
|
4327
|
+
label: "Select sequence part",
|
|
4328
|
+
group: "diagram",
|
|
4329
|
+
requires: ["scene", "selection"],
|
|
4330
|
+
invoker: {
|
|
4331
|
+
timing: "immediate",
|
|
4332
|
+
run(deps, params) {
|
|
4333
|
+
const scene = deps.scene;
|
|
4334
|
+
const selection = deps.selection;
|
|
4335
|
+
const scratch = sequenceScratchOf(params?.affordance);
|
|
4336
|
+
const id = scene === void 0 || scratch === null ? null : sequencePartNodeOf(scene, scratch);
|
|
4337
|
+
if (id === null || selection === void 0) return;
|
|
4338
|
+
const held = selection.get();
|
|
4339
|
+
const shift = params?.mods?.shift === true;
|
|
4340
|
+
selection.set(!shift ? [id] : held.includes(id) ? held.filter((h) => h !== id) : [...held, id]);
|
|
4341
|
+
}
|
|
4342
|
+
},
|
|
4343
|
+
enabled: () => true
|
|
4344
|
+
};
|
|
4345
|
+
function removing(data, part) {
|
|
4346
|
+
if (part.part === "head" || part.part === "lifeline") return removeParticipant(data, part.id);
|
|
4347
|
+
if (part.part === "box") return removeBox(data, part.id);
|
|
4348
|
+
if (part.part === "message" || part.part === "note" || part.part === "fragment" || part.part === "divider") return removeStep(data, part.id);
|
|
4349
|
+
return data;
|
|
4350
|
+
}
|
|
4351
|
+
function sequenceDeletes(scene, ids) {
|
|
4352
|
+
const byRoot = /* @__PURE__ */ new Map();
|
|
4353
|
+
const rest = [];
|
|
4354
|
+
for (const id of ids) {
|
|
4355
|
+
const node = scene.get(id);
|
|
4356
|
+
const part = node === void 0 ? null : sequencePartOf(node);
|
|
4357
|
+
if (part === null) {
|
|
4358
|
+
rest.push(id);
|
|
4359
|
+
continue;
|
|
4360
|
+
}
|
|
4361
|
+
const root = scene.get(part.root);
|
|
4362
|
+
const held = root === void 0 ? null : sequenceRootOf(root);
|
|
4363
|
+
if (held === null) continue;
|
|
4364
|
+
const at = byRoot.get(part.root) ?? { was: held.sequence, marks: [], parts: [] };
|
|
4365
|
+
byRoot.set(part.root, at);
|
|
4366
|
+
if (part.marks !== void 0) at.marks.push(...part.marks);
|
|
4367
|
+
else if (part.id !== void 0) at.parts.push({ part: part.part, id: part.id });
|
|
4368
|
+
}
|
|
4369
|
+
const edits = [...byRoot].flatMap(([id, { was, marks, parts }]) => {
|
|
4370
|
+
const data = parts.reduce(removing, removeMarks(was, marks));
|
|
4371
|
+
return data === was ? [] : [{ id, data }];
|
|
4372
|
+
});
|
|
4373
|
+
return { edits, rest };
|
|
4374
|
+
}
|
|
4375
|
+
function createSequenceDeleteAction(opts = {}) {
|
|
4376
|
+
const commit = sequenceCommitOf(opts);
|
|
4377
|
+
const others = opts.others ?? commitDeleteToScene;
|
|
4378
|
+
return createDeleteAction({
|
|
4379
|
+
commit: (ids, deps) => {
|
|
4380
|
+
const scene = deps.scene;
|
|
4381
|
+
if (scene === void 0) return;
|
|
4382
|
+
const { edits, rest } = sequenceDeletes(scene, ids);
|
|
4383
|
+
for (const edit of edits) commit({ ...edit, label: "Delete" }, { deps });
|
|
4384
|
+
if (rest.length > 0) others(rest, deps);
|
|
4385
|
+
else deps.selection?.set([]);
|
|
4386
|
+
}
|
|
4387
|
+
});
|
|
4388
|
+
}
|
|
4389
|
+
|
|
4390
|
+
// src/sequence/actions.ts
|
|
4391
|
+
var SEQUENCE_DRAG_ACTION_ID = "diagram.sequence.drag";
|
|
4392
|
+
var GRAB_SEQUENCE_ACTION_ID = "diagram.sequence.grab";
|
|
4393
|
+
function carries(s, part) {
|
|
4394
|
+
if (s.part === "head") {
|
|
4395
|
+
if (part.target !== void 0) return "participant" in part.target && part.target.participant === s.id;
|
|
4396
|
+
return part.id === s.id && ["head", "lifeline", "destroy", "activation"].includes(part.part);
|
|
4397
|
+
}
|
|
4398
|
+
if (s.part === "step") {
|
|
4399
|
+
return part.id === s.id || part.target !== void 0 && ("step" in part.target && part.target.step === s.id || "fragment" in part.target && part.target.fragment === s.id);
|
|
4400
|
+
}
|
|
4401
|
+
return s.part === "end" && part.part === "message" && part.id === s.id;
|
|
4402
|
+
}
|
|
4403
|
+
function pressOf2(ctx) {
|
|
4404
|
+
const scratch = sequenceScratchOf(ctx.drag?.affordance);
|
|
4405
|
+
const scene = ctx.deps.scene;
|
|
4406
|
+
const node = scratch === null ? void 0 : scene?.get(scratch.root);
|
|
4407
|
+
const held = node === void 0 ? null : sequenceRootOf(node);
|
|
4408
|
+
const root = scene === void 0 || held === null ? void 0 : placedSequences(scene).find((p) => p.id === scratch.root);
|
|
4409
|
+
if (scratch === null || scene === void 0 || held === null || root === void 0) return null;
|
|
4410
|
+
const carried = /* @__PURE__ */ new Map();
|
|
4411
|
+
for (const id of scene.childrenOf(scratch.root)) {
|
|
4412
|
+
const child = scene.get(id);
|
|
4413
|
+
const part = sequencePartOf(child);
|
|
4414
|
+
if (part !== null && carries(scratch, part)) carried.set(id, child.pose);
|
|
4415
|
+
}
|
|
4416
|
+
return { scratch, scene, root, data: held.sequence, start: ctx.drag?.start ?? { x: ctx.world.x, y: ctx.world.y }, carried };
|
|
4417
|
+
}
|
|
4418
|
+
var nearest = (xs, x) => xs.reduce((best, v, i) => Math.abs(v - x) < Math.abs(xs[best] - x) ? i : best, 0);
|
|
4419
|
+
function proposed(p, at) {
|
|
4420
|
+
const { geometry, origin } = p.root;
|
|
4421
|
+
const local = { x: at.x - origin.x, y: at.y - origin.y };
|
|
4422
|
+
const { scratch } = p;
|
|
4423
|
+
if (scratch.part === "box" || scratch.part === "mark") return { data: p.data, label: "" };
|
|
4424
|
+
if (scratch.part === "head") {
|
|
4425
|
+
const index = geometry.columns.filter((c) => c.x < local.x).length;
|
|
4426
|
+
return { data: moveParticipant(p.data, scratch.id, index), label: "Move participant" };
|
|
4427
|
+
}
|
|
4428
|
+
if (scratch.part === "end") {
|
|
4429
|
+
const column = geometry.columns[nearest(geometry.columns.map((c) => c.x), local.x)];
|
|
4430
|
+
if (column === void 0) return { data: p.data, label: "" };
|
|
4431
|
+
return { data: reconnectMessage(p.data, scratch.id, scratch.end, column.id), label: "Reconnect message" };
|
|
4432
|
+
}
|
|
4433
|
+
const slot = geometry.slots[nearest(geometry.slots.map((s) => s.y), local.y)];
|
|
4434
|
+
if (slot === void 0) return { data: p.data, label: "" };
|
|
4435
|
+
return { data: moveStep(p.data, scratch.id, slot.place), label: "Move step" };
|
|
4436
|
+
}
|
|
4437
|
+
function previewOf(p, id, pose, at) {
|
|
4438
|
+
const dx = at.x - p.start.x;
|
|
4439
|
+
const dy = at.y - p.start.y;
|
|
4440
|
+
if (p.scratch.part === "head") return { ...pose, x: pose.x + dx };
|
|
4441
|
+
if (p.scratch.part === "step") return { ...pose, y: pose.y + dy };
|
|
4442
|
+
const m = p.root.geometry.messages.find((q) => q.id === p.scratch.id);
|
|
4443
|
+
if (m === void 0 || id !== `${p.scratch.root}/msg:${p.scratch.id}` || m.loopY !== void 0) return pose;
|
|
4444
|
+
const shift = pose.x - Math.min(m.x1, m.x2);
|
|
4445
|
+
const still = (p.scratch.end === "from" ? m.x2 : m.x1) + shift;
|
|
4446
|
+
const moving = (p.scratch.end === "from" ? m.x1 : m.x2) + shift + dx;
|
|
4447
|
+
return { ...pose, x: Math.min(still, moving), width: Math.abs(moving - still) };
|
|
4448
|
+
}
|
|
4449
|
+
function createSequenceDragAction(opts = {}) {
|
|
4450
|
+
const commit = sequenceCommitOf(opts);
|
|
4451
|
+
return {
|
|
4452
|
+
id: opts.id ?? SEQUENCE_DRAG_ACTION_ID,
|
|
4453
|
+
label: "Move sequence part",
|
|
4454
|
+
group: "diagram",
|
|
4455
|
+
requires: ["scene"],
|
|
4456
|
+
eligible: { mode: "normal" },
|
|
4457
|
+
invoker: {
|
|
4458
|
+
timing: "ongoing",
|
|
4459
|
+
start(ctx) {
|
|
4460
|
+
const p = pressOf2(ctx);
|
|
4461
|
+
if (p === null) return {};
|
|
4462
|
+
let at = null;
|
|
4463
|
+
let open = true;
|
|
4464
|
+
return {
|
|
4465
|
+
kind: "diagram-sequence-drag",
|
|
4466
|
+
onMove(move) {
|
|
4467
|
+
at = { x: move.world.x, y: move.world.y };
|
|
4468
|
+
},
|
|
4469
|
+
previewIds: () => open && at !== null ? [...p.carried.keys()] : null,
|
|
4470
|
+
previewPose: (id) => {
|
|
4471
|
+
const pose = p.carried.get(id);
|
|
4472
|
+
return open && at !== null && pose !== void 0 ? previewOf(p, id, pose, at) : null;
|
|
4473
|
+
},
|
|
4474
|
+
onEnd(end, reason) {
|
|
4475
|
+
open = false;
|
|
4476
|
+
if (reason !== "commit" || at === null) return;
|
|
4477
|
+
const next = proposed(p, { x: end.world.x, y: end.world.y });
|
|
4478
|
+
if (next.data !== p.data) commit({ id: p.scratch.root, data: next.data, label: next.label }, { ...end, deps: { ...end.deps, scene: p.scene } });
|
|
4479
|
+
}
|
|
4480
|
+
};
|
|
4481
|
+
}
|
|
4482
|
+
},
|
|
4483
|
+
enabled: () => true
|
|
4484
|
+
};
|
|
4485
|
+
}
|
|
4486
|
+
var grab = {
|
|
4487
|
+
id: GRAB_SEQUENCE_ACTION_ID,
|
|
4488
|
+
label: "Grab sequence part",
|
|
4489
|
+
group: "diagram",
|
|
4490
|
+
invoker: { timing: "immediate", run: () => {
|
|
4491
|
+
} },
|
|
4492
|
+
enabled: () => true
|
|
4493
|
+
};
|
|
4494
|
+
function diagramSequence(opts) {
|
|
4495
|
+
const actionId = opts.id ?? SEQUENCE_DRAG_ACTION_ID;
|
|
4496
|
+
const target = `affordance:${SEQUENCE_AFFORDANCE_KIND}`;
|
|
4497
|
+
return {
|
|
4498
|
+
layer: sequenceLayer(opts.scene),
|
|
4499
|
+
contribution: {
|
|
4500
|
+
id: "weasel-diagram-sequence",
|
|
4501
|
+
eligibility: { claimed: true },
|
|
4502
|
+
actions: [createSequenceDragAction({ ...opts, id: actionId }), grab, selectSequencePartAction],
|
|
4503
|
+
bindings: [
|
|
4504
|
+
{ spec: { kind: "drag", target }, actionId, opts: { id: "weasel-diagram-sequence.drag" } },
|
|
4505
|
+
{ spec: { kind: "pointerDown", target }, actionId: GRAB_SEQUENCE_ACTION_ID, opts: { id: "weasel-diagram-sequence.pointerDown" } },
|
|
4506
|
+
{ spec: { kind: "click", target, mods: { shift: "optional" } }, actionId: SELECT_SEQUENCE_PART_ACTION_ID, opts: { id: "weasel-diagram-sequence.click" } }
|
|
4507
|
+
]
|
|
4508
|
+
}
|
|
4509
|
+
};
|
|
4510
|
+
}
|
|
3301
4511
|
function agrees(selection, want) {
|
|
3302
4512
|
if (typeof want === "string" || want === null) return (selection.at(-1) ?? null) === want;
|
|
3303
4513
|
return selection.length === want.length && want.every((id) => selection.includes(id));
|
|
@@ -3407,11 +4617,11 @@ function diagramLayoutOf(specs) {
|
|
|
3407
4617
|
const id = s.id;
|
|
3408
4618
|
if (id === void 0) continue;
|
|
3409
4619
|
if (isBodyOrRegion(s)) {
|
|
3410
|
-
const
|
|
4620
|
+
const region2 = diagramContainerOf(s);
|
|
3411
4621
|
const pinned = isPinned({ id, kind: s.kind, data: s.data });
|
|
3412
4622
|
const { x, y, width, height } = world.get(id);
|
|
3413
|
-
if (
|
|
3414
|
-
if (!pinned &&
|
|
4623
|
+
if (region2 !== null) {
|
|
4624
|
+
if (!pinned && region2.role !== "lane" && region2.fitted !== true) {
|
|
3415
4625
|
containers.push({ kind: "box", id, box: { x, y, width, height } });
|
|
3416
4626
|
}
|
|
3417
4627
|
} else if (!pinned) moves.push({ id, x, y });
|
|
@@ -3439,8 +4649,8 @@ function changes(was, now) {
|
|
|
3439
4649
|
for (const [id, after] of now.routes) {
|
|
3440
4650
|
const before = was.routes.get(id);
|
|
3441
4651
|
if (before === void 0) continue;
|
|
3442
|
-
const
|
|
3443
|
-
if (
|
|
4652
|
+
const moved2 = before.waypoints !== after.waypoints && !samePoints(before.waypoints, after.waypoints);
|
|
4653
|
+
if (moved2 || !samePorts(before.ports, after.ports)) routes.push({ id, ...after });
|
|
3444
4654
|
}
|
|
3445
4655
|
return { moves, routes, containers: regionChanges(was.regions, now.regions) };
|
|
3446
4656
|
}
|
|
@@ -3449,11 +4659,11 @@ function useSceneSync(scene, specs, reports) {
|
|
|
3449
4659
|
const syncing = useRef(false);
|
|
3450
4660
|
const applied = useRef(specs);
|
|
3451
4661
|
useEffect(() => {
|
|
3452
|
-
let
|
|
4662
|
+
let known2 = readScene(scene);
|
|
3453
4663
|
return scene.subscribe(() => {
|
|
3454
4664
|
const now = readScene(scene);
|
|
3455
|
-
const found = syncing.current ? null : changes(
|
|
3456
|
-
|
|
4665
|
+
const found = syncing.current ? null : changes(known2, now);
|
|
4666
|
+
known2 = now;
|
|
3457
4667
|
if (found === null) return;
|
|
3458
4668
|
if (found.moves.length > 0 || found.routes.length > 0) reportsRef.current.onMove?.(found.moves, found.routes);
|
|
3459
4669
|
for (const edit of found.containers) reportsRef.current.onEditContainer?.(edit);
|
|
@@ -3470,6 +4680,15 @@ function useSceneSync(scene, specs, reports) {
|
|
|
3470
4680
|
applied.current = specs;
|
|
3471
4681
|
}, [scene, specs]);
|
|
3472
4682
|
}
|
|
4683
|
+
var isSequenceText = (data) => isTextData(data) && sequencePartOf({ data })?.target !== void 0;
|
|
4684
|
+
function useSequenceTextEdit(scene, report) {
|
|
4685
|
+
const latest = useLatest(report);
|
|
4686
|
+
const on = report !== void 0;
|
|
4687
|
+
return useMemo(() => on ? {
|
|
4688
|
+
isText: isSequenceText,
|
|
4689
|
+
onEnd: (id) => foldSequenceText(scene, id, (edit) => latest.current?.(edit))
|
|
4690
|
+
} : void 0, [on, scene, latest]);
|
|
4691
|
+
}
|
|
3473
4692
|
|
|
3474
4693
|
// src/regionEditing.ts
|
|
3475
4694
|
function laneResizeReports(scene, resize) {
|
|
@@ -3488,9 +4707,9 @@ function laneResizeReports(scene, resize) {
|
|
|
3488
4707
|
const { x, y, width, height } = after(id);
|
|
3489
4708
|
const was = before(id);
|
|
3490
4709
|
if (x === was.x && y === was.y) continue;
|
|
3491
|
-
const
|
|
3492
|
-
if (
|
|
3493
|
-
if (
|
|
4710
|
+
const region2 = diagramContainerOf(node);
|
|
4711
|
+
if (region2 !== null) {
|
|
4712
|
+
if (region2.role === "container" && region2.fitted !== true) boxes.push({ kind: "box", id, box: { x, y, width, height } });
|
|
3494
4713
|
} else if (isDiagramBody(node)) moves.push({ id, x, y });
|
|
3495
4714
|
}
|
|
3496
4715
|
}
|
|
@@ -3565,7 +4784,16 @@ function reportDeleteAction(report) {
|
|
|
3565
4784
|
}
|
|
3566
4785
|
});
|
|
3567
4786
|
}
|
|
3568
|
-
function
|
|
4787
|
+
function sequenceDeleteAction(scene, edit, report) {
|
|
4788
|
+
return createSequenceDeleteAction({
|
|
4789
|
+
commit: edit,
|
|
4790
|
+
others: (ids) => {
|
|
4791
|
+
const removed = removedData(scene, ids);
|
|
4792
|
+
if (report !== null && (removed.nodes.length > 0 || removed.edges.length > 0)) report(removed);
|
|
4793
|
+
}
|
|
4794
|
+
});
|
|
4795
|
+
}
|
|
4796
|
+
function reportResizeAction(report, region2) {
|
|
3569
4797
|
return createResizeAction({
|
|
3570
4798
|
commit: (poses, deps) => {
|
|
3571
4799
|
const picked = new Set(deps.selection?.get() ?? []);
|
|
@@ -3574,7 +4802,7 @@ function reportResizeAction(report, region) {
|
|
|
3574
4802
|
if (!picked.has(id)) continue;
|
|
3575
4803
|
const { x, y, width, height } = pose;
|
|
3576
4804
|
const node = deps.scene?.get(id);
|
|
3577
|
-
if (node !== void 0 && diagramContainerOf(node) !== null)
|
|
4805
|
+
if (node !== void 0 && diagramContainerOf(node) !== null) region2?.({ kind: "box", id, box: { x, y, width, height } });
|
|
3578
4806
|
else resizes.push({ id, x, y, width, height });
|
|
3579
4807
|
}
|
|
3580
4808
|
if (resizes.length > 0) report?.(resizes);
|
|
@@ -3601,6 +4829,7 @@ function useDiagramEditing(props) {
|
|
|
3601
4829
|
const reorders = props.onReorder !== void 0;
|
|
3602
4830
|
const resizes = props.onResize !== void 0;
|
|
3603
4831
|
const regionEdits = props.onEditContainer !== void 0;
|
|
4832
|
+
const sequences = props.onEditSequence !== void 0;
|
|
3604
4833
|
const ports = useMemo(() => mode === "connect" ? diagramPorts({
|
|
3605
4834
|
...portOptions,
|
|
3606
4835
|
participants: source,
|
|
@@ -3648,24 +4877,28 @@ function useDiagramEditing(props) {
|
|
|
3648
4877
|
[reorders, report]
|
|
3649
4878
|
);
|
|
3650
4879
|
const regions = useMemo(() => regionEdits ? regionEditing(scene, selected, report) : null, [regionEdits, scene, selected, report]);
|
|
4880
|
+
const sequence = useMemo(
|
|
4881
|
+
() => sequences ? diagramSequence({ scene, commit: (edit) => report.current.onEditSequence?.(edit) }) : null,
|
|
4882
|
+
[sequences, scene, report]
|
|
4883
|
+
);
|
|
3651
4884
|
const actions = useMemo(() => ({
|
|
3652
4885
|
...NO_MARQUEE,
|
|
3653
|
-
...deletes ? { delete: reportDeleteAction((r) => report.current.onDelete?.(r)) } : {},
|
|
4886
|
+
...sequences ? { delete: sequenceDeleteAction(scene, (edit) => report.current.onEditSequence?.(edit), deletes ? (r) => report.current.onDelete?.(r) : null) } : deletes ? { delete: reportDeleteAction((r) => report.current.onDelete?.(r)) } : {},
|
|
3654
4887
|
...resizes || regionEdits ? { resize: reportResizeAction((r) => report.current.onResize?.(r), (e) => report.current.onEditContainer?.(e)) } : {}
|
|
3655
|
-
}), [deletes, resizes, regionEdits, report]);
|
|
4888
|
+
}), [deletes, sequences, scene, resizes, regionEdits, report]);
|
|
3656
4889
|
const portsLayer = ports?.layer ?? shown;
|
|
3657
4890
|
const layers = useMemo(
|
|
3658
|
-
// Edge ends
|
|
3659
|
-
() => [regions?.layer, labelDrag?.layer, portsLayer, route?.layer, ends?.layer].filter((l) => l != null),
|
|
3660
|
-
[regions, labelDrag, portsLayer, route, ends]
|
|
4891
|
+
// Edge ends after ports and routes: an edge's end sits on a port and beside a route handle, and the last layer is hit first.
|
|
4892
|
+
() => [regions?.layer, labelDrag?.layer, portsLayer, route?.layer, ends?.layer, sequence?.layer].filter((l) => l != null),
|
|
4893
|
+
[regions, labelDrag, portsLayer, route, ends, sequence]
|
|
3661
4894
|
);
|
|
3662
4895
|
const extra = props.ambient;
|
|
3663
4896
|
const ambient = useMemo(() => [
|
|
3664
4897
|
...AMBIENT,
|
|
3665
|
-
...[ports?.contribution, route?.contribution, ends?.contribution, labelDrag?.contribution, label, reorder].filter((c) => c != null),
|
|
4898
|
+
...[ports?.contribution, route?.contribution, ends?.contribution, labelDrag?.contribution, label, reorder, sequence?.contribution].filter((c) => c != null),
|
|
3666
4899
|
...regions?.contributions ?? [],
|
|
3667
4900
|
...extra ?? []
|
|
3668
|
-
], [ports, route, ends, labelDrag, label, reorder, regions, extra]);
|
|
4901
|
+
], [ports, route, ends, labelDrag, label, reorder, sequence, regions, extra]);
|
|
3669
4902
|
return { layers, ambient, actions };
|
|
3670
4903
|
}
|
|
3671
4904
|
function usePagesView(pages) {
|
|
@@ -3801,6 +5034,7 @@ function Inner({
|
|
|
3801
5034
|
onDelete,
|
|
3802
5035
|
onEditLabel,
|
|
3803
5036
|
onMoveLabel,
|
|
5037
|
+
onEditSequence,
|
|
3804
5038
|
onReorder,
|
|
3805
5039
|
onEditContainer,
|
|
3806
5040
|
connectBodies,
|
|
@@ -3810,6 +5044,8 @@ function Inner({
|
|
|
3810
5044
|
pickEdges,
|
|
3811
5045
|
overlays = NO_OVERLAYS,
|
|
3812
5046
|
ambient: extraAmbient,
|
|
5047
|
+
tools,
|
|
5048
|
+
onToolsCreated,
|
|
3813
5049
|
enableKeybindings,
|
|
3814
5050
|
canConnect,
|
|
3815
5051
|
portOptions,
|
|
@@ -3873,16 +5109,16 @@ function Inner({
|
|
|
3873
5109
|
...refit ? { refit } : {}
|
|
3874
5110
|
});
|
|
3875
5111
|
const { defaultView } = fitting;
|
|
3876
|
-
const settled = useLatest((
|
|
3877
|
-
liveOpts?.onSettle?.(
|
|
3878
|
-
if (
|
|
5112
|
+
const settled = useLatest((moved2) => {
|
|
5113
|
+
liveOpts?.onSettle?.(moved2);
|
|
5114
|
+
if (moved2 !== 0) fitting.settle();
|
|
3879
5115
|
});
|
|
3880
5116
|
const live = useLiveLayout({
|
|
3881
5117
|
...liveOpts,
|
|
3882
5118
|
scene,
|
|
3883
5119
|
source,
|
|
3884
5120
|
algorithm: run?.algorithm ?? "force",
|
|
3885
|
-
onSettle: (
|
|
5121
|
+
onSettle: (moved2) => settled.current(moved2)
|
|
3886
5122
|
});
|
|
3887
5123
|
useEffect(() => {
|
|
3888
5124
|
if (run !== null) live.restart();
|
|
@@ -3904,6 +5140,7 @@ function Inner({
|
|
|
3904
5140
|
onResize,
|
|
3905
5141
|
onEditContainer,
|
|
3906
5142
|
onMove,
|
|
5143
|
+
onEditSequence,
|
|
3907
5144
|
connectBodies,
|
|
3908
5145
|
canConnect,
|
|
3909
5146
|
portOptions,
|
|
@@ -3911,16 +5148,19 @@ function Inner({
|
|
|
3911
5148
|
});
|
|
3912
5149
|
const itemDrop = useItemDrop(source, { onDropItem, canDropItem });
|
|
3913
5150
|
const ambient = useMemo(() => itemDrop === null ? editing.ambient : [...editing.ambient, itemDrop], [editing.ambient, itemDrop]);
|
|
3914
|
-
|
|
3915
|
-
const canvas = canvasRef.current;
|
|
3916
|
-
if (canvas === null) return;
|
|
3917
|
-
const disposers = editing.layers.map((layer) => canvas.registerLayer(layer));
|
|
3918
|
-
return () => disposers.forEach((dispose) => dispose());
|
|
3919
|
-
}, [editing.layers]);
|
|
5151
|
+
useRegisteredLayers(canvasRef, editing.layers);
|
|
3920
5152
|
const moves = onMove !== void 0 || onEditContainer !== void 0;
|
|
3921
5153
|
const resizes = onResize !== void 0 || onEditContainer !== void 0;
|
|
3922
|
-
const
|
|
3923
|
-
const
|
|
5154
|
+
const sequences = onEditSequence !== void 0;
|
|
5155
|
+
const edits = moves || onConnect !== void 0 || onReorder !== void 0 || resizes || edgesPick || sequences;
|
|
5156
|
+
const features = useMemo(() => [
|
|
5157
|
+
"view",
|
|
5158
|
+
"pick",
|
|
5159
|
+
...moves ? ["move"] : [],
|
|
5160
|
+
...resizes ? ["resize"] : [],
|
|
5161
|
+
...sequences ? ["edit"] : []
|
|
5162
|
+
], [moves, resizes, sequences]);
|
|
5163
|
+
const textEditor = useSequenceTextEdit(scene, onEditSequence);
|
|
3924
5164
|
const selectTool = useMemo(() => ({ resize: { resizable: diagramResizable(scene) } }), [scene]);
|
|
3925
5165
|
const overlayRef = useOverlayPlacement(canvasRef, scene, overlays);
|
|
3926
5166
|
const fillsOn = [width === void 0 ? "fill-x" : "", height === void 0 ? "fill-y" : ""].join(" ").trim();
|
|
@@ -3933,9 +5173,12 @@ function Inner({
|
|
|
3933
5173
|
selection,
|
|
3934
5174
|
features,
|
|
3935
5175
|
...resizes ? { selectTool } : {},
|
|
5176
|
+
...textEditor ? { textEditor } : {},
|
|
3936
5177
|
enableKeybindings: enableKeybindings ?? edits,
|
|
3937
5178
|
ambient,
|
|
3938
5179
|
actions: editing.actions,
|
|
5180
|
+
...tools ? { tools } : {},
|
|
5181
|
+
...onToolsCreated ? { onToolsCreated } : {},
|
|
3939
5182
|
onClick,
|
|
3940
5183
|
...onHover ? { onHover } : {},
|
|
3941
5184
|
width,
|
|
@@ -3957,6 +5200,14 @@ function Inner({
|
|
|
3957
5200
|
] });
|
|
3958
5201
|
}
|
|
3959
5202
|
var NO_OVERLAYS = [];
|
|
5203
|
+
function useRegisteredLayers(canvasRef, layers) {
|
|
5204
|
+
useEffect(() => {
|
|
5205
|
+
const canvas = canvasRef.current;
|
|
5206
|
+
if (canvas === null) return;
|
|
5207
|
+
const disposers = layers.map((layer) => canvas.registerLayer(layer));
|
|
5208
|
+
return () => disposers.forEach((dispose) => dispose());
|
|
5209
|
+
}, [canvasRef, layers]);
|
|
5210
|
+
}
|
|
3960
5211
|
function DropRules({ scene, canReparent }) {
|
|
3961
5212
|
const latest = useLatest(canReparent);
|
|
3962
5213
|
const asks = canReparent !== void 0;
|
|
@@ -3997,6 +5248,6 @@ function useDiagramApi(apiRef, canvasRef, scene, live, setRun, fitNow) {
|
|
|
3997
5248
|
}), [canvasRef, live, scene, setRun, fitNow]);
|
|
3998
5249
|
}
|
|
3999
5250
|
|
|
4000
|
-
export { ADD_LANE_ACTION_ID, ANYWHERE, CONNECT_ACTION_ID, CONTAINERS_GROUP, CONTAINER_STENCILS, DEFAULT_EDGE_STROKE, DIAGRAM_ITEM_CARRY, DiagramView, EASED_LAYOUTS, EDGE_END_AFFORDANCE_KIND, EDGE_END_LAYER_ID, EDIT_CONTAINER_TITLE_ACTION_ID, GRAB_EDGE_END_ACTION_ID, GRAB_LABEL_ACTION_ID, GRAB_PORT_ACTION_ID, GRAB_WAYPOINT_ACTION_ID, ITEM_DROP_ACTION_ID, LANE_AFFORDANCE_KIND, LANE_LAYER_ID, LANE_RESIZE_ACTION_ID,
|
|
4001
|
-
//# sourceMappingURL=chunk-
|
|
4002
|
-
//# sourceMappingURL=chunk-
|
|
5251
|
+
export { ADD_LANE_ACTION_ID, ANYWHERE, CONNECT_ACTION_ID, CONTAINERS_GROUP, CONTAINER_STENCILS, DEFAULT_EDGE_STROKE, DIAGRAM_ITEM_CARRY, DiagramView, EASED_LAYOUTS, EDGE_END_AFFORDANCE_KIND, EDGE_END_LAYER_ID, EDIT_CONTAINER_TITLE_ACTION_ID, GRAB_EDGE_END_ACTION_ID, GRAB_LABEL_ACTION_ID, GRAB_PORT_ACTION_ID, GRAB_SEQUENCE_ACTION_ID, GRAB_WAYPOINT_ACTION_ID, ITEM_DROP_ACTION_ID, LANE_AFFORDANCE_KIND, LANE_LAYER_ID, LANE_RESIZE_ACTION_ID, MOVE_LABEL_ACTION_ID, PORT_AFFORDANCE_KIND, PORT_LAYER_ID, RECONNECT_ACTION_ID, RELEASE_MEMBERS_ACTION_ID, REMOVE_WAYPOINT_ACTION_ID, REORDER_ACTION_ID, RESET_LABEL_ACTION_ID, RESET_ROUTE_ACTION_ID, ROUTER_LABELS, ROUTE_EDIT_ACTION_ID, SELECT_LABEL_EDGE_ACTION_ID, SELECT_SEQUENCE_PART_ACTION_ID, SEQ, SEQUENCE_AFFORDANCE_KIND, SEQUENCE_DRAG_ACTION_ID, SEQUENCE_LAYER_ID, SEQUENCE_ROLES, SEQ_ARROWS, SEQ_MULTI_SECTION, SET_HOPS_ACTION_ID, SET_ROUTER_ACTION_IDS, STEP_REORDER_ACTION_ID, WAYPOINT_AFFORDANCE_KIND, WAYPOINT_HIT_PX, WAYPOINT_LAYER_ID, addBox, addLane, addParticipant, addSection, avoidSceneInput, bodyAt, commitEdgeToScene, commitLabelToScene, commitLaneResizeToScene, commitReconnectToScene, commitRouteToScene, commitRouterToScene, commitSequence, connectBinding, containerBuild, createAddLaneAction, createConnectAction, createDiagramContribution, createEdgeEndAffordance, createItemDropAction, createLabelDragAction, createLaneAffordance, createLaneResizeAction, createPortAffordance, createReconnectAction, createReleaseMembersAction, createRemoveWaypointAction, createReorderAction, createResetLabelAction, createResetRouteAction, createRouteEditAction, createSequenceDeleteAction, createSequenceDragAction, createSetHopsAction, createSetRouterAction, createSpecHops, createSpecLabelPlacer, createSpecRouter, createStepReorderAction, createWaypointAffordance, defaultCanConnect, diagramCanDropInto, diagramContainers, diagramDropParentAt, diagramEdgeEnds, diagramLabelDrag, diagramLayoutOf, diagramPorts, diagramResizable, diagramSequence, diagramShape, diagramWaypoints, dragItemProps, dragSegment, dragVertex, easedProducer, edgeEndLayer, edgeEndScratchOf, edgePolylines, editContainerTitleAction, editContainerTitleBinding, findStep, foldSequenceText, forceProducer, freshSeqId, grabPortAction, grabPortBindings, groupReorderContribution, groupReorderSlots, headerIdOf, hopDataOps, inOrUnder, insertMark, insertMessage, insertNote, insertStep, insertWaypoint, isBodyEnd, isBodyOrRegion, isDiagramBody, isSequenceText, itemDropContribution, laneLayer, laneResizeFrame, laneScratchOf, lanesOf, moveParticipant, moveStep, movedLabelData, newParticipant, pinSegment, placeOf, placedSequences, poolAxisOf, poolsOf, portLayer, portScratchOf, reconnectBinding, reconnectMessage, redrawSequences, regionHeaderAt, registerDiagramShape, releaseMembers, removeBox, removeMarks, removeMarksOf, removeParticipant, removeSection, removeSegment, removeStep, removeStepAt, removeWaypoint, reorderBinding, reorderContribution, routeHandles, routeStateOf, routedData, routerActions, sceneEdges, sceneParticipants, segmentAxis, selectSequencePartAction, seqIdTaken, sequenceCommitOf, sequenceDeletes, sequenceLayout, sequencePartNodeOf, sequencePartOf, sequenceRootOf, sequenceScratchOf, sequenceSlots, sequenceSpecs, sequenceTextOf, setAutonumber, setFragmentType, setMessageActivation, setMessageArrow, setParticipantOutline, setSequenceText, startItemDrag, startSequence, stepListOf, themeWrites, unpinSegment, unwrapFragment, useLiveLayout, useMirroredSelection, useSequenceTextEdit, waypointLayer, waypointScratchOf, withHopsData, withRouter, worldWith, wrapSteps };
|
|
5252
|
+
//# sourceMappingURL=chunk-EIHPPOAM.js.map
|
|
5253
|
+
//# sourceMappingURL=chunk-EIHPPOAM.js.map
|