@likec4/diagram 1.27.1 → 1.27.3

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 (123) hide show
  1. package/bundle/index.js +2152 -6757
  2. package/dist/LikeC4Diagram.js +1 -1
  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 +0 -1
  10. package/dist/base/primitives/edge/EdgeLabelContainer.js +3 -2
  11. package/dist/base/primitives/element/ElementActionButtons.js +8 -11
  12. package/dist/base/primitives/element/ElementNodeContainer.css.js +4 -4
  13. package/dist/base/updateEdges.js +1 -9
  14. package/dist/base/updateNodes.js +1 -12
  15. package/dist/bundle/LikeC4View.js +2 -2
  16. package/dist/bundle/LikeC4View.props.d.ts +7 -7
  17. package/dist/hooks/useCurrentViewId.js +8 -2
  18. package/dist/hooks/useDiagram.d.ts +1522 -685
  19. package/dist/hooks/useDiagram.js +21 -24
  20. package/dist/likec4diagram/DiagramXYFlow.js +6 -6
  21. package/dist/likec4diagram/ui/notation/NotationPanel.css.js +3 -3
  22. package/dist/likec4diagram/ui/notation/NotationPanel.js +10 -4
  23. package/dist/node_modules/.pnpm/mnemonist@0.40.3_patch_hash_5c12abb43fcff6fd81e53021b89075d53249640d165a2556cc1e58d71201a13a/node_modules/mnemonist/set.js +369 -0
  24. package/dist/overlays/Overlays.js +3 -1
  25. package/dist/overlays/element-details/actor.d.ts +2769 -173
  26. package/dist/overlays/overlay/Overlay.css.d.ts +26 -2
  27. package/dist/overlays/overlay/Overlay.css.js +66 -18
  28. package/dist/overlays/overlay/Overlay.d.ts +7 -6
  29. package/dist/overlays/overlay/Overlay.js +12 -10
  30. package/dist/overlays/overlaysActor.js +2 -2
  31. package/dist/overlays/relationship-details/RelationshipDetails.js +113 -70
  32. package/dist/overlays/relationship-details/SelectEdge.d.ts +1 -1
  33. package/dist/overlays/relationship-details/SelectEdge.js +15 -9
  34. package/dist/overlays/relationship-details/_types.d.ts +4 -1
  35. package/dist/overlays/relationship-details/actor.d.ts +425 -128
  36. package/dist/overlays/relationship-details/actor.js +157 -53
  37. package/dist/overlays/relationship-details/compute.d.ts +12 -0
  38. package/dist/overlays/relationship-details/compute.js +139 -0
  39. package/dist/overlays/relationship-details/custom/ElementActions.js +27 -5
  40. package/dist/overlays/relationship-details/custom/edgeTypes.js +1 -1
  41. package/dist/overlays/relationship-details/custom/nodeTypes.d.ts +2 -1
  42. package/dist/overlays/relationship-details/hooks.d.ts +336 -6
  43. package/dist/overlays/relationship-details/hooks.js +11 -12
  44. package/dist/overlays/relationship-details/layout-to-xyflow.d.ts +12 -0
  45. package/dist/overlays/relationship-details/layout-to-xyflow.js +145 -0
  46. package/dist/overlays/relationship-details/layout.d.ts +22 -0
  47. package/dist/overlays/relationship-details/layout.js +314 -0
  48. package/dist/overlays/relationships-browser/RelationshipsBrowser.d.ts +3 -1
  49. package/dist/overlays/relationships-browser/RelationshipsBrowser.js +2 -2
  50. package/dist/overlays/relationships-browser/_types.d.ts +2 -0
  51. package/dist/overlays/relationships-browser/actor.d.ts +130 -14
  52. package/dist/overlays/relationships-browser/actor.js +30 -16
  53. package/dist/overlays/relationships-browser/custom/ElementActions.js +5 -3
  54. package/dist/overlays/relationships-browser/custom/edgeTypes.d.ts +3 -1
  55. package/dist/overlays/relationships-browser/custom/edgeTypes.js +1 -1
  56. package/dist/overlays/relationships-browser/hooks.d.ts +3 -1
  57. package/dist/overlays/relationships-browser/hooks.js +6 -9
  58. package/dist/overlays/relationships-browser/{-useRelationshipsView.d.ts → layout.d.ts} +3 -1
  59. package/dist/overlays/relationships-browser/{-useRelationshipsView.js → layout.js} +21 -8
  60. package/dist/overlays/relationships-browser/useViewToNodesEdges.d.ts +1 -1
  61. package/dist/overlays/relationships-browser/useViewToNodesEdges.js +3 -1
  62. package/dist/packages/core/src/compute-view/relationships-view/compute.js +1 -1
  63. package/dist/packages/core/src/model/connection/model/ConnectionModel.js +121 -0
  64. package/dist/packages/core/src/model/connection/model/find.js +39 -0
  65. package/dist/packages/core/src/model/connection/ops.js +7 -0
  66. package/dist/packages/core/src/utils/const.js +3 -0
  67. package/dist/packages/core/src/utils/fqn.js +9 -1
  68. package/dist/packages/core/src/utils/iterable/find.js +21 -0
  69. package/dist/packages/core/src/utils/iterable/some.js +21 -0
  70. package/dist/packages/core/src/utils/set.js +48 -0
  71. package/dist/packages/core/src/utils/string-hash.js +13 -0
  72. package/dist/state/diagram-machine.d.ts +1552 -703
  73. package/dist/state/diagram-machine.js +39 -3
  74. package/dist/state/syncManualLayoutActor.d.ts +1 -1
  75. package/dist/styles.css.js +1 -1
  76. package/dist/utils/index.d.ts +0 -1
  77. package/package.json +11 -11
  78. package/src/LikeC4Diagram.props.ts +7 -3
  79. package/src/LikeC4Diagram.tsx +1 -1
  80. package/src/StaticLikeC4Diagram.tsx +1 -1
  81. package/src/base/BaseXYFlow.tsx +2 -1
  82. package/src/base/primitives/compound/CompoundNodeContainer.tsx +0 -2
  83. package/src/base/primitives/edge/EdgeLabelContainer.tsx +7 -5
  84. package/src/base/primitives/element/ElementActionButtons.tsx +10 -11
  85. package/src/base/primitives/element/ElementNodeContainer.css.ts +4 -4
  86. package/src/base/updateEdges.ts +8 -8
  87. package/src/base/updateNodes.ts +11 -11
  88. package/src/bundle/LikeC4View.props.ts +7 -7
  89. package/src/bundle/LikeC4View.tsx +2 -2
  90. package/src/hooks/useCurrentViewId.ts +4 -2
  91. package/src/hooks/useDiagram.ts +22 -24
  92. package/src/likec4diagram/DiagramXYFlow.tsx +6 -6
  93. package/src/likec4diagram/ui/notation/NotationPanel.css.ts +2 -2
  94. package/src/likec4diagram/ui/notation/NotationPanel.tsx +8 -6
  95. package/src/overlays/Overlays.tsx +4 -2
  96. package/src/overlays/overlay/Overlay.css.ts +67 -17
  97. package/src/overlays/overlay/Overlay.tsx +27 -24
  98. package/src/overlays/overlaysActor.ts +1 -1
  99. package/src/overlays/relationship-details/RelationshipDetails.tsx +131 -68
  100. package/src/overlays/relationship-details/SelectEdge.tsx +19 -12
  101. package/src/overlays/relationship-details/_types.ts +3 -1
  102. package/src/overlays/relationship-details/actor.ts +212 -68
  103. package/src/overlays/relationship-details/compute.ts +186 -0
  104. package/src/overlays/relationship-details/custom/ElementActions.tsx +27 -18
  105. package/src/overlays/relationship-details/custom/edgeTypes.tsx +1 -1
  106. package/src/overlays/relationship-details/hooks.ts +12 -13
  107. package/src/overlays/relationship-details/layout-to-xyflow.ts +172 -0
  108. package/src/overlays/relationship-details/layout.ts +470 -0
  109. package/src/overlays/relationships-browser/RelationshipsBrowser.tsx +2 -2
  110. package/src/overlays/relationships-browser/_types.ts +2 -0
  111. package/src/overlays/relationships-browser/actor.ts +39 -14
  112. package/src/overlays/relationships-browser/custom/ElementActions.tsx +5 -3
  113. package/src/overlays/relationships-browser/custom/edgeTypes.tsx +1 -1
  114. package/src/overlays/relationships-browser/hooks.ts +7 -10
  115. package/src/overlays/relationships-browser/{-useRelationshipsView.ts → layout.ts} +26 -33
  116. package/src/overlays/relationships-browser/useViewToNodesEdges.ts +3 -1
  117. package/src/state/diagram-machine.ts +51 -6
  118. package/src/utils/index.ts +0 -1
  119. package/dist/overlays/relationship-details/useLayoutedDetails.d.ts +0 -19
  120. package/dist/overlays/relationship-details/useLayoutedDetails.js +0 -267
  121. package/dist/utils/types.d.ts +0 -8
  122. package/src/overlays/relationship-details/useLayoutedDetails.ts +0 -376
  123. package/src/utils/types.ts +0 -6
