@likec4/diagram 1.58.0 → 1.59.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/dist/LikeC4Diagram.js +1 -1
  2. package/dist/LikeC4Diagram.props.d.ts +1 -1
  3. package/dist/LikeC4Styles.js +1 -1
  4. package/dist/LikeC4View.js +2 -2
  5. package/dist/ReactLikeC4.d.ts +1 -1
  6. package/dist/base/Base.d.ts +3 -2
  7. package/dist/base/Base.js +14 -26
  8. package/dist/base/BaseXYFlow.d.ts +2 -1
  9. package/dist/base/BaseXYFlow.js +63 -4
  10. package/dist/base/keyboardZoom.d.ts +3 -0
  11. package/dist/base/keyboardZoom.js +20 -0
  12. package/dist/base/updateEdges.js +7 -16
  13. package/dist/base/updateNodes.js +3 -9
  14. package/dist/base-primitives/compound/CompoundActionButton.d.ts +2 -1
  15. package/dist/base-primitives/compound/CompoundActionButton.js +5 -2
  16. package/dist/base-primitives/compound/CompoundDetailsButton.d.ts +2 -1
  17. package/dist/base-primitives/compound/CompoundDetailsButton.js +5 -2
  18. package/dist/base-primitives/compound/CompoundTitle.d.ts +7 -1
  19. package/dist/base-primitives/compound/CompoundTitle.js +2 -1
  20. package/dist/base-primitives/compound/actionbtns.css.d.ts +1 -1
  21. package/dist/base-primitives/edge/EdgeActionButton.d.ts +2 -1
  22. package/dist/base-primitives/edge/EdgeActionButton.js +2 -1
  23. package/dist/base-primitives/edge/EdgeContainer.d.ts +1 -1
  24. package/dist/base-primitives/edge/EdgeContainer.js +4 -2
  25. package/dist/base-primitives/edge/EdgeLabel.d.ts +2 -0
  26. package/dist/base-primitives/edge/EdgeLabel.js +2 -5
  27. package/dist/base-primitives/element/ElementActionButtons.d.ts +1 -0
  28. package/dist/base-primitives/element/ElementActionButtons.js +4 -1
  29. package/dist/base-primitives/element/ElementData.d.ts +3 -1
  30. package/dist/base-primitives/element/ElementData.js +2 -1
  31. package/dist/base-primitives/element/ElementDetailsButton.d.ts +2 -1
  32. package/dist/base-primitives/element/ElementDetailsButton.js +5 -2
  33. package/dist/base-primitives/element/ElementNodeContainer.js +1 -1
  34. package/dist/base-primitives/element/ElementShape.js +3 -0
  35. package/dist/components/ErrorFallback.js +3 -5
  36. package/dist/components/Link.js +6 -6
  37. package/dist/components/NavigationPanel.js +1 -1
  38. package/dist/components/SearchControl.css.js +11 -11
  39. package/dist/context/TagStylesContext.d.ts +3 -3
  40. package/dist/context/TagStylesContext.js +16 -16
  41. package/dist/custom/index.d.ts +1 -0
  42. package/dist/custom/index.js +3 -2
  43. package/dist/editor/actor/actions.js +1 -1
  44. package/dist/editor/actor/machine.d.ts +4 -6
  45. package/dist/editor/actor/setup.d.ts +16 -2
  46. package/dist/editor/actor/setup.js +5 -4
  47. package/dist/hooks/index.d.ts +1 -1
  48. package/dist/hooks/safeContext.d.ts +156 -3
  49. package/dist/hooks/safeContext.js +60 -12
  50. package/dist/hooks/useCurrentViewModel.js +1 -1
  51. package/dist/hooks/useDiagram.d.ts +8 -0
  52. package/dist/hooks/useDiagram.js +9 -2
  53. package/dist/hooks/useEditorActor.js +1 -1
  54. package/dist/hooks/useLikeC4ElementsTree.js +1 -1
  55. package/dist/hooks/useLikeC4Model.js +1 -1
  56. package/dist/hooks/useXYFlow.d.ts +1 -0
  57. package/dist/hooks/useXYFlow.js +5 -3
  58. package/dist/index.d.ts +1 -1
  59. package/dist/index.js +2 -2
  60. package/dist/likec4diagram/DiagramUI.js +19 -6
  61. package/dist/likec4diagram/DiagramXYFlow.js +39 -14
  62. package/dist/likec4diagram/convert-to-xyflow.d.ts +3 -5
  63. package/dist/likec4diagram/convert-to-xyflow.js +29 -10
  64. package/dist/likec4diagram/custom/edges/RelationshipEdge.js +13 -4
  65. package/dist/likec4diagram/custom/edges/SequenceStepEdge.js +11 -4
  66. package/dist/likec4diagram/custom/edges/edges.css.js +1 -1
  67. package/dist/likec4diagram/custom/index.d.ts +2 -1
  68. package/dist/likec4diagram/custom/index.js +5 -3
  69. package/dist/likec4diagram/custom/nodes/CompoundActions.js +1 -0
  70. package/dist/likec4diagram/custom/nodes/ElementActions.d.ts +2 -2
  71. package/dist/likec4diagram/custom/nodes/ElementActions.js +13 -3
  72. package/dist/likec4diagram/custom/nodes/NodeNotes.js +0 -4
  73. package/dist/likec4diagram/custom/nodes/SequenceActorNode.js +32 -19
  74. package/dist/likec4diagram/custom/nodes/SequenceSubFlow.d.ts +2 -0
  75. package/dist/likec4diagram/custom/nodes/SequenceSubFlow.js +234 -0
  76. package/dist/likec4diagram/custom/nodes/index.d.ts +1 -0
  77. package/dist/likec4diagram/custom/nodes/nodes.js +20 -5
  78. package/dist/likec4diagram/custom/nodes/toolbar/ColorButton.js +1 -1
  79. package/dist/likec4diagram/custom/nodes/toolbar/_shared.js +1 -1
  80. package/dist/likec4diagram/relationship-popover/RelationshipPopover.js +15 -14
  81. package/dist/likec4diagram/relationship-popover/components.d.ts +1 -1
  82. package/dist/likec4diagram/state/DiagramActorProvider.js +11 -20
  83. package/dist/likec4diagram/state/aligners.js +1 -1
  84. package/dist/likec4diagram/state/assign.d.ts +1 -1
  85. package/dist/likec4diagram/state/assign.js +1 -1
  86. package/dist/likec4diagram/state/createViewChange.js +1 -1
  87. package/dist/likec4diagram/state/diagram-api.d.ts +18 -10
  88. package/dist/likec4diagram/state/diagram-api.js +333 -229
  89. package/dist/likec4diagram/state/machine.actions.d.ts +1026 -332
  90. package/dist/likec4diagram/state/machine.actions.js +115 -44
  91. package/dist/likec4diagram/state/machine.actions.layout.d.ts +123 -51
  92. package/dist/likec4diagram/state/machine.actions.layout.js +40 -33
  93. package/dist/likec4diagram/state/machine.d.ts +154 -16
  94. package/dist/likec4diagram/state/machine.js +5 -41
  95. package/dist/likec4diagram/state/machine.setup.d.ts +84 -19
  96. package/dist/likec4diagram/state/machine.setup.js +65 -12
  97. package/dist/likec4diagram/state/machine.state.initializing.d.ts +59 -33
  98. package/dist/likec4diagram/state/machine.state.navigating.js +7 -3
  99. package/dist/likec4diagram/state/machine.state.ready.d.ts +1540 -476
  100. package/dist/likec4diagram/state/machine.state.ready.focused.d.ts +294 -53
  101. package/dist/likec4diagram/state/machine.state.ready.focused.js +3 -3
  102. package/dist/likec4diagram/state/machine.state.ready.idle.d.ts +264 -73
  103. package/dist/likec4diagram/state/machine.state.ready.idle.js +31 -6
  104. package/dist/likec4diagram/state/machine.state.ready.js +22 -16
  105. package/dist/likec4diagram/state/machine.state.ready.printing.d.ts +23 -9
  106. package/dist/likec4diagram/state/machine.state.ready.walkthrough.d.ts +288 -84
  107. package/dist/likec4diagram/state/machine.state.ready.walkthrough.js +135 -66
  108. package/dist/likec4diagram/state/types.d.ts +4 -2
  109. package/dist/likec4diagram/state/utils.d.ts +7 -0
  110. package/dist/likec4diagram/state/utils.js +36 -34
  111. package/dist/likec4diagram/types.d.ts +47 -3
  112. package/dist/likec4diagram/ui/FloatingSequenceActors.d.ts +6 -0
  113. package/dist/likec4diagram/ui/FloatingSequenceActors.js +155 -0
  114. package/dist/likec4diagram/ui/LayoutDriftFrame.js +2 -2
  115. package/dist/likec4diagram/ui/index.d.ts +2 -0
  116. package/dist/likec4diagram/ui/notation/NotationPanel.css.js +5 -5
  117. package/dist/likec4diagram/ui/sequence-outline/SequenceOutlinePanel.d.ts +2 -0
  118. package/dist/likec4diagram/ui/sequence-outline/SequenceOutlinePanel.js +519 -0
  119. package/dist/likec4diagram/ui/sequence-outline/state.d.ts +36 -0
  120. package/dist/likec4diagram/ui/sequence-outline/state.js +55 -0
  121. package/dist/likec4diagram/xyflow-diagram/diagram-view.d.ts +1 -1
  122. package/dist/likec4diagram/xyflow-diagram/diagram-view.js +112 -60
  123. package/dist/likec4diagram/xyflow-sequence/_types.d.ts +55 -5
  124. package/dist/likec4diagram/xyflow-sequence/const.d.ts +5 -5
  125. package/dist/likec4diagram/xyflow-sequence/const.js +4 -4
  126. package/dist/likec4diagram/xyflow-sequence/layouter.d.ts +30 -6
  127. package/dist/likec4diagram/xyflow-sequence/layouter.js +561 -0
  128. package/dist/likec4diagram/xyflow-sequence/{sequence-layout.d.ts → sequence-view-to-xy.d.ts} +8 -2
  129. package/dist/likec4diagram/xyflow-sequence/{sequence-layout.js → sequence-view-to-xy.js} +111 -14
  130. package/dist/likec4diagram/xyflow-sequence/sequence-view.d.ts +2 -7
  131. package/dist/likec4diagram/xyflow-sequence/sequence-view.js +144 -0
  132. package/dist/likec4diagram/xyflow-sequence/utils.d.ts +9 -1
  133. package/dist/likec4diagram/xyflow-sequence/utils.js +96 -0
  134. package/dist/navigationpanel/NavigationPanel.d.ts +5 -2
  135. package/dist/navigationpanel/NavigationPanel.js +58 -59
  136. package/dist/navigationpanel/NavigationPanelDropdown.js +45 -38
  137. package/dist/navigationpanel/_common.js +2 -2
  138. package/dist/navigationpanel/actor.actions.d.ts +19 -0
  139. package/dist/navigationpanel/actor.actions.js +45 -0
  140. package/dist/navigationpanel/actor.d.ts +34 -96
  141. package/dist/navigationpanel/actor.js +21 -84
  142. package/dist/navigationpanel/actor.setup.d.ts +98 -0
  143. package/dist/navigationpanel/actor.setup.js +31 -0
  144. package/dist/navigationpanel/comparepanel/DriftsSummary.js +4 -5
  145. package/dist/navigationpanel/controls/DetailsControls.js +7 -8
  146. package/dist/navigationpanel/dropdown/ProjectsMenu.js +1 -1
  147. package/dist/navigationpanel/editorpanel/styles.js +8 -8
  148. package/dist/navigationpanel/hooks.d.ts +20 -5
  149. package/dist/navigationpanel/hooks.js +4 -18
  150. package/dist/navigationpanel/styles.css.d.ts +1 -1
  151. package/dist/navigationpanel/walkthrough/ActiveWalkthroughControls.js +2 -2
  152. package/dist/navigationpanel/walkthrough/DynamicViewControls.d.ts +4 -4
  153. package/dist/navigationpanel/walkthrough/DynamicViewControls.js +23 -25
  154. package/dist/navigationpanel/walkthrough/WalkthroughPanel.js +5 -5
  155. package/dist/overlays/Overlays.d.ts +4 -2
  156. package/dist/overlays/Overlays.js +10 -10
  157. package/dist/overlays/element-details/ElementDetailsCard.css.js +17 -17
  158. package/dist/overlays/element-details/MetadataValue.js +15 -15
  159. package/dist/overlays/element-details/TabPanelDeployments.css.js +5 -5
  160. package/dist/overlays/element-details/TabPanelRelationships.css.js +11 -11
  161. package/dist/overlays/element-details/TabPanelRelationships.js +1 -1
  162. package/dist/overlays/element-details/TabPanelStructure.css.js +2 -2
  163. package/dist/overlays/element-details/TabPanelStructure.js +1 -1
  164. package/dist/overlays/element-details/actor.d.ts +2 -3
  165. package/dist/overlays/hooks.d.ts +28 -0
  166. package/dist/overlays/hooks.js +5 -0
  167. package/dist/overlays/overlay/Overlay.js +34 -25
  168. package/dist/overlays/overlaysActor.js +0 -1
  169. package/dist/overlays/relationship-details/custom/nodeTypes.js +1 -1
  170. package/dist/overlays/relationship-details/layout.js +1 -1
  171. package/dist/overlays/relationships-browser/SelectElement.css.js +2 -2
  172. package/dist/overlays/relationships-browser/actor.js +79 -78
  173. package/dist/overlays/relationships-browser/custom/nodeTypes.js +1 -1
  174. package/dist/overlays/relationships-browser/hooks.js +1 -1
  175. package/dist/overlays/relationships-browser/layout.js +2 -2
  176. package/dist/projects-overview/actor.js +4 -4
  177. package/dist/search/Search.js +1 -1
  178. package/dist/search/components/ElementsColumn.css.js +2 -2
  179. package/dist/search/components/ViewsColum.js +1 -1
  180. package/dist/search/components/_shared.css.d.ts +1 -1
  181. package/dist/search/components/_shared.css.js +23 -23
  182. package/dist/search/components/styles.css.js +4 -4
  183. package/dist/shadowroot/ShadowRoot.d.ts +1 -1
  184. package/dist/shadowroot/ShadowRoot.js +76 -28
  185. package/dist/styles2.js +1 -1
  186. package/dist/utils/defineActors.d.ts +21 -0
  187. package/dist/utils/defineActors.js +13 -0
  188. package/dist/utils/index.d.ts +1 -0
  189. package/dist/utils/index.js +5 -4
  190. package/dist/utils/readableText.d.ts +11 -0
  191. package/dist/utils/readableText.js +18 -0
  192. package/package.json +18 -30
  193. package/panda.buildinfo.json +267 -288
  194. package/styles-min.css +1 -1
  195. package/styles.css +1 -1
  196. package/adhoc-editor/package.json +0 -4
  197. package/dist/adhoc-editor/EditorPanel.d.ts +0 -1
  198. package/dist/adhoc-editor/EditorPanel.js +0 -106
  199. package/dist/adhoc-editor/ElementsTree.d.ts +0 -2
  200. package/dist/adhoc-editor/ElementsTree.js +0 -112
  201. package/dist/adhoc-editor/LikeC4AdHocViewEditor.d.ts +0 -4
  202. package/dist/adhoc-editor/LikeC4AdHocViewEditor.js +0 -83
  203. package/dist/adhoc-editor/components/Tree.d.ts +0 -48
  204. package/dist/adhoc-editor/components/Tree.js +0 -213
  205. package/dist/adhoc-editor/hooks.d.ts +0 -14
  206. package/dist/adhoc-editor/hooks.js +0 -34
  207. package/dist/adhoc-editor/index.d.ts +0 -2
  208. package/dist/adhoc-editor/index.js +0 -2
  209. package/dist/adhoc-editor/state/ActorProvider.d.ts +0 -5
  210. package/dist/adhoc-editor/state/ActorProvider.js +0 -37
  211. package/dist/adhoc-editor/state/actor.d.ts +0 -13
  212. package/dist/adhoc-editor/state/actor.editor.d.ts +0 -56
  213. package/dist/adhoc-editor/state/actor.editor.js +0 -167
  214. package/dist/adhoc-editor/state/actor.js +0 -14
  215. package/dist/adhoc-editor/state/actor.layouter.d.ts +0 -51
  216. package/dist/adhoc-editor/state/actor.layouter.js +0 -54
  217. package/dist/adhoc-editor/state/actor.types.d.ts +0 -63
  218. package/dist/adhoc-editor/state/actor.types.js +0 -25
  219. package/dist/adhoc-editor/state/panel.d.ts +0 -95
  220. package/dist/adhoc-editor/state/panel.js +0 -124
  221. package/dist/adhoc-editor/state/utils.d.ts +0 -17
  222. package/dist/adhoc-editor/state/utils.js +0 -25
  223. package/dist/adhoc-editor/useElementsTree.d.ts +0 -18
  224. package/dist/adhoc-editor/useElementsTree.js +0 -98
  225. package/dist/adhoc-editor/viewrules/ViewRulesPanel.d.ts +0 -6
  226. package/dist/context/ShadowRootContext.d.ts +0 -3
  227. package/dist/context/ShadowRootContext.js +0 -5
  228. package/dist/shadowroot/styles.d.ts +0 -13
  229. package/dist/shadowroot/styles.js +0 -60
