@likec4/diagram 1.27.0 → 1.27.2

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 (151) hide show
  1. package/bundle/index.js +2343 -6880
  2. package/dist/LikeC4Diagram.js +3 -9
  3. package/dist/LikeC4Diagram.props.d.ts +5 -3
  4. package/dist/StaticLikeC4Diagram.js +1 -1
  5. package/dist/_virtual/set.js +5 -0
  6. package/dist/_virtual/set2.js +3 -0
  7. package/dist/base/BaseXYFlow.d.ts +2 -1
  8. package/dist/base/primitives/compound/CompoundNodeContainer.d.ts +1 -1
  9. package/dist/base/primitives/compound/CompoundNodeContainer.js +1 -2
  10. package/dist/base/primitives/edge/EdgeLabel.css.js +1 -4
  11. package/dist/base/primitives/edge/EdgeLabelContainer.js +1 -1
  12. package/dist/base/primitives/edge/EdgePath.js +0 -3
  13. package/dist/base/primitives/edge/edge.css.js +2 -0
  14. package/dist/base/primitives/element/ElementActionButtons.js +5 -10
  15. package/dist/base/primitives/element/ElementNodeContainer.css.js +5 -4
  16. package/dist/base/primitives/element/ElementShape.css.js +1 -12
  17. package/dist/base/primitives/element/ElementTitle.css.js +3 -2
  18. package/dist/base/types.js +2 -2
  19. package/dist/base/updateEdges.js +1 -9
  20. package/dist/base/updateNodes.js +1 -12
  21. package/dist/bundle/LikeC4View.js +2 -2
  22. package/dist/bundle/LikeC4View.props.d.ts +7 -7
  23. package/dist/components/Link.js +1 -1
  24. package/dist/hooks/useCurrentViewId.js +8 -2
  25. package/dist/hooks/useDiagram.d.ts +2659 -1996
  26. package/dist/hooks/useDiagram.js +16 -8
  27. package/dist/likec4diagram/DiagramXYFlow.js +10 -9
  28. package/dist/likec4diagram/custom/edges/RelationshipEdge.js +30 -41
  29. package/dist/likec4diagram/custom/nodes/toolbar/Toolbar.js +1 -1
  30. package/dist/likec4diagram/custom/nodes/toolbar/styles.css.js +6 -1
  31. package/dist/likec4diagram/ui/controls/LayoutDriftNotification.js +13 -5
  32. package/dist/likec4diagram/ui/notation/NotationPanel.css.js +3 -3
  33. package/dist/likec4diagram/ui/notation/NotationPanel.js +10 -4
  34. package/dist/likec4diagram/useLayoutConstraints.d.ts +11 -10
  35. package/dist/likec4diagram/useLayoutConstraints.js +64 -61
  36. package/dist/node_modules/.pnpm/mnemonist@0.40.3_patch_hash_5c12abb43fcff6fd81e53021b89075d53249640d165a2556cc1e58d71201a13a/node_modules/mnemonist/set.js +369 -0
  37. package/dist/overlays/Overlays.js +5 -3
  38. package/dist/overlays/element-details/actor.d.ts +2769 -173
  39. package/dist/overlays/overlay/Overlay.css.d.ts +26 -2
  40. package/dist/overlays/overlay/Overlay.css.js +83 -16
  41. package/dist/overlays/overlay/Overlay.d.ts +7 -6
  42. package/dist/overlays/overlay/Overlay.js +39 -32
  43. package/dist/overlays/overlaysActor.js +2 -2
  44. package/dist/overlays/relationship-details/RelationshipDetails.js +113 -70
  45. package/dist/overlays/relationship-details/SelectEdge.d.ts +1 -1
  46. package/dist/overlays/relationship-details/SelectEdge.js +15 -9
  47. package/dist/overlays/relationship-details/_types.d.ts +4 -1
  48. package/dist/overlays/relationship-details/actor.d.ts +415 -128
  49. package/dist/overlays/relationship-details/actor.js +162 -53
  50. package/dist/overlays/relationship-details/compute.d.ts +12 -0
  51. package/dist/overlays/relationship-details/compute.js +139 -0
  52. package/dist/overlays/relationship-details/custom/ElementActions.js +27 -5
  53. package/dist/overlays/relationship-details/custom/edgeTypes.js +1 -1
  54. package/dist/overlays/relationship-details/custom/nodeTypes.d.ts +2 -1
  55. package/dist/overlays/relationship-details/hooks.d.ts +336 -6
  56. package/dist/overlays/relationship-details/hooks.js +9 -7
  57. package/dist/overlays/relationship-details/layout-to-xyflow.d.ts +12 -0
  58. package/dist/overlays/relationship-details/layout-to-xyflow.js +149 -0
  59. package/dist/overlays/relationship-details/layout.d.ts +22 -0
  60. package/dist/overlays/relationship-details/layout.js +314 -0
  61. package/dist/overlays/relationships-browser/RelationshipsBrowser.d.ts +3 -1
  62. package/dist/overlays/relationships-browser/RelationshipsBrowser.js +2 -2
  63. package/dist/overlays/relationships-browser/SelectElement.js +4 -4
  64. package/dist/overlays/relationships-browser/_types.d.ts +2 -0
  65. package/dist/overlays/relationships-browser/actor.d.ts +130 -14
  66. package/dist/overlays/relationships-browser/actor.js +30 -16
  67. package/dist/overlays/relationships-browser/custom/ElementActions.js +5 -3
  68. package/dist/overlays/relationships-browser/custom/edgeTypes.d.ts +3 -1
  69. package/dist/overlays/relationships-browser/custom/edgeTypes.js +1 -1
  70. package/dist/overlays/relationships-browser/hooks.d.ts +3 -1
  71. package/dist/overlays/relationships-browser/hooks.js +1 -1
  72. package/dist/overlays/relationships-browser/{-useRelationshipsView.d.ts → layout.d.ts} +2 -0
  73. package/dist/overlays/relationships-browser/{-useRelationshipsView.js → layout.js} +19 -2
  74. package/dist/overlays/relationships-browser/useViewToNodesEdges.d.ts +1 -1
  75. package/dist/overlays/relationships-browser/useViewToNodesEdges.js +3 -1
  76. package/dist/packages/core/src/compute-view/relationships-view/compute.js +1 -1
  77. package/dist/packages/core/src/model/connection/model/ConnectionModel.js +121 -0
  78. package/dist/packages/core/src/model/connection/model/find.js +39 -0
  79. package/dist/packages/core/src/model/connection/ops.js +7 -0
  80. package/dist/packages/core/src/utils/const.js +3 -0
  81. package/dist/packages/core/src/utils/fqn.js +9 -1
  82. package/dist/packages/core/src/utils/iterable/find.js +21 -0
  83. package/dist/packages/core/src/utils/iterable/some.js +21 -0
  84. package/dist/packages/core/src/utils/set.js +48 -0
  85. package/dist/packages/core/src/utils/string-hash.js +13 -0
  86. package/dist/state/DiagramActorProvider.d.ts +4 -2
  87. package/dist/state/DiagramActorProvider.js +30 -37
  88. package/dist/state/assign.js +2 -2
  89. package/dist/state/diagram-machine.d.ts +1731 -1040
  90. package/dist/state/diagram-machine.js +126 -60
  91. package/dist/state/syncManualLayoutActor.d.ts +1 -1
  92. package/dist/styles.css.js +1 -1
  93. package/package.json +11 -11
  94. package/src/LikeC4Diagram.props.ts +7 -3
  95. package/src/LikeC4Diagram.tsx +2 -8
  96. package/src/StaticLikeC4Diagram.tsx +1 -1
  97. package/src/base/BaseXYFlow.tsx +2 -1
  98. package/src/base/primitives/compound/CompoundNodeContainer.tsx +1 -3
  99. package/src/base/primitives/edge/EdgeLabel.css.ts +1 -4
  100. package/src/base/primitives/edge/EdgeLabelContainer.tsx +1 -1
  101. package/src/base/primitives/edge/EdgePath.tsx +0 -3
  102. package/src/base/primitives/edge/edge.css.ts +2 -0
  103. package/src/base/primitives/element/ElementActionButtons.tsx +6 -7
  104. package/src/base/primitives/element/ElementNodeContainer.css.ts +5 -4
  105. package/src/base/primitives/element/ElementShape.css.ts +1 -12
  106. package/src/base/primitives/element/ElementTitle.css.ts +3 -2
  107. package/src/base/types.ts +2 -7
  108. package/src/base/updateEdges.ts +8 -8
  109. package/src/base/updateNodes.ts +11 -11
  110. package/src/bundle/LikeC4View.props.ts +7 -7
  111. package/src/bundle/LikeC4View.tsx +2 -2
  112. package/src/components/Link.tsx +3 -1
  113. package/src/hooks/useCurrentViewId.ts +4 -2
  114. package/src/hooks/useDiagram.ts +18 -9
  115. package/src/likec4diagram/DiagramXYFlow.tsx +11 -9
  116. package/src/likec4diagram/custom/edges/RelationshipEdge.tsx +39 -48
  117. package/src/likec4diagram/custom/nodes/toolbar/Toolbar.tsx +2 -2
  118. package/src/likec4diagram/custom/nodes/toolbar/styles.css.ts +5 -0
  119. package/src/likec4diagram/ui/controls/LayoutDriftNotification.tsx +8 -4
  120. package/src/likec4diagram/ui/notation/NotationPanel.css.ts +2 -2
  121. package/src/likec4diagram/ui/notation/NotationPanel.tsx +8 -6
  122. package/src/likec4diagram/useLayoutConstraints.ts +84 -89
  123. package/src/overlays/Overlays.tsx +5 -3
  124. package/src/overlays/overlay/Overlay.css.ts +83 -15
  125. package/src/overlays/overlay/Overlay.tsx +52 -41
  126. package/src/overlays/overlaysActor.ts +1 -1
  127. package/src/overlays/relationship-details/RelationshipDetails.tsx +131 -68
  128. package/src/overlays/relationship-details/SelectEdge.tsx +19 -12
  129. package/src/overlays/relationship-details/_types.ts +3 -1
  130. package/src/overlays/relationship-details/actor.ts +217 -68
  131. package/src/overlays/relationship-details/compute.ts +186 -0
  132. package/src/overlays/relationship-details/custom/ElementActions.tsx +27 -18
  133. package/src/overlays/relationship-details/custom/edgeTypes.tsx +1 -1
  134. package/src/overlays/relationship-details/hooks.ts +10 -8
  135. package/src/overlays/relationship-details/layout-to-xyflow.ts +195 -0
  136. package/src/overlays/relationship-details/layout.ts +470 -0
  137. package/src/overlays/relationships-browser/RelationshipsBrowser.tsx +2 -2
  138. package/src/overlays/relationships-browser/SelectElement.tsx +5 -5
  139. package/src/overlays/relationships-browser/_types.ts +2 -0
  140. package/src/overlays/relationships-browser/actor.ts +39 -14
  141. package/src/overlays/relationships-browser/custom/ElementActions.tsx +5 -3
  142. package/src/overlays/relationships-browser/custom/edgeTypes.tsx +1 -1
  143. package/src/overlays/relationships-browser/hooks.ts +2 -2
  144. package/src/overlays/relationships-browser/{-useRelationshipsView.ts → layout.ts} +23 -13
  145. package/src/overlays/relationships-browser/useViewToNodesEdges.ts +3 -1
  146. package/src/state/DiagramActorProvider.tsx +40 -50
  147. package/src/state/assign.ts +2 -2
  148. package/src/state/diagram-machine.ts +151 -75
  149. package/dist/overlays/relationship-details/useLayoutedDetails.d.ts +0 -19
  150. package/dist/overlays/relationship-details/useLayoutedDetails.js +0 -267
  151. package/src/overlays/relationship-details/useLayoutedDetails.ts +0 -376