@@ -26,10 +26,11 @@ import { Base } from '../../base'
26
26
  import { MinZoom, ZIndexes } from '../../base/const'
27
27
  import { updateEdges } from '../../base/updateEdges'
28
28
  import { updateNodes } from '../../base/updateNodes'
29
+ import { typedSystem } from '../../state/utils'
29
30
  import { centerXYInternalNode } from '../../utils'
30
- import type { LayoutRelationshipsViewResult } from './-useRelationshipsView'
31
31
  import type { RelationshipsBrowserTypes } from './_types'
32
32
  import { ViewPadding } from './const'
33
+ import type { LayoutRelationshipsViewResult } from './layout'
33
34
  import { viewToNodesEdge } from './useViewToNodesEdges'
34
35
 
35
36
  type XYFLowInstance = ReactFlowInstance<RelationshipsBrowserTypes.Node, RelationshipsBrowserTypes.Edge>
@@ -247,6 +248,7 @@ export const relationshipsBrowserLogic = setup({
247
248
  layouter,
248
249
  },
249
250
  guards: {
251
+ hasViewId: ({ context }) => context.viewId !== null,
250
252
  isReady: ({ context }) => context.xyflow !== null && context.xystore !== null && context.layouted !== null,
251
253
  anotherSubject: ({ context, event }) => {
252
254
  if (event.type === 'update.view') {
@@ -393,10 +395,27 @@ export const relationshipsBrowserLogic = setup({
393
395
  }
394
396
  }),
395
397
  },
398
+ 'xyflow.edgeClick': {
399
+ guard: 'hasViewId',
400
+ actions: enqueueActions(({ event, context, system, enqueue }) => {
401
+ if (
402
+ event.edge.selected || event.edge.data.relations.length > 1
403
+ // (context.xyedges.some(e => e.data.dimmed === true || e.data.dimmed === 'immediate') && !event.edge.data.dimmed)
404
+ ) {
405
+ enqueue.sendTo(typedSystem(system).overlaysActorRef!, {
406
+ type: 'open.relationshipDetails',
407
+ viewId: context.viewId!,
408
+ source: event.edge.data.sourceFqn,
409
+ target: event.edge.data.targetFqn,
410
+ })
411
+ }
412
+ }),
413
+ },
396
414
  'navigate.to': {
397
415
  actions: [
398
416
  assign({
399
417
  subject: ({ event }) => event.subject,
418
+ viewId: ({ event, context }) => event.viewId ?? context.viewId ?? null,
400
419
  navigateFromNode: ({ event }) => event.fromNode ?? null,
401
420
  }),
402
421
  ],
@@ -443,7 +462,7 @@ export const relationshipsBrowserLogic = setup({
443
462
  actions: [
444
463
  assign({
445
464
  xyedges: ({ context, event }) => {
446
- const hasDimmed = context.xyedges.some(edge => edge.data.dimmed === true)
465
+ const hasDimmed = context.xyedges.some(edge => edge.data.dimmed !== false || edge.selected)
447
466
  return context.xyedges.map(edge => {
448
467
  if (edge.id === event.edge.id) {
449
468
  return Base.setData(edge, {
@@ -451,25 +470,26 @@ export const relationshipsBrowserLogic = setup({
451
470
  dimmed: false,
452
471
  })
453
472
  }
454
- return hasDimmed && !edge.data.dimmed && !edge.selected ? Base.setDimmed(edge, 'immediate') : edge
473
+ return hasDimmed && !edge.selected ? Base.setDimmed(edge, 'immediate') : edge
455
474
  })
456
475
  },
457
476
  }),
458
477
  cancel('undim.edges'),
459
478
  cancel('dim.nonhovered.edges'),
460
- raise({ type: 'dim.nonhovered.edges' }, { id: 'dim.nonhovered.edges', delay: 100 }),
479
+ raise({ type: 'dim.nonhovered.edges' }, { id: 'dim.nonhovered.edges', delay: 200 }),
461
480
  ],
462
481
  },
463
482
  'xyflow.edgeMouseLeave': {
464
483
  actions: [
465
484
  assign({
466
- xyedges: ({ context, event }) =>
467
- context.xyedges.map(edge => {
485
+ xyedges: ({ context, event }) => {
486
+ return context.xyedges.map(edge => {
468
487
  if (edge.id === event.edge.id) {
469
488
  return Base.setHovered(edge, false)
470
489
  }
471
490
  return edge
472
- }),
491
+ })
492
+ },
473
493
  }),
474
494
  cancel('dim.nonhovered.edges'),
475
495
  raise({ type: 'undim.edges' }, { id: 'undim.edges', delay: 400 }),
@@ -477,18 +497,23 @@ export const relationshipsBrowserLogic = setup({
477
497
  },
478
498
  'dim.nonhovered.edges': {
479
499
  actions: assign({
480
- xyedges: ({ context }) => context.xyedges.map(edge => Base.setDimmed(edge, edge.data.hovered !== true)),
500
+ xyedges: ({ context }) =>
501
+ context.xyedges.map(edge =>
502
+ edge.data.hovered
503
+ ? edge
504
+ : Base.setDimmed(edge, edge.data.dimmed === 'immediate' ? 'immediate' : true)
505
+ ),
481
506
  }),
482
507
  },
483
508
  'undim.edges': {
484
509
  actions: assign({
485
510
  xyedges: ({ context }) => {
486
- const hasSelected = context.xyedges.some(edge => edge.selected === true)
487
- if (hasSelected) {
488
- return context.xyedges.map(edge =>
489
- Base.setDimmed(edge, edge.selected !== true ? edge.data.dimmed || 'immediate' : false)
490
- )
491
- }
511
+ // const hasSelected = context.xyedges.some(edge => edge.selected === true)
512
+ // if (hasSelected) {
513
+ // return context.xyedges.map(edge =>
514
+ // Base.setDimmed(edge, edge.selected !== true ? 'immediate' : false)
515
+ // )
516
+ // }
492
517
  return context.xyedges.map(Base.setDimmed(false))
493
518
  },
494
519
  }),
@@ -1,22 +1,24 @@
1
1
  import { IconFileSymlink, IconTransform, IconZoomScan } from '@tabler/icons-react'
2
2
  import { ElementActionButtons } from '../../../base/primitives'
3
3
  import type { NodeProps } from '../../../base/types'
4
- import { useEnabledFeature } from '../../../context/DiagramFeatures'
4
+ import { useEnabledFeatures } from '../../../context/DiagramFeatures'
5
+ import { useCurrentViewId } from '../../../hooks/useCurrentViewId'
5
6
  import { useDiagram } from '../../../hooks/useDiagram'
6
7
  import type { RelationshipsBrowserTypes as Types } from '../_types'
7
8
  import { useRelationshipsBrowser, useRelationshipsBrowserState } from '../hooks'
8
9
 
9
10
  type ElementActionsProps = NodeProps<Types.ElementNodeData>
10
11
  export const ElementActions = (props: ElementActionsProps) => {
11
- const { enableNavigateTo, enableVscode } = useEnabledFeature('NavigateTo', 'Vscode')
12
+ const { enableNavigateTo, enableVscode } = useEnabledFeatures()
12
13
  const diagram = useDiagram()
14
+ const currentViewId = useCurrentViewId()
13
15
  const browser = useRelationshipsBrowser()
14
16
  const subject = useRelationshipsBrowserState(s => s.context.subject)
15
17
 
16
18
  const buttons = [] as ElementActionButtons.Item[]
17
19
 
18
20
  const { navigateTo, fqn } = props.data
19
- if (navigateTo && enableNavigateTo) {
21
+ if (navigateTo && enableNavigateTo && currentViewId !== navigateTo) {
20
22
  buttons.push({
21
23
  key: 'navigate',
22
24
  icon: <IconZoomScan />,
@@ -67,7 +67,7 @@ export const RelationshipEdge = customEdge<RelationshipsBrowserTypes.EdgeData>((
67
67
  label="This relationship is not included in the current view"
68
68
  // withinPortal={false}
69
69
  portalProps={{
70
- target: `#${browser.rootElementId.replaceAll(':', '\\:')}`,
70
+ target: `#${browser.rootElementId}`,
71
71
  }}
72
72
  openDelay={800}
73
73
  >
@@ -2,10 +2,10 @@ import { type Fqn, nonNullable } from '@likec4/core'
2
2
  import { useCallbackRef } from '@mantine/hooks'
3
3
  import { useSelector } from '@xstate/react'
4
4
  import { shallowEqual } from 'fast-equals'
5
- import { createContext, useContext, useMemo, useTransition } from 'react'
5
+ import { createContext, useContext, useMemo } from 'react'
6
6
  import type { OverlaysActorRef } from '../overlaysActor'
7
- import type { LayoutRelationshipsViewResult } from './-useRelationshipsView'
8
7
  import type { RelationshipsBrowserActorRef, RelationshipsBrowserSnapshot } from './actor'
8
+ import type { LayoutRelationshipsViewResult } from './layout'
9
9
 
10
10
  export const RelationshipsBrowserActorContext = createContext<RelationshipsBrowserActorRef | null>(null)
11
11
 
@@ -23,11 +23,10 @@ export function useRelationshipsBrowserState<T>(
23
23
 
24
24
  export function useRelationshipsBrowser() {
25
25
  const actor = useRelationshipsBrowserActor()
26
- const [, startTransition] = useTransition()
27
26
  return useMemo(() => ({
28
27
  actor,
29
28
  get rootElementId(): string {
30
- return `relationships-browser-${actor.sessionId}`
29
+ return `relationships-browser-${actor.sessionId.replaceAll(':', '_')}`
31
30
  },
32
31
  getState: () => actor.getSnapshot().context,
33
32
  send: actor.send,
@@ -44,12 +43,10 @@ export function useRelationshipsBrowser() {
44
43
  })
45
44
  },
46
45
  navigateTo: (subject: Fqn, fromNode?: string) => {
47
- startTransition(() => {
48
- actor.send({
49
- type: 'navigate.to',
50
- subject,
51
- fromNode,
52
- })
46
+ actor.send({
47
+ type: 'navigate.to',
48
+ subject,
49
+ fromNode,
53
50
  })
54
51
  },
55
52
  fitDiagram: () => {
@@ -55,7 +55,7 @@ const Sizes = {
55
55
  edgesep: 25,
56
56
  } satisfies GraphLabel,
57
57
  edgeLabel: {
58
- width: 120,
58
+ width: 140,
59
59
  height: 10,
60
60
  minlen: 1,
61
61
  weight: 1,
@@ -97,19 +97,6 @@ function createGraph() {
97
97
  g.setDefaultEdgeLabel(() => ({ ...Sizes.edgeLabel }))
98
98
  g.setDefaultNodeLabel(() => ({}))
99
99
 
100
- // columns.reduce((prev, column) => {
101
- // const c = graphColumn(column)
102
- // g.setNode(c.id, {})
103
- // g.setNode(c.anchor, { width: 40, height: 2 })
104
- // g.setParent(c.anchor, c.id)
105
- // if (prev) {
106
- // g.setEdge(prev, c.anchor, {
107
- // width: 0
108
- // })
109
- // }
110
- // return c.anchor
111
- // }, null as string | null)
112
-
113
100
  return g
114
101
  }
115
102
  type G = ReturnType<typeof createGraph>
@@ -212,12 +199,14 @@ export type LayoutRelationshipsViewResult = {
212
199
  export namespace LayoutRelationshipsViewResult {
213
200
  export const Empty = '@empty' as ElementKind
214
201
 
215
- export type Node = DiagramNode & {
202
+ export type Node = Omit<DiagramNode, 'deploymentRef' | 'inEdges' | 'outEdges'> & {
216
203
  column: RelationshipsBrowserTypes.Column
217
204
  ports: RelationshipsBrowserTypes.Ports
218
205
  existsInCurrentView: boolean
219
206
  }
220
207
  export type Edge = DiagramEdge & {
208
+ sourceFqn: Fqn
209
+ targetFqn: Fqn
221
210
  sourceHandle: string
222
211
  targetHandle: string
223
212
  existsInCurrentView: boolean
@@ -239,6 +228,8 @@ export function layoutRelationshipsView(
239
228
  name: string
240
229
  source: string // node id
241
230
  target: string // node id
231
+ sourceFqn: Fqn
232
+ targetFqn: Fqn
242
233
  sourceHandle: string
243
234
  targetHandle: string
244
235
  relations: RelationshipModel[]
@@ -250,6 +241,8 @@ export function layoutRelationshipsView(
250
241
  toArray(data.incoming),
251
242
  map(r => ({
252
243
  id: r.source.id,
244
+ sourceFqn: r.source.id,
245
+ targetFqn: r.target.id,
253
246
  source: incomers.byId(r.source.id).graph,
254
247
  target: subjects.byId(r.target.id).graph,
255
248
  relation: r,
@@ -259,6 +252,8 @@ export function layoutRelationshipsView(
259
252
  toArray(data.outgoing),
260
253
  map(r => ({
261
254
  id: r.target.id,
255
+ sourceFqn: r.source.id,
256
+ targetFqn: r.target.id,
262
257
  source: subjects.byId(r.source.id).graph,
263
258
  target: outgoers.byId(r.target.id).graph,
264
259
  relation: r,
@@ -284,6 +279,8 @@ export function layoutRelationshipsView(
284
279
  }, name)
285
280
  edges.push({
286
281
  name,
282
+ sourceFqn: grouped[0].sourceFqn,
283
+ targetFqn: grouped[0].targetFqn,
287
284
  source: source.id,
288
285
  sourceHandle: source.id + '_out' + (g.node(source.id).outPorts.length - 1),
289
286
  target: target.id,
@@ -358,7 +355,7 @@ export function layoutRelationshipsView(
358
355
  for (const edge of g.edges()) {
359
356
  g.setEdge(edge, {
360
357
  ...Sizes.edgeLabel,
361
- width: edgeCount > 30 ? 800 : 400,
358
+ width: edgeCount > 25 ? 800 : 400,
362
359
  })
363
360
  }
364
361
  }
@@ -444,17 +441,6 @@ export function layoutRelationshipsView(
444
441
  const [subject] = [...subjects.root]
445
442
  invariant(subject, 'Subjects should not be empty')
446
443
  let subjectBounds = nodeBounds(subjects.graphNodes.get(subject.id).id)
447
- // let subjectBounds = rest.reduce((bounds, el) => {
448
- // const elBounds = nodeBounds(subjects.graphNodes.get(el.id).id)
449
- // return {
450
- // position: {
451
- // x: Math.min(bounds.position.x, elBounds.position.x),
452
- // y: Math.min(bounds.position.y, elBounds.position.y),
453
- // },
454
- // width: Math.max(bounds.width, elBounds.width),
455
- // height: Math.max(bounds.height, elBounds.height),
456
- // }
457
- // }, nodeBounds(subjects.graphNodes.get(subject.id).id))
458
444
 
459
445
  const nodes = nodeIds.map(({ id }): LayoutRelationshipsViewResult.Node => {
460
446
  const { element, inPorts, outPorts, column } = g.node(id)
@@ -493,8 +479,6 @@ export function layoutRelationshipsView(
493
479
  width: width,
494
480
  height: height,
495
481
  },
496
- inEdges: [],
497
- outEdges: [],
498
482
  children: [],
499
483
  width,
500
484
  height,
@@ -513,7 +497,7 @@ export function layoutRelationshipsView(
513
497
  minX = Math.min(minX, position.x)
514
498
  minY = Math.min(minY, position.y)
515
499
 
516
- const navigateTo = element.defaultView?.id ?? null
500
+ const navigateTo = scope ? ifind(element.scopedViews(), v => v.id !== scope.id)?.id ?? null : null
517
501
 
518
502
  const inheritFromNode = scope?.findNodeWithElement(element.id)
519
503
  const scopedAncestor = scope && !inheritFromNode
@@ -547,8 +531,6 @@ export function layoutRelationshipsView(
547
531
  ...element.$element.style,
548
532
  },
549
533
  navigateTo,
550
- inEdges: [],
551
- outEdges: [],
552
534
  ...(children.length > 0 && { depth: nodeDepth(id) }),
553
535
  children,
554
536
  width,
@@ -577,7 +559,16 @@ export function layoutRelationshipsView(
577
559
  if (!ename) {
578
560
  return acc
579
561
  }
580
- const { name, source, target, relations, sourceHandle, targetHandle } = find(edges, e => e.name === ename)!
562
+ const {
563
+ name,
564
+ source,
565
+ sourceFqn,
566
+ target,
567
+ targetFqn,
568
+ relations,
569
+ sourceHandle,
570
+ targetHandle,
571
+ } = find(edges, e => e.name === ename)!
581
572
  const onlyRelation = only(relations)
582
573
  const label = onlyRelation?.title ?? 'untitled'
583
574
  const isMultiple = relations.length > 1
@@ -587,8 +578,10 @@ export function layoutRelationshipsView(
587
578
  // const edge = g.edge(name)
588
579
  acc.push({
589
580
  id: name as EdgeId,
581
+ sourceFqn,
590
582
  source: source as NodeId,
591
583
  sourceHandle,
584
+ targetFqn,
592
585
  target: target as NodeId,
593
586
  targetHandle,
594
587
  label: isMultiple ? `${relations.length} relationships` : label,
@@ -9,8 +9,8 @@ import {
9
9
  import { useDeepCompareMemo } from '@react-hookz/web'
10
10
  import { hasAtLeast } from 'remeda'
11
11
  import { ZIndexes } from '../../base/const'
12
- import { LayoutRelationshipsViewResult } from './-useRelationshipsView'
13
12
  import type { RelationshipsBrowserTypes } from './_types'
13
+ import { LayoutRelationshipsViewResult } from './layout'
14
14
 
15
15
  // const nodeZIndex = (node: DiagramNode) => node.level - (node.children.length > 0 ? 1 : 0)
16
16
  export function viewToNodesEdge(
@@ -183,6 +183,8 @@ export function viewToNodesEdge(
183
183
  // hidden: !visiblePredicate(edge),
184
184
  deletable: false,
185
185
  data: {
186
+ sourceFqn: edge.sourceFqn,
187
+ targetFqn: edge.targetFqn,
186
188
  relations: edge.relations,
187
189
  color: edge.color ?? 'gray',
188
190
  label: edge.label,
@@ -2,6 +2,7 @@ import {
2
2
  type BBox,
3
3
  type DiagramView,
4
4
  type EdgeId,
5
+ type ElementNotation,
5
6
  type Fqn,
6
7
  type NodeId,
7
8
  type StepEdgeId,
@@ -23,7 +24,7 @@ import {
23
24
  useStoreApi,
24
25
  } from '@xyflow/react'
25
26
  import { type EdgeChange, type NodeChange, type Rect, type Viewport, nodeToRect } from '@xyflow/system'
26
- import { clamp, first, hasAtLeast, prop } from 'remeda'
27
+ import { clamp, first, hasAtLeast, prop, reduce } from 'remeda'
27
28
  import {
28
29
  type ActorLogicFrom,
29
30
  type ActorRef,
@@ -44,7 +45,7 @@ import {
44
45
  import { MinZoom } from '../base/const'
45
46
  import { Base } from '../base/types'
46
47
  import { type EnabledFeatures, type FeatureName, AllDisabled } from '../context/DiagramFeatures'
47
- import type { OpenSourceParams } from '../LikeC4Diagram.props'
48
+ import type { OpenSourceParams, PaddingWithUnit } from '../LikeC4Diagram.props'
48
49
  import type { Types } from '../likec4diagram/types'
49
50
  import { createLayoutConstraints } from '../likec4diagram/useLayoutConstraints'
50
51
  import { overlaysActorLogic } from '../overlays/overlaysActor'
@@ -83,7 +84,7 @@ export interface Input {
83
84
  xystore: XYStoreApi
84
85
  zoomable: boolean
85
86
  pannable: boolean
86
- fitViewPadding: number
87
+ fitViewPadding: PaddingWithUnit
87
88
  nodesSelectable: boolean
88
89
  }
89
90
 
@@ -156,7 +157,7 @@ export type Events =
156
157
  | { type: 'fitDiagram'; duration?: number; bounds?: BBox }
157
158
  | ({ type: 'open.source' } & OpenSourceParams)
158
159
  | { type: 'open.elementDetails'; fqn: Fqn; fromNode?: NodeId | undefined }
159
- | { type: 'open.relationshipDetails'; edgeId: EdgeId }
160
+ | { type: 'open.relationshipDetails'; params: { edgeId: EdgeId } | { source: Fqn; target: Fqn } }
160
161
  | { type: 'open.relationshipsBrowser'; fqn: Fqn }
161
162
  // | { type: 'close.overlay' }
162
163
  | { type: 'navigate.to'; viewId: ViewId; fromNode?: NodeId | undefined }
@@ -170,6 +171,8 @@ export type Events =
170
171
  | { type: 'walkthrough.start'; stepId?: StepEdgeId }
171
172
  | { type: 'walkthrough.step'; direction: 'next' | 'previous' }
172
173
  | { type: 'walkthrough.end' }
174
+ | { type: 'notations.highlight'; notation: ElementNotation; kind?: string }
175
+ | { type: 'notations.unhighlight' }
173
176
  | { type: 'toggle.feature'; feature: FeatureName; forceValue?: boolean }
174
177
 
175
178
  export type ActionArg = { context: Context; event: Events }
@@ -440,6 +443,26 @@ export const diagramMachine = setup({
440
443
  }),
441
444
  }
442
445
  }),
446
+ 'notations.highlight': assign(({ context }, params: { notation: ElementNotation; kind?: string }) => {
447
+ const kinds = params.kind ? [params.kind] : params.notation.kinds
448
+ const xynodes = context.xynodes.map((n) => {
449
+ const node = findDiagramNode(context, n.id)
450
+ if (
451
+ node &&
452
+ node.notation === params.notation.title &&
453
+ node.shape === params.notation.shape &&
454
+ node.color === params.notation.color &&
455
+ kinds.includes(node.kind)
456
+ ) {
457
+ return Base.setDimmed(n, false)
458
+ }
459
+ return Base.setDimmed(n, 'immediate')
460
+ })
461
+ return {
462
+ xynodes,
463
+ xyedges: context.xyedges.map(Base.setDimmed('immediate')),
464
+ }
465
+ }),
443
466
  },
444
467
  }).createMachine({
445
468
  initial: 'initializing',
@@ -617,8 +640,8 @@ export const diagramMachine = setup({
617
640
  'open.relationshipDetails': {
618
641
  actions: sendTo(({ system }) => typedSystem(system).overlaysActorRef!, ({ context, event }) => ({
619
642
  type: 'open.relationshipDetails',
620
- view: context.view,
621
- edgeId: event.edgeId,
643
+ viewId: context.view.id,
644
+ ...event.params,
622
645
  })),
623
646
  },
624
647
  'open.source': {
@@ -666,6 +689,18 @@ export const diagramMachine = setup({
666
689
  params: prop('event'),
667
690
  },
668
691
  },
692
+ 'notations.highlight': {
693
+ actions: {
694
+ type: 'notations.highlight',
695
+ params: prop('event'),
696
+ },
697
+ },
698
+ 'notations.unhighlight': {
699
+ actions: assign(({ context }) => ({
700
+ xynodes: context.xynodes.map(Base.setDimmed(false)),
701
+ xyedges: context.xyedges.map(Base.setDimmed(false)),
702
+ })),
703
+ },
669
704
  'saveManualLayout.*': {
670
705
  guard: 'not readonly',
671
706
  actions: sendTo((c) => c.context.syncLayoutActorRef!, ({ event }) => {
@@ -794,6 +829,11 @@ export const diagramMachine = setup({
794
829
  }),
795
830
  target: 'idle',
796
831
  },
832
+ 'notations.unhighlight': {
833
+ actions: assign(s => ({
834
+ ...focusNodesEdges(s),
835
+ })),
836
+ },
797
837
  },
798
838
  },
799
839
  walkthrough: {
@@ -845,6 +885,11 @@ export const diagramMachine = setup({
845
885
  enqueue('xyflow:fitFocusedBounds')
846
886
  }),
847
887
  },
888
+ 'notations.unhighlight': {
889
+ actions: assign(s => ({
890
+ ...updateActiveWalkthrough(s),
891
+ })),
892
+ },
848
893
  'walkthrough.end': {
849
894
  target: 'idle',
850
895
  },
@@ -1,4 +1,3 @@
1
- export type { AddEdgeData, AddNodeData } from './types'
2
1
  export { vector, VectorImpl } from './vector'
3
2
  export type { Vector } from './vector'
4
3
  export {
@@ -1,19 +0,0 @@
1
- import { DiagramEdge, DiagramView, EdgeId } from '@likec4/core';
2
- import { RelationshipDetailsTypes } from './_types';
3
- export declare const ZIndexes: {
4
- compound: number;
5
- edge: number;
6
- element: number;
7
- max: number;
8
- };
9
- export declare function useLayoutedDetails(edgeId: EdgeId, view: DiagramView): {
10
- edge: DiagramEdge;
11
- xynodes: RelationshipDetailsTypes.Node[];
12
- xyedges: RelationshipDetailsTypes.Edge[];
13
- bounds: {
14
- x: number;
15
- y: number;
16
- width: number;
17
- height: number;
18
- };
19
- };