@@ -0,0 +1,561 @@
1
+ import "../../_virtual/_rolldown/runtime.js";
2
+ import { normalizeSpacing, rectFromSteps } from "./utils.js";
3
+ import { filter, first, flatMap, hasAtLeast, last, map, only, pipe } from "remeda";
4
+ import { invariant, nonNullable, nonexhaustive } from "@likec4/core/utils";
5
+ import { flowGuards } from "@likec4/core/types";
6
+ import * as kiwi from "@lume/kiwi";
7
+ import defu from "defu";
8
+ //#region src/likec4diagram/xyflow-sequence/layouter.ts
9
+ var Strength = {
10
+ required: kiwi.Strength.required,
11
+ strong: kiwi.Strength.strong,
12
+ medium: kiwi.Strength.medium,
13
+ soft: kiwi.Strength.create(0, .8, 1),
14
+ weak: kiwi.Strength.weak
15
+ };
16
+ var SequenceViewLayouter = class {
17
+ #flow;
18
+ #solver = new kiwi.Solver();
19
+ #actors;
20
+ #compounds = [];
21
+ #viewportRight;
22
+ #viewportBottom;
23
+ #rowsTop;
24
+ /**
25
+ * Each row has inner and outer bounds
26
+ * For adjacent rows, outer-bottom equals outer-top of the next row
27
+ *
28
+ * Inner bounds (top and bottom) are updated during layouting (when wrapped with subflow)
29
+ *
30
+ * ------ outer-top -------
31
+ * [ subflow stack begins ]
32
+ * ------ inner-top -------
33
+ * [ A ---> B ]
34
+ * ---- inner-bottom ------
35
+ * [ subflow stack ends ]
36
+ * ---- outer-bottom ------
37
+ */
38
+ #rows = [];
39
+ #subflows = /* @__PURE__ */ new Map();
40
+ constructor({ actors, steps, compounds, flow, collapsedFlows }) {
41
+ this.#solver.maxIterations = 2e3;
42
+ this.#flow = flow;
43
+ const firstRowOffset = Math.max(...actors.map((actor) => actor.height)) + 30;
44
+ this.#rowsTop = this.newVar(firstRowOffset);
45
+ this.constraint(this.#rowsTop, "==", firstRowOffset, Strength.soft);
46
+ this.constraint(this.#rowsTop, ">=", firstRowOffset, Strength.weak);
47
+ this.#viewportRight = this.newVar(0);
48
+ this.#viewportBottom = this.newVar(0);
49
+ this.#actors = this.addActors(actors);
50
+ for (const compound of compounds) {
51
+ const result = this.addCompound(compound);
52
+ const toplevel = result[0];
53
+ this.constraint(toplevel.y1, "==", 0, Strength.strong);
54
+ this.put(this.#rowsTop, Strength.strong).after(toplevel.y2);
55
+ this.#compounds.push(...result);
56
+ }
57
+ const [firstActor, ...restActors] = this.#actors;
58
+ this.constraint(firstActor.offset.left, "==", 0, Strength.strong);
59
+ const lastActor = restActors.reduce((prev, actor) => {
60
+ this.put(actor.x).after(prev.right, 80);
61
+ this.put(prev.offset.right, Strength.strong).before(actor.offset.left, 50);
62
+ this.constraint(actor.centerY, "==", prev.centerY, Strength.strong);
63
+ return actor;
64
+ }, firstActor);
65
+ for (const step of steps) this.addStep(step);
66
+ this.createSubflowAreas(steps, new Set(collapsedFlows));
67
+ this.constraint(this.#viewportRight, "==", lastActor.offset.right);
68
+ const mostBottom = last(this.#rows)?.inner.bottom ?? this.#rowsTop;
69
+ this.put(this.#viewportBottom, Strength.strong).after(mostBottom, 16);
70
+ if (compounds.length > 0) for (const compound of this.#compounds) {
71
+ const from = compound.from.column;
72
+ const to = compound.to.column;
73
+ let maxRow = Math.max(compound.from.maxRow, compound.to.maxRow);
74
+ for (let i = from + 1; i < to; i++) {
75
+ const actorBox = this.actorBox(i);
76
+ maxRow = Math.max(maxRow, actorBox.maxRow);
77
+ }
78
+ const lastRow = nonNullable(this.#rows[maxRow], `row ${maxRow} not found`);
79
+ this.put(compound.bottom, Strength.strong).after(lastRow.inner.bottom, 10);
80
+ }
81
+ this.#solver.updateVariables();
82
+ }
83
+ getSubflowAreas() {
84
+ return [...this.#subflows.entries()].map(([id, { x1, y1, x2, y2 }]) => ({
85
+ id,
86
+ x: x1.value(),
87
+ y: y1.value(),
88
+ width: x2.value() - x1.value(),
89
+ height: y2.value() - y1.value()
90
+ }));
91
+ }
92
+ getActorBox(actor) {
93
+ const actorBox = this.actorBox(actor);
94
+ return {
95
+ x: actorBox.x.value(),
96
+ y: actorBox.y.value(),
97
+ width: actorBox.width,
98
+ height: actorBox.height
99
+ };
100
+ }
101
+ getCompoundBoxes() {
102
+ return this.#compounds.map(({ node, depth, x1, y1, x2, bottom }) => ({
103
+ node,
104
+ depth,
105
+ x: x1.value(),
106
+ y: y1.value(),
107
+ width: x2.value() - x1.value(),
108
+ height: bottom.value() - y1.value()
109
+ }));
110
+ }
111
+ getPortCenter(step, type) {
112
+ const { column, row } = type === "source" ? step.from : step.to;
113
+ const x = this.actorBox(column).centerX;
114
+ const { rowTop } = nonNullable(this.#rows[row]);
115
+ return {
116
+ cx: x.value(),
117
+ cy: rowTop.value() + 40 + step.offset,
118
+ height: type === "source" ? 40 : 24
119
+ };
120
+ }
121
+ isStepCollapsed(step) {
122
+ if (step.from.row === step.to.row) return this.#rows[step.from.row]?.collapsed ?? false;
123
+ const minRow = Math.min(step.from.row, step.to.row);
124
+ const maxRow = Math.min(step.from.row, step.to.row);
125
+ let collapsed = true;
126
+ for (let i = minRow; i <= maxRow; i++) {
127
+ collapsed = collapsed && (this.#rows[i]?.collapsed ?? false);
128
+ if (!collapsed) break;
129
+ }
130
+ return collapsed;
131
+ }
132
+ getViewBounds() {
133
+ return {
134
+ x: 0,
135
+ y: 0,
136
+ width: this.#viewportRight.value(),
137
+ height: this.#viewportBottom.value()
138
+ };
139
+ }
140
+ actorBox(actor) {
141
+ if (typeof actor !== "number") {
142
+ const id = typeof actor === "string" ? actor : actor.id;
143
+ actor = this.#actors.findIndex((a) => a.actor.id === id);
144
+ invariant(actor >= 0, `actor ${id} not found`);
145
+ }
146
+ return nonNullable(this.#actors[actor], `actor at index ${actor} not found`);
147
+ }
148
+ addActors(actors) {
149
+ let accX = 0;
150
+ return map(actors, (actor, column) => {
151
+ const x = this.newVar(accX);
152
+ accX += actor.width + 80;
153
+ const y = this.newVar(0);
154
+ const actorBox = {
155
+ column,
156
+ actor,
157
+ x,
158
+ y,
159
+ centerX: x.plus(Math.round(actor.width / 2)),
160
+ centerY: y.plus(Math.round(actor.height / 2)),
161
+ width: actor.width,
162
+ height: actor.height,
163
+ right: x.plus(actor.width),
164
+ bottom: y.plus(actor.height),
165
+ minRow: Infinity,
166
+ maxRow: -Infinity
167
+ };
168
+ const top = this.newVar(0);
169
+ const left = this.newVar(0);
170
+ const right = this.newVar(0);
171
+ const bottom = this.newVar(0);
172
+ this.put(y, Strength.strong).after(top);
173
+ this.put(x, Strength.strong).after(left);
174
+ this.put(actorBox.right, Strength.strong).before(right);
175
+ this.put(actorBox.bottom, Strength.strong).before(bottom);
176
+ return {
177
+ ...actorBox,
178
+ offset: {
179
+ top,
180
+ left,
181
+ right,
182
+ bottom
183
+ }
184
+ };
185
+ });
186
+ }
187
+ addStep(step) {
188
+ const source = this.actorBox(step.source);
189
+ const target = this.actorBox(step.target);
190
+ source.minRow = Math.min(source.minRow, step.from.row);
191
+ source.maxRow = Math.max(source.maxRow, step.from.row);
192
+ target.minRow = Math.min(target.minRow, step.to.row);
193
+ target.maxRow = Math.max(target.maxRow, step.to.row);
194
+ const [left, right] = source.column <= target.column ? [source, target] : [target, source];
195
+ const width = (step.label?.width ?? 100) + 50;
196
+ if (Math.abs(target.column - source.column) <= 1) if (left !== right) this.constraint(left.centerX.plus(width), "<=", right.centerX);
197
+ else this.constraint(left.centerX.plus(width), "<=", left.offset.right);
198
+ let height = step.label?.height ? step.label.height + 50 + 24 : 100;
199
+ height = Math.max(height, 100) + step.offset;
200
+ this.ensureRow(step.from.row, height);
201
+ if (step.isSelfLoop) this.ensureRow(step.to.row, 0);
202
+ return this;
203
+ }
204
+ /**
205
+ * Recursively adds a compound and its nested compounds to the layout.
206
+ * Also updates offsets of the actor boxes to accommodate the compound.
207
+ */
208
+ addCompound(compound) {
209
+ const PADDING = 32;
210
+ const PADDING_TOP = 40;
211
+ const PADDING_TOP_FROM_ACTOR = 52;
212
+ const children = [];
213
+ const nested = compound.nested.flatMap((c) => {
214
+ const result = this.addCompound(c);
215
+ children.push(result[0]);
216
+ return result;
217
+ });
218
+ const depth = Math.max(...nested.map((c) => c.depth + 1), 0);
219
+ const from = this.actorBox(compound.from);
220
+ const to = this.actorBox(compound.to);
221
+ const x1 = from.offset.left.minus(PADDING);
222
+ from.offset.left = x1;
223
+ const x2 = to.offset.right.plus(PADDING);
224
+ to.offset.right = x2;
225
+ const bottom = this.newVar(0);
226
+ const onlyChild = only(children);
227
+ let y1;
228
+ let y2;
229
+ switch (true) {
230
+ case !!onlyChild:
231
+ y1 = onlyChild.y1.minus(PADDING_TOP);
232
+ y2 = onlyChild.y2.plus(PADDING);
233
+ this.put(onlyChild.bottom).before(bottom, PADDING);
234
+ break;
235
+ case to === from:
236
+ y1 = this.newVar(0);
237
+ y2 = this.newVar(0);
238
+ this.put(y1).before(from.offset.top, PADDING_TOP_FROM_ACTOR);
239
+ this.put(from.offset.bottom).before(y2, PADDING);
240
+ this.put(y2).before(bottom);
241
+ break;
242
+ case children.length > 0:
243
+ y1 = this.newVar(0);
244
+ y2 = this.newVar(0);
245
+ for (const child of children) {
246
+ this.put(y1).before(child.y1, PADDING);
247
+ this.put(child.y2).before(y2, PADDING);
248
+ this.put(child.bottom).before(bottom, PADDING);
249
+ }
250
+ break;
251
+ default:
252
+ y1 = this.newVar(0);
253
+ y2 = this.newVar(0);
254
+ for (var col = from.column; col <= to.column; col++) {
255
+ const offset = this.actorBox(col).offset;
256
+ this.put(y1).before(offset.top, PADDING_TOP_FROM_ACTOR);
257
+ this.put(offset.bottom).before(y2, PADDING);
258
+ }
259
+ this.put(y2).before(bottom);
260
+ break;
261
+ }
262
+ for (var col = from.column; col <= to.column; col++) {
263
+ const offset = this.actorBox(col).offset;
264
+ offset.top = y1;
265
+ offset.bottom = y2;
266
+ }
267
+ return [{
268
+ node: compound.node,
269
+ depth,
270
+ from,
271
+ to,
272
+ x1,
273
+ y1,
274
+ x2,
275
+ y2,
276
+ bottom
277
+ }, ...nested];
278
+ }
279
+ ensureRow(row, rowHeight) {
280
+ while (row >= this.#rows.length) {
281
+ const outerTop = last(this.#rows)?.outer.bottom || this.#rowsTop;
282
+ const innerTop = this.newVar(outerTop.value());
283
+ this.put(innerTop).after(outerTop);
284
+ let heightValue = rowHeight;
285
+ if (row !== this.#rows.length) heightValue = 100;
286
+ const height = new kiwi.Variable();
287
+ height.setValue(heightValue);
288
+ this.#solver.addEditVariable(height, Strength.strong);
289
+ this.#solver.suggestValue(height, heightValue);
290
+ const innerBottom = this.newVar(innerTop.value() + heightValue);
291
+ this.require(innerBottom).after(innerTop);
292
+ this.constraint(innerBottom.minus(innerTop), "==", height, Strength.strong);
293
+ const outerBottom = this.newVar(innerBottom.value());
294
+ this.put(outerBottom).after(innerBottom);
295
+ this.#rows.push({
296
+ inner: {
297
+ top: innerTop,
298
+ bottom: innerBottom
299
+ },
300
+ rowTop: innerTop,
301
+ outer: {
302
+ top: outerTop,
303
+ bottom: outerBottom
304
+ },
305
+ height
306
+ });
307
+ }
308
+ const rowVar = nonNullable(this.#rows[row]);
309
+ if (rowHeight > rowVar.height.value()) {
310
+ rowVar.height.setValue(rowHeight);
311
+ this.#solver.suggestValue(rowVar.height, rowHeight);
312
+ }
313
+ return rowVar;
314
+ }
315
+ collapseRect({ min, max }) {
316
+ const h = 0;
317
+ for (let row = min.row; row <= max.row; row++) {
318
+ const r = nonNullable(this.#rows[row], `Row ${row} not found`);
319
+ r.collapsed = true;
320
+ r.height.setValue(h);
321
+ this.#solver.suggestValue(r.height, h);
322
+ }
323
+ }
324
+ getRectBounds({ min, max }) {
325
+ const firstRow = this.#rows[min.row];
326
+ const lastRow = this.#rows[max.row];
327
+ invariant(firstRow && lastRow, `Subflow box invalid minRow=${min.row} maxRow=${max.row}`);
328
+ return {
329
+ x1: this.actorBox(min.column).centerX,
330
+ x2: this.actorBox(max.column).centerX,
331
+ get top() {
332
+ return firstRow.inner.top;
333
+ },
334
+ set top(value) {
335
+ firstRow.inner.top = value;
336
+ },
337
+ get bottom() {
338
+ return lastRow.inner.bottom;
339
+ },
340
+ set bottom(value) {
341
+ lastRow.inner.bottom = value;
342
+ },
343
+ minY: firstRow.outer.top,
344
+ maxY: lastRow.outer.bottom
345
+ };
346
+ }
347
+ wrapAroundRect(rect, spacing) {
348
+ const p = normalizeSpacing(spacing ?? 16);
349
+ const bounds = this.getRectBounds(rect);
350
+ const x1 = this.newVar(0);
351
+ this.put(x1).before(bounds.x1, p.left);
352
+ const x2 = this.newVar(0);
353
+ this.put(x2).after(bounds.x2, p.right);
354
+ const y1 = this.newVar(bounds.minY.value());
355
+ this.require(y1).after(bounds.minY);
356
+ this.put(y1).before(bounds.top, p.top);
357
+ const y2 = this.newVar(bounds.maxY.value());
358
+ this.put(y2).after(bounds.bottom, p.bottom);
359
+ this.require(y2).before(bounds.maxY);
360
+ bounds.top = y1;
361
+ bounds.bottom = y2;
362
+ return {
363
+ x1,
364
+ y1,
365
+ x2,
366
+ y2
367
+ };
368
+ }
369
+ createSubflowAreas(steps, collapsed) {
370
+ const selectSteps = (id) => filter(steps, (s) => s.id.startsWith(id));
371
+ const spacing = {
372
+ top: 30,
373
+ right: 40,
374
+ bottom: 10,
375
+ left: 90
376
+ };
377
+ /**
378
+ * Expands the parent bounding box to fit all subflows and their nested steps.
379
+ */
380
+ const fitSubflows = ({ area, visited, stretch = false, padding }) => {
381
+ const areas = pipe(visited, filter(flowGuards.isSubFlow), flatMap((b) => this.#subflows.get(b.id) ?? []));
382
+ if (!hasAtLeast(areas, 1)) return;
383
+ const p = defu(padding, spacing);
384
+ const firstArea = first(areas);
385
+ const lastArea = last(areas);
386
+ if (firstArea.min.row == area.min.row) this.require(area.y1).before(firstArea.y1, p.top);
387
+ if (lastArea.max.row == area.max.row) this.require(lastArea.y2).before(area.y2, p.bottom);
388
+ for (const subarea of areas) {
389
+ this.require(subarea.x1).after(area.x1, p.left);
390
+ this.require(subarea.x2).before(area.x2, p.right);
391
+ if (stretch) {
392
+ subarea.x1 = p.left > 0 ? area.x1.plus(p.left) : area.x1;
393
+ subarea.x2 = p.right > 0 ? area.x2.minus(p.right) : area.x2;
394
+ }
395
+ }
396
+ };
397
+ const createSubflowArea = (subflow) => {
398
+ const rect = rectFromSteps(selectSteps(subflow.id));
399
+ let space;
400
+ switch (true) {
401
+ case flowGuards.isAltOrTry(subflow):
402
+ space = 0;
403
+ break;
404
+ case collapsed.has(subflow.id) && flowGuards.isAltOrTryBranch(subflow):
405
+ space = {
406
+ ...spacing,
407
+ top: 36,
408
+ bottom: 0
409
+ };
410
+ break;
411
+ case collapsed.has(subflow.id):
412
+ space = {
413
+ ...spacing,
414
+ top: 24,
415
+ bottom: 0
416
+ };
417
+ break;
418
+ default:
419
+ space = spacing;
420
+ break;
421
+ }
422
+ const area = {
423
+ ...this.wrapAroundRect(rect, space),
424
+ ...rect
425
+ };
426
+ this.#subflows.set(subflow.id, area);
427
+ return area;
428
+ };
429
+ this.#flow.walk({ subflow: ({ subflow, previous, parent }) => ({
430
+ next: collapsed.has(subflow.id) ? [] : subflow.flow,
431
+ onLeave: ({ visited }) => {
432
+ const area = createSubflowArea(subflow);
433
+ const previousSubflow = flowGuards.isSubFlow(previous) && this.#subflows.get(previous.id);
434
+ if (!flowGuards.isAltOrTryBranch(subflow) && previousSubflow) this.put(previousSubflow.y2).before(area.y1, 32);
435
+ if (!parent && area.min.column > 0) this.require(this.actorBox(area.min.column - 1).centerX).before(area.x1, 100);
436
+ switch (true) {
437
+ case collapsed.has(subflow.id):
438
+ this.collapseRect(area);
439
+ return;
440
+ case flowGuards.isAltOrTry(subflow): return fitSubflows({
441
+ area,
442
+ visited,
443
+ padding: {
444
+ top: 30,
445
+ left: 0,
446
+ right: 0
447
+ },
448
+ stretch: true
449
+ });
450
+ case flowGuards.isAltOrTryBranch(subflow): return fitSubflows({
451
+ area,
452
+ visited,
453
+ padding: {
454
+ top: 50,
455
+ left: 32,
456
+ bottom: 32,
457
+ right: 32
458
+ }
459
+ });
460
+ default: return fitSubflows({
461
+ area,
462
+ visited,
463
+ padding: {
464
+ top: 40,
465
+ bottom: 12,
466
+ left: 32,
467
+ right: 16
468
+ }
469
+ });
470
+ }
471
+ }
472
+ }) });
473
+ }
474
+ newVar(initialValue) {
475
+ const v = new kiwi.Variable();
476
+ this.#solver.addEditVariable(v, Strength.weak);
477
+ if (typeof initialValue === "number") {
478
+ v.setValue(initialValue);
479
+ this.#solver.suggestValue(v, initialValue);
480
+ }
481
+ return v;
482
+ }
483
+ require(...args) {
484
+ if (args.length == 1) {
485
+ const [left] = args;
486
+ return {
487
+ before: (right, gap = 0) => {
488
+ let other = gap ? right.minus(gap) : right;
489
+ return this.constraint(left, "<=", other, Strength.required);
490
+ },
491
+ after: (right, gap = 0) => {
492
+ let other = gap ? right.plus(gap) : right;
493
+ return this.constraint(left, ">=", other, Strength.required);
494
+ }
495
+ };
496
+ }
497
+ const [left, op, right] = args;
498
+ const constraint = this.constraint(left, op, right, Strength.required);
499
+ switch (op) {
500
+ case "<=":
501
+ case ">=":
502
+ this.constraint(left, "==", right, Strength.weak);
503
+ break;
504
+ case "<= 0":
505
+ case ">= 0":
506
+ this.constraint(left, "== 0", void 0, Strength.weak);
507
+ break;
508
+ }
509
+ return constraint;
510
+ }
511
+ /**
512
+ * Adds a constraint with medium strength by default
513
+ */
514
+ constraint(left, op, right = void 0, strength = Strength.medium) {
515
+ let operator;
516
+ switch (op) {
517
+ case "==":
518
+ operator = kiwi.Operator.Eq;
519
+ break;
520
+ case ">=":
521
+ operator = kiwi.Operator.Ge;
522
+ break;
523
+ case "<=":
524
+ operator = kiwi.Operator.Le;
525
+ break;
526
+ case "== 0":
527
+ operator = kiwi.Operator.Eq;
528
+ right = 0;
529
+ break;
530
+ case ">= 0":
531
+ operator = kiwi.Operator.Ge;
532
+ right = 0;
533
+ break;
534
+ case "<= 0":
535
+ operator = kiwi.Operator.Le;
536
+ right = 0;
537
+ break;
538
+ default: nonexhaustive(op);
539
+ }
540
+ const constraint = new kiwi.Constraint(left, operator, right ?? 0, strength);
541
+ this.#solver.addConstraint(constraint);
542
+ return constraint;
543
+ }
544
+ put(variable, strength = Strength.required) {
545
+ const eqStrength = strength === Strength.required ? Strength.soft : Strength.weak;
546
+ return {
547
+ before: (other, gap) => {
548
+ if (gap) other = other.minus(gap);
549
+ this.constraint(variable, "<=", other, strength);
550
+ this.constraint(variable, "==", other, eqStrength);
551
+ },
552
+ after: (other, gap) => {
553
+ if (gap) other = other.plus(gap);
554
+ this.constraint(variable, ">=", other, strength);
555
+ this.constraint(variable, "==", other, eqStrength);
556
+ }
557
+ };
558
+ }
559
+ };
560
+ //#endregion
561
+ export { SequenceViewLayouter, Strength };
@@ -1,11 +1,17 @@
1
1
  import { LayoutedDynamicView, ViewId } from '@likec4/core/types';
2
+ import { DiagramContext } from '../state/types';
2
3
  import { Types } from '../types';
3
4
  /**
4
5
  * Converts a sequence layout to XY flow nodes and edges.
5
6
  * @param view The next dynamic view which contains the sequence layout.
6
7
  * @param currentViewId The ID of the current view (optional, used to exclude navigation to the current view)
7
8
  */
8
- export declare function sequenceLayoutToXY(view: LayoutedDynamicView, currentViewId: ViewId | undefined): {
9
- xynodes: Array<Types.SequenceActorNode | Types.SequenceParallelArea | Types.ViewGroupNode>;
9
+ export declare function sequenceLayoutToXY({ view, currentViewId, collapsedFlows }: {
10
+ view: LayoutedDynamicView;
11
+ currentViewId: ViewId | undefined;
12
+ collapsedFlows: DiagramContext['collapsedSequenceFlows'];
13
+ }): {
14
+ xynodes: Array<Types.SequenceActorNode | Types.SequenceParallelArea | Types.SequenceSubflowArea | Types.ViewGroupNode>;
10
15
  xyedges: Array<Types.SequenceStepEdge>;
16
+ layout: LayoutedDynamicView.Sequence.Layout;
11
17
  };