@@ -1,376 +0,0 @@
1
- import dagre, { type GraphLabel, type Label } from '@dagrejs/dagre'
2
- import {
3
- type AbstractRelation,
4
- type DiagramEdge,
5
- type DiagramNode,
6
- type DiagramView,
7
- type EdgeId,
8
- type Fqn,
9
- type LikeC4Model,
10
- type XYPoint,
11
- compareFqnHierarchically,
12
- compareRelations,
13
- invariant,
14
- isAncestor,
15
- } from '@likec4/core'
16
- import { useMemo } from 'react'
17
- import { filter, first, forEach, isTruthy, map, pipe, prop, reverse, sort, sortBy, takeWhile } from 'remeda'
18
- import { useLikeC4Model } from '../../likec4model'
19
- import type { RelationshipDetailsTypes } from './_types'
20
-
21
- /**
22
- * All constants related to the layout
23
- */
24
- const Sizes = {
25
- dagre: {
26
- ranksep: 60,
27
- nodesep: 35,
28
- edgesep: 25,
29
- } satisfies GraphLabel,
30
- edgeLabel: {
31
- width: 120,
32
- height: 10,
33
- minlen: 1,
34
- } satisfies Label,
35
-
36
- nodeWidth: 330,
37
- hodeHeight: 180,
38
-
39
- // Spacer between elements in a compound node
40
- // 0 means no spacer
41
- spacerHeight: 0,
42
-
43
- compoundLabelHeight: 5,
44
- }
45
-
46
- export const ZIndexes = {
47
- compound: 0,
48
- // keep edges and elements in the same layer
49
- edge: 2,
50
- element: 2,
51
- max: 5,
52
- }
53
-
54
- // type DagreNodeData = {
55
- // portId: string
56
- // element: LikeC4Model.Element
57
- // isCompound: boolean
58
- // inPorts: string[]
59
- // outPorts: string[]
60
- // }
61
-
62
- function createGraph() {
63
- const g = new dagre.graphlib.Graph({
64
- directed: true,
65
- compound: true,
66
- })
67
- g.setGraph({
68
- ...Sizes.dagre,
69
- rankdir: 'LR',
70
- })
71
- g.setDefaultEdgeLabel(() => ({ ...Sizes.edgeLabel }))
72
- g.setDefaultNodeLabel(() => ({}))
73
-
74
- return g
75
- }
76
- type G = ReturnType<typeof createGraph>
77
-
78
- type Context = {
79
- g: ReturnType<typeof createGraph>
80
- diagramNodes: Map<Fqn, DiagramNode>
81
- xynodes: Map<Fqn, RelationshipDetailsTypes.Node>
82
- edge: DiagramEdge
83
- xyedges: RelationshipDetailsTypes.Edge[]
84
- }
85
- const sized = (height: number = Sizes.hodeHeight) => ({
86
- width: Sizes.nodeWidth,
87
- height,
88
- })
89
-
90
- const graphId = (node: RelationshipDetailsTypes.Node) => ({
91
- id: node.id,
92
- port: node.type === 'compound' ? `${node.id}::port` : node.id,
93
- })
94
-
95
- function nodeData(
96
- element: LikeC4Model.Element,
97
- ctx: Context,
98
- ): RelationshipDetailsTypes.ElementNodeData & RelationshipDetailsTypes.CompoundNodeData {
99
- // We try to inherit style from existing diagram node
100
- let diagramNode = ctx.diagramNodes.get(element.id)
101
-
102
- // Ansector separetely, because we want to inherit
103
- // color from it if there is no diagram node
104
- const ancestor = diagramNode ?? pipe(
105
- element.ancestors().toArray(),
106
- map(ancestor => ctx.diagramNodes.get(ancestor.id)),
107
- filter(isTruthy),
108
- first(),
109
- )
110
-
111
- return {
112
- fqn: element.id,
113
- title: diagramNode?.title ?? element.title,
114
- technology: diagramNode?.technology ?? element.technology,
115
- description: diagramNode?.description ?? element.description,
116
- color: diagramNode?.color ?? ancestor?.color ?? element.color,
117
- shape: diagramNode?.shape ?? element.shape,
118
- icon: diagramNode?.icon ?? element.icon ?? 'none',
119
- style: diagramNode?.style ?? element.$element.style ?? {},
120
- navigateTo: diagramNode?.navigateTo ?? first(element.scopedViews().take(1).toArray())?.id ?? null,
121
- width: 0,
122
- height: 0,
123
- depth: 1,
124
- ports: {
125
- in: [],
126
- out: [],
127
- },
128
- }
129
- }
130
-
131
- function createXYNode(
132
- nodeType: RelationshipDetailsTypes.Node['type'],
133
- element: LikeC4Model.Element,
134
- ctx: Context,
135
- ): RelationshipDetailsTypes.Node {
136
- let node = ctx.xynodes.get(element.id)
137
- if (node) {
138
- return node
139
- }
140
- const g = ctx.g
141
-
142
- // Create parent node
143
- const parent = pipe(
144
- [...element.ancestors()],
145
- takeWhile(ancestor => !isAncestor(ancestor.id, ctx.edge.source) && !isAncestor(ancestor.id, ctx.edge.target)),
146
- first(),
147
- found => found ? createXYNode('compound', found, ctx) : null,
148
- )
149
-
150
- const isCompound = nodeType === 'compound'
151
-
152
- const base = {
153
- id: element.id,
154
- draggable: false,
155
- selectable: true,
156
- focusable: true,
157
- deletable: false,
158
- position: { x: 0, y: 0 },
159
- zIndex: ZIndexes[nodeType],
160
- initialWidth: 0,
161
- initialHeight: 0,
162
- ...(!!parent && { parentId: parent.id }),
163
- } satisfies Omit<RelationshipDetailsTypes.Node, 'data' | 'type'>
164
-
165
- const xynode: RelationshipDetailsTypes.Node = {
166
- ...base,
167
- type: nodeType,
168
- data: nodeData(element, ctx),
169
- }
170
- ctx.xynodes.set(element.id, xynode)
171
- const k = graphId(xynode)
172
- g.setNode(k.id, sized())
173
-
174
- // There is one-to-one mapping between XYFlow node and dagre node
175
- // Compound node has two nodes: body and port (for edges)
176
- if (xynode.type === 'compound') {
177
- g.setNode(k.port, {
178
- width: Sizes.nodeWidth - Sizes.dagre.ranksep,
179
- height: Sizes.compoundLabelHeight,
180
- })
181
- g.setParent(k.port, k.id)
182
- }
183
-
184
- if (parent) {
185
- const parentGraphId = graphId(parent).id
186
- g.setParent(k.id, parentGraphId)
187
- }
188
-
189
- return xynode
190
- }
191
-
192
- /**
193
- * Apply dagre layout to the graph
194
- * And return a function to get node bounds for xyflow
195
- */
196
- function applyDagreLayout(g: G) {
197
- dagre.layout(g)
198
- return function nodeBounds(nodeId: string, relativeTo?: string): {
199
- position: XYPoint
200
- width: number
201
- height: number
202
- } {
203
- const { x, y, width, height } = g.node(nodeId)
204
- const pos = {
205
- position: {
206
- x: x - Math.round(width / 2),
207
- y: y - Math.round(height / 2),
208
- },
209
- width,
210
- height,
211
- }
212
- if (!relativeTo) {
213
- return pos
214
- }
215
- const offset = nodeBounds(relativeTo).position
216
- return {
217
- position: {
218
- x: pos.position.x - offset.x,
219
- y: pos.position.y - offset.y,
220
- },
221
- width: pos.width,
222
- height: pos.height,
223
- }
224
- }
225
- }
226
-
227
- function layout(
228
- edge: DiagramEdge,
229
- view: DiagramView,
230
- likec4model: LikeC4Model,
231
- ): {
232
- edge: DiagramEdge
233
- xynodes: RelationshipDetailsTypes.Node[]
234
- xyedges: RelationshipDetailsTypes.Edge[]
235
- bounds: { x: number; y: number; width: number; height: number }
236
- } {
237
- const all = new Set([edge.source, edge.target])
238
-
239
- const relations = edge.relations
240
- .map(r => {
241
- const relation = likec4model.relationship(r)
242
- all.add(relation.source.id)
243
- all.add(relation.target.id)
244
- return {
245
- source: relation.source.id,
246
- target: relation.target.id,
247
- relation: relation.$relationship as AbstractRelation,
248
- }
249
- })
250
- .sort(compareRelations)
251
- .reverse()
252
-
253
- const diagramNodes = new Map(view.nodes.map(n => [n.id, n]))
254
- const g = createGraph()
255
-
256
- const ctx: Context = {
257
- g,
258
- xynodes: new Map(),
259
- edge,
260
- diagramNodes,
261
- xyedges: [],
262
- }
263
-
264
- pipe(
265
- [...all],
266
- sort(compareFqnHierarchically),
267
- reverse(),
268
- forEach(id => {
269
- const element = likec4model.element(id)
270
- createXYNode('element', element, ctx)
271
- }),
272
- )
273
-
274
- if (relations.length === 1 && all.size < 4) {
275
- g.setDefaultEdgeLabel(() => ({ width: 250 }))
276
- }
277
-
278
- for (const { relation, ...points } of relations) {
279
- const source = ctx.xynodes.get(points.source)
280
- invariant(source, 'source node not found')
281
- const target = ctx.xynodes.get(points.target)
282
- invariant(target, 'target node not found')
283
-
284
- source.data.ports.out.push(target.id)
285
- target.data.ports.in.push(source.id)
286
-
287
- g.setEdge(graphId(source).port, graphId(target).port)
288
- const edge: RelationshipDetailsTypes.Edge = {
289
- id: relation.id,
290
- type: 'relationship',
291
- source: source.id,
292
- target: target.id,
293
- sourceHandle: source.id + '_out' + (source.data.ports.out.length - 1),
294
- targetHandle: target.id + '_in' + (target.data.ports.in.length - 1),
295
- data: {
296
- relationId: relation.id,
297
- color: relation.color,
298
- label: relation.title ?? null,
299
- technology: relation.technology,
300
- description: relation.description,
301
- navigateTo: relation.navigateTo ?? null,
302
- line: relation.line ?? 'dashed',
303
- },
304
- zIndex: ZIndexes.edge,
305
- }
306
- ctx.xyedges.push(edge)
307
- }
308
-
309
- const nodebounds = applyDagreLayout(ctx.g)
310
-
311
- // Sort ports
312
- const sortedPorts = (nodeId: string, type: 'in' | 'out', ports: string[]) => {
313
- return pipe(
314
- ports,
315
- map((port, index) => {
316
- return {
317
- port: nodeId + '_' + type + index,
318
- topY: nodebounds(port).position.y,
319
- }
320
- }),
321
- sortBy(prop('topY')),
322
- map(prop('port')),
323
- )
324
- }
325
-
326
- const xynodes = [...ctx.xynodes.values()].map((node) => {
327
- const { position, width, height } = nodebounds(node.id, node.parentId)
328
- node.data.ports.in = sortedPorts(node.id, 'in', node.data.ports.in)
329
- node.data.ports.out = sortedPorts(node.id, 'out', node.data.ports.out)
330
- if (node.type === 'element') {
331
- node.data.width = width
332
- node.data.height = height
333
- }
334
- node.position = position
335
- node.initialHeight = height
336
- node.initialWidth = width
337
- node.style = {
338
- width,
339
- height,
340
- }
341
- return node
342
- })
343
-
344
- return {
345
- edge,
346
- xyedges: ctx.xyedges,
347
- xynodes,
348
- bounds: {
349
- x: 0,
350
- y: 0,
351
- width: g.graph().width ?? 0,
352
- height: g.graph().height ?? 0,
353
- },
354
- }
355
- }
356
-
357
- export function useLayoutedDetails(edgeId: EdgeId, view: DiagramView): {
358
- edge: DiagramEdge
359
- xynodes: RelationshipDetailsTypes.Node[]
360
- xyedges: RelationshipDetailsTypes.Edge[]
361
- bounds: { x: number; y: number; width: number; height: number }
362
- } {
363
- const edge = view.edges.find(e => e.id === edgeId)
364
- invariant(edge, `edge ${edgeId} not found in ${view.id}`)
365
- const likec4model = useLikeC4Model(true)
366
- return useMemo(() =>
367
- layout(
368
- edge,
369
- view,
370
- likec4model,
371
- ), [
372
- edge,
373
- view,
374
- layout,
375
- ])
376
- }