@likec4/diagram 1.39.5 → 1.41.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 (140) hide show
  1. package/bundle/{chunk-CW_KClZe.js → chunk-FGcODVxo.js} +1059 -1023
  2. package/bundle/custom.js +61 -60
  3. package/bundle/index.js +2932 -764
  4. package/dist/LikeC4Diagram.d.ts +1 -1
  5. package/dist/LikeC4Diagram.js +7 -4
  6. package/dist/LikeC4Diagram.props.d.ts +6 -1
  7. package/dist/base/const.d.ts +9 -0
  8. package/dist/base/const.js +10 -1
  9. package/dist/base/index.d.ts +1 -0
  10. package/dist/base/primitives/MarkdownBlock.js +2 -0
  11. package/dist/base/primitives/edge/EdgeLabel.js +2 -1
  12. package/dist/base/primitives/edge/EdgeLabelContainer.js +10 -4
  13. package/dist/base/primitives/edge/EdgePath.js +17 -8
  14. package/dist/base/primitives/edge/edge.css.d.ts +0 -1
  15. package/dist/base/primitives/edge/edge.css.js +6 -14
  16. package/dist/base/primitives/element/ElementActionButtons.js +1 -3
  17. package/dist/base/primitives/element/ElementNodeContainer.d.ts +0 -6
  18. package/dist/base/primitives/element/ElementNodeContainer.js +3 -26
  19. package/dist/base/primitives/element/ElementTitle.js +2 -2
  20. package/dist/base/types.d.ts +3 -3
  21. package/dist/bundle/LikeC4View.js +4 -12
  22. package/dist/bundle/LikeC4View.props.d.ts +12 -3
  23. package/dist/bundle/custom.js +1 -1
  24. package/dist/components/Link.js +28 -20
  25. package/dist/custom/customNodes.d.ts +6 -0
  26. package/dist/custom/customNodes.js +2 -1
  27. package/dist/custom/index.js +1 -1
  28. package/dist/hooks/useDiagram.d.ts +5 -1
  29. package/dist/hooks/useDiagram.js +3 -0
  30. package/dist/hooks/useXYFlow.d.ts +4 -439
  31. package/dist/likec4diagram/DiagramUI.js +1 -1
  32. package/dist/likec4diagram/DiagramXYFlow.js +8 -4
  33. package/dist/likec4diagram/convert-to-xyflow.d.ts +14 -0
  34. package/dist/likec4diagram/convert-to-xyflow.js +29 -0
  35. package/dist/likec4diagram/custom/edges/RelationshipEdge.d.ts +4 -4
  36. package/dist/likec4diagram/custom/edges/RelationshipEdge.js +0 -1
  37. package/dist/likec4diagram/custom/edges/SequenceStepEdge.d.ts +3 -0
  38. package/dist/likec4diagram/custom/edges/SequenceStepEdge.js +71 -0
  39. package/dist/likec4diagram/custom/index.js +7 -2
  40. package/dist/likec4diagram/custom/nodes/ElementActions.d.ts +2 -1
  41. package/dist/likec4diagram/custom/nodes/SequenceActorNode.d.ts +4 -0
  42. package/dist/likec4diagram/custom/nodes/SequenceActorNode.js +157 -0
  43. package/dist/likec4diagram/custom/nodes/index.d.ts +1 -0
  44. package/dist/likec4diagram/custom/nodes/nodes.d.ts +1 -2
  45. package/dist/likec4diagram/relationship-popover/RelationshipPopover.js +31 -27
  46. package/dist/likec4diagram/types.d.ts +41 -7
  47. package/dist/likec4diagram/xyflow-diagram/diagram-view.d.ts +11 -0
  48. package/dist/likec4diagram/{useViewToNodesEdges.js → xyflow-diagram/diagram-view.js} +4 -13
  49. package/dist/likec4diagram/xyflow-sequence/_types.d.ts +41 -0
  50. package/dist/likec4diagram/xyflow-sequence/const.d.ts +17 -0
  51. package/dist/likec4diagram/xyflow-sequence/const.js +16 -0
  52. package/dist/likec4diagram/xyflow-sequence/layouter.d.ts +46 -0
  53. package/dist/likec4diagram/xyflow-sequence/layouter.js +408 -0
  54. package/dist/likec4diagram/xyflow-sequence/sequence-view.d.ts +7 -0
  55. package/dist/likec4diagram/xyflow-sequence/sequence-view.js +273 -0
  56. package/dist/likec4diagram/xyflow-sequence/utils.d.ts +14 -0
  57. package/dist/likec4diagram/xyflow-sequence/utils.js +92 -0
  58. package/dist/navigationpanel/NavigationPanelControls.js +2 -2
  59. package/dist/navigationpanel/controls/ViewDetailsCard.js +27 -12
  60. package/dist/navigationpanel/dropdown/ProjectsMenu.js +53 -44
  61. package/dist/navigationpanel/walkthrough/ActiveWalkthroughControls.d.ts +1 -2
  62. package/dist/navigationpanel/walkthrough/ActiveWalkthroughControls.js +10 -41
  63. package/dist/navigationpanel/walkthrough/DynamicViewControls.d.ts +292 -0
  64. package/dist/navigationpanel/walkthrough/DynamicViewControls.js +119 -0
  65. package/dist/navigationpanel/walkthrough/index.d.ts +2 -1
  66. package/dist/overlays/element-details/ElementDetailsCard.css.js +7 -1
  67. package/dist/overlays/element-details/ElementDetailsCard.js +17 -19
  68. package/dist/overlays/relationship-details/RelationshipDetails.js +4 -1
  69. package/dist/overlays/relationship-details/layout.d.ts +3 -2
  70. package/dist/overlays/relationship-details/layout.js +1 -2
  71. package/dist/overlays/relationships-browser/RelationshipsBrowser.js +2 -1
  72. package/dist/overlays/relationships-browser/layout.js +1 -1
  73. package/dist/search/components/ElementsColumn.js +1 -1
  74. package/dist/state/DiagramActorProvider.d.ts +3 -2
  75. package/dist/state/DiagramActorProvider.js +40 -41
  76. package/dist/state/assign.js +11 -4
  77. package/dist/state/diagram-machine.d.ts +224 -194
  78. package/dist/state/diagram-machine.js +170 -63
  79. package/dist/state/utils.d.ts +7 -1
  80. package/dist/state/utils.js +67 -7
  81. package/dist/styles-min.css +1 -1
  82. package/dist/styles.css +1 -1
  83. package/dist/styles.css2.js +1 -1
  84. package/package.json +8 -7
  85. package/panda.buildinfo.json +45 -24
  86. package/src/LikeC4Diagram.props.ts +14 -1
  87. package/src/LikeC4Diagram.tsx +7 -4
  88. package/src/base/const.ts +12 -0
  89. package/src/base/index.ts +2 -0
  90. package/src/base/primitives/MarkdownBlock.tsx +2 -0
  91. package/src/base/primitives/edge/EdgeLabel.tsx +23 -19
  92. package/src/base/primitives/edge/EdgeLabelContainer.tsx +12 -7
  93. package/src/base/primitives/edge/EdgePath.tsx +25 -14
  94. package/src/base/primitives/edge/edge.css.ts +5 -14
  95. package/src/base/primitives/element/ElementActionButtons.tsx +1 -3
  96. package/src/base/primitives/element/ElementNodeContainer.tsx +3 -30
  97. package/src/base/primitives/element/ElementTitle.tsx +2 -3
  98. package/src/base/types.ts +7 -5
  99. package/src/bundle/LikeC4View.props.ts +14 -3
  100. package/src/bundle/LikeC4View.tsx +4 -14
  101. package/src/bundle/ReactLikeC4.tsx +1 -2
  102. package/src/components/Link.tsx +21 -18
  103. package/src/custom/customNodes.ts +7 -0
  104. package/src/hooks/useDiagram.ts +10 -0
  105. package/src/likec4diagram/DiagramUI.tsx +1 -1
  106. package/src/likec4diagram/DiagramXYFlow.tsx +10 -5
  107. package/src/likec4diagram/convert-to-xyflow.ts +45 -0
  108. package/src/likec4diagram/custom/edges/RelationshipEdge.tsx +0 -1
  109. package/src/likec4diagram/custom/edges/SequenceStepEdge.tsx +65 -0
  110. package/src/likec4diagram/custom/index.ts +7 -1
  111. package/src/likec4diagram/custom/nodes/ElementActions.tsx +4 -2
  112. package/src/likec4diagram/custom/nodes/SequenceActorNode.tsx +175 -0
  113. package/src/likec4diagram/custom/nodes/index.ts +1 -0
  114. package/src/likec4diagram/custom/nodes/nodes.tsx +1 -1
  115. package/src/likec4diagram/relationship-popover/RelationshipPopover.tsx +36 -30
  116. package/src/likec4diagram/types.ts +96 -13
  117. package/src/likec4diagram/{useViewToNodesEdges.ts → xyflow-diagram/diagram-view.ts} +7 -28
  118. package/src/likec4diagram/xyflow-sequence/_types.ts +45 -0
  119. package/src/likec4diagram/xyflow-sequence/const.ts +37 -0
  120. package/src/likec4diagram/xyflow-sequence/layouter.ts +567 -0
  121. package/src/likec4diagram/xyflow-sequence/sequence-view.ts +337 -0
  122. package/src/likec4diagram/xyflow-sequence/utils.ts +112 -0
  123. package/src/navigationpanel/NavigationPanelControls.tsx +2 -2
  124. package/src/navigationpanel/controls/ViewDetailsCard.tsx +29 -12
  125. package/src/navigationpanel/dropdown/ProjectsMenu.tsx +5 -1
  126. package/src/navigationpanel/walkthrough/ActiveWalkthroughControls.tsx +5 -40
  127. package/src/navigationpanel/walkthrough/DynamicViewControls.tsx +125 -0
  128. package/src/navigationpanel/walkthrough/index.tsx +2 -1
  129. package/src/overlays/element-details/ElementDetailsCard.css.ts +7 -1
  130. package/src/overlays/element-details/ElementDetailsCard.tsx +24 -25
  131. package/src/overlays/relationship-details/RelationshipDetails.tsx +5 -2
  132. package/src/overlays/relationship-details/layout.ts +4 -3
  133. package/src/overlays/relationships-browser/RelationshipsBrowser.tsx +2 -1
  134. package/src/overlays/relationships-browser/layout.ts +1 -1
  135. package/src/search/components/ElementsColumn.tsx +1 -1
  136. package/src/state/DiagramActorProvider.tsx +46 -51
  137. package/src/state/assign.ts +18 -5
  138. package/src/state/diagram-machine.ts +207 -75
  139. package/src/state/utils.ts +81 -7
  140. package/dist/likec4diagram/useViewToNodesEdges.d.ts +0 -12
