@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
@@ -83,6 +83,8 @@ export namespace RelationshipsBrowserTypes {
83
83
  // Extend the edge types provided by SharedFlowTypes with RelationshipsOfEdgeData
84
84
 
85
85
  export type EdgeData = Base.EdgeData<{
86
+ sourceFqn: Fqn
87
+ targetFqn: Fqn
86
88
  relations: NonEmptyArray<RelationId>
87
89
  color: Color | undefined
88
90
  label: string | null
@@ -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
  >
@@ -4,8 +4,8 @@ import { useSelector } from '@xstate/react'
4
4
  import { shallowEqual } from 'fast-equals'
5
5
  import { createContext, useContext, useMemo, useTransition } 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
 
@@ -27,7 +27,7 @@ export function useRelationshipsBrowser() {
27
27
  return useMemo(() => ({
28
28
  actor,
29
29
  get rootElementId(): string {
30
- return `relationships-browser-${actor.sessionId}`
30
+ return `relationships-browser-${actor.sessionId.replaceAll(':', '_')}`
31
31
  },
32
32
  getState: () => actor.getSnapshot().context,
33
33
  send: actor.send,
@@ -218,6 +218,8 @@ export namespace LayoutRelationshipsViewResult {
218
218
  existsInCurrentView: boolean
219
219
  }
220
220
  export type Edge = DiagramEdge & {
221
+ sourceFqn: Fqn
222
+ targetFqn: Fqn
221
223
  sourceHandle: string
222
224
  targetHandle: string
223
225
  existsInCurrentView: boolean
@@ -239,6 +241,8 @@ export function layoutRelationshipsView(
239
241
  name: string
240
242
  source: string // node id
241
243
  target: string // node id
244
+ sourceFqn: Fqn
245
+ targetFqn: Fqn
242
246
  sourceHandle: string
243
247
  targetHandle: string
244
248
  relations: RelationshipModel[]
@@ -250,6 +254,8 @@ export function layoutRelationshipsView(
250
254
  toArray(data.incoming),
251
255
  map(r => ({
252
256
  id: r.source.id,
257
+ sourceFqn: r.source.id,
258
+ targetFqn: r.target.id,
253
259
  source: incomers.byId(r.source.id).graph,
254
260
  target: subjects.byId(r.target.id).graph,
255
261
  relation: r,
@@ -259,6 +265,8 @@ export function layoutRelationshipsView(
259
265
  toArray(data.outgoing),
260
266
  map(r => ({
261
267
  id: r.target.id,
268
+ sourceFqn: r.source.id,
269
+ targetFqn: r.target.id,
262
270
  source: subjects.byId(r.source.id).graph,
263
271
  target: outgoers.byId(r.target.id).graph,
264
272
  relation: r,
@@ -284,6 +292,8 @@ export function layoutRelationshipsView(
284
292
  }, name)
285
293
  edges.push({
286
294
  name,
295
+ sourceFqn: grouped[0].sourceFqn,
296
+ targetFqn: grouped[0].targetFqn,
287
297
  source: source.id,
288
298
  sourceHandle: source.id + '_out' + (g.node(source.id).outPorts.length - 1),
289
299
  target: target.id,
@@ -444,17 +454,6 @@ export function layoutRelationshipsView(
444
454
  const [subject] = [...subjects.root]
445
455
  invariant(subject, 'Subjects should not be empty')
446
456
  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
457
 
459
458
  const nodes = nodeIds.map(({ id }): LayoutRelationshipsViewResult.Node => {
460
459
  const { element, inPorts, outPorts, column } = g.node(id)
@@ -513,7 +512,7 @@ export function layoutRelationshipsView(
513
512
  minX = Math.min(minX, position.x)
514
513
  minY = Math.min(minY, position.y)
515
514
 
516
- const navigateTo = element.defaultView?.id ?? null
515
+ const navigateTo = scope ? ifind(element.scopedViews(), v => v.id !== scope.id)?.id ?? null : null
517
516
 
518
517
  const inheritFromNode = scope?.findNodeWithElement(element.id)
519
518
  const scopedAncestor = scope && !inheritFromNode
@@ -577,7 +576,16 @@ export function layoutRelationshipsView(
577
576
  if (!ename) {
578
577
  return acc
579
578
  }
580
- const { name, source, target, relations, sourceHandle, targetHandle } = find(edges, e => e.name === ename)!
579
+ const {
580
+ name,
581
+ source,
582
+ sourceFqn,
583
+ target,
584
+ targetFqn,
585
+ relations,
586
+ sourceHandle,
587
+ targetHandle,
588
+ } = find(edges, e => e.name === ename)!
581
589
  const onlyRelation = only(relations)
582
590
  const label = onlyRelation?.title ?? 'untitled'
583
591
  const isMultiple = relations.length > 1
@@ -587,8 +595,10 @@ export function layoutRelationshipsView(
587
595
  // const edge = g.edge(name)
588
596
  acc.push({
589
597
  id: name as EdgeId,
598
+ sourceFqn,
590
599
  source: source as NodeId,
591
600
  sourceHandle,
601
+ targetFqn,
592
602
  target: target as NodeId,
593
603
  targetHandle,
594
604
  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,
@@ -1,24 +1,37 @@
1
- import type { ViewId } from '@likec4/core'
1
+ import type { ViewId, WhereOperator } from '@likec4/core'
2
+ import { useDeepCompareEffect } from '@react-hookz/web'
2
3
  import { useActorRef, useSelector } from '@xstate/react'
3
4
  import { useStoreApi } from '@xyflow/react'
4
5
  import { shallowEqual } from 'fast-equals'
5
- import { type PropsWithChildren, useEffect, useMemo, useRef } from 'react'
6
+ import { type PropsWithChildren, useEffect } from 'react'
6
7
  import { useDiagramEventHandlersRef } from '../context/DiagramEventHandlers'
7
8
  import { DiagramFeatures, useEnabledFeatures } from '../context/DiagramFeatures'
8
9
  import { DiagramActorSafeContext } from '../hooks/safeContext'
9
10
  import { useUpdateEffect } from '../hooks/useUpdateEffect'
10
11
  import type { Types } from '../likec4diagram/types'
12
+ import { useViewToNodesEdges } from '../likec4diagram/useViewToNodesEdges'
11
13
  import { type Input, diagramMachine } from './diagram-machine'
12
14
  import { syncManualLayoutActorLogic } from './syncManualLayoutActor'
13
- import type { DiagramActorRef, DiagramActorSnapshot } from './types'
15
+ import type { DiagramActorSnapshot } from './types'
14
16
 
15
- type ActorContextInput = Omit<Input, 'xystore' | 'features'>
16
- export function DiagramActorProvider({ input, children }: PropsWithChildren<{ input: ActorContextInput }>) {
17
+ const selectToggledFeatures = (state: DiagramActorSnapshot) => state.context.toggledFeatures
18
+ type ActorContextInput = Omit<Input, 'xystore' | 'xynodes' | 'xyedges'>
19
+ export function DiagramActorProvider({
20
+ input: {
21
+ view,
22
+ ...inputs
23
+ },
24
+ where,
25
+ children,
26
+ }: PropsWithChildren<{
27
+ input: ActorContextInput
28
+ where?: WhereOperator<string, string> | undefined
29
+ }>) {
17
30
  const handlersRef = useDiagramEventHandlersRef()
18
31
  const xystore = useStoreApi<Types.Node, Types.Edge>()
19
32
 
20
- const logic = useMemo(() => {
21
- return diagramMachine.provide({
33
+ const actorRef = useActorRef(
34
+ diagramMachine.provide({
22
35
  actions: {
23
36
  'trigger:NavigateTo': ((_, { viewId }) => {
24
37
  handlersRef.current.onNavigateTo?.(viewId as ViewId)
@@ -41,68 +54,45 @@ export function DiagramActorProvider({ input, children }: PropsWithChildren<{ in
41
54
  },
42
55
  }),
43
56
  },
44
- })
45
- }, [handlersRef])
46
-
47
- const actorRef = useActorRef(
48
- logic,
57
+ }),
49
58
  {
50
- id: `diagram:${input.view.id}`,
59
+ id: `diagram:${view.id}`,
51
60
  systemId: 'diagram',
52
61
  // ...inspector,
53
62
  input: {
54
63
  xystore,
55
- ...input,
64
+ view,
65
+ ...inputs,
56
66
  },
57
67
  },
58
68
  )
59
69
 
60
- return (
61
- <DiagramActorSafeContext value={actorRef}>
62
- <SyncStore input={input} actorRef={actorRef} />
63
- <DiagramActorToggledFeatures actorRef={actorRef}>
64
- {children}
65
- </DiagramActorToggledFeatures>
66
- </DiagramActorSafeContext>
67
- )
68
- }
69
-
70
- const SyncStore = (
71
- { input: { view, xyedges, xynodes, ...inputs }, actorRef }: { input: ActorContextInput; actorRef: DiagramActorRef },
72
- ) => {
73
70
  const features = useEnabledFeatures()
74
71
  useUpdateEffect(() => {
75
72
  actorRef.send({ type: 'update.inputs', inputs })
76
- }, [actorRef, inputs])
73
+ }, [inputs])
77
74
 
78
75
  useEffect(() => {
79
76
  actorRef.send({ type: 'update.features', features })
80
- }, [actorRef, features])
77
+ }, [features])
81
78
 
82
- const frameReq = useRef<number>(null)
79
+ const { xyedges, xynodes } = useViewToNodesEdges({
80
+ view,
81
+ where,
82
+ nodesSelectable: inputs.nodesSelectable,
83
+ })
83
84
 
84
- useUpdateEffect(() => {
85
- frameReq.current = requestAnimationFrame(() => {
86
- frameReq.current = null
87
- actorRef.send({ type: 'update.view', view, xyedges, xynodes })
88
- })
89
- return () => {
90
- if (frameReq.current != null) {
91
- cancelAnimationFrame(frameReq.current)
92
- }
93
- frameReq.current = null
94
- }
95
- }, [actorRef, view, xyedges, xynodes])
85
+ useDeepCompareEffect(() => {
86
+ actorRef.send({ type: 'update.view', view, xyedges, xynodes })
87
+ }, [view, xyedges, xynodes])
96
88
 
97
- return null
98
- }
99
-
100
- const selectToggledFeatures = (state: DiagramActorSnapshot) => state.context.toggledFeatures
101
- function DiagramActorToggledFeatures({ children, actorRef }: PropsWithChildren<{ actorRef: DiagramActorRef }>) {
102
89
  const toggledFeatures = useSelector(actorRef, selectToggledFeatures, shallowEqual)
90
+
103
91
  return (
104
- <DiagramFeatures overrides={toggledFeatures}>
105
- {children}
106
- </DiagramFeatures>
92
+ <DiagramActorSafeContext value={actorRef}>
93
+ <DiagramFeatures overrides={toggledFeatures}>
94
+ {children}
95
+ </DiagramFeatures>
96
+ </DiagramActorSafeContext>
107
97
  )
108
98
  }
@@ -391,8 +391,8 @@ export function updateActiveWalkthrough({ context }: ActionArg): Partial<Diagram
391
391
  })
392
392
  }),
393
393
  xynodes: context.xynodes.map(node => {
394
- const active = step.source === node.id || step.target === node.id
395
- return Base.setDimmed(node, !active)
394
+ const dimmed = step.source !== node.id && step.target !== node.id
395
+ return Base.setDimmed(node, dimmed)
396
396
  }),
397
397
  }
398
398
  }