@@ -0,0 +1,125 @@
1
+ import { invariant } from '@likec4/core'
2
+ import type { DynamicViewDisplayVariant } from '@likec4/core/types'
3
+ import { css } from '@likec4/styles/css'
4
+ import { type ButtonProps, Button, SegmentedControl } from '@mantine/core'
5
+ import {
6
+ IconPlayerPlayFilled,
7
+ } from '@tabler/icons-react'
8
+ import { type HTMLMotionProps } from 'motion/react'
9
+ import * as m from 'motion/react-m'
10
+ import { forwardRef } from 'react'
11
+ import { useDiagram, useDiagramContext } from '../../hooks/useDiagram'
12
+ import { Tooltip } from '../_common'
13
+ import { useNavigationActor } from '../hooks'
14
+
15
+ export const TriggerWalkthroughButton = forwardRef<HTMLButtonElement, ButtonProps & HTMLMotionProps<'button'>>((
16
+ props,
17
+ ref,
18
+ ) => (
19
+ <Button
20
+ variant="filled"
21
+ size="xs"
22
+ fw="500"
23
+ {...props}
24
+ ref={ref}
25
+ component={m.button}
26
+ layoutId={'trigger-dynamic-walkthrough'}
27
+ className={css({
28
+ flexShrink: 0,
29
+ })}
30
+ />
31
+ ))
32
+
33
+ function StartWalkthroughButton({ onClick }: { onClick: () => void }) {
34
+ const diagram = useDiagram()
35
+ const actor = useNavigationActor()
36
+ return (
37
+ <Tooltip label="Start Dynamic View Walkthrough">
38
+ <TriggerWalkthroughButton
39
+ onClick={e => {
40
+ e.stopPropagation()
41
+ actor.closeDropdown()
42
+ diagram.startWalkthrough()
43
+ }}
44
+ size="compact-xs"
45
+ h={26}
46
+ classNames={{
47
+ label: css({
48
+ display: {
49
+ base: 'none',
50
+ '@/md': '[inherit]',
51
+ },
52
+ }),
53
+ section: css({
54
+ marginInlineStart: {
55
+ base: '0',
56
+ '@/md': '2',
57
+ },
58
+ }),
59
+ }}
60
+ rightSection={<IconPlayerPlayFilled size={10} />}
61
+ >
62
+ Start
63
+ </TriggerWalkthroughButton>
64
+ </Tooltip>
65
+ )
66
+ }
67
+
68
+ function DynamicViewModeSwitcher({
69
+ value,
70
+ onChange,
71
+ }: {
72
+ value: DynamicViewDisplayVariant
73
+ onChange: (variant: DynamicViewDisplayVariant) => void
74
+ }) {
75
+ return (
76
+ <m.div layout="position">
77
+ <SegmentedControl
78
+ size="xs"
79
+ value={value}
80
+ component={m.div}
81
+ onChange={variant => {
82
+ invariant(variant === 'diagram' || variant === 'sequence', 'Invalid dynamic view variant')
83
+ onChange(variant)
84
+ }}
85
+ classNames={{
86
+ label: css({
87
+ fontSize: 'xxs',
88
+ }),
89
+ }}
90
+ data={[
91
+ {
92
+ value: 'diagram',
93
+ label: 'Diagram',
94
+ },
95
+ {
96
+ value: 'sequence',
97
+ label: 'Sequence',
98
+ },
99
+ ]} />
100
+ </m.div>
101
+ )
102
+ }
103
+
104
+ export function DynamicViewControls() {
105
+ const dynamicViewVariant = useDiagramContext(c => c.dynamicViewVariant)
106
+ const diagram = useDiagram()
107
+ const actor = useNavigationActor()
108
+ return (
109
+ <>
110
+ <DynamicViewModeSwitcher
111
+ key="dynamic-view-mode-switcher"
112
+ value={dynamicViewVariant}
113
+ onChange={mode => {
114
+ diagram.switchDynamicViewVariant(mode)
115
+ }}
116
+ />
117
+ <StartWalkthroughButton
118
+ key="trigger-dynamic-walkthrough"
119
+ onClick={() => {
120
+ actor.closeDropdown()
121
+ diagram.startWalkthrough()
122
+ }} />
123
+ </>
124
+ )
125
+ }
@@ -1 +1,2 @@
1
- export { ActiveWalkthroughControls, StartWalkthroughButton } from './ActiveWalkthroughControls'
1
+ export { ActiveWalkthroughControls } from './ActiveWalkthroughControls'
2
+ export { DynamicViewControls } from './DynamicViewControls'
@@ -25,13 +25,19 @@ export const dialog = css({
25
25
  export const card = css({
26
26
  position: 'absolute',
27
27
  pointerEvents: 'all',
28
+ display: 'flex',
29
+ flexDirection: 'column',
30
+ padding: '4',
28
31
  gap: 'lg',
29
32
  justifyContent: 'stretch',
33
+ color: 'mantine.colors.text',
30
34
  backgroundColor: {
31
35
  base: 'mantine.colors.body',
32
36
  _dark: 'mantine.colors.dark[6]',
33
37
  },
34
- border: `none`,
38
+ boxShadow: 'md',
39
+ overflow: 'hidden',
40
+ border: 'none',
35
41
  backgroundImage: `
36
42
  linear-gradient(180deg,
37
43
  color-mix(in srgb, var(--likec4-palette-fill) 60%, transparent),
@@ -16,7 +16,6 @@ import {
16
16
  ActionIconGroup,
17
17
  Badge,
18
18
  Box,
19
- Card,
20
19
  CloseButton,
21
20
  Divider as MantineDivider,
22
21
  Flex,
@@ -48,7 +47,7 @@ import { DiagramFeatures, IconRenderer, IfEnabled } from '../../context'
48
47
  import { useUpdateEffect } from '../../hooks'
49
48
  import { useDiagram } from '../../hooks/useDiagram'
50
49
  import type { OnNavigateTo } from '../../LikeC4Diagram.props'
51
- import { useLikeC4Model } from '../../likec4model'
50
+ import { useCurrentViewModel } from '../../likec4model'
52
51
  import { stopPropagation } from '../../utils'
53
52
  import * as styles from './ElementDetailsCard.css'
54
53
  import { TabPanelDeployments } from './TabPanelDeployments'
@@ -115,8 +114,7 @@ export function ElementDetailsCard({
115
114
  defaultValue: 'Properties',
116
115
  })
117
116
  const diagram = useDiagram()
118
- const likec4model = useLikeC4Model()
119
- const viewModel = likec4model.view(viewId)
117
+ const viewModel = useCurrentViewModel()
120
118
  const nodeModel = fromNode ? viewModel.findNode(fromNode) : viewModel.findNodeWithElement(fqn)
121
119
 
122
120
  const elementModel = viewModel.$model.element(fqn)
@@ -221,7 +219,7 @@ export function ElementDetailsCard({
221
219
  */
222
220
  useTimeoutEffect(() => {
223
221
  setOpened(true)
224
- }, 200)
222
+ }, 220)
225
223
 
226
224
  return (
227
225
  <m.dialog
@@ -257,9 +255,7 @@ export function ElementDetailsCard({
257
255
  }}
258
256
  >
259
257
  <RemoveScroll forwardProps removeScrollBar={false}>
260
- <Card
261
- shadow="md"
262
- component={m.div}
258
+ <m.div
263
259
  layout
264
260
  layoutRoot
265
261
  drag
@@ -292,13 +288,12 @@ export function ElementDetailsCard({
292
288
  },
293
289
  }}
294
290
  style={{
295
- // `style` prop in Mantine doesn't accept motion values
296
- width: width as any,
297
- height: height as any,
291
+ width,
292
+ height,
298
293
  }}>
299
294
  <div className={styles.cardHeader} onPointerDown={e => controls.start(e)}>
300
- <Group align="start" justify="space-between" gap={'sm'} mb={'sm'} wrap="nowrap">
301
- <Group align="start" gap={'sm'} style={{ cursor: 'default' }} wrap="nowrap">
295
+ <HStack alignItems="start" justify="space-between" gap={'sm'} mb={'sm'} flexWrap="nowrap">
296
+ <HStack alignItems="start" gap={'sm'} style={{ cursor: 'default' }} flexWrap="nowrap">
302
297
  {elementIcon}
303
298
  <div>
304
299
  <Text
@@ -312,15 +307,15 @@ export function ElementDetailsCard({
312
307
  </Text>
313
308
  )}
314
309
  </div>
315
- </Group>
310
+ </HStack>
316
311
  <CloseButton
317
312
  size={'lg'}
318
313
  onClick={e => {
319
314
  e.stopPropagation()
320
315
  close()
321
316
  }} />
322
- </Group>
323
- <Group align="baseline" gap={'sm'} wrap="nowrap">
317
+ </HStack>
318
+ <HStack alignItems="baseline" gap={'sm'} flexWrap="nowrap">
324
319
  <div>
325
320
  <SmallLabel>kind</SmallLabel>
326
321
  <Badge
@@ -403,7 +398,7 @@ export function ElementDetailsCard({
403
398
  </Tooltip>
404
399
  )}
405
400
  </ActionIconGroup>
406
- </Group>
401
+ </HStack>
407
402
  </div>
408
403
  <Tabs
409
404
  value={activeTab}
@@ -426,6 +421,12 @@ export function ElementDetailsCard({
426
421
  <TabsPanel value="Properties">
427
422
  <ScrollArea scrollbars="y" type="scroll" offsetScrollbars>
428
423
  <Box className={styles.propertiesGrid} pt={'xs'}>
424
+ {elementModel.hasSummary && (
425
+ <>
426
+ <PropertyLabel>summary</PropertyLabel>
427
+ <MarkdownBlock value={elementModel.summary} />
428
+ </>
429
+ )}
429
430
  <>
430
431
  <PropertyLabel>description</PropertyLabel>
431
432
  <MarkdownBlock
@@ -517,7 +518,7 @@ export function ElementDetailsCard({
517
518
  dragMomentum={false}
518
519
  onDrag={handleDrag}
519
520
  dragConstraints={{ top: 0, left: 0, right: 0, bottom: 0 }} />
520
- </Card>
521
+ </m.div>
521
522
  </RemoveScroll>
522
523
  </m.dialog>
523
524
  )
@@ -609,12 +610,10 @@ function ElementMetata({
609
610
  {entries(metadata).map(([key, value]) => (
610
611
  <div
611
612
  key={key}
612
- className={cx(
613
- 'group',
614
- css({
615
- display: 'contents',
616
- }),
617
- )}
613
+ style={{
614
+ display: 'contents',
615
+ }}
616
+ className={'group'}
618
617
  >
619
618
  <div
620
619
  className={css({
@@ -651,7 +650,7 @@ function ElementMetata({
651
650
  fontSize: 'sm',
652
651
  padding: 'xxs',
653
652
  whiteSpace: 'pre',
654
- fontFamily: '[var(--mantine-font-family-monospace)]',
653
+ fontFamily: 'mono',
655
654
  userSelect: 'all',
656
655
  })}>
657
656
  {value}
@@ -1,5 +1,5 @@
1
1
  import { type DiagramEdge, type DiagramView, invariant, isAncestor, nonNullable } from '@likec4/core'
2
- import { cx as clsx } from '@likec4/styles/css'
2
+ import { cx } from '@likec4/styles/css'
3
3
  import { ActionIcon, Group } from '@mantine/core'
4
4
  import { useCallbackRef, useStateHistory } from '@mantine/hooks'
5
5
  import { IconChevronLeft, IconChevronRight, IconX } from '@tabler/icons-react'
@@ -145,7 +145,10 @@ const RelationshipDetailsInner = memo(() => {
145
145
  id={browser.rootElementId}
146
146
  nodes={nodes}
147
147
  edges={edges}
148
- className={clsx(initialized ? 'initialized' : 'not-initialized')}
148
+ className={cx(
149
+ initialized ? 'initialized' : 'not-initialized',
150
+ 'likec4-relationship-details',
151
+ )}
149
152
  nodeTypes={nodeTypes}
150
153
  edgeTypes={edgeTypes}
151
154
  onNodesChange={useCallbackRef((changes) => {
@@ -34,6 +34,7 @@ import {
34
34
  sortBy,
35
35
  tap,
36
36
  } from 'remeda'
37
+ import type { Except } from 'type-fest'
37
38
  import type { RelationshipDetailsTypes } from './_types'
38
39
  import type { RelationshipDetailsViewData } from './compute'
39
40
 
@@ -218,14 +219,14 @@ export type LayoutResult = {
218
219
  }
219
220
 
220
221
  export namespace LayoutResult {
221
- export type Node = Omit<DiagramNode, 'modelRef' | 'description' | 'deploymentRef' | 'inEdges' | 'outEdges'> & {
222
+ export type Node = Except<DiagramNode, 'modelRef' | 'description' | 'deploymentRef' | 'inEdges' | 'outEdges'> & {
222
223
  description: RichTextOrEmpty
223
224
  modelRef: Fqn
224
225
  column: RelationshipDetailsTypes.Column
225
226
  ports: RelationshipDetailsTypes.Ports
226
227
  // existsInCurrentView: boolean
227
228
  }
228
- export type Edge = Omit<DiagramEdge, 'relations' | 'description'> & {
229
+ export type Edge = Except<DiagramEdge, 'relations' | 'description'> & {
229
230
  relationId: RelationId
230
231
  sourceHandle: string
231
232
  targetHandle: string
@@ -402,7 +403,7 @@ export function layoutRelationshipDetails(
402
403
  y: position.y,
403
404
  position: [position.x, position.y],
404
405
  title: element.title,
405
- description: RichText.from(element.description),
406
+ description: element.summary,
406
407
  technology: element.technology,
407
408
  tags: [...element.tags],
408
409
  links: null,
@@ -1,6 +1,7 @@
1
1
  import { cx } from '@likec4/styles/css'
2
2
  import { ActionIcon, Group } from '@mantine/core'
3
3
  import { useCallbackRef, useStateHistory } from '@mantine/hooks'
4
+ import { useRafEffect } from '@react-hookz/web'
4
5
  import { IconChevronLeft, IconChevronRight, IconX } from '@tabler/icons-react'
5
6
  import { Panel, ReactFlowProvider, useReactFlow, useStoreApi } from '@xyflow/react'
6
7
  import { shallowEqual } from 'fast-equals'
@@ -183,7 +184,7 @@ const RelationshipsBrowserInner = memo(() => {
183
184
  }
184
185
  }, [historySubjectId, browser])
185
186
 
186
- useEffect(() => {
187
+ useRafEffect(() => {
187
188
  browser.updateView(layouted)
188
189
  }, [layouted, browser])
189
190
 
@@ -518,7 +518,7 @@ export function layoutRelationshipsView(
518
518
  y: position.y,
519
519
  position: [position.x, position.y],
520
520
  title: element.title,
521
- description: RichText.from(element.description),
521
+ description: element.summary,
522
522
  technology: element.technology,
523
523
  tags: [...element.tags],
524
524
  links: null,
@@ -279,7 +279,7 @@ function ElementTreeNode(
279
279
  </Tooltip>
280
280
  </Group>
281
281
  <Highlight component="div" highlight={searchTerms} className={btn.description!} lineClamp={1}>
282
- {element.description.text || 'No description'}
282
+ {element.summary.text || 'No description'}
283
283
  </Highlight>
284
284
  </Box>
285
285
 
@@ -1,32 +1,25 @@
1
- import type { DiagramView, WhereOperator } from '@likec4/core/types'
2
- import { useCustomCompareEffect } from '@react-hookz/web'
1
+ import type { DiagramView, DynamicViewDisplayVariant, WhereOperator } from '@likec4/core/types'
2
+ import { useCustomCompareEffect, useRafEffect } from '@react-hookz/web'
3
3
  import { useActorRef, useSelector } from '@xstate/react'
4
4
  import { useStoreApi } from '@xyflow/react'
5
5
  import { deepEqual, shallowEqual } from 'fast-equals'
6
- import { type PropsWithChildren, useEffect, useRef } from 'react'
6
+ import { type PropsWithChildren, useMemo, useRef } from 'react'
7
7
  import { ErrorBoundary } from '../components/ErrorFallback'
8
8
  import { useDiagramEventHandlers } from '../context/DiagramEventHandlers'
9
9
  import { DiagramFeatures, useEnabledFeatures } from '../context/DiagramFeatures'
10
10
  import { useOnDiagramEvent } from '../custom'
11
11
  import { DiagramActorContextProvider } from '../hooks/safeContext'
12
- import { useCurrentViewId } from '../hooks/useCurrentViewId'
13
12
  import type { ViewPadding } from '../LikeC4Diagram.props'
13
+ import { convertToXYFlow } from '../likec4diagram/convert-to-xyflow'
14
14
  import type { Types } from '../likec4diagram/types'
15
- import { useViewToNodesEdges } from '../likec4diagram/useViewToNodesEdges'
16
15
  import { CurrentViewModelContext } from '../likec4model/LikeC4ModelContext'
17
16
  import { useLikeC4Model } from '../likec4model/useLikeC4Model'
18
17
  import { type DiagramMachine, diagramMachine } from './diagram-machine'
19
18
  import { syncManualLayoutActorLogic } from './syncManualLayoutActor'
20
19
  import type { DiagramActorRef, DiagramActorSnapshot } from './types'
21
20
 
22
- const selectToggledFeatures = (state: DiagramActorSnapshot) => {
23
- if (state.context.features.enableReadOnly || state.context.activeWalkthrough) {
24
- return {
25
- ...state.context.toggledFeatures,
26
- enableReadOnly: true,
27
- }
28
- }
29
- return state.context.toggledFeatures
21
+ const selectDynamicViewVariant = (state: DiagramActorSnapshot) => {
22
+ return state.context.dynamicViewVariant
30
23
  }
31
24
 
32
25
  export function DiagramActorProvider({
@@ -37,6 +30,7 @@ export function DiagramActorProvider({
37
30
  nodesSelectable,
38
31
  where,
39
32
  children,
33
+ dynamicViewVariant: _defaultVariant,
40
34
  }: PropsWithChildren<{
41
35
  view: DiagramView
42
36
  zoomable: boolean
@@ -44,6 +38,7 @@ export function DiagramActorProvider({
44
38
  fitViewPadding: ViewPadding
45
39
  nodesSelectable: boolean
46
40
  where: WhereOperator | null
41
+ dynamicViewVariant: DynamicViewDisplayVariant | undefined
47
42
  }>) {
48
43
  const { handlersRef } = useDiagramEventHandlers()
49
44
  const xystore = useStoreApi<Types.Node, Types.Edge>()
@@ -76,6 +71,7 @@ export function DiagramActorProvider({
76
71
  pannable,
77
72
  fitViewPadding,
78
73
  nodesSelectable,
74
+ dynamicViewVariant: _defaultVariant,
79
75
  },
80
76
  },
81
77
  )
@@ -97,39 +93,56 @@ export function DiagramActorProvider({
97
93
  deepEqual,
98
94
  )
99
95
 
100
- const { xyedges, xynodes } = useViewToNodesEdges({
101
- view,
102
- where,
103
- nodesSelectable,
104
- })
96
+ const dynamicViewVariant = useSelector(actorRef, selectDynamicViewVariant)
105
97
 
106
- useEffect(() => {
107
- actorRef.send({ type: 'update.view', view, xyedges, xynodes })
108
- }, [view, xyedges, xynodes])
98
+ const update = useMemo(
99
+ () => convertToXYFlow({ view, where, nodesSelectable, dynamicViewVariant }),
100
+ [view, where, nodesSelectable, dynamicViewVariant],
101
+ )
109
102
 
110
- const toggledFeatures = useSelector(actorRef, selectToggledFeatures, shallowEqual)
103
+ useRafEffect(() => {
104
+ actorRef.send({
105
+ type: 'update.view',
106
+ ...update,
107
+ })
108
+ }, [actorRef, update])
111
109
 
112
110
  return (
113
111
  <DiagramActorContextProvider value={actorRef}>
114
- <DiagramFeatures overrides={toggledFeatures}>
115
- <ErrorBoundary>
116
- <CurrentViewModelProvider>
117
- {children}
118
- </CurrentViewModelProvider>
119
- </ErrorBoundary>
120
- </DiagramFeatures>
112
+ <ErrorBoundary>
113
+ <CurrentViewModelProvider actorRef={actorRef}>
114
+ {children}
115
+ </CurrentViewModelProvider>
116
+ </ErrorBoundary>
121
117
  <DiagramActorEventListener actorRef={actorRef} />
122
118
  </DiagramActorContextProvider>
123
119
  )
124
120
  }
125
121
 
126
- function CurrentViewModelProvider({ children }: PropsWithChildren) {
127
- const viewId = useCurrentViewId()
122
+ const selectViewIdAndToggledFeatures = (state: DiagramActorSnapshot) => {
123
+ if (state.context.features.enableReadOnly || state.context.activeWalkthrough) {
124
+ return {
125
+ viewId: state.context.view.id,
126
+ toggledFeatures: {
127
+ ...state.context.toggledFeatures,
128
+ enableReadOnly: true,
129
+ },
130
+ }
131
+ }
132
+ return {
133
+ viewId: state.context.view.id,
134
+ toggledFeatures: state.context.toggledFeatures,
135
+ }
136
+ }
137
+ function CurrentViewModelProvider({ children, actorRef }: PropsWithChildren<{ actorRef: DiagramActorRef }>) {
138
+ const { viewId, toggledFeatures } = useSelector(actorRef, selectViewIdAndToggledFeatures, deepEqual)
128
139
  const likec4model = useLikeC4Model()
129
140
  const viewmodel = likec4model.findView(viewId)
130
141
  return (
131
142
  <CurrentViewModelContext.Provider value={viewmodel}>
132
- {children}
143
+ <DiagramFeatures overrides={toggledFeatures}>
144
+ {children}
145
+ </DiagramFeatures>
133
146
  </CurrentViewModelContext.Provider>
134
147
  )
135
148
  }
@@ -141,25 +154,7 @@ function DiagramActorEventListener({ actorRef }: { actorRef: DiagramActorRef })
141
154
  } = useDiagramEventHandlers()
142
155
 
143
156
  useOnDiagramEvent('openSource', ({ params }) => onOpenSource?.(params))
144
-
145
- // onNavigateTo we defer the callback for better responsiveness
146
- // (allowing animation to finish)
147
- useEffect(() => {
148
- if (!onNavigateTo) return
149
- let frame: number
150
-
151
- const subscription = actorRef.on('navigateTo', ({ viewId }) => {
152
- cancelAnimationFrame(frame)
153
- // Slightly defer callback for better responsiveness
154
- frame = requestAnimationFrame(() => {
155
- onNavigateTo(viewId)
156
- })
157
- })
158
- return () => {
159
- cancelAnimationFrame(frame)
160
- subscription.unsubscribe()
161
- }
162
- }, [actorRef, onNavigateTo])
157
+ useOnDiagramEvent('navigateTo', ({ viewId }) => onNavigateTo?.(viewId))
163
158
 
164
159
  return null
165
160
  }
@@ -5,6 +5,7 @@ import { isEmpty, mergeDeep, omit } from 'remeda'
5
5
  import { assertEvent } from 'xstate'
6
6
  import { Base } from '../base/types'
7
7
  import type { Types } from '../likec4diagram/types'
8
+ import { SeqParallelAreaColor } from '../likec4diagram/xyflow-sequence/const'
8
9
  import { type Vector, vector, VectorImpl } from '../utils/vector'
9
10
  import type { ActionArg, Context as DiagramContext } from './diagram-machine'
10
11
 
@@ -68,21 +69,25 @@ export function mergeXYNodesEdges({ context, event }: ActionArg): Partial<Diagra
68
69
  const currentEdges = context.xyedges
69
70
  xyedges = event.xyedges.map((update): Types.Edge => {
70
71
  const existing = currentEdges.find(n => n.id === update.id)
71
- if (existing) {
72
+ if (existing && existing.type === update.type) {
72
73
  if (
73
74
  eq(existing.hidden ?? false, update.hidden ?? false)
74
75
  && eq(existing.data, update.data)
76
+ && eq(existing.source, update.source)
77
+ && eq(existing.target, update.target)
78
+ && eq(existing.sourceHandle, update.sourceHandle)
79
+ && eq(existing.targetHandle, update.targetHandle)
75
80
  ) {
76
81
  return existing
77
82
  }
78
83
  return {
79
- ...existing,
84
+ ...omit(existing, ['sourceHandle', 'targetHandle']),
80
85
  ...update,
81
86
  data: {
82
87
  ...existing.data,
83
88
  ...update.data,
84
89
  },
85
- }
90
+ } as Types.Edge
86
91
  }
87
92
  return update
88
93
  })
@@ -388,7 +393,7 @@ export function resetEdgeControlPoints({ context }: ActionArg): Partial<DiagramC
388
393
  ...edge.data,
389
394
  controlPoints: getControlPointForEdge(edge),
390
395
  },
391
- })
396
+ } as Types.Edge)
392
397
  }),
393
398
  }
394
399
  }
@@ -401,11 +406,19 @@ export function updateActiveWalkthrough({ context }: ActionArg): Partial<Diagram
401
406
  const active = stepId === edge.id || (!!parallelPrefix && edge.id.startsWith(parallelPrefix))
402
407
  return Base.setData(edge, {
403
408
  active,
404
- dimmed: !active,
409
+ dimmed: stepId !== edge.id,
405
410
  })
406
411
  }),
407
412
  xynodes: context.xynodes.map(node => {
408
413
  const dimmed = step.source !== node.id && step.target !== node.id
414
+ if (node.type === 'seq-parallel') {
415
+ return Base.setData(node, {
416
+ color: parallelPrefix === node.data.parallelPrefix
417
+ ? SeqParallelAreaColor.active
418
+ : SeqParallelAreaColor.default,
419
+ dimmed,
420
+ })
421
+ }
409
422
  return Base.setDimmed(node, dimmed)
410
423
  }),
411
424
  }